git: 9992eb435829 - main - gif: use hashalloc(9)

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Sun, 12 Apr 2026 17:40:00 UTC
The branch main has been updated by glebius:

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

commit 9992eb435829a910a2a25c564bf8d2ad7c6557b0
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-04-12 17:26:08 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-04-12 17:26:08 +0000

    gif: use hashalloc(9)
    
    Functional change is that on destruction INVARIANTS checks will run.  Also
    the mask is no longer hardcoded, so makes it easier to make hash size a
    tunable.
    
    Reviewed by:            ae
    Differential Revision:  https://reviews.freebsd.org/D56176
---
 sys/net/if_gif.c       | 21 ---------------------
 sys/net/if_gif.h       |  4 ----
 sys/netinet/in_gif.c   | 27 +++++++++++++++++++++------
 sys/netinet6/in6_gif.c | 27 +++++++++++++++++++++------
 4 files changed, 42 insertions(+), 37 deletions(-)

diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 272ab214a788..71bc8e1b64ce 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -254,27 +254,6 @@ static moduledata_t gif_mod = {
 DECLARE_MODULE(if_gif, gif_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
 MODULE_VERSION(if_gif, 1);
 
-struct gif_list *
-gif_hashinit(void)
-{
-	struct gif_list *hash;
-	int i;
-
-	hash = malloc(sizeof(struct gif_list) * GIF_HASH_SIZE,
-	    M_GIF, M_WAITOK);
-	for (i = 0; i < GIF_HASH_SIZE; i++)
-		CK_LIST_INIT(&hash[i]);
-
-	return (hash);
-}
-
-void
-gif_hashdestroy(struct gif_list *hash)
-{
-
-	free(hash, M_GIF);
-}
-
 #define	MTAG_GIF	1080679712
 static int
 gif_transmit(struct ifnet *ifp, struct mbuf *m)
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index c6692d3dd6bc..97a87c181a77 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -96,10 +96,6 @@ struct etherip_header {
 
 #define	GIF_WAIT()	epoch_wait_preempt(net_epoch_preempt)
 
-/* Prototypes */
-struct gif_list *gif_hashinit(void);
-void gif_hashdestroy(struct gif_list *);
-
 void gif_input(struct mbuf *, struct ifnet *, int, uint8_t);
 int gif_output(struct ifnet *, struct mbuf *, const struct sockaddr *,
 	       struct route *);
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index ebe7a4a62903..1910ef12d6d0 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -46,6 +46,7 @@
 #include <sys/sysctl.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
+#include <sys/hash.h>
 
 #include <net/ethernet.h>
 #include <net/if.h>
@@ -81,15 +82,17 @@ SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW,
  */
 VNET_DEFINE_STATIC(struct gif_list *, ipv4_hashtbl) = NULL;
 VNET_DEFINE_STATIC(struct gif_list *, ipv4_srchashtbl) = NULL;
+VNET_DEFINE_STATIC(u_int, ipv4_hashmask);
 VNET_DEFINE_STATIC(struct gif_list, ipv4_list) = CK_LIST_HEAD_INITIALIZER();
 #define	V_ipv4_hashtbl		VNET(ipv4_hashtbl)
 #define	V_ipv4_srchashtbl	VNET(ipv4_srchashtbl)
+#define	V_ipv4_hashmask		VNET(ipv4_hashmask)
 #define	V_ipv4_list		VNET(ipv4_list)
 
 #define	GIF_HASH(src, dst)	(V_ipv4_hashtbl[\
-    in_gif_hashval((src), (dst)) & (GIF_HASH_SIZE - 1)])
+    in_gif_hashval((src), (dst)) & (V_ipv4_hashmask - 1)])
 #define	GIF_SRCHASH(src)	(V_ipv4_srchashtbl[\
-    fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GIF_HASH_SIZE - 1)])
+    fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (V_ipv4_hashmask - 1)])
 #define	GIF_HASH_SC(sc)		GIF_HASH((sc)->gif_iphdr->ip_src.s_addr,\
     (sc)->gif_iphdr->ip_dst.s_addr)
 static uint32_t
@@ -218,8 +221,15 @@ in_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
 			break;
 		}
 		if (V_ipv4_hashtbl == NULL) {
-			V_ipv4_hashtbl = gif_hashinit();
-			V_ipv4_srchashtbl = gif_hashinit();
+			struct hashalloc_args ha = {
+				.size = GIF_HASH_SIZE,
+				.mtype = M_GIF,
+				.mflags = M_WAITOK,
+				.head = HASH_HEAD_CK_LIST,
+			};
+			V_ipv4_hashtbl = hashalloc(&ha);
+			V_ipv4_srchashtbl = hashalloc(&ha);
+			V_ipv4_hashmask = ha.size - 1;
 		}
 		error = in_gif_checkdup(sc, src->sin_addr.s_addr,
 		    dst->sin_addr.s_addr);
@@ -438,9 +448,14 @@ in_gif_uninit(void)
 		ip_encap_unregister_srcaddr(ipv4_srcaddrtab);
 	}
 	if (V_ipv4_hashtbl != NULL) {
-		gif_hashdestroy(V_ipv4_hashtbl);
+		struct hashalloc_args ha = {
+			.size = V_ipv4_hashmask + 1,
+			.mtype = M_GIF,
+			.head = HASH_HEAD_CK_LIST,
+		};
+		hashfree(V_ipv4_hashtbl, &ha);
 		V_ipv4_hashtbl = NULL;
 		GIF_WAIT();
-		gif_hashdestroy(V_ipv4_srchashtbl);
+		hashfree(V_ipv4_srchashtbl, &ha);
 	}
 }
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index 5159faa1e2e8..18e13175f739 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -47,6 +47,7 @@
 #include <sys/sysctl.h>
 #include <sys/malloc.h>
 #include <sys/proc.h>
+#include <sys/hash.h>
 
 #include <net/ethernet.h>
 #include <net/if.h>
@@ -86,15 +87,17 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim,
  */
 VNET_DEFINE_STATIC(struct gif_list *, ipv6_hashtbl) = NULL;
 VNET_DEFINE_STATIC(struct gif_list *, ipv6_srchashtbl) = NULL;
+VNET_DEFINE_STATIC(u_int, ipv6_hashmask);
 VNET_DEFINE_STATIC(struct gif_list, ipv6_list) = CK_LIST_HEAD_INITIALIZER();
 #define	V_ipv6_hashtbl		VNET(ipv6_hashtbl)
 #define	V_ipv6_srchashtbl	VNET(ipv6_srchashtbl)
+#define	V_ipv6_hashmask		VNET(ipv6_hashmask)
 #define	V_ipv6_list		VNET(ipv6_list)
 
 #define	GIF_HASH(src, dst)	(V_ipv6_hashtbl[\
-    in6_gif_hashval((src), (dst)) & (GIF_HASH_SIZE - 1)])
+    in6_gif_hashval((src), (dst)) & (V_ipv6_hashmask - 1)])
 #define	GIF_SRCHASH(src)	(V_ipv6_srchashtbl[\
-    fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GIF_HASH_SIZE - 1)])
+    fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (V_ipv6_hashmask - 1)])
 #define	GIF_HASH_SC(sc)		GIF_HASH(&(sc)->gif_ip6hdr->ip6_src,\
     &(sc)->gif_ip6hdr->ip6_dst)
 static uint32_t
@@ -237,8 +240,15 @@ in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
 			break;
 
 		if (V_ipv6_hashtbl == NULL) {
-			V_ipv6_hashtbl = gif_hashinit();
-			V_ipv6_srchashtbl = gif_hashinit();
+			struct hashalloc_args ha = {
+				.size = GIF_HASH_SIZE,
+				.mtype = M_GIF,
+				.mflags = M_WAITOK,
+				.head = HASH_HEAD_CK_LIST,
+			};
+			V_ipv6_hashtbl = hashalloc(&ha);
+			V_ipv6_srchashtbl = hashalloc(&ha);
+			V_ipv6_hashmask = ha.size - 1;
 		}
 		error = in6_gif_checkdup(sc, &src->sin6_addr,
 		    &dst->sin6_addr);
@@ -469,9 +479,14 @@ in6_gif_uninit(void)
 		ip6_encap_unregister_srcaddr(ipv6_srcaddrtab);
 	}
 	if (V_ipv6_hashtbl != NULL) {
-		gif_hashdestroy(V_ipv6_hashtbl);
+		struct hashalloc_args ha = {
+			.size = V_ipv6_hashmask + 1,
+			.mtype = M_GIF,
+			.head = HASH_HEAD_CK_LIST,
+		};
+		hashfree(V_ipv6_hashtbl, &ha);
 		V_ipv6_hashtbl = NULL;
 		GIF_WAIT();
-		gif_hashdestroy(V_ipv6_srchashtbl);
+		hashfree(V_ipv6_srchashtbl, &ha);
 	}
 }