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