From 4344b47ebc09b4986fcd3c3800f16029c6e7e5ea Mon Sep 17 00:00:00 2001 From: Gennaro Cimmino Date: Mon, 14 Sep 2026 20:23:16 +0200 Subject: [PATCH] realtek: l3: rtl930x: test the slot that was read otto_l3_930x_find_slot() probed the host route table and then looked at the caller's route instead of the entry it had just read. The placement test asked rt->attr.valid, which both call sites set to true right before calling, so the first address probed was always returned: of the 6144 host route slots only the 512 bucket heads of the first table were reachable, and a second route in a bucket overwrote the first. The lookup test compared route_entry.dst_ip, which otto_l3_930x_host_route_read() does not touch when the entry is invalid or is not IPv4 unicast, so it could match an address the reader never wrote. Ask the entry that was read: an empty slot for placement, and for a lookup a valid entry of the same type whose destination matches. IPv6 unicast destinations are compared with ipv6_addr_equal() instead of through the IPv4 field. Measured on an RTL9303 (Hasivo S1100W-8XGT-SE): two /32 host routes hashing to bucket 281 both ended up at logical index 1686 before this patch. With it each route takes a slot of its own, which is also what exposed the duplicate writes the next patch removes. Assisted-by: Claude:claude-opus-5 Signed-off-by: Gennaro Cimmino Link: https://github.com/openwrt/openwrt/pull/25170 Signed-off-by: Markus Stockhausen --- .../files-6.18/drivers/net/dsa/rtl83xx/l3.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 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 e87867d8f93..9bc8dd36a02 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 @@ -297,10 +297,22 @@ static int otto_l3_930x_find_slot(struct otto_l3_ctrl *ctrl, struct otto_l3_rout otto_l3_930x_host_route_read(ctrl, idx, &route_entry); dev_dbg(ctrl->dev, "route valid %d, route dest: %pI4, hit %d\n", rt->attr.valid, &rt->dst_ip, rt->attr.hit); - if (!must_exist && rt->attr.valid) - return idx; - if (must_exist && route_entry.dst_ip == rt->dst_ip) + if (!must_exist && !route_entry.attr.valid) return idx; + if (must_exist && + route_entry.attr.valid && + route_entry.attr.type == rt->attr.type) { + switch (rt->attr.type) { + case 0: + if (route_entry.dst_ip == rt->dst_ip) + return idx; + break; + case 2: + if (ipv6_addr_equal(&route_entry.dst_ip6, &rt->dst_ip6)) + return idx; + break; + } + } } }