From: Kuniyuki Iwashima <kuniyu@google.com>
To: David Ahern <dsahern@kernel.org>,
Ido Schimmel <idosch@nvidia.com>,
"David S . Miller" <davem@davemloft.net>,
Eric Dumazet <edumazet@google.com>,
Jakub Kicinski <kuba@kernel.org>,
Paolo Abeni <pabeni@redhat.com>
Cc: Simon Horman <horms@kernel.org>,
Kuniyuki Iwashima <kuniyu@google.com>,
Kuniyuki Iwashima <kuni1840@gmail.com>,
netdev@vger.kernel.org
Subject: [PATCH v1 net-next 09/10] net: fib_rules: Only hold RTNL for the first IPv4 RTM_NEWRULE.
Date: Mon, 29 Jun 2026 18:11:01 +0000 [thread overview]
Message-ID: <20260629181226.1929658-10-kuniyu@google.com> (raw)
In-Reply-To: <20260629181226.1929658-1-kuniyu@google.com>
Now, RTM_DELRULE no longer needs RTNL, and the only RTNL dependant
in RTM_NEWRULE is fib_unmerge(), which is called for the first
IPv4 rule.
Let's add fib_rules_ops.need_rtnl() and hold RTNL only for the
first IPv4 rule.
Tested:
The script below creates 1K rules in parallel in 4K netns, and
it got 20x/30x faster for IPv4/IPv6.
#!/bin/bash
N=4096
F=rules.txt
for i in $(seq $N); do ip netns add ns-$i; done
printf 'rule add from all table %d\n' {1..1024} > $F
for v in 4 6; do
echo "=== IPv${v} ==="
time { for i in $(seq $N); do nsenter \
--net=/var/run/netns/ns-$i ip -$v -batch $F & done; wait; }
done
for i in $(seq $N); do ip netns del ns-$i; done
rm -f $F
Without this series:
# ./test.sh
=== IPv4 ===
real 0m22.752s
user 0m7.834s
sys 92m46.721s
=== IPv6 ===
real 0m35.181s
user 0m8.635s
sys 142m30.479s
With this series:
# ./test.sh
=== IPv4 ===
real 0m0.918s
user 0m5.675s
sys 2m7.024s
=== IPv6 ===
real 0m1.214s
user 0m7.917s
sys 4m19.489s
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
include/net/fib_rules.h | 1 +
net/core/fib_rules.c | 15 ++++++---------
net/ipv4/fib_rules.c | 6 ++++++
3 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h
index 7636ef4da5ad..c6b94790fa81 100644
--- a/include/net/fib_rules.h
+++ b/include/net/fib_rules.h
@@ -93,6 +93,7 @@ struct fib_rules_ops {
/* Called after modifications to the rules set, must flush
* the route cache if one exists. */
void (*flush_cache)(struct fib_rules_ops *ops);
+ bool (*need_rtnl)(struct net *net);
int nlgroup;
struct list_head rules_list;
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 2b652dd83241..22e5e5e1a9c4 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -881,6 +881,7 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
struct nlattr *tb[FRA_MAX + 1];
bool user_priority = false;
struct fib_rule_hdr *frh;
+ bool unlock_rtnl = false;
frh = nlmsg_payload(nlh, sizeof(*frh));
if (!frh) {
@@ -906,8 +907,10 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
if (err)
goto errout;
- if (!rtnl_held)
+ if (!rtnl_held && ops->need_rtnl && ops->need_rtnl(net)) {
+ unlock_rtnl = true;
rtnl_net_lock(net);
+ }
mutex_lock(&ops->lock);
err = fib_nl2rule_locked(rule, ops, tb, extack);
@@ -978,7 +981,7 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
fib_rule_get(rule);
mutex_unlock(&ops->lock);
- if (!rtnl_held)
+ if (unlock_rtnl)
rtnl_net_unlock(net);
notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
@@ -989,7 +992,7 @@ int fib_newrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
errout_free:
mutex_unlock(&ops->lock);
- if (!rtnl_held)
+ if (unlock_rtnl)
rtnl_net_unlock(net);
kfree(rule);
errout:
@@ -1038,8 +1041,6 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
if (err)
goto errout;
- if (!rtnl_held)
- rtnl_net_lock(net);
mutex_lock(&ops->lock);
err = fib_nl2rule_locked(nlrule, ops, tb, extack);
@@ -1096,8 +1097,6 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
call_fib_rule_notifiers(net, FIB_EVENT_RULE_DEL, rule, ops, NULL);
mutex_unlock(&ops->lock);
- if (!rtnl_held)
- rtnl_net_unlock(net);
notify_rule_change(RTM_DELRULE, rule, ops, nlh, NETLINK_CB(skb).portid);
fib_rule_put(rule);
@@ -1108,8 +1107,6 @@ int fib_delrule(struct net *net, struct sk_buff *skb, struct nlmsghdr *nlh,
errout_free:
mutex_unlock(&ops->lock);
- if (!rtnl_held)
- rtnl_net_unlock(net);
kfree(nlrule);
errout:
rules_ops_put(ops);
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 16d202246a36..4edb0dca7be8 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -460,6 +460,11 @@ static void fib4_rule_flush_cache(struct fib_rules_ops *ops)
rt_cache_flush(ops->fro_net);
}
+static bool fib4_rule_need_rtnl(struct net *net)
+{
+ return !net->ipv4.fib_has_custom_rules;
+}
+
static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {
.family = AF_INET,
.rule_size = sizeof(struct fib4_rule),
@@ -473,6 +478,7 @@ static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = {
.fill = fib4_rule_fill,
.nlmsg_payload = fib4_rule_nlmsg_payload,
.flush_cache = fib4_rule_flush_cache,
+ .need_rtnl = fib4_rule_need_rtnl,
.nlgroup = RTNLGRP_IPV4_RULE,
.owner = THIS_MODULE,
};
--
2.55.0.rc0.799.gd6f94ed593-goog
next prev parent reply other threads:[~2026-06-29 18:12 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-29 18:10 [PATCH v1 net-next 00/10] net: fib_rules: RTNL-less RTM_NEWRULE and RTM_DELRULE Kuniyuki Iwashima
2026-06-29 18:10 ` [PATCH v1 net-next 01/10] net: fib_rules: Make fib_rules_ops.delete() return void Kuniyuki Iwashima
2026-06-29 18:10 ` [PATCH v1 net-next 02/10] ipv4: fib_rules: Make the need for fib_unmerge() explicit Kuniyuki Iwashima
2026-06-29 18:10 ` [PATCH v1 net-next 03/10] ipv4: fib: Protect fib_new_table() with spinlock Kuniyuki Iwashima
2026-06-29 18:10 ` [PATCH v1 net-next 04/10] ipv4: fib: Drop RTNL annotation for net->ipv4.fib_table_hash[] Kuniyuki Iwashima
2026-06-29 18:10 ` [PATCH v1 net-next 05/10] net: fib_rules: Add fib_rules_ops.lock Kuniyuki Iwashima
2026-06-29 18:10 ` [PATCH v1 net-next 06/10] net: fib_rules: Remove unnecessary EXPORT_SYMBOL Kuniyuki Iwashima
2026-06-29 18:10 ` [PATCH v1 net-next 07/10] net: fib_rules: Drop RTNL assertions Kuniyuki Iwashima
2026-06-29 18:11 ` [PATCH v1 net-next 08/10] net: fib_rules: Use dev_get_by_name_rcu() Kuniyuki Iwashima
2026-06-29 18:11 ` Kuniyuki Iwashima [this message]
2026-06-29 18:11 ` [PATCH v1 net-next 10/10] ipv6: fib_rules: Convert fib6_rules_net_exit_rtnl() to ->exit() Kuniyuki Iwashima
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260629181226.1929658-10-kuniyu@google.com \
--to=kuniyu@google.com \
--cc=davem@davemloft.net \
--cc=dsahern@kernel.org \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=idosch@nvidia.com \
--cc=kuba@kernel.org \
--cc=kuni1840@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox