* [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels
[not found] <20251112072720.5076-1-mmietus97.ref@yahoo.com>
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 01/14] net: dst: implement dstref object Marek Mietus
` (13 more replies)
0 siblings, 14 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
Currently, tunnel xmit flows always take a reference on the dst_entry
for each xmitted packet. These atomic operations are redundant in some
flows.
This patchset introduces the infrastructure required for converting
the tunnel xmit flows to noref, and converts them where possible.
A new opaque type "dstref_t" is introduced. It represents a potentially
noref pointer to a dst_entry.
This allows for noref flows while still allowing the original referenced
flows in cases where noref can't be used.
Additionally, RCU variants for dst cache helpers are introduced,
since most tunnels rely on dst cache for dst resolution.
These changes improve tunnel performance, since less atomic operations
are used.
There are already noref optimizations in both ipv4 and ip6.
(See __ip_queue_xmit, inet6_csk_xmit)
This patchset implements similar optimizations in ip and udp tunnels.
Benchmarks:
I used a vxlan tunnel over a pair of veth peers and measured the average
throughput over multiple samples.
I ran 100 samples on a clean build, and another 100 on a patched
build. Each sample ran for 120 seconds. These were my results:
clean: 70.31 mb/sec, stddev = 1.63
patched: 73.13 mb/sec, stddev = 1.28
TL;DR - This patchset results in a 4% improvement in throughput for
vxlan. It's safe to assume that we might see similar results when testing
other tunnels.
Changes in v4:
- Added the dst_cache_get_rcu function
- Implemented the dstref object and used it to implement noref xmit flows
- Converted all tunnels to use noref xmit flows
- Fixed formatting of comments in dst_cache.h
- Reworded some messages
Link to v3: https://lore.kernel.org/netdev/20250922110622.10368-1-mmietus97@yahoo.com/
Marek Mietus (14):
net: dst: implement dstref object
net: skb: use dstref for storing dst entry
net: skb: rename skb_dstref_restore to skb_dstref_set
net: dst_cache: add noref versions for dst_cache
net: tunnel: use dstref in ip and udp tunnel xmit functions
net: tunnel: return dstref in udp_tunnel{,6}_dst_lookup
net: tunnel: make udp_tunnel{,6}_dst_lookup return a noref dst
net: ovpn: convert ovpn_udp{4,6}_output to use a noref dst
net: wireguard: convert send{4,6} to use a noref dst when possible
net: tunnel: convert ip_md_tunnel_xmit to use a noref dst when
possible
net: tunnel: convert ip_tunnel_xmit to use a noref dst when possible
net: sit: convert ipip6_tunnel_xmit to use a noref dst
net: tipc: convert tipc_udp_xmit to use a noref dst
net: sctp: convert sctp_v{4,6}_xmit to use a noref dst when possible
drivers/net/amt.c | 6 +-
drivers/net/bareudp.c | 63 ++++++-----
drivers/net/geneve.c | 87 +++++++++-------
drivers/net/gtp.c | 10 +-
drivers/net/ovpn/udp.c | 12 +--
drivers/net/vxlan/vxlan_core.c | 80 +++++++-------
drivers/net/wireguard/socket.c | 34 ++++--
include/linux/skbuff.h | 63 ++++-------
include/net/dst.h | 48 ++++++---
include/net/dst_cache.h | 71 +++++++++++++
include/net/dst_metadata.h | 6 +-
include/net/dstref.h | 111 ++++++++++++++++++++
include/net/ip_tunnels.h | 2 +-
include/net/tcp.h | 9 +-
include/net/udp_tunnel.h | 12 +--
net/core/dst_cache.c | 133 ++++++++++++++++++++++--
net/core/pktgen.c | 2 +-
net/ieee802154/6lowpan/reassembly.c | 5 +-
net/ipv4/icmp.c | 6 +-
net/ipv4/ip_fragment.c | 5 +-
net/ipv4/ip_options.c | 8 +-
net/ipv4/ip_tunnel.c | 63 ++++++-----
net/ipv4/ip_tunnel_core.c | 9 +-
net/ipv4/udp_tunnel_core.c | 42 ++++----
net/ipv6/ip6_udp_tunnel.c | 52 +++++----
net/ipv6/netfilter/nf_conntrack_reasm.c | 5 +-
net/ipv6/reassembly.c | 5 +-
net/ipv6/sit.c | 15 +--
net/openvswitch/actions.c | 16 +--
net/openvswitch/datapath.h | 2 +-
net/sched/sch_frag.c | 18 ++--
net/sctp/ipv6.c | 6 +-
net/sctp/protocol.c | 6 +-
net/tipc/udp_media.c | 14 +--
34 files changed, 684 insertions(+), 342 deletions(-)
create mode 100644 include/net/dstref.h
--
2.51.0
^ permalink raw reply [flat|nested] 21+ messages in thread
* [PATCH net-next v4 01/14] net: dst: implement dstref object
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry Marek Mietus
` (12 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
Implement the dstref object, which is a potentially noref pointer to a
struct dst_entry.
A similar object already exists in skb->_skb_refdst,
but is coupled to struct sk_buff, and it can be very useful on its
own. For example, it can be used to return a potentially noref dst from
a function, which is currently not possible unless we attach it to an
skb.
Implement dstref as a standalone object, decoupled from sk_buff.
Some of the helpers have to be in dst.h to prevent a circular include
between skbuff.h and dst.h.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
include/net/dst.h | 28 +++++++++++
include/net/dstref.h | 111 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 139 insertions(+)
create mode 100644 include/net/dstref.h
diff --git a/include/net/dst.h b/include/net/dst.h
index f8aa1239b4db..d7169f067637 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -18,6 +18,7 @@
#include <linux/refcount.h>
#include <linux/rcuref.h>
#include <net/neighbour.h>
+#include <net/dstref.h>
#include <asm/processor.h>
#include <linux/indirect_call_wrapper.h>
@@ -260,6 +261,33 @@ void dst_release(struct dst_entry *dst);
void dst_release_immediate(struct dst_entry *dst);
+/**
+ * dstref_drop - drop the given dstref object.
+ * @dstref: the dstref object to drop.
+ *
+ * This drops the refcount on the dst iff the dstref object holds a reference to it.
+ */
+static inline void dstref_drop(dstref_t dstref)
+{
+ if (!dstref_is_noref(dstref))
+ dst_release(__dstref_dst(dstref));
+}
+
+/**
+ * dstref_clone - clones the given dstref object.
+ * @dstref: the dstref object to clone.
+ *
+ * Clones the dstref while preserving the ownership semantics of the input dstref.
+ *
+ * Return: a clone of the provided dstref object.
+ */
+static inline dstref_t dstref_clone(dstref_t dstref)
+{
+ if (!dstref_is_noref(dstref))
+ dst_clone(__dstref_dst(dstref));
+ return dstref;
+}
+
static inline void refdst_drop(unsigned long refdst)
{
if (!(refdst & SKB_DST_NOREF))
diff --git a/include/net/dstref.h b/include/net/dstref.h
new file mode 100644
index 000000000000..637079260c93
--- /dev/null
+++ b/include/net/dstref.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _NET_DSTREF_H
+#define _NET_DSTREF_H
+
+#include <linux/types.h>
+#include <linux/rcupdate.h>
+#include <linux/compiler.h>
+
+/**
+ * This is required since we can't include dst.h here, in order avoid circular includes between
+ * skbuff.h and dst.h.
+ */
+struct dst_entry;
+
+/**
+ * typedef dstref_t - a pointer to a dst which may or may not hold a reference to the dst.
+ */
+typedef unsigned long __bitwise dstref_t;
+
+/**
+ * This bit is used to specify whether or not the dstref object holds a reference to its dst_entry.
+ */
+#define DSTREF_DST_NOREF 1UL
+#define DSTREF_DST_PTRMASK ~(DSTREF_DST_NOREF)
+
+/**
+ * An empty dstref object which does not point to any dst.
+ */
+#define DSTREF_EMPTY ((__force dstref_t)0UL)
+
+/**
+ * A noref variant of an empty dstref object which does not point to any dst.
+ */
+#define DSTREF_EMPTY_NOREF ((__force dstref_t)DSTREF_DST_NOREF)
+
+/**
+ * dst_to_dstref - create a dstref object which holds a reference to the dst.
+ * @dst: dst to convert.
+ *
+ * The provided dst can be NULL, in which case an empty dstref is returned.
+ *
+ * This function steals the reference on the provided dst, and does not take an extra reference on
+ * it.
+ *
+ * Return: dstref object which points to the given dst and holds a reference to it, or an empty
+ * dstref object if dst is NULL.
+ */
+static inline dstref_t dst_to_dstref(struct dst_entry *dst)
+{
+ return (__force dstref_t)dst;
+}
+
+/**
+ * dst_to_dstref_noref - create a dstref pointer which does not hold a reference to the dst.
+ * @dst: dst to convert.
+ *
+ * The provided dst can be NULL, in which case a noref empty dstref is returned.
+ *
+ * This function must be called within an RCU read-side critical section.
+ *
+ * Return: dstref object which points to the given dst and does not hold a reference to it, or a
+ * noref empty dstref object if dst is NULL.
+ */
+static inline dstref_t dst_to_dstref_noref(struct dst_entry *dst)
+{
+ WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
+ return (__force dstref_t)((unsigned long)dst | DSTREF_DST_NOREF);
+}
+
+/**
+ * Is the given dstref object a noref dstref, which doesn't hold a reference to the dst that it
+ * points to?
+ */
+static inline bool dstref_is_noref(dstref_t dstref)
+{
+ return (__force unsigned long)dstref & DSTREF_DST_NOREF;
+}
+
+/*
+ * __dstref_dst - get the dst that is pointed at by the given dstref object, without performing
+ * safety checks.
+ * @dstref: the dstref object to get the dst of.
+ *
+ * This function returns the dst without performing safety checks.
+ * Prefer using dstref_dst instead of using this function.
+ *
+ * Return: the dst object pointed at by the given dstref object.
+ */
+static inline struct dst_entry *__dstref_dst(dstref_t dstref)
+{
+ return (struct dst_entry *)((__force unsigned long)dstref & DSTREF_DST_PTRMASK);
+}
+
+/**
+ * dstref_dst - get the dst that is pointed at by the given dstref object.
+ * @dstref: the dstref object to get the dst of.
+ *
+ * If the dstref object is noref, this function must be called within an RCU read-side critical
+ * section.
+ *
+ * Return: the dst object pointed at by the given dstref object.
+ */
+static inline struct dst_entry *dstref_dst(dstref_t dstref)
+{
+ WARN_ON(dstref_is_noref(dstref) &&
+ !rcu_read_lock_held() &&
+ !rcu_read_lock_bh_held());
+ return __dstref_dst(dstref);
+}
+
+#endif /* _NET_DSTREF_H */
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 01/14] net: dst: implement dstref object Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 17:09 ` Sabrina Dubroca
2025-11-12 7:27 ` [PATCH net-next v4 03/14] net: skb: rename skb_dstref_restore to skb_dstref_set Marek Mietus
` (11 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
Use the newly introduced dstref object for storing the dst entry
in skb instead of using _skb_refdst, and remove code related
to _skb_refdst.
This is mostly a cosmetic improvement. It improves readability
of functions that previously had to awkwardly access the
internal _skb_refdst, or use its value directly by storing it
in an unsigned long. (this can be seen in pktgen_output_ipsec)
This also fixes functions that used the raw refdst value incorrectly,
which may have resulted in subtle bugs, such as in __skb_dst_copy,
where the refdst value was used directly. (could have resulted in
slow_gro being set even when the dst was NULL if the refdst had the
noref bit set)
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
include/linux/skbuff.h | 63 +++++++++----------------
include/net/dst.h | 26 ++++------
include/net/dst_metadata.h | 6 +--
include/net/tcp.h | 9 ++--
net/core/pktgen.c | 2 +-
net/ieee802154/6lowpan/reassembly.c | 5 +-
net/ipv4/icmp.c | 6 +--
net/ipv4/ip_fragment.c | 5 +-
net/ipv4/ip_options.c | 8 ++--
net/ipv6/netfilter/nf_conntrack_reasm.c | 5 +-
net/ipv6/reassembly.c | 5 +-
net/openvswitch/actions.c | 16 +++----
net/openvswitch/datapath.h | 2 +-
net/sched/sch_frag.c | 18 +++----
14 files changed, 71 insertions(+), 105 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index fb3fec9affaa..c46f817897a4 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -39,6 +39,7 @@
#include <net/net_debug.h>
#include <net/dropreason-core.h>
#include <net/netmem.h>
+#include <net/dstref.h>
/**
* DOC: skb checksums
@@ -786,7 +787,7 @@ enum skb_tstamp_type {
* @dev: Device we arrived on/are leaving by
* @dev_scratch: (aka @dev) alternate use of @dev when @dev would be %NULL
* @cb: Control buffer. Free for use by every layer. Put private vars here
- * @_skb_refdst: destination entry (with norefcount bit)
+ * @_dstref: dstref object pointing to a destination entry
* @len: Length of actual data
* @data_len: Data length
* @mac_len: Length of link layer header
@@ -919,7 +920,7 @@ struct sk_buff {
union {
struct {
- unsigned long _skb_refdst;
+ dstref_t _dstref;
void (*destructor)(struct sk_buff *skb);
};
struct list_head tcp_tsorted_anchor;
@@ -1141,13 +1142,6 @@ static inline bool skb_pfmemalloc(const struct sk_buff *skb)
return unlikely(skb->pfmemalloc);
}
-/*
- * skb might have a dst pointer attached, refcounted or not.
- * _skb_refdst low order bit is set if refcount was _not_ taken
- */
-#define SKB_DST_NOREF 1UL
-#define SKB_DST_PTRMASK ~(SKB_DST_NOREF)
-
/**
* skb_dst - returns skb dst_entry
* @skb: buffer
@@ -1156,52 +1150,40 @@ static inline bool skb_pfmemalloc(const struct sk_buff *skb)
*/
static inline struct dst_entry *skb_dst(const struct sk_buff *skb)
{
- /* If refdst was not refcounted, check we still are in a
- * rcu_read_lock section
- */
- WARN_ON((skb->_skb_refdst & SKB_DST_NOREF) &&
- !rcu_read_lock_held() &&
- !rcu_read_lock_bh_held());
- return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK);
+ return dstref_dst(skb->_dstref);
}
static inline void skb_dst_check_unset(struct sk_buff *skb)
{
- DEBUG_NET_WARN_ON_ONCE((skb->_skb_refdst & SKB_DST_PTRMASK) &&
- !(skb->_skb_refdst & SKB_DST_NOREF));
+ DEBUG_NET_WARN_ON_ONCE(__dstref_dst(skb->_dstref) &&
+ !dstref_is_noref(skb->_dstref));
}
/**
- * skb_dstref_steal() - return current dst_entry value and clear it
+ * skb_dstref_steal() - return current dstref object and clear it
* @skb: buffer
*
- * Resets skb dst_entry without adjusting its reference count. Useful in
- * cases where dst_entry needs to be temporarily reset and restored.
- * Note that the returned value cannot be used directly because it
- * might contain SKB_DST_NOREF bit.
- *
- * When in doubt, prefer skb_dst_drop() over skb_dstref_steal() to correctly
- * handle dst_entry reference counting.
+ * Steals the dstref from the skb, returns it, and leaves an empty dstref instead.
*
- * Returns: original skb dst_entry.
+ * Returns: original dstref object.
*/
-static inline unsigned long skb_dstref_steal(struct sk_buff *skb)
+static inline dstref_t skb_dstref_steal(struct sk_buff *skb)
{
- unsigned long refdst = skb->_skb_refdst;
+ dstref_t dstref = skb->_dstref;
- skb->_skb_refdst = 0;
- return refdst;
+ skb->_dstref = DSTREF_EMPTY;
+ return dstref;
}
/**
- * skb_dstref_restore() - restore skb dst_entry removed via skb_dstref_steal()
+ * skb_dstref_restore() - restore skb dstref removed via skb_dstref_steal()
* @skb: buffer
- * @refdst: dst entry from a call to skb_dstref_steal()
+ * @dstref: dstref object from a call to skb_dstref_steal()
*/
-static inline void skb_dstref_restore(struct sk_buff *skb, unsigned long refdst)
+static inline void skb_dstref_restore(struct sk_buff *skb, dstref_t dstref)
{
skb_dst_check_unset(skb);
- skb->_skb_refdst = refdst;
+ skb->_dstref = dstref;
}
/**
@@ -1216,7 +1198,7 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
{
skb_dst_check_unset(skb);
skb->slow_gro |= !!dst;
- skb->_skb_refdst = (unsigned long)dst;
+ skb->_dstref = dst_to_dstref(dst);
}
/**
@@ -1226,15 +1208,14 @@ static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
*
* Sets skb dst, assuming a reference was not taken on dst.
* If dst entry is cached, we do not take reference and dst_release
- * will be avoided by refdst_drop. If dst entry is not cached, we take
+ * will be avoided by dstref_drop. If dst entry is not cached, we take
* reference, so that last dst_release can destroy the dst immediately.
*/
static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
{
skb_dst_check_unset(skb);
- WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held());
skb->slow_gro |= !!dst;
- skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF;
+ skb->_dstref = dst_to_dstref_noref(dst);
}
/**
@@ -1243,7 +1224,7 @@ static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst)
*/
static inline bool skb_dst_is_noref(const struct sk_buff *skb)
{
- return (skb->_skb_refdst & SKB_DST_NOREF) && skb_dst(skb);
+ return dstref_is_noref(skb->_dstref) && skb_dst(skb);
}
/* For mangling skb->pkt_type from user space side from applications
@@ -5088,7 +5069,7 @@ static inline bool skb_irq_freeable(const struct sk_buff *skb)
return !skb->destructor &&
!secpath_exists(skb) &&
!skb_nfct(skb) &&
- !skb->_skb_refdst &&
+ !__dstref_dst(skb->_dstref) &&
!skb_has_frag_list(skb);
}
diff --git a/include/net/dst.h b/include/net/dst.h
index d7169f067637..47458e51a89c 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -288,12 +288,6 @@ static inline dstref_t dstref_clone(dstref_t dstref)
return dstref;
}
-static inline void refdst_drop(unsigned long refdst)
-{
- if (!(refdst & SKB_DST_NOREF))
- dst_release((struct dst_entry *)(refdst & SKB_DST_PTRMASK));
-}
-
/**
* skb_dst_drop - drops skb dst
* @skb: buffer
@@ -302,23 +296,19 @@ static inline void refdst_drop(unsigned long refdst)
*/
static inline void skb_dst_drop(struct sk_buff *skb)
{
- if (skb->_skb_refdst) {
- refdst_drop(skb->_skb_refdst);
- skb->_skb_refdst = 0UL;
- }
+ dstref_drop(skb->_dstref);
+ skb->_dstref = DSTREF_EMPTY;
}
-static inline void __skb_dst_copy(struct sk_buff *nskb, unsigned long refdst)
+static inline void __skb_dst_copy(struct sk_buff *nskb, dstref_t dstref)
{
- nskb->slow_gro |= !!refdst;
- nskb->_skb_refdst = refdst;
- if (!(nskb->_skb_refdst & SKB_DST_NOREF))
- dst_clone(skb_dst(nskb));
+ nskb->slow_gro |= !!__dstref_dst(dstref);
+ nskb->_dstref = dstref_clone(dstref);
}
static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb)
{
- __skb_dst_copy(nskb, oskb->_skb_refdst);
+ __skb_dst_copy(nskb, oskb->_dstref);
}
/**
@@ -349,11 +339,11 @@ static inline bool skb_dst_force(struct sk_buff *skb)
if (!dst_hold_safe(dst))
dst = NULL;
- skb->_skb_refdst = (unsigned long)dst;
+ skb->_dstref = dst_to_dstref(dst);
skb->slow_gro |= !!dst;
}
- return skb->_skb_refdst != 0UL;
+ return __dstref_dst(skb->_dstref) != NULL;
}
diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h
index 1fc2fb03ce3f..109322ef0d25 100644
--- a/include/net/dst_metadata.h
+++ b/include/net/dst_metadata.h
@@ -102,12 +102,12 @@ static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a,
{
const struct metadata_dst *a, *b;
- if (!(skb_a->_skb_refdst | skb_b->_skb_refdst))
- return 0;
-
a = (const struct metadata_dst *) skb_dst(skb_a);
b = (const struct metadata_dst *) skb_dst(skb_b);
+ if (!a && !b)
+ return 0;
+
if (!a != !b || a->type != b->type)
return 1;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 190b3714e93b..e684f246e798 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2091,20 +2091,19 @@ void tcp_chrono_start(struct sock *sk, const enum tcp_chrono type);
void tcp_chrono_stop(struct sock *sk, const enum tcp_chrono type);
/* This helper is needed, because skb->tcp_tsorted_anchor uses
- * the same memory storage than skb->destructor/_skb_refdst
+ * the same memory storage than skb->destructor/_dstref
*/
static inline void tcp_skb_tsorted_anchor_cleanup(struct sk_buff *skb)
{
skb->destructor = NULL;
- skb->_skb_refdst = 0UL;
+ skb->_dstref = DSTREF_EMPTY;
}
#define tcp_skb_tsorted_save(skb) { \
- unsigned long _save = skb->_skb_refdst; \
- skb->_skb_refdst = 0UL;
+ dstref_t _dstref_save = skb_dstref_steal(skb);
#define tcp_skb_tsorted_restore(skb) \
- skb->_skb_refdst = _save; \
+ skb_dstref_restore(skb, _dstref_save); \
}
void tcp_write_queue_purge(struct sock *sk);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index d41b03fd1f63..e0ac4fbaed06 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -2713,7 +2713,7 @@ static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
* supports both transport/tunnel mode + ESP/AH type.
*/
if ((x->props.mode == XFRM_MODE_TUNNEL) && (pkt_dev->spi != 0))
- skb->_skb_refdst = (unsigned long)&pkt_dev->xdst.u.dst | SKB_DST_NOREF;
+ skb->_dstref = dst_to_dstref_noref(&pkt_dev->xdst.u.dst);
rcu_read_lock_bh();
err = pktgen_xfrm_outer_mode_output(x, skb);
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index ddb6a5817d09..eb23c70c7416 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -142,12 +142,11 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
fq->q.meat == fq->q.len) {
+ dstref_t dstref = skb_dstref_steal(skb);
int res;
- unsigned long orefdst = skb->_skb_refdst;
- skb->_skb_refdst = 0UL;
res = lowpan_frag_reasm(fq, skb, prev_tail, ldev, refs);
- skb->_skb_refdst = orefdst;
+ skb_dstref_restore(skb, dstref);
return res;
}
skb_dst_drop(skb);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 1b7fb5d935ed..6b19a0ffea21 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -536,7 +536,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
err = PTR_ERR(rt2);
} else {
struct flowi4 fl4_2 = {};
- unsigned long orefdst;
+ dstref_t dstref;
fl4_2.daddr = fl4_dec.saddr;
rt2 = ip_route_output_key(net, &fl4_2);
@@ -545,7 +545,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
goto relookup_failed;
}
/* Ugh! */
- orefdst = skb_dstref_steal(skb_in);
+ dstref = skb_dstref_steal(skb_in);
err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr,
dscp, rt2->dst.dev) ? -EINVAL : 0;
@@ -553,7 +553,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
rt2 = skb_rtable(skb_in);
/* steal dst entry from skb_in, don't drop refcnt */
skb_dstref_steal(skb_in);
- skb_dstref_restore(skb_in, orefdst);
+ skb_dstref_restore(skb_in, dstref);
}
if (err)
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index f7012479713b..33080c5350ed 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -365,11 +365,10 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb, int *refs)
if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
qp->q.meat == qp->q.len) {
- unsigned long orefdst = skb->_skb_refdst;
+ dstref_t dstref = skb_dstref_steal(skb);
- skb->_skb_refdst = 0UL;
err = ip_frag_reasm(qp, skb, prev_tail, dev, refs);
- skb->_skb_refdst = orefdst;
+ skb_dstref_restore(skb, dstref);
if (err)
inet_frag_kill(&qp->q, refs);
return err;
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index be8815ce3ac2..d6c712269052 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -591,7 +591,7 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
unsigned char *optptr = skb_network_header(skb) + opt->srr;
struct rtable *rt = skb_rtable(skb);
struct rtable *rt2;
- unsigned long orefdst;
+ dstref_t dstref;
int err;
if (!rt)
@@ -615,16 +615,16 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
}
memcpy(&nexthop, &optptr[srrptr-1], 4);
- orefdst = skb_dstref_steal(skb);
+ dstref = skb_dstref_steal(skb);
err = ip_route_input(skb, nexthop, iph->saddr, ip4h_dscp(iph),
dev) ? -EINVAL : 0;
rt2 = skb_rtable(skb);
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
skb_dst_drop(skb);
- skb_dstref_restore(skb, orefdst);
+ skb_dstref_restore(skb, dstref);
return -EINVAL;
}
- refdst_drop(orefdst);
+ dstref_drop(dstref);
if (rt2->rt_type != RTN_LOCAL)
break;
/* Superfast 8) loopback forward */
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 64ab23ff559b..9fab51fb9497 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -286,11 +286,10 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
fq->q.meat == fq->q.len) {
- unsigned long orefdst = skb->_skb_refdst;
+ dstref_t dstref = skb_dstref_steal(skb);
- skb->_skb_refdst = 0UL;
err = nf_ct_frag6_reasm(fq, skb, prev, dev, refs);
- skb->_skb_refdst = orefdst;
+ skb_dstref_restore(skb, dstref);
/* After queue has assumed skb ownership, only 0 or
* -EINPROGRESS must be returned.
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 25ec8001898d..aa8427f56ff3 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -218,11 +218,10 @@ static int ip6_frag_queue(struct net *net,
if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) &&
fq->q.meat == fq->q.len) {
- unsigned long orefdst = skb->_skb_refdst;
+ dstref_t dstref = skb_dstref_steal(skb);
- skb->_skb_refdst = 0UL;
err = ip6_frag_reasm(fq, skb, prev_tail, dev, refs);
- skb->_skb_refdst = orefdst;
+ skb_dstref_restore(skb, dstref);
return err;
}
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 2832e0794197..31ec8c9e0758 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -761,7 +761,7 @@ static int ovs_vport_output(struct net *net, struct sock *sk,
return -ENOMEM;
}
- __skb_dst_copy(skb, data->dst);
+ __skb_dst_copy(skb, data->dstref);
*OVS_CB(skb) = data->cb;
skb->inner_protocol = data->inner_protocol;
if (data->vlan_tci & VLAN_CFI_MASK)
@@ -806,7 +806,7 @@ static void prepare_frag(struct vport *vport, struct sk_buff *skb,
struct ovs_frag_data *data;
data = this_cpu_ptr(&ovs_pcpu_storage->frag_data);
- data->dst = skb->_skb_refdst;
+ data->dstref = skb->_dstref;
data->vport = vport;
data->cb = *OVS_CB(skb);
data->inner_protocol = skb->inner_protocol;
@@ -844,7 +844,7 @@ static void ovs_fragment(struct net *net, struct vport *vport,
if (key->eth.type == htons(ETH_P_IP)) {
struct rtable ovs_rt = { 0 };
- unsigned long orig_dst;
+ dstref_t orig_dstref;
prepare_frag(vport, skb, orig_network_offset,
ovs_key_mac_proto(key));
@@ -852,14 +852,14 @@ static void ovs_fragment(struct net *net, struct vport *vport,
DST_OBSOLETE_NONE, DST_NOCOUNT);
ovs_rt.dst.dev = vport->dev;
- orig_dst = skb->_skb_refdst;
+ orig_dstref = skb->_dstref;
skb_dst_set_noref(skb, &ovs_rt.dst);
IPCB(skb)->frag_max_size = mru;
ip_do_fragment(net, skb->sk, skb, ovs_vport_output);
- refdst_drop(orig_dst);
+ dstref_drop(orig_dstref);
} else if (key->eth.type == htons(ETH_P_IPV6)) {
- unsigned long orig_dst;
+ dstref_t orig_dstref;
struct rt6_info ovs_rt;
prepare_frag(vport, skb, orig_network_offset,
@@ -869,12 +869,12 @@ static void ovs_fragment(struct net *net, struct vport *vport,
DST_OBSOLETE_NONE, DST_NOCOUNT);
ovs_rt.dst.dev = vport->dev;
- orig_dst = skb->_skb_refdst;
+ orig_dstref = skb->_dstref;
skb_dst_set_noref(skb, &ovs_rt.dst);
IP6CB(skb)->frag_max_size = mru;
ipv6_stub->ipv6_fragment(net, skb->sk, skb, ovs_vport_output);
- refdst_drop(orig_dst);
+ dstref_drop(orig_dstref);
} else {
WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.",
ovs_vport_name(vport), ntohs(key->eth.type), mru,
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index db0c3e69d66c..6bc15cb3a363 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -179,7 +179,7 @@ struct ovs_net {
#define MAX_L2_LEN (VLAN_ETH_HLEN + 3 * MPLS_HLEN)
struct ovs_frag_data {
- unsigned long dst;
+ dstref_t dstref;
struct vport *vport;
struct ovs_skb_cb cb;
__be16 inner_protocol;
diff --git a/net/sched/sch_frag.c b/net/sched/sch_frag.c
index d1d87dce7f3f..bafbbac761da 100644
--- a/net/sched/sch_frag.c
+++ b/net/sched/sch_frag.c
@@ -8,7 +8,7 @@
#include <net/ip6_fib.h>
struct sch_frag_data {
- unsigned long dst;
+ dstref_t dstref;
struct qdisc_skb_cb cb;
__be16 inner_protocol;
u16 vlan_tci;
@@ -33,7 +33,7 @@ static int sch_frag_xmit(struct net *net, struct sock *sk, struct sk_buff *skb)
return -ENOMEM;
}
- __skb_dst_copy(skb, data->dst);
+ __skb_dst_copy(skb, data->dstref);
*qdisc_skb_cb(skb) = data->cb;
skb->inner_protocol = data->inner_protocol;
if (data->vlan_tci & VLAN_CFI_MASK)
@@ -58,7 +58,7 @@ static void sch_frag_prepare_frag(struct sk_buff *skb,
struct sch_frag_data *data;
data = this_cpu_ptr(&sch_frag_data_storage);
- data->dst = skb->_skb_refdst;
+ data->dstref = skb->_dstref;
data->cb = *qdisc_skb_cb(skb);
data->xmit = xmit;
data->inner_protocol = skb->inner_protocol;
@@ -97,7 +97,7 @@ static int sch_fragment(struct net *net, struct sk_buff *skb,
if (skb_protocol(skb, true) == htons(ETH_P_IP)) {
struct rtable sch_frag_rt = { 0 };
- unsigned long orig_dst;
+ dstref_t orig_dstref;
local_lock_nested_bh(&sch_frag_data_storage.bh_lock);
sch_frag_prepare_frag(skb, xmit);
@@ -105,15 +105,15 @@ static int sch_fragment(struct net *net, struct sk_buff *skb,
DST_OBSOLETE_NONE, DST_NOCOUNT);
sch_frag_rt.dst.dev = skb->dev;
- orig_dst = skb->_skb_refdst;
+ orig_dstref = skb->_dstref;
skb_dst_set_noref(skb, &sch_frag_rt.dst);
IPCB(skb)->frag_max_size = mru;
ret = ip_do_fragment(net, skb->sk, skb, sch_frag_xmit);
local_unlock_nested_bh(&sch_frag_data_storage.bh_lock);
- refdst_drop(orig_dst);
+ dstref_drop(orig_dstref);
} else if (skb_protocol(skb, true) == htons(ETH_P_IPV6)) {
- unsigned long orig_dst;
+ dstref_t orig_dstref;
struct rt6_info sch_frag_rt;
local_lock_nested_bh(&sch_frag_data_storage.bh_lock);
@@ -123,14 +123,14 @@ static int sch_fragment(struct net *net, struct sk_buff *skb,
DST_OBSOLETE_NONE, DST_NOCOUNT);
sch_frag_rt.dst.dev = skb->dev;
- orig_dst = skb->_skb_refdst;
+ orig_dstref = skb->_dstref;
skb_dst_set_noref(skb, &sch_frag_rt.dst);
IP6CB(skb)->frag_max_size = mru;
ret = ipv6_stub->ipv6_fragment(net, skb->sk, skb,
sch_frag_xmit);
local_unlock_nested_bh(&sch_frag_data_storage.bh_lock);
- refdst_drop(orig_dst);
+ dstref_drop(orig_dstref);
} else {
net_warn_ratelimited("Fail frag %s: eth=%x, MRU=%d, MTU=%d\n",
netdev_name(skb->dev),
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 03/14] net: skb: rename skb_dstref_restore to skb_dstref_set
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 01/14] net: dst: implement dstref object Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 04/14] net: dst_cache: add noref versions for dst_cache Marek Mietus
` (10 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
After changing skbuff to use the newly introduced dstref object,
skb_dstref_restore is essentially just a setter for the dstref
field.
Rename the skb_dstref_restore function to skb_dstref_set.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
include/linux/skbuff.h | 6 +++---
include/net/tcp.h | 2 +-
net/ieee802154/6lowpan/reassembly.c | 2 +-
net/ipv4/icmp.c | 2 +-
net/ipv4/ip_fragment.c | 2 +-
net/ipv4/ip_options.c | 2 +-
net/ipv6/netfilter/nf_conntrack_reasm.c | 2 +-
net/ipv6/reassembly.c | 2 +-
8 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index c46f817897a4..b71251372600 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -1176,11 +1176,11 @@ static inline dstref_t skb_dstref_steal(struct sk_buff *skb)
}
/**
- * skb_dstref_restore() - restore skb dstref removed via skb_dstref_steal()
+ * skb_dstref_set() - sets skb dstref
* @skb: buffer
- * @dstref: dstref object from a call to skb_dstref_steal()
+ * @dstref: dstref object
*/
-static inline void skb_dstref_restore(struct sk_buff *skb, dstref_t dstref)
+static inline void skb_dstref_set(struct sk_buff *skb, dstref_t dstref)
{
skb_dst_check_unset(skb);
skb->_dstref = dstref;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index e684f246e798..7a7408ad76fb 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -2103,7 +2103,7 @@ static inline void tcp_skb_tsorted_anchor_cleanup(struct sk_buff *skb)
dstref_t _dstref_save = skb_dstref_steal(skb);
#define tcp_skb_tsorted_restore(skb) \
- skb_dstref_restore(skb, _dstref_save); \
+ skb_dstref_set(skb, _dstref_save); \
}
void tcp_write_queue_purge(struct sock *sk);
diff --git a/net/ieee802154/6lowpan/reassembly.c b/net/ieee802154/6lowpan/reassembly.c
index eb23c70c7416..183fb3f95809 100644
--- a/net/ieee802154/6lowpan/reassembly.c
+++ b/net/ieee802154/6lowpan/reassembly.c
@@ -146,7 +146,7 @@ static int lowpan_frag_queue(struct lowpan_frag_queue *fq,
int res;
res = lowpan_frag_reasm(fq, skb, prev_tail, ldev, refs);
- skb_dstref_restore(skb, dstref);
+ skb_dstref_set(skb, dstref);
return res;
}
skb_dst_drop(skb);
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 6b19a0ffea21..bb6c0128a66b 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -553,7 +553,7 @@ static struct rtable *icmp_route_lookup(struct net *net, struct flowi4 *fl4,
rt2 = skb_rtable(skb_in);
/* steal dst entry from skb_in, don't drop refcnt */
skb_dstref_steal(skb_in);
- skb_dstref_restore(skb_in, dstref);
+ skb_dstref_set(skb_in, dstref);
}
if (err)
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 33080c5350ed..a077070240b8 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -368,7 +368,7 @@ static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb, int *refs)
dstref_t dstref = skb_dstref_steal(skb);
err = ip_frag_reasm(qp, skb, prev_tail, dev, refs);
- skb_dstref_restore(skb, dstref);
+ skb_dstref_set(skb, dstref);
if (err)
inet_frag_kill(&qp->q, refs);
return err;
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index d6c712269052..9e247ec9aa97 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -621,7 +621,7 @@ int ip_options_rcv_srr(struct sk_buff *skb, struct net_device *dev)
rt2 = skb_rtable(skb);
if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) {
skb_dst_drop(skb);
- skb_dstref_restore(skb, dstref);
+ skb_dstref_set(skb, dstref);
return -EINVAL;
}
dstref_drop(dstref);
diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c
index 9fab51fb9497..c03ede44cfc7 100644
--- a/net/ipv6/netfilter/nf_conntrack_reasm.c
+++ b/net/ipv6/netfilter/nf_conntrack_reasm.c
@@ -289,7 +289,7 @@ static int nf_ct_frag6_queue(struct frag_queue *fq, struct sk_buff *skb,
dstref_t dstref = skb_dstref_steal(skb);
err = nf_ct_frag6_reasm(fq, skb, prev, dev, refs);
- skb_dstref_restore(skb, dstref);
+ skb_dstref_set(skb, dstref);
/* After queue has assumed skb ownership, only 0 or
* -EINPROGRESS must be returned.
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index aa8427f56ff3..016ca7344427 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -221,7 +221,7 @@ static int ip6_frag_queue(struct net *net,
dstref_t dstref = skb_dstref_steal(skb);
err = ip6_frag_reasm(fq, skb, prev_tail, dev, refs);
- skb_dstref_restore(skb, dstref);
+ skb_dstref_set(skb, dstref);
return err;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 04/14] net: dst_cache: add noref versions for dst_cache
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (2 preceding siblings ...)
2025-11-12 7:27 ` [PATCH net-next v4 03/14] net: skb: rename skb_dstref_restore to skb_dstref_set Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 05/14] net: tunnel: use dstref in ip and udp tunnel xmit functions Marek Mietus
` (9 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
Implement noref variants for existing dst_cache helpers
interacting with dst_entry. This is required for implementing
noref flows, which avoid redundant atomic operations.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
include/net/dst_cache.h | 71 +++++++++++++++++++++
net/core/dst_cache.c | 133 +++++++++++++++++++++++++++++++++++++---
2 files changed, 194 insertions(+), 10 deletions(-)
diff --git a/include/net/dst_cache.h b/include/net/dst_cache.h
index 1961699598e2..3ee387a8db45 100644
--- a/include/net/dst_cache.h
+++ b/include/net/dst_cache.h
@@ -23,6 +23,23 @@ struct dst_cache {
*/
struct dst_entry *dst_cache_get(struct dst_cache *dst_cache);
+/**
+ * dst_cache_get_rcu - perform cache lookup under RCU
+ * @dst_cache: the cache
+ *
+ * Perform cache lookup without taking a reference on the dst.
+ * Must be called with local BH disabled, and within an rcu read side
+ * critical section.
+ *
+ * The caller should use dst_cache_get_ip4() if it need to retrieve the
+ * source address to be used when xmitting to the cached dst.
+ * local BH must be disabled.
+ *
+ * Return: Pointer to retrieved rtable if cache is initialized and
+ * cached dst is valid, NULL otherwise.
+ */
+struct dst_entry *dst_cache_get_rcu(struct dst_cache *dst_cache);
+
/**
* dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address
* @dst_cache: the cache
@@ -32,6 +49,21 @@ struct dst_entry *dst_cache_get(struct dst_cache *dst_cache);
*/
struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr);
+/**
+ * dst_cache_get_ip4_rcu - lookup cache and ipv4 source under RCU
+ * @dst_cache: the cache
+ * @saddr: return value for the retrieved source address
+ *
+ * Perform cache lookup and fetch ipv4 source without taking a
+ * reference on the dst.
+ * Must be called with local BH disabled, and within an rcu read side
+ * critical section.
+ *
+ * Return: Pointer to retrieved rtable if cache is initialized and
+ * cached dst is valid, NULL otherwise.
+ */
+struct rtable *dst_cache_get_ip4_rcu(struct dst_cache *dst_cache, __be32 *saddr);
+
/**
* dst_cache_set_ip4 - store the ipv4 dst into the cache
* @dst_cache: the cache
@@ -43,6 +75,17 @@ struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr);
void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
__be32 saddr);
+/**
+ * dst_cache_steal_ip4 - store the ipv4 dst into the cache and steal its
+ * reference
+ * @dst_cache: the cache
+ * @dst: the entry to be cached whose reference will be stolen
+ * @saddr: the source address to be stored inside the cache
+ *
+ * local BH must be disabled
+ */
+void dst_cache_steal_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
+ __be32 saddr);
#if IS_ENABLED(CONFIG_IPV6)
/**
@@ -56,6 +99,18 @@ void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
const struct in6_addr *saddr);
+/**
+ * dst_cache_steal_ip6 - store the ipv6 dst into the cache and steal its
+ * reference
+ * @dst_cache: the cache
+ * @dst: the entry to be cached whose reference will be stolen
+ * @saddr: the source address to be stored inside the cache
+ *
+ * local BH must be disabled
+ */
+void dst_cache_steal_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+ const struct in6_addr *saddr);
+
/**
* dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address
* @dst_cache: the cache
@@ -65,6 +120,22 @@ void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
*/
struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
struct in6_addr *saddr);
+
+/**
+ * dst_cache_get_ip6_rcu - lookup cache and ipv6 source under RCU
+ * @dst_cache: the cache
+ * @saddr: return value for the retrieved source address
+ *
+ * Perform cache lookup and fetch ipv6 source without taking a
+ * reference on the dst.
+ * Must be called with local BH disabled, and within an rcu read side
+ * critical section.
+ *
+ * Return: Pointer to retrieved dst_entry if cache is initialized and
+ * cached dst is valid, NULL otherwise.
+ */
+struct dst_entry *dst_cache_get_ip6_rcu(struct dst_cache *dst_cache,
+ struct in6_addr *saddr);
#endif
/**
diff --git a/net/core/dst_cache.c b/net/core/dst_cache.c
index 9ab4902324e1..52418cfb9b8a 100644
--- a/net/core/dst_cache.c
+++ b/net/core/dst_cache.c
@@ -25,20 +25,27 @@ struct dst_cache_pcpu {
};
};
-static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
- struct dst_entry *dst, u32 cookie)
+static void __dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
+ struct dst_entry *dst, u32 cookie)
{
DEBUG_NET_WARN_ON_ONCE(!in_softirq());
dst_release(dst_cache->dst);
- if (dst)
- dst_hold(dst);
dst_cache->cookie = cookie;
dst_cache->dst = dst;
}
-static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
- struct dst_cache_pcpu *idst)
+static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache,
+ struct dst_entry *dst, u32 cookie)
+{
+ if (dst)
+ dst_hold(dst);
+
+ __dst_cache_per_cpu_dst_set(dst_cache, dst, cookie);
+}
+
+static struct dst_entry *__dst_cache_per_cpu_get(struct dst_cache *dst_cache,
+ struct dst_cache_pcpu *idst)
{
struct dst_entry *dst;
@@ -47,14 +54,10 @@ static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
if (!dst)
goto fail;
- /* the cache already hold a dst reference; it can't go away */
- dst_hold(dst);
-
if (unlikely(!time_after(idst->refresh_ts,
READ_ONCE(dst_cache->reset_ts)) ||
(READ_ONCE(dst->obsolete) && !dst->ops->check(dst, idst->cookie)))) {
dst_cache_per_cpu_dst_set(idst, NULL, 0);
- dst_release(dst);
goto fail;
}
return dst;
@@ -64,6 +67,18 @@ static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
return NULL;
}
+static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache,
+ struct dst_cache_pcpu *idst)
+{
+ struct dst_entry *dst;
+
+ dst = __dst_cache_per_cpu_get(dst_cache, idst);
+ if (dst)
+ /* the cache already hold a dst reference; it can't go away */
+ dst_hold(dst);
+ return dst;
+}
+
struct dst_entry *dst_cache_get(struct dst_cache *dst_cache)
{
struct dst_entry *dst;
@@ -78,6 +93,20 @@ struct dst_entry *dst_cache_get(struct dst_cache *dst_cache)
}
EXPORT_SYMBOL_GPL(dst_cache_get);
+struct dst_entry *dst_cache_get_rcu(struct dst_cache *dst_cache)
+{
+ struct dst_entry *dst;
+
+ if (!dst_cache->cache)
+ return NULL;
+
+ local_lock_nested_bh(&dst_cache->cache->bh_lock);
+ dst = __dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache));
+ local_unlock_nested_bh(&dst_cache->cache->bh_lock);
+ return dst;
+}
+EXPORT_SYMBOL_GPL(dst_cache_get_rcu);
+
struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr)
{
struct dst_cache_pcpu *idst;
@@ -100,6 +129,28 @@ struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr)
}
EXPORT_SYMBOL_GPL(dst_cache_get_ip4);
+struct rtable *dst_cache_get_ip4_rcu(struct dst_cache *dst_cache, __be32 *saddr)
+{
+ struct dst_cache_pcpu *idst;
+ struct dst_entry *dst;
+
+ if (!dst_cache->cache)
+ return NULL;
+
+ local_lock_nested_bh(&dst_cache->cache->bh_lock);
+ idst = this_cpu_ptr(dst_cache->cache);
+ dst = __dst_cache_per_cpu_get(dst_cache, idst);
+ if (!dst) {
+ local_unlock_nested_bh(&dst_cache->cache->bh_lock);
+ return NULL;
+ }
+
+ *saddr = idst->in_saddr.s_addr;
+ local_unlock_nested_bh(&dst_cache->cache->bh_lock);
+ return dst_rtable(dst);
+}
+EXPORT_SYMBOL_GPL(dst_cache_get_ip4_rcu);
+
void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
__be32 saddr)
{
@@ -116,6 +167,24 @@ void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
}
EXPORT_SYMBOL_GPL(dst_cache_set_ip4);
+void dst_cache_steal_ip4(struct dst_cache *dst_cache, struct dst_entry *dst,
+ __be32 saddr)
+{
+ struct dst_cache_pcpu *idst;
+
+ if (!dst_cache->cache) {
+ dst_release(dst);
+ return;
+ }
+
+ local_lock_nested_bh(&dst_cache->cache->bh_lock);
+ idst = this_cpu_ptr(dst_cache->cache);
+ __dst_cache_per_cpu_dst_set(idst, dst, 0);
+ idst->in_saddr.s_addr = saddr;
+ local_unlock_nested_bh(&dst_cache->cache->bh_lock);
+}
+EXPORT_SYMBOL_GPL(dst_cache_steal_ip4);
+
#if IS_ENABLED(CONFIG_IPV6)
void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
const struct in6_addr *saddr)
@@ -135,6 +204,26 @@ void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
}
EXPORT_SYMBOL_GPL(dst_cache_set_ip6);
+void dst_cache_steal_ip6(struct dst_cache *dst_cache, struct dst_entry *dst,
+ const struct in6_addr *saddr)
+{
+ struct dst_cache_pcpu *idst;
+
+ if (!dst_cache->cache) {
+ dst_release(dst);
+ return;
+ }
+
+ local_lock_nested_bh(&dst_cache->cache->bh_lock);
+
+ idst = this_cpu_ptr(dst_cache->cache);
+ __dst_cache_per_cpu_dst_set(idst, dst,
+ rt6_get_cookie(dst_rt6_info(dst)));
+ idst->in6_saddr = *saddr;
+ local_unlock_nested_bh(&dst_cache->cache->bh_lock);
+}
+EXPORT_SYMBOL_GPL(dst_cache_steal_ip6);
+
struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
struct in6_addr *saddr)
{
@@ -158,6 +247,30 @@ struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache,
return dst;
}
EXPORT_SYMBOL_GPL(dst_cache_get_ip6);
+
+struct dst_entry *dst_cache_get_ip6_rcu(struct dst_cache *dst_cache,
+ struct in6_addr *saddr)
+{
+ struct dst_cache_pcpu *idst;
+ struct dst_entry *dst;
+
+ if (!dst_cache->cache)
+ return NULL;
+
+ local_lock_nested_bh(&dst_cache->cache->bh_lock);
+
+ idst = this_cpu_ptr(dst_cache->cache);
+ dst = __dst_cache_per_cpu_get(dst_cache, idst);
+ if (!dst) {
+ local_unlock_nested_bh(&dst_cache->cache->bh_lock);
+ return NULL;
+ }
+
+ *saddr = idst->in6_saddr;
+ local_unlock_nested_bh(&dst_cache->cache->bh_lock);
+ return dst;
+}
+EXPORT_SYMBOL_GPL(dst_cache_get_ip6_rcu);
#endif
int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp)
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 05/14] net: tunnel: use dstref in ip and udp tunnel xmit functions
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (3 preceding siblings ...)
2025-11-12 7:27 ` [PATCH net-next v4 04/14] net: dst_cache: add noref versions for dst_cache Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 06/14] net: tunnel: return dstref in udp_tunnel{,6}_dst_lookup Marek Mietus
` (8 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
Update iptunnel_xmit and udp{,6}_tunnel_xmit_skb to use dstref
instead of dst_entry/rtable when specifying the destination of
the skb.
This allows passing potentially noref dsts to tunnel xmit functions,
which previously only accepted referenced dsts. This change does not
add any new noref xmit flows.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
drivers/net/amt.c | 6 +++---
drivers/net/bareudp.c | 4 ++--
drivers/net/geneve.c | 7 ++++---
drivers/net/gtp.c | 10 +++++-----
drivers/net/ovpn/udp.c | 4 ++--
drivers/net/vxlan/vxlan_core.c | 4 ++--
drivers/net/wireguard/socket.c | 4 ++--
include/net/ip_tunnels.h | 2 +-
include/net/udp_tunnel.h | 4 ++--
net/ipv4/ip_tunnel.c | 4 ++--
net/ipv4/ip_tunnel_core.c | 9 +++++----
net/ipv4/udp_tunnel_core.c | 4 ++--
net/ipv6/ip6_udp_tunnel.c | 4 ++--
net/ipv6/sit.c | 2 +-
net/sctp/ipv6.c | 2 +-
net/sctp/protocol.c | 2 +-
net/tipc/udp_media.c | 4 ++--
17 files changed, 39 insertions(+), 37 deletions(-)
diff --git a/drivers/net/amt.c b/drivers/net/amt.c
index 902c817a0dea..2fe0937a372c 100644
--- a/drivers/net/amt.c
+++ b/drivers/net/amt.c
@@ -1039,7 +1039,7 @@ static bool amt_send_membership_update(struct amt_dev *amt,
skb_set_inner_protocol(skb, htons(ETH_P_IP));
else
skb_set_inner_protocol(skb, htons(ETH_P_IPV6));
- udp_tunnel_xmit_skb(rt, sock->sk, skb,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock->sk, skb,
fl4.saddr,
fl4.daddr,
AMT_TOS,
@@ -1097,7 +1097,7 @@ static void amt_send_multicast_data(struct amt_dev *amt,
skb_set_inner_protocol(skb, htons(ETH_P_IP));
else
skb_set_inner_protocol(skb, htons(ETH_P_IPV6));
- udp_tunnel_xmit_skb(rt, sock->sk, skb,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock->sk, skb,
fl4.saddr,
fl4.daddr,
AMT_TOS,
@@ -1156,7 +1156,7 @@ static bool amt_send_membership_query(struct amt_dev *amt,
skb_set_inner_protocol(skb, htons(ETH_P_IP));
else
skb_set_inner_protocol(skb, htons(ETH_P_IPV6));
- udp_tunnel_xmit_skb(rt, sock->sk, skb,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock->sk, skb,
fl4.saddr,
fl4.daddr,
AMT_TOS,
diff --git a/drivers/net/bareudp.c b/drivers/net/bareudp.c
index 0df3208783ad..813866cd04db 100644
--- a/drivers/net/bareudp.c
+++ b/drivers/net/bareudp.c
@@ -359,7 +359,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(rt, sock->sk, skb, saddr, info->key.u.ipv4.dst,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), 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),
@@ -427,7 +427,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, sock->sk, skb, dev,
+ udp_tunnel6_xmit_skb(dst_to_dstref(dst), sock->sk, skb, dev,
&saddr, &daddr, prio, ttl,
info->key.label, sport, bareudp->port,
!test_bit(IP_TUNNEL_CSUM_BIT,
diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c
index 77b0c3d52041..0c7949c0561f 100644
--- a/drivers/net/geneve.c
+++ b/drivers/net/geneve.c
@@ -921,8 +921,9 @@ static int geneve_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (unlikely(err))
return err;
- udp_tunnel_xmit_skb(rt, gs4->sock->sk, skb, saddr, info->key.u.ipv4.dst,
- tos, ttl, df, sport, geneve->cfg.info.key.tp_dst,
+ 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,
!net_eq(geneve->net, dev_net(geneve->dev)),
!test_bit(IP_TUNNEL_CSUM_BIT, info->key.tun_flags),
0);
@@ -1013,7 +1014,7 @@ static int geneve6_xmit_skb(struct sk_buff *skb, struct net_device *dev,
if (unlikely(err))
return err;
- udp_tunnel6_xmit_skb(dst, gs6->sock->sk, skb, dev,
+ udp_tunnel6_xmit_skb(dst_to_dstref(dst), 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,
diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c
index 5cb59d72bc82..1db34e7dbf0e 100644
--- a/drivers/net/gtp.c
+++ b/drivers/net/gtp.c
@@ -439,7 +439,7 @@ static int gtp0_send_echo_resp_ip(struct gtp_dev *gtp, struct sk_buff *skb)
return -1;
}
- udp_tunnel_xmit_skb(rt, gtp->sk0, skb,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), gtp->sk0, skb,
fl4.saddr, fl4.daddr,
iph->tos,
ip4_dst_hoplimit(&rt->dst),
@@ -698,7 +698,7 @@ static int gtp1u_send_echo_resp(struct gtp_dev *gtp, struct sk_buff *skb)
return -1;
}
- udp_tunnel_xmit_skb(rt, gtp->sk1u, skb,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), gtp->sk1u, skb,
fl4.saddr, fl4.daddr,
iph->tos,
ip4_dst_hoplimit(&rt->dst),
@@ -1299,7 +1299,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
switch (pktinfo.pctx->sk->sk_family) {
case AF_INET:
- udp_tunnel_xmit_skb(pktinfo.rt, pktinfo.sk, skb,
+ udp_tunnel_xmit_skb(dst_to_dstref(&pktinfo.rt->dst), pktinfo.sk, skb,
pktinfo.fl4.saddr, pktinfo.fl4.daddr,
pktinfo.tos,
ip4_dst_hoplimit(&pktinfo.rt->dst),
@@ -1311,7 +1311,7 @@ static netdev_tx_t gtp_dev_xmit(struct sk_buff *skb, struct net_device *dev)
break;
case AF_INET6:
#if IS_ENABLED(CONFIG_IPV6)
- udp_tunnel6_xmit_skb(&pktinfo.rt6->dst, pktinfo.sk, skb, dev,
+ udp_tunnel6_xmit_skb(dst_to_dstref(&pktinfo.rt6->dst), pktinfo.sk, skb, dev,
&pktinfo.fl6.saddr, &pktinfo.fl6.daddr,
pktinfo.tos,
ip6_dst_hoplimit(&pktinfo.rt->dst),
@@ -2400,7 +2400,7 @@ static int gtp_genl_send_echo_req(struct sk_buff *skb, struct genl_info *info)
return -ENODEV;
}
- udp_tunnel_xmit_skb(rt, sk, skb_to_send,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sk, skb_to_send,
fl4.saddr, fl4.daddr,
inet_dscp_to_dsfield(fl4.flowi4_dscp),
ip4_dst_hoplimit(&rt->dst),
diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
index d6a0f7a0b75d..a765aee6e36b 100644
--- a/drivers/net/ovpn/udp.c
+++ b/drivers/net/ovpn/udp.c
@@ -197,7 +197,7 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
transmit:
- udp_tunnel_xmit_skb(rt, sk, skb, fl.saddr, fl.daddr, 0,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sk, skb, fl.saddr, fl.daddr, 0,
ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport,
fl.fl4_dport, false, sk->sk_no_check_tx, 0);
ret = 0;
@@ -272,7 +272,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
* udp_tunnel_xmit_skb()
*/
skb->ignore_df = 1;
- udp_tunnel6_xmit_skb(dst, sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0,
+ udp_tunnel6_xmit_skb(dst_to_dstref(dst), sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0,
ip6_dst_hoplimit(dst), 0, fl.fl6_sport,
fl.fl6_dport, udp_get_no_check6_tx(sk), 0);
ret = 0;
diff --git a/drivers/net/vxlan/vxlan_core.c b/drivers/net/vxlan/vxlan_core.c
index a5c55e7e4d79..78e5a3393b48 100644
--- a/drivers/net/vxlan/vxlan_core.c
+++ b/drivers/net/vxlan/vxlan_core.c
@@ -2528,7 +2528,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
goto tx_error;
}
- udp_tunnel_xmit_skb(rt, sock4->sock->sk, skb, saddr,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock4->sock->sk, skb, saddr,
pkey->u.ipv4.dst, tos, ttl, df,
src_port, dst_port, xnet, !udp_sum,
ipcb_flags);
@@ -2597,7 +2597,7 @@ void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
goto tx_error;
}
- udp_tunnel6_xmit_skb(ndst, sock6->sock->sk, skb, dev,
+ udp_tunnel6_xmit_skb(dst_to_dstref(ndst), sock6->sock->sk, skb, dev,
&saddr, &pkey->u.ipv6.dst, tos, ttl,
pkey->label, src_port, dst_port, !udp_sum,
ip6cb_flags);
diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c
index 253488f8c00f..342247d324ab 100644
--- a/drivers/net/wireguard/socket.c
+++ b/drivers/net/wireguard/socket.c
@@ -82,7 +82,7 @@ static int send4(struct wg_device *wg, struct sk_buff *skb,
}
skb->ignore_df = 1;
- udp_tunnel_xmit_skb(rt, sock, skb, fl.saddr, fl.daddr, ds,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock, skb, fl.saddr, fl.daddr, ds,
ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport,
fl.fl4_dport, false, false, 0);
goto out;
@@ -149,7 +149,7 @@ static int send6(struct wg_device *wg, struct sk_buff *skb,
}
skb->ignore_df = 1;
- udp_tunnel6_xmit_skb(dst, sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds,
+ udp_tunnel6_xmit_skb(dst_to_dstref(dst), sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds,
ip6_dst_hoplimit(dst), 0, fl.fl6_sport,
fl.fl6_dport, false, 0);
goto out;
diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
index ecae35512b9b..22a51f25206c 100644
--- a/include/net/ip_tunnels.h
+++ b/include/net/ip_tunnels.h
@@ -603,7 +603,7 @@ static inline int iptunnel_pull_header(struct sk_buff *skb, int hdr_len,
return __iptunnel_pull_header(skb, hdr_len, inner_proto, false, xnet);
}
-void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
+void iptunnel_xmit(struct sock *sk, dstref_t dstref, struct sk_buff *skb,
__be32 src, __be32 dst, u8 proto,
u8 tos, u8 ttl, __be16 df, bool xnet, u16 ipcb_flags);
struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md,
diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h
index 9acef2fbd2fd..b47e997be7f4 100644
--- a/include/net/udp_tunnel.h
+++ b/include/net/udp_tunnel.h
@@ -131,12 +131,12 @@ void udp_tunnel_notify_add_rx_port(struct socket *sock, unsigned short type);
void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type);
/* Transmit the skb using UDP encapsulation. */
-void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
+void udp_tunnel_xmit_skb(dstref_t dstref, struct sock *sk, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
__be16 df, __be16 src_port, __be16 dst_port,
bool xnet, bool nocheck, u16 ipcb_flags);
-void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
+void udp_tunnel6_xmit_skb(dstref_t dstref, struct sock *sk,
struct sk_buff *skb,
struct net_device *dev,
const struct in6_addr *saddr,
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 158a30ae7c5f..6aa045793048 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -653,7 +653,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
ip_tunnel_adj_headroom(dev, headroom);
- iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
+ iptunnel_xmit(NULL, dst_to_dstref(&rt->dst), skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
df, !net_eq(tunnel->net, dev_net(dev)), 0);
return;
tx_error:
@@ -842,7 +842,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
ip_tunnel_adj_headroom(dev, max_headroom);
- iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
+ iptunnel_xmit(NULL, dst_to_dstref(&rt->dst), skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
df, !net_eq(tunnel->net, dev_net(dev)), 0);
return;
diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c
index 2e61ac137128..5bdc3c3c5a2e 100644
--- a/net/ipv4/ip_tunnel_core.c
+++ b/net/ipv4/ip_tunnel_core.c
@@ -47,13 +47,14 @@ const struct ip6_tnl_encap_ops __rcu *
ip6tun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly;
EXPORT_SYMBOL(ip6tun_encaps);
-void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
+void iptunnel_xmit(struct sock *sk, dstref_t dstref, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 proto,
__u8 tos, __u8 ttl, __be16 df, bool xnet,
u16 ipcb_flags)
{
int pkt_len = skb->len - skb_inner_network_offset(skb);
- struct net *net = dev_net(rt->dst.dev);
+ struct dst_entry *ndst = dstref_dst(dstref);
+ struct net *net = dev_net(ndst->dev);
struct net_device *dev = skb->dev;
struct iphdr *iph;
int err;
@@ -61,7 +62,7 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
skb_scrub_packet(skb, xnet);
skb_clear_hash_if_not_l4(skb);
- skb_dst_set(skb, &rt->dst);
+ skb_dstref_set(skb, dstref);
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
IPCB(skb)->flags = ipcb_flags;
@@ -73,7 +74,7 @@ void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb,
iph->version = 4;
iph->ihl = sizeof(struct iphdr) >> 2;
- iph->frag_off = ip_mtu_locked(&rt->dst) ? 0 : df;
+ iph->frag_off = ip_mtu_locked(ndst) ? 0 : df;
iph->protocol = proto;
iph->tos = tos;
iph->daddr = dst;
diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
index 54386e06a813..e298861e005d 100644
--- a/net/ipv4/udp_tunnel_core.c
+++ b/net/ipv4/udp_tunnel_core.c
@@ -171,7 +171,7 @@ void udp_tunnel_notify_del_rx_port(struct socket *sock, unsigned short type)
}
EXPORT_SYMBOL_GPL(udp_tunnel_notify_del_rx_port);
-void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb,
+void udp_tunnel_xmit_skb(dstref_t dstref, struct sock *sk, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 tos, __u8 ttl,
__be16 df, __be16 src_port, __be16 dst_port,
bool xnet, bool nocheck, u16 ipcb_flags)
@@ -190,7 +190,7 @@ void udp_tunnel_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb
udp_set_csum(nocheck, skb, src, dst, skb->len);
- iptunnel_xmit(sk, rt, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet,
+ iptunnel_xmit(sk, dstref, skb, src, dst, IPPROTO_UDP, tos, ttl, df, xnet,
ipcb_flags);
}
EXPORT_SYMBOL_GPL(udp_tunnel_xmit_skb);
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
index 0ff547a4bff7..5b6083a27afb 100644
--- a/net/ipv6/ip6_udp_tunnel.c
+++ b/net/ipv6/ip6_udp_tunnel.c
@@ -74,7 +74,7 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg,
}
EXPORT_SYMBOL_GPL(udp_sock_create6);
-void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
+void udp_tunnel6_xmit_skb(dstref_t dstref, struct sock *sk,
struct sk_buff *skb,
struct net_device *dev,
const struct in6_addr *saddr,
@@ -95,7 +95,7 @@ void udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk,
uh->len = htons(skb->len);
- skb_dst_set(skb, dst);
+ skb_dstref_set(skb, dstref);
udp6_set_csum(nocheck, skb, saddr, daddr, skb->len);
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index cf37ad9686e6..ba65bb93b799 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -1026,7 +1026,7 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
skb_set_inner_ipproto(skb, IPPROTO_IPV6);
- iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
+ iptunnel_xmit(NULL, dst_to_dstref(&rt->dst), skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
df, !net_eq(tunnel->net, dev_net(dev)), 0);
return NETDEV_TX_OK;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index d725b2158758..53a6d3adf452 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -261,7 +261,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
skb_set_inner_ipproto(skb, IPPROTO_SCTP);
label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6);
- udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr, &fl6->daddr,
+ udp_tunnel6_xmit_skb(dst_to_dstref(dst), sk, skb, NULL, &fl6->saddr, &fl6->daddr,
tclass, ip6_dst_hoplimit(dst), label,
sctp_sk(sk)->udp_port, t->encap_port, false, 0);
return 0;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 9dbc24af749b..77c16318f62e 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1102,7 +1102,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t)
skb_reset_inner_mac_header(skb);
skb_reset_inner_transport_header(skb);
skb_set_inner_ipproto(skb, IPPROTO_SCTP);
- udp_tunnel_xmit_skb(dst_rtable(dst), sk, skb, fl4->saddr,
+ udp_tunnel_xmit_skb(dst_to_dstref(dst), sk, skb, fl4->saddr,
fl4->daddr, dscp, ip4_dst_hoplimit(dst), df,
sctp_sk(sk)->udp_port, t->encap_port, false, false,
0);
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index b85ab0fb3b8c..8e165b219863 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -195,7 +195,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
}
ttl = ip4_dst_hoplimit(&rt->dst);
- udp_tunnel_xmit_skb(rt, ub->ubsock->sk, skb, src->ipv4.s_addr,
+ udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), ub->ubsock->sk, skb, src->ipv4.s_addr,
dst->ipv4.s_addr, 0, ttl, 0, src->port,
dst->port, false, true, 0);
#if IS_ENABLED(CONFIG_IPV6)
@@ -217,7 +217,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
dst_cache_set_ip6(cache, ndst, &fl6.saddr);
}
ttl = ip6_dst_hoplimit(ndst);
- udp_tunnel6_xmit_skb(ndst, ub->ubsock->sk, skb, NULL,
+ udp_tunnel6_xmit_skb(dst_to_dstref(ndst), ub->ubsock->sk, skb, NULL,
&src->ipv6, &dst->ipv6, 0, ttl, 0,
src->port, dst->port, false, 0);
#endif
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 06/14] net: tunnel: return dstref in udp_tunnel{,6}_dst_lookup
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (4 preceding siblings ...)
2025-11-12 7:27 ` [PATCH net-next v4 05/14] net: tunnel: use dstref in ip and udp tunnel xmit functions Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 07/14] net: tunnel: make udp_tunnel{,6}_dst_lookup return a noref dst Marek Mietus
` (7 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
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@yahoo.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
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 07/14] net: tunnel: make udp_tunnel{,6}_dst_lookup return a noref dst
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (5 preceding siblings ...)
2025-11-12 7:27 ` [PATCH net-next v4 06/14] net: tunnel: return dstref in udp_tunnel{,6}_dst_lookup Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 08/14] net: ovpn: convert ovpn_udp{4,6}_output to use " Marek Mietus
` (6 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
Since udp_tunnel{,6}_dst_lookup return a dstref, we can avoid
incrementing the refcount on the returned dst and return a noref dst.
This only applies when CONFIG_DST_CACHE is enabled. Otherwise we
always perform an output routing lookup, which returns an owned dst.
Update udp_tunnel{,6}_dst_lookup to return a noref dst.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
net/ipv4/udp_tunnel_core.c | 13 ++++++++-----
net/ipv6/ip6_udp_tunnel.c | 13 ++++++++-----
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/net/ipv4/udp_tunnel_core.c b/net/ipv4/udp_tunnel_core.c
index fdfa5420f9bf..9859d6d5f521 100644
--- a/net/ipv4/udp_tunnel_core.c
+++ b/net/ipv4/udp_tunnel_core.c
@@ -240,9 +240,9 @@ int udp_tunnel_dst_lookup(struct sk_buff *skb,
#ifdef CONFIG_DST_CACHE
if (dst_cache) {
- rt = dst_cache_get_ip4(dst_cache, saddr);
+ rt = dst_cache_get_ip4_rcu(dst_cache, saddr);
if (rt) {
- *dstref = dst_to_dstref(&rt->dst);
+ *dstref = dst_to_dstref_noref(&rt->dst);
return 0;
}
}
@@ -269,11 +269,14 @@ int udp_tunnel_dst_lookup(struct sk_buff *skb,
ip_rt_put(rt);
return -ELOOP;
}
+ *saddr = fl4.saddr;
#ifdef CONFIG_DST_CACHE
- if (dst_cache)
- dst_cache_set_ip4(dst_cache, &rt->dst, fl4.saddr);
+ if (dst_cache) {
+ dst_cache_steal_ip4(dst_cache, &rt->dst, fl4.saddr);
+ *dstref = dst_to_dstref_noref(&rt->dst);
+ return 0;
+ }
#endif
- *saddr = fl4.saddr;
*dstref = dst_to_dstref(&rt->dst);
return 0;
}
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c
index ec7bf7d744fe..e832d08b643d 100644
--- a/net/ipv6/ip6_udp_tunnel.c
+++ b/net/ipv6/ip6_udp_tunnel.c
@@ -149,9 +149,9 @@ int udp_tunnel6_dst_lookup(struct sk_buff *skb,
#ifdef CONFIG_DST_CACHE
if (dst_cache) {
- dst = dst_cache_get_ip6(dst_cache, saddr);
+ dst = dst_cache_get_ip6_rcu(dst_cache, saddr);
if (dst) {
- *dstref = dst_to_dstref(dst);
+ *dstref = dst_to_dstref_noref(dst);
return 0;
}
}
@@ -177,11 +177,14 @@ int udp_tunnel6_dst_lookup(struct sk_buff *skb,
dst_release(dst);
return -ELOOP;
}
+ *saddr = fl6.saddr;
#ifdef CONFIG_DST_CACHE
- if (dst_cache)
- dst_cache_set_ip6(dst_cache, dst, &fl6.saddr);
+ if (dst_cache) {
+ dst_cache_steal_ip6(dst_cache, dst, &fl6.saddr);
+ *dstref = dst_to_dstref_noref(dst);
+ return 0;
+ }
#endif
- *saddr = fl6.saddr;
*dstref = dst_to_dstref(dst);
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 08/14] net: ovpn: convert ovpn_udp{4,6}_output to use a noref dst
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (6 preceding siblings ...)
2025-11-12 7:27 ` [PATCH net-next v4 07/14] net: tunnel: make udp_tunnel{,6}_dst_lookup return a noref dst Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 09/14] net: wireguard: convert send{4,6} to use a noref dst when possible Marek Mietus
` (5 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
ovpn_udp{4,6}_output unnecessarily reference the dst_entry from the
dst_cache when interacting with the cache.
Reduce this overhead by avoiding the redundant refcount increments.
These changes are safe as both ipv4 and ip6 support noref xmit under RCU
which is already the case for ovpn.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
drivers/net/ovpn/udp.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c
index a765aee6e36b..6d623a0df782 100644
--- a/drivers/net/ovpn/udp.c
+++ b/drivers/net/ovpn/udp.c
@@ -158,7 +158,7 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
int ret;
local_bh_disable();
- rt = dst_cache_get_ip4(cache, &fl.saddr);
+ rt = dst_cache_get_ip4_rcu(cache, &fl.saddr);
if (rt)
goto transmit;
@@ -194,10 +194,10 @@ static int ovpn_udp4_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
ret);
goto err;
}
- dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
+ dst_cache_steal_ip4(cache, &rt->dst, fl.saddr);
transmit:
- udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sk, skb, fl.saddr, fl.daddr, 0,
+ udp_tunnel_xmit_skb(dst_to_dstref_noref(&rt->dst), sk, skb, fl.saddr, fl.daddr, 0,
ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport,
fl.fl4_dport, false, sk->sk_no_check_tx, 0);
ret = 0;
@@ -235,7 +235,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
};
local_bh_disable();
- dst = dst_cache_get_ip6(cache, &fl.saddr);
+ dst = dst_cache_get_ip6_rcu(cache, &fl.saddr);
if (dst)
goto transmit;
@@ -259,7 +259,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
&bind->remote.in6, ret);
goto err;
}
- dst_cache_set_ip6(cache, dst, &fl.saddr);
+ dst_cache_steal_ip6(cache, dst, &fl.saddr);
transmit:
/* user IPv6 packets may be larger than the transport interface
@@ -272,7 +272,7 @@ static int ovpn_udp6_output(struct ovpn_peer *peer, struct ovpn_bind *bind,
* udp_tunnel_xmit_skb()
*/
skb->ignore_df = 1;
- udp_tunnel6_xmit_skb(dst_to_dstref(dst), sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0,
+ udp_tunnel6_xmit_skb(dst_to_dstref_noref(dst), sk, skb, skb->dev, &fl.saddr, &fl.daddr, 0,
ip6_dst_hoplimit(dst), 0, fl.fl6_sport,
fl.fl6_dport, udp_get_no_check6_tx(sk), 0);
ret = 0;
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 09/14] net: wireguard: convert send{4,6} to use a noref dst when possible
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (7 preceding siblings ...)
2025-11-12 7:27 ` [PATCH net-next v4 08/14] net: ovpn: convert ovpn_udp{4,6}_output to use " Marek Mietus
@ 2025-11-12 7:27 ` Marek Mietus
2025-11-13 16:40 ` Jason A. Donenfeld
2025-11-12 7:33 ` [PATCH net-next v4 10/14] net: tunnel: convert ip_md_tunnel_xmit " Marek Mietus
` (4 subsequent siblings)
13 siblings, 1 reply; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:27 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
send{4,6} unnecessarily reference the dst_entry from the
dst_cache when interacting with the cache.
Reduce this overhead by avoiding the redundant refcount increments.
This is only possible in flows where the cache is used. Otherwise, we
fall-back to a referenced dst.
These changes are safe as both ipv4 and ip6 support noref xmit under RCU
which is already the case for the wireguard send{4,6} functions.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
drivers/net/wireguard/socket.c | 34 ++++++++++++++++++++++++----------
1 file changed, 24 insertions(+), 10 deletions(-)
diff --git a/drivers/net/wireguard/socket.c b/drivers/net/wireguard/socket.c
index 342247d324ab..51c61527da94 100644
--- a/drivers/net/wireguard/socket.c
+++ b/drivers/net/wireguard/socket.c
@@ -29,6 +29,7 @@ static int send4(struct wg_device *wg, struct sk_buff *skb,
};
struct rtable *rt = NULL;
struct sock *sock;
+ dstref_t dstref;
int ret = 0;
skb_mark_not_on_list(skb);
@@ -45,8 +46,10 @@ static int send4(struct wg_device *wg, struct sk_buff *skb,
fl.fl4_sport = inet_sk(sock)->inet_sport;
- if (cache)
- rt = dst_cache_get_ip4(cache, &fl.saddr);
+ if (cache) {
+ rt = dst_cache_get_ip4_rcu(cache, &fl.saddr);
+ dstref = dst_to_dstref_noref(&rt->dst);
+ }
if (!rt) {
security_sk_classify_flow(sock, flowi4_to_flowi_common(&fl));
@@ -77,12 +80,16 @@ static int send4(struct wg_device *wg, struct sk_buff *skb,
wg->dev->name, &endpoint->addr, ret);
goto err;
}
- if (cache)
- dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
+ if (cache) {
+ dst_cache_steal_ip4(cache, &rt->dst, fl.saddr);
+ dstref = dst_to_dstref_noref(&rt->dst);
+ } else {
+ dstref = dst_to_dstref(&rt->dst);
+ }
}
skb->ignore_df = 1;
- udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), sock, skb, fl.saddr, fl.daddr, ds,
+ udp_tunnel_xmit_skb(dstref, sock, skb, fl.saddr, fl.daddr, ds,
ip4_dst_hoplimit(&rt->dst), 0, fl.fl4_sport,
fl.fl4_dport, false, false, 0);
goto out;
@@ -109,6 +116,7 @@ static int send6(struct wg_device *wg, struct sk_buff *skb,
};
struct dst_entry *dst = NULL;
struct sock *sock;
+ dstref_t dstref;
int ret = 0;
skb_mark_not_on_list(skb);
@@ -125,8 +133,10 @@ static int send6(struct wg_device *wg, struct sk_buff *skb,
fl.fl6_sport = inet_sk(sock)->inet_sport;
- if (cache)
- dst = dst_cache_get_ip6(cache, &fl.saddr);
+ if (cache) {
+ dst = dst_cache_get_ip6_rcu(cache, &fl.saddr);
+ dstref = dst_to_dstref_noref(dst);
+ }
if (!dst) {
security_sk_classify_flow(sock, flowi6_to_flowi_common(&fl));
@@ -144,12 +154,16 @@ static int send6(struct wg_device *wg, struct sk_buff *skb,
wg->dev->name, &endpoint->addr, ret);
goto err;
}
- if (cache)
- dst_cache_set_ip6(cache, dst, &fl.saddr);
+ if (cache) {
+ dst_cache_steal_ip6(cache, dst, &fl.saddr);
+ dstref = dst_to_dstref_noref(dst);
+ } else {
+ dstref = dst_to_dstref(dst);
+ }
}
skb->ignore_df = 1;
- udp_tunnel6_xmit_skb(dst_to_dstref(dst), sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds,
+ udp_tunnel6_xmit_skb(dstref, sock, skb, skb->dev, &fl.saddr, &fl.daddr, ds,
ip6_dst_hoplimit(dst), 0, fl.fl6_sport,
fl.fl6_dport, false, 0);
goto out;
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 10/14] net: tunnel: convert ip_md_tunnel_xmit to use a noref dst when possible
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (8 preceding siblings ...)
2025-11-12 7:27 ` [PATCH net-next v4 09/14] net: wireguard: convert send{4,6} to use a noref dst when possible Marek Mietus
@ 2025-11-12 7:33 ` Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 11/14] net: tunnel: convert ip_tunnel_xmit " Marek Mietus
` (3 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:33 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
ip_md_tunnel_xmit unnecessarily references the dst_entry from the
dst_cache when interacting with the cache.
Reduce this overhead by avoiding the redundant refcount increments.
This is only possible in flows where the cache is used. Otherwise, we
fall-back to a referenced dst.
This change is safe since ipv4 supports noref xmit under RCU which is
already the case for ip_md_tunnel_xmit.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
net/ipv4/ip_tunnel.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 6aa045793048..323d085cc377 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -578,6 +578,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
const struct iphdr *inner_iph;
struct rtable *rt = NULL;
struct flowi4 fl4;
+ dstref_t dstref;
__be16 df = 0;
u8 tos, ttl;
bool use_cache;
@@ -608,20 +609,26 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
goto tx_error;
use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
- if (use_cache)
- rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl4.saddr);
+ if (use_cache) {
+ rt = dst_cache_get_ip4_rcu(&tun_info->dst_cache, &fl4.saddr);
+ dstref = dst_to_dstref_noref(&rt->dst);
+ }
if (!rt) {
rt = ip_route_output_key(tunnel->net, &fl4);
if (IS_ERR(rt)) {
DEV_STATS_INC(dev, tx_carrier_errors);
goto tx_error;
}
- if (use_cache)
- dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
- fl4.saddr);
+ if (use_cache) {
+ dst_cache_steal_ip4(&tun_info->dst_cache, &rt->dst,
+ fl4.saddr);
+ dstref = dst_to_dstref_noref(&rt->dst);
+ } else {
+ dstref = dst_to_dstref(&rt->dst);
+ }
}
if (rt->dst.dev == dev) {
- ip_rt_put(rt);
+ dstref_drop(dstref);
DEV_STATS_INC(dev, collisions);
goto tx_error;
}
@@ -630,7 +637,7 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
df = htons(IP_DF);
if (tnl_update_pmtu(dev, skb, rt, df, inner_iph, tunnel_hlen,
key->u.ipv4.dst, true)) {
- ip_rt_put(rt);
+ dstref_drop(dstref);
goto tx_error;
}
@@ -647,13 +654,13 @@ void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len;
if (skb_cow_head(skb, headroom)) {
- ip_rt_put(rt);
+ dstref_drop(dstref);
goto tx_dropped;
}
ip_tunnel_adj_headroom(dev, headroom);
- iptunnel_xmit(NULL, dst_to_dstref(&rt->dst), skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
+ iptunnel_xmit(NULL, dstref, skb, fl4.saddr, fl4.daddr, proto, tos, ttl,
df, !net_eq(tunnel->net, dev_net(dev)), 0);
return;
tx_error:
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 11/14] net: tunnel: convert ip_tunnel_xmit to use a noref dst when possible
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (9 preceding siblings ...)
2025-11-12 7:33 ` [PATCH net-next v4 10/14] net: tunnel: convert ip_md_tunnel_xmit " Marek Mietus
@ 2025-11-12 7:33 ` Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 12/14] net: sit: convert ipip6_tunnel_xmit to use a noref dst Marek Mietus
` (2 subsequent siblings)
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:33 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
ip_tunnel_xmit unnecessarily references the dst_entry from the
dst_cache when interacting with the cache.
Reduce this overhead by avoiding the redundant refcount increments.
This is only possible in flows where the cache is used. Otherwise, we
fall-back to a referenced dst.
This change is safe since ipv4 supports noref xmit under RCU which is
already the case for ip_tunnel_xmit.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
net/ipv4/ip_tunnel.c | 38 +++++++++++++++++++++++---------------
1 file changed, 23 insertions(+), 15 deletions(-)
diff --git a/net/ipv4/ip_tunnel.c b/net/ipv4/ip_tunnel.c
index 323d085cc377..65f4e1cda69d 100644
--- a/net/ipv4/ip_tunnel.c
+++ b/net/ipv4/ip_tunnel.c
@@ -685,6 +685,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
bool use_cache = false;
struct flowi4 fl4;
bool md = false;
+ dstref_t dstref;
bool connected;
u8 tos, ttl;
__be32 dst;
@@ -777,30 +778,37 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
if (connected && md) {
use_cache = ip_tunnel_dst_cache_usable(skb, tun_info);
if (use_cache)
- rt = dst_cache_get_ip4(&tun_info->dst_cache,
- &fl4.saddr);
+ rt = dst_cache_get_ip4_rcu(&tun_info->dst_cache,
+ &fl4.saddr);
} else {
- rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache,
- &fl4.saddr) : NULL;
+ rt = connected ? dst_cache_get_ip4_rcu(&tunnel->dst_cache,
+ &fl4.saddr) : NULL;
}
- if (!rt) {
+ if (rt) {
+ dstref = dst_to_dstref_noref(&rt->dst);
+ } else {
rt = ip_route_output_key(tunnel->net, &fl4);
if (IS_ERR(rt)) {
DEV_STATS_INC(dev, tx_carrier_errors);
goto tx_error;
}
- if (use_cache)
- dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst,
- fl4.saddr);
- else if (!md && connected)
- dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst,
- fl4.saddr);
+ if (use_cache) {
+ dst_cache_steal_ip4(&tun_info->dst_cache, &rt->dst,
+ fl4.saddr);
+ dstref = dst_to_dstref_noref(&rt->dst);
+ } else if (!md && connected) {
+ dst_cache_steal_ip4(&tunnel->dst_cache, &rt->dst,
+ fl4.saddr);
+ dstref = dst_to_dstref_noref(&rt->dst);
+ } else {
+ dstref = dst_to_dstref(&rt->dst);
+ }
}
if (rt->dst.dev == dev) {
- ip_rt_put(rt);
+ dstref_drop(dstref);
DEV_STATS_INC(dev, collisions);
goto tx_error;
}
@@ -810,7 +818,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
df |= (inner_iph->frag_off & htons(IP_DF));
if (tnl_update_pmtu(dev, skb, rt, df, inner_iph, 0, 0, false)) {
- ip_rt_put(rt);
+ dstref_drop(dstref);
goto tx_error;
}
@@ -841,7 +849,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
+ rt->dst.header_len + ip_encap_hlen(&tunnel->encap);
if (skb_cow_head(skb, max_headroom)) {
- ip_rt_put(rt);
+ dstref_drop(dstref);
DEV_STATS_INC(dev, tx_dropped);
kfree_skb(skb);
return;
@@ -849,7 +857,7 @@ void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev,
ip_tunnel_adj_headroom(dev, max_headroom);
- iptunnel_xmit(NULL, dst_to_dstref(&rt->dst), skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
+ iptunnel_xmit(NULL, dstref, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
df, !net_eq(tunnel->net, dev_net(dev)), 0);
return;
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 12/14] net: sit: convert ipip6_tunnel_xmit to use a noref dst
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (10 preceding siblings ...)
2025-11-12 7:33 ` [PATCH net-next v4 11/14] net: tunnel: convert ip_tunnel_xmit " Marek Mietus
@ 2025-11-12 7:33 ` Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 13/14] net: tipc: convert tipc_udp_xmit " Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 14/14] net: sctp: convert sctp_v{4,6}_xmit to use a noref dst when possible Marek Mietus
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:33 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
ipip6_tunnel_xmit unnecessarily references the dst_entry from the
dst_cache when interacting with the cache.
Reduce this overhead by avoiding the redundant refcount increments.
This change is safe since ipv4 supports noref xmit under RCU which is
already the case for ipip6_tunnel_xmit.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
net/ipv6/sit.c | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index ba65bb93b799..98f2e5fb5957 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -933,31 +933,28 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
IPPROTO_IPV6, 0, dst, tiph->saddr, 0, 0,
sock_net_uid(tunnel->net, NULL));
- rt = dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr);
+ rt = dst_cache_get_ip4_rcu(&tunnel->dst_cache, &fl4.saddr);
if (!rt) {
rt = ip_route_output_flow(tunnel->net, &fl4, NULL);
if (IS_ERR(rt)) {
DEV_STATS_INC(dev, tx_carrier_errors);
goto tx_error_icmp;
}
- dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr);
+ dst_cache_steal_ip4(&tunnel->dst_cache, &rt->dst, fl4.saddr);
}
if (rt->rt_type != RTN_UNICAST && rt->rt_type != RTN_LOCAL) {
- ip_rt_put(rt);
DEV_STATS_INC(dev, tx_carrier_errors);
goto tx_error_icmp;
}
tdev = rt->dst.dev;
if (tdev == dev) {
- ip_rt_put(rt);
DEV_STATS_INC(dev, collisions);
goto tx_error;
}
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) {
- ip_rt_put(rt);
goto tx_error;
}
@@ -966,7 +963,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
if (mtu < IPV4_MIN_MTU) {
DEV_STATS_INC(dev, collisions);
- ip_rt_put(rt);
goto tx_error;
}
@@ -980,7 +976,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
if (skb->len > mtu && !skb_is_gso(skb)) {
icmpv6_ndo_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu);
- ip_rt_put(rt);
goto tx_error;
}
}
@@ -1003,7 +998,6 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
(skb_cloned(skb) && !skb_clone_writable(skb, 0))) {
struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom);
if (!new_skb) {
- ip_rt_put(rt);
DEV_STATS_INC(dev, tx_dropped);
kfree_skb(skb);
return NETDEV_TX_OK;
@@ -1020,14 +1014,13 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6));
if (ip_tunnel_encap(skb, &tunnel->encap, &protocol, &fl4) < 0) {
- ip_rt_put(rt);
goto tx_error;
}
skb_set_inner_ipproto(skb, IPPROTO_IPV6);
- iptunnel_xmit(NULL, dst_to_dstref(&rt->dst), skb, fl4.saddr, fl4.daddr, protocol, tos, ttl,
- df, !net_eq(tunnel->net, dev_net(dev)), 0);
+ iptunnel_xmit(NULL, dst_to_dstref_noref(&rt->dst), skb, fl4.saddr, fl4.daddr, protocol,
+ tos, ttl, df, !net_eq(tunnel->net, dev_net(dev)), 0);
return NETDEV_TX_OK;
tx_error_icmp:
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 13/14] net: tipc: convert tipc_udp_xmit to use a noref dst
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (11 preceding siblings ...)
2025-11-12 7:33 ` [PATCH net-next v4 12/14] net: sit: convert ipip6_tunnel_xmit to use a noref dst Marek Mietus
@ 2025-11-12 7:33 ` Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 14/14] net: sctp: convert sctp_v{4,6}_xmit to use a noref dst when possible Marek Mietus
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:33 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
tipc_udp_xmit unnecessarily references the dst_entry from the
dst_cache when interacting with the cache.
Reduce this overhead by avoiding the redundant refcount increments.
This change is safe as both ipv4 and ip6 support noref xmit under RCU
which is already the case for tipc_udp_xmit.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
net/tipc/udp_media.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c
index 8e165b219863..2a6c4df0c0a8 100644
--- a/net/tipc/udp_media.c
+++ b/net/tipc/udp_media.c
@@ -175,7 +175,7 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
int ttl, err;
local_bh_disable();
- ndst = dst_cache_get(cache);
+ ndst = dst_cache_get_rcu(cache);
if (dst->proto == htons(ETH_P_IP)) {
struct rtable *rt = dst_rtable(ndst);
@@ -191,13 +191,13 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
err = PTR_ERR(rt);
goto tx_error;
}
- dst_cache_set_ip4(cache, &rt->dst, fl.saddr);
+ dst_cache_steal_ip4(cache, &rt->dst, fl.saddr);
}
ttl = ip4_dst_hoplimit(&rt->dst);
- udp_tunnel_xmit_skb(dst_to_dstref(&rt->dst), ub->ubsock->sk, skb, src->ipv4.s_addr,
- dst->ipv4.s_addr, 0, ttl, 0, src->port,
- dst->port, false, true, 0);
+ udp_tunnel_xmit_skb(dst_to_dstref_noref(&rt->dst), ub->ubsock->sk, skb,
+ src->ipv4.s_addr, dst->ipv4.s_addr, 0, ttl, 0,
+ src->port, dst->port, false, true, 0);
#if IS_ENABLED(CONFIG_IPV6)
} else {
if (!ndst) {
@@ -214,10 +214,10 @@ static int tipc_udp_xmit(struct net *net, struct sk_buff *skb,
err = PTR_ERR(ndst);
goto tx_error;
}
- dst_cache_set_ip6(cache, ndst, &fl6.saddr);
+ dst_cache_steal_ip6(cache, ndst, &fl6.saddr);
}
ttl = ip6_dst_hoplimit(ndst);
- udp_tunnel6_xmit_skb(dst_to_dstref(ndst), ub->ubsock->sk, skb, NULL,
+ udp_tunnel6_xmit_skb(dst_to_dstref_noref(ndst), ub->ubsock->sk, skb, NULL,
&src->ipv6, &dst->ipv6, 0, ttl, 0,
src->port, dst->port, false, 0);
#endif
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* [PATCH net-next v4 14/14] net: sctp: convert sctp_v{4,6}_xmit to use a noref dst when possible
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
` (12 preceding siblings ...)
2025-11-12 7:33 ` [PATCH net-next v4 13/14] net: tipc: convert tipc_udp_xmit " Marek Mietus
@ 2025-11-12 7:33 ` Marek Mietus
13 siblings, 0 replies; 21+ messages in thread
From: Marek Mietus @ 2025-11-12 7:33 UTC (permalink / raw)
To: netdev, sd, kuba; +Cc: Marek Mietus
sctp_v{4,6}_xmit unnecessarily clone the dst from the transport when
sending an encapsulated skb.
Reduce this overhead by avoiding the refcount increment introduced by
cloning the dst.
Since t->dst is already assumed to be valid throughout both functions,
it's safe to use the dst without incrementing the refcount.
Signed-off-by: Marek Mietus <mmietus97@yahoo.com>
---
net/sctp/ipv6.c | 6 +++---
net/sctp/protocol.c | 6 +++---
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 53a6d3adf452..7b1dbd9aa565 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -219,7 +219,7 @@ int sctp_udp_v6_err(struct sock *sk, struct sk_buff *skb)
static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
{
- struct dst_entry *dst = dst_clone(t->dst);
+ struct dst_entry *dst = t->dst;
struct flowi6 *fl6 = &t->fl.u.ip6;
struct sock *sk = skb->sk;
struct ipv6_pinfo *np = inet6_sk(sk);
@@ -243,7 +243,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
if (!t->encap_port || !sctp_sk(sk)->udp_port) {
int res;
- skb_dst_set(skb, dst);
+ skb_dst_set(skb, dst_clone(dst));
rcu_read_lock();
res = ip6_xmit(sk, skb, fl6, sk->sk_mark,
rcu_dereference(np->opt),
@@ -261,7 +261,7 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
skb_set_inner_ipproto(skb, IPPROTO_SCTP);
label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6);
- udp_tunnel6_xmit_skb(dst_to_dstref(dst), sk, skb, NULL, &fl6->saddr, &fl6->daddr,
+ udp_tunnel6_xmit_skb(dst_to_dstref_noref(dst), sk, skb, NULL, &fl6->saddr, &fl6->daddr,
tclass, ip6_dst_hoplimit(dst), label,
sctp_sk(sk)->udp_port, t->encap_port, false, 0);
return 0;
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 77c16318f62e..04990727c1b0 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -1070,7 +1070,7 @@ static int sctp_inet_supported_addrs(const struct sctp_sock *opt,
/* Wrapper routine that calls the ip transmit routine. */
static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t)
{
- struct dst_entry *dst = dst_clone(t->dst);
+ struct dst_entry *dst = t->dst;
struct flowi4 *fl4 = &t->fl.u.ip4;
struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
@@ -1088,7 +1088,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t)
SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
if (!t->encap_port || !sctp_sk(sk)->udp_port) {
- skb_dst_set(skb, dst);
+ skb_dst_set(skb, dst_clone(dst));
return __ip_queue_xmit(sk, skb, &t->fl, dscp);
}
@@ -1102,7 +1102,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t)
skb_reset_inner_mac_header(skb);
skb_reset_inner_transport_header(skb);
skb_set_inner_ipproto(skb, IPPROTO_SCTP);
- udp_tunnel_xmit_skb(dst_to_dstref(dst), sk, skb, fl4->saddr,
+ udp_tunnel_xmit_skb(dst_to_dstref_noref(dst), sk, skb, fl4->saddr,
fl4->daddr, dscp, ip4_dst_hoplimit(dst), df,
sctp_sk(sk)->udp_port, t->encap_port, false, false,
0);
--
2.51.0
^ permalink raw reply related [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry
2025-11-12 7:27 ` [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry Marek Mietus
@ 2025-11-12 17:09 ` Sabrina Dubroca
2025-11-13 9:36 ` Marek Mietus
0 siblings, 1 reply; 21+ messages in thread
From: Sabrina Dubroca @ 2025-11-12 17:09 UTC (permalink / raw)
To: Marek Mietus, edumazet, pabeni, kuba, davem; +Cc: netdev
2025-11-12, 08:27:08 +0100, Marek Mietus wrote:
> Use the newly introduced dstref object for storing the dst entry
> in skb instead of using _skb_refdst, and remove code related
> to _skb_refdst.
This is an important change to a very core part of networking. You
need to CC all the networking maintainers/reviewers for this series
(ask scripts/get_maintainer.pl).
> This is mostly a cosmetic improvement. It improves readability
That rename, and the rest of the changes in this series. is causing
some non-negligible churn and will take a while to review, to ensure
all the conversions are correct.
@Maintainers can I get some time to look at this in detail?
Also, I'm not sure how we ended up from the previous proposal ("some
tunnels are under RCU so they don't need a reference" [1]) to this.
[1] https://lore.kernel.org/netdev/20250922110622.10368-1-mmietus97@yahoo.com/
--
Sabrina
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry
2025-11-12 17:09 ` Sabrina Dubroca
@ 2025-11-13 9:36 ` Marek Mietus
[not found] ` <CANn89i+qce6WJYUpjH93SMRKA8cQ6Wt-b81O6gu9V5GGnDeo_A@mail.gmail.com>
0 siblings, 1 reply; 21+ messages in thread
From: Marek Mietus @ 2025-11-13 9:36 UTC (permalink / raw)
To: Sabrina Dubroca, edumazet, pabeni, kuba, davem; +Cc: netdev
W dniu 11/12/25 o 18:09, Sabrina Dubroca pisze:
> 2025-11-12, 08:27:08 +0100, Marek Mietus wrote:
>> Use the newly introduced dstref object for storing the dst entry
>> in skb instead of using _skb_refdst, and remove code related
>> to _skb_refdst.
>
> This is an important change to a very core part of networking. You
> need to CC all the networking maintainers/reviewers for this series
> (ask scripts/get_maintainer.pl).
Noted for next time.
>
>> This is mostly a cosmetic improvement. It improves readability
>
> That rename, and the rest of the changes in this series. is causing
> some non-negligible churn and will take a while to review, to ensure
> all the conversions are correct.
>
> @Maintainers can I get some time to look at this in detail?
>
I figured it would require a thorough review.
Thank you for taking the time to look at it!
>
> Also, I'm not sure how we ended up from the previous proposal ("some
> tunnels are under RCU so they don't need a reference" [1]) to this.
>
> [1] https://lore.kernel.org/netdev/20250922110622.10368-1-mmietus97@yahoo.com/
>
As previously discussed with Jakub [2], tunnels that use udp_tunnel_dst_lookup
add notable complexity because the returned dst could either be from
ip_route_output_key (referenced) or from the dst_cache (which I'm changing to
be noref). There are also other tunnels that follow a similar pattern.
The cleanest way to keep track of which dst is referenced and which isn't
is to borrow existing refdst concepts. This allows us to more easily track
the ref state of dst_entries in later flows to avoid unnecessarily taking
a reference. I played around with a couple implementations and this turned
out to be the most elegant. It's a big change, but it's mostly semantic.
[2] https://lore.kernel.org/netdev/20250923184856.6cce6530@kernel.org/
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v4 09/14] net: wireguard: convert send{4,6} to use a noref dst when possible
2025-11-12 7:27 ` [PATCH net-next v4 09/14] net: wireguard: convert send{4,6} to use a noref dst when possible Marek Mietus
@ 2025-11-13 16:40 ` Jason A. Donenfeld
0 siblings, 0 replies; 21+ messages in thread
From: Jason A. Donenfeld @ 2025-11-13 16:40 UTC (permalink / raw)
To: Marek Mietus; +Cc: netdev, sd, kuba
Hi Marek,
On Wed, Nov 12, 2025 at 08:27:15AM +0100, Marek Mietus wrote:
> send{4,6} unnecessarily reference the dst_entry from the
> dst_cache when interacting with the cache.
>
> Reduce this overhead by avoiding the redundant refcount increments.
>
> This is only possible in flows where the cache is used. Otherwise, we
> fall-back to a referenced dst.
>
> These changes are safe as both ipv4 and ip6 support noref xmit under RCU
> which is already the case for the wireguard send{4,6} functions.
Assuming the rest of the patchset is fine, this patch is okay with me,
with one very small nit. The commit subject should be
wireguard: socket: convert send{4,6} to use a noref dst when possible
instead of "net: wireguard" etc.
Please CC me on future revisions of this if you do a v2, and I'll give
my reviewed-by.
Thanks,
Jason
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry
[not found] ` <CANn89i+qce6WJYUpjH93SMRKA8cQ6Wt-b81O6gu9V5GGnDeo_A@mail.gmail.com>
@ 2025-11-13 18:17 ` Sabrina Dubroca
2025-11-17 11:31 ` Marek Mietus
0 siblings, 1 reply; 21+ messages in thread
From: Sabrina Dubroca @ 2025-11-13 18:17 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Marek Mietus, pabeni, kuba, davem, netdev
Eric, it seems your email didn't make it to netdev, quoting:
2025-11-13, 02:38:02 -0800, Eric Dumazet wrote:
> On Thu, Nov 13, 2025 at 1:37 AM Marek Mietus <mmietus97@yahoo.com> wrote:
>
> > W dniu 11/12/25 o 18:09, Sabrina Dubroca pisze:
> > > 2025-11-12, 08:27:08 +0100, Marek Mietus wrote:
> > >> Use the newly introduced dstref object for storing the dst entry
> > >> in skb instead of using _skb_refdst, and remove code related
> > >> to _skb_refdst.
> > >
> > > This is an important change to a very core part of networking. You
> > > need to CC all the networking maintainers/reviewers for this series
> > > (ask scripts/get_maintainer.pl).
> >
> > Noted for next time.
> >
> > >
> > >> This is mostly a cosmetic improvement. It improves readability
> > >
> > > That rename, and the rest of the changes in this series. is causing
> > > some non-negligible churn and will take a while to review, to ensure
> > > all the conversions are correct.
> > >
> > > @Maintainers can I get some time to look at this in detail?
> > >
> >
> > I figured it would require a thorough review.
> > Thank you for taking the time to look at it!
> >
> > >
> > > Also, I'm not sure how we ended up from the previous proposal ("some
> > > tunnels are under RCU so they don't need a reference" [1]) to this.
> > >
> > > [1]
> > https://lore.kernel.org/netdev/20250922110622.10368-1-mmietus97@yahoo.com/
> > >
> >
> > As previously discussed with Jakub [2], tunnels that use
> > udp_tunnel_dst_lookup
> > add notable complexity because the returned dst could either be from
> > ip_route_output_key (referenced) or from the dst_cache (which I'm changing
> > to
> > be noref). There are also other tunnels that follow a similar pattern.
But IMO Jakub's comment about technical debt is not addressed by
pushing dstref all over the tunnel code.
> > The cleanest way to keep track of which dst is referenced and which isn't
> > is to borrow existing refdst concepts. This allows us to more easily track
> > the ref state of dst_entries in later flows to avoid unnecessarily taking
> > a reference. I played around with a couple implementations and this turned
> > out to be the most elegant. It's a big change, but it's mostly semantic.
> >
> > [2] https://lore.kernel.org/netdev/20250923184856.6cce6530@kernel.org/
>
>
> I have not seen the series, so I had to go to the archives.
>
> Too much code churn for my taste, and a true nightmare for future backports
> to stable kernels.
>
> Unless I am mistaken, this is your first submission to the linux kernel,
> please start with more manageable patches.
--
Sabrina
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry
2025-11-13 18:17 ` Sabrina Dubroca
@ 2025-11-17 11:31 ` Marek Mietus
2025-11-18 0:10 ` Jakub Kicinski
0 siblings, 1 reply; 21+ messages in thread
From: Marek Mietus @ 2025-11-17 11:31 UTC (permalink / raw)
To: Sabrina Dubroca, Eric Dumazet; +Cc: netdev, kuba, pabeni, davem
Dear Eric and Sabrina, I'm replying to both of you here.
W dniu 11/13/25 o 19:17, Sabrina Dubroca pisze:
> Eric, it seems your email didn't make it to netdev, quoting:
>
> 2025-11-13, 02:38:02 -0800, Eric Dumazet wrote:
>> On Thu, Nov 13, 2025 at 1:37 AM Marek Mietus <mmietus97@yahoo.com> wrote:
>>
>>> W dniu 11/12/25 o 18:09, Sabrina Dubroca pisze:
>>>> 2025-11-12, 08:27:08 +0100, Marek Mietus wrote:
>>>>> Use the newly introduced dstref object for storing the dst entry
>>>>> in skb instead of using _skb_refdst, and remove code related
>>>>> to _skb_refdst.
>>>>
>>>> This is an important change to a very core part of networking. You
>>>> need to CC all the networking maintainers/reviewers for this series
>>>> (ask scripts/get_maintainer.pl).
>>>
>>> Noted for next time.
>>>
>>>>
>>>>> This is mostly a cosmetic improvement. It improves readability
>>>>
>>>> That rename, and the rest of the changes in this series. is causing
>>>> some non-negligible churn and will take a while to review, to ensure
>>>> all the conversions are correct.
>>>>
>>>> @Maintainers can I get some time to look at this in detail?
>>>>
>>>
>>> I figured it would require a thorough review.
>>> Thank you for taking the time to look at it!
>>>
>>>>
>>>> Also, I'm not sure how we ended up from the previous proposal ("some
>>>> tunnels are under RCU so they don't need a reference" [1]) to this.
>>>>
>>>> [1]
>>> https://lore.kernel.org/netdev/20250922110622.10368-1-mmietus97@yahoo.com/
>>>>
>>>
>>> As previously discussed with Jakub [2], tunnels that use
>>> udp_tunnel_dst_lookup
>>> add notable complexity because the returned dst could either be from
>>> ip_route_output_key (referenced) or from the dst_cache (which I'm changing
>>> to
>>> be noref). There are also other tunnels that follow a similar pattern.
>
> But IMO Jakub's comment about technical debt is not addressed by
> pushing dstref all over the tunnel code.
>
>
I understood it differently. I thought the aforementioned debt referred
to maintaining two different APIs that accomplish the same result, which
is why I took the time to replace all callers in all of the tunnels to use
the new API, and removed the old API. Maybe Jakub can clarify.
>>> The cleanest way to keep track of which dst is referenced and which isn't
>>> is to borrow existing refdst concepts. This allows us to more easily track
>>> the ref state of dst_entries in later flows to avoid unnecessarily taking
>>> a reference. I played around with a couple implementations and this turned
>>> out to be the most elegant. It's a big change, but it's mostly semantic.
>>>
>>> [2] https://lore.kernel.org/netdev/20250923184856.6cce6530@kernel.org/
>>
>>
>> I have not seen the series, so I had to go to the archives.
>>
>> Too much code churn for my taste, and a true nightmare for future backports
>> to stable kernels.
>>
>> Unless I am mistaken, this is your first submission to the linux kernel,
>> please start with more manageable patches.
>
You are correct. This is my first submission. Initially, this series was much
smaller, but that changed due to the generous feedback from Sabrina, Jakub and
Paolo. I tried to make this series smaller, but that ended up in code duplication
between tunnels and some spaghetti code. I did spend quite some time on this new
version, so I'd love to hear your suggestions / feedback if you have any, as I'd
like to continue working on this feature.
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry
2025-11-17 11:31 ` Marek Mietus
@ 2025-11-18 0:10 ` Jakub Kicinski
0 siblings, 0 replies; 21+ messages in thread
From: Jakub Kicinski @ 2025-11-18 0:10 UTC (permalink / raw)
To: Marek Mietus; +Cc: Sabrina Dubroca, Eric Dumazet, netdev, pabeni, davem
On Mon, 17 Nov 2025 12:31:00 +0100 Marek Mietus wrote:
> > But IMO Jakub's comment about technical debt is not addressed by
> > pushing dstref all over the tunnel code.
>
> I understood it differently. I thought the aforementioned debt referred
> to maintaining two different APIs that accomplish the same result, which
> is why I took the time to replace all callers in all of the tunnels to use
> the new API, and removed the old API. Maybe Jakub can clarify.
True, my direct complaint was about only converting a subset of tunnels.
But as Eric said you seem to have gone too far in the opposite direction
now :(
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2025-11-18 0:10 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20251112072720.5076-1-mmietus97.ref@yahoo.com>
2025-11-12 7:27 ` [PATCH net-next v4 00/14] net: tunnel: introduce noref xmit flows for tunnels Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 01/14] net: dst: implement dstref object Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 02/14] net: skb: use dstref for storing dst entry Marek Mietus
2025-11-12 17:09 ` Sabrina Dubroca
2025-11-13 9:36 ` Marek Mietus
[not found] ` <CANn89i+qce6WJYUpjH93SMRKA8cQ6Wt-b81O6gu9V5GGnDeo_A@mail.gmail.com>
2025-11-13 18:17 ` Sabrina Dubroca
2025-11-17 11:31 ` Marek Mietus
2025-11-18 0:10 ` Jakub Kicinski
2025-11-12 7:27 ` [PATCH net-next v4 03/14] net: skb: rename skb_dstref_restore to skb_dstref_set Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 04/14] net: dst_cache: add noref versions for dst_cache Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 05/14] net: tunnel: use dstref in ip and udp tunnel xmit functions Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 06/14] net: tunnel: return dstref in udp_tunnel{,6}_dst_lookup Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 07/14] net: tunnel: make udp_tunnel{,6}_dst_lookup return a noref dst Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 08/14] net: ovpn: convert ovpn_udp{4,6}_output to use " Marek Mietus
2025-11-12 7:27 ` [PATCH net-next v4 09/14] net: wireguard: convert send{4,6} to use a noref dst when possible Marek Mietus
2025-11-13 16:40 ` Jason A. Donenfeld
2025-11-12 7:33 ` [PATCH net-next v4 10/14] net: tunnel: convert ip_md_tunnel_xmit " Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 11/14] net: tunnel: convert ip_tunnel_xmit " Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 12/14] net: sit: convert ipip6_tunnel_xmit to use a noref dst Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 13/14] net: tipc: convert tipc_udp_xmit " Marek Mietus
2025-11-12 7:33 ` [PATCH net-next v4 14/14] net: sctp: convert sctp_v{4,6}_xmit to use a noref dst when possible Marek Mietus
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).