realtek: l3: rtl839x: keep one ROUTING row per gateway MAC

On RTL839x a gateway's L2 entry names the ROUTING row that holds the
gateway's MAC, and that row was the id of the route that claimed the
entry. The other routes through that gateway go on using the row after
the route is gone, and its id can go to a later route, which writes
its own gateway's MAC into it. Those routes then forward to the wrong
gateway.

Give RTL839x the DMAC entries RTL930x has: one ROUTING row per gateway
MAC, held by every route through it (otto_l3_dmac_get()) and written
when it is first taken. The bookkeeping takes 24 KiB, allocated at
probe as on RTL930x.

Measured on an HPE 1920-48G (RTL8393) with #25805 on main 17a3a87f6e,
8 echo requests per case, forwarding off: routes A and B via gateway
G, A removed, then route C via gateway H.
- without this change, C took A's row and B's traffic arrived 8/8 at
  H, sent to H's MAC
- with it, C got a row of its own and B's traffic stayed 8/8 at G
Of the #25805 bench, prefix order in both orders, blackhole, neighbour
loss and back, and 22 routes in random order gave the same results as
there.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25808
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
Gennaro Cimmino authored and Markus Stockhausen committed 2026-10-11 16:45:42 +02:00
1 parent 3735d60599
commit c282dd1f4d
1 file changed
+9 -8
@@ -186,14 +186,16 @@ static void otto_l3_839x_nexthop_read(struct otto_l3_ctrl *ctrl, int idx, struct
rt->nh.gw = v >> 16;
}
static void otto_l3_839x_nexthop_write(struct otto_l3_ctrl *ctrl, int idx, struct otto_l3_route *rt)
/* A ROUTING row holds a gateway's MAC and the index of the source MAC to
* route with, left at 0. The routes through one gateway share its row, the
* way RTL930x routes share a DMAC entry: the L2 entry of the gateway names
* one row, whichever route claimed it.
*/
static int otto_l3_839x_set_egress_mac(struct otto_l3_ctrl *ctrl, u32 idx, u64 mac)
{
u32 data[2];
u32 data[2] = { mac >> 16, mac << 16 };
data[0] = rt->nh.gw >> 16;
data[1] = (rt->nh.gw << 16) | (rt->switch_mac_id << 12);
otto_table_write(RTL8390_TBL_ROUTING, idx, &data);
return otto_table_write(RTL8390_TBL_ROUTING, idx, &data);
}
/* The prefix rows of an RTL839x are the PIE rules L3 keeps for itself. A rule
@@ -219,8 +221,6 @@ static void otto_l3_839x_route_write(struct otto_l3_ctrl *ctrl, int idx, struct
pr.fwd_sel = true;
if (rt->attr.action == ROUTE_ACT_FORWARD) {
/* The next hop is in place before the rule that points at it */
otto_l3_839x_nexthop_write(ctrl, rt->nh.dmac_id, rt);
pr.fwd_act = PIE_ACT_ROUTE_UC;
pr.fwd_data = rt->nh.l2_id;
} else {
@@ -4146,6 +4146,7 @@ const struct otto_l3_config otto_l3_838x_cfg = {
};
const struct otto_l3_config otto_l3_839x_cfg = {
.set_egress_mac = otto_l3_839x_set_egress_mac,
.route_rows_move = otto_l3_839x_route_rows_move,
.route_write = otto_l3_839x_route_write,
.setup = otto_l3_839x_setup,