In icmp6_errcount() we could save a few function calls but I preferred
to keep the conversion as mechanical as possible.  Works fine here on
amd64 (I can test armv7 soon).

ok?


Index: netinet/icmp6.h
===================================================================
RCS file: /d/cvs/src/sys/netinet/icmp6.h,v
retrieving revision 1.42
diff -u -p -r1.42 icmp6.h
--- netinet/icmp6.h     9 Sep 2015 15:51:40 -0000       1.42
+++ netinet/icmp6.h     6 Feb 2017 07:10:21 -0000
@@ -457,22 +457,6 @@ struct icmp6_filter {
  * Variables related to this implementation
  * of the internet control message protocol version 6.
  */
-struct icmp6errstat {
-       u_int64_t icp6errs_dst_unreach_noroute;
-       u_int64_t icp6errs_dst_unreach_admin;
-       u_int64_t icp6errs_dst_unreach_beyondscope;
-       u_int64_t icp6errs_dst_unreach_addr;
-       u_int64_t icp6errs_dst_unreach_noport;
-       u_int64_t icp6errs_packet_too_big;
-       u_int64_t icp6errs_time_exceed_transit;
-       u_int64_t icp6errs_time_exceed_reassembly;
-       u_int64_t icp6errs_paramprob_header;
-       u_int64_t icp6errs_paramprob_nextheader;
-       u_int64_t icp6errs_paramprob_option;
-       u_int64_t icp6errs_redirect; /* we regard redirect as an error here */
-       u_int64_t icp6errs_unknown;
-};
-
 struct icmp6stat {
 /* statistics related to icmp6 packets generated */
        u_int64_t icp6s_error;          /* # of calls to icmp6_error */
@@ -491,25 +475,19 @@ struct icmp6stat {
        u_int64_t icp6s_reflect;
        u_int64_t icp6s_inhist[256];
        u_int64_t icp6s_nd_toomanyopt;  /* too many ND options */
-       struct icmp6errstat icp6s_outerrhist;
-#define icp6s_odst_unreach_noroute \
-       icp6s_outerrhist.icp6errs_dst_unreach_noroute
-#define icp6s_odst_unreach_admin icp6s_outerrhist.icp6errs_dst_unreach_admin
-#define icp6s_odst_unreach_beyondscope \
-       icp6s_outerrhist.icp6errs_dst_unreach_beyondscope
-#define icp6s_odst_unreach_addr icp6s_outerrhist.icp6errs_dst_unreach_addr
-#define icp6s_odst_unreach_noport icp6s_outerrhist.icp6errs_dst_unreach_noport
-#define icp6s_opacket_too_big icp6s_outerrhist.icp6errs_packet_too_big
-#define icp6s_otime_exceed_transit \
-       icp6s_outerrhist.icp6errs_time_exceed_transit
-#define icp6s_otime_exceed_reassembly \
-       icp6s_outerrhist.icp6errs_time_exceed_reassembly
-#define icp6s_oparamprob_header icp6s_outerrhist.icp6errs_paramprob_header
-#define icp6s_oparamprob_nextheader \
-       icp6s_outerrhist.icp6errs_paramprob_nextheader
-#define icp6s_oparamprob_option icp6s_outerrhist.icp6errs_paramprob_option
-#define icp6s_oredirect icp6s_outerrhist.icp6errs_redirect
-#define icp6s_ounknown icp6s_outerrhist.icp6errs_unknown
+       u_int64_t icp6s_odst_unreach_noroute;
+       u_int64_t icp6s_odst_unreach_admin;
+       u_int64_t icp6s_odst_unreach_beyondscope;
+       u_int64_t icp6s_odst_unreach_addr;
+       u_int64_t icp6s_odst_unreach_noport;
+       u_int64_t icp6s_opacket_too_big;
+       u_int64_t icp6s_otime_exceed_transit;
+       u_int64_t icp6s_otime_exceed_reassembly;
+       u_int64_t icp6s_oparamprob_header;
+       u_int64_t icp6s_oparamprob_nextheader;
+       u_int64_t icp6s_oparamprob_option;
+       u_int64_t icp6s_oredirect;      /* we regard redirect as an error here 
*/
+       u_int64_t icp6s_ounknown;
        u_int64_t icp6s_pmtuchg;        /* path MTU changes */
        u_int64_t icp6s_nd_badopt;      /* bad ND options */
        u_int64_t icp6s_badns;          /* bad neighbor solicitation */
@@ -590,6 +568,51 @@ struct icmp6stat {
 #define RTF_PROBEMTU   RTF_PROTO1
 
 #ifdef _KERNEL
+
+#include <sys/percpu.h>
+
+enum icmp6stat_counters {
+       icp6s_error,
+       icp6s_canterror,
+       icp6s_toofreq,
+       icp6s_outhist,
+       icp6s_badcode = icp6s_outhist + 256,
+       icp6s_tooshort,
+       icp6s_checksum,
+       icp6s_badlen,
+       icp6s_reflect,
+       icp6s_inhist,
+       icp6s_nd_toomanyopt = icp6s_inhist + 256,
+       icp6s_odst_unreach_noroute,
+       icp6s_odst_unreach_admin,
+       icp6s_odst_unreach_beyondscope,
+       icp6s_odst_unreach_addr,
+       icp6s_odst_unreach_noport,
+       icp6s_opacket_too_big,
+       icp6s_otime_exceed_transit,
+       icp6s_otime_exceed_reassembly,
+       icp6s_oparamprob_header,
+       icp6s_oparamprob_nextheader,
+       icp6s_oparamprob_option,
+       icp6s_oredirect,
+       icp6s_ounknown,
+       icp6s_pmtuchg,
+       icp6s_nd_badopt,
+       icp6s_badns,
+       icp6s_badna,
+       icp6s_badrs,
+       icp6s_badra,
+       icp6s_badredirect,
+       icp6s_ncounters,
+};
+
+extern struct cpumem *icmp6counters;
+
+static inline void
+icmp6stat_inc(enum icmp6stat_counters c)
+{
+       counters_inc(icmp6counters, c);
+}
 
 struct rtentry;
 struct rttimer;
Index: netinet6/icmp6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/icmp6.c,v
retrieving revision 1.199
diff -u -p -r1.199 icmp6.c
--- netinet6/icmp6.c    5 Feb 2017 16:04:14 -0000       1.199
+++ netinet6/icmp6.c    6 Feb 2017 08:25:47 -0000
@@ -102,7 +102,7 @@
 #include <net/pfvar.h>
 #endif
 
-struct icmp6stat icmp6stat;
+struct cpumem *icmp6counters;
 
 extern struct inpcbtable rawin6pcbtable;
 extern int icmp6errppslim;
@@ -134,7 +134,7 @@ static struct rttimer_queue *icmp6_redir
 /* XXX experimental, turned off */
 static int icmp6_redirect_lowat = -1;
 
-void   icmp6_errcount(struct icmp6errstat *, int, int);
+void   icmp6_errcount(int, int);
 int    icmp6_rip6_input(struct mbuf **, int);
 int    icmp6_ratelimit(const struct in6_addr *, const int, const int);
 const char *icmp6_redirect_diag(struct in6_addr *, struct in6_addr *,
@@ -150,62 +150,63 @@ icmp6_init(void)
        mld6_init();
        icmp6_mtudisc_timeout_q = rt_timer_queue_create(ip6_mtudisc_timeout);
        icmp6_redirect_timeout_q = rt_timer_queue_create(icmp6_redirtimeout);
+       icmp6counters = counters_alloc(icp6s_ncounters);
 }
 
 void
-icmp6_errcount(struct icmp6errstat *stat, int type, int code)
+icmp6_errcount(int type, int code)
 {
        switch (type) {
        case ICMP6_DST_UNREACH:
                switch (code) {
                case ICMP6_DST_UNREACH_NOROUTE:
-                       stat->icp6errs_dst_unreach_noroute++;
+                       icmp6stat_inc(icp6s_odst_unreach_noroute);
                        return;
                case ICMP6_DST_UNREACH_ADMIN:
-                       stat->icp6errs_dst_unreach_admin++;
+                       icmp6stat_inc(icp6s_odst_unreach_admin);
                        return;
                case ICMP6_DST_UNREACH_BEYONDSCOPE:
-                       stat->icp6errs_dst_unreach_beyondscope++;
+                       icmp6stat_inc(icp6s_odst_unreach_beyondscope);
                        return;
                case ICMP6_DST_UNREACH_ADDR:
-                       stat->icp6errs_dst_unreach_addr++;
+                       icmp6stat_inc(icp6s_odst_unreach_addr);
                        return;
                case ICMP6_DST_UNREACH_NOPORT:
-                       stat->icp6errs_dst_unreach_noport++;
+                       icmp6stat_inc(icp6s_odst_unreach_noport);
                        return;
                }
                break;
        case ICMP6_PACKET_TOO_BIG:
-               stat->icp6errs_packet_too_big++;
+               icmp6stat_inc(icp6s_opacket_too_big);
                return;
        case ICMP6_TIME_EXCEEDED:
                switch (code) {
                case ICMP6_TIME_EXCEED_TRANSIT:
-                       stat->icp6errs_time_exceed_transit++;
+                       icmp6stat_inc(icp6s_otime_exceed_transit);
                        return;
                case ICMP6_TIME_EXCEED_REASSEMBLY:
-                       stat->icp6errs_time_exceed_reassembly++;
+                       icmp6stat_inc(icp6s_otime_exceed_reassembly);
                        return;
                }
                break;
        case ICMP6_PARAM_PROB:
                switch (code) {
                case ICMP6_PARAMPROB_HEADER:
-                       stat->icp6errs_paramprob_header++;
+                       icmp6stat_inc(icp6s_oparamprob_header);
                        return;
                case ICMP6_PARAMPROB_NEXTHEADER:
-                       stat->icp6errs_paramprob_nextheader++;
+                       icmp6stat_inc(icp6s_oparamprob_nextheader);
                        return;
                case ICMP6_PARAMPROB_OPTION:
-                       stat->icp6errs_paramprob_option++;
+                       icmp6stat_inc(icp6s_oparamprob_option);
                        return;
                }
                break;
        case ND_REDIRECT:
-               stat->icp6errs_redirect++;
+               icmp6stat_inc(icp6s_oredirect);
                return;
        }
-       stat->icp6errs_unknown++;
+       icmp6stat_inc(icp6s_ounknown);
 }
 
 /*
@@ -241,10 +242,10 @@ icmp6_error(struct mbuf *m, int type, in
        int off;
        int nxt;
 
-       icmp6stat.icp6s_error++;
+       icmp6stat_inc(icp6s_error);
 
        /* count per-type-code statistics */
-       icmp6_errcount(&icmp6stat.icp6s_outerrhist, type, code);
+       icmp6_errcount(type, code);
 
        if (m->m_len < sizeof(struct ip6_hdr)) {
                m = m_pullup(m, sizeof(struct ip6_hdr));
@@ -291,7 +292,7 @@ icmp6_error(struct mbuf *m, int type, in
                IP6_EXTHDR_GET(icp, struct icmp6_hdr *, m, off,
                        sizeof(*icp));
                if (icp == NULL) {
-                       icmp6stat.icp6s_tooshort++;
+                       icmp6stat_inc(icp6s_tooshort);
                        return;
                }
                if (icp->icmp6_type < ICMP6_ECHO_REQUEST ||
@@ -301,7 +302,7 @@ icmp6_error(struct mbuf *m, int type, in
                         * Special case: for redirect (which is
                         * informational) we must not send icmp6 error.
                         */
-                       icmp6stat.icp6s_canterror++;
+                       icmp6stat_inc(icp6s_canterror);
                        goto freeit;
                } else {
                        /* ICMPv6 informational - send the error */
@@ -315,7 +316,7 @@ icmp6_error(struct mbuf *m, int type, in
 
        /* Finally, do rate limitation check. */
        if (icmp6_ratelimit(&oip6->ip6_src, type, code)) {
-               icmp6stat.icp6s_toofreq++;
+               icmp6stat_inc(icp6s_toofreq);
                goto freeit;
        }
 
@@ -358,7 +359,7 @@ icmp6_error(struct mbuf *m, int type, in
         */
        m->m_pkthdr.ph_ifidx = 0;
 
-       icmp6stat.icp6s_outhist[type]++;
+       icmp6stat_inc(icp6s_outhist + type);
        icmp6_reflect(m, sizeof(struct ip6_hdr)); /* header order: IPv6 - 
ICMPv6 */
 
        return;
@@ -394,7 +395,7 @@ icmp6_input(struct mbuf **mp, int *offp,
 
        ip6 = mtod(m, struct ip6_hdr *);
        if (icmp6len < sizeof(struct icmp6_hdr)) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                goto freeit;
        }
 
@@ -403,7 +404,7 @@ icmp6_input(struct mbuf **mp, int *offp,
         */
        IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off, sizeof(*icmp6));
        if (icmp6 == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                return IPPROTO_DONE;
        }
        code = icmp6->icmp6_code;
@@ -413,7 +414,7 @@ icmp6_input(struct mbuf **mp, int *offp,
                    "ICMP6 checksum error(%d|%x) %s\n",
                    icmp6->icmp6_type, sum,
                    inet_ntop(AF_INET6, &ip6->ip6_src, src, sizeof(src))));
-               icmp6stat.icp6s_checksum++;
+               icmp6stat_inc(icp6s_checksum);
                goto freeit;
        }
 
@@ -450,7 +451,7 @@ icmp6_input(struct mbuf **mp, int *offp,
 
        if_put(ifp);
 #endif
-       icmp6stat.icp6s_inhist[icmp6->icmp6_type]++;
+       icmp6stat_inc(icp6s_inhist + icmp6->icmp6_type);
 
        switch (icmp6->icmp6_type) {
        case ICMP6_DST_UNREACH:
@@ -595,8 +596,8 @@ icmp6_input(struct mbuf **mp, int *offp,
                nicmp6->icmp6_type = ICMP6_ECHO_REPLY;
                nicmp6->icmp6_code = 0;
                if (n) {
-                       icmp6stat.icp6s_reflect++;
-                       icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]++;
+                       icmp6stat_inc(icp6s_reflect);
+                       icmp6stat_inc(icp6s_outhist + ICMP6_ECHO_REPLY);
                        icmp6_reflect(n, noff);
                }
                if (!m)
@@ -745,11 +746,11 @@ deliver:
                break;
 
 badcode:
-               icmp6stat.icp6s_badcode++;
+               icmp6stat_inc(icp6s_badcode);
                break;
 
 badlen:
-               icmp6stat.icp6s_badlen++;
+               icmp6stat_inc(icp6s_badlen);
                break;
        }
 
@@ -775,13 +776,13 @@ icmp6_notify_error(struct mbuf *m, int o
        struct sockaddr_in6 icmp6src, icmp6dst;
 
        if (icmp6len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr)) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                goto freeit;
        }
        IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
                       sizeof(*icmp6) + sizeof(struct ip6_hdr));
        if (icmp6 == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                return (-1);
        }
        eip6 = (struct ip6_hdr *)(icmp6 + 1);
@@ -810,7 +811,7 @@ icmp6_notify_error(struct mbuf *m, int o
                                IP6_EXTHDR_GET(eh, struct ip6_ext *, m,
                                               eoff, sizeof(*eh));
                                if (eh == NULL) {
-                                       icmp6stat.icp6s_tooshort++;
+                                       icmp6stat_inc(icp6s_tooshort);
                                        return (-1);
                                }
 
@@ -832,7 +833,7 @@ icmp6_notify_error(struct mbuf *m, int o
                                IP6_EXTHDR_GET(rth, struct ip6_rthdr *, m,
                                               eoff, sizeof(*rth));
                                if (rth == NULL) {
-                                       icmp6stat.icp6s_tooshort++;
+                                       icmp6stat_inc(icp6s_tooshort);
                                        return (-1);
                                }
                                rthlen = (rth->ip6r_len + 1) << 3;
@@ -852,7 +853,7 @@ icmp6_notify_error(struct mbuf *m, int o
                                                       struct ip6_rthdr0 *, m,
                                                       eoff, rthlen);
                                        if (rth0 == NULL) {
-                                               icmp6stat.icp6s_tooshort++;
+                                               icmp6stat_inc(icp6s_tooshort);
                                                return (-1);
                                        }
                                        /* just ignore a bogus header */
@@ -867,7 +868,7 @@ icmp6_notify_error(struct mbuf *m, int o
                                IP6_EXTHDR_GET(fh, struct ip6_frag *, m,
                                               eoff, sizeof(*fh));
                                if (fh == NULL) {
-                                       icmp6stat.icp6s_tooshort++;
+                                       icmp6stat_inc(icp6s_tooshort);
                                        return (-1);
                                }
                                /*
@@ -898,7 +899,7 @@ icmp6_notify_error(struct mbuf *m, int o
                IP6_EXTHDR_GET(icmp6, struct icmp6_hdr *, m, off,
                               sizeof(*icmp6) + sizeof(struct ip6_hdr));
                if (icmp6 == NULL) {
-                       icmp6stat.icp6s_tooshort++;
+                       icmp6stat_inc(icp6s_tooshort);
                        return (-1);
                }
 
@@ -1022,7 +1023,7 @@ icmp6_mtudisc_update(struct ip6ctlparam 
 
                ifp = if_get(rt->rt_ifidx);
                if (ifp != NULL && mtu < ifp->if_mtu) {
-                       icmp6stat.icp6s_pmtuchg++;
+                       icmp6stat_inc(icp6s_pmtuchg);
                        rt->rt_rmx.rmx_mtu = mtu;
                }
                if_put(ifp);
@@ -1357,7 +1358,7 @@ icmp6_redirect_input(struct mbuf *m, int
 
        IP6_EXTHDR_GET(nd_rd, struct nd_redirect *, m, off, icmp6len);
        if (nd_rd == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                if_put(ifp);
                return;
        }
@@ -1538,7 +1539,7 @@ icmp6_redirect_input(struct mbuf *m, int
 
  bad:
        if_put(ifp);
-       icmp6stat.icp6s_badredirect++;
+       icmp6stat_inc(icp6s_badredirect);
        m_freem(m);
 }
 
@@ -1556,7 +1557,7 @@ icmp6_redirect_output(struct mbuf *m0, s
        u_char *p;
        struct sockaddr_in6 src_sa;
 
-       icmp6_errcount(&icmp6stat.icp6s_outerrhist, ND_REDIRECT, 0);
+       icmp6_errcount(ND_REDIRECT, 0);
 
        /* if we are not router, we don't send icmp6 redirect */
        if (!ip6_forwarding)
@@ -1791,7 +1792,7 @@ noredhdropt:
        /* send the packet to outside... */
        ip6_output(m, NULL, NULL, 0, NULL, NULL);
 
-       icmp6stat.icp6s_outhist[ND_REDIRECT]++;
+       icmp6stat_inc(icp6s_outhist + ND_REDIRECT);
 
        if_put(ifp);
        return;
@@ -1987,6 +1988,22 @@ icmp6_redirect_timeout(struct rtentry *r
 int *icmpv6ctl_vars[ICMPV6CTL_MAXID] = ICMPV6CTL_VARS;
 
 int
+icmp6_sysctl_icmp6stat(void *oldp, size_t *oldlenp, void *newp)
+{
+       struct icmp6stat *icmp6stat;
+       int ret;
+
+       CTASSERT(sizeof(*icmp6stat) == icp6s_ncounters * sizeof(uint64_t));
+       icmp6stat = malloc(sizeof(*icmp6stat), M_TEMP, M_WAITOK);
+       counters_read(icmp6counters, (uint64_t *)icmp6stat, icp6s_ncounters);
+       ret = sysctl_rdstruct(oldp, oldlenp, newp,
+           icmp6stat, sizeof(*icmp6stat));
+       free(icmp6stat, M_TEMP, sizeof(*icmp6stat));
+
+       return (ret);
+}
+
+int
 icmp6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
     void *newp, size_t newlen)
 {
@@ -1997,8 +2014,7 @@ icmp6_sysctl(int *name, u_int namelen, v
        switch (name[0]) {
 
        case ICMPV6CTL_STATS:
-               return sysctl_rdstruct(oldp, oldlenp, newp,
-                               &icmp6stat, sizeof(icmp6stat));
+               return icmp6_sysctl_icmp6stat(oldp, oldlenp, newp);
        case ICMPV6CTL_ND6_DRLIST:
        case ICMPV6CTL_ND6_PRLIST:
                return nd6_sysctl(name[0], oldp, oldlenp, newp, newlen);
Index: netinet6/in6_var.h
===================================================================
RCS file: /d/cvs/src/sys/netinet6/in6_var.h,v
retrieving revision 1.64
diff -u -p -r1.64 in6_var.h
--- netinet6/in6_var.h  5 Jul 2016 10:17:14 -0000       1.64
+++ netinet6/in6_var.h  6 Feb 2017 07:10:21 -0000
@@ -334,7 +334,6 @@ struct      in6_aliasreq {
 
 TAILQ_HEAD(in6_ifaddrhead, in6_ifaddr);
 extern struct in6_ifaddrhead in6_ifaddr;
-extern struct icmp6stat icmp6stat;
 
 /*
  * Multi-cast membership entry.  One for each group/ifp that a PCB
Index: netinet6/mld6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/mld6.c,v
retrieving revision 1.49
diff -u -p -r1.49 mld6.c
--- netinet6/mld6.c     21 Dec 2016 12:12:13 -0000      1.49
+++ netinet6/mld6.c     6 Feb 2017 07:10:21 -0000
@@ -165,7 +165,7 @@ mld6_input(struct mbuf *m, int off)
 
        IP6_EXTHDR_GET(mldh, struct mld_hdr *, m, off, sizeof(*mldh));
        if (mldh == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                return;
        }
 
@@ -454,7 +454,7 @@ mld6_sendpkt(struct in6_multi *in6m, int
        im6o.im6o_loop = (ip6_mrouter != NULL);
 #endif
 
-       icmp6stat.icp6s_outhist[type]++;
+       icmp6stat_inc(icp6s_outhist + type);
        ip6_output(mh, &ip6_opts, NULL, ia6 ? 0 : IPV6_UNSPECSRC, &im6o,
            NULL);
 }
Index: netinet6/nd6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.202
diff -u -p -r1.202 nd6.c
--- netinet6/nd6.c      27 Dec 2016 18:45:01 -0000      1.202
+++ netinet6/nd6.c      6 Feb 2017 07:10:21 -0000
@@ -249,7 +249,7 @@ nd6_options(union nd_opts *ndopts)
                         * Message validation requires that all included
                         * options have a length that is greater than zero.
                         */
-                       icmp6stat.icp6s_nd_badopt++;
+                       icmp6stat_inc(icp6s_nd_badopt);
                        bzero(ndopts, sizeof(*ndopts));
                        return -1;
                }
@@ -293,7 +293,7 @@ nd6_options(union nd_opts *ndopts)
 skip1:
                i++;
                if (i > nd6_maxndopt) {
-                       icmp6stat.icp6s_nd_toomanyopt++;
+                       icmp6stat_inc(icp6s_nd_toomanyopt);
                        nd6log((LOG_INFO, "too many loop in nd opt\n"));
                        break;
                }
Index: netinet6/nd6_nbr.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/nd6_nbr.c,v
retrieving revision 1.114
diff -u -p -r1.114 nd6_nbr.c
--- netinet6/nd6_nbr.c  3 Jan 2017 13:32:51 -0000       1.114
+++ netinet6/nd6_nbr.c  6 Feb 2017 07:10:21 -0000
@@ -118,7 +118,7 @@ nd6_ns_input(struct mbuf *m, int off, in
 
        IP6_EXTHDR_GET(nd_ns, struct nd_neighbor_solicit *, m, off, icmp6len);
        if (nd_ns == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                if_put(ifp);
                return;
        }
@@ -339,7 +339,7 @@ nd6_ns_input(struct mbuf *m, int off, in
            inet_ntop(AF_INET6, &daddr6, addr, sizeof(addr))));
        nd6log((LOG_ERR, "nd6_ns_input: tgt=%s\n",
            inet_ntop(AF_INET6, &taddr6, addr, sizeof(addr))));
-       icmp6stat.icp6s_badns++;
+       icmp6stat_inc(icp6s_badns);
        m_freem(m);
        if_put(ifp);
 }
@@ -532,7 +532,7 @@ nd6_ns_output(struct ifnet *ifp, struct 
        m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
 
        ip6_output(m, NULL, NULL, dad ? IPV6_UNSPECSRC : 0, &im6o, NULL);
-       icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]++;
+       icmp6stat_inc(icp6s_outhist + ND_NEIGHBOR_SOLICIT);
        return;
 
   bad:
@@ -589,7 +589,7 @@ nd6_na_input(struct mbuf *m, int off, in
 
        IP6_EXTHDR_GET(nd_na, struct nd_neighbor_advert *, m, off, icmp6len);
        if (nd_na == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                if_put(ifp);
                return;
        }
@@ -875,7 +875,7 @@ nd6_na_input(struct mbuf *m, int off, in
        return;
 
  bad:
-       icmp6stat.icp6s_badna++;
+       icmp6stat_inc(icp6s_badna);
        m_freem(m);
        if_put(ifp);
 }
@@ -1037,7 +1037,7 @@ nd6_na_output(struct ifnet *ifp, struct 
        m->m_pkthdr.csum_flags |= M_ICMP_CSUM_OUT;
 
        ip6_output(m, NULL, NULL, 0, &im6o, NULL);
-       icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]++;
+       icmp6stat_inc(icp6s_outhist+ ND_NEIGHBOR_ADVERT);
        return;
 
   bad:
Index: netinet6/nd6_rtr.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.154
diff -u -p -r1.154 nd6_rtr.c
--- netinet6/nd6_rtr.c  22 Dec 2016 13:39:32 -0000      1.154
+++ netinet6/nd6_rtr.c  6 Feb 2017 07:10:21 -0000
@@ -150,7 +150,7 @@ nd6_rs_input(struct mbuf *m, int off, in
 
        IP6_EXTHDR_GET(nd_rs, struct nd_router_solicit *, m, off, icmp6len);
        if (nd_rs == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                return;
        }
 
@@ -190,7 +190,7 @@ nd6_rs_input(struct mbuf *m, int off, in
        return;
 
  bad:
-       icmp6stat.icp6s_badrs++;
+       icmp6stat_inc(icp6s_badrs);
        m_freem(m);
 }
 
@@ -276,7 +276,7 @@ nd6_rs_output(struct ifnet* ifp, struct 
 
        ip6_output(m, NULL, NULL, 0, &im6o, NULL);
 
-       icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]++;
+       icmp6stat_inc(icp6s_outhist + ND_ROUTER_SOLICIT);
 }
 
 void
@@ -412,7 +412,7 @@ nd6_ra_input(struct mbuf *m, int off, in
 
        IP6_EXTHDR_GET(nd_ra, struct nd_router_advert *, m, off, icmp6len);
        if (nd_ra == NULL) {
-               icmp6stat.icp6s_tooshort++;
+               icmp6stat_inc(icp6s_tooshort);
                if_put(ifp);
                return;
        }
@@ -570,7 +570,7 @@ nd6_ra_input(struct mbuf *m, int off, in
        return;
 
  bad:
-       icmp6stat.icp6s_badra++;
+       icmp6stat_inc(icp6s_badra);
        if_put(ifp);
        m_freem(m);
 }
Index: netinet6/raw_ip6.c
===================================================================
RCS file: /d/cvs/src/sys/netinet6/raw_ip6.c,v
retrieving revision 1.105
diff -u -p -r1.105 raw_ip6.c
--- netinet6/raw_ip6.c  5 Feb 2017 16:04:14 -0000       1.105
+++ netinet6/raw_ip6.c  6 Feb 2017 07:14:10 -0000
@@ -103,7 +103,7 @@
 
 struct inpcbtable rawin6pcbtable;
 
-struct rip6stat rip6stat;
+struct cpumem *rip6counters;
 
 /*
  * Initialize raw connection block queue.
@@ -111,8 +111,8 @@ struct rip6stat rip6stat;
 void
 rip6_init(void)
 {
-
        in_pcbinit(&rawin6pcbtable, 1);
+       rip6counters = counters_alloc(rip6s_ncounters);
 }
 
 int
@@ -125,7 +125,7 @@ rip6_input(struct mbuf **mp, int *offp, 
        struct sockaddr_in6 rip6src;
        struct mbuf *opts = NULL;
 
-       rip6stat.rip6s_ipackets++;
+       rip6stat_inc(rip6s_ipackets);
 
        /* Be proactive about malicious use of IPv4 mapped address */
        if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) ||
@@ -171,10 +171,10 @@ rip6_input(struct mbuf **mp, int *offp, 
                    !IN6_ARE_ADDR_EQUAL(&in6p->inp_faddr6, &ip6->ip6_src))
                        continue;
                if (in6p->inp_cksum6 != -1) {
-                       rip6stat.rip6s_isum++;
+                       rip6stat_inc(rip6s_isum);
                        if (in6_cksum(m, proto, *offp,
                            m->m_pkthdr.len - *offp)) {
-                               rip6stat.rip6s_badsum++;
+                               rip6stat_inc(rip6s_badsum);
                                continue;
                        }
                }
@@ -190,7 +190,7 @@ rip6_input(struct mbuf **mp, int *offp, 
                                        /* should notify about lost packet */
                                        m_freem(n);
                                        m_freem(opts);
-                                       rip6stat.rip6s_fullsock++;
+                                       rip6stat_inc(rip6s_fullsock);
                                } else
                                        sorwakeup(last->inp_socket);
                                opts = NULL;
@@ -207,16 +207,16 @@ rip6_input(struct mbuf **mp, int *offp, 
                    sin6tosa(&rip6src), m, opts) == 0) {
                        m_freem(m);
                        m_freem(opts);
-                       rip6stat.rip6s_fullsock++;
+                       rip6stat_inc(rip6s_fullsock);
                } else
                        sorwakeup(last->inp_socket);
        } else {
                struct counters_ref ref;
                uint64_t *counters;
 
-               rip6stat.rip6s_nosock++;
+               rip6stat_inc(rip6s_nosock);
                if (m->m_flags & M_MCAST)
-                       rip6stat.rip6s_nosockmcast++;
+                       rip6stat_inc(rip6s_nosockmcast);
                if (proto == IPPROTO_NONE)
                        m_freem(m);
                else {
@@ -457,9 +457,9 @@ rip6_output(struct mbuf *m, ...)
        error = ip6_output(m, optp, &in6p->inp_route6, flags,
            in6p->inp_moptions6, in6p);
        if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
-               icmp6stat.icp6s_outhist[type]++;
+               icmp6stat_inc(icp6s_outhist + type);
        } else
-               rip6stat.rip6s_opackets++;
+               rip6stat_inc(rip6s_opackets);
 
        goto freectl;
 
@@ -769,6 +769,18 @@ rip6_usrreq(struct socket *so, int req, 
 }
 
 int
+rip6_sysctl_rip6stat(void *oldp, size_t *oldplen, void *newp)
+{
+       struct rip6stat rip6stat;
+
+       CTASSERT(sizeof(rip6stat) == rip6s_ncounters * sizeof(uint64_t));
+       counters_read(ip6counters, (uint64_t *)&rip6stat, rip6s_ncounters);
+
+       return (sysctl_rdstruct(oldp, oldplen, newp,
+           &rip6stat, sizeof(rip6stat)));
+}
+
+int
 rip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
     void *newp, size_t newlen)
 {
@@ -778,10 +790,7 @@ rip6_sysctl(int *name, u_int namelen, vo
 
        switch (name[0]) {
        case RIPV6CTL_STATS:
-               if (newp != NULL)
-                       return (EPERM);
-               return (sysctl_struct(oldp, oldlenp, newp, newlen,
-                   &rip6stat, sizeof(rip6stat)));
+               return (rip6_sysctl_rip6stat(oldp, oldlenp, newp));
        default:
                return (EOPNOTSUPP);
        }
Index: netinet6/raw_ip6.h
===================================================================
RCS file: /d/cvs/src/sys/netinet6/raw_ip6.h,v
retrieving revision 1.3
diff -u -p -r1.3 raw_ip6.h
--- netinet6/raw_ip6.h  14 Dec 2007 18:33:42 -0000      1.3
+++ netinet6/raw_ip6.h  6 Feb 2017 07:10:21 -0000
@@ -59,7 +59,28 @@ struct rip6stat {
 }
 
 #ifdef _KERNEL
-extern struct rip6stat rip6stat;
+
+#include <sys/percpu.h>
+
+enum rip6stat_counters {
+       rip6s_ipackets,
+       rip6s_isum,
+       rip6s_badsum,
+       rip6s_nosock,
+       rip6s_nosockmcast,
+       rip6s_fullsock,
+       rip6s_opackets,
+       rip6s_ncounters,
+};
+
+extern struct cpumem *rip6counters;
+
+static inline void
+rip6stat_inc(enum rip6stat_counters c)
+{
+       counters_inc(rip6counters, c);
+}
+
 #endif
 
 #endif


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

Reply via email to