Linux Netfilter development
 help / color / mirror / Atom feed
* [PATCH nf,v2] netfilter: nfnetlink_queue: hash queue instance by portid too
@ 2026-09-16 22:02 Pablo Neira Ayuso
  2026-09-16 22:15 ` Pablo Neira Ayuso
  0 siblings, 1 reply; 2+ messages in thread
From: Pablo Neira Ayuso @ 2026-09-16 22:02 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw

netlink_release() calls netlink_remove() before delivering the
NETLINK_URELEASE event. And a new queue instance can be created before
delivering such NETLINK_URELEASE event. This allows for two different
queue instances with the same portid to co-exist for a little while.
Since the instance that is going away is destroyed by portid via netlink
notifier, both the newly created instance and the one that is going away
with the same portid are destroyed.

Fixes: 7af4cc3fa158 ("[NETFILTER]: Add "nfnetlink_queue" netfilter queue handler over nfnetlink")
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: look up at the right instance_table in instance_lookup_by_portid()

 net/netfilter/nfnetlink_queue.c | 31 +++++++++++++++++++++++++++++--
 1 file changed, 29 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index a3bc00280051..07f279c9dd54 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -69,6 +69,7 @@
 
 struct nfqnl_instance {
 	struct hlist_node hlist;		/* global list of queues */
+	struct hlist_node hlist_portid;		/* global list of queues, by portid */
 	struct rhashtable nfqnl_packet_map;
 	struct rcu_work	rwork;
 
@@ -101,6 +102,7 @@ static unsigned int nfnl_queue_net_id __read_mostly;
 struct nfnl_queue_net {
 	spinlock_t instances_lock;
 	struct hlist_head instance_table[INSTANCE_BUCKETS];
+	struct hlist_head instance_table_portid[INSTANCE_BUCKETS];
 };
 
 static struct nfnl_queue_net *nfnl_queue_pernet(struct net *net)
@@ -113,6 +115,11 @@ static inline u_int8_t instance_hashfn(u_int16_t queue_num)
 	return ((queue_num >> 8) ^ queue_num) % INSTANCE_BUCKETS;
 }
 
+static inline u8 instance_portid_hashfn(u32 portid)
+{
+	return portid % INSTANCE_BUCKETS;
+}
+
 static const struct rhashtable_params nfqnl_rhashtable_params = {
 	.head_offset = offsetof(struct nf_queue_entry, hash_node),
 	.key_offset = offsetof(struct nf_queue_entry, id),
@@ -136,6 +143,20 @@ instance_lookup(struct nfnl_queue_net *q, u_int16_t queue_num)
 	return NULL;
 }
 
+static struct nfqnl_instance *
+instance_lookup_by_portid(struct nfnl_queue_net *q, u32 portid)
+{
+	struct nfqnl_instance *inst;
+	struct hlist_head *head;
+
+	head = &q->instance_table_portid[instance_portid_hashfn(portid)];
+	hlist_for_each_entry(inst, head, hlist) {
+		if (inst->peer_portid == portid)
+			return inst;
+	}
+	return NULL;
+}
+
 static struct nfqnl_instance *
 instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
 {
@@ -160,7 +181,8 @@ instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
 		goto out_free;
 
 	spin_lock(&q->instances_lock);
-	if (instance_lookup(q, queue_num)) {
+	if (instance_lookup(q, queue_num) ||
+	    instance_lookup_by_portid(q, queue_num)) {
 		err = -EEXIST;
 		goto out_unlock;
 	}
@@ -172,6 +194,8 @@ instance_create(struct nfnl_queue_net *q, u_int16_t queue_num, u32 portid)
 
 	h = instance_hashfn(queue_num);
 	hlist_add_head_rcu(&inst->hlist, &q->instance_table[h]);
+	h = instance_portid_hashfn(portid);
+	hlist_add_head(&inst->hlist_portid, &q->instance_table_portid[h]);
 
 	spin_unlock(&q->instances_lock);
 
@@ -208,6 +232,7 @@ static void
 __instance_destroy(struct nfqnl_instance *inst)
 {
 	hlist_del_rcu(&inst->hlist);
+	hlist_del(&inst->hlist_portid);
 
 	INIT_RCU_WORK(&inst->rwork, instance_destroy_work);
 	queue_rcu_work(nfq_cleanup_wq, &inst->rwork);
@@ -2121,8 +2146,10 @@ static int __net_init nfnl_queue_net_init(struct net *net)
 	unsigned int i;
 	struct nfnl_queue_net *q = nfnl_queue_pernet(net);
 
-	for (i = 0; i < INSTANCE_BUCKETS; i++)
+	for (i = 0; i < INSTANCE_BUCKETS; i++) {
 		INIT_HLIST_HEAD(&q->instance_table[i]);
+		INIT_HLIST_HEAD(&q->instance_table_portid[i]);
+	}
 
 	spin_lock_init(&q->instances_lock);
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH nf,v2] netfilter: nfnetlink_queue: hash queue instance by portid too
  2026-09-16 22:02 [PATCH nf,v2] netfilter: nfnetlink_queue: hash queue instance by portid too Pablo Neira Ayuso
@ 2026-09-16 22:15 ` Pablo Neira Ayuso
  0 siblings, 0 replies; 2+ messages in thread
From: Pablo Neira Ayuso @ 2026-09-16 22:15 UTC (permalink / raw)
  To: netfilter-devel; +Cc: fw

On Thu, Sep 17, 2026 at 12:02:51AM +0200, Pablo Neira Ayuso wrote:
> netlink_release() calls netlink_remove() before delivering the
> NETLINK_URELEASE event. And a new queue instance can be created before
> delivering such NETLINK_URELEASE event. This allows for two different
> queue instances with the same portid to co-exist for a little while.
> Since the instance that is going away is destroyed by portid via netlink
> notifier, both the newly created instance and the one that is going away
> with the same portid are destroyed.

Scratch this too, it's botched.

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-16 22:15 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-16 22:02 [PATCH nf,v2] netfilter: nfnetlink_queue: hash queue instance by portid too Pablo Neira Ayuso
2026-09-16 22:15 ` Pablo Neira Ayuso

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox