From e400f72c3ab7c349f8b225083894a8b3065efa8f Mon Sep 17 00:00:00 2001 From: Nayana Bidari Date: Mon, 16 Dec 2024 11:48:36 -0800 Subject: [PATCH] Enable netstack s/r by default in runsc. Change the flag name TESTONLY-save-restore-netstack to save-restore-netstack. Set save-restore-netstack flag to true by default in runsc. PiperOrigin-RevId: 706783467 --- Makefile | 1 - pkg/sentry/inet/inet.go | 3 + pkg/sentry/inet/test_stack.go | 6 ++ pkg/sentry/kernel/timekeeper_state.go | 5 ++ pkg/sentry/socket/hostinet/stack.go | 5 ++ pkg/sentry/socket/netstack/stack.go | 16 +++-- pkg/tcpip/stack/addressable_endpoint_state.go | 4 +- pkg/tcpip/stack/stack.go | 1 + pkg/tcpip/transport/icmp/endpoint.go | 2 +- pkg/tcpip/transport/icmp/endpoint_state.go | 10 ++- .../transport/internal/network/endpoint.go | 4 +- pkg/tcpip/transport/packet/endpoint.go | 2 +- pkg/tcpip/transport/packet/endpoint_state.go | 12 +++- pkg/tcpip/transport/raw/endpoint.go | 2 +- pkg/tcpip/transport/raw/endpoint_state.go | 15 +++-- pkg/tcpip/transport/tcp/endpoint.go | 2 +- pkg/tcpip/transport/tcp/endpoint_state.go | 61 +++++++++++-------- pkg/tcpip/transport/udp/endpoint.go | 2 +- pkg/tcpip/transport/udp/endpoint_state.go | 16 +++-- pkg/test/testutil/testutil.go | 14 ++--- runsc/boot/loader.go | 2 +- runsc/config/config.go | 4 +- runsc/config/flags.go | 1 + test/e2e/integration_test.go | 15 ----- 24 files changed, 124 insertions(+), 81 deletions(-) diff --git a/Makefile b/Makefile index 4679c325be..b134296ac8 100644 --- a/Makefile +++ b/Makefile @@ -353,7 +353,6 @@ docker-tests: load-basic $(RUNTIME_BIN) @$(call install_runtime,$(RUNTIME)-dcache,--fdlimit=2000 --dcache=100) # Used by TestDentryCacheLimit. @$(call install_runtime,$(RUNTIME)-host-uds,--host-uds=all) # Used by TestHostSocketConnect. @$(call install_runtime,$(RUNTIME)-overlay,--overlay2=all:self) # Used by TestOverlay*. - @$(call install_runtime,$(RUNTIME)-TESTONLY-save-restore-netstack,--TESTONLY-save-restore-netstack=true) # Used by TestRestoreListenConnWithNetstackSR. @$(call test_runtime,$(RUNTIME),$(INTEGRATION_TARGETS) --test_env=TEST_SAVE_RESTORE_NETSTACK=true //test/e2e:integration_runtime_test //test/e2e:runtime_in_docker_test) .PHONY: docker-tests diff --git a/pkg/sentry/inet/inet.go b/pkg/sentry/inet/inet.go index 5f12113c45..8b4ef8848e 100644 --- a/pkg/sentry/inet/inet.go +++ b/pkg/sentry/inet/inet.go @@ -137,6 +137,9 @@ type Stack interface { // IsSaveRestoreEnabled returns true when netstack s/r is enabled. IsSaveRestoreEnabled() bool + + // Stats returns the network stats. + Stats() tcpip.Stats } // Interface contains information about a network interface. diff --git a/pkg/sentry/inet/test_stack.go b/pkg/sentry/inet/test_stack.go index 119e6c78b6..26d3f61651 100644 --- a/pkg/sentry/inet/test_stack.go +++ b/pkg/sentry/inet/test_stack.go @@ -235,3 +235,9 @@ func (*TestStack) IsSaveRestoreEnabled() bool { // No-op. return false } + +// Stats implements Stack. +func (*TestStack) Stats() tcpip.Stats { + // No-op. + return tcpip.Stats{} +} diff --git a/pkg/sentry/kernel/timekeeper_state.go b/pkg/sentry/kernel/timekeeper_state.go index 38ad158f5e..9845312dc1 100644 --- a/pkg/sentry/kernel/timekeeper_state.go +++ b/pkg/sentry/kernel/timekeeper_state.go @@ -26,6 +26,11 @@ func (t *Timekeeper) beforeSave() { panic("pauseUpdates must be called before Save") } + if t.clocks == nil { + t.restored = nil + return + } + // N.B. we want the *offset* monotonic time. var err error if t.saveMonotonic, err = t.GetTime(time.Monotonic); err != nil { diff --git a/pkg/sentry/socket/hostinet/stack.go b/pkg/sentry/socket/hostinet/stack.go index 32fa99a047..4d1facb0af 100644 --- a/pkg/sentry/socket/hostinet/stack.go +++ b/pkg/sentry/socket/hostinet/stack.go @@ -438,3 +438,8 @@ func (*Stack) EnableSaveRestore() error { func (s *Stack) IsSaveRestoreEnabled() bool { return false } + +// Stats implements inet.Stack.Stats. +func (s *Stack) Stats() tcpip.Stats { + return tcpip.Stats{} +} diff --git a/pkg/sentry/socket/netstack/stack.go b/pkg/sentry/socket/netstack/stack.go index c579f5a2f0..fc21771bd3 100644 --- a/pkg/sentry/socket/netstack/stack.go +++ b/pkg/sentry/socket/netstack/stack.go @@ -592,6 +592,7 @@ func (s *Stack) SetTCPRecovery(recovery inet.TCPLossRecovery) error { // Statistics implements inet.Stack.Statistics. func (s *Stack) Statistics(stat any, arg string) error { + netStats := s.Stats() switch stats := stat.(type) { case *inet.StatDev: for _, ni := range s.Stack.NICInfo() { @@ -622,7 +623,7 @@ func (s *Stack) Statistics(stat any, arg string) error { break } case *inet.StatSNMPIP: - ip := Metrics.IP + ip := netStats.IP // TODO(gvisor.dev/issue/969) Support stubbed stats. *stats = inet.StatSNMPIP{ 0, // Ip/Forwarding. @@ -646,8 +647,8 @@ func (s *Stack) Statistics(stat any, arg string) error { 0, // Support Ip/FragCreates. } case *inet.StatSNMPICMP: - in := Metrics.ICMP.V4.PacketsReceived.ICMPv4PacketStats - out := Metrics.ICMP.V4.PacketsSent.ICMPv4PacketStats + in := netStats.ICMP.V4.PacketsReceived.ICMPv4PacketStats + out := netStats.ICMP.V4.PacketsSent.ICMPv4PacketStats // TODO(gvisor.dev/issue/969) Support stubbed stats. *stats = inet.StatSNMPICMP{ 0, // Icmp/InMsgs. @@ -679,7 +680,7 @@ func (s *Stack) Statistics(stat any, arg string) error { out.InfoReply.Value(), // OutAddrMaskReps. } case *inet.StatSNMPTCP: - tcp := Metrics.TCP + tcp := netStats.TCP // RFC 2012 (updates 1213): SNMPv2-MIB-TCP. *stats = inet.StatSNMPTCP{ 1, // RtoAlgorithm. @@ -699,7 +700,7 @@ func (s *Stack) Statistics(stat any, arg string) error { tcp.ChecksumErrors.Value(), // InCsumErrors. } case *inet.StatSNMPUDP: - udp := Metrics.UDP + udp := netStats.UDP // TODO(gvisor.dev/issue/969) Support stubbed stats. *stats = inet.StatSNMPUDP{ udp.PacketsReceived.Value(), // InDatagrams. @@ -717,6 +718,11 @@ func (s *Stack) Statistics(stat any, arg string) error { return nil } +// Stats implements inet.Stack.Stats. +func (s *Stack) Stats() tcpip.Stats { + return s.Stack.Stats() +} + // RouteTable implements inet.Stack.RouteTable. func (s *Stack) RouteTable() []inet.Route { var routeTable []inet.Route diff --git a/pkg/tcpip/stack/addressable_endpoint_state.go b/pkg/tcpip/stack/addressable_endpoint_state.go index bb2e0faf0f..e08909c816 100644 --- a/pkg/tcpip/stack/addressable_endpoint_state.go +++ b/pkg/tcpip/stack/addressable_endpoint_state.go @@ -738,8 +738,6 @@ func (a *AddressableEndpointState) Cleanup() { var _ AddressEndpoint = (*addressState)(nil) // addressState holds state for an address. -// -// +stateify savable type addressState struct { addressableEndpointState *AddressableEndpointState addr tcpip.AddressWithPrefix @@ -750,7 +748,7 @@ type addressState struct { // // AddressableEndpointState.mu // addressState.mu - mu addressStateRWMutex `state:"nosave"` + mu addressStateRWMutex refs addressStateRefs // checklocks:mu kind AddressKind diff --git a/pkg/tcpip/stack/stack.go b/pkg/tcpip/stack/stack.go index 0232a45eef..645f52f782 100644 --- a/pkg/tcpip/stack/stack.go +++ b/pkg/tcpip/stack/stack.go @@ -1986,6 +1986,7 @@ func (s *Stack) ReplaceConfig(st *Stack) { s.nics[id] = nic _ = s.NextNICID() } + s.tables = st.tables } // Restore restarts the stack after a restore. This must be called after the diff --git a/pkg/tcpip/transport/icmp/endpoint.go b/pkg/tcpip/transport/icmp/endpoint.go index 988604fcd4..c7924d534f 100644 --- a/pkg/tcpip/transport/icmp/endpoint.go +++ b/pkg/tcpip/transport/icmp/endpoint.go @@ -57,7 +57,7 @@ type endpoint struct { // The following fields are initialized at creation time and are // immutable. - stack *stack.Stack `state:"manual"` + stack *stack.Stack transProto tcpip.TransportProtocolNumber waiterQueue *waiter.Queue net network.Endpoint diff --git a/pkg/tcpip/transport/icmp/endpoint_state.go b/pkg/tcpip/transport/icmp/endpoint_state.go index 134797e8b0..9ee7b52158 100644 --- a/pkg/tcpip/transport/icmp/endpoint_state.go +++ b/pkg/tcpip/transport/icmp/endpoint_state.go @@ -36,7 +36,11 @@ func (p *icmpPacket) loadReceivedAt(_ context.Context, nsec int64) { // afterLoad is invoked by stateify. func (e *endpoint) afterLoad(ctx context.Context) { - stack.RestoreStackFromContext(ctx).RegisterRestoredEndpoint(e) + if e.stack.IsSaveRestoreEnabled() { + e.stack.RegisterRestoredEndpoint(e) + } else { + stack.RestoreStackFromContext(ctx).RegisterRestoredEndpoint(e) + } } // beforeSave is invoked by stateify. @@ -50,6 +54,10 @@ func (e *endpoint) Restore(s *stack.Stack) { e.thaw() e.net.Resume(s) + if e.stack.IsSaveRestoreEnabled() { + e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) + return + } e.stack = s e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) diff --git a/pkg/tcpip/transport/internal/network/endpoint.go b/pkg/tcpip/transport/internal/network/endpoint.go index 6a0523963c..8eefeb7b10 100644 --- a/pkg/tcpip/transport/internal/network/endpoint.go +++ b/pkg/tcpip/transport/internal/network/endpoint.go @@ -35,7 +35,7 @@ import ( // +stateify savable type Endpoint struct { // The following fields must only be set once then never changed. - stack *stack.Stack `state:"manual"` + stack *stack.Stack ops *tcpip.SocketOptions netProto tcpip.NetworkProtocolNumber transProto tcpip.TransportProtocolNumber @@ -53,7 +53,7 @@ type Endpoint struct { // +checklocks:mu effectiveNetProto tcpip.NetworkProtocolNumber // +checklocks:mu - connectedRoute *stack.Route `state:"manual"` + connectedRoute *stack.Route `state:"nosave"` // +checklocks:mu multicastMemberships map[multicastMembership]struct{} // +checklocks:mu diff --git a/pkg/tcpip/transport/packet/endpoint.go b/pkg/tcpip/transport/packet/endpoint.go index 9166bca6cc..0cf7c01589 100644 --- a/pkg/tcpip/transport/packet/endpoint.go +++ b/pkg/tcpip/transport/packet/endpoint.go @@ -63,7 +63,7 @@ type endpoint struct { // The following fields are initialized at creation time and are // immutable. - stack *stack.Stack `state:"manual"` + stack *stack.Stack waiterQueue *waiter.Queue cooked bool ops tcpip.SocketOptions diff --git a/pkg/tcpip/transport/packet/endpoint_state.go b/pkg/tcpip/transport/packet/endpoint_state.go index 16be7d6b3a..355381ff3c 100644 --- a/pkg/tcpip/transport/packet/endpoint_state.go +++ b/pkg/tcpip/transport/packet/endpoint_state.go @@ -43,12 +43,20 @@ func (ep *endpoint) beforeSave() { // afterLoad is invoked by stateify. func (ep *endpoint) afterLoad(ctx context.Context) { + if !ep.stack.IsSaveRestoreEnabled() { + ep.mu.Lock() + ep.stack = stack.RestoreStackFromContext(ctx) + ep.mu.Unlock() + } + ep.stack.RegisterRestoredEndpoint(ep) +} + +// Restore implements tcpip.RestoredEndpoint.Restore. +func (ep *endpoint) Restore(_ *stack.Stack) { ep.mu.Lock() defer ep.mu.Unlock() - ep.stack = stack.RestoreStackFromContext(ctx) ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) - if err := ep.stack.RegisterPacketEndpoint(ep.boundNIC, ep.boundNetProto, ep); err != nil { panic(fmt.Sprintf("RegisterPacketEndpoint(%d, %d, _): %s", ep.boundNIC, ep.boundNetProto, err)) } diff --git a/pkg/tcpip/transport/raw/endpoint.go b/pkg/tcpip/transport/raw/endpoint.go index 1eaedc1979..5203c4dd9b 100644 --- a/pkg/tcpip/transport/raw/endpoint.go +++ b/pkg/tcpip/transport/raw/endpoint.go @@ -73,7 +73,7 @@ type endpoint struct { // The following fields are initialized at creation time and are // immutable. - stack *stack.Stack `state:"manual"` + stack *stack.Stack transProto tcpip.TransportProtocolNumber waiterQueue *waiter.Queue associated bool diff --git a/pkg/tcpip/transport/raw/endpoint_state.go b/pkg/tcpip/transport/raw/endpoint_state.go index d915ade2e1..f2e8896ff5 100644 --- a/pkg/tcpip/transport/raw/endpoint_state.go +++ b/pkg/tcpip/transport/raw/endpoint_state.go @@ -16,7 +16,6 @@ package raw import ( "context" - "fmt" "time" "gvisor.dev/gvisor/pkg/tcpip" @@ -35,7 +34,11 @@ func (p *rawPacket) loadReceivedAt(_ context.Context, nsec int64) { // afterLoad is invoked by stateify. func (e *endpoint) afterLoad(ctx context.Context) { - stack.RestoreStackFromContext(ctx).RegisterRestoredEndpoint(e) + if e.stack.IsSaveRestoreEnabled() { + e.stack.RegisterRestoredEndpoint(e) + } else { + stack.RestoreStackFromContext(ctx).RegisterRestoredEndpoint(e) + } } // beforeSave is invoked by stateify. @@ -46,16 +49,20 @@ func (e *endpoint) beforeSave() { // Restore implements tcpip.RestoredEndpoint.Restore. func (e *endpoint) Restore(s *stack.Stack) { + e.setReceiveDisabled(false) e.net.Resume(s) + if e.stack.IsSaveRestoreEnabled() { + e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) + return + } - e.setReceiveDisabled(false) e.stack = s e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) if e.associated { netProto := e.net.NetProto() if err := e.stack.RegisterRawTransportEndpoint(netProto, e.transProto, e); err != nil { - panic(fmt.Sprintf("e.stack.RegisterRawTransportEndpoint(%d, %d, _): %s", netProto, e.transProto, err)) + panic("RegisterRawTransportEndpoint failed during restore") } } } diff --git a/pkg/tcpip/transport/tcp/endpoint.go b/pkg/tcpip/transport/tcp/endpoint.go index 6ef254ff47..49c2474c0d 100644 --- a/pkg/tcpip/transport/tcp/endpoint.go +++ b/pkg/tcpip/transport/tcp/endpoint.go @@ -418,7 +418,7 @@ type Endpoint struct { isPortReserved bool isRegistered bool boundNICID tcpip.NICID - route *stack.Route `state:"manual"` + route *stack.Route `state:"nosave"` ipv4TTL uint8 ipv6HopLimit int16 isConnectNotified bool diff --git a/pkg/tcpip/transport/tcp/endpoint_state.go b/pkg/tcpip/transport/tcp/endpoint_state.go index 98f9ca6526..07b51d381a 100644 --- a/pkg/tcpip/transport/tcp/endpoint_state.go +++ b/pkg/tcpip/transport/tcp/endpoint_state.go @@ -159,21 +159,23 @@ func (e *Endpoint) Restore(s *stack.Stack) { bind := func() { e.mu.Lock() defer e.mu.Unlock() - addr, _, err := e.checkV4MappedLocked(tcpip.FullAddress{Addr: e.BindAddr, Port: e.TransportEndpointInfo.ID.LocalPort}, true /* bind */) - if err != nil { - panic("unable to parse BindAddr: " + err.String()) - } - portRes := ports.Reservation{ - Networks: e.effectiveNetProtos, - Transport: ProtocolNumber, - Addr: addr.Addr, - Port: addr.Port, - Flags: e.boundPortFlags, - BindToDevice: e.boundBindToDevice, - Dest: e.boundDest, - } - if ok := e.stack.ReserveTuple(portRes); !ok { - panic(fmt.Sprintf("unable to re-reserve tuple (%v, %q, %d, %+v, %d, %v)", e.effectiveNetProtos, addr.Addr, addr.Port, e.boundPortFlags, e.boundBindToDevice, e.boundDest)) + if !saveRestoreEnabled { + addr, _, err := e.checkV4MappedLocked(tcpip.FullAddress{Addr: e.BindAddr, Port: e.TransportEndpointInfo.ID.LocalPort}, true /* bind */) + if err != nil { + panic("unable to parse BindAddr: " + err.String()) + } + portRes := ports.Reservation{ + Networks: e.effectiveNetProtos, + Transport: ProtocolNumber, + Addr: addr.Addr, + Port: addr.Port, + Flags: e.boundPortFlags, + BindToDevice: e.boundBindToDevice, + Dest: e.boundDest, + } + if ok := e.stack.ReserveTuple(portRes); !ok { + panic(fmt.Sprintf("unable to re-reserve tuple (%v, %q, %d, %+v, %d, %v)", e.effectiveNetProtos, addr.Addr, addr.Port, e.boundPortFlags, e.boundBindToDevice, e.boundDest)) + } } e.isPortReserved = true @@ -183,7 +185,7 @@ func (e *Endpoint) Restore(s *stack.Stack) { epState := EndpointState(e.origEndpointState) switch { - case epState.connected(): + case epState.connected() || epState == StateTimeWait: bind() if e.connectingAddress.BitLen() == 0 { e.connectingAddress = e.TransportEndpointInfo.ID.RemoteAddress @@ -201,6 +203,10 @@ func (e *Endpoint) Restore(s *stack.Stack) { // Reset the scoreboard to reinitialize the sack information as // we do not restore SACK information. e.scoreboard.Reset() + if saveRestoreEnabled { + // Unregister the endpoint before registering again during Connect. + e.stack.UnregisterTransportEndpoint(e.effectiveNetProtos, header.TCPProtocolNumber, e.TransportEndpointInfo.ID, e, e.boundPortFlags, e.boundBindToDevice) + } e.mu.Lock() err := e.connect(tcpip.FullAddress{NIC: e.boundNICID, Addr: e.connectingAddress, Port: e.TransportEndpointInfo.ID.RemotePort}, false /* handshake */) if _, ok := err.(*tcpip.ErrConnectStarted); !ok { @@ -224,8 +230,8 @@ func (e *Endpoint) Restore(s *stack.Stack) { e.mu.Unlock() connectedLoading.Done() case epState == StateListen: + tcpip.AsyncLoading.Add(1) if !saveRestoreEnabled { - tcpip.AsyncLoading.Add(1) go func() { connectedLoading.Wait() bind() @@ -244,14 +250,19 @@ func (e *Endpoint) Restore(s *stack.Stack) { tcpip.AsyncLoading.Done() }() } else { - e.LockUser() - // All endpoints will be moved to initial state after - // restore. Set endpoint to its originial listen state. - e.setEndpointState(StateListen) - // Initialize the listening context. - rcvWnd := seqnum.Size(e.receiveBufferAvailable()) - e.listenCtx = newListenContext(e.stack, e.protocol, e, rcvWnd, e.ops.GetV6Only(), e.NetProto) - e.UnlockUser() + go func() { + connectedLoading.Wait() + e.LockUser() + // All endpoints will be moved to initial state after + // restore. Set endpoint to its originial listen state. + e.setEndpointState(StateListen) + // Initialize the listening context. + rcvWnd := seqnum.Size(e.receiveBufferAvailable()) + e.listenCtx = newListenContext(e.stack, e.protocol, e, rcvWnd, e.ops.GetV6Only(), e.NetProto) + e.UnlockUser() + listenLoading.Done() + tcpip.AsyncLoading.Done() + }() } case epState == StateConnecting: // Initial SYN hasn't been sent yet so initiate a connect. diff --git a/pkg/tcpip/transport/udp/endpoint.go b/pkg/tcpip/transport/udp/endpoint.go index 0bd7db350a..b5ad77a623 100644 --- a/pkg/tcpip/transport/udp/endpoint.go +++ b/pkg/tcpip/transport/udp/endpoint.go @@ -61,7 +61,7 @@ type endpoint struct { // The following fields are initialized at creation time and do not // change throughout the lifetime of the endpoint. - stack *stack.Stack `state:"manual"` + stack *stack.Stack waiterQueue *waiter.Queue net network.Endpoint stats tcpip.TransportEndpointStats diff --git a/pkg/tcpip/transport/udp/endpoint_state.go b/pkg/tcpip/transport/udp/endpoint_state.go index 488e46600d..c8bc4b1df3 100644 --- a/pkg/tcpip/transport/udp/endpoint_state.go +++ b/pkg/tcpip/transport/udp/endpoint_state.go @@ -16,7 +16,6 @@ package udp import ( "context" - "fmt" "time" "gvisor.dev/gvisor/pkg/tcpip" @@ -36,7 +35,11 @@ func (p *udpPacket) loadReceivedAt(_ context.Context, nsec int64) { // afterLoad is invoked by stateify. func (e *endpoint) afterLoad(ctx context.Context) { - stack.RestoreStackFromContext(ctx).RegisterRestoredEndpoint(e) + if e.stack.IsSaveRestoreEnabled() { + e.stack.RegisterRestoredEndpoint(e) + } else { + stack.RestoreStackFromContext(ctx).RegisterRestoredEndpoint(e) + } } // beforeSave is invoked by stateify. @@ -53,7 +56,10 @@ func (e *endpoint) Restore(s *stack.Stack) { defer e.mu.Unlock() e.net.Resume(s) - + if e.stack.IsSaveRestoreEnabled() { + e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) + return + } e.stack = s e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits) @@ -69,12 +75,12 @@ func (e *endpoint) Restore(s *stack.Stack) { id.RemotePort = e.remotePort id, e.boundBindToDevice, err = e.registerWithStack(e.effectiveNetProtos, id) if err != nil { - panic(err) + panic("registering udp endpoint with the stack failed during restore") } e.localPort = id.LocalPort e.remotePort = id.RemotePort default: - panic(fmt.Sprintf("unhandled state = %s", state)) + panic("unhandled state") } } diff --git a/pkg/test/testutil/testutil.go b/pkg/test/testutil/testutil.go index 18e07cbd41..fc889aab49 100644 --- a/pkg/test/testutil/testutil.go +++ b/pkg/test/testutil/testutil.go @@ -54,11 +54,10 @@ var ( // Flags controlling features for sandbox under test, prefixed with // "test-" to avoid potential conflicts with runsc flags. - checkpointSupported = flag.Bool("test-checkpoint", BoolFromEnv("TEST_CHECKPOINT", true), "control checkpoint/restore support") - isRunningWithOverlay = flag.Bool("test-overlay", BoolFromEnv("TEST_OVERLAY", false), "whether test is running with --overlay2") - isRunningWithNetRaw = flag.Bool("test-net-raw", BoolFromEnv("TEST_NET_RAW", false), "whether test is running with raw socket support") - isRunningWithHostNet = flag.Bool("test-hostnet", BoolFromEnv("TEST_HOSTNET", false), "whether test is running with hostnet") - isRunningWithSaveRestoreNetstack = flag.Bool("test-save-restore-netstack", BoolFromEnv("TEST_SAVE_RESTORE_NETSTACK", false), "whether test is running with --TESTONLY-save-restore-netstack") + checkpointSupported = flag.Bool("test-checkpoint", BoolFromEnv("TEST_CHECKPOINT", true), "control checkpoint/restore support") + isRunningWithOverlay = flag.Bool("test-overlay", BoolFromEnv("TEST_OVERLAY", false), "whether test is running with --overlay2") + isRunningWithNetRaw = flag.Bool("test-net-raw", BoolFromEnv("TEST_NET_RAW", false), "whether test is running with raw socket support") + isRunningWithHostNet = flag.Bool("test-hostnet", BoolFromEnv("TEST_HOSTNET", false), "whether test is running with hostnet") // TestEnvSupportsNetAdmin indicates whether a test sandbox can perform // all net admin tasks. Note that some test environments cannot perform // some tasks despite the presence of CAP_NET_ADMIN. @@ -138,11 +137,6 @@ func IsRunningWithOverlay() bool { return *isRunningWithOverlay } -// IsRunningWithSaveRestoreNetstack returns the relevant command line flag. -func IsRunningWithSaveRestoreNetstack() bool { - return *isRunningWithSaveRestoreNetstack -} - // ImageByName mangles the image name used locally. This depends on the image // build infrastructure in images/ and tools/vm. func ImageByName(name string) string { diff --git a/runsc/boot/loader.go b/runsc/boot/loader.go index 4ae3b787e5..daed7b3a8c 100644 --- a/runsc/boot/loader.go +++ b/runsc/boot/loader.go @@ -542,7 +542,7 @@ func New(args Args) (*Loader, error) { } // S/R is not supported for hostinet. - if l.root.conf.Network != config.NetworkHost && args.Conf.TestOnlySaveRestoreNetstack { + if l.root.conf.Network != config.NetworkHost && args.Conf.SaveRestoreNetstack { l.saveRestoreNet = true if err := netns.Stack().EnableSaveRestore(); err != nil { return nil, fmt.Errorf("enable s/r: %w", err) diff --git a/runsc/config/config.go b/runsc/config/config.go index 3b445870db..8ce81aaf0f 100644 --- a/runsc/config/config.go +++ b/runsc/config/config.go @@ -382,8 +382,8 @@ type Config struct { // TestOnlyAutosaveResume indicates save resume for syscall tests. TestOnlyAutosaveResume bool `flag:"TESTONLY-autosave-resume"` - // TestOnlySaveRestoreNetstack indicates netstack should be saved and restored. - TestOnlySaveRestoreNetstack bool `flag:"TESTONLY-save-restore-netstack"` + // SaveRestoreNetstack indicates netstack should be saved and restored. + SaveRestoreNetstack bool `flag:"save-restore-netstack"` } func (c *Config) validate() error { diff --git a/runsc/config/flags.go b/runsc/config/flags.go index f3df24db26..3cb61f2c61 100644 --- a/runsc/config/flags.go +++ b/runsc/config/flags.go @@ -144,6 +144,7 @@ func RegisterFlags(flagSet *flag.FlagSet) { flagSet.Bool("reproduce-nat", false, "Scrape the host netns NAT table and reproduce it in the sandbox.") flagSet.Bool(flagReproduceNFTables, false, "Attempt to scrape and reproduce nftable rules inside the sandbox. Overrides reproduce-nat when true.") flagSet.Bool(flagNetDisconnectOK, true, "Indicates whether open network connections and open unix domain sockets should be disconnected upon save.") + flagSet.Bool("save-restore-netstack", true, "Enable save/restore for netstack.") // Flags that control sandbox runtime behavior: accelerator related. flagSet.Bool("nvproxy", false, "EXPERIMENTAL: enable support for Nvidia GPUs") diff --git a/test/e2e/integration_test.go b/test/e2e/integration_test.go index 9d755f3809..70e621b71a 100644 --- a/test/e2e/integration_test.go +++ b/test/e2e/integration_test.go @@ -1298,18 +1298,3 @@ func TestRestoreListenConn(t *testing.T) { d := dockerutil.MakeContainer(ctx, t) testCheckpointRestoreListeningConnection(ctx, t, d) } - -// Test to check restore of a TCP listening connection with netstack S/R. -func TestRestoreListenConnWithNetstackSR(t *testing.T) { - if !testutil.IsCheckpointSupported() { - t.Skip("Checkpoint is not supported.") - } - if !testutil.IsRunningWithSaveRestoreNetstack() { - t.Skip("Netstack save restore is not supported.") - } - dockerutil.EnsureDockerExperimentalEnabled() - - ctx := context.Background() - d := dockerutil.MakeContainerWithRuntime(ctx, t, "-TESTONLY-save-restore-netstack") - testCheckpointRestoreListeningConnection(ctx, t, d) -}