Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor #11365

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

refactor #11365

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion pkg/sentry/inet/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type Namespace struct {
//
// At afterLoad(), creator will be used to create network stack. Stateify
// needs to wait for this field to be loaded before calling afterLoad().
creator NetworkStackCreator `state:"wait"`
creator NetworkStackCreator `state:"nosave"`

// isRoot indicates whether this is the root network namespace.
isRoot bool
Expand Down
8 changes: 0 additions & 8 deletions pkg/sentry/kernel/kernel.go
Original file line number Diff line number Diff line change
Expand Up @@ -836,14 +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()
}
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)
defaultIPTables := netfilter.DefaultLinuxTables
s.Stack.Restore(defaultIPTables)
}

// 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()
}
34 changes: 3 additions & 31 deletions pkg/tcpip/stack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -1966,45 +1966,17 @@ func (s *Stack) Pause() {
}
}

func (s *Stack) getNICs() map[tcpip.NICID]*nic {
s.mu.RLock()
defer s.mu.RUnlock()

nics := s.nics
return nics
}

// ReplaceConfig replaces config in the loaded stack.
func (s *Stack) ReplaceConfig(st *Stack) {
if st == nil {
panic("stack.Stack cannot be nil when netstack s/r is enabled")
}

// Update route table.
s.SetRouteTable(st.GetRouteTable())

// Update NICs.
nics := st.getNICs()
s.mu.Lock()
defer s.mu.Unlock()
s.nics = make(map[tcpip.NICID]*nic)
for id, nic := range nics {
nic.stack = s
s.nics[id] = nic
_ = s.NextNICID()
}
s.tables = st.tables
}

// 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(defaultIPTables 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.icmpRateLimiter = NewICMPRateLimiter(s.clock)
s.tables = defaultIPTables(s.clock, s.insecureRNG)
s.mu.Unlock()
for _, e := range eps {
e.Restore(s)
Expand Down
8 changes: 8 additions & 0 deletions runsc/boot/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ go_library(
"loader.go",
"mount_hints.go",
"network.go",
"no_xdp.go",
"restore.go",
"restore_impl.go",
"seccheck.go",
"strace.go",
"vfs.go",
"xdp.go",
],
visibility = [
"//pkg/test:__subpackages__",
Expand Down Expand Up @@ -125,17 +127,23 @@ go_library(
"//pkg/tcpip/transport/tcp",
"//pkg/tcpip/transport/udp",
"//pkg/urpc",
"//pkg/xdp",
"//runsc/boot/filter",
"//runsc/boot/portforward",
"//runsc/boot/pprof",
"//runsc/boot/procfs",
"//runsc/config",
"//runsc/profile",
"//runsc/sandbox/bpf",
"//runsc/specutils",
"//runsc/specutils/seccomp",
"//runsc/version",
"//tools/xdp/cmd",
"@com_github_cilium_ebpf//:go_default_library",
"@com_github_cilium_ebpf//link:go_default_library",
"@com_github_opencontainers_runtime_spec//specs-go:go_default_library",
"@com_github_syndtr_gocapability//capability:go_default_library",
"@com_github_vishvananda_netlink//:go_default_library",
"@org_golang_google_protobuf//proto:go_default_library",
"@org_golang_x_sys//unix:go_default_library",
],
Expand Down
13 changes: 13 additions & 0 deletions runsc/boot/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ const (

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

// ContMgrStoreNetworkConfig stores the network config which are required
// during restore in the loader.
ContMgrStoreNetworkConfig = "containerManager.StoreNetworkConfig"
)

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

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

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

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

// StoreNetworkConfig stores the network config in the loader.
func (cm *containerManager) StoreNetworkConfig(netConf *NetworkConfig, _ *struct{}) error {
cm.l.netConf = netConf
return nil
}
13 changes: 13 additions & 0 deletions runsc/boot/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"encoding/json"
"errors"
"fmt"
"net"
"os"
"runtime"
"strconv"
Expand Down Expand Up @@ -255,6 +256,18 @@ 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
}

// NetworkConfig contains the network config.
type NetworkConfig struct {
Args *CreateLinksAndRoutesArgs
InitArgs *InitPluginStackArgs
Iface net.Interface
Network config.NetworkType
XDPMode config.XDPMode
}

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

func (n *Network) SetupNetworkSandbox(netConf *NetworkConfig, _ *struct{}) error {
switch netConf.XDPMode {
case config.XDPModeOff:
case config.XDPModeNS:
case config.XDPModeRedirect:
if err := n.SetupXDPModeRedirect(netConf, nil); err != nil {
return fmt.Errorf("failed to create XDP tunnel interface: %w", err)
}
return nil
case config.XDPModeTunnel:
if err := n.SetupXDPModeTunnel(netConf, nil); err != nil {
return fmt.Errorf("failed to create XDP tunnel interface: %w", err)
}
return nil
default:
return fmt.Errorf("unknown XDP mode: %v", netConf.XDPMode)
}
return n.CreateLinksAndRoutes(netConf.Args, nil)
}

func (n *Network) SetupNetwork(netConf *NetworkConfig, _ *struct{}) error {
switch netConf.Network {
case config.NetworkNone:
return n.CreateLinksAndRoutes(netConf.Args, nil)
case config.NetworkHost:
/* nothing to do */
return nil
case config.NetworkPlugin:
return n.InitPluginStack(netConf.InitArgs, nil)
case config.NetworkSandbox:
return n.SetupNetworkSandbox(netConf, nil)
default:
return fmt.Errorf("unknown network type")
}
}
42 changes: 42 additions & 0 deletions runsc/boot/no_xdp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright 2025 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !xdp
// +build !xdp

package boot

import (
"errors"
"net"
"os"
)

// This file holds placeholders for XDP support, which is not compiled in by default.
//
// To enable XDP support, build gVisor with `--define=gotags=xdp`.

const noXDPMsg = "XDP support was not built into this release -- rebuild with --define=gotags=xdp"

func (n *Network) SetupXDPModeRedirect(netConf *NetworkConfig, _ *struct{}) error {
return errors.New(noXDPMsg)
}

func createSocketXDP(iface net.Interface) ([]*os.File, error) {
return nil, errors.New(noXDPMsg)
}

func (n *Network) SetupXDPModeTunnel(netConf *NetworkConfig, _ *struct{}) error {
return errors.New(noXDPMsg)
}
20 changes: 20 additions & 0 deletions runsc/boot/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,12 +708,32 @@ func (r *restorer) restore(l *Loader, unsafeSkipRestoreSpecValidation bool) erro

l.kernelInitExtra()

if eps, ok := l.k.RootNetworkNamespace().Stack().(*netstack.Stack); ok {
// The network stack will be loaded from the state file, we do
// not need this network stack anymore.
oldInetStack.Destroy()

n := &Network{
Stack: eps.Stack,
}
log.Infof("network config: %+v", l.netConf)
if err := n.SetupNetwork(l.netConf, nil); err != nil {
return fmt.Errorf("restore network error: %w", err)
}
} else {
l.k.RootNetworkNamespace().RestoreRootStack(hostinet.NewStack())
}

// Refresh the control server with the newly created kernel.
l.ctrl.refreshHandlers()

// Release `l.mu` before calling into callbacks.
cu.Clean()

if _, ok := l.k.RootNetworkNamespace().Stack().(*netstack.Stack); ok {
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
Loading