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.164.2.2 retrieving revision 1.176 diff -u -p -r1.164.2.2 -r1.176 --- src/sys/netinet6/ip6_input.c 2016/11/04 14:49:21 1.164.2.2 +++ src/sys/netinet6/ip6_input.c 2017/03/01 08:54:12 1.176 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_input.c,v 1.164.2.2 2016/11/04 14:49:21 pgoyette Exp $ */ +/* $NetBSD: ip6_input.c,v 1.176 2017/03/01 08:54:12 ozaki-r 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.164.2.2 2016/11/04 14:49:21 pgoyette Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_input.c,v 1.176 2017/03/01 08:54:12 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_gateway.h" @@ -75,7 +75,6 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #include -#include #include #include #include @@ -88,6 +87,7 @@ __KERNEL_RCSID(0, "$NetBSD: ip6_input.c, #include #include #include +#include #include #include @@ -144,6 +144,8 @@ pfil_head_t *inet6_pfil_hook; percpu_t *ip6stat_percpu; +percpu_t *ip6_forward_rt_percpu __cacheline_aligned; + static void ip6_init2(void); static void ip6intr(void *); static struct m_tag *ip6_setdstifaddr(struct mbuf *, const struct in6_ifaddr *); @@ -203,6 +205,10 @@ ip6_init(void) KASSERT(inet6_pfil_hook != NULL); ip6stat_percpu = percpu_alloc(sizeof(uint64_t) * IP6_NSTATS); + + ip6_forward_rt_percpu = percpu_alloc(sizeof(struct route)); + if (ip6_forward_rt_percpu == NULL) + panic("failed to alllocate ip6_forward_rt_percpu"); } static void @@ -252,8 +258,6 @@ ip6intr(void *arg __unused) #endif } -extern struct route ip6_forward_rt; - void ip6_input(struct mbuf *m, struct ifnet *rcvif) { @@ -264,11 +268,12 @@ ip6_input(struct mbuf *m, struct ifnet * int nxt, ours = 0, rh_present = 0; struct ifnet *deliverifp = NULL; int srcrt = 0; - const struct rtentry *rt; + struct rtentry *rt = NULL; union { struct sockaddr dst; struct sockaddr_in6 dst6; } u; + struct route *ro; /* * make sure we don't have onion peering information into m_tag. @@ -448,19 +453,20 @@ ip6_input(struct mbuf *m, struct ifnet * goto bad; } + ro = percpu_getref(ip6_forward_rt_percpu); /* * Multicast check */ if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { - struct in6_multi *in6m = 0; + bool ingroup; in6_ifstat_inc(rcvif, ifs6_in_mcast); /* * See if we belong to the destination multicast group on the * arrival interface. */ - IN6_LOOKUP_MULTI(ip6->ip6_dst, rcvif, in6m); - if (in6m) + ingroup = in6_multi_group(&ip6->ip6_dst, rcvif); + if (ingroup) ours = 1; else if (!ip6_mrouter) { uint64_t *ip6s = IP6_STAT_GETREF(); @@ -468,7 +474,7 @@ ip6_input(struct mbuf *m, struct ifnet * ip6s[IP6_STAT_CANTFORWARD]++; IP6_STAT_PUTREF(); in6_ifstat_inc(rcvif, ifs6_in_discard); - goto bad; + goto bad_unref; } deliverifp = rcvif; goto hbhcheck; @@ -479,7 +485,7 @@ ip6_input(struct mbuf *m, struct ifnet * /* * Unicast check */ - rt = rtcache_lookup2(&ip6_forward_rt, &u.dst, 1, &hit); + rt = rtcache_lookup2(ro, &u.dst, 1, &hit); if (hit) IP6_STATINC(IP6_STAT_FORWARD_CACHEHIT); else @@ -514,18 +520,20 @@ ip6_input(struct mbuf *m, struct ifnet * * packets to a tentative, duplicated, or somehow invalid * address must not be accepted. */ - if (!(ia6->ia6_flags & IN6_IFF_NOTREADY)) { + if (!(ia6->ia6_flags & (IN6_IFF_NOTREADY | IN6_IFF_DETACHED))) { /* this address is ready */ ours = 1; deliverifp = ia6->ia_ifp; /* correct? */ goto hbhcheck; } else { /* address is not ready, so discard the packet. */ + char ip6bufs[INET6_ADDRSTRLEN]; + char ip6bufd[INET6_ADDRSTRLEN]; nd6log(LOG_INFO, "packet to an unready address %s->%s\n", - ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst)); + IN6_PRINT(ip6bufs, &ip6->ip6_src), + IN6_PRINT(ip6bufd, &ip6->ip6_dst)); - goto bad; + goto bad_unref; } } @@ -571,7 +579,7 @@ ip6_input(struct mbuf *m, struct ifnet * if (!ip6_forwarding) { IP6_STATINC(IP6_STAT_CANTFORWARD); in6_ifstat_inc(rcvif, ifs6_in_discard); - goto bad; + goto bad_unref; } hbhcheck: @@ -610,6 +618,8 @@ ip6_input(struct mbuf *m, struct ifnet * #if 0 /*touches NULL pointer*/ in6_ifstat_inc(rcvif, ifs6_in_discard); #endif + rtcache_unref(rt, ro); + percpu_putref(ip6_forward_rt_percpu); return; /* m have already been freed */ } @@ -633,12 +643,16 @@ ip6_input(struct mbuf *m, struct ifnet * icmp6_error(m, ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER, (char *)&ip6->ip6_plen - (char *)ip6); + rtcache_unref(rt, ro); + percpu_putref(ip6_forward_rt_percpu); return; } IP6_EXTHDR_GET(hbh, struct ip6_hbh *, m, sizeof(struct ip6_hdr), sizeof(struct ip6_hbh)); if (hbh == NULL) { IP6_STATINC(IP6_STAT_TOOSHORT); + rtcache_unref(rt, ro); + percpu_putref(ip6_forward_rt_percpu); return; } KASSERT(IP6_HDR_ALIGNED_P(hbh)); @@ -662,7 +676,7 @@ ip6_input(struct mbuf *m, struct ifnet * if (m->m_pkthdr.len - sizeof(struct ip6_hdr) < plen) { IP6_STATINC(IP6_STAT_TOOSHORT); in6_ifstat_inc(rcvif, ifs6_in_truncated); - goto bad; + goto bad_unref; } if (m->m_pkthdr.len > sizeof(struct ip6_hdr) + plen) { if (m->m_len == m->m_pkthdr.len) { @@ -692,13 +706,17 @@ ip6_input(struct mbuf *m, struct ifnet * SOFTNET_UNLOCK(); if (error != 0) { + rtcache_unref(rt, ro); + percpu_putref(ip6_forward_rt_percpu); IP6_STATINC(IP6_STAT_CANTFORWARD); goto bad; } } if (!ours) - goto bad; + goto bad_unref; } else if (!ours) { + rtcache_unref(rt, ro); + percpu_putref(ip6_forward_rt_percpu); ip6_forward(m, srcrt); return; } @@ -718,7 +736,7 @@ ip6_input(struct mbuf *m, struct ifnet * IN6_IS_ADDR_V4MAPPED(&ip6->ip6_dst)) { IP6_STATINC(IP6_STAT_BADSCOPE); in6_ifstat_inc(rcvif, ifs6_in_addrerr); - goto bad; + goto bad_unref; } /* @@ -738,6 +756,12 @@ ip6_input(struct mbuf *m, struct ifnet * in6_ifstat_inc(deliverifp, ifs6_in_deliver); nest = 0; + if (rt != NULL) { + rtcache_unref(rt, ro); + rt = NULL; + } + percpu_putref(ip6_forward_rt_percpu); + rh_present = 0; while (nxt != IPPROTO_DONE) { if (ip6_hdrnestlimit && (++nest > ip6_hdrnestlimit)) { @@ -789,8 +813,13 @@ ip6_input(struct mbuf *m, struct ifnet * SOFTNET_UNLOCK(); } return; + + bad_unref: + rtcache_unref(rt, ro); + percpu_putref(ip6_forward_rt_percpu); bad: m_freem(m); + return; } /*