github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/libnetwork/drivers/windows/windows.go (about) 1 // +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 "encoding/json" 16 "fmt" 17 "net" 18 "strconv" 19 "strings" 20 "sync" 21 22 "github.com/Microsoft/hcsshim" 23 "github.com/Microsoft/hcsshim/osversion" 24 "github.com/docker/libnetwork/datastore" 25 "github.com/docker/libnetwork/discoverapi" 26 "github.com/docker/libnetwork/driverapi" 27 "github.com/docker/libnetwork/netlabel" 28 "github.com/docker/libnetwork/portmapper" 29 "github.com/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 if osversion.Build() <= 16236 { 221 return nil, fmt.Errorf("Invalid network option. OutboundNat is not supported on this OS version") 222 } 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.BadRequestErrorf("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 333 if err != nil { 334 return err 335 } 336 network.Policies = append(network.Policies, vlanPolicy) 337 } 338 339 if config.VSID != 0 { 340 vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{ 341 Type: "VSID", 342 VSID: config.VSID, 343 }) 344 345 if err != nil { 346 return err 347 } 348 network.Policies = append(network.Policies, vsidPolicy) 349 } 350 351 if network.Name == "" { 352 network.Name = id 353 } 354 355 configurationb, err := json.Marshal(network) 356 if err != nil { 357 return err 358 } 359 360 configuration := string(configurationb) 361 logrus.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets) 362 363 hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration) 364 if err != nil { 365 return err 366 } 367 368 config.HnsID = hnsresponse.Id 369 genData[HNSID] = config.HnsID 370 n.created = true 371 372 defer func() { 373 if err != nil { 374 d.DeleteNetwork(n.id) 375 } 376 }() 377 378 hnsIPv4Data := make([]driverapi.IPAMData, len(hnsresponse.Subnets)) 379 380 for i, subnet := range hnsresponse.Subnets { 381 var gwIP, subnetIP *net.IPNet 382 383 //The gateway returned from HNS is an IPAddress. 384 //We need to convert it to an IPNet to use as the Gateway of driverapi.IPAMData struct 385 gwCIDR := subnet.GatewayAddress + "/32" 386 _, gwIP, err = net.ParseCIDR(gwCIDR) 387 if err != nil { 388 return err 389 } 390 391 hnsIPv4Data[i].Gateway = gwIP 392 _, subnetIP, err = net.ParseCIDR(subnet.AddressPrefix) 393 if err != nil { 394 return err 395 } 396 hnsIPv4Data[i].Pool = subnetIP 397 } 398 399 nInfo.UpdateIpamConfig(hnsIPv4Data) 400 401 } else { 402 // Delete any stale HNS endpoints for this network. 403 if endpoints, err := hcsshim.HNSListEndpointRequest(); err == nil { 404 for _, ep := range endpoints { 405 if ep.VirtualNetwork == config.HnsID { 406 logrus.Infof("Removing stale HNS endpoint %s", ep.Id) 407 _, err = hcsshim.HNSEndpointRequest("DELETE", ep.Id, "") 408 if err != nil { 409 logrus.Warnf("Error removing HNS endpoint %s", ep.Id) 410 } 411 } 412 } 413 } else { 414 logrus.Warnf("Error listing HNS endpoints for network %s", config.HnsID) 415 } 416 417 n.created = true 418 } 419 420 return d.storeUpdate(config) 421 } 422 423 func (d *driver) DeleteNetwork(nid string) error { 424 n, err := d.getNetwork(nid) 425 if err != nil { 426 return types.InternalMaskableErrorf("%s", err) 427 } 428 429 n.Lock() 430 config := n.config 431 n.Unlock() 432 433 if n.created { 434 _, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "") 435 if err != nil && err.Error() != errNotFound { 436 return types.ForbiddenErrorf(err.Error()) 437 } 438 } 439 440 d.Lock() 441 delete(d.networks, nid) 442 d.Unlock() 443 444 // delele endpoints belong to this network 445 for _, ep := range n.endpoints { 446 if err := d.storeDelete(ep); err != nil { 447 logrus.Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err) 448 } 449 } 450 451 return d.storeDelete(config) 452 } 453 454 func convertQosPolicies(qosPolicies []types.QosPolicy) ([]json.RawMessage, error) { 455 var qps []json.RawMessage 456 457 // Enumerate through the qos policies specified by the user and convert 458 // them into the internal structure matching the JSON blob that can be 459 // understood by the HCS. 460 for _, elem := range qosPolicies { 461 encodedPolicy, err := json.Marshal(hcsshim.QosPolicy{ 462 Type: "QOS", 463 MaximumOutgoingBandwidthInBytes: elem.MaxEgressBandwidth, 464 }) 465 466 if err != nil { 467 return nil, err 468 } 469 qps = append(qps, encodedPolicy) 470 } 471 return qps, nil 472 } 473 474 // ConvertPortBindings converts PortBindings to JSON for HNS request 475 func ConvertPortBindings(portBindings []types.PortBinding) ([]json.RawMessage, error) { 476 var pbs []json.RawMessage 477 478 // Enumerate through the port bindings specified by the user and convert 479 // them into the internal structure matching the JSON blob that can be 480 // understood by the HCS. 481 for _, elem := range portBindings { 482 proto := strings.ToUpper(elem.Proto.String()) 483 if proto != "TCP" && proto != "UDP" { 484 return nil, fmt.Errorf("invalid protocol %s", elem.Proto.String()) 485 } 486 487 if elem.HostPort != elem.HostPortEnd { 488 return nil, fmt.Errorf("Windows does not support more than one host port in NAT settings") 489 } 490 491 if len(elem.HostIP) != 0 && !elem.HostIP.IsUnspecified() { 492 return nil, fmt.Errorf("Windows does not support host IP addresses in NAT settings") 493 } 494 495 encodedPolicy, err := json.Marshal(hcsshim.NatPolicy{ 496 Type: "NAT", 497 ExternalPort: elem.HostPort, 498 InternalPort: elem.Port, 499 Protocol: elem.Proto.String(), 500 }) 501 502 if err != nil { 503 return nil, err 504 } 505 pbs = append(pbs, encodedPolicy) 506 } 507 return pbs, nil 508 } 509 510 // ParsePortBindingPolicies parses HNS endpoint response message to PortBindings 511 func ParsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) { 512 var bindings []types.PortBinding 513 hcsPolicy := &hcsshim.NatPolicy{} 514 515 for _, elem := range policies { 516 517 if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" { 518 continue 519 } 520 521 binding := types.PortBinding{ 522 HostPort: hcsPolicy.ExternalPort, 523 HostPortEnd: hcsPolicy.ExternalPort, 524 Port: hcsPolicy.InternalPort, 525 Proto: types.ParseProtocol(hcsPolicy.Protocol), 526 HostIP: net.IPv4(0, 0, 0, 0), 527 } 528 529 bindings = append(bindings, binding) 530 } 531 532 return bindings, nil 533 } 534 535 func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) { 536 if epOptions == nil { 537 return nil, nil 538 } 539 540 ec := &endpointOption{} 541 542 if opt, ok := epOptions[netlabel.MacAddress]; ok { 543 if mac, ok := opt.(net.HardwareAddr); ok { 544 ec.MacAddress = mac 545 } else { 546 return nil, fmt.Errorf("Invalid endpoint configuration") 547 } 548 } 549 550 if opt, ok := epOptions[QosPolicies]; ok { 551 if policies, ok := opt.([]types.QosPolicy); ok { 552 ec.QosPolicies = policies 553 } else { 554 return nil, fmt.Errorf("Invalid endpoint configuration") 555 } 556 } 557 558 if opt, ok := epOptions[netlabel.DNSServers]; ok { 559 if dns, ok := opt.([]string); ok { 560 ec.DNSServers = dns 561 } else { 562 return nil, fmt.Errorf("Invalid endpoint configuration") 563 } 564 } 565 566 if opt, ok := epOptions[DisableICC]; ok { 567 if disableICC, ok := opt.(bool); ok { 568 ec.DisableICC = disableICC 569 } else { 570 return nil, fmt.Errorf("Invalid endpoint configuration") 571 } 572 } 573 574 if opt, ok := epOptions[DisableDNS]; ok { 575 if disableDNS, ok := opt.(bool); ok { 576 ec.DisableDNS = disableDNS 577 } else { 578 return nil, fmt.Errorf("Invalid endpoint configuration") 579 } 580 } 581 582 return ec, nil 583 } 584 585 // ParseEndpointConnectivity parses options passed to CreateEndpoint, specifically port bindings, and store in a endpointConnectivity object. 586 func ParseEndpointConnectivity(epOptions map[string]interface{}) (*EndpointConnectivity, error) { 587 if epOptions == nil { 588 return nil, nil 589 } 590 591 ec := &EndpointConnectivity{} 592 593 if opt, ok := epOptions[netlabel.PortMap]; ok { 594 if bs, ok := opt.([]types.PortBinding); ok { 595 ec.PortBindings = bs 596 } else { 597 return nil, fmt.Errorf("Invalid endpoint configuration") 598 } 599 } 600 601 if opt, ok := epOptions[netlabel.ExposedPorts]; ok { 602 if ports, ok := opt.([]types.TransportPort); ok { 603 ec.ExposedPorts = ports 604 } else { 605 return nil, fmt.Errorf("Invalid endpoint configuration") 606 } 607 } 608 return ec, nil 609 } 610 611 func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error { 612 n, err := d.getNetwork(nid) 613 if err != nil { 614 return err 615 } 616 617 // Check if endpoint id is good and retrieve corresponding endpoint 618 ep, err := n.getEndpoint(eid) 619 if err == nil && ep != nil { 620 return driverapi.ErrEndpointExists(eid) 621 } 622 623 endpointStruct := &hcsshim.HNSEndpoint{ 624 VirtualNetwork: n.config.HnsID, 625 } 626 627 epOption, err := parseEndpointOptions(epOptions) 628 if err != nil { 629 return err 630 } 631 epConnectivity, err := ParseEndpointConnectivity(epOptions) 632 if err != nil { 633 return err 634 } 635 636 macAddress := ifInfo.MacAddress() 637 // Use the macaddress if it was provided 638 if macAddress != nil { 639 endpointStruct.MacAddress = strings.Replace(macAddress.String(), ":", "-", -1) 640 } 641 642 portMapping := epConnectivity.PortBindings 643 644 if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" { 645 ip := net.IPv4(0, 0, 0, 0) 646 if ifInfo.Address() != nil { 647 ip = ifInfo.Address().IP 648 } 649 650 portMapping, err = AllocatePorts(n.portMapper, portMapping, ip) 651 if err != nil { 652 return err 653 } 654 655 defer func() { 656 if err != nil { 657 ReleasePorts(n.portMapper, portMapping) 658 } 659 }() 660 } 661 662 endpointStruct.Policies, err = ConvertPortBindings(portMapping) 663 if err != nil { 664 return err 665 } 666 667 qosPolicies, err := convertQosPolicies(epOption.QosPolicies) 668 if err != nil { 669 return err 670 } 671 endpointStruct.Policies = append(endpointStruct.Policies, qosPolicies...) 672 673 if ifInfo.Address() != nil { 674 endpointStruct.IPAddress = ifInfo.Address().IP 675 } 676 677 endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",") 678 679 // overwrite the ep DisableDNS option if DisableGatewayDNS was set to true during the network creation option 680 if n.config.DisableGatewayDNS { 681 logrus.Debugf("n.config.DisableGatewayDNS[%v] overwrites epOption.DisableDNS[%v]", n.config.DisableGatewayDNS, epOption.DisableDNS) 682 epOption.DisableDNS = n.config.DisableGatewayDNS 683 } 684 685 if n.driver.name == "nat" && !epOption.DisableDNS { 686 logrus.Debugf("endpointStruct.EnableInternalDNS =[%v]", endpointStruct.EnableInternalDNS) 687 endpointStruct.EnableInternalDNS = true 688 } 689 690 endpointStruct.DisableICC = epOption.DisableICC 691 692 // Inherit OutboundNat policy from the network 693 if n.config.EnableOutboundNat { 694 outboundNatPolicy, err := json.Marshal(hcsshim.OutboundNatPolicy{ 695 Policy: hcsshim.Policy{Type: hcsshim.OutboundNat}, 696 Exceptions: n.config.OutboundNatExceptions, 697 }) 698 699 if err != nil { 700 return err 701 } 702 endpointStruct.Policies = append(endpointStruct.Policies, outboundNatPolicy) 703 } 704 705 configurationb, err := json.Marshal(endpointStruct) 706 if err != nil { 707 return err 708 } 709 710 hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb)) 711 if err != nil { 712 return err 713 } 714 715 mac, err := net.ParseMAC(hnsresponse.MacAddress) 716 if err != nil { 717 return err 718 } 719 720 // TODO For now the ip mask is not in the info generated by HNS 721 endpoint := &hnsEndpoint{ 722 id: eid, 723 nid: n.id, 724 Type: d.name, 725 addr: &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()}, 726 macAddress: mac, 727 } 728 729 if hnsresponse.GatewayAddress != "" { 730 endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress) 731 } 732 733 endpoint.profileID = hnsresponse.Id 734 endpoint.epConnectivity = epConnectivity 735 endpoint.epOption = epOption 736 endpoint.portMapping, err = ParsePortBindingPolicies(hnsresponse.Policies) 737 738 if err != nil { 739 hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "") 740 return err 741 } 742 743 n.Lock() 744 n.endpoints[eid] = endpoint 745 n.Unlock() 746 747 if ifInfo.Address() == nil { 748 ifInfo.SetIPAddress(endpoint.addr) 749 } 750 751 if macAddress == nil { 752 ifInfo.SetMacAddress(endpoint.macAddress) 753 } 754 755 if err = d.storeUpdate(endpoint); err != nil { 756 logrus.Errorf("Failed to save endpoint %.7s to store: %v", endpoint.id, err) 757 } 758 759 return nil 760 } 761 762 func (d *driver) DeleteEndpoint(nid, eid string) error { 763 n, err := d.getNetwork(nid) 764 if err != nil { 765 return types.InternalMaskableErrorf("%s", err) 766 } 767 768 ep, err := n.getEndpoint(eid) 769 if err != nil { 770 return err 771 } 772 773 if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" { 774 ReleasePorts(n.portMapper, ep.portMapping) 775 } 776 777 n.Lock() 778 delete(n.endpoints, eid) 779 n.Unlock() 780 781 _, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "") 782 if err != nil && err.Error() != errNotFound { 783 return err 784 } 785 786 if err := d.storeDelete(ep); err != nil { 787 logrus.Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err) 788 } 789 return nil 790 } 791 792 func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) { 793 network, err := d.getNetwork(nid) 794 if err != nil { 795 return nil, err 796 } 797 798 ep, err := network.getEndpoint(eid) 799 if err != nil { 800 return nil, err 801 } 802 803 data := make(map[string]interface{}, 1) 804 if network.driver.name == "nat" { 805 data["AllowUnqualifiedDNSQuery"] = true 806 } 807 808 data["hnsid"] = ep.profileID 809 if ep.epConnectivity.ExposedPorts != nil { 810 // Return a copy of the config data 811 epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts)) 812 for _, tp := range ep.epConnectivity.ExposedPorts { 813 epc = append(epc, tp.GetCopy()) 814 } 815 data[netlabel.ExposedPorts] = epc 816 } 817 818 if ep.portMapping != nil { 819 // Return a copy of the operational data 820 pmc := make([]types.PortBinding, 0, len(ep.portMapping)) 821 for _, pm := range ep.portMapping { 822 pmc = append(pmc, pm.GetCopy()) 823 } 824 data[netlabel.PortMap] = pmc 825 } 826 827 if len(ep.macAddress) != 0 { 828 data[netlabel.MacAddress] = ep.macAddress 829 } 830 return data, nil 831 } 832 833 // Join method is invoked when a Sandbox is attached to an endpoint. 834 func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error { 835 network, err := d.getNetwork(nid) 836 if err != nil { 837 return err 838 } 839 840 // Ensure that the endpoint exists 841 endpoint, err := network.getEndpoint(eid) 842 if err != nil { 843 return err 844 } 845 846 err = jinfo.SetGateway(endpoint.gateway) 847 if err != nil { 848 return err 849 } 850 851 endpoint.sandboxID = sboxKey 852 853 err = hcsshim.HotAttachEndpoint(endpoint.sandboxID, endpoint.profileID) 854 if err != nil { 855 // If container doesn't exists in hcs, do not throw error for hot add/remove 856 if err != hcsshim.ErrComputeSystemDoesNotExist { 857 return err 858 } 859 } 860 861 jinfo.DisableGatewayService() 862 return nil 863 } 864 865 // Leave method is invoked when a Sandbox detaches from an endpoint. 866 func (d *driver) Leave(nid, eid string) error { 867 network, err := d.getNetwork(nid) 868 if err != nil { 869 return types.InternalMaskableErrorf("%s", err) 870 } 871 872 // Ensure that the endpoint exists 873 endpoint, err := network.getEndpoint(eid) 874 if err != nil { 875 return err 876 } 877 878 err = hcsshim.HotDetachEndpoint(endpoint.sandboxID, endpoint.profileID) 879 if err != nil { 880 // If container doesn't exists in hcs, do not throw error for hot add/remove 881 if err != hcsshim.ErrComputeSystemDoesNotExist { 882 return err 883 } 884 } 885 return nil 886 } 887 888 func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error { 889 return nil 890 } 891 892 func (d *driver) RevokeExternalConnectivity(nid, eid string) error { 893 return nil 894 } 895 896 func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) { 897 return nil, types.NotImplementedErrorf("not implemented") 898 } 899 900 func (d *driver) NetworkFree(id string) error { 901 return types.NotImplementedErrorf("not implemented") 902 } 903 904 func (d *driver) Type() string { 905 return d.name 906 } 907 908 func (d *driver) IsBuiltIn() bool { 909 return true 910 } 911 912 // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster 913 func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error { 914 return nil 915 } 916 917 // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster 918 func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error { 919 return nil 920 }