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

     1  package overlay
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net"
     8  	"sync"
     9  
    10  	"github.com/Microsoft/hcsshim"
    11  	"github.com/Microsoft/hcsshim/osversion"
    12  	"github.com/containerd/log"
    13  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/driverapi"
    14  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/drivers/windows"
    15  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/netlabel"
    16  	"github.com/Prakhar-Agarwal-byte/moby/libnetwork/types"
    17  )
    18  
    19  type endpointTable map[string]*endpoint
    20  
    21  const overlayEndpointPrefix = "overlay/endpoint"
    22  
    23  type endpoint struct {
    24  	id             string
    25  	nid            string
    26  	profileID      string
    27  	remote         bool
    28  	mac            net.HardwareAddr
    29  	addr           *net.IPNet
    30  	disablegateway bool
    31  	portMapping    []types.PortBinding // Operation port bindings
    32  }
    33  
    34  var (
    35  	// Server 2016 (RS1) does not support concurrent add/delete of endpoints.  Therefore, we need
    36  	// to use this mutex and serialize the add/delete of endpoints on RS1.
    37  	endpointMu   sync.Mutex
    38  	windowsBuild = osversion.Build()
    39  )
    40  
    41  func validateID(nid, eid string) error {
    42  	if nid == "" {
    43  		return fmt.Errorf("invalid network id")
    44  	}
    45  
    46  	if eid == "" {
    47  		return fmt.Errorf("invalid endpoint id")
    48  	}
    49  
    50  	return nil
    51  }
    52  
    53  func (n *network) endpoint(eid string) *endpoint {
    54  	n.Lock()
    55  	defer n.Unlock()
    56  
    57  	return n.endpoints[eid]
    58  }
    59  
    60  func (n *network) addEndpoint(ep *endpoint) {
    61  	n.Lock()
    62  	n.endpoints[ep.id] = ep
    63  	n.Unlock()
    64  }
    65  
    66  func (n *network) deleteEndpoint(eid string) {
    67  	n.Lock()
    68  	delete(n.endpoints, eid)
    69  	n.Unlock()
    70  }
    71  
    72  func (n *network) removeEndpointWithAddress(addr *net.IPNet) {
    73  	var networkEndpoint *endpoint
    74  	n.Lock()
    75  	for _, ep := range n.endpoints {
    76  		if ep.addr.IP.Equal(addr.IP) {
    77  			networkEndpoint = ep
    78  			break
    79  		}
    80  	}
    81  
    82  	if networkEndpoint != nil {
    83  		delete(n.endpoints, networkEndpoint.id)
    84  	}
    85  	n.Unlock()
    86  
    87  	if networkEndpoint != nil {
    88  		log.G(context.TODO()).Debugf("Removing stale endpoint from HNS")
    89  		_, err := endpointRequest("DELETE", networkEndpoint.profileID, "")
    90  		if err != nil {
    91  			log.G(context.TODO()).Debugf("Failed to delete stale overlay endpoint (%.7s) from hns", networkEndpoint.id)
    92  		}
    93  	}
    94  }
    95  
    96  func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error {
    97  	var err error
    98  	if err = validateID(nid, eid); err != nil {
    99  		return err
   100  	}
   101  
   102  	n := d.network(nid)
   103  	if n == nil {
   104  		return fmt.Errorf("network id %q not found", nid)
   105  	}
   106  
   107  	ep := n.endpoint(eid)
   108  	if ep != nil {
   109  		log.G(context.TODO()).Debugf("Deleting stale endpoint %s", eid)
   110  		n.deleteEndpoint(eid)
   111  		_, err := endpointRequest("DELETE", ep.profileID, "")
   112  		if err != nil {
   113  			return err
   114  		}
   115  	}
   116  
   117  	ep = &endpoint{
   118  		id:   eid,
   119  		nid:  n.id,
   120  		addr: ifInfo.Address(),
   121  		mac:  ifInfo.MacAddress(),
   122  	}
   123  
   124  	if ep.addr == nil {
   125  		return fmt.Errorf("create endpoint was not passed interface IP address")
   126  	}
   127  
   128  	s := n.getSubnetforIP(ep.addr)
   129  	if s == nil {
   130  		return fmt.Errorf("no matching subnet for IP %q in network %q", ep.addr, nid)
   131  	}
   132  
   133  	// Todo: Add port bindings and qos policies here
   134  
   135  	hnsEndpoint := &hcsshim.HNSEndpoint{
   136  		Name:              eid,
   137  		VirtualNetwork:    n.hnsID,
   138  		IPAddress:         ep.addr.IP,
   139  		EnableInternalDNS: true,
   140  		GatewayAddress:    s.gwIP.String(),
   141  	}
   142  
   143  	if ep.mac != nil {
   144  		hnsEndpoint.MacAddress = ep.mac.String()
   145  	}
   146  
   147  	paPolicy, err := json.Marshal(hcsshim.PaPolicy{
   148  		Type: "PA",
   149  		PA:   n.providerAddress,
   150  	})
   151  	if err != nil {
   152  		return err
   153  	}
   154  
   155  	hnsEndpoint.Policies = append(hnsEndpoint.Policies, paPolicy)
   156  
   157  	natPolicy, err := json.Marshal(hcsshim.PaPolicy{Type: "OutBoundNAT"})
   158  	if err != nil {
   159  		return err
   160  	}
   161  
   162  	hnsEndpoint.Policies = append(hnsEndpoint.Policies, natPolicy)
   163  
   164  	epConnectivity, err := windows.ParseEndpointConnectivity(epOptions)
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	ep.portMapping = epConnectivity.PortBindings
   170  	ep.portMapping, err = windows.AllocatePorts(n.portMapper, ep.portMapping, ep.addr.IP)
   171  	if err != nil {
   172  		return err
   173  	}
   174  
   175  	defer func() {
   176  		if err != nil {
   177  			windows.ReleasePorts(n.portMapper, ep.portMapping)
   178  		}
   179  	}()
   180  
   181  	pbPolicy, err := windows.ConvertPortBindings(ep.portMapping)
   182  	if err != nil {
   183  		return err
   184  	}
   185  	hnsEndpoint.Policies = append(hnsEndpoint.Policies, pbPolicy...)
   186  
   187  	ep.disablegateway = true
   188  
   189  	configurationb, err := json.Marshal(hnsEndpoint)
   190  	if err != nil {
   191  		return err
   192  	}
   193  
   194  	hnsresponse, err := endpointRequest("POST", "", string(configurationb))
   195  	if err != nil {
   196  		return err
   197  	}
   198  
   199  	ep.profileID = hnsresponse.Id
   200  
   201  	if ep.mac == nil {
   202  		ep.mac, err = net.ParseMAC(hnsresponse.MacAddress)
   203  		if err != nil {
   204  			return err
   205  		}
   206  
   207  		if err := ifInfo.SetMacAddress(ep.mac); err != nil {
   208  			return err
   209  		}
   210  	}
   211  
   212  	ep.portMapping, err = windows.ParsePortBindingPolicies(hnsresponse.Policies)
   213  	if err != nil {
   214  		endpointRequest("DELETE", hnsresponse.Id, "")
   215  		return err
   216  	}
   217  
   218  	n.addEndpoint(ep)
   219  
   220  	return nil
   221  }
   222  
   223  func (d *driver) DeleteEndpoint(nid, eid string) error {
   224  	if err := validateID(nid, eid); err != nil {
   225  		return err
   226  	}
   227  
   228  	n := d.network(nid)
   229  	if n == nil {
   230  		return fmt.Errorf("network id %q not found", nid)
   231  	}
   232  
   233  	ep := n.endpoint(eid)
   234  	if ep == nil {
   235  		return fmt.Errorf("endpoint id %q not found", eid)
   236  	}
   237  
   238  	windows.ReleasePorts(n.portMapper, ep.portMapping)
   239  
   240  	n.deleteEndpoint(eid)
   241  
   242  	_, err := endpointRequest("DELETE", ep.profileID, "")
   243  	if err != nil {
   244  		return err
   245  	}
   246  
   247  	return nil
   248  }
   249  
   250  func (d *driver) EndpointOperInfo(nid, eid string) (map[string]interface{}, error) {
   251  	if err := validateID(nid, eid); err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	n := d.network(nid)
   256  	if n == nil {
   257  		return nil, fmt.Errorf("network id %q not found", nid)
   258  	}
   259  
   260  	ep := n.endpoint(eid)
   261  	if ep == nil {
   262  		return nil, fmt.Errorf("endpoint id %q not found", eid)
   263  	}
   264  
   265  	data := make(map[string]interface{}, 1)
   266  	data["hnsid"] = ep.profileID
   267  	data["AllowUnqualifiedDNSQuery"] = true
   268  
   269  	if ep.portMapping != nil {
   270  		// Return a copy of the operational data
   271  		pmc := make([]types.PortBinding, 0, len(ep.portMapping))
   272  		for _, pm := range ep.portMapping {
   273  			pmc = append(pmc, pm.GetCopy())
   274  		}
   275  		data[netlabel.PortMap] = pmc
   276  	}
   277  
   278  	return data, nil
   279  }
   280  
   281  func endpointRequest(method, path, request string) (*hcsshim.HNSEndpoint, error) {
   282  	if windowsBuild == 14393 {
   283  		endpointMu.Lock()
   284  	}
   285  	hnsresponse, err := hcsshim.HNSEndpointRequest(method, path, request)
   286  	if windowsBuild == 14393 {
   287  		endpointMu.Unlock()
   288  	}
   289  	return hnsresponse, err
   290  }