From c282dd1f4dcd32b849021f8976ae6894f3093c7d Mon Sep 17 00:00:00 2001 From: Gennaro Cimmino Date: Sun, 11 Oct 2026 13:05:54 +0200 Subject: [PATCH] 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 Link: https://github.com/openwrt/openwrt/pull/25808 Signed-off-by: Markus Stockhausen --- .../files-6.18/drivers/net/dsa/rtl83xx/l3.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c index c78469432ae..a22da15dc46 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c @@ -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,