Convert int and bool socket options to use GetSockOptInt and GetSockOptBool

PiperOrigin-RevId: 305699233
This commit is contained in:
Andrei Vagin
2020-04-09 09:31:48 -07:00
committed by gVisor bot
parent 1ebfdcc86c
commit 7928aa345e
11 changed files with 586 additions and 659 deletions
+62 -93
View File
@@ -300,7 +300,7 @@ type SocketOperations struct {
// New creates a new endpoint socket.
func New(t *kernel.Task, family int, skType linux.SockType, protocol int, queue *waiter.Queue, endpoint tcpip.Endpoint) (*fs.File, *syserr.Error) {
if skType == linux.SOCK_STREAM {
if err := endpoint.SetSockOptInt(tcpip.DelayOption, 1); err != nil {
if err := endpoint.SetSockOptBool(tcpip.DelayOption, true); err != nil {
return nil, syserr.TranslateNetstackError(err)
}
}
@@ -965,6 +965,13 @@ func GetSockOpt(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, family in
return nil, syserr.ErrProtocolNotAvailable
}
func boolToInt32(v bool) int32 {
if v {
return 1
}
return 0
}
// getSockOptSocket implements GetSockOpt when level is SOL_SOCKET.
func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, family int, skType linux.SockType, name, outLen int) (interface{}, *syserr.Error) {
// TODO(b/124056281): Stop rejecting short optLen values in getsockopt.
@@ -998,12 +1005,11 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
return nil, syserr.ErrInvalidArgument
}
var v tcpip.PasscredOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.PasscredOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
return boolToInt32(v), nil
case linux.SO_SNDBUF:
if outLen < sizeOfInt32 {
@@ -1042,24 +1048,22 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
return nil, syserr.ErrInvalidArgument
}
var v tcpip.ReuseAddressOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.ReuseAddressOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
return boolToInt32(v), nil
case linux.SO_REUSEPORT:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
var v tcpip.ReusePortOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.ReusePortOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
return boolToInt32(v), nil
case linux.SO_BINDTODEVICE:
var v tcpip.BindToDeviceOption
@@ -1089,24 +1093,22 @@ func getSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, fam
return nil, syserr.ErrInvalidArgument
}
var v tcpip.BroadcastOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.BroadcastOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
return boolToInt32(v), nil
case linux.SO_KEEPALIVE:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
var v tcpip.KeepaliveEnabledOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.KeepaliveEnabledOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
return boolToInt32(v), nil
case linux.SO_LINGER:
if outLen < linux.SizeOfLinger {
@@ -1156,47 +1158,41 @@ func getSockOptTCP(t *kernel.Task, ep commonEndpoint, name, outLen int) (interfa
return nil, syserr.ErrInvalidArgument
}
v, err := ep.GetSockOptInt(tcpip.DelayOption)
v, err := ep.GetSockOptBool(tcpip.DelayOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
if v == 0 {
return int32(1), nil
}
return int32(0), nil
return boolToInt32(!v), nil
case linux.TCP_CORK:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
var v tcpip.CorkOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.CorkOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
return boolToInt32(v), nil
case linux.TCP_QUICKACK:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
var v tcpip.QuickAckOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.QuickAckOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
return int32(v), nil
return boolToInt32(v), nil
case linux.TCP_MAXSEG:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
var v tcpip.MaxSegOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptInt(tcpip.MaxSegOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
@@ -1328,11 +1324,7 @@ func getSockOptIPv6(t *kernel.Task, ep commonEndpoint, name, outLen int) (interf
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
var o int32
if v {
o = 1
}
return o, nil
return boolToInt32(v), nil
case linux.IPV6_PATHMTU:
t.Kernel().EmitUnimplementedEvent(t)
@@ -1342,8 +1334,8 @@ func getSockOptIPv6(t *kernel.Task, ep commonEndpoint, name, outLen int) (interf
if outLen == 0 {
return make([]byte, 0), nil
}
var v tcpip.IPv6TrafficClassOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptInt(tcpip.IPv6TrafficClassOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
@@ -1365,12 +1357,7 @@ func getSockOptIPv6(t *kernel.Task, ep commonEndpoint, name, outLen int) (interf
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
var o int32
if v {
o = 1
}
return o, nil
return boolToInt32(v), nil
default:
emitUnimplementedEventIPv6(t, name)
@@ -1386,8 +1373,8 @@ func getSockOptIP(t *kernel.Task, ep commonEndpoint, name, outLen int, family in
return nil, syserr.ErrInvalidArgument
}
var v tcpip.TTLOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptInt(tcpip.TTLOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
@@ -1403,8 +1390,8 @@ func getSockOptIP(t *kernel.Task, ep commonEndpoint, name, outLen int, family in
return nil, syserr.ErrInvalidArgument
}
var v tcpip.MulticastTTLOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptInt(tcpip.MulticastTTLOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
@@ -1429,23 +1416,19 @@ func getSockOptIP(t *kernel.Task, ep commonEndpoint, name, outLen int, family in
return nil, syserr.ErrInvalidArgument
}
var v tcpip.MulticastLoopOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptBool(tcpip.MulticastLoopOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
if v {
return int32(1), nil
}
return int32(0), nil
return boolToInt32(v), nil
case linux.IP_TOS:
// Length handling for parity with Linux.
if outLen == 0 {
return []byte(nil), nil
}
var v tcpip.IPv4TOSOption
if err := ep.GetSockOpt(&v); err != nil {
v, err := ep.GetSockOptInt(tcpip.IPv4TOSOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
if outLen < sizeOfInt32 {
@@ -1462,11 +1445,7 @@ func getSockOptIP(t *kernel.Task, ep commonEndpoint, name, outLen int, family in
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
var o int32
if v {
o = 1
}
return o, nil
return boolToInt32(v), nil
case linux.IP_PKTINFO:
if outLen < sizeOfInt32 {
@@ -1477,11 +1456,7 @@ func getSockOptIP(t *kernel.Task, ep commonEndpoint, name, outLen int, family in
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
var o int32
if v {
o = 1
}
return o, nil
return boolToInt32(v), nil
default:
emitUnimplementedEventIP(t, name)
@@ -1592,7 +1567,7 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.ReuseAddressOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.ReuseAddressOption, v != 0))
case linux.SO_REUSEPORT:
if len(optVal) < sizeOfInt32 {
@@ -1600,7 +1575,7 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.ReusePortOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.ReusePortOption, v != 0))
case linux.SO_BINDTODEVICE:
n := bytes.IndexByte(optVal, 0)
@@ -1628,7 +1603,7 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.BroadcastOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.BroadcastOption, v != 0))
case linux.SO_PASSCRED:
if len(optVal) < sizeOfInt32 {
@@ -1636,7 +1611,7 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.PasscredOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.PasscredOption, v != 0))
case linux.SO_KEEPALIVE:
if len(optVal) < sizeOfInt32 {
@@ -1644,7 +1619,7 @@ func setSockOptSocket(t *kernel.Task, s socket.SocketOps, ep commonEndpoint, nam
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.KeepaliveEnabledOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.KeepaliveEnabledOption, v != 0))
case linux.SO_SNDTIMEO:
if len(optVal) < linux.SizeOfTimeval {
@@ -1716,11 +1691,7 @@ func setSockOptTCP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *
}
v := usermem.ByteOrder.Uint32(optVal)
var o int
if v == 0 {
o = 1
}
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.DelayOption, o))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.DelayOption, v == 0))
case linux.TCP_CORK:
if len(optVal) < sizeOfInt32 {
@@ -1728,7 +1699,7 @@ func setSockOptTCP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.CorkOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.CorkOption, v != 0))
case linux.TCP_QUICKACK:
if len(optVal) < sizeOfInt32 {
@@ -1736,7 +1707,7 @@ func setSockOptTCP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.QuickAckOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.QuickAckOption, v != 0))
case linux.TCP_MAXSEG:
if len(optVal) < sizeOfInt32 {
@@ -1744,7 +1715,7 @@ func setSockOptTCP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *
}
v := usermem.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.MaxSegOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.MaxSegOption, int(v)))
case linux.TCP_KEEPIDLE:
if len(optVal) < sizeOfInt32 {
@@ -1855,7 +1826,7 @@ func setSockOptIPv6(t *kernel.Task, ep commonEndpoint, name int, optVal []byte)
if v == -1 {
v = 0
}
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.IPv6TrafficClassOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.IPv6TrafficClassOption, int(v)))
case linux.IPV6_RECVTCLASS:
v, err := parseIntOrChar(optVal)
@@ -1940,7 +1911,7 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s
if v < 0 || v > 255 {
return syserr.ErrInvalidArgument
}
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.MulticastTTLOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.MulticastTTLOption, int(v)))
case linux.IP_ADD_MEMBERSHIP:
req, err := copyInMulticastRequest(optVal, false /* allowAddr */)
@@ -1987,9 +1958,7 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s
return err
}
return syserr.TranslateNetstackError(ep.SetSockOpt(
tcpip.MulticastLoopOption(v != 0),
))
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.MulticastLoopOption, v != 0))
case linux.MCAST_JOIN_GROUP:
// FIXME(b/124219304): Implement MCAST_JOIN_GROUP.
@@ -2008,7 +1977,7 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s
} else if v < 1 || v > 255 {
return syserr.ErrInvalidArgument
}
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.TTLOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.TTLOption, int(v)))
case linux.IP_TOS:
if len(optVal) == 0 {
@@ -2018,7 +1987,7 @@ func setSockOptIP(t *kernel.Task, ep commonEndpoint, name int, optVal []byte) *s
if err != nil {
return err
}
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.IPv4TOSOption(v)))
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.IPv4TOSOption, int(v)))
case linux.IP_RECVTOS:
v, err := parseIntOrChar(optVal)
+1
View File
@@ -30,6 +30,7 @@ go_library(
"//pkg/abi/linux",
"//pkg/context",
"//pkg/ilist",
"//pkg/log",
"//pkg/refs",
"//pkg/sync",
"//pkg/syserr",
+31 -19
View File
@@ -20,6 +20,7 @@ import (
"gvisor.dev/gvisor/pkg/abi/linux"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/log"
"gvisor.dev/gvisor/pkg/sync"
"gvisor.dev/gvisor/pkg/syserr"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -838,24 +839,45 @@ func (e *baseEndpoint) SendMsg(ctx context.Context, data [][]byte, c ControlMess
// SetSockOpt sets a socket option. Currently not supported.
func (e *baseEndpoint) SetSockOpt(opt interface{}) *tcpip.Error {
switch v := opt.(type) {
case tcpip.PasscredOption:
e.setPasscred(v != 0)
return nil
}
return nil
}
func (e *baseEndpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {
switch opt {
case tcpip.BroadcastOption:
case tcpip.PasscredOption:
e.setPasscred(v)
case tcpip.ReuseAddressOption:
default:
log.Warningf("Unsupported socket option: %d", opt)
return tcpip.ErrUnknownProtocolOption
}
return nil
}
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)
return tcpip.ErrUnknownProtocolOption
}
return nil
}
func (e *baseEndpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
return false, tcpip.ErrUnknownProtocolOption
switch opt {
case tcpip.KeepaliveEnabledOption:
return false, nil
case tcpip.PasscredOption:
return e.Passcred(), nil
default:
log.Warningf("Unsupported socket option: %d", opt)
return false, tcpip.ErrUnknownProtocolOption
}
}
func (e *baseEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
@@ -914,29 +936,19 @@ func (e *baseEndpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
return int(v), nil
default:
log.Warningf("Unsupported socket option: %d", opt)
return -1, tcpip.ErrUnknownProtocolOption
}
}
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (e *baseEndpoint) GetSockOpt(opt interface{}) *tcpip.Error {
switch o := opt.(type) {
switch opt.(type) {
case tcpip.ErrorOption:
return nil
case *tcpip.PasscredOption:
if e.Passcred() {
*o = tcpip.PasscredOption(1)
} else {
*o = tcpip.PasscredOption(0)
}
return nil
case *tcpip.KeepaliveEnabledOption:
*o = 0
return nil
default:
log.Warningf("Unsupported socket option: %T", opt)
return tcpip.ErrUnknownProtocolOption
}
}
+17 -18
View File
@@ -206,7 +206,7 @@ func TestTransportDemuxerRegister(t *testing.T) {
// the distribution of packets received matches expectations.
func TestBindToDeviceDistribution(t *testing.T) {
type endpointSockopts struct {
reuse int
reuse bool
bindToDevice tcpip.NICID
}
for _, test := range []struct {
@@ -221,11 +221,11 @@ func TestBindToDeviceDistribution(t *testing.T) {
"BindPortReuse",
// 5 endpoints that all have reuse set.
[]endpointSockopts{
{reuse: 1, bindToDevice: 0},
{reuse: 1, bindToDevice: 0},
{reuse: 1, bindToDevice: 0},
{reuse: 1, bindToDevice: 0},
{reuse: 1, bindToDevice: 0},
{reuse: true, bindToDevice: 0},
{reuse: true, bindToDevice: 0},
{reuse: true, bindToDevice: 0},
{reuse: true, bindToDevice: 0},
{reuse: true, bindToDevice: 0},
},
map[tcpip.NICID][]float64{
// Injected packets on dev0 get distributed evenly.
@@ -236,9 +236,9 @@ func TestBindToDeviceDistribution(t *testing.T) {
"BindToDevice",
// 3 endpoints with various bindings.
[]endpointSockopts{
{reuse: 0, bindToDevice: 1},
{reuse: 0, bindToDevice: 2},
{reuse: 0, bindToDevice: 3},
{reuse: false, bindToDevice: 1},
{reuse: false, bindToDevice: 2},
{reuse: false, bindToDevice: 3},
},
map[tcpip.NICID][]float64{
// Injected packets on dev0 go only to the endpoint bound to dev0.
@@ -253,12 +253,12 @@ func TestBindToDeviceDistribution(t *testing.T) {
"ReuseAndBindToDevice",
// 6 endpoints with various bindings.
[]endpointSockopts{
{reuse: 1, bindToDevice: 1},
{reuse: 1, bindToDevice: 1},
{reuse: 1, bindToDevice: 2},
{reuse: 1, bindToDevice: 2},
{reuse: 1, bindToDevice: 2},
{reuse: 1, bindToDevice: 0},
{reuse: true, bindToDevice: 1},
{reuse: true, bindToDevice: 1},
{reuse: true, bindToDevice: 2},
{reuse: true, bindToDevice: 2},
{reuse: true, bindToDevice: 2},
{reuse: true, bindToDevice: 0},
},
map[tcpip.NICID][]float64{
// Injected packets on dev0 get distributed among endpoints bound to
@@ -309,9 +309,8 @@ func TestBindToDeviceDistribution(t *testing.T) {
}(ep)
defer ep.Close()
reusePortOption := tcpip.ReusePortOption(endpoint.reuse)
if err := ep.SetSockOpt(reusePortOption); err != nil {
t.Fatalf("SetSockOpt(%#v) on endpoint %d failed: %s", reusePortOption, i, err)
if err := ep.SetSockOptBool(tcpip.ReusePortOption, endpoint.reuse); err != nil {
t.Fatalf("SetSockOptBool(ReusePortOption, %t) on endpoint %d failed: %s", endpoint.reuse, i, err)
}
bindToDeviceOption := tcpip.BindToDeviceOption(endpoint.bindToDevice)
if err := ep.SetSockOpt(bindToDeviceOption); err != nil {
+69 -76
View File
@@ -520,34 +520,90 @@ type WriteOptions struct {
type SockOptBool int
const (
// BroadcastOption is used by SetSockOpt/GetSockOpt to specify whether
// datagram sockets are allowed to send packets to a broadcast address.
BroadcastOption SockOptBool = iota
// CorkOption is used by SetSockOpt/GetSockOpt to specify if data should be
// held until segments are full by the TCP transport protocol.
CorkOption
// DelayOption is used by SetSockOpt/GetSockOpt to specify if data
// should be sent out immediately by the transport protocol. For TCP,
// it determines if the Nagle algorithm is on or off.
DelayOption
// KeepaliveEnabledOption is used by SetSockOpt/GetSockOpt to specify whether
// TCP keepalive is enabled for this socket.
KeepaliveEnabledOption
// MulticastLoopOption is used by SetSockOpt/GetSockOpt to specify whether
// multicast packets sent over a non-loopback interface will be looped back.
MulticastLoopOption
// PasscredOption is used by SetSockOpt/GetSockOpt to specify whether
// SCM_CREDENTIALS socket control messages are enabled.
//
// Only supported on Unix sockets.
PasscredOption
// QuickAckOption is stubbed out in SetSockOpt/GetSockOpt.
QuickAckOption
// ReceiveTClassOption is used by SetSockOpt/GetSockOpt to specify if the
// IPV6_TCLASS ancillary message is passed with incoming packets.
ReceiveTClassOption SockOptBool = iota
ReceiveTClassOption
// ReceiveTOSOption is used by SetSockOpt/GetSockOpt to specify if the TOS
// ancillary message is passed with incoming packets.
ReceiveTOSOption
// V6OnlyOption is used by {G,S}etSockOptBool to specify whether an IPv6
// socket is to be restricted to sending and receiving IPv6 packets only.
V6OnlyOption
// ReceiveIPPacketInfoOption is used by {G,S}etSockOptBool to specify
// if more inforamtion is provided with incoming packets such
// as interface index and address.
ReceiveIPPacketInfoOption
// TODO(b/146901447): convert existing bool socket options to be handled via
// Get/SetSockOptBool
// ReuseAddressOption is used by SetSockOpt/GetSockOpt to specify whether Bind()
// should allow reuse of local address.
ReuseAddressOption
// ReusePortOption is used by SetSockOpt/GetSockOpt to permit multiple sockets
// to be bound to an identical socket address.
ReusePortOption
// V6OnlyOption is used by {G,S}etSockOptBool to specify whether an IPv6
// socket is to be restricted to sending and receiving IPv6 packets only.
V6OnlyOption
)
// SockOptInt represents socket options which values have the int type.
type SockOptInt int
const (
// KeepaliveCountOption is used by SetSockOpt/GetSockOpt to specify the number
// of un-ACKed TCP keepalives that will be sent before the connection is
// closed.
KeepaliveCountOption SockOptInt = iota
// IPv4TOSOption is used by SetSockOpt/GetSockOpt to specify TOS
// for all subsequent outgoing IPv4 packets from the endpoint.
IPv4TOSOption
// IPv6TrafficClassOption is used by SetSockOpt/GetSockOpt to specify TOS
// for all subsequent outgoing IPv6 packets from the endpoint.
IPv6TrafficClassOption
// MaxSegOption is used by SetSockOpt/GetSockOpt to set/get the current
// Maximum Segment Size(MSS) value as specified using the TCP_MAXSEG option.
MaxSegOption
// MulticastTTLOption is used by SetSockOpt/GetSockOpt to control the default
// TTL value for multicast messages. The default is 1.
MulticastTTLOption
// ReceiveQueueSizeOption is used in GetSockOptInt to specify that the
// number of unread bytes in the input buffer should be returned.
ReceiveQueueSizeOption SockOptInt = iota
ReceiveQueueSizeOption
// SendBufferSizeOption is used by SetSockOptInt/GetSockOptInt to
// specify the send buffer size option.
@@ -561,44 +617,21 @@ const (
// number of unread bytes in the output buffer should be returned.
SendQueueSizeOption
// DelayOption is used by SetSockOpt/GetSockOpt to specify if data
// should be sent out immediately by the transport protocol. For TCP,
// it determines if the Nagle algorithm is on or off.
DelayOption
// TODO(b/137664753): convert all int socket options to be handled via
// GetSockOptInt.
// TTLOption is used by SetSockOpt/GetSockOpt to control the default TTL/hop
// limit value for unicast messages. The default is protocol specific.
//
// A zero value indicates the default.
TTLOption
)
// ErrorOption is used in GetSockOpt to specify that the last error reported by
// the endpoint should be cleared and returned.
type ErrorOption struct{}
// CorkOption is used by SetSockOpt/GetSockOpt to specify if data should be
// held until segments are full by the TCP transport protocol.
type CorkOption int
// ReuseAddressOption is used by SetSockOpt/GetSockOpt to specify whether Bind()
// should allow reuse of local address.
type ReuseAddressOption int
// ReusePortOption is used by SetSockOpt/GetSockOpt to permit multiple sockets
// to be bound to an identical socket address.
type ReusePortOption int
// BindToDeviceOption is used by SetSockOpt/GetSockOpt to specify that sockets
// should bind only on a specific NIC.
type BindToDeviceOption NICID
// QuickAckOption is stubbed out in SetSockOpt/GetSockOpt.
type QuickAckOption int
// PasscredOption is used by SetSockOpt/GetSockOpt to specify whether
// SCM_CREDENTIALS socket control messages are enabled.
//
// Only supported on Unix sockets.
type PasscredOption int
// TCPInfoOption is used by GetSockOpt to expose TCP statistics.
//
// TODO(b/64800844): Add and populate stat fields.
@@ -607,10 +640,6 @@ type TCPInfoOption struct {
RTTVar time.Duration
}
// KeepaliveEnabledOption is used by SetSockOpt/GetSockOpt to specify whether
// TCP keepalive is enabled for this socket.
type KeepaliveEnabledOption int
// KeepaliveIdleOption is used by SetSockOpt/GetSockOpt to specify the time a
// connection must remain idle before the first TCP keepalive packet is sent.
// Once this time is reached, KeepaliveIntervalOption is used instead.
@@ -620,11 +649,6 @@ type KeepaliveIdleOption time.Duration
// interval between sending TCP keepalive packets.
type KeepaliveIntervalOption time.Duration
// KeepaliveCountOption is used by SetSockOpt/GetSockOpt to specify the number
// of un-ACKed TCP keepalives that will be sent before the connection is
// closed.
type KeepaliveCountOption int
// TCPUserTimeoutOption is used by SetSockOpt/GetSockOpt to specify a user
// specified timeout for a given TCP connection.
// See: RFC5482 for details.
@@ -638,20 +662,9 @@ type CongestionControlOption string
// control algorithms.
type AvailableCongestionControlOption string
// ModerateReceiveBufferOption allows the caller to enable/disable TCP receive
// buffer moderation.
type ModerateReceiveBufferOption bool
// MaxSegOption is used by SetSockOpt/GetSockOpt to set/get the current
// Maximum Segment Size(MSS) value as specified using the TCP_MAXSEG option.
type MaxSegOption int
// TTLOption is used by SetSockOpt/GetSockOpt to control the default TTL/hop
// limit value for unicast messages. The default is protocol specific.
//
// A zero value indicates the default.
type TTLOption uint8
// TCPLingerTimeoutOption is used by SetSockOpt/GetSockOpt to set/get the
// maximum duration for which a socket lingers in the TCP_FIN_WAIT_2 state
// before being marked closed.
@@ -668,10 +681,6 @@ type TCPTimeWaitTimeoutOption time.Duration
// for a handshake till the specified timeout until a segment with data arrives.
type TCPDeferAcceptOption time.Duration
// MulticastTTLOption is used by SetSockOpt/GetSockOpt to control the default
// TTL value for multicast messages. The default is 1.
type MulticastTTLOption uint8
// MulticastInterfaceOption is used by SetSockOpt/GetSockOpt to specify a
// default interface for multicast.
type MulticastInterfaceOption struct {
@@ -679,10 +688,6 @@ type MulticastInterfaceOption struct {
InterfaceAddr Address
}
// MulticastLoopOption is used by SetSockOpt/GetSockOpt to specify whether
// multicast packets sent over a non-loopback interface will be looped back.
type MulticastLoopOption bool
// MembershipOption is used by SetSockOpt/GetSockOpt as an argument to
// AddMembershipOption and RemoveMembershipOption.
type MembershipOption struct {
@@ -705,22 +710,10 @@ type RemoveMembershipOption MembershipOption
// TCP out-of-band data is delivered along with the normal in-band data.
type OutOfBandInlineOption int
// BroadcastOption is used by SetSockOpt/GetSockOpt to specify whether
// datagram sockets are allowed to send packets to a broadcast address.
type BroadcastOption int
// DefaultTTLOption is used by stack.(*Stack).NetworkProtocolOption to specify
// a default TTL.
type DefaultTTLOption uint8
// IPv4TOSOption is used by SetSockOpt/GetSockOpt to specify TOS
// for all subsequent outgoing IPv4 packets from the endpoint.
type IPv4TOSOption uint8
// IPv6TrafficClassOption is used by SetSockOpt/GetSockOpt to specify TOS
// for all subsequent outgoing IPv6 packets from the endpoint.
type IPv6TrafficClassOption uint8
// IPPacketInfo is the message struture for IP_PKTINFO.
//
// +stateify savable
+26 -21
View File
@@ -348,29 +348,37 @@ func (e *endpoint) Peek([][]byte) (int64, tcpip.ControlMessages, *tcpip.Error) {
// SetSockOpt sets a socket option.
func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error {
switch o := opt.(type) {
case tcpip.TTLOption:
e.mu.Lock()
e.ttl = uint8(o)
e.mu.Unlock()
}
return nil
}
// SetSockOptBool sets a socket option. Currently not supported.
func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {
return nil
return tcpip.ErrUnknownProtocolOption
}
// SetSockOptInt sets a socket option. Currently not supported.
func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
switch opt {
case tcpip.TTLOption:
e.mu.Lock()
e.ttl = uint8(v)
e.mu.Unlock()
default:
return tcpip.ErrUnknownProtocolOption
}
return nil
}
// GetSockOptBool implements tcpip.Endpoint.GetSockOptBool.
func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
return false, tcpip.ErrUnknownProtocolOption
switch opt {
case tcpip.KeepaliveEnabledOption:
return false, nil
default:
return false, tcpip.ErrUnknownProtocolOption
}
}
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.
@@ -397,26 +405,23 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
e.rcvMu.Unlock()
return v, nil
case tcpip.TTLOption:
e.rcvMu.Lock()
v := int(e.ttl)
e.rcvMu.Unlock()
return v, nil
default:
return -1, tcpip.ErrUnknownProtocolOption
}
return -1, tcpip.ErrUnknownProtocolOption
}
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
switch o := opt.(type) {
switch opt.(type) {
case tcpip.ErrorOption:
return nil
case *tcpip.KeepaliveEnabledOption:
*o = 0
return nil
case *tcpip.TTLOption:
e.rcvMu.Lock()
*o = tcpip.TTLOption(e.ttl)
e.rcvMu.Unlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
+10 -8
View File
@@ -533,14 +533,10 @@ func (e *endpoint) SetSockOptInt(opt tcpip.SockOptInt, v int) *tcpip.Error {
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
switch o := opt.(type) {
switch opt.(type) {
case tcpip.ErrorOption:
return nil
case *tcpip.KeepaliveEnabledOption:
*o = 0
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
@@ -548,7 +544,13 @@ func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
// GetSockOptBool implements tcpip.Endpoint.GetSockOptBool.
func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
return false, tcpip.ErrUnknownProtocolOption
switch opt {
case tcpip.KeepaliveEnabledOption:
return false, nil
default:
return false, tcpip.ErrUnknownProtocolOption
}
}
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.
@@ -576,9 +578,9 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
e.rcvMu.Unlock()
return v, nil
default:
return -1, tcpip.ErrUnknownProtocolOption
}
return -1, tcpip.ErrUnknownProtocolOption
}
// HandlePacket implements stack.RawTransportEndpoint.HandlePacket.
File diff suppressed because it is too large Load Diff
+54 -56
View File
@@ -728,7 +728,7 @@ func TestUserSuppliedMSSOnConnectV4(t *testing.T) {
const maxMSS = mtu - header.IPv4MinimumSize - header.TCPMinimumSize
tests := []struct {
name string
setMSS uint16
setMSS int
expMSS uint16
}{
{
@@ -756,15 +756,14 @@ func TestUserSuppliedMSSOnConnectV4(t *testing.T) {
c.Create(-1)
// Set the MSS socket option.
opt := tcpip.MaxSegOption(test.setMSS)
if err := c.EP.SetSockOpt(opt); err != nil {
t.Fatalf("SetSockOpt(%#v) failed: %s", opt, err)
if err := c.EP.SetSockOptInt(tcpip.MaxSegOption, test.setMSS); err != nil {
t.Fatalf("SetSockOptInt(MaxSegOption, %d) failed: %s", test.setMSS, err)
}
// Get expected window size.
rcvBufSize, err := c.EP.GetSockOptInt(tcpip.ReceiveBufferSizeOption)
if err != nil {
t.Fatalf("GetSockOpt(%v) failed: %s", tcpip.ReceiveBufferSizeOption, err)
t.Fatalf("GetSockOptInt(ReceiveBufferSizeOption) failed: %s", err)
}
ws := tcp.FindWndScale(seqnum.Size(rcvBufSize))
@@ -818,15 +817,14 @@ func TestUserSuppliedMSSOnConnectV6(t *testing.T) {
c.CreateV6Endpoint(true)
// Set the MSS socket option.
opt := tcpip.MaxSegOption(test.setMSS)
if err := c.EP.SetSockOpt(opt); err != nil {
t.Fatalf("SetSockOpt(%#v) failed: %s", opt, err)
if err := c.EP.SetSockOptInt(tcpip.MaxSegOption, int(test.setMSS)); err != nil {
t.Fatalf("SetSockOptInt(MaxSegOption, %d) failed: %s", test.setMSS, err)
}
// Get expected window size.
rcvBufSize, err := c.EP.GetSockOptInt(tcpip.ReceiveBufferSizeOption)
if err != nil {
t.Fatalf("GetSockOpt(%v) failed: %s", tcpip.ReceiveBufferSizeOption, err)
t.Fatalf("GetSockOptInt(ReceiveBufferSizeOption) failed: %s", err)
}
ws := tcp.FindWndScale(seqnum.Size(rcvBufSize))
@@ -1077,17 +1075,17 @@ func TestTOSV4(t *testing.T) {
c.EP = ep
const tos = 0xC0
if err := c.EP.SetSockOpt(tcpip.IPv4TOSOption(tos)); err != nil {
t.Errorf("SetSockOpt(%#v) failed: %s", tcpip.IPv4TOSOption(tos), err)
if err := c.EP.SetSockOptInt(tcpip.IPv4TOSOption, tos); err != nil {
t.Errorf("SetSockOptInt(IPv4TOSOption, %d) failed: %s", tos, err)
}
var v tcpip.IPv4TOSOption
if err := c.EP.GetSockOpt(&v); err != nil {
t.Errorf("GetSockopt failed: %s", err)
v, err := c.EP.GetSockOptInt(tcpip.IPv4TOSOption)
if err != nil {
t.Errorf("GetSockoptInt(IPv4TOSOption) failed: %s", err)
}
if want := tcpip.IPv4TOSOption(tos); v != want {
t.Errorf("got GetSockOpt(...) = %#v, want = %#v", v, want)
if v != tos {
t.Errorf("got GetSockOptInt(IPv4TOSOption) = %d, want = %d", v, tos)
}
testV4Connect(t, c, checker.TOS(tos, 0))
@@ -1125,17 +1123,17 @@ func TestTrafficClassV6(t *testing.T) {
c.CreateV6Endpoint(false)
const tos = 0xC0
if err := c.EP.SetSockOpt(tcpip.IPv6TrafficClassOption(tos)); err != nil {
t.Errorf("SetSockOpt(%#v) failed: %s", tcpip.IPv6TrafficClassOption(tos), err)
if err := c.EP.SetSockOptInt(tcpip.IPv6TrafficClassOption, tos); err != nil {
t.Errorf("SetSockOpInt(IPv6TrafficClassOption, %d) failed: %s", tos, err)
}
var v tcpip.IPv6TrafficClassOption
if err := c.EP.GetSockOpt(&v); err != nil {
t.Fatalf("GetSockopt failed: %s", err)
v, err := c.EP.GetSockOptInt(tcpip.IPv6TrafficClassOption)
if err != nil {
t.Fatalf("GetSockoptInt(IPv6TrafficClassOption) failed: %s", err)
}
if want := tcpip.IPv6TrafficClassOption(tos); v != want {
t.Errorf("got GetSockOpt(...) = %#v, want = %#v", v, want)
if v != tos {
t.Errorf("got GetSockOptInt(IPv6TrafficClassOption) = %d, want = %d", v, tos)
}
// Test the connection request.
@@ -1711,7 +1709,7 @@ func TestNoWindowShrinking(t *testing.T) {
c.CreateConnected(789, 30000, 10)
if err := c.EP.SetSockOptInt(tcpip.ReceiveBufferSizeOption, 5); err != nil {
t.Fatalf("SetSockOpt failed: %v", err)
t.Fatalf("SetSockOptInt(ReceiveBufferSizeOption, 5) failed: %v", err)
}
we, ch := waiter.NewChannelEntry(nil)
@@ -1984,7 +1982,7 @@ func TestScaledWindowAccept(t *testing.T) {
// Set the window size greater than the maximum non-scaled window.
if err := ep.SetSockOptInt(tcpip.ReceiveBufferSizeOption, 65535*3); err != nil {
t.Fatalf("SetSockOpt failed failed: %v", err)
t.Fatalf("SetSockOptInt(ReceiveBufferSizeOption, 65535*3) failed failed: %v", err)
}
if err := ep.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
@@ -2057,7 +2055,7 @@ func TestNonScaledWindowAccept(t *testing.T) {
// Set the window size greater than the maximum non-scaled window.
if err := ep.SetSockOptInt(tcpip.ReceiveBufferSizeOption, 65535*3); err != nil {
t.Fatalf("SetSockOpt failed failed: %v", err)
t.Fatalf("SetSockOptInt(ReceiveBufferSizeOption, 65535*3) failed failed: %v", err)
}
if err := ep.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
@@ -2221,10 +2219,10 @@ func TestSegmentMerging(t *testing.T) {
{
"cork",
func(ep tcpip.Endpoint) {
ep.SetSockOpt(tcpip.CorkOption(1))
ep.SetSockOptBool(tcpip.CorkOption, true)
},
func(ep tcpip.Endpoint) {
ep.SetSockOpt(tcpip.CorkOption(0))
ep.SetSockOptBool(tcpip.CorkOption, false)
},
},
}
@@ -2316,7 +2314,7 @@ func TestDelay(t *testing.T) {
c.CreateConnected(789, 30000, -1 /* epRcvBuf */)
c.EP.SetSockOptInt(tcpip.DelayOption, 1)
c.EP.SetSockOptBool(tcpip.DelayOption, true)
var allData []byte
for i, data := range [][]byte{{0}, {1, 2, 3, 4}, {5, 6, 7}, {8, 9}, {10}, {11}} {
@@ -2364,7 +2362,7 @@ func TestUndelay(t *testing.T) {
c.CreateConnected(789, 30000, -1 /* epRcvBuf */)
c.EP.SetSockOptInt(tcpip.DelayOption, 1)
c.EP.SetSockOptBool(tcpip.DelayOption, true)
allData := [][]byte{{0}, {1, 2, 3}}
for i, data := range allData {
@@ -2397,7 +2395,7 @@ func TestUndelay(t *testing.T) {
// Check that we don't get the second packet yet.
c.CheckNoPacketTimeout("delayed second packet transmitted", 100*time.Millisecond)
c.EP.SetSockOptInt(tcpip.DelayOption, 0)
c.EP.SetSockOptBool(tcpip.DelayOption, false)
// Check that data is received.
second := c.GetPacket()
@@ -2434,8 +2432,8 @@ func TestMSSNotDelayed(t *testing.T) {
fn func(tcpip.Endpoint)
}{
{"no-op", func(tcpip.Endpoint) {}},
{"delay", func(ep tcpip.Endpoint) { ep.SetSockOptInt(tcpip.DelayOption, 1) }},
{"cork", func(ep tcpip.Endpoint) { ep.SetSockOpt(tcpip.CorkOption(1)) }},
{"delay", func(ep tcpip.Endpoint) { ep.SetSockOptBool(tcpip.DelayOption, true) }},
{"cork", func(ep tcpip.Endpoint) { ep.SetSockOptBool(tcpip.CorkOption, true) }},
}
for _, test := range tests {
@@ -2576,12 +2574,12 @@ func TestSetTTL(t *testing.T) {
t.Fatalf("NewEndpoint failed: %v", err)
}
if err := c.EP.SetSockOpt(tcpip.TTLOption(wantTTL)); err != nil {
t.Fatalf("SetSockOpt failed: %v", err)
if err := c.EP.SetSockOptInt(tcpip.TTLOption, int(wantTTL)); err != nil {
t.Fatalf("SetSockOptInt(TTLOption, %d) failed: %s", wantTTL, err)
}
if err := c.EP.Connect(tcpip.FullAddress{Addr: context.TestAddr, Port: context.TestPort}); err != tcpip.ErrConnectStarted {
t.Fatalf("Unexpected return value from Connect: %v", err)
t.Fatalf("Unexpected return value from Connect: %s", err)
}
// Receive SYN packet.
@@ -2621,7 +2619,7 @@ func TestPassiveSendMSSLessThanMTU(t *testing.T) {
// window scaling option.
const rcvBufferSize = 0x20000
if err := ep.SetSockOptInt(tcpip.ReceiveBufferSizeOption, rcvBufferSize); err != nil {
t.Fatalf("SetSockOpt failed failed: %v", err)
t.Fatalf("SetSockOptInt(ReceiveBufferSizeOption, %d) failed failed: %s", rcvBufferSize, err)
}
if err := ep.Bind(tcpip.FullAddress{Port: context.StackPort}); err != nil {
@@ -2765,7 +2763,7 @@ func TestSynOptionsOnActiveConnect(t *testing.T) {
const rcvBufferSize = 0x20000
const wndScale = 2
if err := c.EP.SetSockOptInt(tcpip.ReceiveBufferSizeOption, rcvBufferSize); err != nil {
t.Fatalf("SetSockOpt failed failed: %v", err)
t.Fatalf("SetSockOptInt(ReceiveBufferSizeOption, %d) failed failed: %s", rcvBufferSize, err)
}
// Start connection attempt.
@@ -3882,26 +3880,26 @@ func TestMinMaxBufferSizes(t *testing.T) {
// Set values below the min.
if err := ep.SetSockOptInt(tcpip.ReceiveBufferSizeOption, 199); err != nil {
t.Fatalf("GetSockOpt failed: %v", err)
t.Fatalf("SetSockOptInt(ReceiveBufferSizeOption, 199) failed: %s", err)
}
checkRecvBufferSize(t, ep, 200)
if err := ep.SetSockOptInt(tcpip.SendBufferSizeOption, 299); err != nil {
t.Fatalf("GetSockOpt failed: %v", err)
t.Fatalf("SetSockOptInt(SendBufferSizeOption, 299) failed: %s", err)
}
checkSendBufferSize(t, ep, 300)
// Set values above the max.
if err := ep.SetSockOptInt(tcpip.ReceiveBufferSizeOption, 1+tcp.DefaultReceiveBufferSize*20); err != nil {
t.Fatalf("GetSockOpt failed: %v", err)
t.Fatalf("SetSockOptInt(ReceiveBufferSizeOption) failed: %s", err)
}
checkRecvBufferSize(t, ep, tcp.DefaultReceiveBufferSize*20)
if err := ep.SetSockOptInt(tcpip.SendBufferSizeOption, 1+tcp.DefaultSendBufferSize*30); err != nil {
t.Fatalf("GetSockOpt failed: %v", err)
t.Fatalf("SetSockOptInt(SendBufferSizeOption) failed: %s", err)
}
checkSendBufferSize(t, ep, tcp.DefaultSendBufferSize*30)
@@ -4147,11 +4145,11 @@ func TestConnectAvoidsBoundPorts(t *testing.T) {
case "ipv4":
case "ipv6":
if err := ep.SetSockOptBool(tcpip.V6OnlyOption, true); err != nil {
t.Fatalf("SetSockOpt(V6OnlyOption(true)) failed: %v", err)
t.Fatalf("SetSockOptBool(V6OnlyOption(true)) failed: %s", err)
}
case "dual":
if err := ep.SetSockOptBool(tcpip.V6OnlyOption, false); err != nil {
t.Fatalf("SetSockOpt(V6OnlyOption(false)) failed: %v", err)
t.Fatalf("SetSockOptBool(V6OnlyOption(false)) failed: %s", err)
}
default:
t.Fatalf("unknown network: '%s'", network)
@@ -4477,8 +4475,8 @@ func TestKeepalive(t *testing.T) {
const keepAliveInterval = 10 * time.Millisecond
c.EP.SetSockOpt(tcpip.KeepaliveIdleOption(10 * time.Millisecond))
c.EP.SetSockOpt(tcpip.KeepaliveIntervalOption(keepAliveInterval))
c.EP.SetSockOpt(tcpip.KeepaliveCountOption(5))
c.EP.SetSockOpt(tcpip.KeepaliveEnabledOption(1))
c.EP.SetSockOptInt(tcpip.KeepaliveCountOption, 5)
c.EP.SetSockOptBool(tcpip.KeepaliveEnabledOption, true)
// 5 unacked keepalives are sent. ACK each one, and check that the
// connection stays alive after 5.
@@ -5770,14 +5768,14 @@ func TestReceiveBufferAutoTuning(t *testing.T) {
func TestDelayEnabled(t *testing.T) {
c := context.New(t, defaultMTU)
defer c.Cleanup()
checkDelayOption(t, c, false, 0) // Delay is disabled by default.
checkDelayOption(t, c, false, false) // Delay is disabled by default.
for _, v := range []struct {
delayEnabled tcp.DelayEnabled
wantDelayOption int
wantDelayOption bool
}{
{delayEnabled: false, wantDelayOption: 0},
{delayEnabled: true, wantDelayOption: 1},
{delayEnabled: false, wantDelayOption: false},
{delayEnabled: true, wantDelayOption: true},
} {
c := context.New(t, defaultMTU)
defer c.Cleanup()
@@ -5788,7 +5786,7 @@ func TestDelayEnabled(t *testing.T) {
}
}
func checkDelayOption(t *testing.T, c *context.Context, wantDelayEnabled tcp.DelayEnabled, wantDelayOption int) {
func checkDelayOption(t *testing.T, c *context.Context, wantDelayEnabled tcp.DelayEnabled, wantDelayOption bool) {
t.Helper()
var gotDelayEnabled tcp.DelayEnabled
@@ -5803,12 +5801,12 @@ func checkDelayOption(t *testing.T, c *context.Context, wantDelayEnabled tcp.Del
if err != nil {
t.Fatalf("NewEndPoint(tcp, ipv4, new(waiter.Queue)) failed: %v", err)
}
gotDelayOption, err := ep.GetSockOptInt(tcpip.DelayOption)
gotDelayOption, err := ep.GetSockOptBool(tcpip.DelayOption)
if err != nil {
t.Fatalf("ep.GetSockOptInt(tcpip.DelayOption) failed: %v", err)
t.Fatalf("ep.GetSockOptBool(tcpip.DelayOption) failed: %s", err)
}
if gotDelayOption != wantDelayOption {
t.Errorf("ep.GetSockOptInt(tcpip.DelayOption) got: %d, want: %d", gotDelayOption, wantDelayOption)
t.Errorf("ep.GetSockOptBool(tcpip.DelayOption) got: %t, want: %t", gotDelayOption, wantDelayOption)
}
}
@@ -6620,8 +6618,8 @@ func TestKeepaliveWithUserTimeout(t *testing.T) {
const keepAliveInterval = 10 * time.Millisecond
c.EP.SetSockOpt(tcpip.KeepaliveIdleOption(10 * time.Millisecond))
c.EP.SetSockOpt(tcpip.KeepaliveIntervalOption(keepAliveInterval))
c.EP.SetSockOpt(tcpip.KeepaliveCountOption(10))
c.EP.SetSockOpt(tcpip.KeepaliveEnabledOption(1))
c.EP.SetSockOptInt(tcpip.KeepaliveCountOption, 10)
c.EP.SetSockOptBool(tcpip.KeepaliveEnabledOption, true)
// Set userTimeout to be the duration for 3 keepalive probes.
userTimeout := 30 * time.Millisecond
+113 -124
View File
@@ -501,11 +501,20 @@ func (e *endpoint) Peek([][]byte) (int64, tcpip.ControlMessages, *tcpip.Error) {
// SetSockOptBool implements tcpip.Endpoint.SetSockOptBool.
func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {
switch opt {
case tcpip.BroadcastOption:
e.mu.Lock()
e.broadcast = v
e.mu.Unlock()
case tcpip.MulticastLoopOption:
e.mu.Lock()
e.multicastLoop = v
e.mu.Unlock()
case tcpip.ReceiveTOSOption:
e.mu.Lock()
e.receiveTOS = v
e.mu.Unlock()
return nil
case tcpip.ReceiveTClassOption:
// We only support this option on v6 endpoints.
@@ -516,7 +525,18 @@ func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {
e.mu.Lock()
e.receiveTClass = v
e.mu.Unlock()
return nil
case tcpip.ReceiveIPPacketInfoOption:
e.mu.Lock()
e.receiveIPPacketInfo = v
e.mu.Unlock()
case tcpip.ReuseAddressOption:
case tcpip.ReusePortOption:
e.mu.Lock()
e.reusePort = v
e.mu.Unlock()
case tcpip.V6OnlyOption:
// We only recognize this option on v6 endpoints.
@@ -533,13 +553,8 @@ func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {
}
e.v6only = v
return nil
case tcpip.ReceiveIPPacketInfoOption:
e.mu.Lock()
e.receiveIPPacketInfo = v
e.mu.Unlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
return nil
@@ -547,22 +562,40 @@ 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 {
switch opt {
case tcpip.MulticastTTLOption:
e.mu.Lock()
e.multicastTTL = uint8(v)
e.mu.Unlock()
case tcpip.TTLOption:
e.mu.Lock()
e.ttl = uint8(v)
e.mu.Unlock()
case tcpip.IPv4TOSOption:
e.mu.Lock()
e.sendTOS = uint8(v)
e.mu.Unlock()
case tcpip.IPv6TrafficClassOption:
e.mu.Lock()
e.sendTOS = uint8(v)
e.mu.Unlock()
case tcpip.ReceiveBufferSizeOption:
case tcpip.SendBufferSizeOption:
default:
return tcpip.ErrUnknownProtocolOption
}
return nil
}
// SetSockOpt implements tcpip.Endpoint.SetSockOpt.
func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error {
switch v := opt.(type) {
case tcpip.TTLOption:
e.mu.Lock()
e.ttl = uint8(v)
e.mu.Unlock()
case tcpip.MulticastTTLOption:
e.mu.Lock()
e.multicastTTL = uint8(v)
e.mu.Unlock()
case tcpip.MulticastInterfaceOption:
e.mu.Lock()
defer e.mu.Unlock()
@@ -686,16 +719,6 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error {
e.multicastMemberships[memToRemoveIndex] = e.multicastMemberships[len(e.multicastMemberships)-1]
e.multicastMemberships = e.multicastMemberships[:len(e.multicastMemberships)-1]
case tcpip.MulticastLoopOption:
e.mu.Lock()
e.multicastLoop = bool(v)
e.mu.Unlock()
case tcpip.ReusePortOption:
e.mu.Lock()
e.reusePort = v != 0
e.mu.Unlock()
case tcpip.BindToDeviceOption:
id := tcpip.NICID(v)
if id != 0 && !e.stack.HasNIC(id) {
@@ -704,26 +727,6 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error {
e.mu.Lock()
e.bindToDevice = id
e.mu.Unlock()
return nil
case tcpip.BroadcastOption:
e.mu.Lock()
e.broadcast = v != 0
e.mu.Unlock()
return nil
case tcpip.IPv4TOSOption:
e.mu.Lock()
e.sendTOS = uint8(v)
e.mu.Unlock()
return nil
case tcpip.IPv6TrafficClassOption:
e.mu.Lock()
e.sendTOS = uint8(v)
e.mu.Unlock()
return nil
}
return nil
}
@@ -731,6 +734,21 @@ func (e *endpoint) SetSockOpt(opt interface{}) *tcpip.Error {
// GetSockOptBool implements tcpip.Endpoint.GetSockOptBool.
func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
switch opt {
case tcpip.BroadcastOption:
e.mu.RLock()
v := e.broadcast
e.mu.RUnlock()
return v, nil
case tcpip.KeepaliveEnabledOption:
return false, nil
case tcpip.MulticastLoopOption:
e.mu.RLock()
v := e.multicastLoop
e.mu.RUnlock()
return v, nil
case tcpip.ReceiveTOSOption:
e.mu.RLock()
v := e.receiveTOS
@@ -748,6 +766,22 @@ func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
e.mu.RUnlock()
return v, nil
case tcpip.ReceiveIPPacketInfoOption:
e.mu.RLock()
v := e.receiveIPPacketInfo
e.mu.RUnlock()
return v, nil
case tcpip.ReuseAddressOption:
return false, nil
case tcpip.ReusePortOption:
e.mu.RLock()
v := e.reusePort
e.mu.RUnlock()
return v, nil
case tcpip.V6OnlyOption:
// We only recognize this option on v6 endpoints.
if e.NetProto != header.IPv6ProtocolNumber {
@@ -760,19 +794,32 @@ func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
return v, nil
case tcpip.ReceiveIPPacketInfoOption:
e.mu.RLock()
v := e.receiveIPPacketInfo
e.mu.RUnlock()
return v, nil
default:
return false, tcpip.ErrUnknownProtocolOption
}
return false, tcpip.ErrUnknownProtocolOption
}
// GetSockOptInt implements tcpip.Endpoint.GetSockOptInt.
func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
switch opt {
case tcpip.IPv4TOSOption:
e.mu.RLock()
v := int(e.sendTOS)
e.mu.RUnlock()
return v, nil
case tcpip.IPv6TrafficClassOption:
e.mu.RLock()
v := int(e.sendTOS)
e.mu.RUnlock()
return v, nil
case tcpip.MulticastTTLOption:
e.mu.Lock()
v := int(e.multicastTTL)
e.mu.Unlock()
return v, nil
case tcpip.ReceiveQueueSizeOption:
v := 0
e.rcvMu.Lock()
@@ -794,29 +841,22 @@ func (e *endpoint) GetSockOptInt(opt tcpip.SockOptInt) (int, *tcpip.Error) {
v := e.rcvBufSizeMax
e.rcvMu.Unlock()
return v, nil
}
return -1, tcpip.ErrUnknownProtocolOption
case tcpip.TTLOption:
e.mu.Lock()
v := int(e.ttl)
e.mu.Unlock()
return v, nil
default:
return -1, tcpip.ErrUnknownProtocolOption
}
}
// GetSockOpt implements tcpip.Endpoint.GetSockOpt.
func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
switch o := opt.(type) {
case tcpip.ErrorOption:
return nil
case *tcpip.TTLOption:
e.mu.Lock()
*o = tcpip.TTLOption(e.ttl)
e.mu.Unlock()
return nil
case *tcpip.MulticastTTLOption:
e.mu.Lock()
*o = tcpip.MulticastTTLOption(e.multicastTTL)
e.mu.Unlock()
return nil
case *tcpip.MulticastInterfaceOption:
e.mu.Lock()
*o = tcpip.MulticastInterfaceOption{
@@ -824,67 +864,16 @@ func (e *endpoint) GetSockOpt(opt interface{}) *tcpip.Error {
e.multicastAddr,
}
e.mu.Unlock()
return nil
case *tcpip.MulticastLoopOption:
e.mu.RLock()
v := e.multicastLoop
e.mu.RUnlock()
*o = tcpip.MulticastLoopOption(v)
return nil
case *tcpip.ReuseAddressOption:
*o = 0
return nil
case *tcpip.ReusePortOption:
e.mu.RLock()
v := e.reusePort
e.mu.RUnlock()
*o = 0
if v {
*o = 1
}
return nil
case *tcpip.BindToDeviceOption:
e.mu.RLock()
*o = tcpip.BindToDeviceOption(e.bindToDevice)
e.mu.RUnlock()
return nil
case *tcpip.KeepaliveEnabledOption:
*o = 0
return nil
case *tcpip.BroadcastOption:
e.mu.RLock()
v := e.broadcast
e.mu.RUnlock()
*o = 0
if v {
*o = 1
}
return nil
case *tcpip.IPv4TOSOption:
e.mu.RLock()
*o = tcpip.IPv4TOSOption(e.sendTOS)
e.mu.RUnlock()
return nil
case *tcpip.IPv6TrafficClassOption:
e.mu.RLock()
*o = tcpip.IPv6TrafficClassOption(e.sendTOS)
e.mu.RUnlock()
return nil
default:
return tcpip.ErrUnknownProtocolOption
}
return nil
}
// sendUDP sends a UDP segment via the provided network endpoint and under the
+31 -29
View File
@@ -343,11 +343,11 @@ func (c *testContext) createEndpointForFlow(flow testFlow) {
c.createEndpoint(flow.sockProto())
if flow.isV6Only() {
if err := c.ep.SetSockOptBool(tcpip.V6OnlyOption, true); err != nil {
c.t.Fatalf("SetSockOpt failed: %v", err)
c.t.Fatalf("SetSockOptBool failed: %s", err)
}
} else if flow.isBroadcast() {
if err := c.ep.SetSockOpt(tcpip.BroadcastOption(1)); err != nil {
c.t.Fatal("SetSockOpt failed:", err)
if err := c.ep.SetSockOptBool(tcpip.BroadcastOption, true); err != nil {
c.t.Fatalf("SetSockOptBool failed: %s", err)
}
}
}
@@ -1271,8 +1271,8 @@ func TestTTL(t *testing.T) {
c.createEndpointForFlow(flow)
const multicastTTL = 42
if err := c.ep.SetSockOpt(tcpip.MulticastTTLOption(multicastTTL)); err != nil {
c.t.Fatalf("SetSockOpt failed: %v", err)
if err := c.ep.SetSockOptInt(tcpip.MulticastTTLOption, multicastTTL); err != nil {
c.t.Fatalf("SetSockOptInt failed: %s", err)
}
var wantTTL uint8
@@ -1311,8 +1311,8 @@ func TestSetTTL(t *testing.T) {
c.createEndpointForFlow(flow)
if err := c.ep.SetSockOpt(tcpip.TTLOption(wantTTL)); err != nil {
c.t.Fatalf("SetSockOpt failed: %v", err)
if err := c.ep.SetSockOptInt(tcpip.TTLOption, int(wantTTL)); err != nil {
c.t.Fatalf("SetSockOptInt(TTLOption, %d) failed: %s", wantTTL, err)
}
var p stack.NetworkProtocol
@@ -1346,25 +1346,26 @@ func TestSetTOS(t *testing.T) {
c.createEndpointForFlow(flow)
const tos = testTOS
var v tcpip.IPv4TOSOption
if err := c.ep.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
v, err := c.ep.GetSockOptInt(tcpip.IPv4TOSOption)
if err != nil {
c.t.Errorf("GetSockOptInt(IPv4TOSOption) failed: %s", err)
}
// Test for expected default value.
if v != 0 {
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, 0)
c.t.Errorf("got GetSockOpt(IPv4TOSOption) = 0x%x, want = 0x%x", v, 0)
}
if err := c.ep.SetSockOpt(tcpip.IPv4TOSOption(tos)); err != nil {
c.t.Errorf("SetSockOpt(%T, 0x%x) failed: %s", v, tcpip.IPv4TOSOption(tos), err)
if err := c.ep.SetSockOptInt(tcpip.IPv4TOSOption, tos); err != nil {
c.t.Errorf("SetSockOptInt(IPv4TOSOption, 0x%x) failed: %s", tos, err)
}
if err := c.ep.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
v, err = c.ep.GetSockOptInt(tcpip.IPv4TOSOption)
if err != nil {
c.t.Errorf("GetSockOptInt(IPv4TOSOption) failed: %s", err)
}
if want := tcpip.IPv4TOSOption(tos); v != want {
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, want)
if v != tos {
c.t.Errorf("got GetSockOptInt(IPv4TOSOption) = 0x%x, want = 0x%x", v, tos)
}
testWrite(c, flow, checker.TOS(tos, 0))
@@ -1381,25 +1382,26 @@ func TestSetTClass(t *testing.T) {
c.createEndpointForFlow(flow)
const tClass = testTOS
var v tcpip.IPv6TrafficClassOption
if err := c.ep.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
v, err := c.ep.GetSockOptInt(tcpip.IPv6TrafficClassOption)
if err != nil {
c.t.Errorf("GetSockOptInt(IPv6TrafficClassOption) failed: %s", err)
}
// Test for expected default value.
if v != 0 {
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, 0)
c.t.Errorf("got GetSockOptInt(IPv6TrafficClassOption) = 0x%x, want = 0x%x", v, 0)
}
if err := c.ep.SetSockOpt(tcpip.IPv6TrafficClassOption(tClass)); err != nil {
c.t.Errorf("SetSockOpt(%T, 0x%x) failed: %s", v, tcpip.IPv6TrafficClassOption(tClass), err)
if err := c.ep.SetSockOptInt(tcpip.IPv6TrafficClassOption, tClass); err != nil {
c.t.Errorf("SetSockOptInt(IPv6TrafficClassOption, 0x%x) failed: %s", tClass, err)
}
if err := c.ep.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
v, err = c.ep.GetSockOptInt(tcpip.IPv6TrafficClassOption)
if err != nil {
c.t.Errorf("GetSockOptInt(IPv6TrafficClassOption) failed: %s", err)
}
if want := tcpip.IPv6TrafficClassOption(tClass); v != want {
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, want)
if v != tClass {
c.t.Errorf("got GetSockOptInt(IPv6TrafficClassOption) = 0x%x, want = 0x%x", v, tClass)
}
// The header getter for TClass is called TOS, so use that checker.
@@ -1430,7 +1432,7 @@ func TestReceiveTosTClass(t *testing.T) {
// Verify that setting and reading the option works.
v, err := c.ep.GetSockOptBool(option)
if err != nil {
c.t.Errorf("GetSockoptBool(%s) failed: %s", name, err)
c.t.Errorf("GetSockOptBool(%s) failed: %s", name, err)
}
// Test for expected default value.
if v != false {
@@ -1444,7 +1446,7 @@ func TestReceiveTosTClass(t *testing.T) {
got, err := c.ep.GetSockOptBool(option)
if err != nil {
c.t.Errorf("GetSockoptBool(%s) failed: %s", name, err)
c.t.Errorf("GetSockOptBool(%s) failed: %s", name, err)
}
if got != want {