uhd/mpm/python/usrp_mpm/ethtable.py
Sugandha Gupta 169e3c4bef mpm: ethtable: Add support for bridge mode to Ethernet dispatcher
In bridge mode, packets may be arriving at the Ethernet device which
aren't meant for this device, and thus need different routing
instructions.
2019-01-17 15:38:23 -08:00

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)