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