Add fibs_test:udp_dontroute6, another IPv6 multi-FIB test

PR:		196361
MFC after:	3 weeks
Sponsored by:	Spectra Logic Corp
This commit is contained in:
Alan Somers 2017-02-07 17:40:59 +00:00
parent beaa6e1e64
commit 9d6c66cb9f
2 changed files with 100 additions and 15 deletions

View File

@ -595,6 +595,61 @@ udp_dontroute_cleanup()
cleanup_tap
}
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`
atf_expect_fail "PR196361 IPv6 network routes don't respect net.add_addr_allfibs=0"
# 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_tap
# 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_tap
}
atf_init_test_cases()
{
@ -609,6 +664,7 @@ atf_init_test_cases()
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.
@ -656,6 +712,7 @@ get_tap()
# 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()
{
@ -663,9 +720,10 @@ setup_tap()
local PROTO=$2
local ADDR=$3
local MASK=$4
local FLAGS=$5
get_tap
echo setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB
setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB
echo setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
setfib ${FIB} ifconfig $TAP ${PROTO} ${ADDR}/${MASK} fib $FIB $FLAGS
}
cleanup_tap()

View File

@ -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");