1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test sends traffic from H1 to H2. Either on ingress of $swp1, or on
5# egress of $swp2, the traffic is acted upon by a pedit action. An ingress
6# filter installed on $h2 verifies that the packet looks like expected.
7#
8# +----------------------+                             +----------------------+
9# | H1                   |                             |                   H2 |
10# |    + $h1             |                             |            $h2 +     |
11# |    | 192.0.2.1/28    |                             |   192.0.2.2/28 |     |
12# +----|-----------------+                             +----------------|-----+
13#      |                                                                |
14# +----|----------------------------------------------------------------|-----+
15# | SW |                                                                |     |
16# |  +-|----------------------------------------------------------------|-+   |
17# |  | + $swp1                       BR                           $swp2 + |   |
18# |  +--------------------------------------------------------------------+   |
19# +---------------------------------------------------------------------------+
20
21ALL_TESTS="
22	ping_ipv4
23	test_ip_dsfield
24	test_ip_dscp
25	test_ip_ecn
26	test_ip_dscp_ecn
27"
28
29NUM_NETIFS=4
30source lib.sh
31source tc_common.sh
32
33: ${HIT_TIMEOUT:=2000} # ms
34
35h1_create()
36{
37	simple_if_init $h1 192.0.2.1/28 2001:db8:1::1/64
38}
39
40h1_destroy()
41{
42	simple_if_fini $h1 192.0.2.1/28 2001:db8:1::1/64
43}
44
45h2_create()
46{
47	simple_if_init $h2 192.0.2.2/28 2001:db8:1::2/64
48	tc qdisc add dev $h2 clsact
49}
50
51h2_destroy()
52{
53	tc qdisc del dev $h2 clsact
54	simple_if_fini $h2 192.0.2.2/28 2001:db8:1::2/64
55}
56
57switch_create()
58{
59	ip link add name br1 up type bridge vlan_filtering 1
60	ip link set dev $swp1 master br1
61	ip link set dev $swp1 up
62	ip link set dev $swp2 master br1
63	ip link set dev $swp2 up
64
65	tc qdisc add dev $swp1 clsact
66	tc qdisc add dev $swp2 clsact
67}
68
69switch_destroy()
70{
71	tc qdisc del dev $swp2 clsact
72	tc qdisc del dev $swp1 clsact
73
74	ip link set dev $swp2 nomaster
75	ip link set dev $swp1 nomaster
76	ip link del dev br1
77}
78
79setup_prepare()
80{
81	h1=${NETIFS[p1]}
82	swp1=${NETIFS[p2]}
83
84	swp2=${NETIFS[p3]}
85	h2=${NETIFS[p4]}
86
87	h2mac=$(mac_get $h2)
88
89	vrf_prepare
90	h1_create
91	h2_create
92	switch_create
93}
94
95cleanup()
96{
97	pre_cleanup
98
99	switch_destroy
100	h2_destroy
101	h1_destroy
102	vrf_cleanup
103}
104
105ping_ipv4()
106{
107	ping_test $h1 192.0.2.2
108}
109
110do_test_pedit_dsfield_common()
111{
112	local pedit_locus=$1; shift
113	local pedit_action=$1; shift
114	local mz_flags=$1; shift
115
116	RET=0
117
118	# TOS 125: DSCP 31, ECN 1. Used for testing that the relevant part is
119	# overwritten when zero is selected.
120	$MZ $mz_flags $h1 -c 10 -d 20msec -p 100 \
121	    -a own -b $h2mac -q -t tcp tos=0x7d,sp=54321,dp=12345
122
123	local pkts
124	pkts=$(busywait "$TC_HIT_TIMEOUT" until_counter_is ">= 10" \
125			tc_rule_handle_stats_get "dev $h2 ingress" 101)
126	check_err $? "Expected to get 10 packets, but got $pkts."
127	log_test "$pedit_locus pedit $pedit_action"
128}
129
130do_test_pedit_dsfield()
131{
132	local pedit_locus=$1; shift
133	local pedit_action=$1; shift
134	local match_prot=$1; shift
135	local match_flower=$1; shift
136	local mz_flags=$1; shift
137	local saddr=$1; shift
138	local daddr=$1; shift
139
140	tc filter add $pedit_locus handle 101 pref 1 \
141	   flower action pedit ex munge $pedit_action
142	tc filter add dev $h2 ingress handle 101 pref 1 prot $match_prot \
143	   flower skip_hw $match_flower action pass
144
145	do_test_pedit_dsfield_common "$pedit_locus" "$pedit_action" "$mz_flags"
146
147	tc filter del dev $h2 ingress pref 1
148	tc filter del $pedit_locus pref 1
149}
150
151do_test_ip_dsfield()
152{
153	local locus=$1; shift
154	local dsfield
155
156	for dsfield in 0 1 2 3 128 252 253 254 255; do
157		do_test_pedit_dsfield "$locus"				\
158				      "ip dsfield set $dsfield"		\
159				      ip "ip_tos $dsfield"		\
160				      "-A 192.0.2.1 -B 192.0.2.2"
161	done
162}
163
164test_ip_dsfield()
165{
166	do_test_ip_dsfield "dev $swp1 ingress"
167	do_test_ip_dsfield "dev $swp2 egress"
168}
169
170do_test_ip_dscp()
171{
172	local locus=$1; shift
173	local dscp
174
175	for dscp in 0 1 2 3 32 61 62 63; do
176		do_test_pedit_dsfield "$locus"				       \
177				  "ip dsfield set $((dscp << 2)) retain 0xfc"  \
178				  ip "ip_tos $(((dscp << 2) | 1))"	       \
179				  "-A 192.0.2.1 -B 192.0.2.2"
180	done
181}
182
183test_ip_dscp()
184{
185	do_test_ip_dscp "dev $swp1 ingress"
186	do_test_ip_dscp "dev $swp2 egress"
187}
188
189do_test_ip_ecn()
190{
191	local locus=$1; shift
192	local ecn
193
194	for ecn in 0 1 2 3; do
195		do_test_pedit_dsfield "$locus"				\
196				      "ip dsfield set $ecn retain 0x03"	\
197				      ip "ip_tos $((124 | $ecn))"	\
198				      "-A 192.0.2.1 -B 192.0.2.2"
199	done
200}
201
202test_ip_ecn()
203{
204	do_test_ip_ecn "dev $swp1 ingress"
205	do_test_ip_ecn "dev $swp2 egress"
206}
207
208do_test_ip_dscp_ecn()
209{
210	local locus=$1; shift
211
212	tc filter add $locus handle 101 pref 1				\
213	   flower action pedit ex munge ip dsfield set 124 retain 0xfc	\
214		  action pedit ex munge ip dsfield set 1 retain 0x03
215	tc filter add dev $h2 ingress handle 101 pref 1 prot ip		\
216	   flower skip_hw ip_tos 125 action pass
217
218	do_test_pedit_dsfield_common "$locus" "set DSCP + set ECN"	\
219				      "-A 192.0.2.1 -B 192.0.2.2"
220
221	tc filter del dev $h2 ingress pref 1
222	tc filter del $locus pref 1
223}
224
225test_ip_dscp_ecn()
226{
227	do_test_ip_dscp_ecn "dev $swp1 ingress"
228	do_test_ip_dscp_ecn "dev $swp2 egress"
229}
230
231trap cleanup EXIT
232
233setup_prepare
234setup_wait
235
236tests_run
237
238exit $EXIT_STATUS
239