Author: gnn
Date: Thu Jun  2 17:51:29 2016
New Revision: 301217
URL: https://svnweb.freebsd.org/changeset/base/301217

Log:
  This change re-adds L2 caching for TCP and UDP, as originally added in D4306
  but removed due to other changes in the system. Restore the llentry pointer
  to the "struct route", and use it to cache the L2 lookup (ARP or ND6) as
  appropriate.
  
  Submitted by: Mike Karels
  Differential Revision:        https://reviews.freebsd.org/D6262

Modified:
  head/sys/net/flowtable.c
  head/sys/net/if_arcsubr.c
  head/sys/net/if_ethersubr.c
  head/sys/net/if_fddisubr.c
  head/sys/net/if_fwsubr.c
  head/sys/net/if_iso88025subr.c
  head/sys/net/if_llatbl.h
  head/sys/net/route.c
  head/sys/net/route.h
  head/sys/netinet/if_ether.c
  head/sys/netinet/if_ether.h
  head/sys/netinet/in_pcb.c
  head/sys/netinet/ip_output.c
  head/sys/netinet/toecore.c
  head/sys/netinet6/in6.h
  head/sys/netinet6/in6_pcb.c
  head/sys/netinet6/ip6_output.c
  head/sys/netinet6/nd6.c
  head/sys/netinet6/nd6.h

Modified: head/sys/net/flowtable.c
==============================================================================
--- head/sys/net/flowtable.c    Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/flowtable.c    Thu Jun  2 17:51:29 2016        (r301217)
@@ -696,13 +696,8 @@ flowtable_lookup(sa_family_t sa, struct 
        ro->ro_rt = fle->f_rt;
        ro->ro_flags |= RT_NORTREF;
        lle = fle->f_lle;
-       if (lle != NULL && (lle->la_flags & LLE_VALID)) {
-               ro->ro_prepend = lle->r_linkdata;
-               ro->ro_plen = lle->r_hdrlen;
-               ro->ro_flags |= RT_MAY_LOOP;
-               if (lle->la_flags & LLE_IFADDR)
-                       ro->ro_flags |= RT_L2_ME;
-       }
+       if (lle != NULL && (lle->la_flags & LLE_VALID))
+               ro->ro_lle = lle;       /* share ref with fle->f_lle */
 
        return (0);
 }

Modified: head/sys/net/if_arcsubr.c
==============================================================================
--- head/sys/net/if_arcsubr.c   Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/if_arcsubr.c   Thu Jun  2 17:51:29 2016        (r301217)
@@ -129,7 +129,8 @@ arc_output(struct ifnet *ifp, struct mbu
                else if (ifp->if_flags & IFF_NOARP)
                        adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
                else {
-                       error = arpresolve(ifp, is_gw, m, dst, &adst, NULL);
+                       error = arpresolve(ifp, is_gw, m, dst, &adst, NULL,
+                           NULL);
                        if (error)
                                return (error == EWOULDBLOCK ? 0 : error);
                }
@@ -170,7 +171,8 @@ arc_output(struct ifnet *ifp, struct mbu
                if ((m->m_flags & M_MCAST) != 0)
                        adst = arcbroadcastaddr; /* ARCnet broadcast address */
                else {
-                       error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL);
+                       error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL,
+                           NULL);
                        if (error != 0)
                                return (error == EWOULDBLOCK ? 0 : error);
                }

Modified: head/sys/net/if_ethersubr.c
==============================================================================
--- head/sys/net/if_ethersubr.c Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/if_ethersubr.c Thu Jun  2 17:51:29 2016        (r301217)
@@ -199,7 +199,7 @@ ether_requestencap(struct ifnet *ifp, st
 static int
 ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
        const struct sockaddr *dst, struct route *ro, u_char *phdr,
-       uint32_t *pflags)
+       uint32_t *pflags, struct llentry **plle)
 {
        struct ether_header *eh;
        uint32_t lleflags = 0;
@@ -208,13 +208,16 @@ ether_resolve_addr(struct ifnet *ifp, st
        uint16_t etype;
 #endif
 
+       if (plle)
+               *plle = NULL;
        eh = (struct ether_header *)phdr;
 
        switch (dst->sa_family) {
 #ifdef INET
        case AF_INET:
                if ((m->m_flags & (M_BCAST | M_MCAST)) == 0)
-                       error = arpresolve(ifp, 0, m, dst, phdr, &lleflags);
+                       error = arpresolve(ifp, 0, m, dst, phdr, &lleflags,
+                           plle);
                else {
                        if (m->m_flags & M_BCAST)
                                memcpy(eh->ether_dhost, ifp->if_broadcastaddr,
@@ -233,7 +236,8 @@ ether_resolve_addr(struct ifnet *ifp, st
 #ifdef INET6
        case AF_INET6:
                if ((m->m_flags & M_MCAST) == 0)
-                       error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags);
+                       error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags,
+                           plle);
                else {
                        const struct in6_addr *a6;
                        a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr);
@@ -283,14 +287,40 @@ ether_output(struct ifnet *ifp, struct m
        int loop_copy = 1;
        int hlen;       /* link layer header length */
        uint32_t pflags;
+       struct llentry *lle = NULL;
+       struct rtentry *rt0 = NULL;
+       int addref = 0;
 
        phdr = NULL;
        pflags = 0;
        if (ro != NULL) {
-               phdr = ro->ro_prepend;
-               hlen = ro->ro_plen;
-               pflags = ro->ro_flags;
+               /* XXX BPF uses ro_prepend */
+               if (ro->ro_prepend != NULL) {
+                       phdr = ro->ro_prepend;
+                       hlen = ro->ro_plen;
+               } else if (!(m->m_flags & (M_BCAST | M_MCAST))) {
+                       if ((ro->ro_flags & RT_LLE_CACHE) != 0) {
+                               lle = ro->ro_lle;
+                               if (lle != NULL &&
+                                   (lle->la_flags & LLE_VALID) == 0) {
+                                       LLE_FREE(lle);
+                                       lle = NULL;     /* redundant */
+                                       ro->ro_lle = NULL;
+                               }
+                               if (lle == NULL) {
+                                       /* if we lookup, keep cache */
+                                       addref = 1;
+                               }
+                       }
+                       if (lle != NULL) {
+                               phdr = lle->r_linkdata;
+                               hlen = lle->r_hdrlen;
+                               pflags = lle->r_flags;
+                       }
+               }
+               rt0 = ro->ro_rt;
        }
+
 #ifdef MAC
        error = mac_ifnet_check_transmit(ifp, m);
        if (error)
@@ -308,7 +338,10 @@ ether_output(struct ifnet *ifp, struct m
                /* No prepend data supplied. Try to calculate ourselves. */
                phdr = linkhdr;
                hlen = ETHER_HDR_LEN;
-               error = ether_resolve_addr(ifp, m, dst, ro, phdr, &pflags);
+               error = ether_resolve_addr(ifp, m, dst, ro, phdr, &pflags,
+                   addref ? &lle : NULL);
+               if (addref && lle != NULL)
+                       ro->ro_lle = lle;
                if (error != 0)
                        return (error == EWOULDBLOCK ? 0 : error);
        }

Modified: head/sys/net/if_fddisubr.c
==============================================================================
--- head/sys/net/if_fddisubr.c  Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/if_fddisubr.c  Thu Jun  2 17:51:29 2016        (r301217)
@@ -126,7 +126,7 @@ fddi_output(struct ifnet *ifp, struct mb
        switch (dst->sa_family) {
 #ifdef INET
        case AF_INET: {
-               error = arpresolve(ifp, is_gw, m, dst, edst, NULL);
+               error = arpresolve(ifp, is_gw, m, dst, edst, NULL, NULL);
                if (error)
                        return (error == EWOULDBLOCK ? 0 : error);
                type = htons(ETHERTYPE_IP);
@@ -162,7 +162,7 @@ fddi_output(struct ifnet *ifp, struct mb
 #endif /* INET */
 #ifdef INET6
        case AF_INET6:
-               error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL);
+               error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL, NULL);
                if (error)
                        return (error == EWOULDBLOCK ? 0 : error);
                type = htons(ETHERTYPE_IPV6);

Modified: head/sys/net/if_fwsubr.c
==============================================================================
--- head/sys/net/if_fwsubr.c    Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/if_fwsubr.c    Thu Jun  2 17:51:29 2016        (r301217)
@@ -144,7 +144,8 @@ firewire_output(struct ifnet *ifp, struc
                 * doesn't fit into the arp model.
                 */
                if (unicast) {
-                       error = arpresolve(ifp, is_gw, m, dst, (u_char *) 
destfw, NULL);
+                       error = arpresolve(ifp, is_gw, m, dst,
+                           (u_char *) destfw, NULL, NULL);
                        if (error)
                                return (error == EWOULDBLOCK ? 0 : error);
                }
@@ -174,7 +175,7 @@ firewire_output(struct ifnet *ifp, struc
        case AF_INET6:
                if (unicast) {
                        error = nd6_resolve(fc->fc_ifp, is_gw, m, dst,
-                           (u_char *) destfw, NULL);
+                           (u_char *) destfw, NULL, NULL);
                        if (error)
                                return (error == EWOULDBLOCK ? 0 : error);
                }

Modified: head/sys/net/if_iso88025subr.c
==============================================================================
--- head/sys/net/if_iso88025subr.c      Thu Jun  2 17:31:37 2016        
(r301216)
+++ head/sys/net/if_iso88025subr.c      Thu Jun  2 17:51:29 2016        
(r301217)
@@ -254,7 +254,7 @@ iso88025_output(struct ifnet *ifp, struc
        switch (dst->sa_family) {
 #ifdef INET
        case AF_INET:
-               error = arpresolve(ifp, is_gw, m, dst, edst, NULL);
+               error = arpresolve(ifp, is_gw, m, dst, edst, NULL, NULL);
                if (error)
                        return (error == EWOULDBLOCK ? 0 : error);
                snap_type = ETHERTYPE_IP;
@@ -289,7 +289,7 @@ iso88025_output(struct ifnet *ifp, struc
 #endif /* INET */
 #ifdef INET6
        case AF_INET6:
-               error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL);
+               error = nd6_resolve(ifp, is_gw, m, dst, edst, NULL, NULL);
                if (error)
                        return (error == EWOULDBLOCK ? 0 : error);
                snap_type = ETHERTYPE_IPV6;

Modified: head/sys/net/if_llatbl.h
==============================================================================
--- head/sys/net/if_llatbl.h    Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/if_llatbl.h    Thu Jun  2 17:51:29 2016        (r301217)
@@ -138,7 +138,6 @@ struct llentry {
        LLE_FREE_LOCKED(lle);                                   \
 } while (0)
 
-
 typedef        struct llentry *(llt_lookup_t)(struct lltable *, u_int flags,
     const struct sockaddr *l3addr);
 typedef        struct llentry *(llt_alloc_t)(struct lltable *, u_int flags,

Modified: head/sys/net/route.c
==============================================================================
--- head/sys/net/route.c        Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/route.c        Thu Jun  2 17:51:29 2016        (r301217)
@@ -207,6 +207,8 @@ rt_tables_get_gen(int table, int fam)
        struct rib_head *rnh;
 
        rnh = *rt_tables_get_rnh_ptr(table, fam);
+       KASSERT(rnh != NULL, ("%s: NULL rib_head pointer table %d fam %d",
+           __func__, table, fam));
        return (rnh->rnh_gen);
 }
 

Modified: head/sys/net/route.h
==============================================================================
--- head/sys/net/route.h        Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/net/route.h        Thu Jun  2 17:51:29 2016        (r301217)
@@ -50,6 +50,11 @@
  */
 struct route {
        struct  rtentry *ro_rt;
+       struct  llentry *ro_lle;
+       /*
+        * ro_prepend and ro_plen are only used for bpf to pass in a
+        * preformed header.  They are not cacheable.
+        */
        char            *ro_prepend;
        uint16_t        ro_plen;
        uint16_t        ro_flags;
@@ -71,6 +76,7 @@ struct route {
 #define        RT_REJECT               0x0020          /* Destination is 
reject */
 #define        RT_BLACKHOLE            0x0040          /* Destination is 
blackhole */
 #define        RT_HAS_GW               0x0080          /* Destination has GW  
*/
+#define        RT_LLE_CACHE            0x0100          /* Cache link layer  */
 
 struct rt_metrics {
        u_long  rmx_locks;      /* Kernel must leave these values alone */
@@ -399,6 +405,7 @@ struct rt_addrinfo {
                if ((_ro)->ro_flags & RT_NORTREF) {             \
                        (_ro)->ro_flags &= ~RT_NORTREF;         \
                        (_ro)->ro_rt = NULL;                    \
+                       (_ro)->ro_lle = NULL;                   \
                } else {                                        \
                        RT_LOCK((_ro)->ro_rt);                  \
                        RTFREE_LOCKED((_ro)->ro_rt);            \
@@ -413,9 +420,11 @@ struct rt_addrinfo {
  */
 #define RT_VALIDATE(ro, cookiep, fibnum) do {                          \
        rt_gen_t cookie = RT_GEN(fibnum, (ro)->ro_dst.sa_family);       \
-       if (*(cookiep) != cookie && (ro)->ro_rt != NULL) {              \
-               RTFREE((ro)->ro_rt);                                    \
-               (ro)->ro_rt = NULL;                                     \
+       if (*(cookiep) != cookie) {                                     \
+               if ((ro)->ro_rt != NULL) {                              \
+                       RTFREE((ro)->ro_rt);                            \
+                       (ro)->ro_rt = NULL;                             \
+               }                                                       \
                *(cookiep) = cookie;                                    \
        }                                                               \
 } while (0)

Modified: head/sys/netinet/if_ether.c
==============================================================================
--- head/sys/netinet/if_ether.c Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet/if_ether.c Thu Jun  2 17:51:29 2016        (r301217)
@@ -420,7 +420,8 @@ arprequest(struct ifnet *ifp, const stru
  */
 static int
 arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m,
-       const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
+       const struct sockaddr *dst, u_char *desten, uint32_t *pflags,
+       struct llentry **plle)
 {
        struct llentry *la = NULL, *la_tmp;
        struct mbuf *curr = NULL;
@@ -431,6 +432,8 @@ arpresolve_full(struct ifnet *ifp, int i
 
        if (pflags != NULL)
                *pflags = 0;
+       if (plle != NULL)
+               *plle = NULL;
 
        if ((flags & LLE_CREATE) == 0) {
                IF_AFDATA_RLOCK(ifp);
@@ -483,6 +486,10 @@ arpresolve_full(struct ifnet *ifp, int i
                }
                if (pflags != NULL)
                        *pflags = la->la_flags & (LLE_VALID|LLE_IFADDR);
+               if (plle) {
+                       LLE_ADDREF(la);
+                       *plle = la;
+               }
                LLE_WUNLOCK(la);
                return (0);
        }
@@ -548,12 +555,12 @@ arpresolve_full(struct ifnet *ifp, int i
  */
 int
 arpresolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst,
-    char *desten, uint32_t *pflags)
+    char *desten, uint32_t *pflags, struct llentry **plle)
 {
        int error;
 
        flags |= LLE_ADDRONLY;
-       error = arpresolve_full(ifp, 0, flags, NULL, dst, desten, pflags);
+       error = arpresolve_full(ifp, 0, flags, NULL, dst, desten, pflags, plle);
        return (error);
 }
 
@@ -576,12 +583,15 @@ arpresolve_addr(struct ifnet *ifp, int f
  */
 int
 arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
-       const struct sockaddr *dst, u_char *desten, uint32_t *pflags)
+       const struct sockaddr *dst, u_char *desten, uint32_t *pflags,
+       struct llentry **plle)
 {
        struct llentry *la = NULL;
 
        if (pflags != NULL)
                *pflags = 0;
+       if (plle != NULL)
+               *plle = NULL;
 
        if (m != NULL) {
                if (m->m_flags & M_BCAST) {
@@ -616,7 +626,7 @@ arpresolve(struct ifnet *ifp, int is_gw,
        IF_AFDATA_RUNLOCK(ifp);
 
        return (arpresolve_full(ifp, is_gw, la == NULL ? LLE_CREATE : 0, m, dst,
-           desten, pflags));
+           desten, pflags, plle));
 }
 
 /*

Modified: head/sys/netinet/if_ether.h
==============================================================================
--- head/sys/netinet/if_ether.h Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet/if_ether.h Thu Jun  2 17:51:29 2016        (r301217)
@@ -113,11 +113,14 @@ extern u_char     ether_ipmulticast_min[ETHE
 extern u_char  ether_ipmulticast_max[ETHER_ADDR_LEN];
 
 struct ifaddr;
+struct llentry;
 
 int    arpresolve_addr(struct ifnet *ifp, int flags,
-           const struct sockaddr *dst, char *desten, uint32_t *pflags);
+           const struct sockaddr *dst, char *desten, uint32_t *pflags,
+           struct llentry **plle);
 int    arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
-           const struct sockaddr *dst, u_char *desten, uint32_t *pflags);
+           const struct sockaddr *dst, u_char *desten, uint32_t *pflags,
+           struct llentry **plle);
 void   arprequest(struct ifnet *, const struct in_addr *,
            const struct in_addr *, u_char *);
 void   arp_ifinit(struct ifnet *, struct ifaddr *);

Modified: head/sys/netinet/in_pcb.c
==============================================================================
--- head/sys/netinet/in_pcb.c   Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet/in_pcb.c   Thu Jun  2 17:51:29 2016        (r301217)
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
 #include <net/if.h>
 #include <net/if_var.h>
 #include <net/if_types.h>
+#include <net/if_llatbl.h>
 #include <net/route.h>
 #include <net/rss_config.h>
 #include <net/vnet.h>
@@ -1302,6 +1303,8 @@ in_pcbfree(struct inpcb *inp)
                RTFREE(inp->inp_route.ro_rt);
                inp->inp_route.ro_rt = (struct rtentry *)NULL;
        }
+       if (inp->inp_route.ro_lle)
+               LLE_FREE(inp->inp_route.ro_lle);        /* zeros ro_lle */
 
        inp->inp_vflag = 0;
        inp->inp_flags2 |= INP_FREED;
@@ -2243,6 +2246,8 @@ in_losing(struct inpcb *inp)
                RTFREE(inp->inp_route.ro_rt);
                inp->inp_route.ro_rt = (struct rtentry *)NULL;
        }
+       if (inp->inp_route.ro_lle)
+               LLE_FREE(inp->inp_route.ro_lle);        /* zeros ro_lle */
        return;
 }
 

Modified: head/sys/netinet/ip_output.c
==============================================================================
--- head/sys/netinet/ip_output.c        Thu Jun  2 17:31:37 2016        
(r301216)
+++ head/sys/netinet/ip_output.c        Thu Jun  2 17:51:29 2016        
(r301217)
@@ -245,7 +245,8 @@ ip_output(struct mbuf *m, struct mbuf *o
        if (ro == NULL) {
                ro = &iproute;
                bzero(ro, sizeof (*ro));
-       }
+       } else
+               ro->ro_flags |= RT_LLE_CACHE;
 
 #ifdef FLOWTABLE
        if (ro->ro_rt == NULL)
@@ -311,6 +312,9 @@ again:
                          dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
                RTFREE(rte);
                rte = ro->ro_rt = (struct rtentry *)NULL;
+               if (ro->ro_lle)
+                       LLE_FREE(ro->ro_lle);   /* zeros ro_lle */
+               ro->ro_lle = (struct llentry *)NULL;
        }
        ia = NULL;
        have_ia_ref = 0;

Modified: head/sys/netinet/toecore.c
==============================================================================
--- head/sys/netinet/toecore.c  Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet/toecore.c  Thu Jun  2 17:51:29 2016        (r301217)
@@ -451,12 +451,12 @@ toe_l2_resolve(struct toedev *tod, struc
        switch (sa->sa_family) {
 #ifdef INET
        case AF_INET:
-               rc = arpresolve(ifp, 0, NULL, sa, lladdr, NULL);
+               rc = arpresolve(ifp, 0, NULL, sa, lladdr, NULL, NULL);
                break;
 #endif
 #ifdef INET6
        case AF_INET6:
-               rc = nd6_resolve(ifp, 0, NULL, sa, lladdr, NULL);
+               rc = nd6_resolve(ifp, 0, NULL, sa, lladdr, NULL, NULL);
                break;
 #endif
        default:

Modified: head/sys/netinet6/in6.h
==============================================================================
--- head/sys/netinet6/in6.h     Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet6/in6.h     Thu Jun  2 17:51:29 2016        (r301217)
@@ -375,6 +375,11 @@ extern const struct in6_addr in6addr_lin
 #if __BSD_VISIBLE
 struct route_in6 {
        struct  rtentry *ro_rt;
+       struct  llentry *ro_lle;
+       /*
+        * ro_prepend and ro_plen are only used for bpf to pass in a
+        * preformed header.  They are not cacheable.
+        */
        char            *ro_prepend;
        uint16_t        ro_plen;
        uint16_t        ro_flags;

Modified: head/sys/netinet6/in6_pcb.c
==============================================================================
--- head/sys/netinet6/in6_pcb.c Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet6/in6_pcb.c Thu Jun  2 17:51:29 2016        (r301217)
@@ -92,6 +92,7 @@ __FBSDID("$FreeBSD$");
 
 #include <net/if.h>
 #include <net/if_var.h>
+#include <net/if_llatbl.h>
 #include <net/if_types.h>
 #include <net/route.h>
 
@@ -831,6 +832,8 @@ in6_losing(struct inpcb *in6p)
                RTFREE(in6p->inp_route6.ro_rt);
                in6p->inp_route6.ro_rt = (struct rtentry *)NULL;
        }
+       if (in6p->inp_route.ro_lle)
+               LLE_FREE(in6p->inp_route.ro_lle);       /* zeros ro_lle */
        return;
 }
 
@@ -846,6 +849,8 @@ in6_rtchange(struct inpcb *inp, int errn
                RTFREE(inp->inp_route6.ro_rt);
                inp->inp_route6.ro_rt = (struct rtentry *)NULL;
        }
+       if (inp->inp_route.ro_lle)
+               LLE_FREE(inp->inp_route.ro_lle);        /* zeros ro_lle */
        return inp;
 }
 

Modified: head/sys/netinet6/ip6_output.c
==============================================================================
--- head/sys/netinet6/ip6_output.c      Thu Jun  2 17:31:37 2016        
(r301216)
+++ head/sys/netinet6/ip6_output.c      Thu Jun  2 17:51:29 2016        
(r301217)
@@ -500,7 +500,8 @@ ip6_output(struct mbuf *m0, struct ip6_p
        if (ro == NULL) {
                ro = &ip6route;
                bzero((caddr_t)ro, sizeof(*ro));
-       }
+       } else
+               ro->ro_flags |= RT_LLE_CACHE;
        ro_pmtu = ro;
        if (opt && opt->ip6po_rthdr)
                ro = &opt->ip6po_route;

Modified: head/sys/netinet6/nd6.c
==============================================================================
--- head/sys/netinet6/nd6.c     Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet6/nd6.c     Thu Jun  2 17:51:29 2016        (r301217)
@@ -136,7 +136,7 @@ static void nd6_llinfo_settimer_locked(s
 static void clear_llinfo_pqueue(struct llentry *);
 static void nd6_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
 static int nd6_resolve_slow(struct ifnet *, int, struct mbuf *,
-    const struct sockaddr_in6 *, u_char *, uint32_t *);
+    const struct sockaddr_in6 *, u_char *, uint32_t *, struct llentry **);
 static int nd6_need_cache(struct ifnet *);
  
 
@@ -2175,7 +2175,8 @@ nd6_output_ifp(struct ifnet *ifp, struct
  */
 int
 nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
-    const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags)
+    const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags,
+    struct llentry **plle)
 {
        struct llentry *ln = NULL;
        const struct sockaddr_in6 *dst6;
@@ -2227,7 +2228,7 @@ nd6_resolve(struct ifnet *ifp, int is_gw
        }
        IF_AFDATA_RUNLOCK(ifp);
 
-       return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags));
+       return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags, plle));
 }
 
 
@@ -2244,7 +2245,8 @@ nd6_resolve(struct ifnet *ifp, int is_gw
  */
 static __noinline int
 nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m,
-    const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags)
+    const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags,
+    struct llentry **plle)
 {
        struct llentry *lle = NULL, *lle_tmp;
        struct in6_addr *psrc, src;
@@ -2331,6 +2333,10 @@ nd6_resolve_slow(struct ifnet *ifp, int 
                bcopy(lladdr, desten, ll_len);
                if (pflags != NULL)
                        *pflags = lle->la_flags;
+               if (plle) {
+                       LLE_ADDREF(lle);
+                       *plle = lle;
+               }
                LLE_WUNLOCK(lle);
                return (0);
        }
@@ -2405,7 +2411,7 @@ nd6_resolve_addr(struct ifnet *ifp, int 
 
        flags |= LLE_ADDRONLY;
        error = nd6_resolve_slow(ifp, flags, NULL,
-           (const struct sockaddr_in6 *)dst, desten, pflags);
+           (const struct sockaddr_in6 *)dst, desten, pflags, NULL);
        return (error);
 }
 

Modified: head/sys/netinet6/nd6.h
==============================================================================
--- head/sys/netinet6/nd6.h     Thu Jun  2 17:31:37 2016        (r301216)
+++ head/sys/netinet6/nd6.h     Thu Jun  2 17:51:29 2016        (r301217)
@@ -428,7 +428,7 @@ void nd6_purge(struct ifnet *);
 int nd6_resolve_addr(struct ifnet *ifp, int flags, const struct sockaddr *dst,
     char *desten, uint32_t *pflags);
 int nd6_resolve(struct ifnet *, int, struct mbuf *,
-    const struct sockaddr *, u_char *, uint32_t *);
+    const struct sockaddr *, u_char *, uint32_t *, struct llentry **);
 int nd6_ioctl(u_long, caddr_t, struct ifnet *);
 void nd6_cache_lladdr(struct ifnet *, struct in6_addr *,
        char *, int, int, int);
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to