diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -237,8 +237,8 @@ #ifdef INET6 case AF_INET6: if ((m->m_flags & M_MCAST) == 0) - error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags, - plle); + error = nd6_resolve(ifp, LLE_SF(AF_INET6, 0), m, dst, phdr, + &lleflags, plle); else { const struct in6_addr *a6; a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr); diff --git a/sys/net/if_fwsubr.c b/sys/net/if_fwsubr.c --- a/sys/net/if_fwsubr.c +++ b/sys/net/if_fwsubr.c @@ -176,8 +176,8 @@ #ifdef INET6 case AF_INET6: if (unicast) { - error = nd6_resolve(fc->fc_ifp, is_gw, m, dst, - (u_char *) destfw, NULL, NULL); + error = nd6_resolve(fc->fc_ifp, LLE_SF(AF_INET6, is_gw), + m, dst, (u_char *) destfw, NULL, NULL); if (error) return (error == EWOULDBLOCK ? 0 : error); } diff --git a/sys/net/if_infiniband.c b/sys/net/if_infiniband.c --- a/sys/net/if_infiniband.c +++ b/sys/net/if_infiniband.c @@ -253,7 +253,8 @@ #ifdef INET6 case AF_INET6: if ((m->m_flags & M_MCAST) == 0) { - error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags, plle); + error = nd6_resolve(ifp, LLE_SF(AF_INET6, 0), m, dst, + phdr, &lleflags, plle); } else { infiniband_ipv6_multicast_map( &((const struct sockaddr_in6 *)dst)->sin6_addr, diff --git a/sys/net/if_llatbl.h b/sys/net/if_llatbl.h --- a/sys/net/if_llatbl.h +++ b/sys/net/if_llatbl.h @@ -58,7 +58,8 @@ } r_l3addr; char r_linkdata[LLE_MAX_LINKHDR]; /* L2 data */ uint8_t r_hdrlen; /* length for LL header */ - uint8_t spare0[3]; + uint8_t r_family; /* Upper layer proto family */ + uint8_t spare0[2]; uint16_t r_flags; /* LLE runtime flags */ uint16_t r_skip_req; /* feedback from fast path */ @@ -78,6 +79,9 @@ time_t lle_hittime; /* Time when r_skip_req was unset */ int lle_refcnt; char *ll_addr; /* link-layer address */ + CK_SLIST_HEAD(llentry_children_head,llentry) lle_children; /* child encaps */ + CK_SLIST_ENTRY(llentry) lle_child_next; /* child encaps */ + struct llentry *lle_parent; /* parent for a child */ CK_LIST_ENTRY(llentry) lle_chain; /* chain of deleted items */ struct callout lle_timer; @@ -104,6 +108,8 @@ #define LLE_IS_VALID(lle) (((lle) != NULL) && ((lle) != (void *)-1)) +#define LLE_SF(_fam, _flags) (((_flags) & 0xFFFF) | ((_fam) << 16)) + #define LLE_ADDREF(lle) do { \ LLE_WLOCK_ASSERT(lle); \ KASSERT((lle)->lle_refcnt >= 0, \ @@ -195,6 +201,7 @@ #define LLE_REDIRECT 0x0010 /* installed by redirect; has host rtentry */ #define LLE_PUB 0x0020 /* publish entry ??? */ #define LLE_LINKED 0x0040 /* linked to lookup structure */ +#define LLE_CHILD 0x0080 /* Child LLE storing different AF encap */ /* LLE request flags */ #define LLE_EXCLUSIVE 0x2000 /* return lle xlocked */ #define LLE_UNLOCKED 0x4000 /* return lle unlocked */ @@ -234,6 +241,8 @@ const struct sockaddr *l3addr); int lltable_link_entry(struct lltable *llt, struct llentry *lle); int lltable_unlink_entry(struct lltable *llt, struct llentry *lle); +void lltable_link_child_entry(struct llentry *parent_lle, struct llentry *child_lle); +void lltable_unlink_child_entry(struct llentry *child_lle); void lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa); struct ifnet *lltable_get_ifp(const struct lltable *llt); int lltable_get_af(const struct lltable *llt); @@ -267,6 +276,7 @@ return; llentry_mark_used(lle); } +struct llentry *llentry_lookup_family(struct llentry *lle, int family); int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *); diff --git a/sys/net/if_llatbl.c b/sys/net/if_llatbl.c --- a/sys/net/if_llatbl.c +++ b/sys/net/if_llatbl.c @@ -398,6 +398,26 @@ return (error); } +/* + * Searches for the child entry matching @family inside @lle. + * Returns the entry or NULL. + */ +struct llentry * +llentry_lookup_family(struct llentry *lle, int family) +{ + struct llentry *child_lle; + + if (lle == NULL) + return (NULL); + + CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { + if (child_lle->r_family == family) + return (child_lle); + } + + return (NULL); +} + /* * Requests feedback from the datapath. * First packet using @lle should result in @@ -407,9 +427,17 @@ void llentry_request_feedback(struct llentry *lle) { + struct llentry *child_lle; + LLE_REQ_LOCK(lle); lle->r_skip_req = 1; LLE_REQ_UNLOCK(lle); + + CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { + LLE_REQ_LOCK(child_lle); + child_lle->r_skip_req = 1; + LLE_REQ_UNLOCK(child_lle); + } } /* @@ -431,8 +459,8 @@ * Return 0 if the entry was not used, relevant time_uptime * otherwise. */ -time_t -llentry_get_hittime(struct llentry *lle) +static time_t +llentry_get_hittime_raw(struct llentry *lle) { time_t lle_hittime = 0; @@ -444,6 +472,23 @@ return (lle_hittime); } +time_t +llentry_get_hittime(struct llentry *lle) +{ + time_t lle_hittime = 0; + struct llentry *child_lle; + + lle_hittime = llentry_get_hittime_raw(lle); + + CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { + time_t hittime = llentry_get_hittime_raw(child_lle); + if (hittime > lle_hittime) + lle_hittime = hittime; + } + + return (lle_hittime); +} + /* * Update link-layer header for given @lle after * interface lladdr was changed. @@ -585,7 +630,7 @@ ifp = llt->llt_ifp; IF_AFDATA_WLOCK(ifp); - lle = lla_lookup(llt, LLE_EXCLUSIVE, l3addr); + lle = lla_lookup(llt, LLE_SF(l3addr->sa_family, LLE_EXCLUSIVE), l3addr); if (lle == NULL) { IF_AFDATA_WUNLOCK(ifp); @@ -700,6 +745,25 @@ return (llt->llt_link_entry(llt, lle)); } +void +lltable_link_child_entry(struct llentry *lle, struct llentry *child_lle) +{ + child_lle->lle_parent = lle; + child_lle->lle_tbl = lle->lle_tbl; + child_lle->la_flags |= LLE_LINKED; + CK_SLIST_INSERT_HEAD(&lle->lle_children, child_lle, lle_child_next); +} + +void +lltable_unlink_child_entry(struct llentry *child_lle) +{ + struct llentry *lle = child_lle->lle_parent; + + child_lle->la_flags &= ~LLE_LINKED; + child_lle->lle_parent = NULL; + CK_SLIST_REMOVE(&lle->lle_children, child_lle, llentry, lle_child_next); +} + int lltable_unlink_entry(struct lltable *llt, struct llentry *lle) { diff --git a/sys/netinet/toecore.c b/sys/netinet/toecore.c --- a/sys/netinet/toecore.c +++ b/sys/netinet/toecore.c @@ -483,7 +483,7 @@ #endif #ifdef INET6 case AF_INET6: - rc = nd6_resolve(ifp, 0, NULL, sa, lladdr, NULL, NULL); + rc = nd6_resolve(ifp, LLE_SF(AF_INET6, 0), NULL, sa, lladdr, NULL, NULL); break; #endif default: diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c --- a/sys/netinet6/icmp6.c +++ b/sys/netinet6/icmp6.c @@ -2546,7 +2546,7 @@ struct nd_opt_hdr *nd_opt; char *lladdr; - ln = nd6_lookup(router_ll6, 0, ifp); + ln = nd6_lookup(router_ll6, LLE_SF(AF_INET6, 0), ifp); if (ln == NULL) goto nolladdropt; diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c --- a/sys/netinet6/in6.c +++ b/sys/netinet6/in6.c @@ -2335,6 +2335,11 @@ lle = in6_lltable_find_dst(llt, &sin6->sin6_addr); if (lle == NULL) return (NULL); + + int family = flags >> 16; + if (__predict_false(family != AF_INET6)) + lle = llentry_lookup_family(lle, family); + if (flags & LLE_UNLOCKED) return (lle); diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h --- a/sys/netinet6/nd6.h +++ b/sys/netinet6/nd6.h @@ -379,6 +379,7 @@ bool nd6_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, char *lladdr); struct mbuf *nd6_grab_holdchain(struct llentry *); int nd6_flush_holdchain(struct ifnet *, struct llentry *, struct mbuf *); +void nd6_flush_children_holdchain(struct ifnet *, struct llentry *); int nd6_add_ifa_lle(struct in6_ifaddr *); void nd6_rem_ifa_lle(struct in6_ifaddr *, int); int nd6_output_ifp(struct ifnet *, struct ifnet *, struct mbuf *, diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c --- a/sys/netinet6/nd6.c +++ b/sys/netinet6/nd6.c @@ -139,7 +139,7 @@ static void nd6_llinfo_timer(void *); static void nd6_llinfo_settimer_locked(struct llentry *, long); static void clear_llinfo_pqueue(struct llentry *); -static int nd6_resolve_slow(struct ifnet *, int, struct mbuf *, +static int nd6_resolve_slow(struct ifnet *, int, int, struct mbuf *, const struct sockaddr_in6 *, u_char *, uint32_t *, struct llentry **); static int nd6_need_cache(struct ifnet *); @@ -530,6 +530,10 @@ LLE_WLOCK_ASSERT(ln); + /* Do not schedule timers for child LLEs. */ + if (ln->la_flags & LLE_CHILD) + return; + if (tick < 0) { ln->la_expire = 0; ln->ln_ntick = 0; @@ -1375,40 +1379,76 @@ * Even if the address matches none of our addresses, it might be * in the neighbor cache. */ - if ((lle = nd6_lookup(&addr->sin6_addr, 0, ifp)) != NULL) { + if ((lle = nd6_lookup(&addr->sin6_addr, LLE_SF(AF_INET6, 0), ifp)) != NULL) { LLE_RUNLOCK(lle); rc = 1; } return (rc); } +static __noinline void +nd6_free_children(struct llentry *lle) +{ + struct llentry *child_lle; + + NET_EPOCH_ASSERT(); + LLE_WLOCK_ASSERT(lle); + + while ((child_lle = CK_SLIST_FIRST(&lle->lle_children)) != NULL) { + LLE_WLOCK(child_lle); + lltable_unlink_child_entry(child_lle); + llentry_free(child_lle); + } +} + /* * Tries to update @lle address/prepend data with new @lladdr. * * Returns true on success. * In any case, @lle is returned wlocked. */ -bool -nd6_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, char *lladdr) +static __noinline bool +nd6_try_set_entry_addr_locked(struct ifnet *ifp, struct llentry *lle, char *lladdr) { - u_char linkhdr[LLE_MAX_LINKHDR]; - size_t linkhdrsize; - int lladdr_off; - - LLE_WLOCK_ASSERT(lle); + u_char buf[LLE_MAX_LINKHDR]; + int fam, off; + size_t sz; - linkhdrsize = sizeof(linkhdr); - if (lltable_calc_llheader(ifp, AF_INET6, lladdr, - linkhdr, &linkhdrsize, &lladdr_off) != 0) { + sz = sizeof(buf); + if (lltable_calc_llheader(ifp, AF_INET6, lladdr, buf, &sz, &off) != 0) return (false); + + /* Update data */ + lltable_set_entry_addr(ifp, lle, buf, sz, off); + + struct llentry *child_lle; + CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { + LLE_WLOCK(child_lle); + fam = child_lle->r_family; + sz = sizeof(buf); + if (lltable_calc_llheader(ifp, fam, lladdr, buf, &sz, &off) == 0) { + /* success */ + lltable_set_entry_addr(ifp, child_lle, buf, sz, off); + child_lle->ln_state = ND6_LLINFO_REACHABLE; + } + LLE_WUNLOCK(child_lle); } + return (true); +} + +bool +nd6_try_set_entry_addr(struct ifnet *ifp, struct llentry *lle, char *lladdr) +{ + NET_EPOCH_ASSERT(); + LLE_WLOCK_ASSERT(lle); + if (!lltable_acquire_wlock(ifp, lle)) return (false); - lltable_set_entry_addr(ifp, lle, linkhdr, linkhdrsize, lladdr_off); + bool ret = nd6_try_set_entry_addr_locked(ifp, lle, lladdr); IF_AFDATA_WUNLOCK(ifp); - return (true); + return (ret); } /* @@ -1432,6 +1472,8 @@ LLE_WLOCK_ASSERT(ln); ND6_RLOCK_ASSERT(); + KASSERT((ln->la_flags & LLE_CHILD) == 0, ("child lle")); + ifp = lltable_get_ifp(ln->lle_tbl); if ((ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) != 0) dr = defrouter_lookup_locked(&ln->r_l3addr.addr6, ifp); @@ -1553,6 +1595,8 @@ } IF_AFDATA_UNLOCK(ifp); + nd6_free_children(ln); + llentry_free(ln); if (dr != NULL) defrouter_rele(dr); @@ -1827,7 +1871,7 @@ return (error); NET_EPOCH_ENTER(et); - ln = nd6_lookup(&nb_addr, 0, ifp); + ln = nd6_lookup(&nb_addr, LLE_SF(AF_INET6, 0), ifp); NET_EPOCH_EXIT(et); if (ln == NULL) { @@ -1977,7 +2021,7 @@ * description on it in NS section (RFC 2461 7.2.3). */ flags = lladdr ? LLE_EXCLUSIVE : 0; - ln = nd6_lookup(from, flags, ifp); + ln = nd6_lookup(from, LLE_SF(AF_INET6, flags), ifp); is_newentry = 0; if (ln == NULL) { flags |= LLE_EXCLUSIVE; @@ -2001,7 +2045,7 @@ IF_AFDATA_WLOCK(ifp); LLE_WLOCK(ln); /* Prefer any existing lle over newly-created one */ - ln_tmp = nd6_lookup(from, LLE_EXCLUSIVE, ifp); + ln_tmp = nd6_lookup(from, LLE_SF(AF_INET6, LLE_EXCLUSIVE), ifp); if (ln_tmp == NULL) lltable_link_entry(LLTABLE6(ifp), ln); IF_AFDATA_WUNLOCK(ifp); @@ -2086,6 +2130,8 @@ if (chain != NULL) nd6_flush_holdchain(ifp, ln, chain); + if (do_update) + nd6_flush_children_holdchain(ifp, ln); /* * When the link-layer address of a router changes, select the @@ -2227,7 +2273,7 @@ * - other errors (alloc failure, etc) */ int -nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m, +nd6_resolve(struct ifnet *ifp, int gw_flags, struct mbuf *m, const struct sockaddr *sa_dst, u_char *desten, uint32_t *pflags, struct llentry **plle) { @@ -2261,8 +2307,9 @@ } } - ln = nd6_lookup(&dst6->sin6_addr, plle ? LLE_EXCLUSIVE : LLE_UNLOCKED, - ifp); + int family = gw_flags >> 16; + int lookup_flags = plle ? LLE_EXCLUSIVE : LLE_UNLOCKED; + ln = nd6_lookup(&dst6->sin6_addr, LLE_SF(family, lookup_flags), ifp); if (ln != NULL && (ln->r_flags & RLLE_VALID) != 0) { /* Entry found, let's copy lle info */ bcopy(ln->r_linkdata, desten, ln->r_hdrlen); @@ -2278,19 +2325,39 @@ } else if (plle && ln) LLE_WUNLOCK(ln); - return (nd6_resolve_slow(ifp, 0, m, dst6, desten, pflags, plle)); + return (nd6_resolve_slow(ifp, family, 0, m, dst6, desten, pflags, plle)); } /* - * Finds or creates a new llentry for @addr. + * Finds or creates a new llentry for @addr and @family. * Returns wlocked llentry or NULL. + * + * + * Child LLEs. + * + * Do not have their own state machine (gets marked as static) + * settimer bails out for child LLEs just in case. + * + * Locking order: parent lle gets locked first, chen goes the child. */ static __noinline struct llentry * -nd6_get_llentry(struct ifnet *ifp, const struct in6_addr *addr) +nd6_get_llentry(struct ifnet *ifp, const struct in6_addr *addr, int family) { + struct llentry *child_lle = NULL; struct llentry *lle, *lle_tmp; lle = nd6_alloc(addr, 0, ifp); + if (lle != NULL && family != AF_INET6) { + child_lle = nd6_alloc(addr, 0, ifp); + if (child_lle == NULL) { + lltable_free_entry(LLTABLE6(ifp), lle); + return (NULL); + } + child_lle->r_family = family; + child_lle->la_flags |= LLE_CHILD | LLE_STATIC; + child_lle->ln_state = ND6_LLINFO_INCOMPLETE; + } + if (lle == NULL) { char ip6buf[INET6_ADDRSTRLEN]; log(LOG_DEBUG, @@ -2303,15 +2370,30 @@ IF_AFDATA_WLOCK(ifp); LLE_WLOCK(lle); /* Prefer any existing entry over newly-created one */ - lle_tmp = nd6_lookup(addr, LLE_EXCLUSIVE, ifp); + lle_tmp = nd6_lookup(addr, LLE_SF(AF_INET6, LLE_EXCLUSIVE), ifp); if (lle_tmp == NULL) lltable_link_entry(LLTABLE6(ifp), lle); - IF_AFDATA_WUNLOCK(ifp); - if (lle_tmp != NULL) { + else { lltable_free_entry(LLTABLE6(ifp), lle); - return (lle_tmp); - } else - return (lle); + lle = lle_tmp; + } + if (child_lle != NULL) { + /* Check if child lle for the same family exists */ + lle_tmp = llentry_lookup_family(lle, child_lle->r_family); + LLE_WLOCK(child_lle); + if (lle_tmp == NULL) { + /* Attach */ + lltable_link_child_entry(lle, child_lle); + } else { + /* child lle already exists, free newly-created one */ + lltable_free_entry(LLTABLE6(ifp), child_lle); + child_lle = lle_tmp; + } + LLE_WUNLOCK(lle); + lle = child_lle; + } + IF_AFDATA_WUNLOCK(ifp); + return (lle); } /* @@ -2326,7 +2408,7 @@ * Set noinline to be dtrace-friendly */ static __noinline int -nd6_resolve_slow(struct ifnet *ifp, int flags, struct mbuf *m, +nd6_resolve_slow(struct ifnet *ifp, int family, int flags, struct mbuf *m, const struct sockaddr_in6 *dst, u_char *desten, uint32_t *pflags, struct llentry **plle) { @@ -2343,14 +2425,14 @@ * At this point, the destination of the packet must be a unicast * or an anycast address(i.e. not a multicast). */ - lle = nd6_lookup(&dst->sin6_addr, LLE_EXCLUSIVE, ifp); + lle = nd6_lookup(&dst->sin6_addr, LLE_SF(family, LLE_EXCLUSIVE), ifp); if ((lle == NULL) && nd6_is_addr_neighbor(dst, ifp)) { /* * 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. */ - lle = nd6_get_llentry(ifp, &dst->sin6_addr); + lle = nd6_get_llentry(ifp, &dst->sin6_addr, family); } if (lle == NULL) { @@ -2367,7 +2449,7 @@ * neighbor unreachability detection on expiration. * (RFC 2461 7.3.3) */ - if (lle->ln_state == ND6_LLINFO_STALE) + if ((!(lle->la_flags & LLE_CHILD)) && (lle->ln_state == ND6_LLINFO_STALE)) nd6_llinfo_setstate(lle, ND6_LLINFO_DELAY); /* @@ -2432,6 +2514,14 @@ */ psrc = NULL; send_ns = 0; + + /* If we have child lle, switch to the parent to send NS */ + if (lle->la_flags & LLE_CHILD) { + struct llentry *lle_parent = lle->lle_parent; + LLE_WUNLOCK(lle); + lle = lle_parent; + LLE_WLOCK(lle); + } if (lle->la_asked == 0) { lle->la_asked++; send_ns = 1; @@ -2463,7 +2553,7 @@ int error; flags |= LLE_ADDRONLY; - error = nd6_resolve_slow(ifp, flags, NULL, + error = nd6_resolve_slow(ifp, AF_INET6, flags, NULL, (const struct sockaddr_in6 *)dst, desten, pflags, NULL); return (error); } @@ -2499,6 +2589,22 @@ return (error); } +__noinline void +nd6_flush_children_holdchain(struct ifnet *ifp, struct llentry *lle) +{ + struct llentry *child_lle; + struct mbuf *chain; + + NET_EPOCH_ASSERT(); + + CK_SLIST_FOREACH(child_lle, &lle->lle_children, lle_child_next) { + LLE_WLOCK(child_lle); + chain = nd6_grab_holdchain(child_lle); + LLE_WUNLOCK(child_lle); + nd6_flush_holdchain(ifp, child_lle, chain); + } +} + static int nd6_need_cache(struct ifnet *ifp) { @@ -2552,7 +2658,7 @@ IF_AFDATA_WLOCK(ifp); LLE_WLOCK(ln); /* Unlink any entry if exists */ - ln_tmp = lla_lookup(LLTABLE6(ifp), LLE_EXCLUSIVE, dst); + ln_tmp = lla_lookup(LLTABLE6(ifp), LLE_SF(AF_INET6, LLE_EXCLUSIVE), dst); if (ln_tmp != NULL) lltable_unlink_entry(LLTABLE6(ifp), ln_tmp); lltable_link_entry(LLTABLE6(ifp), ln); diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c --- a/sys/netinet6/nd6_nbr.c +++ b/sys/netinet6/nd6_nbr.c @@ -630,6 +630,7 @@ size_t linkhdrsize; int flags, is_override, is_router, is_solicited; int lladdr_off, lladdrlen, checklink; + bool flush_holdchain = false; NET_EPOCH_ASSERT(); @@ -747,7 +748,7 @@ * If no neighbor cache entry is found, NA SHOULD silently be * discarded. */ - ln = nd6_lookup(&taddr6, LLE_EXCLUSIVE, ifp); + ln = nd6_lookup(&taddr6, LLE_SF(AF_INET6, LLE_EXCLUSIVE), ifp); if (ln == NULL) { goto freeit; } @@ -773,6 +774,7 @@ if (!nd6_try_set_entry_addr(ifp, ln, lladdr)) goto freeit; + flush_holdchain = true; EVENTHANDLER_INVOKE(lle_event, ln, LLENTRY_RESOLVED); if (is_solicited) nd6_llinfo_setstate(ln, ND6_LLINFO_REACHABLE); @@ -899,6 +901,8 @@ if (chain != NULL) nd6_flush_holdchain(ifp, ln, chain); + if (flush_holdchain) + nd6_flush_children_holdchain(ifp, ln); if (checklink) pfxlist_onlink_check(); diff --git a/sys/ofed/drivers/infiniband/core/ib_addr.c b/sys/ofed/drivers/infiniband/core/ib_addr.c --- a/sys/ofed/drivers/infiniband/core/ib_addr.c +++ b/sys/ofed/drivers/infiniband/core/ib_addr.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -584,8 +585,8 @@ } else { bool is_gw = (nh->nh_flags & NHF_GATEWAY) != 0; memset(edst, 0, MAX_ADDR_LEN); - error = nd6_resolve(ifp, is_gw, NULL, is_gw ? - &nh->gw_sa : (const struct sockaddr *)&dst_tmp, + error = nd6_resolve(ifp, LLE_SF(AF_INET6, is_gw), NULL, + is_gw ? &nh->gw_sa : (const struct sockaddr *)&dst_tmp, edst, NULL, NULL); if (error != 0) goto error_put_ifp;