| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // +build !build_with_native_toolchain |
| |
| // link/bridge implements a bridging LinkEndpoint |
| // It can be writable. |
| package bridge |
| |
| import ( |
| "hash/fnv" |
| "math" |
| "sort" |
| "strings" |
| |
| "fidl/fuchsia/hardware/network" |
| |
| "go.fuchsia.dev/fuchsia/src/connectivity/network/netstack/link" |
| |
| "gvisor.dev/gvisor/pkg/tcpip" |
| "gvisor.dev/gvisor/pkg/tcpip/header" |
| "gvisor.dev/gvisor/pkg/tcpip/stack" |
| ) |
| |
| var _ stack.LinkEndpoint = (*Endpoint)(nil) |
| var _ link.Controller = (*Endpoint)(nil) |
| |
| type Endpoint struct { |
| links map[tcpip.LinkAddress]*BridgeableEndpoint |
| dispatcher stack.NetworkDispatcher |
| mtu uint32 |
| capabilities stack.LinkEndpointCapabilities |
| maxHeaderLength uint16 |
| linkAddress tcpip.LinkAddress |
| } |
| |
| // New creates a new link from a list of BridgeableEndpoints that bridges |
| // packets written to it and received from any of its constituent links. |
| // |
| // The new link will have the minumum of the MTUs, the maximum of the max |
| // header lengths, and minimum set of the capabilities. This function takes |
| // ownership of `links`. |
| func New(links []*BridgeableEndpoint) *Endpoint { |
| // TODO(fxbug.dev/57022): Make sure links are all using the same kind of link. |
| sort.Slice(links, func(i, j int) bool { |
| return strings.Compare(string(links[i].LinkAddress()), string(links[j].LinkAddress())) > 0 |
| }) |
| ep := &Endpoint{ |
| links: make(map[tcpip.LinkAddress]*BridgeableEndpoint), |
| mtu: math.MaxUint32, |
| } |
| h := fnv.New64() |
| for _, l := range links { |
| linkAddress := l.LinkAddress() |
| ep.links[linkAddress] = l |
| |
| // mtu is the maximum write size, which is the minimum of any link's mtu. |
| if mtu := l.MTU(); mtu < ep.mtu { |
| ep.mtu = mtu |
| } |
| |
| // Resolution is required if any link requires it. |
| ep.capabilities |= l.Capabilities() & stack.CapabilityResolutionRequired |
| |
| // maxHeaderLength is the space to reserve for possible addition |
| // headers. We want to reserve enough to suffice for all links. |
| if maxHeaderLength := l.MaxHeaderLength(); maxHeaderLength > ep.maxHeaderLength { |
| ep.maxHeaderLength = maxHeaderLength |
| } |
| |
| if _, err := h.Write([]byte(linkAddress)); err != nil { |
| panic(err) |
| } |
| } |
| b := h.Sum(nil)[:6] |
| // The second bit of the first byte indicates "locally administered". |
| b[0] |= 1 << 1 |
| ep.linkAddress = tcpip.LinkAddress(b) |
| return ep |
| } |
| |
| // Up calls SetBridge(bridge) on all the constituent links of a bridge. |
| // |
| // This causes each constituent link to delegate dispatch to the bridge, |
| // meaning that received packets will be written out of or dispatched back up |
| // the stack for another constituent link. |
| func (ep *Endpoint) Up() error { |
| for _, l := range ep.links { |
| l.SetBridge(ep) |
| } |
| return nil |
| } |
| |
| // Down calls SetBridge(nil) on all the constituent links of a bridge. |
| // |
| // This causes each bridgeable endpoint to go back to its state before |
| // bridging, dispatching up the stack to the default NetworkDispatcher |
| // implementation directly. |
| func (ep *Endpoint) Down() error { |
| for _, l := range ep.links { |
| l.SetBridge(nil) |
| } |
| return nil |
| } |
| |
| // SetPromiscuousMode on a bridge is a no-op, since all of the constituent |
| // links on a bridge need to already be in promiscuous mode for bridging to |
| // work. |
| func (ep *Endpoint) SetPromiscuousMode(bool) error { |
| return nil |
| } |
| |
| func (*Endpoint) DeviceClass() network.DeviceClass { |
| return network.DeviceClassBridge |
| } |
| |
| func (ep *Endpoint) MTU() uint32 { |
| return ep.mtu |
| } |
| |
| func (ep *Endpoint) Capabilities() stack.LinkEndpointCapabilities { |
| return ep.capabilities |
| } |
| |
| func (ep *Endpoint) MaxHeaderLength() uint16 { |
| return ep.maxHeaderLength |
| } |
| |
| func (ep *Endpoint) LinkAddress() tcpip.LinkAddress { |
| return ep.linkAddress |
| } |
| |
| func (ep *Endpoint) WritePacket(r *stack.Route, gso *stack.GSO, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) *tcpip.Error { |
| for _, l := range ep.links { |
| // We need to clone the packet buffer because each bridged endpoint may try |
| // to set the packet buffer's link header, but the header may only be set |
| // once for the lifetime of a packet buffer. |
| if err := l.WritePacket(r, gso, protocol, pkt.Clone()); err != nil { |
| return err |
| } |
| } |
| return nil |
| } |
| |
| // WritePackets returns the number of packets in hdrs that were successfully |
| // written to all links. |
| func (ep *Endpoint) WritePackets(r *stack.Route, gso *stack.GSO, pkts stack.PacketBufferList, protocol tcpip.NetworkProtocolNumber) (int, *tcpip.Error) { |
| if len(ep.links) == 0 { |
| return 0, nil |
| } |
| |
| // Set the initial value to the maximum positive value for an unsized integer |
| // (all bits set to 1 excluding the most significant bit). |
| n := int(^uint(0) >> 1) |
| for _, l := range ep.links { |
| // We need to clone the packet buffers because each bridged endpoint may try |
| // to set the packet buffers' link header, but the header may only be set |
| // once for the lifetime of a packet buffer. |
| var pktsList stack.PacketBufferList |
| for pkt := pkts.Front(); pkt != nil; pkt = pkt.Next() { |
| pktsList.PushBack(pkt.Clone()) |
| } |
| i, err := l.WritePackets(r, gso, pktsList, protocol) |
| if err != nil { |
| return 0, err |
| } |
| |
| if i < n { |
| n = i |
| } |
| } |
| return n, nil |
| } |
| |
| func (ep *Endpoint) Attach(d stack.NetworkDispatcher) { |
| ep.dispatcher = d |
| if d == nil { |
| for _, l := range ep.links { |
| l.SetBridge(nil) |
| } |
| } |
| } |
| |
| func (ep *Endpoint) IsAttached() bool { |
| return ep.dispatcher != nil |
| } |
| |
| // DeliverNetworkPacketToBridge delivers a network packet to the bridged network. |
| // |
| // Endpoint does not implement stack.NetworkEndpoint.DeliverNetworkPacket because we need |
| // to know which BridgeableEndpoint the packet was delivered from to prevent packet loops. |
| func (ep *Endpoint) DeliverNetworkPacketToBridge(rxEP *BridgeableEndpoint, srcLinkAddr, dstLinkAddr tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { |
| // Is the destination link address a multicast/broadcast? |
| // |
| // If the least significant bit of the first octet is 1, then the address is a |
| // multicast address. |
| // |
| // See the IEEE Std 802-2001 document for more details. Specifically, |
| // section 9.2.1 of http://ieee802.org/secmail/pdfocSP2xXA6d.pdf: |
| // "A 48-bit universal address consists of two parts. The first 24 bits |
| // correspond to the OUI as assigned by the IEEE, except that the |
| // assignee may set the LSB of the first octet to 1 for group addresses |
| // or set it to 0 for individual addresses." |
| flood := len(dstLinkAddr) == header.EthernetAddressSize && dstLinkAddr[0]&1 == 1 |
| |
| if !flood { |
| switch dstLinkAddr { |
| case ep.linkAddress: |
| ep.dispatcher.DeliverNetworkPacket(srcLinkAddr, dstLinkAddr, protocol, pkt) |
| return |
| } |
| } |
| |
| // The bridge `ep` isn't included in ep.links below and we don't want to write |
| // out of rxEP, otherwise the rest of this function would just be |
| // "ep.WritePacket and if flood, also deliver to ep.links." |
| if flood { |
| // We need to clone the packet buffer because the stack may attempt to set the |
| // network or transport headers which may only be done once for the lifetime |
| // of a packet buffer. |
| ep.dispatcher.DeliverNetworkPacket(srcLinkAddr, dstLinkAddr, protocol, pkt.Clone()) |
| } |
| |
| // NB: This isn't really a valid Route; Route is a public type but cannot |
| // be instantiated fully outside of the stack package, because its |
| // underlying referencedNetworkEndpoint cannot be accessed. |
| // This means that methods on Route that depend on accessing the |
| // underlying LinkEndpoint like MTU() will panic, but it would be |
| // extremely strange for the LinkEndpoint we're calling WritePacket on to |
| // access itself so indirectly. |
| var r stack.Route |
| r.LocalLinkAddress = srcLinkAddr |
| r.NetProto = protocol |
| r.ResolveWith(dstLinkAddr) |
| |
| // TODO(fxbug.dev/20778): Learn which destinations are on which links and restrict transmission, like a bridge. |
| for _, l := range ep.links { |
| // Don't write back out interface from which the frame arrived |
| // because that causes interoperability issues with a router. |
| if l != rxEP { |
| // We need to clone the packet buffers because each bridged endpoint may try |
| // to set the packet buffers' link header, but the header may only be set |
| // once for the lifetime of a packet buffer. |
| l.WritePacket(&r, nil, protocol, pkt.Clone()) |
| } |
| } |
| } |
| |
| // Wait implements stack.LinkEndpoint. |
| func (ep *Endpoint) Wait() { |
| for _, e := range ep.links { |
| e.Wait() |
| } |
| } |
| |
| // ARPHardwareType implements stack.LinkEndpoint. |
| func (e *Endpoint) ARPHardwareType() header.ARPHardwareType { |
| // Use the first bridged endpoint. |
| for _, link := range e.links { |
| return link.ARPHardwareType() |
| } |
| |
| return header.ARPHardwareNone |
| } |
| |
| // AddHeader implements stack.LinkEndpoint. |
| func (e *Endpoint) AddHeader(local, remote tcpip.LinkAddress, protocol tcpip.NetworkProtocolNumber, pkt *stack.PacketBuffer) { |
| // Use the first bridged endpoint. |
| for _, link := range e.links { |
| if len(local) == 0 { |
| local = e.LinkAddress() |
| } |
| link.AddHeader(local, remote, protocol, pkt) |
| return |
| } |
| } |