Skip to content

Commit abf5927

Browse files
nybidarigvisor-bot
authored andcommitted
Refactor setting up network during restore.
Previously, during sandbox restore the network configuration was restored by creating a new network stack (which has all the config scraped from the host) and the replacing this new config such as NICs, routes and IP addresses from the new stack to the loaded/restored stack. This change refactors the process by introducing a new `inet.NetworkArgs` interface that abstracts how the network stack is configured. The `Loader` now implements this interface and configures the loaded stack directly using the configuration scraped from the host during restore. `Kernel.LoadFrom` accepts this interface (instead of stack), allowing it to configure the restored stack using either the Loader's configuration. PiperOrigin-RevId: 941330876
1 parent 879cb2d commit abf5927

13 files changed

Lines changed: 124 additions & 64 deletions

File tree

pkg/sentry/inet/inet.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,8 @@ type Stack interface {
106106
// Restore restarts the network stack after restore.
107107
Restore()
108108

109-
// ReplaceConfig replaces the new network stack configuration to the
110-
// loaded or saved network stack after restore.
111-
// TODO(b/379115439): This method is a workaround to update netstack config
112-
// during restore. It should be removed after a new method is added to
113-
// extract the complete config from the spec and update it in the loaded
114-
// stack during restore.
115-
ReplaceConfig(st Stack)
109+
// ResetConfig resets the stack's NICs and configuration.
110+
ResetConfig()
116111

117112
// Destroy the network stack.
118113
Destroy()
@@ -301,3 +296,8 @@ type VethPeerReq struct {
301296
// Stack is the stack where the second end has to be added.
302297
Stack Stack
303298
}
299+
300+
// NetworkArgs configures a network stack directly.
301+
type NetworkArgs interface {
302+
ConfigureNetwork(s Stack) error
303+
}

pkg/sentry/inet/test_stack.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,12 @@ func (s *TestStack) Pause() {}
184184
// Restore implements Stack.
185185
func (s *TestStack) Restore() {}
186186

187-
// ReplaceConfig implements Stack.
188-
func (s *TestStack) ReplaceConfig(_ Stack) {}
187+
// ResetConfig implements Stack.
188+
func (s *TestStack) ResetConfig() {
189+
s.InterfacesMap = make(map[int32]Interface)
190+
s.InterfaceAddrsMap = make(map[int32][]InterfaceAddr)
191+
s.RouteList = nil
192+
}
189193

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

pkg/sentry/kernel/kernel.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ func (k *Kernel) invalidateUnsavableMappings(ctx context.Context) error {
915915
}
916916

917917
// LoadFrom returns a new Kernel loaded from args.
918-
func (k *Kernel) LoadFrom(ctx context.Context, r io.Reader, asyncMFLoader *AsyncMFLoader, timeReady chan struct{}, net inet.Stack, clocks sentrytime.Clocks, vfsOpts *vfs.CompleteRestoreOptions, timeline *timing.Timeline) error {
918+
func (k *Kernel) LoadFrom(ctx context.Context, r io.Reader, asyncMFLoader *AsyncMFLoader, timeReady chan struct{}, networkArgs inet.NetworkArgs, clocks sentrytime.Clocks, vfsOpts *vfs.CompleteRestoreOptions, timeline *timing.Timeline) error {
919919
defer timeline.End()
920920
if hostarch.PageSize != 4096 {
921921
return fmt.Errorf("restore is not supported with %dK page size", hostarch.PageSize/1024)
@@ -987,11 +987,14 @@ func (k *Kernel) LoadFrom(ctx context.Context, r io.Reader, asyncMFLoader *Async
987987
}
988988

989989
if s := k.rootNetworkNamespace.Stack(); s != nil {
990-
if net != nil {
991-
log.Infof("Reconfiguring network for restore")
992-
s.ReplaceConfig(net)
990+
if networkArgs == nil {
991+
return fmt.Errorf("network configuration cannot be nil during restore")
992+
}
993+
log.Infof("Reconfiguring network for restore")
994+
s.ResetConfig()
995+
if err := networkArgs.ConfigureNetwork(s); err != nil {
996+
return fmt.Errorf("configuring network: %w", err)
993997
}
994-
log.Debugf("Restore network stack")
995998
s.Restore()
996999
timeline.Reached("Network stack restored")
9971000
}

pkg/sentry/socket/hostinet/stack.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,8 @@ func (*Stack) Pause() {}
409409
// Restore implements inet.Stack.Restore.
410410
func (*Stack) Restore() {}
411411

412-
// ReplaceConfig implements inet.Stack.ReplaceConfig.
413-
func (s *Stack) ReplaceConfig(_ inet.Stack) {}
412+
// ResetConfig implements inet.Stack.ResetConfig.
413+
func (*Stack) ResetConfig() {}
414414

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

pkg/sentry/socket/netstack/stack.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1112,7 +1112,12 @@ func (s *Stack) Restore() {
11121112
s.Stack.Restore()
11131113
}
11141114

1115-
// ReplaceConfig implements inet.Stack.ReplaceConfig.
1115+
// ResetConfig implements inet.Stack.ResetConfig.
1116+
func (s *Stack) ResetConfig() {
1117+
s.Stack.ResetConfig()
1118+
}
1119+
1120+
// ReplaceConfig replaces config in the loaded stack.
11161121
func (s *Stack) ReplaceConfig(st inet.Stack) {
11171122
if _, ok := st.(*Stack); !ok {
11181123
panic("netstack.Stack cannot be nil when netstack s/r is enabled")

pkg/tcpip/stack/icmp_rate_limit.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
package stack
1616

1717
import (
18+
"context"
19+
1820
"golang.org/x/time/rate"
1921
"gvisor.dev/gvisor/pkg/tcpip"
2022
)
@@ -34,9 +36,15 @@ const (
3436
//
3537
// +stateify savable
3638
type ICMPRateLimiter struct {
37-
// TODO(b/341946753): Restore when netstack is savable.
3839
limiter *rate.Limiter `state:"nosave"`
3940
clock tcpip.Clock
41+
limit rate.Limit
42+
burst int
43+
}
44+
45+
// afterLoad is invoked by stateify.
46+
func (l *ICMPRateLimiter) afterLoad(context.Context) {
47+
l.limiter = rate.NewLimiter(l.limit, l.burst)
4048
}
4149

4250
// NewICMPRateLimiter returns a global rate limiter for controlling the rate
@@ -46,11 +54,14 @@ func NewICMPRateLimiter(clock tcpip.Clock) *ICMPRateLimiter {
4654
return &ICMPRateLimiter{
4755
clock: clock,
4856
limiter: rate.NewLimiter(icmpLimit, icmpBurst),
57+
limit: icmpLimit,
58+
burst: icmpBurst,
4959
}
5060
}
5161

5262
// SetLimit sets a new Limit for the limiter.
5363
func (l *ICMPRateLimiter) SetLimit(limit rate.Limit) {
64+
l.limit = limit
5465
l.limiter.SetLimitAt(l.clock.Now(), limit)
5566
}
5667

@@ -61,6 +72,7 @@ func (l *ICMPRateLimiter) Limit() rate.Limit {
6172

6273
// SetBurst sets a new burst size for the limiter.
6374
func (l *ICMPRateLimiter) SetBurst(burst int) {
75+
l.burst = burst
6476
l.limiter.SetBurstAt(l.clock.Now(), burst)
6577
}
6678

pkg/tcpip/stack/stack.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,10 +2086,19 @@ func (s *Stack) getNICs() map[tcpip.NICID]*nic {
20862086
return nics
20872087
}
20882088

2089+
// ResetConfig resets the stack's NICs and ID generator.
2090+
func (s *Stack) ResetConfig() {
2091+
s.mu.Lock()
2092+
defer s.mu.Unlock()
2093+
s.nics = make(map[tcpip.NICID]*nic)
2094+
s.loopbackNIC = nil
2095+
s.nicIDGen.Store(0)
2096+
}
2097+
20892098
// ReplaceConfig replaces config in the loaded stack.
20902099
func (s *Stack) ReplaceConfig(st *Stack) {
20912100
if st == nil {
2092-
panic("stack.Stack cannot be nil when netstack s/r is enabled")
2101+
panic("stack.Stack cannot be nil when replacing config")
20932102
}
20942103

20952104
// Update route table.
@@ -2104,9 +2113,6 @@ func (s *Stack) ReplaceConfig(st *Stack) {
21042113
s.tables = st.IPTables()
21052114
s.nftables = st.NFTables()
21062115

2107-
// Update NICs.
2108-
s.nics = make(map[tcpip.NICID]*nic)
2109-
s.loopbackNIC = nil
21102116
for id, nic := range nics {
21112117
nic.stack = s
21122118
s.nics[id] = nic
@@ -2320,6 +2326,11 @@ func (s *Stack) IPTables() *IPTables {
23202326
return s.tables
23212327
}
23222328

2329+
// SetIPTables sets the stack's iptables.
2330+
func (s *Stack) SetIPTables(tables *IPTables) {
2331+
s.tables = tables
2332+
}
2333+
23232334
// NFTables returns the stack's nftables.
23242335
func (s *Stack) NFTables() NFTablesInterface {
23252336
return s.nftables

runsc/boot/controller.go

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,12 @@ const (
141141
// ContMgrContainerRuntimeState returns the runtime state of a container.
142142
ContMgrContainerRuntimeState = "containerManager.ContainerRuntimeState"
143143

144-
// ContMgrCreateLinksAndRoutes creates links and routes, and sets network args in loader.
145-
ContMgrCreateLinksAndRoutes = "containerManager.CreateLinksAndRoutes"
146-
147144
// ContMgrGetNetworkConfig returns the network interfaces and routes applied
148145
// during the creation of root container.
149146
ContMgrGetNetworkConfig = "containerManager.GetNetworkConfig"
147+
148+
// ContMgrSetNetworkArgs sets network args in loader without creating links.
149+
ContMgrSetNetworkArgs = "containerManager.SetNetworkArgs"
150150
)
151151

152152
const (
@@ -1234,25 +1234,27 @@ func (cm *containerManager) GetSavings(_ *struct{}, s *Savings) error {
12341234
return nil
12351235
}
12361236

1237-
// CreateLinksAndRoutes creates links and routes, and sets the network arguments.
1238-
func (cm *containerManager) CreateLinksAndRoutes(args *CreateLinksAndRoutesArgs, _ *struct{}) error {
1239-
log.Debugf("containerManager.CreateLinksAndRoutes")
1237+
// SetNetworkArgs sets the network arguments without creating links and routes.
1238+
func (cm *containerManager) SetNetworkArgs(args *CreateLinksAndRoutesArgs, _ *struct{}) error {
1239+
log.Debugf("containerManager.SetNetworkArgs")
12401240
if args == nil {
12411241
return fmt.Errorf("cannot set nil networkArgs")
12421242
}
12431243

1244-
if eps, ok := cm.l.k.RootNetworkNamespace().Stack().(*netstack.Stack); ok {
1245-
n := &Network{
1246-
Stack: eps.Stack,
1247-
Kernel: cm.l.k,
1248-
}
1249-
if err := n.CreateLinksAndRoutes(args, nil); err != nil {
1250-
return err
1251-
}
1252-
cm.l.mu.Lock()
1253-
cm.l.networkArgs = args
1254-
cm.l.mu.Unlock()
1244+
// Create a new CreateLinksAndRoutesArgs variable to store in the loader
1245+
// as the fds associated with the original argument passed to this urpc
1246+
// will be closed when it returns.
1247+
networkArgs := *args
1248+
dupedFDs, err := fd.NewFromFiles(args.FilePayload.Files)
1249+
if err != nil {
1250+
return fmt.Errorf("failed to dup network FDs: %w", err)
12551251
}
1252+
// Release the duplicated FDs back to os.File objects and store them in the copy.
1253+
networkArgs.FilePayload.Files = fd.ReleaseToFiles(dupedFDs, "network-fd")
1254+
1255+
cm.l.mu.Lock()
1256+
cm.l.networkArgs = &networkArgs
1257+
cm.l.mu.Unlock()
12561258
return nil
12571259
}
12581260

runsc/boot/loader.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -821,6 +821,37 @@ func New(args Args) (*Loader, error) {
821821
return l, nil
822822
}
823823

824+
// ConfigureNetwork implements inet.NetworkArgs.ConfigureNetwork.
825+
func (l *Loader) ConfigureNetwork(s inet.Stack) error {
826+
if l.networkArgs == nil {
827+
return nil
828+
}
829+
830+
// Close the FDs after they are used to configure the stack.
831+
defer func() {
832+
for _, f := range l.networkArgs.FilePayload.Files {
833+
f.Close()
834+
}
835+
l.networkArgs.FilePayload.Files = nil
836+
}()
837+
838+
eps, ok := s.(*netstack.Stack)
839+
if !ok {
840+
return nil
841+
}
842+
if eps.Stack.IPTables() == nil {
843+
eps.Stack.SetIPTables(netfilter.DefaultLinuxTables(eps.Stack.Clock(), eps.Stack.InsecureRNG()))
844+
}
845+
if nftables.IsNFTablesEnabled() && eps.Stack.NFTables() == nil {
846+
eps.Stack.SetNFTables(nftables.NewNFTables(eps.Stack.Clock(), eps.Stack.SecureRNG()))
847+
}
848+
n := &Network{
849+
Stack: eps.Stack,
850+
Kernel: l.k,
851+
}
852+
return n.CreateLinksAndRoutes(l.networkArgs, nil)
853+
}
854+
824855
// createProcessArgs creates args that can be used with kernel.CreateProcess.
825856
func createProcessArgs(id string, spec *specs.Spec, conf *config.Config, creds *auth.Credentials, k *kernel.Kernel, pidns *kernel.PIDNamespace) (kernel.CreateProcessArgs, error) {
826857
// Create initial limits.
@@ -1086,6 +1117,12 @@ func (l *Loader) run() error {
10861117
pprof.Initialize()
10871118
}
10881119

1120+
if l.networkArgs != nil {
1121+
if err := l.ConfigureNetwork(l.k.RootNetworkNamespace().Stack()); err != nil {
1122+
return err
1123+
}
1124+
}
1125+
10891126
// Finally done with all configuration. Setup filters before user code
10901127
// is loaded.
10911128
if err := l.installSeccompFilters(); err != nil {

runsc/boot/loader_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,7 @@ func TestNetworkConfig(t *testing.T) {
663663
},
664664
},
665665
}
666-
if err := l.ctrl.manager.CreateLinksAndRoutes(args, nil); err != nil {
666+
if err := l.ctrl.manager.SetNetworkArgs(args, nil); err != nil {
667667
t.Errorf("error calling SetNetworkConfig: %v", err)
668668
}
669669
var networkArgs CreateLinksAndRoutesArgs

0 commit comments

Comments
 (0)