Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ipmr: Add dedicated mutex for mrt->{mfc_hash,mfc_cache_list}.

We will no longer hold RTNL for ipmr_rtm_route() to modify the
MFC hash table.

Only __dev_get_by_index() in rtm_to_ipmr_mfcc() is the RTNL
dependant, otherwise, we just need protection for mrt->mfc_hash
and mrt->mfc_cache_list.

Let's add a new mutex for ipmr_mfc_add(), ipmr_mfc_delete(),
and mroute_clean_tables() (setsockopt(MRT_FLUSH or MRT_DONE)).

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/20260228221800.1082070-15-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Kuniyuki Iwashima and committed by
Jakub Kicinski
3c1e53e5 4480d5fa

+23 -6
+1
include/net/netns/ipv4.h
··· 281 281 #endif 282 282 struct fib_notifier_ops *ipmr_notifier_ops; 283 283 atomic_t ipmr_seq; 284 + struct mutex mfc_mutex; 284 285 #endif 285 286 #ifdef CONFIG_IP_ROUTE_MULTIPATH 286 287 struct sysctl_fib_multipath_hash_seed sysctl_fib_multipath_hash_seed;
+22 -6
net/ipv4/ipmr.c
··· 1329 1329 1330 1330 /* Wipe the cache */ 1331 1331 if (flags & (MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC)) { 1332 + mutex_lock(&net->ipv4.mfc_mutex); 1333 + 1332 1334 list_for_each_entry_safe(c, tmp, &mrt->mfc_cache_list, list) { 1333 1335 if (((c->mfc_flags & MFC_STATIC) && !(flags & MRT_FLUSH_MFC_STATIC)) || 1334 1336 (!(c->mfc_flags & MFC_STATIC) && !(flags & MRT_FLUSH_MFC))) ··· 1343 1341 mroute_netlink_event(mrt, cache, RTM_DELROUTE); 1344 1342 mr_cache_put(c); 1345 1343 } 1344 + 1345 + mutex_unlock(&net->ipv4.mfc_mutex); 1346 1346 } 1347 1347 1348 1348 if (flags & MRT_FLUSH_MFC) { ··· 1502 1498 } 1503 1499 if (parent == 0) 1504 1500 parent = mfc.mfcc_parent; 1501 + 1502 + mutex_lock(&net->ipv4.mfc_mutex); 1503 + 1505 1504 if (optname == MRT_DEL_MFC || optname == MRT_DEL_MFC_PROXY) 1506 1505 ret = ipmr_mfc_delete(mrt, &mfc, parent); 1507 1506 else 1508 1507 ret = ipmr_mfc_add(net, mrt, &mfc, 1509 1508 sk == rtnl_dereference(mrt->mroute_sk), 1510 1509 parent); 1510 + 1511 + mutex_unlock(&net->ipv4.mfc_mutex); 1511 1512 break; 1512 1513 case MRT_FLUSH: { 1513 1514 LIST_HEAD(dev_kill_list); ··· 2922 2913 struct netlink_ext_ack *extack) 2923 2914 { 2924 2915 struct net *net = sock_net(skb->sk); 2925 - int ret, mrtsock, parent; 2926 - struct mr_table *tbl; 2916 + int ret, mrtsock = 0, parent; 2917 + struct mr_table *tbl = NULL; 2927 2918 struct mfcctl mfcc; 2928 2919 2929 - mrtsock = 0; 2930 - tbl = NULL; 2931 2920 ret = rtm_to_ipmr_mfcc(net, nlh, &mfcc, &mrtsock, &tbl, extack); 2932 2921 if (ret < 0) 2933 2922 return ret; 2934 2923 2935 2924 parent = ret ? mfcc.mfcc_parent : -1; 2925 + 2926 + mutex_lock(&net->ipv4.mfc_mutex); 2927 + 2936 2928 if (nlh->nlmsg_type == RTM_NEWROUTE) 2937 - return ipmr_mfc_add(net, tbl, &mfcc, mrtsock, parent); 2929 + ret = ipmr_mfc_add(net, tbl, &mfcc, mrtsock, parent); 2938 2930 else 2939 - return ipmr_mfc_delete(tbl, &mfcc, parent); 2931 + ret = ipmr_mfc_delete(tbl, &mfcc, parent); 2932 + 2933 + mutex_unlock(&net->ipv4.mfc_mutex); 2934 + 2935 + return ret; 2940 2936 } 2941 2937 2942 2938 static bool ipmr_fill_table(struct mr_table *mrt, struct sk_buff *skb) ··· 3282 3268 { 3283 3269 LIST_HEAD(dev_kill_list); 3284 3270 int err; 3271 + 3272 + mutex_init(&net->ipv4.mfc_mutex); 3285 3273 3286 3274 err = ipmr_notifier_init(net); 3287 3275 if (err)