From e59089db5fc9e576d772c61f18610eaeaa331de3 Mon Sep 17 00:00:00 2001 From: Gennaro Cimmino Date: Wed, 30 Sep 2026 19:26:29 +0200 Subject: [PATCH] realtek: l3: skip IPv4 routes without a nexthop device A blackhole, unreachable or prohibit route has no device behind its nexthop: fib_create_info() refuses one for these types and skips the nexthop check that would find one, so fib_nh_dev stays NULL. otto_l3_fib_add_v4() hands that device to is_vlan_dev() before any test, and otto_l3_fib_check_v4(), which the delete path runs as well, does the same in its variable initialisers. On an RTL9303 with the L3 offload built in, "ip route add blackhole 10.99.8.0/24" oopses in the rtl83xx work queue and panics the box: CPU 0 Unable to handle kernel paging request at virtual address 00000000, epc == 8070fe3c, ra == 80710594 Workqueue: rtl83xx otto_l3_fib_event_work_do epc : 8070fe3c otto_l3_fib_add_v4+0x1c0/0x794 Kernel panic - not syncing: Fatal exception The faulting load is the priv_flags word is_vlan_dev() tests. Such routes are common on a router, for address space it announces but does not use. Handle them where a route through a nexthop object is already handled, for the same reasons: there is nothing to offload, and the route can still replace one that was, so the entry for its destination is taken out, and a host route is trapped where the host table can hold it. The delete path takes the same exit. Tested on an RTL9303 (Hasivo S1100W-8XGT-SE) with the L3 offload built in. Without this change the command above panics the box; with it, a blackhole /24 stays in the kernel with no entry in hardware, an offloaded /24 replaced by a blackhole loses its entry and gets it back when replaced through the gateway again, a blackhole /32 gets a trap entry in the host table, unreachable and prohibit routes go in as well, and every delete leaves no entry and no oops. RTL839x, which runs this code in a stock build, was not tested. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Gennaro Cimmino Link: https://github.com/openwrt/openwrt/pull/25513 Signed-off-by: Markus Stockhausen --- .../files-6.18/drivers/net/dsa/rtl83xx/l3.c | 19 +++++++++++-------- 1 file changed, 11 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 8df0a9274c1..de673d6183c 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 @@ -1526,13 +1526,14 @@ static int otto_l3_fib_add_v4(struct otto_l3_ctrl *ctrl, struct fib_entry_notifi struct fib_nh *nh; int port, vlan; - /* A route through a nexthop object is not offloaded and has no - * nexthop array to read, but it can replace a route that is. An - * offloaded shorter prefix would forward its traffic, so trap it where - * the host table can hold it. + /* A route through a nexthop object has no nexthop array to read, and a + * blackhole, unreachable or prohibit route has no device behind its + * nexthop. Neither is offloaded, but either can replace a route that + * is. An offloaded shorter prefix would forward its traffic, so trap + * it where the host table can hold it. */ - if (info->fi->nh) { - dev_dbg(ctrl->dev, "route through a nexthop object, not offloaded\n"); + if (info->fi->nh || !fib_info_nh(info->fi, 0)->fib_nh_dev) { + dev_dbg(ctrl->dev, "route not offloaded: no device or a nexthop object\n"); route = otto_l3_route_find(ctrl, info->tb_id, ROUTE_TYPE_IP4UC, info->dst, NULL, info->dst_len); if (route) @@ -1646,8 +1647,10 @@ static int otto_l3_fib_del_v4(struct otto_l3_ctrl *ctrl, struct fib_entry_notifi struct in6_addr gw; struct fib_nh *nh; - /* A route through a nexthop object holds at most a trap entry */ - if (info->fi->nh) { + /* A route through a nexthop object or without a device holds at most a + * trap entry + */ + if (info->fi->nh || !fib_info_nh(info->fi, 0)->fib_nh_dev) { route = otto_l3_route_find(ctrl, info->tb_id, ROUTE_TYPE_IP4UC, info->dst, NULL, info->dst_len); if (route)