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 link $rp1 type vlan id 200
88	ip link set dev $rp1.200 addrgenmode eui64
89	ip link set dev $rp1.200 up
90	ip address add dev $rp1.200 192.0.2.2/28
91	ip address add dev $rp1.200 2001:db8:1::2/64
92	ip stats set dev $rp1.200 l3_stats on
93}
94
95router_rp1_200_destroy()
96{
97	ip stats set dev $rp1.200 l3_stats off
98	ip address del dev $rp1.200 2001:db8:1::2/64
99	ip address del dev $rp1.200 192.0.2.2/28
100	ip link del dev $rp1.200
101}
102
103router_create()
104{
105	ip link set dev $rp1 up
106	router_rp1_200_create
107
108	ip link set dev $rp2 up
109	vlan_create $rp2 200 "" 192.0.2.17/28 2001:db8:2::2/64
110}
111
112router_destroy()
113{
114	vlan_destroy $rp2 200
115	ip link set dev $rp2 down
116
117	router_rp1_200_destroy
118	ip link set dev $rp1 down
119}
120
121setup_prepare()
122{
123	h1=${NETIFS[p1]}
124	rp1=${NETIFS[p2]}
125
126	rp2=${NETIFS[p3]}
127	h2=${NETIFS[p4]}
128
129	rp1mac=$(mac_get $rp1)
130	rp2mac=$(mac_get $rp2)
131
132	vrf_prepare
133
134	h1_create
135	h2_create
136
137	router_create
138
139	forwarding_enable
140}
141
142cleanup()
143{
144	pre_cleanup
145
146	forwarding_restore
147
148	router_destroy
149
150	h2_destroy
151	h1_destroy
152
153	vrf_cleanup
154}
155
156ping_ipv4()
157{
158	ping_test $h1.200 192.0.2.18 " IPv4"
159}
160
161ping_ipv6()
162{
163	ping_test $h1.200 2001:db8:2::1 " IPv6"
164}
165
166send_packets_rx_ipv4()
167{
168	# Send 21 packets instead of 20, because the first one might trap and go
169	# through the SW datapath, which might not bump the HW counter.
170	$MZ $h1.200 -c 21 -d 20msec -p 100 \
171	    -a own -b $rp1mac -A 192.0.2.1 -B 192.0.2.18 \
172	    -q -t udp sp=54321,dp=12345
173}
174
175send_packets_rx_ipv6()
176{
177	$MZ $h1.200 -6 -c 21 -d 20msec -p 100 \
178	    -a own -b $rp1mac -A 2001:db8:1::1 -B 2001:db8:2::1 \
179	    -q -t udp sp=54321,dp=12345
180}
181
182send_packets_tx_ipv4()
183{
184	$MZ $h2.200 -c 21 -d 20msec -p 100 \
185	    -a own -b $rp2mac -A 192.0.2.18 -B 192.0.2.1 \
186	    -q -t udp sp=54321,dp=12345
187}
188
189send_packets_tx_ipv6()
190{
191	$MZ $h2.200 -6 -c 21 -d 20msec -p 100 \
192	    -a own -b $rp2mac -A 2001:db8:2::1 -B 2001:db8:1::1 \
193	    -q -t udp sp=54321,dp=12345
194}
195
196___test_stats()
197{
198	local dir=$1; shift
199	local prot=$1; shift
200
201	local a
202	local b
203
204	a=$(hw_stats_get l3_stats $rp1.200 ${dir} packets)
205	send_packets_${dir}_${prot}
206	"$@"
207	b=$(busywait "$TC_HIT_TIMEOUT" until_counter_is ">= $a + 20" \
208		       hw_stats_get l3_stats $rp1.200 ${dir} packets)
209	check_err $? "Traffic not reflected in the counter: $a -> $b"
210}
211
212__test_stats()
213{
214	local dir=$1; shift
215	local prot=$1; shift
216
217	RET=0
218	___test_stats "$dir" "$prot"
219	log_test "Test $dir packets: $prot"
220}
221
222test_stats_rx_ipv4()
223{
224	__test_stats rx ipv4
225}
226
227test_stats_tx_ipv4()
228{
229	__test_stats tx ipv4
230}
231
232test_stats_rx_ipv6()
233{
234	__test_stats rx ipv6
235}
236
237test_stats_tx_ipv6()
238{
239	__test_stats tx ipv6
240}
241
242# Make sure everything works well even after stats have been disabled and
243# reenabled on the same device without touching the L3 configuration.
244respin_enablement()
245{
246	log_info "Turning stats off and on again"
247	ip stats set dev $rp1.200 l3_stats off
248	ip stats set dev $rp1.200 l3_stats on
249}
250
251# For the initial run, l3_stats is enabled on a completely set up netdevice. Now
252# do it the other way around: enabling the L3 stats on an L2 netdevice, and only
253# then apply the L3 configuration.
254reapply_config()
255{
256	log_info "Reapplying configuration"
257
258	router_rp1_200_destroy
259
260	ip link add name $rp1.200 link $rp1 type vlan id 200
261	ip link set dev $rp1.200 addrgenmode none
262	ip stats set dev $rp1.200 l3_stats on
263	ip link set dev $rp1.200 addrgenmode eui64
264	ip link set dev $rp1.200 up
265	ip address add dev $rp1.200 192.0.2.2/28
266	ip address add dev $rp1.200 2001:db8:1::2/64
267}
268
269__test_stats_report()
270{
271	local dir=$1; shift
272	local prot=$1; shift
273
274	local a
275	local b
276
277	RET=0
278
279	a=$(hw_stats_get l3_stats $rp1.200 ${dir} packets)
280	send_packets_${dir}_${prot}
281	ip address flush dev $rp1.200
282	b=$(busywait "$TC_HIT_TIMEOUT" until_counter_is ">= $a + 20" \
283		       hw_stats_get l3_stats $rp1.200 ${dir} packets)
284	check_err $? "Traffic not reflected in the counter: $a -> $b"
285	log_test "Test ${dir} packets: stats pushed on loss of L3"
286
287	ip stats set dev $rp1.200 l3_stats off
288	ip link del dev $rp1.200
289	router_rp1_200_create
290}
291
292test_stats_report_rx()
293{
294	__test_stats_report rx ipv4
295}
296
297test_stats_report_tx()
298{
299	__test_stats_report tx ipv4
300}
301
302test_destroy_enabled()
303{
304	RET=0
305
306	ip link del dev $rp1.200
307	router_rp1_200_create
308
309	log_test "Destroy l3_stats-enabled netdev"
310}
311
312test_double_enable()
313{
314	RET=0
315	___test_stats rx ipv4 \
316		ip stats set dev $rp1.200 l3_stats on
317	log_test "Test stat retention across a spurious enablement"
318}
319
320trap cleanup EXIT
321
322setup_prepare
323setup_wait
324
325used=$(ip -j stats show dev $rp1.200 group offload subgroup hw_stats_info |
326	   jq '.[].info.l3_stats.used')
327kind=$(ip -j -d link show dev $rp1 |
328	   jq -r '.[].linkinfo.info_kind')
329if [[ $used != true ]]; then
330	if [[ $kind == veth ]]; then
331		log_test_skip "l3_stats not offloaded on veth interface"
332		EXIT_STATUS=$ksft_skip
333	else
334		RET=1 log_test "l3_stats not offloaded"
335	fi
336else
337	tests_run
338fi
339
340exit $EXIT_STATUS
341