1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# +--------------------+                     +----------------------+
5# | H1                 |                     |                   H2 |
6# |                    |                     |                      |
7# |          $h1.200 + |                     | + $h2.200            |
8# |     192.0.2.1/28 | |                     | | 192.0.2.18/28      |
9# | 2001:db8:1::1/64 | |                     | | 2001:db8:2::1/64   |
10# |                  | |                     | |                    |
11# |              $h1 + |                     | + $h2                |
12# |                  | |                     | |                    |
13# +------------------|-+                     +-|--------------------+
14#                    |                         |
15# +------------------|-------------------------|--------------------+
16# | SW               |                         |                    |
17# |                  |                         |                    |
18# |             $rp1 +                         + $rp2               |
19# |                  |                         |                    |
20# |         $rp1.200 +                         + $rp2.200           |
21# |     192.0.2.2/28                             192.0.2.17/28      |
22# | 2001:db8:1::2/64                             2001:db8:2::2/64   |
23# |                                                                 |
24# +-----------------------------------------------------------------+
25
26ALL_TESTS="
27	ping_ipv4
28	ping_ipv6
29	test_stats_rx_ipv4
30	test_stats_tx_ipv4
31	test_stats_rx_ipv6
32	test_stats_tx_ipv6
33	respin_enablement
34	test_stats_rx_ipv4
35	test_stats_tx_ipv4
36	test_stats_rx_ipv6
37	test_stats_tx_ipv6
38	reapply_config
39	ping_ipv4
40	ping_ipv6
41	test_stats_rx_ipv4
42	test_stats_tx_ipv4
43	test_stats_rx_ipv6
44	test_stats_tx_ipv6
45	test_stats_report_rx
46	test_stats_report_tx
47	test_destroy_enabled
48	test_double_enable
49"
50NUM_NETIFS=4
51source lib.sh
52
53h1_create()
54{
55	simple_if_init $h1
56	vlan_create $h1 200 v$h1 192.0.2.1/28 2001:db8:1::1/64
57	ip route add 192.0.2.16/28 vrf v$h1 nexthop via 192.0.2.2
58	ip -6 route add 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2
59}
60
61h1_destroy()
62{
63	ip -6 route del 2001:db8:2::/64 vrf v$h1 nexthop via 2001:db8:1::2
64	ip route del 192.0.2.16/28 vrf v$h1 nexthop via 192.0.2.2
65	vlan_destroy $h1 200
66	simple_if_fini $h1
67}
68
69h2_create()
70{
71	simple_if_init $h2
72	vlan_create $h2 200 v$h2 192.0.2.18/28 2001:db8:2::1/64
73	ip route add 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.17
74	ip -6 route add 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::2
75}
76
77h2_destroy()
78{
79	ip -6 route del 2001:db8:1::/64 vrf v$h2 nexthop via 2001:db8:2::2
80	ip route del 192.0.2.0/28 vrf v$h2 nexthop via 192.0.2.17
81	vlan_destroy $h2 200
82	simple_if_fini $h2
83}
84
85router_rp1_200_create()
86{
87	ip link add name $rp1.200 up \
88		link $rp1 addrgenmode eui64 type vlan id 200
89	ip address add dev $rp1.200 192.0.2.2/28
90	ip address add dev $rp1.200 2001:db8:1::2/64
91	ip stats set dev $rp1.200 l3_stats on
92}
93
94router_rp1_200_destroy()
95{
96	ip stats set dev $rp1.200 l3_stats off
97	ip address del dev $rp1.200 2001:db8:1::2/64
98	ip address del dev $rp1.200 192.0.2.2/28
99	ip link del dev $rp1.200
100}
101
102router_create()
103{
104	ip link set dev $rp1 up
105	router_rp1_200_create
106
107	ip link set dev $rp2 up
108	vlan_create $rp2 200 "" 192.0.2.17/28 2001:db8:2::2/64
109}
110
111router_destroy()
112{
113	vlan_destroy $rp2 200
114	ip link set dev $rp2 down
115
116	router_rp1_200_destroy
117	ip link set dev $rp1 down
118}
119
120setup_prepare()
121{
122	h1=${NETIFS[p1]}
123	rp1=${NETIFS[p2]}
124
125	rp2=${NETIFS[p3]}
126	h2=${NETIFS[p4]}
127
128	rp1mac=$(mac_get $rp1)
129	rp2mac=$(mac_get $rp2)
130
131	vrf_prepare
132
133	h1_create
134	h2_create
135
136	router_create
137
138	forwarding_enable
139}
140
141cleanup()
142{
143	pre_cleanup
144
145	forwarding_restore
146
147	router_destroy
148
149	h2_destroy
150	h1_destroy
151
152	vrf_cleanup
153}
154
155ping_ipv4()
156{
157	ping_test $h1.200 192.0.2.18 " IPv4"
158}
159
160ping_ipv6()
161{
162	ping_test $h1.200 2001:db8:2::1 " IPv6"
163}
164
165get_l3_stat()
166{
167	local selector=$1; shift
168
169	ip -j stats show dev $rp1.200 group offload subgroup l3_stats |
170		  jq '.[0].stats64.'$selector
171}
172
173send_packets_rx_ipv4()
174{
175	# Send 21 packets instead of 20, because the first one might trap and go
176	# through the SW datapath, which might not bump the HW counter.
177	$MZ $h1.200 -c 21 -d 20msec -p 100 \
178	    -a own -b $rp1mac -A 192.0.2.1 -B 192.0.2.18 \
179	    -q -t udp sp=54321,dp=12345
180}
181
182send_packets_rx_ipv6()
183{
184	$MZ $h1.200 -6 -c 21 -d 20msec -p 100 \
185	    -a own -b $rp1mac -A 2001:db8:1::1 -B 2001:db8:2::1 \
186	    -q -t udp sp=54321,dp=12345
187}
188
189send_packets_tx_ipv4()
190{
191	$MZ $h2.200 -c 21 -d 20msec -p 100 \
192	    -a own -b $rp2mac -A 192.0.2.18 -B 192.0.2.1 \
193	    -q -t udp sp=54321,dp=12345
194}
195
196send_packets_tx_ipv6()
197{
198	$MZ $h2.200 -6 -c 21 -d 20msec -p 100 \
199	    -a own -b $rp2mac -A 2001:db8:2::1 -B 2001:db8:1::1 \
200	    -q -t udp sp=54321,dp=12345
201}
202
203___test_stats()
204{
205	local dir=$1; shift
206	local prot=$1; shift
207
208	local a
209	local b
210
211	a=$(get_l3_stat ${dir}.packets)
212	send_packets_${dir}_${prot}
213	"$@"
214	b=$(busywait "$TC_HIT_TIMEOUT" until_counter_is ">= $a + 20" \
215		       get_l3_stat ${dir}.packets)
216	check_err $? "Traffic not reflected in the counter: $a -> $b"
217}
218
219__test_stats()
220{
221	local dir=$1; shift
222	local prot=$1; shift
223
224	RET=0
225	___test_stats "$dir" "$prot"
226	log_test "Test $dir packets: $prot"
227}
228
229test_stats_rx_ipv4()
230{
231	__test_stats rx ipv4
232}
233
234test_stats_tx_ipv4()
235{
236	__test_stats tx ipv4
237}
238
239test_stats_rx_ipv6()
240{
241	__test_stats rx ipv6
242}
243
244test_stats_tx_ipv6()
245{
246	__test_stats tx ipv6
247}
248
249# Make sure everything works well even after stats have been disabled and
250# reenabled on the same device without touching the L3 configuration.
251respin_enablement()
252{
253	log_info "Turning stats off and on again"
254	ip stats set dev $rp1.200 l3_stats off
255	ip stats set dev $rp1.200 l3_stats on
256}
257
258# For the initial run, l3_stats is enabled on a completely set up netdevice. Now
259# do it the other way around: enabling the L3 stats on an L2 netdevice, and only
260# then apply the L3 configuration.
261reapply_config()
262{
263	log_info "Reapplying configuration"
264
265	router_rp1_200_destroy
266
267	ip link add name $rp1.200 link $rp1 addrgenmode none type vlan id 200
268	ip stats set dev $rp1.200 l3_stats on
269	ip link set dev $rp1.200 up addrgenmode eui64
270	ip address add dev $rp1.200 192.0.2.2/28
271	ip address add dev $rp1.200 2001:db8:1::2/64
272}
273
274__test_stats_report()
275{
276	local dir=$1; shift
277	local prot=$1; shift
278
279	local a
280	local b
281
282	RET=0
283
284	a=$(get_l3_stat ${dir}.packets)
285	send_packets_${dir}_${prot}
286	ip address flush dev $rp1.200
287	b=$(busywait "$TC_HIT_TIMEOUT" until_counter_is ">= $a + 20" \
288		       get_l3_stat ${dir}.packets)
289	check_err $? "Traffic not reflected in the counter: $a -> $b"
290	log_test "Test ${dir} packets: stats pushed on loss of L3"
291
292	ip stats set dev $rp1.200 l3_stats off
293	ip link del dev $rp1.200
294	router_rp1_200_create
295}
296
297test_stats_report_rx()
298{
299	__test_stats_report rx ipv4
300}
301
302test_stats_report_tx()
303{
304	__test_stats_report tx ipv4
305}
306
307test_destroy_enabled()
308{
309	RET=0
310
311	ip link del dev $rp1.200
312	router_rp1_200_create
313
314	log_test "Destroy l3_stats-enabled netdev"
315}
316
317test_double_enable()
318{
319	RET=0
320	___test_stats rx ipv4 \
321		ip stats set dev $rp1.200 l3_stats on
322	log_test "Test stat retention across a spurious enablement"
323}
324
325trap cleanup EXIT
326
327setup_prepare
328setup_wait
329
330tests_run
331
332exit $EXIT_STATUS
333