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