brintos

brintos / linux-shallow public Read only

0
0
Text · 14.6 KiB · 1e565f4 Raw
477 lines · bash
1#!/bin/bash2# SPDX-License-Identifier: GPL-2.03#4# Setup/topology:5#6#    NS1             NS2             NS37#   veth1 <---> veth2   veth3 <---> veth4 (the top route)8#   veth5 <---> veth6   veth7 <---> veth8 (the bottom route)9#10#   each vethN gets IPv[4|6]_N address11#12#   IPv*_SRC = IPv*_113#   IPv*_DST = IPv*_414#15#   all tests test pings from IPv*_SRC to IPv*_DST16#17#   by default, routes are configured to allow packets to go18#   IP*_1 <=> IP*_2 <=> IP*_3 <=> IP*_4 (the top route)19#20#   a GRE device is installed in NS3 with IPv*_GRE, and21#   NS1/NS2 are configured to route packets to IPv*_GRE via IP*_822#   (the bottom route)23#24# Tests:25#26#   1. routes NS2->IPv*_DST are brought down, so the only way a ping27#      from IP*_SRC to IP*_DST can work is via IPv*_GRE28#29#   2a. in an egress test, a bpf LWT_XMIT program is installed on veth130#       that encaps the packets with an IP/GRE header to route to IPv*_GRE31#32#       ping: SRC->[encap at veth1:egress]->GRE:decap->DST33#       ping replies go DST->SRC directly34#35#   2b. in an ingress test, a bpf LWT_IN program is installed on veth236#       that encaps the packets with an IP/GRE header to route to IPv*_GRE37#38#       ping: SRC->[encap at veth2:ingress]->GRE:decap->DST39#       ping replies go DST->SRC directly40 41BPF_FILE="test_lwt_ip_encap.bpf.o"42if [[ $EUID -ne 0 ]]; then43	echo "This script must be run as root"44	echo "FAIL"45	exit 146fi47 48readonly NS1="ns1-$(mktemp -u XXXXXX)"49readonly NS2="ns2-$(mktemp -u XXXXXX)"50readonly NS3="ns3-$(mktemp -u XXXXXX)"51 52readonly IPv4_1="172.16.1.100"53readonly IPv4_2="172.16.2.100"54readonly IPv4_3="172.16.3.100"55readonly IPv4_4="172.16.4.100"56readonly IPv4_5="172.16.5.100"57readonly IPv4_6="172.16.6.100"58readonly IPv4_7="172.16.7.100"59readonly IPv4_8="172.16.8.100"60readonly IPv4_GRE="172.16.16.100"61 62readonly IPv4_SRC=$IPv4_163readonly IPv4_DST=$IPv4_464 65readonly IPv6_1="fb01::1"66readonly IPv6_2="fb02::1"67readonly IPv6_3="fb03::1"68readonly IPv6_4="fb04::1"69readonly IPv6_5="fb05::1"70readonly IPv6_6="fb06::1"71readonly IPv6_7="fb07::1"72readonly IPv6_8="fb08::1"73readonly IPv6_GRE="fb10::1"74 75readonly IPv6_SRC=$IPv6_176readonly IPv6_DST=$IPv6_477 78TEST_STATUS=079TESTS_SUCCEEDED=080TESTS_FAILED=081 82TMPFILE=""83 84process_test_results()85{86	if [[ "${TEST_STATUS}" -eq 0 ]] ; then87		echo "PASS"88		TESTS_SUCCEEDED=$((TESTS_SUCCEEDED+1))89	else90		echo "FAIL"91		TESTS_FAILED=$((TESTS_FAILED+1))92	fi93}94 95print_test_summary_and_exit()96{97	echo "passed tests: ${TESTS_SUCCEEDED}"98	echo "failed tests: ${TESTS_FAILED}"99	if [ "${TESTS_FAILED}" -eq "0" ] ; then100		exit 0101	else102		exit 1103	fi104}105 106setup()107{108	set -e  # exit on error109	TEST_STATUS=0110 111	# create devices and namespaces112	ip netns add "${NS1}"113	ip netns add "${NS2}"114	ip netns add "${NS3}"115 116	# rp_filter gets confused by what these tests are doing, so disable it117	ip netns exec ${NS1} sysctl -wq net.ipv4.conf.all.rp_filter=0118	ip netns exec ${NS2} sysctl -wq net.ipv4.conf.all.rp_filter=0119	ip netns exec ${NS3} sysctl -wq net.ipv4.conf.all.rp_filter=0120	ip netns exec ${NS1} sysctl -wq net.ipv4.conf.default.rp_filter=0121	ip netns exec ${NS2} sysctl -wq net.ipv4.conf.default.rp_filter=0122	ip netns exec ${NS3} sysctl -wq net.ipv4.conf.default.rp_filter=0123 124	# disable IPv6 DAD because it sometimes takes too long and fails tests125	ip netns exec ${NS1} sysctl -wq net.ipv6.conf.all.accept_dad=0126	ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.accept_dad=0127	ip netns exec ${NS3} sysctl -wq net.ipv6.conf.all.accept_dad=0128	ip netns exec ${NS1} sysctl -wq net.ipv6.conf.default.accept_dad=0129	ip netns exec ${NS2} sysctl -wq net.ipv6.conf.default.accept_dad=0130	ip netns exec ${NS3} sysctl -wq net.ipv6.conf.default.accept_dad=0131 132	ip link add veth1 type veth peer name veth2133	ip link add veth3 type veth peer name veth4134	ip link add veth5 type veth peer name veth6135	ip link add veth7 type veth peer name veth8136 137	ip netns exec ${NS2} sysctl -wq net.ipv4.ip_forward=1138	ip netns exec ${NS2} sysctl -wq net.ipv6.conf.all.forwarding=1139 140	ip link set veth1 netns ${NS1}141	ip link set veth2 netns ${NS2}142	ip link set veth3 netns ${NS2}143	ip link set veth4 netns ${NS3}144	ip link set veth5 netns ${NS1}145	ip link set veth6 netns ${NS2}146	ip link set veth7 netns ${NS2}147	ip link set veth8 netns ${NS3}148 149	if [ ! -z "${VRF}" ] ; then150		ip -netns ${NS1} link add red type vrf table 1001151		ip -netns ${NS1} link set red up152		ip -netns ${NS1} route add table 1001 unreachable default metric 8192153		ip -netns ${NS1} -6 route add table 1001 unreachable default metric 8192154		ip -netns ${NS1} link set veth1 vrf red155		ip -netns ${NS1} link set veth5 vrf red156 157		ip -netns ${NS2} link add red type vrf table 1001158		ip -netns ${NS2} link set red up159		ip -netns ${NS2} route add table 1001 unreachable default metric 8192160		ip -netns ${NS2} -6 route add table 1001 unreachable default metric 8192161		ip -netns ${NS2} link set veth2 vrf red162		ip -netns ${NS2} link set veth3 vrf red163		ip -netns ${NS2} link set veth6 vrf red164		ip -netns ${NS2} link set veth7 vrf red165	fi166 167	# configure addesses: the top route (1-2-3-4)168	ip -netns ${NS1}    addr add ${IPv4_1}/24  dev veth1169	ip -netns ${NS2}    addr add ${IPv4_2}/24  dev veth2170	ip -netns ${NS2}    addr add ${IPv4_3}/24  dev veth3171	ip -netns ${NS3}    addr add ${IPv4_4}/24  dev veth4172	ip -netns ${NS1} -6 addr add ${IPv6_1}/128 nodad dev veth1173	ip -netns ${NS2} -6 addr add ${IPv6_2}/128 nodad dev veth2174	ip -netns ${NS2} -6 addr add ${IPv6_3}/128 nodad dev veth3175	ip -netns ${NS3} -6 addr add ${IPv6_4}/128 nodad dev veth4176 177	# configure addresses: the bottom route (5-6-7-8)178	ip -netns ${NS1}    addr add ${IPv4_5}/24  dev veth5179	ip -netns ${NS2}    addr add ${IPv4_6}/24  dev veth6180	ip -netns ${NS2}    addr add ${IPv4_7}/24  dev veth7181	ip -netns ${NS3}    addr add ${IPv4_8}/24  dev veth8182	ip -netns ${NS1} -6 addr add ${IPv6_5}/128 nodad dev veth5183	ip -netns ${NS2} -6 addr add ${IPv6_6}/128 nodad dev veth6184	ip -netns ${NS2} -6 addr add ${IPv6_7}/128 nodad dev veth7185	ip -netns ${NS3} -6 addr add ${IPv6_8}/128 nodad dev veth8186 187	ip -netns ${NS1} link set dev veth1 up188	ip -netns ${NS2} link set dev veth2 up189	ip -netns ${NS2} link set dev veth3 up190	ip -netns ${NS3} link set dev veth4 up191	ip -netns ${NS1} link set dev veth5 up192	ip -netns ${NS2} link set dev veth6 up193	ip -netns ${NS2} link set dev veth7 up194	ip -netns ${NS3} link set dev veth8 up195 196	# configure routes: IP*_SRC -> veth1/IP*_2 (= top route) default;197	# the bottom route to specific bottom addresses198 199	# NS1200	# top route201	ip -netns ${NS1}    route add ${IPv4_2}/32  dev veth1 ${VRF}202	ip -netns ${NS1}    route add default dev veth1 via ${IPv4_2} ${VRF}  # go top by default203	ip -netns ${NS1} -6 route add ${IPv6_2}/128 dev veth1 ${VRF}204	ip -netns ${NS1} -6 route add default dev veth1 via ${IPv6_2} ${VRF}  # go top by default205	# bottom route206	ip -netns ${NS1}    route add ${IPv4_6}/32  dev veth5 ${VRF}207	ip -netns ${NS1}    route add ${IPv4_7}/32  dev veth5 via ${IPv4_6} ${VRF}208	ip -netns ${NS1}    route add ${IPv4_8}/32  dev veth5 via ${IPv4_6} ${VRF}209	ip -netns ${NS1} -6 route add ${IPv6_6}/128 dev veth5 ${VRF}210	ip -netns ${NS1} -6 route add ${IPv6_7}/128 dev veth5 via ${IPv6_6} ${VRF}211	ip -netns ${NS1} -6 route add ${IPv6_8}/128 dev veth5 via ${IPv6_6} ${VRF}212 213	# NS2214	# top route215	ip -netns ${NS2}    route add ${IPv4_1}/32  dev veth2 ${VRF}216	ip -netns ${NS2}    route add ${IPv4_4}/32  dev veth3 ${VRF}217	ip -netns ${NS2} -6 route add ${IPv6_1}/128 dev veth2 ${VRF}218	ip -netns ${NS2} -6 route add ${IPv6_4}/128 dev veth3 ${VRF}219	# bottom route220	ip -netns ${NS2}    route add ${IPv4_5}/32  dev veth6 ${VRF}221	ip -netns ${NS2}    route add ${IPv4_8}/32  dev veth7 ${VRF}222	ip -netns ${NS2} -6 route add ${IPv6_5}/128 dev veth6 ${VRF}223	ip -netns ${NS2} -6 route add ${IPv6_8}/128 dev veth7 ${VRF}224 225	# NS3226	# top route227	ip -netns ${NS3}    route add ${IPv4_3}/32  dev veth4228	ip -netns ${NS3}    route add ${IPv4_1}/32  dev veth4 via ${IPv4_3}229	ip -netns ${NS3}    route add ${IPv4_2}/32  dev veth4 via ${IPv4_3}230	ip -netns ${NS3} -6 route add ${IPv6_3}/128 dev veth4231	ip -netns ${NS3} -6 route add ${IPv6_1}/128 dev veth4 via ${IPv6_3}232	ip -netns ${NS3} -6 route add ${IPv6_2}/128 dev veth4 via ${IPv6_3}233	# bottom route234	ip -netns ${NS3}    route add ${IPv4_7}/32  dev veth8235	ip -netns ${NS3}    route add ${IPv4_5}/32  dev veth8 via ${IPv4_7}236	ip -netns ${NS3}    route add ${IPv4_6}/32  dev veth8 via ${IPv4_7}237	ip -netns ${NS3} -6 route add ${IPv6_7}/128 dev veth8238	ip -netns ${NS3} -6 route add ${IPv6_5}/128 dev veth8 via ${IPv6_7}239	ip -netns ${NS3} -6 route add ${IPv6_6}/128 dev veth8 via ${IPv6_7}240 241	# configure IPv4 GRE device in NS3, and a route to it via the "bottom" route242	ip -netns ${NS3} tunnel add gre_dev mode gre remote ${IPv4_1} local ${IPv4_GRE} ttl 255243	ip -netns ${NS3} link set gre_dev up244	ip -netns ${NS3} addr add ${IPv4_GRE} dev gre_dev245	ip -netns ${NS1} route add ${IPv4_GRE}/32 dev veth5 via ${IPv4_6} ${VRF}246	ip -netns ${NS2} route add ${IPv4_GRE}/32 dev veth7 via ${IPv4_8} ${VRF}247 248 249	# configure IPv6 GRE device in NS3, and a route to it via the "bottom" route250	ip -netns ${NS3} -6 tunnel add name gre6_dev mode ip6gre remote ${IPv6_1} local ${IPv6_GRE} ttl 255251	ip -netns ${NS3} link set gre6_dev up252	ip -netns ${NS3} -6 addr add ${IPv6_GRE} nodad dev gre6_dev253	ip -netns ${NS1} -6 route add ${IPv6_GRE}/128 dev veth5 via ${IPv6_6} ${VRF}254	ip -netns ${NS2} -6 route add ${IPv6_GRE}/128 dev veth7 via ${IPv6_8} ${VRF}255 256	TMPFILE=$(mktemp /tmp/test_lwt_ip_encap.XXXXXX)257 258	sleep 1  # reduce flakiness259	set +e260}261 262cleanup()263{264	if [ -f ${TMPFILE} ] ; then265		rm ${TMPFILE}266	fi267 268	ip netns del ${NS1} 2> /dev/null269	ip netns del ${NS2} 2> /dev/null270	ip netns del ${NS3} 2> /dev/null271}272 273trap cleanup EXIT274 275remove_routes_to_gredev()276{277	ip -netns ${NS1} route del ${IPv4_GRE} dev veth5 ${VRF}278	ip -netns ${NS2} route del ${IPv4_GRE} dev veth7 ${VRF}279	ip -netns ${NS1} -6 route del ${IPv6_GRE}/128 dev veth5 ${VRF}280	ip -netns ${NS2} -6 route del ${IPv6_GRE}/128 dev veth7 ${VRF}281}282 283add_unreachable_routes_to_gredev()284{285	ip -netns ${NS1} route add unreachable ${IPv4_GRE}/32 ${VRF}286	ip -netns ${NS2} route add unreachable ${IPv4_GRE}/32 ${VRF}287	ip -netns ${NS1} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}288	ip -netns ${NS2} -6 route add unreachable ${IPv6_GRE}/128 ${VRF}289}290 291test_ping()292{293	local readonly PROTO=$1294	local readonly EXPECTED=$2295	local RET=0296 297	if [ "${PROTO}" == "IPv4" ] ; then298		ip netns exec ${NS1} ping  -c 1 -W 1 -I veth1 ${IPv4_DST} 2>&1 > /dev/null299		RET=$?300	elif [ "${PROTO}" == "IPv6" ] ; then301		ip netns exec ${NS1} ping6 -c 1 -W 1 -I veth1 ${IPv6_DST} 2>&1 > /dev/null302		RET=$?303	else304		echo "    test_ping: unknown PROTO: ${PROTO}"305		TEST_STATUS=1306	fi307 308	if [ "0" != "${RET}" ]; then309		RET=1310	fi311 312	if [ "${EXPECTED}" != "${RET}" ] ; then313		echo "    test_ping failed: expected: ${EXPECTED}; got ${RET}"314		TEST_STATUS=1315	fi316}317 318test_gso()319{320	local readonly PROTO=$1321	local readonly PKT_SZ=5000322	local IP_DST=""323	: > ${TMPFILE}  # trim the capture file324 325	# check that nc is present326	command -v nc >/dev/null 2>&1 || \327		{ echo >&2 "nc is not available: skipping TSO tests"; return; }328 329	# listen on port 9000, capture TCP into $TMPFILE330	if [ "${PROTO}" == "IPv4" ] ; then331		IP_DST=${IPv4_DST}332		ip netns exec ${NS3} bash -c \333			"nc -4 -l -p 9000 > ${TMPFILE} &"334	elif [ "${PROTO}" == "IPv6" ] ; then335		IP_DST=${IPv6_DST}336		ip netns exec ${NS3} bash -c \337			"nc -6 -l -p 9000 > ${TMPFILE} &"338		RET=$?339	else340		echo "    test_gso: unknown PROTO: ${PROTO}"341		TEST_STATUS=1342	fi343	sleep 1  # let nc start listening344 345	# send a packet larger than MTU346	ip netns exec ${NS1} bash -c \347		"dd if=/dev/zero bs=$PKT_SZ count=1 > /dev/tcp/${IP_DST}/9000 2>/dev/null"348	sleep 2 # let the packet get delivered349 350	# verify we received all expected bytes351	SZ=$(stat -c %s ${TMPFILE})352	if [ "$SZ" != "$PKT_SZ" ] ; then353		echo "    test_gso failed: ${PROTO}"354		TEST_STATUS=1355	fi356}357 358test_egress()359{360	local readonly ENCAP=$1361	echo "starting egress ${ENCAP} encap test ${VRF}"362	setup363 364	# by default, pings work365	test_ping IPv4 0366	test_ping IPv6 0367 368	# remove NS2->DST routes, ping fails369	ip -netns ${NS2}    route del ${IPv4_DST}/32  dev veth3 ${VRF}370	ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}371	test_ping IPv4 1372	test_ping IPv6 1373 374	# install replacement routes (LWT/eBPF), pings succeed375	if [ "${ENCAP}" == "IPv4" ] ; then376		ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \377			${BPF_FILE} sec encap_gre dev veth1 ${VRF}378		ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \379			${BPF_FILE} sec encap_gre dev veth1 ${VRF}380	elif [ "${ENCAP}" == "IPv6" ] ; then381		ip -netns ${NS1} route add ${IPv4_DST} encap bpf xmit obj \382			${BPF_FILE} sec encap_gre6 dev veth1 ${VRF}383		ip -netns ${NS1} -6 route add ${IPv6_DST} encap bpf xmit obj \384			${BPF_FILE} sec encap_gre6 dev veth1 ${VRF}385	else386		echo "    unknown encap ${ENCAP}"387		TEST_STATUS=1388	fi389	test_ping IPv4 0390	test_ping IPv6 0391 392	# skip GSO tests with VRF: VRF routing needs properly assigned393	# source IP/device, which is easy to do with ping and hard with dd/nc.394	if [ -z "${VRF}" ] ; then395		test_gso IPv4396		test_gso IPv6397	fi398 399	# a negative test: remove routes to GRE devices: ping fails400	remove_routes_to_gredev401	test_ping IPv4 1402	test_ping IPv6 1403 404	# another negative test405	add_unreachable_routes_to_gredev406	test_ping IPv4 1407	test_ping IPv6 1408 409	cleanup410	process_test_results411}412 413test_ingress()414{415	local readonly ENCAP=$1416	echo "starting ingress ${ENCAP} encap test ${VRF}"417	setup418 419	# need to wait a bit for IPv6 to autoconf, otherwise420	# ping6 sometimes fails with "unable to bind to address"421 422	# by default, pings work423	test_ping IPv4 0424	test_ping IPv6 0425 426	# remove NS2->DST routes, pings fail427	ip -netns ${NS2}    route del ${IPv4_DST}/32  dev veth3 ${VRF}428	ip -netns ${NS2} -6 route del ${IPv6_DST}/128 dev veth3 ${VRF}429	test_ping IPv4 1430	test_ping IPv6 1431 432	# install replacement routes (LWT/eBPF), pings succeed433	if [ "${ENCAP}" == "IPv4" ] ; then434		ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \435			${BPF_FILE} sec encap_gre dev veth2 ${VRF}436		ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \437			${BPF_FILE} sec encap_gre dev veth2 ${VRF}438	elif [ "${ENCAP}" == "IPv6" ] ; then439		ip -netns ${NS2} route add ${IPv4_DST} encap bpf in obj \440			${BPF_FILE} sec encap_gre6 dev veth2 ${VRF}441		ip -netns ${NS2} -6 route add ${IPv6_DST} encap bpf in obj \442			${BPF_FILE} sec encap_gre6 dev veth2 ${VRF}443	else444		echo "FAIL: unknown encap ${ENCAP}"445		TEST_STATUS=1446	fi447	test_ping IPv4 0448	test_ping IPv6 0449 450	# a negative test: remove routes to GRE devices: ping fails451	remove_routes_to_gredev452	test_ping IPv4 1453	test_ping IPv6 1454 455	# another negative test456	add_unreachable_routes_to_gredev457	test_ping IPv4 1458	test_ping IPv6 1459 460	cleanup461	process_test_results462}463 464VRF=""465test_egress IPv4466test_egress IPv6467test_ingress IPv4468test_ingress IPv6469 470VRF="vrf red"471test_egress IPv4472test_egress IPv6473test_ingress IPv4474test_ingress IPv6475 476print_test_summary_and_exit477