Skip to content

Commit 5e26e9f

Browse files
CKI Backport BotHangbin Liu
authored andcommitted
ipv6: anycast: Don't hold RTNL for IPV6_JOIN_ANYCAST.
JIRA: https://issues.redhat.com/browse/RHEL-115325 commit eb1ac9f Author: Kuniyuki Iwashima <kuniyu@google.com> Date: Wed Jul 2 16:01:31 2025 -0700 ipv6: anycast: Don't hold RTNL for IPV6_JOIN_ANYCAST. inet6_sk(sk)->ipv6_ac_list is protected by lock_sock(). In ipv6_sock_ac_join(), only __dev_get_by_index(), __dev_get_by_flags(), and __in6_dev_get() require RTNL. __dev_get_by_flags() is only used by ipv6_sock_ac_join() and can be converted to RCU version. Let's replace RCU version helper and drop RTNL from IPV6_JOIN_ANYCAST. setsockopt_needs_rtnl() will be removed in the next patch. Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com> Reviewed-by: Eric Dumazet <edumazet@google.com> Link: https://patch.msgid.link/20250702230210.3115355-15-kuni1840@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: CKI Backport Bot <cki-ci-bot+cki-gitlab-backport-bot@redhat.com>
1 parent cc56e24 commit 5e26e9f

File tree

4 files changed

+34
-34
lines changed

4 files changed

+34
-34
lines changed

include/linux/netdevice.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3160,8 +3160,8 @@ int dev_get_iflink(const struct net_device *dev);
31603160
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
31613161
int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
31623162
struct net_device_path_stack *stack);
3163-
struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags,
3164-
unsigned short mask);
3163+
struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags,
3164+
unsigned short mask);
31653165
struct net_device *dev_get_by_name(struct net *net, const char *name);
31663166
struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
31673167
struct net_device *__dev_get_by_name(struct net *net, const char *name);

net/core/dev.c

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,33 +1102,31 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
11021102
EXPORT_SYMBOL(dev_getfirstbyhwtype);
11031103

11041104
/**
1105-
* __dev_get_by_flags - find any device with given flags
1106-
* @net: the applicable net namespace
1107-
* @if_flags: IFF_* values
1108-
* @mask: bitmask of bits in if_flags to check
1105+
* dev_get_by_flags_rcu - find any device with given flags
1106+
* @net: the applicable net namespace
1107+
* @if_flags: IFF_* values
1108+
* @mask: bitmask of bits in if_flags to check
11091109
*
1110-
* Search for any interface with the given flags. Returns NULL if a device
1111-
* is not found or a pointer to the device. Must be called inside
1112-
* rtnl_lock(), and result refcount is unchanged.
1110+
* Search for any interface with the given flags.
1111+
*
1112+
* Context: rcu_read_lock() must be held.
1113+
* Returns: NULL if a device is not found or a pointer to the device.
11131114
*/
1114-
1115-
struct net_device *__dev_get_by_flags(struct net *net, unsigned short if_flags,
1116-
unsigned short mask)
1115+
struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags,
1116+
unsigned short mask)
11171117
{
1118-
struct net_device *dev, *ret;
1119-
1120-
ASSERT_RTNL();
1118+
struct net_device *dev;
11211119

1122-
ret = NULL;
1123-
for_each_netdev(net, dev) {
1124-
if (((dev->flags ^ if_flags) & mask) == 0) {
1125-
ret = dev;
1126-
break;
1120+
for_each_netdev_rcu(net, dev) {
1121+
if (((READ_ONCE(dev->flags) ^ if_flags) & mask) == 0) {
1122+
dev_hold(dev);
1123+
return dev;
11271124
}
11281125
}
1129-
return ret;
1126+
1127+
return NULL;
11301128
}
1131-
EXPORT_SYMBOL(__dev_get_by_flags);
1129+
EXPORT_IPV6_MOD(dev_get_by_flags_rcu);
11321130

11331131
/**
11341132
* dev_valid_name - check if name is okay for network device

net/ipv6/anycast.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,13 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
7373
struct inet6_dev *idev;
7474
int err = 0, ishost;
7575

76-
ASSERT_RTNL();
77-
7876
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
7977
return -EPERM;
8078
if (ipv6_addr_is_multicast(addr))
8179
return -EINVAL;
8280

8381
if (ifindex)
84-
dev = __dev_get_by_index(net, ifindex);
82+
dev = dev_get_by_index(net, ifindex);
8583

8684
if (ipv6_chk_addr_and_flags(net, addr, dev, true, 0, IFA_F_TENTATIVE)) {
8785
err = -EINVAL;
@@ -102,26 +100,30 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
102100
if (ifindex == 0) {
103101
struct rt6_info *rt;
104102

103+
rcu_read_lock();
105104
rt = rt6_lookup(net, addr, NULL, 0, NULL, 0);
106105
if (rt) {
107-
dev = rt->dst.dev;
106+
dev = dst_dev(&rt->dst);
107+
dev_hold(dev);
108108
ip6_rt_put(rt);
109109
} else if (ishost) {
110+
rcu_read_unlock();
110111
err = -EADDRNOTAVAIL;
111112
goto error;
112113
} else {
113114
/* router, no matching interface: just pick one */
114-
dev = __dev_get_by_flags(net, IFF_UP,
115-
IFF_UP | IFF_LOOPBACK);
115+
dev = dev_get_by_flags_rcu(net, IFF_UP,
116+
IFF_UP | IFF_LOOPBACK);
116117
}
118+
rcu_read_unlock();
117119
}
118120

119121
if (!dev) {
120122
err = -ENODEV;
121123
goto error;
122124
}
123125

124-
idev = __in6_dev_get(dev);
126+
idev = in6_dev_get(dev);
125127
if (!idev) {
126128
if (ifindex)
127129
err = -ENODEV;
@@ -144,7 +146,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
144146
if (ishost)
145147
err = -EADDRNOTAVAIL;
146148
if (err)
147-
goto error;
149+
goto error_idev;
148150
}
149151

150152
err = __ipv6_dev_ac_inc(idev, addr);
@@ -154,7 +156,11 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
154156
pac = NULL;
155157
}
156158

159+
error_idev:
160+
in6_dev_put(idev);
157161
error:
162+
dev_put(dev);
163+
158164
if (pac)
159165
sock_kfree_s(sk, pac, sizeof(*pac));
160166
return err;

net/ipv6/ipv6_sockglue.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,6 @@ struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
119119

120120
static bool setsockopt_needs_rtnl(int optname)
121121
{
122-
switch (optname) {
123-
case IPV6_JOIN_ANYCAST:
124-
return true;
125-
}
126122
return false;
127123
}
128124

0 commit comments

Comments
 (0)