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