Set PktType for all Ethernet Packets

In preparation for improving ARP handling of gratuitous ARPs, set PktType in
regular inbound flow instead of only when handling packet sockets.

PiperOrigin-RevId: 501562322
This commit is contained in:
Bruno Dal Bo
2023-01-12 07:43:18 -08:00
committed by gVisor bot
parent e49f78af9e
commit 2b208ac832
13 changed files with 115 additions and 51 deletions
+1
View File
@@ -26,5 +26,6 @@ go_test(
"//pkg/tcpip/header",
"//pkg/tcpip/link/channel",
"//pkg/tcpip/stack",
"@com_github_google_go_cmp//cmp:go_default_library",
],
)
+12 -1
View File
@@ -64,10 +64,21 @@ func (e *Endpoint) DeliverNetworkPacket(_ tcpip.NetworkProtocolNumber, pkt stack
if !ok {
return
}
eth := header.Ethernet(hdr)
dst := eth.DestinationAddress()
if dst == header.EthernetBroadcastAddress {
pkt.PktType = tcpip.PacketBroadcast
} else if header.IsMulticastEthernetAddress(dst) {
pkt.PktType = tcpip.PacketMulticast
} else if dst == e.LinkAddress() {
pkt.PktType = tcpip.PacketHost
} else {
pkt.PktType = tcpip.PacketOtherHost
}
// Note, there is no need to check the destination link address here since
// the ethernet hardware filters frames based on their destination addresses.
e.Endpoint.DeliverNetworkPacket(header.Ethernet(hdr).Type() /* protocol */, pkt)
e.Endpoint.DeliverNetworkPacket(eth.Type() /* protocol */, pkt)
}
// Capabilities implements stack.LinkEndpoint.
+75 -27
View File
@@ -19,6 +19,7 @@ import (
"os"
"testing"
"github.com/google/go-cmp/cmp"
"gvisor.dev/gvisor/pkg/bufferv2"
"gvisor.dev/gvisor/pkg/refs"
"gvisor.dev/gvisor/pkg/tcpip"
@@ -30,47 +31,94 @@ import (
var _ stack.NetworkDispatcher = (*testNetworkDispatcher)(nil)
type deliveredPacket struct {
protocol tcpip.NetworkProtocolNumber
packet stack.PacketBufferPtr
}
type testNetworkDispatcher struct {
networkPackets int
networkPackets []deliveredPacket
}
func (t *testNetworkDispatcher) DeliverNetworkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr) {
t.networkPackets++
func (t *testNetworkDispatcher) DeliverNetworkPacket(proto tcpip.NetworkProtocolNumber, pb stack.PacketBufferPtr) {
t.networkPackets = append(t.networkPackets, deliveredPacket{protocol: proto, packet: pb})
}
func (*testNetworkDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr, bool) {
func (*testNetworkDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr) {
panic("not implemented")
}
func TestDeliverNetworkPacket(t *testing.T) {
const (
linkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06")
otherLinkAddr1 = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x07")
otherLinkAddr2 = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x08")
linkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x06")
otherLinkAddr = tcpip.LinkAddress("\x02\x02\x03\x04\x05\x07")
)
e := ethernet.New(channel.New(0, 0, linkAddr))
var networkDispatcher testNetworkDispatcher
e.Attach(&networkDispatcher)
for _, testCase := range []struct {
name string
dstAddr tcpip.LinkAddress
pktType tcpip.PacketType
}{
{
name: "unicast",
dstAddr: linkAddr,
pktType: tcpip.PacketHost,
},
{
name: "broadcast",
dstAddr: header.EthernetBroadcastAddress,
pktType: tcpip.PacketBroadcast,
},
{
name: "multicast",
dstAddr: tcpip.LinkAddress("\xFF\x00\x00\x00\x05\x07"),
pktType: tcpip.PacketMulticast,
},
{
name: "other host",
dstAddr: tcpip.LinkAddress("\x02\x02\x03\x04\x05\x08"),
pktType: tcpip.PacketOtherHost,
},
} {
t.Run(testCase.name, func(t *testing.T) {
if networkDispatcher.networkPackets != 0 {
t.Fatalf("got networkDispatcher.networkPackets = %d, want = 0", networkDispatcher.networkPackets)
}
e := ethernet.New(channel.New(0, 0, linkAddr))
var networkDispatcher testNetworkDispatcher
e.Attach(&networkDispatcher)
// An ethernet frame with a destination link address that is not assigned to
// our ethernet link endpoint should still be delivered to the network
// dispatcher since the ethernet endpoint is not expected to filter frames.
eth := make([]byte, header.EthernetMinimumSize)
header.Ethernet(eth).Encode(&header.EthernetFields{
SrcAddr: otherLinkAddr1,
DstAddr: otherLinkAddr2,
Type: header.IPv4ProtocolNumber,
})
p := stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: bufferv2.MakeWithData(eth)})
defer p.DecRef()
e.DeliverNetworkPacket(0, p)
if networkDispatcher.networkPackets != 1 {
t.Fatalf("got networkDispatcher.networkPackets = %d, want = 1", networkDispatcher.networkPackets)
if got, want := len(networkDispatcher.networkPackets), 0; got != want {
t.Fatalf("got networkDispatcher.networkPackets = %d, want = %d", got, want)
}
const networkProtocol = header.IPv4ProtocolNumber
// An ethernet frame with a destination link address that is not assigned to
// our ethernet link endpoint should still be delivered to the network
// dispatcher since the ethernet endpoint is not expected to filter frames.
eth := make([]byte, header.EthernetMinimumSize)
header.Ethernet(eth).Encode(&header.EthernetFields{
SrcAddr: otherLinkAddr,
DstAddr: testCase.dstAddr,
Type: networkProtocol,
})
p := stack.NewPacketBuffer(stack.PacketBufferOptions{Payload: bufferv2.MakeWithData(eth)})
defer p.DecRef()
e.DeliverNetworkPacket(0, p)
if got, want := len(networkDispatcher.networkPackets), 1; got != want {
t.Fatalf("got networkDispatcher.networkPackets = %d, want = %d", got, want)
}
delivered := networkDispatcher.networkPackets[0]
if diff := cmp.Diff(delivered.packet.LinkHeader().Slice(), eth); diff != "" {
t.Errorf("LinkHeader mismatch (-want +got):\n%s", diff)
}
if got, want := delivered.protocol, networkProtocol; got != want {
t.Errorf("got delivered.protocol = %d, want = %d", got, want)
}
if got, want := delivered.packet.PktType, testCase.pktType; got != want {
t.Errorf("got delivered.packet.PktType = %d, want = %d", got, want)
}
})
}
}
+2 -2
View File
@@ -137,7 +137,7 @@ func (c *context) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt
c.ch <- packetInfo{protocol, pkt}
}
func (c *context) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr, bool) {
func (c *context) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr) {
c.t.Fatal("DeliverLinkPacket not implemented")
}
@@ -575,7 +575,7 @@ func (d *fakeNetworkDispatcher) DeliverNetworkPacket(_ tcpip.NetworkProtocolNumb
d.pkts = append(d.pkts, pkt)
}
func (*fakeNetworkDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr, bool) {
func (*fakeNetworkDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr) {
panic("not implemented")
}
+2 -2
View File
@@ -61,12 +61,12 @@ func (e *Endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pk
}
// DeliverLinkPacket implements stack.NetworkDispatcher.
func (e *Endpoint) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr, incoming bool) {
func (e *Endpoint) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) {
e.mu.RLock()
d := e.dispatcher
e.mu.RUnlock()
if d != nil {
d.DeliverLinkPacket(protocol, pkt, incoming)
d.DeliverLinkPacket(protocol, pkt)
}
}
+1 -1
View File
@@ -57,7 +57,7 @@ func (d *counterDispatcher) DeliverNetworkPacket(tcpip.NetworkProtocolNumber, st
d.count++
}
func (*counterDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr, bool) {
func (*counterDispatcher) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr) {
panic("not implemented")
}
+2 -2
View File
@@ -41,7 +41,7 @@ func New(lower stack.LinkEndpoint) stack.LinkEndpoint {
// DeliverNetworkPacket implements stack.NetworkDispatcher.
func (e *endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) {
e.Endpoint.DeliverLinkPacket(protocol, pkt, true /* incoming */)
e.Endpoint.DeliverLinkPacket(protocol, pkt)
e.Endpoint.DeliverNetworkPacket(protocol, pkt)
}
@@ -49,7 +49,7 @@ func (e *endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pk
// WritePackets implements stack.LinkEndpoint.
func (e *endpoint) WritePackets(pkts stack.PacketBufferList) (int, tcpip.Error) {
for _, pkt := range pkts.AsSlice() {
e.Endpoint.DeliverLinkPacket(pkt.NetworkProtocolNumber, pkt, false /* incoming */)
e.Endpoint.DeliverLinkPacket(pkt.NetworkProtocolNumber, pkt)
}
return e.Endpoint.WritePackets(pkts)
@@ -59,7 +59,6 @@ var _ stack.NetworkDispatcher = (*testNetworkDispatcher)(nil)
type linkPacketInfo struct {
pkt stack.PacketBufferPtr
protocol tcpip.NetworkProtocolNumber
incoming bool
}
type networkPacketInfo struct {
@@ -99,11 +98,10 @@ func (t *testNetworkDispatcher) DeliverNetworkPacket(protocol tcpip.NetworkProto
t.networkPacket = networkPacket
}
func (t *testNetworkDispatcher) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr, incoming bool) {
func (t *testNetworkDispatcher) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) {
linkPacket := linkPacketInfo{
pkt: pkt.IncRef(),
protocol: protocol,
incoming: incoming,
}
if t.linkPacket != (linkPacketInfo{}) {
@@ -128,6 +126,7 @@ func TestPacketDispatch(t *testing.T) {
pkt.NetworkProtocolNumber = protocol
{
pkt.PktType = tcpip.PacketOutgoing
var pkts stack.PacketBufferList
pkts.PushBack(pkt)
if n, err := ep.WritePackets(pkts); err != nil {
@@ -139,18 +138,19 @@ func TestPacketDispatch(t *testing.T) {
if want := (networkPacketInfo{}); d.networkPacket != want {
t.Errorf("got d.networkPacket = %#v, want = %#v", d.networkPacket, want)
}
if want := (linkPacketInfo{pkt: pkt, protocol: protocol, incoming: false}); d.linkPacket != want {
if want := (linkPacketInfo{pkt: pkt, protocol: protocol}); d.linkPacket != want {
t.Errorf("got d.linkPacket = %#v, want = %#v", d.linkPacket, want)
}
}
d.reset()
{
pkt.PktType = tcpip.PacketHost
nullEP.disp.DeliverNetworkPacket(protocol, pkt)
if want := (networkPacketInfo{pkt: pkt, protocol: protocol}); d.networkPacket != want {
t.Errorf("got d.networkPacket = %#v, want = %#v", d.networkPacket, want)
}
if want := (linkPacketInfo{pkt: pkt, protocol: protocol, incoming: true}); d.linkPacket != want {
if want := (linkPacketInfo{pkt: pkt, protocol: protocol}); d.linkPacket != want {
t.Errorf("got d.linkPacket = %#v, want = %#v", d.linkPacket, want)
}
}
+1 -1
View File
@@ -154,7 +154,7 @@ func (c *testContext) DeliverNetworkPacket(proto tcpip.NetworkProtocolNumber, pk
c.packetCh <- struct{}{}
}
func (c *testContext) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr, bool) {
func (c *testContext) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr) {
c.t.Fatal("DeliverLinkPacket not implemented")
}
+2 -2
View File
@@ -63,12 +63,12 @@ func (e *Endpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pk
}
// DeliverLinkPacket implements stack.NetworkDispatcher.
func (e *Endpoint) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr, incoming bool) {
func (e *Endpoint) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt stack.PacketBufferPtr) {
if !e.dispatchGate.Enter() {
return
}
e.dispatcher.DeliverLinkPacket(protocol, pkt, incoming)
e.dispatcher.DeliverLinkPacket(protocol, pkt)
e.dispatchGate.Leave()
}
+1 -1
View File
@@ -43,7 +43,7 @@ func (e *countedEndpoint) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNum
e.dispatchCount++
}
func (*countedEndpoint) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr, bool) {
func (*countedEndpoint) DeliverLinkPacket(tcpip.NetworkProtocolNumber, stack.PacketBufferPtr) {
panic("not implemented")
}
+10 -6
View File
@@ -386,6 +386,8 @@ func (n *nic) writePacket(pkt PacketBufferPtr) tcpip.Error {
}
func (n *nic) writeRawPacket(pkt PacketBufferPtr) tcpip.Error {
// Always an outgoing packet.
pkt.PktType = tcpip.PacketOutgoing
if err := n.qDisc.WritePacket(pkt); err != nil {
if _, ok := err.(*tcpip.ErrNoBufferSpace); ok {
n.stats.txPacketsDroppedNoBufferSpace.Increment()
@@ -738,7 +740,7 @@ func (n *nic) DeliverNetworkPacket(protocol tcpip.NetworkProtocolNumber, pkt Pac
n.gro.dispatch(pkt, protocol, networkEndpoint)
}
func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr, incoming bool) {
func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr) {
// Deliver to interested packet endpoints without holding NIC lock.
var packetEPPkt PacketBufferPtr
defer func() {
@@ -764,11 +766,13 @@ func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt Packet
// populate it in the packet buffer we provide to packet endpoints as
// packet endpoints inspect link headers.
packetEPPkt.LinkHeader().Consume(len(pkt.LinkHeader().Slice()))
if incoming {
packetEPPkt.PktType = pkt.PktType
// Assume the packet is for us if the packet type is unset.
// The packet type is set to PacketOutgoing when sending packets so
// this may only be unset for incoming packets where link endpoints
// have not set it.
if packetEPPkt.PktType == 0 {
packetEPPkt.PktType = tcpip.PacketHost
} else {
packetEPPkt.PktType = tcpip.PacketOutgoing
}
}
@@ -785,7 +789,7 @@ func (n *nic) DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt Packet
n.packetEPsMu.Unlock()
// On Linux, only ETH_P_ALL endpoints get outbound packets.
if incoming && protoEPsOK {
if pkt.PktType != tcpip.PacketOutgoing && protoEPsOK {
protoEPs.forEach(deliverPacketEPs)
}
if anyEPsOK {
+1 -1
View File
@@ -1034,7 +1034,7 @@ type NetworkDispatcher interface {
// This method should be called with both incoming and outgoing packets.
//
// If the link-layer has a header, the packet's link header must be populated.
DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr, incoming bool)
DeliverLinkPacket(protocol tcpip.NetworkProtocolNumber, pkt PacketBufferPtr)
}
// LinkEndpointCapabilities is the type associated with the capabilities