[RFC PATCH net-next 01/12] selftests: forwarding: Add initial testing framework

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxxxx>
Signed-off-by: Ido Schimmel <idosch@xxxxxxxxxxxx>
---
 tools/testing/selftests/Makefile                   |   1 +
 tools/testing/selftests/forwarding/.gitignore      |   1 +
 tools/testing/selftests/forwarding/Makefile        |   6 +
 tools/testing/selftests/forwarding/README          |  56 +++++++
 tools/testing/selftests/forwarding/bridge.sh       | 111 +++++++++++++
 tools/testing/selftests/forwarding/config          |  12 ++
 .../selftests/forwarding/forwarding.config.sample  |  19 +++
 tools/testing/selftests/forwarding/lib.sh          | 175 +++++++++++++++++++++
 8 files changed, 381 insertions(+)
 create mode 100644 tools/testing/selftests/forwarding/.gitignore
 create mode 100644 tools/testing/selftests/forwarding/Makefile
 create mode 100644 tools/testing/selftests/forwarding/README
 create mode 100755 tools/testing/selftests/forwarding/bridge.sh
 create mode 100644 tools/testing/selftests/forwarding/config
 create mode 100644 tools/testing/selftests/forwarding/forwarding.config.sample
 create mode 100644 tools/testing/selftests/forwarding/lib.sh

diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index eaf599dc2137..77b34d093a86 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -8,6 +8,7 @@ TARGETS += cpu-hotplug
 TARGETS += efivarfs
 TARGETS += exec
 TARGETS += firmware
+TARGETS += forwarding
 TARGETS += ftrace
 TARGETS += futex
 TARGETS += gpio
diff --git a/tools/testing/selftests/forwarding/.gitignore b/tools/testing/selftests/forwarding/.gitignore
new file mode 100644
index 000000000000..a793eef5b876
--- /dev/null
+++ b/tools/testing/selftests/forwarding/.gitignore
@@ -0,0 +1 @@
+forwarding.config
diff --git a/tools/testing/selftests/forwarding/Makefile b/tools/testing/selftests/forwarding/Makefile
new file mode 100644
index 000000000000..ef9380c49123
--- /dev/null
+++ b/tools/testing/selftests/forwarding/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+# Makefile for forwarding selftests
+
+TEST_PROGS := bridge.sh
+
+include ../lib.mk
diff --git a/tools/testing/selftests/forwarding/README b/tools/testing/selftests/forwarding/README
new file mode 100644
index 000000000000..4a0964c42860
--- /dev/null
+++ b/tools/testing/selftests/forwarding/README
@@ -0,0 +1,56 @@
+Motivation
+==========
+
+One of the nice things about network namespaces is that they allow one
+to easily create and test complex environments.
+
+Unfortunately, these namespaces can not be used with actual switching
+ASICs, as their ports can not be migrated to other network namespaces
+(NETIF_F_NETNS_LOCAL) and most of them probably do not support the
+L1-separation provided by namespaces.
+
+However, a similar kind of flexibility can be achieved by using VRFs and
+by looping the switch ports together. For example:
+
+                             br0
+                              +
+               vrf-h1         |           vrf-h2
+                 +        +---+----+        +
+                 |        |        |        |
+    192.0.2.1/24 +        +        +        + 192.0.2.2/24
+               swp1     swp2     swp3     swp4
+                 +        +        +        +
+                 |        |        |        |
+                 +--------+        +--------+
+
+The VRFs act as lightweight namespaces representing hosts connected to
+the switch.
+
+This approach for testing switch ASICs has several advantages over the
+traditional method that requires multiple physical machines, to name a
+few:
+
+1. Only the device under test (DUT) is being tested without noise from
+other system.
+
+2. Ability to easily provision complex topologies. Testing bridging
+between 4-ports LAGs or 8-way ECMP requires many physical links that are
+not always available. With the VRF-based approach one merely needs to
+loopback more ports.
+
+These tests are written with switch ASICs in mind, but they can be run
+on any Linux box using veth pairs to emulate physical loopbacks.
+
+Guidelines for Writing Tests
+============================
+
+o Where possible, reuse an existing topology for different tests instead
+  of recreating the same topology.
+o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and
+  RFC 5737, respectively.
+o Where possible, tests shall be written so that they can be reused by
+  multiple topologies and added to lib.sh.
+o Checks shall be added to lib.sh for any external dependencies.
+o Code shall be checked using ShellCheck [1] prior to submission.
+
+1. https://www.shellcheck.net/
diff --git a/tools/testing/selftests/forwarding/bridge.sh b/tools/testing/selftests/forwarding/bridge.sh
new file mode 100755
index 000000000000..c53086c53b37
--- /dev/null
+++ b/tools/testing/selftests/forwarding/bridge.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+NUM_NETIFS=4
+source lib.sh
+
+h1_create()
+{
+	vrf_create "vrf-h1" 1
+	ip link set dev $h1 master vrf-h1
+
+	ip link set dev vrf-h1 up
+	ip link set dev $h1 up
+
+	ip address add 192.0.2.1/24 dev $h1
+	ip address add 2001:db8:1::1/64 dev $h1
+}
+
+h1_destroy()
+{
+	ip address del 2001:db8:1::1/64 dev $h1
+	ip address del 192.0.2.1/24 dev $h1
+
+	ip link set dev $h1 down
+	vrf_destroy "vrf-h1" 1
+}
+
+h2_create()
+{
+	vrf_create "vrf-h2" 2
+	ip link set dev $h2 master vrf-h2
+
+	ip link set dev vrf-h2 up
+	ip link set dev $h2 up
+
+	ip address add 192.0.2.2/24 dev $h2
+	ip address add 2001:db8:1::2/64 dev $h2
+}
+
+h2_destroy()
+{
+	ip address del 2001:db8:1::2/64 dev $h2
+	ip address del 192.0.2.2/24 dev $h2
+
+	ip link set dev $h2 down
+	vrf_destroy "vrf-h2" 2
+}
+
+bridge_create()
+{
+	ip link add dev br0 type bridge vlan_filtering 1 mcast_snooping 0
+
+	ip link set dev $swp1 master br0
+	ip link set dev $swp2 master br0
+
+	ip link set dev br0 up
+	ip link set dev $swp1 up
+	ip link set dev $swp2 up
+}
+
+bridge_destroy()
+{
+	ip link set dev $swp2 down
+	ip link set dev $swp1 down
+
+	ip link del dev br0
+}
+
+setup_prepare()
+{
+	h1=${NETIFS[p1]}
+	swp1=${NETIFS[p2]}
+
+	swp2=${NETIFS[p3]}
+	h2=${NETIFS[p4]}
+
+	netifs_arr=($h1 $swp1 $swp2 $h2)
+
+	vrf_prepare
+
+	h1_create
+	h2_create
+
+	bridge_create
+}
+
+cleanup()
+{
+	bridge_destroy
+
+	h2_destroy
+	h1_destroy
+
+	vrf_cleanup
+}
+
+trap cleanup EXIT
+
+setup_prepare
+setup_wait
+
+ping_test "vrf-h1" 192.0.2.2
+ping_test "vrf-h1" 2001:db8:1::2
+
+old_mtu=$(mtu_get $h1)
+mtu_change 9000 "${netifs_arr[@]}"
+ping_test "vrf-h1" 192.0.2.2
+ping_test "vrf-h1" 2001:db8:1::2
+mtu_change $old_mtu "${netifs_arr[@]}"
+
+exit $EXIT_STATUS
diff --git a/tools/testing/selftests/forwarding/config b/tools/testing/selftests/forwarding/config
new file mode 100644
index 000000000000..5cd2aed97958
--- /dev/null
+++ b/tools/testing/selftests/forwarding/config
@@ -0,0 +1,12 @@
+CONFIG_BRIDGE=m
+CONFIG_VLAN_8021Q=m
+CONFIG_BRIDGE_VLAN_FILTERING=y
+CONFIG_NET_L3_MASTER_DEV=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
+CONFIG_NET_VRF=m
+CONFIG_BPF_SYSCALL=y
+CONFIG_CGROUP_BPF=y
+CONFIG_NET_CLS_FLOWER=m
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_VETH=m
diff --git a/tools/testing/selftests/forwarding/forwarding.config.sample b/tools/testing/selftests/forwarding/forwarding.config.sample
new file mode 100644
index 000000000000..f2b14814e4ba
--- /dev/null
+++ b/tools/testing/selftests/forwarding/forwarding.config.sample
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Topology description. p1 looped back to p2, p3 to p4 and so on.
+declare -A NETIFS
+
+NETIFS[p1]=veth0
+NETIFS[p2]=veth1
+NETIFS[p3]=veth2
+NETIFS[p4]=veth3
+NETIFS[p5]=veth4
+NETIFS[p6]=veth5
+NETIFS[p7]=veth6
+NETIFS[p8]=veth7
+
+# Various configuration options applicable to the testing framework.
+declare -A OPTIONS
+
+# Time to wait after interfaces participating in the test are all UP.
+OPTIONS[wait_time]=5
diff --git a/tools/testing/selftests/forwarding/lib.sh b/tools/testing/selftests/forwarding/lib.sh
new file mode 100644
index 000000000000..bb423371f4de
--- /dev/null
+++ b/tools/testing/selftests/forwarding/lib.sh
@@ -0,0 +1,175 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+
+if [[ "$(id -u)" -ne 0 ]]; then
+	echo "SKIP: need root privileges"
+	exit 0
+fi
+
+if [[ ! -f forwarding.config ]]; then
+	echo "SKIP: could not find configuration file"
+	exit 0
+fi
+
+tc -j &> /dev/null
+if [[ $? -ne 0 ]]; then
+	echo "SKIP: iproute2 too old, missing JSON support"
+	exit 0
+fi
+
+if [[ ! -x "$(command -v jq)" ]]; then
+	echo "SKIP: jq not installed"
+	exit 0
+fi
+
+if [[ ! -v NUM_NETIFS ]]; then
+	echo "SKIP: importer does not define \"NUM_NETIFS\""
+	exit 0
+fi
+
+source forwarding.config
+
+for i in $(eval echo {1..$NUM_NETIFS}); do
+	ip link show dev ${NETIFS[p$i]} &> /dev/null
+	if [[ $? -ne 0 ]]; then
+		echo "SKIP: could not find all required interfaces"
+		exit 0
+	fi
+done
+
+# Exit status to return at the end. Set in case one of the tests fails.
+EXIT_STATUS=0
+# Per-test return value. Clear at the beginning of each test.
+RET=0
+
+### Helpers ###
+
+check_err()
+{
+	local err=$1
+	local msg=$2
+
+	if [[ $RET -eq 0 ]]; then
+		RET=$err
+		retmsg=$msg
+	fi
+}
+
+check_fail()
+{
+	local err=$1
+	local msg=$2
+
+	if [[ $err -eq 0 ]]; then
+		RET=1
+		retmsg=$msg
+	fi
+}
+
+print_result()
+{
+	local test_name=$1
+	local opt_str=$2
+
+	if [[ $# -eq 2 ]]; then
+		opt_str="($opt_str)"
+	fi
+
+	if [[ $RET -ne 0 ]]; then
+		EXIT_STATUS=1
+		echo "FAIL: $test_name $opt_str"
+		if [[ ! -z "$retmsg" ]]; then
+			echo "$retmsg"
+		fi
+		return 1
+	fi
+
+	echo "PASS: $test_name $opt_str"
+	return 0
+}
+
+setup_wait()
+{
+	for i in $(eval echo {1..$NUM_NETIFS}); do
+		while true; do
+			ip link show dev ${NETIFS[p$i]} up \
+				| grep 'state UP' &> /dev/null
+			if [[ $? -ne 0 ]]; then
+				sleep 1
+			else
+				break
+			fi
+		done
+	done
+
+	# Make sure links are ready.
+	sleep ${OPTIONS[wait_time]}
+}
+
+vrf_prepare()
+{
+	ip -4 rule add pref 32765 table local
+	ip -4 rule del pref 0
+	ip -6 rule add pref 32765 table local
+	ip -6 rule del pref 0
+}
+
+vrf_cleanup()
+{
+	ip -6 rule add pref 0 table local
+	ip -6 rule del pref 32765
+	ip -4 rule add pref 0 table local
+	ip -4 rule del pref 32765
+}
+
+vrf_create()
+{
+	local vrf_name=$1
+	local tb_id=$2
+
+	ip link add dev $vrf_name type vrf table $tb_id
+	ip -4 route add table $tb_id unreachable default metric 4278198272
+	ip -6 route add table $tb_id unreachable default metric 4278198272
+}
+
+vrf_destroy()
+{
+	local vrf_name=$1
+	local tb_id=$2
+
+	ip -6 route del table $tb_id unreachable default metric 4278198272
+	ip -4 route del table $tb_id unreachable default metric 4278198272
+	ip link del dev $vrf_name
+}
+
+mtu_get()
+{
+	local if_name=$1
+
+	ip -j link show dev $if_name | jq '.[]["mtu"]'
+}
+
+mtu_change()
+{
+	local new_mtu=$1
+	local if_name
+
+	shift
+	for if_name in "${@}"; do
+		ip link set dev $if_name mtu $new_mtu
+	done
+}
+
+### Tests ###
+
+ping_test()
+{
+	local vrf_name=$1
+	local dip=$2
+
+	RET=0
+
+	ip vrf exec $vrf_name ping $dip -c 10 -i 0.1 -w 2 &> /dev/null
+	check_err $?
+	print_result "ping"
+}
-- 
2.14.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kselftest" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Samba]     [Device Mapper]

  Powered by Linux