Files
RTLPlayground/doc/l2.md
T
DrDoof 14b2ce1c49 trap: deliver reserved multicast to the CPU by trap, STP first
A reserved-multicast trap goes to the port named in EXT_CPU_CTRL, which
names no port out of reset, so trapped frames were dropped at ingress.
trap_init() points it at the CPU port once at startup, and
trap_rma_set() changes only the action field of an RMA register.

A trapped frame arrives without the VLAN tag a forwarded one gets, so
TRAP_RX_BODY() gives the offset of the payload for both forms.

STP now traps its address while it runs instead of steering it with a
static L2 entry per VLAN, so turning it on no longer walks the VLAN
table and a pvid change no longer needs stp off and on. With STP off
the flooding entries are restored as before.

A trapped BPDU passes the tagged-only ingress filter that drops a
forwarded one, so the stp_setup() warning about such ports goes.
2026-10-12 01:16:28 +02:00

4.3 KiB

L2

The RTL827x provides access and configuration options to an L2 table that is used to associate device-MACs with ports on which those devices can be reached in the LAN. The code so far configures automatic learning and uses a default for aging of the learned addresses.

L2 Tables

Access to the tables is done using table access registers. The same access registers also provide access to the VLAN configuration tables. An idea of how the table works can be gained from the RTL8369 Datasheet section 8.17 and in particular table 20.

The central table register is RTL837X_TBL_CTRL(0x5cac).

Register RTL837X_TBL_CTRL bytes: EE EE TT CC
EE: Entry
TT: Table type
CC: Command (Bit 0: Execute, Bit 1: Write)
TT: 04: TBL_L2_UNICAST, 03: TBL_VLAN

An entry is retrieved from the tables by setting the data in registers to the desired entry filter, then executing a table command by writing to RTL837X_TBL_CTRL with execute bit 0 set, table type set and entry identifier (VLAN-Id or hash for L2). Data will be fetched from the table and is available once the execute bit has been cleared by the ASIC. Data then is in the output data registers

#define RTL837x_L2_DATA_OUT_A	0x5ccc
#define RTL837x_L2_DATA_OUT_B	0x5cd0
#define RTL837x_L2_DATA_OUT_C	0x5cd4

DATA_OUT_A   DATA_OUT_B   L2_DATA_OUT_C
M2 M3 M4 M5  fV VV M0 M1  xx xF xx gg

M0-M5: 6 bytes of MAC, M0 is MSB
V: 12 bits of VLAN-ID
f: bit 5 set: Entry is valid, otherwise stale
   bit 6: bit 0 of port-number
   bit 7: bit 1 of port-number
g: bit 0: bit 2 of port-number
   bit 1: bit 3 of port-number (MSB)
   bit 2: bit 0 of entry-age
   bit 3: bit 1 of entry-age
   bit 4: bit 2 of entry-age (MSB)
F: bit 0: entry is static(1) or learned (0)

The next entry can be now found in RTL837x_TBL_DATA_0 (entry = RTL837x_TBL_DATA_0_bits(0-11) + 1), which can be used to get the next entry by writing this value to RTL837X_TBL_CTRL and executing again for the given table type. This entry number is probably a hash, for which the algorithm is unknown.

Deleting the entire L2 table is done by checking and setting 0x53dc to 0x0, then writing 0x00010000 to register RTL837x_L2_TBL_CTRL and waiting until the bit 16 that was set has cleared.

API support in the code

The RTLPlayground code provides support for reading the L2 tables from the ASIC and flushing the table in order to quickly forget the learned entries.

> l2
        MAC       VLAN    type    port
3c:18:a0:7e:11:00 0x0001  learned 5
1c:2a:a3:23:00:02 0x0001  learned 7

Static multicast entries

Slow-protocol frames such as LACPDUs and STP BPDUs have to reach the CPU without being flooded to the other ports. No bridge relays these frames: their addresses are in the set that 802.1D-2004 clause 7.12.6 forbids a bridge to forward, and what travels the network is the information, with every bridge regenerating BPDUs of its own on its designated ports. The reserved-multicast trap action does that: it delivers to the port named in EXT_CPU_CTRL (0x6724), which trap_init() sets to 9, the CPU port, at startup; with the reset value 0xf it names no port and the trapped frame is dropped. STP traps its address while it runs (see stp.md). Where the action is left at forward, the egress can be constrained with a static L2 multicast entry instead: the lookup hits the entry's own port mask rather than the VLAN flood mask. Verified on a SWTGW218AS both ways, with the CPU bit cleared, where delivery stops, and with the CPU bit alone, where nothing egresses.

port_l2mc_set() writes one such entry. The SMI layout is the L2 multicast variant of the table entry:

DATA_IN_A = MAC bytes 5..2                            -> c2 00 00 <mac_last>
DATA_IN_B = MAC[1..0] | vid<<16 | IVL<<29 | pmask[1:0]<<30
DATA_IN_C = pmask[9:2]

Lookups are IVL, so an entry made for VID 0 is never matched and a caller adds one entry per PVID in use. The write goes through the table access register with the table selector set to the L2 lookup table, TBL_L2_UNICAST in the code, a name that despite appearances covers the multicast entries as well. The hardware hashes MAC and VID to pick the bucket slot by itself. Writing the same MAC and VID again replaces the entry rather than adding a second one, so a caller can retarget the mask at will, for instance back to all ports to restore flooding.