github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/libnetwork/drivers/windows/windows.go (about)

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