Abstract out initialization of most aspects of struct inpcbinfo from
their calling contexts in {IP divert, raw IP sockets, TCP, UDP} and
create new helper functions: in_pcbinfo_init() and in_pcbinfo_destroy()
to do this work in a central spot.  As inpcbinfo becomes more complex
due to ongoing work to add connection groups, this will reduce code
duplication.

MFC after:	3 months
Reviewed by:	bz
Sponsored by:	Juniper Networks

Index: tcp_subr.c
===================================================================
--- tcp_subr.c	(revision 204829)
+++ tcp_subr.c	(working copy)
@@ -376,25 +376,15 @@
 
 	TUNABLE_INT_FETCH("net.inet.tcp.sack.enable", &V_tcp_do_sack);
 
-	INP_INFO_LOCK_INIT(&V_tcbinfo, "tcp");
-	LIST_INIT(&V_tcb);
-#ifdef VIMAGE
-	V_tcbinfo.ipi_vnet = curvnet;
-#endif
-	V_tcbinfo.ipi_listhead = &V_tcb;
 	hashsize = TCBHASHSIZE;
 	TUNABLE_INT_FETCH("net.inet.tcp.tcbhashsize", &hashsize);
 	if (!powerof2(hashsize)) {
 		printf("WARNING: TCB hash size not a power of 2\n");
 		hashsize = 512; /* safe default */
 	}
-	V_tcbinfo.ipi_hashbase = hashinit(hashsize, M_PCB,
-	    &V_tcbinfo.ipi_hashmask);
-	V_tcbinfo.ipi_porthashbase = hashinit(hashsize, M_PCB,
-	    &V_tcbinfo.ipi_porthashmask);
-	V_tcbinfo.ipi_zone = uma_zcreate("tcp_inpcb", sizeof(struct inpcb),
-	    NULL, NULL, tcp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
-	uma_zone_set_max(V_tcbinfo.ipi_zone, maxsockets);
+	in_pcbinfo_init(&V_tcbinfo, "tcp", &V_tcb, hashsize, hashsize,
+	    "tcp", tcp_inpcb_init, NULL, UMA_ZONE_NOFREE);
+
 	/*
 	 * These have to be type stable for the benefit of the timers.
 	 */
@@ -464,11 +454,7 @@
 	syncache_destroy();
 
 	/* XXX check that hashes are empty! */
-	hashdestroy(V_tcbinfo.ipi_hashbase, M_PCB,
-	    V_tcbinfo.ipi_hashmask);
-	hashdestroy(V_tcbinfo.ipi_porthashbase, M_PCB,
-	    V_tcbinfo.ipi_porthashmask);
-	INP_INFO_LOCK_DESTROY(&V_tcbinfo);
+	in_pcbinfo_destroy(&V_tcbinfo);
 }
 #endif
 
Index: raw_ip.c
===================================================================
--- raw_ip.c	(revision 204825)
+++ raw_ip.c	(working copy)
@@ -185,19 +185,8 @@
 rip_init(void)
 {
 
-	INP_INFO_LOCK_INIT(&V_ripcbinfo, "rip");
-	LIST_INIT(&V_ripcb);
-#ifdef VIMAGE
-	V_ripcbinfo.ipi_vnet = curvnet;
-#endif
-	V_ripcbinfo.ipi_listhead = &V_ripcb;
-	V_ripcbinfo.ipi_hashbase =
-	    hashinit(INP_PCBHASH_RAW_SIZE, M_PCB, &V_ripcbinfo.ipi_hashmask);
-	V_ripcbinfo.ipi_porthashbase =
-	    hashinit(1, M_PCB, &V_ripcbinfo.ipi_porthashmask);
-	V_ripcbinfo.ipi_zone = uma_zcreate("ripcb", sizeof(struct inpcb),
-	    NULL, NULL, rip_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
-	uma_zone_set_max(V_ripcbinfo.ipi_zone, maxsockets);
+	in_pcbinfo_init(&V_ripcbinfo, "rip", &V_ripcb, INP_PCBHASH_RAW_SIZE,
+	    1, "ripcb", rip_inpcb_init, NULL, UMA_ZONE_NOFREE);
 	EVENTHANDLER_REGISTER(maxsockets_change, rip_zone_change, NULL,
 	    EVENTHANDLER_PRI_ANY);
 }
@@ -207,10 +196,7 @@
 rip_destroy(void)
 {
 
-	hashdestroy(V_ripcbinfo.ipi_hashbase, M_PCB,
-	    V_ripcbinfo.ipi_hashmask);
-	hashdestroy(V_ripcbinfo.ipi_porthashbase, M_PCB,
-	    V_ripcbinfo.ipi_porthashmask);
+	in_pcbinfo_destroy(&V_ripcbinfo);
 }
 #endif
 
Index: ip_divert.c
===================================================================
--- ip_divert.c	(revision 204825)
+++ ip_divert.c	(working copy)
@@ -147,35 +147,20 @@
 div_init(void)
 {
 
-	INP_INFO_LOCK_INIT(&V_divcbinfo, "div");
-	LIST_INIT(&V_divcb);
-	V_divcbinfo.ipi_listhead = &V_divcb;
-#ifdef VIMAGE
-	V_divcbinfo.ipi_vnet = curvnet;
-#endif
 	/*
-	 * XXX We don't use the hash list for divert IP, but it's easier
-	 * to allocate a one entry hash list than it is to check all
-	 * over the place for hashbase == NULL.
+	 * XXX We don't use the hash list for divert IP, but it's easier to
+	 * allocate one-entry hash lists than it is to check all over the
+	 * place for hashbase == NULL.
 	 */
-	V_divcbinfo.ipi_hashbase = hashinit(1, M_PCB, &V_divcbinfo.ipi_hashmask);
-	V_divcbinfo.ipi_porthashbase = hashinit(1, M_PCB,
-	    &V_divcbinfo.ipi_porthashmask);
-	V_divcbinfo.ipi_zone = uma_zcreate("divcb", sizeof(struct inpcb),
-	    NULL, NULL, div_inpcb_init, div_inpcb_fini, UMA_ALIGN_PTR,
-	    UMA_ZONE_NOFREE);
-	uma_zone_set_max(V_divcbinfo.ipi_zone, maxsockets);
+	in_pcbinfo_init(&V_divcbinfo, "div", &V_divcb, 1, 1, "divcb",
+	    div_inpcb_init, div_inpcb_fini, UMA_ZONE_NOFREE);
 }
 
 static void
 div_destroy(void)
 {
 
-	INP_INFO_LOCK_DESTROY(&V_divcbinfo);
-	uma_zdestroy(V_divcbinfo.ipi_zone);
-	hashdestroy(V_divcbinfo.ipi_hashbase, M_PCB, V_divcbinfo.ipi_hashmask);
-	hashdestroy(V_divcbinfo.ipi_porthashbase, M_PCB,
-	    V_divcbinfo.ipi_porthashmask);
+	in_pcbinfo_destroy(&V_divcbinfo);
 }
 
 /*
Index: in_pcb.c
===================================================================
--- in_pcb.c	(revision 204825)
+++ in_pcb.c	(working copy)
@@ -184,6 +184,47 @@
  */
 
 /*
+ * Initialize an inpcbinfo -- we should be able to reduce the number of
+ * arguments in time.
+ */
+void
+in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name,
+    struct inpcbhead *listhead, int hash_nelements, int porthash_nelements,
+    char *inpcbzone_name, uma_init inpcbzone_init, uma_fini inpcbzone_fini,
+    uint32_t inpcbzone_flags)
+{
+
+	INP_INFO_LOCK_INIT(pcbinfo, name);
+#ifdef VIMAGE
+	pcbinfo->ipi_vnet = curvnet;
+#endif
+	pcbinfo->ipi_listhead = listhead;
+	LIST_INIT(pcbinfo->ipi_listhead);
+	pcbinfo->ipi_hashbase = hashinit(hash_nelements, M_PCB,
+	    &pcbinfo->ipi_hashmask);
+	pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB,
+	    &pcbinfo->ipi_porthashmask);
+	pcbinfo->ipi_zone = uma_zcreate(inpcbzone_name, sizeof(struct inpcb),
+	    NULL, NULL, inpcbzone_init, inpcbzone_fini, UMA_ALIGN_PTR,
+	    inpcbzone_flags);
+	uma_zone_set_max(pcbinfo->ipi_zone, maxsockets);
+}
+
+/*
+ * Destroy an inpcbinfo.
+ */
+void
+in_pcbinfo_destroy(struct inpcbinfo *pcbinfo)
+{
+
+	hashdestroy(pcbinfo->ipi_hashbase, M_PCB, pcbinfo->ipi_hashmask);
+	hashdestroy(pcbinfo->ipi_porthashbase, M_PCB,
+	    pcbinfo->ipi_porthashmask);
+	uma_zdestroy(pcbinfo->ipi_zone);
+	INP_INFO_LOCK_DESTROY(pcbinfo);
+}
+
+/*
  * Allocate a PCB and associate it with the socket.
  * On success return with the PCB locked.
  */
Index: in_pcb.h
===================================================================
--- in_pcb.h	(revision 204825)
+++ in_pcb.h	(working copy)
@@ -42,6 +42,7 @@
 #ifdef _KERNEL
 #include <sys/rwlock.h>
 #include <net/vnet.h>
+#include <vm/uma.h>
 #endif
 
 #define	in6pcb		inpcb	/* for KAME src sync over BSD*'s */
@@ -483,6 +484,13 @@
 
 extern struct callout ipport_tick_callout;
 
+void	in_pcbinfo_destroy(struct inpcbinfo *);
+void	in_pcbinfo_init(struct inpcbinfo *pcbinfo, const char *name,
+	    struct inpcbhead *listhead, int hash_nelements,
+	    int porthash_nelements, char *inpcbzone_name,
+	    uma_init inpcbzone_init, uma_fini inpcbzone_fini,
+	    uint32_t inpcbzone_flags);
+
 void	in_pcbpurgeif0(struct inpcbinfo *, struct ifnet *);
 int	in_pcballoc(struct socket *, struct inpcbinfo *);
 int	in_pcbbind(struct inpcb *, struct sockaddr *, struct ucred *);
Index: udp_usrreq.c
===================================================================
--- udp_usrreq.c	(revision 204826)
+++ udp_usrreq.c	(working copy)
@@ -180,25 +180,11 @@
 {
 
 	V_udp_blackhole = 0;
-
-	INP_INFO_LOCK_INIT(&V_udbinfo, "udp");
-	LIST_INIT(&V_udb);
-#ifdef VIMAGE
-	V_udbinfo.ipi_vnet = curvnet;
-#endif
-	V_udbinfo.ipi_listhead = &V_udb;
-	V_udbinfo.ipi_hashbase = hashinit(UDBHASHSIZE, M_PCB,
-	    &V_udbinfo.ipi_hashmask);
-	V_udbinfo.ipi_porthashbase = hashinit(UDBHASHSIZE, M_PCB,
-	    &V_udbinfo.ipi_porthashmask);
-	V_udbinfo.ipi_zone = uma_zcreate("udp_inpcb", sizeof(struct inpcb),
-	    NULL, NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
-	uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets);
-
+	in_pcbinfo_init(&V_udbinfo, "udp", &V_udb, UDBHASHSIZE, UDBHASHSIZE,
+	    "udp_inpcb", udp_inpcb_init, NULL, UMA_ZONE_NOFREE);
 	V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb),
 	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 	uma_zone_set_max(V_udpcb_zone, maxsockets);
-
 	EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL,
 	    EVENTHANDLER_PRI_ANY);
 }
@@ -241,14 +227,8 @@
 udp_destroy(void)
 {
 
-	hashdestroy(V_udbinfo.ipi_hashbase, M_PCB,
-	    V_udbinfo.ipi_hashmask);
-	hashdestroy(V_udbinfo.ipi_porthashbase, M_PCB,
-	    V_udbinfo.ipi_porthashmask);
-
+	in_pcbinfo_destroy(&V_udbinfo);
 	uma_zdestroy(V_udpcb_zone);
-	uma_zdestroy(V_udbinfo.ipi_zone);
-	INP_INFO_LOCK_DESTROY(&V_udbinfo);
 }
 #endif
 
