diff options
author | Bert Muthalaly <stijlist@google.com> | 2018-09-19 13:42:55 -0700 |
---|---|---|
committer | Shentubot <shentubot@google.com> | 2018-09-19 13:43:58 -0700 |
commit | 2e497de2d9f6c410a214faae9962e762757b0648 (patch) | |
tree | 992c064bd360dc50f8369d76d1481e5eb58ec612 /pkg/tcpip/link/fdbased | |
parent | f0a92b6b67382a1f8da5ef2622c59afdb1c40f13 (diff) |
Pass local link address to DeliverNetworkPacket
This allows a NetworkDispatcher to implement transparent bridging,
assuming all implementations of LinkEndpoint.WritePacket call eth.Encode
with header.EthernetFields.SrcAddr set to the passed
Route.LocalLinkAddress, if it is provided.
PiperOrigin-RevId: 213686651
Change-Id: I446a4ac070970202f0724ef796ff1056ae4dd72a
Diffstat (limited to 'pkg/tcpip/link/fdbased')
-rw-r--r-- | pkg/tcpip/link/fdbased/endpoint.go | 28 | ||||
-rw-r--r-- | pkg/tcpip/link/fdbased/endpoint_test.go | 59 |
2 files changed, 60 insertions, 27 deletions
diff --git a/pkg/tcpip/link/fdbased/endpoint.go b/pkg/tcpip/link/fdbased/endpoint.go index 40a10eb9b..ee99ada07 100644 --- a/pkg/tcpip/link/fdbased/endpoint.go +++ b/pkg/tcpip/link/fdbased/endpoint.go @@ -164,17 +164,24 @@ func (e *endpoint) WritePacket(r *stack.Route, hdr buffer.Prependable, payload b views[0] = hdr.View() views = append(views, payload.Views()...) vv := buffer.NewVectorisedView(len(views[0])+payload.Size(), views) - e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, protocol, vv) + e.dispatcher.DeliverNetworkPacket(e, r.RemoteLinkAddress, r.LocalLinkAddress, protocol, vv) return nil } if e.hdrSize > 0 { // Add ethernet header if needed. eth := header.Ethernet(hdr.Prepend(header.EthernetMinimumSize)) - eth.Encode(&header.EthernetFields{ + ethHdr := &header.EthernetFields{ DstAddr: r.RemoteLinkAddress, - SrcAddr: e.addr, Type: protocol, - }) + } + + // Preserve the src address if it's set in the route. + if r.LocalLinkAddress != "" { + ethHdr.SrcAddr = r.LocalLinkAddress + } else { + ethHdr.SrcAddr = e.addr + } + eth.Encode(ethHdr) } if payload.Size() == 0 { @@ -223,12 +230,15 @@ func (e *endpoint) dispatch(largeV buffer.View) (bool, *tcpip.Error) { return false, nil } - var p tcpip.NetworkProtocolNumber - var addr tcpip.LinkAddress + var ( + p tcpip.NetworkProtocolNumber + remoteLinkAddr, localLinkAddr tcpip.LinkAddress + ) if e.hdrSize > 0 { eth := header.Ethernet(e.views[0]) p = eth.Type() - addr = eth.SourceAddress() + remoteLinkAddr = eth.SourceAddress() + localLinkAddr = eth.DestinationAddress() } else { // We don't get any indication of what the packet is, so try to guess // if it's an IPv4 or IPv6 packet. @@ -246,7 +256,7 @@ func (e *endpoint) dispatch(largeV buffer.View) (bool, *tcpip.Error) { vv := buffer.NewVectorisedView(n, e.views[:used]) vv.TrimFront(e.hdrSize) - e.dispatcher.DeliverNetworkPacket(e, addr, p, vv) + e.dispatcher.DeliverNetworkPacket(e, remoteLinkAddr, localLinkAddr, p, vv) // Prepare e.views for another packet: release used views. for i := 0; i < used; i++ { @@ -287,7 +297,7 @@ func (e *InjectableEndpoint) Attach(dispatcher stack.NetworkDispatcher) { // Inject injects an inbound packet. func (e *InjectableEndpoint) Inject(protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) { - e.dispatcher.DeliverNetworkPacket(e, "", protocol, vv) + e.dispatcher.DeliverNetworkPacket(e, "" /* remoteLinkAddr */, "" /* localLinkAddr */, protocol, vv) } // NewInjectable creates a new fd-based InjectableEndpoint. diff --git a/pkg/tcpip/link/fdbased/endpoint_test.go b/pkg/tcpip/link/fdbased/endpoint_test.go index 411ad7832..52e532ebb 100644 --- a/pkg/tcpip/link/fdbased/endpoint_test.go +++ b/pkg/tcpip/link/fdbased/endpoint_test.go @@ -31,6 +31,13 @@ import ( "gvisor.googlesource.com/gvisor/pkg/tcpip/stack" ) +const ( + mtu = 1500 + laddr = tcpip.LinkAddress("\x11\x22\x33\x44\x55\x66") + raddr = tcpip.LinkAddress("\x77\x88\x99\xaa\xbb\xcc") + proto = 10 +) + type packetInfo struct { raddr tcpip.LinkAddress proto tcpip.NetworkProtocolNumber @@ -78,12 +85,11 @@ func (c *context) cleanup() { syscall.Close(c.fds[1]) } -func (c *context) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) { +func (c *context) DeliverNetworkPacket(linkEP stack.LinkEndpoint, remoteLinkAddr tcpip.LinkAddress, localLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, vv buffer.VectorisedView) { c.ch <- packetInfo{remoteLinkAddr, protocol, vv.ToView()} } func TestNoEthernetProperties(t *testing.T) { - const mtu = 1500 c := newContext(t, &Options{MTU: mtu}) defer c.cleanup() @@ -97,7 +103,6 @@ func TestNoEthernetProperties(t *testing.T) { } func TestEthernetProperties(t *testing.T) { - const mtu = 1500 c := newContext(t, &Options{EthernetHeader: true, MTU: mtu}) defer c.cleanup() @@ -111,7 +116,6 @@ func TestEthernetProperties(t *testing.T) { } func TestAddress(t *testing.T) { - const mtu = 1500 addrs := []tcpip.LinkAddress{"", "abc", "def"} for _, a := range addrs { t.Run(fmt.Sprintf("Address: %q", a), func(t *testing.T) { @@ -126,13 +130,6 @@ func TestAddress(t *testing.T) { } func TestWritePacket(t *testing.T) { - const ( - mtu = 1500 - laddr = tcpip.LinkAddress("\x11\x22\x33\x44\x55\x66") - raddr = tcpip.LinkAddress("\x77\x88\x99\xaa\xbb\xcc") - proto = 10 - ) - lengths := []int{0, 100, 1000} eths := []bool{true, false} @@ -197,14 +194,40 @@ func TestWritePacket(t *testing.T) { } } -func TestDeliverPacket(t *testing.T) { - const ( - mtu = 1500 - laddr = tcpip.LinkAddress("\x11\x22\x33\x44\x55\x66") - raddr = tcpip.LinkAddress("\x77\x88\x99\xaa\xbb\xcc") - proto = 10 - ) +func TestPreserveSrcAddress(t *testing.T) { + baddr := tcpip.LinkAddress("\xcc\xbb\xaa\x77\x88\x99") + c := newContext(t, &Options{Address: laddr, MTU: mtu, EthernetHeader: true}) + defer c.cleanup() + + // Set LocalLinkAddress in route to the value of the bridged address. + r := &stack.Route{ + RemoteLinkAddress: raddr, + LocalLinkAddress: baddr, + } + + // WritePacket panics given a prependable with anything less than + // the minimum size of the ethernet header. + hdr := buffer.NewPrependable(header.EthernetMinimumSize) + if err := c.ep.WritePacket(r, hdr, buffer.VectorisedView{}, proto); err != nil { + t.Fatalf("WritePacket failed: %v", err) + } + + // Read from the FD, then compare with what we wrote. + b := make([]byte, mtu) + n, err := syscall.Read(c.fds[0], b) + if err != nil { + t.Fatalf("Read failed: %v", err) + } + b = b[:n] + h := header.Ethernet(b) + + if a := h.SourceAddress(); a != baddr { + t.Fatalf("SourceAddress() = %v, want %v", a, baddr) + } +} + +func TestDeliverPacket(t *testing.T) { lengths := []int{100, 1000} eths := []bool{true, false} |