brintos

brintos / linux-shallow public Read only

0
0
Text · 14.0 KiB · f11756e Raw
447 lines · bash
1#!/bin/sh2# SPDX-License-Identifier: GPL-2.03 4# Author: Matthias May <matthias.may@westermo.com>5#6# This script evaluates ip tunnels that are capable of carrying L2 traffic7# if they inherit or set the inheritable fields.8# Namely these tunnels are: 'gretap', 'vxlan' and 'geneve'.9# Checked inheritable fields are: TOS and TTL.10# The outer tunnel protocol of 'IPv4' or 'IPv6' is verified-11# As payload frames of type 'IPv4', 'IPv6' and 'other'(ARP) are verified.12# In addition this script also checks if forcing a specific field in the13# outer header is working.14 15# Return 4 by default (Kselftest SKIP code)16ERR=417 18if [ "$(id -u)" != "0" ]; then19	echo "Please run as root."20	exit $ERR21fi22if ! which tcpdump > /dev/null 2>&1; then23	echo "No tcpdump found. Required for this test."24	exit $ERR25fi26 27expected_tos="0x00"28expected_ttl="0"29failed=false30 31readonly NS0=$(mktemp -u ns0-XXXXXXXX)32readonly NS1=$(mktemp -u ns1-XXXXXXXX)33 34RUN_NS0="ip netns exec ${NS0}"35 36get_random_tos() {37	# Get a random hex tos value between 0x00 and 0xfc, a multiple of 438	echo "0x$(tr -dc '0-9a-f' < /dev/urandom | head -c 1)\39$(tr -dc '048c' < /dev/urandom | head -c 1)"40}41get_random_ttl() {42	# Get a random dec value between 0 and 25543	printf "%d" "0x$(tr -dc '0-9a-f' < /dev/urandom | head -c 2)"44}45get_field() {46	# Expects to get the 'head -n 1' of a captured frame by tcpdump.47	# Parses this first line and returns the specified field.48	local field="$1"49	local input="$2"50	local found=false51	input="$(echo "$input" | tr -d '(),')"52	for input_field in $input; do53		if $found; then54			echo "$input_field"55			return56		fi57		# The next field that we iterate over is the looked for value58		if [ "$input_field" = "$field" ]; then59			found=true60		fi61	done62	echo "0"63}64setup() {65	local type="$1"66	local outer="$2"67	local inner="$3"68	local tos_ttl="$4"69	local vlan="$5"70	local test_tos="0x00"71	local test_ttl="0"72 73	# We don't want a test-tos of 0x00,74	# because this is the value that we get when no tos is set.75	expected_tos="$(get_random_tos)"76	while [ "$expected_tos" = "0x00" ]; do77		expected_tos="$(get_random_tos)"78	done79	if [ "$tos_ttl" = "random" ]; then80		test_tos="$expected_tos"81		tos="fixed $test_tos"82	elif [ "$tos_ttl" = "inherit" ]; then83		test_tos="$tos_ttl"84		tos="inherit $expected_tos"85	fi86 87	# We don't want a test-ttl of 64 or 0,88	# because 64 is when no ttl is set and 0 is not a valid ttl.89	expected_ttl="$(get_random_ttl)"90	while [ "$expected_ttl" = "64" ] || [ "$expected_ttl" = "0" ]; do91		expected_ttl="$(get_random_ttl)"92	done93 94	if [ "$tos_ttl" = "random" ]; then95		test_ttl="$expected_ttl"96		ttl="fixed $test_ttl"97	elif [ "$tos_ttl" = "inherit" ]; then98		test_ttl="$tos_ttl"99		ttl="inherit $expected_ttl"100	fi101	printf "│%7s │%6s │%6s │%13s │%13s │%6s │" \102	"$type" "$outer" "$inner" "$tos" "$ttl" "$vlan"103 104	# Create netns NS0 and NS1 and connect them with a veth pair105	ip netns add "${NS0}"106	ip netns add "${NS1}"107	ip link add name veth0 netns "${NS0}" type veth \108		peer name veth1 netns "${NS1}"109	ip -netns "${NS0}" link set dev veth0 up110	ip -netns "${NS1}" link set dev veth1 up111	ip -netns "${NS0}" address flush dev veth0112	ip -netns "${NS1}" address flush dev veth1113 114	local local_addr1=""115	local local_addr2=""116	if [ "$type" = "gre" ] || [ "$type" = "vxlan" ]; then117		if [ "$outer" = "4" ]; then118			local_addr1="local 198.18.0.1"119			local_addr2="local 198.18.0.2"120		elif [ "$outer" = "6" ]; then121			local_addr1="local fdd1:ced0:5d88:3fce::1"122			local_addr2="local fdd1:ced0:5d88:3fce::2"123		fi124	fi125	local vxlan=""126	if [ "$type" = "vxlan" ]; then127		vxlan="vni 100 dstport 4789"128	fi129	local geneve=""130	if [ "$type" = "geneve" ]; then131		geneve="vni 100"132	fi133	# Create tunnel and assign outer IPv4/IPv6 addresses134	if [ "$outer" = "4" ]; then135		if [ "$type" = "gre" ]; then136			type="gretap"137		fi138		ip -netns "${NS0}" address add 198.18.0.1/24 dev veth0139		ip -netns "${NS1}" address add 198.18.0.2/24 dev veth1140		ip -netns "${NS0}" link add name tep0 type $type $local_addr1 \141			remote 198.18.0.2 tos $test_tos ttl $test_ttl         \142			$vxlan $geneve143		ip -netns "${NS1}" link add name tep1 type $type $local_addr2 \144			remote 198.18.0.1 tos $test_tos ttl $test_ttl         \145			$vxlan $geneve146	elif [ "$outer" = "6" ]; then147		if [ "$type" = "gre" ]; then148			type="ip6gretap"149		fi150		ip -netns "${NS0}" address add fdd1:ced0:5d88:3fce::1/64 \151			dev veth0 nodad152		ip -netns "${NS1}" address add fdd1:ced0:5d88:3fce::2/64 \153			dev veth1 nodad154		ip -netns "${NS0}" link add name tep0 type $type $local_addr1 \155			remote fdd1:ced0:5d88:3fce::2 tos $test_tos           \156			ttl $test_ttl $vxlan $geneve157		ip -netns "${NS1}" link add name tep1 type $type $local_addr2 \158			remote fdd1:ced0:5d88:3fce::1 tos $test_tos           \159			ttl $test_ttl $vxlan $geneve160	fi161 162	# Bring L2-tunnel link up and create VLAN on top163	ip -netns "${NS0}" link set tep0 up164	ip -netns "${NS1}" link set tep1 up165	ip -netns "${NS0}" address flush dev tep0166	ip -netns "${NS1}" address flush dev tep1167	local parent168	if $vlan; then169		parent="vlan99-"170		ip -netns "${NS0}" link add link tep0 name ${parent}0 \171			type vlan id 99172		ip -netns "${NS1}" link add link tep1 name ${parent}1 \173			type vlan id 99174		ip -netns "${NS0}" link set dev ${parent}0 up175		ip -netns "${NS1}" link set dev ${parent}1 up176		ip -netns "${NS0}" address flush dev ${parent}0177		ip -netns "${NS1}" address flush dev ${parent}1178	else179		parent="tep"180	fi181 182	# Assign inner IPv4/IPv6 addresses183	if [ "$inner" = "4" ] || [ "$inner" = "other" ]; then184		ip -netns "${NS0}" address add 198.19.0.1/24 brd + dev ${parent}0185		ip -netns "${NS1}" address add 198.19.0.2/24 brd + dev ${parent}1186	elif [ "$inner" = "6" ]; then187		ip -netns "${NS0}" address add fdd4:96cf:4eae:443b::1/64 \188			dev ${parent}0 nodad189		ip -netns "${NS1}" address add fdd4:96cf:4eae:443b::2/64 \190			dev ${parent}1 nodad191	fi192}193 194verify() {195	local outer="$1"196	local inner="$2"197	local tos_ttl="$3"198	local vlan="$4"199 200	local ping_pid out captured_tos captured_ttl result201 202	local ping_dst203	if [ "$inner" = "4" ]; then204		ping_dst="198.19.0.2"205	elif [ "$inner" = "6" ]; then206		ping_dst="fdd4:96cf:4eae:443b::2"207	elif [ "$inner" = "other" ]; then208		ping_dst="198.19.0.3" # Generates ARPs which are not IPv4/IPv6209	fi210	if [ "$tos_ttl" = "inherit" ]; then211		${RUN_NS0} ping -i 0.1 $ping_dst -Q "$expected_tos"          \212			 -t "$expected_ttl" 2>/dev/null 1>&2 & ping_pid="$!"213	else214		${RUN_NS0} ping -i 0.1 $ping_dst 2>/dev/null 1>&2 & ping_pid="$!"215	fi216	local tunnel_type_offset tunnel_type_proto req_proto_offset req_offset217	if [ "$type" = "gre" ]; then218		tunnel_type_proto="0x2f"219	elif [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then220		tunnel_type_proto="0x11"221	fi222	if [ "$outer" = "4" ]; then223		tunnel_type_offset="9"224		if [ "$inner" = "4" ]; then225			req_proto_offset="47"226			req_offset="58"227			if [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then228				req_proto_offset="$((req_proto_offset + 12))"229				req_offset="$((req_offset + 12))"230			fi231			if $vlan; then232				req_proto_offset="$((req_proto_offset + 4))"233				req_offset="$((req_offset + 4))"234			fi235			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \236				-i veth0 -n                                   \237				ip[$tunnel_type_offset] = $tunnel_type_proto and \238				ip[$req_proto_offset] = 0x01 and              \239				ip[$req_offset] = 0x08 2>/dev/null            \240				| head -n 1)"241		elif [ "$inner" = "6" ]; then242			req_proto_offset="44"243			req_offset="78"244			if [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then245				req_proto_offset="$((req_proto_offset + 12))"246				req_offset="$((req_offset + 12))"247			fi248			if $vlan; then249				req_proto_offset="$((req_proto_offset + 4))"250				req_offset="$((req_offset + 4))"251			fi252			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \253				-i veth0 -n                                   \254				ip[$tunnel_type_offset] = $tunnel_type_proto and \255				ip[$req_proto_offset] = 0x3a and              \256				ip[$req_offset] = 0x80 2>/dev/null            \257				| head -n 1)"258		elif [ "$inner" = "other" ]; then259			req_proto_offset="36"260			req_offset="45"261			if [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then262				req_proto_offset="$((req_proto_offset + 12))"263				req_offset="$((req_offset + 12))"264			fi265			if $vlan; then266				req_proto_offset="$((req_proto_offset + 4))"267				req_offset="$((req_offset + 4))"268			fi269			if [ "$tos_ttl" = "inherit" ]; then270				expected_tos="0x00"271				expected_ttl="64"272			fi273			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \274				-i veth0 -n                                   \275				ip[$tunnel_type_offset] = $tunnel_type_proto and \276				ip[$req_proto_offset] = 0x08 and              \277				ip[$((req_proto_offset + 1))] = 0x06 and      \278				ip[$req_offset] = 0x01 2>/dev/null            \279				| head -n 1)"280		fi281	elif [ "$outer" = "6" ]; then282		if [ "$type" = "gre" ]; then283			tunnel_type_offset="40"284		elif [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then285			tunnel_type_offset="6"286		fi287		if [ "$inner" = "4" ]; then288			local req_proto_offset="75"289			local req_offset="86"290			if [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then291				req_proto_offset="$((req_proto_offset + 4))"292				req_offset="$((req_offset + 4))"293			fi294			if $vlan; then295				req_proto_offset="$((req_proto_offset + 4))"296				req_offset="$((req_offset + 4))"297			fi298			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \299				-i veth0 -n                                   \300				ip6[$tunnel_type_offset] = $tunnel_type_proto and \301				ip6[$req_proto_offset] = 0x01 and             \302				ip6[$req_offset] = 0x08 2>/dev/null           \303				| head -n 1)"304		elif [ "$inner" = "6" ]; then305			local req_proto_offset="72"306			local req_offset="106"307			if [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then308				req_proto_offset="$((req_proto_offset + 4))"309				req_offset="$((req_offset + 4))"310			fi311			if $vlan; then312				req_proto_offset="$((req_proto_offset + 4))"313				req_offset="$((req_offset + 4))"314			fi315			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \316				-i veth0 -n                                   \317				ip6[$tunnel_type_offset] = $tunnel_type_proto and \318				ip6[$req_proto_offset] = 0x3a and             \319				ip6[$req_offset] = 0x80 2>/dev/null           \320				| head -n 1)"321		elif [ "$inner" = "other" ]; then322			local req_proto_offset="64"323			local req_offset="73"324			if [ "$type" = "vxlan" ] || [ "$type" = "geneve" ]; then325				req_proto_offset="$((req_proto_offset + 4))"326				req_offset="$((req_offset + 4))"327			fi328			if $vlan; then329				req_proto_offset="$((req_proto_offset + 4))"330				req_offset="$((req_offset + 4))"331			fi332			if [ "$tos_ttl" = "inherit" ]; then333				expected_tos="0x00"334				expected_ttl="64"335			fi336			out="$(${RUN_NS0} tcpdump --immediate-mode -p -c 1 -v \337				-i veth0 -n                                   \338				ip6[$tunnel_type_offset] = $tunnel_type_proto and \339				ip6[$req_proto_offset] = 0x08 and             \340				ip6[$((req_proto_offset + 1))] = 0x06 and     \341				ip6[$req_offset] = 0x01 2>/dev/null           \342				| head -n 1)"343		fi344	fi345	kill -9 $ping_pid346	wait $ping_pid 2>/dev/null || true347	result="FAIL"348	if [ "$outer" = "4" ]; then349		captured_ttl="$(get_field "ttl" "$out")"350		captured_tos="$(printf "0x%02x" "$(get_field "tos" "$out")")"351		if [ "$captured_tos" = "$expected_tos" ] &&352		   [ "$captured_ttl" = "$expected_ttl" ]; then353			result="OK"354		fi355	elif [ "$outer" = "6" ]; then356		captured_ttl="$(get_field "hlim" "$out")"357		captured_tos="$(printf "0x%02x" "$(get_field "class" "$out")")"358		if [ "$captured_tos" = "$expected_tos" ] &&359		   [ "$captured_ttl" = "$expected_ttl" ]; then360			result="OK"361		fi362	fi363 364	printf "%7s │\n" "$result"365	if [ "$result" = "FAIL" ]; then366		failed=true367		if [ "$captured_tos" != "$expected_tos" ]; then368			printf "│%43s%27s │\n" \369			"Expected TOS value: $expected_tos" \370			"Captured TOS value: $captured_tos"371		fi372		if [ "$captured_ttl" != "$expected_ttl" ]; then373			printf "│%43s%27s │\n" \374			"Expected TTL value: $expected_ttl" \375			"Captured TTL value: $captured_ttl"376		fi377		printf "│%71s│\n" " "378	fi379}380 381cleanup() {382	ip netns del "${NS0}" 2>/dev/null383	ip netns del "${NS1}" 2>/dev/null384}385 386exit_handler() {387	# Don't exit immediately if one of the intermediate commands fails.388	# We might be called at the end of the script, when the network389	# namespaces have already been deleted. So cleanup() may fail, but we390	# still need to run until 'exit $ERR' or the script won't return the391	# correct error code.392	set +e393 394	cleanup395 396	exit $ERR397}398 399# Restore the default SIGINT handler (just in case) and exit.400# The exit handler will take care of cleaning everything up.401interrupted() {402	trap - INT403 404	exit $ERR405}406 407set -e408trap exit_handler EXIT409trap interrupted INT410 411printf "┌────────┬───────┬───────┬──────────────┬"412printf "──────────────┬───────┬────────┐\n"413for type in gre vxlan geneve; do414	if ! $(modprobe "$type" 2>/dev/null); then415		continue416	fi417	for outer in 4 6; do418		printf "├────────┼───────┼───────┼──────────────┼"419		printf "──────────────┼───────┼────────┤\n"420		printf "│  Type  │ outer | inner │     tos      │"421		printf "      ttl     │  vlan │ result │\n"422		for inner in 4 6 other; do423			printf "├────────┼───────┼───────┼──────────────┼"424			printf "──────────────┼───────┼────────┤\n"425			for tos_ttl in inherit random; do426				for vlan in false true; do427					setup "$type" "$outer" "$inner" \428					"$tos_ttl" "$vlan"429					verify "$outer" "$inner" "$tos_ttl" \430					"$vlan"431					cleanup432				done433			done434		done435	done436done437printf "└────────┴───────┴───────┴──────────────┴"438printf "──────────────┴───────┴────────┘\n"439 440# All tests done.441# Set ERR appropriately: it will be returned by the exit handler.442if $failed; then443	ERR=1444else445	ERR=0446fi447