Implement GetSockOpt PACKET_HDRLEN and add a test for tcpdump.

PiperOrigin-RevId: 724445536
This commit is contained in:
Lucas Manning
2025-02-07 13:06:14 -08:00
committed by gVisor bot
parent de6637c27c
commit 9c490f813d
7 changed files with 148 additions and 10 deletions
+32 -3
View File
@@ -907,9 +907,9 @@ func GetSockOpt(t *kernel.Task, s socket.Socket, ep commonEndpoint, family int,
case linux.SOL_ICMPV6:
return getSockOptICMPv6(t, s, ep, name, outLen)
case linux.SOL_UDP,
linux.SOL_RAW,
linux.SOL_PACKET:
case linux.SOL_PACKET:
return getSockOptPacket(t, s, ep, name, outPtr, outLen)
case linux.SOL_UDP, linux.SOL_RAW:
// Not supported.
}
@@ -1850,6 +1850,29 @@ func getSockOptIP(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int,
return nil, syserr.ErrProtocolNotAvailable
}
func getSockOptPacket(t *kernel.Task, s socket.Socket, ep commonEndpoint, name int, outPtr hostarch.Addr, outLen int) (marshal.Marshallable, *syserr.Error) {
if _, ok := ep.(tcpip.Endpoint); !ok {
log.Warningf("SOL_PACKET options not supported on endpoints other than tcpip.Endpoint: option = %d, endpoint = %T", name, ep)
return nil, syserr.ErrUnknownProtocolOption
}
switch name {
case linux.PACKET_HDRLEN:
var version primitive.Int32
version.CopyIn(t, outPtr)
switch version {
case linux.TPACKET_V1:
v := primitive.Int32(uint32((*linux.TpacketHdr)(nil).SizeBytes()))
return &v, nil
case linux.TPACKET_V2:
v := primitive.Int32(uint32((*linux.Tpacket2Hdr)(nil).SizeBytes()))
return &v, nil
default:
return nil, syserr.ErrInvalidArgument
}
}
return nil, syserr.ErrProtocolNotAvailable
}
// SetSockOpt can be used to implement the linux syscall setsockopt(2) for
// sockets backed by a commonEndpoint.
func SetSockOpt(t *kernel.Task, s socket.Socket, ep commonEndpoint, level int, name int, optVal []byte) *syserr.Error {
@@ -2761,6 +2784,12 @@ func setSockOptPacket(t *kernel.Task, s socket.Socket, ep commonEndpoint, name i
}
v := hostarch.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.PacketMMapVersionOption, int(v)))
case linux.PACKET_RESERVE:
v := hostarch.ByteOrder.Uint32(optVal)
return syserr.TranslateNetstackError(ep.SetSockOptInt(tcpip.PacketMMapReserveOption, int(v)))
case linux.PACKET_ADD_MEMBERSHIP, linux.PACKET_AUXDATA:
// Silently ignore these options.
return nil
default:
return syserr.ErrNotSupported
}
@@ -71,6 +71,7 @@ type Endpoint struct {
cooked bool
packetEP stack.MappablePacketEndpoint
reserve uint32
nicID tcpip.NICID
netProto tcpip.NetworkProtocolNumber
version int
@@ -99,6 +100,9 @@ func (m *Endpoint) Init(ctx context.Context, opts stack.PacketMMapOpts) error {
m.nicID = opts.NICID
m.netProto = opts.NetProto
m.version = opts.Version
m.reserve = opts.Reserve
m.nicID = opts.NICID
m.netProto = opts.NetProto
switch m.version {
case linux.TPACKET_V1:
m.headerLen = linux.TPACKET_HDRLEN
@@ -114,7 +118,7 @@ func (m *Endpoint) Init(ctx context.Context, opts stack.PacketMMapOpts) error {
if opts.Req.TpBlockSize%hostarch.PageSize != 0 {
return linuxerr.EINVAL
}
if opts.Req.TpFrameSize < m.headerLen {
if opts.Req.TpFrameSize < m.headerLen+m.reserve {
return linuxerr.EINVAL
}
if opts.Req.TpFrameSize&(linux.TPACKET_ALIGNMENT-1) != 0 {
@@ -206,14 +210,14 @@ func (m *Endpoint) HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtoco
pktBuf.TrimFront(int64(len(pkt.LinkHeader().Slice()) + len(pkt.VirtioNetHeader().Slice())))
// Cooked packet endpoints don't include the link-headers in received
// packets.
netOffset = linux.TPacketAlign(m.headerLen + minMacLen)
netOffset = linux.TPacketAlign(m.headerLen+minMacLen) + m.reserve
macOffset = netOffset
} else {
virtioNetHdrLen := uint32(len(pkt.VirtioNetHeader().Slice()))
macLen := uint32(len(pkt.LinkHeader().Slice())) + virtioNetHdrLen
netOffset = linux.TPacketAlign(m.headerLen + macLen)
netOffset = linux.TPacketAlign(m.headerLen+macLen) + m.reserve
if macLen < minMacLen {
netOffset = linux.TPacketAlign(m.headerLen + minMacLen)
netOffset = linux.TPacketAlign(m.headerLen+minMacLen) + m.reserve
}
if virtioNetHdrLen > 0 {
netOffset += virtioNetHdrLen