Move SO_SNDBUF to socketops.

This CL moves {S,G}etsockopt of SO_SNDBUF from all endpoints to socketops. For
unix sockets, we do not support setting of this option.

PiperOrigin-RevId: 353871484
This commit is contained in:
Nayana Bidari
2021-01-26 08:25:34 -08:00
committed by gVisor bot
parent 3946075403
commit daf0d3f6ca
24 changed files with 246 additions and 235 deletions
+15 -2
View File
@@ -846,7 +846,7 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
return nil, syserr.ErrInvalidArgument
}
size, err := ep.GetSockOptInt(tcpip.SendBufferSizeOption)
size, err := ep.SocketOptions().GetSendBufferSize()
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
@@ -1615,8 +1615,21 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
return syserr.ErrInvalidArgument
}
family, skType, skProto := s.Type()
// TODO(gvisor.dev/issue/5132): We currently do not support
// setting this option for unix sockets.
if family == linux.AF_UNIX {
return nil
}
getBufferLimits := tcpip.GetStackSendBufferLimits
if isTCPSocket(skType, skProto) {
getBufferLimits = tcp.GetTCPSendBufferLimits
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.SendBufferSizeOption, int(v)))
ep.SocketOptions().SetSendBufferSize(int64(v), true, getBufferLimits)
return nil
case linux.SO_RCVBUF:
if len(optVal) < sizeOfInt32 {
@@ -128,7 +128,7 @@ func newConnectioned(ctx context.Context, stype linux.SockType, uid UniqueIDProv
idGenerator: uid,
stype: stype,
}
ep.ops.InitHandler(ep)
ep.ops.InitHandler(ep, nil)
return ep
}
@@ -173,7 +173,7 @@ func NewExternal(ctx context.Context, stype linux.SockType, uid UniqueIDProvider
idGenerator: uid,
stype: stype,
}
ep.ops.InitHandler(ep)
ep.ops.InitHandler(ep, nil)
return ep
}
@@ -296,7 +296,7 @@ func (e *connectionedEndpoint) BidirectionalConnect(ctx context.Context, ce Conn
idGenerator: e.idGenerator,
stype: e.stype,
}
ne.ops.InitHandler(ne)
ne.ops.InitHandler(ne, nil)
readQueue := &queue{ReaderQueue: ce.WaiterQueue(), WriterQueue: ne.Queue, limit: initialLimit}
readQueue.InitRefs()
@@ -44,7 +44,7 @@ func NewConnectionless(ctx context.Context) Endpoint {
q := queue{ReaderQueue: ep.Queue, WriterQueue: &waiter.Queue{}, limit: initialLimit}
q.InitRefs()
ep.receiver = &queueReceiver{readQueue: &q}
ep.ops.InitHandler(ep)
ep.ops.InitHandler(ep, nil)
return ep
}
+21 -14
View File
@@ -842,7 +842,6 @@ func (e *baseEndpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
func (e *baseEndpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
switch opt {
case tcpip.SendBufferSizeOption:
case tcpip.ReceiveBufferSizeOption:
default:
log.Warningf("Unsupported socket option: %d", opt)
@@ -850,6 +849,27 @@ func (e *baseEndpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
return nil
}
// IsUnixSocket implements tcpip.SocketOptionsHandler.IsUnixSocket.
func (e *baseEndpoint) IsUnixSocket() bool {
return true
}
// GetSendBufferSize implements tcpip.SocketOptionsHandler.GetSendBufferSize.
func (e *baseEndpoint) GetSendBufferSize() (int64, *tcpip.Error) {
e.Lock()
defer e.Unlock()
if !e.Connected() {
return -1, tcpip.ErrNotConnected
}
v := e.connected.SendMaxQueueSize()
if v < 0 {
return -1, tcpip.ErrQueueSizeNotSupported
}
return v, nil
}
func (e *baseEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
switch opt {
case tcpip.ReceiveQueueSizeOption:
@@ -879,19 +899,6 @@ func (e *baseEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
}
return int(v), nil
case tcpip.SendBufferSizeOption:
e.Lock()
if !e.Connected() {
e.Unlock()
return -1, tcpip.ErrNotConnected
}
v := e.connected.SendMaxQueueSize()
e.Unlock()
if v < 0 {
return -1, tcpip.ErrQueueSizeNotSupported
}
return int(v), nil
case tcpip.ReceiveBufferSizeOption:
e.Lock()
if e.receiver == nil {
+78 -1
View File
@@ -15,11 +15,16 @@
package tcpip
import (
"math"
"sync/atomic"
"gvisor.dev/gvisor/pkg/sync"
)
// PacketOverheadFactor is used to multiply the value provided by the user on a
// SetSockOpt for setting the send/receive buffer sizes sockets.
const PacketOverheadFactor = 2
// SocketOptionsHandler holds methods that help define endpoint specific
// behavior for socket level socket options. These must be implemented by
// endpoints to get notified when socket level options are set.
@@ -48,6 +53,12 @@ type SocketOptionsHandler interface {
// HasNIC is invoked to check if the NIC is valid for SO_BINDTODEVICE.
HasNIC(v int32) bool
// GetSendBufferSize is invoked to get the SO_SNDBUFSIZE.
GetSendBufferSize() (int64, *Error)
// IsUnixSocket is invoked to check if the socket is of unix domain.
IsUnixSocket() bool
}
// DefaultSocketOptionsHandler is an embeddable type that implements no-op
@@ -84,6 +95,27 @@ func (*DefaultSocketOptionsHandler) HasNIC(int32) bool {
return false
}
// GetSendBufferSize implements SocketOptionsHandler.GetSendBufferSize.
func (*DefaultSocketOptionsHandler) GetSendBufferSize() (int64, *Error) {
return 0, nil
}
// IsUnixSocket implements SocketOptionsHandler.IsUnixSocket.
func (*DefaultSocketOptionsHandler) IsUnixSocket() bool {
return false
}
// StackHandler holds methods to access the stack options. These must be
// implemented by the stack.
type StackHandler interface {
// Option allows retrieving stack wide options.
Option(option interface{}) *Error
// TransportProtocolOption allows retrieving individual protocol level
// option values.
TransportProtocolOption(proto TransportProtocolNumber, option GettableTransportProtocolOption) *Error
}
// SocketOptions contains all the variables which store values for SOL_SOCKET,
// SOL_IP, SOL_IPV6 and SOL_TCP level options.
//
@@ -91,6 +123,9 @@ func (*DefaultSocketOptionsHandler) HasNIC(int32) bool {
type SocketOptions struct {
handler SocketOptionsHandler
// StackHandler is initialized at the creation time and will not change.
stackHandler StackHandler `state:"manual"`
// These fields are accessed and modified using atomic operations.
// broadcastEnabled determines whether datagram sockets are allowed to
@@ -170,6 +205,9 @@ type SocketOptions struct {
// bindToDevice determines the device to which the socket is bound.
bindToDevice int32
// sendBufferSize determines the send buffer size for this socket.
sendBufferSize int64
// mu protects the access to the below fields.
mu sync.Mutex `state:"nosave"`
@@ -180,8 +218,9 @@ type SocketOptions struct {
// InitHandler initializes the handler. This must be called before using the
// socket options utility.
func (so *SocketOptions) InitHandler(handler SocketOptionsHandler) {
func (so *SocketOptions) InitHandler(handler SocketOptionsHandler, stack StackHandler) {
so.handler = handler
so.stackHandler = stack
}
func storeAtomicBool(addr *uint32, v bool) {
@@ -518,3 +557,41 @@ func (so *SocketOptions) SetBindToDevice(bindToDevice int32) *Error {
atomic.StoreInt32(&so.bindToDevice, bindToDevice)
return nil
}
// GetSendBufferSize gets value for SO_SNDBUF option.
func (so *SocketOptions) GetSendBufferSize() (int64, *Error) {
if so.handler.IsUnixSocket() {
return so.handler.GetSendBufferSize()
}
return atomic.LoadInt64(&so.sendBufferSize), nil
}
// SetSendBufferSize sets value for SO_SNDBUF option. notify indicates if the
// stack handler should be invoked to set the send buffer size.
func (so *SocketOptions) SetSendBufferSize(sendBufferSize int64, notify bool, getBufferLimits GetSendBufferLimits) {
v := sendBufferSize
ss := getBufferLimits(so.stackHandler)
if notify {
// TODO(b/176170271): Notify waiters after size has grown.
// Make sure the send buffer size is within the min and max
// allowed.
min := int64(ss.Min)
max := int64(ss.Max)
// Validate the send buffer size with min and max values.
// Multiply it by factor of 2.
if v > max {
v = max
}
if v < math.MaxInt32/PacketOverheadFactor {
v *= PacketOverheadFactor
if v < min {
v = min
}
} else {
v = math.MaxInt32
}
}
atomic.StoreInt64(&so.sendBufferSize, v)
}
+2 -2
View File
@@ -444,7 +444,7 @@ type Stack struct {
// sendBufferSize holds the min/default/max send buffer sizes for
// endpoints other than TCP.
sendBufferSize SendBufferSizeOption
sendBufferSize tcpip.SendBufferSizeOption
// receiveBufferSize holds the min/default/max receive buffer sizes for
// endpoints other than TCP.
@@ -646,7 +646,7 @@ func New(opts Options) *Stack {
uniqueIDGenerator: opts.UniqueID,
nudDisp: opts.NUDDisp,
randomGenerator: mathrand.New(randSrc),
sendBufferSize: SendBufferSizeOption{
sendBufferSize: tcpip.SendBufferSizeOption{
Min: MinBufferSize,
Default: DefaultBufferSize,
Max: DefaultMaxBufferSize,
+5 -11
View File
@@ -14,7 +14,9 @@
package stack
import "gvisor.dev/gvisor/pkg/tcpip"
import (
"gvisor.dev/gvisor/pkg/tcpip"
)
const (
// MinBufferSize is the smallest size of a receive or send buffer.
@@ -29,14 +31,6 @@ const (
DefaultMaxBufferSize = 4 << 20 // 4 MiB
)
// SendBufferSizeOption is used by stack.(Stack*).Option/SetOption to
// get/set the default, min and max send buffer sizes.
type SendBufferSizeOption struct {
Min int
Default int
Max int
}
// ReceiveBufferSizeOption is used by stack.(Stack*).Option/SetOption to
// get/set the default, min and max receive buffer sizes.
type ReceiveBufferSizeOption struct {
@@ -48,7 +42,7 @@ type ReceiveBufferSizeOption struct {
// SetOption allows setting stack wide options.
func (s *Stack) SetOption(option interface{}) *tcpip.Error {
switch v := option.(type) {
case SendBufferSizeOption:
case tcpip.SendBufferSizeOption:
// Make sure we don't allow lowering the buffer below minimum
// required for stack to work.
if v.Min < MinBufferSize {
@@ -88,7 +82,7 @@ func (s *Stack) SetOption(option interface{}) *tcpip.Error {
// Option allows retrieving stack wide options.
func (s *Stack) Option(option interface{}) *tcpip.Error {
switch v := option.(type) {
case *SendBufferSizeOption:
case *tcpip.SendBufferSizeOption:
s.mu.RLock()
*v = s.sendBufferSize
s.mu.RUnlock()
+11 -11
View File
@@ -3336,21 +3336,21 @@ func TestStackSendBufferSizeOption(t *testing.T) {
const sMin = stack.MinBufferSize
testCases := []struct {
name string
ss stack.SendBufferSizeOption
ss tcpip.SendBufferSizeOption
err *tcpip.Error
}{
// Invalid configurations.
{"min_below_zero", stack.SendBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
{"min_zero", stack.SendBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
{"default_below_min", stack.SendBufferSizeOption{Min: 0, Default: sMin - 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
{"default_above_max", stack.SendBufferSizeOption{Min: 0, Default: sMin + 1, Max: sMin}, tcpip.ErrInvalidOptionValue},
{"max_below_min", stack.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
{"min_below_zero", tcpip.SendBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
{"min_zero", tcpip.SendBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, tcpip.ErrInvalidOptionValue},
{"default_below_min", tcpip.SendBufferSizeOption{Min: 0, Default: sMin - 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
{"default_above_max", tcpip.SendBufferSizeOption{Min: 0, Default: sMin + 1, Max: sMin}, tcpip.ErrInvalidOptionValue},
{"max_below_min", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, tcpip.ErrInvalidOptionValue},
// Valid Configurations
{"in_ascending_order", stack.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 2}, nil},
{"all_equal", stack.SendBufferSizeOption{Min: sMin, Default: sMin, Max: sMin}, nil},
{"min_default_equal", stack.SendBufferSizeOption{Min: sMin, Default: sMin, Max: sMin + 1}, nil},
{"default_max_equal", stack.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 1}, nil},
{"in_ascending_order", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 2}, nil},
{"all_equal", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin, Max: sMin}, nil},
{"min_default_equal", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin, Max: sMin + 1}, nil},
{"default_max_equal", tcpip.SendBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 1}, nil},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
@@ -3359,7 +3359,7 @@ func TestStackSendBufferSizeOption(t *testing.T) {
if err := s.SetOption(tc.ss); err != tc.err {
t.Fatalf("s.SetOption(%+v) = %v, want: %v", tc.ss, err, tc.err)
}
var ss stack.SendBufferSizeOption
var ss tcpip.SendBufferSizeOption
if tc.err == nil {
if err := s.Option(&ss); err != nil {
t.Fatalf("s.Option(%+v) = %v, want: nil", ss, err)
+5 -5
View File
@@ -68,9 +68,9 @@ func (f *fakeTransportEndpoint) SocketOptions() *tcpip.SocketOptions {
return &f.ops
}
func newFakeTransportEndpoint(proto *fakeTransportProtocol, netProto tcpip.NetworkProtocolNumber, uniqueID uint64) tcpip.Endpoint {
ep := &fakeTransportEndpoint{TransportEndpointInfo: stack.TransportEndpointInfo{NetProto: netProto}, proto: proto, uniqueID: uniqueID}
ep.ops.InitHandler(ep)
func newFakeTransportEndpoint(proto *fakeTransportProtocol, netProto tcpip.NetworkProtocolNumber, s *stack.Stack) tcpip.Endpoint {
ep := &fakeTransportEndpoint{TransportEndpointInfo: stack.TransportEndpointInfo{NetProto: netProto}, proto: proto, uniqueID: s.UniqueID()}
ep.ops.InitHandler(ep, s)
return ep
}
@@ -234,7 +234,7 @@ func (f *fakeTransportEndpoint) HandlePacket(id stack.TransportEndpointID, pkt *
peerAddr: route.RemoteAddress,
route: route,
}
ep.ops.InitHandler(ep)
ep.ops.InitHandler(ep, f.proto.stack)
f.acceptQueue = append(f.acceptQueue, ep)
}
@@ -282,7 +282,7 @@ func (*fakeTransportProtocol) Number() tcpip.TransportProtocolNumber {
}
func (f *fakeTransportProtocol) NewEndpoint(netProto tcpip.NetworkProtocolNumber, _ *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
return newFakeTransportEndpoint(f, netProto, f.stack.UniqueID()), nil
return newFakeTransportEndpoint(f, netProto, f.stack), nil
}
func (*fakeTransportProtocol) NewRawEndpoint(tcpip.NetworkProtocolNumber, *waiter.Queue) (tcpip.Endpoint, *tcpip.Error) {
+25 -4
View File
@@ -826,10 +826,6 @@ const (
// number of unread bytes in the input buffer should be returned.
ReceiveQueueSizeOption
// SendBufferSizeOption is used by SetSockOptInt/GetSockOptInt to
// specify the send buffer size option.
SendBufferSizeOption
// ReceiveBufferSizeOption is used by SetSockOptInt/GetSockOptInt to
// specify the receive buffer size option.
ReceiveBufferSizeOption
@@ -1234,6 +1230,31 @@ type IPPacketInfo struct {
DestinationAddr Address
}
// SendBufferSizeOption is used by stack.(Stack*).Option/SetOption to
// get/set the default, min and max send buffer sizes.
type SendBufferSizeOption struct {
// Min is the minimum size for send buffer.
Min int
// Default is the default size for send buffer.
Default int
// Max is the maximum size for send buffer.
Max int
}
// GetSendBufferLimits is used to get the send buffer size limits.
type GetSendBufferLimits func(StackHandler) SendBufferSizeOption
// GetStackSendBufferLimits is used to get default, min and max send buffer size.
func GetStackSendBufferLimits(so StackHandler) SendBufferSizeOption {
var ss SendBufferSizeOption
if err := so.Option(&ss); err != nil {
panic(fmt.Sprintf("s.Option(%#v) = %s", ss, err))
}
return ss
}
// Route is a row in the routing table. It specifies through which NIC (and
// gateway) sets of packets should be routed. A row is considered viable if the
// masked target address matches the destination address in the row.
+9 -9
View File
@@ -69,8 +69,7 @@ type endpoint struct {
rcvClosed bool
// The following fields are protected by the mu mutex.
mu sync.RWMutex `state:"nosave"`
sndBufSize int
mu sync.RWMutex `state:"nosave"`
// shutdownFlags represent the current shutdown state of the endpoint.
shutdownFlags tcpip.ShutdownFlags
state endpointState
@@ -94,11 +93,17 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt
},
waiterQueue: waiterQueue,
rcvBufSizeMax: 32 * 1024,
sndBufSize: 32 * 1024,
state: stateInitial,
uniqueID: s.UniqueID(),
}
ep.ops.InitHandler(ep)
ep.ops.InitHandler(ep, ep.stack)
ep.ops.SetSendBufferSize(32*1024, false /* notify */, tcpip.GetStackSendBufferLimits)
// Override with stack defaults.
var ss tcpip.SendBufferSizeOption
if err := s.Option(&ss); err == nil {
ep.ops.SetSendBufferSize(int64(ss.Default), false /* notify */, tcpip.GetStackSendBufferLimits)
}
return ep, nil
}
@@ -363,11 +368,6 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
}
e.rcvMu.Unlock()
return v, nil
case tcpip.SendBufferSizeOption:
e.mu.Lock()
v := e.sndBufSize
e.mu.Unlock()
return v, nil
case tcpip.ReceiveBufferSizeOption:
e.rcvMu.Lock()
@@ -69,6 +69,7 @@ func (e *endpoint) afterLoad() {
// Resume implements tcpip.ResumableEndpoint.Resume.
func (e *endpoint) Resume(s *stack.Stack) {
e.stack = s
e.ops.InitHandler(e, e.stack)
if e.state != stateBound && e.state != stateConnected {
return
+8 -35
View File
@@ -79,13 +79,11 @@ type endpoint struct {
rcvClosed bool
// The following fields are protected by mu.
mu sync.RWMutex `state:"nosave"`
sndBufSize int
sndBufSizeMax int
closed bool
stats tcpip.TransportEndpointStats `state:"nosave"`
bound bool
boundNIC tcpip.NICID
mu sync.RWMutex `state:"nosave"`
closed bool
stats tcpip.TransportEndpointStats `state:"nosave"`
bound bool
boundNIC tcpip.NICID
// lastErrorMu protects lastError.
lastErrorMu sync.Mutex `state:"nosave"`
@@ -106,14 +104,13 @@ func NewEndpoint(s *stack.Stack, cooked bool, netProto tcpip.NetworkProtocolNumb
netProto: netProto,
waiterQueue: waiterQueue,
rcvBufSizeMax: 32 * 1024,
sndBufSize: 32 * 1024,
}
ep.ops.InitHandler(ep)
ep.ops.InitHandler(ep, ep.stack)
// Override with stack defaults.
var ss stack.SendBufferSizeOption
var ss tcpip.SendBufferSizeOption
if err := s.Option(&ss); err == nil {
ep.sndBufSizeMax = ss.Default
ep.ops.SetSendBufferSize(int64(ss.Default), false /* notify */, tcpip.GetStackSendBufferLimits)
}
var rs stack.ReceiveBufferSizeOption
@@ -320,24 +317,6 @@ func (ep *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
// SetSockOptInt implements tcpip.Endpoint.SetSockOptInt.
func (ep *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
switch opt {
case tcpip.SendBufferSizeOption:
// Make sure the send buffer size is within the min and max
// allowed.
var ss stack.SendBufferSizeOption
if err := ep.stack.Option(&ss); err != nil {
panic(fmt.Sprintf("s.Option(%#v) = %s", ss, err))
}
if v > ss.Max {
v = ss.Max
}
if v < ss.Min {
v = ss.Min
}
ep.mu.Lock()
ep.sndBufSizeMax = v
ep.mu.Unlock()
return nil
case tcpip.ReceiveBufferSizeOption:
// Make sure the receive buffer size is within the min and max
// allowed.
@@ -395,12 +374,6 @@ func (ep *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
ep.rcvMu.Unlock()
return v, nil
case tcpip.SendBufferSizeOption:
ep.mu.Lock()
v := ep.sndBufSizeMax
ep.mu.Unlock()
return v, nil
case tcpip.ReceiveBufferSizeOption:
ep.rcvMu.Lock()
v := ep.rcvBufSizeMax
+1 -1
View File
@@ -63,8 +63,8 @@ func (ep *endpoint) loadRcvBufSizeMax(max int) {
// afterLoad is invoked by stateify.
func (ep *endpoint) afterLoad() {
// StackFromEnv is a stack used specifically for save/restore.
ep.stack = stack.StackFromEnv
ep.ops.InitHandler(ep, ep.stack)
// TODO(gvisor.dev/173): Once bind is supported, choose the right NIC.
if err := ep.stack.RegisterPacketEndpoint(0, ep.netProto, ep); err != nil {
+8 -34
View File
@@ -76,12 +76,10 @@ type endpoint struct {
rcvClosed bool
// The following fields are protected by mu.
mu sync.RWMutex `state:"nosave"`
sndBufSize int
sndBufSizeMax int
closed bool
connected bool
bound bool
mu sync.RWMutex `state:"nosave"`
closed bool
connected bool
bound bool
// route is the route to a remote network endpoint. It is set via
// Connect(), and is valid only when conneted is true.
route *stack.Route `state:"manual"`
@@ -112,16 +110,16 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt
},
waiterQueue: waiterQueue,
rcvBufSizeMax: 32 * 1024,
sndBufSizeMax: 32 * 1024,
associated: associated,
}
e.ops.InitHandler(e)
e.ops.InitHandler(e, e.stack)
e.ops.SetHeaderIncluded(!associated)
e.ops.SetSendBufferSize(32*1024, false /* notify */, tcpip.GetStackSendBufferLimits)
// Override with stack defaults.
var ss stack.SendBufferSizeOption
var ss tcpip.SendBufferSizeOption
if err := s.Option(&ss); err == nil {
e.sndBufSizeMax = ss.Default
e.ops.SetSendBufferSize(int64(ss.Default), false /* notify */, tcpip.GetStackSendBufferLimits)
}
var rs stack.ReceiveBufferSizeOption
@@ -511,24 +509,6 @@ func (e *endpoint) SetSockOpt(opt tcpip.SettableSocketOption) *tcpip.Error {
// SetSockOptInt implements tcpip.Endpoint.SetSockOptInt.
func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
switch opt {
case tcpip.SendBufferSizeOption:
// Make sure the send buffer size is within the min and max
// allowed.
var ss stack.SendBufferSizeOption
if err := e.stack.Option(&ss); err != nil {
panic(fmt.Sprintf("s.Option(%#v) = %s", ss, err))
}
if v > ss.Max {
v = ss.Max
}
if v < ss.Min {
v = ss.Min
}
e.mu.Lock()
e.sndBufSizeMax = v
e.mu.Unlock()
return nil
case tcpip.ReceiveBufferSizeOption:
// Make sure the receive buffer size is within the min and max
// allowed.
@@ -570,12 +550,6 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
e.rcvMu.Unlock()
return v, nil
case tcpip.SendBufferSizeOption:
e.mu.Lock()
v := e.sndBufSizeMax
e.mu.Unlock()
return v, nil
case tcpip.ReceiveBufferSizeOption:
e.rcvMu.Lock()
v := e.rcvBufSizeMax
@@ -69,6 +69,7 @@ func (e *endpoint) afterLoad() {
// Resume implements tcpip.ResumableEndpoint.Resume.
func (e *endpoint) Resume(s *stack.Stack) {
e.stack = s
e.ops.InitHandler(e, e.stack)
// If the endpoint is connected, re-connect.
if e.connected {
+35 -41
View File
@@ -557,7 +557,6 @@ type endpoint struct {
// When the send side is closed, the protocol goroutine is notified via
// sndCloseWaker, and sndClosed is set to true.
sndBufMu sync.Mutex `state:"nosave"`
sndBufSize int
sndBufUsed int
sndClosed bool
sndBufInQueue seqnum.Size
@@ -869,7 +868,6 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
waiterQueue: waiterQueue,
state: StateInitial,
rcvBufSize: DefaultReceiveBufferSize,
sndBufSize: DefaultSendBufferSize,
sndMTU: int(math.MaxInt32),
keepalive: keepalive{
// Linux defaults.
@@ -882,13 +880,14 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
windowClamp: DefaultReceiveBufferSize,
maxSynRetries: DefaultSynRetries,
}
e.ops.InitHandler(e)
e.ops.InitHandler(e, e.stack)
e.ops.SetMulticastLoop(true)
e.ops.SetQuickAck(true)
e.ops.SetSendBufferSize(DefaultSendBufferSize, false /* notify */, GetTCPSendBufferLimits)
var ss tcpip.TCPSendBufferSizeRangeOption
if err := s.TransportProtocolOption(ProtocolNumber, &ss); err == nil {
e.sndBufSize = ss.Default
e.ops.SetSendBufferSize(int64(ss.Default), false /* notify */, GetTCPSendBufferLimits)
}
var rs tcpip.TCPReceiveBufferSizeRangeOption
@@ -967,7 +966,8 @@ func (e *endpoint) Readiness(mask waiter.EventMask) waiter.EventMask {
// Determine if the endpoint is writable if requested.
if (mask & waiter.EventOut) != 0 {
e.sndBufMu.Lock()
if e.sndClosed || e.sndBufUsed < e.sndBufSize {
sndBufSize := e.getSendBufferSize()
if e.sndClosed || e.sndBufUsed < sndBufSize {
result |= waiter.EventOut
}
e.sndBufMu.Unlock()
@@ -1499,7 +1499,8 @@ func (e *endpoint) isEndpointWritableLocked() (int, *tcpip.Error) {
return 0, tcpip.ErrClosedForSend
}
avail := e.sndBufSize - e.sndBufUsed
sndBufSize := e.getSendBufferSize()
avail := sndBufSize - e.sndBufUsed
if avail <= 0 {
return 0, tcpip.ErrWouldBlock
}
@@ -1692,6 +1693,14 @@ func (e *endpoint) OnCorkOptionSet(v bool) {
}
}
func (e *endpoint) getSendBufferSize() int {
sndBufSize, err := e.ops.GetSendBufferSize()
if err != nil {
panic(fmt.Sprintf("e.ops.GetSendBufferSize() = %s", err))
}
return int(sndBufSize)
}
// SetSockOptInt sets a socket option.
func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
// Lower 2 bits represents ECN bits. RFC 3168, section 23.1
@@ -1785,31 +1794,6 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
e.rcvListMu.Unlock()
e.UnlockUser()
case tcpip.SendBufferSizeOption:
// Make sure the send buffer size is within the min and max
// allowed.
var ss tcpip.TCPSendBufferSizeRangeOption
if err := e.stack.TransportProtocolOption(ProtocolNumber, &ss); err != nil {
panic(fmt.Sprintf("e.stack.TransportProtocolOption(%d, %#v) = %s", ProtocolNumber, &ss, err))
}
if v > ss.Max {
v = ss.Max
}
if v < math.MaxInt32/SegOverheadFactor {
v *= SegOverheadFactor
if v < ss.Min {
v = ss.Min
}
} else {
v = math.MaxInt32
}
e.sndBufMu.Lock()
e.sndBufSize = v
e.sndBufMu.Unlock()
case tcpip.TTLOption:
e.LockUser()
e.ttl = uint8(v)
@@ -1995,12 +1979,6 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
case tcpip.ReceiveQueueSizeOption:
return e.readyReceiveSize()
case tcpip.SendBufferSizeOption:
e.sndBufMu.Lock()
v := e.sndBufSize
e.sndBufMu.Unlock()
return v, nil
case tcpip.ReceiveBufferSizeOption:
e.rcvListMu.Lock()
v := e.rcvBufSize
@@ -2749,13 +2727,14 @@ func (e *endpoint) HandleControlPacket(typ stack.ControlType, extra uint32, pkt
// updateSndBufferUsage is called by the protocol goroutine when room opens up
// in the send buffer. The number of newly available bytes is v.
func (e *endpoint) updateSndBufferUsage(v int) {
sendBufferSize := e.getSendBufferSize()
e.sndBufMu.Lock()
notify := e.sndBufUsed >= e.sndBufSize>>1
notify := e.sndBufUsed >= sendBufferSize>>1
e.sndBufUsed -= v
// We only notify when there is half the sndBufSize available after
// We only notify when there is half the sendBufferSize available after
// a full buffer event occurs. This ensures that we don't wake up
// writers to queue just 1-2 segments and go back to sleep.
notify = notify && e.sndBufUsed < e.sndBufSize>>1
notify = notify && e.sndBufUsed < int(sendBufferSize)>>1
e.sndBufMu.Unlock()
if notify {
@@ -2967,8 +2946,9 @@ func (e *endpoint) completeState() stack.TCPEndpointState {
s.SACK.ReceivedBlocks, s.SACK.MaxSACKED = e.scoreboard.Copy()
// Copy endpoint send state.
sndBufSize := e.getSendBufferSize()
e.sndBufMu.Lock()
s.SndBufSize = e.sndBufSize
s.SndBufSize = sndBufSize
s.SndBufUsed = e.sndBufUsed
s.SndClosed = e.sndClosed
s.SndBufInQueue = e.sndBufInQueue
@@ -3113,3 +3093,17 @@ func (e *endpoint) Wait() {
func (e *endpoint) SocketOptions() *tcpip.SocketOptions {
return &e.ops
}
// GetTCPSendBufferLimits is used to get send buffer size limits for TCP.
func GetTCPSendBufferLimits(s tcpip.StackHandler) tcpip.SendBufferSizeOption {
var ss tcpip.TCPSendBufferSizeRangeOption
if err := s.TransportProtocolOption(header.TCPProtocolNumber, &ss); err != nil {
panic(fmt.Sprintf("s.TransportProtocolOption(%d, %#v) = %s", header.TCPProtocolNumber, ss, err))
}
return tcpip.SendBufferSizeOption{
Min: ss.Min,
Default: ss.Default,
Max: ss.Max,
}
}
+4 -2
View File
@@ -179,14 +179,16 @@ func (e *endpoint) afterLoad() {
// Resume implements tcpip.ResumableEndpoint.Resume.
func (e *endpoint) Resume(s *stack.Stack) {
e.stack = s
e.ops.InitHandler(e, e.stack)
e.segmentQueue.thaw()
epState := e.origEndpointState
switch epState {
case StateInitial, StateBound, StateListen, StateConnecting, StateEstablished:
var ss tcpip.TCPSendBufferSizeRangeOption
if err := e.stack.TransportProtocolOption(ProtocolNumber, &ss); err == nil {
if e.sndBufSize < ss.Min || e.sndBufSize > ss.Max {
panic(fmt.Sprintf("endpoint.sndBufSize %d is outside the min and max allowed [%d, %d]", e.sndBufSize, ss.Min, ss.Max))
sendBufferSize := e.getSendBufferSize()
if sendBufferSize < ss.Min || sendBufferSize > ss.Max {
panic(fmt.Sprintf("endpoint sendBufferSize %d is outside the min and max allowed [%d, %d]", sendBufferSize, ss.Min, ss.Max))
}
}
+4 -8
View File
@@ -4365,9 +4365,9 @@ func checkRecvBufferSize(t *testing.T, ep tcpip.Endpoint, v int) {
func checkSendBufferSize(t *testing.T, ep tcpip.Endpoint, v int) {
t.Helper()
s, err := ep.GetSockOptInt(tcpip.SendBufferSizeOption)
s, err := ep.SocketOptions().GetSendBufferSize()
if err != nil {
t.Fatalf("GetSockOpt failed: %s", err)
t.Fatalf("GetSendBufferSize failed: %s", err)
}
if int(s) != v {
@@ -4473,9 +4473,7 @@ func TestMinMaxBufferSizes(t *testing.T) {
checkRecvBufferSize(t, ep, 200)
if err := ep.SetSockOptInt(tcpip.SendBufferSizeOption, 149); err != nil {
t.Fatalf("SetSockOptInt(SendBufferSizeOption, 299) failed: %s", err)
}
ep.SocketOptions().SetSendBufferSize(149, true, tcp.GetTCPSendBufferLimits)
checkSendBufferSize(t, ep, 300)
@@ -4487,9 +4485,7 @@ func TestMinMaxBufferSizes(t *testing.T) {
// Values above max are capped at max and then doubled.
checkRecvBufferSize(t, ep, tcp.DefaultReceiveBufferSize*20*2)
if err := ep.SetSockOptInt(tcpip.SendBufferSizeOption, 1+tcp.DefaultSendBufferSize*30); err != nil {
t.Fatalf("SetSockOptInt(SendBufferSizeOption) failed: %s", err)
}
ep.SocketOptions().SetSendBufferSize(1+tcp.DefaultSendBufferSize*30, true, tcp.GetTCPSendBufferLimits)
// Values above max are capped at max and then doubled.
checkSendBufferSize(t, ep, tcp.DefaultSendBufferSize*30*2)
+5 -32
View File
@@ -97,9 +97,7 @@ type endpoint struct {
rcvClosed bool
// The following fields are protected by the mu mutex.
mu sync.RWMutex `state:"nosave"`
sndBufSize int
sndBufSizeMax int
mu sync.RWMutex `state:"nosave"`
// state must be read/set using the EndpointState()/setEndpointState()
// methods.
state EndpointState
@@ -176,18 +174,18 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
// Linux defaults to TTL=1.
multicastTTL: 1,
rcvBufSizeMax: 32 * 1024,
sndBufSizeMax: 32 * 1024,
multicastMemberships: make(map[multicastMembership]struct{}),
state: StateInitial,
uniqueID: s.UniqueID(),
}
e.ops.InitHandler(e)
e.ops.InitHandler(e, e.stack)
e.ops.SetMulticastLoop(true)
e.ops.SetSendBufferSize(32*1024, false /* notify */, tcpip.GetStackSendBufferLimits)
// Override with stack defaults.
var ss stack.SendBufferSizeOption
var ss tcpip.SendBufferSizeOption
if err := s.Option(&ss); err == nil {
e.sndBufSizeMax = ss.Default
e.ops.SetSendBufferSize(int64(ss.Default), false /* notify */, tcpip.GetStackSendBufferLimits)
}
var rs stack.ReceiveBufferSizeOption
@@ -632,25 +630,6 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
e.rcvBufSizeMax = v
e.mu.Unlock()
return nil
case tcpip.SendBufferSizeOption:
// Make sure the send buffer size is within the min and max
// allowed.
var ss stack.SendBufferSizeOption
if err := e.stack.Option(&ss); err != nil {
panic(fmt.Sprintf("e.stack.Option(%#v) = %s", ss, err))
}
if v < ss.Min {
v = ss.Min
}
if v > ss.Max {
v = ss.Max
}
e.mu.Lock()
e.sndBufSizeMax = v
e.mu.Unlock()
return nil
}
return nil
@@ -811,12 +790,6 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
e.rcvMu.Unlock()
return v, nil
case tcpip.SendBufferSizeOption:
e.mu.Lock()
v := e.sndBufSizeMax
e.mu.Unlock()
return v, nil
case tcpip.ReceiveBufferSizeOption:
e.rcvMu.Lock()
v := e.rcvBufSizeMax

Some files were not shown because too many files have changed in this diff Show More