aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/net/pmtu.sh
blob: 0d010f982272e2e38e7f987ceb8a5cd7fd0ec9cf (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
#
# Check that route PMTU values match expectations
#
# Tests currently implemented:
#
# - test_pmtu_vti6_exception
#	Set up vti6 tunnel on top of veth, with xfrm states and policies, in two
#	namespaces with matching endpoints. Check that route exception is
#	created by exceeding link layer MTU with ping to other endpoint. Then
#	decrease and increase MTU of tunnel, checking that route exception PMTU
#	changes accordingly

NS_A="ns-$(mktemp -u XXXXXX)"
NS_B="ns-$(mktemp -u XXXXXX)"
ns_a="ip netns exec ${NS_A}"
ns_b="ip netns exec ${NS_B}"

veth6_a_addr="fd00:1::a"
veth6_b_addr="fd00:1::b"
veth6_mask="64"

vti6_a_addr="fd00:2::a"
vti6_b_addr="fd00:2::b"
vti6_mask="64"

setup_namespaces() {
	ip netns add ${NS_A} || return 1
	ip netns add ${NS_B}
}

setup_veth() {
	${ns_a} ip link add veth_a type veth peer name veth_b || return 1
	${ns_a} ip link set veth_b netns ${NS_B}

	${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a
	${ns_b} ip addr add ${veth6_b_addr}/${veth6_mask} dev veth_b

	${ns_a} ip link set veth_a up
	${ns_b} ip link set veth_b up
}

setup_vti6() {
	${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 1
	${ns_b} ip link add vti_b type vti6 local ${veth6_b_addr} remote ${veth6_a_addr} key 10

	${ns_a} ip addr add ${vti6_a_addr}/${vti6_mask} dev vti_a
	${ns_b} ip addr add ${vti6_b_addr}/${vti6_mask} dev vti_b

	${ns_a} ip link set vti_a up
	${ns_b} ip link set vti_b up

	sleep 1
}

setup_xfrm() {
	${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1
	${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
	${ns_a} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel
	${ns_a} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel

	${ns_b} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
	${ns_b} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
	${ns_b} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel
	${ns_b} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel
}

setup() {
	tunnel_type="$1"

	[ "$(id -u)" -ne 0 ] && echo "SKIP: need to run as root" && exit 0

	setup_namespaces || { echo "SKIP: namespaces not supported"; exit 0; }
	setup_veth || { echo "SKIP: veth not supported"; exit 0; }

	case ${tunnel_type} in
	"vti6")
		setup_vti6 || { echo "SKIP: vti6 not supported"; exit 0; }
		setup_xfrm || { echo "SKIP: xfrm not supported"; exit 0; }
		;;
	*)
		;;
	esac
}

cleanup() {
	ip netns del ${NS_A} 2 > /dev/null
	ip netns del ${NS_B} 2 > /dev/null
}

mtu() {
	ns_cmd="${1}"
	dev="${2}"
	mtu="${3}"

	${ns_cmd} ip link set dev ${dev} mtu ${mtu}
}

route_get_dst_exception() {
	ns_cmd="${1}"
	dst="${2}"

	${ns_cmd} ip route get "${dst}"
}

route_get_dst_pmtu_from_exception() {
	ns_cmd="${1}"
	dst="${2}"

	exception="$(route_get_dst_exception "${ns_cmd}" ${dst})"
	next=0
	for i in ${exception}; do
		[ ${next} -eq 1 ] && echo "${i}" && return
		[ "${i}" = "mtu" ] && next=1
	done
}

test_pmtu_vti6_exception() {
	setup vti6

	# Create route exception by exceeding link layer MTU
	mtu "${ns_a}" veth_a 4000
	mtu "${ns_b}" veth_b 4000
	mtu "${ns_a}" vti_a 5000
	mtu "${ns_b}" vti_b 5000
	${ns_a} ping6 -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null

	# Check that exception was created
	if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" = "" ]; then
		echo "FAIL: Tunnel exceeding link layer MTU didn't create route exception"
		exit 1
	fi

	# Decrease tunnel MTU, check for PMTU decrease in route exception
	mtu "${ns_a}" vti_a 3000

	if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then
		echo "FAIL: Decreasing tunnel MTU didn't decrease route exception PMTU"
		exit 1
	fi

	# Increase tunnel MTU, check for PMTU increase in route exception
	mtu "${ns_a}" vti_a 9000
	if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then
		echo "FAIL: Increasing tunnel MTU didn't increase route exception PMTU"
		exit 1
	fi

	echo "PASS"
}

trap cleanup EXIT

test_pmtu_vti6_exception

exit 0