Now that the routing table contains all the information required to do address lookups, here's a diff to stop using it.
This diff contains three independent chunks. - The first one "reverts" the internals of ifa_ifwithaddr() to iterate on the global list of interfaces (&ifnet). I didn't replace the internals of this function because I don't want to use it in the interrupt path. - The second chunk replaces a lookup on the IPv4 list of addresses. - And the third one substitutes the ifa_ifwithaddr() call in the hot path. Using the routing table directly there, will let us reduce the number of lookups to 1 in the forwarding case. One this is in and stable I'll send a diff to remove the RB-tree. Ok? Index: net/if.c =================================================================== RCS file: /home/ncvs/src/sys/net/if.c,v retrieving revision 1.300 diff -u -p -r1.300 if.c --- net/if.c 25 Aug 2014 14:00:34 -0000 1.300 +++ net/if.c 23 Sep 2014 08:44:05 -0000 @@ -840,25 +840,39 @@ if_congestion_clear(void *arg) /* * Locate an interface based on a complete address. */ -/*ARGSUSED*/ struct ifaddr * ifa_ifwithaddr(struct sockaddr *addr, u_int rtableid) { - struct ifaddr_item *ifai, key; - - bzero(&key, sizeof(key)); - key.ifai_addr = addr; - key.ifai_rdomain = rtable_l2(rtableid); - - ifai = RB_FIND(ifaddr_items, &ifaddr_items, &key); - if (ifai) - return (ifai->ifai_ifa); - return (NULL); -} + struct ifnet *ifp; + struct ifaddr *ifa; + u_int rdomain; #define equal(a1, a2) \ (bcmp((caddr_t)(a1), (caddr_t)(a2), \ ((struct sockaddr *)(a1))->sa_len) == 0) + + rdomain = rtable_l2(rtableid); + TAILQ_FOREACH(ifp, &ifnet, if_list) { + if (ifp->if_rdomain != rdomain) + continue; + + TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) { + if (ifa->ifa_addr->sa_family != addr->sa_family) + continue; + + if (equal(addr, ifa->ifa_addr)) + return (ifa); + + /* IP6 doesn't have broadcast */ + if ((ifp->if_flags & IFF_BROADCAST) && + ifa->ifa_broadaddr && + ifa->ifa_broadaddr->sa_len != 0 && + equal(ifa->ifa_broadaddr, addr)) + return (ifa); + } + } + return (NULL); +} /* * Locate the point to point interface with a given destination address. Index: netinet/ip_icmp.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_icmp.c,v retrieving revision 1.124 diff -u -p -r1.124 ip_icmp.c --- netinet/ip_icmp.c 14 Sep 2014 14:17:26 -0000 1.124 +++ netinet/ip_icmp.c 23 Sep 2014 08:44:05 -0000 @@ -686,9 +686,11 @@ int icmp_reflect(struct mbuf *m, struct mbuf **op, struct in_ifaddr *ia) { struct ip *ip = mtod(m, struct ip *); - struct in_addr t; struct mbuf *opts = 0; + struct sockaddr_in sin; + struct rtentry *rt; int optlen = (ip->ip_hl << 2) - sizeof(struct ip); + u_int rtableid; if (!in_canforward(ip->ip_src) && ((ip->ip_src.s_addr & IN_CLASSA_NET) != @@ -700,58 +702,53 @@ icmp_reflect(struct mbuf *m, struct mbuf #if NPF > 0 pf_pkt_addr_changed(m); #endif - t = ip->ip_dst; - ip->ip_dst = ip->ip_src; + rtableid = m->m_pkthdr.ph_rtableid; + /* * If the incoming packet was addressed directly to us, * use dst as the src for the reply. For broadcast, use * the address which corresponds to the incoming interface. */ if (ia == NULL) { - TAILQ_FOREACH(ia, &in_ifaddr, ia_list) { - if (ia->ia_ifp->if_rdomain != - rtable_l2(m->m_pkthdr.ph_rtableid)) - continue; - if (t.s_addr == ia->ia_addr.sin_addr.s_addr) - break; - if ((ia->ia_ifp->if_flags & IFF_BROADCAST) && - ia->ia_broadaddr.sin_addr.s_addr != 0 && - t.s_addr == ia->ia_broadaddr.sin_addr.s_addr) - break; + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_addr = ip->ip_dst; + + rt = rtalloc1(sintosa(&sin), 0, rtableid); + if (rt != NULL) { + if (rt->rt_flags & (RTF_LOCAL|RTF_BROADCAST)) + ia = ifatoia(rt->rt_ifa); + rtfree(rt); } } + /* * The following happens if the packet was not addressed to us. * Use the new source address and do a route lookup. If it fails * drop the packet as there is no path to the host. */ if (ia == NULL) { - struct sockaddr_in *dst; - struct route ro; - - memset(&ro, 0, sizeof(ro)); - ro.ro_tableid = m->m_pkthdr.ph_rtableid; - dst = satosin(&ro.ro_dst); - dst->sin_family = AF_INET; - dst->sin_len = sizeof(*dst); - dst->sin_addr = ip->ip_src; + memset(&sin, 0, sizeof(sin)); + sin.sin_len = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_addr = ip->ip_src; /* keep packet in the original virtual instance */ - ro.ro_rt = rtalloc1(&ro.ro_dst, RT_REPORT, - m->m_pkthdr.ph_rtableid); - if (ro.ro_rt == 0) { + rt = rtalloc1(sintosa(&sin), RT_REPORT, rtableid); + if (rt == NULL) { ipstat.ips_noroute++; m_freem(m); return (EHOSTUNREACH); } - ia = ifatoia(ro.ro_rt->rt_ifa); - ro.ro_rt->rt_use++; - RTFREE(ro.ro_rt); + ia = ifatoia(rt->rt_ifa); + rt->rt_use++; + rtfree(rt); } - t = ia->ia_addr.sin_addr; - ip->ip_src = t; + ip->ip_dst = ip->ip_src; + ip->ip_src = ia->ia_addr.sin_addr; ip->ip_ttl = MAXTTL; if (optlen > 0) { Index: netinet/ip_input.c =================================================================== RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v retrieving revision 1.235 diff -u -p -r1.235 ip_input.c --- netinet/ip_input.c 13 Jul 2014 13:57:56 -0000 1.235 +++ netinet/ip_input.c 23 Sep 2014 08:44:05 -0000 @@ -643,7 +643,8 @@ bad: int in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct in_addr ina) { - struct in_ifaddr *ia; + struct in_ifaddr *ia = NULL; + struct rtentry *rt; struct sockaddr_in sin; #if NPF > 0 struct pf_state_key *key; @@ -666,7 +667,12 @@ in_ouraddr(struct mbuf *m, struct ifnet sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_addr = ina; - ia = ifatoia(ifa_ifwithaddr(sintosa(&sin), m->m_pkthdr.ph_rtableid)); + rt = rtalloc1(sintosa(&sin), 0, m->m_pkthdr.ph_rtableid); + if (rt != NULL) { + if (rt->rt_flags & (RTF_LOCAL|RTF_BROADCAST)) + ia = ifatoia(rt->rt_ifa); + rtfree(rt); + } if (ia == NULL) { struct ifaddr *ifa;