]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ipmr: Don't hold RTNL for ipmr_rtm_route().
authorKuniyuki Iwashima <kuniyu@google.com>
Sat, 28 Feb 2026 22:17:33 +0000 (22:17 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 3 Mar 2026 02:49:41 +0000 (18:49 -0800)
ipmr_mfc_add() and ipmr_mfc_delete() are already protected
by a dedicated mutex.

rtm_to_ipmr_mfcc() calls __ipmr_get_table(), __dev_get_by_index(),
amd ipmr_find_vif().

Once __dev_get_by_index() is converted to dev_get_by_index_rcu(),
we can move the other two functions under that same RCU section
and drop RTNL for ipmr_rtm_route().

Let's do that conversion and drop ASSERT_RTNL() in
mr_call_mfc_notifiers().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260228221800.1082070-16-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/linux/mroute_base.h
net/ipv4/ipmr.c

index 0baa6f994da9e3ff58d591225164da4e01dd9ea8..cf3374580f744dadc731f5f92da0518efc26c9be 100644 (file)
@@ -208,7 +208,6 @@ static inline int mr_call_mfc_notifiers(struct net *net,
                .tb_id = tb_id
        };
 
-       ASSERT_RTNL();
        atomic_inc(ipmr_seq);
        return call_fib_notifiers(net, event_type, &info.info);
 }
index d4983d8a9b2a06c6a813169b383bf46bbd731e9b..8a08d09b4c309b15ec05c395aadd7defacf404a7 100644 (file)
@@ -1211,7 +1211,6 @@ static int ipmr_mfc_delete(struct mr_table *mrt, struct mfcctl *mfc, int parent)
        struct net *net = read_pnet(&mrt->net);
        struct mfc_cache *c;
 
-       /* The entries are added/deleted only under RTNL */
        rcu_read_lock();
        c = ipmr_cache_find_parent(mrt, mfc->mfcc_origin.s_addr,
                                   mfc->mfcc_mcastgrp.s_addr, parent);
@@ -1238,7 +1237,6 @@ static int ipmr_mfc_add(struct net *net, struct mr_table *mrt,
        if (mfc->mfcc_parent >= MAXVIFS)
                return -ENFILE;
 
-       /* The entries are added/deleted only under RTNL */
        rcu_read_lock();
        c = ipmr_cache_find_parent(mrt, mfc->mfcc_origin.s_addr,
                                   mfc->mfcc_mcastgrp.s_addr, parent);
@@ -2853,10 +2851,10 @@ static int rtm_to_ipmr_mfcc(struct net *net, struct nlmsghdr *nlh,
 {
        struct net_device *dev = NULL;
        u32 tblid = RT_TABLE_DEFAULT;
+       int ret, rem, iif = 0;
        struct mr_table *mrt;
        struct nlattr *attr;
        struct rtmsg *rtm;
-       int ret, rem;
 
        ret = nlmsg_validate_deprecated(nlh, sizeof(*rtm), RTA_MAX,
                                        rtm_ipmr_policy, extack);
@@ -2883,11 +2881,7 @@ static int rtm_to_ipmr_mfcc(struct net *net, struct nlmsghdr *nlh,
                        mfcc->mfcc_mcastgrp.s_addr = nla_get_be32(attr);
                        break;
                case RTA_IIF:
-                       dev = __dev_get_by_index(net, nla_get_u32(attr));
-                       if (!dev) {
-                               ret = -ENODEV;
-                               goto out;
-                       }
+                       iif = nla_get_u32(attr);
                        break;
                case RTA_MULTIPATH:
                        if (ipmr_nla_get_ttls(attr, mfcc) < 0) {
@@ -2903,16 +2897,30 @@ static int rtm_to_ipmr_mfcc(struct net *net, struct nlmsghdr *nlh,
                        break;
                }
        }
+
+       rcu_read_lock();
+
        mrt = __ipmr_get_table(net, tblid);
        if (!mrt) {
                ret = -ENOENT;
-               goto out;
+               goto unlock;
        }
+
+       if (iif) {
+               dev = dev_get_by_index_rcu(net, iif);
+               if (!dev) {
+                       ret = -ENODEV;
+                       goto unlock;
+               }
+
+               mfcc->mfcc_parent = ipmr_find_vif(mrt, dev);
+       }
+
        *mrtret = mrt;
        *mrtsock = rtm->rtm_protocol == RTPROT_MROUTED ? 1 : 0;
-       if (dev)
-               mfcc->mfcc_parent = ipmr_find_vif(mrt, dev);
 
+unlock:
+       rcu_read_unlock();
 out:
        return ret;
 }
@@ -3343,9 +3351,9 @@ static const struct rtnl_msg_handler ipmr_rtnl_msg_handlers[] __initconst = {
        {.protocol = RTNL_FAMILY_IPMR, .msgtype = RTM_GETLINK,
         .dumpit = ipmr_rtm_dumplink, .flags = RTNL_FLAG_DUMP_UNLOCKED},
        {.protocol = RTNL_FAMILY_IPMR, .msgtype = RTM_NEWROUTE,
-        .doit = ipmr_rtm_route},
+        .doit = ipmr_rtm_route, .flags = RTNL_FLAG_DOIT_UNLOCKED},
        {.protocol = RTNL_FAMILY_IPMR, .msgtype = RTM_DELROUTE,
-        .doit = ipmr_rtm_route},
+        .doit = ipmr_rtm_route, .flags = RTNL_FLAG_DOIT_UNLOCKED},
        {.protocol = RTNL_FAMILY_IPMR, .msgtype = RTM_GETROUTE,
         .doit = ipmr_rtm_getroute, .dumpit = ipmr_rtm_dumproute,
         .flags = RTNL_FLAG_DOIT_UNLOCKED | RTNL_FLAG_DUMP_UNLOCKED},