since counters are an array of uint64_t values, this uses an enum
to list the indexes into such an array.

we still export an ipstat struct to userland (which you can see
with netstat -sp ip). the export cheats a bit because we know that
the struct is a collection of u_longs, so we just iterate over the
coutners and the struct as an array and assign values.

ok?

Index: net/if_bridge.c
===================================================================
RCS file: /cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.287
diff -u -p -r1.287 if_bridge.c
--- net/if_bridge.c     3 Oct 2016 15:53:09 -0000       1.287
+++ net/if_bridge.c     9 Nov 2016 04:45:23 -0000
@@ -1603,25 +1603,25 @@ bridge_ip(struct bridge_softc *sc, int d
                /* Copy minimal header, and drop invalids */
                if (m->m_len < sizeof(struct ip) &&
                    (m = m_pullup(m, sizeof(struct ip))) == NULL) {
-                       ipstat.ips_toosmall++;
+                       ipstat_inc(ips_toosmall);
                        return (NULL);
                }
                ip = mtod(m, struct ip *);
 
                if (ip->ip_v != IPVERSION) {
-                       ipstat.ips_badvers++;
+                       ipstat_inc(ips_badvers);
                        goto dropit;
                }
 
                hlen = ip->ip_hl << 2;  /* get whole header length */
                if (hlen < sizeof(struct ip)) {
-                       ipstat.ips_badhlen++;
+                       ipstat_inc(ips_badhlen);
                        goto dropit;
                }
 
                if (hlen > m->m_len) {
                        if ((m = m_pullup(m, hlen)) == NULL) {
-                               ipstat.ips_badhlen++;
+                               ipstat_inc(ips_badhlen);
                                return (NULL);
                        }
                        ip = mtod(m, struct ip *);
@@ -1629,13 +1629,13 @@ bridge_ip(struct bridge_softc *sc, int d
 
                if ((m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_OK) == 0) {
                        if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_BAD) {
-                               ipstat.ips_badsum++;
+                               ipstat_inc(ips_badsum);
                                goto dropit;
                        }
 
-                       ipstat.ips_inswcsum++;
+                       ipstat_inc(ips_inswcsum);
                        if (in_cksum(m, hlen) != 0) {
-                               ipstat.ips_badsum++;
+                               ipstat_inc(ips_badsum);
                                goto dropit;
                        }
                }
@@ -1678,7 +1678,7 @@ bridge_ip(struct bridge_softc *sc, int d
                if (0 && (ifp->if_capabilities & IFCAP_CSUM_IPv4))
                        m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
-                       ipstat.ips_outswcsum++;
+                       ipstat_inc(ips_outswcsum);
                        ip->ip_sum = in_cksum(m, hlen);
                }
 
@@ -1848,7 +1848,7 @@ bridge_fragment(struct bridge_softc *sc,
        }
 
        if (error == 0)
-               ipstat.ips_fragmented++;
+               ipstat_inc(ips_fragmented);
 
        return;
  dropit:
Index: net/if_etherip.c
===================================================================
RCS file: /cvs/src/sys/net/if_etherip.c,v
retrieving revision 1.7
diff -u -p -r1.7 if_etherip.c
--- net/if_etherip.c    13 Apr 2016 11:41:15 -0000      1.7
+++ net/if_etherip.c    9 Nov 2016 04:45:23 -0000
@@ -430,7 +430,7 @@ ip_etherip_input(struct mbuf *m, ...)
 
        if (ip->ip_p != IPPROTO_ETHERIP) {
                m_freem(m);
-               ipstat.ips_noproto++;
+               ipstat_inc(ips_noproto);
                return;
        }
 
Index: net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.996
diff -u -p -r1.996 pf.c
--- net/pf.c    28 Oct 2016 07:54:19 -0000      1.996
+++ net/pf.c    9 Nov 2016 04:45:23 -0000
@@ -5825,7 +5825,7 @@ pf_route(struct mbuf **m, struct pf_pdes
        if (!r->rt) {
                rt = rtalloc(sintosa(dst), RT_RESOLVE, rtableid);
                if (rt == NULL) {
-                       ipstat.ips_noroute++;
+                       ipstat_inc(ips_noroute);
                        goto bad;
                }
 
@@ -5859,7 +5859,7 @@ pf_route(struct mbuf **m, struct pf_pdes
 
                rt = rtalloc(sintosa(dst), RT_RESOLVE, rtableid);
                if (rt == NULL) {
-                       ipstat.ips_noroute++;
+                       ipstat_inc(ips_noroute);
                        goto bad;
                }
        }
@@ -5887,7 +5887,7 @@ pf_route(struct mbuf **m, struct pf_pdes
                if (ifp->if_capabilities & IFCAP_CSUM_IPv4)
                        m0->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
-                       ipstat.ips_outswcsum++;
+                       ipstat_inc(ips_outswcsum);
                        ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
                }
                error = ifp->if_output(ifp, m0, sintosa(dst), rt);
@@ -5899,7 +5899,7 @@ pf_route(struct mbuf **m, struct pf_pdes
         * Must be able to put at least 8 bytes per fragment.
         */
        if (ip->ip_off & htons(IP_DF)) {
-               ipstat.ips_cantfrag++;
+               ipstat_inc(ips_cantfrag);
                if (r->rt != PF_DUPTO) {
                        icmp_error(m0, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, 0,
                            ifp->if_mtu);
@@ -5925,7 +5925,7 @@ pf_route(struct mbuf **m, struct pf_pdes
        }
 
        if (error == 0)
-               ipstat.ips_fragmented++;
+               ipstat_inc(ips_fragmented);
 
 done:
        if (r->rt != PF_DUPTO)
Index: netinet/ip_icmp.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_icmp.c,v
retrieving revision 1.152
diff -u -p -r1.152 ip_icmp.c
--- netinet/ip_icmp.c   22 Aug 2016 15:37:23 -0000      1.152
+++ netinet/ip_icmp.c   9 Nov 2016 04:45:23 -0000
@@ -751,7 +751,7 @@ icmp_reflect(struct mbuf *m, struct mbuf
                /* keep packet in the original virtual instance */
                rt = rtalloc(sintosa(&sin), RT_RESOLVE, rtableid);
                if (rt == NULL) {
-                       ipstat.ips_noroute++;
+                       ipstat_inc(ips_noroute);
                        m_freem(m);
                        return (EHOSTUNREACH);
                }
Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.282
diff -u -p -r1.282 ip_input.c
--- netinet/ip_input.c  22 Sep 2016 10:12:25 -0000      1.282
+++ netinet/ip_input.c  9 Nov 2016 04:45:23 -0000
@@ -120,7 +120,9 @@ struct niqueue ipintrq = NIQUEUE_INITIAL
 struct pool ipqent_pool;
 struct pool ipq_pool;
 
-struct ipstat ipstat;
+struct cpumem *ipcounters;
+
+int ip_sysctl_ipstat(void *, size_t *, void *);
 
 static struct mbuf_queue       ipsend_mq;
 
@@ -132,7 +134,7 @@ void        ip_forward(struct mbuf *, struct if
 int    ip_input_ipsec_fwd_check(struct mbuf *, int);
 int    ip_input_ipsec_ours_check(struct mbuf *, int);
 #endif /* IPSEC */
-
+       
 static void ip_send_dispatch(void *);
 static struct task ipsend_task = TASK_INITIALIZER(ip_send_dispatch, 
&ipsend_mq);
 /*
@@ -166,6 +168,8 @@ ip_init(void)
        const u_int16_t defrootonlyports_tcp[] = DEFROOTONLYPORTS_TCP;
        const u_int16_t defrootonlyports_udp[] = DEFROOTONLYPORTS_UDP;
 
+       ipcounters = counters_alloc(ips_ncounters, M_PCB);
+
        pool_init(&ipqent_pool, sizeof(struct ipqent), 0,
            IPL_SOFTNET, 0, "ipqe",  NULL);
        pool_init(&ipq_pool, sizeof(struct ipq), 0,
@@ -247,25 +251,25 @@ ipv4_input(struct mbuf *m)
        if (ifp == NULL)
                goto bad;
 
-       ipstat.ips_total++;
+       ipstat_inc(ips_total);
        if (m->m_len < sizeof (struct ip) &&
            (m = m_pullup(m, sizeof (struct ip))) == NULL) {
-               ipstat.ips_toosmall++;
+               ipstat_inc(ips_toosmall);
                goto out;
        }
        ip = mtod(m, struct ip *);
        if (ip->ip_v != IPVERSION) {
-               ipstat.ips_badvers++;
+               ipstat_inc(ips_badvers);
                goto bad;
        }
        hlen = ip->ip_hl << 2;
        if (hlen < sizeof(struct ip)) { /* minimum header length */
-               ipstat.ips_badhlen++;
+               ipstat_inc(ips_badhlen);
                goto bad;
        }
        if (hlen > m->m_len) {
                if ((m = m_pullup(m, hlen)) == NULL) {
-                       ipstat.ips_badhlen++;
+                       ipstat_inc(ips_badhlen);
                        goto out;
                }
                ip = mtod(m, struct ip *);
@@ -275,20 +279,20 @@ ipv4_input(struct mbuf *m)
        if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
            (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
                if ((ifp->if_flags & IFF_LOOPBACK) == 0) {
-                       ipstat.ips_badaddr++;
+                       ipstat_inc(ips_badaddr);
                        goto bad;
                }
        }
 
        if ((m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_OK) == 0) {
                if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_IN_BAD) {
-                       ipstat.ips_badsum++;
+                       ipstat_inc(ips_badsum);
                        goto bad;
                }
 
-               ipstat.ips_inswcsum++;
+               ipstat_inc(ips_inswcsum);
                if (in_cksum(m, hlen) != 0) {
-                       ipstat.ips_badsum++;
+                       ipstat_inc(ips_badsum);
                        goto bad;
                }
        }
@@ -300,7 +304,7 @@ ipv4_input(struct mbuf *m)
         * Convert fields to host representation.
         */
        if (len < hlen) {
-               ipstat.ips_badlen++;
+               ipstat_inc(ips_badlen);
                goto bad;
        }
 
@@ -311,7 +315,7 @@ ipv4_input(struct mbuf *m)
         * Drop packet if shorter than we expect.
         */
        if (m->m_pkthdr.len < len) {
-               ipstat.ips_tooshort++;
+               ipstat_inc(ips_tooshort);
                goto bad;
        }
        if (m->m_pkthdr.len > len) {
@@ -370,7 +374,7 @@ ipv4_input(struct mbuf *m)
                if (ipmforwarding && ip_mrouter) {
                        if (m->m_flags & M_EXT) {
                                if ((m = m_pullup(m, hlen)) == NULL) {
-                                       ipstat.ips_toosmall++;
+                                       ipstat_inc(ips_toosmall);
                                        goto out;
                                }
                                ip = mtod(m, struct ip *);
@@ -391,7 +395,7 @@ ipv4_input(struct mbuf *m)
                        rv = ip_mforward(m, ifp);
                        KERNEL_UNLOCK();
                        if (rv != 0) {
-                               ipstat.ips_cantforward++;
+                               ipstat_inc(ips_cantforward);
                                goto bad;
                        }
 
@@ -404,7 +408,7 @@ ipv4_input(struct mbuf *m)
                                ip_ours(m);
                                goto out;
                        }
-                       ipstat.ips_forward++;
+                       ipstat_inc(ips_forward);
                }
 #endif
                /*
@@ -412,9 +416,9 @@ ipv4_input(struct mbuf *m)
                 * arrival interface.
                 */
                if (!in_hasmulti(&ip->ip_dst, ifp)) {
-                       ipstat.ips_notmember++;
+                       ipstat_inc(ips_notmember);
                        if (!IN_LOCAL_GROUP(ip->ip_dst.s_addr))
-                               ipstat.ips_cantforward++;
+                               ipstat_inc(ips_cantforward);
                        goto bad;
                }
                ip_ours(m);
@@ -436,7 +440,7 @@ ipv4_input(struct mbuf *m)
         * Not for us; forward if possible and desirable.
         */
        if (ipforwarding == 0) {
-               ipstat.ips_cantforward++;
+               ipstat_inc(ips_cantforward);
                goto bad;
        }
 #ifdef IPSEC
@@ -445,7 +449,7 @@ ipv4_input(struct mbuf *m)
                rv = ip_input_ipsec_fwd_check(m, hlen);
                KERNEL_UNLOCK();
                if (rv != 0) {
-                       ipstat.ips_cantforward++;
+                       ipstat_inc(ips_cantforward);
                        goto bad;
                }
                /*
@@ -493,7 +497,7 @@ ip_ours(struct mbuf *m)
        if (ip->ip_off &~ htons(IP_DF | IP_RF)) {
                if (m->m_flags & M_EXT) {               /* XXX */
                        if ((m = m_pullup(m, hlen)) == NULL) {
-                               ipstat.ips_toosmall++;
+                               ipstat_inc(ips_toosmall);
                                return;
                        }
                        ip = mtod(m, struct ip *);
@@ -526,7 +530,7 @@ found:
                         */
                        if (ntohs(ip->ip_len) == 0 ||
                            (ntohs(ip->ip_len) & 0x7) != 0) {
-                               ipstat.ips_badfrags++;
+                               ipstat_inc(ips_badfrags);
                                goto bad;
                        }
                }
@@ -538,16 +542,16 @@ found:
                 * attempt reassembly; if it succeeds, proceed.
                 */
                if (mff || ip->ip_off) {
-                       ipstat.ips_fragments++;
+                       ipstat_inc(ips_fragments);
                        if (ip_frags + 1 > ip_maxqueue) {
                                ip_flush();
-                               ipstat.ips_rcvmemdrop++;
+                               ipstat_inc(ips_rcvmemdrop);
                                goto bad;
                        }
 
                        ipqe = pool_get(&ipqent_pool, PR_NOWAIT);
                        if (ipqe == NULL) {
-                               ipstat.ips_rcvmemdrop++;
+                               ipstat_inc(ips_rcvmemdrop);
                                goto bad;
                        }
                        ip_frags++;
@@ -558,7 +562,7 @@ found:
                        if (m == NULL) {
                                return;
                        }
-                       ipstat.ips_reassembled++;
+                       ipstat_inc(ips_reassembled);
                        ip = mtod(m, struct ip *);
                        hlen = ip->ip_hl << 2;
                        ip->ip_len = htons(ntohs(ip->ip_len) + hlen);
@@ -570,7 +574,7 @@ found:
 #ifdef IPSEC
        if (ipsec_in_use) {
                if (ip_input_ipsec_ours_check(m, hlen) != 0) {
-                       ipstat.ips_cantforward++;
+                       ipstat_inc(ips_cantforward);
                        goto bad;
                }
        }
@@ -580,7 +584,7 @@ found:
        /*
         * Switch out to protocol's input routine.
         */
-       ipstat.ips_delivered++;
+       ipstat_inc(ips_delivered);
        (*inetsw[ip_protox[ip->ip_p]].pr_input)(m, hlen, NULL, 0);
        return;
 bad:
@@ -896,7 +900,7 @@ insert:
        q = LIST_FIRST(&fp->ipq_fragq);
        ip = q->ipqe_ip;
        if ((next + (ip->ip_hl << 2)) > IP_MAXPACKET) {
-               ipstat.ips_toolong++;
+               ipstat_inc(ips_toolong);
                ip_freef(fp);
                return (0);
        }
@@ -938,7 +942,7 @@ insert:
        return (m);
 
 dropfrag:
-       ipstat.ips_fragdropped++;
+       ipstat_inc(ips_fragdropped);
        m_freem(m);
        pool_put(&ipqent_pool, ipqe);
        ip_frags--;
@@ -979,7 +983,7 @@ ip_slowtimo(void)
        for (fp = LIST_FIRST(&ipq); fp != NULL; fp = nfp) {
                nfp = LIST_NEXT(fp, ipq_q);
                if (--fp->ipq_ttl == 0) {
-                       ipstat.ips_fragtimeout++;
+                       ipstat_inc(ips_fragtimeout);
                        ip_freef(fp);
                }
        }
@@ -993,7 +997,7 @@ void
 ip_drain(void)
 {
        while (!LIST_EMPTY(&ipq)) {
-               ipstat.ips_fragdropped++;
+               ipstat_inc(ips_fragdropped);
                ip_freef(LIST_FIRST(&ipq));
        }
 }
@@ -1008,7 +1012,7 @@ ip_flush(void)
 
        /* ipq already locked */
        while (!LIST_EMPTY(&ipq) && ip_frags > ip_maxqueue * 3 / 4 && --max) {
-               ipstat.ips_fragdropped++;
+               ipstat_inc(ips_fragdropped);
                ip_freef(LIST_FIRST(&ipq));
        }
 }
@@ -1263,7 +1267,7 @@ ip_dooptions(struct mbuf *m, struct ifne
 bad:
        KERNEL_UNLOCK();
        icmp_error(m, type, code, 0, 0);
-       ipstat.ips_badoptions++;
+       ipstat_inc(ips_badoptions);
        return (1);
 }
 
@@ -1413,7 +1417,7 @@ ip_forward(struct mbuf *m, struct ifnet 
 
        dest = 0;
        if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
-               ipstat.ips_cantforward++;
+               ipstat_inc(ips_cantforward);
                m_freem(m);
                goto freecopy;
        }
@@ -1494,11 +1498,11 @@ ip_forward(struct mbuf *m, struct ifnet 
            NULL, NULL, 0);
        rt = ro.ro_rt;
        if (error)
-               ipstat.ips_cantforward++;
+               ipstat_inc(ips_cantforward);
        else {
-               ipstat.ips_forward++;
+               ipstat_inc(ips_forward);
                if (type)
-                       ipstat.ips_redirectsent++;
+                       ipstat_inc(ips_redirectsent);
                else
                        goto freecopy;
        }
@@ -1538,7 +1542,7 @@ ip_forward(struct mbuf *m, struct ifnet 
                        }
                }
 #endif /*IPSEC*/
-               ipstat.ips_cantfrag++;
+               ipstat_inc(ips_cantfrag);
                break;
 
        case EACCES:
@@ -1632,8 +1636,7 @@ ip_sysctl(int *name, u_int namelen, void
                return (sysctl_niq(name + 1, namelen - 1,
                    oldp, oldlenp, newp, newlen, &ipintrq));
        case IPCTL_STATS:
-               return (sysctl_rdstruct(oldp, oldlenp, newp,
-                   &ipstat, sizeof(ipstat)));
+               return (ip_sysctl_ipstat(oldp, oldlenp, newp));
 #ifdef MROUTING
        case IPCTL_MRTSTATS:
                return (sysctl_rdstruct(oldp, oldlenp, newp,
@@ -1662,6 +1665,24 @@ ip_sysctl(int *name, u_int namelen, void
                return (EOPNOTSUPP);
        }
        /* NOTREACHED */
+}
+
+int
+ip_sysctl_ipstat(void *oldp, size_t *oldlenp, void *newp)
+{
+       uint64_t counters[ips_ncounters];
+       struct ipstat ipstat;
+       u_long *words = (u_long *)&ipstat;
+       int i;
+
+       KASSERT(sizeof(ipstat) == (nitems(counters) * sizeof(u_long)));
+
+       counters_read(ipcounters, counters, nitems(counters));
+
+       for (i = 0; i < nitems(counters); i++)
+               words[i] = (u_long)counters[i];
+
+       return (sysctl_rdstruct(oldp, oldlenp, newp, &ipstat, sizeof(ipstat)));
 }
 
 void
Index: netinet/ip_output.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.327
diff -u -p -r1.327 ip_output.c
--- netinet/ip_output.c 4 Sep 2016 17:18:56 -0000       1.327
+++ netinet/ip_output.c 9 Nov 2016 04:45:23 -0000
@@ -133,7 +133,7 @@ ip_output(struct mbuf *m0, struct mbuf *
                ip->ip_off &= htons(IP_DF);
                ip->ip_id = htons(ip_randomid());
                ip->ip_hl = hlen >> 2;
-               ipstat.ips_localout++;
+               ipstat_inc(ips_localout);
        } else {
                hlen = ip->ip_hl << 2;
        }
@@ -204,7 +204,7 @@ reroute:
                            &ip->ip_src.s_addr, ro->ro_tableid);
 
                if (ro->ro_rt == NULL) {
-                       ipstat.ips_noroute++;
+                       ipstat_inc(ips_noroute);
                        error = EHOSTUNREACH;
                        goto bad;
                }
@@ -284,7 +284,7 @@ reroute:
                 * output
                 */
                if (!ifp) {
-                       ipstat.ips_noroute++;
+                       ipstat_inc(ips_noroute);
                        error = EHOSTUNREACH;
                        goto bad;
                }
@@ -298,7 +298,7 @@ reroute:
                      (ifp->if_flags & IFF_MULTICAST) == 0) ||
                     ((m->m_flags & M_BCAST) &&
                      (ifp->if_flags & IFF_BROADCAST) == 0)) && (tdb == NULL)) {
-                       ipstat.ips_noroute++;
+                       ipstat_inc(ips_noroute);
                        error = ENETUNREACH;
                        goto bad;
                }
@@ -464,7 +464,7 @@ sendit:
                    (ifp->if_bridgeport == NULL))
                        m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
-                       ipstat.ips_outswcsum++;
+                       ipstat_inc(ips_outswcsum);
                        ip->ip_sum = in_cksum(m, hlen);
                }
 
@@ -495,7 +495,7 @@ sendit:
                    (ro->ro_rt->rt_rmx.rmx_mtu > ifp->if_mtu)) {
                        ro->ro_rt->rt_rmx.rmx_mtu = ifp->if_mtu;
                }
-               ipstat.ips_cantfrag++;
+               ipstat_inc(ips_cantfrag);
                goto bad;
        }
 
@@ -515,7 +515,7 @@ sendit:
        }
 
        if (error == 0)
-               ipstat.ips_fragmented++;
+               ipstat_inc(ips_fragmented);
 
 done:
        if (ro == &iproute && ro->ro_rt)
@@ -676,7 +676,7 @@ ip_fragment(struct mbuf *m, struct ifnet
        for (off = hlen + len; off < ntohs(ip->ip_len); off += len) {
                MGETHDR(m, M_DONTWAIT, MT_HEADER);
                if (m == NULL) {
-                       ipstat.ips_odropped++;
+                       ipstat_inc(ips_odropped);
                        error = ENOBUFS;
                        goto sendorfree;
                }
@@ -705,7 +705,7 @@ ip_fragment(struct mbuf *m, struct ifnet
                mhip->ip_len = htons((u_int16_t)(len + mhlen));
                m->m_next = m_copym(m0, off, len, M_NOWAIT);
                if (m->m_next == 0) {
-                       ipstat.ips_odropped++;
+                       ipstat_inc(ips_odropped);
                        error = ENOBUFS;
                        goto sendorfree;
                }
@@ -718,10 +718,10 @@ ip_fragment(struct mbuf *m, struct ifnet
                    (ifp->if_bridgeport == NULL))
                        m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
                else {
-                       ipstat.ips_outswcsum++;
+                       ipstat_inc(ips_outswcsum);
                        mhip->ip_sum = in_cksum(m, mhlen);
                }
-               ipstat.ips_ofragments++;
+               ipstat_inc(ips_ofragments);
                fragments++;
        }
        /*
@@ -739,7 +739,7 @@ ip_fragment(struct mbuf *m, struct ifnet
            (ifp->if_bridgeport == NULL))
                m->m_pkthdr.csum_flags |= M_IPV4_CSUM_OUT;
        else {
-               ipstat.ips_outswcsum++;
+               ipstat_inc(ips_outswcsum);
                ip->ip_sum = in_cksum(m, hlen);
        }
 sendorfree:
Index: netinet/ip_var.h
===================================================================
RCS file: /cvs/src/sys/netinet/ip_var.h,v
retrieving revision 1.62
diff -u -p -r1.62 ip_var.h
--- netinet/ip_var.h    15 Apr 2016 11:18:40 -0000      1.62
+++ netinet/ip_var.h    9 Nov 2016 04:45:23 -0000
@@ -96,6 +96,53 @@ struct ipoption {
 
 #ifdef _KERNEL
 
+#include <sys/percpu.h>
+
+enum ipstat_counters {
+       ips_total,              /* total packets received */
+       ips_badsum,             /* checksum bad */
+       ips_tooshort,           /* packet too short */
+       ips_toosmall,           /* not enough data */
+       ips_badhlen,            /* ip header length < data size */
+       ips_badlen,             /* ip length < ip header length */
+       ips_fragments,          /* fragments received */
+       ips_fragdropped,        /* frags dropped (dups, out of space) */
+       ips_fragtimeout,        /* fragments timed out */
+       ips_forward,            /* packets forwarded */
+       ips_cantforward,        /* packets rcvd for unreachable dest */
+       ips_redirectsent,       /* packets forwarded on same net */
+       ips_noproto,            /* unknown or unsupported protocol */
+       ips_delivered,          /* datagrams delivered to upper level*/
+       ips_localout,           /* total ip packets generated here */
+       ips_odropped,           /* lost packets due to nobufs, etc. */
+       ips_reassembled,        /* total packets reassembled ok */
+       ips_fragmented,         /* datagrams successfully fragmented */
+       ips_ofragments,         /* output fragments created */
+       ips_cantfrag,           /* don't fragment flag was set, etc. */
+       ips_badoptions,         /* error in option processing */
+       ips_noroute,            /* packets discarded due to no route */
+       ips_badvers,            /* ip version != 4 */
+       ips_rawout,             /* total raw ip packets generated */
+       ips_badfrags,           /* malformed fragments (bad length) */
+       ips_rcvmemdrop,         /* frags dropped for lack of memory */
+       ips_toolong,            /* ip length > max ip packet size */
+       ips_nogif,              /* no match gif found */
+       ips_badaddr,            /* invalid address on header */
+       ips_inswcsum,           /* software checksummed on input */
+       ips_outswcsum,          /* software checksummed on output */
+       ips_notmember,          /* multicasts for unregistered groups */
+
+       ips_ncounters
+};
+
+extern struct cpumem *ipcounters;
+
+static inline void
+ipstat_inc(enum ipstat_counters c)
+{
+       counters_inc(ipcounters, c);
+}
+
 /*
  * Structure attached to inpcb.ip_moptions and
  * passed to ip_output when IP multicast options are in use.
Index: netinet/raw_ip.c
===================================================================
RCS file: /cvs/src/sys/netinet/raw_ip.c,v
retrieving revision 1.86
diff -u -p -r1.86 raw_ip.c
--- netinet/raw_ip.c    7 Mar 2016 18:44:00 -0000       1.86
+++ netinet/raw_ip.c    9 Nov 2016 04:45:23 -0000
@@ -126,6 +126,8 @@ rip_input(struct mbuf *m, ...)
        struct ip *ip = mtod(m, struct ip *);
        struct inpcb *inp, *last = NULL;
        struct mbuf *opts = NULL;
+       struct counters_ref ref;
+       uint64_t *counters;
 
        ripsrc.sin_addr = ip->ip_src;
        TAILQ_FOREACH(inp, &rawcbtable.inpt_queue, inp_queue) {
@@ -195,8 +197,11 @@ rip_input(struct mbuf *m, ...)
                        icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PROTOCOL, 0, 
0);
                else
                        m_freem(m);
-               ipstat.ips_noproto++;
-               ipstat.ips_delivered--;
+
+               counters = counters_enter(&ref, ipcounters);
+               counters[ips_noproto]++;
+               counters[ips_delivered]--;
+               counters_leave(&ref, ipcounters);
        }
 }
 
@@ -267,7 +272,7 @@ rip_output(struct mbuf *m, ...)
                }
                /* XXX prevent ip_output from overwriting header fields */
                flags |= IP_RAWOUTPUT;
-               ipstat.ips_rawout++;
+               ipstat_inc(ips_rawout);
        }
 #ifdef INET6
        /*
Index: sys/percpu.h
===================================================================
RCS file: /cvs/src/sys/sys/percpu.h,v
retrieving revision 1.3
diff -u -p -r1.3 percpu.h
--- sys/percpu.h        24 Oct 2016 23:58:33 -0000      1.3
+++ sys/percpu.h        9 Nov 2016 04:45:23 -0000
@@ -138,6 +138,40 @@ counters_leave(struct counters_ref *ref,
        cpumem_leave(cm, ref->c);
 }
 
+static inline void
+counters_inc(struct cpumem *cm, unsigned int c)
+{
+       struct counters_ref ref;
+       uint64_t *counters;
+
+       counters = counters_enter(&ref, cm);
+       counters[c]++;
+       counters_leave(&ref, cm);
+}
+
+static inline void
+counters_add(struct cpumem *cm, unsigned int c, uint64_t v)
+{
+       struct counters_ref ref;
+       uint64_t *counters;
+
+       counters = counters_enter(&ref, cm);
+       counters[c] += v;
+       counters_leave(&ref, cm);
+}
+
+static inline void
+counters_pkt(struct cpumem *cm, unsigned int c, unsigned int b, uint64_t v)
+{
+       struct counters_ref ref;
+       uint64_t *counters;
+
+       counters = counters_enter(&ref, cm);
+       counters[c]++;
+       counters[b] += v;
+       counters_leave(&ref, cm);
+}
+
 #ifdef MULTIPROCESSOR
 #define COUNTERS_BOOT_MEMORY(_name, _n)                                        
\
        CPUMEM_BOOT_MEMORY(_name, ((_n) + 1) * sizeof(uint64_t))

Reply via email to