Many network stack subsystems use a single global data structure to hold
all pertinent statatistics for the subsystem.  These structures are
sometimes "borrowed" by kernel modules that require a place to store
statistics for similar events.

Add KPI accessor functions for statistics structures referenced by kernel
modules so that they no longer encode certain specifics of how the data
structures are named and stored.  This change is intended to make it
easier to move to per-CPU network stats following 8.0-RELEASE.

The following modules are affected by this change:

	if_bridge
	if_cxgb
	if_gif
	ip_mroute
	ipdivert
	pf

In practice, most of these statistics consumers should, in fact, maintain
their own statistics data structures rather than borrowing structures
from the base network stack.  However, that change is too agressive for
this point in the release cycle.

Reviewed by:	

Index: netinet/udp_var.h
===================================================================
--- netinet/udp_var.h	(revision 196013)
+++ netinet/udp_var.h	(working copy)
@@ -91,8 +91,19 @@
 };
 
 #ifdef _KERNEL
+/*
+ * In-kernel consumers can use these accessor macros directly to update
+ * stats.
+ */
 #define	UDPSTAT_ADD(name, val)	V_udpstat.name += (val)
 #define	UDPSTAT_INC(name)	UDPSTAT_ADD(name, 1)
+
+/*
+ * Kernel module consumers must use this accessor macro.
+ */
+void	kmod_udpstat_inc(int statnum);
+#define	KMOD_UDPSTAT_INC(name)						\
+	kmod_udpstat_inc(offsetof(struct udpstat, name) / sizeof(u_long))
 #endif
 
 /*
Index: netinet/tcp_input.c
===================================================================
--- netinet/tcp_input.c	(revision 196019)
+++ netinet/tcp_input.c	(working copy)
@@ -217,6 +217,20 @@
 static void inline
 		 tcp_congestion_exp(struct tcpcb *);
 
+/*
+ * Kernel module interface for updating tcpstat.  The argument is an index
+ * into tcpstat treated as an array of u_long.  While this encodes the
+ * general layout of tcpstat into the caller, it doesn't encode its location,
+ * so that future changes to add, for example, per-CPU stats support won't
+ * cause binary compatibility problems for kernel modules.
+ */
+void
+kmod_tcpstat_inc(int statnum)
+{
+
+	(*((u_long *)&V_tcpstat + statnum))++;
+}
+
 static void inline
 tcp_congestion_exp(struct tcpcb *tp)
 {
Index: netinet/ip_divert.c
===================================================================
--- netinet/ip_divert.c	(revision 196019)
+++ netinet/ip_divert.c	(working copy)
@@ -186,7 +186,7 @@
 div_input(struct mbuf *m, int off)
 {
 
-	IPSTAT_INC(ips_noproto);
+	KMOD_IPSTAT_INC(ips_noproto);
 	m_freem(m);
 }
 
@@ -310,8 +310,8 @@
 	INP_INFO_RUNLOCK(&V_divcbinfo);
 	if (sa == NULL) {
 		m_freem(m);
-		IPSTAT_INC(ips_noproto);
-		IPSTAT_DEC(ips_delivered);
+		KMOD_IPSTAT_INC(ips_noproto);
+		KMOD_IPSTAT_DEC(ips_delivered);
         }
 }
 
@@ -396,7 +396,7 @@
 			ip->ip_off = ntohs(ip->ip_off);
 
 			/* Send packet to output processing */
-			IPSTAT_INC(ips_rawout);			/* XXX */
+			KMOD_IPSTAT_INC(ips_rawout);		/* XXX */
 
 #ifdef MAC
 			mac_inpcb_create_mbuf(inp, m);
@@ -567,7 +567,7 @@
 	/* Packet must have a header (but that's about it) */
 	if (m->m_len < sizeof (struct ip) &&
 	    (m = m_pullup(m, sizeof (struct ip))) == 0) {
-		IPSTAT_INC(ips_toosmall);
+		KMOD_IPSTAT_INC(ips_toosmall);
 		m_freem(m);
 		return EINVAL;
 	}
Index: netinet/tcp_var.h
===================================================================
--- netinet/tcp_var.h	(revision 196013)
+++ netinet/tcp_var.h	(working copy)
@@ -474,8 +474,19 @@
 };
 
 #ifdef _KERNEL
+/*
+ * In-kernel consumers can use these accessor macros directly to update
+ * stats.
+ */
 #define	TCPSTAT_ADD(name, val)	V_tcpstat.name += (val)
 #define	TCPSTAT_INC(name)	TCPSTAT_ADD(name, 1)
+
+/*
+ * Kernel module consumers must use this accessor macro.
+ */
+void	kmod_tcpstat_inc(int statnum);
+#define	KMOD_TCPSTAT_INC(name)						\
+	kmod_tcpstat_inc(offsetof(struct tcpstat, name) / sizeof(u_long))
 #endif
 
 /*
Index: netinet/icmp6.h
===================================================================
--- netinet/icmp6.h	(revision 196013)
+++ netinet/icmp6.h	(working copy)
@@ -600,8 +600,19 @@
 };
 
 #ifdef _KERNEL
+/*
+ * In-kernel consumers can use these accessor macros directly to update
+ * stats.
+ */
 #define	ICMP6STAT_ADD(name, val)	V_icmp6stat.name += (val)
 #define	ICMP6STAT_INC(name)		ICMP6STAT_ADD(name, 1)
+
+/*
+ * Kernel module consumers must use this accessor macro.
+ */
+void	kmod_icmp6stat_inc(int statnum);
+#define	KMOD_ICMP6STAT_INC(name)					\
+	kmod_icmp6stat_inc(offsetof(struct icmp6stat, name) / sizeof(u_quad_t))
 #endif
 
 /*
Index: netinet/ip_input.c
===================================================================
--- netinet/ip_input.c	(revision 196019)
+++ netinet/ip_input.c	(working copy)
@@ -235,6 +235,27 @@
 
 static void	ip_freef(struct ipqhead *, struct ipq *);
 
+/*
+ * Kernel module interface for updating ipstat.  The argument is an index
+ * into ipstat treated as an array of u_long.  While this encodes the general
+ * layout of ipstat into the caller, it doesn't encode its location, so that
+ * future changes to add, for example, per-CPU stats support won't cause
+ * binary compatibility problems for kernel modules.
+ */
+void
+kmod_ipstat_inc(int statnum)
+{
+
+	(*((u_long *)&V_ipstat + statnum))++;
+}
+
+void
+kmod_ipstat_dec(int statnum)
+{
+
+	(*((u_long *)&V_ipstat + statnum))--;
+}
+
 static int
 sysctl_netinet_intr_queue_maxlen(SYSCTL_HANDLER_ARGS)
 {
Index: netinet/in_gif.c
===================================================================
--- netinet/in_gif.c	(revision 196019)
+++ netinet/in_gif.c	(working copy)
@@ -281,14 +281,14 @@
 	sc = (struct gif_softc *)encap_getarg(m);
 	if (sc == NULL) {
 		m_freem(m);
-		IPSTAT_INC(ips_nogif);
+		KMOD_IPSTAT_INC(ips_nogif);
 		return;
 	}
 
 	gifp = GIF2IFP(sc);
 	if (gifp == NULL || (gifp->if_flags & IFF_UP) == 0) {
 		m_freem(m);
-		IPSTAT_INC(ips_nogif);
+		KMOD_IPSTAT_INC(ips_nogif);
 		return;
 	}
 
@@ -348,7 +348,7 @@
  		break;	
 
 	default:
-		IPSTAT_INC(ips_nogif);
+		KMOD_IPSTAT_INC(ips_nogif);
 		m_freem(m);
 		return;
 	}
Index: netinet/icmp_var.h
===================================================================
--- netinet/icmp_var.h	(revision 196013)
+++ netinet/icmp_var.h	(working copy)
@@ -58,8 +58,19 @@
 };
 
 #ifdef _KERNEL
+/*
+ * In-kernel consumers can use these accessor macros directly to update
+ * stats.
+ */
 #define	ICMPSTAT_ADD(name, val)	V_icmpstat.name += (val)
 #define	ICMPSTAT_INC(name)	ICMPSTAT_ADD(name, 1)
+
+/*
+ * Kernel module consumers must use this accessor macro.
+ */
+void	kmod_icmpstat_inc(int statnum);
+#define	KMOD_ICMPSTAT_INC(name)						\
+	kmod_icmpstat_inc(offsetof(struct icmpstat, name) / sizeof(u_long))
 #endif
 
 /*
Index: netinet/ip_icmp.c
===================================================================
--- netinet/ip_icmp.c	(revision 196019)
+++ netinet/ip_icmp.c	(working copy)
@@ -172,6 +172,20 @@
 }
 
 /*
+ * Kernel module interface for updating icmpstat.  The argument is an index
+ * into icmpstat treated as an array of u_long.  While this encodes the
+ * general layout of icmpstat into the caller, it doesn't encode its
+ * location, so that future changes to add, for example, per-CPU stats
+ * support won't cause binary compatibility problems for kernel modules.
+ */
+void
+kmod_icmpstat_inc(int statnum)
+{
+
+	(*((u_long *)&V_icmpstat + statnum))++;
+}
+
+/*
  * Generate an error packet of type error
  * in response to bad packet ip.
  */
Index: netinet/ip_var.h
===================================================================
--- netinet/ip_var.h	(revision 196013)
+++ netinet/ip_var.h	(working copy)
@@ -131,11 +131,25 @@
 
 #include <net/vnet.h>
 
+/*
+ * In-kernel consumers can use these accessor macros directly to update
+ * stats.
+ */
 #define	IPSTAT_ADD(name, val)	V_ipstat.name += (val)
 #define	IPSTAT_SUB(name, val)	V_ipstat.name -= (val)
 #define	IPSTAT_INC(name)	IPSTAT_ADD(name, 1)
 #define	IPSTAT_DEC(name)	IPSTAT_SUB(name, 1)
 
+/*
+ * Kernel module consumers must use this accessor macro.
+ */
+void	kmod_ipstat_inc(int statnum);
+#define	KMOD_IPSTAT_INC(name)						\
+	kmod_ipstat_inc(offsetof(struct ipstat, name) / sizeof(u_long))
+void	kmod_ipstat_dec(int statnum);
+#define	KMOD_IPSTAT_DEC(name)						\
+	kmod_ipstat_dec(offsetof(struct ipstat, name) / sizeof(u_long))
+
 /* flags passed to ip_output as last parameter */
 #define	IP_FORWARDING		0x1		/* most of ip header exists */
 #define	IP_RAWOUTPUT		0x2		/* raw ip header exists */
Index: netinet/udp_usrreq.c
===================================================================
--- netinet/udp_usrreq.c	(revision 196019)
+++ netinet/udp_usrreq.c	(working copy)
@@ -203,6 +203,20 @@
 	    EVENTHANDLER_PRI_ANY);
 }
 
+/*
+ * Kernel module interface for updating udpstat.  The argument is an index
+ * into udpstat treated as an array of u_long.  While this encodes the
+ * general layout of udpstat into the caller, it doesn't encode its location,
+ * so that future changes to add, for example, per-CPU stats support won't
+ * cause binary compatibility problems for kernel modules.
+ */
+void
+kmod_udpstat_inc(int statnum)
+{
+
+	(*((u_long *)&V_udpstat + statnum))++;
+}
+
 int
 udp_newudpcb(struct inpcb *inp)
 {
Index: dev/cxgb/ulp/tom/cxgb_cpl_io.c
===================================================================
--- dev/cxgb/ulp/tom/cxgb_cpl_io.c	(revision 196019)
+++ dev/cxgb/ulp/tom/cxgb_cpl_io.c	(working copy)
@@ -3821,7 +3821,7 @@
 #endif
 
 	toep->tp_state = tp->t_state;
-	TCPSTAT_INC(tcps_connects);
+	KMOD_TCPSTAT_INC(tcps_connects);
 				
 }
 
Index: net/if_bridge.c
===================================================================
--- net/if_bridge.c	(revision 196019)
+++ net/if_bridge.c	(working copy)
@@ -3244,12 +3244,12 @@
 		if ((m = m_copyup(m, sizeof(struct ip),
 			(max_linkhdr + 3) & ~3)) == NULL) {
 			/* XXXJRT new stat, please */
-			IPSTAT_INC(ips_toosmall);
+			KMOD_IPSTAT_INC(ips_toosmall);
 			goto bad;
 		}
 	} else if (__predict_false(m->m_len < sizeof (struct ip))) {
 		if ((m = m_pullup(m, sizeof (struct ip))) == NULL) {
-			IPSTAT_INC(ips_toosmall);
+			KMOD_IPSTAT_INC(ips_toosmall);
 			goto bad;
 		}
 	}
@@ -3257,17 +3257,17 @@
 	if (ip == NULL) goto bad;
 
 	if (ip->ip_v != IPVERSION) {
-		IPSTAT_INC(ips_badvers);
+		KMOD_IPSTAT_INC(ips_badvers);
 		goto bad;
 	}
 	hlen = ip->ip_hl << 2;
 	if (hlen < sizeof(struct ip)) { /* minimum header length */
-		IPSTAT_INC(ips_badhlen);
+		KMOD_IPSTAT_INC(ips_badhlen);
 		goto bad;
 	}
 	if (hlen > m->m_len) {
 		if ((m = m_pullup(m, hlen)) == 0) {
-			IPSTAT_INC(ips_badhlen);
+			KMOD_IPSTAT_INC(ips_badhlen);
 			goto bad;
 		}
 		ip = mtod(m, struct ip *);
@@ -3284,7 +3284,7 @@
 		}
 	}
 	if (sum) {
-		IPSTAT_INC(ips_badsum);
+		KMOD_IPSTAT_INC(ips_badsum);
 		goto bad;
 	}
 
@@ -3295,7 +3295,7 @@
 	 * Check for additional length bogosity
 	 */
 	if (len < hlen) {
-		IPSTAT_INC(ips_badlen);
+		KMOD_IPSTAT_INC(ips_badlen);
 		goto bad;
 	}
 
@@ -3305,7 +3305,7 @@
 	 * Drop packet if shorter than we expect.
 	 */
 	if (m->m_pkthdr.len < len) {
-		IPSTAT_INC(ips_tooshort);
+		KMOD_IPSTAT_INC(ips_tooshort);
 		goto bad;
 	}
 
@@ -3418,7 +3418,7 @@
 	}
 
 	if (error == 0)
-		IPSTAT_INC(ips_fragmented);
+		KMOD_IPSTAT_INC(ips_fragmented);
 
 	return (error);
 
Index: netinet6/icmp6.c
===================================================================
--- netinet6/icmp6.c	(revision 196019)
+++ netinet6/icmp6.c	(working copy)
@@ -152,6 +152,20 @@
 	V_icmp6errpps_count = 0;
 }
 
+/*
+ * Kernel module interface for updating icmp6stat.  The argument is an index
+ * into icmp6stat treated as an array of u_quad_t.  While this encodes the
+ * general layout of icmp6stat into the caller, it doesn't encode its
+ * location, so that future changes to add, for example, per-CPU stats
+ * support won't cause binary compatibility problems for kernel modules.
+ */
+void
+kmod_icmp6stat_inc(int statnum)
+{
+
+	(*((u_quad_t *)&V_icmp6stat + statnum))++;
+}
+
 static void
 icmp6_errcount(struct icmp6errstat *stat, int type, int code)
 {
Index: contrib/pf/net/pf.c
===================================================================
--- contrib/pf/net/pf.c	(revision 196019)
+++ contrib/pf/net/pf.c	(working copy)
@@ -6141,7 +6141,7 @@
 	if (r->rt == PF_FASTROUTE) {
 		in_rtalloc(ro, 0);
 		if (ro->ro_rt == 0) {
-			IPSTAT_INC(ips_noroute);
+			KMOD_IPSTAT_INC(ips_noroute);
 			goto bad;
 		}
 
@@ -6272,16 +6272,16 @@
 		if ((ifp->if_capabilities & IFCAP_CSUM_IPv4) &&
 		    ifp->if_bridge == NULL) {
 			m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
-			IPSTAT_INC(ips_outhwcsum);
+			KMOD_IPSTAT_INC(ips_outhwcsum);
 		} else {
 			ip->ip_sum = 0;
 			ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
 		}
 		/* Update relevant hardware checksum stats for TCP/UDP */
 		if (m0->m_pkthdr.csum_flags & M_TCPV4_CSUM_OUT)
-			TCPSTAT_INC(tcpstat.tcps_outhwcsum);
+			KMOD_TCPSTAT_INC(tcps_outhwcsum);
 		else if (m0->m_pkthdr.csum_flags & M_UDPV4_CSUM_OUT)
-			UDPSTAT_INC(udps_outhwcsum);
+			KMOD_UDPSTAT_INC(udps_outhwcsum);
 		error = (*ifp->if_output)(ifp, m0, sintosa(dst), NULL);
 		goto done;
 	}
@@ -6291,7 +6291,7 @@
 	 * Must be able to put at least 8 bytes per fragment.
 	 */
 	if (ip->ip_off & htons(IP_DF)) {
-		IPSTAT_INC(ips_cantfrag);
+		KMOD_IPSTAT_INC(ips_cantfrag);
 		if (r->rt != PF_DUPTO) {
 #ifdef __FreeBSD__
 			/* icmp_error() expects host byte ordering */
@@ -6348,7 +6348,7 @@
 	}
 
 	if (error == 0)
-		IPSTAT_INC(ips_fragmented);
+		KMOD_IPSTAT_INC(ips_fragmented);
 
 done:
 	if (r->rt != PF_DUPTO)
@@ -6622,23 +6622,23 @@
 		switch (p) {
 		case IPPROTO_TCP:
 		    {
-			TCPSTAT_INC(tcps_rcvbadsum);
+			KMOD_TCPSTAT_INC(tcps_rcvbadsum);
 			break;
 		    }
 		case IPPROTO_UDP:
 		    {
-			UDPSTAT_INC(udps_badsum);
+			KMOD_UDPSTAT_INC(udps_badsum);
 			break;
 		    }
 		case IPPROTO_ICMP:
 		    {
-			ICMPSTAT_INC(icps_checksum);
+			KMOD_ICMPSTAT_INC(icps_checksum);
 			break;
 		    }
 #ifdef INET6
 		case IPPROTO_ICMPV6:
 		    {
-			ICMP6STAT_INC(icp6s_checksum);
+			KMOD_ICMP6STAT_INC(icp6s_checksum);
 			break;
 		    }
 #endif /* INET6 */
@@ -6725,17 +6725,17 @@
 		m->m_pkthdr.csum_flags |= flag_bad;
 		switch (p) {
 		case IPPROTO_TCP:
-			TCPSTAT_INC(tcps_rcvbadsum);
+			KMOD_TCPSTAT_INC(tcps_rcvbadsum);
 			break;
 		case IPPROTO_UDP:
-			UDPSTAT_INC(udps_badsum);
+			KMOD_UDPSTAT_INC(udps_badsum);
 			break;
 		case IPPROTO_ICMP:
-			ICMPSTAT_INC(icps_checksum);
+			KMOD_ICMPSTAT_INC(icps_checksum);
 			break;
 #ifdef INET6
 		case IPPROTO_ICMPV6:
-			ICMP6STAT_INC(icp6s_checksum);
+			KMOD_ICMP6STAT_INC(icp6s_checksum);
 			break;
 #endif /* INET6 */
 		}
