git: d1a8f1a62f31 - main - ipfw: don't use the upper half lock to walk dynamic states buckets

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Mon, 26 Jan 2026 23:12:32 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=d1a8f1a62f31779e1902b856b44249b198178fc9

commit d1a8f1a62f31779e1902b856b44249b198178fc9
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-01-26 23:05:17 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-01-26 23:05:17 +0000

    ipfw: don't use the upper half lock to walk dynamic states buckets
    
    The lock is sleepable and we can't grab it in dyn_tick().  Use the
    individual bucket locks instead.
    
    Fixes:  e3caa360d5d0a73af0de1d293d5b8ff6e900ceb4
---
 sys/netpfil/ipfw/ip_fw_dynamic.c | 18 ++++--------------
 1 file changed, 4 insertions(+), 14 deletions(-)

diff --git a/sys/netpfil/ipfw/ip_fw_dynamic.c b/sys/netpfil/ipfw/ip_fw_dynamic.c
index 99fd72de5e0a..d2bf4f4fc899 100644
--- a/sys/netpfil/ipfw/ip_fw_dynamic.c
+++ b/sys/netpfil/ipfw/ip_fw_dynamic.c
@@ -2498,13 +2498,8 @@ dyn_send_keepalive_ipv4(struct ip_fw_chain *chain)
 	uint32_t bucket;
 
 	mbufq_init(&q, INT_MAX);
-	IPFW_UH_RLOCK(chain);
-	/*
-	 * It is safe to not use hazard pointer and just do lockless
-	 * access to the lists, because states entries can not be deleted
-	 * while we hold IPFW_UH_RLOCK.
-	 */
 	for (bucket = 0; bucket < V_curr_dyn_buckets; bucket++) {
+		DYN_BUCKET_LOCK(bucket);
 		CK_SLIST_FOREACH(s, &V_dyn_ipv4[bucket], entry) {
 			/*
 			 * Only established TCP connections that will
@@ -2517,8 +2512,8 @@ dyn_send_keepalive_ipv4(struct ip_fw_chain *chain)
 				continue;
 			dyn_enqueue_keepalive_ipv4(&q, s);
 		}
+		DYN_BUCKET_UNLOCK(bucket);
 	}
-	IPFW_UH_RUNLOCK(chain);
 	while ((m = mbufq_dequeue(&q)) != NULL)
 		ip_output(m, NULL, NULL, 0, NULL, NULL);
 }
@@ -2605,13 +2600,8 @@ dyn_send_keepalive_ipv6(struct ip_fw_chain *chain)
 	uint32_t bucket;
 
 	mbufq_init(&q, INT_MAX);
-	IPFW_UH_RLOCK(chain);
-	/*
-	 * It is safe to not use hazard pointer and just do lockless
-	 * access to the lists, because states entries can not be deleted
-	 * while we hold IPFW_UH_RLOCK.
-	 */
 	for (bucket = 0; bucket < V_curr_dyn_buckets; bucket++) {
+		DYN_BUCKET_LOCK(bucket);
 		CK_SLIST_FOREACH(s, &V_dyn_ipv6[bucket], entry) {
 			/*
 			 * Only established TCP connections that will
@@ -2624,8 +2614,8 @@ dyn_send_keepalive_ipv6(struct ip_fw_chain *chain)
 				continue;
 			dyn_enqueue_keepalive_ipv6(&q, s);
 		}
+		DYN_BUCKET_UNLOCK(bucket);
 	}
-	IPFW_UH_RUNLOCK(chain);
 	while ((m = mbufq_dequeue(&q)) != NULL)
 		ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
 }