realtek: l3: place local table rows ahead of main's

The kernel looks the local table up before main, so an address of the
switch is delivered to it even when main holds a route of the same
length to that address. The hardware answers with the first prefix row
that matches, and a route is placed after every row of its length or
longer: whichever of the two came first won, and a /128 route in main
added before the address forwarded the address's traffic away.

Place a local table entry after the longer rows only, ahead of main's
of the same length. Main's row stays, and answers again once the
address is gone.

Tested on a Hasivo S1100W-8XGT-SE (RTL9303) with L3 offload enabled,
main against main with this and the next commit, which only touches
the IPv4 host table. fd00:9f::1/128 through a gateway in hardware,
then fd00:9f::1/64 added to the switch, and 5 echoes to the address:
main left the route's row ahead of the address's and forwarded all 5
to the gateway, unanswered; now the switch answers all 5. With the
address gone again, the route forwards all 5 to its gateway on both.

Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net>
Link: https://github.com/openwrt/openwrt/pull/25598
Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
Gennaro Cimmino authored and Markus Stockhausen committed 2026-10-04 18:47:46 +02:00
1 parent 8a6ae95526
commit d3301f3ea0
1 file changed
+6 -1
@@ -1046,7 +1046,12 @@ static int otto_l3_route_place(struct otto_l3_ctrl *ctrl, struct otto_l3_route *
if (ctrl->prefix_rows_stale)
return -1;
below = otto_l3_prefix_rows(ctrl, r->attr.type, r->prefix_len);
/* The local table is looked up before main, so its entries go ahead of
* main's of the same length: the hardware answers with the first row
* that matches.
*/
below = otto_l3_prefix_rows(ctrl, r->attr.type,
r->prefix_len + (r->tb_id == RT_TABLE_LOCAL));
rows = otto_l3_prefix_rows(ctrl, r->attr.type, 0);
if (r->attr.type == ROUTE_TYPE_IP6UC) {