tech-net archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Per-cpu stats for network interfaces
Another thing needed to make the network stack MP-safe is fixing the way interface statistics are kept. We dealt with this some years ago for protocol statistics. This change builds upon that.
For network interfaces, it's a little trickier.
1- The stats are intermingled with other less-volatile information in "struct if_data".
2- There are a lot more network interface drivers than there are protocols, making the transition to the New Way harder.
IMO, "struct if_data" should be used only for exporting the information to user-space, and this change starts us down this path (eventually, "struct ifnet" will no longer contain a "struct if_data").
To ease the transition for drivers, the API is a little different than the other net_stats-based ones. Specifically, it doesn't actually flip the switch on per-cpu stats just yet, although all of the stuff is there. Instead, it allows un-converted drivers to co-exist with drivers that have been converted to the new API. This is done with some preprocessor macros that are at the root of why it's a little different. If we want, we can tidy these differences up later, or we can live with them... not a decision we need to make now.
Attached is a preliminary diff, along with a couple of example driver conversions. Feedback, please! If there is consensus on this approach, I'll convert the drivers as time permits (it's pretty simple mechanical change).
Index: dev/ic/aic6915.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/aic6915.c,v
retrieving revision 1.40
diff -u -p -r1.40 aic6915.c
--- dev/ic/aic6915.c 30 Oct 2019 07:26:28 -0000 1.40
+++ dev/ic/aic6915.c 25 Jan 2020 16:15:46 -0000
@@ -502,7 +502,7 @@ sf_watchdog(struct ifnet *ifp)
struct sf_softc *sc = ifp->if_softc;
printf("%s: device timeout\n", device_xname(sc->sc_dev));
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
(void) sf_init(ifp);
@@ -746,7 +746,7 @@ sf_rxintr(struct sf_softc *sc)
*/
m = ds->ds_mbuf;
if (sf_add_rxbuf(sc, rxidx) != 0) {
- ifp->if_ierrors++;
+ if_statinc(ifp, if_ierrors);
SF_INIT_RXDESC(sc, rxidx);
bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
@@ -762,7 +762,7 @@ sf_rxintr(struct sf_softc *sc)
MGETHDR(m, M_DONTWAIT, MT_DATA);
if (m == NULL) {
dropit:
- ifp->if_ierrors++;
+ if_statinc(ifp, if_ierrors);
SF_INIT_RXDESC(sc, rxidx);
bus_dmamap_sync(sc->sc_dmat, ds->ds_dmamap, 0,
ds->ds_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
@@ -846,19 +846,25 @@ sf_stats_update(struct sf_softc *sc)
sf_genreg_write(sc, SF_STATS_BASE + (i * sizeof(uint32_t)), 0);
}
- ifp->if_opackets += stats.TransmitOKFrames;
+ uint64_t *ifs = IF_STAT_GETREF(ifp);
- ifp->if_collisions += stats.SingleCollisionFrames +
+ ifs[IF_STAT_OPACKETS] += stats.TransmitOKFrames;
+
+ ifs[IF_STAT_COLLISIONS] += stats.SingleCollisionFrames +
stats.MultipleCollisionFrames;
- ifp->if_oerrors += stats.TransmitAbortDueToExcessiveCollisions +
+ ifs[IF_STAT_OERRORS] +=
+ stats.TransmitAbortDueToExcessiveCollisions +
stats.TransmitAbortDueToExcessingDeferral +
stats.FramesLostDueToInternalTransmitErrors;
- ifp->if_ierrors += stats.ReceiveCRCErrors + stats.AlignmentErrors +
+ ifs[IF_STAT_IERRORS] +=
+ stats.ReceiveCRCErrors + stats.AlignmentErrors +
stats.ReceiveFramesTooLong + stats.ReceiveFramesTooShort +
stats.ReceiveFramesJabbersError +
stats.FramesLostDueToInternalReceiveErrors;
+
+ IF_STAT_PUTREF(ifp);
}
/*
Index: dev/pci/if_pcn.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_pcn.c,v
retrieving revision 1.72
diff -u -p -r1.72 if_pcn.c
--- dev/pci/if_pcn.c 11 Oct 2019 14:22:46 -0000 1.72
+++ dev/pci/if_pcn.c 25 Jan 2020 16:15:47 -0000
@@ -1163,7 +1163,7 @@ pcn_watchdog(struct ifnet *ifp)
if (sc->sc_txfree != PCN_NTXDESC) {
printf("%s: device timeout (txfree %d txsfree %d)\n",
device_xname(sc->sc_dev), sc->sc_txfree, sc->sc_txsfree);
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
/* Reset the interface. */
(void) pcn_init(ifp);
@@ -1248,11 +1248,11 @@ pcn_intr(void *arg)
if (csr0 & LE_C0_ERR) {
if (csr0 & LE_C0_BABL) {
PCN_EVCNT_INCR(&sc->sc_ev_babl);
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
}
if (csr0 & LE_C0_MISS) {
PCN_EVCNT_INCR(&sc->sc_ev_miss);
- ifp->if_ierrors++;
+ if_statinc(ifp, if_ierrors);
}
if (csr0 & LE_C0_MERR) {
PCN_EVCNT_INCR(&sc->sc_ev_merr);
@@ -1266,14 +1266,14 @@ pcn_intr(void *arg)
if ((csr0 & LE_C0_RXON) == 0) {
printf("%s: receiver disabled\n",
device_xname(sc->sc_dev));
- ifp->if_ierrors++;
+ if_statinc(ifp, if_ierrors);
wantinit = 1;
}
if ((csr0 & LE_C0_TXON) == 0) {
printf("%s: transmitter disabled\n",
device_xname(sc->sc_dev));
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
wantinit = 1;
}
}
@@ -1349,7 +1349,7 @@ pcn_txintr(struct pcn_softc *sc)
for (j = txs->txs_firstdesc;; j = PCN_NEXTTX(j)) {
tmd = le32toh(sc->sc_txdescs[j].tmd1);
if (tmd & LE_T1_ERR) {
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
if (sc->sc_swstyle == LE_B20_SSTYLE_PCNETPCI3)
tmd2 = le32toh(sc->sc_txdescs[j].tmd0);
else
@@ -1380,21 +1380,21 @@ pcn_txintr(struct pcn_softc *sc)
device_xname(sc->sc_dev));
}
if (tmd2 & LE_T2_LCOL)
- ifp->if_collisions++;
+ if_statinc(ifp, if_collisions);
if (tmd2 & LE_T2_RTRY)
- ifp->if_collisions += 16;
+ if_statadd(ifp, if_collisions, 16);
goto next_packet;
}
if (j == txs->txs_lastdesc)
break;
}
if (tmd1 & LE_T1_ONE)
- ifp->if_collisions++;
+ if_statinc(ifp, if_collisions);
else if (tmd & LE_T1_MORE) {
/* Real number is unknown. */
- ifp->if_collisions += 2;
+ if_statadd(ifp, if_collisions, 2);
}
- ifp->if_opackets++;
+ if_statinc(ifp, if_opackets);
next_packet:
sc->sc_txfree += txs->txs_dmamap->dm_nsegs;
bus_dmamap_sync(sc->sc_dmat, txs->txs_dmamap,
@@ -1461,7 +1461,7 @@ pcn_rxintr(struct pcn_softc *sc)
* buffer.
*/
if (rmd1 & LE_R1_ERR) {
- ifp->if_ierrors++;
+ if_statinc(ifp, if_ierrors);
/*
* If we got an overflow error, chances
* are there will be a CRC error. In
@@ -1530,7 +1530,7 @@ pcn_rxintr(struct pcn_softc *sc)
m = rxs->rxs_mbuf;
if (pcn_add_rxbuf(sc, i) != 0) {
dropit:
- ifp->if_ierrors++;
+ if_statinc(ifp, if_ierrors);
PCN_INIT_RXDESC(sc, i);
bus_dmamap_sync(sc->sc_dmat,
rxs->rxs_dmamap, 0,
Index: dev/pci/if_wm.c
===================================================================
RCS file: /cvsroot/src/sys/dev/pci/if_wm.c,v
retrieving revision 1.662
diff -u -p -r1.662 if_wm.c
--- dev/pci/if_wm.c 24 Jan 2020 02:50:41 -0000 1.662
+++ dev/pci/if_wm.c 25 Jan 2020 16:15:47 -0000
@@ -3266,7 +3266,7 @@ wm_watchdog_txq_locked(struct ifnet *ifp
"%s: device timeout (txfree %d txsfree %d txnext %d)\n",
device_xname(sc->sc_dev), txq->txq_free, txq->txq_sfree,
txq->txq_next);
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
#ifdef WM_DEBUG
for (i = txq->txq_sdirty; i != txq->txq_snext;
i = WM_NEXTTXS(txq, i)) {
@@ -3331,8 +3331,9 @@ wm_tick(void *arg)
WM_EVCNT_ADD(&sc->sc_ev_rx_macctl, CSR_READ(sc, WMREG_FCRUC));
}
- ifp->if_collisions += CSR_READ(sc, WMREG_COLC);
- ifp->if_ierrors += 0ULL /* ensure quad_t */
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_COLLISIONS] += CSR_READ(sc, WMREG_COLC);
+ stats[IF_STAT_IERRORS] += 0ULL /* ensure quad_t */
+ CSR_READ(sc, WMREG_CRCERRS)
+ CSR_READ(sc, WMREG_ALGNERRC)
+ CSR_READ(sc, WMREG_SYMERRC)
@@ -3349,7 +3350,8 @@ wm_tick(void *arg)
* If you want to know the nubmer of WMREG_RMBC, you should use such as
* own EVCNT instead of if_iqdrops.
*/
- ifp->if_iqdrops += CSR_READ(sc, WMREG_MPC);
+ stats[IF_STAT_IQDROPS] += CSR_READ(sc, WMREG_MPC);
+ IF_STAT_PUTREF(ifp);
if (sc->sc_flags & WM_F_HAS_MII)
mii_tick(&sc->sc_mii);
@@ -5847,8 +5849,10 @@ wm_init_locked(struct ifnet *ifp)
wm_stop_locked(ifp, 0);
/* Update statistics before reset */
- ifp->if_collisions += CSR_READ(sc, WMREG_COLC);
- ifp->if_ierrors += CSR_READ(sc, WMREG_RXERRC);
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_COLLISIONS] += CSR_READ(sc, WMREG_COLC);
+ stats[IF_STAT_IERRORS] += CSR_READ(sc, WMREG_RXERRC);
+ IF_STAT_PUTREF(ifp);
/* PCH_SPT hardware workaround */
if (sc->sc_type == WM_T_PCH_SPT)
@@ -7562,7 +7566,7 @@ wm_start(struct ifnet *ifp)
KASSERT(if_is_mpsafe(ifp));
#endif
/*
- * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.
+ * if_obytes and if_omcasts are added in if_transmit()@if.c.
*/
mutex_enter(txq->txq_lock);
@@ -7596,10 +7600,11 @@ wm_transmit(struct ifnet *ifp, struct mb
return ENOBUFS;
}
- /* XXX NOMPSAFE: ifp->if_data should be percpu. */
- ifp->if_obytes += m->m_pkthdr.len;
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_OBYTES] += m->m_pkthdr.len;
if (m->m_flags & M_MCAST)
- ifp->if_omcasts++;
+ stats[IF_STAT_OMCASTS]++;
+ IF_STAT_PUTREF(ifp);
if (mutex_tryenter(txq->txq_lock)) {
if (!txq->txq_stopping)
@@ -8167,7 +8172,7 @@ wm_nq_start(struct ifnet *ifp)
KASSERT(if_is_mpsafe(ifp));
#endif
/*
- * ifp->if_obytes and ifp->if_omcasts are added in if_transmit()@if.c.
+ * if_obytes and if_omcasts are added in if_transmit()@if.c.
*/
mutex_enter(txq->txq_lock);
@@ -8201,10 +8206,11 @@ wm_nq_transmit(struct ifnet *ifp, struct
return ENOBUFS;
}
- /* XXX NOMPSAFE: ifp->if_data should be percpu. */
- ifp->if_obytes += m->m_pkthdr.len;
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_OBYTES] += m->m_pkthdr.len;
if (m->m_flags & M_MCAST)
- ifp->if_omcasts++;
+ stats[IF_STAT_OMCASTS]++;
+ IF_STAT_PUTREF(ifp);
/*
* The situations which this mutex_tryenter() fails at running time
@@ -8649,18 +8655,18 @@ wm_txeof(struct wm_txqueue *txq, u_int l
if (((status & (WTX_ST_EC | WTX_ST_LC)) != 0)
&& ((sc->sc_type < WM_T_82574)
|| (sc->sc_type == WM_T_80003))) {
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
if (status & WTX_ST_LC)
log(LOG_WARNING, "%s: late collision\n",
device_xname(sc->sc_dev));
else if (status & WTX_ST_EC) {
- ifp->if_collisions +=
- TX_COLLISION_THRESHOLD + 1;
+ if_statadd(ifp, if_collisions,
+ TX_COLLISION_THRESHOLD + 1);
log(LOG_WARNING, "%s: excessive collisions\n",
device_xname(sc->sc_dev));
}
} else
- ifp->if_opackets++;
+ if_statinc(ifp, if_opackets);
txq->txq_packets++;
txq->txq_bytes += txs->txs_mbuf->m_pkthdr.len;
@@ -8982,7 +8988,7 @@ wm_rxeof(struct wm_rxqueue *rxq, u_int l
* Failed, throw away what we've done so
* far, and discard the rest of the packet.
*/
- ifp->if_ierrors++;
+ if_statinc(ifp, if_ierrors);
bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0,
rxs->rxs_dmamap->dm_mapsize, BUS_DMASYNC_PREREAD);
wm_init_rxdesc(rxq, i);
Index: net/files.net
===================================================================
RCS file: /cvsroot/src/sys/net/files.net,v
retrieving revision 1.24
diff -u -p -r1.24 files.net
--- net/files.net 20 Jan 2020 18:38:18 -0000 1.24
+++ net/files.net 25 Jan 2020 16:15:48 -0000
@@ -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: net/if.c
===================================================================
RCS file: /cvsroot/src/sys/net/if.c,v
retrieving revision 1.468
diff -u -p -r1.468 if.c
--- net/if.c 20 Jan 2020 18:38:18 -0000 1.468
+++ net/if.c 25 Jan 2020 16:15:49 -0000
@@ -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,20 @@ void if_tunnel_ro_percpu_rtcache_free(pe
percpu_foreach(ro_percpu, if_tunnel_rtcache_free_pc, NULL);
}
+static void
+if_export_if_data(ifnet_t *ifp, struct if_data *ifi)
+{
+
+ 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;
+ if_stats_to_if_data(ifp, ifi);
+}
/* common */
int
@@ -3083,7 +3101,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);
break;
case SIOCGIFINDEX:
@@ -3093,20 +3111,8 @@ 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);
+ if_stats_zero(ifp);
getnanotime(&ifp->if_lastchange);
break;
case SIOCSIFMTU:
@@ -3595,9 +3601,11 @@ if_transmit(struct ifnet *ifp, struct mb
goto out;
}
- ifp->if_obytes += pktlen;
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_OBYTES] += pktlen;
if (mcast)
- ifp->if_omcasts++;
+ stats[IF_STAT_OMCASTS]++;
+ IF_STAT_PUTREF(ifp);
if ((ifp->if_flags & IFF_OACTIVE) == 0)
if_start_lock(ifp);
@@ -3666,7 +3674,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: net/if.h
===================================================================
RCS file: /cvsroot/src/sys/net/if.h,v
retrieving revision 1.277
diff -u -p -r1.277 if.h
--- net/if.h 19 Sep 2019 06:07:24 -0000 1.277
+++ net/if.h 25 Jan 2020 16:15:49 -0000
@@ -273,6 +273,9 @@ 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. */
+#ifdef __IF_STATS_PERCPU
+ percpu_t *if_stats; /* :: statistics */
+#endif /* __IF_STATS_PERCPU */
struct if_data if_data; /* ?: statistics and other data about if */
/*
* Procedure handles. If you add more of these, don't forget the
@@ -393,6 +396,8 @@ typedef struct ifnet {
if_multiaddrs; /* 6: */
#endif
} ifnet_t;
+
+#include <net/if_stats.h>
#define if_mtu if_data.ifi_mtu
#define if_type if_data.ifi_type
@@ -401,6 +406,7 @@ typedef struct ifnet {
#define if_metric if_data.ifi_metric
#define if_link_state if_data.ifi_link_state
#define if_baudrate if_data.ifi_baudrate
+#ifndef __IF_STATS_PERCPU
#define if_ipackets if_data.ifi_ipackets
#define if_ierrors if_data.ifi_ierrors
#define if_opackets if_data.ifi_opackets
@@ -412,6 +418,7 @@ typedef struct ifnet {
#define if_omcasts if_data.ifi_omcasts
#define if_iqdrops if_data.ifi_iqdrops
#define if_noproto if_data.ifi_noproto
+#endif /* __IF_STATS_PERCPU */
#define if_lastchange if_data.ifi_lastchange
#define if_name(ifp) ((ifp)->if_xname)
Index: net/if_bridge.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_bridge.c,v
retrieving revision 1.165
diff -u -p -r1.165 if_bridge.c
--- net/if_bridge.c 5 Aug 2019 13:30:21 -0000 1.165
+++ net/if_bridge.c 25 Jan 2020 16:15:49 -0000
@@ -1465,10 +1465,12 @@ bridge_enqueue(struct bridge_softc *sc,
return;
}
- sc->sc_if.if_opackets++;
- sc->sc_if.if_obytes += len;
+ uint64_t *stats = IF_STAT_GETREF(&sc->sc_if);
+ stats[IF_STAT_OPACKETS]++;
+ stats[IF_STAT_OBYTES] += len;
if (mflags & M_MCAST)
- sc->sc_if.if_omcasts++;
+ stats[IF_STAT_OMCASTS]++;
+ IF_STAT_PUTREF(&sc->sc_if);
}
/*
@@ -1750,8 +1752,10 @@ bridge_forward(struct bridge_softc *sc,
goto out;
}
- sc->sc_if.if_ipackets++;
- sc->sc_if.if_ibytes += m->m_pkthdr.len;
+ uint64_t *stats = IF_STAT_GETREF(&sc->sc_if);
+ stats[IF_STAT_IPACKETS]++;
+ stats[IF_STAT_IBYTES] += m->m_pkthdr.len;
+ IF_STAT_PUTREF(&sc->sc_if);
/*
* Look up the bridge_iflist.
Index: net/if_faith.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_faith.c,v
retrieving revision 1.60
diff -u -p -r1.60 if_faith.c
--- net/if_faith.c 27 Apr 2019 06:18:15 -0000 1.60
+++ net/if_faith.c 25 Jan 2020 16:15:49 -0000
@@ -201,8 +201,10 @@ faithoutput(struct ifnet *ifp, struct mb
rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
}
pktlen = m->m_pkthdr.len;
- ifp->if_opackets++;
- ifp->if_obytes += pktlen;
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_OPACKETS]++;
+ stats[IF_STAT_OBYTES] += pktlen;
+ IF_STAT_PUTREF(ifp);
switch (af) {
#ifdef INET
case AF_INET:
@@ -225,8 +227,10 @@ faithoutput(struct ifnet *ifp, struct mb
s = splnet();
if (__predict_true(pktq_enqueue(pktq, m, 0))) {
- ifp->if_ipackets++;
- ifp->if_ibytes += pktlen;
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_IPACKETS]++;
+ stats[IF_STAT_IBYTES] += pktlen;
+ IF_STAT_PUTREF(ifp);
error = 0;
} else {
m_freem(m);
Index: net/if_gif.c
===================================================================
RCS file: /cvsroot/src/sys/net/if_gif.c,v
retrieving revision 1.150
diff -u -p -r1.150 if_gif.c
--- net/if_gif.c 30 Oct 2019 03:45:59 -0000 1.150
+++ net/if_gif.c 25 Jan 2020 16:15:49 -0000
@@ -563,7 +563,7 @@ end:
if (var != NULL)
gif_putref_variant(var, &psref);
if (error)
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
return error;
}
@@ -593,7 +593,7 @@ gif_start(struct ifnet *ifp)
if (sizeof(int) > m->m_len) {
m = m_pullup(m, sizeof(int));
if (!m) {
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
continue;
}
}
@@ -604,12 +604,14 @@ gif_start(struct ifnet *ifp)
len = m->m_pkthdr.len;
error = var->gv_output(var, family, m);
+ uint64_t *stats = IF_STAT_GETREF(ifp);
if (error)
- ifp->if_oerrors++;
+ stats[IF_STAT_OERRORS]++;
else {
- ifp->if_opackets++;
- ifp->if_obytes += len;
+ stats[IF_STAT_OPACKETS]++;
+ stats[IF_STAT_OBYTES] += len;
}
+ IF_STAT_PUTREF(ifp);
}
gif_putref_variant(var, &psref);
@@ -651,7 +653,7 @@ gif_transmit_direct(struct gif_variant *
if (sizeof(int) > m->m_len) {
m = m_pullup(m, sizeof(int));
if (!m) {
- ifp->if_oerrors++;
+ if_statinc(ifp, if_oerrors);
return ENOBUFS;
}
}
@@ -661,13 +663,15 @@ gif_transmit_direct(struct gif_variant *
len = m->m_pkthdr.len;
+ uint64_t *stats = IF_STAT_GETREF(ifp);
error = var->gv_output(var, family, m);
if (error)
- ifp->if_oerrors++;
+ stats[IF_STAT_OERRORS]++;
else {
- ifp->if_opackets++;
- ifp->if_obytes += len;
+ stats[IF_STAT_OPACKETS]++;
+ stats[IF_STAT_OBYTES] += len;
}
+ IF_STAT_PUTREF(ifp);
return error;
}
@@ -717,8 +721,10 @@ gif_input(struct mbuf *m, int af, struct
const uint32_t h = pktq_rps_hash(m);
#endif
if (__predict_true(pktq_enqueue(pktq, m, h))) {
- ifp->if_ibytes += pktlen;
- ifp->if_ipackets++;
+ uint64_t *stats = IF_STAT_GETREF(ifp);
+ stats[IF_STAT_IBYTES] += pktlen;
+ stats[IF_STAT_IPACKETS]++;
+ IF_STAT_PUTREF(ifp);
} else {
m_freem(m);
}
Index: net/if_stats.c
===================================================================
RCS file: net/if_stats.c
diff -N net/if_stats.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ net/if_stats.c 25 Jan 2020 16:15:49 -0000
@@ -0,0 +1,167 @@
+/* $NetBSD$ */
+
+/*-
+ * 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$");
+
+#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 *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 *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
+
+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_data * const ifi = v2;
+ int s = splnet();
+
+ ifi->ifi_ipackets += local_counters[IF_STAT_IPACKETS];
+ ifi->ifi_ierrors += local_counters[IF_STAT_IERRORS];
+ ifi->ifi_opackets += local_counters[IF_STAT_OPACKETS];
+ ifi->ifi_oerrors += local_counters[IF_STAT_OERRORS];
+ ifi->ifi_collisions += local_counters[IF_STAT_COLLISIONS];
+ ifi->ifi_ibytes += local_counters[IF_STAT_IBYTES];
+ ifi->ifi_obytes += local_counters[IF_STAT_OBYTES];
+ ifi->ifi_imcasts += local_counters[IF_STAT_IMCASTS];
+ ifi->ifi_omcasts += local_counters[IF_STAT_OMCASTS];
+ ifi->ifi_iqdrops += local_counters[IF_STAT_IQDROPS];
+ ifi->ifi_noproto += local_counters[IF_STAT_NOPROTO];
+
+ 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.
+ */
+void
+if_stats_to_if_data(ifnet_t *ifp, struct if_data *ifi)
+{
+
+ memset(ifi, 0, sizeof(*ifi));
+ percpu_foreach(ifp->if_stats, if_stats_to_if_data_cb, ifi);
+}
+
+static void
+if_stats_zero_cb(void *v1, void *v2, struct cpu_info *ci)
+{
+ int s = splnet();
+
+ memset(v1, 0, IF_STATS_SIZE);
+
+ splx(s);
+}
+
+/*
+ * if_stats_zero --
+ * Zero the interface statistics.
+ */
+void
+if_stats_zero(ifnet_t *ifp)
+{
+
+ percpu_foreach(ifp->if_stats, if_stats_zero_cb, NULL);
+}
+
+#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.
+ */
+void
+if_stats_to_if_data(ifnet_t *ifp, struct if_data *ifi)
+{
+ int s = splnet();
+
+ memcpy(&ifi->ifi_ipackets, &ifp->if_data.ifi_ipackets,
+ offsetof(struct if_data, ifi_lastchange) -
+ offsetof(struct if_data, ifi_ipackets));
+
+ splx(s);
+}
+
+/*
+ * if_stats_zero --
+ * Zero the interface statistics.
+ */
+void
+if_stats_zero(ifnet_t *ifp)
+{
+ int s = splnet();
+
+ 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: net/if_stats.h
===================================================================
RCS file: net/if_stats.h
diff -N net/if_stats.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ net/if_stats.h 25 Jan 2020 16:15:49 -0000
@@ -0,0 +1,150 @@
+/* $NetBSD$ */
+
+/*-
+ * 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_
+
+#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
+#include <net/net_stats.h>
+
+#define IF_STAT_GETREF(ifp) _NET_STAT_GETREF((ifp)->if_stats)
+#define IF_STAT_PUTREF(ifp) _NET_STAT_PUTREF((ifp)->if_stats)
+
+#define IF_STAT_IPACKETS if_ipackets
+#define IF_STAT_IERRORS if_ierrors
+#define IF_STAT_OPACKETS if_opackets
+#define IF_STAT_OERRORS if_oerrors
+#define IF_STAT_COLLISIONS if_collisions
+#define IF_STAT_IBYTES if_ibytes
+#define IF_STAT_OBYTES if_obytes
+#define IF_STAT_IMCASTS if_imcasts
+#define IF_STAT_OMCASTS if_omcasts
+#define IF_STAT_IQDROPS if_iqdrops
+#define IF_STAT_NOPROTO if_noproto
+
+static inline void
+if_statinc(ifnet_t *ifp, if_stat_t x)
+{
+ _NET_STATINC((ifp)->if_stats, x);
+}
+
+static inline void
+if_statdec(ifnet_t *ifp, if_stat_t x)
+{
+ _NET_STATDEC((ifp)->if_stats, 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_statsub(ifnet_t *ifp, if_stat_t x, uint64_t v)
+{
+ _NET_STATSUB((ifp)->if_stats, 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 uint64_t *
+IF_STAT_GETREF(ifnet_t *ifp)
+{
+ return (uint64_t *)(((uintptr_t)ifp) +
+ offsetof(ifnet_t, if_data.ifi_ipackets));
+}
+
+#define IF_STAT_PUTREF(ifp) __nothing
+
+#define _IF_STAT_IDX(x) \
+ ((offsetof(struct if_data, x) - \
+ offsetof(struct if_data, ifi_ipackets)) / sizeof(uint64_t))
+
+#define IF_STAT_IPACKETS _IF_STAT_IDX(ifi_ipackets)
+#define IF_STAT_IERRORS _IF_STAT_IDX(ifi_ierrors)
+#define IF_STAT_OPACKETS _IF_STAT_IDX(ifi_opackets)
+#define IF_STAT_OERRORS _IF_STAT_IDX(ifi_oerrors)
+#define IF_STAT_COLLISIONS _IF_STAT_IDX(ifi_collisions)
+#define IF_STAT_IBYTES _IF_STAT_IDX(ifi_ibytes)
+#define IF_STAT_OBYTES _IF_STAT_IDX(ifi_obytes)
+#define IF_STAT_IMCASTS _IF_STAT_IDX(ifi_imcasts)
+#define IF_STAT_OMCASTS _IF_STAT_IDX(ifi_omcasts)
+#define IF_STAT_IQDROPS _IF_STAT_IDX(ifi_iqdrops)
+#define IF_STAT_NOPROTO _IF_STAT_IDX(ifi_noproto)
+
+#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)
+
+#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 *);
+void if_stats_zero(ifnet_t *);
+#endif /* _KERNEL */
+
+#endif /* !_NET_IF_STATS_H_ */
-- thorpej
Home |
Main Index |
Thread Index |
Old Index