1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4# This test is for checking IPv4 and IPv6 FIB rules API
5
6ret=0
7
8PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
9IP="ip -netns testns"
10
11RTABLE=100
12GW_IP4=192.51.100.2
13SRC_IP=192.51.100.3
14GW_IP6=2001:db8:1::2
15SRC_IP6=2001:db8:1::3
16
17DEV_ADDR=192.51.100.1
18DEV_ADDR6=2001:db8:1::1
19DEV=dummy0
20
21log_test()
22{
23	local rc=$1
24	local expected=$2
25	local msg="$3"
26
27	if [ ${rc} -eq ${expected} ]; then
28		nsuccess=$((nsuccess+1))
29		printf "\n    TEST: %-50s  [ OK ]\n" "${msg}"
30	else
31		ret=1
32		nfail=$((nfail+1))
33		printf "\n    TEST: %-50s  [FAIL]\n" "${msg}"
34		if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
35			echo
36			echo "hit enter to continue, 'q' to quit"
37			read a
38			[ "$a" = "q" ] && exit 1
39		fi
40	fi
41}
42
43log_section()
44{
45	echo
46	echo "######################################################################"
47	echo "TEST SECTION: $*"
48	echo "######################################################################"
49}
50
51setup()
52{
53	set -e
54	ip netns add testns
55	$IP link set dev lo up
56
57	$IP link add dummy0 type dummy
58	$IP link set dev dummy0 up
59	$IP address add $DEV_ADDR/24 dev dummy0
60	$IP -6 address add $DEV_ADDR6/64 dev dummy0
61
62	set +e
63}
64
65cleanup()
66{
67	$IP link del dev dummy0 &> /dev/null
68	ip netns del testns
69}
70
71fib_check_iproute_support()
72{
73	ip rule help 2>&1 | grep -q $1
74	if [ $? -ne 0 ]; then
75		echo "SKIP: iproute2 iprule too old, missing $1 match"
76		return 1
77	fi
78
79	ip route get help 2>&1 | grep -q $2
80	if [ $? -ne 0 ]; then
81		echo "SKIP: iproute2 get route too old, missing $2 match"
82		return 1
83	fi
84
85	return 0
86}
87
88fib_rule6_del()
89{
90	$IP -6 rule del $1
91	log_test $? 0 "rule6 del $1"
92}
93
94fib_rule6_del_by_pref()
95{
96	pref=$($IP -6 rule show | grep "$1 lookup $TABLE" | cut -d ":" -f 1)
97	$IP -6 rule del pref $pref
98}
99
100fib_rule6_test_match_n_redirect()
101{
102	local match="$1"
103	local getmatch="$2"
104
105	$IP -6 rule add $match table $RTABLE
106	$IP -6 route get $GW_IP6 $getmatch | grep -q "table $RTABLE"
107	log_test $? 0 "rule6 check: $1"
108
109	fib_rule6_del_by_pref "$match"
110	log_test $? 0 "rule6 del by pref: $match"
111}
112
113fib_rule6_test()
114{
115	# setup the fib rule redirect route
116	$IP -6 route add table $RTABLE default via $GW_IP6 dev $DEV onlink
117
118	match="oif $DEV"
119	fib_rule6_test_match_n_redirect "$match" "$match" "oif redirect to table"
120
121	match="from $SRC_IP6 iif $DEV"
122	fib_rule6_test_match_n_redirect "$match" "$match" "iif redirect to table"
123
124	match="tos 0x10"
125	fib_rule6_test_match_n_redirect "$match" "$match" "tos redirect to table"
126
127	match="fwmark 0x64"
128	getmatch="mark 0x64"
129	fib_rule6_test_match_n_redirect "$match" "$getmatch" "fwmark redirect to table"
130
131	fib_check_iproute_support "uidrange" "uid"
132	if [ $? -eq 0 ]; then
133		match="uidrange 100-100"
134		getmatch="uid 100"
135		fib_rule6_test_match_n_redirect "$match" "$getmatch" "uid redirect to table"
136	fi
137
138	fib_check_iproute_support "sport" "sport"
139	if [ $? -eq 0 ]; then
140		match="sport 666 dport 777"
141		fib_rule6_test_match_n_redirect "$match" "$match" "sport and dport redirect to table"
142	fi
143
144	fib_check_iproute_support "ipproto" "ipproto"
145	if [ $? -eq 0 ]; then
146		match="ipproto tcp"
147		fib_rule6_test_match_n_redirect "$match" "$match" "ipproto match"
148	fi
149
150	fib_check_iproute_support "ipproto" "ipproto"
151	if [ $? -eq 0 ]; then
152		match="ipproto ipv6-icmp"
153		fib_rule6_test_match_n_redirect "$match" "$match" "ipproto ipv6-icmp match"
154	fi
155}
156
157fib_rule4_del()
158{
159	$IP rule del $1
160	log_test $? 0 "del $1"
161}
162
163fib_rule4_del_by_pref()
164{
165	pref=$($IP rule show | grep "$1 lookup $TABLE" | cut -d ":" -f 1)
166	$IP rule del pref $pref
167}
168
169fib_rule4_test_match_n_redirect()
170{
171	local match="$1"
172	local getmatch="$2"
173
174	$IP rule add $match table $RTABLE
175	$IP route get $GW_IP4 $getmatch | grep -q "table $RTABLE"
176	log_test $? 0 "rule4 check: $1"
177
178	fib_rule4_del_by_pref "$match"
179	log_test $? 0 "rule4 del by pref: $match"
180}
181
182fib_rule4_test()
183{
184	# setup the fib rule redirect route
185	$IP route add table $RTABLE default via $GW_IP4 dev $DEV onlink
186
187	match="oif $DEV"
188	fib_rule4_test_match_n_redirect "$match" "$match" "oif redirect to table"
189
190	# need enable forwarding and disable rp_filter temporarily as all the
191	# addresses are in the same subnet and egress device == ingress device.
192	ip netns exec testns sysctl -w net.ipv4.ip_forward=1
193	ip netns exec testns sysctl -w net.ipv4.conf.$DEV.rp_filter=0
194	match="from $SRC_IP iif $DEV"
195	fib_rule4_test_match_n_redirect "$match" "$match" "iif redirect to table"
196	ip netns exec testns sysctl -w net.ipv4.ip_forward=0
197
198	match="tos 0x10"
199	fib_rule4_test_match_n_redirect "$match" "$match" "tos redirect to table"
200
201	match="fwmark 0x64"
202	getmatch="mark 0x64"
203	fib_rule4_test_match_n_redirect "$match" "$getmatch" "fwmark redirect to table"
204
205	fib_check_iproute_support "uidrange" "uid"
206	if [ $? -eq 0 ]; then
207		match="uidrange 100-100"
208		getmatch="uid 100"
209		fib_rule4_test_match_n_redirect "$match" "$getmatch" "uid redirect to table"
210	fi
211
212	fib_check_iproute_support "sport" "sport"
213	if [ $? -eq 0 ]; then
214		match="sport 666 dport 777"
215		fib_rule4_test_match_n_redirect "$match" "$match" "sport and dport redirect to table"
216	fi
217
218	fib_check_iproute_support "ipproto" "ipproto"
219	if [ $? -eq 0 ]; then
220		match="ipproto tcp"
221		fib_rule4_test_match_n_redirect "$match" "$match" "ipproto tcp match"
222	fi
223
224	fib_check_iproute_support "ipproto" "ipproto"
225	if [ $? -eq 0 ]; then
226		match="ipproto icmp"
227		fib_rule4_test_match_n_redirect "$match" "$match" "ipproto icmp match"
228	fi
229}
230
231run_fibrule_tests()
232{
233	log_section "IPv4 fib rule"
234	fib_rule4_test
235	log_section "IPv6 fib rule"
236	fib_rule6_test
237}
238
239if [ "$(id -u)" -ne 0 ];then
240	echo "SKIP: Need root privileges"
241	exit 0
242fi
243
244if [ ! -x "$(command -v ip)" ]; then
245	echo "SKIP: Could not run test without ip tool"
246	exit 0
247fi
248
249# start clean
250cleanup &> /dev/null
251setup
252run_fibrule_tests
253cleanup
254
255if [ "$TESTS" != "none" ]; then
256	printf "\nTests passed: %3d\n" ${nsuccess}
257	printf "Tests failed: %3d\n"   ${nfail}
258fi
259
260exit $ret
261