Commit 46a94e44 authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski
Browse files

ipv6: ip6_mc_input() and ip6_mr_input() cleanups



Both functions are always called under RCU.

We remove the extra rcu_read_lock()/rcu_read_unlock().

We use skb_dst_dev_net_rcu() instead of skb_dst_dev_net().

We use dev_net_rcu() instead of dev_net().

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reviewed-by: default avatarKuniyuki Iwashima <kuniyu@google.com>
Link: https://patch.msgid.link/20250630121934.3399505-11-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 93d1cff3
Loading
Loading
Loading
Loading
+11 −18
Original line number Diff line number Diff line
@@ -501,38 +501,32 @@ EXPORT_SYMBOL_GPL(ip6_input);

int ip6_mc_input(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	int sdif = inet6_sdif(skb);
	const struct ipv6hdr *hdr;
	struct net_device *dev;
	bool deliver;

	__IP6_UPD_PO_STATS(skb_dst_dev_net(skb),
			 __in6_dev_get_safely(skb->dev), IPSTATS_MIB_INMCAST,
	__IP6_UPD_PO_STATS(skb_dst_dev_net_rcu(skb),
			   __in6_dev_get_safely(dev), IPSTATS_MIB_INMCAST,
			   skb->len);

	/* skb->dev passed may be master dev for vrfs. */
	if (sdif) {
		rcu_read_lock();
		dev = dev_get_by_index_rcu(dev_net(skb->dev), sdif);
		dev = dev_get_by_index_rcu(dev_net_rcu(dev), sdif);
		if (!dev) {
			rcu_read_unlock();
			kfree_skb(skb);
			return -ENODEV;
		}
	} else {
		dev = skb->dev;
	}

	hdr = ipv6_hdr(skb);
	deliver = ipv6_chk_mcast_addr(dev, &hdr->daddr, NULL);
	if (sdif)
		rcu_read_unlock();

#ifdef CONFIG_IPV6_MROUTE
	/*
	 *      IPv6 multicast router mode is now supported ;)
	 */
	if (atomic_read(&dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding) &&
	if (atomic_read(&dev_net_rcu(skb->dev)->ipv6.devconf_all->mc_forwarding) &&
	    !(ipv6_addr_type(&hdr->daddr) &
	      (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) &&
	    likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) {
@@ -573,22 +567,21 @@ int ip6_mc_input(struct sk_buff *skb)
			/* unknown RA - process it normally */
		}

		if (deliver)
		if (deliver) {
			skb2 = skb_clone(skb, GFP_ATOMIC);
		else {
		} else {
			skb2 = skb;
			skb = NULL;
		}

		if (skb2) {
		if (skb2)
			ip6_mr_input(skb2);
	}
	}
out:
#endif
	if (likely(deliver))
	if (likely(deliver)) {
		ip6_input(skb);
	else {
	} else {
		/* discard */
		kfree_skb(skb);
	}
+4 −5
Original line number Diff line number Diff line
@@ -2301,21 +2301,20 @@ static void ip6_mr_output_finish(struct net *net, struct mr_table *mrt,

int ip6_mr_input(struct sk_buff *skb)
{
	struct net_device *dev = skb->dev;
	struct net *net = dev_net_rcu(dev);
	struct mfc6_cache *cache;
	struct net *net = dev_net(skb->dev);
	struct mr_table *mrt;
	struct flowi6 fl6 = {
		.flowi6_iif	= skb->dev->ifindex,
		.flowi6_iif	= dev->ifindex,
		.flowi6_mark	= skb->mark,
	};
	int err;
	struct net_device *dev;

	/* skb->dev passed in is the master dev for vrfs.
	 * Get the proper interface that does have a vif associated with it.
	 */
	dev = skb->dev;
	if (netif_is_l3_master(skb->dev)) {
	if (netif_is_l3_master(dev)) {
		dev = dev_get_by_index_rcu(net, IPCB(skb)->iif);
		if (!dev) {
			kfree_skb(skb);