[vfs2] Implement /proc/sys/net/ipv4/tcp_rmem and /proc/sys/net/ipv4/tcp_wmem.
Updates #1035 PiperOrigin-RevId: 327253907
This commit is contained in:
parent
673b6cc7fc
commit
b9d87ae7af
|
@ -36,6 +36,7 @@ go_library(
|
|||
"//pkg/sentry/socket/unix/transport",
|
||||
"//pkg/sentry/usage",
|
||||
"//pkg/sentry/vfs",
|
||||
"//pkg/sync",
|
||||
"//pkg/syserror",
|
||||
"//pkg/tcpip/header",
|
||||
"//pkg/usermem",
|
||||
|
|
|
@ -25,10 +25,18 @@ import (
|
|||
"gvisor.dev/gvisor/pkg/sentry/kernel"
|
||||
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
|
||||
"gvisor.dev/gvisor/pkg/sentry/vfs"
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/syserror"
|
||||
"gvisor.dev/gvisor/pkg/usermem"
|
||||
)
|
||||
|
||||
type tcpMemDir int
|
||||
|
||||
const (
|
||||
tcpRMem tcpMemDir = iota
|
||||
tcpWMem
|
||||
)
|
||||
|
||||
// newSysDir returns the dentry corresponding to /proc/sys directory.
|
||||
func (fs *filesystem) newSysDir(root *auth.Credentials, k *kernel.Kernel) *kernfs.Dentry {
|
||||
return kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
|
@ -56,7 +64,9 @@ func (fs *filesystem) newSysNetDir(root *auth.Credentials, k *kernel.Kernel) *ke
|
|||
contents = map[string]*kernfs.Dentry{
|
||||
"ipv4": kernfs.NewStaticDir(root, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), 0555, map[string]*kernfs.Dentry{
|
||||
"tcp_recovery": fs.newDentry(root, fs.NextIno(), 0644, &tcpRecoveryData{stack: stack}),
|
||||
"tcp_rmem": fs.newDentry(root, fs.NextIno(), 0644, &tcpMemData{stack: stack, dir: tcpRMem}),
|
||||
"tcp_sack": fs.newDentry(root, fs.NextIno(), 0644, &tcpSackData{stack: stack}),
|
||||
"tcp_wmem": fs.newDentry(root, fs.NextIno(), 0644, &tcpMemData{stack: stack, dir: tcpWMem}),
|
||||
|
||||
// The following files are simple stubs until they are implemented in
|
||||
// netstack, most of these files are configuration related. We use the
|
||||
|
@ -181,10 +191,11 @@ func (d *tcpSackData) Generate(ctx context.Context, buf *bytes.Buffer) error {
|
|||
// Tough luck.
|
||||
val = "1\n"
|
||||
}
|
||||
buf.WriteString(val)
|
||||
return nil
|
||||
_, err := buf.WriteString(val)
|
||||
return err
|
||||
}
|
||||
|
||||
// Write implements vfs.WritableDynamicBytesSource.Write.
|
||||
func (d *tcpSackData) Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
if offset != 0 {
|
||||
// No need to handle partial writes thus far.
|
||||
|
@ -200,7 +211,7 @@ func (d *tcpSackData) Write(ctx context.Context, src usermem.IOSequence, offset
|
|||
var v int32
|
||||
n, err := usermem.CopyInt32StringInVec(ctx, src.IO, src.Addrs, &v, src.Opts)
|
||||
if err != nil {
|
||||
return n, err
|
||||
return 0, err
|
||||
}
|
||||
if d.enabled == nil {
|
||||
d.enabled = new(bool)
|
||||
|
@ -228,10 +239,11 @@ func (d *tcpRecoveryData) Generate(ctx context.Context, buf *bytes.Buffer) error
|
|||
return err
|
||||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf("%d\n", recovery))
|
||||
return nil
|
||||
_, err = buf.WriteString(fmt.Sprintf("%d\n", recovery))
|
||||
return err
|
||||
}
|
||||
|
||||
// Write implements vfs.WritableDynamicBytesSource.Write.
|
||||
func (d *tcpRecoveryData) Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
if offset != 0 {
|
||||
// No need to handle partial writes thus far.
|
||||
|
@ -254,3 +266,91 @@ func (d *tcpRecoveryData) Write(ctx context.Context, src usermem.IOSequence, off
|
|||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// tcpMemData implements vfs.WritableDynamicBytesSource for
|
||||
// /proc/sys/net/ipv4/tcp_rmem and /proc/sys/net/ipv4/tcp_wmem.
|
||||
//
|
||||
// +stateify savable
|
||||
type tcpMemData struct {
|
||||
kernfs.DynamicBytesFile
|
||||
|
||||
dir tcpMemDir
|
||||
stack inet.Stack `state:"wait"`
|
||||
|
||||
// mu protects against concurrent reads/writes to FDs based on the dentry
|
||||
// backing this byte source.
|
||||
mu sync.Mutex `state:"nosave"`
|
||||
}
|
||||
|
||||
var _ vfs.WritableDynamicBytesSource = (*tcpMemData)(nil)
|
||||
|
||||
// Generate implements vfs.DynamicBytesSource.
|
||||
func (d *tcpMemData) Generate(ctx context.Context, buf *bytes.Buffer) error {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
size, err := d.readSizeLocked()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = buf.WriteString(fmt.Sprintf("%d\t%d\t%d\n", size.Min, size.Default, size.Max))
|
||||
return err
|
||||
}
|
||||
|
||||
// Write implements vfs.WritableDynamicBytesSource.Write.
|
||||
func (d *tcpMemData) Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error) {
|
||||
if offset != 0 {
|
||||
// No need to handle partial writes thus far.
|
||||
return 0, syserror.EINVAL
|
||||
}
|
||||
if src.NumBytes() == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
||||
// Limit the amount of memory allocated.
|
||||
src = src.TakeFirst(usermem.PageSize - 1)
|
||||
size, err := d.readSizeLocked()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
buf := []int32{int32(size.Min), int32(size.Default), int32(size.Max)}
|
||||
n, err := usermem.CopyInt32StringsInVec(ctx, src.IO, src.Addrs, buf, src.Opts)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
newSize := inet.TCPBufferSize{
|
||||
Min: int(buf[0]),
|
||||
Default: int(buf[1]),
|
||||
Max: int(buf[2]),
|
||||
}
|
||||
if err := d.writeSizeLocked(newSize); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// Precondition: d.mu must be locked.
|
||||
func (d *tcpMemData) readSizeLocked() (inet.TCPBufferSize, error) {
|
||||
switch d.dir {
|
||||
case tcpRMem:
|
||||
return d.stack.TCPReceiveBufferSize()
|
||||
case tcpWMem:
|
||||
return d.stack.TCPSendBufferSize()
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown tcpMemFile type: %v", d.dir))
|
||||
}
|
||||
}
|
||||
|
||||
// Precondition: d.mu must be locked.
|
||||
func (d *tcpMemData) writeSizeLocked(size inet.TCPBufferSize) error {
|
||||
switch d.dir {
|
||||
case tcpRMem:
|
||||
return d.stack.SetTCPReceiveBufferSize(size)
|
||||
case tcpWMem:
|
||||
return d.stack.SetTCPSendBufferSize(size)
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown tcpMemFile type: %v", d.dir))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue