Page MenuHomeFreeBSD

D31379.id93951.diff
No OneTemporary

D31379.id93951.diff

Index: sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
===================================================================
--- sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
+++ sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
@@ -689,7 +689,9 @@
register struct mbuf *m = *mpp;
int len, off, error = 0, hlen, code;
struct ifnet *ifp, *sifp;
- struct sockaddr_in dst;
+ struct route ro;
+ struct sockaddr_in *dst;
+ const struct sockaddr *gw;
struct nhop_object *nh;
u_long fibnum = 0;
u_short ip_off;
@@ -739,10 +741,12 @@
/*
* Route packet.
*/
- bzero(&dst, sizeof (dst));
- dst.sin_family = AF_INET;
- dst.sin_addr = ip->ip_dst;
- dst.sin_len = sizeof(dst);
+ bzero(&ro, sizeof (ro));
+ dst = (struct sockaddr_in *)&ro.ro_dst;
+ dst->sin_family = AF_INET;
+ dst->sin_addr = ip->ip_dst;
+ dst->sin_len = sizeof(dst);
+ gw = (const struct sockaddr *)dst;
fr = fin->fin_fr;
if ((fr != NULL) && !(fr->fr_flags & FR_KEEPSTATE) && (fdp != NULL) &&
@@ -762,11 +766,11 @@
}
if ((fdp != NULL) && (fdp->fd_ip.s_addr != 0))
- dst.sin_addr = fdp->fd_ip;
+ dst->sin_addr = fdp->fd_ip;
fibnum = M_GETFIB(m0);
NET_EPOCH_ASSERT();
- nh = fib4_lookup(fibnum, dst.sin_addr, 0, NHR_NONE, 0);
+ nh = fib4_lookup(fibnum, dst->sin_addr, 0, NHR_NONE, 0);
if (nh == NULL) {
if (in_localaddr(ip->ip_dst))
error = EHOSTUNREACH;
@@ -777,8 +781,10 @@
if (ifp == NULL)
ifp = nh->nh_ifp;
- if (nh->nh_flags & NHF_GATEWAY)
- dst.sin_addr = nh->gw4_sa.sin_addr;
+ if (nh->nh_flags & NHF_GATEWAY) {
+ gw = &nh->gw_sa;
+ ro.ro_flags |= RT_HAS_GW;
+ }
/*
* For input packets which are being "fastrouted", they won't
@@ -822,9 +828,7 @@
if (ntohs(ip->ip_len) <= ifp->if_mtu) {
if (!ip->ip_sum)
ip->ip_sum = in_cksum(m, hlen);
- error = (*ifp->if_output)(ifp, m, (struct sockaddr *)&dst,
- NULL
- );
+ error = (*ifp->if_output)(ifp, m, gw, &ro);
goto done;
}
/*
@@ -904,10 +908,7 @@
m0 = m->m_act;
m->m_act = 0;
if (error == 0)
- error = (*ifp->if_output)(ifp, m,
- (struct sockaddr *)&dst,
- NULL
- );
+ error = (*ifp->if_output)(ifp, m, gw, &ro);
else
FREE_MB_T(m);
}
Index: sys/dev/cxgbe/tom/t4_listen.c
===================================================================
--- sys/dev/cxgbe/tom/t4_listen.c
+++ sys/dev/cxgbe/tom/t4_listen.c
@@ -1113,7 +1113,14 @@
if (nh->nh_ifp != ifp)
return (NULL);
if (nh->nh_flags & NHF_GATEWAY)
- ((struct sockaddr_in *)dst)->sin_addr = nh->gw4_sa.sin_addr;
+ if (nh->gw_sa.sa_family == AF_INET)
+ ((struct sockaddr_in *)dst)->sin_addr = nh->gw4_sa.sin_addr;
+ else {
+ bzero(dst, sizeof(struct sockaddr_in6));
+ dst->sa_len = sizeof(struct sockaddr_in6);
+ dst->sa_family = AF_INET6;
+ ((struct sockaddr_in6 *)dst)->sin6_addr = nh->gw6_sa.sin6_addr;
+ }
else
((struct sockaddr_in *)dst)->sin_addr = inc->inc_faddr;
}
Index: sys/dev/iicbus/if_ic.c
===================================================================
--- sys/dev/iicbus/if_ic.c
+++ sys/dev/iicbus/if_ic.c
@@ -372,7 +372,7 @@
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &hdr, sizeof(hdr));
else
- hdr = dst->sa_family;
+ hdr = RO_GET_FAMILY(ro, dst);
mtx_lock(&sc->ic_lock);
ifp->if_drv_flags |= IFF_DRV_RUNNING;
Index: sys/net/debugnet.c
===================================================================
--- sys/net/debugnet.c
+++ sys/net/debugnet.c
@@ -673,6 +673,7 @@
goto cleanup;
}
+ /* TODO support AF_INET6 */
if (nh->gw_sa.sa_family == AF_INET)
gw_sin = &nh->gw4_sa;
else {
Index: sys/net/if_disc.c
===================================================================
--- sys/net/if_disc.c
+++ sys/net/if_disc.c
@@ -185,7 +185,7 @@
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
- af = dst->sa_family;
+ af = RO_GET_FAMILY(ro, dst);
if (bpf_peers_present(ifp->if_bpf))
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m);
Index: sys/net/if_ethersubr.c
===================================================================
--- sys/net/if_ethersubr.c
+++ sys/net/if_ethersubr.c
@@ -236,10 +236,11 @@
#endif
#ifdef INET6
case AF_INET6:
- if ((m->m_flags & M_MCAST) == 0)
- error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags,
- plle);
- else {
+ if ((m->m_flags & M_MCAST) == 0) {
+ int af = RO_GET_FAMILY(ro, dst);
+ error = nd6_resolve(ifp, LLE_SF(af, 0), m, dst, phdr,
+ &lleflags, plle);
+ } else {
const struct in6_addr *a6;
a6 = &(((const struct sockaddr_in6 *)dst)->sin6_addr);
ETHER_MAP_IPV6_MULTICAST(a6, eh->ether_dhost);
@@ -353,7 +354,7 @@
if ((pflags & RT_L2_ME) != 0) {
update_mbuf_csumflags(m, m);
- return (if_simloop(ifp, m, dst->sa_family, 0));
+ return (if_simloop(ifp, m, RO_GET_FAMILY(ro, dst), 0));
}
loop_copy = (pflags & RT_MAY_LOOP) != 0;
@@ -400,7 +401,7 @@
*/
if ((n = m_dup(m, M_NOWAIT)) != NULL) {
update_mbuf_csumflags(m, n);
- (void)if_simloop(ifp, n, dst->sa_family, hlen);
+ (void)if_simloop(ifp, n, RO_GET_FAMILY(ro, dst), hlen);
} else
if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
}
Index: sys/net/if_fwsubr.c
===================================================================
--- sys/net/if_fwsubr.c
+++ sys/net/if_fwsubr.c
@@ -94,6 +94,7 @@
#if defined(INET) || defined(INET6)
int is_gw = 0;
#endif
+ int af = RO_GET_FAMILY(ro, dst);
#ifdef MAC
error = mac_ifnet_check_transmit(ifp, m);
@@ -137,6 +138,26 @@
destfw = NULL;
}
+ switch (af) {
+#ifdef INET
+ case AF_INET:
+ type = ETHERTYPE_IP;
+ break;
+ case AF_ARP:
+ type = ETHERTYPE_ARP;
+ break;
+#endif
+#ifdef INET6
+ case AF_INET6:
+ type = ETHERTYPE_IPV6;
+ break;
+#endif
+ default:
+ if_printf(ifp, "can't handle af%d\n", af);
+ error = EAFNOSUPPORT;
+ goto bad;
+ }
+
switch (dst->sa_family) {
#ifdef INET
case AF_INET:
@@ -151,7 +172,6 @@
if (error)
return (error == EWOULDBLOCK ? 0 : error);
}
- type = ETHERTYPE_IP;
break;
case AF_ARP:
@@ -159,7 +179,6 @@
struct arphdr *ah;
ah = mtod(m, struct arphdr *);
ah->ar_hrd = htons(ARPHRD_IEEE1394);
- type = ETHERTYPE_ARP;
if (unicast)
*destfw = *(struct fw_hwaddr *) ar_tha(ah);
@@ -176,12 +195,11 @@
#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, is_gw), m,
+ dst, (u_char *) destfw, NULL, NULL);
if (error)
return (error == EWOULDBLOCK ? 0 : error);
}
- type = ETHERTYPE_IPV6;
break;
#endif
Index: sys/net/if_gif.c
===================================================================
--- sys/net/if_gif.c
+++ sys/net/if_gif.c
@@ -409,7 +409,7 @@
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
- af = dst->sa_family;
+ af = RO_GET_FAMILY(ro, dst);
/*
* Now save the af in the inbound pkt csum data, this is a cheat since
* we are using the inbound csum_data field to carry the af over to
Index: sys/net/if_gre.c
===================================================================
--- sys/net/if_gre.c
+++ sys/net/if_gre.c
@@ -613,7 +613,7 @@
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
- af = dst->sa_family;
+ af = RO_GET_FAMILY(ro, dst);
/*
* Now save the af in the inbound pkt csum data, this is a cheat since
* we are using the inbound csum_data field to carry the af over to
Index: sys/net/if_infiniband.c
===================================================================
--- sys/net/if_infiniband.c
+++ sys/net/if_infiniband.c
@@ -253,7 +253,9 @@
#ifdef INET6
case AF_INET6:
if ((m->m_flags & M_MCAST) == 0) {
- error = nd6_resolve(ifp, 0, m, dst, phdr, &lleflags, plle);
+ int af = RO_GET_FAMILY(ro, dst);
+ error = nd6_resolve(ifp, LLE_SA(af, 0), m, dst,
+ phdr, &lleflags, plle);
} else {
infiniband_ipv6_multicast_map(
&((const struct sockaddr_in6 *)dst)->sin6_addr,
@@ -370,7 +372,7 @@
if ((pflags & RT_L2_ME) != 0) {
update_mbuf_csumflags(m, m);
- return (if_simloop(ifp, m, dst->sa_family, 0));
+ return (if_simloop(ifp, m, RO_GET_FAMILY(ro, dst), 0));
}
/*
Index: sys/net/if_llatbl.h
===================================================================
--- sys/net/if_llatbl.h
+++ 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 *);
Index: sys/net/if_llatbl.c
===================================================================
--- sys/net/if_llatbl.c
+++ 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)
{
Index: sys/net/if_me.c
===================================================================
--- sys/net/if_me.c
+++ sys/net/if_me.c
@@ -533,14 +533,14 @@
static int
me_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
- struct route *ro __unused)
+ struct route *ro)
{
uint32_t af;
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
- af = dst->sa_family;
+ af = RO_GET_FAMILY(ro, dst);
m->m_pkthdr.csum_data = af;
return (ifp->if_transmit(ifp, m));
}
Index: sys/net/if_spppsubr.c
===================================================================
--- sys/net/if_spppsubr.c
+++ sys/net/if_spppsubr.c
@@ -780,6 +780,7 @@
int ipproto = PPP_IP;
#endif
int debug = ifp->if_flags & IFF_DEBUG;
+ int af = RO_GET_FAMILY(ro, dst);
SPPP_LOCK(sp);
@@ -805,7 +806,7 @@
* dialout event in case IPv6 has been
* administratively disabled on that interface.
*/
- if (dst->sa_family == AF_INET6 &&
+ if (af == AF_INET6 &&
!(sp->confflags & CONF_ENABLE_IPV6))
goto drop;
#endif
@@ -818,7 +819,7 @@
}
#ifdef INET
- if (dst->sa_family == AF_INET) {
+ if (af == AF_INET) {
/* XXX Check mbuf length here? */
struct ip *ip = mtod (m, struct ip*);
struct tcphdr *tcp = (struct tcphdr*) ((long*)ip + ip->ip_hl);
@@ -888,14 +889,14 @@
#endif
#ifdef INET6
- if (dst->sa_family == AF_INET6) {
+ if (af == AF_INET6) {
/* XXX do something tricky here? */
}
#endif
if (sp->pp_mode == PP_FR) {
/* Add frame relay header. */
- m = sppp_fr_header (sp, m, dst->sa_family);
+ m = sppp_fr_header (sp, m, af);
if (! m)
goto nobufs;
goto out;
@@ -926,7 +927,7 @@
h->control = PPP_UI; /* Unnumbered Info */
}
- switch (dst->sa_family) {
+ switch (af) {
#ifdef INET
case AF_INET: /* Internet Protocol */
if (sp->pp_mode == IFF_CISCO)
Index: sys/net/if_stf.c
===================================================================
--- sys/net/if_stf.c
+++ sys/net/if_stf.c
@@ -427,6 +427,7 @@
#endif
sc = ifp->if_softc;
+ /* FIXME possible sockaddr_in gw ? */
dst6 = (const struct sockaddr_in6 *)dst;
/* just in case */
Index: sys/net/if_tuntap.c
===================================================================
--- sys/net/if_tuntap.c
+++ sys/net/if_tuntap.c
@@ -1401,8 +1401,9 @@
/* BPF writes need to be handled specially. */
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
+ /* FIXME TUN is p-t-p device */
else
- af = dst->sa_family;
+ af = RO_GET_FAMILY(ro, dst);
if (bpf_peers_present(ifp->if_bpf))
bpf_mtap2(ifp->if_bpf, &af, sizeof(af), m0);
Index: sys/net/route.h
===================================================================
--- sys/net/route.h
+++ sys/net/route.h
@@ -394,6 +394,10 @@
} \
} while (0)
+#define RO_GET_FAMILY(ro, dst) ((ro) != NULL && \
+ (ro)->ro_flags & RT_HAS_GW \
+ ? (ro)->ro_dst.sa_family : (dst)->sa_family)
+
/*
* Validate a cached route based on a supplied cookie. If there is an
* out-of-date cache, simply free it. Update the generation number
Index: sys/net/route/route_ctl.c
===================================================================
--- sys/net/route/route_ctl.c
+++ sys/net/route/route_ctl.c
@@ -106,6 +106,20 @@
&VNET_NAME(rib_route_multipath), 0, "Enable route multipath");
#undef _MP_FLAGS
+#if defined(INET) && defined(INET6)
+/*
+#define V_rib_route_ipv4_nexthop VNET(rib_route_ipv4_nexthop)
+VNET_DEFINE(u_int, rib_route_ipv4_nexthop) = 1;
+SYSCTL_UINT(_net_route, OID_AUTO, ipv4_nexthop, CTLFLAG_RW | CTLFLAG_VNET,
+ &VNET_NAME(rib_route_ipv4_nexthop), 0, "Enable IPv6 route via IPv4 Next Hop address");
+*/
+
+#define V_rib_route_ipv6_nexthop VNET(rib_route_ipv6_nexthop)
+VNET_DEFINE(u_int, rib_route_ipv6_nexthop) = 1;
+SYSCTL_UINT(_net_route, OID_AUTO, ipv6_nexthop, CTLFLAG_RW | CTLFLAG_VNET,
+ &VNET_NAME(rib_route_ipv6_nexthop), 0, "Enable IPv4 route via IPv6 Next Hop address");
+#endif
+
/* Routing table UMA zone */
VNET_DEFINE_STATIC(uma_zone_t, rtzone);
#define V_rtzone VNET(rtzone)
@@ -197,6 +211,34 @@
return (rnh);
}
+#if defined(INET) && defined(INET6)
+/*
+static bool
+rib_can_ipv4_nexthop_address(struct rib_head *rh)
+{
+ int result;
+
+ CURVNET_SET(rh->rib_vnet);
+ result = !!V_rib_route_ipv4_nexthop;
+ CURVNET_RESTORE();
+
+ return (result);
+}
+*/
+
+static bool
+rib_can_ipv6_nexthop_address(struct rib_head *rh)
+{
+ int result;
+
+ CURVNET_SET(rh->rib_vnet);
+ result = !!V_rib_route_ipv6_nexthop;
+ CURVNET_RESTORE();
+
+ return (result);
+}
+#endif
+
#ifdef ROUTE_MPATH
static bool
rib_can_multipath(struct rib_head *rh)
@@ -582,6 +624,11 @@
return (true);
else if (gateway->sa_family == AF_LINK)
return (true);
+#if defined(INET) && defined(INET6)
+ else if (dst->sa_family == AF_INET && gateway->sa_family == AF_INET6 &&
+ rib_can_ipv6_nexthop_address(rnh))
+ return (true);
+#endif
return (false);
}
Index: sys/netgraph/netflow/netflow.c
===================================================================
--- sys/netgraph/netflow/netflow.c
+++ sys/netgraph/netflow/netflow.c
@@ -364,6 +364,7 @@
fle->f.fle_o_ifx = nh->nh_ifp->if_index;
if (nh->gw_sa.sa_family == AF_INET)
fle->f.next_hop = nh->gw4_sa.sin_addr;
+ /* FIXME else nh->gw_sa.sa_family == AF_INET6 ? */
fle->f.dst_mask = plen;
}
}
Index: sys/netgraph/ng_iface.c
===================================================================
--- sys/netgraph/ng_iface.c
+++ sys/netgraph/ng_iface.c
@@ -371,7 +371,7 @@
if (dst->sa_family == AF_UNSPEC)
bcopy(dst->sa_data, &af, sizeof(af));
else
- af = dst->sa_family;
+ af = RO_GET_FAMILY(ro, dst);
/* Berkeley packet filter */
ng_iface_bpftap(ifp, m, af);
Index: sys/netinet/ip_fastfwd.c
===================================================================
--- sys/netinet/ip_fastfwd.c
+++ sys/netinet/ip_fastfwd.c
@@ -199,7 +199,9 @@
struct ip *ip;
struct mbuf *m0 = NULL;
struct nhop_object *nh = NULL;
- struct sockaddr_in dst;
+ struct route ro;
+ struct sockaddr_in *dst;
+ const struct sockaddr *gw;
struct in_addr dest, odest, rtdest;
uint16_t ip_len, ip_off;
int error = 0;
@@ -421,19 +423,23 @@
ip_len = ntohs(ip->ip_len);
ip_off = ntohs(ip->ip_off);
- bzero(&dst, sizeof(dst));
- dst.sin_family = AF_INET;
- dst.sin_len = sizeof(dst);
- if (nh->nh_flags & NHF_GATEWAY)
- dst.sin_addr = nh->gw4_sa.sin_addr;
- else
- dst.sin_addr = dest;
+ bzero(&ro, sizeof(ro));
+ dst = (struct sockaddr_in *)&ro.ro_dst;
+ dst->sin_family = AF_INET;
+ dst->sin_len = sizeof(*dst);
+ dst->sin_addr = dest;
+ if (nh->nh_flags & NHF_GATEWAY) {
+ gw = &nh->gw_sa;
+ ro.ro_flags |= RT_HAS_GW;
+ } else
+ gw = (const struct sockaddr *)dst;
/*
* Handle redirect case.
*/
redest.s_addr = 0;
- if (V_ipsendredirects && (nh->nh_ifp == m->m_pkthdr.rcvif))
+ if (V_ipsendredirects && (nh->nh_ifp == m->m_pkthdr.rcvif) &&
+ gw->sa_family == AF_INET)
mcopy = ip_redir_alloc(m, nh, ip, &redest.s_addr);
/*
@@ -448,8 +454,7 @@
* Send off the packet via outgoing interface
*/
IP_PROBE(send, NULL, NULL, ip, nh->nh_ifp, ip, NULL);
- error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m,
- (struct sockaddr *)&dst, NULL);
+ error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m, gw, &ro);
} else {
/*
* Handle EMSGSIZE with icmp reply needfrag for TCP MTU discovery
@@ -484,7 +489,7 @@
mtod(m, struct ip *), nh->nh_ifp,
mtod(m, struct ip *), NULL);
error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m,
- (struct sockaddr *)&dst, NULL);
+ gw, &ro);
if (error)
break;
} while ((m = m0) != NULL);
Index: sys/netinet/ip_input.c
===================================================================
--- sys/netinet/ip_input.c
+++ sys/netinet/ip_input.c
@@ -1065,13 +1065,16 @@
if (nh_ia != NULL &&
(src & nh_ia->ia_subnetmask) == nh_ia->ia_subnet) {
- if (nh->nh_flags & NHF_GATEWAY)
- dest.s_addr = nh->gw4_sa.sin_addr.s_addr;
- else
- dest.s_addr = ip->ip_dst.s_addr;
/* Router requirements says to only send host redirects */
type = ICMP_REDIRECT;
code = ICMP_REDIRECT_HOST;
+ if (nh->nh_flags & NHF_GATEWAY) {
+ if (nh->gw_sa.sa_family == AF_INET)
+ dest.s_addr = nh->gw4_sa.sin_addr.s_addr;
+ else /* Do not redirect in case gw is AF_INET6 */
+ type = 0;
+ } else
+ dest.s_addr = ip->ip_dst.s_addr;
}
}
}
Index: sys/netinet/ip_output.c
===================================================================
--- sys/netinet/ip_output.c
+++ sys/netinet/ip_output.c
@@ -212,7 +212,7 @@
static int
ip_output_send(struct inpcb *inp, struct ifnet *ifp, struct mbuf *m,
- const struct sockaddr_in *gw, struct route *ro, bool stamp_tag)
+ const struct sockaddr *gw, struct route *ro, bool stamp_tag)
{
#ifdef KERN_TLS
struct ktls_session *tls = NULL;
@@ -273,7 +273,7 @@
m->m_pkthdr.csum_flags |= CSUM_SND_TAG;
}
- error = (*ifp->if_output)(ifp, m, (const struct sockaddr *)gw, ro);
+ error = (*ifp->if_output)(ifp, m, gw, ro);
done:
/* Check for route change invalidating send tags. */
@@ -329,12 +329,13 @@
int mtu = 0;
int error = 0;
int vlan_pcp = -1;
- struct sockaddr_in *dst, sin;
- const struct sockaddr_in *gw;
+ struct sockaddr_in *dst;
+ const struct sockaddr *gw;
struct in_ifaddr *ia = NULL;
struct in_addr src;
int isbroadcast;
uint16_t ip_len, ip_off;
+ struct route iproute;
uint32_t fibnum;
#if defined(IPSEC) || defined(IPSEC_SUPPORT)
int no_route_but_check_spd = 0;
@@ -386,23 +387,23 @@
* therefore we need restore gw if we're redoing lookup.
*/
fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : M_GETFIB(m);
- if (ro != NULL)
- dst = (struct sockaddr_in *)&ro->ro_dst;
- else
- dst = &sin;
- if (ro == NULL || ro->ro_nh == NULL) {
- bzero(dst, sizeof(*dst));
+ if (ro == NULL) {
+ ro = &iproute;
+ bzero(ro, sizeof (*ro));
+ }
+ dst = (struct sockaddr_in *)&ro->ro_dst;
+ if (ro->ro_nh == NULL) {
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = ip->ip_dst;
}
- gw = dst;
+ gw = (const struct sockaddr *)dst;
again:
/*
* Validate route against routing table additions;
* a better/more specific route might have been added.
*/
- if (inp != NULL && ro != NULL && ro->ro_nh != NULL)
+ if (inp != NULL && ro->ro_nh != NULL)
NH_VALIDATE(ro, &inp->inp_rt_cookie, fibnum);
/*
* If there is a cached route,
@@ -412,7 +413,7 @@
* cache with IPv6.
* Also check whether routing cache needs invalidation.
*/
- if (ro != NULL && ro->ro_nh != NULL &&
+ if (ro->ro_nh != NULL &&
((!NH_IS_VALID(ro->ro_nh)) || dst->sin_family != AF_INET ||
dst->sin_addr.s_addr != ip->ip_dst.s_addr))
RO_INVALIDATE_CACHE(ro);
@@ -469,7 +470,7 @@
src = IA_SIN(ia)->sin_addr;
else
src.s_addr = INADDR_ANY;
- } else if (ro != NULL) {
+ } else if (ro != &iproute) {
if (ro->ro_nh == NULL) {
/*
* We want to do any cloning requested by the link
@@ -502,11 +503,11 @@
counter_u64_add(nh->nh_pksent, 1);
rt_update_ro_flags(ro, nh);
if (nh->nh_flags & NHF_GATEWAY)
- gw = &nh->gw4_sa;
+ gw = &nh->gw_sa;
if (nh->nh_flags & NHF_HOST)
isbroadcast = (nh->nh_flags & NHF_BROADCAST);
- else if (ifp->if_flags & IFF_BROADCAST)
- isbroadcast = in_ifaddr_broadcast(gw->sin_addr, ia);
+ else if ((ifp->if_flags & IFF_BROADCAST) && (gw->sa_family == AF_INET))
+ isbroadcast = in_ifaddr_broadcast(((const struct sockaddr_in *)gw)->sin_addr, ia);
else
isbroadcast = 0;
mtu = nh->nh_mtu;
@@ -531,6 +532,7 @@
}
ifp = nh->nh_ifp;
mtu = nh->nh_mtu;
+ rt_update_ro_flags(ro, nh);
/*
* We are rewriting here dst to be gw actually, contradicting
* comment at the beginning of the function. However, in this
@@ -538,15 +540,15 @@
* In case if pfil(9) sends us back to beginning of the
* function, the dst would be rewritten by ip_output_pfil().
*/
- MPASS(dst == &sin);
if (nh->nh_flags & NHF_GATEWAY)
- dst->sin_addr = nh->gw4_sa.sin_addr;
+ gw = &nh->gw_sa;
ia = ifatoia(nh->nh_ifa);
src = IA_SIN(ia)->sin_addr;
isbroadcast = (((nh->nh_flags & (NHF_HOST | NHF_BROADCAST)) ==
(NHF_HOST | NHF_BROADCAST)) ||
((ifp->if_flags & IFF_BROADCAST) &&
- in_ifaddr_broadcast(dst->sin_addr, ia)));
+ (gw->sa_family == AF_INET) &&
+ in_ifaddr_broadcast(((const struct sockaddr_in *)gw)->sin_addr, ia)));
}
/* Catch a possible divide by zero later. */
@@ -561,7 +563,7 @@
* still points to the address in "ro". (It may have been
* changed to point to a gateway address, above.)
*/
- gw = dst;
+ gw = (const struct sockaddr *)dst;
/*
* See if the caller provided any multicast options
*/
@@ -721,7 +723,7 @@
RO_NHFREE(ro);
ro->ro_prepend = NULL;
}
- gw = dst;
+ gw = (const struct sockaddr *)dst;
ip = mtod(m, struct ip *);
goto again;
}
Index: sys/netinet/toecore.c
===================================================================
--- sys/netinet/toecore.c
+++ 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:
Index: sys/netinet6/icmp6.c
===================================================================
--- sys/netinet6/icmp6.c
+++ 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;
Index: sys/netinet6/in6.c
===================================================================
--- sys/netinet6/in6.c
+++ 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);
Index: sys/netinet6/nd6.h
===================================================================
--- sys/netinet6/nd6.h
+++ 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 *,
Index: sys/netinet6/nd6.c
===================================================================
--- sys/netinet6/nd6.c
+++ 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);
Index: sys/netinet6/nd6_nbr.c
===================================================================
--- sys/netinet6/nd6_nbr.c
+++ 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();
Index: sys/ofed/drivers/infiniband/core/ib_addr.c
===================================================================
--- sys/ofed/drivers/infiniband/core/ib_addr.c
+++ sys/ofed/drivers/infiniband/core/ib_addr.c
@@ -396,9 +396,16 @@
} else {
bool is_gw = (nh->nh_flags & NHF_GATEWAY) != 0;
memset(edst, 0, MAX_ADDR_LEN);
- error = arpresolve(ifp, is_gw, NULL, is_gw ?
- &nh->gw_sa : (const struct sockaddr *)&dst_tmp,
- edst, NULL, NULL);
+#ifdef INET6
+ if (is_gw && nh->gw_sa.sa_family == AF_INET6)
+ error = nd6_resolve(ifp, LLE_SF(AF_INET, 1), NULL, &nh->gw_sa,
+ edst, NULL, NULL);
+ else
+#endif
+ error = arpresolve(ifp, is_gw, NULL, is_gw ?
+ &nh->gw_sa : (const struct sockaddr *)&dst_tmp,
+ edst, NULL, NULL);
+
if (error != 0)
goto error_put_ifp;
else if (is_gw)
@@ -584,7 +591,7 @@
} 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 ?
+ 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)

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 28, 2:44 AM (22 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
26272029
Default Alt Text
D31379.id93951.diff (39 KB)

Event Timeline