mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add support to return protocol in recvmsg for AF_PACKET.
Updates #173 PiperOrigin-RevId: 321690756
This commit is contained in:
committed by
gVisor bot
parent
e6894cb99f
commit
dcf6ddc277
@@ -297,8 +297,9 @@ type socketOpsCommon struct {
|
||||
readView buffer.View
|
||||
// readCM holds control message information for the last packet read
|
||||
// from Endpoint.
|
||||
readCM tcpip.ControlMessages
|
||||
sender tcpip.FullAddress
|
||||
readCM tcpip.ControlMessages
|
||||
sender tcpip.FullAddress
|
||||
linkPacketInfo tcpip.LinkPacketInfo
|
||||
|
||||
// sockOptTimestamp corresponds to SO_TIMESTAMP. When true, timestamps
|
||||
// of returned messages can be returned via control messages. When
|
||||
@@ -447,8 +448,21 @@ func (s *socketOpsCommon) fetchReadView() *syserr.Error {
|
||||
}
|
||||
s.readView = nil
|
||||
s.sender = tcpip.FullAddress{}
|
||||
s.linkPacketInfo = tcpip.LinkPacketInfo{}
|
||||
|
||||
v, cms, err := s.Endpoint.Read(&s.sender)
|
||||
var v buffer.View
|
||||
var cms tcpip.ControlMessages
|
||||
var err *tcpip.Error
|
||||
|
||||
switch e := s.Endpoint.(type) {
|
||||
// The ordering of these interfaces matters. The most specific
|
||||
// interfaces must be specified before the more generic Endpoint
|
||||
// interface.
|
||||
case tcpip.PacketEndpoint:
|
||||
v, cms, err = e.ReadPacket(&s.sender, &s.linkPacketInfo)
|
||||
case tcpip.Endpoint:
|
||||
v, cms, err = e.Read(&s.sender)
|
||||
}
|
||||
if err != nil {
|
||||
atomic.StoreUint32(&s.readViewHasData, 0)
|
||||
return syserr.TranslateNetstackError(err)
|
||||
@@ -2509,6 +2523,10 @@ func (s *socketOpsCommon) nonBlockingRead(ctx context.Context, dst usermem.IOSeq
|
||||
var addrLen uint32
|
||||
if isPacket && senderRequested {
|
||||
addr, addrLen = ConvertAddress(s.family, s.sender)
|
||||
switch v := addr.(type) {
|
||||
case *linux.SockAddrLink:
|
||||
v.Protocol = htons(uint16(s.linkPacketInfo.Protocol))
|
||||
}
|
||||
}
|
||||
|
||||
if peek {
|
||||
|
||||
@@ -549,6 +549,25 @@ type Endpoint interface {
|
||||
SetOwner(owner PacketOwner)
|
||||
}
|
||||
|
||||
// LinkPacketInfo holds Link layer information for a received packet.
|
||||
//
|
||||
// +stateify savable
|
||||
type LinkPacketInfo struct {
|
||||
// Protocol is the NetworkProtocolNumber for the packet.
|
||||
Protocol NetworkProtocolNumber
|
||||
}
|
||||
|
||||
// PacketEndpoint are additional methods that are only implemented by Packet
|
||||
// endpoints.
|
||||
type PacketEndpoint interface {
|
||||
// ReadPacket reads a datagram/packet from the endpoint and optionally
|
||||
// returns the sender and additional LinkPacketInfo.
|
||||
//
|
||||
// This method does not block if there is no data pending. It will also
|
||||
// either return an error or data, never both.
|
||||
ReadPacket(*FullAddress, *LinkPacketInfo) (buffer.View, ControlMessages, *Error)
|
||||
}
|
||||
|
||||
// EndpointInfo is the interface implemented by each endpoint info struct.
|
||||
type EndpointInfo interface {
|
||||
// IsEndpointInfo is an empty method to implement the tcpip.EndpointInfo
|
||||
|
||||
@@ -45,6 +45,9 @@ type packet struct {
|
||||
timestampNS int64
|
||||
// senderAddr is the network address of the sender.
|
||||
senderAddr tcpip.FullAddress
|
||||
// packetInfo holds additional information like the protocol
|
||||
// of the packet etc.
|
||||
packetInfo tcpip.LinkPacketInfo
|
||||
}
|
||||
|
||||
// endpoint is the packet socket implementation of tcpip.Endpoint. It is legal
|
||||
@@ -151,8 +154,8 @@ func (ep *endpoint) Close() {
|
||||
// ModerateRecvBuf implements tcpip.Endpoint.ModerateRecvBuf.
|
||||
func (ep *endpoint) ModerateRecvBuf(copied int) {}
|
||||
|
||||
// Read implements tcpip.Endpoint.Read.
|
||||
func (ep *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMessages, *tcpip.Error) {
|
||||
// Read implements tcpip.PacketEndpoint.ReadPacket.
|
||||
func (ep *endpoint) ReadPacket(addr *tcpip.FullAddress, info *tcpip.LinkPacketInfo) (buffer.View, tcpip.ControlMessages, *tcpip.Error) {
|
||||
ep.rcvMu.Lock()
|
||||
|
||||
// If there's no data to read, return that read would block or that the
|
||||
@@ -177,9 +180,18 @@ func (ep *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMes
|
||||
*addr = packet.senderAddr
|
||||
}
|
||||
|
||||
if info != nil {
|
||||
*info = packet.packetInfo
|
||||
}
|
||||
|
||||
return packet.data.ToView(), tcpip.ControlMessages{HasTimestamp: true, Timestamp: packet.timestampNS}, nil
|
||||
}
|
||||
|
||||
// Read implements tcpip.Endpoint.Read.
|
||||
func (ep *endpoint) Read(addr *tcpip.FullAddress) (buffer.View, tcpip.ControlMessages, *tcpip.Error) {
|
||||
return ep.ReadPacket(addr, nil)
|
||||
}
|
||||
|
||||
func (ep *endpoint) Write(p tcpip.Payloader, opts tcpip.WriteOptions) (int64, <-chan struct{}, *tcpip.Error) {
|
||||
// TODO(b/129292371): Implement.
|
||||
return 0, nil, tcpip.ErrInvalidOptionValue
|
||||
@@ -428,12 +440,14 @@ func (ep *endpoint) HandlePacket(nicID tcpip.NICID, localAddr tcpip.LinkAddress,
|
||||
NIC: nicID,
|
||||
Addr: tcpip.Address(hdr.SourceAddress()),
|
||||
}
|
||||
packet.packetInfo.Protocol = netProto
|
||||
} else {
|
||||
// Guess the would-be ethernet header.
|
||||
packet.senderAddr = tcpip.FullAddress{
|
||||
NIC: nicID,
|
||||
Addr: tcpip.Address(localAddr),
|
||||
}
|
||||
packet.packetInfo.Protocol = netProto
|
||||
}
|
||||
|
||||
if ep.cooked {
|
||||
|
||||
@@ -193,6 +193,7 @@ void ReceiveMessage(int sock, int ifindex) {
|
||||
EXPECT_EQ(src.sll_family, AF_PACKET);
|
||||
EXPECT_EQ(src.sll_ifindex, ifindex);
|
||||
EXPECT_EQ(src.sll_halen, ETH_ALEN);
|
||||
EXPECT_EQ(ntohs(src.sll_protocol), ETH_P_IP);
|
||||
// This came from the loopback device, so the address is all 0s.
|
||||
for (int i = 0; i < src.sll_halen; i++) {
|
||||
EXPECT_EQ(src.sll_addr[i], 0);
|
||||
|
||||
@@ -200,6 +200,7 @@ TEST_P(RawPacketTest, Receive) {
|
||||
EXPECT_EQ(src.sll_family, AF_PACKET);
|
||||
EXPECT_EQ(src.sll_ifindex, GetLoopbackIndex());
|
||||
EXPECT_EQ(src.sll_halen, ETH_ALEN);
|
||||
EXPECT_EQ(ntohs(src.sll_protocol), ETH_P_IP);
|
||||
// This came from the loopback device, so the address is all 0s.
|
||||
for (int i = 0; i < src.sll_halen; i++) {
|
||||
EXPECT_EQ(src.sll_addr[i], 0);
|
||||
|
||||
Reference in New Issue
Block a user