summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorgnn <gnn@FreeBSD.org>2016-06-02 17:51:29 +0000
committergnn <gnn@FreeBSD.org>2016-06-02 17:51:29 +0000
commitd75e0c471e231b57a58d0a0f8f77ed359ed0e190 (patch)
tree35865ebb972dd3afe8974183497a1af7a56b33fc /sys
parent56e3e42896aee2eb336ee7d14417f427bbf2f505 (diff)
downloadFreeBSD-src-d75e0c471e231b57a58d0a0f8f77ed359ed0e190.zip
FreeBSD-src-d75e0c471e231b57a58d0a0f8f77ed359ed0e190.tar.gz
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
Diffstat (limited to 'sys')
-rw-r--r--sys/net/flowtable.c9
-rw-r--r--sys/net/if_arcsubr.c6
-rw-r--r--sys/net/if_ethersubr.c47
-rw-r--r--sys/net/if_fddisubr.c4
-rw-r--r--sys/net/if_fwsubr.c5
-rw-r--r--sys/net/if_iso88025subr.c4
-rw-r--r--sys/net/if_llatbl.h1
-rw-r--r--sys/net/route.c2
-rw-r--r--sys/net/route.h15
-rw-r--r--sys/netinet/if_ether.c20
-rw-r--r--sys/netinet/if_ether.h7
-rw-r--r--sys/netinet/in_pcb.c5
-rw-r--r--sys/netinet/ip_output.c6
-rw-r--r--sys/netinet/toecore.c4
-rw-r--r--sys/netinet6/in6.h5
-rw-r--r--sys/netinet6/in6_pcb.c5
-rw-r--r--sys/netinet6/ip6_output.c3
-rw-r--r--sys/netinet6/nd6.c16
-rw-r--r--sys/netinet6/nd6.h2
19 files changed, 123 insertions, 43 deletions
diff --git a/sys/net/flowtable.c b/sys/net/flowtable.c
index 895b233..35aff00 100644
--- a/sys/net/flowtable.c
+++ b/sys/net/flowtable.c
@@ -696,13 +696,8 @@ flowtable_lookup(sa_family_t sa, struct mbuf *m, struct route *ro)
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);
}
diff --git a/sys/net/if_arcsubr.c b/sys/net/if_arcsubr.c
index ff38b68..3bf372b 100644
--- a/sys/net/if_arcsubr.c
+++ b/sys/net/if_arcsubr.c
@@ -129,7 +129,8 @@ arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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 mbuf *m, const struct sockaddr *dst,
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);
}
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 6f0e6e3..9346aec 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -199,7 +199,7 @@ ether_requestencap(struct ifnet *ifp, struct if_encap_req *req)
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, struct mbuf *m,
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, struct mbuf *m,
#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 mbuf *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 mbuf *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);
}
diff --git a/sys/net/if_fddisubr.c b/sys/net/if_fddisubr.c
index 1ebd4da..b02901f 100644
--- a/sys/net/if_fddisubr.c
+++ b/sys/net/if_fddisubr.c
@@ -126,7 +126,7 @@ fddi_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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 mbuf *m, const struct sockaddr *dst,
#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);
diff --git a/sys/net/if_fwsubr.c b/sys/net/if_fwsubr.c
index c2253d4..57f4256 100644
--- a/sys/net/if_fwsubr.c
+++ b/sys/net/if_fwsubr.c
@@ -144,7 +144,8 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
* 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, struct mbuf *m, const struct sockaddr *dst,
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);
}
diff --git a/sys/net/if_iso88025subr.c b/sys/net/if_iso88025subr.c
index a96e2b9..8306154 100644
--- a/sys/net/if_iso88025subr.c
+++ b/sys/net/if_iso88025subr.c
@@ -254,7 +254,7 @@ iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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, struct mbuf *m, const struct sockaddr *dst,
#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;
diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h
index b6111c6..51de726 100644
--- a/sys/net/if_llatbl.h
+++ b/sys/net/if_llatbl.h
@@ -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,
diff --git a/sys/net/route.c b/sys/net/route.c
index 4b191d0..26e3b85 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -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);
}
diff --git a/sys/net/route.h b/sys/net/route.h
index e0ff6b4..46e2ace 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -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)
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index eac3c1d..48fae92 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -420,7 +420,8 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
*/
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 is_gw, int flags, struct mbuf *m,
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 is_gw, int flags, struct mbuf *m,
}
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 is_gw, int flags, struct mbuf *m,
*/
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 flags, const struct sockaddr *dst,
*/
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, struct mbuf *m,
IF_AFDATA_RUNLOCK(ifp);
return (arpresolve_full(ifp, is_gw, la == NULL ? LLE_CREATE : 0, m, dst,
- desten, pflags));
+ desten, pflags, plle));
}
/*
diff --git a/sys/netinet/if_ether.h b/sys/netinet/if_ether.h
index 06ec210..27e51f7 100644
--- a/sys/netinet/if_ether.h
+++ b/sys/netinet/if_ether.h
@@ -113,11 +113,14 @@ extern u_char ether_ipmulticast_min[ETHER_ADDR_LEN];
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 *);
diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 50e5d6e..7d5da0e 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -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;
}
diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c
index ec19960..27363a0 100644
--- a/sys/netinet/ip_output.c
+++ b/sys/netinet/ip_output.c
@@ -245,7 +245,8 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
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;
diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c
index 4bca16c..3354b01 100644
--- a/sys/netinet/toecore.c
+++ b/sys/netinet/toecore.c
@@ -451,12 +451,12 @@ toe_l2_resolve(struct toedev *tod, struct ifnet *ifp, struct sockaddr *sa,
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:
diff --git a/sys/netinet6/in6.h b/sys/netinet6/in6.h
index ae049f0..c84881e 100644
--- a/sys/netinet6/in6.h
+++ b/sys/netinet6/in6.h
@@ -375,6 +375,11 @@ extern const struct in6_addr in6addr_linklocal_allv2routers;
#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;
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 98f4cd3..ff8813b 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -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 errno)
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;
}
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index e12aee4..fde6710 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -500,7 +500,8 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
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;
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index 6db94fd..0585cd7 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -136,7 +136,7 @@ static void nd6_llinfo_settimer_locked(struct llentry *, long);
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 ifnet *origifp, struct mbuf *m,
*/
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, struct mbuf *m,
}
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, struct mbuf *m,
*/
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 flags, struct mbuf *m,
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, const struct sockaddr *dst,
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);
}
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 0978f0d..ce98975 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -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);
OpenPOWER on IntegriCloud