mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-13 17:38:48 +04:00
realtek: l3: keep a trap whose source list is incomplete
A prefix with source-specific IPv6 routes gets one trap row, which keeps a list of their sources and goes once the list is empty and no route without a source is left. When the allocation for a source failed, that source was left out: once the list was empty the row went, or a route without a source took it over, though the kernel still had the source-specific route the row was trapping for. Mark the row when a source could not be tracked, count it as still standing for sources, and ask for a FIB replay, which builds the list again from scratch. Tested on a Hasivo S1100W-8XGT-SE (RTL9303) with L3 offload enabled, through a bench-only debugfs counter that fails the next source allocation: under an IPv6 /32 forwarding in hardware, a /48 with a source-specific route via another host and a source-specific blackhole for the sender, whose tracking fails. Once the first is deleted, the kernel drops the sender's echoes: without this change the trap row goes and the /32 forwards all 5 to the host, with it the row stays, the FIB is replayed and none arrive. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net> Link: https://github.com/openwrt/openwrt/pull/25623 Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
1 parent
580a493cb9
commit
47b46ced13
2 files changed
+22
-4
No files matched your search
@@ -2235,6 +2235,14 @@ static struct otto_l3_route_src *otto_l3_route_src_find(struct otto_l3_route *r,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* A source that could not be tracked is still a route the row stands for */
|
||||
static bool otto_l3_route_has_srcs(struct otto_l3_route *r)
|
||||
{
|
||||
return !list_empty(&r->srcs) || r->srcs_incomplete;
|
||||
}
|
||||
|
||||
static void otto_l3_resync_request(struct otto_l3_ctrl *ctrl);
|
||||
|
||||
/* A source-specific route matches only the packets from its source, and the
|
||||
* hardware matches on the destination alone, so the destination traps for as
|
||||
* long as one of them remains. The trap row counts the members of each source
|
||||
@@ -2278,8 +2286,17 @@ static int otto_l3_fib_add_v6_src(struct otto_l3_ctrl *ctrl, struct fib6_info *r
|
||||
s = otto_l3_route_src_find(route, &rt->fib6_src);
|
||||
if (!s) {
|
||||
s = kzalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (!s)
|
||||
if (!s) {
|
||||
/* The row keeps trapping whatever the list says; a replay
|
||||
* builds the list again
|
||||
*/
|
||||
route->srcs_incomplete = true;
|
||||
dev_err(ctrl->dev, "%pI6c/%d from %pI6c/%d: no memory to track the source\n",
|
||||
&rt->fib6_dst.addr, rt->fib6_dst.plen,
|
||||
&rt->fib6_src.addr, rt->fib6_src.plen);
|
||||
otto_l3_resync_request(ctrl);
|
||||
return -ENOMEM;
|
||||
}
|
||||
s->addr = rt->fib6_src.addr;
|
||||
s->plen = rt->fib6_src.plen;
|
||||
list_add_tail(&s->list, &route->srcs);
|
||||
@@ -2312,7 +2329,7 @@ static int otto_l3_fib_del_v6_src(struct otto_l3_ctrl *ctrl, struct fib6_info *r
|
||||
list_del(&s->list);
|
||||
kfree(s);
|
||||
|
||||
if (list_empty(&route->srcs) && !route->members)
|
||||
if (!otto_l3_route_has_srcs(route) && !route->members)
|
||||
otto_l3_route_teardown(ctrl, route);
|
||||
|
||||
return 0;
|
||||
@@ -2389,7 +2406,7 @@ static int otto_l3_fib_add_v6(struct otto_l3_ctrl *ctrl, struct fib6_entry_notif
|
||||
*/
|
||||
route = otto_l3_route_find(ctrl, rt->fib6_table->tb6_id, ROUTE_TYPE_IP6UC,
|
||||
0, &rt->fib6_dst.addr, rt->fib6_dst.plen);
|
||||
if (route && !list_empty(&route->srcs)) {
|
||||
if (route && otto_l3_route_has_srcs(route)) {
|
||||
route->members = members;
|
||||
return 0;
|
||||
}
|
||||
@@ -2507,7 +2524,7 @@ static int otto_l3_fib_del_v6(struct otto_l3_ctrl *ctrl, struct fib6_entry_notif
|
||||
if (route && ipv6_addr_any(&route->gw_ip)) {
|
||||
if (route->members > members)
|
||||
route->members -= members;
|
||||
else if (!list_empty(&route->srcs))
|
||||
else if (otto_l3_route_has_srcs(route))
|
||||
route->members = 0;
|
||||
else
|
||||
otto_l3_route_teardown(ctrl, route);
|
||||
|
||||
@@ -87,6 +87,7 @@ struct otto_l3_route {
|
||||
int row; /* Row it occupies in the prefix route table */
|
||||
unsigned int members; /* FIB entries a trap row stands for */
|
||||
struct list_head srcs; /* source-specific routes a trap row stands for */
|
||||
bool srcs_incomplete; /* a source could not be tracked */
|
||||
struct rhlist_head linkage;
|
||||
struct list_head list; /* all routes, for lookups by destination */
|
||||
u32 tb_id; /* routing table the route came from */
|
||||
|
||||
Reference in new issue
Block a user