Module Name: src Committed By: christos Date: Mon Dec 8 00:19:37 UTC 2014
Modified Files: src/sys/netinet6: ip6_forward.c Log Message: Merge some common code in the failed forwarding case, while providing better diagnostics, and fixing leaks. To generate a diff of this commit: cvs rdiff -u -r1.74 -r1.75 src/sys/netinet6/ip6_forward.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet6/ip6_forward.c diff -u src/sys/netinet6/ip6_forward.c:1.74 src/sys/netinet6/ip6_forward.c:1.75 --- src/sys/netinet6/ip6_forward.c:1.74 Fri Nov 14 12:34:23 2014 +++ src/sys/netinet6/ip6_forward.c Sun Dec 7 19:19:37 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: ip6_forward.c,v 1.74 2014/11/14 17:34:23 maxv Exp $ */ +/* $NetBSD: ip6_forward.c,v 1.75 2014/12/08 00:19:37 christos Exp $ */ /* $KAME: ip6_forward.c,v 1.109 2002/09/11 08:10:17 sakane Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.74 2014/11/14 17:34:23 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ip6_forward.c,v 1.75 2014/12/08 00:19:37 christos Exp $"); #include "opt_gateway.h" #include "opt_ipsec.h" @@ -74,6 +74,39 @@ struct route ip6_forward_rt; extern pfil_head_t *inet6_pfil_hook; /* XXX */ +static void +ip6_cantforward(const struct ip6_hdr *ip6, const struct ifnet *srcifp, + const struct ifnet *dstifp, const char *fmt, ...) +{ + char sbuf[INET6_ADDRSTRLEN], dbuf[INET6_ADDRSTRLEN]; + char reason[256]; + va_list ap; + uint64_t *ip6s; + + /* update statistics */ + ip6s = IP6_STAT_GETREF(); + ip6s[IP6_STAT_CANTFORWARD]++; + if (dstifp) + ip6s[IP6_STAT_BADSCOPE]++; + IP6_STAT_PUTREF(); + + if (dstifp) + in6_ifstat_inc(dstifp, ifs6_in_discard); + + if (ip6_log_time + ip6_log_interval >= time_second) + return; + ip6_log_time = time_second; + + va_start(ap, fmt); + snprintf(reason, sizeof(reason), fmt, ap); + va_end(ap); + + log(LOG_DEBUG, "Cannot forward from %s@%s to %s@%s nxt %d (%s)\n", + IN6_PRINT(sbuf, &ip6->ip6_src), srcifp ? if_name(srcifp) : "?", + IN6_PRINT(dbuf, &ip6->ip6_dst), dstifp ? if_name(dstifp) : "?", + ip6->ip6_nxt, reason); +} + /* * Forward a packet. If some error occurs return the sender * an icmp packet. Note we can't always generate a meaningful @@ -96,7 +129,7 @@ ip6_forward(struct mbuf *m, int srcrt) int error = 0, type = 0, code = 0; struct mbuf *mcopy = NULL; struct ifnet *origifp; /* maybe unnecessary */ - u_int32_t inzone, outzone; + uint32_t inzone, outzone; struct in6_addr src_in6, dst_in6; #ifdef IPSEC int needipsec = 0; @@ -117,18 +150,10 @@ ip6_forward(struct mbuf *m, int srcrt) if ((m->m_flags & (M_BCAST|M_MCAST)) != 0 || IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) || IN6_IS_ADDR_UNSPECIFIED(&ip6->ip6_src)) { - IP6_STATINC(IP6_STAT_CANTFORWARD); - /* XXX in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard) */ - if (ip6_log_time + ip6_log_interval < time_second) { - ip6_log_time = time_second; - log(LOG_DEBUG, - "cannot forward " - "from %s to %s nxt %d received on %s\n", - ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst), - ip6->ip6_nxt, - if_name(m->m_pkthdr.rcvif)); - } + ip6_cantforward(ip6, m->m_pkthdr.rcvif, NULL, + ((m->m_flags & (M_BCAST|M_MCAST)) != 0) ? "bcast/mcast" : + IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ? "mcast/dst" : + "unspec/src"); m_freem(m); return; } @@ -215,46 +240,19 @@ ip6_forward(struct mbuf *m, int srcrt) * [draft-ietf-ipngwg-icmp-v3-07, Section 3.1] */ src_in6 = ip6->ip6_src; - if (in6_setscope(&src_in6, rt->rt_ifp, &outzone)) { - /* XXX: this should not happen */ - uint64_t *ip6s = IP6_STAT_GETREF(); - ip6s[IP6_STAT_CANTFORWARD]++; - ip6s[IP6_STAT_BADSCOPE]++; - IP6_STAT_PUTREF(); - m_freem(m); - return; - } - if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) { - uint64_t *ip6s = IP6_STAT_GETREF(); - ip6s[IP6_STAT_CANTFORWARD]++; - ip6s[IP6_STAT_BADSCOPE]++; - IP6_STAT_PUTREF(); - m_freem(m); - return; - } - if (inzone != outzone) { - uint64_t *ip6s = IP6_STAT_GETREF(); - ip6s[IP6_STAT_CANTFORWARD]++; - ip6s[IP6_STAT_BADSCOPE]++; - IP6_STAT_PUTREF(); - in6_ifstat_inc(rt->rt_ifp, ifs6_in_discard); - - if (ip6_log_time + ip6_log_interval < time_second) { - ip6_log_time = time_second; - log(LOG_DEBUG, - "cannot forward " - "src %s, dst %s, nxt %d, rcvif %s, outif %s\n", - ip6_sprintf(&ip6->ip6_src), - ip6_sprintf(&ip6->ip6_dst), - ip6->ip6_nxt, - if_name(m->m_pkthdr.rcvif), if_name(rt->rt_ifp)); - } + inzone = outzone = ~0; + if (in6_setscope(&src_in6, rt->rt_ifp, &outzone) != 0 || + in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone) != 0 || + inzone != outzone) { + ip6_cantforward(ip6, m->m_pkthdr.rcvif, rt->rt_ifp, + "src inzone %d outzone %d", inzone, outzone); if (mcopy) icmp6_error(mcopy, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE, 0); m_freem(m); return; } + #ifdef IPSEC /* * If we need to encapsulate the packet, do it here @@ -277,13 +275,15 @@ ip6_forward(struct mbuf *m, int srcrt) * packet to a different zone by (e.g.) a default route. */ dst_in6 = ip6->ip6_dst; + inzone = outzone = ~0; if (in6_setscope(&dst_in6, m->m_pkthdr.rcvif, &inzone) != 0 || in6_setscope(&dst_in6, rt->rt_ifp, &outzone) != 0 || inzone != outzone) { - uint64_t *ip6s = IP6_STAT_GETREF(); - ip6s[IP6_STAT_CANTFORWARD]++; - ip6s[IP6_STAT_BADSCOPE]++; - IP6_STAT_PUTREF(); + ip6_cantforward(ip6, m->m_pkthdr.rcvif, rt->rt_ifp, + "dst inzone %d outzone %d", inzone, outzone); + if (mcopy) + icmp6_error(mcopy, ICMP6_DST_UNREACH, + ICMP6_DST_UNREACH_BEYONDSCOPE, 0); m_freem(m); return; }