Hi,

I converted the igmp stats to use percpu counters.  This work is
basically the same as what dlg@ did for other parts of the stack.
I looked at the diff and adjusted it for igmp.

diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c
index 11446ce4188..c2a0a4839b4 100644
--- a/sys/netinet/igmp.c
+++ b/sys/netinet/igmp.c
@@ -101,13 +101,14 @@ int *igmpctl_vars[IGMPCTL_MAXID] = IGMPCTL_VARS;
 int            igmp_timers_are_running;
 static struct router_info *rti_head;
 static struct mbuf *router_alert;
-struct igmpstat igmpstat;
+struct cpumem *igmpcounters;
 
 void igmp_checktimer(struct ifnet *);
 void igmp_sendpkt(struct in_multi *, int, in_addr_t);
 int rti_fill(struct in_multi *);
 struct router_info * rti_find(struct ifnet *);
 void igmp_input_if(struct ifnet *, struct mbuf *, int);
+int igmp_sysctl_igmpstat(void *, size_t *, void *);
 
 void
 igmp_init(void)
@@ -117,6 +118,7 @@ igmp_init(void)
        igmp_timers_are_running = 0;
        rti_head = 0;
 
+       igmpcounters = counters_alloc(igps_ncounters, M_COUNTERS);
        router_alert = m_get(M_DONTWAIT, MT_DATA);
        if (router_alert == NULL) {
                printf("%s: no mbuf\n", __func__);
@@ -217,7 +219,7 @@ igmp_input(struct mbuf *m, ...)
        iphlen = va_arg(ap, int);
        va_end(ap);
 
-       ++igmpstat.igps_rcv_total;
+       igmpstat_inc(igps_rcv_total);
 
        ifp = if_get(m->m_pkthdr.ph_ifidx);
        if (ifp == NULL) {
@@ -248,14 +250,14 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int 
iphlen)
         * Validate lengths
         */
        if (igmplen < IGMP_MINLEN) {
-               ++igmpstat.igps_rcv_tooshort;
+               igmpstat_inc(igps_rcv_tooshort);
                m_freem(m);
                return;
        }
        minlen = iphlen + IGMP_MINLEN;
        if ((m->m_flags & M_EXT || m->m_len < minlen) &&
            (m = m_pullup(m, minlen)) == NULL) {
-               ++igmpstat.igps_rcv_tooshort;
+               igmpstat_inc(igps_rcv_tooshort);
                return;
        }
 
@@ -266,7 +268,7 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int iphlen)
        m->m_len -= iphlen;
        igmp = mtod(m, struct igmp *);
        if (in_cksum(m, igmplen)) {
-               ++igmpstat.igps_rcv_badsum;
+               igmpstat_inc(igps_rcv_badsum);
                m_freem(m);
                return;
        }
@@ -277,7 +279,7 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int iphlen)
        switch (igmp->igmp_type) {
 
        case IGMP_HOST_MEMBERSHIP_QUERY:
-               ++igmpstat.igps_rcv_queries;
+               igmpstat_inc(igps_rcv_queries);
 
                if (ifp->if_flags & IFF_LOOPBACK)
                        break;
@@ -292,7 +294,7 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int iphlen)
                        rti->rti_age = 0;
 
                        if (ip->ip_dst.s_addr != INADDR_ALLHOSTS_GROUP) {
-                               ++igmpstat.igps_rcv_badqueries;
+                               igmpstat_inc(igps_rcv_badqueries);
                                m_freem(m);
                                return;
                        }
@@ -317,7 +319,7 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int iphlen)
                        }
                } else {
                        if (!IN_MULTICAST(ip->ip_dst.s_addr)) {
-                               ++igmpstat.igps_rcv_badqueries;
+                               igmpstat_inc(igps_rcv_badqueries);
                                m_freem(m);
                                return;
                        }
@@ -367,14 +369,14 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int 
iphlen)
                break;
 
        case IGMP_v1_HOST_MEMBERSHIP_REPORT:
-               ++igmpstat.igps_rcv_reports;
+               igmpstat_inc(igps_rcv_reports);
 
                if (ifp->if_flags & IFF_LOOPBACK)
                        break;
 
                if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
                    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
-                       ++igmpstat.igps_rcv_badreports;
+                       igmpstat_inc(igps_rcv_badreports);
                        m_freem(m);
                        return;
                }
@@ -401,7 +403,7 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int iphlen)
                IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
                if (inm != NULL) {
                        inm->inm_timer = 0;
-                       ++igmpstat.igps_rcv_ourreports;
+                       igmpstat_inc(igps_rcv_ourreports);
 
                        switch (inm->inm_state) {
                        case IGMP_IDLE_MEMBER:
@@ -433,14 +435,14 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int 
iphlen)
                        break;
 #endif
 
-               ++igmpstat.igps_rcv_reports;
+               igmpstat_inc(igps_rcv_reports);
 
                if (ifp->if_flags & IFF_LOOPBACK)
                        break;
 
                if (!IN_MULTICAST(igmp->igmp_group.s_addr) ||
                    igmp->igmp_group.s_addr != ip->ip_dst.s_addr) {
-                       ++igmpstat.igps_rcv_badreports;
+                       igmpstat_inc(igps_rcv_badreports);
                        m_freem(m);
                        return;
                }
@@ -469,7 +471,7 @@ igmp_input_if(struct ifnet *ifp, struct mbuf *m, int iphlen)
                IN_LOOKUP_MULTI(igmp->igmp_group, ifp, inm);
                if (inm != NULL) {
                        inm->inm_timer = 0;
-                       ++igmpstat.igps_rcv_ourreports;
+                       igmpstat_inc(igps_rcv_ourreports);
 
                        switch (inm->inm_state) {
                        case IGMP_DELAYING_MEMBER:
@@ -667,7 +669,7 @@ igmp_sendpkt(struct in_multi *inm, int type, in_addr_t addr)
 
        ip_output(m, router_alert, NULL, IP_MULTICASTOPTS, &imo, NULL, 0);
 
-       ++igmpstat.igps_snd_reports;
+       igmpstat_inc(igps_snd_reports);
 }
 
 /*
@@ -685,8 +687,7 @@ igmp_sysctl(int *name, u_int namelen, void *oldp, size_t 
*oldlenp,
        case IGMPCTL_STATS:
                if (newp != NULL)
                        return (EPERM);
-               return (sysctl_struct(oldp, oldlenp, newp, newlen,
-                   &igmpstat, sizeof(igmpstat)));
+               return (igmp_sysctl_igmpstat(oldp, oldlenp, newp));
        default:
                if (name[0] < IGMPCTL_MAXID)
                        return (sysctl_int_arr(igmpctl_vars, name, namelen,
@@ -695,3 +696,22 @@ igmp_sysctl(int *name, u_int namelen, void *oldp, size_t 
*oldlenp,
        }
        /* NOTREACHED */
 }
+
+int
+igmp_sysctl_igmpstat(void *oldp, size_t *oldlenp, void *newp)
+{
+       uint64_t counters[igps_ncounters];
+       struct igmpstat igmpstat;
+       u_long *words = (u_long *)&igmpstat;
+       int i;
+
+       KASSERT(sizeof(igmpstat) == (nitems(counters) * sizeof(u_long)));
+
+       counters_read(igmpcounters, counters, nitems(counters));
+
+       for (i = 0; i < nitems(counters); i++)
+               words[i] = (u_long)counters[i];
+
+       return (sysctl_rdstruct(oldp, oldlenp, newp,
+           &igmpstat, sizeof(igmpstat)));
+}
diff --git a/sys/netinet/igmp_var.h b/sys/netinet/igmp_var.h
index ea066093ec4..290b1bef7d6 100644
--- a/sys/netinet/igmp_var.h
+++ b/sys/netinet/igmp_var.h
@@ -78,7 +78,29 @@ struct igmpstat {
 }
 
 #ifdef _KERNEL
-extern struct igmpstat igmpstat;
+
+#include <sys/percpu.h>
+
+enum igmpstat_counters {
+       igps_rcv_total,         /* total IGMP messages received */
+       igps_rcv_tooshort,      /* received with too few bytes */
+       igps_rcv_badsum,        /* received with bad checksum */
+       igps_rcv_queries,       /* received membership queries */
+       igps_rcv_badqueries,    /* received invalid queries */
+       igps_rcv_reports,       /* received membership reports */
+       igps_rcv_badreports,    /* received invalid reports */
+       igps_rcv_ourreports,    /* received reports for our groups */
+       igps_snd_reports,       /* sent membership reports */
+       igps_ncounters
+};
+
+extern struct cpumem *igmpcounters;
+
+static inline void
+igmpstat_inc(enum igmpstat_counters c)
+{
+       counters_inc(igmpcounters, c);
+}
 
 /*
  * Macro to compute a random timer value between 1 and (IGMP_MAX_REPORTING_
-- 
2.11.0

Reply via email to