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;

Reply via email to