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

Commit 6767cbd7 authored by Paolo Abeni's avatar Paolo Abeni Committed by Subash Abhinov Kasiviswanathan
Browse files

udp6: set rx_dst_cookie on rx_dst updates



Currently, in the udp6 code, the dst cookie is not initialized/updated
concurrently with the RX dst used by early demux.

As a result, the dst_check() in the early_demux path always fails,
the rx dst cache is always invalidated, and we can't really
leverage significant gain from the demux lookup.

Fix it adding udp6 specific variant of sk_rx_dst_set() and use it
to set the dst cookie when the dst entry is really changed.

The issue is there since the introduction of early demux for ipv6.

CRs-Fixed: 2122802
Change-Id: I607ee86f4b53dd422dda81d88fdfb03a73647676
Fixes: 5425077d73e0 ("net: ipv6: Add early demux handler for UDP unicast")
Acked-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Git-commit: 64f0f5d18a47c703c85576375cc010e83dac6a48
Git-repo: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git


Signed-off-by: default avatarSubash Abhinov Kasiviswanathan <subashab@codeaurora.org>
parent 18fb43b4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -247,7 +247,7 @@ static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb,

/* net/ipv4/udp.c */
void udp_v4_early_demux(struct sk_buff *skb);
void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst);
bool udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst);
int udp_get_port(struct sock *sk, unsigned short snum,
		 int (*saddr_cmp)(const struct sock *,
				  const struct sock *));
+3 −1
Original line number Diff line number Diff line
@@ -1627,14 +1627,16 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
/* For TCP sockets, sk_rx_dst is protected by socket lock
 * For UDP, we use xchg() to guard against concurrent changes.
 */
void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
bool udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
{
	struct dst_entry *old;

	if (dst_hold_safe(dst)) {
		old = xchg(&sk->sk_rx_dst, dst);
		dst_release(old);
		return old != dst;
	}
	return false;
}
EXPORT_SYMBOL(udp_sk_rx_dst_set);

+10 −1
Original line number Diff line number Diff line
@@ -754,6 +754,15 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
	return 0;
}

static void udp6_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst)
{
	if (udp_sk_rx_dst_set(sk, dst)) {
		const struct rt6_info *rt = (const struct rt6_info *)dst;

		inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt);
	}
}

int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
		   int proto)
{
@@ -803,7 +812,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
		int ret;

		if (unlikely(sk->sk_rx_dst != dst))
			udp_sk_rx_dst_set(sk, dst);
			udp6_sk_rx_dst_set(sk, dst);

		ret = udpv6_queue_rcv_skb(sk, skb);
		sock_put(sk);