github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/drivers/windows/windows.go (about) 1 //go:build windows 2 3 // Shim for the Host Network Service (HNS) to manage networking for 4 // Windows Server containers and Hyper-V containers. This module 5 // is a basic libnetwork driver that passes all the calls to HNS 6 // It implements the 4 networking modes supported by HNS L2Bridge, 7 // L2Tunnel, NAT and Transparent(DHCP) 8 // 9 // The network are stored in memory and docker daemon ensures discovering 10 // and loading these networks on startup 11 12 package windows 13 14 import ( 15 "context" 16 "encoding/json" 17 "fmt" 18 "net" 19 "strconv" 20 "strings" 21 "sync" 22 23 "github.com/Microsoft/hcsshim" 24 "github.com/containerd/log" 25 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/datastore" 26 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/driverapi" 27 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/netlabel" 28 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/portmapper" 29 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/scope" 30 "github.com/Prakhar-Agarwal-byte/moby/libnetwork/types" 31 ) 32 33 // networkConfiguration for network specific configuration 34 type networkConfiguration struct { 35 ID string 36 Type string 37 Name string 38 HnsID string 39 RDID string 40 VLAN uint 41 VSID uint 42 DNSServers string 43 MacPools []hcsshim.MacPool 44 DNSSuffix string 45 SourceMac string 46 NetworkAdapterName string 47 dbIndex uint64 48 dbExists bool 49 DisableGatewayDNS bool 50 EnableOutboundNat bool 51 OutboundNatExceptions []string 52 } 53 54 // endpointConfiguration represents the user specified configuration for the sandbox endpoint 55 type endpointOption struct { 56 MacAddress net.HardwareAddr 57 QosPolicies []types.QosPolicy 58 DNSServers []string 59 DisableDNS bool 60 DisableICC bool 61 } 62 63 // EndpointConnectivity stores the port bindings and exposed ports that the user has specified in epOptions. 64 type EndpointConnectivity struct { 65 PortBindings []types.PortBinding 66 ExposedPorts []types.TransportPort 67 } 68 69 type hnsEndpoint struct { 70 id string 71 nid string 72 profileID string 73 Type string 74 // Note: Currently, the sandboxID is the same as the containerID since windows does 75 // not expose the sandboxID. 76 // In the future, windows will support a proper sandboxID that is different 77 // than the containerID. 78 // Therefore, we are using sandboxID now, so that we won't have to change this code 79 // when windows properly supports a sandboxID. 80 sandboxID string 81 macAddress net.HardwareAddr 82 epOption *endpointOption // User specified parameters 83 epConnectivity *EndpointConnectivity // User specified parameters 84 portMapping []types.PortBinding // Operation port bindings 85 addr *net.IPNet 86 gateway net.IP 87 dbIndex uint64 88 dbExists bool 89 } 90 91 type hnsNetwork struct { 92 id string 93 created bool 94 config *networkConfiguration 95 endpoints map[string]*hnsEndpoint // key: endpoint id 96 driver *driver // The network's driver 97 portMapper *portmapper.PortMapper 98 sync.Mutex 99 } 100 101 type driver struct { 102 name string 103 networks map[string]*hnsNetwork 104 store *datastore.Store 105 sync.Mutex 106 } 107 108 const ( 109 errNotFound = "HNS failed with error : The object identifier does not represent a valid object. " 110 ) 111 112 var builtinLocalDrivers = map[string]struct{}{ 113 "transparent": {}, 114 "l2bridge": {}, 115 "l2tunnel": {}, 116 "nat": {}, 117 "internal": {}, 118 "private": {}, 119 "ics": {}, 120 } 121 122 // IsBuiltinLocalDriver validates if network-type is a builtin local-scoped driver 123 func IsBuiltinLocalDriver(networkType string) bool { 124 _, ok := builtinLocalDrivers[networkType] 125 return ok 126 } 127 128 // New constructs a new bridge driver 129 func newDriver(networkType string) *driver { 130 return &driver{name: networkType, networks: map[string]*hnsNetwork{}} 131 } 132 133 // GetInit returns an initializer for the given network type 134 func RegisterBuiltinLocalDrivers(r driverapi.Registerer, driverConfig func(string) map[string]interface{}) error { 135 for networkType := range builtinLocalDrivers { 136 d := newDriver(networkType) 137 err := d.initStore(driverConfig(networkType)) 138 if err != nil { 139 return fmt.Errorf("failed to initialize %q driver: %w", networkType, err) 140 } 141 142 err = r.RegisterDriver(networkType, d, driverapi.Capability{ 143 DataScope: scope.Local, 144 ConnectivityScope: scope.Local, 145 }) 146 if err != nil { 147 return fmt.Errorf("failed to register %q driver: %w", networkType, err) 148 } 149 } 150 return nil 151 } 152 153 func (d *driver) getNetwork(id string) (*hnsNetwork, error) { 154 d.Lock() 155 defer d.Unlock() 156 157 if nw, ok := d.networks[id]; ok { 158 return nw, nil 159 } 160 161 return nil, types.NotFoundErrorf("network not found: %s", id) 162 } 163 164 func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) { 165 n.Lock() 166 defer n.Unlock() 167 168 if ep, ok := n.endpoints[eid]; ok { 169 return ep, nil 170 } 171 172 return nil, types.NotFoundErrorf("Endpoint not found: %s", eid) 173 } 174 175 func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) { 176 config := &networkConfiguration{Type: d.name} 177 178 for label, value := range genericOptions { 179 switch label { 180 case NetworkName: 181 config.Name = value 182 case HNSID: 183 config.HnsID = value 184 case RoutingDomain: 185 config.RDID = value 186 case Interface: 187 config.NetworkAdapterName = value 188 case DNSSuffix: 189 config.DNSSuffix = value 190 case DNSServers: 191 config.DNSServers = value 192 case DisableGatewayDNS: 193 b, err := strconv.ParseBool(value) 194 if err != nil { 195 return nil, err 196 } 197 config.DisableGatewayDNS = b 198 case MacPool: 199 config.MacPools = make([]hcsshim.MacPool, 0) 200 s := strings.Split(value, ",") 201 if len(s)%2 != 0 { 202 return nil, types.InvalidParameterErrorf("invalid mac pool. You must specify both a start range and an end range") 203 } 204 for i := 0; i < len(s)-1; i += 2 { 205 config.MacPools = append(config.MacPools, hcsshim.MacPool{ 206 StartMacAddress: s[i], 207 EndMacAddress: s[i+1], 208 }) 209 } 210 case VLAN: 211 vlan, err := strconv.ParseUint(value, 10, 32) 212 if err != nil { 213 return nil, err 214 } 215 config.VLAN = uint(vlan) 216 case VSID: 217 vsid, err := strconv.ParseUint(value, 10, 32) 218 if err != nil { 219 return nil, err 220 } 221 config.VSID = uint(vsid) 222 case EnableOutboundNat: 223 b, err := strconv.ParseBool(value) 224 if err != nil { 225 return nil, err 226 } 227 config.EnableOutboundNat = b 228 case OutboundNatExceptions: 229 s := strings.Split(value, ",") 230 config.OutboundNatExceptions = s 231 } 232 } 233 234 config.ID = id 235 config.Type = d.name 236 return config, nil 237 } 238 239 func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error { 240 if len(ipamV6Data) > 0 { 241 return types.ForbiddenErrorf("windowsshim driver doesn't support v6 subnets") 242 } 243 244 if len(ipamV4Data) == 0 { 245 return types.InvalidParameterErrorf("network %s requires ipv4 configuration", id) 246 } 247 248 return nil 249 } 250 251 func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) { 252 } 253 254 func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) { 255 return "", nil 256 } 257 258 func (d *driver) createNetwork(config *networkConfiguration) *hnsNetwork { 259 network := &hnsNetwork{ 260 id: config.ID, 261 endpoints: make(map[string]*hnsEndpoint), 262 config: config, 263 driver: d, 264 portMapper: portmapper.New(), 265 } 266 267 d.Lock() 268 d.networks[config.ID] = network 269 d.Unlock() 270 271 return network 272 } 273 274 // Create a new network 275 func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error { 276 if _, err := d.getNetwork(id); err == nil { 277 return types.ForbiddenErrorf("network %s exists", id) 278 } 279 280 genData, ok := option[netlabel.GenericData].(map[string]string) 281 if !ok { 282 return fmt.Errorf("Unknown generic data option") 283 } 284 285 // Parse and validate the config. It should not conflict with existing networks' config 286 config, err := d.parseNetworkOptions(id, genData) 287 if err != nil { 288 return err 289 } 290 291 err = config.processIPAM(id, ipV4Data, ipV6Data) 292 if err != nil { 293 return err 294 } 295 296 n := d.createNetwork(config) 297 298 // A non blank hnsid indicates that the network was discovered 299 // from HNS. No need to call HNS if this network was discovered 300 // from HNS 301 if config.HnsID == "" { 302 subnets := []hcsshim.Subnet{} 303 304 for _, ipData := range ipV4Data { 305 subnet := hcsshim.Subnet{ 306 AddressPrefix: ipData.Pool.String(), 307 } 308 309 if ipData.Gateway != nil { 310 subnet.GatewayAddress = ipData.Gateway.IP.String() 311 } 312 313 subnets = append(subnets, subnet) 314 } 315 316 network := &hcsshim.HNSNetwork{ 317 Name: config.Name, 318 Type: d.name, 319 Subnets: subnets, 320 DNSServerList: config.DNSServers, 321 DNSSuffix: config.DNSSuffix, 322 MacPools: config.MacPools, 323 SourceMac: config.SourceMac, 324 NetworkAdapterName: config.NetworkAdapterName, 325 } 326 327 if config.VLAN != 0 { 328 vlanPolicy, err := json.Marshal(hcsshim.VlanPolicy{ 329 Type: "VLAN", 330 VLAN: config.VLAN, 331 }) 332 if err != nil { 333 return err 334 } 335 network.Policies = append(network.Policies, vlanPolicy) 336 } 337 338 if config.VSID != 0 { 339 vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{ 340 Type: "VSID", 341 VSID: config.VSID, 342 }) 343 if err != nil { 344 return err 345 } 346 network.Policies = append(network.Policies, vsidPolicy) 347 } 348 349 if network.Name == "" { 350 network.Name = id 351 } 352 353 configurationb, err := json.Marshal(network) 354 if err != nil { 355 return err 356 } 357 358 configuration := string(configurationb) 359 log.G(context.TODO()).Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets) 360 361 hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration) 362 if err != nil { 363 return err 364 } 365 366 config.HnsID = hnsresponse.Id 367 genData[HNSID] = config.HnsID 368 n.created = true 369 370 defer func() { 371 if err != nil { 372 d.DeleteNetwork(n.id) 373 } 374 }() 375 376 hnsIPv4Data := make([]driverapi.IPAMData, len(hnsresponse.Subnets)) 377 378 for i, subnet := range hnsresponse.Subnets { 379 var gwIP, subnetIP *net.IPNet 380 381 // The gateway returned from HNS is an IPAddress. 382 // We need to convert it to an IPNet to use as the Gateway of driverapi.IPAMData struct 383 gwCIDR := subnet.GatewayAddress + "/32" 384 _, gwIP, err = net.ParseCIDR(gwCIDR) 385 if err != nil { 386 return err 387 } 388 389 hnsIPv4Data[i].Gateway = gwIP 390 _, subnetIP, err = net.ParseCIDR(subnet.AddressPrefix) 391 if err != nil { 392 return err 393 } 394 hnsIPv4Data[i].Pool = subnetIP 395 } 396 397 nInfo.UpdateIpamConfig(hnsIPv4Data) 398 399 } else { 400 // Delete any stale HNS endpoints for this network. 401 if endpoints, err := hcsshim.HNSListEndpointRequest(); err == nil { 402 for _, ep := range endpoints { 403 if ep.VirtualNetwork == config.HnsID { 404 log.G(context.TODO()).Infof("Removing stale HNS endpoint %s", ep.Id) 405 _, err = hcsshim.HNSEndpointRequest("DELETE", ep.Id, "") 406 if err != nil { 407 log.G(context.TODO()).Warnf("Error removing HNS endpoint %s", ep.Id) 408 } 409 } 410 } 411 } else { 412 log.G(context.TODO()).Warnf("Error listing HNS endpoints for network %s", config.HnsID) 413 } 414 415 n.created = true 416 } 417 418 return d.storeUpdate(config) 419 } 420 421 func (d *driver) DeleteNetwork(nid string) error { 422 n, err := d.getNetwork(nid) 423 if err != nil { 424 return types.InternalMaskableErrorf("%s", err) 425 } 426 427 n.Lock() 428 config := n.config 429 n.Unlock() 430 431 if n.created { 432 _, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "") 433 if err != nil && err.Error() != errNotFound { 434 return types.ForbiddenErrorf(err.Error()) 435 } 436 } 437 438 d.Lock() 439 delete(d.networks, nid) 440 d.Unlock() 441 442 // delele endpoints belong to this network 443 for _, ep := range n.endpoints { 444 if err := d.storeDelete(ep); err != nil { 445 log.G(context.TODO()).Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err) 446 } 447 } 448 449 return d.storeDelete(config) 450 } 451 452 func convertQosPolicies(qosPolicies []types.QosPolicy) ([]json.RawMessage, error) { 453 var qps []json.RawMessage 454 455 // Enumerate through the qos policies specified by the user and convert 456 // them into the internal structure matching the JSON blob that can be 457 // understood by the HCS. 458 for _, elem := range qosPolicies { 459 encodedPolicy, err := json.Marshal(hcsshim.QosPolicy{ 460 Type: "QOS", 461 MaximumOutgoingBandwidthInBytes: elem.MaxEgressBandwidth, 462 }) 463 if err != nil { 464 return nil, err 465 } 466 qps = append(qps, encodedPolicy) 467 } 468 return qps, nil 469 } 470 471 // ConvertPortBindings converts PortBindings to JSON for HNS request 472 func ConvertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) { 473 var pbs []json.RawMessage 474 475 // Enumerate through the port bindings specified by the user and convert 476 // them into the internal structure matching the JSON blob that can be 477 // understood by the HCS. 478 for _, elem := range portBindings { 479 proto := strings.ToUpper(elem.Proto.String()) 480 if proto != "TCP" && proto != "UDP" { 481 return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String()) 482 } 483 484 if elem.HostPort != elem.HostPortEnd { 485 return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings") 486 } 487 488 if len(elem.HostIP) != 0 && !elem.HostIP.IsUnspecified() { 489 return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings") 490 } 491 492 encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{ 493 Type: "NAT", 494 ExternalPort: elem.HostPort, 495 InternalPort: elem.Port, 496 Protocol: elem.Proto.String(), 497 ExternalPortReserved: true, 498 }) 499 if err != nil { 500 return nil, err 501 } 502 pbs = append(pbs, encodedPolicy) 503 } 504 return pbs, nil 505 } 506 507 // ParsePortBindingPolicies parses HNS endpoint response message to PortBindings 508 func ParsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) { 509 var bindings []types.PortBinding 510 hcsPolicy := &hcsshim.NatPolicy{} 511 512 for _, elem := range policies { 513 514 if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" { 515 continue 516 } 517 518 binding := types.PortBinding{ 519 HostPort: hcsPolicy.ExternalPort, 520 HostPortEnd: hcsPolicy.ExternalPort, 521 Port: hcsPolicy.InternalPort, 522 Proto: types.ParseProtocol(hcsPolicy.Protocol), 523 HostIP: net.IPv4(0, 0, 0, 0), 524 } 525 526 bindings = append(bindings, binding) 527 } 528 529 return bindings, nil 530 } 531 532 func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) { 533 if epOptions == nil { 534 return nil, nil 535 } 536 537 ec := &endpointOption{} 538 539 if opt, ok := epOptions[netlabel.MacAddress]; ok { 540 if mac, ok := opt.(net.HardwareAddr); ok { 541 ec.MacAddress = mac 542 } else { 543 return nil, fmt.Errorf("Invalid endpoint configuration") 544 } 545 } 546 547 if opt, ok := epOptions[QosPolicies]; ok { 548 if policies, ok := opt.([]types.QosPolicy); ok { 549 ec.QosPolicies = policies 550 } else { 551 return nil, fmt.Errorf("Invalid endpoint configuration") 552 } 553 } 554 555 if opt, ok := epOptions[netlabel.DNSServers]; ok { 556 if dns, ok := opt.([]string); ok { 557 ec.DNSServers = dns 558 } else { 559 return nil, fmt.Errorf("Invalid endpoint configuration") 560 } 561 } 562 563 if opt, ok := epOptions[DisableICC]; ok { 564 if disableICC, ok := opt.(bool); ok { 565 ec.DisableICC = disableICC 566 } else { 567 return nil, fmt.Errorf("Invalid endpoint configuration") 568 } 569 } 570 571 if opt, ok := epOptions[DisableDNS]; ok { 572 if disableDNS, ok := opt.(bool); ok { 573 ec.DisableDNS = disableDNS 574 } else { 575 return nil, fmt.Errorf("Invalid endpoint configuration") 576 } 577 } 578 579 return ec, nil 580 } 581 582 // ParseEndpointConnectivity parses options passed to CreateEndpoint, specifically port bindings, and store in a endpointConnectivity object. 583 func ParseEndpointConnectivity(epOptions map[string]interface{}) (*EndpointConnectivity, error) { 584 if epOptions == nil { 585 return nil, nil 586 } 587 588 ec := &EndpointConnectivity{} 589 590 if opt, ok := epOptions[netlabel.PortMap]; ok { 591 if bs, ok := opt.([]types.PortBinding); ok { 592 ec.PortBindings = bs 593 } else { 594 return nil, fmt.Errorf("Invalid endpoint configuration") 595 } 596 } 597 598 if opt, ok := epOptions[netlabel.ExposedPorts]; ok { 599 if ports, ok := opt.([]types.TransportPort); ok { 600 ec.ExposedPorts = ports 601 } else { 602 return nil, fmt.Errorf("Invalid endpoint configuration") 603 } 604 } 605 return ec, nil 606 } 607 608 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { 609 n, err := d.getNetwork(nid) 610 if err != nil { 611 return err 612 } 613 614 // Check if endpoint id is good and retrieve corresponding endpoint 615 ep, err := n.getEndpoint(eid) 616 if err == nil && ep != nil { 617 return driverapi.ErrEndpointExists(eid) 618 } 619 620 endpointStruct := &hcsshim.HNSEndpoint{ 621 VirtualNetwork: n.config.HnsID, 622 } 623 624 epOption, err := parseEndpointOptions(epOptions) 625 if err != nil { 626 return err 627 } 628 epConnectivity, err := ParseEndpointConnectivity(epOptions) 629 if err != nil { 630 return err 631 } 632 633 macAddress := ifInfo.MacAddress() 634 // Use the macaddress if it was provided 635 if macAddress != nil { 636 endpointStruct.MacAddress = strings.ReplaceAll(macAddress.String(), ":", "-") 637 } 638 639 portMapping := epConnectivity.PortBindings 640 641 if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" { 642 ip := net.IPv4(0, 0, 0, 0) 643 if ifInfo.Address() != nil { 644 ip = ifInfo.Address().IP 645 } 646 647 portMapping, err = AllocatePorts(n.portMapper, portMapping, ip) 648 if err != nil { 649 return err 650 } 651 652 defer func() { 653 if err != nil { 654 ReleasePorts(n.portMapper, portMapping) 655 } 656 }() 657 } 658 659 endpointStruct.Policies, err = ConvertPortBindings(portMapping) 660 if err != nil { 661 return err 662 } 663 664 qosPolicies, err := convertQosPolicies(epOption.QosPolicies) 665 if err != nil { 666 return err 667 } 668 endpointStruct.Policies = append(endpointStruct.Policies, qosPolicies...) 669 670 if ifInfo.Address() != nil { 671 endpointStruct.IPAddress = ifInfo.Address().IP 672 } 673 674 endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",") 675 676 // overwrite the ep DisableDNS option if DisableGatewayDNS was set to true during the network creation option 677 if n.config.DisableGatewayDNS { 678 log.G(context.TODO()).Debugf("n.config.DisableGatewayDNS[%v] overwrites epOption.DisableDNS[%v]", n.config.DisableGatewayDNS, epOption.DisableDNS) 679 epOption.DisableDNS = n.config.DisableGatewayDNS 680 } 681 682 if n.driver.name == "nat" && !epOption.DisableDNS { 683 endpointStruct.EnableInternalDNS = true 684 log.G(context.TODO()).Debugf("endpointStruct.EnableInternalDNS =[%v]", endpointStruct.EnableInternalDNS) 685 } 686 687 endpointStruct.DisableICC = epOption.DisableICC 688 689 // Inherit OutboundNat policy from the network 690 if n.config.EnableOutboundNat { 691 outboundNatPolicy, err := json.Marshal(hcsshim.OutboundNatPolicy{ 692 Policy: hcsshim.Policy{Type: hcsshim.OutboundNat}, 693 Exceptions: n.config.OutboundNatExceptions, 694 }) 695 if err != nil { 696 return err 697 } 698 endpointStruct.Policies = append(endpointStruct.Policies, outboundNatPolicy) 699 } 700 701 configurationb, err := json.Marshal(endpointStruct) 702 if err != nil { 703 return err 704 } 705 706 hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb)) 707 if err != nil { 708 return err 709 } 710 711 mac, err := net.ParseMAC(hnsresponse.MacAddress) 712 if err != nil { 713 return err 714 } 715 716 // TODO For now the ip mask is not in the info generated by HNS 717 endpoint := &hnsEndpoint{ 718 id: eid, 719 nid: n.id, 720 Type: d.name, 721 addr: &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()}, 722 macAddress: mac, 723 } 724 725 if hnsresponse.GatewayAddress != "" { 726 endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress) 727 } 728 729 endpoint.profileID = hnsresponse.Id 730 endpoint.epConnectivity = epConnectivity 731 endpoint.epOption = epOption 732 endpoint.portMapping, err = ParsePortBindingPolicies(hnsresponse.Policies) 733 734 if err != nil { 735 hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "") 736 return err 737 } 738 739 n.Lock() 740 n.endpoints[eid] = endpoint 741 n.Unlock() 742 743 if ifInfo.Address() == nil { 744 ifInfo.SetIPAddress(endpoint.addr) 745 } 746 747 if macAddress == nil { 748 ifInfo.SetMacAddress(endpoint.macAddress) 749 } 750 751 if err = d.storeUpdate(endpoint); err != nil { 752 log.G(context.TODO()).Errorf("Failed to save endpoint %.7s to store: %v", endpoint.id, err) 753 } 754 755 return nil 756 } 757 758 func (d *driver) DeleteEndpoint(nid, eid string) error { 759 n, err := d.getNetwork(nid) 760 if err != nil { 761 return types.InternalMaskableErrorf("%s", err) 762 } 763 764 ep, err := n.getEndpoint(eid) 765 if err != nil { 766 return err 767 } 768 769 if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" { 770 ReleasePorts(n.portMapper, ep.portMapping) 771 } 772 773 n.Lock() 774 delete(n.endpoints, eid) 775 n.Unlock() 776 777 _, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "") 778 if err != nil && err.Error() != errNotFound { 779 return err 780 } 781 782 if err := d.storeDelete(ep); err != nil { 783 log.G(context.TODO()).Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err) 784 } 785 return nil 786 } 787 788 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { 789 network, err := d.getNetwork(nid) 790 if err != nil { 791 return nil, err 792 } 793 794 ep, err := network.getEndpoint(eid) 795 if err != nil { 796 return nil, err 797 } 798 799 data := make(map[string]interface{}, 1) 800 if network.driver.name == "nat" { 801 data["AllowUnqualifiedDNSQuery"] = true 802 } 803 804 data["hnsid"] = ep.profileID 805 if ep.epConnectivity.ExposedPorts != nil { 806 // Return a copy of the config data 807 epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts)) 808 for _, tp := range ep.epConnectivity.ExposedPorts { 809 epc = append(epc, tp.GetCopy()) 810 } 811 data[netlabel.ExposedPorts] = epc 812 } 813 814 if ep.portMapping != nil { 815 // Return a copy of the operational data 816 pmc := make([]types.PortBinding, 0, len(ep.portMapping)) 817 for _, pm := range ep.portMapping { 818 pmc = append(pmc, pm.GetCopy()) 819 } 820 data[netlabel.PortMap] = pmc 821 } 822 823 if len(ep.macAddress) != 0 { 824 data[netlabel.MacAddress] = ep.macAddress 825 } 826 return data, nil 827 } 828 829 // Join method is invoked when a Sandbox is attached to an endpoint. 830 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 831 network, err := d.getNetwork(nid) 832 if err != nil { 833 return err 834 } 835 836 // Ensure that the endpoint exists 837 endpoint, err := network.getEndpoint(eid) 838 if err != nil { 839 return err 840 } 841 842 err = jinfo.SetGateway(endpoint.gateway) 843 if err != nil { 844 return err 845 } 846 847 endpoint.sandboxID = sboxKey 848 849 err = hcsshim.HotAttachEndpoint(endpoint.sandboxID, endpoint.profileID) 850 if err != nil { 851 // If container doesn't exists in hcs, do not throw error for hot add/remove 852 if err != hcsshim.ErrComputeSystemDoesNotExist { 853 return err 854 } 855 } 856 857 jinfo.DisableGatewayService() 858 return nil 859 } 860 861 // Leave method is invoked when a Sandbox detaches from an endpoint. 862 func (d *driver) Leave(nid, eid string) error { 863 network, err := d.getNetwork(nid) 864 if err != nil { 865 return types.InternalMaskableErrorf("%s", err) 866 } 867 868 // Ensure that the endpoint exists 869 endpoint, err := network.getEndpoint(eid) 870 if err != nil { 871 return err 872 } 873 874 err = hcsshim.HotDetachEndpoint(endpoint.sandboxID, endpoint.profileID) 875 if err != nil { 876 // If container doesn't exists in hcs, do not throw error for hot add/remove 877 if err != hcsshim.ErrComputeSystemDoesNotExist { 878 return err 879 } 880 } 881 return nil 882 } 883 884 func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { 885 return nil 886 } 887 888 func (d *driver) RevokeExternalConnectivity(nid, eid string) error { 889 return nil 890 } 891 892 func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { 893 return nil, types.NotImplementedErrorf("not implemented") 894 } 895 896 func (d *driver) NetworkFree(id string) error { 897 return types.NotImplementedErrorf("not implemented") 898 } 899 900 func (d *driver) Type() string { 901 return d.name 902 } 903 904 func (d *driver) IsBuiltIn() bool { 905 return true 906 }