Commit 2a683d00 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Jakub Kicinski
Browse files

dev: Pass netdevice_tracker to dev_get_by_flags_rcu().



This is a follow-up for commit eb1ac9ff ("ipv6: anycast: Don't
hold RTNL for IPV6_JOIN_ANYCAST.").

We should not add a new device lookup API without netdevice_tracker.

Let's pass netdevice_tracker to dev_get_by_flags_rcu() and rename it
with netdev_ prefix to match other newer APIs.

Note that we always use GFP_ATOMIC for netdev_hold() as it's expected
to be called under RCU.

Suggested-by: default avatarJakub Kicinski <kuba@kernel.org>
Link: https://lore.kernel.org/netdev/20250708184053.102109f6@kernel.org/


Signed-off-by: default avatarKuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250711051120.2866855-1-kuniyu@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent f25a7eaa
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3332,8 +3332,6 @@ int dev_get_iflink(const struct net_device *dev);
int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb);
int dev_fill_forward_path(const struct net_device *dev, const u8 *daddr,
			  struct net_device_path_stack *stack);
struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short flags,
					unsigned short mask);
struct net_device *dev_get_by_name(struct net *net, const char *name);
struct net_device *dev_get_by_name_rcu(struct net *net, const char *name);
struct net_device *__dev_get_by_name(struct net *net, const char *name);
@@ -3396,6 +3394,8 @@ struct net_device *netdev_get_by_index(struct net *net, int ifindex,
				       netdevice_tracker *tracker, gfp_t gfp);
struct net_device *netdev_get_by_name(struct net *net, const char *name,
				      netdevice_tracker *tracker, gfp_t gfp);
struct net_device *netdev_get_by_flags_rcu(struct net *net, netdevice_tracker *tracker,
					   unsigned short flags, unsigned short mask);
struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex);
void netdev_copy_name(struct net_device *dev, char *name);

+6 −5
Original line number Diff line number Diff line
@@ -1267,8 +1267,9 @@ struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type)
EXPORT_SYMBOL(dev_getfirstbyhwtype);

/**
 * dev_get_by_flags_rcu - find any device with given flags
 * netdev_get_by_flags_rcu - find any device with given flags
 * @net: the applicable net namespace
 * @tracker: tracking object for the acquired reference
 * @if_flags: IFF_* values
 * @mask: bitmask of bits in if_flags to check
 *
@@ -1277,21 +1278,21 @@ EXPORT_SYMBOL(dev_getfirstbyhwtype);
 * Context: rcu_read_lock() must be held.
 * Returns: NULL if a device is not found or a pointer to the device.
 */
struct net_device *dev_get_by_flags_rcu(struct net *net, unsigned short if_flags,
					unsigned short mask)
struct net_device *netdev_get_by_flags_rcu(struct net *net, netdevice_tracker *tracker,
					   unsigned short if_flags, unsigned short mask)
{
	struct net_device *dev;

	for_each_netdev_rcu(net, dev) {
		if (((READ_ONCE(dev->flags) ^ if_flags) & mask) == 0) {
			dev_hold(dev);
			netdev_hold(dev, tracker, GFP_ATOMIC);
			return dev;
		}
	}

	return NULL;
}
EXPORT_IPV6_MOD(dev_get_by_flags_rcu);
EXPORT_IPV6_MOD(netdev_get_by_flags_rcu);

/**
 *	dev_valid_name - check if name is okay for network device
+6 −5
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct ipv6_ac_socklist *pac = NULL;
	struct net *net = sock_net(sk);
	netdevice_tracker dev_tracker;
	struct net_device *dev = NULL;
	struct inet6_dev *idev;
	int err = 0, ishost;
@@ -79,7 +80,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
		return -EINVAL;

	if (ifindex)
		dev = dev_get_by_index(net, ifindex);
		dev = netdev_get_by_index(net, ifindex, &dev_tracker, GFP_KERNEL);

	if (ipv6_chk_addr_and_flags(net, addr, dev, true, 0, IFA_F_TENTATIVE)) {
		err = -EINVAL;
@@ -104,7 +105,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
		rt = rt6_lookup(net, addr, NULL, 0, NULL, 0);
		if (rt) {
			dev = dst_dev(&rt->dst);
			dev_hold(dev);
			netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
			ip6_rt_put(rt);
		} else if (ishost) {
			rcu_read_unlock();
@@ -112,7 +113,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
			goto error;
		} else {
			/* router, no matching interface: just pick one */
			dev = dev_get_by_flags_rcu(net, IFF_UP,
			dev = netdev_get_by_flags_rcu(net, &dev_tracker, IFF_UP,
						      IFF_UP | IFF_LOOPBACK);
		}
		rcu_read_unlock();
@@ -159,7 +160,7 @@ int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
error_idev:
	in6_dev_put(idev);
error:
	dev_put(dev);
	netdev_put(dev, &dev_tracker);

	if (pac)
		sock_kfree_s(sk, pac, sizeof(*pac));