8278a24f5ba63481668d3ad7b383d48bc3a0b3d9
[platform/kernel/linux-rpi.git] / tools / testing / selftests / net / pmtu.sh
1 #!/bin/sh
2 # SPDX-License-Identifier: GPL-2.0
3 #
4 # Check that route PMTU values match expectations, and that initial device MTU
5 # values are assigned correctly
6 #
7 # Tests currently implemented:
8 #
9 # - pmtu_ipv4
10 #       Set up two namespaces, A and B, with two paths between them over routers
11 #       R1 and R2 (also implemented with namespaces), with different MTUs:
12 #
13 #         segment a_r1    segment b_r1          a_r1: 2000
14 #       .--------------R1--------------.        a_r2: 1500
15 #       A                               B       a_r3: 2000
16 #       '--------------R2--------------'        a_r4: 1400
17 #         segment a_r2    segment b_r2
18 #
19 #       Check that PMTU exceptions with the correct PMTU are created. Then
20 #       decrease and increase the MTU of the local link for one of the paths,
21 #       A to R1, checking that route exception PMTU changes accordingly over
22 #       this path. Also check that locked exceptions are created when an ICMP
23 #       message advertising a PMTU smaller than net.ipv4.route.min_pmtu is
24 #       received
25 #
26 # - pmtu_ipv6
27 #       Same as pmtu_ipv4, except for locked PMTU tests, using IPv6
28 #
29 # - pmtu_vti4_exception
30 #       Set up vti tunnel on top of veth, with xfrm states and policies, in two
31 #       namespaces with matching endpoints. Check that route exception is not
32 #       created if link layer MTU is not exceeded, then exceed it and check that
33 #       exception is created with the expected PMTU. The approach described
34 #       below for IPv6 doesn't apply here, because, on IPv4, administrative MTU
35 #       changes alone won't affect PMTU
36 #
37 # - pmtu_vti6_exception
38 #       Set up vti6 tunnel on top of veth, with xfrm states and policies, in two
39 #       namespaces with matching endpoints. Check that route exception is
40 #       created by exceeding link layer MTU with ping to other endpoint. Then
41 #       decrease and increase MTU of tunnel, checking that route exception PMTU
42 #       changes accordingly
43 #
44 # - pmtu_vti4_default_mtu
45 #       Set up vti4 tunnel on top of veth, in two namespaces with matching
46 #       endpoints. Check that MTU assigned to vti interface is the MTU of the
47 #       lower layer (veth) minus additional lower layer headers (zero, for veth)
48 #       minus IPv4 header length
49 #
50 # - pmtu_vti6_default_mtu
51 #       Same as above, for IPv6
52 #
53 # - pmtu_vti4_link_add_mtu
54 #       Set up vti4 interface passing MTU value at link creation, check MTU is
55 #       configured, and that link is not created with invalid MTU values
56 #
57 # - pmtu_vti6_link_add_mtu
58 #       Same as above, for IPv6
59 #
60 # - pmtu_vti6_link_change_mtu
61 #       Set up two dummy interfaces with different MTUs, create a vti6 tunnel
62 #       and check that configured MTU is used on link creation and changes, and
63 #       that MTU is properly calculated instead when MTU is not configured from
64 #       userspace
65
66 # Kselftest framework requirement - SKIP code is 4.
67 ksft_skip=4
68
69 # Some systems don't have a ping6 binary anymore
70 which ping6 > /dev/null 2>&1 && ping6=$(which ping6) || ping6=$(which ping)
71
72 tests="
73         pmtu_ipv4_exception             ipv4: PMTU exceptions
74         pmtu_ipv6_exception             ipv6: PMTU exceptions
75         pmtu_vti6_exception             vti6: PMTU exceptions
76         pmtu_vti4_exception             vti4: PMTU exceptions
77         pmtu_vti4_default_mtu           vti4: default MTU assignment
78         pmtu_vti6_default_mtu           vti6: default MTU assignment
79         pmtu_vti4_link_add_mtu          vti4: MTU setting on link creation
80         pmtu_vti6_link_add_mtu          vti6: MTU setting on link creation
81         pmtu_vti6_link_change_mtu       vti6: MTU changes on link changes"
82
83 NS_A="ns-$(mktemp -u XXXXXX)"
84 NS_B="ns-$(mktemp -u XXXXXX)"
85 NS_R1="ns-$(mktemp -u XXXXXX)"
86 NS_R2="ns-$(mktemp -u XXXXXX)"
87 ns_a="ip netns exec ${NS_A}"
88 ns_b="ip netns exec ${NS_B}"
89 ns_r1="ip netns exec ${NS_R1}"
90 ns_r2="ip netns exec ${NS_R2}"
91
92 # Addressing and routing for tests with routers: four network segments, with
93 # index SEGMENT between 1 and 4, a common prefix (PREFIX4 or PREFIX6) and an
94 # identifier ID, which is 1 for hosts (A and B), 2 for routers (R1 and R2).
95 # Addresses are:
96 # - IPv4: PREFIX4.SEGMENT.ID (/24)
97 # - IPv6: PREFIX6:SEGMENT::ID (/64)
98 prefix4="192.168"
99 prefix6="fd00"
100 a_r1=1
101 a_r2=2
102 b_r1=3
103 b_r2=4
104 #       ns      peer    segment
105 routing_addrs="
106         A       R1      ${a_r1}
107         A       R2      ${a_r2}
108         B       R1      ${b_r1}
109         B       R2      ${b_r2}
110 "
111 # Traffic from A to B goes through R1 by default, and through R2, if destined to
112 # B's address on the b_r2 segment.
113 # Traffic from B to A goes through R1.
114 #       ns      destination             gateway
115 routes="
116         A       default                 ${prefix4}.${a_r1}.2
117         A       ${prefix4}.${b_r2}.1    ${prefix4}.${a_r2}.2
118         B       default                 ${prefix4}.${b_r1}.2
119
120         A       default                 ${prefix6}:${a_r1}::2
121         A       ${prefix6}:${b_r2}::1   ${prefix6}:${a_r2}::2
122         B       default                 ${prefix6}:${b_r1}::2
123 "
124
125 veth4_a_addr="192.168.1.1"
126 veth4_b_addr="192.168.1.2"
127 veth4_mask="24"
128 veth6_a_addr="fd00:1::a"
129 veth6_b_addr="fd00:1::b"
130 veth6_mask="64"
131
132 vti4_a_addr="192.168.2.1"
133 vti4_b_addr="192.168.2.2"
134 vti4_mask="24"
135 vti6_a_addr="fd00:2::a"
136 vti6_b_addr="fd00:2::b"
137 vti6_mask="64"
138
139 dummy6_0_addr="fc00:1000::0"
140 dummy6_1_addr="fc00:1001::0"
141 dummy6_mask="64"
142
143 cleanup_done=1
144 err_buf=
145
146 err() {
147         err_buf="${err_buf}${1}
148 "
149 }
150
151 err_flush() {
152         echo -n "${err_buf}"
153         err_buf=
154 }
155
156 # Find the auto-generated name for this namespace
157 nsname() {
158         eval echo \$NS_$1
159 }
160
161 setup_namespaces() {
162         for n in ${NS_A} ${NS_B} ${NS_R1} ${NS_R2}; do
163                 ip netns add ${n} || return 1
164         done
165 }
166
167 setup_veth() {
168         ${ns_a} ip link add veth_a type veth peer name veth_b || return 1
169         ${ns_a} ip link set veth_b netns ${NS_B}
170
171         ${ns_a} ip addr add ${veth4_a_addr}/${veth4_mask} dev veth_a
172         ${ns_b} ip addr add ${veth4_b_addr}/${veth4_mask} dev veth_b
173
174         ${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a
175         ${ns_b} ip addr add ${veth6_b_addr}/${veth6_mask} dev veth_b
176
177         ${ns_a} ip link set veth_a up
178         ${ns_b} ip link set veth_b up
179 }
180
181 setup_vti() {
182         proto=${1}
183         veth_a_addr="${2}"
184         veth_b_addr="${3}"
185         vti_a_addr="${4}"
186         vti_b_addr="${5}"
187         vti_mask=${6}
188
189         [ ${proto} -eq 6 ] && vti_type="vti6" || vti_type="vti"
190
191         ${ns_a} ip link add vti${proto}_a type ${vti_type} local ${veth_a_addr} remote ${veth_b_addr} key 10 || return 1
192         ${ns_b} ip link add vti${proto}_b type ${vti_type} local ${veth_b_addr} remote ${veth_a_addr} key 10
193
194         ${ns_a} ip addr add ${vti_a_addr}/${vti_mask} dev vti${proto}_a
195         ${ns_b} ip addr add ${vti_b_addr}/${vti_mask} dev vti${proto}_b
196
197         ${ns_a} ip link set vti${proto}_a up
198         ${ns_b} ip link set vti${proto}_b up
199
200         sleep 1
201 }
202
203 setup_vti4() {
204         setup_vti 4 ${veth4_a_addr} ${veth4_b_addr} ${vti4_a_addr} ${vti4_b_addr} ${vti4_mask}
205 }
206
207 setup_vti6() {
208         setup_vti 6 ${veth6_a_addr} ${veth6_b_addr} ${vti6_a_addr} ${vti6_b_addr} ${vti6_mask}
209 }
210
211 setup_xfrm() {
212         proto=${1}
213         veth_a_addr="${2}"
214         veth_b_addr="${3}"
215
216         ${ns_a} ip -${proto} xfrm state add src ${veth_a_addr} dst ${veth_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1
217         ${ns_a} ip -${proto} xfrm state add src ${veth_b_addr} dst ${veth_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
218         ${ns_a} ip -${proto} xfrm policy add dir out mark 10 tmpl src ${veth_a_addr} dst ${veth_b_addr} proto esp mode tunnel
219         ${ns_a} ip -${proto} xfrm policy add dir in mark 10 tmpl src ${veth_b_addr} dst ${veth_a_addr} proto esp mode tunnel
220
221         ${ns_b} ip -${proto} xfrm state add src ${veth_a_addr} dst ${veth_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
222         ${ns_b} ip -${proto} xfrm state add src ${veth_b_addr} dst ${veth_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel
223         ${ns_b} ip -${proto} xfrm policy add dir out mark 10 tmpl src ${veth_b_addr} dst ${veth_a_addr} proto esp mode tunnel
224         ${ns_b} ip -${proto} xfrm policy add dir in mark 10 tmpl src ${veth_a_addr} dst ${veth_b_addr} proto esp mode tunnel
225 }
226
227 setup_xfrm4() {
228         setup_xfrm 4 ${veth4_a_addr} ${veth4_b_addr}
229 }
230
231 setup_xfrm6() {
232         setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr}
233 }
234
235 setup_routing() {
236         for i in ${NS_R1} ${NS_R2}; do
237                 ip netns exec ${i} sysctl -q net/ipv4/ip_forward=1
238                 ip netns exec ${i} sysctl -q net/ipv6/conf/all/forwarding=1
239         done
240
241         for i in ${routing_addrs}; do
242                 [ "${ns}" = "" ]        && ns="${i}"            && continue
243                 [ "${peer}" = "" ]      && peer="${i}"          && continue
244                 [ "${segment}" = "" ]   && segment="${i}"
245
246                 ns_name="$(nsname ${ns})"
247                 peer_name="$(nsname ${peer})"
248                 if="veth_${ns}-${peer}"
249                 ifpeer="veth_${peer}-${ns}"
250
251                 # Create veth links
252                 ip link add ${if} up netns ${ns_name} type veth peer name ${ifpeer} netns ${peer_name} || return 1
253                 ip -n ${peer_name} link set dev ${ifpeer} up
254
255                 # Add addresses
256                 ip -n ${ns_name}   addr add ${prefix4}.${segment}.1/24  dev ${if}
257                 ip -n ${ns_name}   addr add ${prefix6}:${segment}::1/64 dev ${if}
258
259                 ip -n ${peer_name} addr add ${prefix4}.${segment}.2/24  dev ${ifpeer}
260                 ip -n ${peer_name} addr add ${prefix6}:${segment}::2/64 dev ${ifpeer}
261
262                 ns=""; peer=""; segment=""
263         done
264
265         for i in ${routes}; do
266                 [ "${ns}" = "" ]        && ns="${i}"            && continue
267                 [ "${addr}" = "" ]      && addr="${i}"          && continue
268                 [ "${gw}" = "" ]        && gw="${i}"
269
270                 ns_name="$(nsname ${ns})"
271
272                 ip -n ${ns_name} route add ${addr} via ${gw}
273
274                 ns=""; addr=""; gw=""
275         done
276 }
277
278 setup() {
279         [ "$(id -u)" -ne 0 ] && echo "  need to run as root" && return $ksft_skip
280
281         cleanup_done=0
282         for arg do
283                 eval setup_${arg} || { echo "  ${arg} not supported"; return 1; }
284         done
285 }
286
287 cleanup() {
288         [ ${cleanup_done} -eq 1 ] && return
289         for n in ${NS_A} ${NS_B} ${NS_R1} ${NS_R2}; do
290                 ip netns del ${n} 2> /dev/null
291         done
292         cleanup_done=1
293 }
294
295 mtu() {
296         ns_cmd="${1}"
297         dev="${2}"
298         mtu="${3}"
299
300         ${ns_cmd} ip link set dev ${dev} mtu ${mtu}
301 }
302
303 mtu_parse() {
304         input="${1}"
305
306         next=0
307         for i in ${input}; do
308                 [ ${next} -eq 1 -a "${i}" = "lock" ] && next=2 && continue
309                 [ ${next} -eq 1 ] && echo "${i}" && return
310                 [ ${next} -eq 2 ] && echo "lock ${i}" && return
311                 [ "${i}" = "mtu" ] && next=1
312         done
313 }
314
315 link_get() {
316         ns_cmd="${1}"
317         name="${2}"
318
319         ${ns_cmd} ip link show dev "${name}"
320 }
321
322 link_get_mtu() {
323         ns_cmd="${1}"
324         name="${2}"
325
326         mtu_parse "$(link_get "${ns_cmd}" ${name})"
327 }
328
329 route_get_dst_exception() {
330         ns_cmd="${1}"
331         dst="${2}"
332
333         ${ns_cmd} ip route get "${dst}"
334 }
335
336 route_get_dst_pmtu_from_exception() {
337         ns_cmd="${1}"
338         dst="${2}"
339
340         mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})"
341 }
342
343 check_pmtu_value() {
344         expected="${1}"
345         value="${2}"
346         event="${3}"
347
348         [ "${expected}" = "any" ] && [ -n "${value}" ] && return 0
349         [ "${value}" = "${expected}" ] && return 0
350         [ -z "${value}" ] &&    err "  PMTU exception wasn't created after ${event}" && return 1
351         [ -z "${expected}" ] && err "  PMTU exception shouldn't exist after ${event}" && return 1
352         err "  found PMTU exception with incorrect MTU ${value}, expected ${expected}, after ${event}"
353         return 1
354 }
355
356 test_pmtu_ipvX() {
357         family=${1}
358
359         setup namespaces routing || return 2
360
361         if [ ${family} -eq 4 ]; then
362                 ping=ping
363                 dst1="${prefix4}.${b_r1}.1"
364                 dst2="${prefix4}.${b_r2}.1"
365         else
366                 ping=${ping6}
367                 dst1="${prefix6}:${b_r1}::1"
368                 dst2="${prefix6}:${b_r2}::1"
369         fi
370
371         # Set up initial MTU values
372         mtu "${ns_a}"  veth_A-R1 2000
373         mtu "${ns_r1}" veth_R1-A 2000
374         mtu "${ns_r1}" veth_R1-B 1400
375         mtu "${ns_b}"  veth_B-R1 1400
376
377         mtu "${ns_a}"  veth_A-R2 2000
378         mtu "${ns_r2}" veth_R2-A 2000
379         mtu "${ns_r2}" veth_R2-B 1500
380         mtu "${ns_b}"  veth_B-R2 1500
381
382         # Create route exceptions
383         ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1800 ${dst1} > /dev/null
384         ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1800 ${dst2} > /dev/null
385
386         # Check that exceptions have been created with the correct PMTU
387         pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})"
388         check_pmtu_value "1400" "${pmtu_1}" "exceeding MTU" || return 1
389         pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})"
390         check_pmtu_value "1500" "${pmtu_2}" "exceeding MTU" || return 1
391
392         # Decrease local MTU below PMTU, check for PMTU decrease in route exception
393         mtu "${ns_a}"  veth_A-R1 1300
394         mtu "${ns_r1}" veth_R1-A 1300
395         pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})"
396         check_pmtu_value "1300" "${pmtu_1}" "decreasing local MTU" || return 1
397         # Second exception shouldn't be modified
398         pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})"
399         check_pmtu_value "1500" "${pmtu_2}" "changing local MTU on a link not on this path" || return 1
400
401         # Increase MTU, check for PMTU increase in route exception
402         mtu "${ns_a}"  veth_A-R1 1700
403         mtu "${ns_r1}" veth_R1-A 1700
404         pmtu_1="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst1})"
405         check_pmtu_value "1700" "${pmtu_1}" "increasing local MTU" || return 1
406         # Second exception shouldn't be modified
407         pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})"
408         check_pmtu_value "1500" "${pmtu_2}" "changing local MTU on a link not on this path" || return 1
409
410         # Skip PMTU locking tests for IPv6
411         [ $family -eq 6 ] && return 0
412
413         # Decrease remote MTU on path via R2, get new exception
414         mtu "${ns_r2}" veth_R2-B 400
415         mtu "${ns_b}"  veth_B-R2 400
416         ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1400 ${dst2} > /dev/null
417         pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})"
418         check_pmtu_value "lock 552" "${pmtu_2}" "exceeding MTU, with MTU < min_pmtu" || return 1
419
420         # Decrease local MTU below PMTU
421         mtu "${ns_a}"  veth_A-R2 500
422         mtu "${ns_r2}" veth_R2-A 500
423         pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})"
424         check_pmtu_value "500" "${pmtu_2}" "decreasing local MTU" || return 1
425
426         # Increase local MTU
427         mtu "${ns_a}"  veth_A-R2 1500
428         mtu "${ns_r2}" veth_R2-A 1500
429         pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})"
430         check_pmtu_value "1500" "${pmtu_2}" "increasing local MTU" || return 1
431
432         # Get new exception
433         ${ns_a} ${ping} -q -M want -i 0.1 -w 2 -s 1400 ${dst2} > /dev/null
434         pmtu_2="$(route_get_dst_pmtu_from_exception "${ns_a}" ${dst2})"
435         check_pmtu_value "lock 552" "${pmtu_2}" "exceeding MTU, with MTU < min_pmtu" || return 1
436 }
437
438 test_pmtu_ipv4_exception() {
439         test_pmtu_ipvX 4
440 }
441
442 test_pmtu_ipv6_exception() {
443         test_pmtu_ipvX 6
444 }
445
446 test_pmtu_vti4_exception() {
447         setup namespaces veth vti4 xfrm4 || return 2
448
449         veth_mtu=1500
450         vti_mtu=$((veth_mtu - 20))
451
452         #                                SPI   SN   IV  ICV   pad length   next header
453         esp_payload_rfc4106=$((vti_mtu - 4   - 4  - 8 - 16  - 1          - 1))
454         ping_payload=$((esp_payload_rfc4106 - 28))
455
456         mtu "${ns_a}" veth_a ${veth_mtu}
457         mtu "${ns_b}" veth_b ${veth_mtu}
458         mtu "${ns_a}" vti4_a ${vti_mtu}
459         mtu "${ns_b}" vti4_b ${vti_mtu}
460
461         # Send DF packet without exceeding link layer MTU, check that no
462         # exception is created
463         ${ns_a} ping -q -M want -i 0.1 -w 2 -s ${ping_payload} ${vti4_b_addr} > /dev/null
464         pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})"
465         check_pmtu_value "" "${pmtu}" "sending packet smaller than PMTU (IP payload length ${esp_payload_rfc4106})" || return 1
466
467         # Now exceed link layer MTU by one byte, check that exception is created
468         # with the right PMTU value
469         ${ns_a} ping -q -M want -i 0.1 -w 2 -s $((ping_payload + 1)) ${vti4_b_addr} > /dev/null
470         pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})"
471         check_pmtu_value "${esp_payload_rfc4106}" "${pmtu}" "exceeding PMTU (IP payload length $((esp_payload_rfc4106 + 1)))"
472 }
473
474 test_pmtu_vti6_exception() {
475         setup namespaces veth vti6 xfrm6 || return 2
476         fail=0
477
478         # Create route exception by exceeding link layer MTU
479         mtu "${ns_a}" veth_a 4000
480         mtu "${ns_b}" veth_b 4000
481         mtu "${ns_a}" vti6_a 5000
482         mtu "${ns_b}" vti6_b 5000
483         ${ns_a} ${ping6} -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null
484
485         # Check that exception was created
486         pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})"
487         check_pmtu_value any "${pmtu}" "creating tunnel exceeding link layer MTU" || return 1
488
489         # Decrease tunnel MTU, check for PMTU decrease in route exception
490         mtu "${ns_a}" vti6_a 3000
491         pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})"
492         check_pmtu_value "3000" "${pmtu}" "decreasing tunnel MTU" || fail=1
493
494         # Increase tunnel MTU, check for PMTU increase in route exception
495         mtu "${ns_a}" vti6_a 9000
496         pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})"
497         check_pmtu_value "9000" "${pmtu}" "increasing tunnel MTU" || fail=1
498
499         return ${fail}
500 }
501
502 test_pmtu_vti4_default_mtu() {
503         setup namespaces veth vti4 || return 2
504
505         # Check that MTU of vti device is MTU of veth minus IPv4 header length
506         veth_mtu="$(link_get_mtu "${ns_a}" veth_a)"
507         vti4_mtu="$(link_get_mtu "${ns_a}" vti4_a)"
508         if [ $((veth_mtu - vti4_mtu)) -ne 20 ]; then
509                 err "  vti MTU ${vti4_mtu} is not veth MTU ${veth_mtu} minus IPv4 header length"
510                 return 1
511         fi
512 }
513
514 test_pmtu_vti6_default_mtu() {
515         setup namespaces veth vti6 || return 2
516
517         # Check that MTU of vti device is MTU of veth minus IPv6 header length
518         veth_mtu="$(link_get_mtu "${ns_a}" veth_a)"
519         vti6_mtu="$(link_get_mtu "${ns_a}" vti6_a)"
520         if [ $((veth_mtu - vti6_mtu)) -ne 40 ]; then
521                 err "  vti MTU ${vti6_mtu} is not veth MTU ${veth_mtu} minus IPv6 header length"
522                 return 1
523         fi
524 }
525
526 test_pmtu_vti4_link_add_mtu() {
527         setup namespaces || return 2
528
529         ${ns_a} ip link add vti4_a type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10
530         [ $? -ne 0 ] && err "  vti not supported" && return 2
531         ${ns_a} ip link del vti4_a
532
533         fail=0
534
535         min=68
536         max=$((65535 - 20))
537         # Check invalid values first
538         for v in $((min - 1)) $((max + 1)); do
539                 ${ns_a} ip link add vti4_a mtu ${v} type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10 2>/dev/null
540                 # This can fail, or MTU can be adjusted to a proper value
541                 [ $? -ne 0 ] && continue
542                 mtu="$(link_get_mtu "${ns_a}" vti4_a)"
543                 if [ ${mtu} -lt ${min} -o ${mtu} -gt ${max} ]; then
544                         err "  vti tunnel created with invalid MTU ${mtu}"
545                         fail=1
546                 fi
547                 ${ns_a} ip link del vti4_a
548         done
549
550         # Now check valid values
551         for v in ${min} 1300 ${max}; do
552                 ${ns_a} ip link add vti4_a mtu ${v} type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10
553                 mtu="$(link_get_mtu "${ns_a}" vti4_a)"
554                 ${ns_a} ip link del vti4_a
555                 if [ "${mtu}" != "${v}" ]; then
556                         err "  vti MTU ${mtu} doesn't match configured value ${v}"
557                         fail=1
558                 fi
559         done
560
561         return ${fail}
562 }
563
564 test_pmtu_vti6_link_add_mtu() {
565         setup namespaces || return 2
566
567         ${ns_a} ip link add vti6_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10
568         [ $? -ne 0 ] && err "  vti6 not supported" && return 2
569         ${ns_a} ip link del vti6_a
570
571         fail=0
572
573         min=68                  # vti6 can carry IPv4 packets too
574         max=$((65535 - 40))
575         # Check invalid values first
576         for v in $((min - 1)) $((max + 1)); do
577                 ${ns_a} ip link add vti6_a mtu ${v} type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 2>/dev/null
578                 # This can fail, or MTU can be adjusted to a proper value
579                 [ $? -ne 0 ] && continue
580                 mtu="$(link_get_mtu "${ns_a}" vti6_a)"
581                 if [ ${mtu} -lt ${min} -o ${mtu} -gt ${max} ]; then
582                         err "  vti6 tunnel created with invalid MTU ${v}"
583                         fail=1
584                 fi
585                 ${ns_a} ip link del vti6_a
586         done
587
588         # Now check valid values
589         for v in 68 1280 1300 $((65535 - 40)); do
590                 ${ns_a} ip link add vti6_a mtu ${v} type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10
591                 mtu="$(link_get_mtu "${ns_a}" vti6_a)"
592                 ${ns_a} ip link del vti6_a
593                 if [ "${mtu}" != "${v}" ]; then
594                         err "  vti6 MTU ${mtu} doesn't match configured value ${v}"
595                         fail=1
596                 fi
597         done
598
599         return ${fail}
600 }
601
602 test_pmtu_vti6_link_change_mtu() {
603         setup namespaces || return 2
604
605         ${ns_a} ip link add dummy0 mtu 1500 type dummy
606         [ $? -ne 0 ] && err "  dummy not supported" && return 2
607         ${ns_a} ip link add dummy1 mtu 3000 type dummy
608         ${ns_a} ip link set dummy0 up
609         ${ns_a} ip link set dummy1 up
610
611         ${ns_a} ip addr add ${dummy6_0_addr}/${dummy6_mask} dev dummy0
612         ${ns_a} ip addr add ${dummy6_1_addr}/${dummy6_mask} dev dummy1
613
614         fail=0
615
616         # Create vti6 interface bound to device, passing MTU, check it
617         ${ns_a} ip link add vti6_a mtu 1300 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr}
618         mtu="$(link_get_mtu "${ns_a}" vti6_a)"
619         if [ ${mtu} -ne 1300 ]; then
620                 err "  vti6 MTU ${mtu} doesn't match configured value 1300"
621                 fail=1
622         fi
623
624         # Move to another device with different MTU, without passing MTU, check
625         # MTU is adjusted
626         ${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr}
627         mtu="$(link_get_mtu "${ns_a}" vti6_a)"
628         if [ ${mtu} -ne $((3000 - 40)) ]; then
629                 err "  vti MTU ${mtu} is not dummy MTU 3000 minus IPv6 header length"
630                 fail=1
631         fi
632
633         # Move it back, passing MTU, check MTU is not overridden
634         ${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr}
635         mtu="$(link_get_mtu "${ns_a}" vti6_a)"
636         if [ ${mtu} -ne 1280 ]; then
637                 err "  vti6 MTU ${mtu} doesn't match configured value 1280"
638                 fail=1
639         fi
640
641         return ${fail}
642 }
643
644 usage() {
645         echo
646         echo "$0 [TEST]..."
647         echo "If no TEST argument is given, all tests will be run."
648         echo
649         echo "Available tests${tests}"
650         exit 1
651 }
652
653 for arg do
654         # Check first that all requested tests are available before running any
655         command -v > /dev/null "test_${arg}" || { echo "=== Test ${arg} not found"; usage; }
656 done
657
658 trap cleanup EXIT
659
660 exitcode=0
661 desc=0
662 IFS="   
663 "
664 for t in ${tests}; do
665         [ $desc -eq 0 ] && name="${t}" && desc=1 && continue || desc=0
666
667         run_this=1
668         for arg do
669                 [ "${arg}" = "${name}" ] && run_this=1 && break
670                 run_this=0
671         done
672         [ $run_this -eq 0 ] && continue
673
674         (
675                 unset IFS
676                 eval test_${name}
677                 ret=$?
678                 cleanup
679
680                 if [ $ret -eq 0 ]; then
681                         printf "TEST: %-60s  [ OK ]\n" "${t}"
682                 elif [ $ret -eq 1 ]; then
683                         printf "TEST: %-60s  [FAIL]\n" "${t}"
684                         err_flush
685                         exit 1
686                 elif [ $ret -eq 2 ]; then
687                         printf "TEST: %-60s  [SKIP]\n" "${t}"
688                         err_flush
689                 fi
690         )
691         [ $? -ne 0 ] && exitcode=1
692 done
693
694 exit ${exitcode}