Diff below makes ip_forward() use the route entry fetched in in_ouraddr().

As you can imagine a proper caching could be done for forwarding using
PF statekey.

This diff has been tested by Hrvoje Popovski who confirmed that the
benchmark performances are similar to the ones using a single cache
entry.

ok?


Index: netinet/ip_input.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.274
diff -u -p -r1.274 ip_input.c
--- netinet/ip_input.c  25 Apr 2016 12:33:48 -0000      1.274
+++ netinet/ip_input.c  25 Apr 2016 12:34:46 -0000
@@ -126,8 +126,8 @@ static struct mbuf_queue    ipsend_mq;
 
 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);
+int    in_ouraddr(struct mbuf *, struct ifnet *, struct rtentry **);
+void   ip_forward(struct mbuf *, struct ifnet *, struct rtentry *, int);
 #ifdef IPSEC
 int    ip_input_ipsec_fwd_check(struct mbuf *, int);
 int    ip_input_ipsec_ours_check(struct mbuf *, int);
@@ -223,8 +223,9 @@ ipintr(void)
 void
 ipv4_input(struct mbuf *m)
 {
-       struct ifnet *ifp;
-       struct ip *ip;
+       struct ifnet    *ifp;
+       struct rtentry  *rt = NULL;
+       struct ip       *ip;
        int hlen, len;
 #if defined(MROUTING) || defined(IPSEC)
        int rv;
@@ -341,7 +342,7 @@ ipv4_input(struct mbuf *m)
                goto out;
        }
 
-       if (in_ouraddr(m, ifp, ip->ip_dst)) {
+       if (in_ouraddr(m, ifp, &rt)) {
                ip_ours(m);
                goto out;
        }
@@ -443,12 +444,13 @@ ipv4_input(struct mbuf *m)
        }
 #endif /* IPSEC */
 
-       ip_forward(m, ifp, pfrdr);
+       ip_forward(m, ifp, rt, pfrdr);
        if_put(ifp);
        return;
 bad:
        m_freem(m);
 out:
+       rtfree(rt);
        if_put(ifp);
 }
 
@@ -575,9 +577,10 @@ bad:
 }
 
 int
-in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct in_addr ina)
+in_ouraddr(struct mbuf *m, struct ifnet *ifp, struct rtentry **prt)
 {
        struct rtentry          *rt;
+       struct ip               *ip;
        struct sockaddr_in       sin;
        int                      match = 0;
 #if NPF > 0
@@ -597,10 +600,12 @@ in_ouraddr(struct mbuf *m, struct ifnet 
        }
 #endif
 
+       ip = mtod(m, struct ip *);
+
        memset(&sin, 0, sizeof(sin));
        sin.sin_len = sizeof(sin);
        sin.sin_family = AF_INET;
-       sin.sin_addr = ina;
+       sin.sin_addr = ip->ip_dst;
        rt = rtalloc(sintosa(&sin), 0, m->m_pkthdr.ph_rtableid);
        if (rtisvalid(rt)) {
                if (ISSET(rt->rt_flags, RTF_LOCAL))
@@ -618,7 +623,7 @@ in_ouraddr(struct mbuf *m, struct ifnet 
                        m->m_flags |= M_BCAST;
                }
        }
-       rtfree(rt);
+       *prt = rt;
 
        if (!match) {
                struct ifaddr *ifa;
@@ -630,7 +635,7 @@ in_ouraddr(struct mbuf *m, struct ifnet 
                 * address on the interface it was received on.
                 */
                if (!ISSET(m->m_flags, M_BCAST) ||
-                   !IN_CLASSFULBROADCAST(ina.s_addr, ina.s_addr))
+                   !IN_CLASSFULBROADCAST(ip->ip_dst.s_addr, ip->ip_dst.s_addr))
                        return (0);
 
                if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid))
@@ -645,7 +650,7 @@ in_ouraddr(struct mbuf *m, struct ifnet 
                        if (ifa->ifa_addr->sa_family != AF_INET)
                                continue;
 
-                       if (IN_CLASSFULBROADCAST(ina.s_addr,
+                       if (IN_CLASSFULBROADCAST(ip->ip_dst.s_addr,
                            ifatoia(ifa)->ia_addr.sin_addr.s_addr)) {
                                match = 1;
                                break;
@@ -1241,7 +1246,7 @@ ip_dooptions(struct mbuf *m, struct ifne
        }
        KERNEL_UNLOCK();
        if (forward && ipforwarding) {
-               ip_forward(m, ifp, 1);
+               ip_forward(m, ifp, NULL, 1);
                return (1);
        }
        return (0);
@@ -1387,12 +1392,11 @@ int inetctlerrmap[PRC_NCMDS] = {
  * via a source route.
  */
 void
-ip_forward(struct mbuf *m, struct ifnet *ifp, int srcrt)
+ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt)
 {
        struct mbuf mfake, *mcopy = NULL;
        struct ip *ip = mtod(m, struct ip *);
        struct sockaddr_in *sin;
-       struct rtentry *rt;
        struct route ro;
        int error, type = 0, code = 0, destmtu = 0, fake = 0, len;
        u_int32_t dest;
@@ -1401,25 +1405,27 @@ ip_forward(struct mbuf *m, struct ifnet 
        if (m->m_flags & (M_BCAST|M_MCAST) || in_canforward(ip->ip_dst) == 0) {
                ipstat.ips_cantforward++;
                m_freem(m);
-               return;
+               goto freecopy;
        }
        if (ip->ip_ttl <= IPTTLDEC) {
                icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS, dest, 0);
-               return;
+               goto freecopy;
        }
 
-
        sin = satosin(&ro.ro_dst);
        memset(sin, 0, sizeof(*sin));
        sin->sin_family = AF_INET;
        sin->sin_len = sizeof(*sin);
        sin->sin_addr = ip->ip_dst;
 
-       rt = rtalloc_mpath(sintosa(sin), &ip->ip_src.s_addr,
-           m->m_pkthdr.ph_rtableid);
-       if (rt == NULL) {
-               icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
-               return;
+       if (!rtisvalid(rt)) {
+               rtfree(rt);
+               rt = rtalloc_mpath(sintosa(sin), &ip->ip_src.s_addr,
+                   m->m_pkthdr.ph_rtableid);
+               if (rt == NULL) {
+                       icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
+                       return;
+               }
        }
 
        /*

Reply via email to