Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a2496350 authored by Stephen Suryaputra's avatar Stephen Suryaputra Committed by Greg Kroah-Hartman
Browse files

vrf: Increment Icmp6InMsgs on the original netdev

[ Upstream commit e1ae5c2ea4783b1fd87be250f9fcc9d9e1a6ba3f ]

Get the ingress interface and increment ICMP counters based on that
instead of skb->dev when the the dev is a VRF device.

This is a follow up on the following message:
https://www.spinics.net/lists/netdev/msg560268.html



v2: Avoid changing skb->dev since it has unintended effect for local
    delivery (David Ahern).
Signed-off-by: default avatarStephen Suryaputra <ssuryaextr@gmail.com>
Reviewed-by: default avatarDavid Ahern <dsahern@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Stable-dep-of: 2aaa8a15de73 ("icmp6: Fix null-ptr-deref of ip6_null_entry->rt6i_idev in icmp6_dev().")
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent fad83822
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -340,6 +340,22 @@ static inline struct inet6_dev *__in6_dev_get(const struct net_device *dev)
	return rcu_dereference_rtnl(dev->ip6_ptr);
}

/**
 * __in6_dev_stats_get - get inet6_dev pointer for stats
 * @dev: network device
 * @skb: skb for original incoming interface if neeeded
 *
 * Caller must hold rcu_read_lock or RTNL, because this function
 * does not take a reference on the inet6_dev.
 */
static inline struct inet6_dev *__in6_dev_stats_get(const struct net_device *dev,
						    const struct sk_buff *skb)
{
	if (netif_is_l3_master(dev))
		dev = dev_get_by_index_rcu(dev_net(dev), inet6_iif(skb));
	return __in6_dev_get(dev);
}

/**
 * __in6_dev_get_safely - get inet6_dev pointer from netdevice
 * @dev: network device
+11 −6
Original line number Diff line number Diff line
@@ -395,23 +395,28 @@ static struct dst_entry *icmpv6_route_lookup(struct net *net,
	return ERR_PTR(err);
}

static int icmp6_iif(const struct sk_buff *skb)
static struct net_device *icmp6_dev(const struct sk_buff *skb)
{
	int iif = skb->dev->ifindex;
	struct net_device *dev = skb->dev;

	/* for local traffic to local address, skb dev is the loopback
	 * device. Check if there is a dst attached to the skb and if so
	 * get the real device index. Same is needed for replies to a link
	 * local address on a device enslaved to an L3 master device
	 */
	if (unlikely(iif == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
	if (unlikely(dev->ifindex == LOOPBACK_IFINDEX || netif_is_l3_master(skb->dev))) {
		const struct rt6_info *rt6 = skb_rt6_info(skb);

		if (rt6)
			iif = rt6->rt6i_idev->dev->ifindex;
			dev = rt6->rt6i_idev->dev;
	}

	return iif;
	return dev;
}

static int icmp6_iif(const struct sk_buff *skb)
{
	return icmp6_dev(skb)->ifindex;
}

/*
@@ -800,7 +805,7 @@ void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info)
static int icmpv6_rcv(struct sk_buff *skb)
{
	struct net *net = dev_net(skb->dev);
	struct net_device *dev = skb->dev;
	struct net_device *dev = icmp6_dev(skb);
	struct inet6_dev *idev = __in6_dev_get(dev);
	const struct in6_addr *saddr, *daddr;
	struct icmp6hdr *hdr;
+2 −2
Original line number Diff line number Diff line
@@ -302,7 +302,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
			   skb_network_header_len(skb));

	rcu_read_lock();
	__IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
	__IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMOKS);
	rcu_read_unlock();
	fq->q.fragments = NULL;
	fq->q.rb_fragments = RB_ROOT;
@@ -317,7 +317,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *skb,
	net_dbg_ratelimited("ip6_frag_reasm: no memory for reassembly\n");
out_fail:
	rcu_read_lock();
	__IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
	__IP6_INC_STATS(net, __in6_dev_stats_get(dev, skb), IPSTATS_MIB_REASMFAILS);
	rcu_read_unlock();
	inet_frag_kill(&fq->q);
	return -1;