aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorZhenlei Huang <zlei.huang@gmail.com>2021-08-22 22:28:47 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2021-08-22 22:56:08 +0000
commit62e1a437f3285e785d9b35a476d36a469a90028d (patch)
tree371cf19e2cae5884ebac7bc3a864d2b056aa7f1c /sys/net
parenteccb516db8b7fec957b139c3a9a2e16175551067 (diff)
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/debugnet.c1
-rw-r--r--sys/net/if_disc.c2
-rw-r--r--sys/net/if_ethersubr.c11
-rw-r--r--sys/net/if_fwsubr.c28
-rw-r--r--sys/net/if_gif.c2
-rw-r--r--sys/net/if_gre.c2
-rw-r--r--sys/net/if_infiniband.c7
-rw-r--r--sys/net/if_loop.c2
-rw-r--r--sys/net/if_me.c4
-rw-r--r--sys/net/if_spppsubr.c11
-rw-r--r--sys/net/if_tuntap.c2
-rw-r--r--sys/net/route.h4
-rw-r--r--sys/net/route/route_ctl.c30
13 files changed, 80 insertions, 26 deletions
diff --git a/sys/net/debugnet.c b/sys/net/debugnet.c
index bb59ff33a93f..8652597c55db 100644
--- a/sys/net/debugnet.c
+++ b/sys/net/debugnet.c
@@ -673,6 +673,7 @@ debugnet_connect(const struct debugnet_conn_params *dcp,
goto cleanup;
}
+ /* TODO support AF_INET6 */
if (nh->gw_sa.sa_family == AF_INET)
gw_sin = &nh->gw4_sa;
else {
diff --git a/sys/net/if_disc.c b/sys/net/if_disc.c
index ac0028c42f70..14d544dfd86a 100644
--- a/sys/net/if_disc.c
+++ b/sys/net/if_disc.c
@@ -185,7 +185,7 @@ discoutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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);
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 6d8b79d4dd12..3209e8a82978 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -236,10 +236,11 @@ ether_resolve_addr(struct ifnet *ifp, struct mbuf *m,
#endif
#ifdef INET6
case AF_INET6:
- if ((m->m_flags & M_MCAST) == 0)
- error = nd6_resolve(ifp, LLE_SF(AF_INET6, 0), m, dst, phdr,
+ 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 {
+ } 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 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
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 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
*/
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);
}
diff --git a/sys/net/if_fwsubr.c b/sys/net/if_fwsubr.c
index a6c43d4d05a4..321721737d36 100644
--- a/sys/net/if_fwsubr.c
+++ b/sys/net/if_fwsubr.c
@@ -94,6 +94,7 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#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 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
if (error)
return (error == EWOULDBLOCK ? 0 : error);
}
- type = ETHERTYPE_IP;
break;
case AF_ARP:
@@ -159,7 +179,6 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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 @@ firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#ifdef INET6
case AF_INET6:
if (unicast) {
- error = nd6_resolve(fc->fc_ifp, LLE_SF(AF_INET6, 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
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 113bcb5c916e..796f427e356b 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -409,7 +409,7 @@ gif_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
index 19014f9fd3de..5ad452ac38e0 100644
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -613,7 +613,7 @@ gre_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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
diff --git a/sys/net/if_infiniband.c b/sys/net/if_infiniband.c
index 244b2a5ba117..4dfbd5272d15 100644
--- a/sys/net/if_infiniband.c
+++ b/sys/net/if_infiniband.c
@@ -253,8 +253,9 @@ infiniband_resolve_addr(struct ifnet *ifp, struct mbuf *m,
#ifdef INET6
case AF_INET6:
if ((m->m_flags & M_MCAST) == 0) {
- error = nd6_resolve(ifp, LLE_SF(AF_INET6, 0), m, dst,
- phdr, &lleflags, plle);
+ int af = RO_GET_FAMILY(ro, dst);
+ error = nd6_resolve(ifp, LLE_SF(af, 0), m, dst, phdr,
+ &lleflags, plle);
} else {
infiniband_ipv6_multicast_map(
&((const struct sockaddr_in6 *)dst)->sin6_addr,
@@ -371,7 +372,7 @@ infiniband_output(struct ifnet *ifp, struct mbuf *m,
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));
}
/*
diff --git a/sys/net/if_loop.c b/sys/net/if_loop.c
index cbff8200806a..643ef2240fe1 100644
--- a/sys/net/if_loop.c
+++ b/sys/net/if_loop.c
@@ -235,7 +235,7 @@ looutput(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
if (dst->sa_family == AF_UNSPEC || dst->sa_family == pseudo_AF_HDRCMPLT)
bcopy(dst->sa_data, &af, sizeof(af));
else
- af = dst->sa_family;
+ af = RO_GET_FAMILY(ro, dst);
#if 1 /* XXX */
switch (af) {
diff --git a/sys/net/if_me.c b/sys/net/if_me.c
index aafc07c2b203..067ab22cd84d 100644
--- a/sys/net/if_me.c
+++ b/sys/net/if_me.c
@@ -533,14 +533,14 @@ drop:
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));
}
diff --git a/sys/net/if_spppsubr.c b/sys/net/if_spppsubr.c
index fbf7b0ea8f4c..804367025532 100644
--- a/sys/net/if_spppsubr.c
+++ b/sys/net/if_spppsubr.c
@@ -780,6 +780,7 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
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 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
* 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 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
}
#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 @@ sppp_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
#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 @@ nobufs: if (debug)
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)
diff --git a/sys/net/if_tuntap.c b/sys/net/if_tuntap.c
index b4b1b77ddc7c..bd9fc811d19f 100644
--- a/sys/net/if_tuntap.c
+++ b/sys/net/if_tuntap.c
@@ -1402,7 +1402,7 @@ tunoutput(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
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), m0);
diff --git a/sys/net/route.h b/sys/net/route.h
index 67217f237e0b..ec77d39b9649 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -394,6 +394,10 @@ struct rt_addrinfo {
} \
} 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
diff --git a/sys/net/route/route_ctl.c b/sys/net/route/route_ctl.c
index a686d1623053..6db088102cd3 100644
--- a/sys/net/route/route_ctl.c
+++ b/sys/net/route/route_ctl.c
@@ -106,6 +106,14 @@ SYSCTL_UINT(_net_route, OID_AUTO, multipath, _MP_FLAGS | CTLFLAG_VNET,
&VNET_NAME(rib_route_multipath), 0, "Enable route multipath");
#undef _MP_FLAGS
+#if defined(INET) && defined(INET6)
+FEATURE(ipv4_rfc5549_support, "Route IPv4 packets via IPv6 nexthops");
+#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 +205,20 @@ get_rnh(uint32_t fibnum, const struct rt_addrinfo *info)
return (rnh);
}
+#if defined(INET) && defined(INET6)
+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,7 +604,13 @@ check_gateway(struct rib_head *rnh, struct sockaddr *dst,
return (true);
else if (gateway->sa_family == AF_LINK)
return (true);
- return (false);
+#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
+ else
+ return (false);
}
/*