In order to do *only one* route lookup without using a global variable
(yes, I'm looking at you netinet6) and without doing too much spaghetti,
here's a refactoring of ip_input().

It basically merges in_ouraddr() into ip_input(), but some operations
are shuffled, when possible, to reduces differences with the IPv6
version.

It also increments rt_use counters for the local routes, (say yeah!).

Comment, bikeshed, ok?

Index: netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.240
diff -u -p -r1.240 ip_input.c
--- netinet/ip_input.c  4 Nov 2014 15:24:40 -0000       1.240
+++ netinet/ip_input.c  5 Nov 2014 13:52:25 -0000
@@ -123,7 +123,6 @@ struct ipstat ipstat;
 
 void   ip_ours(struct mbuf *);
 int    ip_dooptions(struct mbuf *, struct ifnet *);
-int    in_ouraddr(struct mbuf *, struct ifnet *, struct in_addr);
 void   ip_forward(struct mbuf *, struct ifnet *, int);
 
 /*
@@ -222,6 +221,8 @@ ipintr(void)
 void
 ipv4_input(struct mbuf *m)
 {
+       struct sockaddr_in sin;
+       struct rtentry *rt;
        struct ifnet *ifp;
        struct ip *ip;
        int hlen, len;
@@ -341,11 +342,25 @@ ipv4_input(struct mbuf *m)
                return;
        }
 
-       if (in_ouraddr(m, ifp, ip->ip_dst)) {
+       if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
+           ip->ip_dst.s_addr == INADDR_ANY) {
+               ip_ours(m);
+               return;
+       }
+
+#if NPF > 0
+       /* No need for a route lookup if we already know it's for us. */
+       if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED ||
+           (m->m_pkthdr.pf.statekey && m->m_pkthdr.pf.statekey->inp)) {
                ip_ours(m);
                return;
        }
 
+       /* If we have linked state keys it is certainly forwarded. */
+       if (m->m_pkthdr.pf.statekey && m->m_pkthdr.pf.statekey->reverse)
+               goto forward;
+#endif
+
        if (IN_MULTICAST(ip->ip_dst.s_addr)) {
                struct in_multi *inm;
 #ifdef MROUTING
@@ -401,12 +416,79 @@ ipv4_input(struct mbuf *m)
                return;
        }
 
-       if (ip->ip_dst.s_addr == INADDR_BROADCAST ||
-           ip->ip_dst.s_addr == INADDR_ANY) {
-               ip_ours(m);
-               return;
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_len = sizeof(sin);
+       sin.sin_family = AF_INET;
+       sin.sin_addr = ip->ip_dst;
+
+       rt = rtalloc(sintosa(&sin), 0, m->m_pkthdr.ph_rtableid);
+       if (rt != NULL) {
+               /*
+                * We consider a packet as local if its destination
+                * matches a local route and the associated interface
+                * is up.
+                */
+               if (ISSET(rt->rt_flags, RTF_LOCAL)) {
+                       /*
+                        * XXX Since local routes' rt_ifp points to lo0
+                        * we cannot rely on the rtentry flags.
+                        */
+                       if (ISSET(rt->rt_ifa->ifa_ifp->if_flags, IFF_UP)) {
+                               rt->rt_use++;
+                               rtfree(rt);
+                               ip_ours(m);
+                               return;
+                       }
+               }
+
+               /*
+                * This matches a broadcast address on one of our interfaces.
+                * If directedbcast is enabled we only consider it local if it
+                * is received on the interface with that address.
+                */
+               if (ISSET(rt->rt_flags, RTF_BROADCAST) &&
+                   ISSET(rt->rt_flags, RTF_UP) &&
+                   (!ip_directedbcast || rt->rt_ifp == ifp)) {
+                       rt->rt_use++;
+                       rtfree(rt);
+
+                       /* Make sure M_BCAST is set */
+                       m->m_flags |= M_BCAST;
+                       ip_ours(m);
+                       return;
+               }
+
+               rtfree(rt);
+       }
+
+       /*
+        * No local address or broadcast address found, so check for
+        * ancient classful broadcast addresses.
+        * It must have been broadcast on the link layer, and for an
+        * address on the interface it was received on.
+        */
+       if (ISSET(m->m_flags, M_BCAST) &&
+           IN_CLASSFULBROADCAST(ip->ip_dst.s_addr, ip->ip_dst.s_addr)) {
+               struct ifaddr *ifa;
+
+               /*
+                * The check in the loop assumes you only rx a packet
+                * on an UP interface, and that M_BCAST will only be
+                * set on a BROADCAST interface.
+                */
+               TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
+                       if (ifa->ifa_addr->sa_family != AF_INET)
+                               continue;
+
+                       if (IN_CLASSFULBROADCAST(ip->ip_dst.s_addr,
+                           ifatoia(ifa)->ia_addr.sin_addr.s_addr)) {
+                               ip_ours(m);
+                               return;
+                       }
+               }
        }
 
+forward:
 #if NCARP > 0
        if (ifp->if_type == IFT_CARP && ip->ip_p == IPPROTO_ICMP &&
            carp_lsdrop(m, AF_INET, &ip->ip_src.s_addr, &ip->ip_dst.s_addr))
@@ -636,89 +718,6 @@ found:
        return;
 bad:
        m_freem(m);
-}
-
-int
-in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct in_addr ina)
-{
-       struct in_ifaddr        *ia = NULL;
-       struct rtentry          *rt;
-       struct sockaddr_in       sin;
-#if NPF > 0
-       struct pf_state_key     *key;
-
-       if (m->m_pkthdr.pf.flags & PF_TAG_DIVERTED)
-               return (1);
-
-       key = m->m_pkthdr.pf.statekey;
-       if (key != NULL) {
-               if (key->inp != NULL)
-                       return (1);
-
-               /* If we have linked state keys it is certainly forwarded. */
-               if (key->reverse != NULL)
-                       return (0);
-       }
-#endif
-
-       memset(&sin, 0, sizeof(sin));
-       sin.sin_len = sizeof(sin);
-       sin.sin_family = AF_INET;
-       sin.sin_addr = ina;
-       rt = rtalloc(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;
-
-               /*
-                * No local address or broadcast address found, so check for
-                * ancient classful broadcast addresses.
-                * It must have been broadcast on the link layer, and for an
-                * address on the interface it was received on.
-                */
-               if (!ISSET(m->m_flags, M_BCAST) ||
-                   !IN_CLASSFULBROADCAST(ina.s_addr, ina.s_addr))
-                       return (0);
-
-               if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid))
-                       return (0);
-               /*
-                * The check in the loop assumes you only rx a packet on an UP
-                * interface, and that M_BCAST will only be set on a BROADCAST
-                * interface.
-                */
-               TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
-                       if (ifa->ifa_addr->sa_family != AF_INET)
-                               continue;
-
-                       if (IN_CLASSFULBROADCAST(ina.s_addr,
-                           ifatoia(ifa)->ia_addr.sin_addr.s_addr))
-                               return (1);
-               }
-
-               return (0);
-       }
-
-       if (ina.s_addr != ia->ia_addr.sin_addr.s_addr) {
-               /*
-                * This matches a broadcast address on one of our interfaces.
-                * If directedbcast is enabled we only consider it local if it
-                * is received on the interface with that address.
-                */
-               if (ip_directedbcast && ia->ia_ifp != ifp)
-                       return (0);
-
-               /* Make sure M_BCAST is set */
-               if (m)
-                       m->m_flags |= M_BCAST;
-       }
-
-       return (ISSET(ia->ia_ifp->if_flags, IFF_UP));
 }
 
 struct in_ifaddr *

Reply via email to