From c02a77e9f86bdc6f4f3f3587167021e3fe55a401 Mon Sep 17 00:00:00 2001 From: eri Date: Thu, 2 Jul 2015 18:10:41 +0000 Subject: Avoid doing multiple route lookups for the same destination IP during forwarding ip_forward() does a route lookup for testing this packet can be sent to a known destination, it also can do another route lookup if it detects that an ICMP redirect is needed, it forgets all of this and handovers to ip_output() to do the same lookup yet again. This optimisation just does one route lookup during the forwarding path and handovers that to be considered by ip_output(). Differential Revision: https://reviews.freebsd.org/D2964 Approved by: ae, gnn(mentor) MFC after: 1 week --- sys/netinet/ip_input.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'sys/netinet/ip_input.c') diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index f4b6dfc..49e8b42 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -897,6 +897,7 @@ ip_forward(struct mbuf *m, int srcrt) struct ip *ip = mtod(m, struct ip *); struct in_ifaddr *ia; struct mbuf *mcopy; + struct sockaddr_in *sin; struct in_addr dest; struct route ro; int error, type = 0, code = 0, mtu = 0; @@ -925,7 +926,22 @@ ip_forward(struct mbuf *m, int srcrt) } #endif - ia = ip_rtaddr(ip->ip_dst, M_GETFIB(m)); + bzero(&ro, sizeof(ro)); + sin = (struct sockaddr_in *)&ro.ro_dst; + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + sin->sin_addr = ip->ip_dst; +#ifdef RADIX_MPATH + rtalloc_mpath_fib(&ro, + ntohl(ip->ip_src.s_addr ^ ip->ip_dst.s_addr), + M_GETFIB(m)); +#else + in_rtalloc_ign(&ro, 0, M_GETFIB(m)); +#endif + if (ro.ro_rt != NULL) { + ia = ifatoia(ro.ro_rt->rt_ifa); + ifa_ref(&ia->ia_ifa); + } #ifndef IPSEC /* * 'ia' may be NULL if there is no route for this destination. @@ -934,6 +950,7 @@ ip_forward(struct mbuf *m, int srcrt) */ if (!srcrt && ia == NULL) { icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); + RO_RTFREE(&ro); return; } #endif @@ -990,16 +1007,8 @@ ip_forward(struct mbuf *m, int srcrt) dest.s_addr = 0; if (!srcrt && V_ipsendredirects && ia != NULL && ia->ia_ifp == m->m_pkthdr.rcvif) { - struct sockaddr_in *sin; struct rtentry *rt; - bzero(&ro, sizeof(ro)); - sin = (struct sockaddr_in *)&ro.ro_dst; - sin->sin_family = AF_INET; - sin->sin_len = sizeof(*sin); - sin->sin_addr = ip->ip_dst; - in_rtalloc_ign(&ro, 0, M_GETFIB(m)); - rt = ro.ro_rt; if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 && @@ -1018,16 +1027,8 @@ ip_forward(struct mbuf *m, int srcrt) code = ICMP_REDIRECT_HOST; } } - if (rt) - RTFREE(rt); } - /* - * Try to cache the route MTU from ip_output so we can consider it for - * the ICMP_UNREACH_NEEDFRAG "Next-Hop MTU" field described in RFC1191. - */ - bzero(&ro, sizeof(ro)); - error = ip_output(m, NULL, &ro, IP_FORWARDING, NULL, NULL); if (error == EMSGSIZE && ro.ro_rt) -- cgit v1.1