mirror of
https://github.com/logicog/RTLPlayground.git
synced 2026-10-29 17:54:14 +08:00
port: pin the management MAC to the CPU port with a static L2 entry
The CPU's own MAC exists in the L2 table only as a learned entry, created whenever the CPU transmits, and it ages out like any other dynamic entry. Unknown unicast is not flooded to the CPU port, so on an idle switch (no web session, no management traffic) the entry expires after the aging time and frames for the management IP no longer reach the CPU: pings die until the next CPU transmission (an ARP reply) re-teaches the entry, then die again. Real management sessions keep the entry alive continuously, which is why this is only visible on idle switches. Install a static entry for the management MAC on the CPU port after the startup config has been replayed, so it lands in the final management VLAN, and move it when the management VLAN is changed at runtime. Entry mechanics, established on hardware: a table write with read-method 0 hashes the key in TBL_DATA_IN and places the entry itself (a search returns index 0 on a miss, there is no software-visible insertion slot). The age field in the third data word must be non-zero for the entry to be visible to lookup at all, and the static flag (bit 0 of byte 1 of that word) stops the aging engine from decrementing it: with the flag a full-age entry survives untouched where an identical unflagged entry ages to invisible within the aging period. With no management VLAN configured the entry lives in VLAN 1.
This commit is contained in:
1 parent
4c8e0ce975
commit
3b8dba6e87
4 files changed
+60
No files matched your search
@@ -911,3 +911,57 @@ bool port_ingress_vlan_filter_get(uint8_t port) __banked
|
||||
|
||||
return reg_bit_test(RTL837X_VLAN_PORT_IGR_FLTR, port);
|
||||
}
|
||||
|
||||
// C1 bit 0: static (no aging); age at C3[4:2] must be non-zero or the
|
||||
// entry is invisible to lookup
|
||||
static void l2_mgmt_entry_fill(__xdata uint8_t *mac, __xdata uint16_t vlan)
|
||||
{
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_A, mac[2], mac[3], mac[4], mac[5]);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_B, 0x20 | ((CPU_PORT & 0x3) << 6) | (vlan >> 8),
|
||||
vlan & 0xff, mac[0], mac[1]);
|
||||
REG_WRITE(RTL837x_TBL_DATA_IN_C, 0x00, 0x01, 0x00, (7 << 2) | (CPU_PORT >> 2));
|
||||
}
|
||||
|
||||
static void l2_mgmt_tbl_prepare(void)
|
||||
{
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
sfr_data[2] &= 0x3f;
|
||||
sfr_data[1] &= 0xf8;
|
||||
reg_write_m(RTL837x_TBL_DATA_0);
|
||||
}
|
||||
|
||||
static void wait_table_ready(void)
|
||||
{
|
||||
do {
|
||||
reg_read(RTL837X_TBL_CTRL);
|
||||
} while (SFR_DATA_0 & TBL_EXECUTE);
|
||||
}
|
||||
|
||||
/** Pin the management MAC to the CPU port; remove_entry deletes it */
|
||||
void port_l2_static_mgmt(__xdata uint8_t *mac, __xdata uint16_t vlan, __xdata bool remove_entry) __banked
|
||||
{
|
||||
wait_table_ready();
|
||||
|
||||
// vlan 0 = management VLAN disabled: untagged management resolves in
|
||||
// VLAN 1; clients in other VLANs keep their learned entry and age as before
|
||||
if (!vlan)
|
||||
vlan = 1;
|
||||
l2_mgmt_entry_fill(mac, vlan);
|
||||
l2_mgmt_tbl_prepare();
|
||||
if (remove_entry) {
|
||||
// a search miss returns index 0, not a slot
|
||||
REG_WRITE(RTL837X_TBL_CTRL, 0x00, 0x00, TBL_L2_UNICAST, TBL_EXECUTE);
|
||||
wait_table_ready();
|
||||
reg_read_m(RTL837x_TBL_DATA_0);
|
||||
if (!(sfr_data[2] & 0x10))
|
||||
return;
|
||||
sfr_data[1] |= 0x04; // CLEAR-entry
|
||||
reg_write_m(RTL837x_TBL_DATA_0);
|
||||
__xdata uint16_t idx = (((uint16_t)sfr_data[2] & 0x0f) << 8) | sfr_data[3];
|
||||
REG_WRITE(RTL837X_TBL_CTRL, idx >> 8, idx & 0xff, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE);
|
||||
} else {
|
||||
// method-0 write: the hardware hashes the key and places the entry
|
||||
REG_WRITE(RTL837X_TBL_CTRL, 0x00, 0x00, TBL_L2_UNICAST, TBL_WRITE | TBL_EXECUTE);
|
||||
}
|
||||
wait_table_ready();
|
||||
}
|
||||
Reference in new issue
Block a user