Add support for Stack level options.
Linux controls socket send/receive buffers using a few sysctl variables - net.core.rmem_default - net.core.rmem_max - net.core.wmem_max - net.core.wmem_default - net.ipv4.tcp_rmem - net.ipv4.tcp_wmem The first 4 control the default socket buffer sizes for all sockets raw/packet/tcp/udp and also the maximum permitted socket buffer that can be specified in setsockopt(SOL_SOCKET, SO_(RCV|SND)BUF,...). The last two control the TCP auto-tuning limits and override the default specified in rmem_default/wmem_default as well as the max limits. Netstack today only implements tcp_rmem/tcp_wmem and incorrectly uses it to limit the maximum size in setsockopt() as well as uses it for raw/udp sockets. This changelist introduces the other 4 and updates the udp/raw sockets to use the newly introduced variables. The values for min/max match the current tcp_rmem/wmem values and the default value buffers for UDP/RAW sockets is updated to match the linux value of 212KiB up from the really low current value of 32 KiB. Updates #3043 Fixes #3043 PiperOrigin-RevId: 318089805
This commit is contained in:
parent
364ac92baf
commit
b070e218c6
|
@ -228,7 +228,7 @@ func newNetstackImpl(mode string) (impl, error) {
|
|||
})
|
||||
|
||||
// Set protocol options.
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSACKEnabled(*sack)); err != nil {
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SACKEnabled(*sack)); err != nil {
|
||||
return nil, fmt.Errorf("SetTransportProtocolOption for SACKEnabled failed: %s", err)
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,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 tcpip.StackReceiveBufferSizeOption
|
||||
var rs tcp.ReceiveBufferSizeOption
|
||||
err := s.Stack.TransportProtocolOption(tcp.ProtocolNumber, &rs)
|
||||
return inet.TCPBufferSize{
|
||||
Min: rs.Min,
|
||||
|
@ -154,7 +154,7 @@ func (s *Stack) TCPReceiveBufferSize() (inet.TCPBufferSize, error) {
|
|||
|
||||
// SetTCPReceiveBufferSize implements inet.Stack.SetTCPReceiveBufferSize.
|
||||
func (s *Stack) SetTCPReceiveBufferSize(size inet.TCPBufferSize) error {
|
||||
rs := tcpip.StackReceiveBufferSizeOption{
|
||||
rs := tcp.ReceiveBufferSizeOption{
|
||||
Min: size.Min,
|
||||
Default: size.Default,
|
||||
Max: size.Max,
|
||||
|
@ -164,7 +164,7 @@ func (s *Stack) SetTCPReceiveBufferSize(size inet.TCPBufferSize) error {
|
|||
|
||||
// TCPSendBufferSize implements inet.Stack.TCPSendBufferSize.
|
||||
func (s *Stack) TCPSendBufferSize() (inet.TCPBufferSize, error) {
|
||||
var ss tcpip.StackSendBufferSizeOption
|
||||
var ss tcp.SendBufferSizeOption
|
||||
err := s.Stack.TransportProtocolOption(tcp.ProtocolNumber, &ss)
|
||||
return inet.TCPBufferSize{
|
||||
Min: ss.Min,
|
||||
|
@ -175,7 +175,7 @@ func (s *Stack) TCPSendBufferSize() (inet.TCPBufferSize, error) {
|
|||
|
||||
// SetTCPSendBufferSize implements inet.Stack.SetTCPSendBufferSize.
|
||||
func (s *Stack) SetTCPSendBufferSize(size inet.TCPBufferSize) error {
|
||||
ss := tcpip.StackSendBufferSizeOption{
|
||||
ss := tcp.SendBufferSizeOption{
|
||||
Min: size.Min,
|
||||
Default: size.Default,
|
||||
Max: size.Max,
|
||||
|
@ -185,14 +185,14 @@ func (s *Stack) SetTCPSendBufferSize(size inet.TCPBufferSize) error {
|
|||
|
||||
// TCPSACKEnabled implements inet.Stack.TCPSACKEnabled.
|
||||
func (s *Stack) TCPSACKEnabled() (bool, error) {
|
||||
var sack tcpip.StackSACKEnabled
|
||||
var sack tcp.SACKEnabled
|
||||
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, tcpip.StackSACKEnabled(enabled))).ToError()
|
||||
return syserr.TranslateNetstackError(s.Stack.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SACKEnabled(enabled))).ToError()
|
||||
}
|
||||
|
||||
// Statistics implements inet.Stack.Statistics.
|
||||
|
|
|
@ -48,6 +48,7 @@ go_library(
|
|||
"route.go",
|
||||
"stack.go",
|
||||
"stack_global_state.go",
|
||||
"stack_options.go",
|
||||
"transport_demuxer.go",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
|
|
|
@ -471,6 +471,14 @@ type Stack struct {
|
|||
// randomGenerator is an injectable pseudo random generator that can be
|
||||
// used when a random number is required.
|
||||
randomGenerator *mathrand.Rand
|
||||
|
||||
// sendBufferSize holds the min/default/max send buffer sizes for
|
||||
// endpoints other than TCP.
|
||||
sendBufferSize SendBufferSizeOption
|
||||
|
||||
// receiveBufferSize holds the min/default/max receive buffer sizes for
|
||||
// endpoints other than TCP.
|
||||
receiveBufferSize ReceiveBufferSizeOption
|
||||
}
|
||||
|
||||
// UniqueID is an abstract generator of unique identifiers.
|
||||
|
@ -683,6 +691,16 @@ func New(opts Options) *Stack {
|
|||
tempIIDSeed: opts.TempIIDSeed,
|
||||
forwarder: newForwardQueue(),
|
||||
randomGenerator: mathrand.New(randSrc),
|
||||
sendBufferSize: SendBufferSizeOption{
|
||||
Min: MinBufferSize,
|
||||
Default: DefaultBufferSize,
|
||||
Max: DefaultMaxBufferSize,
|
||||
},
|
||||
receiveBufferSize: ReceiveBufferSizeOption{
|
||||
Min: MinBufferSize,
|
||||
Default: DefaultBufferSize,
|
||||
Max: DefaultMaxBufferSize,
|
||||
},
|
||||
}
|
||||
|
||||
// Add specified network protocols.
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
// Copyright 2020 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 stack
|
||||
|
||||
import "gvisor.dev/gvisor/pkg/tcpip"
|
||||
|
||||
const (
|
||||
// MinBufferSize is the smallest size of a receive or send buffer.
|
||||
MinBufferSize = 4 << 10 // 4 KiB
|
||||
|
||||
// DefaultBufferSize is the default size of the send/recv buffer for a
|
||||
// transport endpoint.
|
||||
DefaultBufferSize = 212 << 10 // 212 KiB
|
||||
|
||||
// DefaultMaxBufferSize is the default maximum permitted size of a
|
||||
// send/receive buffer.
|
||||
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 {
|
||||
Min int
|
||||
Default int
|
||||
Max int
|
||||
}
|
||||
|
||||
// SetOption allows setting stack wide options.
|
||||
func (s *Stack) SetOption(option interface{}) *tcpip.Error {
|
||||
switch v := option.(type) {
|
||||
case SendBufferSizeOption:
|
||||
// Make sure we don't allow lowering the buffer below minimum
|
||||
// required for stack to work.
|
||||
if v.Min < MinBufferSize {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
||||
if v.Default < v.Min || v.Default > v.Max {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
s.sendBufferSize = v
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
|
||||
case ReceiveBufferSizeOption:
|
||||
// Make sure we don't allow lowering the buffer below minimum
|
||||
// required for stack to work.
|
||||
if v.Min < MinBufferSize {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
||||
if v.Default < v.Min || v.Default > v.Max {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
s.receiveBufferSize = v
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
|
||||
default:
|
||||
return tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
}
|
||||
|
||||
// Option allows retrieving stack wide options.
|
||||
func (s *Stack) Option(option interface{}) *tcpip.Error {
|
||||
switch v := option.(type) {
|
||||
case *SendBufferSizeOption:
|
||||
s.mu.RLock()
|
||||
*v = s.sendBufferSize
|
||||
s.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
case *ReceiveBufferSizeOption:
|
||||
s.mu.RLock()
|
||||
*v = s.receiveBufferSize
|
||||
s.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
default:
|
||||
return tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
}
|
|
@ -3338,3 +3338,83 @@ func TestDoDADWhenNICEnabled(t *testing.T) {
|
|||
t.Fatalf("got stack.GetMainNICAddress(%d, %d) = (%s, nil), want = (%s, nil)", nicID, header.IPv6ProtocolNumber, got, addr.AddressWithPrefix)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStackReceiveBufferSizeOption(t *testing.T) {
|
||||
const sMin = stack.MinBufferSize
|
||||
testCases := []struct {
|
||||
name string
|
||||
rs stack.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},
|
||||
|
||||
// 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},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{})
|
||||
defer s.Close()
|
||||
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
|
||||
if tc.err == nil {
|
||||
if err := s.Option(&rs); err != nil {
|
||||
t.Fatalf("s.Option(%#v) = %v, want: nil", rs, err)
|
||||
}
|
||||
if got, want := rs, tc.rs; got != want {
|
||||
t.Fatalf("s.Option(..) returned unexpected value got: %#v, want: %#v", got, want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStackSendBufferSizeOption(t *testing.T) {
|
||||
const sMin = stack.MinBufferSize
|
||||
testCases := []struct {
|
||||
name string
|
||||
ss stack.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},
|
||||
|
||||
// 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},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
s := stack.New(stack.Options{})
|
||||
defer s.Close()
|
||||
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
|
||||
if tc.err == nil {
|
||||
if err := s.Option(&ss); err != nil {
|
||||
t.Fatalf("s.Option(%+v) = %v, want: nil", ss, err)
|
||||
}
|
||||
if got, want := ss, tc.ss; got != want {
|
||||
t.Fatalf("s.Option(..) returned unexpected value got: %#v, want: %#v", got, want)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -813,33 +813,8 @@ type OutOfBandInlineOption int
|
|||
// a default TTL.
|
||||
type DefaultTTLOption uint8
|
||||
|
||||
// StackSACKEnabled is used by stack.(*Stack).TransportProtocolOption to
|
||||
// enable/disable SACK support in TCP. See: https://tools.ietf.org/html/rfc2018.
|
||||
type StackSACKEnabled bool
|
||||
|
||||
// StackDelayEnabled is used by stack.(Stack*).TransportProtocolOption to
|
||||
// enable/disable Nagle's algorithm in TCP.
|
||||
type StackDelayEnabled bool
|
||||
|
||||
// StackSendBufferSizeOption is used by stack.(Stack*).TransportProtocolOption
|
||||
// to get/set the default, min and max send buffer sizes.
|
||||
type StackSendBufferSizeOption struct {
|
||||
Min int
|
||||
Default int
|
||||
Max int
|
||||
}
|
||||
|
||||
// StackReceiveBufferSizeOption is used by
|
||||
// stack.(Stack*).TransportProtocolOption to get/set the default, min and max
|
||||
// receive buffer sizes.
|
||||
type StackReceiveBufferSizeOption struct {
|
||||
Min int
|
||||
Default int
|
||||
Max int
|
||||
}
|
||||
|
||||
//
|
||||
// IPPacketInfo is the message struture for IP_PKTINFO.
|
||||
// IPPacketInfo is the message structure for IP_PKTINFO.
|
||||
//
|
||||
// +stateify savable
|
||||
type IPPacketInfo struct {
|
||||
|
|
|
@ -111,13 +111,13 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, transProt
|
|||
}
|
||||
|
||||
// Override with stack defaults.
|
||||
var ss tcpip.StackSendBufferSizeOption
|
||||
if err := s.TransportProtocolOption(transProto, &ss); err == nil {
|
||||
var ss stack.SendBufferSizeOption
|
||||
if err := s.Option(&ss); err == nil {
|
||||
e.sndBufSizeMax = ss.Default
|
||||
}
|
||||
|
||||
var rs tcpip.StackReceiveBufferSizeOption
|
||||
if err := s.TransportProtocolOption(transProto, &rs); err == nil {
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
if err := s.Option(&rs); err == nil {
|
||||
e.rcvBufSizeMax = rs.Default
|
||||
}
|
||||
|
||||
|
@ -541,9 +541,9 @@ 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 tcpip.StackSendBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(e.TransProto, &ss); err != nil {
|
||||
panic(fmt.Sprintf("s.TransportProtocolOption(%d, %+v) = %s", e.TransProto, ss, err))
|
||||
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
|
||||
|
@ -559,9 +559,9 @@ 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 tcpip.StackReceiveBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(e.TransProto, &rs); err != nil {
|
||||
panic(fmt.Sprintf("s.TransportProtocolOption(%d, %+v) = %s", e.TransProto, rs, err))
|
||||
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
|
||||
|
|
|
@ -521,7 +521,7 @@ func (h *handshake) execute() *tcpip.Error {
|
|||
s.AddWaker(&h.ep.newSegmentWaker, wakerForNewSegment)
|
||||
defer s.Done()
|
||||
|
||||
var sackEnabled tcpip.StackSACKEnabled
|
||||
var sackEnabled SACKEnabled
|
||||
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.
|
||||
|
|
|
@ -847,12 +847,12 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
|
|||
maxSynRetries: DefaultSynRetries,
|
||||
}
|
||||
|
||||
var ss tcpip.StackSendBufferSizeOption
|
||||
var ss SendBufferSizeOption
|
||||
if err := s.TransportProtocolOption(ProtocolNumber, &ss); err == nil {
|
||||
e.sndBufSize = ss.Default
|
||||
}
|
||||
|
||||
var rs tcpip.StackReceiveBufferSizeOption
|
||||
var rs ReceiveBufferSizeOption
|
||||
if err := s.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
|
||||
e.rcvBufSize = rs.Default
|
||||
}
|
||||
|
@ -867,7 +867,7 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
|
|||
e.rcvAutoParams.disabled = !bool(mrb)
|
||||
}
|
||||
|
||||
var de tcpip.StackDelayEnabled
|
||||
var de DelayEnabled
|
||||
if err := s.TransportProtocolOption(ProtocolNumber, &de); err == nil && de {
|
||||
e.SetSockOptBool(tcpip.DelayOption, true)
|
||||
}
|
||||
|
@ -1584,7 +1584,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 tcpip.StackReceiveBufferSizeOption
|
||||
var rs ReceiveBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
|
||||
if v < rs.Min {
|
||||
v = rs.Min
|
||||
|
@ -1634,7 +1634,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 tcpip.StackSendBufferSizeOption
|
||||
var ss SendBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &ss); err == nil {
|
||||
if v < ss.Min {
|
||||
v = ss.Min
|
||||
|
@ -1674,7 +1674,7 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
|
|||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
}
|
||||
var rs tcpip.StackReceiveBufferSizeOption
|
||||
var rs ReceiveBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
|
||||
if v < rs.Min/2 {
|
||||
v = rs.Min / 2
|
||||
|
@ -2595,7 +2595,7 @@ func (e *endpoint) receiveBufferSize() int {
|
|||
}
|
||||
|
||||
func (e *endpoint) maxReceiveBufferSize() int {
|
||||
var rs tcpip.StackReceiveBufferSizeOption
|
||||
var rs ReceiveBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err != nil {
|
||||
// As a fallback return the hardcoded max buffer size.
|
||||
return MaxBufferSize
|
||||
|
@ -2676,7 +2676,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 tcpip.StackSACKEnabled
|
||||
var v SACKEnabled
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &v); err != nil {
|
||||
// Stack doesn't support SACK. So just return.
|
||||
return
|
||||
|
|
|
@ -182,13 +182,17 @@ func (e *endpoint) Resume(s *stack.Stack) {
|
|||
epState := e.origEndpointState
|
||||
switch epState {
|
||||
case StateInitial, StateBound, StateListen, StateConnecting, StateEstablished:
|
||||
var ss tcpip.StackSendBufferSizeOption
|
||||
var ss SendBufferSizeOption
|
||||
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))
|
||||
}
|
||||
if e.rcvBufSize < ss.Min || e.rcvBufSize > ss.Max {
|
||||
panic(fmt.Sprintf("endpoint.rcvBufSize %d is outside the min and max allowed [%d, %d]", e.rcvBufSize, ss.Min, ss.Max))
|
||||
}
|
||||
|
||||
var rs ReceiveBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
|
||||
if e.rcvBufSize < rs.Min || e.rcvBufSize > rs.Max {
|
||||
panic(fmt.Sprintf("endpoint.rcvBufSize %d is outside the min and max allowed [%d, %d]", e.rcvBufSize, rs.Min, rs.Max))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,6 +76,31 @@ const (
|
|||
ccCubic = "cubic"
|
||||
)
|
||||
|
||||
// SACKEnabled is used by stack.(*Stack).TransportProtocolOption to
|
||||
// enable/disable SACK support in TCP. See: https://tools.ietf.org/html/rfc2018.
|
||||
type SACKEnabled bool
|
||||
|
||||
// DelayEnabled is used by stack.(Stack*).TransportProtocolOption to
|
||||
// enable/disable Nagle's algorithm in TCP.
|
||||
type DelayEnabled bool
|
||||
|
||||
// SendBufferSizeOption is used by stack.(Stack*).TransportProtocolOption
|
||||
// to get/set the default, min and max TCP send buffer sizes.
|
||||
type SendBufferSizeOption struct {
|
||||
Min int
|
||||
Default int
|
||||
Max int
|
||||
}
|
||||
|
||||
// ReceiveBufferSizeOption is used by
|
||||
// stack.(Stack*).TransportProtocolOption to get/set the default, min and max
|
||||
// TCP receive buffer sizes.
|
||||
type ReceiveBufferSizeOption struct {
|
||||
Min int
|
||||
Default int
|
||||
Max int
|
||||
}
|
||||
|
||||
// syncRcvdCounter tracks the number of endpoints in the SYN-RCVD state. The
|
||||
// value is protected by a mutex so that we can increment only when it's
|
||||
// guaranteed not to go above a threshold.
|
||||
|
@ -137,8 +162,8 @@ type protocol struct {
|
|||
mu sync.RWMutex
|
||||
sackEnabled bool
|
||||
delayEnabled bool
|
||||
sendBufferSize tcpip.StackSendBufferSizeOption
|
||||
recvBufferSize tcpip.StackReceiveBufferSizeOption
|
||||
sendBufferSize SendBufferSizeOption
|
||||
recvBufferSize ReceiveBufferSizeOption
|
||||
congestionControl string
|
||||
availableCongestionControl []string
|
||||
moderateReceiveBuffer bool
|
||||
|
@ -249,19 +274,19 @@ func replyWithReset(s *segment, tos, ttl uint8) {
|
|||
// SetOption implements stack.TransportProtocol.SetOption.
|
||||
func (p *protocol) SetOption(option interface{}) *tcpip.Error {
|
||||
switch v := option.(type) {
|
||||
case tcpip.StackSACKEnabled:
|
||||
case SACKEnabled:
|
||||
p.mu.Lock()
|
||||
p.sackEnabled = bool(v)
|
||||
p.mu.Unlock()
|
||||
return nil
|
||||
|
||||
case tcpip.StackDelayEnabled:
|
||||
case DelayEnabled:
|
||||
p.mu.Lock()
|
||||
p.delayEnabled = bool(v)
|
||||
p.mu.Unlock()
|
||||
return nil
|
||||
|
||||
case tcpip.StackSendBufferSizeOption:
|
||||
case SendBufferSizeOption:
|
||||
if v.Min <= 0 || v.Default < v.Min || v.Default > v.Max {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
@ -270,7 +295,7 @@ func (p *protocol) SetOption(option interface{}) *tcpip.Error {
|
|||
p.mu.Unlock()
|
||||
return nil
|
||||
|
||||
case tcpip.StackReceiveBufferSizeOption:
|
||||
case ReceiveBufferSizeOption:
|
||||
if v.Min <= 0 || v.Default < v.Min || v.Default > v.Max {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
|
@ -363,25 +388,25 @@ func (p *protocol) SetOption(option interface{}) *tcpip.Error {
|
|||
// Option implements stack.TransportProtocol.Option.
|
||||
func (p *protocol) Option(option interface{}) *tcpip.Error {
|
||||
switch v := option.(type) {
|
||||
case *tcpip.StackSACKEnabled:
|
||||
case *SACKEnabled:
|
||||
p.mu.RLock()
|
||||
*v = tcpip.StackSACKEnabled(p.sackEnabled)
|
||||
*v = SACKEnabled(p.sackEnabled)
|
||||
p.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
case *tcpip.StackDelayEnabled:
|
||||
case *DelayEnabled:
|
||||
p.mu.RLock()
|
||||
*v = tcpip.StackDelayEnabled(p.delayEnabled)
|
||||
*v = DelayEnabled(p.delayEnabled)
|
||||
p.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
case *tcpip.StackSendBufferSizeOption:
|
||||
case *SendBufferSizeOption:
|
||||
p.mu.RLock()
|
||||
*v = p.sendBufferSize
|
||||
p.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
case *tcpip.StackReceiveBufferSizeOption:
|
||||
case *ReceiveBufferSizeOption:
|
||||
p.mu.RLock()
|
||||
*v = p.recvBufferSize
|
||||
p.mu.RUnlock()
|
||||
|
@ -491,12 +516,12 @@ func (*protocol) Parse(pkt *stack.PacketBuffer) bool {
|
|||
// NewProtocol returns a TCP transport protocol.
|
||||
func NewProtocol() stack.TransportProtocol {
|
||||
return &protocol{
|
||||
sendBufferSize: tcpip.StackSendBufferSizeOption{
|
||||
sendBufferSize: SendBufferSizeOption{
|
||||
Min: MinBufferSize,
|
||||
Default: DefaultSendBufferSize,
|
||||
Max: MaxBufferSize,
|
||||
},
|
||||
recvBufferSize: tcpip.StackReceiveBufferSizeOption{
|
||||
recvBufferSize: ReceiveBufferSizeOption{
|
||||
Min: MinBufferSize,
|
||||
Default: DefaultReceiveBufferSize,
|
||||
Max: MaxBufferSize,
|
||||
|
|
|
@ -46,8 +46,8 @@ func createConnectedWithSACKAndTS(c *context.Context) *context.RawEndpoint {
|
|||
|
||||
func setStackSACKPermitted(t *testing.T, c *context.Context, enable bool) {
|
||||
t.Helper()
|
||||
if err := c.Stack().SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSACKEnabled(enable)); err != nil {
|
||||
t.Fatalf("c.s.SetTransportProtocolOption(tcp.ProtocolNumber, StackSACKEnabled(%t) = %s", enable, err)
|
||||
if err := c.Stack().SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SACKEnabled(enable)); err != nil {
|
||||
t.Fatalf("c.s.SetTransportProtocolOption(tcp.ProtocolNumber, SACKEnabled(%t) = %s", enable, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4005,7 +4005,7 @@ func TestDefaultBufferSizes(t *testing.T) {
|
|||
checkRecvBufferSize(t, ep, tcp.DefaultReceiveBufferSize)
|
||||
|
||||
// Change the default send buffer size.
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSendBufferSizeOption{
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SendBufferSizeOption{
|
||||
Min: 1,
|
||||
Default: tcp.DefaultSendBufferSize * 2,
|
||||
Max: tcp.DefaultSendBufferSize * 20}); err != nil {
|
||||
|
@ -4022,7 +4022,7 @@ func TestDefaultBufferSizes(t *testing.T) {
|
|||
checkRecvBufferSize(t, ep, tcp.DefaultReceiveBufferSize)
|
||||
|
||||
// Change the default receive buffer size.
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackReceiveBufferSizeOption{
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{
|
||||
Min: 1,
|
||||
Default: tcp.DefaultReceiveBufferSize * 3,
|
||||
Max: tcp.DefaultReceiveBufferSize * 30}); err != nil {
|
||||
|
@ -4053,11 +4053,11 @@ func TestMinMaxBufferSizes(t *testing.T) {
|
|||
defer ep.Close()
|
||||
|
||||
// Change the min/max values for send/receive
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackReceiveBufferSizeOption{Min: 200, Default: tcp.DefaultReceiveBufferSize * 2, Max: tcp.DefaultReceiveBufferSize * 20}); err != nil {
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{Min: 200, Default: tcp.DefaultReceiveBufferSize * 2, Max: tcp.DefaultReceiveBufferSize * 20}); err != nil {
|
||||
t.Fatalf("SetTransportProtocolOption failed: %s", err)
|
||||
}
|
||||
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSendBufferSizeOption{Min: 300, Default: tcp.DefaultSendBufferSize * 3, Max: tcp.DefaultSendBufferSize * 30}); err != nil {
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SendBufferSizeOption{Min: 300, Default: tcp.DefaultSendBufferSize * 3, Max: tcp.DefaultSendBufferSize * 30}); err != nil {
|
||||
t.Fatalf("SetTransportProtocolOption failed: %s", err)
|
||||
}
|
||||
|
||||
|
@ -5696,7 +5696,7 @@ func TestReceiveBufferAutoTuningApplicationLimited(t *testing.T) {
|
|||
// the segment queue holding unprocessed packets is limited to 500.
|
||||
const receiveBufferSize = 80 << 10 // 80KB.
|
||||
const maxReceiveBufferSize = receiveBufferSize * 10
|
||||
if err := stk.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackReceiveBufferSizeOption{Min: 1, Default: receiveBufferSize, Max: maxReceiveBufferSize}); err != nil {
|
||||
if err := stk.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{Min: 1, Default: receiveBufferSize, Max: maxReceiveBufferSize}); err != nil {
|
||||
t.Fatalf("SetTransportProtocolOption failed: %s", err)
|
||||
}
|
||||
|
||||
|
@ -5817,7 +5817,7 @@ func TestReceiveBufferAutoTuning(t *testing.T) {
|
|||
// the segment queue holding unprocessed packets is limited to 300.
|
||||
const receiveBufferSize = 80 << 10 // 80KB.
|
||||
const maxReceiveBufferSize = receiveBufferSize * 10
|
||||
if err := stk.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackReceiveBufferSizeOption{Min: 1, Default: receiveBufferSize, Max: maxReceiveBufferSize}); err != nil {
|
||||
if err := stk.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{Min: 1, Default: receiveBufferSize, Max: maxReceiveBufferSize}); err != nil {
|
||||
t.Fatalf("SetTransportProtocolOption failed: %s", err)
|
||||
}
|
||||
|
||||
|
@ -5959,7 +5959,7 @@ func TestDelayEnabled(t *testing.T) {
|
|||
checkDelayOption(t, c, false, false) // Delay is disabled by default.
|
||||
|
||||
for _, v := range []struct {
|
||||
delayEnabled tcpip.StackDelayEnabled
|
||||
delayEnabled tcp.DelayEnabled
|
||||
wantDelayOption bool
|
||||
}{
|
||||
{delayEnabled: false, wantDelayOption: false},
|
||||
|
@ -5974,10 +5974,10 @@ func TestDelayEnabled(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func checkDelayOption(t *testing.T, c *context.Context, wantDelayEnabled tcpip.StackDelayEnabled, wantDelayOption bool) {
|
||||
func checkDelayOption(t *testing.T, c *context.Context, wantDelayEnabled tcp.DelayEnabled, wantDelayOption bool) {
|
||||
t.Helper()
|
||||
|
||||
var gotDelayEnabled tcpip.StackDelayEnabled
|
||||
var gotDelayEnabled tcp.DelayEnabled
|
||||
if err := c.Stack().TransportProtocolOption(tcp.ProtocolNumber, &gotDelayEnabled); err != nil {
|
||||
t.Fatalf("TransportProtocolOption(tcp, &gotDelayEnabled) failed: %s", err)
|
||||
}
|
||||
|
|
|
@ -144,11 +144,11 @@ func New(t *testing.T, mtu uint32) *Context {
|
|||
})
|
||||
|
||||
// Allow minimum send/receive buffer sizes to be 1 during tests.
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSendBufferSizeOption{Min: 1, Default: tcp.DefaultSendBufferSize, Max: 10 * tcp.DefaultSendBufferSize}); err != nil {
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SendBufferSizeOption{Min: 1, Default: tcp.DefaultSendBufferSize, Max: 10 * tcp.DefaultSendBufferSize}); err != nil {
|
||||
t.Fatalf("SetTransportProtocolOption failed: %s", err)
|
||||
}
|
||||
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackReceiveBufferSizeOption{Min: 1, Default: tcp.DefaultReceiveBufferSize, Max: 10 * tcp.DefaultReceiveBufferSize}); err != nil {
|
||||
if err := s.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.ReceiveBufferSizeOption{Min: 1, Default: tcp.DefaultReceiveBufferSize, Max: 10 * tcp.DefaultReceiveBufferSize}); err != nil {
|
||||
t.Fatalf("SetTransportProtocolOption failed: %s", err)
|
||||
}
|
||||
|
||||
|
@ -1091,7 +1091,7 @@ func (c *Context) PassiveConnectWithOptions(maxPayload, wndScale int, synOptions
|
|||
// SACKEnabled returns true if the TCP Protocol option SACKEnabled is set to true
|
||||
// for the Stack in the context.
|
||||
func (c *Context) SACKEnabled() bool {
|
||||
var v tcpip.StackSACKEnabled
|
||||
var v tcp.SACKEnabled
|
||||
if err := c.Stack().TransportProtocolOption(tcp.ProtocolNumber, &v); err != nil {
|
||||
// Stack doesn't support SACK. So just return.
|
||||
return false
|
||||
|
|
|
@ -190,13 +190,13 @@ func newEndpoint(s *stack.Stack, netProto tcpip.NetworkProtocolNumber, waiterQue
|
|||
}
|
||||
|
||||
// Override with stack defaults.
|
||||
var ss tcpip.StackSendBufferSizeOption
|
||||
if err := s.TransportProtocolOption(ProtocolNumber, &ss); err == nil {
|
||||
var ss stack.SendBufferSizeOption
|
||||
if err := s.Option(&ss); err == nil {
|
||||
e.sndBufSizeMax = ss.Default
|
||||
}
|
||||
|
||||
var rs tcpip.StackReceiveBufferSizeOption
|
||||
if err := s.TransportProtocolOption(ProtocolNumber, &rs); err == nil {
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
if err := s.Option(&rs); err == nil {
|
||||
e.rcvBufSizeMax = rs.Default
|
||||
}
|
||||
|
||||
|
@ -629,9 +629,9 @@ 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 tcpip.StackReceiveBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &rs); err != nil {
|
||||
panic(fmt.Sprintf("e.stack.TransportProtocolOption(%d, %+v) = %s", ProtocolNumber, rs, err))
|
||||
var rs stack.ReceiveBufferSizeOption
|
||||
if err := e.stack.Option(&rs); err != nil {
|
||||
panic(fmt.Sprintf("e.stack.Option(%#v) = %s", rs, err))
|
||||
}
|
||||
|
||||
if v < rs.Min {
|
||||
|
@ -648,9 +648,9 @@ 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 tcpip.StackSendBufferSizeOption
|
||||
if err := e.stack.TransportProtocolOption(ProtocolNumber, &ss); err != nil {
|
||||
panic(fmt.Sprintf("e.stack.TransportProtocolOption(%d, %+v) = %s", ProtocolNumber, ss, err))
|
||||
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 {
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
package udp
|
||||
|
||||
import (
|
||||
"gvisor.dev/gvisor/pkg/sync"
|
||||
"gvisor.dev/gvisor/pkg/tcpip"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/buffer"
|
||||
"gvisor.dev/gvisor/pkg/tcpip/header"
|
||||
|
@ -50,9 +49,6 @@ const (
|
|||
)
|
||||
|
||||
type protocol struct {
|
||||
mu sync.RWMutex
|
||||
sendBufferSize tcpip.StackSendBufferSizeOption
|
||||
recvBufferSize tcpip.StackReceiveBufferSizeOption
|
||||
}
|
||||
|
||||
// Number returns the udp protocol number.
|
||||
|
@ -203,48 +199,12 @@ func (p *protocol) HandleUnknownDestinationPacket(r *stack.Route, id stack.Trans
|
|||
|
||||
// SetOption implements stack.TransportProtocol.SetOption.
|
||||
func (p *protocol) SetOption(option interface{}) *tcpip.Error {
|
||||
switch v := option.(type) {
|
||||
case tcpip.StackSendBufferSizeOption:
|
||||
if v.Min <= 0 || v.Default < v.Min || v.Default > v.Max {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
p.mu.Lock()
|
||||
p.sendBufferSize = v
|
||||
p.mu.Unlock()
|
||||
return nil
|
||||
|
||||
case tcpip.StackReceiveBufferSizeOption:
|
||||
if v.Min <= 0 || v.Default < v.Min || v.Default > v.Max {
|
||||
return tcpip.ErrInvalidOptionValue
|
||||
}
|
||||
p.mu.Lock()
|
||||
p.recvBufferSize = v
|
||||
p.mu.Unlock()
|
||||
return nil
|
||||
|
||||
default:
|
||||
return tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
return tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
|
||||
// Option implements stack.TransportProtocol.Option.
|
||||
func (p *protocol) Option(option interface{}) *tcpip.Error {
|
||||
switch v := option.(type) {
|
||||
case *tcpip.StackSendBufferSizeOption:
|
||||
p.mu.RLock()
|
||||
*v = p.sendBufferSize
|
||||
p.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
case *tcpip.StackReceiveBufferSizeOption:
|
||||
p.mu.RLock()
|
||||
*v = p.recvBufferSize
|
||||
p.mu.RUnlock()
|
||||
return nil
|
||||
|
||||
default:
|
||||
return tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
return tcpip.ErrUnknownProtocolOption
|
||||
}
|
||||
|
||||
// Close implements stack.TransportProtocol.Close.
|
||||
|
@ -267,8 +227,5 @@ func (*protocol) Parse(pkt *stack.PacketBuffer) bool {
|
|||
|
||||
// NewProtocol returns a UDP transport protocol.
|
||||
func NewProtocol() stack.TransportProtocol {
|
||||
return &protocol{
|
||||
sendBufferSize: tcpip.StackSendBufferSizeOption{Min: MinBufferSize, Default: DefaultSendBufferSize, Max: MaxBufferSize},
|
||||
recvBufferSize: tcpip.StackReceiveBufferSizeOption{Min: MinBufferSize, Default: DefaultReceiveBufferSize, Max: MaxBufferSize},
|
||||
}
|
||||
return &protocol{}
|
||||
}
|
||||
|
|
|
@ -1058,7 +1058,7 @@ func newEmptySandboxNetworkStack(clock tcpip.Clock, uniqueID stack.UniqueID) (in
|
|||
})}
|
||||
|
||||
// Enable SACK Recovery.
|
||||
if err := s.Stack.SetTransportProtocolOption(tcp.ProtocolNumber, tcpip.StackSACKEnabled(true)); err != nil {
|
||||
if err := s.Stack.SetTransportProtocolOption(tcp.ProtocolNumber, tcp.SACKEnabled(true)); err != nil {
|
||||
return nil, fmt.Errorf("failed to enable SACK: %s", err)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue