Skip to content

Commit

Permalink
netstack refactor
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 719364530
  • Loading branch information
nybidari authored and gvisor-bot committed Jan 28, 2025
1 parent 0b5ee6d commit cc3cd9b
Show file tree
Hide file tree
Showing 13 changed files with 243 additions and 124 deletions.
8 changes: 0 additions & 8 deletions pkg/sentry/inet/inet.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,14 +100,6 @@ type Stack interface {
// Restore restarts the network stack after restore.
Restore()

// ReplaceConfig replaces the new network stack configuration to the
// loaded or saved network stack after restore.
// TODO(b/379115439): This method is a workaround to update netstack config
// during restore. It should be removed after a new method is added to
// extract the complete config from the spec and update it in the loaded
// stack during restore.
ReplaceConfig(st Stack)

// Destroy the network stack.
Destroy()

Expand Down
3 changes: 0 additions & 3 deletions pkg/sentry/inet/test_stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,6 @@ func (s *TestStack) Pause() {}
// Restore implements Stack.
func (s *TestStack) Restore() {}

// ReplaceConfig implements Stack.
func (s *TestStack) ReplaceConfig(_ Stack) {}

// Resume implements Stack.
func (s *TestStack) Resume() {}

Expand Down
10 changes: 0 additions & 10 deletions pkg/sentry/kernel/kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -836,16 +836,6 @@ func (k *Kernel) LoadFrom(ctx context.Context, r, pagesMetadata io.Reader, pages

if saveRestoreNet {
log.Infof("netstack save restore is enabled")
s := k.rootNetworkNamespace.Stack()
if s == nil {
panic("inet.Stack cannot be nil when netstack s/r is enabled")
}
if net != nil {
s.ReplaceConfig(net)
}
s.Restore()
} else if net != nil {
net.Restore()
}

if err := k.vfs.CompleteRestore(ctx, vfsOpts); err != nil {
Expand Down
3 changes: 0 additions & 3 deletions pkg/sentry/socket/hostinet/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,9 +398,6 @@ func (*Stack) Pause() {}
// Restore implements inet.Stack.Restore.
func (*Stack) Restore() {}

// ReplaceConfig implements inet.Stack.ReplaceConfig.
func (s *Stack) ReplaceConfig(_ inet.Stack) {}

// Resume implements inet.Stack.Resume.
func (*Stack) Resume() {}

Expand Down
12 changes: 3 additions & 9 deletions pkg/sentry/socket/netstack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/refs"
"gvisor.dev/gvisor/pkg/sentry/inet"
"gvisor.dev/gvisor/pkg/sentry/socket/netfilter"
"gvisor.dev/gvisor/pkg/sentry/socket/netlink/nlmsg"
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/tcpip"
Expand Down Expand Up @@ -922,15 +923,8 @@ func (s *Stack) Pause() {

// Restore implements inet.Stack.Restore.
func (s *Stack) Restore() {
s.Stack.Restore()
}

// ReplaceConfig implements inet.Stack.ReplaceConfig.
func (s *Stack) ReplaceConfig(st inet.Stack) {
if _, ok := st.(*Stack); !ok {
panic("netstack.Stack cannot be nil when netstack s/r is enabled")
}
s.Stack.ReplaceConfig(st.(*Stack).Stack)
tables := netfilter.DefaultLinuxTables
s.Stack.Restore(tables)
}

// Resume implements inet.Stack.Resume.
Expand Down
4 changes: 4 additions & 0 deletions pkg/tcpip/stack/save_restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ import (
"time"

cryptorand "gvisor.dev/gvisor/pkg/rand"
"gvisor.dev/gvisor/pkg/tcpip"
)

// afterLoad is invoked by stateify.
func (s *Stack) afterLoad(context.Context) {
s.insecureRNG = rand.New(rand.NewSource(time.Now().UnixNano()))
s.secureRNG = cryptorand.RNGFrom(cryptorand.Reader)
s.mu.Lock()
s.nics = make(map[tcpip.NICID]*nic)
s.mu.Unlock()
}
4 changes: 3 additions & 1 deletion pkg/tcpip/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -1998,13 +1998,15 @@ func (s *Stack) ReplaceConfig(st *Stack) {

// Restore restarts the stack after a restore. This must be called after the
// entire system has been restored.
func (s *Stack) Restore() {
func (s *Stack) Restore(fn func(clock tcpip.Clock, rand *rand.Rand) *IPTables) {
// RestoredEndpoint.Restore() may call other methods on s, so we can't hold
// s.mu while restoring the endpoints.
s.mu.Lock()
eps := s.restoredEndpoints
s.restoredEndpoints = nil
saveRestoreEnabled := s.saveRestoreEnabled
s.tables = fn(s.clock, s.insecureRNG)
s.icmpRateLimiter = NewICMPRateLimiter(s.clock)
s.mu.Unlock()
for _, e := range eps {
e.Restore(s)
Expand Down
12 changes: 12 additions & 0 deletions runsc/boot/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ const (

// ContMgrContainerRuntimeState returns the runtime state of a container.
ContMgrContainerRuntimeState = "containerManager.ContainerRuntimeState"

// ContMgrStoreNetworkConfig stores the network configuration in the loader.
ContMgrStoreNetworkConfig = "containerManager.StoreNetworkConfig"
)

const (
Expand All @@ -131,6 +134,9 @@ const (

// DebugStacks collects sandbox stacks for debugging.
DebugStacks = "debug.Stacks"

// NetworkSetupNetwork sets up network.
NetworkSetupNetwork = "Network.SetupNetwork"
)

// Profiling related commands (see pprof.go for more details).
Expand Down Expand Up @@ -943,3 +949,9 @@ func (cm *containerManager) ContainerRuntimeState(cid *string, state *ContainerR
*state = cm.l.containerRuntimeState(*cid)
return nil
}

// StoreNetworkConfig stores the network configuration.
func (cm *containerManager) StoreNetworkConfig(netConf *NetworkConfig, _ *struct{}) error {
cm.l.netConf = netConf
return nil
}
3 changes: 3 additions & 0 deletions runsc/boot/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,9 @@ type Loader struct {
// saveRestoreNet indicates if the saved network stack should be used
// during restore.
saveRestoreNet bool

// netConf contains the network configuration required during restore.
netConf *NetworkConfig
}

// execID uniquely identifies a sentry process that is executed in a container.
Expand Down
24 changes: 24 additions & 0 deletions runsc/boot/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,3 +605,27 @@ func ipMaskToAddressMask(ipMask net.IPMask) tcpip.AddressMask {
addr := ipToAddress(net.IP(ipMask))
return tcpip.MaskFromBytes(addr.AsSlice())
}

// NetworkConfig contains network configuration.
type NetworkConfig struct {
Args *CreateLinksAndRoutesArgs
InitArgs *InitPluginStackArgs
Network config.NetworkType
}

// SetupNetwork sets up the network during start and restore.
func (n *Network) SetupNetwork(netConf *NetworkConfig, _ *struct{}) error {
switch netConf.Network {
case config.NetworkNone, config.NetworkSandbox:
if err := n.CreateLinksAndRoutes(netConf.Args, nil); err != nil {
return err
}
case config.NetworkPlugin:
if err := n.InitPluginStack(netConf.InitArgs, nil); err != nil {
return err
}
default:
return fmt.Errorf("invalid network type: %v", netConf.Network)
}
return nil
}
54 changes: 54 additions & 0 deletions runsc/boot/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,22 @@ func createNetworkStackForRestore(l *Loader) (*stack.Stack, inet.Stack) {
return nil, hostinet.NewStack()
}

// IsXDP returns true if the XDP mode has to be enabled in network.
func IsXDP(conf *config.Config) bool {
if conf.Network != config.NetworkSandbox {
return false
}
switch conf.XDP.Mode {
case config.XDPModeOff:
case config.XDPModeNS:
case config.XDPModeRedirect, config.XDPModeTunnel:
return true
default:
panic("invalid XDP mode configured")
}
return false
}

func (r *restorer) restore(l *Loader) error {
log.Infof("Starting to restore %d containers", len(r.containers))

Expand Down Expand Up @@ -311,6 +327,44 @@ func (r *restorer) restore(l *Loader) error {
// Release `l.mu` before calling into callbacks.
cu.Clean()

if IsXDP(l.root.conf) {
curNetwork := l.k.RootNetworkNamespace().Stack()
eps, ok := curNetwork.(*netstack.Stack)
if !ok {
return fmt.Errorf("invalid network config with XDP mode")

}
if oldStack == nil {
return fmt.Errorf("invalid network config with XDP mode")
}
// TODO(b/340617793): Configure routes and devices in the loaded stack
// similar to non-XDP and remove ReplaceConfig.
eps.Stack.ReplaceConfig(oldStack)
l.k.RootNetworkNamespace().Stack().Restore()
} else if l.saveRestoreNet {
curNetwork := l.k.RootNetworkNamespace().Stack()
if eps, ok := curNetwork.(*netstack.Stack); ok {
if oldStack != nil {
oldStack.Destroy()
}
n := &Network{
Stack: eps.Stack,
Kernel: l.k,
}
if err := n.SetupNetwork(l.netConf, nil); err != nil {
return fmt.Errorf("SetupNetwork failed with error: %v", err)
}
l.k.RootNetworkNamespace().Stack().Restore()
} else {
// Restore the network stack with a new hostinet stack.
// Save/Restore is not supported for hostinet.
l.k.RootNetworkNamespace().RestoreRootStack(hostinet.NewStack())
}
} else {
// TODO(b/340617793): Delete when netstack s/r is enabled by default.
l.k.RootNetworkNamespace().Stack().Restore()
}

// r.restoreDone() signals and waits for the sandbox to start.
if err := r.restoreDone(); err != nil {
return fmt.Errorf("restorer.restoreDone callback failed: %w", err)
Expand Down
Loading

0 comments on commit cc3cd9b

Please sign in to comment.