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  }