]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ip6mr: Convert ip6mr_rtm_getroute() to RCU.
authorKuniyuki Iwashima <kuniyu@google.com>
Thu, 4 Jun 2026 22:46:23 +0000 (22:46 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 9 Jun 2026 00:06:23 +0000 (17:06 -0700)
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 <kuniyu@google.com>
Link: https://patch.msgid.link/20260604224712.3209821-6-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv6/ip6mr.c

index 018985593b032f3ec99b27f1657ce6412abc4c7c..51ba22f595068952e4a4e6431adbc3b23392b3a1 100644 (file)
@@ -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;
 }