mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Move SO_RCVBUF to socketops.
Fixes #2926, #674 PiperOrigin-RevId: 369457123
This commit is contained in:
committed by
gVisor bot
parent
2c8379d957
commit
3fff4c4a0f
@@ -384,8 +384,16 @@ func (c *ConnectedEndpoint) CloseUnread() {}
|
||||
|
||||
// SetSendBufferSize implements transport.ConnectedEndpoint.SetSendBufferSize.
|
||||
func (c *ConnectedEndpoint) SetSendBufferSize(v int64) (newSz int64) {
|
||||
// gVisor does not permit setting of SO_SNDBUF for host backed unix domain
|
||||
// sockets.
|
||||
// gVisor does not permit setting of SO_SNDBUF for host backed unix
|
||||
// domain sockets.
|
||||
return atomic.LoadInt64(&c.sndbuf)
|
||||
}
|
||||
|
||||
// SetReceiveBufferSize implements transport.ConnectedEndpoint.SetReceiveBufferSize.
|
||||
func (c *ConnectedEndpoint) SetReceiveBufferSize(v int64) (newSz int64) {
|
||||
// gVisor does not permit setting of SO_RCVBUF for host backed unix
|
||||
// domain sockets. Receive buffer does not have any effect for unix
|
||||
// sockets and we claim to be the same as send buffer.
|
||||
return atomic.LoadInt64(&c.sndbuf)
|
||||
}
|
||||
|
||||
|
||||
@@ -333,8 +333,16 @@ func (c *ConnectedEndpoint) CloseUnread() {}
|
||||
|
||||
// SetSendBufferSize implements transport.ConnectedEndpoint.SetSendBufferSize.
|
||||
func (c *ConnectedEndpoint) SetSendBufferSize(v int64) (newSz int64) {
|
||||
// gVisor does not permit setting of SO_SNDBUF for host backed unix domain
|
||||
// sockets.
|
||||
// gVisor does not permit setting of SO_SNDBUF for host backed unix
|
||||
// domain sockets.
|
||||
return atomic.LoadInt64(&c.sndbuf)
|
||||
}
|
||||
|
||||
// SetReceiveBufferSize implements transport.ConnectedEndpoint.SetReceiveBufferSize.
|
||||
func (c *ConnectedEndpoint) SetReceiveBufferSize(v int64) (newSz int64) {
|
||||
// gVisor does not permit setting of SO_RCVBUF for host backed unix
|
||||
// domain sockets. Receive buffer does not have any effect for unix
|
||||
// sockets and we claim to be the same as send buffer.
|
||||
return atomic.LoadInt64(&c.sndbuf)
|
||||
}
|
||||
|
||||
|
||||
@@ -886,10 +886,7 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
|
||||
return nil, syserr.ErrInvalidArgument
|
||||
}
|
||||
|
||||
size, err := ep.GetSockOptInt(tcpip.ReceiveBufferSizeOption)
|
||||
if err != nil {
|
||||
return nil, syserr.TranslateNetstackError(err)
|
||||
}
|
||||
size := ep.SocketOptions().GetReceiveBufferSize()
|
||||
|
||||
if size > math.MaxInt32 {
|
||||
size = math.MaxInt32
|
||||
@@ -1662,7 +1659,7 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
|
||||
}
|
||||
|
||||
v := hostarch.ByteOrder.Uint32(optVal)
|
||||
ep.SocketOptions().SetSendBufferSize(int64(v), true)
|
||||
ep.SocketOptions().SetSendBufferSize(int64(v), true /* notify */)
|
||||
return nil
|
||||
|
||||
case linux.SO_RCVBUF:
|
||||
@@ -1671,7 +1668,8 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
|
||||
}
|
||||
|
||||
v := hostarch.ByteOrder.Uint32(optVal)
|
||||
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.ReceiveBufferSizeOption, int(v)))
|
||||
ep.SocketOptions().SetReceiveBufferSize(int64(v), true /* notify */)
|
||||
return nil
|
||||
|
||||
case linux.SO_REUSEADDR:
|
||||
if len(optVal) < sizeOfInt32 {
|
||||
|
||||
@@ -130,7 +130,8 @@ func newConnectioned(ctx context.Context, stype linux.SockType, uid UniqueIDProv
|
||||
}
|
||||
|
||||
ep.ops.SetSendBufferSize(defaultBufferSize, false /* notify */)
|
||||
ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits)
|
||||
ep.ops.SetReceiveBufferSize(defaultBufferSize, false /* notify */)
|
||||
ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
|
||||
return ep
|
||||
}
|
||||
|
||||
@@ -175,8 +176,9 @@ func NewExternal(ctx context.Context, stype linux.SockType, uid UniqueIDProvider
|
||||
idGenerator: uid,
|
||||
stype: stype,
|
||||
}
|
||||
ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits)
|
||||
ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
|
||||
ep.ops.SetSendBufferSize(connected.SendMaxQueueSize(), false /* notify */)
|
||||
ep.ops.SetReceiveBufferSize(defaultBufferSize, false /* notify */)
|
||||
return ep
|
||||
}
|
||||
|
||||
@@ -299,8 +301,9 @@ func (e *connectionedEndpoint) BidirectionalConnect(ctx context.Context, ce Conn
|
||||
idGenerator: e.idGenerator,
|
||||
stype: e.stype,
|
||||
}
|
||||
ne.ops.InitHandler(ne, &stackHandler{}, getSendBufferLimits)
|
||||
ne.ops.InitHandler(ne, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
|
||||
ne.ops.SetSendBufferSize(defaultBufferSize, false /* notify */)
|
||||
ne.ops.SetReceiveBufferSize(defaultBufferSize, false /* notify */)
|
||||
|
||||
readQueue := &queue{ReaderQueue: ce.WaiterQueue(), WriterQueue: ne.Queue, limit: defaultBufferSize}
|
||||
readQueue.InitRefs()
|
||||
@@ -366,6 +369,7 @@ func (e *connectionedEndpoint) Connect(ctx context.Context, server BoundEndpoint
|
||||
// to reflect this endpoint's send buffer size.
|
||||
if bufSz := e.connected.SetSendBufferSize(e.ops.GetSendBufferSize()); bufSz != e.ops.GetSendBufferSize() {
|
||||
e.ops.SetSendBufferSize(bufSz, false /* notify */)
|
||||
e.ops.SetReceiveBufferSize(bufSz, false /* notify */)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -54,5 +54,5 @@ func (e *connectionedEndpoint) loadAcceptedChan(acceptedSlice []*connectionedEnd
|
||||
|
||||
// afterLoad is invoked by stateify.
|
||||
func (e *connectionedEndpoint) afterLoad() {
|
||||
e.ops.InitHandler(e, &stackHandler{}, getSendBufferLimits)
|
||||
e.ops.InitHandler(e, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ func NewConnectionless(ctx context.Context) Endpoint {
|
||||
q.InitRefs()
|
||||
ep.receiver = &queueReceiver{readQueue: &q}
|
||||
ep.ops.SetSendBufferSize(defaultBufferSize, false /* notify */)
|
||||
ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits)
|
||||
ep.ops.SetReceiveBufferSize(defaultBufferSize, false /* notify */)
|
||||
ep.ops.InitHandler(ep, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
|
||||
return ep
|
||||
}
|
||||
|
||||
|
||||
@@ -16,5 +16,5 @@ package transport
|
||||
|
||||
// afterLoad is invoked by stateify.
|
||||
func (e *connectionlessEndpoint) afterLoad() {
|
||||
e.ops.InitHandler(e, &stackHandler{}, getSendBufferLimits)
|
||||
e.ops.InitHandler(e, &stackHandler{}, getSendBufferLimits, getReceiveBufferLimits)
|
||||
}
|
||||
|
||||
@@ -868,11 +868,7 @@ func (e *baseEndpoint) SetSockOpt(opt tcpip.SettableSocketOption) tcpip.Error {
|
||||
}
|
||||
|
||||
func (e *baseEndpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) tcpip.Error {
|
||||
switch opt {
|
||||
case tcpip.ReceiveBufferSizeOption:
|
||||
default:
|
||||
log.Warningf("Unsupported socket option: %d", opt)
|
||||
}
|
||||
log.Warningf("Unsupported socket option: %d", opt)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -905,19 +901,6 @@ func (e *baseEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) {
|
||||
}
|
||||
return int(v), nil
|
||||
|
||||
case tcpip.ReceiveBufferSizeOption:
|
||||
e.Lock()
|
||||
if e.receiver == nil {
|
||||
e.Unlock()
|
||||
return -1, &tcpip.ErrNotConnected{}
|
||||
}
|
||||
v := e.receiver.RecvMaxQueueSize()
|
||||
e.Unlock()
|
||||
if v < 0 {
|
||||
return -1, &tcpip.ErrQueueSizeNotSupported{}
|
||||
}
|
||||
return int(v), nil
|
||||
|
||||
default:
|
||||
log.Warningf("Unsupported socket option: %d", opt)
|
||||
return -1, &tcpip.ErrUnknownProtocolOption{}
|
||||
@@ -1029,3 +1012,15 @@ func getSendBufferLimits(tcpip.StackHandler) tcpip.SendBufferSizeOption {
|
||||
Max: maxBufferSize,
|
||||
}
|
||||
}
|
||||
|
||||
// getReceiveBufferLimits implements tcpip.GetReceiveBufferLimits.
|
||||
//
|
||||
// We define min, max and default values for unix socket implementation. Unix
|
||||
// sockets do not use receive buffer.
|
||||
func getReceiveBufferLimits(tcpip.StackHandler) tcpip.ReceiveBufferSizeOption {
|
||||
return tcpip.ReceiveBufferSizeOption{
|
||||
Min: minimumBufferSize,
|
||||
Default: defaultBufferSize,
|
||||
Max: maxBufferSize,
|
||||
}
|
||||
}
|
||||
|
||||
+57
-1
@@ -58,6 +58,9 @@ type SocketOptionsHandler interface {
|
||||
// changed. The handler is invoked with the new value for the socket send
|
||||
// buffer size. It also returns the newly set value.
|
||||
OnSetSendBufferSize(v int64) (newSz int64)
|
||||
|
||||
// OnSetReceiveBufferSize is invoked to set the SO_RCVBUFSIZE.
|
||||
OnSetReceiveBufferSize(v, oldSz int64) (newSz int64)
|
||||
}
|
||||
|
||||
// DefaultSocketOptionsHandler is an embeddable type that implements no-op
|
||||
@@ -99,6 +102,11 @@ func (*DefaultSocketOptionsHandler) OnSetSendBufferSize(v int64) (newSz int64) {
|
||||
return v
|
||||
}
|
||||
|
||||
// OnSetReceiveBufferSize implements SocketOptionsHandler.OnSetReceiveBufferSize.
|
||||
func (*DefaultSocketOptionsHandler) OnSetReceiveBufferSize(v, oldSz int64) (newSz int64) {
|
||||
return v
|
||||
}
|
||||
|
||||
// StackHandler holds methods to access the stack options. These must be
|
||||
// implemented by the stack.
|
||||
type StackHandler interface {
|
||||
@@ -207,6 +215,14 @@ type SocketOptions struct {
|
||||
// sendBufferSize determines the send buffer size for this socket.
|
||||
sendBufferSize int64
|
||||
|
||||
// getReceiveBufferLimits provides the handler to get the min, default and
|
||||
// max size for receive buffer. It is initialized at the creation time and
|
||||
// will not change.
|
||||
getReceiveBufferLimits GetReceiveBufferLimits `state:"manual"`
|
||||
|
||||
// receiveBufferSize determines the receive buffer size for this socket.
|
||||
receiveBufferSize int64
|
||||
|
||||
// mu protects the access to the below fields.
|
||||
mu sync.Mutex `state:"nosave"`
|
||||
|
||||
@@ -217,10 +233,11 @@ type SocketOptions struct {
|
||||
|
||||
// InitHandler initializes the handler. This must be called before using the
|
||||
// socket options utility.
|
||||
func (so *SocketOptions) InitHandler(handler SocketOptionsHandler, stack StackHandler, getSendBufferLimits GetSendBufferLimits) {
|
||||
func (so *SocketOptions) InitHandler(handler SocketOptionsHandler, stack StackHandler, getSendBufferLimits GetSendBufferLimits, getReceiveBufferLimits GetReceiveBufferLimits) {
|
||||
so.handler = handler
|
||||
so.stackHandler = stack
|
||||
so.getSendBufferLimits = getSendBufferLimits
|
||||
so.getReceiveBufferLimits = getReceiveBufferLimits
|
||||
}
|
||||
|
||||
func storeAtomicBool(addr *uint32, v bool) {
|
||||
@@ -632,3 +649,42 @@ func (so *SocketOptions) SetSendBufferSize(sendBufferSize int64, notify bool) {
|
||||
newSz := so.handler.OnSetSendBufferSize(v)
|
||||
atomic.StoreInt64(&so.sendBufferSize, newSz)
|
||||
}
|
||||
|
||||
// GetReceiveBufferSize gets value for SO_RCVBUF option.
|
||||
func (so *SocketOptions) GetReceiveBufferSize() int64 {
|
||||
return atomic.LoadInt64(&so.receiveBufferSize)
|
||||
}
|
||||
|
||||
// SetReceiveBufferSize sets value for SO_RCVBUF option.
|
||||
func (so *SocketOptions) SetReceiveBufferSize(receiveBufferSize int64, notify bool) {
|
||||
if !notify {
|
||||
atomic.StoreInt64(&so.receiveBufferSize, receiveBufferSize)
|
||||
return
|
||||
}
|
||||
|
||||
// Make sure the send buffer size is within the min and max
|
||||
// allowed.
|
||||
v := receiveBufferSize
|
||||
ss := so.getReceiveBufferLimits(so.stackHandler)
|
||||
min := int64(ss.Min)
|
||||
max := int64(ss.Max)
|
||||
// Validate the send buffer size with min and max values.
|
||||
if v > max {
|
||||
v = max
|
||||
}
|
||||
|
||||
// Multiply it by factor of 2.
|
||||
if v < math.MaxInt32/PacketOverheadFactor {
|
||||
v *= PacketOverheadFactor
|
||||
if v < min {
|
||||
v = min
|
||||
}
|
||||
} else {
|
||||
v = math.MaxInt32
|
||||
}
|
||||
|
||||
oldSz := atomic.LoadInt64(&so.receiveBufferSize)
|
||||
// Notify endpoint about change in buffer size.
|
||||
newSz := so.handler.OnSetReceiveBufferSize(v, oldSz)
|
||||
atomic.StoreInt64(&so.receiveBufferSize, newSz)
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ type Stack struct {
|
||||
|
||||
// receiveBufferSize holds the min/default/max receive buffer sizes for
|
||||
// endpoints other than TCP.
|
||||
receiveBufferSize ReceiveBufferSizeOption
|
||||
receiveBufferSize tcpip.ReceiveBufferSizeOption
|
||||
|
||||
// tcpInvalidRateLimit is the maximal rate for sending duplicate
|
||||
// acknowledgements in response to incoming TCP packets that are for an existing
|
||||
@@ -368,7 +368,7 @@ func New(opts Options) *Stack {
|
||||
Default: DefaultBufferSize,
|
||||
Max: DefaultMaxBufferSize,
|
||||
},
|
||||
receiveBufferSize: ReceiveBufferSizeOption{
|
||||
receiveBufferSize: tcpip.ReceiveBufferSizeOption{
|
||||
Min: MinBufferSize,
|
||||
Default: DefaultBufferSize,
|
||||
Max: DefaultMaxBufferSize,
|
||||
|
||||
@@ -68,7 +68,7 @@ func (s *Stack) SetOption(option interface{}) tcpip.Error {
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
|
||||
case ReceiveBufferSizeOption:
|
||||
case tcpip.ReceiveBufferSizeOption:
|
||||
// Make sure we don't allow lowering the buffer below minimum
|
||||
// required for stack to work.
|
||||
if v.Min < MinBufferSize {
|
||||
@@ -107,7 +107,7 @@ func (s *Stack) Option(option interface{}) tcpip.Error {
|
||||
s.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
case *ReceiveBufferSizeOption:
|
||||
case *tcpip.ReceiveBufferSizeOption:
|
||||
s.mu.RLock()
|
||||
*v = s.receiveBufferSize
|
||||
s.mu.RUnlock()
|
||||
|
||||
@@ -3357,21 +3357,21 @@ func TestStackReceiveBufferSizeOption(t *testing.T) {
|
||||
const sMin = stack.MinBufferSize
|
||||
testCases := []struct {
|
||||
name string
|
||||
rs stack.ReceiveBufferSizeOption
|
||||
rs tcpip.ReceiveBufferSizeOption
|
||||
err tcpip.Error
|
||||
}{
|
||||
// Invalid configurations.
|
||||
{"min_below_zero", stack.ReceiveBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"min_zero", stack.ReceiveBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"default_below_min", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin - 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"default_above_max", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"max_below_min", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"min_below_zero", tcpip.ReceiveBufferSizeOption{Min: -1, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"min_zero", tcpip.ReceiveBufferSizeOption{Min: 0, Default: sMin, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"default_below_min", tcpip.ReceiveBufferSizeOption{Min: sMin, Default: sMin - 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"default_above_max", tcpip.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin}, &tcpip.ErrInvalidOptionValue{}},
|
||||
{"max_below_min", tcpip.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin - 1}, &tcpip.ErrInvalidOptionValue{}},
|
||||
|
||||
// Valid Configurations
|
||||
{"in_ascending_order", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 2}, nil},
|
||||
{"all_equal", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin, Max: sMin}, nil},
|
||||
{"min_default_equal", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin, Max: sMin + 1}, nil},
|
||||
{"default_max_equal", stack.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 1}, nil},
|
||||
{"in_ascending_order", tcpip.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 2}, nil},
|
||||
{"all_equal", tcpip.ReceiveBufferSizeOption{Min: sMin, Default: sMin, Max: sMin}, nil},
|
||||
{"min_default_equal", tcpip.ReceiveBufferSizeOption{Min: sMin, Default: sMin, Max: sMin + 1}, nil},
|
||||
{"default_max_equal", tcpip.ReceiveBufferSizeOption{Min: sMin, Default: sMin + 1, Max: sMin + 1}, nil},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -3380,7 +3380,7 @@ func TestStackReceiveBufferSizeOption(t *testing.T) {
|
||||
if err := s.SetOption(tc.rs); err != tc.err {
|
||||
t.Fatalf("s.SetOption(%#v) = %v, want: %v", tc.rs, err, tc.err)
|
||||
}
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
var rs tcpip.ReceiveBufferSizeOption
|
||||
if tc.err == nil {
|
||||
if err := s.Option(&rs); err != nil {
|
||||
t.Fatalf("s.Option(%#v) = %v, want: nil", rs, err)
|
||||
|
||||
@@ -353,10 +353,6 @@ type RcvBufAutoTuneParams struct {
|
||||
//
|
||||
// +stateify savable
|
||||
type TCPRcvBufState struct {
|
||||
// RcvBufSize is the size of the receive socket buffer for the
|
||||
// endpoint.
|
||||
RcvBufSize int
|
||||
|
||||
// RcvBufUsed is the amount of bytes actually held in the receive
|
||||
// socket buffer for the endpoint.
|
||||
RcvBufUsed int
|
||||
|
||||
@@ -70,7 +70,7 @@ func (f *fakeTransportEndpoint) SocketOptions() *tcpip.SocketOptions {
|
||||
|
||||
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, tcpip.GetStackSendBufferLimits)
|
||||
ep.ops.InitHandler(ep, s, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
|
||||
return ep
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ func (f *fakeTransportEndpoint) HandlePacket(id stack.TransportEndpointID, pkt *
|
||||
peerAddr: route.RemoteAddress(),
|
||||
route: route,
|
||||
}
|
||||
ep.ops.InitHandler(ep, f.proto.stack, tcpip.GetStackSendBufferLimits)
|
||||
ep.ops.InitHandler(ep, f.proto.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
|
||||
f.acceptQueue = append(f.acceptQueue, ep)
|
||||
}
|
||||
|
||||
|
||||
+25
-4
@@ -691,10 +691,6 @@ const (
|
||||
// number of unread bytes in the input buffer should be returned.
|
||||
ReceiveQueueSizeOption
|
||||
|
||||
// ReceiveBufferSizeOption is used by SetSockOptInt/GetSockOptInt to
|
||||
// specify the receive buffer size option.
|
||||
ReceiveBufferSizeOption
|
||||
|
||||
// SendQueueSizeOption is used in GetSockOptInt to specify that the
|
||||
// number of unread bytes in the output buffer should be returned.
|
||||
SendQueueSizeOption
|
||||
@@ -1144,6 +1140,19 @@ type SendBufferSizeOption struct {
|
||||
Max int
|
||||
}
|
||||
|
||||
// ReceiveBufferSizeOption is used by stack.(Stack*).Option/SetOption to
|
||||
// get/set the default, min and max receive buffer sizes.
|
||||
type ReceiveBufferSizeOption 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
|
||||
|
||||
@@ -1156,6 +1165,18 @@ func GetStackSendBufferLimits(so StackHandler) SendBufferSizeOption {
|
||||
return ss
|
||||
}
|
||||
|
||||
// GetReceiveBufferLimits is used to get the send buffer size limits.
|
||||
type GetReceiveBufferLimits func(StackHandler) ReceiveBufferSizeOption
|
||||
|
||||
// GetStackReceiveBufferLimits is used to get default, min and max send buffer size.
|
||||
func GetStackReceiveBufferLimits(so StackHandler) ReceiveBufferSizeOption {
|
||||
var ss ReceiveBufferSizeOption
|
||||
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.
|
||||
|
||||
@@ -63,12 +63,11 @@ type endpoint struct {
|
||||
|
||||
// The following fields are used to manage the receive queue, and are
|
||||
// protected by rcvMu.
|
||||
rcvMu sync.Mutex `state:"nosave"`
|
||||
rcvReady bool
|
||||
rcvList icmpPacketList
|
||||
rcvBufSizeMax int `state:".(int)"`
|
||||
rcvBufSize int
|
||||
rcvClosed bool
|
||||
rcvMu sync.Mutex `state:"nosave"`
|
||||
rcvReady bool
|
||||
rcvList icmpPacketList
|
||||
rcvBufSize int
|
||||
rcvClosed bool
|
||||
|
||||
// The following fields are protected by the mu mutex.
|
||||
mu sync.RWMutex `state:"nosave"`
|
||||
@@ -84,6 +83,10 @@ type endpoint struct {
|
||||
|
||||
// ops is used to get socket level options.
|
||||
ops tcpip.SocketOptions
|
||||
|
||||
// frozen indicates if the packets should be delivered to the endpoint
|
||||
// during restore.
|
||||
frozen bool
|
||||
}
|
||||
|
||||
func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProto tcpip.TransportProtocolNumber, waiterQueue *waiter.Queue) (tcpip.Endpoint, tcpip.Error) {
|
||||
@@ -93,19 +96,23 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt
|
||||
NetProto: netProto,
|
||||
TransProto: transProto,
|
||||
},
|
||||
waiterQueue: waiterQueue,
|
||||
rcvBufSizeMax: 32 * 1024,
|
||||
state: stateInitial,
|
||||
uniqueID: s.UniqueID(),
|
||||
waiterQueue: waiterQueue,
|
||||
state: stateInitial,
|
||||
uniqueID: s.UniqueID(),
|
||||
}
|
||||
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits)
|
||||
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
|
||||
ep.ops.SetSendBufferSize(32*1024, false /* notify */)
|
||||
ep.ops.SetReceiveBufferSize(32*1024, false /* notify */)
|
||||
|
||||
// Override with stack defaults.
|
||||
var ss tcpip.SendBufferSizeOption
|
||||
if err := s.Option(&ss); err == nil {
|
||||
ep.ops.SetSendBufferSize(int64(ss.Default), false /* notify */)
|
||||
}
|
||||
var rs tcpip.ReceiveBufferSizeOption
|
||||
if err := s.Option(&rs); err == nil {
|
||||
ep.ops.SetReceiveBufferSize(int64(rs.Default), false /* notify */)
|
||||
}
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
@@ -371,12 +378,6 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) {
|
||||
e.rcvMu.Unlock()
|
||||
return v, nil
|
||||
|
||||
case tcpip.ReceiveBufferSizeOption:
|
||||
e.rcvMu.Lock()
|
||||
v := e.rcvBufSizeMax
|
||||
e.rcvMu.Unlock()
|
||||
return v, nil
|
||||
|
||||
case tcpip.TTLOption:
|
||||
e.rcvMu.Lock()
|
||||
v := int(e.ttl)
|
||||
@@ -774,7 +775,8 @@ func (e *endpoint) HandlePacket(id stack.TransportEndpointID, pkt *stack.PacketB
|
||||
return
|
||||
}
|
||||
|
||||
if e.rcvBufSize >= e.rcvBufSizeMax {
|
||||
rcvBufSize := e.ops.GetReceiveBufferSize()
|
||||
if e.frozen || e.rcvBufSize >= int(rcvBufSize) {
|
||||
e.rcvMu.Unlock()
|
||||
e.stack.Stats().DroppedPackets.Increment()
|
||||
e.stats.ReceiveErrors.ReceiveBufferOverflow.Increment()
|
||||
@@ -843,3 +845,18 @@ func (*endpoint) LastError() tcpip.Error {
|
||||
func (e *endpoint) SocketOptions() *tcpip.SocketOptions {
|
||||
return &e.ops
|
||||
}
|
||||
|
||||
// freeze prevents any more packets from being delivered to the endpoint.
|
||||
func (e *endpoint) freeze() {
|
||||
e.mu.Lock()
|
||||
e.frozen = true
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
// thaw unfreezes a previously frozen endpoint using endpoint.freeze() allows
|
||||
// new packets to be delivered again.
|
||||
func (e *endpoint) thaw() {
|
||||
e.mu.Lock()
|
||||
e.frozen = false
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -36,40 +36,21 @@ func (p *icmpPacket) loadData(data buffer.VectorisedView) {
|
||||
p.data = data
|
||||
}
|
||||
|
||||
// beforeSave is invoked by stateify.
|
||||
func (e *endpoint) beforeSave() {
|
||||
// Stop incoming packets from being handled (and mutate endpoint state).
|
||||
// The lock will be released after savercvBufSizeMax(), which would have
|
||||
// saved e.rcvBufSizeMax and set it to 0 to continue blocking incoming
|
||||
// packets.
|
||||
e.rcvMu.Lock()
|
||||
}
|
||||
|
||||
// saveRcvBufSizeMax is invoked by stateify.
|
||||
func (e *endpoint) saveRcvBufSizeMax() int {
|
||||
max := e.rcvBufSizeMax
|
||||
// Make sure no new packets will be handled regardless of the lock.
|
||||
e.rcvBufSizeMax = 0
|
||||
// Release the lock acquired in beforeSave() so regular endpoint closing
|
||||
// logic can proceed after save.
|
||||
e.rcvMu.Unlock()
|
||||
return max
|
||||
}
|
||||
|
||||
// loadRcvBufSizeMax is invoked by stateify.
|
||||
func (e *endpoint) loadRcvBufSizeMax(max int) {
|
||||
e.rcvBufSizeMax = max
|
||||
}
|
||||
|
||||
// afterLoad is invoked by stateify.
|
||||
func (e *endpoint) afterLoad() {
|
||||
stack.StackFromEnv.RegisterRestoredEndpoint(e)
|
||||
}
|
||||
|
||||
// beforeSave is invoked by stateify.
|
||||
func (e *endpoint) beforeSave() {
|
||||
e.freeze()
|
||||
}
|
||||
|
||||
// Resume implements tcpip.ResumableEndpoint.Resume.
|
||||
func (e *endpoint) Resume(s *stack.Stack) {
|
||||
e.thaw()
|
||||
e.stack = s
|
||||
e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits)
|
||||
e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
|
||||
|
||||
if e.state != stateBound && e.state != stateConnected {
|
||||
return
|
||||
|
||||
@@ -72,11 +72,10 @@ type endpoint struct {
|
||||
|
||||
// The following fields are used to manage the receive queue and are
|
||||
// protected by rcvMu.
|
||||
rcvMu sync.Mutex `state:"nosave"`
|
||||
rcvList packetList
|
||||
rcvBufSizeMax int `state:".(int)"`
|
||||
rcvBufSize int
|
||||
rcvClosed bool
|
||||
rcvMu sync.Mutex `state:"nosave"`
|
||||
rcvList packetList
|
||||
rcvBufSize int
|
||||
rcvClosed bool
|
||||
|
||||
// The following fields are protected by mu.
|
||||
mu sync.RWMutex `state:"nosave"`
|
||||
@@ -91,6 +90,10 @@ type endpoint struct {
|
||||
|
||||
// ops is used to get socket level options.
|
||||
ops tcpip.SocketOptions
|
||||
|
||||
// frozen indicates if the packets should be delivered to the endpoint
|
||||
// during restore.
|
||||
frozen bool
|
||||
}
|
||||
|
||||
// NewEndpoint returns a new packet endpoint.
|
||||
@@ -100,12 +103,12 @@ func NewEndpoint(s *stack.Stack, cooked bool, netProto tcpip.NetworkProtocolNumb
|
||||
TransportEndpointInfo: stack.TransportEndpointInfo{
|
||||
NetProto: netProto,
|
||||
},
|
||||
cooked: cooked,
|
||||
netProto: netProto,
|
||||
waiterQueue: waiterQueue,
|
||||
rcvBufSizeMax: 32 * 1024,
|
||||
cooked: cooked,
|
||||
netProto: netProto,
|
||||
waiterQueue: waiterQueue,
|
||||
}
|
||||
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits)
|
||||
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
|
||||
ep.ops.SetReceiveBufferSize(32*1024, false /* notify */)
|
||||
|
||||
// Override with stack defaults.
|
||||
var ss tcpip.SendBufferSizeOption
|
||||
@@ -113,9 +116,9 @@ func NewEndpoint(s *stack.Stack, cooked bool, netProto tcpip.NetworkProtocolNumb
|
||||
ep.ops.SetSendBufferSize(int64(ss.Default), false /* notify */)
|
||||
}
|
||||
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
var rs tcpip.ReceiveBufferSizeOption
|
||||
if err := s.Option(&rs); err == nil {
|
||||
ep.rcvBufSizeMax = rs.Default
|
||||
ep.ops.SetReceiveBufferSize(int64(rs.Default), false /* notify */)
|
||||
}
|
||||
|
||||
if err := s.RegisterPacketEndpoint(0, netProto, ep); err != nil {
|
||||
@@ -316,28 +319,7 @@ 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.ReceiveBufferSizeOption:
|
||||
// Make sure the receive buffer size is within the min and max
|
||||
// allowed.
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
if err := ep.stack.Option(&rs); err != nil {
|
||||
panic(fmt.Sprintf("s.Option(%#v) = %s", rs, err))
|
||||
}
|
||||
if v > rs.Max {
|
||||
v = rs.Max
|
||||
}
|
||||
if v < rs.Min {
|
||||
v = rs.Min
|
||||
}
|
||||
ep.rcvMu.Lock()
|
||||
ep.rcvBufSizeMax = v
|
||||
ep.rcvMu.Unlock()
|
||||
return nil
|
||||
|
||||
default:
|
||||
return &tcpip.ErrUnknownProtocolOption{}
|
||||
}
|
||||
return &tcpip.ErrUnknownProtocolOption{}
|
||||
}
|
||||
|
||||
func (ep *endpoint) LastError() tcpip.Error {
|
||||
@@ -374,12 +356,6 @@ func (ep *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) {
|
||||
ep.rcvMu.Unlock()
|
||||
return v, nil
|
||||
|
||||
case tcpip.ReceiveBufferSizeOption:
|
||||
ep.rcvMu.Lock()
|
||||
v := ep.rcvBufSizeMax
|
||||
ep.rcvMu.Unlock()
|
||||
return v, nil
|
||||
|
||||
default:
|
||||
return -1, &tcpip.ErrUnknownProtocolOption{}
|
||||
}
|
||||
@@ -397,7 +373,8 @@ func (ep *endpoint) HandlePacket(nicID tcpip.NICID, localAddr tcpip.LinkAddress,
|
||||
return
|
||||
}
|
||||
|
||||
if ep.rcvBufSize >= ep.rcvBufSizeMax {
|
||||
rcvBufSize := ep.ops.GetReceiveBufferSize()
|
||||
if ep.frozen || ep.rcvBufSize >= int(rcvBufSize) {
|
||||
ep.rcvMu.Unlock()
|
||||
ep.stack.Stats().DroppedPackets.Increment()
|
||||
ep.stats.ReceiveErrors.ReceiveBufferOverflow.Increment()
|
||||
@@ -513,3 +490,18 @@ func (ep *endpoint) SetOwner(owner tcpip.PacketOwner) {}
|
||||
func (ep *endpoint) SocketOptions() *tcpip.SocketOptions {
|
||||
return &ep.ops
|
||||
}
|
||||
|
||||
// freeze prevents any more packets from being delivered to the endpoint.
|
||||
func (ep *endpoint) freeze() {
|
||||
ep.mu.Lock()
|
||||
ep.frozen = true
|
||||
ep.mu.Unlock()
|
||||
}
|
||||
|
||||
// thaw unfreezes a previously frozen endpoint using endpoint.freeze() allows
|
||||
// new packets to be delivered again.
|
||||
func (ep *endpoint) thaw() {
|
||||
ep.mu.Lock()
|
||||
ep.frozen = false
|
||||
ep.mu.Unlock()
|
||||
}
|
||||
|
||||
@@ -38,33 +38,14 @@ func (p *packet) loadData(data buffer.VectorisedView) {
|
||||
|
||||
// beforeSave is invoked by stateify.
|
||||
func (ep *endpoint) beforeSave() {
|
||||
// Stop incoming packets from being handled (and mutate endpoint state).
|
||||
// The lock will be released after saveRcvBufSizeMax(), which would have
|
||||
// saved ep.rcvBufSizeMax and set it to 0 to continue blocking incoming
|
||||
// packets.
|
||||
ep.rcvMu.Lock()
|
||||
}
|
||||
|
||||
// saveRcvBufSizeMax is invoked by stateify.
|
||||
func (ep *endpoint) saveRcvBufSizeMax() int {
|
||||
max := ep.rcvBufSizeMax
|
||||
// Make sure no new packets will be handled regardless of the lock.
|
||||
ep.rcvBufSizeMax = 0
|
||||
// Release the lock acquired in beforeSave() so regular endpoint closing
|
||||
// logic can proceed after save.
|
||||
ep.rcvMu.Unlock()
|
||||
return max
|
||||
}
|
||||
|
||||
// loadRcvBufSizeMax is invoked by stateify.
|
||||
func (ep *endpoint) loadRcvBufSizeMax(max int) {
|
||||
ep.rcvBufSizeMax = max
|
||||
ep.freeze()
|
||||
}
|
||||
|
||||
// afterLoad is invoked by stateify.
|
||||
func (ep *endpoint) afterLoad() {
|
||||
ep.thaw()
|
||||
ep.stack = stack.StackFromEnv
|
||||
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits)
|
||||
ep.ops.InitHandler(ep, ep.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
|
||||
|
||||
// TODO(gvisor.dev/173): Once bind is supported, choose the right NIC.
|
||||
if err := ep.stack.RegisterPacketEndpoint(0, ep.netProto, ep); err != nil {
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
package raw
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
@@ -69,11 +68,10 @@ type endpoint struct {
|
||||
|
||||
// The following fields are used to manage the receive queue and are
|
||||
// protected by rcvMu.
|
||||
rcvMu sync.Mutex `state:"nosave"`
|
||||
rcvList rawPacketList
|
||||
rcvBufSize int
|
||||
rcvBufSizeMax int `state:".(int)"`
|
||||
rcvClosed bool
|
||||
rcvMu sync.Mutex `state:"nosave"`
|
||||
rcvList rawPacketList
|
||||
rcvBufSize int
|
||||
rcvClosed bool
|
||||
|
||||
// The following fields are protected by mu.
|
||||
mu sync.RWMutex `state:"nosave"`
|
||||
@@ -89,6 +87,10 @@ type endpoint struct {
|
||||
|
||||
// ops is used to get socket level options.
|
||||
ops tcpip.SocketOptions
|
||||
|
||||
// frozen indicates if the packets should be delivered to the endpoint
|
||||
// during restore.
|
||||
frozen bool
|
||||
}
|
||||
|
||||
// NewEndpoint returns a raw endpoint for the given protocols.
|
||||
@@ -107,13 +109,13 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt
|
||||
NetProto: netProto,
|
||||
TransProto: transProto,
|
||||
},
|
||||
waiterQueue: waiterQueue,
|
||||
rcvBufSizeMax: 32 * 1024,
|
||||
associated: associated,
|
||||
waiterQueue: waiterQueue,
|
||||
associated: associated,
|
||||
}
|
||||
e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits)
|
||||
e.ops.InitHandler(e, e.stack, tcpip.GetStackSendBufferLimits, tcpip.GetStackReceiveBufferLimits)
|
||||
e.ops.SetHeaderIncluded(!associated)
|
||||
e.ops.SetSendBufferSize(32*1024, false /* notify */)
|
||||
e.ops.SetReceiveBufferSize(32*1024, false /* notify */)
|
||||
|
||||
// Override with stack defaults.
|
||||
var ss tcpip.SendBufferSizeOption
|
||||
@@ -121,16 +123,16 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt
|
||||
e.ops.SetSendBufferSize(int64(ss.Default), false /* notify */)
|
||||
}
|
||||
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
var rs tcpip.ReceiveBufferSizeOption
|
||||
if err := s.Option(&rs); err == nil {
|
||||
e.rcvBufSizeMax = rs.Default
|
||||
e.ops.SetReceiveBufferSize(int64(rs.Default), false /* notify */)
|
||||
}
|
||||
|
||||
// Unassociated endpoints are write-only and users call Write() with IP
|
||||
// headers included. Because they're write-only, We don't need to
|
||||
// register with the stack.
|
||||
if !associated {
|
||||
e.rcvBufSizeMax = 0
|
||||
e.ops.SetReceiveBufferSize(0, false)
|
||||
e.waiterQueue = nil
|
||||
return e, nil
|
||||
}
|
||||
@@ -511,30 +513,8 @@ 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.ReceiveBufferSizeOption:
|
||||
// Make sure the receive buffer size is within the min and max
|
||||
// allowed.
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
if err := e.stack.Option(&rs); err != nil {
|
||||
panic(fmt.Sprintf("s.Option(%#v) = %s", rs, err))
|
||||
}
|
||||
if v > rs.Max {
|
||||
v = rs.Max
|
||||
}
|
||||
if v < rs.Min {
|
||||
v = rs.Min
|
||||
}
|
||||
e.rcvMu.Lock()
|
||||
e.rcvBufSizeMax = v
|
||||
e.rcvMu.Unlock()
|
||||
return nil
|
||||
|
||||
default:
|
||||
return &tcpip.ErrUnknownProtocolOption{}
|
||||
}
|
||||
return &tcpip.ErrUnknownProtocolOption{}
|
||||
}
|
||||
|
||||
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
|
||||
@@ -555,12 +535,6 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, tcpip.Error) {
|
||||
e.rcvMu.Unlock()
|
||||
return v, nil
|
||||
|
||||
case tcpip.ReceiveBufferSizeOption:
|
||||
e.rcvMu.Lock()
|
||||
v := e.rcvBufSizeMax
|
||||
e.rcvMu.Unlock()
|
||||
return v, nil
|
||||
|
||||
default:
|
||||
return -1, &tcpip.ErrUnknownProtocolOption{}
|
||||
}
|
||||
@@ -587,7 +561,8 @@ func (e *endpoint) HandlePacket(pkt *stack.PacketBuffer) {
|
||||
return
|
||||
}
|
||||
|
||||
if e.rcvBufSize >= e.rcvBufSizeMax {
|
||||
rcvBufSize := e.ops.GetReceiveBufferSize()
|
||||
if e.frozen || e.rcvBufSize >= int(rcvBufSize) {
|
||||
e.rcvMu.Unlock()
|
||||
e.mu.RUnlock()
|
||||
e.stack.Stats().DroppedPackets.Increment()
|
||||
@@ -690,3 +665,18 @@ func (*endpoint) LastError() tcpip.Error {
|
||||
func (e *endpoint) SocketOptions() *tcpip.SocketOptions {
|
||||
return &e.ops
|
||||
}
|
||||
|
||||
// freeze prevents any more packets from being delivered to the endpoint.
|
||||
func (e *endpoint) freeze() {
|
||||
e.mu.Lock()
|
||||
e.frozen = true
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
// thaw unfreezes a previously frozen endpoint using endpoint.freeze() allows
|
||||
// new packets to be delivered again.
|
||||
func (e *endpoint) thaw() {
|
||||
e.mu.Lock()
|
||||
e.frozen = false
|
||||
e.mu.Unlock()
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user