diff options
author | Ghanan Gowripalan <ghanan@google.com> | 2021-01-06 14:01:05 -0800 |
---|---|---|
committer | gVisor bot <gvisor-bot@google.com> | 2021-01-06 14:02:45 -0800 |
commit | 7817e3b5e4202eb2001806b5043052a2f5b591a4 (patch) | |
tree | 0784014a9b19933a67ff3adb259135e1d71d393e | |
parent | abe9d9f67f2c2c696ef26690fa8518dfc4e28728 (diff) |
Do not filter frames in ethernet link endpoint
Ethernet frames are usually filtered at the hardware-level so there is
no need to filter the frames in software.
For test purposes, a new link endpoint was introduced to filter frames
based on their destination.
PiperOrigin-RevId: 350422941
-rw-r--r-- | pkg/tcpip/link/ethernet/BUILD | 16 | ||||
-rw-r--r-- | pkg/tcpip/link/ethernet/ethernet.go | 6 | ||||
-rw-r--r-- | pkg/tcpip/link/ethernet/ethernet_test.go | 71 | ||||
-rw-r--r-- | pkg/tcpip/tests/integration/BUILD | 1 | ||||
-rw-r--r-- | pkg/tcpip/tests/integration/forward_test.go | 37 | ||||
-rw-r--r-- | pkg/tcpip/tests/integration/link_resolution_test.go | 5 |
6 files changed, 125 insertions, 11 deletions
diff --git a/pkg/tcpip/link/ethernet/BUILD b/pkg/tcpip/link/ethernet/BUILD index ec92ed623..0ae0d201a 100644 --- a/pkg/tcpip/link/ethernet/BUILD +++ b/pkg/tcpip/link/ethernet/BUILD @@ -1,4 +1,4 @@ -load("//tools:defs.bzl", "go_library") +load("//tools:defs.bzl", "go_library", "go_test") package(licenses = ["notice"]) @@ -13,3 +13,17 @@ go_library( "//pkg/tcpip/stack", ], ) + +go_test( + name = "ethernet_test", + size = "small", + srcs = ["ethernet_test.go"], + deps = [ + ":ethernet", + "//pkg/tcpip", + "//pkg/tcpip/buffer", + "//pkg/tcpip/header", + "//pkg/tcpip/link/channel", + "//pkg/tcpip/stack", + ], +) diff --git a/pkg/tcpip/link/ethernet/ethernet.go b/pkg/tcpip/link/ethernet/ethernet.go index beefcd008..89e3e6164 100644 --- a/pkg/tcpip/link/ethernet/ethernet.go +++ b/pkg/tcpip/link/ethernet/ethernet.go @@ -49,10 +49,10 @@ func (e *Endpoint) DeliverNetworkPacket(_, _ tcpip.LinkAddress, _ tcpip.NetworkP return } + // Note, there is no need to check the destination link address here since + // the ethernet hardware filters frames based on their destination addresses. eth := header.Ethernet(hdr) - if dst := eth.DestinationAddress(); dst == e.Endpoint.LinkAddress() || dst == header.EthernetBroadcastAddress || header.IsMulticastEthernetAddress(dst) { - e.Endpoint.DeliverNetworkPacket(eth.SourceAddress() /* remote */, dst /* local */, eth.Type() /* protocol */, pkt) - } + e.Endpoint.DeliverNetworkPacket(eth.SourceAddress() /* remote */, eth.DestinationAddress() /* local */, eth.Type() /* protocol */, pkt) } // Capabilities implements stack.LinkEndpoint. diff --git a/pkg/tcpip/link/ethernet/ethernet_test.go b/pkg/tcpip/link/ethernet/ethernet_test.go new file mode 100644 index 000000000..08a7f1ce1 --- /dev/null +++ b/pkg/tcpip/link/ethernet/ethernet_test.go @@ -0,0 +1,71 @@ +// Copyright 2021 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package ethernet_test + +import ( + "testing" + + "gvisor.dev/gvisor/pkg/tcpip" + "gvisor.dev/gvisor/pkg/tcpip/buffer" + "gvisor.dev/gvisor/pkg/tcpip/header" + "gvisor.dev/gvisor/pkg/tcpip/link/channel" + "gvisor.dev/gvisor/pkg/tcpip/link/ethernet" + "gvisor.dev/gvisor/pkg/tcpip/stack" +) + +var _ stack.NetworkDispatcher = (*testNetworkDispatcher)(nil) + +type testNetworkDispatcher struct { + networkPackets int +} + +func (t *testNetworkDispatcher) DeliverNetworkPacket(_, _ tcpip.LinkAddress, _ tcpip.NetworkProtocolNumber, _ *stack.PacketBuffer) { + t.networkPackets++ +} + +func (*testNetworkDispatcher) DeliverOutboundPacket(_, _ tcpip.LinkAddress, _ tcpip.NetworkProtocolNumber, _ *stack.PacketBuffer) { +} + +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") + ) + + e := ethernet.New(channel.New(0, 0, linkAddr)) + var networkDispatcher testNetworkDispatcher + e.Attach(&networkDispatcher) + + if networkDispatcher.networkPackets != 0 { + t.Fatalf("got networkDispatcher.networkPackets = %d, want = 0", networkDispatcher.networkPackets) + } + + // 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 := buffer.NewView(header.EthernetMinimumSize) + header.Ethernet(eth).Encode(&header.EthernetFields{ + SrcAddr: otherLinkAddr1, + DstAddr: otherLinkAddr2, + Type: header.IPv4ProtocolNumber, + }) + e.DeliverNetworkPacket("", "", 0, stack.NewPacketBuffer(stack.PacketBufferOptions{ + Data: eth.ToVectorisedView(), + })) + if networkDispatcher.networkPackets != 1 { + t.Fatalf("got networkDispatcher.networkPackets = %d, want = 1", networkDispatcher.networkPackets) + } +} diff --git a/pkg/tcpip/tests/integration/BUILD b/pkg/tcpip/tests/integration/BUILD index 800025fb9..bb3b2ed0d 100644 --- a/pkg/tcpip/tests/integration/BUILD +++ b/pkg/tcpip/tests/integration/BUILD @@ -19,6 +19,7 @@ go_test( "//pkg/tcpip/link/channel", "//pkg/tcpip/link/ethernet", "//pkg/tcpip/link/loopback", + "//pkg/tcpip/link/nested", "//pkg/tcpip/link/pipe", "//pkg/tcpip/network/arp", "//pkg/tcpip/network/ipv4", diff --git a/pkg/tcpip/tests/integration/forward_test.go b/pkg/tcpip/tests/integration/forward_test.go index 39343b966..907565ac4 100644 --- a/pkg/tcpip/tests/integration/forward_test.go +++ b/pkg/tcpip/tests/integration/forward_test.go @@ -21,7 +21,9 @@ import ( "github.com/google/go-cmp/cmp" "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/buffer" + "gvisor.dev/gvisor/pkg/tcpip/header" "gvisor.dev/gvisor/pkg/tcpip/link/ethernet" + "gvisor.dev/gvisor/pkg/tcpip/link/nested" "gvisor.dev/gvisor/pkg/tcpip/link/pipe" "gvisor.dev/gvisor/pkg/tcpip/network/arp" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" @@ -31,6 +33,33 @@ import ( "gvisor.dev/gvisor/pkg/waiter" ) +var _ stack.NetworkDispatcher = (*endpointWithDestinationCheck)(nil) +var _ stack.LinkEndpoint = (*endpointWithDestinationCheck)(nil) + +// newEthernetEndpoint returns an ethernet link endpoint that wraps an inner +// link endpoint and checks the destination link address before delivering +// network packets to the network dispatcher. +// +// See ethernet.Endpoint for more details. +func newEthernetEndpoint(ep stack.LinkEndpoint) *endpointWithDestinationCheck { + var e endpointWithDestinationCheck + e.Endpoint.Init(ethernet.New(ep), &e) + return &e +} + +// endpointWithDestinationCheck is a link endpoint that checks the destination +// link address before delivering network packets to the network dispatcher. +type endpointWithDestinationCheck struct { + nested.Endpoint +} + +// DeliverNetworkPacket implements stack.NetworkDispatcher. +func (e *endpointWithDestinationCheck) DeliverNetworkPacket(src, dst tcpip.LinkAddress, proto tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { + if dst == e.Endpoint.LinkAddress() || dst == header.EthernetBroadcastAddress || header.IsMulticastEthernetAddress(dst) { + e.Endpoint.DeliverNetworkPacket(src, dst, proto, pkt) + } +} + func TestForwarding(t *testing.T) { const ( host1NICID = 1 @@ -209,16 +238,16 @@ func TestForwarding(t *testing.T) { host1NIC, routerNIC1 := pipe.New(linkAddr1, linkAddr2) routerNIC2, host2NIC := pipe.New(linkAddr3, linkAddr4) - if err := host1Stack.CreateNIC(host1NICID, ethernet.New(host1NIC)); err != nil { + if err := host1Stack.CreateNIC(host1NICID, newEthernetEndpoint(host1NIC)); err != nil { t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err) } - if err := routerStack.CreateNIC(routerNICID1, ethernet.New(routerNIC1)); err != nil { + if err := routerStack.CreateNIC(routerNICID1, newEthernetEndpoint(routerNIC1)); err != nil { t.Fatalf("routerStack.CreateNIC(%d, _): %s", routerNICID1, err) } - if err := routerStack.CreateNIC(routerNICID2, ethernet.New(routerNIC2)); err != nil { + if err := routerStack.CreateNIC(routerNICID2, newEthernetEndpoint(routerNIC2)); err != nil { t.Fatalf("routerStack.CreateNIC(%d, _): %s", routerNICID2, err) } - if err := host2Stack.CreateNIC(host2NICID, ethernet.New(host2NIC)); err != nil { + if err := host2Stack.CreateNIC(host2NICID, newEthernetEndpoint(host2NIC)); err != nil { t.Fatalf("host2Stack.CreateNIC(%d, _): %s", host2NICID, err) } diff --git a/pkg/tcpip/tests/integration/link_resolution_test.go b/pkg/tcpip/tests/integration/link_resolution_test.go index bf8a1241f..b41b72381 100644 --- a/pkg/tcpip/tests/integration/link_resolution_test.go +++ b/pkg/tcpip/tests/integration/link_resolution_test.go @@ -22,7 +22,6 @@ import ( "gvisor.dev/gvisor/pkg/tcpip" "gvisor.dev/gvisor/pkg/tcpip/buffer" "gvisor.dev/gvisor/pkg/tcpip/header" - "gvisor.dev/gvisor/pkg/tcpip/link/ethernet" "gvisor.dev/gvisor/pkg/tcpip/link/pipe" "gvisor.dev/gvisor/pkg/tcpip/network/arp" "gvisor.dev/gvisor/pkg/tcpip/network/ipv4" @@ -133,10 +132,10 @@ func TestPing(t *testing.T) { host1NIC, host2NIC := pipe.New(linkAddr1, linkAddr2) - if err := host1Stack.CreateNIC(host1NICID, ethernet.New(host1NIC)); err != nil { + if err := host1Stack.CreateNIC(host1NICID, newEthernetEndpoint(host1NIC)); err != nil { t.Fatalf("host1Stack.CreateNIC(%d, _): %s", host1NICID, err) } - if err := host2Stack.CreateNIC(host2NICID, ethernet.New(host2NIC)); err != nil { + if err := host2Stack.CreateNIC(host2NICID, newEthernetEndpoint(host2NIC)); err != nil { t.Fatalf("host2Stack.CreateNIC(%d, _): %s", host2NICID, err) } |