1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# +-----------------------+                          +------------------------+
5# | H1 (vrf)              |                          | H2 (vrf)               |
6# |    + $h1              |                          |    + $h2               |
7# |    | 192.0.2.1/28     |                          |    | 192.0.2.2/28      |
8# |    | 2001:db8:1::1/64 |                          |    | 2001:db8:1::2/64  |
9# +----|------------------+                          +----|-------------------+
10#      |                                                  |
11# +----|--------------------------------------------------|-------------------+
12# | SW |                                                  |                   |
13# | +--|--------------------------------------------------|-----------------+ |
14# | |  + $swp1                   BR1 (802.1d)             + $swp2           | |
15# | |                                                                       | |
16# | |  + vx1 (vxlan)                                                        | |
17# | |    local 2001:db8:3::1                                                | |
18# | |    remote 2001:db8:4::1 2001:db8:5::1                                 | |
19# | |    id 1000 dstport $VXPORT                                            | |
20# | +-----------------------------------------------------------------------+ |
21# |                                                                           |
22# |  2001:db8:4::0/64 via 2001:db8:3::2                                       |
23# |  2001:db8:5::0/64 via 2001:db8:3::2                                       |
24# |                                                                           |
25# |    + $rp1                                                                 |
26# |    | 2001:db8:3::1/64                                                     |
27# +----|----------------------------------------------------------------------+
28#      |
29# +----|----------------------------------------------------------+
30# |    |                                             VRP2 (vrf)   |
31# |    + $rp2                                                     |
32# |      2001:db8:3::2/64                                         |
33# |                                                               |  (maybe) HW
34# =============================================================================
35# |                                                               |  (likely) SW
36# |    + v1 (veth)                             + v3 (veth)        |
37# |    | 2001:db8:4::2/64                      | 2001:db8:5::2/64 |
38# +----|---------------------------------------|------------------+
39#      |                                       |
40# +----|--------------------------------+ +----|-------------------------------+
41# |    + v2 (veth)        NS1 (netns)   | |    + v4 (veth)        NS2 (netns)  |
42# |      2001:db8:4::1/64               | |      2001:db8:5::1/64              |
43# |                                     | |                                    |
44# | 2001:db8:3::0/64 via 2001:db8:4::2  | | 2001:db8:3::0/64 via 2001:db8:5::2 |
45# | 2001:db8:5::1/128 via 2001:db8:4::2 | | 2001:db8:4::1/128 via              |
46# |                                     | |         2001:db8:5::2              |
47# |                                     | |                                    |
48# | +-------------------------------+   | | +-------------------------------+  |
49# | |                  BR2 (802.1d) |   | | |                  BR2 (802.1d) |  |
50# | |  + vx2 (vxlan)                |   | | |  + vx2 (vxlan)                |  |
51# | |    local 2001:db8:4::1        |   | | |    local 2001:db8:5::1        |  |
52# | |    remote 2001:db8:3::1       |   | | |    remote 2001:db8:3::1       |  |
53# | |    remote 2001:db8:5::1       |   | | |    remote 2001:db8:4::1       |  |
54# | |    id 1000 dstport $VXPORT    |   | | |    id 1000 dstport $VXPORT    |  |
55# | |                               |   | | |                               |  |
56# | |  + w1 (veth)                  |   | | |  + w1 (veth)                  |  |
57# | +--|----------------------------+   | | +--|----------------------------+  |
58# |    |                                | |    |                               |
59# | +--|----------------------------+   | | +--|----------------------------+  |
60# | |  + w2 (veth)        VW2 (vrf) |   | | |  + w2 (veth)        VW2 (vrf) |  |
61# | |    192.0.2.3/28               |   | | |    192.0.2.4/28               |  |
62# | |    2001:db8:1::3/64           |   | | |    2001:db8:1::4/64           |  |
63# | +-------------------------------+   | | +-------------------------------+  |
64# +-------------------------------------+ +------------------------------------+
65
66: ${VXPORT:=4789}
67export VXPORT
68
69: ${ALL_TESTS:="
70	ping_ipv4
71	ping_ipv6
72	test_flood
73	test_unicast
74	test_ttl
75	test_tos
76	test_ecn_encap
77	test_ecn_decap
78	reapply_config
79	ping_ipv4
80	ping_ipv6
81	test_flood
82	test_unicast
83"}
84
85NUM_NETIFS=6
86source lib.sh
87source tc_common.sh
88
89h1_create()
90{
91	simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
92	tc qdisc add dev $h1 clsact
93}
94
95h1_destroy()
96{
97	tc qdisc del dev $h1 clsact
98	simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64
99}
100
101h2_create()
102{
103	simple_if_init $h2 192.0.2.2/28 2001:db8:1::2/64
104	tc qdisc add dev $h2 clsact
105}
106
107h2_destroy()
108{
109	tc qdisc del dev $h2 clsact
110	simple_if_fini $h2 192.0.2.2/28 2001:db8:1::2/64
111}
112
113rp1_set_addr()
114{
115	ip address add dev $rp1 2001:db8:3::1/64
116
117	ip route add 2001:db8:4::0/64 nexthop via 2001:db8:3::2
118	ip route add 2001:db8:5::0/64 nexthop via 2001:db8:3::2
119}
120
121rp1_unset_addr()
122{
123	ip route del 2001:db8:5::0/64 nexthop via 2001:db8:3::2
124	ip route del 2001:db8:4::0/64 nexthop via 2001:db8:3::2
125
126	ip address del dev $rp1 2001:db8:3::1/64
127}
128
129switch_create()
130{
131	ip link add name br1 type bridge vlan_filtering 0 mcast_snooping 0
132	# Make sure the bridge uses the MAC address of the local port and not
133	# that of the VxLAN's device.
134	ip link set dev br1 address $(mac_get $swp1)
135	ip link set dev br1 up
136
137	ip link set dev $rp1 up
138	rp1_set_addr
139	tc qdisc add dev $rp1 clsact
140
141	ip link add name vx1 type vxlan id 1000	local 2001:db8:3::1 \
142		dstport "$VXPORT" nolearning udp6zerocsumrx udp6zerocsumtx \
143		tos inherit ttl 100
144	ip link set dev vx1 up
145
146	ip link set dev vx1 master br1
147	ip link set dev $swp1 master br1
148	ip link set dev $swp1 up
149	tc qdisc add dev $swp1 clsact
150
151	ip link set dev $swp2 master br1
152	ip link set dev $swp2 up
153
154	bridge fdb append dev vx1 00:00:00:00:00:00 dst 2001:db8:4::1 self
155	bridge fdb append dev vx1 00:00:00:00:00:00 dst 2001:db8:5::1 self
156}
157
158switch_destroy()
159{
160	bridge fdb del dev vx1 00:00:00:00:00:00 dst 2001:db8:5::1 self
161	bridge fdb del dev vx1 00:00:00:00:00:00 dst 2001:db8:4::1 self
162
163	ip link set dev $swp2 down
164	ip link set dev $swp2 nomaster
165
166	tc qdisc del dev $swp1 clsact
167	ip link set dev $swp1 down
168	ip link set dev $swp1 nomaster
169
170	ip link set dev vx1 nomaster
171	ip link set dev vx1 down
172	ip link del dev vx1
173
174	tc qdisc del dev $rp1 clsact
175	rp1_unset_addr
176	ip link set dev $rp1 down
177
178	ip link set dev br1 down
179	ip link del dev br1
180}
181
182vrp2_create()
183{
184	simple_if_init $rp2 2001:db8:3::2/64
185	__simple_if_init v1 v$rp2 2001:db8:4::2/64
186	__simple_if_init v3 v$rp2 2001:db8:5::2/64
187	tc qdisc add dev v1 clsact
188}
189
190vrp2_destroy()
191{
192	tc qdisc del dev v1 clsact
193	__simple_if_fini v3 2001:db8:5::2/64
194	__simple_if_fini v1 2001:db8:4::2/64
195	simple_if_fini $rp2 2001:db8:3::2/64
196}
197
198ns_init_common()
199{
200	local in_if=$1; shift
201	local in_addr=$1; shift
202	local other_in_addr=$1; shift
203	local nh_addr=$1; shift
204	local host_addr_ipv4=$1; shift
205	local host_addr_ipv6=$1; shift
206
207	ip link set dev $in_if up
208	ip address add dev $in_if $in_addr/64
209	tc qdisc add dev $in_if clsact
210
211	ip link add name br2 type bridge vlan_filtering 0
212	ip link set dev br2 up
213
214	ip link add name w1 type veth peer name w2
215
216	ip link set dev w1 master br2
217	ip link set dev w1 up
218
219	ip link add name vx2 type vxlan id 1000 local $in_addr \
220		dstport "$VXPORT" udp6zerocsumrx
221	ip link set dev vx2 up
222	bridge fdb append dev vx2 00:00:00:00:00:00 dst 2001:db8:3::1 self
223	bridge fdb append dev vx2 00:00:00:00:00:00 dst $other_in_addr self
224
225	ip link set dev vx2 master br2
226	tc qdisc add dev vx2 clsact
227
228	simple_if_init w2 $host_addr_ipv4/28 $host_addr_ipv6/64
229
230	ip route add 2001:db8:3::0/64 nexthop via $nh_addr
231	ip route add $other_in_addr/128 nexthop via $nh_addr
232}
233export -f ns_init_common
234
235ns1_create()
236{
237	ip netns add ns1
238	ip link set dev v2 netns ns1
239	in_ns ns1 \
240	      ns_init_common v2 2001:db8:4::1 2001:db8:5::1 2001:db8:4::2 \
241	      192.0.2.3 2001:db8:1::3
242}
243
244ns1_destroy()
245{
246	ip netns exec ns1 ip link set dev v2 netns 1
247	ip netns del ns1
248}
249
250ns2_create()
251{
252	ip netns add ns2
253	ip link set dev v4 netns ns2
254	in_ns ns2 \
255	      ns_init_common v4 2001:db8:5::1 2001:db8:4::1 2001:db8:5::2 \
256	      192.0.2.4 2001:db8:1::4
257}
258
259ns2_destroy()
260{
261	ip netns exec ns2 ip link set dev v4 netns 1
262	ip netns del ns2
263}
264
265setup_prepare()
266{
267	h1=${NETIFS[p1]}
268	swp1=${NETIFS[p2]}
269
270	swp2=${NETIFS[p3]}
271	h2=${NETIFS[p4]}
272
273	rp1=${NETIFS[p5]}
274	rp2=${NETIFS[p6]}
275
276	vrf_prepare
277	forwarding_enable
278
279	h1_create
280	h2_create
281	switch_create
282
283	ip link add name v1 type veth peer name v2
284	ip link add name v3 type veth peer name v4
285	vrp2_create
286	ns1_create
287	ns2_create
288
289	r1_mac=$(in_ns ns1 mac_get w2)
290	r2_mac=$(in_ns ns2 mac_get w2)
291	h2_mac=$(mac_get $h2)
292}
293
294cleanup()
295{
296	pre_cleanup
297
298	ns2_destroy
299	ns1_destroy
300	vrp2_destroy
301	ip link del dev v3
302	ip link del dev v1
303
304	switch_destroy
305	h2_destroy
306	h1_destroy
307
308	forwarding_restore
309	vrf_cleanup
310}
311
312# For the first round of tests, vx1 is the first device to get
313# attached to the bridge, and at that point the local IP is already
314# configured. Try the other scenario of attaching the devices to a an
315# already-offloaded bridge, and only then assign the local IP.
316reapply_config()
317{
318	log_info "Reapplying configuration"
319
320	bridge fdb del dev vx1 00:00:00:00:00:00 dst 2001:db8:5::1 self
321	bridge fdb del dev vx1 00:00:00:00:00:00 dst 2001:db8:4::1 self
322	ip link set dev vx1 nomaster
323	rp1_unset_addr
324	sleep 5
325
326	ip link set dev vx1 master br1
327	bridge fdb append dev vx1 00:00:00:00:00:00 dst 2001:db8:4::1 self
328	bridge fdb append dev vx1 00:00:00:00:00:00 dst 2001:db8:5::1 self
329	sleep 1
330	rp1_set_addr
331	sleep 5
332}
333
334__ping_ipv4()
335{
336	local vxlan_local_ip=$1; shift
337	local vxlan_remote_ip=$1; shift
338	local src_ip=$1; shift
339	local dst_ip=$1; shift
340	local dev=$1; shift
341	local info=$1; shift
342
343	RET=0
344
345	tc filter add dev $rp1 egress protocol ipv6 pref 1 handle 101 \
346		flower ip_proto udp src_ip $vxlan_local_ip \
347		dst_ip $vxlan_remote_ip dst_port $VXPORT $TC_FLAG action pass
348	# Match ICMP-reply packets after decapsulation, so source IP is
349	# destination IP of the ping and destination IP is source IP of the
350	# ping.
351	tc filter add dev $swp1 egress protocol ip pref 1 handle 101 \
352		flower src_ip $dst_ip dst_ip $src_ip \
353		$TC_FLAG action pass
354
355	# Send 100 packets and verify that at least 100 packets hit the rule,
356	# to overcome ARP noise.
357	PING_COUNT=100 PING_TIMEOUT=11 ping_do $dev $dst_ip
358	check_err $? "Ping failed"
359
360	tc_check_at_least_x_packets "dev $rp1 egress" 101 10 100
361	check_err $? "Encapsulated packets did not go through router"
362
363	tc_check_at_least_x_packets "dev $swp1 egress" 101 10 100
364	check_err $? "Decapsulated packets did not go through switch"
365
366	log_test "ping: $info"
367
368	tc filter del dev $swp1 egress
369	tc filter del dev $rp1 egress
370}
371
372ping_ipv4()
373{
374	RET=0
375
376	local local_sw_ip=2001:db8:3::1
377	local remote_ns1_ip=2001:db8:4::1
378	local remote_ns2_ip=2001:db8:5::1
379	local h1_ip=192.0.2.1
380	local w2_ns1_ip=192.0.2.3
381	local w2_ns2_ip=192.0.2.4
382
383	ping_test $h1 192.0.2.2 ": local->local"
384
385	__ping_ipv4 $local_sw_ip $remote_ns1_ip $h1_ip $w2_ns1_ip $h1 \
386		"local->remote 1"
387	__ping_ipv4 $local_sw_ip $remote_ns2_ip $h1_ip $w2_ns2_ip $h1 \
388		"local->remote 2"
389}
390
391__ping_ipv6()
392{
393	local vxlan_local_ip=$1; shift
394	local vxlan_remote_ip=$1; shift
395	local src_ip=$1; shift
396	local dst_ip=$1; shift
397	local dev=$1; shift
398	local info=$1; shift
399
400	RET=0
401
402	tc filter add dev $rp1 egress protocol ipv6 pref 1 handle 101 \
403		flower ip_proto udp src_ip $vxlan_local_ip \
404		dst_ip $vxlan_remote_ip dst_port $VXPORT $TC_FLAG action pass
405	# Match ICMP-reply packets after decapsulation, so source IP is
406	# destination IP of the ping and destination IP is source IP of the
407	# ping.
408	tc filter add dev $swp1 egress protocol ipv6 pref 1 handle 101 \
409		flower src_ip $dst_ip dst_ip $src_ip $TC_FLAG action pass
410
411	# Send 100 packets and verify that at least 100 packets hit the rule,
412	# to overcome neighbor discovery noise.
413	PING_COUNT=100 PING_TIMEOUT=11 ping6_do $dev $dst_ip
414	check_err $? "Ping failed"
415
416	tc_check_at_least_x_packets "dev $rp1 egress" 101 100
417	check_err $? "Encapsulated packets did not go through router"
418
419	tc_check_at_least_x_packets "dev $swp1 egress" 101 100
420	check_err $? "Decapsulated packets did not go through switch"
421
422	log_test "ping6: $info"
423
424	tc filter del dev $swp1 egress
425	tc filter del dev $rp1 egress
426}
427
428ping_ipv6()
429{
430	RET=0
431
432	local local_sw_ip=2001:db8:3::1
433	local remote_ns1_ip=2001:db8:4::1
434	local remote_ns2_ip=2001:db8:5::1
435	local h1_ip=2001:db8:1::1
436	local w2_ns1_ip=2001:db8:1::3
437	local w2_ns2_ip=2001:db8:1::4
438
439	ping6_test $h1 2001:db8:1::2 ": local->local"
440
441	__ping_ipv6 $local_sw_ip $remote_ns1_ip $h1_ip $w2_ns1_ip $h1 \
442		"local->remote 1"
443	__ping_ipv6 $local_sw_ip $remote_ns2_ip $h1_ip $w2_ns2_ip $h1 \
444		"local->remote 2"
445}
446
447maybe_in_ns()
448{
449	echo ${1:+in_ns} $1
450}
451
452__flood_counter_add_del()
453{
454	local add_del=$1; shift
455	local dst_ip=$1; shift
456	local dev=$1; shift
457	local ns=$1; shift
458
459	# Putting the ICMP capture both to HW and to SW will end up
460	# double-counting the packets that are trapped to slow path, such as for
461	# the unicast test. Adding either skip_hw or skip_sw fixes this problem,
462	# but with skip_hw, the flooded packets are not counted at all, because
463	# those are dropped due to MAC address mismatch; and skip_sw is a no-go
464	# for veth-based topologies.
465	#
466	# So try to install with skip_sw and fall back to skip_sw if that fails.
467
468	$(maybe_in_ns $ns) tc filter $add_del dev "$dev" ingress \
469	   proto ipv6 pref 100 flower dst_ip $dst_ip ip_proto \
470	   icmpv6 skip_sw action pass 2>/dev/null || \
471	$(maybe_in_ns $ns) tc filter $add_del dev "$dev" ingress \
472	   proto ipv6 pref 100 flower dst_ip $dst_ip ip_proto \
473	   icmpv6 skip_hw action pass
474}
475
476flood_counter_install()
477{
478	__flood_counter_add_del add "$@"
479}
480
481flood_counter_uninstall()
482{
483	__flood_counter_add_del del "$@"
484}
485
486flood_fetch_stat()
487{
488	local dev=$1; shift
489	local ns=$1; shift
490
491	$(maybe_in_ns $ns) tc_rule_stats_get $dev 100 ingress
492}
493
494flood_fetch_stats()
495{
496	local counters=("${@}")
497	local counter
498
499	for counter in "${counters[@]}"; do
500		flood_fetch_stat $counter
501	done
502}
503
504vxlan_flood_test()
505{
506	local mac=$1; shift
507	local dst=$1; shift
508	local -a expects=("${@}")
509
510	local -a counters=($h2 "vx2 ns1" "vx2 ns2")
511	local counter
512	local key
513
514	for counter in "${counters[@]}"; do
515		flood_counter_install $dst $counter
516	done
517
518	local -a t0s=($(flood_fetch_stats "${counters[@]}"))
519	$MZ -6 $h1 -c 10 -d 100msec -p 64 -b $mac -B $dst -t icmp6 type=128 -q
520	sleep 1
521	local -a t1s=($(flood_fetch_stats "${counters[@]}"))
522
523	for key in ${!t0s[@]}; do
524		local delta=$((t1s[$key] - t0s[$key]))
525		local expect=${expects[$key]}
526
527		((expect == delta))
528		check_err $? "${counters[$key]}: Expected to capture $expect packets, got $delta."
529	done
530
531	for counter in "${counters[@]}"; do
532		flood_counter_uninstall $dst $counter
533	done
534}
535
536__test_flood()
537{
538	local mac=$1; shift
539	local dst=$1; shift
540	local what=$1; shift
541
542	RET=0
543
544	vxlan_flood_test $mac $dst 10 10 10
545
546	log_test "VXLAN: $what"
547}
548
549test_flood()
550{
551	__test_flood de:ad:be:ef:13:37 2001:db8:1::100 "flood"
552}
553
554vxlan_fdb_add_del()
555{
556	local add_del=$1; shift
557	local mac=$1; shift
558	local dev=$1; shift
559	local dst=$1; shift
560
561	bridge fdb $add_del dev $dev $mac self static permanent \
562		${dst:+dst} $dst 2>/dev/null
563	bridge fdb $add_del dev $dev $mac master static 2>/dev/null
564}
565
566__test_unicast()
567{
568	local mac=$1; shift
569	local dst=$1; shift
570	local hit_idx=$1; shift
571	local what=$1; shift
572
573	RET=0
574
575	local -a expects=(0 0 0)
576	expects[$hit_idx]=10
577
578	vxlan_flood_test $mac $dst "${expects[@]}"
579
580	log_test "VXLAN: $what"
581}
582
583test_unicast()
584{
585	local -a targets=("$h2_mac $h2"
586			  "$r1_mac vx1 2001:db8:4::1"
587			  "$r2_mac vx1 2001:db8:5::1")
588	local target
589
590	for target in "${targets[@]}"; do
591		vxlan_fdb_add_del add $target
592	done
593
594	__test_unicast $h2_mac 2001:db8:1::2 0 "local MAC unicast"
595	__test_unicast $r1_mac 2001:db8:1::3 1 "remote MAC 1 unicast"
596	__test_unicast $r2_mac 2001:db8:1::4 2 "remote MAC 2 unicast"
597
598	for target in "${targets[@]}"; do
599		vxlan_fdb_add_del del $target
600	done
601}
602
603vxlan_ping_test()
604{
605	local ping_dev=$1; shift
606	local ping_dip=$1; shift
607	local ping_args=$1; shift
608	local capture_dev=$1; shift
609	local capture_dir=$1; shift
610	local capture_pref=$1; shift
611	local expect=$1; shift
612
613	local t0=$(tc_rule_stats_get $capture_dev $capture_pref $capture_dir)
614	ping6_do $ping_dev $ping_dip "$ping_args"
615	local t1=$(tc_rule_stats_get $capture_dev $capture_pref $capture_dir)
616	local delta=$((t1 - t0))
617
618	# Tolerate a couple stray extra packets.
619	((expect <= delta && delta <= expect + 2))
620	check_err $? "$capture_dev: Expected to capture $expect packets, got $delta."
621}
622
623test_ttl()
624{
625	RET=0
626
627	tc filter add dev v1 egress pref 77 protocol ipv6 \
628		flower ip_ttl 99 action pass
629	vxlan_ping_test $h1 2001:db8:1::3 "" v1 egress 77 10
630	tc filter del dev v1 egress pref 77 protocol ipv6
631
632	log_test "VXLAN: envelope TTL"
633}
634
635test_tos()
636{
637	RET=0
638
639	tc filter add dev v1 egress pref 77 protocol ipv6 \
640		flower ip_tos 0x14 action pass
641	vxlan_ping_test $h1 2001:db8:1::3 "-Q 0x14" v1 egress 77 10
642	vxlan_ping_test $h1 2001:db8:1::3 "-Q 0x18" v1 egress 77 0
643	tc filter del dev v1 egress pref 77 protocol ipv6
644
645	log_test "VXLAN: envelope TOS inheritance"
646}
647
648__test_ecn_encap()
649{
650	local q=$1; shift
651	local tos=$1; shift
652
653	RET=0
654
655	tc filter add dev v1 egress pref 77 protocol ipv6 \
656		flower ip_tos $tos action pass
657	sleep 1
658	vxlan_ping_test $h1 2001:db8:1::3 "-Q $q" v1 egress 77 10
659	tc filter del dev v1 egress pref 77 protocol ipv6
660
661	log_test "VXLAN: ECN encap: $q->$tos"
662}
663
664test_ecn_encap()
665{
666	# In accordance with INET_ECN_encapsulate()
667	__test_ecn_encap 0x00 0x00
668	__test_ecn_encap 0x01 0x01
669	__test_ecn_encap 0x02 0x02
670	__test_ecn_encap 0x03 0x02
671}
672
673vxlan_encapped_ping_do()
674{
675	local count=$1; shift
676	local dev=$1; shift
677	local next_hop_mac=$1; shift
678	local dest_ip=$1; shift
679	local dest_mac=$1; shift
680	local inner_tos=$1; shift
681	local outer_tos=$1; shift
682	local saddr="20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:03"
683	local daddr="20:01:0d:b8:00:01:00:00:00:00:00:00:00:00:00:01"
684
685	$MZ -6 $dev -c $count -d 100msec -q \
686		-b $next_hop_mac -B $dest_ip \
687		-t udp tos=$outer_tos,sp=23456,dp=$VXPORT,p=$(:
688		    )"08:"$(                      : VXLAN flags
689		    )"00:00:00:"$(                : VXLAN reserved
690		    )"00:03:e8:"$(                : VXLAN VNI
691		    )"00:"$(                      : VXLAN reserved
692		    )"$dest_mac:"$(               : ETH daddr
693		    )"$(mac_get w2):"$(           : ETH saddr
694		    )"86:dd:"$(                   : ETH type
695		    )"6"$(			  : IP version
696		    )"$inner_tos"$(               : Traffic class
697		    )"0:00:00:"$(                 : Flow label
698		    )"00:08:"$(                   : Payload length
699		    )"3a:"$(                      : Next header
700		    )"04:"$(                      : Hop limit
701		    )"$saddr:"$(		  : IP saddr
702		    )"$daddr:"$(		  : IP daddr
703		    )"80:"$(			  : ICMPv6.type
704		    )"00:"$(			  : ICMPv6.code
705		    )"00:"$(			  : ICMPv6.checksum
706		    )
707}
708export -f vxlan_encapped_ping_do
709
710vxlan_encapped_ping_test()
711{
712	local ping_dev=$1; shift
713	local nh_dev=$1; shift
714	local ping_dip=$1; shift
715	local inner_tos=$1; shift
716	local outer_tos=$1; shift
717	local stat_get=$1; shift
718	local expect=$1; shift
719
720	local t0=$($stat_get)
721
722	in_ns ns1 \
723		vxlan_encapped_ping_do 10 $ping_dev $(mac_get $nh_dev) \
724			$ping_dip $(mac_get $h1) \
725			$inner_tos $outer_tos
726	sleep 1
727	local t1=$($stat_get)
728	local delta=$((t1 - t0))
729
730	# Tolerate a couple stray extra packets.
731	((expect <= delta && delta <= expect + 2))
732	check_err $? "Expected to capture $expect packets, got $delta."
733}
734export -f vxlan_encapped_ping_test
735
736__test_ecn_decap()
737{
738	local orig_inner_tos=$1; shift
739	local orig_outer_tos=$1; shift
740	local decapped_tos=$1; shift
741
742	RET=0
743
744	tc filter add dev $h1 ingress pref 77 protocol ipv6 \
745		flower src_ip 2001:db8:1::3 dst_ip 2001:db8:1::1 \
746		ip_tos $decapped_tos action drop
747	sleep 1
748	vxlan_encapped_ping_test v2 v1 2001:db8:3::1 \
749				 $orig_inner_tos $orig_outer_tos \
750				 "tc_rule_stats_get $h1 77 ingress" 10
751	tc filter del dev $h1 ingress pref 77
752
753	log_test "VXLAN: ECN decap: $orig_outer_tos/$orig_inner_tos->$decapped_tos"
754}
755
756test_ecn_decap_error()
757{
758	local orig_inner_tos="0:0"
759	local orig_outer_tos=03
760
761	RET=0
762
763	vxlan_encapped_ping_test v2 v1 2001:db8:3::1 \
764				 $orig_inner_tos $orig_outer_tos \
765				 "link_stats_rx_errors_get vx1" 10
766
767	log_test "VXLAN: ECN decap: $orig_outer_tos/$orig_inner_tos->error"
768}
769
770test_ecn_decap()
771{
772	# In accordance with INET_ECN_decapsulate()
773	__test_ecn_decap "0:0" 00 0x00
774	__test_ecn_decap "0:0" 01 0x00
775	__test_ecn_decap "0:0" 02 0x00
776	# 00 03 is tested in test_ecn_decap_error()
777	__test_ecn_decap "0:1" 00 0x01
778	__test_ecn_decap "0:1" 01 0x01
779	__test_ecn_decap "0:1" 02 0x01
780	__test_ecn_decap "0:1" 03 0x03
781	__test_ecn_decap "0:2" 00 0x02
782	__test_ecn_decap "0:2" 01 0x01
783	__test_ecn_decap "0:2" 02 0x02
784	__test_ecn_decap "0:2" 03 0x03
785	__test_ecn_decap "0:3" 00 0x03
786	__test_ecn_decap "0:3" 01 0x03
787	__test_ecn_decap "0:3" 02 0x03
788	__test_ecn_decap "0:3" 03 0x03
789	test_ecn_decap_error
790}
791
792test_all()
793{
794	log_info "Running tests with UDP port $VXPORT"
795	tests_run
796}
797
798trap cleanup EXIT
799
800setup_prepare
801setup_wait
802test_all
803
804exit $EXIT_STATUS
805