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	for i in $(eval echo {1..$num_remotes}); do
163		lsb=$((i + 1))
164
165		bridge fdb append 00:00:00:00:00:00 dev vxlan0 self \
166			dst 2001:db8:2::$lsb
167	done
168}
169
170flooding_filters_add()
171{
172	local num_remotes=$1
173	local lsb
174	local i
175
176	tc qdisc add dev $rp2 clsact
177
178	for i in $(eval echo {1..$num_remotes}); do
179		lsb=$((i + 1))
180
181		tc filter add dev $rp2 ingress protocol ipv6 pref $i handle $i \
182			flower ip_proto udp dst_ip 2001:db8:2::$lsb \
183			dst_port 4789 skip_sw action drop
184	done
185}
186
187flooding_filters_del()
188{
189	local num_remotes=$1
190	local i
191
192	for i in $(eval echo {1..$num_remotes}); do
193		tc filter del dev $rp2 ingress protocol ipv6 pref $i \
194			handle $i flower
195	done
196
197	tc qdisc del dev $rp2 clsact
198}
199
200flooding_check_packets()
201{
202	local packets=("$@")
203	local num_remotes=${#packets[@]}
204	local i
205
206	for i in $(eval echo {1..$num_remotes}); do
207		tc_check_packets "dev $rp2 ingress" $i ${packets[i - 1]}
208		check_err $? "remote $i - did not get expected number of packets"
209	done
210}
211
212flooding_test()
213{
214	# Use 16 remote VTEPs that will be stored in 4 records. The array
215	# 'packets' will store how many packets are expected to be received
216	# by each remote VTEP at each stage of the test
217	declare -a packets=(1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1)
218	local num_remotes=16
219
220	RET=0
221
222	# Add FDB entries for remote VTEPs and corresponding tc filters on the
223	# ingress of the nexthop router. These filters will count how many
224	# packets were flooded to each remote VTEP
225	flooding_remotes_add $num_remotes
226	flooding_filters_add $num_remotes
227
228	# Send one packet and make sure it is flooded to all the remote VTEPs
229	$MZ $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
230	flooding_check_packets "${packets[@]}"
231	log_test "flood after 1 packet"
232
233	# Delete the third record which corresponds to VTEPs with LSB 10..13
234	# and check that packet is flooded correctly when we remove a record
235	# from the middle of the list
236	RET=0
237
238	packets=(2 2 2 2 2 2 2 2 1 1 1 1 2 2 2 2)
239	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::10
240	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::11
241	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::12
242	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::13
243
244	$MZ $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
245	flooding_check_packets "${packets[@]}"
246	log_test "flood after 2 packets"
247
248	# Delete the first record and make sure the packet is flooded correctly
249	RET=0
250
251	packets=(2 2 2 2 3 3 3 3 1 1 1 1 3 3 3 3)
252	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::2
253	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::3
254	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::4
255	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::5
256
257	$MZ $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
258	flooding_check_packets "${packets[@]}"
259	log_test "flood after 3 packets"
260
261	# Delete the last record and make sure the packet is flooded correctly
262	RET=0
263
264	packets=(2 2 2 2 4 4 4 4 1 1 1 1 3 3 3 3)
265	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::14
266	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::15
267	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::16
268	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::17
269
270	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
271	flooding_check_packets "${packets[@]}"
272	log_test "flood after 4 packets"
273
274	# Delete the last record, one entry at a time and make sure single
275	# entries are correctly removed
276	RET=0
277
278	packets=(2 2 2 2 4 5 5 5 1 1 1 1 3 3 3 3)
279	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::6
280
281	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
282	flooding_check_packets "${packets[@]}"
283	log_test "flood after 5 packets"
284
285	RET=0
286
287	packets=(2 2 2 2 4 5 6 6 1 1 1 1 3 3 3 3)
288	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::7
289
290	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
291	flooding_check_packets "${packets[@]}"
292	log_test "flood after 6 packets"
293
294	RET=0
295
296	packets=(2 2 2 2 4 5 6 7 1 1 1 1 3 3 3 3)
297	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::8
298
299	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
300	flooding_check_packets "${packets[@]}"
301	log_test "flood after 7 packets"
302
303	RET=0
304
305	packets=(2 2 2 2 4 5 6 7 1 1 1 1 3 3 3 3)
306	bridge fdb del 00:00:00:00:00:00 dev vxlan0 self dst 2001:db8:2::9
307
308	$MZ -6 $h1 -q -p 64 -b de:ad:be:ef:13:37 -t ip -c 1
309	flooding_check_packets "${packets[@]}"
310	log_test "flood after 8 packets"
311
312	flooding_filters_del $num_remotes
313}
314
315trap cleanup EXIT
316
317setup_prepare
318setup_wait
319
320tests_run
321
322exit $EXIT_STATUS
323