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