Enable IPV6_RECVTCLASS socket option for datagram sockets

Added the ability to get/set the IP_RECVTCLASS socket option on UDP endpoints.
If enabled, traffic class from the incoming Network Header passed as ancillary
data in the ControlMessages.

Adding Get/SetSockOptBool to decrease the overhead of getting/setting simple
options. (This was absorbed in a CL that will be landing before this one).

Test:
* Added unit test to udp_test.go that tests getting/setting as well as
verifying that we receive expected TOS from incoming packet.
* Added a syscall test for verifying getting/setting
* Removed test skip for existing syscall test to enable end to end test.
PiperOrigin-RevId: 295840218
This commit is contained in:
gVisor bot
2020-02-18 15:45:36 -08:00
parent 247843bbc5
commit 56fd9504aa
9 changed files with 260 additions and 109 deletions
+1 -1
View File
@@ -329,7 +329,7 @@ func PackTOS(t *kernel.Task, tos uint8, buf []byte) []byte {
}
// PackTClass packs an IPV6_TCLASS socket control message.
func PackTClass(t *kernel.Task, tClass int32, buf []byte) []byte {
func PackTClass(t *kernel.Task, tClass uint32, buf []byte) []byte {
return putCmsgStruct(
buf,
linux.SOL_IPV6,
+26 -1
View File
@@ -1318,6 +1318,22 @@ func getSockOptIPv6(t *kernel.Task, ep commonEndpoint, name, outLen int) (interf
}
return ib, nil
case linux.IPV6_RECVTCLASS:
if outLen < sizeOfInt32 {
return nil, syserr.ErrInvalidArgument
}
v, err := ep.GetSockOptBool(tcpip.ReceiveTClassOption)
if err != nil {
return nil, syserr.TranslateNetstackError(err)
}
var o int32
if v {
o = 1
}
return o, nil
default:
emitUnimplementedEventIPv6(t, name)
}
@@ -1803,6 +1819,14 @@ func setSockOptIPv6(t *kernel.Task, ep commonEndpoint, name int, optVal []byte)
}
return syserr.TranslateNetstackError(ep.SetSockOpt(tcpip.IPv6TrafficClassOption(v)))
case linux.IPV6_RECVTCLASS:
v, err := parseIntOrChar(optVal)
if err != nil {
return err
}
return syserr.TranslateNetstackError(ep.SetSockOptBool(tcpip.ReceiveTClassOption, v != 0))
default:
emitUnimplementedEventIPv6(t, name)
}
@@ -2086,7 +2110,6 @@ func emitUnimplementedEventIPv6(t *kernel.Task, name int) {
linux.IPV6_RECVPATHMTU,
linux.IPV6_RECVPKTINFO,
linux.IPV6_RECVRTHDR,
linux.IPV6_RECVTCLASS,
linux.IPV6_RTHDR,
linux.IPV6_RTHDRDSTOPTS,
linux.IPV6_TCLASS,
@@ -2424,6 +2447,8 @@ func (s *SocketOperations) controlMessages() socket.ControlMessages {
Timestamp: s.readCM.Timestamp,
HasTOS: s.readCM.HasTOS,
TOS: s.readCM.TOS,
HasTClass: s.readCM.HasTClass,
TClass: s.readCM.TClass,
HasIPPacketInfo: s.readCM.HasIPPacketInfo,
PacketInfo: s.readCM.PacketInfo,
},
+14
View File
@@ -161,6 +161,20 @@ func FragmentFlags(flags uint8) NetworkChecker {
}
}
// ReceiveTClass creates a checker that checks the TCLASS field in
// ControlMessages.
func ReceiveTClass(want uint32) ControlMessagesChecker {
return func(t *testing.T, cm tcpip.ControlMessages) {
t.Helper()
if !cm.HasTClass {
t.Fatalf("got cm.HasTClass = %t, want cm.TClass = %d", cm.HasTClass, want)
}
if got := cm.TClass; got != want {
t.Fatalf("got cm.TClass = %d, want %d", got, want)
}
}
}
// ReceiveTOS creates a checker that checks the TOS field in ControlMessages.
func ReceiveTOS(want uint8) ControlMessagesChecker {
return func(t *testing.T, cm tcpip.ControlMessages) {
+11 -4
View File
@@ -323,11 +323,11 @@ type ControlMessages struct {
// TOS is the IPv4 type of service of the associated packet.
TOS uint8
// HasTClass indicates whether Tclass is valid/set.
// HasTClass indicates whether TClass is valid/set.
HasTClass bool
// Tclass is the IPv6 traffic class of the associated packet.
TClass int32
// TClass is the IPv6 traffic class of the associated packet.
TClass uint32
// HasIPPacketInfo indicates whether PacketInfo is set.
HasIPPacketInfo bool
@@ -502,9 +502,13 @@ type WriteOptions struct {
type SockOptBool int
const (
// ReceiveTClassOption is used by SetSockOpt/GetSockOpt to specify if the
// IPV6_TCLASS ancillary message is passed with incoming packets.
ReceiveTClassOption SockOptBool = iota
// ReceiveTOSOption is used by SetSockOpt/GetSockOpt to specify if the TOS
// ancillary message is passed with incoming packets.
ReceiveTOSOption SockOptBool = iota
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.
@@ -514,6 +518,9 @@ const (
// 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
)
// SockOptInt represents socket options which values have the int type.
+36 -2
View File
@@ -32,7 +32,8 @@ type udpPacket struct {
packetInfo tcpip.IPPacketInfo
data buffer.VectorisedView `state:".(buffer.VectorisedView)"`
timestamp int64
tos uint8
// tos stores either the receiveTOS or receiveTClass value.
tos uint8
}
// EndpointState represents the state of a UDP endpoint.
@@ -119,6 +120,10 @@ type endpoint struct {
// as ancillary data to ControlMessages on Read.
receiveTOS bool
// receiveTClass determines if the incoming IPv6 TClass header field is
// passed as ancillary data to ControlMessages on Read.
receiveTClass bool
// receiveIPPacketInfo determines if the packet info is returned by Read.
receiveIPPacketInfo bool
@@ -258,13 +263,18 @@ func (e *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMess
}
e.mu.RLock()
receiveTOS := e.receiveTOS
receiveTClass := e.receiveTClass
receiveIPPacketInfo := e.receiveIPPacketInfo
e.mu.RUnlock()
if receiveTOS {
cm.HasTOS = true
cm.TOS = p.tos
}
if receiveTClass {
cm.HasTClass = true
// Although TClass is an 8-bit value it's read in the CMsg as a uint32.
cm.TClass = uint32(p.tos)
}
if receiveIPPacketInfo {
cm.HasIPPacketInfo = true
cm.PacketInfo = p.packetInfo
@@ -490,6 +500,17 @@ func (e *endpoint) SetSockOptBool(opt tcpip.SockOptBool, v bool) *tcpip.Error {
e.mu.Unlock()
return nil
case tcpip.ReceiveTClassOption:
// We only support this option on v6 endpoints.
if e.NetProto != header.IPv6ProtocolNumber {
return tcpip.ErrNotSupported
}
e.mu.Lock()
e.receiveTClass = v
e.mu.Unlock()
return nil
case tcpip.V6OnlyOption:
// We only recognize this option on v6 endpoints.
if e.NetProto != header.IPv6ProtocolNumber {
@@ -709,6 +730,17 @@ func (e *endpoint) GetSockOptBool(opt tcpip.SockOptBool) (bool, *tcpip.Error) {
e.mu.RUnlock()
return v, nil
case tcpip.ReceiveTClassOption:
// We only support this option on v6 endpoints.
if e.NetProto != header.IPv6ProtocolNumber {
return false, tcpip.ErrNotSupported
}
e.mu.RLock()
v := e.receiveTClass
e.mu.RUnlock()
return v, nil
case tcpip.V6OnlyOption:
// We only recognize this option on v6 endpoints.
if e.NetProto != header.IPv6ProtocolNumber {
@@ -1273,6 +1305,8 @@ func (e *endpoint) HandlePacket(r *stack.Route, id stack.TransportEndpointID, pk
packet.packetInfo.LocalAddr = r.LocalAddress
packet.packetInfo.DestinationAddr = r.RemoteAddress
packet.packetInfo.NIC = r.NICID()
case header.IPv6ProtocolNumber:
packet.tos, _ = header.IPv6(pkt.NetworkHeader).TOS()
}
packet.timestamp = e.stack.NowNanoseconds()
+71 -49
View File
@@ -409,6 +409,7 @@ func (c *testContext) injectV6Packet(payload []byte, h *header4Tuple, valid bool
// Initialize the IP header.
ip := header.IPv6(buf)
ip.Encode(&header.IPv6Fields{
TrafficClass: testTOS,
PayloadLength: uint16(header.UDPMinimumSize + len(payload)),
NextHeader: uint8(udp.ProtocolNumber),
HopLimit: 65,
@@ -1336,7 +1337,7 @@ func TestSetTTL(t *testing.T) {
}
}
func TestTOSV4(t *testing.T) {
func TestSetTOS(t *testing.T) {
for _, flow := range []testFlow{unicastV4, multicastV4, broadcast} {
t.Run(fmt.Sprintf("flow:%s", flow), func(t *testing.T) {
c := newDualTestContext(t, defaultMTU)
@@ -1347,23 +1348,23 @@ func TestTOSV4(t *testing.T) {
const tos = testTOS
var v tcpip.IPv4TOSOption
if err := c.ep.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt failed: %s", err)
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
}
// Test for expected default value.
if v != 0 {
c.t.Errorf("got GetSockOpt(...) = %#v, want = %#v", v, 0)
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, 0)
}
if err := c.ep.SetSockOpt(tcpip.IPv4TOSOption(tos)); err != nil {
c.t.Errorf("SetSockOpt(%#v) failed: %s", tcpip.IPv4TOSOption(tos), err)
c.t.Errorf("SetSockOpt(%T, 0x%x) failed: %s", v, tcpip.IPv4TOSOption(tos), err)
}
if err := c.ep.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt failed: %s", err)
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
}
if want := tcpip.IPv4TOSOption(tos); v != want {
c.t.Errorf("got GetSockOpt(...) = %#v, want = %#v", v, want)
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, want)
}
testWrite(c, flow, checker.TOS(tos, 0))
@@ -1371,7 +1372,7 @@ func TestTOSV4(t *testing.T) {
}
}
func TestTOSV6(t *testing.T) {
func TestSetTClass(t *testing.T) {
for _, flow := range []testFlow{unicastV4in6, unicastV6, unicastV6Only, multicastV4in6, multicastV6, broadcastIn6} {
t.Run(fmt.Sprintf("flow:%s", flow), func(t *testing.T) {
c := newDualTestContext(t, defaultMTU)
@@ -1379,71 +1380,92 @@ func TestTOSV6(t *testing.T) {
c.createEndpointForFlow(flow)
const tos = testTOS
const tClass = testTOS
var v tcpip.IPv6TrafficClassOption
if err := c.ep.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt failed: %s", err)
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
}
// Test for expected default value.
if v != 0 {
c.t.Errorf("got GetSockOpt(...) = %#v, want = %#v", v, 0)
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, 0)
}
if err := c.ep.SetSockOpt(tcpip.IPv6TrafficClassOption(tos)); err != nil {
c.t.Errorf("SetSockOpt failed: %s", err)
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.GetSockOpt(&v); err != nil {
c.t.Errorf("GetSockopt failed: %s", err)
c.t.Errorf("GetSockopt(%T) failed: %s", v, err)
}
if want := tcpip.IPv6TrafficClassOption(tos); v != want {
c.t.Errorf("got GetSockOpt(...) = %#v, want = %#v", v, want)
if want := tcpip.IPv6TrafficClassOption(tClass); v != want {
c.t.Errorf("got GetSockOpt(%T) = 0x%x, want = 0x%x", v, v, want)
}
testWrite(c, flow, checker.TOS(tos, 0))
// The header getter for TClass is called TOS, so use that checker.
testWrite(c, flow, checker.TOS(tClass, 0))
})
}
}
func TestReceiveTOSV4(t *testing.T) {
for _, flow := range []testFlow{unicastV4, broadcast} {
t.Run(fmt.Sprintf("flow:%s", flow), func(t *testing.T) {
c := newDualTestContext(t, defaultMTU)
defer c.cleanup()
func TestReceiveTosTClass(t *testing.T) {
testCases := []struct {
name string
getReceiveOption tcpip.SockOptBool
tests []testFlow
}{
{"ReceiveTosOption", tcpip.ReceiveTOSOption, []testFlow{unicastV4, broadcast}},
{"ReceiveTClassOption", tcpip.ReceiveTClassOption, []testFlow{unicastV4in6, unicastV6, unicastV6Only, broadcastIn6}},
}
for _, testCase := range testCases {
for _, flow := range testCase.tests {
t.Run(fmt.Sprintf("%s:flow:%s", testCase.name, flow), func(t *testing.T) {
c := newDualTestContext(t, defaultMTU)
defer c.cleanup()
c.createEndpointForFlow(flow)
c.createEndpointForFlow(flow)
option := testCase.getReceiveOption
name := testCase.name
// Verify that setting and reading the option works.
v, err := c.ep.GetSockOptBool(tcpip.ReceiveTOSOption)
if err != nil {
c.t.Fatal("GetSockOptBool(tcpip.ReceiveTOSOption) failed:", err)
}
// Test for expected default value.
if v != false {
c.t.Errorf("got GetSockOptBool(tcpip.ReceiveTOSOption) = %t, want = %t", v, false)
}
// 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)
}
// Test for expected default value.
if v != false {
c.t.Errorf("got GetSockOptBool(%s) = %t, want = %t", name, v, false)
}
want := true
if err := c.ep.SetSockOptBool(tcpip.ReceiveTOSOption, want); err != nil {
c.t.Fatalf("SetSockOptBool(tcpip.ReceiveTOSOption, %t) failed: %s", want, err)
}
want := true
if err := c.ep.SetSockOptBool(option, want); err != nil {
c.t.Fatalf("SetSockOptBool(%s, %t) failed: %s", name, want, err)
}
got, err := c.ep.GetSockOptBool(tcpip.ReceiveTOSOption)
if err != nil {
c.t.Fatal("GetSockOptBool(tcpip.ReceiveTOSOption) failed:", err)
}
if got != want {
c.t.Fatalf("got GetSockOptBool(tcpip.ReceiveTOSOption) = %t, want = %t", got, want)
}
got, err := c.ep.GetSockOptBool(option)
if err != nil {
c.t.Errorf("GetSockoptBool(%s) failed: %s", name, err)
}
// Verify that the correct received TOS is handed through as
// ancillary data to the ControlMessages struct.
if err := c.ep.Bind(tcpip.FullAddress{Port: stackPort}); err != nil {
c.t.Fatal("Bind failed:", err)
}
testRead(c, flow, checker.ReceiveTOS(testTOS))
})
if got != want {
c.t.Errorf("got GetSockOptBool(%s) = %t, want = %t", name, got, want)
}
// Verify that the correct received TOS or TClass is handed through as
// ancillary data to the ControlMessages struct.
if err := c.ep.Bind(tcpip.FullAddress{Port: stackPort}); err != nil {
c.t.Fatalf("Bind failed: %s", err)
}
switch option {
case tcpip.ReceiveTClassOption:
testRead(c, flow, checker.ReceiveTClass(testTOS))
case tcpip.ReceiveTOSOption:
testRead(c, flow, checker.ReceiveTOS(testTOS))
default:
t.Fatalf("unknown test variant: %s", name)
}
})
}
}
}
+8 -8
View File
@@ -84,20 +84,20 @@ SocketPairKind DualStackUDPBidirectionalBindSocketPair(int type);
// SocketPairs created with AF_INET and the given type.
SocketPairKind IPv4UDPUnboundSocketPair(int type);
// IPv4UDPUnboundSocketPair returns a SocketKind that represents
// a SimpleSocket created with AF_INET, SOCK_DGRAM, and the given type.
// IPv4UDPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET, SOCK_DGRAM, and the given type.
SocketKind IPv4UDPUnboundSocket(int type);
// IPv6UDPUnboundSocketPair returns a SocketKind that represents
// a SimpleSocket created with AF_INET6, SOCK_DGRAM, and the given type.
// IPv6UDPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET6, SOCK_DGRAM, and the given type.
SocketKind IPv6UDPUnboundSocket(int type);
// IPv4TCPUnboundSocketPair returns a SocketKind that represents
// a SimpleSocket created with AF_INET, SOCK_STREAM and the given type.
// IPv4TCPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET, SOCK_STREAM and the given type.
SocketKind IPv4TCPUnboundSocket(int type);
// IPv6TCPUnboundSocketPair returns a SocketKind that represents
// a SimpleSocket created with AF_INET6, SOCK_STREAM and the given type.
// IPv6TCPUnboundSocket returns a SocketKind that represents a SimpleSocket
// created with AF_INET6, SOCK_STREAM and the given type.
SocketKind IPv6TCPUnboundSocket(int type);
// IfAddrHelper is a helper class that determines the local interfaces present
+93 -40
View File
@@ -14,6 +14,7 @@
#include "test/syscalls/linux/socket_ip_udp_generic.h"
#include <errno.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <poll.h>
@@ -209,46 +210,6 @@ TEST_P(UDPSocketPairTest, SetMulticastLoopChar) {
EXPECT_EQ(get, kSockOptOn);
}
// Ensure that Receiving TOS is off by default.
TEST_P(UDPSocketPairTest, RecvTosDefault) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(
getsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, kSockOptOff);
}
// Test that setting and getting IP_RECVTOS works as expected.
TEST_P(UDPSocketPairTest, SetRecvTos) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS,
&kSockOptOff, sizeof(kSockOptOff)),
SyscallSucceeds());
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(
getsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, kSockOptOff);
ASSERT_THAT(setsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS,
&kSockOptOn, sizeof(kSockOptOn)),
SyscallSucceeds());
ASSERT_THAT(
getsockopt(sockets->first_fd(), IPPROTO_IP, IP_RECVTOS, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, kSockOptOn);
}
TEST_P(UDPSocketPairTest, ReuseAddrDefault) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
@@ -401,5 +362,97 @@ TEST_P(UDPSocketPairTest, SetAndGetIPPKTINFO) {
EXPECT_EQ(get_len, sizeof(get));
}
// Holds TOS or TClass information for IPv4 or IPv6 respectively.
struct RecvTosOption {
int level;
int option;
};
RecvTosOption GetRecvTosOption(int domain) {
TEST_CHECK(domain == AF_INET || domain == AF_INET6);
RecvTosOption opt;
switch (domain) {
case AF_INET:
opt.level = IPPROTO_IP;
opt.option = IP_RECVTOS;
break;
case AF_INET6:
opt.level = IPPROTO_IPV6;
opt.option = IPV6_RECVTCLASS;
break;
}
return opt;
}
// Ensure that Receiving TOS or TCLASS is off by default.
TEST_P(UDPSocketPairTest, RecvTosDefault) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
RecvTosOption t = GetRecvTosOption(GetParam().domain);
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(
getsockopt(sockets->first_fd(), t.level, t.option, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, kSockOptOff);
}
// Test that setting and getting IP_RECVTOS or IPV6_RECVTCLASS works as
// expected.
TEST_P(UDPSocketPairTest, SetRecvTos) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
RecvTosOption t = GetRecvTosOption(GetParam().domain);
ASSERT_THAT(setsockopt(sockets->first_fd(), t.level, t.option, &kSockOptOff,
sizeof(kSockOptOff)),
SyscallSucceeds());
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(
getsockopt(sockets->first_fd(), t.level, t.option, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, kSockOptOff);
ASSERT_THAT(setsockopt(sockets->first_fd(), t.level, t.option, &kSockOptOn,
sizeof(kSockOptOn)),
SyscallSucceeds());
ASSERT_THAT(
getsockopt(sockets->first_fd(), t.level, t.option, &get, &get_len),
SyscallSucceedsWithValue(0));
EXPECT_EQ(get_len, sizeof(get));
EXPECT_EQ(get, kSockOptOn);
}
// Test that any socket (including IPv6 only) accepts the IPv4 TOS option: this
// mirrors behavior in linux.
TEST_P(UDPSocketPairTest, TOSRecvMismatch) {
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
RecvTosOption t = GetRecvTosOption(AF_INET);
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(
getsockopt(sockets->first_fd(), t.level, t.option, &get, &get_len),
SyscallSucceedsWithValue(0));
}
// Test that an IPv4 socket does not support the IPv6 TClass option.
TEST_P(UDPSocketPairTest, TClassRecvMismatch) {
// This should only test AF_INET sockets for the mismatch behavior.
SKIP_IF(GetParam().domain != AF_INET);
auto sockets = ASSERT_NO_ERRNO_AND_VALUE(NewSocketPair());
int get = -1;
socklen_t get_len = sizeof(get);
ASSERT_THAT(getsockopt(sockets->first_fd(), IPPROTO_IPV6, IPV6_RECVTCLASS,
&get, &get_len),
SyscallFailsWithErrno(EOPNOTSUPP));
}
} // namespace testing
} // namespace gvisor
@@ -1349,9 +1349,6 @@ TEST_P(UdpSocketTest, TimestampIoctlPersistence) {
// outgoing packets, and that a receiving socket with IP_RECVTOS or
// IPV6_RECVTCLASS will create the corresponding control message.
TEST_P(UdpSocketTest, SetAndReceiveTOS) {
// TODO(b/144868438): IPV6_RECVTCLASS not supported for netstack.
SKIP_IF((GetParam() != AddressFamily::kIpv4) && IsRunningOnGvisor() &&
!IsRunningWithHostinet());
ASSERT_THAT(bind(s_, addr_[0], addrlen_), SyscallSucceeds());
ASSERT_THAT(connect(t_, addr_[0], addrlen_), SyscallSucceeds());
@@ -1422,7 +1419,6 @@ TEST_P(UdpSocketTest, SetAndReceiveTOS) {
// TOS byte on outgoing packets, and that a receiving socket with IP_RECVTOS or
// IPV6_RECVTCLASS will create the corresponding control message.
TEST_P(UdpSocketTest, SendAndReceiveTOS) {
// TODO(b/144868438): IPV6_RECVTCLASS not supported for netstack.
// TODO(b/146661005): Setting TOS via cmsg not supported for netstack.
SKIP_IF(IsRunningOnGvisor() && !IsRunningWithHostinet());
ASSERT_THAT(bind(s_, addr_[0], addrlen_), SyscallSucceeds());