1314818Sngie#!/bin/bash
2272343Sngie# SPDX-License-Identifier: GPL-2.0
3272343Sngie
4272343Sngie# This test sends traffic from H1 to H2. Either on ingress of $swp1, or on
5272343Sngie# egress of $swp2, the traffic is acted upon by a pedit action. An ingress
6272343Sngie# filter installed on $h2 verifies that the packet looks like expected.
7272343Sngie#
8272343Sngie# +----------------------+                             +----------------------+
9272343Sngie# | H1                   |                             |                   H2 |
10272343Sngie# |    + $h1             |                             |            $h2 +     |
11272343Sngie# |    | 192.0.2.1/28    |                             |   192.0.2.2/28 |     |
12272343Sngie# +----|-----------------+                             +----------------|-----+
13272343Sngie#      |                                                                |
14272343Sngie# +----|----------------------------------------------------------------|-----+
15272343Sngie# | SW |                                                                |     |
16272343Sngie# |  +-|----------------------------------------------------------------|-+   |
17272343Sngie# |  | + $swp1                       BR                           $swp2 + |   |
18272343Sngie# |  +--------------------------------------------------------------------+   |
19272343Sngie# +---------------------------------------------------------------------------+
20272343Sngie
21272343SngieALL_TESTS="
22272343Sngie	ping_ipv4
23272343Sngie	ping_ipv6
24272343Sngie	test_ip_dsfield
25272343Sngie	test_ip_dscp
26272343Sngie	test_ip_ecn
27272343Sngie	test_ip_dscp_ecn
28272343Sngie	test_ip6_dsfield
29272343Sngie	test_ip6_dscp
30272343Sngie	test_ip6_ecn
31272343Sngie"
32272343Sngie
33272343SngieNUM_NETIFS=4
34272343Sngiesource lib.sh
35272343Sngiesource tc_common.sh
36272343Sngie
37272343Sngie: ${HIT_TIMEOUT:=2000} # ms
38272343Sngie
39272343Sngieh1_create()
40272343Sngie{
41273395Sngie	simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
42272343Sngie}
43272343Sngie
44272343Sngieh1_destroy()
45272343Sngie{
46272343Sngie	simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64
47272343Sngie}
48272343Sngie
49272343Sngieh2_create()
50272343Sngie{
51272343Sngie	simple_if_init $h2 192.0.2.2/28 2001:db8:1::2/64
52272343Sngie	tc qdisc add dev $h2 clsact
53272343Sngie}
54272343Sngie
55272343Sngieh2_destroy()
56272343Sngie{
57272343Sngie	tc qdisc del dev $h2 clsact
58272343Sngie	simple_if_fini $h2 192.0.2.2/28 2001:db8:1::2/64
59272343Sngie}
60272343Sngie
61272343Sngieswitch_create()
62272343Sngie{
63272343Sngie	ip link add name br1 type bridge vlan_filtering 1
64272343Sngie	ip link set dev br1 addrgenmode none
65272343Sngie	ip link set dev br1 up
66272343Sngie	ip link set dev $swp1 master br1
67272343Sngie	ip link set dev $swp1 up
68272343Sngie	ip link set dev $swp2 master br1
69272343Sngie	ip link set dev $swp2 up
70272343Sngie
71272343Sngie	tc qdisc add dev $swp1 clsact
72272343Sngie	tc qdisc add dev $swp2 clsact
73272343Sngie}
74272343Sngie
75272343Sngieswitch_destroy()
76272343Sngie{
77272343Sngie	tc qdisc del dev $swp2 clsact
78272343Sngie	tc qdisc del dev $swp1 clsact
79272343Sngie
80272343Sngie	ip link set dev $swp2 down
81272343Sngie	ip link set dev $swp2 nomaster
82272343Sngie	ip link set dev $swp1 down
83272343Sngie	ip link set dev $swp1 nomaster
84272343Sngie	ip link del dev br1
85272343Sngie}
86272343Sngie
87272343Sngiesetup_prepare()
88272343Sngie{
89272343Sngie	h1=${NETIFS[p1]}
90272343Sngie	swp1=${NETIFS[p2]}
91272343Sngie
92272343Sngie	swp2=${NETIFS[p3]}
93272343Sngie	h2=${NETIFS[p4]}
94272343Sngie
95272343Sngie	h2mac=$(mac_get $h2)
96272343Sngie
97272343Sngie	vrf_prepare
98272343Sngie	h1_create
99272343Sngie	h2_create
100272343Sngie	switch_create
101272343Sngie}
102272343Sngie
103272343Sngiecleanup()
104272343Sngie{
105272343Sngie	pre_cleanup
106272343Sngie
107272343Sngie	switch_destroy
108272343Sngie	h2_destroy
109272343Sngie	h1_destroy
110272343Sngie	vrf_cleanup
111272343Sngie}
112272343Sngie
113272343Sngieping_ipv4()
114272343Sngie{
115272343Sngie	ping_test $h1 192.0.2.2
116272343Sngie}
117272343Sngie
118272343Sngieping_ipv6()
119272343Sngie{
120272343Sngie	ping6_test $h1 2001:db8:1::2
121272343Sngie}
122272343Sngie
123272343Sngiedo_test_pedit_dsfield_common()
124272343Sngie{
125272343Sngie	local pedit_locus=$1; shift
126272343Sngie	local pedit_action=$1; shift
127272343Sngie	local mz_flags=$1; shift
128272343Sngie
129272343Sngie	RET=0
130272343Sngie
131272343Sngie	# TOS 125: DSCP 31, ECN 1. Used for testing that the relevant part is
132272343Sngie	# overwritten when zero is selected.
133272343Sngie	$MZ $mz_flags $h1 -c 10 -d 20msec -p 100 \
134272343Sngie	    -a own -b $h2mac -q -t tcp tos=0x7d,sp=54321,dp=12345
135272343Sngie
136272343Sngie	local pkts
137272343Sngie	pkts=$(busywait "$TC_HIT_TIMEOUT" until_counter_is ">= 10" \
138272343Sngie			tc_rule_handle_stats_get "dev $h2 ingress" 101)
139272343Sngie	check_err $? "Expected to get 10 packets on test probe, but got $pkts."
140272343Sngie
141272343Sngie	pkts=$(tc_rule_handle_stats_get "$pedit_locus" 101)
142272343Sngie	((pkts >= 10))
143272343Sngie	check_err $? "Expected to get 10 packets on pedit rule, but got $pkts."
144272343Sngie
145272343Sngie	log_test "$pedit_locus pedit $pedit_action"
146272343Sngie}
147272343Sngie
148272343Sngiedo_test_pedit_dsfield()
149272343Sngie{
150272343Sngie	local pedit_locus=$1; shift
151272343Sngie	local pedit_action=$1; shift
152272343Sngie	local match_prot=$1; shift
153272343Sngie	local match_flower=$1; shift
154272343Sngie	local mz_flags=$1; shift
155272343Sngie	local saddr=$1; shift
156272343Sngie	local daddr=$1; shift
157272343Sngie
158272343Sngie	tc filter add $pedit_locus handle 101 pref 1 \
159272343Sngie	   flower action pedit ex munge $pedit_action
160272343Sngie	tc filter add dev $h2 ingress handle 101 pref 1 prot $match_prot \
161272343Sngie	   flower skip_hw $match_flower action pass
162272343Sngie
163272343Sngie	do_test_pedit_dsfield_common "$pedit_locus" "$pedit_action" "$mz_flags"
164272343Sngie
165272343Sngie	tc filter del dev $h2 ingress pref 1
166272343Sngie	tc filter del $pedit_locus pref 1
167272343Sngie}
168272343Sngie
169272343Sngiedo_test_ip_dsfield()
170272343Sngie{
171272343Sngie	local locus=$1; shift
172272343Sngie	local dsfield
173272343Sngie
174272343Sngie	for dsfield in 0 1 2 3 128 252 253 254 255; do
175272343Sngie		do_test_pedit_dsfield "$locus"				\
176272343Sngie				      "ip dsfield set $dsfield"		\
177272343Sngie				      ip "ip_tos $dsfield"		\
178272343Sngie				      "-A 192.0.2.1 -B 192.0.2.2"
179272343Sngie	done
180272343Sngie}
181272343Sngie
182272343Sngietest_ip_dsfield()
183272343Sngie{
184272343Sngie	do_test_ip_dsfield "dev $swp1 ingress"
185272343Sngie	do_test_ip_dsfield "dev $swp2 egress"
186272343Sngie}
187272343Sngie
188272343Sngiedo_test_ip_dscp()
189272343Sngie{
190272343Sngie	local locus=$1; shift
191272343Sngie	local dscp
192272343Sngie
193272343Sngie	for dscp in 0 1 2 3 32 61 62 63; do
194272343Sngie		do_test_pedit_dsfield "$locus"				       \
195272343Sngie				  "ip dsfield set $((dscp << 2)) retain 0xfc"  \
196272343Sngie				  ip "ip_tos $(((dscp << 2) | 1))"	       \
197272343Sngie				  "-A 192.0.2.1 -B 192.0.2.2"
198272343Sngie	done
199272343Sngie}
200272343Sngie
201272343Sngietest_ip_dscp()
202272343Sngie{
203272343Sngie	do_test_ip_dscp "dev $swp1 ingress"
204272343Sngie	do_test_ip_dscp "dev $swp2 egress"
205272343Sngie}
206272343Sngie
207272343Sngiedo_test_ip_ecn()
208{
209	local locus=$1; shift
210	local ecn
211
212	for ecn in 0 1 2 3; do
213		do_test_pedit_dsfield "$locus"				\
214				      "ip dsfield set $ecn retain 0x03"	\
215				      ip "ip_tos $((124 | $ecn))"	\
216				      "-A 192.0.2.1 -B 192.0.2.2"
217	done
218}
219
220test_ip_ecn()
221{
222	do_test_ip_ecn "dev $swp1 ingress"
223	do_test_ip_ecn "dev $swp2 egress"
224}
225
226do_test_ip_dscp_ecn()
227{
228	local locus=$1; shift
229
230	tc filter add $locus handle 101 pref 1				\
231	   flower action pedit ex munge ip dsfield set 124 retain 0xfc	\
232		  action pedit ex munge ip dsfield set 1 retain 0x03
233	tc filter add dev $h2 ingress handle 101 pref 1 prot ip		\
234	   flower skip_hw ip_tos 125 action pass
235
236	do_test_pedit_dsfield_common "$locus" "set DSCP + set ECN"	\
237				      "-A 192.0.2.1 -B 192.0.2.2"
238
239	tc filter del dev $h2 ingress pref 1
240	tc filter del $locus pref 1
241}
242
243test_ip_dscp_ecn()
244{
245	do_test_ip_dscp_ecn "dev $swp1 ingress"
246	do_test_ip_dscp_ecn "dev $swp2 egress"
247}
248
249do_test_ip6_dsfield()
250{
251	local locus=$1; shift
252	local dsfield
253
254	for dsfield in 0 1 2 3 128 252 253 254 255; do
255		do_test_pedit_dsfield "$locus"				\
256				  "ip6 traffic_class set $dsfield"	\
257				  ipv6 "ip_tos $dsfield"		\
258				  "-6 -A 2001:db8:1::1 -B 2001:db8:1::2"
259	done
260}
261
262test_ip6_dsfield()
263{
264	do_test_ip6_dsfield "dev $swp1 ingress"
265	do_test_ip6_dsfield "dev $swp2 egress"
266}
267
268do_test_ip6_dscp()
269{
270	local locus=$1; shift
271	local dscp
272
273	for dscp in 0 1 2 3 32 61 62 63; do
274		do_test_pedit_dsfield "$locus"				       \
275			    "ip6 traffic_class set $((dscp << 2)) retain 0xfc" \
276			    ipv6 "ip_tos $(((dscp << 2) | 1))"		       \
277			    "-6 -A 2001:db8:1::1 -B 2001:db8:1::2"
278	done
279}
280
281test_ip6_dscp()
282{
283	do_test_ip6_dscp "dev $swp1 ingress"
284	do_test_ip6_dscp "dev $swp2 egress"
285}
286
287do_test_ip6_ecn()
288{
289	local locus=$1; shift
290	local ecn
291
292	for ecn in 0 1 2 3; do
293		do_test_pedit_dsfield "$locus"				\
294				"ip6 traffic_class set $ecn retain 0x3"	\
295				ipv6 "ip_tos $((124 | $ecn))"		\
296				"-6 -A 2001:db8:1::1 -B 2001:db8:1::2"
297	done
298}
299
300test_ip6_ecn()
301{
302	do_test_ip6_ecn "dev $swp1 ingress"
303	do_test_ip6_ecn "dev $swp2 egress"
304}
305
306trap cleanup EXIT
307
308setup_prepare
309setup_wait
310
311tests_run
312
313exit $EXIT_STATUS
314