Maybe I'm comparing apples and oranges, but I got curious and compared
the size of various kernels on amd64:

* -current GENERIC:
  text    data    bss     dec     hex
  9197408 269192  684032  10150632        9ae2e8

* percpu tcpstat, not inlined, GENERIC:
  text    data    bss     dec     hex
  9199200 269192  684032  10152424        9ae9e8
  overhead: 1792 bytes

* percpu tcpstat, GENERIC:
  text    data    bss     dec     hex
  9199536 269192  684032  10152760        9aeb38
  overhead: 2128 bytes


* -current GENERIC.MP:
  text    data    bss     dec     hex
  9248800 270792  688128  10207720        9bc1e8

* percpu tcpstat, not inlined, GENERIC.MP:
  text    data    bss     dec     hex
  9250768 270792  688128  10209688        9bc998
  overhead: 1968 bytes

* percpu tcpstat, GENERIC.MP:
  text    data    bss     dec     hex
  9254320 270792  688128  10213240        9bd778
  overhead: 5520 bytes

So the counters api is not free.  I don't think that size is a problem
for regular kernels, but we'd better test constrained install media.
I haven't done so for ip6stat yet, I can handle amd64.


Anyway, tcpstat diff below, a bit ugly because that struct is a mix of
uint32_t and uint64_t.  Comments / reviews welcome.


Index: net/pf.c
===================================================================
RCS file: /d/cvs/src/sys/net/pf.c,v
retrieving revision 1.1013
diff -u -p -r1.1013 pf.c
--- net/pf.c    30 Jan 2017 17:52:24 -0000      1.1013
+++ net/pf.c    31 Jan 2017 00:10:40 -0000
@@ -6026,7 +6026,7 @@ pf_check_tcp_cksum(struct mbuf *m, int o
        }
 
        /* need to do it in software */
-       tcpstat.tcps_inswcsum++;
+       tcpstat_inc(tcps_inswcsum);
 
        switch (af) {
        case AF_INET:
@@ -6047,7 +6047,7 @@ pf_check_tcp_cksum(struct mbuf *m, int o
                unhandled_af(af);
        }
        if (sum) {
-               tcpstat.tcps_rcvbadsum++;
+               tcpstat_inc(tcps_rcvbadsum);
                m->m_pkthdr.csum_flags |= M_TCP_CSUM_IN_BAD;
                return (1);
        }
Index: netinet/ip_output.c
===================================================================
RCS file: /d/cvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.334
diff -u -p -r1.334 ip_output.c
--- netinet/ip_output.c 10 Jan 2017 09:01:18 -0000      1.334
+++ netinet/ip_output.c 31 Jan 2017 01:31:13 -0000
@@ -1798,7 +1798,7 @@ in_proto_cksum_out(struct mbuf *m, struc
        if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) {
                if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv4) ||
                    ip->ip_hl != 5 || ifp->if_bridgeport != NULL) {
-                       tcpstat.tcps_outswcsum++;
+                       tcpstat_inc(tcps_outswcsum);
                        in_delayed_cksum(m);
                        m->m_pkthdr.csum_flags &= ~M_TCP_CSUM_OUT; /* Clear */
                }
Index: netinet/tcp_input.c
===================================================================
RCS file: /d/cvs/src/sys/netinet/tcp_input.c,v
retrieving revision 1.337
diff -u -p -r1.337 tcp_input.c
--- netinet/tcp_input.c 29 Jan 2017 19:58:47 -0000      1.337
+++ netinet/tcp_input.c 31 Jan 2017 13:33:00 -0000
@@ -234,7 +234,7 @@ tcp_reass(struct tcpcb *tp, struct tcphd
                if (tiqe == NULL || th->th_seq != tp->rcv_nxt) {
                        /* Flush segment queue for this connection */
                        tcp_freeq(tp);
-                       tcpstat.tcps_rcvmemdrop++;
+                       tcpstat_inc(tcps_rcvmemdrop);
                        m_freem(m);
                        return (0);
                }
@@ -261,8 +261,8 @@ tcp_reass(struct tcpcb *tp, struct tcphd
                i = phdr->th_seq + phdr->th_reseqlen - th->th_seq;
                if (i > 0) {
                        if (i >= *tlen) {
-                               tcpstat.tcps_rcvduppack++;
-                               tcpstat.tcps_rcvdupbyte += *tlen;
+                               tcpstat_pkt(tcps_rcvduppack, tcps_rcvdupbyte,
+                                   *tlen);
                                m_freem(m);
                                pool_put(&tcpqe_pool, tiqe);
                                return (0);
@@ -272,8 +272,7 @@ tcp_reass(struct tcpcb *tp, struct tcphd
                        th->th_seq += i;
                }
        }
-       tcpstat.tcps_rcvoopack++;
-       tcpstat.tcps_rcvoobyte += *tlen;
+       tcpstat_pkt(tcps_rcvoopack, tcps_rcvoobyte, *tlen);
 
        /*
         * While we overlap succeeding segments trim them or,
@@ -389,7 +388,7 @@ tcp_input(struct mbuf **mp, int *offp, i
        u_char iptos;
 #endif
 
-       tcpstat.tcps_rcvtotal++;
+       tcpstat_inc(tcps_rcvtotal);
 
        opti.ts_present = 0;
        opti.maxseg = 0;
@@ -448,7 +447,7 @@ tcp_input(struct mbuf **mp, int *offp, i
 
        IP6_EXTHDR_GET(th, struct tcphdr *, m, iphlen, sizeof(*th));
        if (!th) {
-               tcpstat.tcps_rcvshort++;
+               tcpstat_inc(tcps_rcvshort);
                return IPPROTO_DONE;
        }
 
@@ -508,10 +507,10 @@ tcp_input(struct mbuf **mp, int *offp, i
                int sum;
 
                if (m->m_pkthdr.csum_flags & M_TCP_CSUM_IN_BAD) {
-                       tcpstat.tcps_rcvbadsum++;
+                       tcpstat_inc(tcps_rcvbadsum);
                        goto drop;
                }
-               tcpstat.tcps_inswcsum++;
+               tcpstat_inc(tcps_inswcsum);
                switch (af) {
                case AF_INET:
                        sum = in4_cksum(m, IPPROTO_TCP, iphlen, tlen);
@@ -524,7 +523,7 @@ tcp_input(struct mbuf **mp, int *offp, i
 #endif
                }
                if (sum != 0) {
-                       tcpstat.tcps_rcvbadsum++;
+                       tcpstat_inc(tcps_rcvbadsum);
                        goto drop;
                }
        }
@@ -535,14 +534,14 @@ tcp_input(struct mbuf **mp, int *offp, i
         */
        off = th->th_off << 2;
        if (off < sizeof(struct tcphdr) || off > tlen) {
-               tcpstat.tcps_rcvbadoff++;
+               tcpstat_inc(tcps_rcvbadoff);
                goto drop;
        }
        tlen -= off;
        if (off > sizeof(struct tcphdr)) {
                IP6_EXTHDR_GET(th, struct tcphdr *, m, iphlen, off);
                if (!th) {
-                       tcpstat.tcps_rcvshort++;
+                       tcpstat_inc(tcps_rcvshort);
                        return IPPROTO_DONE;
                }
                optlen = off - sizeof(struct tcphdr);
@@ -602,7 +601,7 @@ findpcb:
                int     inpl_reverse = 0;
                if (m->m_pkthdr.pf.flags & PF_TAG_TRANSLATE_LOCALHOST)
                        inpl_reverse = 1;
-               ++tcpstat.tcps_pcbhashmiss;
+               tcpstat_inc(tcps_pcbhashmiss);
                switch (af) {
 #ifdef INET6
                case AF_INET6:
@@ -624,7 +623,7 @@ findpcb:
                 * but should either do a listen or a connect soon.
                 */
                if (inp == NULL) {
-                       ++tcpstat.tcps_noport;
+                       tcpstat_inc(tcps_noport);
                        goto dropwithreset_ratelim;
                }
        }
@@ -841,14 +840,14 @@ findpcb:
                                        case AF_INET6:
                                                if 
(IN6_ARE_ADDR_EQUAL(&ip6->ip6_src,
                                                    &ip6->ip6_dst)) {
-                                                       tcpstat.tcps_badsyn++;
+                                                       
tcpstat_inc(tcps_badsyn);
                                                        goto drop;
                                                }
                                                break;
 #endif /* INET6 */
                                        case AF_INET:
                                                if (ip->ip_dst.s_addr == 
ip->ip_src.s_addr) {
-                                                       tcpstat.tcps_badsyn++;
+                                                       
tcpstat_inc(tcps_badsyn);
                                                        goto drop;
                                                }
                                                break;
@@ -862,7 +861,7 @@ findpcb:
                                if (so->so_qlen > so->so_qlimit ||
                                    syn_cache_add(&src.sa, &dst.sa, th, iphlen,
                                    so, m, optp, optlen, &opti, reuse) == -1) {
-                                       tcpstat.tcps_dropsyn++;
+                                       tcpstat_inc(tcps_dropsyn);
                                        goto drop;
                                }
                                return IPPROTO_DONE;
@@ -895,7 +894,7 @@ findpcb:
        ipsp_spd_lookup(m, af, iphlen, &error, IPSP_DIRECTION_IN,
            tdb, inp, 0);
        if (error) {
-               tcpstat.tcps_rcvnosec++;
+               tcpstat_inc(tcps_rcvnosec);
                goto drop;
        }
 #endif /* IPSEC */
@@ -941,7 +940,7 @@ findpcb:
        /* if congestion experienced, set ECE bit in subsequent packets. */
        if ((iptos & IPTOS_ECN_MASK) == IPTOS_ECN_CE) {
                tp->t_flags |= TF_RCVD_CE;
-               tcpstat.tcps_ecn_rcvce++;
+               tcpstat_inc(tcps_ecn_rcvce);
        }
 #endif
        /*
@@ -987,7 +986,7 @@ findpcb:
                                /*
                                 * this is a pure ack for outstanding data.
                                 */
-                               ++tcpstat.tcps_predack;
+                               tcpstat_inc(tcps_predack);
                                if (opti.ts_present && opti.ts_ecr)
                                        tcp_xmit_timer(tp, tcp_now - 
opti.ts_ecr);
                                else if (tp->t_rtttime &&
@@ -995,8 +994,8 @@ findpcb:
                                        tcp_xmit_timer(tp,
                                            tcp_now - tp->t_rtttime);
                                acked = th->th_ack - tp->snd_una;
-                               tcpstat.tcps_rcvackpack++;
-                               tcpstat.tcps_rcvackbyte += acked;
+                               tcpstat_pkt(tcps_rcvackpack, tcps_rcvackbyte,
+                                   acked);
                                ND6_HINT(tp);
                                sbdrop(&so->so_snd, acked);
 
@@ -1073,10 +1072,9 @@ findpcb:
                        if (tp->sack_enable && tp->rcv_numsacks)
                                tcp_clean_sackreport(tp);
 #endif /* TCP_SACK */
-                       ++tcpstat.tcps_preddat;
+                       tcpstat_inc(tcps_preddat);
                        tp->rcv_nxt += tlen;
-                       tcpstat.tcps_rcvpack++;
-                       tcpstat.tcps_rcvbyte += tlen;
+                       tcpstat_pkt(tcps_rcvpack, tcps_rcvbyte, tlen);
                        ND6_HINT(tp);
 
                        TCP_SETUP_ACK(tp, tiflags, m);
@@ -1143,7 +1141,7 @@ findpcb:
        case TCPS_SYN_RECEIVED:
                if (tiflags & TH_ACK) {
                        if (tiflags & TH_SYN) {
-                               tcpstat.tcps_badsyn++;
+                               tcpstat_inc(tcps_badsyn);
                                goto dropwithreset;
                        }
                        if (SEQ_LEQ(th->th_ack, tp->snd_una) ||
@@ -1215,13 +1213,13 @@ findpcb:
                        case TH_ECE|TH_CWR:
                                tp->t_flags |= TF_ECN_PERMIT;
                                tiflags &= ~(TH_ECE|TH_CWR);
-                               tcpstat.tcps_ecn_accepts++;
+                               tcpstat_inc(tcps_ecn_accepts);
                        }
                }
 #endif
 
                if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
-                       tcpstat.tcps_connects++;
+                       tcpstat_inc(tcps_connects);
                        soisconnected(so);
                        tp->t_state = TCPS_ESTABLISHED;
                        TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepidle);
@@ -1265,8 +1263,8 @@ trimthenstep6:
                        m_adj(m, -todrop);
                        tlen = tp->rcv_wnd;
                        tiflags &= ~TH_FIN;
-                       tcpstat.tcps_rcvpackafterwin++;
-                       tcpstat.tcps_rcvbyteafterwin += todrop;
+                       tcpstat_pkt(tcps_rcvpackafterwin, tcps_rcvbyteafterwin,
+                           todrop);
                }
                tp->snd_wl1 = th->th_seq - 1;
                tp->rcv_up = th->th_seq;
@@ -1332,9 +1330,8 @@ trimthenstep6:
                         */
                        tp->ts_recent = 0;
                } else {
-                       tcpstat.tcps_rcvduppack++;
-                       tcpstat.tcps_rcvdupbyte += tlen;
-                       tcpstat.tcps_pawsdrop++;
+                       tcpstat_pkt(tcps_rcvduppack, tcps_rcvdupbyte, tlen);
+                       tcpstat_inc(tcps_pawsdrop);
                        goto dropafterack;
                }
        }
@@ -1363,11 +1360,11 @@ trimthenstep6:
                         * but keep on processing for RST or ACK.
                         */
                        tp->t_flags |= TF_ACKNOW;
-                       tcpstat.tcps_rcvdupbyte += todrop = tlen;
-                       tcpstat.tcps_rcvduppack++;
+                       todrop = tlen;
+                       tcpstat_pkt(tcps_rcvduppack, tcps_rcvdupbyte, todrop);
                } else {
-                       tcpstat.tcps_rcvpartduppack++;
-                       tcpstat.tcps_rcvpartdupbyte += todrop;
+                       tcpstat_pkt(tcps_rcvpartduppack, tcps_rcvpartdupbyte,
+                           todrop);
                }
                hdroptlen += todrop;    /* drop from head afterwards */
                th->th_seq += todrop;
@@ -1387,7 +1384,7 @@ trimthenstep6:
        if ((so->so_state & SS_NOFDREF) &&
            tp->t_state > TCPS_CLOSE_WAIT && tlen) {
                tp = tcp_close(tp);
-               tcpstat.tcps_rcvafterclose++;
+               tcpstat_inc(tcps_rcvafterclose);
                goto dropwithreset;
        }
 
@@ -1397,9 +1394,9 @@ trimthenstep6:
         */
        todrop = (th->th_seq + tlen) - (tp->rcv_nxt+tp->rcv_wnd);
        if (todrop > 0) {
-               tcpstat.tcps_rcvpackafterwin++;
+               tcpstat_inc(tcps_rcvpackafterwin);
                if (todrop >= tlen) {
-                       tcpstat.tcps_rcvbyteafterwin += tlen;
+                       tcpstat_add(tcps_rcvbyteafterwin, tlen);
                        /*
                         * If window is closed can only take segments at
                         * window edge, and have to drop data and PUSH from
@@ -1409,11 +1406,11 @@ trimthenstep6:
                         */
                        if (tp->rcv_wnd == 0 && th->th_seq == tp->rcv_nxt) {
                                tp->t_flags |= TF_ACKNOW;
-                               tcpstat.tcps_rcvwinprobe++;
+                               tcpstat_inc(tcps_rcvwinprobe);
                        } else
                                goto dropafterack;
                } else
-                       tcpstat.tcps_rcvbyteafterwin += todrop;
+                       tcpstat_add(tcps_rcvbyteafterwin, todrop);
                m_adj(m, -todrop);
                tlen -= todrop;
                tiflags &= ~(TH_PUSH|TH_FIN);
@@ -1467,7 +1464,7 @@ trimthenstep6:
                        so->so_error = ECONNRESET;
                close:
                        tp->t_state = TCPS_CLOSED;
-                       tcpstat.tcps_drops++;
+                       tcpstat_inc(tcps_drops);
                        tp = tcp_close(tp);
                        goto drop;
                case TCPS_CLOSING:
@@ -1506,7 +1503,7 @@ trimthenstep6:
         * The ACK was checked above.
         */
        case TCPS_SYN_RECEIVED:
-               tcpstat.tcps_connects++;
+               tcpstat_inc(tcps_connects);
                soisconnected(so);
                tp->t_state = TCPS_ESTABLISHED;
                TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepidle);
@@ -1554,10 +1551,10 @@ trimthenstep6:
                                        tp->snd_cwnd = tp->snd_ssthresh;
                                        tp->snd_last = tp->snd_max;
                                        tp->t_flags |= TF_SEND_CWR;
-                                       tcpstat.tcps_cwr_ecn++;
+                                       tcpstat_inc(tcps_cwr_ecn);
                                }
                        }
-                       tcpstat.tcps_ecn_rcvece++;
+                       tcpstat_inc(tcps_ecn_rcvece);
                }
                /*
                 * if we receive CWR, we know that the peer has reduced
@@ -1565,7 +1562,7 @@ trimthenstep6:
                 */
                if ((tiflags & TH_CWR)) {
                        tp->t_flags &= ~TF_RCVD_CE;
-                       tcpstat.tcps_ecn_rcvcwr++;
+                       tcpstat_inc(tcps_ecn_rcvcwr);
                }
 #endif /* TCP_ECN */
 
@@ -1587,7 +1584,7 @@ trimthenstep6:
                                if (th->th_seq != tp->rcv_nxt &&
                                   SEQ_LT(th->th_ack,
                                   tp->snd_una - tp->max_sndwnd)) {
-                                       tcpstat.tcps_rcvacktooold++;
+                                       tcpstat_inc(tcps_rcvacktooold);
                                        goto drop;
                                }
                                break;
@@ -1603,7 +1600,7 @@ trimthenstep6:
                                break;
                        }
                        if (tiwin == tp->snd_wnd) {
-                               tcpstat.tcps_rcvdupack++;
+                               tcpstat_inc(tcps_rcvdupack);
                                /*
                                 * If we have outstanding data (other than
                                 * a window probe), this is a completely
@@ -1668,8 +1665,8 @@ trimthenstep6:
 #ifdef TCP_ECN
                                                tp->t_flags |= TF_SEND_CWR;
 #endif
-                                               tcpstat.tcps_cwr_frecovery++;
-                                               
tcpstat.tcps_sack_recovery_episode++;
+                                               tcpstat_inc(tcps_cwr_frecovery);
+                                               
tcpstat_inc(tcps_sack_recovery_episode);
 #if defined(TCP_SACK) && defined(TCP_FACK)
                                                tp->t_dupacks = tcprexmtthresh;
                                                (void) tcp_output(tp);
@@ -1697,8 +1694,8 @@ trimthenstep6:
 #ifdef TCP_ECN
                                        tp->t_flags |= TF_SEND_CWR;
 #endif
-                                       tcpstat.tcps_cwr_frecovery++;
-                                       tcpstat.tcps_sndrexmitfast++;
+                                       tcpstat_inc(tcps_cwr_frecovery);
+                                       tcpstat_inc(tcps_sndrexmitfast);
                                        (void) tcp_output(tp);
 
                                        tp->snd_cwnd = tp->snd_ssthresh +
@@ -1787,12 +1784,11 @@ trimthenstep6:
                tp->t_dupacks = 0;
 #endif
                if (SEQ_GT(th->th_ack, tp->snd_max)) {
-                       tcpstat.tcps_rcvacktoomuch++;
+                       tcpstat_inc(tcps_rcvacktoomuch);
                        goto dropafterack_ratelim;
                }
                acked = th->th_ack - tp->snd_una;
-               tcpstat.tcps_rcvackpack++;
-               tcpstat.tcps_rcvackbyte += acked;
+               tcpstat_pkt(tcps_rcvackpack, tcps_rcvackbyte, acked);
 
                /*
                 * If we have a timestamp reply, update smoothed
@@ -1965,7 +1961,7 @@ step6:
                /* keep track of pure window updates */
                if (tlen == 0 &&
                    tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
-                       tcpstat.tcps_rcvwinupd++;
+                       tcpstat_inc(tcps_rcvwinupd);
                tp->snd_wnd = tiwin;
                tp->snd_wl1 = th->th_seq;
                tp->snd_wl2 = th->th_ack;
@@ -2051,8 +2047,7 @@ dodata:                                                   
/* XXX */
                        TCP_SETUP_ACK(tp, tiflags, m);
                        tp->rcv_nxt += tlen;
                        tiflags = th->th_flags & TH_FIN;
-                       tcpstat.tcps_rcvpack++;
-                       tcpstat.tcps_rcvbyte += tlen;
+                       tcpstat_pkt(tcps_rcvpack, tcps_rcvbyte, tlen);
                        ND6_HINT(tp);
                        if (so->so_state & SS_CANTRCVMORE)
                                m_freem(m);
@@ -2164,7 +2159,7 @@ badsyn:
        /*
         * Received a bad SYN.  Increment counters and dropwithreset.
         */
-       tcpstat.tcps_badsyn++;
+       tcpstat_inc(tcps_badsyn);
        tp = NULL;
        goto dropwithreset;
 
@@ -2391,7 +2386,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *
        }
 
        if ((sigp ? TF_SIGNATURE : 0) ^ (tp->t_flags & TF_SIGNATURE)) {
-               tcpstat.tcps_rcvbadsig++;
+               tcpstat_inc(tcps_rcvbadsig);
                return (-1);
        }
 
@@ -2399,7 +2394,7 @@ tcp_dooptions(struct tcpcb *tp, u_char *
                char sig[16];
 
                if (tdb == NULL) {
-                       tcpstat.tcps_rcvbadsig++;
+                       tcpstat_inc(tcps_rcvbadsig);
                        return (-1);
                }
 
@@ -2407,11 +2402,11 @@ tcp_dooptions(struct tcpcb *tp, u_char *
                        return (-1);
 
                if (timingsafe_bcmp(sig, sigp, 16)) {
-                       tcpstat.tcps_rcvbadsig++;
+                       tcpstat_inc(tcps_rcvbadsig);
                        return (-1);
                }
 
-               tcpstat.tcps_rcvgoodsig++;
+               tcpstat_inc(tcps_rcvgoodsig);
        }
 #endif /* TCP_SIGNATURE */
 
@@ -2549,7 +2544,7 @@ tcp_sack_option(struct tcpcb *tp, struct
        /* Note: TCPOLEN_SACK must be 2*sizeof(tcp_seq) */
        tmp_cp = cp + 2;
        tmp_olen = optlen - 2;
-       tcpstat.tcps_sack_rcv_opts++;
+       tcpstat_inc(tcps_sack_rcv_opts);
        if (tp->snd_numholes < 0)
                tp->snd_numholes = 0;
        if (tp->t_maxseg == 0)
@@ -2869,7 +2864,7 @@ tcp_xmit_timer(struct tcpcb *tp, int rtt
        else if (rtt > TCP_RTT_MAX)
                rtt = TCP_RTT_MAX;
 
-       tcpstat.tcps_rttupdated++;
+       tcpstat_inc(tcps_rttupdated);
        if (tp->t_srtt != 0) {
                /*
                 * delta is fixed point with 2 (TCP_RTT_BASE_SHIFT) bits
@@ -3409,7 +3404,7 @@ syn_cache_insert(struct syn_cache *sc, s
                        }
                }
                arc4random_buf(set->scs_random, sizeof(set->scs_random));
-               tcpstat.tcps_sc_seedrandom++;
+               tcpstat_inc(tcps_sc_seedrandom);
        }
 
        SYN_HASHALL(sc->sc_hash, &sc->sc_src.sa, &sc->sc_dst.sa,
@@ -3422,7 +3417,7 @@ syn_cache_insert(struct syn_cache *sc, s
         * limit or the total cache size limit.
         */
        if (scp->sch_length >= tcp_syn_bucket_limit) {
-               tcpstat.tcps_sc_bucketoverflow++;
+               tcpstat_inc(tcps_sc_bucketoverflow);
                /*
                 * Someone might attack our bucket hash function.  Reseed
                 * with random as soon as the passive syn cache gets empty.
@@ -3446,7 +3441,7 @@ syn_cache_insert(struct syn_cache *sc, s
        } else if (set->scs_count >= tcp_syn_cache_limit) {
                struct syn_cache_head *scp2, *sce;
 
-               tcpstat.tcps_sc_overflowed++;
+               tcpstat_inc(tcps_sc_overflowed);
                /*
                 * The cache is full.  Toss the oldest entry in the
                 * first non-empty bucket we can find.
@@ -3496,7 +3491,7 @@ syn_cache_insert(struct syn_cache *sc, s
        set->scs_count++;
        set->scs_use--;
 
-       tcpstat.tcps_sc_added++;
+       tcpstat_inc(tcps_sc_added);
 
        /*
         * If the active cache has exceeded its use limit and
@@ -3536,7 +3531,7 @@ syn_cache_timer(void *arg)
        if (sc->sc_rxttot >= tcptv_keep_init)
                goto dropit;
 
-       tcpstat.tcps_sc_retransmitted++;
+       tcpstat_inc(tcps_sc_retransmitted);
        (void) syn_cache_respond(sc, NULL);
 
        /* Advance the timer back-off. */
@@ -3548,7 +3543,7 @@ syn_cache_timer(void *arg)
        return;
 
  dropit:
-       tcpstat.tcps_sc_timed_out++;
+       tcpstat_inc(tcps_sc_timed_out);
        syn_cache_rm(sc);
        syn_cache_put(sc);
        NET_UNLOCK(s);
@@ -3822,7 +3817,7 @@ syn_cache_get(struct sockaddr *src, stru
 #ifdef TCP_ECN
        if (sc->sc_flags & SCF_ECN_PERMIT) {
                tp->t_flags |= TF_ECN_PERMIT;
-               tcpstat.tcps_ecn_accepts++;
+               tcpstat_inc(tcps_ecn_accepts);
        }
 #endif
 #ifdef TCP_SACK
@@ -3837,7 +3832,7 @@ syn_cache_get(struct sockaddr *src, stru
        tp->t_state = TCPS_SYN_RECEIVED;
        tp->t_rcvtime = tcp_now;
        TCP_TIMER_ARM(tp, TCPT_KEEP, tcptv_keep_init);
-       tcpstat.tcps_accepts++;
+       tcpstat_inc(tcps_accepts);
 
        tcp_mss(tp, sc->sc_peermaxseg);  /* sets t_maxseg */
        if (sc->sc_peermaxseg)
@@ -3859,7 +3854,7 @@ syn_cache_get(struct sockaddr *src, stru
                tp->rcv_adv = tp->rcv_nxt + sc->sc_win;
        tp->last_ack_sent = tp->rcv_nxt;
 
-       tcpstat.tcps_sc_completed++;
+       tcpstat_inc(tcps_sc_completed);
        syn_cache_put(sc);
        return (so);
 
@@ -3871,7 +3866,7 @@ abort:
        if (so != NULL)
                (void) soabort(so);
        syn_cache_put(sc);
-       tcpstat.tcps_sc_aborted++;
+       tcpstat_inc(tcps_sc_aborted);
        return ((struct socket *)(-1));
 }
 
@@ -3896,7 +3891,7 @@ syn_cache_reset(struct sockaddr *src, st
            SEQ_GT(th->th_seq, sc->sc_irs + 1))
                return;
        syn_cache_rm(sc);
-       tcpstat.tcps_sc_reset++;
+       tcpstat_inc(tcps_sc_reset);
        syn_cache_put(sc);
 }
 
@@ -3930,7 +3925,7 @@ syn_cache_unreach(struct sockaddr *src, 
        }
 
        syn_cache_rm(sc);
-       tcpstat.tcps_sc_unreach++;
+       tcpstat_inc(tcps_sc_unreach);
        syn_cache_put(sc);
 }
 
@@ -4013,7 +4008,7 @@ syn_cache_add(struct sockaddr *src, stru
         */
        sc = syn_cache_lookup(src, dst, &scp, sotoinpcb(so)->inp_rtableid);
        if (sc != NULL) {
-               tcpstat.tcps_sc_dupesyn++;
+               tcpstat_inc(tcps_sc_dupesyn);
                if (ipopts) {
                        /*
                         * If we were remembering a previous source route,
@@ -4024,8 +4019,8 @@ syn_cache_add(struct sockaddr *src, stru
                }
                sc->sc_timestamp = tb.ts_recent;
                if (syn_cache_respond(sc, m) == 0) {
-                       tcpstat.tcps_sndacks++;
-                       tcpstat.tcps_sndtotal++;
+                       tcpstat_inc(tcps_sndacks);
+                       tcpstat_inc(tcps_sndtotal);
                }
                return (0);
        }
@@ -4111,11 +4106,11 @@ syn_cache_add(struct sockaddr *src, stru
        sc->sc_tp = tp;
        if (syn_cache_respond(sc, m) == 0) {
                syn_cache_insert(sc, tp);
-               tcpstat.tcps_sndacks++;
-               tcpstat.tcps_sndtotal++;
+               tcpstat_inc(tcps_sndacks);
+               tcpstat_inc(tcps_sndtotal);
        } else {
                syn_cache_put(sc);
-               tcpstat.tcps_sc_dropped++;
+               tcpstat_inc(tcps_sc_dropped);
        }
 
        return (0);
Index: netinet/tcp_output.c
===================================================================
RCS file: /d/cvs/src/sys/netinet/tcp_output.c,v
retrieving revision 1.118
diff -u -p -r1.118 tcp_output.c
--- netinet/tcp_output.c        19 Jul 2016 21:28:43 -0000      1.118
+++ netinet/tcp_output.c        31 Jan 2017 01:33:39 -0000
@@ -641,7 +641,7 @@ send:
                int count = 0;  /* actual number of SACKs inserted */
                int maxsack = (MAX_TCPOPTLEN - (optlen + 4))/TCPOLEN_SACK;
 
-               tcpstat.tcps_sack_snd_opts++;
+               tcpstat_inc(tcps_sack_snd_opts);
                maxsack = min(maxsack, TCP_MAX_SACK);
                for (i = 0; (i < tp->rcv_numsacks && count < maxsack); i++) {
                        struct sackblk sack = tp->sackblks[i];
@@ -685,13 +685,13 @@ send:
         */
        if (len) {
                if (tp->t_force && len == 1)
-                       tcpstat.tcps_sndprobe++;
+                       tcpstat_inc(tcps_sndprobe);
                else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {
-                       tcpstat.tcps_sndrexmitpack++;
-                       tcpstat.tcps_sndrexmitbyte += len;
+                       tcpstat_pkt(tcps_sndrexmitpack,
+                           tcps_sndrexmitbyte, len);
                } else {
-                       tcpstat.tcps_sndpack++;
-                       tcpstat.tcps_sndbyte += len;
+                       tcpstat_pkt(tcps_sndpack,
+                           tcps_sndbyte, len);
                }
 #ifdef notyet
                if ((m = m_copypack(so->so_snd.sb_mb, off,
@@ -746,13 +746,13 @@ send:
                        flags |= TH_PUSH;
        } else {
                if (tp->t_flags & TF_ACKNOW)
-                       tcpstat.tcps_sndacks++;
+                       tcpstat_inc(tcps_sndacks);
                else if (flags & (TH_SYN|TH_FIN|TH_RST))
-                       tcpstat.tcps_sndctrl++;
+                       tcpstat_inc(tcps_sndctrl);
                else if (SEQ_GT(tp->snd_up, tp->snd_una))
-                       tcpstat.tcps_sndurg++;
+                       tcpstat_inc(tcps_sndurg);
                else
-                       tcpstat.tcps_sndwinup++;
+                       tcpstat_inc(tcps_sndwinup);
 
                MGETHDR(m, M_DONTWAIT, MT_HEADER);
                if (m != NULL && max_linkhdr + hdrlen > MHLEN) {
@@ -823,8 +823,8 @@ send:
 #if defined(TCP_SACK) && defined(TCP_FACK)
                tp->retran_data += len;
 #endif /* TCP_FACK */
-               tcpstat.tcps_sack_rexmits++;
-               tcpstat.tcps_sack_rexmit_bytes += len;
+               tcpstat_pkt(tcps_sack_rexmits,
+                   tcps_sack_rexmit_bytes, len);
        }
 #endif /* TCP_SACK */
 
@@ -841,7 +841,7 @@ send:
                 */
                if (tp->t_flags & TF_RCVD_CE) {
                        flags |= TH_ECE;
-                       tcpstat.tcps_ecn_sndece++;
+                       tcpstat_inc(tcps_ecn_sndece);
                }
                if (!(tp->t_flags & TF_DISABLE_ECN)) {
                        /*
@@ -862,7 +862,7 @@ send:
                    (tp->t_flags & TF_SEND_CWR)) {
                        flags |= TH_CWR;
                        tp->t_flags &= ~TF_SEND_CWR;
-                       tcpstat.tcps_ecn_sndcwr++;
+                       tcpstat_inc(tcps_ecn_sndcwr);
                }
        }
 #endif
@@ -982,7 +982,7 @@ send:
                        if (tp->t_rtttime == 0) {
                                tp->t_rtttime = tcp_now;
                                tp->t_rtseq = startseq;
-                               tcpstat.tcps_segstimed++;
+                               tcpstat_inc(tcps_segstimed);
                        }
                }
 
@@ -1073,7 +1073,7 @@ send:
                        /* don't set ECT */
                } else {
                        needect = 1;
-                       tcpstat.tcps_ecn_sndect++;
+                       tcpstat_inc(tcps_ecn_sndect);
                }
        }
 #endif
@@ -1172,9 +1172,9 @@ out:
        if (packetlen > tp->t_pmtud_mtu_sent)
                tp->t_pmtud_mtu_sent = packetlen;
 
-       tcpstat.tcps_sndtotal++;
+       tcpstat_inc(tcps_sndtotal);
        if (tp->t_flags & TF_DELACK)
-               tcpstat.tcps_delack++;
+               tcpstat_inc(tcps_delack);
 
        /*
         * Data sent (as far as we can tell).
Index: netinet/tcp_subr.c
===================================================================
RCS file: /d/cvs/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.159
diff -u -p -r1.159 tcp_subr.c
--- netinet/tcp_subr.c  26 Jan 2017 13:03:47 -0000      1.159
+++ netinet/tcp_subr.c  31 Jan 2017 14:04:36 -0000
@@ -131,9 +131,32 @@ struct pool tcpqe_pool;
 struct pool sackhl_pool;
 #endif
 
-struct tcpstat tcpstat;                /* tcp statistics */
+struct cpumem *tcpcounters;            /* tcp statistics */
 tcp_seq  tcp_iss;
 
+#ifdef TCPSTAT_INLINE
+/* nothing */
+#else
+void
+tcpstat_inc(enum tcpstat_counters c)
+{
+       counters_inc(tcpcounters, c);
+}
+
+void
+tcpstat_add(enum tcpstat_counters c, uint64_t v)
+{
+       counters_add(tcpcounters, c, v);
+}
+
+void
+tcpstat_pkt(enum tcpstat_counters pcounter, enum tcpstat_counters bcounter,
+    uint64_t v)
+{
+       counters_pkt(tcpcounters, pcounter, bcounter, v);
+}
+#endif
+
 /*
  * Tcp initialization
  */
@@ -153,6 +176,8 @@ tcp_init(void)
 #endif /* TCP_SACK */
        in_pcbinit(&tcbtable, TCB_INITIAL_HASH_SIZE);
 
+       tcpcounters = counters_alloc(tcps_ncounters, M_COUNTERS);
+
 #ifdef INET6
        /*
         * Since sizeof(struct ip6_hdr) > sizeof(struct ip), we
@@ -494,9 +519,9 @@ tcp_drop(struct tcpcb *tp, int errno)
        if (TCPS_HAVERCVDSYN(tp->t_state)) {
                tp->t_state = TCPS_CLOSED;
                (void) tcp_output(tp);
-               tcpstat.tcps_drops++;
+               tcpstat_inc(tcps_drops);
        } else
-               tcpstat.tcps_conndrops++;
+               tcpstat_inc(tcps_conndrops);
        if (errno == ETIMEDOUT && tp->t_softerror)
                errno = tp->t_softerror;
        so->so_error = errno;
@@ -551,7 +576,7 @@ tcp_reaper(void *arg)
        struct tcpcb *tp = arg;
 
        pool_put(&tcpcb_pool, tp);
-       tcpstat.tcps_closed++;
+       tcpstat_inc(tcps_closed);
 }
 
 int
Index: netinet/tcp_timer.c
===================================================================
RCS file: /d/cvs/src/sys/netinet/tcp_timer.c,v
retrieving revision 1.53
diff -u -p -r1.53 tcp_timer.c
--- netinet/tcp_timer.c 19 Dec 2016 08:36:49 -0000      1.53
+++ netinet/tcp_timer.c 31 Jan 2017 01:31:13 -0000
@@ -226,12 +226,12 @@ tcp_timer_rexmt(void *arg)
 #endif
        if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
                tp->t_rxtshift = TCP_MAXRXTSHIFT;
-               tcpstat.tcps_timeoutdrop++;
+               tcpstat_inc(tcps_timeoutdrop);
                (void)tcp_drop(tp, tp->t_softerror ?
                    tp->t_softerror : ETIMEDOUT);
                goto out;
        }
-       tcpstat.tcps_rexmttimeo++;
+       tcpstat_inc(tcps_rexmttimeo);
        rto = TCP_REXMTVAL(tp);
        if (rto < tp->t_rttmin)
                rto = tp->t_rttmin;
@@ -363,7 +363,7 @@ tcp_timer_rexmt(void *arg)
                tp->t_flags |= TF_SEND_CWR;
 #endif
 #if 1 /* TCP_ECN */
-               tcpstat.tcps_cwr_timeout++;
+               tcpstat_inc(tcps_cwr_timeout);
 #endif
        }
        (void) tcp_output(tp);
@@ -384,7 +384,7 @@ tcp_timer_persist(void *arg)
             TCP_TIMER_ISARMED(tp, TCPT_REXMT)) {
                goto out;
        }
-       tcpstat.tcps_persisttimeo++;
+       tcpstat_inc(tcps_persisttimeo);
        /*
         * Hack: if the peer is dead/unreachable, we do not
         * time out if the window is closed.  After a full
@@ -398,7 +398,7 @@ tcp_timer_persist(void *arg)
        if (tp->t_rxtshift == TCP_MAXRXTSHIFT &&
            ((tcp_now - tp->t_rcvtime) >= tcp_maxpersistidle ||
            (tcp_now - tp->t_rcvtime) >= rto * tcp_totbackoff)) {
-               tcpstat.tcps_persistdrop++;
+               tcpstat_inc(tcps_persistdrop);
                tp = tcp_drop(tp, ETIMEDOUT);
                goto out;
        }
@@ -420,7 +420,7 @@ tcp_timer_keep(void *arg)
        if (tp->t_flags & TF_DEAD)
                goto out;
 
-       tcpstat.tcps_keeptimeo++;
+       tcpstat_inc(tcps_keeptimeo);
        if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
                goto dropit;
        if ((tcp_always_keepalive ||
@@ -441,7 +441,7 @@ tcp_timer_keep(void *arg)
                 * by the protocol spec, this requires the
                 * correspondent TCP to respond.
                 */
-               tcpstat.tcps_keepprobe++;
+               tcpstat_inc(tcps_keepprobe);
                tcp_respond(tp, mtod(tp->t_template, caddr_t),
                    NULL, tp->rcv_nxt, tp->snd_una - 1, 0, 0);
                TCP_TIMER_ARM(tp, TCPT_KEEP, tcp_keepintvl);
@@ -452,7 +452,7 @@ tcp_timer_keep(void *arg)
        return;
 
  dropit:
-       tcpstat.tcps_keepdrops++;
+       tcpstat_inc(tcps_keepdrops);
        tp = tcp_drop(tp, ETIMEDOUT);
        NET_UNLOCK(s);
 }
Index: netinet/tcp_usrreq.c
===================================================================
RCS file: /d/cvs/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.142
diff -u -p -r1.142 tcp_usrreq.c
--- netinet/tcp_usrreq.c        10 Jan 2017 09:01:18 -0000      1.142
+++ netinet/tcp_usrreq.c        31 Jan 2017 10:52:11 -0000
@@ -283,7 +283,7 @@ tcp_usrreq(struct socket *so, int req, s
                tcp_rscale(tp, sb_max);
 
                soisconnecting(so);
-               tcpstat.tcps_connattempt++;
+               tcpstat_inc(tcps_connattempt);
                tp->t_state = TCPS_SYN_SENT;
                TCP_TIMER_ARM(tp, TCPT_KEEP, tcptv_keep_init);
                tcp_set_iss_tsm(tp);
@@ -808,7 +808,7 @@ tcp_ident(void *oldp, size_t *oldlenp, v
        }
 
        if (inp == NULL) {
-               ++tcpstat.tcps_pcbhashmiss;
+               tcpstat_inc(tcps_pcbhashmiss);
                switch (tir.faddr.ss_family) {
 #ifdef INET6
                case AF_INET6:
@@ -836,6 +836,137 @@ tcp_ident(void *oldp, size_t *oldlenp, v
        return (error);
 }
 
+int
+tcp_sysctl_tcpstat(void *oldp, size_t *oldlenp, void *newp)
+{
+       struct tcpstat tcpstat;
+       struct counters_ref cr;
+       uint64_t *counters;
+       struct syn_cache_set *set;
+       int i = 0;
+
+#define ASSIGN(field)  do { tcpstat.field = counters[i++]; } while (0)
+
+       counters = counters_enter(&cr, tcpcounters);
+       ASSIGN(tcps_connattempt);
+       ASSIGN(tcps_accepts);
+       ASSIGN(tcps_connects);
+       ASSIGN(tcps_drops);
+       ASSIGN(tcps_conndrops);
+       ASSIGN(tcps_closed);
+       ASSIGN(tcps_segstimed);
+       ASSIGN(tcps_rttupdated);
+       ASSIGN(tcps_delack);
+       ASSIGN(tcps_timeoutdrop);
+       ASSIGN(tcps_rexmttimeo);
+       ASSIGN(tcps_persisttimeo);
+       ASSIGN(tcps_persistdrop);
+       ASSIGN(tcps_keeptimeo);
+       ASSIGN(tcps_keepprobe);
+       ASSIGN(tcps_keepdrops);
+       ASSIGN(tcps_sndtotal);
+       ASSIGN(tcps_sndpack);
+       ASSIGN(tcps_sndbyte);
+       ASSIGN(tcps_sndrexmitpack);
+       ASSIGN(tcps_sndrexmitbyte);
+       ASSIGN(tcps_sndrexmitfast);
+       ASSIGN(tcps_sndacks);
+       ASSIGN(tcps_sndprobe);
+       ASSIGN(tcps_sndurg);
+       ASSIGN(tcps_sndwinup);
+       ASSIGN(tcps_sndctrl);
+       ASSIGN(tcps_rcvtotal);
+       ASSIGN(tcps_rcvpack);
+       ASSIGN(tcps_rcvbyte);
+       ASSIGN(tcps_rcvbadsum);
+       ASSIGN(tcps_rcvbadoff);
+       ASSIGN(tcps_rcvmemdrop);
+       ASSIGN(tcps_rcvnosec);
+       ASSIGN(tcps_rcvshort);
+       ASSIGN(tcps_rcvduppack);
+       ASSIGN(tcps_rcvdupbyte);
+       ASSIGN(tcps_rcvpartduppack);
+       ASSIGN(tcps_rcvpartdupbyte);
+       ASSIGN(tcps_rcvoopack);
+       ASSIGN(tcps_rcvoobyte);
+       ASSIGN(tcps_rcvpackafterwin);
+       ASSIGN(tcps_rcvbyteafterwin);
+       ASSIGN(tcps_rcvafterclose);
+       ASSIGN(tcps_rcvwinprobe);
+       ASSIGN(tcps_rcvdupack);
+       ASSIGN(tcps_rcvacktoomuch);
+       ASSIGN(tcps_rcvacktooold);
+       ASSIGN(tcps_rcvackpack);
+       ASSIGN(tcps_rcvackbyte);
+       ASSIGN(tcps_rcvwinupd);
+       ASSIGN(tcps_pawsdrop);
+       ASSIGN(tcps_predack);
+       ASSIGN(tcps_preddat);
+       ASSIGN(tcps_pcbhashmiss);
+       ASSIGN(tcps_noport);
+       ASSIGN(tcps_badsyn);
+       ASSIGN(tcps_dropsyn);
+       ASSIGN(tcps_rcvbadsig);
+       ASSIGN(tcps_rcvgoodsig);
+       ASSIGN(tcps_inswcsum);
+       ASSIGN(tcps_outswcsum);
+       ASSIGN(tcps_ecn_accepts);
+       ASSIGN(tcps_ecn_rcvece);
+       ASSIGN(tcps_ecn_rcvcwr);
+       ASSIGN(tcps_ecn_rcvce);
+       ASSIGN(tcps_ecn_sndect);
+       ASSIGN(tcps_ecn_sndece);
+       ASSIGN(tcps_ecn_sndcwr);
+       ASSIGN(tcps_cwr_ecn);
+       ASSIGN(tcps_cwr_frecovery);
+       ASSIGN(tcps_cwr_timeout);
+       ASSIGN(tcps_sc_added);
+       ASSIGN(tcps_sc_completed);
+       ASSIGN(tcps_sc_timed_out);
+       ASSIGN(tcps_sc_overflowed);
+       ASSIGN(tcps_sc_reset);
+       ASSIGN(tcps_sc_unreach);
+       ASSIGN(tcps_sc_bucketoverflow);
+       ASSIGN(tcps_sc_aborted);
+       ASSIGN(tcps_sc_dupesyn);
+       ASSIGN(tcps_sc_dropped);
+       ASSIGN(tcps_sc_collisions);
+       ASSIGN(tcps_sc_retransmitted);
+       ASSIGN(tcps_sc_seedrandom);
+       ASSIGN(tcps_sc_hash_size);
+       ASSIGN(tcps_sc_entry_count);
+       ASSIGN(tcps_sc_entry_limit);
+       ASSIGN(tcps_sc_bucket_maxlen);
+       ASSIGN(tcps_sc_bucket_limit);
+       ASSIGN(tcps_sc_uses_left);
+       ASSIGN(tcps_conndrained);
+       ASSIGN(tcps_sack_recovery_episode);
+       ASSIGN(tcps_sack_rexmits);
+       ASSIGN(tcps_sack_rexmit_bytes);
+       ASSIGN(tcps_sack_rcv_opts);
+       ASSIGN(tcps_sack_snd_opts);
+       counters_leave(&cr, tcpcounters);
+
+#undef ASSIGN
+
+       set = &tcp_syn_cache[tcp_syn_cache_active];
+       tcpstat.tcps_sc_hash_size = set->scs_size;
+       tcpstat.tcps_sc_entry_count = set->scs_count;
+       tcpstat.tcps_sc_entry_limit = tcp_syn_cache_limit;
+       tcpstat.tcps_sc_bucket_maxlen = 0;
+       for (i = 0; i < set->scs_size; i++) {
+               if (tcpstat.tcps_sc_bucket_maxlen <
+                   set->scs_buckethead[i].sch_length)
+                       tcpstat.tcps_sc_bucket_maxlen =
+                               set->scs_buckethead[i].sch_length;
+       }
+       tcpstat.tcps_sc_bucket_limit = tcp_syn_bucket_limit;
+       tcpstat.tcps_sc_uses_left = set->scs_use;
+
+       return (sysctl_rdstruct(oldp, oldlenp, newp,
+           &tcpstat, sizeof(tcpstat)));
+}
+
 /*
  * Sysctl for tcp variables.
  */
@@ -913,28 +1044,7 @@ tcp_sysctl(int *name, u_int namelen, voi
 #endif
 
        case TCPCTL_STATS:
-               if (newp != NULL)
-                       return (EPERM);
-               {
-                       struct syn_cache_set *set;
-                       int i;
-
-                       set = &tcp_syn_cache[tcp_syn_cache_active];
-                       tcpstat.tcps_sc_hash_size = set->scs_size;
-                       tcpstat.tcps_sc_entry_count = set->scs_count;
-                       tcpstat.tcps_sc_entry_limit = tcp_syn_cache_limit;
-                       tcpstat.tcps_sc_bucket_maxlen = 0;
-                       for (i = 0; i < set->scs_size; i++) {
-                               if (tcpstat.tcps_sc_bucket_maxlen <
-                                   set->scs_buckethead[i].sch_length)
-                                       tcpstat.tcps_sc_bucket_maxlen =
-                                           set->scs_buckethead[i].sch_length;
-                       }
-                       tcpstat.tcps_sc_bucket_limit = tcp_syn_bucket_limit;
-                       tcpstat.tcps_sc_uses_left = set->scs_use;
-               }
-               return (sysctl_struct(oldp, oldlenp, newp, newlen,
-                   &tcpstat, sizeof(tcpstat)));
+               return (tcp_sysctl_tcpstat(oldp, oldlenp, newp));
 
        case TCPCTL_SYN_USE_LIMIT:
                error = sysctl_int(oldp, oldlenp, newp, newlen,
Index: netinet/tcp_var.h
===================================================================
RCS file: /d/cvs/src/sys/netinet/tcp_var.h,v
retrieving revision 1.120
diff -u -p -r1.120 tcp_var.h
--- netinet/tcp_var.h   29 Jan 2017 19:58:47 -0000      1.120
+++ netinet/tcp_var.h   31 Jan 2017 14:23:33 -0000
@@ -566,8 +566,141 @@ struct tcp_ident_mapping {
 };
 
 #ifdef _KERNEL
+
+#include <sys/percpu.h>
+
+enum tcpstat_counters {
+       tcps_connattempt,
+       tcps_accepts,
+       tcps_connects,
+       tcps_drops,
+       tcps_conndrops,
+       tcps_closed,
+       tcps_segstimed,
+       tcps_rttupdated,
+       tcps_delack,
+       tcps_timeoutdrop,
+       tcps_rexmttimeo,
+       tcps_persisttimeo,
+       tcps_persistdrop,
+       tcps_keeptimeo,
+       tcps_keepprobe,
+       tcps_keepdrops,
+       tcps_sndtotal,
+       tcps_sndpack,
+       tcps_sndbyte,
+       tcps_sndrexmitpack,
+       tcps_sndrexmitbyte,
+       tcps_sndrexmitfast,
+       tcps_sndacks,
+       tcps_sndprobe,
+       tcps_sndurg,
+       tcps_sndwinup,
+       tcps_sndctrl,
+       tcps_rcvtotal,
+       tcps_rcvpack,
+       tcps_rcvbyte,
+       tcps_rcvbadsum,
+       tcps_rcvbadoff,
+       tcps_rcvmemdrop,
+       tcps_rcvnosec,
+       tcps_rcvshort,
+       tcps_rcvduppack,
+       tcps_rcvdupbyte,
+       tcps_rcvpartduppack,
+       tcps_rcvpartdupbyte,
+       tcps_rcvoopack,
+       tcps_rcvoobyte,
+       tcps_rcvpackafterwin,
+       tcps_rcvbyteafterwin,
+       tcps_rcvafterclose,
+       tcps_rcvwinprobe,
+       tcps_rcvdupack,
+       tcps_rcvacktoomuch,
+       tcps_rcvacktooold,
+       tcps_rcvackpack,
+       tcps_rcvackbyte,
+       tcps_rcvwinupd,
+       tcps_pawsdrop,
+       tcps_predack,
+       tcps_preddat,
+       tcps_pcbhashmiss,
+       tcps_noport,
+       tcps_badsyn,
+       tcps_dropsyn,
+       tcps_rcvbadsig,
+       tcps_rcvgoodsig,
+       tcps_inswcsum,
+       tcps_outswcsum,
+       tcps_ecn_accepts,
+       tcps_ecn_rcvece,
+       tcps_ecn_rcvcwr,
+       tcps_ecn_rcvce,
+       tcps_ecn_sndect,
+       tcps_ecn_sndece,
+       tcps_ecn_sndcwr,
+       tcps_cwr_ecn,
+       tcps_cwr_frecovery,
+       tcps_cwr_timeout,
+       tcps_sc_added,
+       tcps_sc_completed,
+       tcps_sc_timed_out,
+       tcps_sc_overflowed,
+       tcps_sc_reset,
+       tcps_sc_unreach,
+       tcps_sc_bucketoverflow,
+       tcps_sc_aborted,
+       tcps_sc_dupesyn,
+       tcps_sc_dropped,
+       tcps_sc_collisions,
+       tcps_sc_retransmitted,
+       tcps_sc_seedrandom,
+       tcps_sc_hash_size,
+       tcps_sc_entry_count,
+       tcps_sc_entry_limit,
+       tcps_sc_bucket_maxlen,
+       tcps_sc_bucket_limit,
+       tcps_sc_uses_left,
+       tcps_conndrained,
+       tcps_sack_recovery_episode,
+       tcps_sack_rexmits,
+       tcps_sack_rexmit_bytes,
+       tcps_sack_rcv_opts,
+       tcps_sack_snd_opts,
+       tcps_ncounters,
+};
+
+extern struct cpumem *tcpcounters;
+
+//#define TCPSTAT_INLINE
+
+#ifdef TCPSTAT_INLINE
+static inline void
+tcpstat_inc(enum tcpstat_counters c)
+{
+       counters_inc(tcpcounters, c);
+}
+
+static inline void
+tcpstat_add(enum tcpstat_counters c, uint64_t v)
+{
+       counters_add(tcpcounters, c, v);
+}
+
+static inline void
+tcpstat_pkt(enum tcpstat_counters pcounter, enum tcpstat_counters bcounter,
+    uint64_t v)
+{
+       counters_pkt(tcpcounters, pcounter, bcounter, v);
+}
+#else
+void   tcpstat_inc(enum tcpstat_counters);
+void   tcpstat_add(enum tcpstat_counters, uint64_t);
+void   tcpstat_pkt(enum tcpstat_counters, enum tcpstat_counters bcounter,
+    uint64_t v);
+#endif
+
 extern struct inpcbtable tcbtable;     /* head of queue of active tcpcb's */
-extern struct tcpstat tcpstat; /* tcp statistics */
 extern u_int32_t tcp_now;              /* for RFC 1323 timestamps */
 extern int tcp_do_rfc1323;     /* enabled/disabled? */
 extern int tcptv_keep_init;    /* time to keep alive the initial SYN packet */
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       31 Jan 2017 00:10:40 -0000
@@ -2732,7 +2732,7 @@ in6_proto_cksum_out(struct mbuf *m, stru
                if (!ifp || !(ifp->if_capabilities & IFCAP_CSUM_TCPv6) ||
                    ip6->ip6_nxt != IPPROTO_TCP ||
                    ifp->if_bridgeport != NULL) {
-                       tcpstat.tcps_outswcsum++;
+                       tcpstat_inc(tcps_outswcsum);
                        in6_delayed_cksum(m, IPPROTO_TCP);
                        m->m_pkthdr.csum_flags &= ~M_TCP_CSUM_OUT; /* Clear */
                }


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

Reply via email to