I failed to find a nice place where to initialize the counters. The code that uses counters is reachable even if gif(4) isn't compiled in.
I can think of 3 obvious ways to call the init function. 1. call ipip_init() through .pr_init. The idea would be to call ipip_init() once per protosw entry that needs it, so the function should return early if it was already run. 2. call ipip_init() from ip_init(), after all ip_init() is always compiled in. 3. call ipip_init() from init_main.c. The diff implements option 3, but what do you folks prefer? Thoughts / ok? Index: kern/init_main.c =================================================================== RCS file: /d/cvs/src/sys/kern/init_main.c,v retrieving revision 1.267 diff -u -p -r1.267 init_main.c --- kern/init_main.c 6 Mar 2017 10:48:16 -0000 1.267 +++ kern/init_main.c 7 Mar 2017 14:20:17 -0000 @@ -147,6 +147,7 @@ void taskq_init(void); void timeout_proc_init(void); void pool_gc_pages(void *); void percpu_init(void); +void ipip_init(void); extern char sigcode[], esigcode[], sigcoderet[]; #ifdef SYSCALL_DEBUG @@ -364,6 +365,9 @@ main(void *framep) /* Per CPU memory allocation */ percpu_init(); + + /* IP-in-IP memory allocation */ + ipip_init(); /* Initialize the file systems. */ #if defined(NFSSERVER) || defined(NFSCLIENT) Index: netinet/ip_ipip.c =================================================================== RCS file: /d/cvs/src/sys/netinet/ip_ipip.c,v retrieving revision 1.71 diff -u -p -r1.71 ip_ipip.c --- netinet/ip_ipip.c 29 Jan 2017 19:58:47 -0000 1.71 +++ netinet/ip_ipip.c 7 Mar 2017 14:20:17 -0000 @@ -84,7 +84,14 @@ */ int ipip_allow = 0; -struct ipipstat ipipstat; +struct cpumem *ipipcounters; + +void +ipip_init(void) +{ + if (ipipcounters == NULL) + ipipcounters = counters_alloc(ipips_ncounters); +} /* * Really only a wrapper for ipip_input(), for use with pr_input. @@ -95,7 +102,7 @@ ip4_input(struct mbuf **mp, int *offp, i /* If we do not accept IP-in-IP explicitly, drop. */ if (!ipip_allow && ((*mp)->m_flags & (M_AUTH|M_CONF)) == 0) { DPRINTF(("ip4_input(): dropped due to policy\n")); - ipipstat.ipips_pdrops++; + ipipstat_inc(ipips_pdrops); m_freem(*mp); return IPPROTO_DONE; } @@ -129,7 +136,7 @@ ipip_input(struct mbuf **mp, int *offp, u_int8_t v; sa_family_t af; - ipipstat.ipips_ipackets++; + ipipstat_inc(ipips_ipackets); m_copydata(m, 0, 1, &v); @@ -143,7 +150,7 @@ ipip_input(struct mbuf **mp, int *offp, break; #endif default: - ipipstat.ipips_family++; + ipipstat_inc(ipips_family); m_freem(m); return IPPROTO_DONE; } @@ -152,7 +159,7 @@ ipip_input(struct mbuf **mp, int *offp, if (m->m_len < hlen) { if ((m = m_pullup(m, hlen)) == NULL) { DPRINTF(("ipip_input(): m_pullup() failed\n")); - ipipstat.ipips_hdrops++; + ipipstat_inc(ipips_hdrops); return IPPROTO_DONE; } } @@ -179,7 +186,7 @@ ipip_input(struct mbuf **mp, int *offp, /* Sanity check */ if (m->m_pkthdr.len < sizeof(struct ip)) { - ipipstat.ipips_hdrops++; + ipipstat_inc(ipips_hdrops); m_freem(m); return IPPROTO_DONE; } @@ -195,7 +202,7 @@ ipip_input(struct mbuf **mp, int *offp, break; #endif default: - ipipstat.ipips_family++; + ipipstat_inc(ipips_family); m_freem(m); return IPPROTO_DONE; } @@ -206,7 +213,7 @@ ipip_input(struct mbuf **mp, int *offp, if (m->m_len < hlen) { if ((m = m_pullup(m, hlen)) == NULL) { DPRINTF(("ipip_input(): m_pullup() failed\n")); - ipipstat.ipips_hdrops++; + ipipstat_inc(ipips_hdrops); return IPPROTO_DONE; } } @@ -229,7 +236,7 @@ ipip_input(struct mbuf **mp, int *offp, ECN_ALLOWED_IPSEC : ECN_ALLOWED; if (!ip_ecn_egress(mode, &otos, &ipo->ip_tos)) { DPRINTF(("ipip_input(): ip_ecn_egress() failed")); - ipipstat.ipips_pdrops++; + ipipstat_inc(ipips_pdrops); m_freem(m); return IPPROTO_DONE; } @@ -249,7 +256,7 @@ ipip_input(struct mbuf **mp, int *offp, itos = (ntohl(ip6->ip6_flow) >> 20) & 0xff; if (!ip_ecn_egress(ECN_ALLOWED, &otos, &itos)) { DPRINTF(("ipip_input(): ip_ecn_egress() failed")); - ipipstat.ipips_pdrops++; + ipipstat_inc(ipips_pdrops); m_freem(m); return IPPROTO_DONE; } @@ -291,7 +298,7 @@ ipip_input(struct mbuf **mp, int *offp, rt = rtalloc((struct sockaddr *)&ss, 0, m->m_pkthdr.ph_rtableid); if ((rt != NULL) && (rt->rt_flags & RTF_LOCAL)) { - ipipstat.ipips_spoof++; + ipipstat_inc(ipips_spoof); m_freem(m); rtfree(rt); return IPPROTO_DONE; @@ -302,7 +309,7 @@ ipip_input(struct mbuf **mp, int *offp, } /* Statistics */ - ipipstat.ipips_ibytes += m->m_pkthdr.len - iphlen; + ipipstat_add(ipips_ibytes, m->m_pkthdr.len - iphlen); /* * Interface pointer stays the same; if no IPsec processing has @@ -336,7 +343,7 @@ ipip_input(struct mbuf **mp, int *offp, #endif if (niq_enqueue(ifq, m) != 0) { - ipipstat.ipips_qfull++; + ipipstat_inc(ipips_qfull); DPRINTF(("ipip_input(): packet dropped because of full " "queue\n")); } @@ -375,7 +382,7 @@ ipip_output(struct mbuf *m, struct tdb * ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), ntohl(tdb->tdb_spi))); - ipipstat.ipips_unspec++; + ipipstat_inc(ipips_unspec); m_freem(m); *mp = NULL; return EINVAL; @@ -384,7 +391,7 @@ ipip_output(struct mbuf *m, struct tdb * M_PREPEND(m, sizeof(struct ip), M_DONTWAIT); if (m == NULL) { DPRINTF(("ipip_output(): M_PREPEND failed\n")); - ipipstat.ipips_hdrops++; + ipipstat_inc(ipips_hdrops); *mp = NULL; return ENOBUFS; } @@ -441,7 +448,7 @@ ipip_output(struct mbuf *m, struct tdb * else { m_freem(m); *mp = NULL; - ipipstat.ipips_family++; + ipipstat_inc(ipips_family); return EAFNOSUPPORT; } @@ -461,7 +468,7 @@ ipip_output(struct mbuf *m, struct tdb * ipsp_address(&tdb->tdb_dst, buf, sizeof(buf)), ntohl(tdb->tdb_spi))); - ipipstat.ipips_unspec++; + ipipstat_inc(ipips_unspec); m_freem(m); *mp = NULL; return ENOBUFS; @@ -480,7 +487,7 @@ ipip_output(struct mbuf *m, struct tdb * M_PREPEND(m, sizeof(struct ip6_hdr), M_DONTWAIT); if (m == NULL) { DPRINTF(("ipip_output(): M_PREPEND failed\n")); - ipipstat.ipips_hdrops++; + ipipstat_inc(ipips_hdrops); *mp = NULL; return ENOBUFS; } @@ -518,7 +525,7 @@ ipip_output(struct mbuf *m, struct tdb * } else { m_freem(m); *mp = NULL; - ipipstat.ipips_family++; + ipipstat_inc(ipips_family); return EAFNOSUPPORT; } @@ -533,11 +540,11 @@ ipip_output(struct mbuf *m, struct tdb * tdb->tdb_dst.sa.sa_family)); m_freem(m); *mp = NULL; - ipipstat.ipips_family++; + ipipstat_inc(ipips_family); return EAFNOSUPPORT; } - ipipstat.ipips_opackets++; + ipipstat_inc(ipips_opackets); *mp = m; if (tdb->tdb_dst.sa.sa_family == AF_INET) { @@ -545,7 +552,7 @@ ipip_output(struct mbuf *m, struct tdb * tdb->tdb_cur_bytes += m->m_pkthdr.len - sizeof(struct ip); - ipipstat.ipips_obytes += m->m_pkthdr.len - sizeof(struct ip); + ipipstat_add(ipips_obytes, m->m_pkthdr.len - sizeof(struct ip)); } #ifdef INET6 @@ -554,8 +561,8 @@ ipip_output(struct mbuf *m, struct tdb * tdb->tdb_cur_bytes += m->m_pkthdr.len - sizeof(struct ip6_hdr); - ipipstat.ipips_obytes += - m->m_pkthdr.len - sizeof(struct ip6_hdr); + ipipstat_add(ipips_obytes, + m->m_pkthdr.len - sizeof(struct ip6_hdr)); } #endif /* INET6 */ @@ -592,6 +599,17 @@ ipe4_input(struct mbuf *m, int hlen, int #endif /* IPSEC */ int +ipip_sysctl_ipipstat(void *oldp, size_t *oldlenp, void *newp) +{ + struct ipipstat ipipstat; + + CTASSERT(sizeof(ipipstat) == (ipips_ncounters * sizeof(uint64_t))); + counters_read(ipipcounters, (uint64_t *)&ipipstat, ipips_ncounters); + return (sysctl_rdstruct(oldp, oldlenp, newp, + &ipipstat, sizeof(ipipstat))); +} + +int ipip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { @@ -603,10 +621,7 @@ ipip_sysctl(int *name, u_int namelen, vo case IPIPCTL_ALLOW: return (sysctl_int(oldp, oldlenp, newp, newlen, &ipip_allow)); case IPIPCTL_STATS: - if (newp != NULL) - return (EPERM); - return (sysctl_struct(oldp, oldlenp, newp, newlen, - &ipipstat, sizeof(ipipstat))); + return (ipip_sysctl_ipipstat(oldp, oldlenp, newp)); default: return (ENOPROTOOPT); } Index: netinet/ip_ipip.h =================================================================== RCS file: /d/cvs/src/sys/netinet/ip_ipip.h,v retrieving revision 1.7 diff -u -p -r1.7 ip_ipip.h --- netinet/ip_ipip.h 20 Feb 2017 17:04:25 -0000 1.7 +++ netinet/ip_ipip.h 7 Mar 2017 14:20:17 -0000 @@ -73,9 +73,39 @@ struct ipipstat { } #ifdef _KERNEL + +#include <sys/percpu.h> + +enum ipipstat_counters { + ipips_ipackets, + ipips_opackets, + ipips_hdrops, + ipips_qfull, + ipips_ibytes, + ipips_obytes, + ipips_pdrops, + ipips_spoof, + ipips_family, + ipips_unspec, + ipips_ncounters +}; + +extern struct cpumem *ipipcounters; + +static inline void +ipipstat_inc(enum ipipstat_counters c) +{ + counters_inc(ipipcounters, c); +} + +static inline void +ipipstat_add(enum ipipstat_counters c, uint64_t v) +{ + counters_add(ipipcounters, c, v); +} + int ipip_sysctl(int *, u_int, void *, size_t *, void *, size_t); extern int ipip_allow; -extern struct ipipstat ipipstat; #endif /* _KERNEL */ #endif /* _NETINET_IPIP_H_ */ -- jca | PGP : 0x1524E7EE / 5135 92C1 AD36 5293 2BDF DDCC 0DFA 74AE 1524 E7EE