Skip to content

Commit

Permalink
Support setsockopt SO_SNDBUF/SO_RCVBUF for raw/udp sockets.
Browse files Browse the repository at this point in the history
Updates #173,#6
Fixes #2888

PiperOrigin-RevId: 312689994
  • Loading branch information
hbhasker authored and gvisor-bot committed Jun 9, 2020
1 parent 12f9094 commit 22aeb5e
Show file tree
Hide file tree
Showing 16 changed files with 667 additions and 87 deletions.
2 changes: 1 addition & 1 deletion benchmarks/tcp/tcp_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ func newNetstackImpl(mode string) (impl, error) {
})

// Set protocol options.
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SACKEnabled(*sack)); err != nil {
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSACKEnabled(*sack)); err != nil {
return nil, fmt.Errorf("SetTransportProtocolOption for SACKEnabled failed: %v", err)
}

Expand Down
12 changes: 6 additions & 6 deletions pkg/sentry/socket/netstack/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (s *Stack) AddInterfaceAddr(idx int32, addr inet.InterfaceAddr) error {

// TCPReceiveBufferSize implements inet.Stack.TCPReceiveBufferSize.
func (s *Stack) TCPReceiveBufferSize() (inet.TCPBufferSize, error) {
var rs tcp.ReceiveBufferSizeOption
var rs tcpip.StackReceiveBufferSizeOption
err := s.Stack.TransportProtocolOption(tcp.ProtocolNumber, &rs)
return inet.TCPBufferSize{
Min: rs.Min,
Expand All @@ -155,7 +155,7 @@ func (s *Stack) TCPReceiveBufferSize() (inet.TCPBufferSize, error) {

// SetTCPReceiveBufferSize implements inet.Stack.SetTCPReceiveBufferSize.
func (s *Stack) SetTCPReceiveBufferSize(size inet.TCPBufferSize) error {
rs := tcp.ReceiveBufferSizeOption{
rs := tcpip.StackReceiveBufferSizeOption{
Min: size.Min,
Default: size.Default,
Max: size.Max,
Expand All @@ -165,7 +165,7 @@ func (s *Stack) SetTCPReceiveBufferSize(size inet.TCPBufferSize) error {

// TCPSendBufferSize implements inet.Stack.TCPSendBufferSize.
func (s *Stack) TCPSendBufferSize() (inet.TCPBufferSize, error) {
var ss tcp.SendBufferSizeOption
var ss tcpip.StackSendBufferSizeOption
err := s.Stack.TransportProtocolOption(tcp.ProtocolNumber, &ss)
return inet.TCPBufferSize{
Min: ss.Min,
Expand All @@ -176,7 +176,7 @@ func (s *Stack) TCPSendBufferSize() (inet.TCPBufferSize, error) {

// SetTCPSendBufferSize implements inet.Stack.SetTCPSendBufferSize.
func (s *Stack) SetTCPSendBufferSize(size inet.TCPBufferSize) error {
ss := tcp.SendBufferSizeOption{
ss := tcpip.StackSendBufferSizeOption{
Min: size.Min,
Default: size.Default,
Max: size.Max,
Expand All @@ -186,14 +186,14 @@ func (s *Stack) SetTCPSendBufferSize(size inet.TCPBufferSize) error {

// TCPSACKEnabled implements inet.Stack.TCPSACKEnabled.
func (s *Stack) TCPSACKEnabled() (bool, error) {
var sack tcp.SACKEnabled
var sack tcpip.StackSACKEnabled
err := s.Stack.TransportProtocolOption(tcp.ProtocolNumber, &sack)
return bool(sack), syserr.TranslateNetstackError(err).ToError()
}

// SetTCPSACKEnabled implements inet.Stack.SetTCPSACKEnabled.
func (s *Stack) SetTCPSACKEnabled(enabled bool) error {
return syserr.TranslateNetstackError(s.Stack.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SACKEnabled(enabled))).ToError()
return syserr.TranslateNetstackError(s.Stack.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSACKEnabled(enabled))).ToError()
}

// Statistics implements inet.Stack.Statistics.
Expand Down
24 changes: 24 additions & 0 deletions pkg/tcpip/tcpip.go
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,30 @@ type OutOfBandInlineOption int
// a default TTL.
type DefaultTTLOption uint8

// StackSACKEnabled option can be used to enable SACK support in the TCP
// protocol. See: https://tools.ietf.org/html/rfc2018.
type StackSACKEnabled bool

// StackDelayEnabled option can be used to enable Nagle's algorithm in the TCP protocol.
type StackDelayEnabled bool

// StackSendBufferSizeOption allows the stack-wide default, min and max send
// buffer sizes to be queried or configured.
type StackSendBufferSizeOption struct {
Min int
Default int
Max int
}

// StackReceiveBufferSizeOption allows the stack-wide default, min and max
// receive buffer sizes to be queried or configured.
type StackReceiveBufferSizeOption struct {
Min int
Default int
Max int
}

//
// IPPacketInfo is the message struture for IP_PKTINFO.
//
// +stateify savable
Expand Down
67 changes: 58 additions & 9 deletions pkg/tcpip/transport/raw/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
package raw

import (
"fmt"

"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/tcpip"
"gvisor.dev/gvisor/pkg/tcpip/buffer"
Expand Down Expand Up @@ -66,16 +68,17 @@ type endpoint struct {
// protected by rcvMu.
rcvMu sync.Mutex `state:"nosave"`
rcvList rawPacketList
rcvBufSizeMax int `state:".(int)"`
rcvBufSize int
rcvBufSizeMax int `state:".(int)"`
rcvClosed bool

// The following fields are protected by mu.
mu sync.RWMutex `state:"nosave"`
sndBufSize int
closed bool
connected bool
bound bool
mu sync.RWMutex `state:"nosave"`
sndBufSize int
sndBufSizeMax int
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"`
Expand Down Expand Up @@ -103,10 +106,21 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt
},
waiterQueue: waiterQueue,
rcvBufSizeMax: 32 * 1024,
sndBufSize: 32 * 1024,
sndBufSizeMax: 32 * 1024,
associated: associated,
}

// Override with stack defaults.
var ss tcpip.StackSendBufferSizeOption
if err := s.TransportProtocolOption(transProto, &ss); err == nil {
e.sndBufSizeMax = ss.Default
}

var rs tcpip.StackReceiveBufferSizeOption
if err := s.TransportProtocolOption(transProto, &rs); err == nil {
e.rcvBufSizeMax = rs.Default
}

// 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.
Expand Down Expand Up @@ -523,7 +537,42 @@ func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {

// SetSockOptInt implements tcpip.Endpoint.SetSockOptInt.
func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
return tcpip.ErrUnknownProtocolOption
switch opt {
case tcpip.SendBufferSizeOption:
var ss tcpip.StackSendBufferSizeOption
if err := e.stack.TransportProtocolOption(e.TransProto, &ss); err != nil {
panic(fmt.Sprintf("s.TransportProtocolOption(%d, %+v) = err", e.TransProto, ss))
}
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:
var rs tcpip.StackReceiveBufferSizeOption
if err := e.stack.TransportProtocolOption(e.TransProto, &rs); err != nil {
panic(fmt.Sprintf("s.TransportProtocolOption(%d, %+v) = err", e.TransProto, rs))
}
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
}
}

// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
Expand Down Expand Up @@ -563,7 +612,7 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {

case tcpip.SendBufferSizeOption:
e.mu.Lock()
v := e.sndBufSize
v := e.sndBufSizeMax
e.mu.Unlock()
return v, nil

Expand Down
2 changes: 1 addition & 1 deletion pkg/tcpip/transport/tcp/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ func (h *handshake) execute() *tcpip.Error {
s.AddWaker(&h.ep.newSegmentWaker, wakerForNewSegment)
defer s.Done()

var sackEnabled SACKEnabled
var sackEnabled tcpip.StackSACKEnabled
if err := h.ep.stack.TransportProtocolOption(ProtocolNumber, &sackEnabled); err != nil {
// If stack returned an error when checking for SACKEnabled
// status then just default to switching off SACK negotiation.
Expand Down
16 changes: 8 additions & 8 deletions pkg/tcpip/transport/tcp/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,12 +847,12 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
maxSynRetries: DefaultSynRetries,
}

var ss SendBufferSizeOption
var ss tcpip.StackSendBufferSizeOption
if err := s.TransportProtocolOption(ProtocolNumber, &ss); err == nil {
e.sndBufSize = ss.Default
}

var rs ReceiveBufferSizeOption
var rs tcpip.StackReceiveBufferSizeOption
if err := s.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
e.rcvBufSize = rs.Default
}
Expand All @@ -867,7 +867,7 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
e.rcvAutoParams.disabled = !bool(mrb)
}

var de DelayEnabled
var de tcpip.StackDelayEnabled
if err := s.TransportProtocolOption(ProtocolNumber, &de); err == nil && de {
e.SetSockOptBool(tcpip.DelayOption, true)
}
Expand Down Expand Up @@ -1582,7 +1582,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
case tcpip.ReceiveBufferSizeOption:
// Make sure the receive buffer size is within the min and max
// allowed.
var rs ReceiveBufferSizeOption
var rs tcpip.StackReceiveBufferSizeOption
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
if v < rs.Min {
v = rs.Min
Expand Down Expand Up @@ -1632,7 +1632,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
case tcpip.SendBufferSizeOption:
// Make sure the send buffer size is within the min and max
// allowed.
var ss SendBufferSizeOption
var ss tcpip.StackSendBufferSizeOption
if err := e.stack.TransportProtocolOption(ProtocolNumber, &ss); err == nil {
if v < ss.Min {
v = ss.Min
Expand Down Expand Up @@ -1672,7 +1672,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
return tcpip.ErrInvalidOptionValue
}
}
var rs ReceiveBufferSizeOption
var rs tcpip.StackReceiveBufferSizeOption
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
if v < rs.Min/2 {
v = rs.Min / 2
Expand Down Expand Up @@ -2594,7 +2594,7 @@ func (e *endpoint) receiveBufferSize() int {
}

func (e *endpoint) maxReceiveBufferSize() int {
var rs ReceiveBufferSizeOption
var rs tcpip.StackReceiveBufferSizeOption
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err != nil {
// As a fallback return the hardcoded max buffer size.
return MaxBufferSize
Expand Down Expand Up @@ -2675,7 +2675,7 @@ func timeStampOffset() uint32 {
// if the SYN options indicate that the SACK option was negotiated and the TCP
// stack is configured to enable TCP SACK option.
func (e *endpoint) maybeEnableSACKPermitted(synOpts *header.TCPSynOptions) {
var v SACKEnabled
var v tcpip.StackSACKEnabled
if err := e.stack.TransportProtocolOption(ProtocolNumber, &v); err != nil {
// Stack doesn't support SACK. So just return.
return
Expand Down
2 changes: 1 addition & 1 deletion pkg/tcpip/transport/tcp/endpoint_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func (e *endpoint) Resume(s *stack.Stack) {
epState := e.origEndpointState
switch epState {
case StateInitial, StateBound, StateListen, StateConnecting, StateEstablished:
var ss SendBufferSizeOption
var ss tcpip.StackSendBufferSizeOption
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))
Expand Down
Loading

0 comments on commit 22aeb5e

Please sign in to comment.