1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
#
# 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)
|