Add support to return protocol in recvmsg for AF_PACKET.

Updates #173

PiperOrigin-RevId: 321690756
This commit is contained in:
Bhasker Hariharan
2020-07-16 18:40:32 -07:00
committed by gVisor bot
parent e6894cb99f
commit dcf6ddc277
5 changed files with 58 additions and 5 deletions
+21 -3
View File
@@ -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 {
+19
View File
@@ -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
+16 -2
View File
@@ -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 {
+1
View File
@@ -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);
+1
View File
@@ -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);