Wed Jan 29 03:16:28 2020 UTC ()
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.


(thorpej)
diff -r1.41 -r1.42 src/sys/net/Makefile
diff -r1.24 -r1.25 src/sys/net/files.net
diff -r1.468 -r1.469 src/sys/net/if.c
diff -r1.277 -r1.278 src/sys/net/if.h
diff -r0 -r1.1 src/sys/net/if_stats.c
diff -r0 -r1.1 src/sys/net/if_stats.h

cvs diff -r1.41 -r1.42 src/sys/net/Makefile (expand / switch to unified diff)

--- src/sys/net/Makefile 2020/01/20 18:38:18 1.41
+++ src/sys/net/Makefile 2020/01/29 03:16:28 1.42
@@ -1,17 +1,17 @@ @@ -1,17 +1,17 @@
1# $NetBSD: Makefile,v 1.41 2020/01/20 18:38:18 thorpej Exp $ 1# $NetBSD: Makefile,v 1.42 2020/01/29 03:16:28 thorpej Exp $
2 2
3INCSDIR= /usr/include/net 3INCSDIR= /usr/include/net
4 4
5INCS= bpf.h bpfjit.h bpfdesc.h dlt.h ethertypes.h if.h if_arc.h if_arp.h \ 5INCS= bpf.h bpfjit.h bpfdesc.h dlt.h ethertypes.h if.h if_arc.h if_arp.h \
6 if_bridgevar.h if_dl.h if_ether.h if_gif.h \ 6 if_bridgevar.h if_dl.h if_ether.h if_gif.h \
7 if_gre.h if_ieee1394.h if_ipsec.h if_llc.h if_media.h if_mpls.h \ 7 if_gre.h if_ieee1394.h if_ipsec.h if_llc.h if_media.h if_mpls.h \
8 if_pflog.h if_ppp.h if_pppoe.h if_l2tp.h if_sppp.h if_srt.h if_stf.h \ 8 if_pflog.h if_ppp.h if_pppoe.h if_l2tp.h if_sppp.h if_srt.h if_stats.h \
9 if_tap.h if_tun.h if_types.h if_vlanvar.h net_stats.h \ 9 if_stf.h if_tap.h if_tun.h if_types.h if_vlanvar.h net_stats.h \
10 netisr.h pfil.h pfkeyv2.h pfvar.h ppp-comp.h ppp_defs.h radix.h \ 10 netisr.h pfil.h pfkeyv2.h pfvar.h ppp-comp.h ppp_defs.h radix.h \
11 raw_cb.h route.h slcompress.h slip.h zlib.h 11 raw_cb.h route.h slcompress.h slip.h zlib.h
12 12
13SUBDIR= agr npf 13SUBDIR= agr npf
14 14
15.include <bsd.kinc.mk> 15.include <bsd.kinc.mk>
16 16
17.PATH: ${NETBSDSRCDIR}/sys/dist/pf/net 17.PATH: ${NETBSDSRCDIR}/sys/dist/pf/net

cvs diff -r1.24 -r1.25 src/sys/net/files.net (expand / switch to unified diff)

--- src/sys/net/files.net 2020/01/20 18:38:18 1.24
+++ src/sys/net/files.net 2020/01/29 03:16:28 1.25
@@ -1,40 +1,41 @@ @@ -1,40 +1,41 @@
1# $NetBSD: files.net,v 1.24 2020/01/20 18:38:18 thorpej Exp $ 1# $NetBSD: files.net,v 1.25 2020/01/29 03:16:28 thorpej Exp $
2 2
3# XXX CLEANUP 3# XXX CLEANUP
4define net 4define net
5file net/bpf.c bpfilter 5file net/bpf.c bpfilter
6file net/bpf_filter.c bpf_filter 6file net/bpf_filter.c bpf_filter
7file net/bpf_stub.c net 7file net/bpf_stub.c net
8file net/bsd-comp.c ppp & ppp_bsdcomp 8file net/bsd-comp.c ppp & ppp_bsdcomp
9file net/dl_print.c 9file net/dl_print.c
10file net/ether_sw_offload.c bridge 10file net/ether_sw_offload.c bridge
11file net/if.c net 11file net/if.c net
12file net/if_arcsubr.c arcnet needs-flag 12file net/if_arcsubr.c arcnet needs-flag
13file net/if_bridge.c bridge needs-flag 13file net/if_bridge.c bridge needs-flag
14file net/bridgestp.c bridge 14file net/bridgestp.c bridge
15file net/if_ethersubr.c ether | netatalk | wlan needs-flag 15file net/if_ethersubr.c ether | netatalk | wlan needs-flag
16file net/if_faith.c faith & (inet | inet6) needs-flag 16file net/if_faith.c faith & (inet | inet6) needs-flag
17file net/if_gif.c gif needs-flag 17file net/if_gif.c gif needs-flag
18file net/if_gre.c gre needs-flag 18file net/if_gre.c gre needs-flag
19file net/if_ieee1394subr.c ieee1394 19file net/if_ieee1394subr.c ieee1394
20file net/if_ipsec.c ipsec & ipsecif 20file net/if_ipsec.c ipsec & ipsecif
21file net/if_llatbl.c inet | inet6 21file net/if_llatbl.c inet | inet6
22file net/if_l2tp.c l2tp needs-flag 22file net/if_l2tp.c l2tp needs-flag
23file net/if_loop.c loop 23file net/if_loop.c loop
24file net/if_media.c net 24file net/if_media.c net
25file net/if_mpls.c mpls needs-flag 25file net/if_mpls.c mpls needs-flag
26file net/if_ppp.c ppp needs-flag 26file net/if_ppp.c ppp needs-flag
27file net/if_srt.c srt 27file net/if_srt.c srt
 28file net/if_stats.c net
28file net/if_stf.c stf & inet & inet6 needs-flag 29file net/if_stf.c stf & inet & inet6 needs-flag
29file net/if_sl.c sl needs-flag 30file net/if_sl.c sl needs-flag
30file net/if_spppsubr.c sppp 31file net/if_spppsubr.c sppp
31file net/if_tap.c tap 32file net/if_tap.c tap
32file net/if_tun.c tun 33file net/if_tun.c tun
33file net/if_vlan.c vlan needs-flag 34file net/if_vlan.c vlan needs-flag
34file net/if_pppoe.c pppoe needs-flag 35file net/if_pppoe.c pppoe needs-flag
35file net/pfil.c net 36file net/pfil.c net
36file net/ppp-deflate.c ppp & ppp_deflate 37file net/ppp-deflate.c ppp & ppp_deflate
37file net/ppp_tty.c ppp 38file net/ppp_tty.c ppp
38file net/pktqueue.c net 39file net/pktqueue.c net
39file net/net_stats.c net 40file net/net_stats.c net
40file net/radix.c net 41file net/radix.c net

cvs diff -r1.468 -r1.469 src/sys/net/if.c (expand / switch to unified diff)

--- src/sys/net/if.c 2020/01/20 18:38:18 1.468
+++ src/sys/net/if.c 2020/01/29 03:16:28 1.469
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: if.c,v 1.468 2020/01/20 18:38:18 thorpej Exp $ */ 1/* $NetBSD: if.c,v 1.469 2020/01/29 03:16:28 thorpej Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc. 4 * Copyright (c) 1999, 2000, 2001, 2008 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by William Studenmund and Jason R. Thorpe. 8 * by William Studenmund and Jason R. Thorpe.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -80,27 +80,27 @@ @@ -80,27 +80,27 @@
80 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 80 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
81 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 81 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
82 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 82 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
83 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 83 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
84 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 84 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
85 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 85 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
86 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 86 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
87 * SUCH DAMAGE. 87 * SUCH DAMAGE.
88 * 88 *
89 * @(#)if.c 8.5 (Berkeley) 1/9/95 89 * @(#)if.c 8.5 (Berkeley) 1/9/95
90 */ 90 */
91 91
92#include <sys/cdefs.h> 92#include <sys/cdefs.h>
93__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.468 2020/01/20 18:38:18 thorpej Exp $"); 93__KERNEL_RCSID(0, "$NetBSD: if.c,v 1.469 2020/01/29 03:16:28 thorpej Exp $");
94 94
95#if defined(_KERNEL_OPT) 95#if defined(_KERNEL_OPT)
96#include "opt_inet.h" 96#include "opt_inet.h"
97#include "opt_ipsec.h" 97#include "opt_ipsec.h"
98#include "opt_atalk.h" 98#include "opt_atalk.h"
99#include "opt_wlan.h" 99#include "opt_wlan.h"
100#include "opt_net_mpsafe.h" 100#include "opt_net_mpsafe.h"
101#include "opt_mrouting.h" 101#include "opt_mrouting.h"
102#endif 102#endif
103 103
104#include <sys/param.h> 104#include <sys/param.h>
105#include <sys/mbuf.h> 105#include <sys/mbuf.h>
106#include <sys/systm.h> 106#include <sys/systm.h>
@@ -723,26 +723,29 @@ if_initialize(ifnet_t *ifp) @@ -723,26 +723,29 @@ if_initialize(ifnet_t *ifp)
723 ifp->if_link_si = softint_establish(flags, 723 ifp->if_link_si = softint_establish(flags,
724 if_link_state_change_si, ifp); 724 if_link_state_change_si, ifp);
725 if (ifp->if_link_si == NULL) { 725 if (ifp->if_link_si == NULL) {
726 rv = ENOMEM; 726 rv = ENOMEM;
727 goto fail; 727 goto fail;
728 } 728 }
729 } 729 }
730 730
731 PSLIST_ENTRY_INIT(ifp, if_pslist_entry); 731 PSLIST_ENTRY_INIT(ifp, if_pslist_entry);
732 PSLIST_INIT(&ifp->if_addr_pslist); 732 PSLIST_INIT(&ifp->if_addr_pslist);
733 psref_target_init(&ifp->if_psref, ifnet_psref_class); 733 psref_target_init(&ifp->if_psref, ifnet_psref_class);
734 ifp->if_ioctl_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE); 734 ifp->if_ioctl_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NONE);
735 LIST_INIT(&ifp->if_multiaddrs); 735 LIST_INIT(&ifp->if_multiaddrs);
 736 if ((rv = if_stats_init(ifp)) != 0) {
 737 goto fail;
 738 }
736 739
737 IFNET_GLOBAL_LOCK(); 740 IFNET_GLOBAL_LOCK();
738 if_getindex(ifp); 741 if_getindex(ifp);
739 IFNET_GLOBAL_UNLOCK(); 742 IFNET_GLOBAL_UNLOCK();
740 743
741 return 0; 744 return 0;
742 745
743fail: 746fail:
744 IF_AFDATA_LOCK_DESTROY(ifp); 747 IF_AFDATA_LOCK_DESTROY(ifp);
745 748
746 pfil_run_ifhooks(if_pfil, PFIL_IFNET_DETACH, ifp); 749 pfil_run_ifhooks(if_pfil, PFIL_IFNET_DETACH, ifp);
747 (void)pfil_head_destroy(ifp->if_pfil); 750 (void)pfil_head_destroy(ifp->if_pfil);
748 751
@@ -806,27 +809,27 @@ if_register(ifnet_t *ifp) @@ -806,27 +809,27 @@ if_register(ifnet_t *ifp)
806 * - You can use if_percpuq_* directly in your driver 809 * - You can use if_percpuq_* directly in your driver
807 * - In this case, you need to allocate struct if_percpuq in driver's softc 810 * - In this case, you need to allocate struct if_percpuq in driver's softc
808 * - See wm(4) as a reference implementation 811 * - See wm(4) as a reference implementation
809 */ 812 */
810 813
811static void 814static void
812if_percpuq_softint(void *arg) 815if_percpuq_softint(void *arg)
813{ 816{
814 struct if_percpuq *ipq = arg; 817 struct if_percpuq *ipq = arg;
815 struct ifnet *ifp = ipq->ipq_ifp; 818 struct ifnet *ifp = ipq->ipq_ifp;
816 struct mbuf *m; 819 struct mbuf *m;
817 820
818 while ((m = if_percpuq_dequeue(ipq)) != NULL) { 821 while ((m = if_percpuq_dequeue(ipq)) != NULL) {
819 ifp->if_ipackets++; 822 if_statinc(ifp, if_ipackets);
820 bpf_mtap(ifp, m, BPF_D_IN); 823 bpf_mtap(ifp, m, BPF_D_IN);
821 824
822 ifp->_if_input(ifp, m); 825 ifp->_if_input(ifp, m);
823 } 826 }
824} 827}
825 828
826static void 829static void
827if_percpuq_init_ifq(void *p, void *arg __unused, struct cpu_info *ci __unused) 830if_percpuq_init_ifq(void *p, void *arg __unused, struct cpu_info *ci __unused)
828{ 831{
829 struct ifqueue *const ifq = p; 832 struct ifqueue *const ifq = p;
830 833
831 memset(ifq, 0, sizeof(*ifq)); 834 memset(ifq, 0, sizeof(*ifq));
832 ifq->ifq_maxlen = IFQ_MAXLEN; 835 ifq->ifq_maxlen = IFQ_MAXLEN;
@@ -1100,27 +1103,27 @@ if_deferred_start_destroy(struct ifnet * @@ -1100,27 +1103,27 @@ if_deferred_start_destroy(struct ifnet *
1100 1103
1101/* 1104/*
1102 * The common interface input routine that is called by device drivers, 1105 * The common interface input routine that is called by device drivers,
1103 * which should be used only when the driver's rx handler already runs 1106 * which should be used only when the driver's rx handler already runs
1104 * in softint. 1107 * in softint.
1105 */ 1108 */
1106void 1109void
1107if_input(struct ifnet *ifp, struct mbuf *m) 1110if_input(struct ifnet *ifp, struct mbuf *m)
1108{ 1111{
1109 1112
1110 KASSERT(ifp->if_percpuq == NULL); 1113 KASSERT(ifp->if_percpuq == NULL);
1111 KASSERT(!cpu_intr_p()); 1114 KASSERT(!cpu_intr_p());
1112 1115
1113 ifp->if_ipackets++; 1116 if_statinc(ifp, if_ipackets);
1114 bpf_mtap(ifp, m, BPF_D_IN); 1117 bpf_mtap(ifp, m, BPF_D_IN);
1115 1118
1116 ifp->_if_input(ifp, m); 1119 ifp->_if_input(ifp, m);
1117} 1120}
1118 1121
1119/* 1122/*
1120 * DEPRECATED. Use if_initialize and if_register instead. 1123 * DEPRECATED. Use if_initialize and if_register instead.
1121 * See the above comment of if_initialize. 1124 * See the above comment of if_initialize.
1122 * 1125 *
1123 * Note that it implicitly enables if_percpuq to make drivers easy to 1126 * Note that it implicitly enables if_percpuq to make drivers easy to
1124 * migrate softint-based if_input without much changes. If you don't 1127 * migrate softint-based if_input without much changes. If you don't
1125 * want to enable it, use if_initialize instead. 1128 * want to enable it, use if_initialize instead.
1126 */ 1129 */
@@ -1511,26 +1514,27 @@ restart: @@ -1511,26 +1514,27 @@ restart:
1511 if (in6_present) 1514 if (in6_present)
1512 pktq_barrier(ip6_pktq); 1515 pktq_barrier(ip6_pktq);
1513#endif 1516#endif
1514 xc_barrier(0); 1517 xc_barrier(0);
1515 1518
1516 if (ifp->if_percpuq != NULL) { 1519 if (ifp->if_percpuq != NULL) {
1517 if_percpuq_destroy(ifp->if_percpuq); 1520 if_percpuq_destroy(ifp->if_percpuq);
1518 ifp->if_percpuq = NULL; 1521 ifp->if_percpuq = NULL;
1519 } 1522 }
1520 1523
1521 mutex_obj_free(ifp->if_ioctl_lock); 1524 mutex_obj_free(ifp->if_ioctl_lock);
1522 ifp->if_ioctl_lock = NULL; 1525 ifp->if_ioctl_lock = NULL;
1523 mutex_obj_free(ifp->if_snd.ifq_lock); 1526 mutex_obj_free(ifp->if_snd.ifq_lock);
 1527 if_stats_fini(ifp);
1524 1528
1525 splx(s); 1529 splx(s);
1526 1530
1527#ifdef IFAREF_DEBUG 1531#ifdef IFAREF_DEBUG
1528 if_check_and_free_ifa_list(ifp); 1532 if_check_and_free_ifa_list(ifp);
1529#endif 1533#endif
1530} 1534}
1531 1535
1532static void 1536static void
1533if_detach_queues(struct ifnet *ifp, struct ifqueue *q) 1537if_detach_queues(struct ifnet *ifp, struct ifqueue *q)
1534{ 1538{
1535 struct mbuf *m, *prev, *next; 1539 struct mbuf *m, *prev, *next;
1536 1540
@@ -2949,26 +2953,42 @@ if_tunnel_rtcache_free_pc(void *p, void  @@ -2949,26 +2953,42 @@ if_tunnel_rtcache_free_pc(void *p, void
2949 struct tunnel_ro *tro = p; 2953 struct tunnel_ro *tro = p;
2950 2954
2951 mutex_enter(tro->tr_lock); 2955 mutex_enter(tro->tr_lock);
2952 rtcache_free(tro->tr_ro); 2956 rtcache_free(tro->tr_ro);
2953 mutex_exit(tro->tr_lock); 2957 mutex_exit(tro->tr_lock);
2954} 2958}
2955 2959
2956void if_tunnel_ro_percpu_rtcache_free(percpu_t *ro_percpu) 2960void if_tunnel_ro_percpu_rtcache_free(percpu_t *ro_percpu)
2957{ 2961{
2958 2962
2959 percpu_foreach(ro_percpu, if_tunnel_rtcache_free_pc, NULL); 2963 percpu_foreach(ro_percpu, if_tunnel_rtcache_free_pc, NULL);
2960} 2964}
2961 2965
 2966void
 2967if_export_if_data(ifnet_t * const ifp, struct if_data *ifi, bool zero_stats)
 2968{
 2969
 2970 /* Collet the volatile stats first; this zeros *ifi. */
 2971 if_stats_to_if_data(ifp, ifi, zero_stats);
 2972
 2973 ifi->ifi_type = ifp->if_type;
 2974 ifi->ifi_addrlen = ifp->if_addrlen;
 2975 ifi->ifi_hdrlen = ifp->if_hdrlen;
 2976 ifi->ifi_link_state = ifp->if_link_state;
 2977 ifi->ifi_mtu = ifp->if_mtu;
 2978 ifi->ifi_metric = ifp->if_metric;
 2979 ifi->ifi_baudrate = ifp->if_baudrate;
 2980 ifi->ifi_lastchange = ifp->if_lastchange;
 2981}
2962 2982
2963/* common */ 2983/* common */
2964int 2984int
2965ifioctl_common(struct ifnet *ifp, u_long cmd, void *data) 2985ifioctl_common(struct ifnet *ifp, u_long cmd, void *data)
2966{ 2986{
2967 int s; 2987 int s;
2968 struct ifreq *ifr; 2988 struct ifreq *ifr;
2969 struct ifcapreq *ifcr; 2989 struct ifcapreq *ifcr;
2970 struct ifdatareq *ifdr; 2990 struct ifdatareq *ifdr;
2971 unsigned short flags; 2991 unsigned short flags;
2972 char *descr; 2992 char *descr;
2973 int error; 2993 int error;
2974 2994
@@ -3073,50 +3093,37 @@ ifioctl_common(struct ifnet *ifp, u_long @@ -3073,50 +3093,37 @@ ifioctl_common(struct ifnet *ifp, u_long
3073 case SIOCGIFCAP: 3093 case SIOCGIFCAP:
3074 ifcr = data; 3094 ifcr = data;
3075 ifcr->ifcr_capabilities = ifp->if_capabilities; 3095 ifcr->ifcr_capabilities = ifp->if_capabilities;
3076 ifcr->ifcr_capenable = ifp->if_capenable; 3096 ifcr->ifcr_capenable = ifp->if_capenable;
3077 break; 3097 break;
3078 3098
3079 case SIOCSIFMETRIC: 3099 case SIOCSIFMETRIC:
3080 ifr = data; 3100 ifr = data;
3081 ifp->if_metric = ifr->ifr_metric; 3101 ifp->if_metric = ifr->ifr_metric;
3082 break; 3102 break;
3083 3103
3084 case SIOCGIFDATA: 3104 case SIOCGIFDATA:
3085 ifdr = data; 3105 ifdr = data;
3086 ifdr->ifdr_data = ifp->if_data; 3106 if_export_if_data(ifp, &ifdr->ifdr_data, false);
3087 break; 3107 break;
3088 3108
3089 case SIOCGIFINDEX: 3109 case SIOCGIFINDEX:
3090 ifr = data; 3110 ifr = data;
3091 ifr->ifr_index = ifp->if_index; 3111 ifr->ifr_index = ifp->if_index;
3092 break; 3112 break;
3093 3113
3094 case SIOCZIFDATA: 3114 case SIOCZIFDATA:
3095 ifdr = data; 3115 ifdr = data;
3096 ifdr->ifdr_data = ifp->if_data; 3116 if_export_if_data(ifp, &ifdr->ifdr_data, true);
3097 /* 
3098 * Assumes that the volatile counters that can be 
3099 * zero'ed are at the end of if_data. 
3100 */ 
3101 memset(&ifp->if_data.ifi_ipackets, 0, sizeof(ifp->if_data) - 
3102 offsetof(struct if_data, ifi_ipackets)); 
3103 /* 
3104 * The memset() clears to the bottm of if_data. In the area, 
3105 * if_lastchange is included. Please be careful if new entry 
3106 * will be added into if_data or rewite this. 
3107 * 
3108 * And also, update if_lastchnage. 
3109 */ 
3110 getnanotime(&ifp->if_lastchange); 3117 getnanotime(&ifp->if_lastchange);
3111 break; 3118 break;
3112 case SIOCSIFMTU: 3119 case SIOCSIFMTU:
3113 ifr = data; 3120 ifr = data;
3114 if (ifp->if_mtu == ifr->ifr_mtu) 3121 if (ifp->if_mtu == ifr->ifr_mtu)
3115 break; 3122 break;
3116 ifp->if_mtu = ifr->ifr_mtu; 3123 ifp->if_mtu = ifr->ifr_mtu;
3117 /* 3124 /*
3118 * If the link MTU changed, do network layer specific procedure. 3125 * If the link MTU changed, do network layer specific procedure.
3119 */ 3126 */
3120#ifdef INET6 3127#ifdef INET6
3121 KERNEL_LOCK_UNLESS_NET_MPSAFE(); 3128 KERNEL_LOCK_UNLESS_NET_MPSAFE();
3122 if (in6_present) 3129 if (in6_present)
@@ -3585,29 +3592,31 @@ if_transmit(struct ifnet *ifp, struct mb @@ -3585,29 +3592,31 @@ if_transmit(struct ifnet *ifp, struct mb
3585{ 3592{
3586 int s, error; 3593 int s, error;
3587 size_t pktlen = m->m_pkthdr.len; 3594 size_t pktlen = m->m_pkthdr.len;
3588 bool mcast = (m->m_flags & M_MCAST) != 0; 3595 bool mcast = (m->m_flags & M_MCAST) != 0;
3589 3596
3590 s = splnet(); 3597 s = splnet();
3591 3598
3592 IFQ_ENQUEUE(&ifp->if_snd, m, error); 3599 IFQ_ENQUEUE(&ifp->if_snd, m, error);
3593 if (error != 0) { 3600 if (error != 0) {
3594 /* mbuf is already freed */ 3601 /* mbuf is already freed */
3595 goto out; 3602 goto out;
3596 } 3603 }
3597 3604
3598 ifp->if_obytes += pktlen; 3605 net_stat_ref_t nsr = IF_STAT_GETREF(ifp);
 3606 if_statadd_ref(nsr, if_obytes, pktlen);
3599 if (mcast) 3607 if (mcast)
3600 ifp->if_omcasts++; 3608 if_statinc_ref(nsr, if_omcasts);
 3609 IF_STAT_PUTREF(ifp);
3601 3610
3602 if ((ifp->if_flags & IFF_OACTIVE) == 0) 3611 if ((ifp->if_flags & IFF_OACTIVE) == 0)
3603 if_start_lock(ifp); 3612 if_start_lock(ifp);
3604out: 3613out:
3605 splx(s); 3614 splx(s);
3606 3615
3607 return error; 3616 return error;
3608} 3617}
3609 3618
3610int 3619int
3611if_transmit_lock(struct ifnet *ifp, struct mbuf *m) 3620if_transmit_lock(struct ifnet *ifp, struct mbuf *m)
3612{ 3621{
3613 int error; 3622 int error;
@@ -3656,27 +3665,27 @@ ifq_enqueue2(struct ifnet *ifp, struct i @@ -3656,27 +3665,27 @@ ifq_enqueue2(struct ifnet *ifp, struct i
3656 && ALTQ_IS_ENABLED(&ifp->if_snd) == 0 3665 && ALTQ_IS_ENABLED(&ifp->if_snd) == 0
3657#endif 3666#endif
3658 ) { 3667 ) {
3659 if (IF_QFULL(ifq)) { 3668 if (IF_QFULL(ifq)) {
3660 IF_DROP(&ifp->if_snd); 3669 IF_DROP(&ifp->if_snd);
3661 m_freem(m); 3670 m_freem(m);
3662 if (error == 0) 3671 if (error == 0)
3663 error = ENOBUFS; 3672 error = ENOBUFS;
3664 } else 3673 } else
3665 IF_ENQUEUE(ifq, m); 3674 IF_ENQUEUE(ifq, m);
3666 } else 3675 } else
3667 IFQ_ENQUEUE(&ifp->if_snd, m, error); 3676 IFQ_ENQUEUE(&ifp->if_snd, m, error);
3668 if (error != 0) { 3677 if (error != 0) {
3669 ++ifp->if_oerrors; 3678 if_statinc(ifp, if_oerrors);
3670 return error; 3679 return error;
3671 } 3680 }
3672 return 0; 3681 return 0;
3673} 3682}
3674 3683
3675int 3684int
3676if_addr_init(ifnet_t *ifp, struct ifaddr *ifa, const bool src) 3685if_addr_init(ifnet_t *ifp, struct ifaddr *ifa, const bool src)
3677{ 3686{
3678 int rc; 3687 int rc;
3679 3688
3680 KASSERT(IFNET_LOCKED(ifp)); 3689 KASSERT(IFNET_LOCKED(ifp));
3681 if (ifp->if_initaddr != NULL) 3690 if (ifp->if_initaddr != NULL)
3682 rc = (*ifp->if_initaddr)(ifp, ifa, src); 3691 rc = (*ifp->if_initaddr)(ifp, ifa, src);

cvs diff -r1.277 -r1.278 src/sys/net/if.h (expand / switch to unified diff)

--- src/sys/net/if.h 2019/09/19 06:07:24 1.277
+++ src/sys/net/if.h 2020/01/29 03:16:28 1.278
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: if.h,v 1.277 2019/09/19 06:07:24 knakahara Exp $ */ 1/* $NetBSD: if.h,v 1.278 2020/01/29 03:16:28 thorpej Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc. 4 * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by William Studenmund and Jason R. Thorpe. 8 * by William Studenmund and Jason R. Thorpe.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -163,26 +163,28 @@ struct if_clone { @@ -163,26 +163,28 @@ struct if_clone {
163 163
164/* 164/*
165 * Structure used to query names of interface cloners. 165 * Structure used to query names of interface cloners.
166 */ 166 */
167struct if_clonereq { 167struct if_clonereq {
168 int ifcr_total; /* total cloners (out) */ 168 int ifcr_total; /* total cloners (out) */
169 int ifcr_count; /* room for this many in user buffer */ 169 int ifcr_count; /* room for this many in user buffer */
170 char *ifcr_buffer; /* buffer for cloner names */ 170 char *ifcr_buffer; /* buffer for cloner names */
171}; 171};
172 172
173/* 173/*
174 * Structure defining statistics and other data kept regarding a network 174 * Structure defining statistics and other data kept regarding a network
175 * interface. 175 * interface.
 176 *
 177 * Only used for exporting data from the interface.
176 */ 178 */
177struct if_data { 179struct if_data {
178 /* generic interface information */ 180 /* generic interface information */
179 u_char ifi_type; /* ethernet, tokenring, etc. */ 181 u_char ifi_type; /* ethernet, tokenring, etc. */
180 u_char ifi_addrlen; /* media address length */ 182 u_char ifi_addrlen; /* media address length */
181 u_char ifi_hdrlen; /* media header length */ 183 u_char ifi_hdrlen; /* media header length */
182 int ifi_link_state; /* current link state */ 184 int ifi_link_state; /* current link state */
183 uint64_t ifi_mtu; /* maximum transmission unit */ 185 uint64_t ifi_mtu; /* maximum transmission unit */
184 uint64_t ifi_metric; /* routing metric (external only) */ 186 uint64_t ifi_metric; /* routing metric (external only) */
185 uint64_t ifi_baudrate; /* linespeed */ 187 uint64_t ifi_baudrate; /* linespeed */
186 /* volatile statistics */ 188 /* volatile statistics */
187 uint64_t ifi_ipackets; /* packets received on interface */ 189 uint64_t ifi_ipackets; /* packets received on interface */
188 uint64_t ifi_ierrors; /* input errors on interface */ 190 uint64_t ifi_ierrors; /* input errors on interface */
@@ -263,27 +265,40 @@ typedef struct ifnet { @@ -263,27 +265,40 @@ typedef struct ifnet {
263 /* DEPRECATED. Keep it to avoid breaking kvm(3) users */ 265 /* DEPRECATED. Keep it to avoid breaking kvm(3) users */
264 TAILQ_ENTRY(ifnet) 266 TAILQ_ENTRY(ifnet)
265 if_list; /* i: all struct ifnets are chained */ 267 if_list; /* i: all struct ifnets are chained */
266 TAILQ_HEAD(, ifaddr) 268 TAILQ_HEAD(, ifaddr)
267 if_addrlist; /* i: linked list of addresses per if */ 269 if_addrlist; /* i: linked list of addresses per if */
268 char if_xname[IFNAMSIZ]; 270 char if_xname[IFNAMSIZ];
269 /* :: external name (name + unit) */ 271 /* :: external name (name + unit) */
270 int if_pcount; /* i: number of promiscuous listeners */ 272 int if_pcount; /* i: number of promiscuous listeners */
271 struct bpf_if *if_bpf; /* :: packet filter structure */ 273 struct bpf_if *if_bpf; /* :: packet filter structure */
272 if_index_t if_index; /* :: numeric abbreviation for this if */ 274 if_index_t if_index; /* :: numeric abbreviation for this if */
273 short if_timer; /* ?: time 'til if_slowtimo called */ 275 short if_timer; /* ?: time 'til if_slowtimo called */
274 unsigned short if_flags; /* i: up/down, broadcast, etc. */ 276 unsigned short if_flags; /* i: up/down, broadcast, etc. */
275 short if_extflags; /* :: if_output MP-safe, etc. */ 277 short if_extflags; /* :: if_output MP-safe, etc. */
276 struct if_data if_data; /* ?: statistics and other data about if */ 278#ifdef __IF_STATS_PERCPU
 279 u_char if_type; /* :: ethernet, tokenring, etc. */
 280 u_char if_addrlen; /* :: media address length */
 281 u_char if_hdrlen; /* :: media header length */
 282 /* XXX audit :? fields here. */
 283 int if_link_state; /* :? current link state */
 284 uint64_t if_mtu; /* :? maximum transmission unit */
 285 uint64_t if_metric; /* :? routing metric (external only) */
 286 uint64_t if_baudrate; /* :? linespeed */
 287 struct timespec if_lastchange; /* :? last operational state change */
 288 percpu_t *if_stats; /* :: statistics */
 289#else /* ! __IF_STATS_PERCPU */
 290 struct if_data if_data; /* ?: statistics and other data */
 291#endif /* __IF_STATS_PERCPU */
277 /* 292 /*
278 * Procedure handles. If you add more of these, don't forget the 293 * Procedure handles. If you add more of these, don't forget the
279 * corresponding NULL stub in if.c. 294 * corresponding NULL stub in if.c.
280 */ 295 */
281 int (*if_output) /* :: output routine (enqueue) */ 296 int (*if_output) /* :: output routine (enqueue) */
282 (struct ifnet *, struct mbuf *, const struct sockaddr *, 297 (struct ifnet *, struct mbuf *, const struct sockaddr *,
283 const struct rtentry *); 298 const struct rtentry *);
284 void (*_if_input) /* :: input routine (from h/w driver) */ 299 void (*_if_input) /* :: input routine (from h/w driver) */
285 (struct ifnet *, struct mbuf *); 300 (struct ifnet *, struct mbuf *);
286 void (*if_start) /* :: initiate output routine */ 301 void (*if_start) /* :: initiate output routine */
287 (struct ifnet *); 302 (struct ifnet *);
288 int (*if_transmit) /* :: output routine, must be MP-safe */ 303 int (*if_transmit) /* :: output routine, must be MP-safe */
289 (struct ifnet *, struct mbuf *); 304 (struct ifnet *, struct mbuf *);
@@ -383,46 +398,50 @@ typedef struct ifnet { @@ -383,46 +398,50 @@ typedef struct ifnet {
383 if_pslist_entry;/* i: */ 398 if_pslist_entry;/* i: */
384 struct psref_target 399 struct psref_target
385 if_psref; /* :: */ 400 if_psref; /* :: */
386 struct pslist_head 401 struct pslist_head
387 if_addr_pslist; /* i: */ 402 if_addr_pslist; /* i: */
388 struct if_deferred_start 403 struct if_deferred_start
389 *if_deferred_start; 404 *if_deferred_start;
390 /* :: */ 405 /* :: */
391 /* XXX should be protocol independent */ 406 /* XXX should be protocol independent */
392 LIST_HEAD(, in6_multi) 407 LIST_HEAD(, in6_multi)
393 if_multiaddrs; /* 6: */ 408 if_multiaddrs; /* 6: */
394#endif 409#endif
395} ifnet_t; 410} ifnet_t;
 411
 412#include <net/if_stats.h>
396  413
 414#ifndef __IF_STATS_PERCPU
397#define if_mtu if_data.ifi_mtu 415#define if_mtu if_data.ifi_mtu
398#define if_type if_data.ifi_type 416#define if_type if_data.ifi_type
399#define if_addrlen if_data.ifi_addrlen 417#define if_addrlen if_data.ifi_addrlen
400#define if_hdrlen if_data.ifi_hdrlen 418#define if_hdrlen if_data.ifi_hdrlen
401#define if_metric if_data.ifi_metric 419#define if_metric if_data.ifi_metric
402#define if_link_state if_data.ifi_link_state 420#define if_link_state if_data.ifi_link_state
403#define if_baudrate if_data.ifi_baudrate 421#define if_baudrate if_data.ifi_baudrate
404#define if_ipackets if_data.ifi_ipackets 422#define if_ipackets if_data.ifi_ipackets
405#define if_ierrors if_data.ifi_ierrors 423#define if_ierrors if_data.ifi_ierrors
406#define if_opackets if_data.ifi_opackets 424#define if_opackets if_data.ifi_opackets
407#define if_oerrors if_data.ifi_oerrors 425#define if_oerrors if_data.ifi_oerrors
408#define if_collisions if_data.ifi_collisions 426#define if_collisions if_data.ifi_collisions
409#define if_ibytes if_data.ifi_ibytes 427#define if_ibytes if_data.ifi_ibytes
410#define if_obytes if_data.ifi_obytes 428#define if_obytes if_data.ifi_obytes
411#define if_imcasts if_data.ifi_imcasts 429#define if_imcasts if_data.ifi_imcasts
412#define if_omcasts if_data.ifi_omcasts 430#define if_omcasts if_data.ifi_omcasts
413#define if_iqdrops if_data.ifi_iqdrops 431#define if_iqdrops if_data.ifi_iqdrops
414#define if_noproto if_data.ifi_noproto 432#define if_noproto if_data.ifi_noproto
415#define if_lastchange if_data.ifi_lastchange 433#define if_lastchange if_data.ifi_lastchange
 434#endif /* __IF_STATS_PERCPU */
416#define if_name(ifp) ((ifp)->if_xname) 435#define if_name(ifp) ((ifp)->if_xname)
417 436
418#define IFF_UP 0x0001 /* interface is up */ 437#define IFF_UP 0x0001 /* interface is up */
419#define IFF_BROADCAST 0x0002 /* broadcast address valid */ 438#define IFF_BROADCAST 0x0002 /* broadcast address valid */
420#define IFF_DEBUG 0x0004 /* turn on debugging */ 439#define IFF_DEBUG 0x0004 /* turn on debugging */
421#define IFF_LOOPBACK 0x0008 /* is a loopback net */ 440#define IFF_LOOPBACK 0x0008 /* is a loopback net */
422#define IFF_POINTOPOINT 0x0010 /* interface is point-to-point link */ 441#define IFF_POINTOPOINT 0x0010 /* interface is point-to-point link */
423/* 0x0020 was IFF_NOTRAILERS */ 442/* 0x0020 was IFF_NOTRAILERS */
424#define IFF_RUNNING 0x0040 /* resources allocated */ 443#define IFF_RUNNING 0x0040 /* resources allocated */
425#define IFF_NOARP 0x0080 /* no address resolution protocol */ 444#define IFF_NOARP 0x0080 /* no address resolution protocol */
426#define IFF_PROMISC 0x0100 /* receive all packets */ 445#define IFF_PROMISC 0x0100 /* receive all packets */
427#define IFF_ALLMULTI 0x0200 /* receive all multicast packets */ 446#define IFF_ALLMULTI 0x0200 /* receive all multicast packets */
428#define IFF_OACTIVE 0x0400 /* transmission in progress */ 447#define IFF_OACTIVE 0x0400 /* transmission in progress */
@@ -1080,26 +1099,27 @@ void if_free(struct ifnet *); @@ -1080,26 +1099,27 @@ void if_free(struct ifnet *);
1080void if_initname(struct ifnet *, const char *, int); 1099void if_initname(struct ifnet *, const char *, int);
1081struct ifaddr *if_dl_create(const struct ifnet *, const struct sockaddr_dl **); 1100struct ifaddr *if_dl_create(const struct ifnet *, const struct sockaddr_dl **);
1082void if_activate_sadl(struct ifnet *, struct ifaddr *, 1101void if_activate_sadl(struct ifnet *, struct ifaddr *,
1083 const struct sockaddr_dl *); 1102 const struct sockaddr_dl *);
1084void if_set_sadl(struct ifnet *, const void *, u_char, bool); 1103void if_set_sadl(struct ifnet *, const void *, u_char, bool);
1085void if_alloc_sadl(struct ifnet *); 1104void if_alloc_sadl(struct ifnet *);
1086void if_free_sadl(struct ifnet *, int); 1105void if_free_sadl(struct ifnet *, int);
1087int if_initialize(struct ifnet *); 1106int if_initialize(struct ifnet *);
1088void if_register(struct ifnet *); 1107void if_register(struct ifnet *);
1089int if_attach(struct ifnet *); /* Deprecated. Use if_initialize and if_register */ 1108int if_attach(struct ifnet *); /* Deprecated. Use if_initialize and if_register */
1090void if_attachdomain(void); 1109void if_attachdomain(void);
1091void if_deactivate(struct ifnet *); 1110void if_deactivate(struct ifnet *);
1092bool if_is_deactivated(const struct ifnet *); 1111bool if_is_deactivated(const struct ifnet *);
 1112void if_export_if_data(struct ifnet *, struct if_data *, bool);
1093void if_purgeaddrs(struct ifnet *, int, void (*)(struct ifaddr *)); 1113void if_purgeaddrs(struct ifnet *, int, void (*)(struct ifaddr *));
1094void if_detach(struct ifnet *); 1114void if_detach(struct ifnet *);
1095void if_down(struct ifnet *); 1115void if_down(struct ifnet *);
1096void if_down_locked(struct ifnet *); 1116void if_down_locked(struct ifnet *);
1097void if_link_state_change(struct ifnet *, int); 1117void if_link_state_change(struct ifnet *, int);
1098void if_link_state_change_softint(struct ifnet *, int); 1118void if_link_state_change_softint(struct ifnet *, int);
1099void if_up(struct ifnet *); 1119void if_up(struct ifnet *);
1100void ifinit(void); 1120void ifinit(void);
1101void ifinit1(void); 1121void ifinit1(void);
1102void ifinit_post(void); 1122void ifinit_post(void);
1103int ifaddrpref_ioctl(struct socket *, u_long, void *, struct ifnet *); 1123int ifaddrpref_ioctl(struct socket *, u_long, void *, struct ifnet *);
1104extern int (*ifioctl)(struct socket *, u_long, void *, struct lwp *); 1124extern int (*ifioctl)(struct socket *, u_long, void *, struct lwp *);
1105int ifioctl_common(struct ifnet *, u_long, void *); 1125int ifioctl_common(struct ifnet *, u_long, void *);

File Added: src/sys/net/if_stats.c
/*	$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 */

File Added: src/sys/net/if_stats.h
/*	$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_ */