[PATCH v3 net-next 07/15] ip6mr: Convert ip6mr_rtm_dumproute() to RCU.

Kuniyuki Iwashima
2026-04-07T21:20:15Z

ip6mr_rtm_dumproute() calls mr_table_dump() or mr_rtm_dumproute(),
and mr_rtm_dumproute() finally calls mr_table_dump().

mr_table_dump() calls the passed function, _ip6mr_fill_mroute().

_ip6mr_fill_mroute() is a wrapper for ip6mr_fill_mroute() to cast
struct mr_mfc * to struct mfc6_cache *.

ip6mr_fill_mroute() can already be called safely under RCU.

Let's convert ip6mr_rtm_dumproute() to RCU.

Now there is no user of the rtnl_held field in struct
fib_dump_filter, and the next patch will remove it.

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
net/ipv6/ip6mr.c | 29 ++++++++++++++++++++---------
1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c
index 389471e740bc..cd28bea8c11a 100644
--- a/net/ipv6/ip6mr.c
+++ b/net/ipv6/ip6mr.c
@@ -1391,7 +1391,7 @@ static const struct rtnl_msg_handler ip6mr_rtnl_msg_handlers[] __initconst_or_mo
{.owner = THIS_MODULE, .protocol = RTNL_FAMILY_IP6MR,
.msgtype = RTM_GETROUTE,
.doit = ip6mr_rtm_getroute, .dumpit = ip6mr_rtm_dumproute,
- .flags = RTNL_FLAG_DOIT_UNLOCKED},
+ .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},
};

int __init ip6_mr_init(void)
@@ -2751,15 +2751,17 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)
{
const struct nlmsghdr *nlh = cb->nlh;
struct fib_dump_filter filter = {
- .rtnl_held = true,
+ .rtnl_held = false,
};
int err;

+ rcu_read_lock();
+
if (cb->strict_check) {
err = ip_valid_fib_dump_req(sock_net(skb->sk), nlh,
&filter, cb);
if (err < 0)
- return err;
+ goto unlock;
}

if (filter.table_id) {
@@ -2767,17 +2769,26 @@ static int ip6mr_rtm_dumproute(struct sk_buff *skb, struct netlink_callback *cb)

mrt = __ip6mr_get_table(sock_net(skb->sk), filter.table_id);
if (!mrt) {
- if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR)
- return skb->len;
+ if (rtnl_msg_family(cb->nlh) != RTNL_FAMILY_IP6MR) {
+ err = skb->len;
+ goto unlock;
+ }

NL_SET_ERR_MSG_MOD(cb->extack, "MR table does not exist");
- return -ENOENT;
+ err = -ENOENT;
+ goto unlock;
}
+
err = mr_table_dump(mrt, skb, cb, _ip6mr_fill_mroute,
&mfc_unres_lock, &filter);
- return skb->len ? : err;
+ err = skb->len ? : err;
+ goto unlock;
}

- return mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
- _ip6mr_fill_mroute, &mfc_unres_lock, &filter);
+ err = mr_rtm_dumproute(skb, cb, ip6mr_mr_table_iter,
+ _ip6mr_fill_mroute, &mfc_unres_lock, &filter);
+unlock:
+ rcu_read_unlock();
+
+ return err;
}
--
2.53.0.1213.gd9a14994de-goog