Index: sys/netinet/ip_output.c =================================================================== --- sys/netinet/ip_output.c +++ sys/netinet/ip_output.c @@ -227,7 +227,7 @@ struct route iproute; struct rtentry *rte; /* cache for ro->ro_rt */ uint32_t fibnum; - int have_ia_ref; + struct in_addr ia_addr; #ifdef IPSEC int no_route_but_check_spd = 0; #endif @@ -294,7 +294,7 @@ } again: ia = NULL; - have_ia_ref = 0; + ia_addr.s_addr = INADDR_ANY; /* * If routing to interface only, short circuit routing lookup. * The use of an all-ones broadcast address implies this; an @@ -310,10 +310,11 @@ error = ENETUNREACH; goto bad; } - have_ia_ref = 1; + ifp = ia->ia_ifp; + ia_addr = IA_SIN(ia)->sin_addr; + ifa_free(&ia->ia_ifa); ip->ip_dst.s_addr = INADDR_BROADCAST; dst->sin_addr = ip->ip_dst; - ifp = ia->ia_ifp; ip->ip_ttl = 1; isbroadcast = 1; } else if (flags & IP_ROUTETOIF) { @@ -325,8 +326,9 @@ error = ENETUNREACH; goto bad; } - have_ia_ref = 1; ifp = ia->ia_ifp; + ia_addr = IA_SIN(ia)->sin_addr; + ifa_free(&ia->ia_ifa); ip->ip_ttl = 1; isbroadcast = in_broadcast(dst->sin_addr, ifp); } else if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && @@ -337,8 +339,10 @@ */ ifp = imo->imo_multicast_ifp; IFP_TO_IA(ifp, ia, &in_ifa_tracker); - if (ia) - have_ia_ref = 1; + if (ia) { + ia_addr = IA_SIN(ia)->sin_addr; + ifa_free(&ia->ia_ifa); + } isbroadcast = 0; /* fool gcc */ } else { /* @@ -374,6 +378,8 @@ goto bad; } ia = ifatoia(rte->rt_ifa); + if (ia) + ia_addr = IA_SIN(ia)->sin_addr; ifp = rte->rt_ifp; counter_u64_add(rte->rt_pksent, 1); if (rte->rt_flags & RTF_GATEWAY) @@ -432,8 +438,7 @@ */ if (ip->ip_src.s_addr == INADDR_ANY) { /* Interface may have no addresses. */ - if (ia != NULL) - ip->ip_src = IA_SIN(ia)->sin_addr; + ip->ip_src = ia_addr; } if ((imo == NULL && in_mcast_loop) || @@ -499,9 +504,7 @@ */ if (ip->ip_src.s_addr == INADDR_ANY) { /* Interface may have no addresses. */ - if (ia != NULL) { - ip->ip_src = IA_SIN(ia)->sin_addr; - } + ip->ip_src = ia_addr; } /* @@ -565,8 +568,6 @@ case -1: /* Need to try again */ /* Reset everything for a new round */ RO_RTFREE(ro); - if (have_ia_ref) - ifa_free(&ia->ia_ifa); ro->ro_prepend = NULL; rte = NULL; gw = dst; @@ -610,21 +611,6 @@ m->m_pkthdr.csum_flags &= ~CSUM_IP; } - /* - * Record statistics for this interface address. - * With CSUM_TSO the byte/packet count will be slightly - * incorrect because we count the IP+TCP headers only - * once instead of for every generated packet. - */ - if (!(flags & IP_FORWARDING) && ia) { - if (m->m_pkthdr.csum_flags & CSUM_TSO) - counter_u64_add(ia->ia_ifa.ifa_opackets, - m->m_pkthdr.len / m->m_pkthdr.tso_segsz); - else - counter_u64_add(ia->ia_ifa.ifa_opackets, 1); - - counter_u64_add(ia->ia_ifa.ifa_obytes, m->m_pkthdr.len); - } #ifdef MBUF_STRESS_TEST if (mbuf_frag_size && m->m_pkthdr.len > mbuf_frag_size) m = m_fragment(m, M_NOWAIT, mbuf_frag_size); @@ -658,12 +644,7 @@ m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) { - /* Record statistics for this interface address. */ - if (ia != NULL) { - counter_u64_add(ia->ia_ifa.ifa_opackets, 1); - counter_u64_add(ia->ia_ifa.ifa_obytes, - m->m_pkthdr.len); - } + /* * Reset layer specific mbuf flags * to avoid confusing upper layers. @@ -690,8 +671,6 @@ * calling RTFREE on it again. */ ro->ro_rt = NULL; - if (have_ia_ref) - ifa_free(&ia->ia_ifa); return (error); bad: m_freem(m); Index: sys/netinet6/in6.h =================================================================== --- sys/netinet6/in6.h +++ sys/netinet6/in6.h @@ -663,6 +663,8 @@ int in6_addrscope(const struct in6_addr *); char *ip6_sprintf(char *, const struct in6_addr *); struct in6_ifaddr *in6_ifawithifp(struct ifnet *, struct in6_addr *); +void in6_accountoifa(struct ifnet *, const struct in6_addr *, + uint64_t, uint64_t); extern void in6_if_up(struct ifnet *); struct sockaddr; extern u_char ip6_protox[]; Index: sys/netinet6/in6.c =================================================================== --- sys/netinet6/in6.c +++ sys/netinet6/in6.c @@ -149,6 +149,8 @@ static int in6_broadcast_ifa(struct ifnet *, struct in6_aliasreq *, struct in6_ifaddr *, int); +static struct in6_ifaddr *in6_ifawithifp_locked(struct ifnet *, + const struct in6_addr *); #define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) #define ia62ifa(ia6) (&((ia6)->ia_ifa)) @@ -1748,11 +1750,12 @@ * hard coding... */ int -in6_matchlen(struct in6_addr *src, struct in6_addr *dst) +in6_matchlen(const struct in6_addr *src, const struct in6_addr *dst) { int match = 0; - u_char *s = (u_char *)src, *d = (u_char *)dst; - u_char *lim = s + 16, r; + const u_char *s = (const u_char *)src, *d = (const u_char *)dst; + const u_char *lim = s + 16; + u_char r; while (s < lim) if ((r = (*d++ ^ *s++)) != 0) { @@ -1818,8 +1821,8 @@ * return the best address out of the same scope. if no address was * found, return the first valid address from designated IF. */ -struct in6_ifaddr * -in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) +static struct in6_ifaddr * +in6_ifawithifp_locked(struct ifnet *ifp, const struct in6_addr *dst) { int dst_scope = in6_addrscope(dst), blen = -1, tlen; struct ifaddr *ifa; @@ -1834,7 +1837,6 @@ * If two or more, return one which matches the dst longest. * If none, return one of global addresses assigned other ifs. */ - IF_ADDR_RLOCK(ifp); TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) continue; @@ -1866,11 +1868,8 @@ besta = (struct in6_ifaddr *)ifa; } } - if (besta) { - ifa_ref(&besta->ia_ifa); - IF_ADDR_RUNLOCK(ifp); + if (besta) return (besta); - } TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { if (ifa->ifa_addr->sa_family != AF_INET6) @@ -1887,28 +1886,48 @@ continue; } - if (ifa != NULL) - ifa_ref(ifa); - IF_ADDR_RUNLOCK(ifp); return (struct in6_ifaddr *)ifa; } /* use the last-resort values, that are, deprecated addresses */ - if (dep[0]) { - ifa_ref((struct ifaddr *)dep[0]); - IF_ADDR_RUNLOCK(ifp); + if (dep[0]) return dep[0]; - } - if (dep[1]) { - ifa_ref((struct ifaddr *)dep[1]); - IF_ADDR_RUNLOCK(ifp); + if (dep[1]) return dep[1]; - } - IF_ADDR_RUNLOCK(ifp); return NULL; } +struct in6_ifaddr * +in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) +{ + struct in6_ifaddr *ia6; + + IF_ADDR_RLOCK(ifp); + ia6 = in6_ifawithifp_locked(ifp, dst); + if (ia6 != NULL) + ifa_ref(&ia6->ia_ifa); + IF_ADDR_RUNLOCK(ifp); + + return (ia6); +} + +void +in6_accountoifa(struct ifnet *ifp, const struct in6_addr *dst, + uint64_t opackets, uint64_t obytes) +{ + struct in6_ifaddr *ia6; + + IF_ADDR_RLOCK(ifp); + ia6 = in6_ifawithifp_locked(ifp, dst); + if (ia6 != NULL) { + counter_u64_add(ia6->ia_ifa.ifa_opackets, opackets); + counter_u64_add(ia6->ia_ifa.ifa_obytes, obytes); + } + IF_ADDR_RUNLOCK(ifp); +} + + /* * perform DAD when interface becomes IFF_UP. */ Index: sys/netinet6/in6_var.h =================================================================== --- sys/netinet6/in6_var.h +++ sys/netinet6/in6_var.h @@ -804,7 +804,7 @@ struct in6_ifaddr *in6ifa_ifwithaddr(const struct in6_addr *, uint32_t); struct in6_ifaddr *in6ifa_llaonifp(struct ifnet *); int in6_addr2zoneid(struct ifnet *, struct in6_addr *, u_int32_t *); -int in6_matchlen(struct in6_addr *, struct in6_addr *); +int in6_matchlen(const struct in6_addr *, const struct in6_addr *); int in6_are_prefix_equal(struct in6_addr *, struct in6_addr *, int); void in6_prefixlen2mask(struct in6_addr *, int); int in6_prefix_ioctl(struct socket *, u_long, caddr_t, Index: sys/netinet6/ip6_output.c =================================================================== --- sys/netinet6/ip6_output.c +++ sys/netinet6/ip6_output.c @@ -928,17 +928,9 @@ * transmit packet without fragmentation */ if (dontfrag || (!alwaysfrag && tlen <= mtu)) { /* case 1-a and 2-a */ - struct in6_ifaddr *ia6; - ip6 = mtod(m, struct ip6_hdr *); - ia6 = in6_ifawithifp(ifp, &ip6->ip6_src); - if (ia6) { - /* Record statistics for this interface address. */ - counter_u64_add(ia6->ia_ifa.ifa_opackets, 1); - counter_u64_add(ia6->ia_ifa.ifa_obytes, - m->m_pkthdr.len); - ifa_free(&ia6->ia_ifa); - } + + in6_accountoifa(ifp, &ip6->ip6_src, 1, m->m_pkthdr.len); error = nd6_output_ifp(ifp, origifp, m, dst, NULL); goto done; } @@ -1028,21 +1020,26 @@ m = m0->m_nextpkt; m0->m_nextpkt = 0; m_freem(m0); + uint64_t opackets = 0; + uint64_t obytes = 0; + ip6 = mtod(m, struct ip6_hdr *); + src0 = ip6->ip6_src; for (m0 = m; m; m = m0) { m0 = m->m_nextpkt; m->m_nextpkt = 0; if (error == 0) { - /* Record statistics for this interface address. */ - if (ia) { - counter_u64_add(ia->ia_ifa.ifa_opackets, 1); - counter_u64_add(ia->ia_ifa.ifa_obytes, - m->m_pkthdr.len); - } + opackets++; + obytes += m->m_pkthdr.len; error = nd6_output_ifp(ifp, origifp, m, dst, NULL); } else m_freem(m); } + ip6 = mtod(m, struct ip6_hdr *); + + /* Record statistics for this interface address. */ + in6_accountoifa(ifp, &src0, opackets, obytes); + if (error == 0) IP6STAT_INC(ip6s_fragmented);