github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/libnetwork/service_common.go (about)

     1  //go:build linux || windows
     2  // +build linux windows
     3  
     4  package libnetwork
     5  
     6  import (
     7  	"net"
     8  
     9  	"github.com/docker/libnetwork/internal/setmatrix"
    10  	"github.com/sirupsen/logrus"
    11  )
    12  
    13  const maxSetStringLen = 350
    14  
    15  func (c *controller) addEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, addService bool, method string) error {
    16  	n, err := c.NetworkByID(nID)
    17  	if err != nil {
    18  		return err
    19  	}
    20  
    21  	logrus.Debugf("addEndpointNameResolution %s %s add_service:%t sAliases:%v tAliases:%v", eID, svcName, addService, serviceAliases, taskAliases)
    22  
    23  	// Add container resolution mappings
    24  	c.addContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)
    25  
    26  	serviceID := svcID
    27  	if serviceID == "" {
    28  		// This is the case of a normal container not part of a service
    29  		serviceID = eID
    30  	}
    31  
    32  	// Add endpoint IP to special "tasks.svc_name" so that the applications have access to DNS RR.
    33  	n.(*network).addSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
    34  	for _, alias := range serviceAliases {
    35  		n.(*network).addSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
    36  	}
    37  
    38  	// Add service name to vip in DNS, if vip is valid. Otherwise resort to DNS RR
    39  	if len(vip) == 0 {
    40  		n.(*network).addSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
    41  		for _, alias := range serviceAliases {
    42  			n.(*network).addSvcRecords(eID, alias, serviceID, ip, nil, false, method)
    43  		}
    44  	}
    45  
    46  	if addService && len(vip) != 0 {
    47  		n.(*network).addSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
    48  		for _, alias := range serviceAliases {
    49  			n.(*network).addSvcRecords(eID, alias, serviceID, vip, nil, false, method)
    50  		}
    51  	}
    52  
    53  	return nil
    54  }
    55  
    56  func (c *controller) addContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
    57  	n, err := c.NetworkByID(nID)
    58  	if err != nil {
    59  		return err
    60  	}
    61  	logrus.Debugf("addContainerNameResolution %s %s", eID, containerName)
    62  
    63  	// Add resolution for container name
    64  	n.(*network).addSvcRecords(eID, containerName, eID, ip, nil, true, method)
    65  
    66  	// Add resolution for taskaliases
    67  	for _, alias := range taskAliases {
    68  		n.(*network).addSvcRecords(eID, alias, eID, ip, nil, false, method)
    69  	}
    70  
    71  	return nil
    72  }
    73  
    74  func (c *controller) deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName string, vip net.IP, serviceAliases, taskAliases []string, ip net.IP, rmService, multipleEntries bool, method string) error {
    75  	n, err := c.NetworkByID(nID)
    76  	if err != nil {
    77  		return err
    78  	}
    79  
    80  	logrus.Debugf("deleteEndpointNameResolution %s %s rm_service:%t suppress:%t sAliases:%v tAliases:%v", eID, svcName, rmService, multipleEntries, serviceAliases, taskAliases)
    81  
    82  	// Delete container resolution mappings
    83  	c.delContainerNameResolution(nID, eID, containerName, taskAliases, ip, method)
    84  
    85  	serviceID := svcID
    86  	if serviceID == "" {
    87  		// This is the case of a normal container not part of a service
    88  		serviceID = eID
    89  	}
    90  
    91  	// Delete the special "tasks.svc_name" backend record.
    92  	if !multipleEntries {
    93  		n.(*network).deleteSvcRecords(eID, "tasks."+svcName, serviceID, ip, nil, false, method)
    94  		for _, alias := range serviceAliases {
    95  			n.(*network).deleteSvcRecords(eID, "tasks."+alias, serviceID, ip, nil, false, method)
    96  		}
    97  	}
    98  
    99  	// If we are doing DNS RR delete the endpoint IP from DNS record right away.
   100  	if !multipleEntries && len(vip) == 0 {
   101  		n.(*network).deleteSvcRecords(eID, svcName, serviceID, ip, nil, false, method)
   102  		for _, alias := range serviceAliases {
   103  			n.(*network).deleteSvcRecords(eID, alias, serviceID, ip, nil, false, method)
   104  		}
   105  	}
   106  
   107  	// Remove the DNS record for VIP only if we are removing the service
   108  	if rmService && len(vip) != 0 && !multipleEntries {
   109  		n.(*network).deleteSvcRecords(eID, svcName, serviceID, vip, nil, false, method)
   110  		for _, alias := range serviceAliases {
   111  			n.(*network).deleteSvcRecords(eID, alias, serviceID, vip, nil, false, method)
   112  		}
   113  	}
   114  
   115  	return nil
   116  }
   117  
   118  func (c *controller) delContainerNameResolution(nID, eID, containerName string, taskAliases []string, ip net.IP, method string) error {
   119  	n, err := c.NetworkByID(nID)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	logrus.Debugf("delContainerNameResolution %s %s", eID, containerName)
   124  
   125  	// Delete resolution for container name
   126  	n.(*network).deleteSvcRecords(eID, containerName, eID, ip, nil, true, method)
   127  
   128  	// Delete resolution for taskaliases
   129  	for _, alias := range taskAliases {
   130  		n.(*network).deleteSvcRecords(eID, alias, eID, ip, nil, true, method)
   131  	}
   132  
   133  	return nil
   134  }
   135  
   136  func newService(name string, id string, ingressPorts []*PortConfig, serviceAliases []string) *service {
   137  	return &service{
   138  		name:          name,
   139  		id:            id,
   140  		ingressPorts:  ingressPorts,
   141  		loadBalancers: make(map[string]*loadBalancer),
   142  		aliases:       serviceAliases,
   143  		ipToEndpoint:  setmatrix.NewSetMatrix(),
   144  	}
   145  }
   146  
   147  func (c *controller) getLBIndex(sid, nid string, ingressPorts []*PortConfig) int {
   148  	skey := serviceKey{
   149  		id:    sid,
   150  		ports: portConfigs(ingressPorts).String(),
   151  	}
   152  	c.Lock()
   153  	s, ok := c.serviceBindings[skey]
   154  	c.Unlock()
   155  
   156  	if !ok {
   157  		return 0
   158  	}
   159  
   160  	s.Lock()
   161  	lb := s.loadBalancers[nid]
   162  	s.Unlock()
   163  
   164  	return int(lb.fwMark)
   165  }
   166  
   167  // cleanupServiceDiscovery when the network is being deleted, erase all the associated service discovery records
   168  func (c *controller) cleanupServiceDiscovery(cleanupNID string) {
   169  	c.Lock()
   170  	defer c.Unlock()
   171  	if cleanupNID == "" {
   172  		logrus.Debugf("cleanupServiceDiscovery for all networks")
   173  		c.svcRecords = make(map[string]svcInfo)
   174  		return
   175  	}
   176  	logrus.Debugf("cleanupServiceDiscovery for network:%s", cleanupNID)
   177  	delete(c.svcRecords, cleanupNID)
   178  }
   179  
   180  func (c *controller) cleanupServiceBindings(cleanupNID string) {
   181  	var cleanupFuncs []func()
   182  
   183  	logrus.Debugf("cleanupServiceBindings for %s", cleanupNID)
   184  	c.Lock()
   185  	services := make([]*service, 0, len(c.serviceBindings))
   186  	for _, s := range c.serviceBindings {
   187  		services = append(services, s)
   188  	}
   189  	c.Unlock()
   190  
   191  	for _, s := range services {
   192  		s.Lock()
   193  		// Skip the serviceBindings that got deleted
   194  		if s.deleted {
   195  			s.Unlock()
   196  			continue
   197  		}
   198  		for nid, lb := range s.loadBalancers {
   199  			if cleanupNID != "" && nid != cleanupNID {
   200  				continue
   201  			}
   202  			for eid, be := range lb.backEnds {
   203  				cleanupFuncs = append(cleanupFuncs, makeServiceCleanupFunc(c, s, nid, eid, lb.vip, be.ip))
   204  			}
   205  		}
   206  		s.Unlock()
   207  	}
   208  
   209  	for _, f := range cleanupFuncs {
   210  		f()
   211  	}
   212  
   213  }
   214  
   215  func makeServiceCleanupFunc(c *controller, s *service, nID, eID string, vip net.IP, ip net.IP) func() {
   216  	// ContainerName and taskAliases are not available here, this is still fine because the Service discovery
   217  	// cleanup already happened before. The only thing that rmServiceBinding is still doing here a part from the Load
   218  	// Balancer bookeeping, is to keep consistent the mapping of endpoint to IP.
   219  	return func() {
   220  		if err := c.rmServiceBinding(s.name, s.id, nID, eID, "", vip, s.ingressPorts, s.aliases, []string{}, ip, "cleanupServiceBindings", false, true); err != nil {
   221  			logrus.Errorf("Failed to remove service bindings for service %s network %s endpoint %s while cleanup: %v", s.id, nID, eID, err)
   222  		}
   223  	}
   224  }
   225  
   226  func (c *controller) addServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases, taskAliases []string, ip net.IP, method string) error {
   227  	var addService bool
   228  
   229  	// Failure to lock the network ID on add can result in racing
   230  	// racing against network deletion resulting in inconsistent
   231  	// state in the c.serviceBindings map and it's sub-maps. Also,
   232  	// always lock network ID before services to avoid deadlock.
   233  	c.networkLocker.Lock(nID)
   234  	defer c.networkLocker.Unlock(nID)
   235  
   236  	n, err := c.NetworkByID(nID)
   237  	if err != nil {
   238  		return err
   239  	}
   240  
   241  	skey := serviceKey{
   242  		id:    svcID,
   243  		ports: portConfigs(ingressPorts).String(),
   244  	}
   245  
   246  	var s *service
   247  	for {
   248  		c.Lock()
   249  		var ok bool
   250  		s, ok = c.serviceBindings[skey]
   251  		if !ok {
   252  			// Create a new service if we are seeing this service
   253  			// for the first time.
   254  			s = newService(svcName, svcID, ingressPorts, serviceAliases)
   255  			c.serviceBindings[skey] = s
   256  		}
   257  		c.Unlock()
   258  		s.Lock()
   259  		if !s.deleted {
   260  			// ok the object is good to be used
   261  			break
   262  		}
   263  		s.Unlock()
   264  	}
   265  	logrus.Debugf("addServiceBinding from %s START for %s %s p:%p nid:%s skey:%v", method, svcName, eID, s, nID, skey)
   266  	defer s.Unlock()
   267  
   268  	lb, ok := s.loadBalancers[nID]
   269  	if !ok {
   270  		// Create a new load balancer if we are seeing this
   271  		// network attachment on the service for the first
   272  		// time.
   273  		fwMarkCtrMu.Lock()
   274  
   275  		lb = &loadBalancer{
   276  			vip:      vip,
   277  			fwMark:   fwMarkCtr,
   278  			backEnds: make(map[string]*lbBackend),
   279  			service:  s,
   280  		}
   281  
   282  		fwMarkCtr++
   283  		fwMarkCtrMu.Unlock()
   284  
   285  		s.loadBalancers[nID] = lb
   286  		addService = true
   287  	}
   288  
   289  	lb.backEnds[eID] = &lbBackend{ip, false}
   290  
   291  	ok, entries := s.assignIPToEndpoint(ip.String(), eID)
   292  	if !ok || entries > 1 {
   293  		setStr, b := s.printIPToEndpoint(ip.String())
   294  		if len(setStr) > maxSetStringLen {
   295  			setStr = setStr[:maxSetStringLen]
   296  		}
   297  		logrus.Warnf("addServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
   298  	}
   299  
   300  	// Add loadbalancer service and backend to the network
   301  	n.(*network).addLBBackend(ip, lb)
   302  
   303  	// Add the appropriate name resolutions
   304  	c.addEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, addService, "addServiceBinding")
   305  
   306  	logrus.Debugf("addServiceBinding from %s END for %s %s", method, svcName, eID)
   307  
   308  	return nil
   309  }
   310  
   311  func (c *controller) rmServiceBinding(svcName, svcID, nID, eID, containerName string, vip net.IP, ingressPorts []*PortConfig, serviceAliases []string, taskAliases []string, ip net.IP, method string, deleteSvcRecords bool, fullRemove bool) error {
   312  
   313  	var rmService bool
   314  
   315  	skey := serviceKey{
   316  		id:    svcID,
   317  		ports: portConfigs(ingressPorts).String(),
   318  	}
   319  
   320  	c.Lock()
   321  	s, ok := c.serviceBindings[skey]
   322  	c.Unlock()
   323  	if !ok {
   324  		logrus.Warnf("rmServiceBinding %s %s %s aborted c.serviceBindings[skey] !ok", method, svcName, eID)
   325  		return nil
   326  	}
   327  
   328  	s.Lock()
   329  	defer s.Unlock()
   330  	logrus.Debugf("rmServiceBinding from %s START for %s %s p:%p nid:%s sKey:%v deleteSvc:%t", method, svcName, eID, s, nID, skey, deleteSvcRecords)
   331  	lb, ok := s.loadBalancers[nID]
   332  	if !ok {
   333  		logrus.Warnf("rmServiceBinding %s %s %s aborted s.loadBalancers[nid] !ok", method, svcName, eID)
   334  		return nil
   335  	}
   336  
   337  	be, ok := lb.backEnds[eID]
   338  	if !ok {
   339  		logrus.Warnf("rmServiceBinding %s %s %s aborted lb.backEnds[eid] && lb.disabled[eid] !ok", method, svcName, eID)
   340  		return nil
   341  	}
   342  
   343  	if fullRemove {
   344  		// delete regardless
   345  		delete(lb.backEnds, eID)
   346  	} else {
   347  		be.disabled = true
   348  	}
   349  
   350  	if len(lb.backEnds) == 0 {
   351  		// All the backends for this service have been
   352  		// removed. Time to remove the load balancer and also
   353  		// remove the service entry in IPVS.
   354  		rmService = true
   355  
   356  		delete(s.loadBalancers, nID)
   357  		logrus.Debugf("rmServiceBinding %s delete %s, p:%p in loadbalancers len:%d", eID, nID, lb, len(s.loadBalancers))
   358  	}
   359  
   360  	ok, entries := s.removeIPToEndpoint(ip.String(), eID)
   361  	if !ok || entries > 0 {
   362  		setStr, b := s.printIPToEndpoint(ip.String())
   363  		if len(setStr) > maxSetStringLen {
   364  			setStr = setStr[:maxSetStringLen]
   365  		}
   366  		logrus.Warnf("rmServiceBinding %s possible transient state ok:%t entries:%d set:%t %s", eID, ok, entries, b, setStr)
   367  	}
   368  
   369  	// Remove loadbalancer service(if needed) and backend in all
   370  	// sandboxes in the network only if the vip is valid.
   371  	if entries == 0 {
   372  		// The network may well have been deleted from the store (and
   373  		// dataplane) before the last of the service bindings.  On Linux that's
   374  		// ok because removing the network sandbox from the dataplane
   375  		// implicitly cleans up all related dataplane state.
   376  		// On the Windows dataplane, VFP policylists must be removed
   377  		// independently of the network, and they must be removed before the HNS
   378  		// network. Otherwise, policylist removal fails with "network not
   379  		// found." On Windows cleanupServiceBindings must be called prior to
   380  		// removing the network from the store or dataplane.
   381  		n, err := c.NetworkByID(nID)
   382  		if err == nil {
   383  			n.(*network).rmLBBackend(ip, lb, rmService, fullRemove)
   384  		}
   385  	}
   386  
   387  	// Delete the name resolutions
   388  	if deleteSvcRecords {
   389  		c.deleteEndpointNameResolution(svcName, svcID, nID, eID, containerName, vip, serviceAliases, taskAliases, ip, rmService, entries > 0, "rmServiceBinding")
   390  	}
   391  
   392  	if len(s.loadBalancers) == 0 {
   393  		// All loadbalancers for the service removed. Time to
   394  		// remove the service itself.
   395  		c.Lock()
   396  
   397  		// Mark the object as deleted so that the add won't use it wrongly
   398  		s.deleted = true
   399  		// NOTE The delete from the serviceBindings map has to be the last operation else we are allowing a race between this service
   400  		// that is getting deleted and a new service that will be created if the entry is not anymore there
   401  		delete(c.serviceBindings, skey)
   402  		c.Unlock()
   403  	}
   404  
   405  	logrus.Debugf("rmServiceBinding from %s END for %s %s", method, svcName, eID)
   406  	return nil
   407  }