github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/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/libnetwork/datastore" 26 "github.com/docker/libnetwork/discoverapi" 27 "github.com/docker/libnetwork/driverapi" 28 "github.com/docker/libnetwork/netlabel" 29 "github.com/docker/libnetwork/portmapper" 30 "github.com/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 ExternalPortReserved: true, 502 }) 503 504 if err != nil { 505 return nil, err 506 } 507 pbs = append(pbs, encodedPolicy) 508 } 509 return pbs, nil 510 } 511 512 // ParsePortBindingPolicies parses HNS endpoint response message to PortBindings 513 func ParsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) { 514 var bindings []types.PortBinding 515 hcsPolicy := &hcsshim.NatPolicy{} 516 517 for _, elem := range policies { 518 519 if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" { 520 continue 521 } 522 523 binding := types.PortBinding{ 524 HostPort: hcsPolicy.ExternalPort, 525 HostPortEnd: hcsPolicy.ExternalPort, 526 Port: hcsPolicy.InternalPort, 527 Proto: types.ParseProtocol(hcsPolicy.Protocol), 528 HostIP: net.IPv4(0, 0, 0, 0), 529 } 530 531 bindings = append(bindings, binding) 532 } 533 534 return bindings, nil 535 } 536 537 func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) { 538 if epOptions == nil { 539 return nil, nil 540 } 541 542 ec := &endpointOption{} 543 544 if opt, ok := epOptions[netlabel.MacAddress]; ok { 545 if mac, ok := opt.(net.HardwareAddr); ok { 546 ec.MacAddress = mac 547 } else { 548 return nil, fmt.Errorf("Invalid endpoint configuration") 549 } 550 } 551 552 if opt, ok := epOptions[QosPolicies]; ok { 553 if policies, ok := opt.([]types.QosPolicy); ok { 554 ec.QosPolicies = policies 555 } else { 556 return nil, fmt.Errorf("Invalid endpoint configuration") 557 } 558 } 559 560 if opt, ok := epOptions[netlabel.DNSServers]; ok { 561 if dns, ok := opt.([]string); ok { 562 ec.DNSServers = dns 563 } else { 564 return nil, fmt.Errorf("Invalid endpoint configuration") 565 } 566 } 567 568 if opt, ok := epOptions[DisableICC]; ok { 569 if disableICC, ok := opt.(bool); ok { 570 ec.DisableICC = disableICC 571 } else { 572 return nil, fmt.Errorf("Invalid endpoint configuration") 573 } 574 } 575 576 if opt, ok := epOptions[DisableDNS]; ok { 577 if disableDNS, ok := opt.(bool); ok { 578 ec.DisableDNS = disableDNS 579 } else { 580 return nil, fmt.Errorf("Invalid endpoint configuration") 581 } 582 } 583 584 return ec, nil 585 } 586 587 // ParseEndpointConnectivity parses options passed to CreateEndpoint, specifically port bindings, and store in a endpointConnectivity object. 588 func ParseEndpointConnectivity(epOptions map[string]interface{}) (*EndpointConnectivity, error) { 589 if epOptions == nil { 590 return nil, nil 591 } 592 593 ec := &EndpointConnectivity{} 594 595 if opt, ok := epOptions[netlabel.PortMap]; ok { 596 if bs, ok := opt.([]types.PortBinding); ok { 597 ec.PortBindings = bs 598 } else { 599 return nil, fmt.Errorf("Invalid endpoint configuration") 600 } 601 } 602 603 if opt, ok := epOptions[netlabel.ExposedPorts]; ok { 604 if ports, ok := opt.([]types.TransportPort); ok { 605 ec.ExposedPorts = ports 606 } else { 607 return nil, fmt.Errorf("Invalid endpoint configuration") 608 } 609 } 610 return ec, nil 611 } 612 613 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { 614 n, err := d.getNetwork(nid) 615 if err != nil { 616 return err 617 } 618 619 // Check if endpoint id is good and retrieve corresponding endpoint 620 ep, err := n.getEndpoint(eid) 621 if err == nil && ep != nil { 622 return driverapi.ErrEndpointExists(eid) 623 } 624 625 endpointStruct := &hcsshim.HNSEndpoint{ 626 VirtualNetwork: n.config.HnsID, 627 } 628 629 epOption, err := parseEndpointOptions(epOptions) 630 if err != nil { 631 return err 632 } 633 epConnectivity, err := ParseEndpointConnectivity(epOptions) 634 if err != nil { 635 return err 636 } 637 638 macAddress := ifInfo.MacAddress() 639 // Use the macaddress if it was provided 640 if macAddress != nil { 641 endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1) 642 } 643 644 portMapping := epConnectivity.PortBindings 645 646 if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" { 647 ip := net.IPv4(0, 0, 0, 0) 648 if ifInfo.Address() != nil { 649 ip = ifInfo.Address().IP 650 } 651 652 portMapping, err = AllocatePorts(n.portMapper, portMapping, ip) 653 if err != nil { 654 return err 655 } 656 657 defer func() { 658 if err != nil { 659 ReleasePorts(n.portMapper, portMapping) 660 } 661 }() 662 } 663 664 endpointStruct.Policies, err = ConvertPortBindings(portMapping) 665 if err != nil { 666 return err 667 } 668 669 qosPolicies, err := convertQosPolicies(epOption.QosPolicies) 670 if err != nil { 671 return err 672 } 673 endpointStruct.Policies = append(endpointStruct.Policies, qosPolicies...) 674 675 if ifInfo.Address() != nil { 676 endpointStruct.IPAddress = ifInfo.Address().IP 677 } 678 679 endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",") 680 681 // overwrite the ep DisableDNS option if DisableGatewayDNS was set to true during the network creation option 682 if n.config.DisableGatewayDNS { 683 logrus.Debugf("n.config.DisableGatewayDNS[%v] overwrites epOption.DisableDNS[%v]", n.config.DisableGatewayDNS, epOption.DisableDNS) 684 epOption.DisableDNS = n.config.DisableGatewayDNS 685 } 686 687 if n.driver.name == "nat" && !epOption.DisableDNS { 688 logrus.Debugf("endpointStruct.EnableInternalDNS =[%v]", endpointStruct.EnableInternalDNS) 689 endpointStruct.EnableInternalDNS = true 690 } 691 692 endpointStruct.DisableICC = epOption.DisableICC 693 694 // Inherit OutboundNat policy from the network 695 if n.config.EnableOutboundNat { 696 outboundNatPolicy, err := json.Marshal(hcsshim.OutboundNatPolicy{ 697 Policy: hcsshim.Policy{Type: hcsshim.OutboundNat}, 698 Exceptions: n.config.OutboundNatExceptions, 699 }) 700 701 if err != nil { 702 return err 703 } 704 endpointStruct.Policies = append(endpointStruct.Policies, outboundNatPolicy) 705 } 706 707 configurationb, err := json.Marshal(endpointStruct) 708 if err != nil { 709 return err 710 } 711 712 hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb)) 713 if err != nil { 714 return err 715 } 716 717 mac, err := net.ParseMAC(hnsresponse.MacAddress) 718 if err != nil { 719 return err 720 } 721 722 // TODO For now the ip mask is not in the info generated by HNS 723 endpoint := &hnsEndpoint{ 724 id: eid, 725 nid: n.id, 726 Type: d.name, 727 addr: &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()}, 728 macAddress: mac, 729 } 730 731 if hnsresponse.GatewayAddress != "" { 732 endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress) 733 } 734 735 endpoint.profileID = hnsresponse.Id 736 endpoint.epConnectivity = epConnectivity 737 endpoint.epOption = epOption 738 endpoint.portMapping, err = ParsePortBindingPolicies(hnsresponse.Policies) 739 740 if err != nil { 741 hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "") 742 return err 743 } 744 745 n.Lock() 746 n.endpoints[eid] = endpoint 747 n.Unlock() 748 749 if ifInfo.Address() == nil { 750 ifInfo.SetIPAddress(endpoint.addr) 751 } 752 753 if macAddress == nil { 754 ifInfo.SetMacAddress(endpoint.macAddress) 755 } 756 757 if err = d.storeUpdate(endpoint); err != nil { 758 logrus.Errorf("Failed to save endpoint %.7s to store: %v", endpoint.id, err) 759 } 760 761 return nil 762 } 763 764 func (d *driver) DeleteEndpoint(nid, eid string) error { 765 n, err := d.getNetwork(nid) 766 if err != nil { 767 return types.InternalMaskableErrorf("%s", err) 768 } 769 770 ep, err := n.getEndpoint(eid) 771 if err != nil { 772 return err 773 } 774 775 if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" { 776 ReleasePorts(n.portMapper, ep.portMapping) 777 } 778 779 n.Lock() 780 delete(n.endpoints, eid) 781 n.Unlock() 782 783 _, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "") 784 if err != nil && err.Error() != errNotFound { 785 return err 786 } 787 788 if err := d.storeDelete(ep); err != nil { 789 logrus.Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err) 790 } 791 return nil 792 } 793 794 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { 795 network, err := d.getNetwork(nid) 796 if err != nil { 797 return nil, err 798 } 799 800 ep, err := network.getEndpoint(eid) 801 if err != nil { 802 return nil, err 803 } 804 805 data := make(map[string]interface{}, 1) 806 if network.driver.name == "nat" { 807 data["AllowUnqualifiedDNSQuery"] = true 808 } 809 810 data["hnsid"] = ep.profileID 811 if ep.epConnectivity.ExposedPorts != nil { 812 // Return a copy of the config data 813 epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts)) 814 for _, tp := range ep.epConnectivity.ExposedPorts { 815 epc = append(epc, tp.GetCopy()) 816 } 817 data[netlabel.ExposedPorts] = epc 818 } 819 820 if ep.portMapping != nil { 821 // Return a copy of the operational data 822 pmc := make([]types.PortBinding, 0, len(ep.portMapping)) 823 for _, pm := range ep.portMapping { 824 pmc = append(pmc, pm.GetCopy()) 825 } 826 data[netlabel.PortMap] = pmc 827 } 828 829 if len(ep.macAddress) != 0 { 830 data[netlabel.MacAddress] = ep.macAddress 831 } 832 return data, nil 833 } 834 835 // Join method is invoked when a Sandbox is attached to an endpoint. 836 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 837 network, err := d.getNetwork(nid) 838 if err != nil { 839 return err 840 } 841 842 // Ensure that the endpoint exists 843 endpoint, err := network.getEndpoint(eid) 844 if err != nil { 845 return err 846 } 847 848 err = jinfo.SetGateway(endpoint.gateway) 849 if err != nil { 850 return err 851 } 852 853 endpoint.sandboxID = sboxKey 854 855 err = hcsshim.HotAttachEndpoint(endpoint.sandboxID, endpoint.profileID) 856 if err != nil { 857 // If container doesn't exists in hcs, do not throw error for hot add/remove 858 if err != hcsshim.ErrComputeSystemDoesNotExist { 859 return err 860 } 861 } 862 863 jinfo.DisableGatewayService() 864 return nil 865 } 866 867 // Leave method is invoked when a Sandbox detaches from an endpoint. 868 func (d *driver) Leave(nid, eid string) error { 869 network, err := d.getNetwork(nid) 870 if err != nil { 871 return types.InternalMaskableErrorf("%s", err) 872 } 873 874 // Ensure that the endpoint exists 875 endpoint, err := network.getEndpoint(eid) 876 if err != nil { 877 return err 878 } 879 880 err = hcsshim.HotDetachEndpoint(endpoint.sandboxID, endpoint.profileID) 881 if err != nil { 882 // If container doesn't exists in hcs, do not throw error for hot add/remove 883 if err != hcsshim.ErrComputeSystemDoesNotExist { 884 return err 885 } 886 } 887 return nil 888 } 889 890 func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { 891 return nil 892 } 893 894 func (d *driver) RevokeExternalConnectivity(nid, eid string) error { 895 return nil 896 } 897 898 func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { 899 return nil, types.NotImplementedErrorf("not implemented") 900 } 901 902 func (d *driver) NetworkFree(id string) error { 903 return types.NotImplementedErrorf("not implemented") 904 } 905 906 func (d *driver) Type() string { 907 return d.name 908 } 909 910 func (d *driver) IsBuiltIn() bool { 911 return true 912 } 913 914 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster 915 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { 916 return nil 917 } 918 919 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster 920 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { 921 return nil 922 }