On 18/05/16(Wed) 22:56, Martin Pieuchot wrote:
> 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).

New diff with ND bits.  Please test and report back.

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  23 May 2016 12:21:45 -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: netinet/if_ether.c
===================================================================
RCS file: /cvs/src/sys/netinet/if_ether.c,v
retrieving revision 1.209
diff -u -p -r1.209 if_ether.c
--- netinet/if_ether.c  23 May 2016 09:23:43 -0000      1.209
+++ netinet/if_ether.c  23 May 2016 12:21:45 -0000
@@ -281,9 +281,8 @@ arpresolve(struct ifnet *ifp, struct rte
        struct llinfo_arp *la = NULL;
        struct sockaddr_dl *sdl;
        struct rtentry *rt = NULL;
-       struct mbuf *mh;
        char addr[INET_ADDRSTRLEN];
-       int error, created = 0;
+       int error;
 
        if (m->m_flags & M_BCAST) {     /* broadcast */
                memcpy(desten, etherbroadcastaddr, sizeof(etherbroadcastaddr));
@@ -294,41 +293,20 @@ arpresolve(struct ifnet *ifp, struct rte
                return (0);
        }
 
-       if (rt0 != NULL) {
-               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);
-               }
+       error = rt_checkgate(rt0, &rt);
+       if (error) {
+               m_freem(m);
+               return (error);
+       }
 
-               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, 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)));
+       if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
+               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 (la == NULL || rt == NULL)
-               goto bad;
+
        sdl = satosdl(rt->rt_gateway);
        if (sdl->sdl_alen > 0 && sdl->sdl_alen != ETHER_ADDR_LEN) {
                log(LOG_DEBUG, "%s: %s: incorrect arp information\n", __func__,
@@ -336,6 +314,7 @@ arpresolve(struct ifnet *ifp, struct rte
                        addr, sizeof(addr)));
                goto bad;
        }
+
        /*
         * Check the address family and length is valid, the address
         * is resolved; otherwise, try to resolve.
@@ -343,10 +322,9 @@ arpresolve(struct ifnet *ifp, struct rte
        if ((rt->rt_expire == 0 || rt->rt_expire > time_second) &&
            sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
                memcpy(desten, LLADDR(sdl), sdl->sdl_alen);
-               if (created)
-                       rtfree(rt);
                return (0);
        }
+
        if (ifp->if_flags & IFF_NOARP)
                goto bad;
 
@@ -355,7 +333,11 @@ arpresolve(struct ifnet *ifp, struct rte
         * response yet. Insert mbuf in hold queue if below limit
         * if above the limit free the queue without queuing the new packet.
         */
+       la = (struct llinfo_arp *)rt->rt_llinfo;
+       KASSERT(la != NULL);
        if (la_hold_total < LA_HOLD_TOTAL && la_hold_total < nmbclust / 64) {
+               struct mbuf *mh;
+
                if (ml_len(&la->la_ml) >= LA_HOLD_QUEUE) {
                        mh = ml_dequeue(&la->la_ml);
                        la_hold_total--;
@@ -396,14 +378,11 @@ arpresolve(struct ifnet *ifp, struct rte
                        }
                }
        }
-       if (created)
-               rtfree(rt);
+
        return (EAGAIN);
 
 bad:
        m_freem(m);
-       if (created)
-               rtfree(rt);
        return (EINVAL);
 }
 
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      23 May 2016 12:38:56 -0000
@@ -1507,20 +1507,15 @@ nd6_output(struct ifnet *ifp, struct mbu
        struct mbuf *m = m0;
        struct rtentry *rt = rt0;
        struct llinfo_nd6 *ln = NULL;
-       int created = 0, error = 0;
+       int error = 0;
 
        if (IN6_IS_ADDR_MULTICAST(&dst->sin6_addr))
                goto sendpkt;
 
-       /*
-        * next hop determination.
-        */
-       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 (nd6_need_cache(ifp) == 0)
@@ -1532,42 +1527,17 @@ nd6_output(struct ifnet *ifp, struct mbu
         * At this point, the destination of the packet must be a unicast
         * or an anycast address(i.e. not a multicast).
         */
-
-       /* Look up the neighbor cache for the nexthop */
-       if (rt != NULL && (rt->rt_flags & RTF_LLINFO) != 0)
-               ln = (struct llinfo_nd6 *)rt->rt_llinfo;
-       else {
-               /*
-                * Since nd6_is_addr_neighbor() internally calls nd6_lookup(),
-                * the condition below is not very efficient.  But we believe
-                * it is tolerable, because this should be a rare case.
-                */
-               if (nd6_is_addr_neighbor(dst, ifp)) {
-                       rt = nd6_lookup(&dst->sin6_addr, 1, ifp,
-                           ifp->if_rdomain);
-                       if (rt != NULL) {
-                               created = 1;
-                               ln = (struct llinfo_nd6 *)rt->rt_llinfo;
-                       }
-               }
+       if (!ISSET(rt->rt_flags, RTF_LLINFO)) {
+               char addr[INET6_ADDRSTRLEN];
+               log(LOG_DEBUG, "%s: %s: route contains no ND information\n",
+                   __func__, inet_ntop(AF_INET6,
+                   &satosin6(rt_key(rt))->sin6_addr, addr, sizeof(addr)));
+               m_freem(m);
+               return (EINVAL);
        }
-       if (ln == NULL || rt == NULL) {
-               if ((ND_IFINFO(ifp)->flags & ND6_IFF_PERFORMNUD) == 0) {
-                       char addr[INET6_ADDRSTRLEN];
-
-                       log(LOG_DEBUG, "%s: can't allocate llinfo for %s "
-                           "(ln=%p, rt=%p)\n", __func__,
-                           inet_ntop(AF_INET6, &dst->sin6_addr,
-                               addr, sizeof(addr)),
-                           ln, rt);
-                       m_freem(m);
-                       if (created)
-                               rtfree(rt);
-                       return (EIO);   /* XXX: good error? */
-               }
 
-               goto sendpkt;   /* send anyway */
-       }
+       ln = (struct llinfo_nd6 *)rt->rt_llinfo;
+       KASSERT(ln != NULL);
 
        /*
         * Move this entry to the head of the queue so that it is less likely
@@ -1617,14 +1587,10 @@ nd6_output(struct ifnet *ifp, struct mbu
                    (long)ND_IFINFO(ifp)->retrans * hz / 1000);
                nd6_ns_output(ifp, NULL, &dst->sin6_addr, ln, 0);
        }
-       if (created)
-               rtfree(rt);
        return (0);
 
   sendpkt:
        error = ifp->if_output(ifp, m, sin6tosa(dst), rt);
-       if (created)
-               rtfree(rt);
        return (error);
 }
 
@@ -1665,12 +1631,6 @@ nd6_storelladdr(struct ifnet *ifp, struc
                        m_freem(m);
                        return (EINVAL);
                }
-       }
-
-       if (rt0 == NULL) {
-               /* this could happen, if we could not allocate memory */
-               m_freem(m);
-               return (ENOMEM);
        }
 
        error = rt_checkgate(rt0, &rt);

Reply via email to