aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIdo Schimmel <idosch@mellanox.com>2018-02-28 05:25:06 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-28 12:25:47 -0500
commit73bae6736b6b577b52fbba2d4b71a5a3e9920fb5 (patch)
treed43ffba823395681367b3db91d9e1aec0b9a2a7a
parent8230819494b3bf284ca7262ac5f877333147b937 (diff)
selftests: forwarding: Add initial testing framework
Add initial framework to test packet forwarding functionality. The tests can run on actual devices using loop-backed cables or using veth pairs. Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: Ido Schimmel <idosch@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--tools/testing/selftests/net/forwarding/.gitignore1
-rw-r--r--tools/testing/selftests/net/forwarding/README56
-rwxr-xr-xtools/testing/selftests/net/forwarding/bridge_vlan_aware.sh83
-rw-r--r--tools/testing/selftests/net/forwarding/config12
-rw-r--r--tools/testing/selftests/net/forwarding/forwarding.config.sample31
-rw-r--r--tools/testing/selftests/net/forwarding/lib.sh282
6 files changed, 465 insertions, 0 deletions
diff --git a/tools/testing/selftests/net/forwarding/.gitignore b/tools/testing/selftests/net/forwarding/.gitignore
new file mode 100644
index 000000000000..a793eef5b876
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/.gitignore
@@ -0,0 +1 @@
forwarding.config
diff --git a/tools/testing/selftests/net/forwarding/README b/tools/testing/selftests/net/forwarding/README
new file mode 100644
index 000000000000..4a0964c42860
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/README
@@ -0,0 +1,56 @@
1Motivation
2==========
3
4One of the nice things about network namespaces is that they allow one
5to easily create and test complex environments.
6
7Unfortunately, these namespaces can not be used with actual switching
8ASICs, as their ports can not be migrated to other network namespaces
9(NETIF_F_NETNS_LOCAL) and most of them probably do not support the
10L1-separation provided by namespaces.
11
12However, a similar kind of flexibility can be achieved by using VRFs and
13by looping the switch ports together. For example:
14
15 br0
16 +
17 vrf-h1 | vrf-h2
18 + +---+----+ +
19 | | | |
20 192.0.2.1/24 + + + + 192.0.2.2/24
21 swp1 swp2 swp3 swp4
22 + + + +
23 | | | |
24 +--------+ +--------+
25
26The VRFs act as lightweight namespaces representing hosts connected to
27the switch.
28
29This approach for testing switch ASICs has several advantages over the
30traditional method that requires multiple physical machines, to name a
31few:
32
331. Only the device under test (DUT) is being tested without noise from
34other system.
35
362. Ability to easily provision complex topologies. Testing bridging
37between 4-ports LAGs or 8-way ECMP requires many physical links that are
38not always available. With the VRF-based approach one merely needs to
39loopback more ports.
40
41These tests are written with switch ASICs in mind, but they can be run
42on any Linux box using veth pairs to emulate physical loopbacks.
43
44Guidelines for Writing Tests
45============================
46
47o Where possible, reuse an existing topology for different tests instead
48 of recreating the same topology.
49o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and
50 RFC 5737, respectively.
51o Where possible, tests shall be written so that they can be reused by
52 multiple topologies and added to lib.sh.
53o Checks shall be added to lib.sh for any external dependencies.
54o Code shall be checked using ShellCheck [1] prior to submission.
55
561. https://www.shellcheck.net/
diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh
new file mode 100755
index 000000000000..e6faa9548460
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh
@@ -0,0 +1,83 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4NUM_NETIFS=4
5source lib.sh
6
7h1_create()
8{
9 simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64
10}
11
12h1_destroy()
13{
14 simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64
15}
16
17h2_create()
18{
19 simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64
20}
21
22h2_destroy()
23{
24 simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64
25}
26
27switch_create()
28{
29 ip link add dev br0 type bridge vlan_filtering 1 mcast_snooping 0
30
31 ip link set dev $swp1 master br0
32 ip link set dev $swp2 master br0
33
34 ip link set dev br0 up
35 ip link set dev $swp1 up
36 ip link set dev $swp2 up
37}
38
39switch_destroy()
40{
41 ip link set dev $swp2 down
42 ip link set dev $swp1 down
43
44 ip link del dev br0
45}
46
47setup_prepare()
48{
49 h1=${NETIFS[p1]}
50 swp1=${NETIFS[p2]}
51
52 swp2=${NETIFS[p3]}
53 h2=${NETIFS[p4]}
54
55 vrf_prepare
56
57 h1_create
58 h2_create
59
60 switch_create
61}
62
63cleanup()
64{
65 pre_cleanup
66
67 switch_destroy
68
69 h2_destroy
70 h1_destroy
71
72 vrf_cleanup
73}
74
75trap cleanup EXIT
76
77setup_prepare
78setup_wait
79
80ping_test $h1 192.0.2.2
81ping6_test $h1 2001:db8:1::2
82
83exit $EXIT_STATUS
diff --git a/tools/testing/selftests/net/forwarding/config b/tools/testing/selftests/net/forwarding/config
new file mode 100644
index 000000000000..5cd2aed97958
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/config
@@ -0,0 +1,12 @@
1CONFIG_BRIDGE=m
2CONFIG_VLAN_8021Q=m
3CONFIG_BRIDGE_VLAN_FILTERING=y
4CONFIG_NET_L3_MASTER_DEV=y
5CONFIG_IPV6_MULTIPLE_TABLES=y
6CONFIG_NET_VRF=m
7CONFIG_BPF_SYSCALL=y
8CONFIG_CGROUP_BPF=y
9CONFIG_NET_CLS_FLOWER=m
10CONFIG_NET_SCH_INGRESS=m
11CONFIG_NET_ACT_GACT=m
12CONFIG_VETH=m
diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample
new file mode 100644
index 000000000000..ab235c124f20
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample
@@ -0,0 +1,31 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4##############################################################################
5# Topology description. p1 looped back to p2, p3 to p4 and so on.
6declare -A NETIFS
7
8NETIFS[p1]=veth0
9NETIFS[p2]=veth1
10NETIFS[p3]=veth2
11NETIFS[p4]=veth3
12NETIFS[p5]=veth4
13NETIFS[p6]=veth5
14NETIFS[p7]=veth6
15NETIFS[p8]=veth7
16
17##############################################################################
18# Defines
19
20# IPv4 ping utility name
21PING=ping
22# IPv6 ping utility name. Some distributions use 'ping' for IPv6.
23PING6=ping6
24# Packet generator. Some distributions use 'mz'.
25MZ=mausezahn
26# Time to wait after interfaces participating in the test are all UP
27WAIT_TIME=5
28# Whether to pause on failure or not.
29PAUSE_ON_FAIL=no
30# Whether to pause on cleanup or not.
31PAUSE_ON_CLEANUP=no
diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh
new file mode 100644
index 000000000000..ff6550e9ddaf
--- /dev/null
+++ b/tools/testing/selftests/net/forwarding/lib.sh
@@ -0,0 +1,282 @@
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3
4##############################################################################
5# Defines
6
7# Can be overridden by the configuration file.
8PING=${PING:=ping}
9PING6=${PING6:=ping6}
10WAIT_TIME=${WAIT_TIME:=5}
11PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no}
12PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no}
13
14if [[ -f forwarding.config ]]; then
15 source forwarding.config
16fi
17
18##############################################################################
19# Sanity checks
20
21if [[ "$(id -u)" -ne 0 ]]; then
22 echo "SKIP: need root privileges"
23 exit 0
24fi
25
26tc -j &> /dev/null
27if [[ $? -ne 0 ]]; then
28 echo "SKIP: iproute2 too old, missing JSON support"
29 exit 0
30fi
31
32if [[ ! -x "$(command -v jq)" ]]; then
33 echo "SKIP: jq not installed"
34 exit 0
35fi
36
37if [[ ! -v NUM_NETIFS ]]; then
38 echo "SKIP: importer does not define \"NUM_NETIFS\""
39 exit 0
40fi
41
42##############################################################################
43# Network interfaces configuration
44
45for i in $(eval echo {1..$NUM_NETIFS}); do
46 ip link show dev ${NETIFS[p$i]} &> /dev/null
47 if [[ $? -ne 0 ]]; then
48 echo "SKIP: could not find all required interfaces"
49 exit 0
50 fi
51done
52
53##############################################################################
54# Helpers
55
56# Exit status to return at the end. Set in case one of the tests fails.
57EXIT_STATUS=0
58# Per-test return value. Clear at the beginning of each test.
59RET=0
60
61check_err()
62{
63 local err=$1
64 local msg=$2
65
66 if [[ $RET -eq 0 && $err -ne 0 ]]; then
67 RET=$err
68 retmsg=$msg
69 fi
70}
71
72check_fail()
73{
74 local err=$1
75 local msg=$2
76
77 if [[ $RET -eq 0 && $err -eq 0 ]]; then
78 RET=1
79 retmsg=$msg
80 fi
81}
82
83log_test()
84{
85 local test_name=$1
86 local opt_str=$2
87
88 if [[ $# -eq 2 ]]; then
89 opt_str="($opt_str)"
90 fi
91
92 if [[ $RET -ne 0 ]]; then
93 EXIT_STATUS=1
94 printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str"
95 if [[ ! -z "$retmsg" ]]; then
96 printf "\t%s\n" "$retmsg"
97 fi
98 if [ "${PAUSE_ON_FAIL}" = "yes" ]; then
99 echo "Hit enter to continue, 'q' to quit"
100 read a
101 [ "$a" = "q" ] && exit 1
102 fi
103 return 1
104 fi
105
106 printf "TEST: %-60s [PASS]\n" "$test_name $opt_str"
107 return 0
108}
109
110setup_wait()
111{
112 for i in $(eval echo {1..$NUM_NETIFS}); do
113 while true; do
114 ip link show dev ${NETIFS[p$i]} up \
115 | grep 'state UP' &> /dev/null
116 if [[ $? -ne 0 ]]; then
117 sleep 1
118 else
119 break
120 fi
121 done
122 done
123
124 # Make sure links are ready.
125 sleep $WAIT_TIME
126}
127
128pre_cleanup()
129{
130 if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then
131 echo "Pausing before cleanup, hit any key to continue"
132 read
133 fi
134}
135
136vrf_prepare()
137{
138 ip -4 rule add pref 32765 table local
139 ip -4 rule del pref 0
140 ip -6 rule add pref 32765 table local
141 ip -6 rule del pref 0
142}
143
144vrf_cleanup()
145{
146 ip -6 rule add pref 0 table local
147 ip -6 rule del pref 32765
148 ip -4 rule add pref 0 table local
149 ip -4 rule del pref 32765
150}
151
152__last_tb_id=0
153declare -A __TB_IDS
154
155__vrf_td_id_assign()
156{
157 local vrf_name=$1
158
159 __last_tb_id=$((__last_tb_id + 1))
160 __TB_IDS[$vrf_name]=$__last_tb_id
161 return $__last_tb_id
162}
163
164__vrf_td_id_lookup()
165{
166 local vrf_name=$1
167
168 return ${__TB_IDS[$vrf_name]}
169}
170
171vrf_create()
172{
173 local vrf_name=$1
174 local tb_id
175
176 __vrf_td_id_assign $vrf_name
177 tb_id=$?
178
179 ip link add dev $vrf_name type vrf table $tb_id
180 ip -4 route add table $tb_id unreachable default metric 4278198272
181 ip -6 route add table $tb_id unreachable default metric 4278198272
182}
183
184vrf_destroy()
185{
186 local vrf_name=$1
187 local tb_id
188
189 __vrf_td_id_lookup $vrf_name
190 tb_id=$?
191
192 ip -6 route del table $tb_id unreachable default metric 4278198272
193 ip -4 route del table $tb_id unreachable default metric 4278198272
194 ip link del dev $vrf_name
195}
196
197__addr_add_del()
198{
199 local if_name=$1
200 local add_del=$2
201 local array
202
203 shift
204 shift
205 array=("${@}")
206
207 for addrstr in "${array[@]}"; do
208 ip address $add_del $addrstr dev $if_name
209 done
210}
211
212simple_if_init()
213{
214 local if_name=$1
215 local vrf_name
216 local array
217
218 shift
219 vrf_name=v$if_name
220 array=("${@}")
221
222 vrf_create $vrf_name
223 ip link set dev $if_name master $vrf_name
224 ip link set dev $vrf_name up
225 ip link set dev $if_name up
226
227 __addr_add_del $if_name add "${array[@]}"
228}
229
230simple_if_fini()
231{
232 local if_name=$1
233 local vrf_name
234 local array
235
236 shift
237 vrf_name=v$if_name
238 array=("${@}")
239
240 __addr_add_del $if_name del "${array[@]}"
241
242 ip link set dev $if_name down
243 vrf_destroy $vrf_name
244}
245
246master_name_get()
247{
248 local if_name=$1
249
250 ip -j link show dev $if_name | jq -r '.[]["master"]'
251}
252
253##############################################################################
254# Tests
255
256ping_test()
257{
258 local if_name=$1
259 local dip=$2
260 local vrf_name
261
262 RET=0
263
264 vrf_name=$(master_name_get $if_name)
265 ip vrf exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev/null
266 check_err $?
267 log_test "ping"
268}
269
270ping6_test()
271{
272 local if_name=$1
273 local dip=$2
274 local vrf_name
275
276 RET=0
277
278 vrf_name=$(master_name_get $if_name)
279 ip vrf exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev/null
280 check_err $?
281 log_test "ping6"
282}