github.com/tonistiigi/docker@v0.10.1-0.20240229224939-974013b0dc6a/libnetwork/sandbox_linux.go (about)

     1  package libnetwork
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"time"
     8  
     9  	"github.com/containerd/log"
    10  	"github.com/docker/docker/libnetwork/netutils"
    11  	"github.com/docker/docker/libnetwork/osl"
    12  	"github.com/docker/docker/libnetwork/types"
    13  )
    14  
    15  func releaseOSSboxResources(ns *osl.Namespace, ep *Endpoint) {
    16  	for _, i := range ns.Interfaces() {
    17  		// Only remove the interfaces owned by this endpoint from the sandbox.
    18  		if ep.hasInterface(i.SrcName()) {
    19  			if err := i.Remove(); err != nil {
    20  				log.G(context.TODO()).Debugf("Remove interface %s failed: %v", i.SrcName(), err)
    21  			}
    22  		}
    23  	}
    24  
    25  	ep.mu.Lock()
    26  	joinInfo := ep.joinInfo
    27  	vip := ep.virtualIP
    28  	lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR
    29  	ep.mu.Unlock()
    30  
    31  	if len(vip) > 0 && lbModeIsDSR {
    32  		ipNet := &net.IPNet{IP: vip, Mask: net.CIDRMask(32, 32)}
    33  		if err := ns.RemoveAliasIP(ns.GetLoopbackIfaceName(), ipNet); err != nil {
    34  			log.G(context.TODO()).WithError(err).Debugf("failed to remove virtual ip %v to loopback", ipNet)
    35  		}
    36  	}
    37  
    38  	if joinInfo == nil {
    39  		return
    40  	}
    41  
    42  	// Remove non-interface routes.
    43  	for _, r := range joinInfo.StaticRoutes {
    44  		if err := ns.RemoveStaticRoute(r); err != nil {
    45  			log.G(context.TODO()).Debugf("Remove route failed: %v", err)
    46  		}
    47  	}
    48  }
    49  
    50  // Statistics retrieves the interfaces' statistics for the sandbox.
    51  func (sb *Sandbox) Statistics() (map[string]*types.InterfaceStatistics, error) {
    52  	m := make(map[string]*types.InterfaceStatistics)
    53  
    54  	sb.mu.Lock()
    55  	osb := sb.osSbox
    56  	sb.mu.Unlock()
    57  	if osb == nil {
    58  		return m, nil
    59  	}
    60  
    61  	var err error
    62  	for _, i := range osb.Interfaces() {
    63  		if m[i.DstName()], err = i.Statistics(); err != nil {
    64  			return m, err
    65  		}
    66  	}
    67  
    68  	return m, nil
    69  }
    70  
    71  func (sb *Sandbox) updateGateway(ep *Endpoint) error {
    72  	sb.mu.Lock()
    73  	osSbox := sb.osSbox
    74  	sb.mu.Unlock()
    75  	if osSbox == nil {
    76  		return nil
    77  	}
    78  	osSbox.UnsetGateway()     //nolint:errcheck
    79  	osSbox.UnsetGatewayIPv6() //nolint:errcheck
    80  
    81  	if ep == nil {
    82  		return nil
    83  	}
    84  
    85  	ep.mu.Lock()
    86  	joinInfo := ep.joinInfo
    87  	ep.mu.Unlock()
    88  
    89  	if err := osSbox.SetGateway(joinInfo.gw); err != nil {
    90  		return fmt.Errorf("failed to set gateway while updating gateway: %v", err)
    91  	}
    92  
    93  	if err := osSbox.SetGatewayIPv6(joinInfo.gw6); err != nil {
    94  		return fmt.Errorf("failed to set IPv6 gateway while updating gateway: %v", err)
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func (sb *Sandbox) ExecFunc(f func()) error {
   101  	sb.mu.Lock()
   102  	osSbox := sb.osSbox
   103  	sb.mu.Unlock()
   104  	if osSbox != nil {
   105  		return osSbox.InvokeFunc(f)
   106  	}
   107  	return fmt.Errorf("osl sandbox unavailable in ExecFunc for %v", sb.ContainerID())
   108  }
   109  
   110  // SetKey updates the Sandbox Key.
   111  func (sb *Sandbox) SetKey(basePath string) error {
   112  	start := time.Now()
   113  	defer func() {
   114  		log.G(context.TODO()).Debugf("sandbox set key processing took %s for container %s", time.Since(start), sb.ContainerID())
   115  	}()
   116  
   117  	if basePath == "" {
   118  		return types.InvalidParameterErrorf("invalid sandbox key")
   119  	}
   120  
   121  	sb.mu.Lock()
   122  	if sb.inDelete {
   123  		sb.mu.Unlock()
   124  		return types.ForbiddenErrorf("failed to SetKey: sandbox %q delete in progress", sb.id)
   125  	}
   126  	oldosSbox := sb.osSbox
   127  	sb.mu.Unlock()
   128  
   129  	if oldosSbox != nil {
   130  		// If we already have an OS sandbox, release the network resources from that
   131  		// and destroy the OS snab. We are moving into a new home further down. Note that none
   132  		// of the network resources gets destroyed during the move.
   133  		if err := sb.releaseOSSbox(); err != nil {
   134  			log.G(context.TODO()).WithError(err).Error("Error destroying os sandbox")
   135  		}
   136  	}
   137  
   138  	osSbox, err := osl.GetSandboxForExternalKey(basePath, sb.Key())
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	sb.mu.Lock()
   144  	sb.osSbox = osSbox
   145  	sb.mu.Unlock()
   146  
   147  	// If the resolver was setup before stop it and set it up in the
   148  	// new osl sandbox.
   149  	if oldosSbox != nil && sb.resolver != nil {
   150  		sb.resolver.Stop()
   151  
   152  		if err := sb.osSbox.InvokeFunc(sb.resolver.SetupFunc(0)); err == nil {
   153  			if err := sb.resolver.Start(); err != nil {
   154  				log.G(context.TODO()).Errorf("Resolver Start failed for container %s, %q", sb.ContainerID(), err)
   155  			}
   156  		} else {
   157  			log.G(context.TODO()).Errorf("Resolver Setup Function failed for container %s, %q", sb.ContainerID(), err)
   158  		}
   159  	}
   160  
   161  	if err := sb.finishInitDNS(); err != nil {
   162  		return err
   163  	}
   164  
   165  	for _, ep := range sb.Endpoints() {
   166  		if err = sb.populateNetworkResources(ep); err != nil {
   167  			return err
   168  		}
   169  	}
   170  
   171  	return nil
   172  }
   173  
   174  // IPv6 support can always be determined for host networking. For other network
   175  // types it can only be determined once there's a container namespace to probe,
   176  // return ok=false in that case.
   177  func (sb *Sandbox) ipv6Enabled() (enabled, ok bool) {
   178  	// For host networking, IPv6 support depends on the host.
   179  	if sb.config.useDefaultSandBox {
   180  		return netutils.IsV6Listenable(), true
   181  	}
   182  
   183  	// For other network types, look at whether the container's loopback interface has an IPv6 address.
   184  	sb.mu.Lock()
   185  	osSbox := sb.osSbox
   186  	sb.mu.Unlock()
   187  
   188  	if osSbox == nil {
   189  		return false, false
   190  	}
   191  	return osSbox.IPv6LoEnabled(), true
   192  }
   193  
   194  func (sb *Sandbox) releaseOSSbox() error {
   195  	sb.mu.Lock()
   196  	osSbox := sb.osSbox
   197  	sb.osSbox = nil
   198  	sb.mu.Unlock()
   199  
   200  	if osSbox == nil {
   201  		return nil
   202  	}
   203  
   204  	for _, ep := range sb.Endpoints() {
   205  		releaseOSSboxResources(osSbox, ep)
   206  	}
   207  
   208  	return osSbox.Destroy()
   209  }
   210  
   211  func (sb *Sandbox) restoreOslSandbox() error {
   212  	var routes []*types.StaticRoute
   213  
   214  	// restore osl sandbox
   215  	interfaces := make(map[osl.Iface][]osl.IfaceOption)
   216  	for _, ep := range sb.endpoints {
   217  		ep.mu.Lock()
   218  		joinInfo := ep.joinInfo
   219  		i := ep.iface
   220  		ep.mu.Unlock()
   221  
   222  		if i == nil {
   223  			log.G(context.TODO()).Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID())
   224  			continue
   225  		}
   226  
   227  		ifaceOptions := []osl.IfaceOption{
   228  			osl.WithIPv4Address(i.addr),
   229  			osl.WithRoutes(i.routes),
   230  		}
   231  		if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
   232  			ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6))
   233  		}
   234  		if i.mac != nil {
   235  			ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac))
   236  		}
   237  		if len(i.llAddrs) != 0 {
   238  			ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs))
   239  		}
   240  		interfaces[osl.Iface{SrcName: i.srcName, DstPrefix: i.dstPrefix}] = ifaceOptions
   241  		if joinInfo != nil {
   242  			routes = append(routes, joinInfo.StaticRoutes...)
   243  		}
   244  		if ep.needResolver() {
   245  			sb.startResolver(true)
   246  		}
   247  	}
   248  
   249  	gwep := sb.getGatewayEndpoint()
   250  	if gwep == nil {
   251  		return nil
   252  	}
   253  
   254  	// restore osl sandbox
   255  	return sb.osSbox.Restore(interfaces, routes, gwep.joinInfo.gw, gwep.joinInfo.gw6)
   256  }
   257  
   258  func (sb *Sandbox) populateNetworkResources(ep *Endpoint) error {
   259  	sb.mu.Lock()
   260  	if sb.osSbox == nil {
   261  		sb.mu.Unlock()
   262  		return nil
   263  	}
   264  	inDelete := sb.inDelete
   265  	sb.mu.Unlock()
   266  
   267  	ep.mu.Lock()
   268  	joinInfo := ep.joinInfo
   269  	i := ep.iface
   270  	lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR
   271  	ep.mu.Unlock()
   272  
   273  	if ep.needResolver() {
   274  		sb.startResolver(false)
   275  	}
   276  
   277  	if i != nil && i.srcName != "" {
   278  		var ifaceOptions []osl.IfaceOption
   279  
   280  		ifaceOptions = append(ifaceOptions, osl.WithIPv4Address(i.addr), osl.WithRoutes(i.routes))
   281  		if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
   282  			ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6))
   283  		}
   284  		if len(i.llAddrs) != 0 {
   285  			ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs))
   286  		}
   287  		if i.mac != nil {
   288  			ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac))
   289  		}
   290  
   291  		if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
   292  			return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
   293  		}
   294  
   295  		if len(ep.virtualIP) > 0 && lbModeIsDSR {
   296  			if sb.loadBalancerNID == "" {
   297  				if err := sb.osSbox.DisableARPForVIP(i.srcName); err != nil {
   298  					return fmt.Errorf("failed disable ARP for VIP: %v", err)
   299  				}
   300  			}
   301  			ipNet := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)}
   302  			if err := sb.osSbox.AddAliasIP(sb.osSbox.GetLoopbackIfaceName(), ipNet); err != nil {
   303  				return fmt.Errorf("failed to add virtual ip %v to loopback: %v", ipNet, err)
   304  			}
   305  		}
   306  	}
   307  
   308  	if joinInfo != nil {
   309  		// Set up non-interface routes.
   310  		for _, r := range joinInfo.StaticRoutes {
   311  			if err := sb.osSbox.AddStaticRoute(r); err != nil {
   312  				return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err)
   313  			}
   314  		}
   315  	}
   316  
   317  	if ep == sb.getGatewayEndpoint() {
   318  		if err := sb.updateGateway(ep); err != nil {
   319  			return err
   320  		}
   321  	}
   322  
   323  	// Make sure to add the endpoint to the populated endpoint set
   324  	// before populating loadbalancers.
   325  	sb.mu.Lock()
   326  	sb.populatedEndpoints[ep.ID()] = struct{}{}
   327  	sb.mu.Unlock()
   328  
   329  	// Populate load balancer only after updating all the other
   330  	// information including gateway and other routes so that
   331  	// loadbalancers are populated all the network state is in
   332  	// place in the sandbox.
   333  	sb.populateLoadBalancers(ep)
   334  
   335  	// Only update the store if we did not come here as part of
   336  	// sandbox delete. If we came here as part of delete then do
   337  	// not bother updating the store. The sandbox object will be
   338  	// deleted anyway
   339  	if !inDelete {
   340  		return sb.storeUpdate()
   341  	}
   342  
   343  	return nil
   344  }