summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/netinet6/icmp6.c4
-rw-r--r--sys/netinet6/in6.c12
-rw-r--r--sys/netinet6/in6_src.c4
-rw-r--r--sys/netinet6/nd6.c72
-rw-r--r--sys/netinet6/nd6.h1
-rw-r--r--sys/netinet6/nd6_nbr.c7
-rw-r--r--sys/netinet6/nd6_rtr.c108
-rwxr-xr-xtests/sys/netinet/fibs_test.sh499
-rw-r--r--tests/sys/netinet/udp_dontroute.c53
9 files changed, 605 insertions, 155 deletions
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index d6d2784..a94ed8f 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -2147,7 +2147,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
* source address of the erroneous packet.
*/
in6_splitscope(&ip6->ip6_src, &dst6, &scopeid);
- error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
+ error = in6_selectsrc_addr(M_GETFIB(m), &dst6,
scopeid, NULL, &src6, &hlim);
if (error) {
@@ -2289,7 +2289,7 @@ icmp6_redirect_input(struct mbuf *m, int off)
uint32_t scopeid;
in6_splitscope(&reddst6, &kdst, &scopeid);
- if (fib6_lookup_nh_basic(RT_DEFAULT_FIB, &kdst, scopeid, 0, 0,&nh6)==0){
+ if (fib6_lookup_nh_basic(ifp->if_fib, &kdst, scopeid, 0, 0,&nh6)==0){
if ((nh6.nh_flags & NHF_GATEWAY) == 0) {
nd6log((LOG_ERR,
"ICMP6 redirect rejected; no route "
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index 8f1cae9..4df3564 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -159,6 +159,7 @@ in6_newaddrmsg(struct in6_ifaddr *ia, int cmd)
struct sockaddr_dl gateway;
struct sockaddr_in6 mask, addr;
struct rtentry rt;
+ int fibnum;
/*
* initialize for rtmsg generation
@@ -176,8 +177,9 @@ in6_newaddrmsg(struct in6_ifaddr *ia, int cmd)
rt.rt_flags = RTF_HOST | RTF_STATIC;
if (cmd == RTM_ADD)
rt.rt_flags |= RTF_UP;
- /* Announce arrival of local address to all FIBs. */
- rt_newaddrmsg(cmd, &ia->ia_ifa, 0, &rt);
+ fibnum = V_rt_add_addr_allfibs ? RT_ALL_FIBS : ia62ifa(ia)->ifa_ifp->if_fib;
+ /* Announce arrival of local address to this FIB. */
+ rt_newaddrmsg_fib(cmd, &ia->ia_ifa, 0, &rt, fibnum);
}
int
@@ -2115,15 +2117,15 @@ in6_lltable_rtcheck(struct ifnet *ifp,
uint32_t scopeid;
int error;
char ip6buf[INET6_ADDRSTRLEN];
+ int fibnum;
KASSERT(l3addr->sa_family == AF_INET6,
("sin_family %d", l3addr->sa_family));
- /* Our local addresses are always only installed on the default FIB. */
-
sin6 = (const struct sockaddr_in6 *)l3addr;
in6_splitscope(&sin6->sin6_addr, &dst, &scopeid);
- error = fib6_lookup_nh_basic(RT_DEFAULT_FIB, &dst, scopeid, 0, 0, &nh6);
+ fibnum = V_rt_add_addr_allfibs ? RT_DEFAULT_FIB : ifp->if_fib;
+ error = fib6_lookup_nh_basic(fibnum, &dst, scopeid, 0, 0, &nh6);
if (error != 0 || (nh6.nh_flags & NHF_GATEWAY) || nh6.nh_ifp != ifp) {
struct ifaddr *ifa;
/*
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 54c0a0a..59d0cb9 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -297,7 +297,7 @@ in6_selectsrc(uint32_t fibnum, struct sockaddr_in6 *dstsock,
*/
/* get the outgoing interface */
if ((error = in6_selectif(dstsock, opts, mopts, &ifp, oifp,
- (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) != 0)
+ (inp != NULL) ? inp->inp_inc.inc_fibnum : fibnum)) != 0)
return (error);
#ifdef DIAGNOSTIC
@@ -563,7 +563,7 @@ in6_selectsrc_socket(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
uint32_t fibnum;
int error;
- fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB;
+ fibnum = inp->inp_inc.inc_fibnum;
retifp = NULL;
error = in6_selectsrc(fibnum, dstsock, opts, inp, cred, &retifp, srcp);
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index ebaaedc..d7a8760 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -157,6 +157,7 @@ nd6_lle_event(void *arg __unused, struct llentry *lle, int evt)
struct sockaddr_dl gw;
struct ifnet *ifp;
int type;
+ int fibnum;
LLE_WLOCK_ASSERT(lle);
@@ -194,8 +195,9 @@ nd6_lle_event(void *arg __unused, struct llentry *lle, int evt)
rtinfo.rti_info[RTAX_DST] = (struct sockaddr *)&dst;
rtinfo.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&gw;
rtinfo.rti_addrs = RTA_DST | RTA_GATEWAY;
+ fibnum = V_rt_add_addr_allfibs ? RT_ALL_FIBS : ifp->if_fib;
rt_missmsg_fib(type, &rtinfo, RTF_HOST | RTF_LLDATA | (
- type == RTM_ADD ? RTF_UP: 0), 0, RT_DEFAULT_FIB);
+ type == RTM_ADD ? RTF_UP: 0), 0, fibnum);
}
/*
@@ -1200,7 +1202,7 @@ nd6_purge(struct ifnet *ifp)
if (ND_IFINFO(ifp)->flags & ND6_IFF_ACCEPT_RTADV) {
/* Refresh default router list. */
- defrouter_select();
+ defrouter_select_fib(ifp->if_fib);
}
}
@@ -1253,7 +1255,7 @@ static int
nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
{
struct nd_prefix *pr;
- struct ifaddr *dstaddr;
+ struct ifaddr *ifa;
struct rt_addrinfo info;
struct sockaddr_in6 rt_key;
const struct sockaddr *dst6;
@@ -1287,9 +1289,6 @@ nd6_is_new_addr_neighbor(const struct sockaddr_in6 *addr, struct ifnet *ifp)
bzero(&info, sizeof(info));
info.rti_info[RTAX_DST] = (struct sockaddr *)&rt_key;
- /* Always use the default FIB here. XXME - why? */
- fibnum = RT_DEFAULT_FIB;
-
/*
* If the address matches one of our addresses,
* it should be a neighbor.
@@ -1303,19 +1302,31 @@ restart:
continue;
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
- /* Always use the default FIB here. */
dst6 = (const struct sockaddr *)&pr->ndpr_prefix;
- genid = V_nd6_list_genid;
- ND6_RUNLOCK();
-
- /* Restore length field before retrying lookup */
- rt_key.sin6_len = sizeof(rt_key);
- error = rib_lookup_info(fibnum, dst6, 0, 0, &info);
+ /*
+ * We only need to check all FIBs if add_addr_allfibs
+ * is unset. If set, checking any FIB will suffice.
+ */
+ fibnum = V_rt_add_addr_allfibs ? rt_numfibs - 1 : 0;
+ for (; fibnum < rt_numfibs; fibnum++) {
+ genid = V_nd6_list_genid;
+ ND6_RUNLOCK();
- ND6_RLOCK();
- if (genid != V_nd6_list_genid)
- goto restart;
+ /*
+ * Restore length field before
+ * retrying lookup
+ */
+ rt_key.sin6_len = sizeof(rt_key);
+ error = rib_lookup_info(fibnum, dst6, 0, 0,
+ &info);
+
+ ND6_RLOCK();
+ if (genid != V_nd6_list_genid)
+ goto restart;
+ if (error == 0)
+ break;
+ }
if (error != 0)
continue;
@@ -1346,13 +1357,18 @@ restart:
* If the address is assigned on the node of the other side of
* a p2p interface, the address should be a neighbor.
*/
- dstaddr = ifa_ifwithdstaddr((const struct sockaddr *)addr, RT_ALL_FIBS);
- if (dstaddr != NULL) {
- if (dstaddr->ifa_ifp == ifp) {
- ifa_free(dstaddr);
- return (1);
+ if (ifp->if_flags & IFF_POINTOPOINT) {
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
+ if (ifa->ifa_addr->sa_family != addr->sin6_family)
+ continue;
+ if (ifa->ifa_dstaddr != NULL &&
+ sa_equal(addr, ifa->ifa_dstaddr)) {
+ IF_ADDR_RUNLOCK(ifp);
+ return 1;
+ }
}
- ifa_free(dstaddr);
+ IF_ADDR_RUNLOCK(ifp);
}
/*
@@ -1485,7 +1501,7 @@ nd6_free(struct llentry **lnp, int gc)
/*
* We need to unlock to avoid a LOR with rt6_flush() with the
* rnh and for the calls to pfxlist_onlink_check() and
- * defrouter_select() in the block further down for calls
+ * defrouter_select_fib() in the block further down for calls
* into nd6_lookup(). We still hold a ref.
*/
LLE_WUNLOCK(ln);
@@ -1500,7 +1516,7 @@ nd6_free(struct llentry **lnp, int gc)
if (dr) {
/*
- * Since defrouter_select() does not affect the
+ * Since defrouter_select_fib() does not affect the
* on-link determination and MIP6 needs the check
* before the default router selection, we perform
* the check now.
@@ -1510,7 +1526,7 @@ nd6_free(struct llentry **lnp, int gc)
/*
* Refresh default router list.
*/
- defrouter_select();
+ defrouter_select_fib(dr->ifp->if_fib);
}
/*
@@ -2104,11 +2120,11 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
* Question: can we restrict the first condition to the "is_newentry"
* case?
* XXX: when we hear an RA from a new router with the link-layer
- * address option, defrouter_select() is called twice, since
+ * address option, defrouter_select_fib() is called twice, since
* defrtrlist_update called the function as well. However, I believe
* we can compromise the overhead, since it only happens the first
* time.
- * XXX: although defrouter_select() should not have a bad effect
+ * XXX: although defrouter_select_fib() should not have a bad effect
* for those are not autoconfigured hosts, we explicitly avoid such
* cases for safety.
*/
@@ -2117,7 +2133,7 @@ nd6_cache_lladdr(struct ifnet *ifp, struct in6_addr *from, char *lladdr,
/*
* guaranteed recursion
*/
- defrouter_select();
+ defrouter_select_fib(ifp->if_fib);
}
}
diff --git a/sys/netinet6/nd6.h b/sys/netinet6/nd6.h
index 9b9fa3d..243e954 100644
--- a/sys/netinet6/nd6.h
+++ b/sys/netinet6/nd6.h
@@ -469,6 +469,7 @@ void nd6_dad_stop(struct ifaddr *);
void nd6_rs_input(struct mbuf *, int, int);
void nd6_ra_input(struct mbuf *, int, int);
void defrouter_reset(void);
+void defrouter_select_fib(int fibnum);
void defrouter_select(void);
void defrouter_ref(struct nd_defrouter *);
void defrouter_rele(struct nd_defrouter *);
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index 2ac1d7a..8bbdf85 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -262,8 +262,7 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
bzero(&info, sizeof(info));
info.rti_info[RTAX_GATEWAY] = (struct sockaddr *)&rt_gateway;
- /* Always use the default FIB. */
- if (rib_lookup_info(RT_DEFAULT_FIB, (struct sockaddr *)&dst6,
+ if (rib_lookup_info(ifp->if_fib, (struct sockaddr *)&dst6,
0, 0, &info) == 0) {
if ((info.rti_flags & RTF_ANNOUNCE) != 0 &&
rt_gateway.sdl_family == AF_LINK) {
@@ -485,7 +484,7 @@ nd6_ns_output_fib(struct ifnet *ifp, const struct in6_addr *saddr6,
uint32_t scopeid;
in6_splitscope(&ip6->ip6_dst, &dst6, &scopeid);
- error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
+ error = in6_selectsrc_addr(fibnum, &dst6,
scopeid, ifp, &src6, NULL);
if (error) {
char ip6buf[INET6_ADDRSTRLEN];
@@ -982,7 +981,7 @@ nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
* Select a source whose scope is the same as that of the dest.
*/
in6_splitscope(&daddr6, &dst6, &scopeid);
- error = in6_selectsrc_addr(RT_DEFAULT_FIB, &dst6,
+ error = in6_selectsrc_addr(fibnum, &dst6,
scopeid, ifp, &src6, NULL);
if (error) {
char ip6buf[INET6_ADDRSTRLEN];
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index a44a8b1..193ce99 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -500,7 +500,7 @@ defrouter_addreq(struct nd_defrouter *new)
error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def,
(struct sockaddr *)&gate, (struct sockaddr *)&mask,
- RTF_GATEWAY, &newrt, RT_DEFAULT_FIB);
+ RTF_GATEWAY, &newrt, new->ifp->if_fib);
if (newrt) {
nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
RTFREE(newrt);
@@ -551,8 +551,8 @@ defrouter_rele(struct nd_defrouter *dr)
/*
* Remove the default route for a given router.
- * This is just a subroutine function for defrouter_select(), and should
- * not be called from anywhere else.
+ * This is just a subroutine function for defrouter_select_fib(), and
+ * should not be called from anywhere else.
*/
static void
defrouter_delreq(struct nd_defrouter *dr)
@@ -571,7 +571,7 @@ defrouter_delreq(struct nd_defrouter *dr)
in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def,
(struct sockaddr *)&gate,
- (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, RT_DEFAULT_FIB);
+ (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, dr->ifp->if_fib);
if (oldrt) {
nd6_rtmsg(RTM_DELETE, oldrt);
RTFREE(oldrt);
@@ -698,11 +698,11 @@ defrouter_del(struct nd_defrouter *dr)
/*
* If the router is the primary one, choose a new one.
- * Note that defrouter_select() will remove the current gateway
- * from the routing table.
+ * Note that defrouter_select_fib() will remove the current
+ * gateway from the routing table.
*/
if (deldr)
- defrouter_select();
+ defrouter_select_fib(deldr->ifp->if_fib);
/*
* Release the list reference.
@@ -730,13 +730,23 @@ defrouter_del(struct nd_defrouter *dr)
* even when the multipath routing is available, because we're not sure about
* the benefits for stub hosts comparing to the risk of making the code
* complicated and the possibility of introducing bugs.
+ *
+ * We maintain a single list of routers for multiple FIBs, only considering one
+ * at a time based on the receiving interface's FIB. If @fibnum is RT_ALL_FIBS,
+ * we do the whole thing multiple times.
*/
void
-defrouter_select(void)
+defrouter_select_fib(int fibnum)
{
struct nd_defrouter *dr, *selected_dr, *installed_dr;
struct llentry *ln = NULL;
+ if (fibnum == RT_ALL_FIBS) {
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ defrouter_select_fib(fibnum);
+ }
+ }
+
ND6_RLOCK();
/*
* Let's handle easy case (3) first:
@@ -755,7 +765,7 @@ defrouter_select(void)
selected_dr = installed_dr = NULL;
TAILQ_FOREACH(dr, &V_nd_defrouter, dr_entry) {
IF_AFDATA_RLOCK(dr->ifp);
- if (selected_dr == NULL &&
+ if (selected_dr == NULL && dr->ifp->if_fib == fibnum &&
(ln = nd6_lookup(&dr->rtaddr, 0, dr->ifp)) &&
ND6_IS_LLINFO_PROBREACH(ln)) {
selected_dr = dr;
@@ -767,14 +777,17 @@ defrouter_select(void)
ln = NULL;
}
- if (dr->installed) {
+ if (dr->installed && dr->ifp->if_fib == fibnum) {
if (installed_dr == NULL) {
installed_dr = dr;
defrouter_ref(installed_dr);
} else {
- /* this should not happen. warn for diagnosis. */
- log(LOG_ERR,
- "defrouter_select: more than one router is installed\n");
+ /*
+ * this should not happen.
+ * warn for diagnosis.
+ */
+ log(LOG_ERR, "defrouter_select_fib: more than "
+ "one router is installed\n");
}
}
}
@@ -789,14 +802,24 @@ defrouter_select(void)
if (selected_dr == NULL) {
if (installed_dr == NULL ||
TAILQ_NEXT(installed_dr, dr_entry) == NULL)
- selected_dr = TAILQ_FIRST(&V_nd_defrouter);
+ dr = TAILQ_FIRST(&V_nd_defrouter);
else
- selected_dr = TAILQ_NEXT(installed_dr, dr_entry);
- defrouter_ref(selected_dr);
+ dr = TAILQ_NEXT(installed_dr, dr_entry);
+
+ /* Ensure we select a router for this FIB. */
+ TAILQ_FOREACH_FROM(dr, &V_nd_defrouter, dr_entry) {
+ if (dr->ifp->if_fib == fibnum) {
+ selected_dr = dr;
+ defrouter_ref(selected_dr);
+ break;
+ }
+ }
} else if (installed_dr != NULL) {
IF_AFDATA_RLOCK(installed_dr->ifp);
- if ((ln = nd6_lookup(&installed_dr->rtaddr, 0, installed_dr->ifp)) &&
+ if ((ln = nd6_lookup(&installed_dr->rtaddr, 0,
+ installed_dr->ifp)) &&
ND6_IS_LLINFO_PROBREACH(ln) &&
+ installed_dr->ifp->if_fib == fibnum &&
rtpref(selected_dr) <= rtpref(installed_dr)) {
defrouter_rele(selected_dr);
selected_dr = installed_dr;
@@ -808,18 +831,30 @@ defrouter_select(void)
ND6_RUNLOCK();
/*
- * If the selected router is different than the installed one,
- * remove the installed router and install the selected one.
- * Note that the selected router is never NULL here.
+ * If we selected a router for this FIB and it's different
+ * than the installed one, remove the installed router and
+ * install the selected one in its place.
*/
if (installed_dr != selected_dr) {
if (installed_dr != NULL) {
defrouter_delreq(installed_dr);
defrouter_rele(installed_dr);
}
- defrouter_addreq(selected_dr);
+ if (selected_dr != NULL)
+ defrouter_addreq(selected_dr);
}
- defrouter_rele(selected_dr);
+ if (selected_dr != NULL)
+ defrouter_rele(selected_dr);
+}
+
+/*
+ * Maintain old KPI for default router selection.
+ * If unspecified, we can re-select routers for all FIBs.
+ */
+void
+defrouter_select(void)
+{
+ defrouter_select_fib(RT_ALL_FIBS);
}
/*
@@ -942,7 +977,7 @@ restart:
V_nd6_list_genid++;
ND6_WUNLOCK();
- defrouter_select();
+ defrouter_select_fib(new->ifp->if_fib);
return (n);
}
@@ -1731,7 +1766,7 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa)
struct rtentry *rt;
struct sockaddr_in6 mask6;
u_long rtflags;
- int error, a_failure, fibnum;
+ int error, a_failure, fibnum, maxfib;
/*
* in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
@@ -1742,8 +1777,15 @@ nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa)
mask6.sin6_addr = pr->ndpr_mask;
rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
+ if(V_rt_add_addr_allfibs) {
+ fibnum = 0;
+ maxfib = rt_numfibs;
+ } else {
+ fibnum = ifa->ifa_ifp->if_fib;
+ maxfib = fibnum + 1;
+ }
a_failure = 0;
- for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ for (; fibnum < maxfib; fibnum++) {
rt = NULL;
error = in6_rtrequest(RTM_ADD,
@@ -1831,6 +1873,10 @@ nd6_prefix_onlink(struct nd_prefix *pr)
if ((opr->ndpr_stateflags & NDPRF_ONLINK) == 0)
continue;
+ if (!V_rt_add_addr_allfibs &&
+ opr->ndpr_ifp->if_fib != pr->ndpr_ifp->if_fib)
+ continue;
+
if (opr->ndpr_plen == pr->ndpr_plen &&
in6_are_prefix_equal(&pr->ndpr_prefix.sin6_addr,
&opr->ndpr_prefix.sin6_addr, pr->ndpr_plen)) {
@@ -1891,7 +1937,7 @@ nd6_prefix_offlink(struct nd_prefix *pr)
struct rtentry *rt;
char ip6buf[INET6_ADDRSTRLEN];
uint64_t genid;
- int fibnum, a_failure;
+ int fibnum, maxfib, a_failure;
ND6_ONLINK_LOCK_ASSERT();
ND6_UNLOCK_ASSERT();
@@ -1909,8 +1955,16 @@ nd6_prefix_offlink(struct nd_prefix *pr)
mask6.sin6_len = sizeof(sa6);
bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
+ if (V_rt_add_addr_allfibs) {
+ fibnum = 0;
+ maxfib = rt_numfibs;
+ } else {
+ fibnum = ifp->if_fib;
+ maxfib = fibnum + 1;
+ }
+
a_failure = 0;
- for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ for (; fibnum < maxfib; fibnum++) {
rt = NULL;
error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
(struct sockaddr *)&mask6, 0, &rt, fibnum);
diff --git a/tests/sys/netinet/fibs_test.sh b/tests/sys/netinet/fibs_test.sh
index 70b53e8..febcbb7 100755
--- a/tests/sys/netinet/fibs_test.sh
+++ b/tests/sys/netinet/fibs_test.sh
@@ -39,8 +39,7 @@
# arpresolve only checked the default route.
#
# Outline:
-# Create two tap(4) interfaces
-# Simulate a crossover cable between them by using net/socat
+# Create two connected epair(4) interfaces
# Use nping (from security/nmap) to send an ICMP echo request from one
# interface to the other, spoofing the source IP. The source IP must be
# spoofed, or else it will already have an entry in the arp table.
@@ -51,7 +50,7 @@ arpresolve_checks_interface_fib_head()
atf_set "descr" "arpresolve should check the interface fib, not the default fib, for routes"
atf_set "require.user" "root"
atf_set "require.config" "fibs"
- atf_set "require.progs" "socat nping"
+ atf_set "require.progs" "nping"
}
arpresolve_checks_interface_fib_body()
{
@@ -74,19 +73,13 @@ arpresolve_checks_interface_fib_body()
fi
get_fibs 2
- # Configure TAP interfaces
- setup_tap "$FIB0" ${ADDR0} ${MASK0}
- TAP0=$TAP
- setup_tap "$FIB1" ${ADDR1} ${MASK1}
- TAP1=$TAP
-
- # Simulate a crossover cable
- socat /dev/${TAP0} /dev/${TAP1} &
- SOCAT_PID=$!
- echo ${SOCAT_PID} >> "processes_to_kill"
+ # Configure epair interfaces
+ get_epair
+ setup_iface "$EPAIRA" "$FIB0" inet ${ADDR0} ${MASK0}
+ setup_iface "$EPAIRB" "$FIB1" inet ${ADDR1} ${MASK1}
# Send an ICMP echo request with a spoofed source IP
- setfib 2 nping -c 1 -e ${TAP0} -S ${SPOOF_ADDR} \
+ setfib "$FIB0" nping -c 1 -e ${EPAIRA} -S ${SPOOF_ADDR} \
--source-mac ${SPOOF_MAC} --icmp --icmp-type "echo-request" \
--icmp-code 0 --icmp-id 0xdead --icmp-seq 1 --data 0xbeef \
${ADDR1}
@@ -94,17 +87,11 @@ arpresolve_checks_interface_fib_body()
# characteristic error message
dmesg | grep "llinfo.*${SPOOF_ADDR}"
# Check that the ARP entry exists
- atf_check -o match:"${SPOOF_ADDR}.*expires" setfib 3 arp ${SPOOF_ADDR}
+ atf_check -o match:"${SPOOF_ADDR}.*expires" setfib "$FIB1" arp ${SPOOF_ADDR}
}
arpresolve_checks_interface_fib_cleanup()
{
- if [ -f processes_to_kill ]; then
- for pid in $(cat processes_to_kill); do
- kill "${pid}"
- done
- rm -f processes_to_kill
- fi
- cleanup_tap
+ cleanup_ifaces
}
@@ -112,7 +99,7 @@ arpresolve_checks_interface_fib_cleanup()
atf_test_case loopback_and_network_routes_on_nondefault_fib cleanup
loopback_and_network_routes_on_nondefault_fib_head()
{
- atf_set "descr" "When creating and deleting loopback routes, use the interface's fib"
+ atf_set "descr" "When creating and deleting loopback IPv4 routes, use the interface's fib"
atf_set "require.user" "root"
atf_set "require.config" "fibs"
}
@@ -132,7 +119,7 @@ loopback_and_network_routes_on_nondefault_fib_body()
get_fibs 1
# Configure a TAP interface
- setup_tap ${FIB0} ${ADDR} ${MASK}
+ setup_tap ${FIB0} inet ${ADDR} ${MASK}
# Check whether the host route exists in only the correct FIB
setfib ${FIB0} netstat -rn -f inet | grep -q "^${ADDR}.*UHS.*lo0"
@@ -156,14 +143,71 @@ loopback_and_network_routes_on_nondefault_fib_body()
setfib 0 netstat -rn -f inet | \
grep -q "^${SUBNET}/${MASK}.*${TAPD}"
if [ 0 -eq $? ]; then
- setfib ${FIB0} netstat -rn -f inet
+ setfib 0 netstat -rn -f inet
atf_fail "Network route appeared in the wrong FIB"
fi
}
loopback_and_network_routes_on_nondefault_fib_cleanup()
{
- cleanup_tap
+ cleanup_ifaces
+}
+
+atf_test_case loopback_and_network_routes_on_nondefault_fib_inet6 cleanup
+loopback_and_network_routes_on_nondefault_fib_inet6_head()
+{
+ atf_set "descr" "When creating and deleting loopback IPv6 routes, use the interface's fib"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+
+loopback_and_network_routes_on_nondefault_fib_inet6_body()
+{
+ # Configure the TAP interface to use a nonrouteable RFC3849
+ # address and a non-default fib
+ ADDR="2001:db8::2"
+ SUBNET="2001:db8::"
+ MASK="64"
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 1
+
+ # Configure a TAP interface
+ setup_tap ${FIB0} inet6 ${ADDR} ${MASK}
+
+ # Check whether the host route exists in only the correct FIB
+ setfib ${FIB0} netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0"
+ if [ 0 -ne $? ]; then
+ setfib ${FIB0} netstat -rn -f inet6
+ atf_fail "Host route did not appear in the correct FIB"
+ fi
+ setfib 0 netstat -rn -f inet6 | grep -q "^${ADDR}.*UHS.*lo0"
+ if [ 0 -eq $? ]; then
+ setfib 0 netstat -rn -f inet6
+ atf_fail "Host route appeared in the wrong FIB"
+ fi
+
+ # Check whether the network route exists in only the correct FIB
+ setfib ${FIB0} netstat -rn -f inet6 | \
+ grep -q "^${SUBNET}/${MASK}.*${TAPD}"
+ if [ 0 -ne $? ]; then
+ setfib ${FIB0} netstat -rn -f inet6
+ atf_fail "Network route did not appear in the correct FIB"
+ fi
+ setfib 0 netstat -rn -f inet6 | \
+ grep -q "^${SUBNET}/${MASK}.*${TAPD}"
+ if [ 0 -eq $? ]; then
+ setfib 0 netstat -rn -f inet6
+ atf_fail "Network route appeared in the wrong FIB"
+ fi
+}
+
+loopback_and_network_routes_on_nondefault_fib_inet6_cleanup()
+{
+ cleanup_ifaces
}
@@ -171,7 +215,7 @@ loopback_and_network_routes_on_nondefault_fib_cleanup()
atf_test_case default_route_with_multiple_fibs_on_same_subnet cleanup
default_route_with_multiple_fibs_on_same_subnet_head()
{
- atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default routes"
+ atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv4 routes"
atf_set "require.user" "root"
atf_set "require.config" "fibs"
}
@@ -193,9 +237,9 @@ default_route_with_multiple_fibs_on_same_subnet_body()
get_fibs 2
# Configure TAP interfaces
- setup_tap "$FIB0" ${ADDR0} ${MASK}
+ setup_tap "$FIB0" inet ${ADDR0} ${MASK}
TAP0=$TAP
- setup_tap "$FIB1" ${ADDR1} ${MASK}
+ setup_tap "$FIB1" inet ${ADDR1} ${MASK}
TAP1=$TAP
# Attempt to add default routes
@@ -212,7 +256,54 @@ default_route_with_multiple_fibs_on_same_subnet_body()
default_route_with_multiple_fibs_on_same_subnet_cleanup()
{
- cleanup_tap
+ cleanup_ifaces
+}
+
+atf_test_case default_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
+default_route_with_multiple_fibs_on_same_subnet_inet6_head()
+{
+ atf_set "descr" "Multiple interfaces on the same subnet but with different fibs can both have default IPv6 routes"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+
+default_route_with_multiple_fibs_on_same_subnet_inet6_body()
+{
+ # Configure the TAP interfaces to use nonrouteable RFC3849
+ # addresses and non-default FIBs
+ ADDR0="2001:db8::2"
+ ADDR1="2001:db8::3"
+ GATEWAY="2001:db8::1"
+ SUBNET="2001:db8::"
+ MASK="64"
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 2
+
+ # Configure TAP interfaces
+ setup_tap "$FIB0" inet6 ${ADDR0} ${MASK}
+ TAP0=$TAP
+ setup_tap "$FIB1" inet6 ${ADDR1} ${MASK}
+ TAP1=$TAP
+
+ # Attempt to add default routes
+ setfib ${FIB0} route -6 add default ${GATEWAY}
+ setfib ${FIB1} route -6 add default ${GATEWAY}
+
+ # Verify that the default route exists for both fibs, with their
+ # respective interfaces.
+ atf_check -o match:"^default.*${TAP0}$" \
+ setfib ${FIB0} netstat -rn -f inet6
+ atf_check -o match:"^default.*${TAP1}$" \
+ setfib ${FIB1} netstat -rn -f inet6
+}
+
+default_route_with_multiple_fibs_on_same_subnet_inet6_cleanup()
+{
+ cleanup_ifaces
}
@@ -223,7 +314,7 @@ default_route_with_multiple_fibs_on_same_subnet_cleanup()
atf_test_case same_ip_multiple_ifaces_fib0 cleanup
same_ip_multiple_ifaces_fib0_head()
{
- atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface."
+ atf_set "descr" "Can remove an IPv4 alias from an interface when the same IPv4 is also assigned to another interface."
atf_set "require.user" "root"
atf_set "require.config" "fibs"
}
@@ -237,22 +328,22 @@ same_ip_multiple_ifaces_fib0_body()
# of net.add_addr_allfibs
# Setup the interfaces, then remove one alias. It should not panic.
- setup_tap 0 ${ADDR} ${MASK0}
+ setup_tap 0 inet ${ADDR} ${MASK0}
TAP0=${TAP}
- setup_tap 0 ${ADDR} ${MASK1}
+ setup_tap 0 inet ${ADDR} ${MASK1}
TAP1=${TAP}
ifconfig ${TAP1} -alias ${ADDR}
# Do it again, in the opposite order. It should not panic.
- setup_tap 0 ${ADDR} ${MASK0}
+ setup_tap 0 inet ${ADDR} ${MASK0}
TAP0=${TAP}
- setup_tap 0 ${ADDR} ${MASK1}
+ setup_tap 0 inet ${ADDR} ${MASK1}
TAP1=${TAP}
ifconfig ${TAP0} -alias ${ADDR}
}
same_ip_multiple_ifaces_fib0_cleanup()
{
- cleanup_tap
+ cleanup_ifaces
}
# Regression test for PR kern/189088
@@ -266,7 +357,7 @@ same_ip_multiple_ifaces_fib0_cleanup()
atf_test_case same_ip_multiple_ifaces cleanup
same_ip_multiple_ifaces_head()
{
- atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface, on non-default FIBs."
+ atf_set "descr" "Can remove an IPv4 alias from an interface when the same address is also assigned to another interface, on non-default FIBs."
atf_set "require.user" "root"
atf_set "require.config" "fibs"
}
@@ -282,18 +373,18 @@ same_ip_multiple_ifaces_body()
get_fibs 2
# Setup the interfaces, then remove one alias. It should not panic.
- setup_tap ${FIB0} ${ADDR} ${MASK0}
+ setup_tap ${FIB0} inet ${ADDR} ${MASK0}
TAP0=${TAP}
- setup_tap ${FIB1} ${ADDR} ${MASK1}
+ setup_tap ${FIB1} inet ${ADDR} ${MASK1}
TAP1=${TAP}
ifconfig ${TAP1} -alias ${ADDR}
atf_check -o not-match:"^${ADDR}[[:space:]]" \
setfib ${FIB1} netstat -rn -f inet
# Do it again, in the opposite order. It should not panic.
- setup_tap ${FIB0} ${ADDR} ${MASK0}
+ setup_tap ${FIB0} inet ${ADDR} ${MASK0}
TAP0=${TAP}
- setup_tap ${FIB1} ${ADDR} ${MASK1}
+ setup_tap ${FIB1} inet ${ADDR} ${MASK1}
TAP1=${TAP}
ifconfig ${TAP0} -alias ${ADDR}
atf_check -o not-match:"^${ADDR}[[:space:]]" \
@@ -303,16 +394,145 @@ same_ip_multiple_ifaces_cleanup()
{
# Due to PR kern/189088, we must destroy the interfaces in LIFO order
# in order for the routes to be correctly cleaned up.
- for TAPD in `tail -r "tap_devices_to_cleanup"`; do
+ for TAPD in `tail -r "ifaces_to_cleanup"`; do
+ echo ifconfig ${TAPD} destroy
ifconfig ${TAPD} destroy
done
}
+atf_test_case same_ip_multiple_ifaces_inet6 cleanup
+same_ip_multiple_ifaces_inet6_head()
+{
+ atf_set "descr" "Can remove an IPv6 alias from an interface when the same address is also assigned to another interface, on non-default FIBs."
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+same_ip_multiple_ifaces_inet6_body()
+{
+ ADDR="2001:db8::2"
+ MASK0="64"
+ MASK1="128"
+
+ # Unlike most of the tests in this file, this is applicable regardless
+ # of net.add_addr_allfibs
+ get_fibs 2
+
+ # Setup the interfaces, then remove one alias. It should not panic.
+ setup_tap ${FIB0} inet6 ${ADDR} ${MASK0}
+ TAP0=${TAP}
+ setup_tap ${FIB1} inet6 ${ADDR} ${MASK1}
+ TAP1=${TAP}
+ atf_check -s exit:0 ifconfig ${TAP1} inet6 ${ADDR} -alias
+ atf_check -o not-match:"^${ADDR}[[:space:]]" \
+ setfib ${FIB1} netstat -rn -f inet6
+ ifconfig ${TAP1} destroy
+ ifconfig ${TAP0} destroy
+
+ # Do it again, in the opposite order. It should not panic.
+ setup_tap ${FIB0} inet6 ${ADDR} ${MASK0}
+ TAP0=${TAP}
+ setup_tap ${FIB1} inet6 ${ADDR} ${MASK1}
+ TAP1=${TAP}
+ atf_check -s exit:0 ifconfig ${TAP0} inet6 ${ADDR} -alias
+ atf_check -o not-match:"^${ADDR}[[:space:]]" \
+ setfib ${FIB0} netstat -rn -f inet6
+}
+same_ip_multiple_ifaces_inet6_cleanup()
+{
+ cleanup_ifaces
+}
+
+atf_test_case slaac_on_nondefault_fib6 cleanup
+slaac_on_nondefault_fib6_head()
+{
+ atf_set "descr" "SLAAC correctly installs routes on non-default FIBs"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs" "allow_sysctl_side_effects"
+}
+slaac_on_nondefault_fib6_body()
+{
+ # Configure the epair interfaces to use nonrouteable RFC3849
+ # addresses and non-default FIBs
+ PREFIX="2001:db8:$(printf "%x" `jot -r 1 0 65535`):$(printf "%x" `jot -r 1 0 65535`)"
+ ADDR="$PREFIX::2"
+ GATEWAY="$PREFIX::1"
+ SUBNET="$PREFIX:"
+ MASK="64"
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 2
+
+ sysctl -n "net.inet6.ip6.rfc6204w3" >> "rfc6204w3.state"
+ sysctl -n "net.inet6.ip6.forwarding" >> "forwarding.state"
+ # Enable forwarding so the kernel will send RAs
+ sysctl net.inet6.ip6.forwarding=1
+ # Enable RFC6204W3 mode so the kernel will enable default router
+ # selection while also forwarding packets
+ sysctl net.inet6.ip6.rfc6204w3=1
+
+ # Configure epair interfaces
+ get_epair
+ setup_iface "$EPAIRA" "$FIB0" inet6 ${ADDR} ${MASK}
+ echo setfib $FIB1 ifconfig "$EPAIRB" inet6 -ifdisabled accept_rtadv fib $FIB1 up
+ setfib $FIB1 ifconfig "$EPAIRB" inet6 -ifdisabled accept_rtadv fib $FIB1 up
+ rtadvd -p rtadvd.pid -C rtadvd.sock -c /dev/null "$EPAIRA"
+ rtsol "$EPAIRB"
+
+ # Check SLAAC address
+ atf_check -o match:"inet6 ${SUBNET}.*prefixlen ${MASK}.*autoconf" \
+ ifconfig "$EPAIRB"
+ # Check local route
+ atf_check -o match:"${SUBNET}.*\<UHS\>.*lo0" \
+ netstat -rnf inet6 -F $FIB1
+ # Check subnet route
+ atf_check -o match:"${SUBNET}:/${MASK}.*\<U\>.*$EPAIRB" \
+ netstat -rnf inet6 -F $FIB1
+ # Check default route
+ atf_check -o match:"default.*\<UG\>.*$EPAIRB" \
+ netstat -rnf inet6 -F $FIB1
+
+ # Check that none of the above routes appeared on other routes
+ for fib in $( seq 0 $(($(sysctl -n net.fibs) - 1))); do
+ if [ "$fib" = "$FIB1" -o "$fib" = "$FIB0" ]; then
+ continue
+ fi
+ atf_check -o not-match:"${SUBNET}.*\<UHS\>.*lo0" \
+ netstat -rnf inet6 -F $fib
+ atf_check -o not-match:"${SUBNET}:/${MASK}.*\<U\>.*$EPAIRB" \
+ netstat -rnf inet6 -F $fib
+ atf_check -o not-match:"default.*\<UG\>.*$EPAIRB" \
+ netstat -rnf inet6 -F $fib
+ done
+}
+slaac_on_nondefault_fib6_cleanup()
+{
+ if [ -f "rtadvd.pid" ]; then
+ # rtadvd can take a long time to shutdown. Use SIGKILL to kill
+ # it right away. The downside to using SIGKILL is that it
+ # won't send final RAs to all interfaces, but we don't care
+ # because we're about to destroy its interface anyway.
+ pkill -kill -F rtadvd.pid
+ rm -f rtadvd.pid
+ fi
+ cleanup_ifaces
+ if [ -f "forwarding.state" ] ; then
+ sysctl "net.inet6.ip6.forwarding"=`cat "forwarding.state"`
+ rm "forwarding.state"
+ fi
+ if [ -f "rfc6204w3.state" ] ; then
+ sysctl "net.inet6.ip6.rfc6204w3"=`cat "rfc6204w3.state"`
+ rm "rfc6204w3.state"
+ fi
+}
+
# Regression test for kern/187550
atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
subnet_route_with_multiple_fibs_on_same_subnet_head()
{
- atf_set "descr" "Multiple FIBs can have subnet routes for the same subnet"
+ atf_set "descr" "Multiple FIBs can have IPv4 subnet routes for the same subnet"
atf_set "require.user" "root"
atf_set "require.config" "fibs"
}
@@ -333,8 +553,8 @@ subnet_route_with_multiple_fibs_on_same_subnet_body()
get_fibs 2
# Configure TAP interfaces
- setup_tap "$FIB0" ${ADDR0} ${MASK}
- setup_tap "$FIB1" ${ADDR1} ${MASK}
+ setup_tap "$FIB0" inet ${ADDR0} ${MASK}
+ setup_tap "$FIB1" inet ${ADDR1} ${MASK}
# Check that a subnet route exists on both fibs
atf_check -o ignore setfib "$FIB0" route get $ADDR1
@@ -343,7 +563,44 @@ subnet_route_with_multiple_fibs_on_same_subnet_body()
subnet_route_with_multiple_fibs_on_same_subnet_cleanup()
{
- cleanup_tap
+ cleanup_ifaces
+}
+
+atf_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6 cleanup
+subnet_route_with_multiple_fibs_on_same_subnet_inet6_head()
+{
+ atf_set "descr" "Multiple FIBs can have IPv6 subnet routes for the same subnet"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+
+subnet_route_with_multiple_fibs_on_same_subnet_inet6_body()
+{
+ # Configure the TAP interfaces to use a RFC3849 nonrouteable addresses
+ # and a non-default fib
+ ADDR0="2001:db8::2"
+ ADDR1="2001:db8::3"
+ SUBNET="2001:db8::"
+ MASK="64"
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 2
+
+ # Configure TAP interfaces
+ setup_tap "$FIB0" inet6 ${ADDR0} ${MASK}
+ setup_tap "$FIB1" inet6 ${ADDR1} ${MASK}
+
+ # Check that a subnet route exists on both fibs
+ atf_check -o ignore setfib "$FIB0" route -6 get $ADDR1
+ atf_check -o ignore setfib "$FIB1" route -6 get $ADDR0
+}
+
+subnet_route_with_multiple_fibs_on_same_subnet_inet6_cleanup()
+{
+ cleanup_ifaces
}
# Test that source address selection works correctly for UDP packets with
@@ -386,19 +643,19 @@ udp_dontroute_body()
get_fibs 2
# Configure the TAP interfaces
- setup_tap ${FIB0} ${ADDR0} ${MASK}
+ setup_tap ${FIB0} inet ${ADDR0} ${MASK}
TARGET_TAP=${TAP}
- setup_tap ${FIB1} ${ADDR1} ${MASK}
+ setup_tap ${FIB1} inet ${ADDR1} ${MASK}
# Send a UDP packet with SO_DONTROUTE. In the failure case, it will
# return ENETUNREACH, or send the packet to the wrong tap
atf_check -o ignore setfib ${FIB0} \
${SRCDIR}/udp_dontroute ${TARGET} /dev/${TARGET_TAP}
- cleanup_tap
+ cleanup_ifaces
# Repeat, but this time target the other tap
- setup_tap ${FIB0} ${ADDR0} ${MASK}
- setup_tap ${FIB1} ${ADDR1} ${MASK}
+ setup_tap ${FIB0} inet ${ADDR0} ${MASK}
+ setup_tap ${FIB1} inet ${ADDR1} ${MASK}
TARGET_TAP=${TAP}
atf_check -o ignore setfib ${FIB1} \
@@ -407,7 +664,60 @@ udp_dontroute_body()
udp_dontroute_cleanup()
{
- cleanup_tap
+ cleanup_ifaces
+}
+
+atf_test_case udp_dontroute6 cleanup
+udp_dontroute6_head()
+{
+ atf_set "descr" "Source address selection for UDP IPv6 packets with SO_DONTROUTE on non-default FIBs works"
+ atf_set "require.user" "root"
+ atf_set "require.config" "fibs"
+}
+
+udp_dontroute6_body()
+{
+ # Configure the TAP interface to use an RFC3849 nonrouteable address
+ # and a non-default fib
+ ADDR0="2001:db8::2"
+ ADDR1="2001:db8::3"
+ SUBNET="2001:db8::"
+ MASK="64"
+ # Use a different IP on the same subnet as the target
+ TARGET="2001:db8::100"
+ SRCDIR=`atf_get_srcdir`
+
+ # Check system configuration
+ if [ 0 != `sysctl -n net.add_addr_allfibs` ]; then
+ atf_skip "This test requires net.add_addr_allfibs=0"
+ fi
+ get_fibs 2
+
+ # Configure the TAP interfaces. Use no_dad so the addresses will be
+ # ready right away and won't be marked as tentative until DAD
+ # completes.
+ setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad
+ TARGET_TAP=${TAP}
+ setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad
+
+ # Send a UDP packet with SO_DONTROUTE. In the failure case, it will
+ # return ENETUNREACH, or send the packet to the wrong tap
+ atf_check -o ignore setfib ${FIB0} \
+ ${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP}
+ cleanup_ifaces
+
+ # Repeat, but this time target the other tap
+ setup_tap ${FIB0} inet6 ${ADDR0} ${MASK} no_dad
+ setup_tap ${FIB1} inet6 ${ADDR1} ${MASK} no_dad
+ TARGET_TAP=${TAP}
+
+ atf_check -o ignore setfib ${FIB1} \
+ ${SRCDIR}/udp_dontroute -6 ${TARGET} /dev/${TARGET_TAP}
+}
+
+udp_dontroute6_cleanup()
+{
+ cleanup_ifaces
}
@@ -415,11 +725,17 @@ atf_init_test_cases()
{
atf_add_test_case arpresolve_checks_interface_fib
atf_add_test_case loopback_and_network_routes_on_nondefault_fib
+ atf_add_test_case loopback_and_network_routes_on_nondefault_fib_inet6
atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
+ atf_add_test_case default_route_with_multiple_fibs_on_same_subnet_inet6
atf_add_test_case same_ip_multiple_ifaces_fib0
atf_add_test_case same_ip_multiple_ifaces
+ atf_add_test_case same_ip_multiple_ifaces_inet6
+ atf_add_test_case slaac_on_nondefault_fib6
atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
+ atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet_inet6
atf_add_test_case udp_dontroute
+ atf_add_test_case udp_dontroute6
}
# Looks up one or more fibs from the configuration data and validates them.
@@ -443,46 +759,81 @@ get_fibs()
done
}
+# Creates a new pair of connected epair(4) interface, registers them for
+# cleanup, and returns their namen via the environment variables EPAIRA and
+# EPAIRB
+get_epair()
+{
+ local EPAIRD
+
+ if EPAIRD=`ifconfig epair create`; then
+ # Record the epair device so we can clean it up later
+ echo ${EPAIRD} >> "ifaces_to_cleanup"
+ EPAIRA=${EPAIRD}
+ EPAIRB=${EPAIRD%a}b
+ else
+ atf_skip "Could not create epair(4) interfaces"
+ fi
+}
+
# Creates a new tap(4) interface, registers it for cleanup, and returns the
# name via the environment variable TAP
get_tap()
{
- local TAPN=0
- while ! ifconfig tap${TAPN} create > /dev/null 2>&1; do
- if [ "$TAPN" -ge 8 ]; then
- atf_skip "Could not create a tap(4) interface"
- else
- TAPN=$(($TAPN + 1))
- fi
- done
- local TAPD=tap${TAPN}
- # Record the TAP device so we can clean it up later
- echo ${TAPD} >> "tap_devices_to_cleanup"
- TAP=${TAPD}
+ local TAPD
+
+ if TAPD=`ifconfig tap create`; then
+ # Record the TAP device so we can clean it up later
+ echo ${TAPD} >> "ifaces_to_cleanup"
+ TAP=${TAPD}
+ else
+ atf_skip "Could not create a tap(4) interface"
+ fi
+}
+
+# Configure an ethernet interface
+# parameters:
+# Interface name
+# fib
+# Protocol (inet or inet6)
+# IP address
+# Netmask in number of bits (eg 24 or 8)
+# Extra flags
+# Return: None
+setup_iface()
+{
+ local IFACE=$1
+ local FIB=$2
+ local PROTO=$3
+ local ADDR=$4
+ local MASK=$5
+ local FLAGS=$6
+ echo setfib ${FIB} \
+ ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
+ setfib ${FIB} ifconfig $IFACE ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
}
# Create a tap(4) interface, configure it, and register it for cleanup.
# parameters:
# fib
+# Protocol (inet or inet6)
# IP address
# Netmask in number of bits (eg 24 or 8)
+# Extra flags
# Return: the tap interface name as the env variable TAP
setup_tap()
{
- local FIB=$1
- local ADDR=$2
- local MASK=$3
get_tap
- echo setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
- setfib ${FIB} ifconfig $TAP ${ADDR}/${MASK} fib $FIB
+ setup_iface "$TAP" "$@"
}
-cleanup_tap()
+cleanup_ifaces()
{
- if [ -f tap_devices_to_cleanup ]; then
- for tap_device in $(cat tap_devices_to_cleanup); do
- ifconfig "${tap_device}" destroy
+ if [ -f ifaces_to_cleanup ]; then
+ for iface in $(cat ifaces_to_cleanup); do
+ echo ifconfig "${iface}" destroy
+ ifconfig "${iface}" destroy 2>/dev/null || true
done
- rm -f tap_devices_to_cleanup
+ rm -f ifaces_to_cleanup
fi
}
diff --git a/tests/sys/netinet/udp_dontroute.c b/tests/sys/netinet/udp_dontroute.c
index 79421fd..24e3fc4 100644
--- a/tests/sys/netinet/udp_dontroute.c
+++ b/tests/sys/netinet/udp_dontroute.c
@@ -41,6 +41,7 @@
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -52,7 +53,7 @@
int
main(int argc, char **argv)
{
- struct sockaddr_in dst;
+ struct sockaddr_storage dst;
int s, t;
int opt;
int ret;
@@ -60,17 +61,33 @@ main(int argc, char **argv)
const char* sendbuf = "Hello, World!";
const size_t buflen = 80;
char recvbuf[buflen];
+ bool v6 = false;
+ const char *addr, *tapdev;
+ const uint16_t port = 46120;
- if (argc != 3) {
- fprintf(stderr, "Usage: %s ip_address tapdev\n", argv[0]);
+ bzero(&dst, sizeof(dst));
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "Usage: %s [-6] ip_address tapdev\n", argv[0]);
exit(2);
}
- t = open(argv[2], O_RDWR | O_NONBLOCK);
+ if (strcmp("-6", argv[1]) == 0) {
+ v6 = true;
+ addr = argv[2];
+ tapdev = argv[3];
+ } else {
+ addr = argv[1];
+ tapdev = argv[2];
+ }
+
+ t = open(tapdev, O_RDWR | O_NONBLOCK);
if (t < 0)
err(EXIT_FAILURE, "open");
- s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (v6)
+ s = socket(PF_INET6, SOCK_DGRAM, 0);
+ else
+ s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0)
err(EXIT_FAILURE, "socket");
opt = 1;
@@ -79,16 +96,26 @@ main(int argc, char **argv)
if (ret == -1)
err(EXIT_FAILURE, "setsockopt(SO_DONTROUTE)");
- dst.sin_len = sizeof(dst);
- dst.sin_family = AF_INET;
- dst.sin_port = htons(46120);
- dst.sin_addr.s_addr = inet_addr(argv[1]);
- if (dst.sin_addr.s_addr == htonl(INADDR_NONE)) {
- fprintf(stderr, "Invalid address: %s\n", argv[1]);
- exit(2);
+ if (v6) {
+ struct sockaddr_in6 *dst6 = ((struct sockaddr_in6*)&dst);
+
+ dst.ss_len = sizeof(struct sockaddr_in6);
+ dst.ss_family = AF_INET6;
+ dst6->sin6_port = htons(port);
+ ret = inet_pton(AF_INET6, addr, &dst6->sin6_addr);
+ } else {
+ struct sockaddr_in *dst4 = ((struct sockaddr_in*)&dst);
+
+ dst.ss_len = sizeof(struct sockaddr_in);
+ dst.ss_family = AF_INET;
+ dst4->sin_port = htons(port);
+ ret = inet_pton(AF_INET, addr, &dst4->sin_addr);
}
+ if (ret != 1)
+ err(EXIT_FAILURE, "inet_pton returned %d", ret);
+
ret = sendto(s, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&dst,
- dst.sin_len);
+ dst.ss_len);
if (ret == -1)
err(EXIT_FAILURE, "sendto");
OpenPOWER on IntegriCloud