Back in the old cool days you could simply call ether_output() with a
stuffed sockaddr and it will do the L2 resolution for you...  Well as
long as you do not care about IPv6 it's true.

During the last years I tried to reduce the number of places where
ether_output() was called without passing it a "struct rtentry" as
last argument.  The reason for this move is to remove a potential
route insertion in arpresolve(), done in read-only context (hot path).

Diff below convert the last offender explicitly passing NULL to an
if_output() function: pf_route().

I'm interested in tests but keep in mind that it is highly probable
that some code paths still path a NULL pointer as last argument, if
rtalloc(9) fails and its return is not checked.  That's why I added
a KASSERT(), to fix these cases.

Index: net/if_ethersubr.c
===================================================================
RCS file: /cvs/src/sys/net/if_ethersubr.c,v
retrieving revision 1.236
diff -u -p -r1.236 if_ethersubr.c
--- net/if_ethersubr.c  18 May 2016 20:15:14 -0000      1.236
+++ net/if_ethersubr.c  18 May 2016 20:45:47 -0000
@@ -193,8 +193,12 @@ ether_output(struct ifnet *ifp, struct m
        struct mbuf *mcopy = NULL;
        struct ether_header *eh;
        struct arpcom *ac = (struct arpcom *)ifp;
+       sa_family_t af = dst->sa_family;
        int error = 0;
 
+       KASSERT(rt != NULL || ISSET(m->m_flags, M_MCAST|M_BCAST) ||
+               af == AF_UNSPEC || af == pseudo_AF_HDRCMPLT);
+
 #ifdef DIAGNOSTIC
        if (ifp->if_rdomain != rtable_l2(m->m_pkthdr.ph_rtableid)) {
                printf("%s: trying to send packet on wrong domain. "
@@ -208,7 +212,7 @@ ether_output(struct ifnet *ifp, struct m
        if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
                senderr(ENETDOWN);
 
-       switch (dst->sa_family) {
+       switch (af) {
        case AF_INET:
                error = arpresolve(ifp, rt, m, dst, edst);
                if (error)
Index: net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.970
diff -u -p -r1.970 pf.c
--- net/pf.c    3 May 2016 12:13:38 -0000       1.970
+++ net/pf.c    18 May 2016 20:45:49 -0000
@@ -5574,6 +5574,12 @@ pf_route(struct mbuf **m, struct pf_rule
                                    s->rt_addr.v4.s_addr;
                        ifp = s->rt_kif ? s->rt_kif->pfik_ifp : NULL;
                }
+
+               rt = rtalloc(sintosa(dst), RT_RESOLVE, rtableid);
+               if (rt == NULL) {
+                       ipstat.ips_noroute++;
+                       goto bad;
+               }
        }
        if (ifp == NULL)
                goto bad;
@@ -5602,7 +5608,7 @@ pf_route(struct mbuf **m, struct pf_rule
                        ipstat.ips_outswcsum++;
                        ip->ip_sum = in_cksum(m0, ip->ip_hl << 2);
                }
-               error = ifp->if_output(ifp, m0, sintosa(dst), NULL);
+               error = ifp->if_output(ifp, m0, sintosa(dst), rt);
                goto done;
        }
 
@@ -5631,7 +5637,7 @@ pf_route(struct mbuf **m, struct pf_rule
                m1 = m0->m_nextpkt;
                m0->m_nextpkt = 0;
                if (error == 0)
-                       error = ifp->if_output(ifp, m0, sintosa(dst), NULL);
+                       error = ifp->if_output(ifp, m0, sintosa(dst), rt);
                else
                        m_freem(m0);
        }
Index: netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.207
diff -u -p -r1.207 if_ether.c
--- netinet/if_ether.c  18 May 2016 20:15:14 -0000      1.207
+++ netinet/if_ether.c  18 May 2016 20:45:50 -0000
@@ -294,40 +294,28 @@ arpresolve(struct ifnet *ifp, struct rte
                return (0);
        }
 
-       if (rt0 != NULL) {
-               error = rt_checkgate(rt0, &rt);
-               if (error) {
-                       m_freem(m);
-                       return (error);
-               }
+       error = rt_checkgate(rt0, &rt);
+       if (error) {
+               m_freem(m);
+               return (error);
+       }
 
-               if ((rt->rt_flags & RTF_LLINFO) == 0) {
-                       log(LOG_DEBUG, "%s: %s: route contains no arp"
-                           " information\n", __func__, inet_ntop(AF_INET,
-                               &satosin(rt_key(rt))->sin_addr, addr,
-                               sizeof(addr)));
-                       m_freem(m);
-                       return (EINVAL);
-               }
+       if ((rt->rt_flags & RTF_LLINFO) == 0) {
+               log(LOG_DEBUG, "%s: %s: route contains no arp"
+                   " information\n", __func__, inet_ntop(AF_INET,
+                       &satosin(rt_key(rt))->sin_addr, addr,
+                       sizeof(addr)));
+               m_freem(m);
+               return (EINVAL);
+       }
 
-               la = (struct llinfo_arp *)rt->rt_llinfo;
-               if (la == NULL)
-                       log(LOG_DEBUG, "%s: %s: route without link "
-                           "local address\n", __func__, inet_ntop(AF_INET,
-                               &satosin(dst)->sin_addr, addr, sizeof(addr)));
-       } else {
-               rt = arplookup(satosin(dst)->sin_addr.s_addr, 1, 0,
-                   ifp->if_rdomain);
-               if (rt != NULL) {
-                       created = 1;
-                       la = ((struct llinfo_arp *)rt->rt_llinfo);
-               }
-               if (la == NULL)
-                       log(LOG_DEBUG, "%s: %s: can't allocate llinfo\n",
-                           __func__,
-                           inet_ntop(AF_INET, &satosin(dst)->sin_addr,
-                               addr, sizeof(addr)));
+       la = (struct llinfo_arp *)rt->rt_llinfo;
+       if (la == NULL) {
+               inet_ntop(AF_INET, &satosin(dst)->sin_addr, addr, sizeof(addr));
+               log(LOG_DEBUG, "%s: %s: route without link local address\n",
+                   __func__, addr);
        }
+
        if (la == NULL || rt == NULL)
                goto bad;
        sdl = satosdl(rt->rt_gateway);
Index: netinet6/nd6.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6.c,v
retrieving revision 1.179
diff -u -p -r1.179 nd6.c
--- netinet6/nd6.c      17 May 2016 08:29:14 -0000      1.179
+++ netinet6/nd6.c      18 May 2016 20:45:50 -0000
@@ -1667,12 +1667,6 @@ nd6_storelladdr(struct ifnet *ifp, struc
                }
        }
 
-       if (rt0 == NULL) {
-               /* this could happen, if we could not allocate memory */
-               m_freem(m);
-               return (ENOMEM);
-       }
-
        error = rt_checkgate(rt0, &rt);
        if (error) {
                m_freem(m);

Reply via email to