Skip to content

Commit

Permalink
Create the interfaces for PACKET_MMAP endpoints to implement.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 715019134
  • Loading branch information
manninglucas authored and gvisor-bot committed Jan 14, 2025
1 parent 3649ca9 commit 1381189
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 0 deletions.
66 changes: 66 additions & 0 deletions pkg/abi/linux/socket.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,72 @@ const (
PACKET_OUTGOING = 4 // Outgoing of any type
)

// Packet socket options from <linux/if_packet.h>
const (
PACKET_RX_RING = 5
)

// Statuses for a frame in a packet_mmap ring buffer from <linux/if_packet.h>.
const (
TP_STATUS_KERNEL = 0
TP_STATUS_USER = 0x1
TP_STATUS_COPY = 0x2
TP_STATUS_LOSING = 0x4
TP_STATUS_CSUM_NOT_READY = 0x8
TP_STATUS_VLAN_VALID = 0x10
TP_STATUS_BLK_TMO = 0x20
TP_STATUS_VLAN_TPID_VALID = 0x40
TP_STATUS_CSUM_VALID = 0x80
TP_STATUS_GSO_TCP = 0x100
)

// TpacketReq is the request for a packet_mmap ring buffer from
// <linux/if_packet.h>.
//
// +marshal
type TpacketReq struct {
TpBlockSize uint32
TpBlockNr uint32
TpFrameSize uint32
TpFrameNr uint32
}

// TpacketHdr is the header for a frame in a packet_mmap ring buffer from
// <linux/if_packet.h>.
//
// +marshal
type TpacketHdr struct {
TpStatus uint64
TpLen uint32
TpSnaplen uint32
TpMac uint16
TpNet uint16
TpSec uint32
TpUsec uint32 `marshal:"unaligned"`
}

// TpacketAlignment is the alignment of a frame in a packet_mmap ring buffer
// from <linux/if_packet.h>.
const (
TPACKET_ALIGNMENT = 16
)

// TPACKET_V1 is the version of a packet_mmap ring buffer from
// <linux/if_packet.h> that is implemented in gVisor.
const (
TPACKET_V1 = iota
)

// TPACKET_HDRLEN is the length of a TpacketHdr from <linux/if_packet.h>.
var (
TPACKET_HDRLEN = uint32((*TpacketHdr)(nil).SizeBytes()) + uint32((*SockAddrLink)(nil).SizeBytes())
)

// TPacketAlign aligns a value to the alignment of a TPacket.
func TPacketAlign(x uint32) uint32 {
return (x + TPACKET_ALIGNMENT - 1) &^ (TPACKET_ALIGNMENT - 1)
}

// Socket options from socket.h.
const (
SO_DEBUG = 1
Expand Down
1 change: 1 addition & 0 deletions pkg/sentry/socket/netstack/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ go_library(
"//pkg/sentry/kernel",
"//pkg/sentry/kernel/auth",
"//pkg/sentry/ktime",
"//pkg/sentry/memmap",
"//pkg/sentry/socket",
"//pkg/sentry/socket/netfilter",
"//pkg/sentry/socket/netlink/nlmsg",
Expand Down
23 changes: 23 additions & 0 deletions pkg/sentry/socket/netstack/netstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import (
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
"gvisor.dev/gvisor/pkg/sentry/ktime"
"gvisor.dev/gvisor/pkg/sentry/memmap"
"gvisor.dev/gvisor/pkg/sentry/socket"
"gvisor.dev/gvisor/pkg/sentry/socket/netfilter"
epb "gvisor.dev/gvisor/pkg/sentry/socket/netstack/events_go_proto"
Expand Down Expand Up @@ -318,6 +319,28 @@ const sizeOfInt32 int = 4

var errStackType = syserr.New("expected but did not receive a netstack.Stack", errno.EINVAL)

// mappableEndpoint is the interface implemented by endpoints that support
// mmap.
type mappableEndpoint interface {
// ConfigureMMap implements vfs.FileDescriptionImpl.ConfigureMMap.
ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error

// AddMapping implements memmap.Mappable.AddMapping.
AddMapping(context.Context, memmap.MappingSpace, hostarch.AddrRange, uint64, bool) error

// RemoveMapping implements memmap.Mappable.RemoveMapping.
RemoveMapping(context.Context, memmap.MappingSpace, hostarch.AddrRange, uint64, bool)

// CopyMapping implements memmap.Mappable.CopyMapping.
CopyMapping(context.Context, memmap.MappingSpace, hostarch.AddrRange, hostarch.AddrRange, uint64, bool) error

// Translate implements memmap.Mappable.Translate.
Translate(context.Context, memmap.MappableRange, memmap.MappableRange, hostarch.AccessType) ([]memmap.Translation, error)

// InvalidateUnsavable implements memmap.Mappable.InvalidateUnsavable.
InvalidateUnsavable(context.Context) error
}

// commonEndpoint represents the intersection of a tcpip.Endpoint and a
// transport.Endpoint.
type commonEndpoint interface {
Expand Down
3 changes: 3 additions & 0 deletions pkg/syserr/netstack.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ var (
ErrMulticastInputCannotBeOutput = New((&tcpip.ErrMulticastInputCannotBeOutput{}).String(), errno.EINVAL)
ErrMissingRequiredFields = New((&tcpip.ErrMissingRequiredFields{}).String(), errno.EINVAL)
ErrNoNet = New((&tcpip.ErrNoNet{}).String(), errno.ENONET)
ErrEndpointBusy = New((&tcpip.ErrEndpointBusy{}).String(), errno.EBUSY)
)

// TranslateNetstackError converts an error from the tcpip package to a sentry
Expand Down Expand Up @@ -149,6 +150,8 @@ func TranslateNetstackError(err tcpip.Error) *Error {
return ErrMulticastInputCannotBeOutput
case *tcpip.ErrMissingRequiredFields:
return ErrMissingRequiredFields
case *tcpip.ErrEndpointBusy:
return ErrEndpointBusy
default:
panic(fmt.Sprintf("unknown error %T", err))
}
Expand Down
18 changes: 18 additions & 0 deletions pkg/tcpip/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,4 +620,22 @@ func (*ErrMulticastInputCannotBeOutput) IgnoreStats() bool {
}
func (*ErrMulticastInputCannotBeOutput) String() string { return "output cannot contain input" }

// ErrEndpointBusy indicates that the operation cannot be completed because the
// endpoint is busy.
//
// +stateify savable
type ErrEndpointBusy struct{}

// isError implements Error.
func (*ErrEndpointBusy) isError() {}

// IgnoreStats implements Error.
func (*ErrEndpointBusy) IgnoreStats() bool {
return true
}

func (*ErrEndpointBusy) String() string {
return "operation cannot be completed because the endpoint is busy"
}

// LINT.ThenChange(../syserr/netstack.go)
52 changes: 52 additions & 0 deletions pkg/tcpip/stack/registration.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,58 @@ type PacketEndpoint interface {
HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *PacketBuffer)
}

// MappablePacketEndpoint is a packet endpoint that supports forwarding its
// packets to a PacketMMapEndpoint.
type MappablePacketEndpoint interface {
PacketEndpoint

// ConfigurePacketMMap configures the endpoint to use a memory mapped endpoint
// handler ep. All packets sent or received via this endpoint will be handled
// by the PacketMMapEndpoint.
ConfigurePacketMMap(ep PacketMMapEndpoint)
}

// PacketMMapCopyHandler is a function that is called when a packet received is
// too large for the buffer size specified for the memory mapped endpoint. In
// this case, the packet is copied and passed to the PacketMMapCopyHandler.
type PacketMMapCopyHandler func(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *PacketBuffer)

// InitPacketMMapOpts are the options for initializing a PacketMMapEndpoint.
type InitPacketMMapOpts struct {
RxReq, TxReq *tcpip.TpacketReq
Cooked bool
Stack *Stack
Stats *tcpip.TransportEndpointStats
Wq *waiter.Queue
CopyHandler PacketMMapCopyHandler
}

// PacketMMapEndpoint is the interface implemented by endpoints to handle memory
// mapped packets over the packet transport protocol (PACKET_MMAP).
type PacketMMapEndpoint interface {
// HandlePacket is called by the stack when new packets arrive that
// match the endpoint.
//
// Implementers should treat packet as immutable and should copy it
// before before modification.
//
// linkHeader may have a length of 0, in which case the PacketEndpoint
// should construct its own ethernet header for applications.
//
// HandlePacket may modify pkt.
HandlePacket(nicID tcpip.NICID, netProto tcpip.NetworkProtocolNumber, pkt *PacketBuffer)

// Close releases any resources associated with the endpoint.
Close()

// Readiness returns the events that the endpoint is ready for.
Readiness(mask waiter.EventMask) waiter.EventMask

// InitPacketMMap initializes the endpoint. It must be called before any other
// methods.
InitPacketMMap(opts InitPacketMMapOpts) tcpip.Error
}

// UnknownDestinationPacketDisposition enumerates the possible return values from
// HandleUnknownDestinationPacket().
type UnknownDestinationPacketDisposition int
Expand Down
13 changes: 13 additions & 0 deletions pkg/tcpip/tcpip.go
Original file line number Diff line number Diff line change
Expand Up @@ -1185,6 +1185,19 @@ func (*ICMPv6Filter) isGettableSocketOption() {}

func (*ICMPv6Filter) isSettableSocketOption() {}

// TpacketReq is the tpacket_req structure as described in
// https://www.kernel.org/doc/Documentation/networking/packet_mmap.txt
//
// +stateify savable
type TpacketReq struct {
TpBlockSize uint32
TpBlockNr uint32
TpFrameSize uint32
TpFrameNr uint32
}

func (*TpacketReq) isSettableSocketOption() {}

// EndpointState represents the state of an endpoint.
type EndpointState uint8

Expand Down

0 comments on commit 1381189

Please sign in to comment.