1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Test VxLAN flooding. The device stores flood records in a singly linked list
5# where each record stores up to four IPv6 addresses of remote VTEPs. The test
6# verifies that packets are correctly flooded in various cases such as deletion
7# of a record in the middle of the list.
8#
9# +-----------------------+
10# | H1 (vrf)              |
11# |    + $h1              |
12# |    | 2001:db8:1::1/64 |
13# +----|------------------+
14#      |
15# +----|----------------------------------------------------------------------+
16# | SW |                                                                      |
17# | +--|--------------------------------------------------------------------+ |
18# | |  + $swp1                   BR0 (802.1d)                               | |
19# | |                                                                       | |
20# | |  + vxlan0 (vxlan)                                                     | |
21# | |    local 2001:db8:2::1                                                | |
22# | |    remote 2001:db8:2::{2..17}                                         | |
23# | |    id 10 dstport 4789                                                 | |
24# | +-----------------------------------------------------------------------+ |
25# |                                                                           |
26# |  2001:db8:2::0/64 via 2001:db8:3::2                                       |
27# |                                                                           |
28# |    + $rp1                                                                 |
29# |    | 2001:db8:3::1/64                                                     |
30# +----|----------------------------------------------------------------------+
31#      |
32# +----|--------------------------------------------------------+
33# |    |                                               R2 (vrf) |
34# |    + $rp2                                                   |
35# |      2001:db8:3::2/64                                       |
36# |                                                             |
37# +-------------------------------------------------------------+
38
39lib_dir=$(dirname $0)/../../../../net/forwarding
40
41ALL_TESTS="flooding_test"
42NUM_NETIFS=4
43source $lib_dir/tc_common.sh
44source $lib_dir/lib.sh
45
46h1_create()
47{
48	simple_if_init $h1 2001:db8:1::1/64
49}
50
51h1_destroy()
52{
53	simple_if_fini $h1 2001:db8:1::1/64
54}
55
56switch_create()
57{
58	# Make sure the bridge uses the MAC address of the local port and
59	# not that of the VxLAN's device
60	ip link add dev br0 type bridge mcast_snooping 0
61	ip link set dev br0 address $(mac_get $swp1)
62
63	ip link add name vxlan0 type vxlan id 10 nolearning \
64		udp6zerocsumrx udp6zerocsumtx ttl 20 tos inherit \
65		local 2001:db8:2::1 dstport 4789
66
67	ip address add 2001:db8:2::1/128 dev lo
68
69	ip link set dev $swp1 master br0
70	ip link set dev vxlan0 master br0
71
72	ip link set dev br0 up
73	ip link set dev $swp1 up
74	ip link set dev vxlan0 up
75}
76
77switch_destroy()
78{
79	ip link set dev vxlan0 down
80	ip link set dev $swp1 down
81	ip link set dev br0 down
82
83	ip link set dev vxlan0 nomaster
84	ip link set dev $swp1 nomaster
85
86	ip address del 2001:db8:2::1/128 dev lo
87
88	ip link del dev vxlan0
89
90	ip link del dev br0
91}
92
93router1_create()
94{
95	# This router is in the default VRF, where the VxLAN device is
96	# performing the L3 lookup
97	ip link set dev $rp1 up
98	ip address add 2001:db8:3::1/64 dev $rp1
99	ip route add 2001:db8:2::0/64 via 2001:db8:3::2
100}
101
102router1_destroy()
103{
104	ip route del 2001:db8:2::0/64 via 2001:db8:3::2
105	ip address del 2001:db8:3::1/64 dev $rp1
106	ip link set dev $rp1 down
107}
108
109router2_create()
110{
111	# This router is not in the default VRF, so use simple_if_init()
112	simple_if_init $rp2 2001:db8:3::2/64
113}
114
115router2_destroy()
116{
117	simple_if_fini $rp2 2001:db8:3::2/64
118}
119
120setup_prepare()
121{
122	h1=${NETIFS[p1]}
123	swp1=${NETIFS[p2]}
124
125	rp1=${NETIFS[p3]}
126	rp2=${NETIFS[p4]}
127
128	vrf_prepare
129
130	h1_create
131
132	switch_create
133
134	router1_create
135	router2_create
136
137	forwarding_enable
138}
139
140cleanup()
141{
142	pre_cleanup
143
144	forwarding_restore
145
146	router2_destroy
147	router1_destroy
148
149	switch_destroy
150
151	h1_destroy
152
153	vrf_cleanup
154}
155
156flooding_remotes_add()
157{
158	local num_remotes=$1
159	local lsb
160	local i
161
162	# Prevent unwanted packets from entering the bridge and interfering
163	# with the test.
164	tc qdisc add dev br0 clsact
165	tc filter add dev br0 egress protocol all pref 1 handle 1 \
166		matchall skip_hw action drop
167	tc qdisc add dev $h1 clsact
168	tc filter add dev $h1 egress protocol all pref 1 handle 1 \
169		flower skip_hw dst_mac de:ad:be:ef:13:37 action pass
170	tc filter add dev $h1 egress protocol all pref 2 handle 2 \
171		matchall skip_hw action drop
172
173	for i in $(eval echo {1..$num_remotes}); do
174		lsb=$((i + 1))
175
176		bridge fdb append 00:00:00:00:00:00 dev vxlan0 self \
177			dst 2001:db8:2::$lsb
178	done
179}
180
181flooding_filters_add()
182{
183	local num_remotes=$1
184	local lsb
185	local i
186
187	tc qdisc add dev $rp2 clsact
188
189	for i in $(eval echo {1..$num_remotes}); do
190		lsb=$((i + 1))
191
192		tc filter add dev $rp2 ingress protocol ipv6 pref $i handle $i \
193			flower ip_proto udp dst_ip 2001:db8:2::$lsb \
194			dst_port 4789 skip_sw action drop
195	done
196}
197
198flooding_filters_del()
199{
200	local num_remotes=$1
201	local i
202
203	for i in $(eval echo {1..$num_remotes}); do
204		tc filter del dev $rp2 ingress protocol ipv6 pref $i \
205			handle $i flower
206	done
207
208	tc qdisc del dev $rp2 clsact
209
210	tc filter del dev $h1 egress protocol all pref 2 handle 2 matchall
211	tc filter del dev $h1 egress protocol all pref 1 handle 1 flower
212	tc qdisc del dev $h1 clsact
213	tc filter del dev br0 egress protocol all pref 1 handle 1 matchall
214	tc qdisc del dev br0 clsact
215}
216
217flooding_check_packets()
218{
219	local packets=("$@")
220	local num_remotes=${#packets[@]}
221	local i
222
223	for i in $(eval echo {1..$num_remotes}); do
224		tc_check_packets "dev $rp2 ingress" $i ${packets[i - 1]}
225		check_err $? "remote $i - did not get expected number of packets"
226	done
227}
228
229flooding_test()
230{
231	# Use 16 remote VTEPs that will be stored in 4 records. The array
232	# 'packets' will store how many packets are expected to be received
233	# by each remote VTEP at each stage of the test
234	declare -a packets=(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
235	local num_remotes=16
236
237	RET=0
238
239	# Add FDB entries for remote VTEPs and corresponding tc filters on the
240	# ingress of the nexthop router. These filters will count how many
241	# packets were flooded to each remote VTEP
242	flooding_remotes_add $num_remotes
243	flooding_filters_add $num_remotes
244
245	# Send one packet and make sure it is flooded to all the remote VTEPs
246	$MZ $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
247	flooding_check_packets "${packets[@]}"
248	log_test "flood after 1 packet"
249
250	# Delete the third record which corresponds to VTEPs with LSB 10..13
251	# and check that packet is flooded correctly when we remove a record
252	# from the middle of the list
253	RET=0
254
255	packets=(2 2 2 2 2 2 2 2 1 1 1 1 2 2 2 2)
256	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::10
257	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::11
258	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::12
259	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::13
260
261	$MZ $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
262	flooding_check_packets "${packets[@]}"
263	log_test "flood after 2 packets"
264
265	# Delete the first record and make sure the packet is flooded correctly
266	RET=0
267
268	packets=(2 2 2 2 3 3 3 3 1 1 1 1 3 3 3 3)
269	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::2
270	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::3
271	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::4
272	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::5
273
274	$MZ $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
275	flooding_check_packets "${packets[@]}"
276	log_test "flood after 3 packets"
277
278	# Delete the last record and make sure the packet is flooded correctly
279	RET=0
280
281	packets=(2 2 2 2 4 4 4 4 1 1 1 1 3 3 3 3)
282	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::14
283	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::15
284	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::16
285	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::17
286
287	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
288	flooding_check_packets "${packets[@]}"
289	log_test "flood after 4 packets"
290
291	# Delete the last record, one entry at a time and make sure single
292	# entries are correctly removed
293	RET=0
294
295	packets=(2 2 2 2 4 5 5 5 1 1 1 1 3 3 3 3)
296	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::6
297
298	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
299	flooding_check_packets "${packets[@]}"
300	log_test "flood after 5 packets"
301
302	RET=0
303
304	packets=(2 2 2 2 4 5 6 6 1 1 1 1 3 3 3 3)
305	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::7
306
307	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
308	flooding_check_packets "${packets[@]}"
309	log_test "flood after 6 packets"
310
311	RET=0
312
313	packets=(2 2 2 2 4 5 6 7 1 1 1 1 3 3 3 3)
314	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::8
315
316	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
317	flooding_check_packets "${packets[@]}"
318	log_test "flood after 7 packets"
319
320	RET=0
321
322	packets=(2 2 2 2 4 5 6 7 1 1 1 1 3 3 3 3)
323	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::9
324
325	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
326	flooding_check_packets "${packets[@]}"
327	log_test "flood after 8 packets"
328
329	flooding_filters_del $num_remotes
330}
331
332trap cleanup EXIT
333
334setup_prepare
335setup_wait
336
337tests_run
338
339exit $EXIT_STATUS
340