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_ */