blob: fe5c503a8a6e71c602839ae8118db2f0418bb968 [file] [log] [blame]
// 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
}
}