github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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/docker/docker/libnetwork/datastore"
    25  	"github.com/docker/docker/libnetwork/discoverapi"
    26  	"github.com/docker/docker/libnetwork/driverapi"
    27  	"github.com/docker/docker/libnetwork/netlabel"
    28  	"github.com/docker/docker/libnetwork/portmapper"
    29  	"github.com/docker/docker/libnetwork/types"
    30  	"github.com/sirupsen/logrus"
    31  )
    32  
    33  // networkConfiguration for network specific configuration
    34  type networkConfiguration struct {
    35  	ID                    string
    36  	Type                  string
    37  	Name                  string
    38  	HnsID                 string
    39  	RDID                  string
    40  	VLAN                  uint
    41  	VSID                  uint
    42  	DNSServers            string
    43  	MacPools              []hcsshim.MacPool
    44  	DNSSuffix             string
    45  	SourceMac             string
    46  	NetworkAdapterName    string
    47  	dbIndex               uint64
    48  	dbExists              bool
    49  	DisableGatewayDNS     bool
    50  	EnableOutboundNat     bool
    51  	OutboundNatExceptions []string
    52  }
    53  
    54  // endpointConfiguration represents the user specified configuration for the sandbox endpoint
    55  type endpointOption struct {
    56  	MacAddress  net.HardwareAddr
    57  	QosPolicies []types.QosPolicy
    58  	DNSServers  []string
    59  	DisableDNS  bool
    60  	DisableICC  bool
    61  }
    62  
    63  // EndpointConnectivity stores the port bindings and exposed ports that the user has specified in epOptions.
    64  type EndpointConnectivity struct {
    65  	PortBindings []types.PortBinding
    66  	ExposedPorts []types.TransportPort
    67  }
    68  
    69  type hnsEndpoint struct {
    70  	id        string
    71  	nid       string
    72  	profileID string
    73  	Type      string
    74  	// Note: Currently, the sandboxID is the same as the containerID since windows does
    75  	// not expose the sandboxID.
    76  	// In the future, windows will support a proper sandboxID that is different
    77  	// than the containerID.
    78  	// Therefore, we are using sandboxID now, so that we won't have to change this code
    79  	// when windows properly supports a sandboxID.
    80  	sandboxID      string
    81  	macAddress     net.HardwareAddr
    82  	epOption       *endpointOption       // User specified parameters
    83  	epConnectivity *EndpointConnectivity // User specified parameters
    84  	portMapping    []types.PortBinding   // Operation port bindings
    85  	addr           *net.IPNet
    86  	gateway        net.IP
    87  	dbIndex        uint64
    88  	dbExists       bool
    89  }
    90  
    91  type hnsNetwork struct {
    92  	id         string
    93  	created    bool
    94  	config     *networkConfiguration
    95  	endpoints  map[string]*hnsEndpoint // key: endpoint id
    96  	driver     *driver                 // The network's driver
    97  	portMapper *portmapper.PortMapper
    98  	sync.Mutex
    99  }
   100  
   101  type driver struct {
   102  	name     string
   103  	networks map[string]*hnsNetwork
   104  	store    datastore.DataStore
   105  	sync.Mutex
   106  }
   107  
   108  const (
   109  	errNotFound = "HNS failed with error : The object identifier does not represent a valid object. "
   110  )
   111  
   112  // IsBuiltinLocalDriver validates if network-type is a builtin local-scoped driver
   113  func IsBuiltinLocalDriver(networkType string) bool {
   114  	if "l2bridge" == networkType || "l2tunnel" == networkType ||
   115  		"nat" == networkType || "ics" == networkType ||
   116  		"transparent" == networkType || "internal" == networkType ||
   117  		"private" == networkType {
   118  		return true
   119  	}
   120  
   121  	return false
   122  }
   123  
   124  // New constructs a new bridge driver
   125  func newDriver(networkType string) *driver {
   126  	return &driver{name: networkType, networks: map[string]*hnsNetwork{}}
   127  }
   128  
   129  // GetInit returns an initializer for the given network type
   130  func GetInit(networkType string) func(dc driverapi.DriverCallback, config map[string]interface{}) error {
   131  	return func(dc driverapi.DriverCallback, config map[string]interface{}) error {
   132  		if !IsBuiltinLocalDriver(networkType) {
   133  			return types.BadRequestErrorf("Network type not supported: %s", networkType)
   134  		}
   135  
   136  		d := newDriver(networkType)
   137  
   138  		err := d.initStore(config)
   139  		if err != nil {
   140  			return err
   141  		}
   142  
   143  		return dc.RegisterDriver(networkType, d, driverapi.Capability{
   144  			DataScope:         datastore.LocalScope,
   145  			ConnectivityScope: datastore.LocalScope,
   146  		})
   147  	}
   148  }
   149  
   150  func (d *driver) getNetwork(id string) (*hnsNetwork, error) {
   151  	d.Lock()
   152  	defer d.Unlock()
   153  
   154  	if nw, ok := d.networks[id]; ok {
   155  		return nw, nil
   156  	}
   157  
   158  	return nil, types.NotFoundErrorf("network not found: %s", id)
   159  }
   160  
   161  func (n *hnsNetwork) getEndpoint(eid string) (*hnsEndpoint, error) {
   162  	n.Lock()
   163  	defer n.Unlock()
   164  
   165  	if ep, ok := n.endpoints[eid]; ok {
   166  		return ep, nil
   167  	}
   168  
   169  	return nil, types.NotFoundErrorf("Endpoint not found: %s", eid)
   170  }
   171  
   172  func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string) (*networkConfiguration, error) {
   173  	config := &networkConfiguration{Type: d.name}
   174  
   175  	for label, value := range genericOptions {
   176  		switch label {
   177  		case NetworkName:
   178  			config.Name = value
   179  		case HNSID:
   180  			config.HnsID = value
   181  		case RoutingDomain:
   182  			config.RDID = value
   183  		case Interface:
   184  			config.NetworkAdapterName = value
   185  		case DNSSuffix:
   186  			config.DNSSuffix = value
   187  		case DNSServers:
   188  			config.DNSServers = value
   189  		case DisableGatewayDNS:
   190  			b, err := strconv.ParseBool(value)
   191  			if err != nil {
   192  				return nil, err
   193  			}
   194  			config.DisableGatewayDNS = b
   195  		case MacPool:
   196  			config.MacPools = make([]hcsshim.MacPool, 0)
   197  			s := strings.Split(value, ",")
   198  			if len(s)%2 != 0 {
   199  				return nil, types.BadRequestErrorf("Invalid mac pool. You must specify both a start range and an end range")
   200  			}
   201  			for i := 0; i < len(s)-1; i += 2 {
   202  				config.MacPools = append(config.MacPools, hcsshim.MacPool{
   203  					StartMacAddress: s[i],
   204  					EndMacAddress:   s[i+1],
   205  				})
   206  			}
   207  		case VLAN:
   208  			vlan, err := strconv.ParseUint(value, 10, 32)
   209  			if err != nil {
   210  				return nil, err
   211  			}
   212  			config.VLAN = uint(vlan)
   213  		case VSID:
   214  			vsid, err := strconv.ParseUint(value, 10, 32)
   215  			if err != nil {
   216  				return nil, err
   217  			}
   218  			config.VSID = uint(vsid)
   219  		case EnableOutboundNat:
   220  			b, err := strconv.ParseBool(value)
   221  			if err != nil {
   222  				return nil, err
   223  			}
   224  			config.EnableOutboundNat = b
   225  		case OutboundNatExceptions:
   226  			s := strings.Split(value, ",")
   227  			config.OutboundNatExceptions = s
   228  		}
   229  	}
   230  
   231  	config.ID = id
   232  	config.Type = d.name
   233  	return config, nil
   234  }
   235  
   236  func (c *networkConfiguration) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error {
   237  	if len(ipamV6Data) > 0 {
   238  		return types.ForbiddenErrorf("windowsshim driver doesn't support v6 subnets")
   239  	}
   240  
   241  	if len(ipamV4Data) == 0 {
   242  		return types.BadRequestErrorf("network %s requires ipv4 configuration", id)
   243  	}
   244  
   245  	return nil
   246  }
   247  
   248  func (d *driver) EventNotify(etype driverapi.EventType, nid, tableName, key string, value []byte) {
   249  }
   250  
   251  func (d *driver) DecodeTableEntry(tablename string, key string, value []byte) (string, map[string]string) {
   252  	return "", nil
   253  }
   254  
   255  func (d *driver) createNetwork(config *networkConfiguration) *hnsNetwork {
   256  	network := &hnsNetwork{
   257  		id:         config.ID,
   258  		endpoints:  make(map[string]*hnsEndpoint),
   259  		config:     config,
   260  		driver:     d,
   261  		portMapper: portmapper.New(""),
   262  	}
   263  
   264  	d.Lock()
   265  	d.networks[config.ID] = network
   266  	d.Unlock()
   267  
   268  	return network
   269  }
   270  
   271  // Create a new network
   272  func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
   273  	if _, err := d.getNetwork(id); err == nil {
   274  		return types.ForbiddenErrorf("network %s exists", id)
   275  	}
   276  
   277  	genData, ok := option[netlabel.GenericData].(map[string]string)
   278  	if !ok {
   279  		return fmt.Errorf("Unknown generic data option")
   280  	}
   281  
   282  	// Parse and validate the config. It should not conflict with existing networks' config
   283  	config, err := d.parseNetworkOptions(id, genData)
   284  	if err != nil {
   285  		return err
   286  	}
   287  
   288  	err = config.processIPAM(id, ipV4Data, ipV6Data)
   289  	if err != nil {
   290  		return err
   291  	}
   292  
   293  	n := d.createNetwork(config)
   294  
   295  	// A non blank hnsid indicates that the network was discovered
   296  	// from HNS. No need to call HNS if this network was discovered
   297  	// from HNS
   298  	if config.HnsID == "" {
   299  		subnets := []hcsshim.Subnet{}
   300  
   301  		for _, ipData := range ipV4Data {
   302  			subnet := hcsshim.Subnet{
   303  				AddressPrefix: ipData.Pool.String(),
   304  			}
   305  
   306  			if ipData.Gateway != nil {
   307  				subnet.GatewayAddress = ipData.Gateway.IP.String()
   308  			}
   309  
   310  			subnets = append(subnets, subnet)
   311  		}
   312  
   313  		network := &hcsshim.HNSNetwork{
   314  			Name:               config.Name,
   315  			Type:               d.name,
   316  			Subnets:            subnets,
   317  			DNSServerList:      config.DNSServers,
   318  			DNSSuffix:          config.DNSSuffix,
   319  			MacPools:           config.MacPools,
   320  			SourceMac:          config.SourceMac,
   321  			NetworkAdapterName: config.NetworkAdapterName,
   322  		}
   323  
   324  		if config.VLAN != 0 {
   325  			vlanPolicy, err := json.Marshal(hcsshim.VlanPolicy{
   326  				Type: "VLAN",
   327  				VLAN: config.VLAN,
   328  			})
   329  
   330  			if err != nil {
   331  				return err
   332  			}
   333  			network.Policies = append(network.Policies, vlanPolicy)
   334  		}
   335  
   336  		if config.VSID != 0 {
   337  			vsidPolicy, err := json.Marshal(hcsshim.VsidPolicy{
   338  				Type: "VSID",
   339  				VSID: config.VSID,
   340  			})
   341  
   342  			if err != nil {
   343  				return err
   344  			}
   345  			network.Policies = append(network.Policies, vsidPolicy)
   346  		}
   347  
   348  		if network.Name == "" {
   349  			network.Name = id
   350  		}
   351  
   352  		configurationb, err := json.Marshal(network)
   353  		if err != nil {
   354  			return err
   355  		}
   356  
   357  		configuration := string(configurationb)
   358  		logrus.Debugf("HNSNetwork Request =%v Address Space=%v", configuration, subnets)
   359  
   360  		hnsresponse, err := hcsshim.HNSNetworkRequest("POST", "", configuration)
   361  		if err != nil {
   362  			return err
   363  		}
   364  
   365  		config.HnsID = hnsresponse.Id
   366  		genData[HNSID] = config.HnsID
   367  		n.created = true
   368  
   369  		defer func() {
   370  			if err != nil {
   371  				d.DeleteNetwork(n.id)
   372  			}
   373  		}()
   374  
   375  		hnsIPv4Data := make([]driverapi.IPAMData, len(hnsresponse.Subnets))
   376  
   377  		for i, subnet := range hnsresponse.Subnets {
   378  			var gwIP, subnetIP *net.IPNet
   379  
   380  			// The gateway returned from HNS is an IPAddress.
   381  			// We need to convert it to an IPNet to use as the Gateway of driverapi.IPAMData struct
   382  			gwCIDR := subnet.GatewayAddress + "/32"
   383  			_, gwIP, err = net.ParseCIDR(gwCIDR)
   384  			if err != nil {
   385  				return err
   386  			}
   387  
   388  			hnsIPv4Data[i].Gateway = gwIP
   389  			_, subnetIP, err = net.ParseCIDR(subnet.AddressPrefix)
   390  			if err != nil {
   391  				return err
   392  			}
   393  			hnsIPv4Data[i].Pool = subnetIP
   394  		}
   395  
   396  		nInfo.UpdateIpamConfig(hnsIPv4Data)
   397  
   398  	} else {
   399  		// Delete any stale HNS endpoints for this network.
   400  		if endpoints, err := hcsshim.HNSListEndpointRequest(); err == nil {
   401  			for _, ep := range endpoints {
   402  				if ep.VirtualNetwork == config.HnsID {
   403  					logrus.Infof("Removing stale HNS endpoint %s", ep.Id)
   404  					_, err = hcsshim.HNSEndpointRequest("DELETE", ep.Id, "")
   405  					if err != nil {
   406  						logrus.Warnf("Error removing HNS endpoint %s", ep.Id)
   407  					}
   408  				}
   409  			}
   410  		} else {
   411  			logrus.Warnf("Error listing HNS endpoints for network %s", config.HnsID)
   412  		}
   413  
   414  		n.created = true
   415  	}
   416  
   417  	return d.storeUpdate(config)
   418  }
   419  
   420  func (d *driver) DeleteNetwork(nid string) error {
   421  	n, err := d.getNetwork(nid)
   422  	if err != nil {
   423  		return types.InternalMaskableErrorf("%s", err)
   424  	}
   425  
   426  	n.Lock()
   427  	config := n.config
   428  	n.Unlock()
   429  
   430  	if n.created {
   431  		_, err = hcsshim.HNSNetworkRequest("DELETE", config.HnsID, "")
   432  		if err != nil && err.Error() != errNotFound {
   433  			return types.ForbiddenErrorf(err.Error())
   434  		}
   435  	}
   436  
   437  	d.Lock()
   438  	delete(d.networks, nid)
   439  	d.Unlock()
   440  
   441  	// delele endpoints belong to this network
   442  	for _, ep := range n.endpoints {
   443  		if err := d.storeDelete(ep); err != nil {
   444  			logrus.Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
   445  		}
   446  	}
   447  
   448  	return d.storeDelete(config)
   449  }
   450  
   451  func convertQosPolicies(qosPolicies []types.QosPolicy) ([]json.RawMessage, error) {
   452  	var qps []json.RawMessage
   453  
   454  	// Enumerate through the qos policies specified by the user and convert
   455  	// them into the internal structure matching the JSON blob that can be
   456  	// understood by the HCS.
   457  	for _, elem := range qosPolicies {
   458  		encodedPolicy, err := json.Marshal(hcsshim.QosPolicy{
   459  			Type:                            "QOS",
   460  			MaximumOutgoingBandwidthInBytes: elem.MaxEgressBandwidth,
   461  		})
   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  
   500  		if err != nil {
   501  			return nil, err
   502  		}
   503  		pbs = append(pbs, encodedPolicy)
   504  	}
   505  	return pbs, nil
   506  }
   507  
   508  // ParsePortBindingPolicies parses HNS endpoint response message to PortBindings
   509  func ParsePortBindingPolicies(policies []json.RawMessage) ([]types.PortBinding, error) {
   510  	var bindings []types.PortBinding
   511  	hcsPolicy := &hcsshim.NatPolicy{}
   512  
   513  	for _, elem := range policies {
   514  
   515  		if err := json.Unmarshal([]byte(elem), &hcsPolicy); err != nil || hcsPolicy.Type != "NAT" {
   516  			continue
   517  		}
   518  
   519  		binding := types.PortBinding{
   520  			HostPort:    hcsPolicy.ExternalPort,
   521  			HostPortEnd: hcsPolicy.ExternalPort,
   522  			Port:        hcsPolicy.InternalPort,
   523  			Proto:       types.ParseProtocol(hcsPolicy.Protocol),
   524  			HostIP:      net.IPv4(0, 0, 0, 0),
   525  		}
   526  
   527  		bindings = append(bindings, binding)
   528  	}
   529  
   530  	return bindings, nil
   531  }
   532  
   533  func parseEndpointOptions(epOptions map[string]interface{}) (*endpointOption, error) {
   534  	if epOptions == nil {
   535  		return nil, nil
   536  	}
   537  
   538  	ec := &endpointOption{}
   539  
   540  	if opt, ok := epOptions[netlabel.MacAddress]; ok {
   541  		if mac, ok := opt.(net.HardwareAddr); ok {
   542  			ec.MacAddress = mac
   543  		} else {
   544  			return nil, fmt.Errorf("Invalid endpoint configuration")
   545  		}
   546  	}
   547  
   548  	if opt, ok := epOptions[QosPolicies]; ok {
   549  		if policies, ok := opt.([]types.QosPolicy); ok {
   550  			ec.QosPolicies = policies
   551  		} else {
   552  			return nil, fmt.Errorf("Invalid endpoint configuration")
   553  		}
   554  	}
   555  
   556  	if opt, ok := epOptions[netlabel.DNSServers]; ok {
   557  		if dns, ok := opt.([]string); ok {
   558  			ec.DNSServers = dns
   559  		} else {
   560  			return nil, fmt.Errorf("Invalid endpoint configuration")
   561  		}
   562  	}
   563  
   564  	if opt, ok := epOptions[DisableICC]; ok {
   565  		if disableICC, ok := opt.(bool); ok {
   566  			ec.DisableICC = disableICC
   567  		} else {
   568  			return nil, fmt.Errorf("Invalid endpoint configuration")
   569  		}
   570  	}
   571  
   572  	if opt, ok := epOptions[DisableDNS]; ok {
   573  		if disableDNS, ok := opt.(bool); ok {
   574  			ec.DisableDNS = disableDNS
   575  		} else {
   576  			return nil, fmt.Errorf("Invalid endpoint configuration")
   577  		}
   578  	}
   579  
   580  	return ec, nil
   581  }
   582  
   583  // ParseEndpointConnectivity parses options passed to CreateEndpoint, specifically port bindings, and store in a endpointConnectivity object.
   584  func ParseEndpointConnectivity(epOptions map[string]interface{}) (*EndpointConnectivity, error) {
   585  	if epOptions == nil {
   586  		return nil, nil
   587  	}
   588  
   589  	ec := &EndpointConnectivity{}
   590  
   591  	if opt, ok := epOptions[netlabel.PortMap]; ok {
   592  		if bs, ok := opt.([]types.PortBinding); ok {
   593  			ec.PortBindings = bs
   594  		} else {
   595  			return nil, fmt.Errorf("Invalid endpoint configuration")
   596  		}
   597  	}
   598  
   599  	if opt, ok := epOptions[netlabel.ExposedPorts]; ok {
   600  		if ports, ok := opt.([]types.TransportPort); ok {
   601  			ec.ExposedPorts = ports
   602  		} else {
   603  			return nil, fmt.Errorf("Invalid endpoint configuration")
   604  		}
   605  	}
   606  	return ec, nil
   607  }
   608  
   609  func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
   610  	n, err := d.getNetwork(nid)
   611  	if err != nil {
   612  		return err
   613  	}
   614  
   615  	// Check if endpoint id is good and retrieve corresponding endpoint
   616  	ep, err := n.getEndpoint(eid)
   617  	if err == nil && ep != nil {
   618  		return driverapi.ErrEndpointExists(eid)
   619  	}
   620  
   621  	endpointStruct := &hcsshim.HNSEndpoint{
   622  		VirtualNetwork: n.config.HnsID,
   623  	}
   624  
   625  	epOption, err := parseEndpointOptions(epOptions)
   626  	if err != nil {
   627  		return err
   628  	}
   629  	epConnectivity, err := ParseEndpointConnectivity(epOptions)
   630  	if err != nil {
   631  		return err
   632  	}
   633  
   634  	macAddress := ifInfo.MacAddress()
   635  	// Use the macaddress if it was provided
   636  	if macAddress != nil {
   637  		endpointStruct.MacAddress = strings.ReplaceAll(macAddress.String(), ":", "-")
   638  	}
   639  
   640  	portMapping := epConnectivity.PortBindings
   641  
   642  	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
   643  		ip := net.IPv4(0, 0, 0, 0)
   644  		if ifInfo.Address() != nil {
   645  			ip = ifInfo.Address().IP
   646  		}
   647  
   648  		portMapping, err = AllocatePorts(n.portMapper, portMapping, ip)
   649  		if err != nil {
   650  			return err
   651  		}
   652  
   653  		defer func() {
   654  			if err != nil {
   655  				ReleasePorts(n.portMapper, portMapping)
   656  			}
   657  		}()
   658  	}
   659  
   660  	endpointStruct.Policies, err = ConvertPortBindings(portMapping)
   661  	if err != nil {
   662  		return err
   663  	}
   664  
   665  	qosPolicies, err := convertQosPolicies(epOption.QosPolicies)
   666  	if err != nil {
   667  		return err
   668  	}
   669  	endpointStruct.Policies = append(endpointStruct.Policies, qosPolicies...)
   670  
   671  	if ifInfo.Address() != nil {
   672  		endpointStruct.IPAddress = ifInfo.Address().IP
   673  	}
   674  
   675  	endpointStruct.DNSServerList = strings.Join(epOption.DNSServers, ",")
   676  
   677  	// overwrite the ep DisableDNS option if DisableGatewayDNS was set to true during the network creation option
   678  	if n.config.DisableGatewayDNS {
   679  		logrus.Debugf("n.config.DisableGatewayDNS[%v] overwrites epOption.DisableDNS[%v]", n.config.DisableGatewayDNS, epOption.DisableDNS)
   680  		epOption.DisableDNS = n.config.DisableGatewayDNS
   681  	}
   682  
   683  	if n.driver.name == "nat" && !epOption.DisableDNS {
   684  		logrus.Debugf("endpointStruct.EnableInternalDNS =[%v]", endpointStruct.EnableInternalDNS)
   685  		endpointStruct.EnableInternalDNS = true
   686  	}
   687  
   688  	endpointStruct.DisableICC = epOption.DisableICC
   689  
   690  	// Inherit OutboundNat policy from the network
   691  	if n.config.EnableOutboundNat {
   692  		outboundNatPolicy, err := json.Marshal(hcsshim.OutboundNatPolicy{
   693  			Policy:     hcsshim.Policy{Type: hcsshim.OutboundNat},
   694  			Exceptions: n.config.OutboundNatExceptions,
   695  		})
   696  
   697  		if err != nil {
   698  			return err
   699  		}
   700  		endpointStruct.Policies = append(endpointStruct.Policies, outboundNatPolicy)
   701  	}
   702  
   703  	configurationb, err := json.Marshal(endpointStruct)
   704  	if err != nil {
   705  		return err
   706  	}
   707  
   708  	hnsresponse, err := hcsshim.HNSEndpointRequest("POST", "", string(configurationb))
   709  	if err != nil {
   710  		return err
   711  	}
   712  
   713  	mac, err := net.ParseMAC(hnsresponse.MacAddress)
   714  	if err != nil {
   715  		return err
   716  	}
   717  
   718  	// TODO For now the ip mask is not in the info generated by HNS
   719  	endpoint := &hnsEndpoint{
   720  		id:         eid,
   721  		nid:        n.id,
   722  		Type:       d.name,
   723  		addr:       &net.IPNet{IP: hnsresponse.IPAddress, Mask: hnsresponse.IPAddress.DefaultMask()},
   724  		macAddress: mac,
   725  	}
   726  
   727  	if hnsresponse.GatewayAddress != "" {
   728  		endpoint.gateway = net.ParseIP(hnsresponse.GatewayAddress)
   729  	}
   730  
   731  	endpoint.profileID = hnsresponse.Id
   732  	endpoint.epConnectivity = epConnectivity
   733  	endpoint.epOption = epOption
   734  	endpoint.portMapping, err = ParsePortBindingPolicies(hnsresponse.Policies)
   735  
   736  	if err != nil {
   737  		hcsshim.HNSEndpointRequest("DELETE", hnsresponse.Id, "")
   738  		return err
   739  	}
   740  
   741  	n.Lock()
   742  	n.endpoints[eid] = endpoint
   743  	n.Unlock()
   744  
   745  	if ifInfo.Address() == nil {
   746  		ifInfo.SetIPAddress(endpoint.addr)
   747  	}
   748  
   749  	if macAddress == nil {
   750  		ifInfo.SetMacAddress(endpoint.macAddress)
   751  	}
   752  
   753  	if err = d.storeUpdate(endpoint); err != nil {
   754  		logrus.Errorf("Failed to save endpoint %.7s to store: %v", endpoint.id, err)
   755  	}
   756  
   757  	return nil
   758  }
   759  
   760  func (d *driver) DeleteEndpoint(nid, eid string) error {
   761  	n, err := d.getNetwork(nid)
   762  	if err != nil {
   763  		return types.InternalMaskableErrorf("%s", err)
   764  	}
   765  
   766  	ep, err := n.getEndpoint(eid)
   767  	if err != nil {
   768  		return err
   769  	}
   770  
   771  	if n.config.Type == "l2bridge" || n.config.Type == "l2tunnel" {
   772  		ReleasePorts(n.portMapper, ep.portMapping)
   773  	}
   774  
   775  	n.Lock()
   776  	delete(n.endpoints, eid)
   777  	n.Unlock()
   778  
   779  	_, err = hcsshim.HNSEndpointRequest("DELETE", ep.profileID, "")
   780  	if err != nil && err.Error() != errNotFound {
   781  		return err
   782  	}
   783  
   784  	if err := d.storeDelete(ep); err != nil {
   785  		logrus.Warnf("Failed to remove bridge endpoint %.7s from store: %v", ep.id, err)
   786  	}
   787  	return nil
   788  }
   789  
   790  func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
   791  	network, err := d.getNetwork(nid)
   792  	if err != nil {
   793  		return nil, err
   794  	}
   795  
   796  	ep, err := network.getEndpoint(eid)
   797  	if err != nil {
   798  		return nil, err
   799  	}
   800  
   801  	data := make(map[string]interface{}, 1)
   802  	if network.driver.name == "nat" {
   803  		data["AllowUnqualifiedDNSQuery"] = true
   804  	}
   805  
   806  	data["hnsid"] = ep.profileID
   807  	if ep.epConnectivity.ExposedPorts != nil {
   808  		// Return a copy of the config data
   809  		epc := make([]types.TransportPort, 0, len(ep.epConnectivity.ExposedPorts))
   810  		for _, tp := range ep.epConnectivity.ExposedPorts {
   811  			epc = append(epc, tp.GetCopy())
   812  		}
   813  		data[netlabel.ExposedPorts] = epc
   814  	}
   815  
   816  	if ep.portMapping != nil {
   817  		// Return a copy of the operational data
   818  		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
   819  		for _, pm := range ep.portMapping {
   820  			pmc = append(pmc, pm.GetCopy())
   821  		}
   822  		data[netlabel.PortMap] = pmc
   823  	}
   824  
   825  	if len(ep.macAddress) != 0 {
   826  		data[netlabel.MacAddress] = ep.macAddress
   827  	}
   828  	return data, nil
   829  }
   830  
   831  // Join method is invoked when a Sandbox is attached to an endpoint.
   832  func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
   833  	network, err := d.getNetwork(nid)
   834  	if err != nil {
   835  		return err
   836  	}
   837  
   838  	// Ensure that the endpoint exists
   839  	endpoint, err := network.getEndpoint(eid)
   840  	if err != nil {
   841  		return err
   842  	}
   843  
   844  	err = jinfo.SetGateway(endpoint.gateway)
   845  	if err != nil {
   846  		return err
   847  	}
   848  
   849  	endpoint.sandboxID = sboxKey
   850  
   851  	err = hcsshim.HotAttachEndpoint(endpoint.sandboxID, endpoint.profileID)
   852  	if err != nil {
   853  		// If container doesn't exists in hcs, do not throw error for hot add/remove
   854  		if err != hcsshim.ErrComputeSystemDoesNotExist {
   855  			return err
   856  		}
   857  	}
   858  
   859  	jinfo.DisableGatewayService()
   860  	return nil
   861  }
   862  
   863  // Leave method is invoked when a Sandbox detaches from an endpoint.
   864  func (d *driver) Leave(nid, eid string) error {
   865  	network, err := d.getNetwork(nid)
   866  	if err != nil {
   867  		return types.InternalMaskableErrorf("%s", err)
   868  	}
   869  
   870  	// Ensure that the endpoint exists
   871  	endpoint, err := network.getEndpoint(eid)
   872  	if err != nil {
   873  		return err
   874  	}
   875  
   876  	err = hcsshim.HotDetachEndpoint(endpoint.sandboxID, endpoint.profileID)
   877  	if err != nil {
   878  		// If container doesn't exists in hcs, do not throw error for hot add/remove
   879  		if err != hcsshim.ErrComputeSystemDoesNotExist {
   880  			return err
   881  		}
   882  	}
   883  	return nil
   884  }
   885  
   886  func (d *driver) ProgramExternalConnectivity(nid, eid string, options map[string]interface{}) error {
   887  	return nil
   888  }
   889  
   890  func (d *driver) RevokeExternalConnectivity(nid, eid string) error {
   891  	return nil
   892  }
   893  
   894  func (d *driver) NetworkAllocate(id string, option map[string]string, ipV4Data, ipV6Data []driverapi.IPAMData) (map[string]string, error) {
   895  	return nil, types.NotImplementedErrorf("not implemented")
   896  }
   897  
   898  func (d *driver) NetworkFree(id string) error {
   899  	return types.NotImplementedErrorf("not implemented")
   900  }
   901  
   902  func (d *driver) Type() string {
   903  	return d.name
   904  }
   905  
   906  func (d *driver) IsBuiltIn() bool {
   907  	return true
   908  }
   909  
   910  // DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
   911  func (d *driver) DiscoverNew(dType discoverapi.DiscoveryType, data interface{}) error {
   912  	return nil
   913  }
   914  
   915  // DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
   916  func (d *driver) DiscoverDelete(dType discoverapi.DiscoveryType, data interface{}) error {
   917  	return nil
   918  }