mirror of
https://github.com/saymrwulf/uhd.git
synced 2026-05-16 21:10:10 +00:00
In bridge mode, packets may be arriving at the Ethernet device which aren't meant for this device, and thus need different routing instructions.
187 lines
6.8 KiB
Python
187 lines
6.8 KiB
Python
#
|
|
# Copyright 2017-2018 Ettus Research, a National Instruments Company
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
#
|
|
"""
|
|
Ethernet dispatcher table control
|
|
"""
|
|
|
|
from builtins import str
|
|
from builtins import object
|
|
import netaddr
|
|
from usrp_mpm.mpmlog import get_logger
|
|
from usrp_mpm.sys_utils.uio import UIO
|
|
from usrp_mpm.sys_utils.net import get_mac_addr
|
|
|
|
|
|
class EthDispatcherTable(object):
|
|
"""
|
|
Controls an Ethernet dispatcher table.
|
|
"""
|
|
DEFAULT_VITA_PORT = (49153, 49154)
|
|
# Address offsets:
|
|
ETH_IP_OFFSET = 0x0000
|
|
ETH_PORT_OFFSET = 0x0004
|
|
FORWARD_ETH_BCAST_OFFSET = 0x0008
|
|
BRIDGE_MAC_LO_OFFSET = 0x0010
|
|
BRIDGE_MAC_HI_OFFSET = 0x0014
|
|
BRIDGE_IP_OFFSET = 0x0018
|
|
BRIDGE_PORT_OFFSET = 0x001c
|
|
BRIDGE_ENABLE_OFFSET = 0x0020
|
|
SID_IP_OFFSET = 0x1000
|
|
SID_PORT_MAC_HI_OFFSET = 0x1400
|
|
SID_MAC_LO_OFFSET = 0x1800
|
|
LADDR_IP_OFFSET = 0x1D00
|
|
LADDR_PORT_MAC_HI_OFFSET = 0x1E00
|
|
LADDR_MAC_LO_OFFSET = 0x1F00
|
|
|
|
|
|
def __init__(self, label):
|
|
self.log = get_logger(label)
|
|
self._regs = UIO(label=label, read_only=False)
|
|
self.poke32 = self._regs.poke32
|
|
self.peek32 = self._regs.peek32
|
|
|
|
def set_bridge_mode(self, bridge_mode):
|
|
" Enable/Disable Bridge Mode "
|
|
self.log.trace("Bridge Mode {}".format(
|
|
"Enabled" if bridge_mode else "Disabled"
|
|
))
|
|
self.poke32(self.BRIDGE_ENABLE_OFFSET, int(bridge_mode))
|
|
|
|
def set_bridge_mac_addr(self, mac_addr):
|
|
"""
|
|
Set the bridge MAC address for this Ethernet dispatcher.
|
|
Outgoing packets will have this MAC address.
|
|
"""
|
|
self.log.debug("Setting bridge MAC address to `{}'".format(mac_addr))
|
|
mac_addr_int = int(netaddr.EUI(mac_addr))
|
|
self.log.trace("Writing to address 0x{:04X}: 0x{:04X}".format(
|
|
self.BRIDGE_MAC_LO_OFFSET, mac_addr_int & 0xFFFFFFFF
|
|
))
|
|
self.poke32(self.BRIDGE_MAC_LO_OFFSET, mac_addr_int & 0xFFFFFFFF)
|
|
self.log.trace("Writing to address 0x{:04X}: 0x{:04X}".format(
|
|
self.BRIDGE_MAC_HI_OFFSET, mac_addr_int >> 32
|
|
))
|
|
self.poke32(self.BRIDGE_MAC_HI_OFFSET, mac_addr_int >> 32)
|
|
|
|
def set_ipv4_addr(self, ip_addr, bridge_en=False):
|
|
"""
|
|
Set the own IPv4 address for this Ethernet dispatcher.
|
|
Outgoing packets will have this IP address.
|
|
"""
|
|
if bridge_en:
|
|
own_ip_offset = self.BRIDGE_IP_OFFSET
|
|
else:
|
|
own_ip_offset = self.ETH_IP_OFFSET
|
|
self.log.debug("Setting my own IP address to `{}'".format(ip_addr))
|
|
ip_addr_int = int(netaddr.IPAddress(ip_addr))
|
|
with self._regs:
|
|
self.poke32(own_ip_offset, ip_addr_int)
|
|
|
|
def set_vita_port(self, port_value=None, port_idx=None, bridge_en=False):
|
|
"""
|
|
Set the port that is used for incoming VITA traffic. This is used to
|
|
distinguish traffic that goes to the FPGA from that going to the ARM.
|
|
"""
|
|
port_idx = port_idx or 0
|
|
port_value = port_value or self.DEFAULT_VITA_PORT[port_idx]
|
|
assert port_idx in (0) #FIXME: Fix port_idx = 1
|
|
if bridge_en:
|
|
port_reg_addr = self.BRIDGE_PORT_OFFSET
|
|
else:
|
|
port_reg_addr = self.ETH_PORT_OFFSET
|
|
with self._regs:
|
|
self.poke32(port_reg_addr, port_value)
|
|
|
|
def set_route(self, sid, ip_addr, udp_port, mac_addr=None):
|
|
"""
|
|
Sets up routing in the Ethernet dispatcher. From sid, only the
|
|
destination part is important. After this call, any CHDR packet
|
|
reaching this Ethernet dispatcher will get routed to `ip_addr' and
|
|
`udp_port'.
|
|
|
|
It automatically looks up the MAC address of the destination unless a
|
|
MAC address is given.
|
|
|
|
sid -- Full SID, but only destination part matters.
|
|
ip_addr -- IPv4 destination address. String format ("1.2.3.4").
|
|
udp_addr -- Destination UDP port.
|
|
mac_addr -- If given, this will replace an ARP lookup for the MAC
|
|
address. String format, ("aa:bb:cc:dd:ee:ff"), case does
|
|
not matter.
|
|
"""
|
|
udp_port = int(udp_port)
|
|
if mac_addr is None:
|
|
mac_addr = get_mac_addr(ip_addr)
|
|
if mac_addr is None:
|
|
self.log.error(
|
|
"Could not resolve a MAC address for IP address `{}'".format(ip_addr)
|
|
)
|
|
if sid.dst_addr == 0 or sid.dst_addr == 1:
|
|
table_addr = sid.dst_ep
|
|
ip_base_offset = self.SID_IP_OFFSET
|
|
port_mac_hi_base_offset = self.SID_PORT_MAC_HI_OFFSET
|
|
mac_lo_base_offset = self.SID_MAC_LO_OFFSET
|
|
self.log.debug(
|
|
"Routing SID `{sid}' (endpoint `{ep}') to IP address `{ip}', " \
|
|
"MAC address `{mac}', port `{port}'".format(
|
|
sid=str(sid),
|
|
ep=table_addr,
|
|
ip=ip_addr,
|
|
mac=mac_addr,
|
|
port=udp_port
|
|
)
|
|
)
|
|
else: #populate local addr eth dispatch table
|
|
table_addr = sid.dst_addr
|
|
ip_base_offset = self.LADDR_IP_OFFSET
|
|
port_mac_hi_base_offset = self.LADDR_PORT_MAC_HI_OFFSET
|
|
mac_lo_base_offset = self.LADDR_MAC_LO_OFFSET
|
|
self.log.debug(
|
|
"Routing SID `{sid}' (local addr`{addr}') to IP address `{ip}', " \
|
|
"MAC address `{mac}', port `{port}'".format(
|
|
sid=str(sid),
|
|
addr=table_addr,
|
|
ip=ip_addr,
|
|
mac=mac_addr,
|
|
port=udp_port
|
|
)
|
|
)
|
|
ip_addr_int = int(netaddr.IPAddress(ip_addr))
|
|
mac_addr_int = int(netaddr.EUI(mac_addr))
|
|
dst_offset = 4 * table_addr
|
|
|
|
def poke_and_trace(addr, data):
|
|
" Do a poke32() and log.trace() "
|
|
self.log.trace("Writing to address 0x{:04X}: 0x{:04X}".format(
|
|
addr, data
|
|
))
|
|
self.poke32(addr, data)
|
|
|
|
with self._regs:
|
|
poke_and_trace(
|
|
ip_base_offset + dst_offset,
|
|
ip_addr_int
|
|
)
|
|
poke_and_trace(
|
|
mac_lo_base_offset + dst_offset,
|
|
mac_addr_int & 0xFFFFFFFF,
|
|
)
|
|
poke_and_trace(
|
|
port_mac_hi_base_offset + dst_offset,
|
|
(udp_port << 16) | (mac_addr_int >> 32)
|
|
)
|
|
|
|
def set_forward_policy(self, forward_eth, forward_bcast):
|
|
"""
|
|
Forward Ethernet packet not matching OWN_IP to CROSSOVER
|
|
Forward broadcast packet to CPU and CROSSOVER
|
|
"""
|
|
reg_value = int(bool(forward_eth) << 1) | int(bool(forward_bcast))
|
|
self.log.trace("Writing to address 0x{:04X}: 0x{:04X}".format(
|
|
self.FORWARD_ETH_BCAST_OFFSET, reg_value
|
|
))
|
|
with self._regs:
|
|
self.poke32(self.FORWARD_ETH_BCAST_OFFSET, reg_value)
|