Very lightly tested.  I used the existing percpu counters as examples.

I don't like the hardcoding of "32" in ip6_input() but I am not sure how
to solve it nicely; the easiest way would be to just kill those
ipv6-specific mbuf stats.  Would anyone miss them?

        Mbuf statistics:
                299 one mbufs
                two or more mbuf:
                        vether0 = 2
                12 one ext mbufs
                0 two or more ext mbufs

Thoughts?

Other netinet6/* counters will follow.


Index: net/if_bridge.c
===================================================================
RCS file: /d/cvs/src/sys/net/if_bridge.c,v
retrieving revision 1.293
diff -u -p -r1.293 if_bridge.c
--- net/if_bridge.c     24 Jan 2017 10:08:30 -0000      1.293
+++ net/if_bridge.c     30 Jan 2017 21:02:30 -0000
@@ -1692,7 +1692,7 @@ bridge_ip(struct bridge_softc *sc, int d
                if (m->m_len < sizeof(struct ip6_hdr)) {
                        if ((m = m_pullup(m, sizeof(struct ip6_hdr)))
                            == NULL) {
-                               ip6stat.ip6s_toosmall++;
+                               ip6stat_inc(ip6s_toosmall);
                                return (NULL);
                        }
                }
@@ -1700,7 +1700,7 @@ bridge_ip(struct bridge_softc *sc, int d
                ip6 = mtod(m, struct ip6_hdr *);
 
                if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
-                       ip6stat.ip6s_badvers++;
+                       ip6stat_inc(ip6s_badvers);
                        goto dropit;
                }
 
Index: net/pf.c
===================================================================
RCS file: /d/cvs/src/sys/net/pf.c,v
retrieving revision 1.1011
diff -u -p -r1.1011 pf.c
--- net/pf.c    25 Jan 2017 06:15:50 -0000      1.1011
+++ net/pf.c    30 Jan 2017 21:02:30 -0000
@@ -5998,7 +5998,7 @@ pf_route6(struct pf_pdesc *pd, struct pf
 
        rt = rtalloc(sin6tosa(dst), RT_RESOLVE, rtableid);
        if (!rtisvalid(rt)) {
-               ip6stat.ip6s_noroute++;
+               ip6stat_inc(ip6s_noroute);
                goto bad;
        }
 
Index: netinet/ipsec_input.c
===================================================================
RCS file: /d/cvs/src/sys/netinet/ipsec_input.c,v
retrieving revision 1.141
diff -u -p -r1.141 ipsec_input.c
--- netinet/ipsec_input.c       29 Jan 2017 19:58:47 -0000      1.141
+++ netinet/ipsec_input.c       30 Jan 2017 21:02:30 -0000
@@ -985,7 +985,7 @@ ah6_input_cb(struct mbuf *m, int off, in
         */
        while (nxt != IPPROTO_DONE) {
                if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
-                       ip6stat.ip6s_toomanyhdr++;
+                       ip6stat_inc(ip6s_toomanyhdr);
                        goto bad;
                }
 
@@ -994,7 +994,7 @@ ah6_input_cb(struct mbuf *m, int off, in
                 * more sanity checks in header chain processing.
                 */
                if (m->m_pkthdr.len < off) {
-                       ip6stat.ip6s_tooshort++;
+                       ip6stat_inc(ip6s_tooshort);
                        goto bad;
                }
                nxt = (*inet6sw[ip6_protox[nxt]].pr_input)(&m, &off, nxt);
Index: netinet6/dest6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/dest6.c,v
retrieving revision 1.15
diff -u -p -r1.15 dest6.c
--- netinet6/dest6.c    14 Mar 2015 03:38:52 -0000      1.15
+++ netinet6/dest6.c    30 Jan 2017 21:02:30 -0000
@@ -73,7 +73,7 @@ dest6_input(struct mbuf **mp, int *offp,
        for (optlen = 0; dstoptlen > 0; dstoptlen -= optlen, opt += optlen) {
                if (*opt != IP6OPT_PAD1 &&
                    (dstoptlen < IP6OPT_MINLEN || *(opt + 1) + 2 > dstoptlen)) {
-                       ip6stat.ip6s_toosmall++;
+                       ip6stat_inc(ip6s_toosmall);
                        goto bad;
                }
 
Index: netinet6/frag6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/frag6.c,v
retrieving revision 1.71
diff -u -p -r1.71 frag6.c
--- netinet6/frag6.c    28 Nov 2016 11:12:45 -0000      1.71
+++ netinet6/frag6.c    30 Jan 2017 21:02:30 -0000
@@ -190,7 +190,7 @@ frag6_input(struct mbuf **mp, int *offp,
                return IPPROTO_DONE;
        }
 
-       ip6stat.ip6s_fragments++;
+       ip6stat_inc(ip6s_fragments);
 
        /* offset now points to data portion */
        offset += sizeof(struct ip6_frag);
@@ -203,7 +203,7 @@ frag6_input(struct mbuf **mp, int *offp,
         */
        fragoff = ntohs(ip6f->ip6f_offlg & IP6F_OFF_MASK);
        if (fragoff == 0 && !(ip6f->ip6f_offlg & IP6F_MORE_FRAG)) {
-               ip6stat.ip6s_reassembled++;
+               ip6stat_inc(ip6s_reassembled);
                *offp = offset;
                return ip6f->ip6f_nxt;
        }
@@ -496,7 +496,7 @@ frag6_input(struct mbuf **mp, int *offp,
                m->m_pkthdr.len = plen;
        }
 
-       ip6stat.ip6s_reassembled++;
+       ip6stat_inc(ip6s_reassembled);
 
        /*
         * Tell launch routine the next header
@@ -514,14 +514,14 @@ frag6_input(struct mbuf **mp, int *offp,
                m_freem(IP6_REASS_MBUF(af6));
                free(af6, M_FTABLE, sizeof(*af6));
        }
-       ip6stat.ip6s_fragdropped += q6->ip6q_nfrag;
+       counters_add(ip6counters, ip6s_fragdropped, q6->ip6q_nfrag);
        TAILQ_REMOVE(&frag6_queue, q6, ip6q_queue);
        frag6_nfrags -= q6->ip6q_nfrag;
        free(q6, M_FTABLE, sizeof(*q6));
        frag6_nfragpackets--;
 
  dropfrag:
-       ip6stat.ip6s_fragdropped++;
+       ip6stat_inc(ip6s_fragdropped);
        m_freem(m);
        IP6Q_UNLOCK();
        return IPPROTO_DONE;
@@ -608,7 +608,7 @@ frag6_slowtimo(void)
        IP6Q_LOCK();
        TAILQ_FOREACH_SAFE(q6, &frag6_queue, ip6q_queue, nq6)
                if (--q6->ip6q_ttl == 0) {
-                       ip6stat.ip6s_fragtimeout++;
+                       ip6stat_inc(ip6s_fragtimeout);
                        frag6_freef(q6);
                }
 
@@ -619,7 +619,7 @@ frag6_slowtimo(void)
         */
        while (frag6_nfragpackets > (u_int)ip6_maxfragpackets &&
            !TAILQ_EMPTY(&frag6_queue)) {
-               ip6stat.ip6s_fragoverflow++;
+               ip6stat_inc(ip6s_fragoverflow);
                frag6_freef(TAILQ_LAST(&frag6_queue, ip6q_head));
        }
        IP6Q_UNLOCK();
@@ -636,7 +636,7 @@ frag6_drain(void)
        if (ip6q_lock_try() == 0)
                return;
        while ((q6 = TAILQ_FIRST(&frag6_queue)) != NULL) {
-               ip6stat.ip6s_fragdropped++;
+               ip6stat_inc(ip6s_fragdropped);
                frag6_freef(q6);
        }
        IP6Q_UNLOCK();
Index: netinet6/icmp6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/icmp6.c,v
retrieving revision 1.197
diff -u -p -r1.197 icmp6.c
--- netinet6/icmp6.c    19 Jan 2017 14:49:19 -0000      1.197
+++ netinet6/icmp6.c    30 Jan 2017 21:02:30 -0000
@@ -1124,8 +1124,13 @@ icmp6_rip6_input(struct mbuf **mp, int o
                } else
                        sorwakeup(last->inp_socket);
        } else {
+               struct counters_ref ref;
+               uint64_t *counters;
+
                m_freem(m);
-               ip6stat.ip6s_delivered--;
+               counters = counters_enter(&ref, ip6counters);
+               counters[ip6s_delivered]--;
+               counters_leave(&ref, ip6counters);
        }
        return IPPROTO_DONE;
 }
Index: netinet6/in6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/in6.c,v
retrieving revision 1.196
diff -u -p -r1.196 in6.c
--- netinet6/in6.c      21 Dec 2016 12:11:12 -0000      1.196
+++ netinet6/in6.c      30 Jan 2017 21:02:30 -0000
@@ -1839,20 +1839,20 @@ in6_ifawithscope(struct ifnet *oifp, str
 
        /* count statistics for future improvements */
        if (ia6_best == NULL)
-               ip6stat.ip6s_sources_none++;
+               ip6stat_inc(ip6s_sources_none);
        else {
                if (oifp == ia6_best->ia_ifp)
-                       ip6stat.ip6s_sources_sameif[best_scope]++;
+                       ip6stat_inc(ip6s_sources_sameif + best_scope);
                else
-                       ip6stat.ip6s_sources_otherif[best_scope]++;
+                       ip6stat_inc(ip6s_sources_otherif + best_scope);
 
                if (best_scope == dst_scope)
-                       ip6stat.ip6s_sources_samescope[best_scope]++;
+                       ip6stat_inc(ip6s_sources_samescope + best_scope);
                else
-                       ip6stat.ip6s_sources_otherscope[best_scope]++;
+                       ip6stat_inc(ip6s_sources_otherscope + best_scope);
 
                if ((ia6_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
-                       ip6stat.ip6s_sources_deprecated[best_scope]++;
+                       ip6stat_inc(ip6s_sources_deprecated + best_scope);
        }
 
        return (ia6_best);
Index: netinet6/ip6_forward.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/ip6_forward.c,v
retrieving revision 1.93
diff -u -p -r1.93 ip6_forward.c
--- netinet6/ip6_forward.c      3 Oct 2016 12:33:21 -0000       1.93
+++ netinet6/ip6_forward.c      30 Jan 2017 21:02:30 -0000
@@ -103,7 +103,7 @@ ip6_forward(struct mbuf *m, struct rtent
        if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 ||
            IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
            IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
-               ip6stat.ip6s_cantforward++;
+               ip6stat_inc(ip6s_cantforward);
                if (ip6_log_time + ip6_log_interval < time_uptime) {
                        ip6_log_time = time_uptime;
                        inet_ntop(AF_INET6, &ip6->ip6_src, src6, sizeof(src6));
@@ -171,7 +171,7 @@ reroute:
                rt = rtalloc_mpath(sin6tosa(dst), &ip6->ip6_src.s6_addr32[0],
                    m->m_pkthdr.ph_rtableid);
                if (rt == NULL) {
-                       ip6stat.ip6s_noroute++;
+                       ip6stat_inc(ip6s_noroute);
                        if (mcopy) {
                                icmp6_error(mcopy, ICMP6_DST_UNREACH,
                                            ICMP6_DST_UNREACH_NOROUTE, 0);
@@ -190,8 +190,8 @@ reroute:
         */
        if (in6_addr2scopeid(m->m_pkthdr.ph_ifidx, &ip6->ip6_src) !=
            in6_addr2scopeid(rt->rt_ifidx, &ip6->ip6_src)) {
-               ip6stat.ip6s_cantforward++;
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_cantforward);
+               ip6stat_inc(ip6s_badscope);
 
                if (ip6_log_time + ip6_log_interval < time_uptime) {
                        ip6_log_time = time_uptime;
@@ -316,11 +316,11 @@ reroute:
 
        error = ifp->if_output(ifp, m, sin6tosa(dst), rt);
        if (error) {
-               ip6stat.ip6s_cantforward++;
+               ip6stat_inc(ip6s_cantforward);
        } else {
-               ip6stat.ip6s_forward++;
+               ip6stat_inc(ip6s_forward);
                if (type)
-                       ip6stat.ip6s_redirectsent++;
+                       ip6stat_inc(ip6s_redirectsent);
                else {
                        if (mcopy)
                                goto freecopy;
Index: netinet6/ip6_input.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/ip6_input.c,v
retrieving revision 1.175
diff -u -p -r1.175 ip6_input.c
--- netinet6/ip6_input.c        29 Jan 2017 19:58:47 -0000      1.175
+++ netinet6/ip6_input.c        30 Jan 2017 21:02:30 -0000
@@ -117,7 +117,9 @@
 struct in6_ifaddrhead in6_ifaddr;
 struct niqueue ip6intrq = NIQUEUE_INITIALIZER(IFQ_MAXLEN, NETISR_IPV6);
 
-struct ip6stat ip6stat;
+struct cpumem *ip6counters;
+
+int ip6_sysctl_ip6stat(void *, size_t *, void *);
 
 int ip6_check_rh0hdr(struct mbuf *, int *);
 
@@ -158,6 +160,8 @@ ip6_init(void)
        frag6_init();
 
        mq_init(&ip6send_mq, 64, IPL_SOFTNET);
+
+       ip6counters = counters_alloc(ip6s_ncounters, M_COUNTERS);
 }
 
 /*
@@ -193,27 +197,28 @@ ip6_input(struct mbuf *m)
 
        if (m->m_flags & M_EXT) {
                if (m->m_next)
-                       ip6stat.ip6s_mext2m++;
+                       ip6stat_inc(ip6s_mext2m);
                else
-                       ip6stat.ip6s_mext1++;
+                       ip6stat_inc(ip6s_mext1);
        } else {
                if (m->m_next) {
                        int ifidx = m->m_pkthdr.ph_ifidx;
                        if (m->m_flags & M_LOOP)
                                ifidx = rtable_loindex(m->m_pkthdr.ph_rtableid);
-                       if (ifidx < nitems(ip6stat.ip6s_m2m))
-                               ip6stat.ip6s_m2m[ifidx]++;
+                       /* XXX hardcoded */
+                       if (ifidx < 32)
+                               ip6stat_inc(ip6s_m2m + ifidx);
                        else
-                               ip6stat.ip6s_m2m[0]++;
+                               ip6stat_inc(ip6s_m2m);
                } else
-                       ip6stat.ip6s_m1++;
+                       ip6stat_inc(ip6s_m1);
        }
 
-       ip6stat.ip6s_total++;
+       ip6stat_inc(ip6s_total);
 
        if (m->m_len < sizeof(struct ip6_hdr)) {
                if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) {
-                       ip6stat.ip6s_toosmall++;
+                       ip6stat_inc(ip6s_toosmall);
                        if_put(ifp);
                        return;
                }
@@ -222,7 +227,7 @@ ip6_input(struct mbuf *m)
        ip6 = mtod(m, struct ip6_hdr *);
 
        if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) {
-               ip6stat.ip6s_badvers++;
+               ip6stat_inc(ip6s_badvers);
                goto bad;
        }
 
@@ -232,7 +237,7 @@ ip6_input(struct mbuf *m)
            ip6->ip6_dst.s6_addr32))
                goto bad;
 #endif
-       ip6stat.ip6s_nxthist[ip6->ip6_nxt]++;
+       ip6stat_inc(ip6s_nxthist + ip6->ip6_nxt);
 
        /*
         * Check against address spoofing/corruption.
@@ -242,20 +247,20 @@ ip6_input(struct mbuf *m)
                /*
                 * XXX: "badscope" is not very suitable for a multicast source.
                 */
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_badscope);
                goto bad;
        }
        if ((IN6_IS_ADDR_LOOPBACK(&ip6->ip6_src) ||
            IN6_IS_ADDR_LOOPBACK(&ip6->ip6_dst)) &&
            (ifp->if_flags & IFF_LOOPBACK) == 0) {
-                   ip6stat.ip6s_badscope++;
+                   ip6stat_inc(ip6s_badscope);
                    goto bad;
        }
        /* Drop packets if interface ID portion is already filled. */
        if (((IN6_IS_SCOPE_EMBED(&ip6->ip6_src) && ip6->ip6_src.s6_addr16[1]) ||
            (IN6_IS_SCOPE_EMBED(&ip6->ip6_dst) && ip6->ip6_dst.s6_addr16[1])) &&
            (ifp->if_flags & IFF_LOOPBACK) == 0) {
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_badscope);
                goto bad;
        }
        if (IN6_IS_ADDR_MC_INTFACELOCAL(&ip6->ip6_dst) &&
@@ -266,7 +271,7 @@ ip6_input(struct mbuf *m)
                 * because ip6_mloopback() passes the "actual" interface
                 * as the outgoing/incoming interface.
                 */
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_badscope);
                goto bad;
        }
 
@@ -284,7 +289,7 @@ ip6_input(struct mbuf *m)
         */
        if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
            IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) {
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_badscope);
                goto bad;
        }
 
@@ -295,7 +300,7 @@ ip6_input(struct mbuf *m)
         */
        if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) ||
            IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) {
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_badscope);
                goto bad;
        }
 
@@ -351,7 +356,7 @@ ip6_input(struct mbuf *m)
         */
        if (!(m->m_pkthdr.pf.flags & PF_TAG_PROCESSED) &&
            ip6_check_rh0hdr(m, &off)) {
-               ip6stat.ip6s_badoptions++;
+               ip6stat_inc(ip6s_badoptions);
                icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, off);
                /* m is already freed */
                if_put(ifp);
@@ -408,7 +413,7 @@ ip6_input(struct mbuf *m)
                         * must be discarded, else it may be accepted below.
                         */
                        if (ip6_mforward(ip6, ifp, m)) {
-                               ip6stat.ip6s_cantforward++;
+                               ip6stat_inc(ip6s_cantforward);
                                goto bad;
                        }
 
@@ -418,9 +423,9 @@ ip6_input(struct mbuf *m)
                }
 #endif
                if (!ours) {
-                       ip6stat.ip6s_notmember++;
+                       ip6stat_inc(ip6s_notmember);
                        if (!IN6_IS_ADDR_MC_LINKLOCAL(&ip6->ip6_dst))
-                               ip6stat.ip6s_cantforward++;
+                               ip6stat_inc(ip6s_cantforward);
                        goto bad;
                }
                goto hbhcheck;
@@ -478,7 +483,7 @@ ip6_input(struct mbuf *m)
         * and we're not a router.
         */
        if (!ip6_forwarding) {
-               ip6stat.ip6s_cantforward++;
+               ip6stat_inc(ip6s_cantforward);
                goto bad;
        }
 
@@ -512,12 +517,12 @@ ip6_input(struct mbuf *m)
        /*
         * Tell launch routine the next header
         */
-       ip6stat.ip6s_delivered++;
+       ip6stat_inc(ip6s_delivered);
        nest = 0;
 
        while (nxt != IPPROTO_DONE) {
                if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) {
-                       ip6stat.ip6s_toomanyhdr++;
+                       ip6stat_inc(ip6s_toomanyhdr);
                        goto bad;
                }
 
@@ -526,7 +531,7 @@ ip6_input(struct mbuf *m)
                 * more sanity checks in header chain processing.
                 */
                if (m->m_pkthdr.len < off) {
-                       ip6stat.ip6s_tooshort++;
+                       ip6stat_inc(ip6s_tooshort);
                        goto bad;
                }
 
@@ -588,7 +593,7 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
                         * contained, ip6_hopopts_input() must set a valid
                         * (non-zero) payload length to the variable plen.
                         */
-                       ip6stat.ip6s_badoptions++;
+                       ip6stat_inc(ip6s_badoptions);
                        icmp6_error(m, ICMP6_PARAM_PROB,
                                    ICMP6_PARAMPROB_HEADER,
                                    (caddr_t)&ip6->ip6_plen - (caddr_t)ip6);
@@ -597,7 +602,7 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
                IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
                        sizeof(struct ip6_hbh));
                if (hbh == NULL) {
-                       ip6stat.ip6s_tooshort++;
+                       ip6stat_inc(ip6s_tooshort);
                        return (-1);
                }
                *nxtp = hbh->ip6h_nxt;
@@ -618,7 +623,7 @@ ip6_hbhchcheck(struct mbuf *m, int *offp
         * Drop packet if shorter than we expect.
         */
        if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) {
-               ip6stat.ip6s_tooshort++;
+               ip6stat_inc(ip6s_tooshort);
                m_freem(m);
                return (-1);
        }
@@ -721,14 +726,14 @@ ip6_hopopts_input(u_int32_t *plenp, u_in
        IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m,
                sizeof(struct ip6_hdr), sizeof(struct ip6_hbh));
        if (hbh == NULL) {
-               ip6stat.ip6s_tooshort++;
+               ip6stat_inc(ip6s_tooshort);
                return -1;
        }
        hbhlen = (hbh->ip6h_len + 1) << 3;
        IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr),
                hbhlen);
        if (hbh == NULL) {
-               ip6stat.ip6s_tooshort++;
+               ip6stat_inc(ip6s_tooshort);
                return -1;
        }
        off += hbhlen;
@@ -771,7 +776,7 @@ ip6_process_hopopts(struct mbuf *m, u_in
                        break;
                case IP6OPT_PADN:
                        if (hbhlen < IP6OPT_MINLEN) {
-                               ip6stat.ip6s_toosmall++;
+                               ip6stat_inc(ip6s_toosmall);
                                goto bad;
                        }
                        optlen = *(opt + 1) + 2;
@@ -779,7 +784,7 @@ ip6_process_hopopts(struct mbuf *m, u_in
                case IP6OPT_ROUTER_ALERT:
                        /* XXX may need check for alignment */
                        if (hbhlen < IP6OPT_RTALERT_LEN) {
-                               ip6stat.ip6s_toosmall++;
+                               ip6stat_inc(ip6s_toosmall);
                                goto bad;
                        }
                        if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) {
@@ -796,7 +801,7 @@ ip6_process_hopopts(struct mbuf *m, u_in
                case IP6OPT_JUMBO:
                        /* XXX may need check for alignment */
                        if (hbhlen < IP6OPT_JUMBO_LEN) {
-                               ip6stat.ip6s_toosmall++;
+                               ip6stat_inc(ip6s_toosmall);
                                goto bad;
                        }
                        if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) {
@@ -814,7 +819,7 @@ ip6_process_hopopts(struct mbuf *m, u_in
                         */
                        ip6 = mtod(m, struct ip6_hdr *);
                        if (ip6->ip6_plen) {
-                               ip6stat.ip6s_badoptions++;
+                               ip6stat_inc(ip6s_badoptions);
                                icmp6_error(m, ICMP6_PARAM_PROB,
                                    ICMP6_PARAMPROB_HEADER,
                                    erroff + opt - opthead);
@@ -838,7 +843,7 @@ ip6_process_hopopts(struct mbuf *m, u_in
                         * there's no explicit mention in specification.
                         */
                        if (*plenp != 0) {
-                               ip6stat.ip6s_badoptions++;
+                               ip6stat_inc(ip6s_badoptions);
                                icmp6_error(m, ICMP6_PARAM_PROB,
                                    ICMP6_PARAMPROB_HEADER,
                                    erroff + opt + 2 - opthead);
@@ -850,7 +855,7 @@ ip6_process_hopopts(struct mbuf *m, u_in
                         * jumbo payload length must be larger than 65535.
                         */
                        if (jumboplen <= IPV6_MAXPACKET) {
-                               ip6stat.ip6s_badoptions++;
+                               ip6stat_inc(ip6s_badoptions);
                                icmp6_error(m, ICMP6_PARAM_PROB,
                                    ICMP6_PARAMPROB_HEADER,
                                    erroff + opt + 2 - opthead);
@@ -861,7 +866,7 @@ ip6_process_hopopts(struct mbuf *m, u_in
                        break;
                default:                /* unknown option */
                        if (hbhlen < IP6OPT_MINLEN) {
-                               ip6stat.ip6s_toosmall++;
+                               ip6stat_inc(ip6s_toosmall);
                                goto bad;
                        }
                        optlen = ip6_unknown_opt(opt, m,
@@ -898,11 +903,11 @@ ip6_unknown_opt(u_int8_t *optp, struct m
                m_freem(m);
                return (-1);
        case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */
-               ip6stat.ip6s_badoptions++;
+               ip6stat_inc(ip6s_badoptions);
                icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off);
                return (-1);
        case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */
-               ip6stat.ip6s_badoptions++;
+               ip6stat_inc(ip6s_badoptions);
                ip6 = mtod(m, struct ip6_hdr *);
                if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
                    (m->m_flags & (M_BCAST|M_MCAST)))
@@ -1005,14 +1010,14 @@ ip6_savecontrol(struct inpcb *in6p, stru
                        ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr),
                            ip6->ip6_nxt);
                        if (ext == NULL) {
-                               ip6stat.ip6s_tooshort++;
+                               ip6stat_inc(ip6s_tooshort);
                                return;
                        }
                        hbh = mtod(ext, struct ip6_hbh *);
                        hbhlen = (hbh->ip6h_len + 1) << 3;
                        if (hbhlen != ext->m_len) {
                                m_freem(ext);
-                               ip6stat.ip6s_tooshort++;
+                               ip6stat_inc(ip6s_tooshort);
                                return;
                        }
 
@@ -1065,7 +1070,7 @@ ip6_savecontrol(struct inpcb *in6p, stru
 
                        ext = ip6_pullexthdr(m, off, nxt);
                        if (ext == NULL) {
-                               ip6stat.ip6s_tooshort++;
+                               ip6stat_inc(ip6s_tooshort);
                                return;
                        }
                        ip6e = mtod(ext, struct ip6_ext *);
@@ -1075,7 +1080,7 @@ ip6_savecontrol(struct inpcb *in6p, stru
                                elen = (ip6e->ip6e_len + 1) << 3;
                        if (elen != ext->m_len) {
                                m_freem(ext);
-                               ip6stat.ip6s_tooshort++;
+                               ip6stat_inc(ip6s_tooshort);
                                return;
                        }
 
@@ -1371,8 +1376,7 @@ ip6_sysctl(int *name, u_int namelen, voi
        case IPV6CTL_STATS:
                if (newp != NULL)
                        return (EPERM);
-               return (sysctl_struct(oldp, oldlenp, newp, newlen,
-                   &ip6stat, sizeof(ip6stat)));
+               return (ip6_sysctl_ip6stat(oldp, oldlenp, newp));
 #ifdef MROUTING
        case IPV6CTL_MRTSTATS:
                if (newp != NULL)
@@ -1413,6 +1417,23 @@ ip6_sysctl(int *name, u_int namelen, voi
                return (EOPNOTSUPP);
        }
        /* NOTREACHED */
+}
+
+int
+ip6_sysctl_ip6stat(void *oldp, size_t *oldlenp, void *newp)
+{
+       struct ip6stat *ip6stat;
+       int ret;
+
+       CTASSERT(sizeof(*ip6stat) == (ip6s_ncounters * sizeof(uint64_t)));
+
+       ip6stat = malloc(sizeof(*ip6stat), M_TEMP, M_WAITOK);
+       counters_read(ip6counters, (uint64_t *)ip6stat, ip6s_ncounters);
+       ret = sysctl_rdstruct(oldp, oldlenp, newp,
+           ip6stat, sizeof(*ip6stat));
+       free(ip6stat, M_TEMP, sizeof(*ip6stat));
+
+       return (ret);
 }
 
 void
Index: netinet6/ip6_mroute.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/ip6_mroute.c,v
retrieving revision 1.107
diff -u -p -r1.107 ip6_mroute.c
--- netinet6/ip6_mroute.c       6 Jan 2017 10:02:57 -0000       1.107
+++ netinet6/ip6_mroute.c       30 Jan 2017 21:02:30 -0000
@@ -875,7 +875,7 @@ ip6_mforward(struct ip6_hdr *ip6, struct
         * (although such packets must normally set 1 to the hop limit field).
         */
        if (IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) {
-               ip6stat.ip6s_cantforward++;
+               ip6stat_inc(ip6s_cantforward);
                if (ip6_log_time + ip6_log_interval < time_uptime) {
                        char src[INET6_ADDRSTRLEN], dst[INET6_ADDRSTRLEN];
 
@@ -1160,7 +1160,7 @@ ip6_mdq(struct mbuf *m, struct ifnet *if
                             in6_addr2scopeid(ifp->if_index, &ip6->ip6_src) !=
                             in6_addr2scopeid(mif6table[mifi].m6_ifp->if_index,
                                              &ip6->ip6_src))) {
-                               ip6stat.ip6s_badscope++;
+                               ip6stat_inc(ip6s_badscope);
                                continue;
                        }
 
Index: netinet6/ip6_output.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/ip6_output.c,v
retrieving revision 1.222
diff -u -p -r1.222 ip6_output.c
--- netinet6/ip6_output.c       27 Jan 2017 02:55:36 -0000      1.222
+++ netinet6/ip6_output.c       30 Jan 2017 21:02:30 -0000
@@ -361,16 +361,16 @@ ip6_output(struct mbuf *m0, struct ip6_p
                 * we explicitly check the address here for safety.
                 */
                error = EOPNOTSUPP;
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_badscope);
                goto bad;
        }
        if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_src)) {
                error = EOPNOTSUPP;
-               ip6stat.ip6s_badscope++;
+               ip6stat_inc(ip6s_badscope);
                goto bad;
        }
 
-       ip6stat.ip6s_localout++;
+       ip6stat_inc(ip6s_localout);
 
        /*
         * Route packet.
@@ -455,7 +455,7 @@ reroute:
        if (ifp == NULL) {
                rt = in6_selectroute(&dstsock, opt, ro, ro->ro_tableid);
                if (rt == NULL) {
-                       ip6stat.ip6s_noroute++;
+                       ip6stat_inc(ip6s_noroute);
                        error = EHOSTUNREACH;
                        goto bad;
                }
@@ -484,7 +484,7 @@ reroute:
                 * Confirm that the outgoing interface supports multicast.
                 */
                if ((ifp->if_flags & IFF_MULTICAST) == 0) {
-                       ip6stat.ip6s_noroute++;
+                       ip6stat_inc(ip6s_noroute);
                        error = ENETUNREACH;
                        goto bad;
                }
@@ -738,7 +738,7 @@ reroute:
                m0 = m;
                error = ip6_fragment(m0, hlen, nextproto, mtu);
                if (error)
-                       ip6stat.ip6s_odropped++;
+                       ip6stat_inc(ip6s_odropped);
        }
 
        /*
@@ -751,7 +751,7 @@ reroute:
                m0 = m->m_nextpkt;
                m->m_nextpkt = 0;
                if (error == 0) {
-                       ip6stat.ip6s_ofragments++;
+                       ip6stat_inc(ip6s_ofragments);
                        error = ifp->if_output(ifp, m, sin6tosa(dst),
                            ro->ro_rt);
                } else
@@ -759,7 +759,7 @@ reroute:
        }
 
        if (error == 0)
-               ip6stat.ip6s_fragmented++;
+               ip6stat_inc(ip6s_fragmented);
 
 done:
        if_put(ifp);
Index: netinet6/ip6_var.h
===================================================================
RCS file: /d/cvs/src/sys/netinet6/ip6_var.h,v
retrieving revision 1.65
diff -u -p -r1.65 ip6_var.h
--- netinet6/ip6_var.h  2 Dec 2016 11:16:04 -0000       1.65
+++ netinet6/ip6_var.h  30 Jan 2017 21:02:30 -0000
@@ -203,6 +203,59 @@ struct     ip6stat {
 };
 
 #ifdef _KERNEL
+
+#include <sys/percpu.h>
+
+enum ip6stat_counters {
+       ip6s_total,
+       ip6s_tooshort,
+       ip6s_toosmall,
+       ip6s_fragments,
+       ip6s_fragdropped,
+       ip6s_fragtimeout,
+       ip6s_fragoverflow,
+       ip6s_forward,
+       ip6s_cantforward,
+       ip6s_redirectsent,
+       ip6s_delivered,
+       ip6s_localout,
+       ip6s_odropped,
+       ip6s_reassembled,
+       ip6s_fragmented,
+       ip6s_ofragments,
+       ip6s_cantfrag,
+       ip6s_badoptions,
+       ip6s_noroute,
+       ip6s_badvers,
+       ip6s_rawout,
+       ip6s_badscope,
+       ip6s_notmember,
+       ip6s_nxthist,
+       ip6s_m1 = ip6s_nxthist + 256,
+       ip6s_m2m,
+       ip6s_mext1 = ip6s_m2m + 32,
+       ip6s_mext2m,
+       ip6s_nogif,
+       ip6s_toomanyhdr,
+       ip6s_sources_none,
+       ip6s_sources_sameif,
+       ip6s_sources_otherif = ip6s_sources_sameif + 16,
+       ip6s_sources_samescope = ip6s_sources_otherif + 16,
+       ip6s_sources_otherscope = ip6s_sources_samescope + 16,
+       ip6s_sources_deprecated = ip6s_sources_otherscope + 16,
+       ip6s_forward_cachehit = ip6s_sources_deprecated + 16,
+       ip6s_forward_cachemiss,
+       ip6s_ncounters,
+};
+
+extern struct cpumem *ip6counters;
+
+static inline void
+ip6stat_inc(enum ip6stat_counters c)
+{
+       counters_inc(ip6counters, c);
+}
+
 /* flags passed to ip6_output as last parameter */
 #define        IPV6_UNSPECSRC          0x01    /* allow :: as the source 
address */
 #define        IPV6_FORWARDING         0x02    /* most of IPv6 header exists */
@@ -211,7 +264,6 @@ struct      ip6stat {
 extern int ip6_mtudisc_timeout;                /* mtu discovery */
 extern struct rttimer_queue *icmp6_mtudisc_timeout_q;
 
-extern struct  ip6stat ip6stat;        /* statistics */
 extern int     ip6_defhlim;            /* default hop limit */
 extern int     ip6_defmcasthlim;       /* default multicast hop limit */
 extern int     ip6_forwarding;         /* act as router? */
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.103
diff -u -p -r1.103 raw_ip6.c
--- netinet6/raw_ip6.c  23 Jan 2017 16:31:24 -0000      1.103
+++ netinet6/raw_ip6.c  30 Jan 2017 21:02:30 -0000
@@ -211,6 +211,9 @@ rip6_input(struct mbuf **mp, int *offp, 
                } else
                        sorwakeup(last->inp_socket);
        } else {
+               struct counters_ref ref;
+               uint64_t *counters;
+
                rip6stat.rip6s_nosock++;
                if (m->m_flags & M_MCAST)
                        rip6stat.rip6s_nosockmcast++;
@@ -222,7 +225,9 @@ rip6_input(struct mbuf **mp, int *offp, 
                            ICMP6_PARAMPROB_NEXTHEADER,
                            prvnxtp - mtod(m, u_int8_t *));
                }
-               ip6stat.ip6s_delivered--;
+               counters = counters_enter(&ref, ip6counters);
+               counters[ip6s_delivered]--;
+               counters_leave(&ref, ip6counters);
        }
        return IPPROTO_DONE;
 }
Index: netinet6/route6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/route6.c,v
retrieving revision 1.19
diff -u -p -r1.19 route6.c
--- netinet6/route6.c   5 Dec 2014 15:50:04 -0000       1.19
+++ netinet6/route6.c   30 Jan 2017 21:02:30 -0000
@@ -60,7 +60,7 @@ route6_input(struct mbuf **mp, int *offp
        ip6 = mtod(m, struct ip6_hdr *);
        IP6_EXTHDR_GET(rh, struct ip6_rthdr *, m, off, sizeof(*rh));
        if (rh == NULL) {
-               ip6stat.ip6s_tooshort++;
+               ip6stat_inc(ip6s_tooshort);
                return IPPROTO_DONE;
        }
 
@@ -77,7 +77,7 @@ route6_input(struct mbuf **mp, int *offp
                        rhlen = (rh->ip6r_len + 1) << 3;
                        break;  /* Final dst. Just ignore the header. */
                }
-               ip6stat.ip6s_badoptions++;
+               ip6stat_inc(ip6s_badoptions);
                icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER,
                            (caddr_t)&rh->ip6r_type - (caddr_t)ip6);
                return (IPPROTO_DONE);


-- 
jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF  DDCC 0DFA 74AE 1524 E7EE

Reply via email to