github.com/khulnasoft-lab/khulnasoft@v26.0.1-0.20240328202558-330a6f959fe0+incompatible/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  	// Set up hosts and resolv.conf files. IPv6 support in the container can't be
   162  	// determined yet, as sysctls haven't been applied by the runtime. Calling
   163  	// FinishInit after the container task has been created, when sysctls have been
   164  	// applied will regenerate these files.
   165  	if err := sb.finishInitDNS(); err != nil {
   166  		return err
   167  	}
   168  
   169  	for _, ep := range sb.Endpoints() {
   170  		if err = sb.populateNetworkResources(ep); err != nil {
   171  			return err
   172  		}
   173  	}
   174  
   175  	return nil
   176  }
   177  
   178  // FinishConfig completes Sandbox configuration. If called after the container task has been
   179  // created, and sysctl settings applied, the configuration will be based on the container's
   180  // IPv6 support.
   181  func (sb *Sandbox) FinishConfig() error {
   182  	if sb.config.useDefaultSandBox {
   183  		return nil
   184  	}
   185  
   186  	sb.mu.Lock()
   187  	osSbox := sb.osSbox
   188  	sb.mu.Unlock()
   189  	if osSbox == nil {
   190  		return nil
   191  	}
   192  
   193  	// If sysctl changes have been made, IPv6 may have been enabled/disabled since last checked.
   194  	osSbox.RefreshIPv6LoEnabled()
   195  
   196  	return sb.finishInitDNS()
   197  }
   198  
   199  // IPv6 support can always be determined for host networking. For other network
   200  // types it can only be determined once there's a container namespace to probe,
   201  // return ok=false in that case.
   202  func (sb *Sandbox) ipv6Enabled() (enabled, ok bool) {
   203  	// For host networking, IPv6 support depends on the host.
   204  	if sb.config.useDefaultSandBox {
   205  		return netutils.IsV6Listenable(), true
   206  	}
   207  
   208  	// For other network types, look at whether the container's loopback interface has an IPv6 address.
   209  	sb.mu.Lock()
   210  	osSbox := sb.osSbox
   211  	sb.mu.Unlock()
   212  
   213  	if osSbox == nil {
   214  		return false, false
   215  	}
   216  	return osSbox.IPv6LoEnabled(), true
   217  }
   218  
   219  func (sb *Sandbox) releaseOSSbox() error {
   220  	sb.mu.Lock()
   221  	osSbox := sb.osSbox
   222  	sb.osSbox = nil
   223  	sb.mu.Unlock()
   224  
   225  	if osSbox == nil {
   226  		return nil
   227  	}
   228  
   229  	for _, ep := range sb.Endpoints() {
   230  		releaseOSSboxResources(osSbox, ep)
   231  	}
   232  
   233  	return osSbox.Destroy()
   234  }
   235  
   236  func (sb *Sandbox) restoreOslSandbox() error {
   237  	var routes []*types.StaticRoute
   238  
   239  	// restore osl sandbox
   240  	interfaces := make(map[osl.Iface][]osl.IfaceOption)
   241  	for _, ep := range sb.endpoints {
   242  		ep.mu.Lock()
   243  		joinInfo := ep.joinInfo
   244  		i := ep.iface
   245  		ep.mu.Unlock()
   246  
   247  		if i == nil {
   248  			log.G(context.TODO()).Errorf("error restoring endpoint %s for container %s", ep.Name(), sb.ContainerID())
   249  			continue
   250  		}
   251  
   252  		ifaceOptions := []osl.IfaceOption{
   253  			osl.WithIPv4Address(i.addr),
   254  			osl.WithRoutes(i.routes),
   255  		}
   256  		if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
   257  			ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6))
   258  		}
   259  		if i.mac != nil {
   260  			ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac))
   261  		}
   262  		if len(i.llAddrs) != 0 {
   263  			ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs))
   264  		}
   265  		interfaces[osl.Iface{SrcName: i.srcName, DstPrefix: i.dstPrefix}] = ifaceOptions
   266  		if joinInfo != nil {
   267  			routes = append(routes, joinInfo.StaticRoutes...)
   268  		}
   269  		if ep.needResolver() {
   270  			sb.startResolver(true)
   271  		}
   272  	}
   273  
   274  	gwep := sb.getGatewayEndpoint()
   275  	if gwep == nil {
   276  		return nil
   277  	}
   278  
   279  	// restore osl sandbox
   280  	return sb.osSbox.Restore(interfaces, routes, gwep.joinInfo.gw, gwep.joinInfo.gw6)
   281  }
   282  
   283  func (sb *Sandbox) populateNetworkResources(ep *Endpoint) error {
   284  	sb.mu.Lock()
   285  	if sb.osSbox == nil {
   286  		sb.mu.Unlock()
   287  		return nil
   288  	}
   289  	inDelete := sb.inDelete
   290  	sb.mu.Unlock()
   291  
   292  	ep.mu.Lock()
   293  	joinInfo := ep.joinInfo
   294  	i := ep.iface
   295  	lbModeIsDSR := ep.network.loadBalancerMode == loadBalancerModeDSR
   296  	ep.mu.Unlock()
   297  
   298  	if ep.needResolver() {
   299  		sb.startResolver(false)
   300  	}
   301  
   302  	if i != nil && i.srcName != "" {
   303  		var ifaceOptions []osl.IfaceOption
   304  
   305  		ifaceOptions = append(ifaceOptions, osl.WithIPv4Address(i.addr), osl.WithRoutes(i.routes))
   306  		if i.addrv6 != nil && i.addrv6.IP.To16() != nil {
   307  			ifaceOptions = append(ifaceOptions, osl.WithIPv6Address(i.addrv6))
   308  		}
   309  		if len(i.llAddrs) != 0 {
   310  			ifaceOptions = append(ifaceOptions, osl.WithLinkLocalAddresses(i.llAddrs))
   311  		}
   312  		if i.mac != nil {
   313  			ifaceOptions = append(ifaceOptions, osl.WithMACAddress(i.mac))
   314  		}
   315  
   316  		if err := sb.osSbox.AddInterface(i.srcName, i.dstPrefix, ifaceOptions...); err != nil {
   317  			return fmt.Errorf("failed to add interface %s to sandbox: %v", i.srcName, err)
   318  		}
   319  
   320  		if len(ep.virtualIP) > 0 && lbModeIsDSR {
   321  			if sb.loadBalancerNID == "" {
   322  				if err := sb.osSbox.DisableARPForVIP(i.srcName); err != nil {
   323  					return fmt.Errorf("failed disable ARP for VIP: %v", err)
   324  				}
   325  			}
   326  			ipNet := &net.IPNet{IP: ep.virtualIP, Mask: net.CIDRMask(32, 32)}
   327  			if err := sb.osSbox.AddAliasIP(sb.osSbox.GetLoopbackIfaceName(), ipNet); err != nil {
   328  				return fmt.Errorf("failed to add virtual ip %v to loopback: %v", ipNet, err)
   329  			}
   330  		}
   331  	}
   332  
   333  	if joinInfo != nil {
   334  		// Set up non-interface routes.
   335  		for _, r := range joinInfo.StaticRoutes {
   336  			if err := sb.osSbox.AddStaticRoute(r); err != nil {
   337  				return fmt.Errorf("failed to add static route %s: %v", r.Destination.String(), err)
   338  			}
   339  		}
   340  	}
   341  
   342  	if ep == sb.getGatewayEndpoint() {
   343  		if err := sb.updateGateway(ep); err != nil {
   344  			return err
   345  		}
   346  	}
   347  
   348  	// Make sure to add the endpoint to the populated endpoint set
   349  	// before populating loadbalancers.
   350  	sb.mu.Lock()
   351  	sb.populatedEndpoints[ep.ID()] = struct{}{}
   352  	sb.mu.Unlock()
   353  
   354  	// Populate load balancer only after updating all the other
   355  	// information including gateway and other routes so that
   356  	// loadbalancers are populated all the network state is in
   357  	// place in the sandbox.
   358  	sb.populateLoadBalancers(ep)
   359  
   360  	// Only update the store if we did not come here as part of
   361  	// sandbox delete. If we came here as part of delete then do
   362  	// not bother updating the store. The sandbox object will be
   363  	// deleted anyway
   364  	if !inDelete {
   365  		return sb.storeUpdate()
   366  	}
   367  
   368  	return nil
   369  }