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  }