1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4ALL_TESTS="gact_drop_and_ok_test mirred_egress_redirect_test \
5	mirred_egress_mirror_test matchall_mirred_egress_mirror_test \
6	gact_trap_test mirred_egress_to_ingress_test \
7	mirred_egress_to_ingress_tcp_test"
8NUM_NETIFS=4
9source tc_common.sh
10source lib.sh
11
12require_command ncat
13
14tcflags="skip_hw"
15
16h1_create()
17{
18	simple_if_init $h1 192.0.2.1/24
19	tc qdisc add dev $h1 clsact
20}
21
22h1_destroy()
23{
24	tc qdisc del dev $h1 clsact
25	simple_if_fini $h1 192.0.2.1/24
26}
27
28h2_create()
29{
30	simple_if_init $h2 192.0.2.2/24
31	tc qdisc add dev $h2 clsact
32}
33
34h2_destroy()
35{
36	tc qdisc del dev $h2 clsact
37	simple_if_fini $h2 192.0.2.2/24
38}
39
40switch_create()
41{
42	simple_if_init $swp1 192.0.2.2/24
43	tc qdisc add dev $swp1 clsact
44
45	simple_if_init $swp2 192.0.2.1/24
46}
47
48switch_destroy()
49{
50	simple_if_fini $swp2 192.0.2.1/24
51
52	tc qdisc del dev $swp1 clsact
53	simple_if_fini $swp1 192.0.2.2/24
54}
55
56mirred_egress_test()
57{
58	local action=$1
59	local protocol=$2
60	local classifier=$3
61	local classifier_args=$4
62
63	RET=0
64
65	tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \
66		dst_ip 192.0.2.2 action drop
67
68	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
69		-t ip -q
70
71	tc_check_packets "dev $h2 ingress" 101 1
72	check_fail $? "Matched without redirect rule inserted"
73
74	tc filter add dev $swp1 ingress protocol $protocol pref 1 handle 101 \
75		$classifier $tcflags $classifier_args \
76		action mirred egress $action dev $swp2
77
78	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
79		-t ip -q
80
81	tc_check_packets "dev $h2 ingress" 101 1
82	check_err $? "Did not match incoming $action packet"
83
84	tc filter del dev $swp1 ingress protocol $protocol pref 1 handle 101 \
85		$classifier
86	tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower
87
88	log_test "mirred egress $classifier $action ($tcflags)"
89}
90
91gact_drop_and_ok_test()
92{
93	RET=0
94
95	tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \
96		$tcflags dst_ip 192.0.2.2 action drop
97
98	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
99		-t ip -q
100
101	tc_check_packets "dev $swp1 ingress" 102 1
102	check_err $? "Packet was not dropped"
103
104	tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \
105		$tcflags dst_ip 192.0.2.2 action ok
106
107	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
108		-t ip -q
109
110	tc_check_packets "dev $swp1 ingress" 101 1
111	check_err $? "Did not see passed packet"
112
113	tc_check_packets "dev $swp1 ingress" 102 2
114	check_fail $? "Packet was dropped and it should not reach here"
115
116	tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower
117	tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower
118
119	log_test "gact drop and ok ($tcflags)"
120}
121
122gact_trap_test()
123{
124	RET=0
125
126	if [[ "$tcflags" != "skip_sw" ]]; then
127		return 0;
128	fi
129
130	tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \
131		skip_hw dst_ip 192.0.2.2 action drop
132	tc filter add dev $swp1 ingress protocol ip pref 3 handle 103 flower \
133		$tcflags dst_ip 192.0.2.2 action mirred egress redirect \
134		dev $swp2
135
136	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
137		-t ip -q
138
139	tc_check_packets "dev $swp1 ingress" 101 1
140	check_fail $? "Saw packet without trap rule inserted"
141
142	tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \
143		$tcflags dst_ip 192.0.2.2 action trap
144
145	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
146		-t ip -q
147
148	tc_check_packets "dev $swp1 ingress" 102 1
149	check_err $? "Packet was not trapped"
150
151	tc_check_packets "dev $swp1 ingress" 101 1
152	check_err $? "Did not see trapped packet"
153
154	tc filter del dev $swp1 ingress protocol ip pref 3 handle 103 flower
155	tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower
156	tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower
157
158	log_test "trap ($tcflags)"
159}
160
161mirred_egress_to_ingress_test()
162{
163	RET=0
164
165	tc filter add dev $h1 protocol ip pref 100 handle 100 egress flower \
166		ip_proto icmp src_ip 192.0.2.1 dst_ip 192.0.2.2 type 8 action \
167			ct commit nat src addr 192.0.2.2 pipe \
168			ct clear pipe \
169			ct commit nat dst addr 192.0.2.1 pipe \
170			mirred ingress redirect dev $h1
171
172	tc filter add dev $swp1 protocol ip pref 11 handle 111 ingress flower \
173		ip_proto icmp src_ip 192.0.2.1 dst_ip 192.0.2.2 type 8 action drop
174	tc filter add dev $swp1 protocol ip pref 12 handle 112 ingress flower \
175		ip_proto icmp src_ip 192.0.2.1 dst_ip 192.0.2.2 type 0 action pass
176
177	$MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \
178		-t icmp "ping,id=42,seq=10" -q
179
180	tc_check_packets "dev $h1 egress" 100 1
181	check_err $? "didn't mirror first packet"
182
183	tc_check_packets "dev $swp1 ingress" 111 1
184	check_fail $? "didn't redirect first packet"
185	tc_check_packets "dev $swp1 ingress" 112 1
186	check_err $? "didn't receive reply to first packet"
187
188	ping 192.0.2.2 -I$h1 -c1 -w1 -q 1>/dev/null 2>&1
189
190	tc_check_packets "dev $h1 egress" 100 2
191	check_err $? "didn't mirror second packet"
192	tc_check_packets "dev $swp1 ingress" 111 1
193	check_fail $? "didn't redirect second packet"
194	tc_check_packets "dev $swp1 ingress" 112 2
195	check_err $? "didn't receive reply to second packet"
196
197	tc filter del dev $h1 egress protocol ip pref 100 handle 100 flower
198	tc filter del dev $swp1 ingress protocol ip pref 11 handle 111 flower
199	tc filter del dev $swp1 ingress protocol ip pref 12 handle 112 flower
200
201	log_test "mirred_egress_to_ingress ($tcflags)"
202}
203
204mirred_egress_to_ingress_tcp_test()
205{
206	mirred_e2i_tf1=$(mktemp) mirred_e2i_tf2=$(mktemp)
207
208	RET=0
209	dd conv=sparse status=none if=/dev/zero bs=1M count=2 of=$mirred_e2i_tf1
210	tc filter add dev $h1 protocol ip pref 100 handle 100 egress flower \
211		$tcflags ip_proto tcp src_ip 192.0.2.1 dst_ip 192.0.2.2 \
212			action ct commit nat src addr 192.0.2.2 pipe \
213			action ct clear pipe \
214			action ct commit nat dst addr 192.0.2.1 pipe \
215			action ct clear pipe \
216			action skbedit ptype host pipe \
217			action mirred ingress redirect dev $h1
218	tc filter add dev $h1 protocol ip pref 101 handle 101 egress flower \
219		$tcflags ip_proto icmp \
220			action mirred ingress redirect dev $h1
221	tc filter add dev $h1 protocol ip pref 102 handle 102 ingress flower \
222		ip_proto icmp \
223			action drop
224
225	ip vrf exec v$h1 ncat --recv-only -w10 -l -p 12345 -o $mirred_e2i_tf2 &
226	local rpid=$!
227	ip vrf exec v$h1 ncat -w1 --send-only 192.0.2.2 12345 <$mirred_e2i_tf1
228	wait -n $rpid
229	cmp -s $mirred_e2i_tf1 $mirred_e2i_tf2
230	check_err $? "server output check failed"
231
232	$MZ $h1 -c 10 -p 64 -a $h1mac -b $h1mac -A 192.0.2.1 -B 192.0.2.1 \
233		-t icmp "ping,id=42,seq=5" -q
234	tc_check_packets "dev $h1 egress" 101 10
235	check_err $? "didn't mirred redirect ICMP"
236	tc_check_packets "dev $h1 ingress" 102 10
237	check_err $? "didn't drop mirred ICMP"
238	local overlimits=$(tc_rule_stats_get ${h1} 101 egress .overlimits)
239	test ${overlimits} = 10
240	check_err $? "wrong overlimits, expected 10 got ${overlimits}"
241
242	tc filter del dev $h1 egress protocol ip pref 100 handle 100 flower
243	tc filter del dev $h1 egress protocol ip pref 101 handle 101 flower
244	tc filter del dev $h1 ingress protocol ip pref 102 handle 102 flower
245
246	rm -f $mirred_e2i_tf1 $mirred_e2i_tf2
247	log_test "mirred_egress_to_ingress_tcp ($tcflags)"
248}
249
250setup_prepare()
251{
252	h1=${NETIFS[p1]}
253	swp1=${NETIFS[p2]}
254
255	swp2=${NETIFS[p3]}
256	h2=${NETIFS[p4]}
257
258	h1mac=$(mac_get $h1)
259	h2mac=$(mac_get $h2)
260
261	swp1origmac=$(mac_get $swp1)
262	swp2origmac=$(mac_get $swp2)
263	ip link set $swp1 address $h2mac
264	ip link set $swp2 address $h1mac
265
266	vrf_prepare
267
268	h1_create
269	h2_create
270	switch_create
271}
272
273cleanup()
274{
275	local tf
276
277	pre_cleanup
278
279	switch_destroy
280	h2_destroy
281	h1_destroy
282
283	vrf_cleanup
284
285	ip link set $swp2 address $swp2origmac
286	ip link set $swp1 address $swp1origmac
287
288	for tf in $mirred_e2i_tf1 $mirred_e2i_tf2; do rm -f $tf; done
289}
290
291mirred_egress_redirect_test()
292{
293	mirred_egress_test "redirect" "ip" "flower" "dst_ip 192.0.2.2"
294}
295
296mirred_egress_mirror_test()
297{
298	mirred_egress_test "mirror" "ip" "flower" "dst_ip 192.0.2.2"
299}
300
301matchall_mirred_egress_mirror_test()
302{
303	mirred_egress_test "mirror" "all" "matchall" ""
304}
305
306trap cleanup EXIT
307
308setup_prepare
309setup_wait
310
311tests_run
312
313tc_offload_check
314if [[ $? -ne 0 ]]; then
315	log_info "Could not test offloaded functionality"
316else
317	tcflags="skip_sw"
318	tests_run
319fi
320
321exit $EXIT_STATUS
322