mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
netstack: add gro_flush_timeout
Makes a per-interface file available to configure the GRO timeout, e.g. /sys/class/net/eth0/gro_flush_timeout PiperOrigin-RevId: 487082821
This commit is contained in:
committed by
gVisor bot
parent
28bbe00821
commit
901d9a75d3
@@ -19,6 +19,7 @@ go_library(
|
||||
srcs = [
|
||||
"dir_refs.go",
|
||||
"kcov.go",
|
||||
"net.go",
|
||||
"sys.go",
|
||||
],
|
||||
visibility = ["//pkg/sentry:internal"],
|
||||
@@ -33,6 +34,7 @@ go_library(
|
||||
"//pkg/refsvfs2",
|
||||
"//pkg/sentry/arch",
|
||||
"//pkg/sentry/fsimpl/kernfs",
|
||||
"//pkg/sentry/inet",
|
||||
"//pkg/sentry/kernel",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
"//pkg/sentry/memmap",
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright 2022 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.
|
||||
|
||||
package sys
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/context"
|
||||
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
|
||||
"gvisor.dev/gvisor/pkg/sentry/inet"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
// newNetDir returns a directory containing a subdirectory for each network
|
||||
// interface.
|
||||
func (fs *filesystem) newNetDir(ctx context.Context, creds *auth.Credentials, mode linux.FileMode) map[string]kernfs.Inode {
|
||||
// Get list of interfaces.
|
||||
stk := inet.StackFromContext(ctx)
|
||||
if stk == nil {
|
||||
return map[string]kernfs.Inode{}
|
||||
}
|
||||
|
||||
subDirs := make(map[string]kernfs.Inode)
|
||||
for idx, iface := range stk.Interfaces() {
|
||||
subDirs[iface.Name] = fs.newIfaceDir(ctx, creds, mode, idx, stk)
|
||||
}
|
||||
return subDirs
|
||||
}
|
||||
|
||||
// newIfaceDir returns a directory containing per-interface files.
|
||||
func (fs *filesystem) newIfaceDir(ctx context.Context, creds *auth.Credentials, mode linux.FileMode, idx int32, stk inet.Stack) kernfs.Inode {
|
||||
files := map[string]kernfs.Inode{
|
||||
"gro_flush_timeout": fs.newGROTimeoutFile(ctx, creds, mode, idx, stk),
|
||||
}
|
||||
return fs.newDir(ctx, creds, mode, files)
|
||||
}
|
||||
|
||||
// groTimeoutFile enables the reading and writing of the GRO timeout.
|
||||
//
|
||||
// +stateify savable
|
||||
type groTimeoutFile struct {
|
||||
implStatFS
|
||||
kernfs.DynamicBytesFile
|
||||
|
||||
idx int32
|
||||
stk inet.Stack
|
||||
}
|
||||
|
||||
// newGROTimeoutFile returns a file that can be used to read and set the GRO
|
||||
// timeout.
|
||||
func (fs *filesystem) newGROTimeoutFile(ctx context.Context, creds *auth.Credentials, mode linux.FileMode, idx int32, stk inet.Stack) kernfs.Inode {
|
||||
file := groTimeoutFile{idx: idx, stk: stk}
|
||||
file.DynamicBytesFile.Init(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), &file, mode)
|
||||
return &file
|
||||
}
|
||||
|
||||
// Generate implements vfs.DynamicBytesSource.Generate.
|
||||
func (gf *groTimeoutFile) Generate(ctx context.Context, buf *bytes.Buffer) error {
|
||||
timeout, err := gf.stk.GROTimeout(gf.idx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(buf, "%d\n", timeout.Nanoseconds())
|
||||
return nil
|
||||
}
|
||||
|
||||
// Write implements vfs.WritableDynamicBytesSource.Write.
|
||||
func (gf *groTimeoutFile) Write(ctx context.Context, _ *vfs.FileDescription, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
val := []int32{0}
|
||||
nRead, err := usermem.CopyInt32StringsInVec(ctx, src.IO, src.Addrs, val, src.Opts)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
gf.stk.SetGROTimeout(gf.idx, time.Duration(val[0])*time.Nanosecond)
|
||||
return nRead, nil
|
||||
}
|
||||
@@ -108,12 +108,14 @@ func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
|
||||
classSub := map[string]kernfs.Inode{
|
||||
"power_supply": fs.newDir(ctx, creds, defaultSysDirMode, nil),
|
||||
"net": fs.newDir(ctx, creds, defaultSysDirMode, fs.newNetDir(ctx, creds, defaultSysDirMode)),
|
||||
}
|
||||
devicesSub := map[string]kernfs.Inode{
|
||||
"system": fs.newDir(ctx, creds, defaultSysDirMode, map[string]kernfs.Inode{
|
||||
"cpu": cpuDir(ctx, fs, creds),
|
||||
}),
|
||||
}
|
||||
|
||||
productName := ""
|
||||
if opts.InternalData != nil {
|
||||
data := opts.InternalData.(*InternalData)
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
package inet
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
@@ -108,6 +110,12 @@ type Stack interface {
|
||||
// SetPortRange sets the UDP and TCP IPv4 and IPv6 ephemeral port range
|
||||
// (inclusive).
|
||||
SetPortRange(start uint16, end uint16) error
|
||||
|
||||
// GROTimeout returns the GRO timeout.
|
||||
GROTimeout(NICID int32) (time.Duration, error)
|
||||
|
||||
// GROTimeout sets the GRO timeout.
|
||||
SetGROTimeout(NICID int32, timeout time.Duration) error
|
||||
}
|
||||
|
||||
// Interface contains information about a network interface.
|
||||
|
||||
@@ -17,6 +17,7 @@ package inet
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||
@@ -184,3 +185,15 @@ func (*TestStack) SetPortRange(start uint16, end uint16) error {
|
||||
// No-op.
|
||||
return nil
|
||||
}
|
||||
|
||||
// GROTimeout implements Stack.
|
||||
func (*TestStack) GROTimeout(NICID int32) (time.Duration, error) {
|
||||
// No-op.
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// SetGROTimeout implements Stack.
|
||||
func (*TestStack) SetGROTimeout(NICID int32, timeout time.Duration) error {
|
||||
// No-op.
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
@@ -515,3 +516,14 @@ func (*Stack) PortRange() (uint16, uint16) {
|
||||
func (*Stack) SetPortRange(uint16, uint16) error {
|
||||
return linuxerr.EACCES
|
||||
}
|
||||
|
||||
// GROTimeout implements inet.Stack.GROTimeout.
|
||||
func (s *Stack) GROTimeout(NICID int32) (time.Duration, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
// SetGROTimeout implements inet.Stack.SetGROTimeout.
|
||||
func (s *Stack) SetGROTimeout(NICID int32, timeout time.Duration) error {
|
||||
// We don't support setting the hostinet GRO timeout.
|
||||
return linuxerr.EINVAL
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package netstack
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
"gvisor.dev/gvisor/pkg/errors/linuxerr"
|
||||
@@ -491,3 +492,14 @@ func (s *Stack) PortRange() (uint16, uint16) {
|
||||
func (s *Stack) SetPortRange(start uint16, end uint16) error {
|
||||
return syserr.TranslateNetstackError(s.Stack.SetPortRange(start, end)).ToError()
|
||||
}
|
||||
|
||||
// GROTimeout implements inet.Stack.GROTimeout.
|
||||
func (s *Stack) GROTimeout(NICID int32) (time.Duration, error) {
|
||||
timeout, err := s.Stack.GROTimeout(NICID)
|
||||
return timeout, syserr.TranslateNetstackError(err).ToError()
|
||||
}
|
||||
|
||||
// SetGROTimeout implements inet.Stack.SetGROTimeout.
|
||||
func (s *Stack) SetGROTimeout(NICID int32, timeout time.Duration) error {
|
||||
return syserr.TranslateNetstackError(s.Stack.SetGROTimeout(NICID, timeout)).ToError()
|
||||
}
|
||||
|
||||
@@ -710,6 +710,33 @@ func (s *Stack) SetPortRange(start uint16, end uint16) tcpip.Error {
|
||||
return s.PortManager.SetPortRange(start, end)
|
||||
}
|
||||
|
||||
// GROTimeout returns the GRO timeout.
|
||||
func (s *Stack) GROTimeout(NICID int32) (time.Duration, tcpip.Error) {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
nic, ok := s.nics[tcpip.NICID(NICID)]
|
||||
if !ok {
|
||||
return 0, &tcpip.ErrUnknownNICID{}
|
||||
}
|
||||
|
||||
return nic.gro.getInterval(), nil
|
||||
}
|
||||
|
||||
// SetGROTimeout sets the GRO timeout.
|
||||
func (s *Stack) SetGROTimeout(NICID int32, timeout time.Duration) tcpip.Error {
|
||||
s.mu.RLock()
|
||||
defer s.mu.RUnlock()
|
||||
|
||||
nic, ok := s.nics[tcpip.NICID(NICID)]
|
||||
if !ok {
|
||||
return &tcpip.ErrUnknownNICID{}
|
||||
}
|
||||
|
||||
nic.gro.setInterval(timeout)
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetRouteTable assigns the route table to be used by this stack. It
|
||||
// specifies which NIC to use for given destination address ranges.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user