From 76ea2ba2297e0bbd9ddecc971edff93039def6f2 Mon Sep 17 00:00:00 2001 From: Kuniyuki Iwashima Date: Thu, 4 Jun 2026 22:46:23 +0000 Subject: [PATCH] ip6mr: Convert ip6mr_rtm_getroute() to RCU. ip6mr_rtm_getroute() calls __ip6mr_get_table(), ip6mr_cache_find(), and ip6mr_fill_mroute(). Once created, struct mr_table is not freed until netns dismantle, so it's safe under RCU. ip6mr_cache_find() iterates mrt->mfc_hash with rhl_for_each_entry_rcu(). struct mr_mfc is freed with call_rcu(), so this is also safe under RCU. ip6mr_fill_mroute() calls mr_fill_mroute(), which properly uses RCU helpers. Let's call them under RCU and register ip6mr_rtm_getroute() with RTNL_FLAG_DOIT_UNLOCKED. Signed-off-by: Kuniyuki Iwashima Link: https://patch.msgid.link/20260604224712.3209821-6-kuniyu@google.com Signed-off-by: Jakub Kicinski --- net/ipv6/ip6mr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 018985593b032..51ba22f595068 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -1386,7 +1386,8 @@ static struct pernet_operations ip6mr_net_ops = { static const struct rtnl_msg_handler ip6mr_rtnl_msg_handlers[] __initconst_or_module = { {.owner = THIS_MODULE, .protocol = RTNL_FAMILY_IP6MR, .msgtype = RTM_GETROUTE, - .doit = ip6mr_rtm_getroute, .dumpit = ip6mr_rtm_dumproute}, + .doit = ip6mr_rtm_getroute, .dumpit = ip6mr_rtm_dumproute, + .flags = RTNL_FLAG_DOIT_UNLOCKED}, }; int __init ip6_mr_init(void) @@ -2710,6 +2711,8 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, grp = nla_get_in6_addr(tb[RTA_DST]); tableid = nla_get_u32_default(tb[RTA_TABLE], 0); + rcu_read_lock(); + mrt = __ip6mr_get_table(net, tableid ?: RT_TABLE_DEFAULT); if (!mrt) { NL_SET_ERR_MSG_MOD(extack, "MR table does not exist"); @@ -2717,10 +2720,7 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, goto err; } - /* entries are added/deleted only under RTNL */ - rcu_read_lock(); cache = ip6mr_cache_find(mrt, &src, &grp); - rcu_read_unlock(); if (!cache) { NL_SET_ERR_MSG_MOD(extack, "MR cache entry not found"); err = -ENOENT; @@ -2732,9 +2732,12 @@ static int ip6mr_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh, if (err < 0) goto err; + rcu_read_unlock(); + return rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); err: + rcu_read_unlock(); kfree_skb(skb); return err; } -- 2.47.3