Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137907699
D31379.id93951.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
39 KB
Referenced Files
None
Subscribers
None
D31379.id93951.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D31379: [lltable] Add support for "child" LLEs holding encap for IPv4oIPv6 entries.
Attached
Detach File
Event Timeline
Log In to Comment