Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/netinet6/ip6_input.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.113 retrieving revision 1.116 diff -u -p -r1.113 -r1.116 --- src/sys/netinet6/ip6_input.c 2007/12/04 10:27:34 1.113 +++ src/sys/netinet6/ip6_input.c 2008/04/15 03:57:04 1.116 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.113 2007/12/04 10:27:34 dyoung Exp $ */ +/* $NetBSD: ip6_input.c,v 1.116 2008/04/15 03:57:04 thorpej Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -62,7 +62,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.113 2007/12/04 10:27:34 dyoung Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.116 2008/04/15 03:57:04 thorpej Exp $"); #include "opt_inet.h" #include "opt_inet6.h" @@ -102,6 +102,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #include #include +#include #include #include #include @@ -146,7 +147,7 @@ int ip6_sourcecheck_interval; /* XXX */ struct pfil_head inet6_pfil_hook; #endif -struct ip6stat ip6stat; +percpu_t *ip6stat_percpu; static void ip6_init2(void *); static struct m_tag *ip6_setdstifaddr(struct mbuf *, const struct in6_ifaddr *); @@ -159,7 +160,7 @@ static struct mbuf *ip6_pullexthdr(struc * All protocols not implemented in kernel go to raw IP6 protocol handler. */ void -ip6_init() +ip6_init(void) { const struct ip6protosw *pr; int i; @@ -195,6 +196,8 @@ ip6_init() printf("ip6_init: WARNING: unable to register pfil hook, " "error %d\n", i); #endif /* PFIL_HOOKS */ + + ip6stat_percpu = percpu_alloc(sizeof(uint64_t) * IP6_NSTATS); } static void @@ -217,7 +220,7 @@ ip6_init2(void *dummy) * IP6 input interrupt handling. Just pass the packet to ip6_input. */ void -ip6intr() +ip6intr(void) { int s; struct mbuf *m; @@ -280,25 +283,26 @@ ip6_input(struct mbuf *m) */ if (m->m_flags & M_EXT) { if (m->m_next) - ip6stat.ip6s_mext2m++; + IP6_STATINC(IP6_STAT_MEXT2M); else - ip6stat.ip6s_mext1++; + IP6_STATINC(IP6_STAT_MEXT1); } else { -#define M2MMAX __arraycount(ip6stat.ip6s_m2m) +#define M2MMAX 32 if (m->m_next) { if (m->m_flags & M_LOOP) { - ip6stat.ip6s_m2m[lo0ifp->if_index]++; /* XXX */ - } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) - ip6stat.ip6s_m2m[m->m_pkthdr.rcvif->if_index]++; - else - ip6stat.ip6s_m2m[0]++; + /*XXX*/ IP6_STATINC(IP6_STAT_M2M + lo0ifp->if_index); + } else if (m->m_pkthdr.rcvif->if_index < M2MMAX) { + IP6_STATINC(IP6_STAT_M2M + + m->m_pkthdr.rcvif->if_index); + } else + IP6_STATINC(IP6_STAT_M2M); } else - ip6stat.ip6s_m1++; + IP6_STATINC(IP6_STAT_M1); #undef M2MMAX } in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_receive); - ip6stat.ip6s_total++; + IP6_STATINC(IP6_STAT_TOTAL); /* * If the IPv6 header is not aligned, slurp it up into a new @@ -311,14 +315,14 @@ ip6_input(struct mbuf *m) if ((m = m_copyup(m, sizeof(struct ip6_hdr), (max_linkhdr + 3) & ~3)) == NULL) { /* XXXJRT new stat, please */ - ip6stat.ip6s_toosmall++; + IP6_STATINC(IP6_STAT_TOOSMALL); in6_ifstat_inc(inifp, ifs6_in_hdrerr); return; } } else if (__predict_false(m->m_len < sizeof(struct ip6_hdr))) { struct ifnet *inifp = m->m_pkthdr.rcvif; if ((m = m_pullup(m, sizeof(struct ip6_hdr))) == NULL) { - ip6stat.ip6s_toosmall++; + IP6_STATINC(IP6_STAT_TOOSMALL); in6_ifstat_inc(inifp, ifs6_in_hdrerr); return; } @@ -327,7 +331,7 @@ ip6_input(struct mbuf *m) ip6 = mtod(m, struct ip6_hdr *); if ((ip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { - ip6stat.ip6s_badvers++; + IP6_STATINC(IP6_STAT_BADVERS); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); goto bad; } @@ -376,7 +380,7 @@ ip6_input(struct mbuf *m) } #endif /* PFIL_HOOKS */ - ip6stat.ip6s_nxthist[ip6->ip6_nxt]++; + IP6_STATINC(IP6_STAT_NXTHIST + ip6->ip6_nxt); #ifdef ALTQ if (altq_input != NULL && (*altq_input)(m, AF_INET6) == 0) { @@ -393,7 +397,7 @@ ip6_input(struct mbuf *m) /* * XXX: "badscope" is not very suitable for a multicast source. */ - ip6stat.ip6s_badscope++; + IP6_STATINC(IP6_STAT_BADSCOPE); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } @@ -411,7 +415,7 @@ ip6_input(struct mbuf *m) */ if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { - ip6stat.ip6s_badscope++; + IP6_STATINC(IP6_STAT_BADSCOPE); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } @@ -425,7 +429,7 @@ ip6_input(struct mbuf *m) */ if (IN6_IS_ADDR_V4COMPAT(&ip6->ip6_src) || IN6_IS_ADDR_V4COMPAT(&ip6->ip6_dst)) { - ip6stat.ip6s_badscope++; + IP6_STATINC(IP6_STAT_BADSCOPE); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } @@ -446,12 +450,12 @@ ip6_input(struct mbuf *m) goto bad; ip6 = mtod(m, struct ip6_hdr *); if (in6_clearscope(&ip6->ip6_src) || in6_clearscope(&ip6->ip6_dst)) { - ip6stat.ip6s_badscope++; /* XXX */ + IP6_STATINC(IP6_STAT_BADSCOPE); /* XXX */ goto bad; } if (in6_setscope(&ip6->ip6_src, m->m_pkthdr.rcvif, NULL) || in6_setscope(&ip6->ip6_dst, m->m_pkthdr.rcvif, NULL)) { - ip6stat.ip6s_badscope++; + IP6_STATINC(IP6_STAT_BADSCOPE); goto bad; } @@ -470,8 +474,10 @@ ip6_input(struct mbuf *m) if (in6m) ours = 1; else if (!ip6_mrouter) { - ip6stat.ip6s_notmember++; - ip6stat.ip6s_cantforward++; + uint64_t *ip6s = IP6_STAT_GETREF(); + ip6s[IP6_STAT_NOTMEMBER]++; + ip6s[IP6_STAT_CANTFORWARD]++; + IP6_STAT_PUTREF(); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } @@ -486,9 +492,9 @@ ip6_input(struct mbuf *m) */ rt = rtcache_lookup2(&ip6_forward_rt, &u.dst, 1, &hit); if (hit) - ip6stat.ip6s_forward_cachehit++; + IP6_STATINC(IP6_STAT_FORWARD_CACHEHIT); else - ip6stat.ip6s_forward_cachemiss++; + IP6_STATINC(IP6_STAT_FORWARD_CACHEMISS); #define rt6_getkey(__rt) satocsin6(rt_getkey(__rt)) @@ -578,7 +584,7 @@ ip6_input(struct mbuf *m) * and we're not a router. */ if (!ip6_forwarding) { - ip6stat.ip6s_cantforward++; + IP6_STATINC(IP6_STAT_CANTFORWARD); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); goto bad; } @@ -633,7 +639,7 @@ ip6_input(struct mbuf *m) * contained, ip6_hopopts_input() must set a valid * (non-zero) payload length to the variable plen. */ - ip6stat.ip6s_badoptions++; + IP6_STATINC(IP6_STAT_BADOPTIONS); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); icmp6_error(m, ICMP6_PARAM_PROB, @@ -644,7 +650,7 @@ ip6_input(struct mbuf *m) IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); return; } KASSERT(IP6_HDR_ALIGNED_P(hbh)); @@ -666,7 +672,7 @@ ip6_input(struct mbuf *m) * Drop packet if shorter than we expect. */ if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } @@ -691,7 +697,7 @@ ip6_input(struct mbuf *m) * must be discarded, else it may be accepted below. */ if (ip6_mrouter && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { - ip6stat.ip6s_cantforward++; + IP6_STATINC(IP6_STAT_CANTFORWARD); m_freem(m); return; } @@ -717,7 +723,7 @@ ip6_input(struct mbuf *m) */ if (IN6_IS_ADDR_V4MAPPED(&ip6->ip6_src) || IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { - ip6stat.ip6s_badscope++; + IP6_STATINC(IP6_STAT_BADSCOPE); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_addrerr); goto bad; } @@ -733,14 +739,14 @@ ip6_input(struct mbuf *m) ia6->ia_ifa.ifa_data.ifad_inbytes += m->m_pkthdr.len; } #endif - ip6stat.ip6s_delivered++; + IP6_STATINC(IP6_STAT_DELIVERED); in6_ifstat_inc(deliverifp, ifs6_in_deliver); nest = 0; rh_present = 0; while (nxt != IPPROTO_DONE) { if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { - ip6stat.ip6s_toomanyhdr++; + IP6_STATINC(IP6_STAT_TOOMANYHDR); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); goto bad; } @@ -750,7 +756,7 @@ ip6_input(struct mbuf *m) * more sanity checks in header chain processing. */ if (m->m_pkthdr.len < off) { - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_truncated); goto bad; } @@ -759,7 +765,7 @@ ip6_input(struct mbuf *m) if (rh_present++) { in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_hdrerr); - ip6stat.ip6s_badoptions++; + IP6_STATINC(IP6_STAT_BADOPTIONS); goto bad; } } @@ -873,14 +879,14 @@ ip6_hopopts_input(u_int32_t *plenp, u_in IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); return -1; } hbhlen = (hbh->ip6h_len + 1) << 3; IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), hbhlen); if (hbh == NULL) { - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); return -1; } KASSERT(IP6_HDR_ALIGNED_P(hbh)); @@ -924,7 +930,7 @@ ip6_process_hopopts(struct mbuf *m, u_in break; case IP6OPT_PADN: if (hbhlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; + IP6_STATINC(IP6_STAT_TOOSMALL); goto bad; } optlen = *(opt + 1) + 2; @@ -932,7 +938,7 @@ ip6_process_hopopts(struct mbuf *m, u_in case IP6OPT_RTALERT: /* XXX may need check for alignment */ if (hbhlen < IP6OPT_RTALERT_LEN) { - ip6stat.ip6s_toosmall++; + IP6_STATINC(IP6_STAT_TOOSMALL); goto bad; } if (*(opt + 1) != IP6OPT_RTALERT_LEN - 2) { @@ -949,7 +955,7 @@ ip6_process_hopopts(struct mbuf *m, u_in case IP6OPT_JUMBO: /* XXX may need check for alignment */ if (hbhlen < IP6OPT_JUMBO_LEN) { - ip6stat.ip6s_toosmall++; + IP6_STATINC(IP6_STAT_TOOSMALL); goto bad; } if (*(opt + 1) != IP6OPT_JUMBO_LEN - 2) { @@ -967,7 +973,7 @@ ip6_process_hopopts(struct mbuf *m, u_in */ ip6 = mtod(m, struct ip6_hdr *); if (ip6->ip6_plen) { - ip6stat.ip6s_badoptions++; + IP6_STATINC(IP6_STAT_BADOPTIONS); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt - opthead); @@ -991,7 +997,7 @@ ip6_process_hopopts(struct mbuf *m, u_in * there's no explicit mention in specification. */ if (*plenp != 0) { - ip6stat.ip6s_badoptions++; + IP6_STATINC(IP6_STAT_BADOPTIONS); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt + 2 - opthead); @@ -1003,7 +1009,7 @@ ip6_process_hopopts(struct mbuf *m, u_in * jumbo payload length must be larger than 65535. */ if (jumboplen <= IPV6_MAXPACKET) { - ip6stat.ip6s_badoptions++; + IP6_STATINC(IP6_STAT_BADOPTIONS); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, erroff + opt + 2 - opthead); @@ -1014,7 +1020,7 @@ ip6_process_hopopts(struct mbuf *m, u_in break; default: /* unknown option */ if (hbhlen < IP6OPT_MINLEN) { - ip6stat.ip6s_toosmall++; + IP6_STATINC(IP6_STAT_TOOSMALL); goto bad; } optlen = ip6_unknown_opt(opt, m, @@ -1051,11 +1057,11 @@ ip6_unknown_opt(u_int8_t *optp, struct m m_freem(m); return (-1); case IP6OPT_TYPE_FORCEICMP: /* send ICMP even if multicasted */ - ip6stat.ip6s_badoptions++; + IP6_STATINC(IP6_STAT_BADOPTIONS); icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_OPTION, off); return (-1); case IP6OPT_TYPE_ICMP: /* send ICMP if not multicasted */ - ip6stat.ip6s_badoptions++; + IP6_STATINC(IP6_STAT_BADOPTIONS); ip6 = mtod(m, struct ip6_hdr *); if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || (m->m_flags & (M_BCAST|M_MCAST))) @@ -1170,14 +1176,14 @@ ip6_savecontrol(struct in6pcb *in6p, str ext = ip6_pullexthdr(m, sizeof(struct ip6_hdr), xip6->ip6_nxt); if (ext == NULL) { - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); return; } hbh = mtod(ext, struct ip6_hbh *); hbhlen = (hbh->ip6h_len + 1) << 3; if (hbhlen != ext->m_len) { m_freem(ext); - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); return; } @@ -1229,7 +1235,7 @@ ip6_savecontrol(struct in6pcb *in6p, str ext = ip6_pullexthdr(m, off, nxt); if (ext == NULL) { - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); return; } ip6e = mtod(ext, struct ip6_ext *); @@ -1239,7 +1245,7 @@ ip6_savecontrol(struct in6pcb *in6p, str elen = (ip6e->ip6e_len + 1) << 3; if (elen != ext->m_len) { m_freem(ext); - ip6stat.ip6s_tooshort++; + IP6_STATINC(IP6_STAT_TOOSHORT); return; } KASSERT(IP6_HDR_ALIGNED_P(ip6e)); @@ -1640,6 +1646,38 @@ u_char inet6ctlerrmap[PRC_NCMDS] = { ENOPROTOOPT }; +static void +ip6stat_convert_to_user_cb(void *v1, void *v2, struct cpu_info *ci) +{ + uint64_t *ip6sc = v1; + uint64_t *ip6s = v2; + u_int i; + + for (i = 0; i < IP6_NSTATS; i++) + ip6s[i] += ip6sc[i]; +} + +static void +ip6stat_convert_to_user(uint64_t *ip6s) +{ + + memset(ip6s, 0, sizeof(uint64_t) * IP6_NSTATS); + percpu_foreach(ip6stat_percpu, ip6stat_convert_to_user_cb, ip6s); +} + +static int +sysctl_net_inet6_ip6_stats(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + uint64_t ip6s[IP6_NSTATS]; + + ip6stat_convert_to_user(ip6s); + node = *rnode; + node.sysctl_data = ip6s; + node.sysctl_size = sizeof(ip6s); + return (sysctl_lookup(SYSCTLFN_CALL(&node))); +} + SYSCTL_SETUP(sysctl_net_inet6_ip6_setup, "sysctl net.inet6.ip6 subtree setup") { #ifdef RFC2292 @@ -1893,7 +1931,7 @@ SYSCTL_SETUP(sysctl_net_inet6_ip6_setup, CTLFLAG_PERMANENT, CTLTYPE_STRUCT, "stats", SYSCTL_DESCR("IPv6 statistics"), - NULL, 0, &ip6stat, sizeof(ip6stat), + sysctl_net_inet6_ip6_stats, 0, NULL, 0, CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_STATS, CTL_EOL); sysctl_createv(clog, 0, NULL, NULL, @@ -1927,3 +1965,11 @@ SYSCTL_SETUP(sysctl_net_inet6_ip6_setup, CTL_CREATE, CTL_EOL); #endif } + +void +ip6_statinc(u_int stat) +{ + + KASSERT(stat < IP6_NSTATS); + IP6_STATINC(stat); +}