[PATCH net v3 1/1] ipv4: fib: bound automatic table ID allocation

From: Zihan Xi

Date: Tue Sep 01 2026 - 07:00:33 EST


fib_empty_table() probes every table ID from 1 until it finds a
free one. IPv4 tables are stored in a 256-bucket hash table, so a
dense set of IDs makes each probe walk a growing hash chain while
RTNL is held.

Automatic table assignment ("ip rule ... table 0") is an IPv4-only
legacy path. Bound the automatically allocated ID to 4096 so the
RTNL hold stays bounded, without changing lookups of explicitly
specified table IDs.

This changes user-visible behavior. A table-0 rule previously
received the lowest free ID in 1..RT_TABLE_MAX (0xFFFFFFFF). After
this patch the search stops at 4096 and the rule add fails with
ENOBUFS if that range is fully occupied. Explicit table IDs above
4096 remain usable.

The automatic path is unused in practice: it is IPv4-only, not
documented by ip-rule, uncovered by kernel selftests, and both
NetworkManager and systemd refuse table 0.

Fixes: b801f54917b7 ("[NET]: Increate RT_TABLE_MAX to 2^32")
Cc: stable@xxxxxxxxxxxxxxx
Reported-by: Vega <vega@xxxxxxxxxx>
Suggested-by: Ido Schimmel <idosch@xxxxxxxxxx>
Assisted-by: Codex:gpt-5.4
Signed-off-by: Zihan Xi <zihanx@xxxxxxxxxx>
Reviewed-by: Ido Schimmel <idosch@xxxxxxxxxx>
---
changes in v3:
- Spell out that table-0 auto-assignment returns ENOBUFS if
IDs 1..4096 are occupied, while other functionality is
unchanged.
- Add Reviewed-by from Ido Schimmel.
- v2 Link: https://lore.kernel.org/all/7b6bd9bb1bf6bd43db18156f42b2d7f83789a673.1788223735.git.zihanx@xxxxxxxxxx/
changes in v2:
- Replace the bitmap-based O(N) rewrite with a 4096 cap on
automatically allocated table IDs, as suggested by Ido Schimmel.
- Point Fixes: at b801f54917b7, which first raised RT_TABLE_MAX
to 2^32. 1af5a8c4a11c only switched the probe to a hash lookup
while the scan was still capped at 255.
- v1 Link: https://lore.kernel.org/all/0a00492a13038b268c1e0a219c138d07cfab92b3.1787982246.git.zihanx@xxxxxxxxxx/

net/ipv4/fib_rules.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 4edb0dca7be8..060501b376a8 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -214,6 +214,8 @@ INDIRECT_CALLABLE_SCOPE int fib4_rule_match(struct fib_rule *rule,
return 1;
}

+#define FIB_MAX_AUTO_TABLE_ID 4096
+
static struct fib_table *fib_empty_table(struct net *net)
{
u32 id = 1;
@@ -222,7 +224,7 @@ static struct fib_table *fib_empty_table(struct net *net)
if (!fib_get_table(net, id))
return fib_new_table(net, id);

- if (id++ == RT_TABLE_MAX)
+ if (id++ == FIB_MAX_AUTO_TABLE_ID)
break;
}
return NULL;
--
2.43.0