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;