Module Name:    src
Committed By:   thorpej
Date:           Wed Jan 29 03:16:28 UTC 2020

Modified Files:
        src/sys/net: Makefile files.net if.c if.h
Added Files:
        src/sys/net: if_stats.c if_stats.h

Log Message:
Add support for MP-safe network interface statistics by maintaining them
in per-cpu storage, and collecting them for export in an if_data structure
when user-space wants them.

The new if_stat API is structured to make a gradual transition to the
new way in network drivers possible, and per-cpu stats are currently
disabled (thus there is no kernel ABI change).  Once all drivers have
been converted, the old ABI will be removed, and per-cpu stats will be
enabled universally.


To generate a diff of this commit:
cvs rdiff -u -r1.41 -r1.42 src/sys/net/Makefile
cvs rdiff -u -r1.24 -r1.25 src/sys/net/files.net
cvs rdiff -u -r1.468 -r1.469 src/sys/net/if.c
cvs rdiff -u -r1.277 -r1.278 src/sys/net/if.h
cvs rdiff -u -r0 -r1.1 src/sys/net/if_stats.c src/sys/net/if_stats.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/net/Makefile
diff -u src/sys/net/Makefile:1.41 src/sys/net/Makefile:1.42
--- src/sys/net/Makefile:1.41	Mon Jan 20 18:38:18 2020
+++ src/sys/net/Makefile	Wed Jan 29 03:16:28 2020
@@ -1,12 +1,12 @@
-#	$NetBSD: Makefile,v 1.41 2020/01/20 18:38:18 thorpej Exp $
+#	$NetBSD: Makefile,v 1.42 2020/01/29 03:16:28 thorpej Exp $
 
 INCSDIR= /usr/include/net
 
 INCS=	bpf.h bpfjit.h bpfdesc.h dlt.h ethertypes.h if.h if_arc.h if_arp.h \
 	if_bridgevar.h if_dl.h if_ether.h if_gif.h \
 	if_gre.h if_ieee1394.h if_ipsec.h if_llc.h if_media.h if_mpls.h \
-	if_pflog.h if_ppp.h if_pppoe.h if_l2tp.h if_sppp.h if_srt.h if_stf.h \
-	if_tap.h if_tun.h if_types.h if_vlanvar.h net_stats.h \
+	if_pflog.h if_ppp.h if_pppoe.h if_l2tp.h if_sppp.h if_srt.h if_stats.h \
+	if_stf.h if_tap.h if_tun.h if_types.h if_vlanvar.h net_stats.h \
 	netisr.h pfil.h pfkeyv2.h pfvar.h ppp-comp.h ppp_defs.h radix.h \
 	raw_cb.h route.h slcompress.h slip.h zlib.h
 

Index: src/sys/net/files.net
diff -u src/sys/net/files.net:1.24 src/sys/net/files.net:1.25
--- src/sys/net/files.net:1.24	Mon Jan 20 18:38:18 2020
+++ src/sys/net/files.net	Wed Jan 29 03:16:28 2020
@@ -1,4 +1,4 @@
-#	$NetBSD: files.net,v 1.24 2020/01/20 18:38:18 thorpej Exp $
+#	$NetBSD: files.net,v 1.25 2020/01/29 03:16:28 thorpej Exp $
 
 # XXX CLEANUP
 define	net
@@ -25,6 +25,7 @@ file	net/if_media.c			net
 file	net/if_mpls.c			mpls			needs-flag
 file	net/if_ppp.c			ppp			needs-flag
 file	net/if_srt.c			srt
+file	net/if_stats.c			net
 file	net/if_stf.c			stf & inet & inet6	needs-flag
 file	net/if_sl.c			sl			needs-flag
 file	net/if_spppsubr.c		sppp

Index: src/sys/net/if.c
diff -u src/sys/net/if.c:1.468 src/sys/net/if.c:1.469
--- src/sys/net/if.c:1.468	Mon Jan 20 18:38:18 2020
+++ src/sys/net/if.c	Wed Jan 29 03:16:28 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.c,v 1.468 2020/01/20 18:38:18 thorpej Exp $	*/
+/*	$NetBSD: if.c,v 1.469 2020/01/29 03:16:28 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
@@ -90,7 +90,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.468 2020/01/20 18:38:18 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.469 2020/01/29 03:16:28 thorpej Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_inet.h"
@@ -733,6 +733,9 @@ if_initialize(ifnet_t *ifp)
 	psref_target_init(&ifp->if_psref, ifnet_psref_class);
 	ifp->if_ioctl_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
 	LIST_INIT(&ifp->if_multiaddrs);
+	if ((rv = if_stats_init(ifp)) != 0) {
+		goto fail;
+	}
 
 	IFNET_GLOBAL_LOCK();
 	if_getindex(ifp);
@@ -816,7 +819,7 @@ if_percpuq_softint(void *arg)
 	struct mbuf *m;
 
 	while ((m = if_percpuq_dequeue(ipq)) != NULL) {
-		ifp->if_ipackets++;
+		if_statinc(ifp, if_ipackets);
 		bpf_mtap(ifp, m, BPF_D_IN);
 
 		ifp->_if_input(ifp, m);
@@ -1110,7 +1113,7 @@ if_input(struct ifnet *ifp, struct mbuf 
 	KASSERT(ifp->if_percpuq == NULL);
 	KASSERT(!cpu_intr_p());
 
-	ifp->if_ipackets++;
+	if_statinc(ifp, if_ipackets);
 	bpf_mtap(ifp, m, BPF_D_IN);
 
 	ifp->_if_input(ifp, m);
@@ -1521,6 +1524,7 @@ restart:
 	mutex_obj_free(ifp->if_ioctl_lock);
 	ifp->if_ioctl_lock = NULL;
 	mutex_obj_free(ifp->if_snd.ifq_lock);
+	if_stats_fini(ifp);
 
 	splx(s);
 
@@ -2959,6 +2963,22 @@ void if_tunnel_ro_percpu_rtcache_free(pe
 	percpu_foreach(ro_percpu, if_tunnel_rtcache_free_pc, NULL);
 }
 
+void
+if_export_if_data(ifnet_t * const ifp, struct if_data *ifi, bool zero_stats)
+{
+
+	/* Collet the volatile stats first; this zeros *ifi. */
+	if_stats_to_if_data(ifp, ifi, zero_stats);
+
+	ifi->ifi_type = ifp->if_type;
+	ifi->ifi_addrlen = ifp->if_addrlen;
+	ifi->ifi_hdrlen = ifp->if_hdrlen;
+	ifi->ifi_link_state = ifp->if_link_state;
+	ifi->ifi_mtu = ifp->if_mtu;
+	ifi->ifi_metric = ifp->if_metric;
+	ifi->ifi_baudrate = ifp->if_baudrate;
+	ifi->ifi_lastchange = ifp->if_lastchange;
+}
 
 /* common */
 int
@@ -3083,7 +3103,7 @@ ifioctl_common(struct ifnet *ifp, u_long
 
 	case SIOCGIFDATA:
 		ifdr = data;
-		ifdr->ifdr_data = ifp->if_data;
+		if_export_if_data(ifp, &ifdr->ifdr_data, false);
 		break;
 
 	case SIOCGIFINDEX:
@@ -3093,20 +3113,7 @@ ifioctl_common(struct ifnet *ifp, u_long
 
 	case SIOCZIFDATA:
 		ifdr = data;
-		ifdr->ifdr_data = ifp->if_data;
-		/*
-		 * Assumes that the volatile counters that can be
-		 * zero'ed are at the end of if_data.
-		 */
-		memset(&ifp->if_data.ifi_ipackets, 0, sizeof(ifp->if_data) -
-		    offsetof(struct if_data, ifi_ipackets));
-		/*
-		 * The memset() clears to the bottm of if_data. In the area,
-		 * if_lastchange is included. Please be careful if new entry
-		 * will be added into if_data or rewite this.
-		 *
-		 * And also, update if_lastchnage.
-		 */
+		if_export_if_data(ifp, &ifdr->ifdr_data, true);
 		getnanotime(&ifp->if_lastchange);
 		break;
 	case SIOCSIFMTU:
@@ -3595,9 +3602,11 @@ if_transmit(struct ifnet *ifp, struct mb
 		goto out;
 	}
 
-	ifp->if_obytes += pktlen;
+	net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
+	if_statadd_ref(nsr, if_obytes, pktlen);
 	if (mcast)
-		ifp->if_omcasts++;
+		if_statinc_ref(nsr, if_omcasts);
+	IF_STAT_PUTREF(ifp);
 
 	if ((ifp->if_flags & IFF_OACTIVE) == 0)
 		if_start_lock(ifp);
@@ -3666,7 +3675,7 @@ ifq_enqueue2(struct ifnet *ifp, struct i
 	} else
 		IFQ_ENQUEUE(&ifp->if_snd, m, error);
 	if (error != 0) {
-		++ifp->if_oerrors;
+		if_statinc(ifp, if_oerrors);
 		return error;
 	}
 	return 0;

Index: src/sys/net/if.h
diff -u src/sys/net/if.h:1.277 src/sys/net/if.h:1.278
--- src/sys/net/if.h:1.277	Thu Sep 19 06:07:24 2019
+++ src/sys/net/if.h	Wed Jan 29 03:16:28 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: if.h,v 1.277 2019/09/19 06:07:24 knakahara Exp $	*/
+/*	$NetBSD: if.h,v 1.278 2020/01/29 03:16:28 thorpej Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
@@ -173,6 +173,8 @@ struct if_clonereq {
 /*
  * Structure defining statistics and other data kept regarding a network
  * interface.
+ *
+ * Only used for exporting data from the interface.
  */
 struct if_data {
 	/* generic interface information */
@@ -273,7 +275,20 @@ typedef struct ifnet {
 	short		if_timer;	/* ?: time 'til if_slowtimo called */
 	unsigned short	if_flags;	/* i: up/down, broadcast, etc. */
 	short		if_extflags;	/* :: if_output MP-safe, etc. */
-	struct if_data	if_data;	/* ?: statistics and other data about if */
+#ifdef __IF_STATS_PERCPU
+	u_char		if_type;	/* :: ethernet, tokenring, etc. */
+	u_char		if_addrlen;	/* :: media address length */
+	u_char		if_hdrlen;	/* :: media header length */
+	/* XXX audit :? fields here. */
+	int		if_link_state;	/* :? current link state */
+	uint64_t	if_mtu;		/* :? maximum transmission unit */
+	uint64_t	if_metric;	/* :? routing metric (external only) */
+	uint64_t	if_baudrate;	/* :? linespeed */
+	struct timespec	if_lastchange;	/* :? last operational state change */
+	percpu_t	*if_stats;	/* :: statistics */
+#else /* ! __IF_STATS_PERCPU */
+	struct if_data	if_data;	/* ?: statistics and other data */
+#endif /* __IF_STATS_PERCPU */
 	/*
 	 * Procedure handles.  If you add more of these, don't forget the
 	 * corresponding NULL stub in if.c.
@@ -393,7 +408,10 @@ typedef struct ifnet {
 			if_multiaddrs;	/* 6: */
 #endif
 } ifnet_t;
+
+#include <net/if_stats.h>
  
+#ifndef __IF_STATS_PERCPU
 #define	if_mtu		if_data.ifi_mtu
 #define	if_type		if_data.ifi_type
 #define	if_addrlen	if_data.ifi_addrlen
@@ -413,6 +431,7 @@ typedef struct ifnet {
 #define	if_iqdrops	if_data.ifi_iqdrops
 #define	if_noproto	if_data.ifi_noproto
 #define	if_lastchange	if_data.ifi_lastchange
+#endif /* __IF_STATS_PERCPU */
 #define	if_name(ifp)	((ifp)->if_xname)
 
 #define	IFF_UP		0x0001		/* interface is up */
@@ -1090,6 +1109,7 @@ int	if_attach(struct ifnet *); /* Deprec
 void	if_attachdomain(void);
 void	if_deactivate(struct ifnet *);
 bool	if_is_deactivated(const struct ifnet *);
+void	if_export_if_data(struct ifnet *, struct if_data *, bool);
 void	if_purgeaddrs(struct ifnet *, int, void (*)(struct ifaddr *));
 void	if_detach(struct ifnet *);
 void	if_down(struct ifnet *);

Added files:

Index: src/sys/net/if_stats.c
diff -u /dev/null src/sys/net/if_stats.c:1.1
--- /dev/null	Wed Jan 29 03:16:28 2020
+++ src/sys/net/if_stats.c	Wed Jan 29 03:16:28 2020
@@ -0,0 +1,161 @@
+/*	$NetBSD: if_stats.c,v 1.1 2020/01/29 03:16:28 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: if_stats.c,v 1.1 2020/01/29 03:16:28 thorpej Exp $");
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+
+#include <net/if.h>
+
+#define	IF_STATS_SIZE	(sizeof(uint64_t) * IF_NSTATS)
+
+/*
+ * if_stats_init --
+ *	Initialize statistics storage for a network interface.
+ */
+int
+if_stats_init(ifnet_t * const ifp)
+{
+#ifdef __IF_STATS_PERCPU
+	ifp->if_stats = percpu_alloc(IF_STATS_SIZE);
+	if (ifp->if_stats == NULL)
+		return ENOMEM;
+#endif /* __IF_STATS_PERCPU */
+	return 0;
+}
+
+/*
+ * if_stats_fini --
+ *	Tear down statistics storage for a network interface.
+ */
+void
+if_stats_fini(ifnet_t * const ifp)
+{
+#ifdef __IF_STATS_PERCPU
+	percpu_t *pc = ifp->if_stats;
+	ifp->if_stats = NULL;
+	if (pc) {
+		percpu_free(pc, IF_STATS_SIZE);
+	}
+#endif /* __IF_STATS_PERCPU */
+}
+
+#ifdef __IF_STATS_PERCPU
+
+struct if_stats_to_if_data_ctx {
+	struct if_data * const ifi;
+	const bool zero_stats;
+};
+
+static void
+if_stats_to_if_data_cb(void *v1, void *v2, struct cpu_info *ci)
+{
+	const uint64_t * const local_counters = v1;
+	struct if_stats_to_if_data_ctx *ctx = v2;
+
+	int s = splnet();
+
+	if (ctx->ifi) {
+		ctx->ifi->ifi_ipackets   += local_counters[if_ipackets];
+		ctx->ifi->ifi_ierrors    += local_counters[if_ierrors];
+		ctx->ifi->ifi_opackets   += local_counters[if_opackets];
+		ctx->ifi->ifi_oerrors    += local_counters[if_oerrors];
+		ctx->ifi->ifi_collisions += local_counters[if_collisions];
+		ctx->ifi->ifi_ibytes     += local_counters[if_ibytes];
+		ctx->ifi->ifi_obytes     += local_counters[if_obytes];
+		ctx->ifi->ifi_imcasts    += local_counters[if_imcasts];
+		ctx->ifi->ifi_omcasts    += local_counters[if_omcasts];
+		ctx->ifi->ifi_iqdrops    += local_counters[if_iqdrops];
+		ctx->ifi->ifi_noproto    += local_counters[if_noproto];
+	}
+
+	if (ctx->zero_stats) {
+		memset(v1, 0, IF_STATS_SIZE);
+	}
+
+	splx(s);
+}
+
+/*
+ * if_stats_to_if_data --
+ *	Collect the interface statistics and place them into the
+ *	legacy if_data structure for reportig to user space.
+ *	Optionally zeros the stats after collection.
+ */
+void
+if_stats_to_if_data(ifnet_t * const ifp, struct if_data * const ifi,
+		    const bool zero_stats)
+{
+	struct if_stats_to_if_data_ctx ctx = {
+		.ifi = ifi,
+		.zero_stats = zero_stats,
+	};
+
+	memset(ifi, 0, sizeof(*ifi));
+	percpu_foreach(ifp->if_stats, if_stats_to_if_data_cb, &ctx);
+}
+
+#else /* ! __IF_STATS_PERCPU */
+
+/*
+ * if_stats_to_if_data --
+ *	Collect the interface statistics and place them into the
+ *	legacy if_data structure for reportig to user space.
+ *	Optionally zeros the stats after collection.
+ */
+void
+if_stats_to_if_data(ifnet_t * const ifp, struct if_data * const ifi,
+		    const bool zero_stats)
+{
+
+	memset(ifi, 0, sizeof(*ifi));
+
+	int s = splnet();
+
+	if (ifi) {
+		memcpy(&ifi->ifi_ipackets, &ifp->if_data.ifi_ipackets,
+		    offsetof(struct if_data, ifi_lastchange) -
+		    offsetof(struct if_data, ifi_ipackets));
+	}
+
+	if (zero_stats) {
+		memset(&ifp->if_data.ifi_ipackets, 0,
+		    offsetof(struct if_data, ifi_lastchange) -
+		    offsetof(struct if_data, ifi_ipackets));
+	}
+
+	splx(s);
+}
+
+#endif /* __IF_STATS_PERCPU */
Index: src/sys/net/if_stats.h
diff -u /dev/null src/sys/net/if_stats.h:1.1
--- /dev/null	Wed Jan 29 03:16:28 2020
+++ src/sys/net/if_stats.h	Wed Jan 29 03:16:28 2020
@@ -0,0 +1,165 @@
+/*	$NetBSD: if_stats.h,v 1.1 2020/01/29 03:16:28 thorpej Exp $	*/
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _NET_IF_STATS_H_
+#define _NET_IF_STATS_H_
+
+#include <net/net_stats.h>
+
+#ifdef __IF_STATS_PERCPU
+/*
+ * Interface statistics.  All values are unsigned 64-bit.
+ */
+typedef enum {
+	if_ipackets		= 0,	/* packets received on interface */
+	if_ierrors		= 1,	/* input errors on interface */
+	if_opackets		= 2,	/* packets sent on interface */
+	if_oerrors		= 3,	/* output errors on interface */
+	if_collisions		= 4,	/* collisions on csma interfaces */
+	if_ibytes		= 5,	/* total number of octets received */
+	if_obytes		= 6,	/* total number of octets sent */
+	if_imcasts		= 7,	/* packets received via multicast */
+	if_omcasts		= 8,	/* packets sent via multicast */
+	if_iqdrops		= 9,	/* dropped on input, this interface */
+	if_noproto		= 10,	/* destined for unsupported protocol */
+
+	IF_NSTATS		= 11
+} if_stat_t;
+
+#ifdef _KERNEL
+
+#define	IF_STAT_GETREF(ifp)	_NET_STAT_GETREF((ifp)->if_stats)
+#define	IF_STAT_PUTREF(ifp)	_NET_STAT_PUTREF((ifp)->if_stats)
+
+static inline void
+if_statinc(ifnet_t *ifp, if_stat_t x)
+{
+	_NET_STATINC((ifp)->if_stats, x);
+}
+
+static inline void
+if_statinc_ref(net_stat_ref_t nsr, if_stat_t x)
+{
+	_NET_STATINC_REF(nsr, x);
+}
+
+static inline void
+if_statdec(ifnet_t *ifp, if_stat_t x)
+{
+	_NET_STATDEC((ifp)->if_stats, x);
+}
+
+static inline void
+if_statdec_ref(net_stat_ref_t nsr, if_stat_t x)
+{
+	_NET_STATDEC_REF(nsr, x);
+}
+
+static inline void
+if_statadd(ifnet_t *ifp, if_stat_t x, uint64_t v)
+{
+	_NET_STATADD((ifp)->if_stats, x, v);
+}
+
+static inline void
+if_statadd_ref(net_stat_ref_t nsr, if_stat_t x, uint64_t v)
+{
+	_NET_STATADD_REF(nsr, x, v);
+}
+
+static inline void
+if_statadd2(ifnet_t *ifp, if_stat_t x1, uint64_t v1, if_stat_t x2, uint64_t v2)
+{
+	net_stat_ref_t _nsr_ = IF_STAT_GETREF(ifp);
+	_NET_STATADD_REF(_nsr_, x1, v1);
+	_NET_STATADD_REF(_nsr_, x2, v2);
+	IF_STAT_PUTREF(ifp);
+}
+
+static inline void
+if_statsub(ifnet_t *ifp, if_stat_t x, uint64_t v)
+{
+	_NET_STATSUB((ifp)->if_stats, x, v);
+}
+
+static inline void
+if_statsub_ref(net_stat_ref_t nsr, if_stat_t x, uint64_t v)
+{
+	_NET_STATSUB_REF(nsr, x, v);
+}
+
+#endif /* _KERNEL */
+
+#else /* ! __IF_STATS_PERCPU */
+
+#ifdef _KERNEL
+
+/*
+ * Transitional aid to allow drivers to migrate to the new API.  Once
+ * all drivers are transitioned, the implementation will be replaced
+ * with per-cpu counters.
+ */
+
+static inline net_stat_ref_t
+IF_STAT_GETREF(ifnet_t *ifp)
+{
+	return (net_stat_ref_t)ifp;
+}
+
+#define	IF_STAT_PUTREF(ifp)	__nothing
+
+#define	if_statinc(ifp, x)	do { ++(ifp)->x; } while (/*CONSTCOND*/0)
+#define	if_statdec(ifp, x)	do { --(ifp)->x; } while (/*CONSTCOND*/0)
+#define	if_statadd(ifp, x, v)	do { (ifp)->x += (v); } while (/*CONSTCOND*/0)
+#define	if_statsub(ifp, x, v)	do { (ifp)->x -= (v); } while (/*CONSTCOND*/0)
+
+#define	if_statadd2(ifp, x1, v1, x2, v2)				\
+do {									\
+	(ifp)->x1 += (v1);						\
+	(ifp)->x2 += (v2);						\
+} while (/*CONSTCOND*/0)
+
+#define	if_statinc_ref(r, x)	if_statinc((ifnet_t *)(r), x)
+#define	if_statdec_ref(r, x)	if_statdec((ifnet_t *)(r), x)
+#define	if_statadd_ref(r, x, v)	if_statadd((ifnet_t *)(r), x, v)
+#define	if_statsub_ref(r, x, v)	if_statsub((ifnet_t *)(r), x, v)
+
+#endif /* _KERNEL */
+
+#endif /* __IF_STATS_PERCPU */
+
+#ifdef _KERNEL
+int	if_stats_init(ifnet_t *);
+void	if_stats_fini(ifnet_t *);
+void	if_stats_to_if_data(ifnet_t *, struct if_data *, bool);
+#endif /* _KERNEL */
+
+#endif /* !_NET_IF_STATS_H_ */

Reply via email to