[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251112072720.5076-2-mmietus97@yahoo.com>
Date: Wed, 12 Nov 2025 08:27:07 +0100
From: Marek Mietus <mmietus97@...oo.com>
To: netdev@...r.kernel.org,
sd@...asysnail.net,
kuba@...nel.org
Cc: Marek Mietus <mmietus97@...oo.com>
Subject: [PATCH net-next v4 01/14] net: dst: implement dstref object
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@...oo.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
Powered by blists - more mailing lists