summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge V. Neville-Neil <gnn@FreeBSD.org>2016-06-02 17:51:29 +0000
committerGeorge V. Neville-Neil <gnn@FreeBSD.org>2016-06-02 17:51:29 +0000
commit6d7682268826ca15ed86237eb25286740b952f1c (patch)
tree35865ebb972dd3afe8974183497a1af7a56b33fc
parent55a87f85cfe1614b1745392afa56177e063eabb5 (diff)
Notes
-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 895b233ab1a3c..35aff00a5ab39 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 ff38b68f5dc2a..3bf372baba6c9 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 6f0e6e3cc1776..9346aecb9f827 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 1ebd4da44d6f2..b02901ffab8e8 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 c2253d4ef0ae9..57f42567128fd 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 a96e2b9c69463..8306154e56756 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 b6111c65cc9f8..51de726a621ec 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 4b191d00d4e04..26e3b851c15a3 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 e0ff6b4081a6e..46e2ace15f903 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 eac3c1d247824..48fae92ae5fed 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 06ec210c07fba..27e51f78b69c3 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 50e5d6e45d211..7d5da0e8e0eba 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 ec1996078d1d2..27363a096eb3f 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 4bca16c09120b..3354b01794af9 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 ae049f0d11066..c84881e404274 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 98f4cd3c1cdd9..ff8813b143475 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 e12aee44e6352..fde6710e225f9 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 6db94fd0eddb9..0585cd714e04f 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 0978f0d2e9663..ce98975d3792e 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);