lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251112072720.5076-7-mmietus97@yahoo.com>
Date: Wed, 12 Nov 2025 08:27:12 +0100
From: Marek Mietus <mmietus97@...oo.com>
To: netdev@...r.kernel.org,
	sd@...asysnail.net,
	kuba@...nel.org
Cc: Marek Mietus <mmietus97@...oo.com>
Subject: [PATCH net-next v4 06/14] net: tunnel: return dstref in udp_tunnel{,6}_dst_lookup

Update udp_tunnel{,6}_dst_lookup to return a dstref instead of
dst_entry/rtable. The returned dstref is only valid inside the RCU
read-side critical section in which it was queried. Update all callers
to take that into account.

VXLAN had one unique dst access (in vxlan_xmit_one) that was outside
of RCU, so that line had to be moved.

Signed-off-by: Marek Mietus <mmietus97@...oo.com>
---
 drivers/net/bareudp.c          | 63 +++++++++++++-----------
 drivers/net/geneve.c           | 90 ++++++++++++++++++----------------
 drivers/net/vxlan/vxlan_core.c | 80 +++++++++++++++---------------
 include/net/udp_tunnel.h       |  8 +--
 net/ipv4/udp_tunnel_core.c     | 27 +++++-----
 net/ipv6/ip6_udp_tunnel.c      | 37 ++++++++------
 6 files changed, 164 insertions(+), 141 deletions(-)

diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index 813866cd04db..12408ee37b3c 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -313,6 +313,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	struct rtable *rt;
 	__be16 sport, df;
 	int min_headroom;
+	dstref_t dstref;
 	__u8 tos, ttl;
 	__be32 saddr;
 	int err;
@@ -326,13 +327,15 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	sport = udp_flow_src_port(bareudp->net, skb,
 				  bareudp->sport_min, USHRT_MAX,
 				  true);
-	rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, &info->key,
-				   sport, bareudp->port, key->tos,
-				   use_cache ?
-				   (struct dst_cache *)&info->dst_cache : NULL);
+	err = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr, &info->key,
+				    sport, bareudp->port, key->tos,
+				    use_cache ?
+				    (struct dst_cache *)&info->dst_cache : NULL, &dstref);
 
-	if (IS_ERR(rt))
-		return PTR_ERR(rt);
+	if (err)
+		return err;
+
+	rt = dst_rtable(dstref_dst(dstref));
 
 	skb_tunnel_check_pmtu(skb, &rt->dst,
 			      BAREUDP_IPV4_HLEN + info->options_len, false);
@@ -359,7 +362,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 		goto free_dst;
 
 	skb_set_inner_protocol(skb, bareudp->ethertype);
-	udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock->sk, skb, saddr, info->key.u.ipv4.dst,
+	udp_tunnel_xmit_skb(dstref, sock->sk, skb, saddr, info->key.u.ipv4.dst,
 			    tos, ttl, df, sport, bareudp->port,
 			    !net_eq(bareudp->net, dev_net(bareudp->dev)),
 			    !test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags),
@@ -367,7 +370,7 @@ static int bareudp_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	return 0;
 
 free_dst:
-	dst_release(&rt->dst);
+	dstref_drop(dstref);
 	return err;
 }
 
@@ -383,6 +386,7 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	struct dst_entry *dst = NULL;
 	struct in6_addr saddr, daddr;
 	int min_headroom;
+	dstref_t dstref;
 	__u8 prio, ttl;
 	__be16 sport;
 	int err;
@@ -396,12 +400,15 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	sport = udp_flow_src_port(bareudp->net, skb,
 				  bareudp->sport_min, USHRT_MAX,
 				  true);
-	dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, 0, &saddr,
+	err = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, 0, &saddr,
 				     key, sport, bareudp->port, key->tos,
 				     use_cache ?
-				     (struct dst_cache *) &info->dst_cache : NULL);
-	if (IS_ERR(dst))
-		return PTR_ERR(dst);
+				     (struct dst_cache *)&info->dst_cache : NULL, &dstref);
+
+	if (err)
+		return err;
+
+	dst = dstref_dst(dstref);
 
 	skb_tunnel_check_pmtu(skb, dst, BAREUDP_IPV6_HLEN + info->options_len,
 			      false);
@@ -427,7 +434,7 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 		goto free_dst;
 
 	daddr = info->key.u.ipv6.dst;
-	udp_tunnel6_xmit_skb(dst_to_dstref(dst), sock->sk, skb, dev,
+	udp_tunnel6_xmit_skb(dstref, sock->sk, skb, dev,
 			     &saddr, &daddr, prio, ttl,
 			     info->key.label, sport, bareudp->port,
 			     !test_bit(IP_TUNNEL_CSUM_BIT,
@@ -436,7 +443,7 @@ static int bareudp6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	return 0;
 
 free_dst:
-	dst_release(dst);
+	dstref_drop(dstref);
 	return err;
 }
 
@@ -503,8 +510,10 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,
 {
 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
 	struct bareudp_dev *bareudp = netdev_priv(dev);
+	dstref_t dstref;
 	bool use_cache;
 	__be16 sport;
+	int err;
 
 	use_cache = ip_tunnel_dst_cache_usable(skb, info);
 	sport = udp_flow_src_port(bareudp->net, skb,
@@ -512,31 +521,29 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,
 				  true);
 
 	if (!ipv6_mod_enabled() || ip_tunnel_info_af(info) == AF_INET) {
-		struct rtable *rt;
 		__be32 saddr;
 
-		rt = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr,
-					   &info->key, sport, bareudp->port,
-					   info->key.tos,
-					   use_cache ? &info->dst_cache : NULL);
-		if (IS_ERR(rt))
-			return PTR_ERR(rt);
+		err = udp_tunnel_dst_lookup(skb, dev, bareudp->net, 0, &saddr,
+					    &info->key, sport, bareudp->port,
+					    info->key.tos,
+					    use_cache ? &info->dst_cache : NULL, &dstref);
+		if (err)
+			return err;
 
-		ip_rt_put(rt);
+		dstref_drop(dstref);
 		info->key.u.ipv4.src = saddr;
 	} else if (ip_tunnel_info_af(info) == AF_INET6) {
-		struct dst_entry *dst;
 		struct in6_addr saddr;
 		struct socket *sock = rcu_dereference(bareudp->sock);
 
-		dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock,
+		err = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock,
 					     0, &saddr, &info->key,
 					     sport, bareudp->port, info->key.tos,
-					     use_cache ? &info->dst_cache : NULL);
-		if (IS_ERR(dst))
-			return PTR_ERR(dst);
+					     use_cache ? &info->dst_cache : NULL, &dstref);
+		if (err)
+			return err;
 
-		dst_release(dst);
+		dstref_drop(dstref);
 		info->key.u.ipv6.src = saddr;
 	} else {
 		return -EINVAL;
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 0c7949c0561f..0c307fad4f69 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -766,12 +766,13 @@ static void geneve_build_header(struct genevehdr *geneveh,
 		ip_tunnel_info_opts_get(geneveh->options, info);
 }
 
-static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
+static int geneve_build_skb(dstref_t dstref, struct sk_buff *skb,
 			    const struct ip_tunnel_info *info,
 			    bool xnet, int ip_hdr_len,
 			    bool inner_proto_inherit)
 {
 	bool udp_sum = test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags);
+	struct dst_entry *dst = dstref_dst(dstref);
 	struct genevehdr *gnvh;
 	__be16 inner_proto;
 	int min_headroom;
@@ -797,7 +798,7 @@ static int geneve_build_skb(struct dst_entry *dst, struct sk_buff *skb,
 	return 0;
 
 free_dst:
-	dst_release(dst);
+	dstref_drop(dstref);
 	return err;
 }
 
@@ -826,6 +827,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
 	const struct ip_tunnel_key *key = &info->key;
 	struct rtable *rt;
+	dstref_t dstref;
 	bool use_cache;
 	__u8 tos, ttl;
 	__be16 df = 0;
@@ -845,19 +847,21 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 				  geneve->cfg.port_min,
 				  geneve->cfg.port_max, true);
 
-	rt = udp_tunnel_dst_lookup(skb, dev, geneve->net, 0, &saddr,
-				   &info->key,
-				   sport, geneve->cfg.info.key.tp_dst, tos,
-				   use_cache ?
-				   (struct dst_cache *)&info->dst_cache : NULL);
-	if (IS_ERR(rt))
-		return PTR_ERR(rt);
+	err = udp_tunnel_dst_lookup(skb, dev, geneve->net, 0, &saddr,
+				    &info->key,
+				    sport, geneve->cfg.info.key.tp_dst, tos,
+				    use_cache ?
+				    (struct dst_cache *)&info->dst_cache : NULL, &dstref);
+	if (err)
+		return err;
+
+	rt = dst_rtable(dstref_dst(dstref));
 
 	err = skb_tunnel_check_pmtu(skb, &rt->dst,
 				    GENEVE_IPV4_HLEN + info->options_len,
 				    netif_is_any_bridge_port(dev));
 	if (err < 0) {
-		dst_release(&rt->dst);
+		dstref_drop(dstref);
 		return err;
 	} else if (err) {
 		struct ip_tunnel_info *info;
@@ -868,7 +872,7 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 
 			unclone = skb_tunnel_info_unclone(skb);
 			if (unlikely(!unclone)) {
-				dst_release(&rt->dst);
+				dstref_drop(dstref);
 				return -ENOMEM;
 			}
 
@@ -877,13 +881,13 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 		}
 
 		if (!pskb_may_pull(skb, ETH_HLEN)) {
-			dst_release(&rt->dst);
+			dstref_drop(dstref);
 			return -EINVAL;
 		}
 
 		skb->protocol = eth_type_trans(skb, geneve->dev);
 		__netif_rx(skb);
-		dst_release(&rt->dst);
+		dstref_drop(dstref);
 		return -EMSGSIZE;
 	}
 
@@ -916,14 +920,13 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 		}
 	}
 
-	err = geneve_build_skb(&rt->dst, skb, info, xnet, sizeof(struct iphdr),
+	err = geneve_build_skb(dstref, skb, info, xnet, sizeof(struct iphdr),
 			       inner_proto_inherit);
 	if (unlikely(err))
 		return err;
 
-	udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), gs4->sock->sk, skb, saddr,
-			    info->key.u.ipv4.dst, tos, ttl, df, sport,
-			    geneve->cfg.info.key.tp_dst,
+	udp_tunnel_xmit_skb(dstref, gs4->sock->sk, skb, saddr, info->key.u.ipv4.dst,
+			    tos, ttl, df, sport, geneve->cfg.info.key.tp_dst,
 			    !net_eq(geneve->net, dev_net(geneve->dev)),
 			    !test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags),
 			    0);
@@ -941,6 +944,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 	const struct ip_tunnel_key *key = &info->key;
 	struct dst_entry *dst = NULL;
 	struct in6_addr saddr;
+	dstref_t dstref;
 	bool use_cache;
 	__u8 prio, ttl;
 	__be16 sport;
@@ -958,19 +962,21 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 				  geneve->cfg.port_min,
 				  geneve->cfg.port_max, true);
 
-	dst = udp_tunnel6_dst_lookup(skb, dev, geneve->net, gs6->sock, 0,
+	err = udp_tunnel6_dst_lookup(skb, dev, geneve->net, gs6->sock, 0,
 				     &saddr, key, sport,
 				     geneve->cfg.info.key.tp_dst, prio,
 				     use_cache ?
-				     (struct dst_cache *)&info->dst_cache : NULL);
-	if (IS_ERR(dst))
-		return PTR_ERR(dst);
+				     (struct dst_cache *)&info->dst_cache : NULL, &dstref);
+	if (err)
+		return err;
+
+	dst = dstref_dst(dstref);
 
 	err = skb_tunnel_check_pmtu(skb, dst,
 				    GENEVE_IPV6_HLEN + info->options_len,
 				    netif_is_any_bridge_port(dev));
 	if (err < 0) {
-		dst_release(dst);
+		dstref_drop(dstref);
 		return err;
 	} else if (err) {
 		struct ip_tunnel_info *info = skb_tunnel_info(skb);
@@ -980,7 +986,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 
 			unclone = skb_tunnel_info_unclone(skb);
 			if (unlikely(!unclone)) {
-				dst_release(dst);
+				dstref_drop(dstref);
 				return -ENOMEM;
 			}
 
@@ -989,13 +995,13 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 		}
 
 		if (!pskb_may_pull(skb, ETH_HLEN)) {
-			dst_release(dst);
+			dstref_drop(dstref);
 			return -EINVAL;
 		}
 
 		skb->protocol = eth_type_trans(skb, geneve->dev);
 		__netif_rx(skb);
-		dst_release(dst);
+		dstref_drop(dstref);
 		return -EMSGSIZE;
 	}
 
@@ -1009,12 +1015,12 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
 			ttl = key->ttl;
 		ttl = ttl ? : ip6_dst_hoplimit(dst);
 	}
-	err = geneve_build_skb(dst, skb, info, xnet, sizeof(struct ipv6hdr),
+	err = geneve_build_skb(dstref, skb, info, xnet, sizeof(struct ipv6hdr),
 			       inner_proto_inherit);
 	if (unlikely(err))
 		return err;
 
-	udp_tunnel6_xmit_skb(dst_to_dstref(dst), gs6->sock->sk, skb, dev,
+	udp_tunnel6_xmit_skb(dstref, gs6->sock->sk, skb, dev,
 			     &saddr, &key->u.ipv6.dst, prio, ttl,
 			     info->key.label, sport, geneve->cfg.info.key.tp_dst,
 			     !test_bit(IP_TUNNEL_CSUM_BIT,
@@ -1081,10 +1087,11 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 {
 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
 	struct geneve_dev *geneve = netdev_priv(dev);
+	dstref_t dstref;
 	__be16 sport;
+	int err;
 
 	if (ip_tunnel_info_af(info) == AF_INET) {
-		struct rtable *rt;
 		struct geneve_sock *gs4 = rcu_dereference(geneve->sock4);
 		bool use_cache;
 		__be32 saddr;
@@ -1099,19 +1106,18 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 					  geneve->cfg.port_min,
 					  geneve->cfg.port_max, true);
 
-		rt = udp_tunnel_dst_lookup(skb, dev, geneve->net, 0, &saddr,
-					   &info->key,
-					   sport, geneve->cfg.info.key.tp_dst,
-					   tos,
-					   use_cache ? &info->dst_cache : NULL);
-		if (IS_ERR(rt))
-			return PTR_ERR(rt);
+		err = udp_tunnel_dst_lookup(skb, dev, geneve->net, 0, &saddr,
+					    &info->key,
+					    sport, geneve->cfg.info.key.tp_dst,
+					    tos,
+					    use_cache ? &info->dst_cache : NULL, &dstref);
+		if (err)
+			return err;
 
-		ip_rt_put(rt);
+		dstref_drop(dstref);
 		info->key.u.ipv4.src = saddr;
 #if IS_ENABLED(CONFIG_IPV6)
 	} else if (ip_tunnel_info_af(info) == AF_INET6) {
-		struct dst_entry *dst;
 		struct geneve_sock *gs6 = rcu_dereference(geneve->sock6);
 		struct in6_addr saddr;
 		bool use_cache;
@@ -1126,14 +1132,14 @@ static int geneve_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 					  geneve->cfg.port_min,
 					  geneve->cfg.port_max, true);
 
-		dst = udp_tunnel6_dst_lookup(skb, dev, geneve->net, gs6->sock, 0,
+		err = udp_tunnel6_dst_lookup(skb, dev, geneve->net, gs6->sock, 0,
 					     &saddr, &info->key, sport,
 					     geneve->cfg.info.key.tp_dst, prio,
-					     use_cache ? &info->dst_cache : NULL);
-		if (IS_ERR(dst))
-			return PTR_ERR(dst);
+					     use_cache ? &info->dst_cache : NULL, &dstref);
+		if (err)
+			return err;
 
-		dst_release(dst);
+		dstref_drop(dstref);
 		info->key.u.ipv6.src = saddr;
 #endif
 	} else {
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index 78e5a3393b48..02ccf60d854a 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2297,7 +2297,7 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev,
 				 struct vxlan_dev *vxlan,
 				 int addr_family,
 				 __be16 dst_port, int dst_ifindex, __be32 vni,
-				 struct dst_entry *dst,
+				 dstref_t dstref,
 				 u32 rt_flags)
 {
 #if IS_ENABLED(CONFIG_IPV6)
@@ -2313,7 +2313,7 @@ static int encap_bypass_if_local(struct sk_buff *skb, struct net_device *dev,
 	    vxlan->cfg.flags & VXLAN_F_LOCALBYPASS) {
 		struct vxlan_dev *dst_vxlan;
 
-		dst_release(dst);
+		dstref_drop(dstref);
 		dst_vxlan = vxlan_find_vni(vxlan->net, dst_ifindex, vni,
 					   addr_family, dst_port,
 					   vxlan->cfg.flags);
@@ -2344,6 +2344,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 	struct vxlan_metadata _md;
 	struct vxlan_metadata *md = &_md;
 	unsigned int pkt_len = skb->len;
+	dstref_t dstref = DSTREF_EMPTY;
 	__be16 src_port = 0, dst_port;
 	struct dst_entry *ndst = NULL;
 	int addr_family;
@@ -2463,15 +2464,16 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 		if (!ifindex)
 			ifindex = sock4->sock->sk->sk_bound_dev_if;
 
-		rt = udp_tunnel_dst_lookup(skb, dev, vxlan->net, ifindex,
-					   &saddr, pkey, src_port, dst_port,
-					   tos, use_cache ? dst_cache : NULL);
-		if (IS_ERR(rt)) {
-			err = PTR_ERR(rt);
+		err = udp_tunnel_dst_lookup(skb, dev, vxlan->net, ifindex,
+					    &saddr, pkey, src_port, dst_port,
+					    tos, use_cache ? dst_cache : NULL, &dstref);
+		if (err) {
 			reason = SKB_DROP_REASON_IP_OUTNOROUTES;
 			goto tx_error;
 		}
 
+		rt = dst_rtable(dstref_dst(dstref));
+
 		if (flags & VXLAN_F_MC_ROUTE)
 			ipcb_flags |= IPSKB_MCROUTE;
 
@@ -2479,7 +2481,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 			/* Bypass encapsulation if the destination is local */
 			err = encap_bypass_if_local(skb, dev, vxlan, AF_INET,
 						    dst_port, ifindex, vni,
-						    &rt->dst, rt->rt_flags);
+						    dstref, rt->rt_flags);
 			if (err)
 				goto out_unlock;
 
@@ -2515,7 +2517,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 				unclone->key.u.ipv4.dst = saddr;
 			}
 			vxlan_encap_bypass(skb, vxlan, vxlan, vni, false);
-			dst_release(ndst);
+			dstref_drop(dstref);
 			goto out_unlock;
 		}
 
@@ -2528,7 +2530,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 			goto tx_error;
 		}
 
-		udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock4->sock->sk, skb, saddr,
+		udp_tunnel_xmit_skb(dstref, sock4->sock->sk, skb, saddr,
 				    pkey->u.ipv4.dst, tos, ttl, df,
 				    src_port, dst_port, xnet, !udp_sum,
 				    ipcb_flags);
@@ -2541,17 +2543,17 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 		if (!ifindex)
 			ifindex = sock6->sock->sk->sk_bound_dev_if;
 
-		ndst = udp_tunnel6_dst_lookup(skb, dev, vxlan->net, sock6->sock,
-					      ifindex, &saddr, pkey,
-					      src_port, dst_port, tos,
-					      use_cache ? dst_cache : NULL);
-		if (IS_ERR(ndst)) {
-			err = PTR_ERR(ndst);
-			ndst = NULL;
+		err = udp_tunnel6_dst_lookup(skb, dev, vxlan->net, sock6->sock,
+					     ifindex, &saddr, pkey,
+					     src_port, dst_port, tos,
+					     use_cache ? dst_cache : NULL, &dstref);
+		if (err) {
 			reason = SKB_DROP_REASON_IP_OUTNOROUTES;
 			goto tx_error;
 		}
 
+		ndst = dstref_dst(dstref);
+
 		if (flags & VXLAN_F_MC_ROUTE)
 			ip6cb_flags |= IP6SKB_MCROUTE;
 
@@ -2560,7 +2562,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 
 			err = encap_bypass_if_local(skb, dev, vxlan, AF_INET6,
 						    dst_port, ifindex, vni,
-						    ndst, rt6i_flags);
+						    dstref, rt6i_flags);
 			if (err)
 				goto out_unlock;
 		}
@@ -2583,7 +2585,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 			}
 
 			vxlan_encap_bypass(skb, vxlan, vxlan, vni, false);
-			dst_release(ndst);
+			dstref_drop(dstref);
 			goto out_unlock;
 		}
 
@@ -2597,7 +2599,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 			goto tx_error;
 		}
 
-		udp_tunnel6_xmit_skb(dst_to_dstref(ndst), sock6->sock->sk, skb, dev,
+		udp_tunnel6_xmit_skb(dstref, sock6->sock->sk, skb, dev,
 				     &saddr, &pkey->u.ipv6.dst, tos, ttl,
 				     pkey->label, src_port, dst_port, !udp_sum,
 				     ip6cb_flags);
@@ -2615,12 +2617,12 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
 	return;
 
 tx_error:
+	dstref_drop(dstref);
 	rcu_read_unlock();
 	if (err == -ELOOP)
 		DEV_STATS_INC(dev, collisions);
 	else if (err == -ENETUNREACH)
 		DEV_STATS_INC(dev, tx_carrier_errors);
-	dst_release(ndst);
 	DEV_STATS_INC(dev, tx_errors);
 	vxlan_vnifilter_count(vxlan, vni, NULL, VXLAN_VNI_STATS_TX_ERRORS, 0);
 	kfree_skb_reason(skb, reason);
@@ -3208,6 +3210,8 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 	struct vxlan_dev *vxlan = netdev_priv(dev);
 	struct ip_tunnel_info *info = skb_tunnel_info(skb);
 	__be16 sport, dport;
+	dstref_t dstref;
+	int err;
 
 	sport = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min,
 				  vxlan->cfg.port_max, true);
@@ -3215,35 +3219,33 @@ static int vxlan_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb)
 
 	if (ip_tunnel_info_af(info) == AF_INET) {
 		struct vxlan_sock *sock4 = rcu_dereference(vxlan->vn4_sock);
-		struct rtable *rt;
 
 		if (!sock4)
 			return -EIO;
 
-		rt = udp_tunnel_dst_lookup(skb, dev, vxlan->net, 0,
-					   &info->key.u.ipv4.src,
-					   &info->key,
-					   sport, dport, info->key.tos,
-					   &info->dst_cache);
-		if (IS_ERR(rt))
-			return PTR_ERR(rt);
-		ip_rt_put(rt);
+		err = udp_tunnel_dst_lookup(skb, dev, vxlan->net, 0,
+					    &info->key.u.ipv4.src,
+					    &info->key,
+					    sport, dport, info->key.tos,
+					    &info->dst_cache, &dstref);
+		if (err)
+			return err;
+		dstref_drop(dstref);
 	} else {
 #if IS_ENABLED(CONFIG_IPV6)
 		struct vxlan_sock *sock6 = rcu_dereference(vxlan->vn6_sock);
-		struct dst_entry *ndst;
 
 		if (!sock6)
 			return -EIO;
 
-		ndst = udp_tunnel6_dst_lookup(skb, dev, vxlan->net, sock6->sock,
-					      0, &info->key.u.ipv6.src,
-					      &info->key,
-					      sport, dport, info->key.tos,
-					      &info->dst_cache);
-		if (IS_ERR(ndst))
-			return PTR_ERR(ndst);
-		dst_release(ndst);
+		err = udp_tunnel6_dst_lookup(skb, dev, vxlan->net, sock6->sock,
+					     0, &info->key.u.ipv6.src,
+					     &info->key,
+					     sport, dport, info->key.tos,
+					     &info->dst_cache, &dstref);
+		if (err)
+			return err;
+		dstref_drop(dstref);
 #else /* !CONFIG_IPV6 */
 		return -EPFNOSUPPORT;
 #endif
diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
index b47e997be7f4..72f33139426a 100644
--- a/include/net/udp_tunnel.h
+++ b/include/net/udp_tunnel.h
@@ -147,21 +147,21 @@ void udp_tunnel6_xmit_skb(dstref_t dstref, struct sock *sk,
 
 void udp_tunnel_sock_release(struct socket *sock);
 
-struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb,
+int udp_tunnel_dst_lookup(struct sk_buff *skb,
 				     struct net_device *dev,
 				     struct net *net, int oif,
 				     __be32 *saddr,
 				     const struct ip_tunnel_key *key,
 				     __be16 sport, __be16 dport, u8 tos,
-				     struct dst_cache *dst_cache);
-struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb,
+				     struct dst_cache *dst_cache, dstref_t *dstref);
+int udp_tunnel6_dst_lookup(struct sk_buff *skb,
 					 struct net_device *dev,
 					 struct net *net,
 					 struct socket *sock, int oif,
 					 struct in6_addr *saddr,
 					 const struct ip_tunnel_key *key,
 					 __be16 sport, __be16 dport, u8 dsfield,
-					 struct dst_cache *dst_cache);
+					 struct dst_cache *dst_cache, dstref_t *dstref);
 
 struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family,
 				    const unsigned long *flags,
diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
index e298861e005d..fdfa5420f9bf 100644
--- a/net/ipv4/udp_tunnel_core.c
+++ b/net/ipv4/udp_tunnel_core.c
@@ -227,13 +227,13 @@ struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb,  unsigned short family,
 }
 EXPORT_SYMBOL_GPL(udp_tun_rx_dst);
 
-struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb,
-				     struct net_device *dev,
-				     struct net *net, int oif,
-				     __be32 *saddr,
-				     const struct ip_tunnel_key *key,
-				     __be16 sport, __be16 dport, u8 tos,
-				     struct dst_cache *dst_cache)
+int udp_tunnel_dst_lookup(struct sk_buff *skb,
+			  struct net_device *dev,
+			  struct net *net, int oif,
+			  __be32 *saddr,
+			  const struct ip_tunnel_key *key,
+			  __be16 sport, __be16 dport, u8 tos,
+			  struct dst_cache *dst_cache, dstref_t *dstref)
 {
 	struct rtable *rt = NULL;
 	struct flowi4 fl4;
@@ -241,8 +241,10 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb,
 #ifdef CONFIG_DST_CACHE
 	if (dst_cache) {
 		rt = dst_cache_get_ip4(dst_cache, saddr);
-		if (rt)
-			return rt;
+		if (rt) {
+			*dstref = dst_to_dstref(&rt->dst);
+			return 0;
+		}
 	}
 #endif
 
@@ -260,19 +262,20 @@ struct rtable *udp_tunnel_dst_lookup(struct sk_buff *skb,
 	rt = ip_route_output_key(net, &fl4);
 	if (IS_ERR(rt)) {
 		netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr);
-		return ERR_PTR(-ENETUNREACH);
+		return -ENETUNREACH;
 	}
 	if (rt->dst.dev == dev) { /* is this necessary? */
 		netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr);
 		ip_rt_put(rt);
-		return ERR_PTR(-ELOOP);
+		return -ELOOP;
 	}
 #ifdef CONFIG_DST_CACHE
 	if (dst_cache)
 		dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr);
 #endif
 	*saddr = fl4.saddr;
-	return rt;
+	*dstref = dst_to_dstref(&rt->dst);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(udp_tunnel_dst_lookup);
 
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
index 5b6083a27afb..ec7bf7d744fe 100644
--- a/net/ipv6/ip6_udp_tunnel.c
+++ b/net/ipv6/ip6_udp_tunnel.c
@@ -126,21 +126,23 @@ EXPORT_SYMBOL_GPL(udp_tunnel6_xmit_skb);
  *      @dport: UDP destination port
  *      @dsfield: The traffic class field
  *      @dst_cache: The dst cache to use for lookup
+ *      @dstref: Memory to store the dstref object returned from the lookup
  *      This function performs a route lookup on a UDP tunnel
  *
- *      It returns a valid dst pointer and stores src address to be used in
- *      tunnel in param saddr on success, else a pointer encoded error code.
+ *      On success, it stores the dstref object that represents the result of the lookup
+ *      in the dstref param, and the src address to be used for the tunnel in the saddr param.
+ *
+ *      Returns: 0 on success, negative error code on failure
  */
 
-struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb,
-					 struct net_device *dev,
-					 struct net *net,
-					 struct socket *sock,
-					 int oif,
-					 struct in6_addr *saddr,
-					 const struct ip_tunnel_key *key,
-					 __be16 sport, __be16 dport, u8 dsfield,
-					 struct dst_cache *dst_cache)
+int udp_tunnel6_dst_lookup(struct sk_buff *skb,
+			   struct net_device *dev,
+			   struct net *net,
+			   struct socket *sock, int oif,
+			   struct in6_addr *saddr,
+			   const struct ip_tunnel_key *key,
+			   __be16 sport, __be16 dport, u8 dsfield,
+			   struct dst_cache *dst_cache, dstref_t *dstref)
 {
 	struct dst_entry *dst = NULL;
 	struct flowi6 fl6;
@@ -148,8 +150,10 @@ struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb,
 #ifdef CONFIG_DST_CACHE
 	if (dst_cache) {
 		dst = dst_cache_get_ip6(dst_cache, saddr);
-		if (dst)
-			return dst;
+		if (dst) {
+			*dstref = dst_to_dstref(dst);
+			return 0;
+		}
 	}
 #endif
 	memset(&fl6, 0, sizeof(fl6));
@@ -166,19 +170,20 @@ struct dst_entry *udp_tunnel6_dst_lookup(struct sk_buff *skb,
 					      NULL);
 	if (IS_ERR(dst)) {
 		netdev_dbg(dev, "no route to %pI6\n", &fl6.daddr);
-		return ERR_PTR(-ENETUNREACH);
+		return -ENETUNREACH;
 	}
 	if (dst_dev(dst) == dev) { /* is this necessary? */
 		netdev_dbg(dev, "circular route to %pI6\n", &fl6.daddr);
 		dst_release(dst);
-		return ERR_PTR(-ELOOP);
+		return -ELOOP;
 	}
 #ifdef CONFIG_DST_CACHE
 	if (dst_cache)
 		dst_cache_set_ip6(dst_cache, dst, &fl6.saddr);
 #endif
 	*saddr = fl6.saddr;
-	return dst;
+	*dstref = dst_to_dstref(dst);
+	return 0;
 }
 EXPORT_SYMBOL_GPL(udp_tunnel6_dst_lookup);
 
-- 
2.51.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ