summaryrefslogtreecommitdiffstats
path: root/testsuite
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--testsuite/Makefile97
-rw-r--r--testsuite/iproute2/Makefile34
-rw-r--r--testsuite/lib/generic.sh134
-rwxr-xr-xtestsuite/tests/bridge/vlan/show.t30
-rwxr-xr-xtestsuite/tests/bridge/vlan/tunnelshow.t33
-rwxr-xr-xtestsuite/tests/ip/link/add_type_bareudp.t86
-rwxr-xr-xtestsuite/tests/ip/link/add_type_xfrm.t17
-rwxr-xr-xtestsuite/tests/ip/link/new_link.t15
-rwxr-xr-xtestsuite/tests/ip/link/show_dev_wo_vf_rate.t6
-rwxr-xr-xtestsuite/tests/ip/netns/set_nsid.t22
-rwxr-xr-xtestsuite/tests/ip/netns/set_nsid_batch.t18
-rwxr-xr-xtestsuite/tests/ip/route/add_default_route.t35
-rwxr-xr-xtestsuite/tests/ip/rule/dsfield.t29
-rwxr-xr-xtestsuite/tests/ip/tunnel/add_tunnel.t27
-rw-r--r--testsuite/tests/ss/ss1.dumpbin0 -> 720 bytes
-rwxr-xr-xtestsuite/tests/ss/ssfilter.t48
-rwxr-xr-xtestsuite/tests/tc/batch.t23
-rwxr-xr-xtestsuite/tests/tc/cbq.t10
-rwxr-xr-xtestsuite/tests/tc/dsmark.t31
-rwxr-xr-xtestsuite/tests/tc/flower_mpls.t82
-rwxr-xr-xtestsuite/tests/tc/mpls.t69
-rwxr-xr-xtestsuite/tests/tc/pedit.t217
-rwxr-xr-xtestsuite/tests/tc/policer.t13
-rwxr-xr-xtestsuite/tests/tc/vlan.t85
-rw-r--r--testsuite/tools/Makefile9
-rw-r--r--testsuite/tools/generate_nlmsg.c116
26 files changed, 1286 insertions, 0 deletions
diff --git a/testsuite/Makefile b/testsuite/Makefile
new file mode 100644
index 0000000..fb50f61
--- /dev/null
+++ b/testsuite/Makefile
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: GPL-2.0
+## -- Config --
+DEV := lo
+PREFIX := sudo -E unshare -n
+RESULTS_DIR := results
+## -- End Config --
+
+HAVE_UNSHARED_UTIL := $(shell unshare --version 2> /dev/null)
+
+rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))
+
+TESTS := $(patsubst tests/%,%,$(call rwildcard,tests/,*.t))
+TESTS_DIR := $(dir $(TESTS))
+
+IPVERS := $(filter-out iproute2/Makefile,$(wildcard iproute2/*))
+
+KENVFN := $(shell mktemp /tmp/tc_testkenv.XXXXXX)
+ifneq (,$(wildcard /proc/config.gz))
+ KCPATH := /proc/config.gz
+else
+ KVER := $(shell uname -r)
+ KCPATHS := /lib/modules/$(KVER)/config /boot/config-$(KVER)
+ KCPATH := $(firstword $(wildcard $(KCPATHS)))
+endif
+
+.PHONY: compile listtests alltests configure $(TESTS)
+
+configure:
+ $(MAKE) -C iproute2 configure
+
+compile: configure generate_nlmsg
+ $(MAKE) -C iproute2
+
+listtests:
+ @for t in $(TESTS); do \
+ echo "$$t"; \
+ done
+
+generate_nlmsg:
+ $(MAKE) -C tools
+
+alltests: generate_nlmsg $(TESTS)
+
+testclean:
+ @echo "Removing $(RESULTS_DIR) dir ..."
+ @rm -rf $(RESULTS_DIR)
+
+clean: testclean
+ @rm -f iproute2/iproute2-this
+ @rm -f tests/ip/link/dev_wo_vf_rate.nl
+ $(MAKE) -C tools clean
+
+distclean: clean
+ $(MAKE) -C iproute2 distclean
+
+$(TESTS): generate_nlmsg testclean
+ifeq (,$(IPVERS))
+ $(error Please run make first)
+endif
+ifeq (,$(HAVE_UNSHARED_UTIL))
+ $(error Please install util-linux tools to run tests in separated network namespace)
+endif
+ @./tools/generate_nlmsg
+
+ @mkdir -p $(RESULTS_DIR)
+
+ @for d in $(TESTS_DIR); do \
+ mkdir -p $(RESULTS_DIR)/$$d; \
+ done
+
+ @if [ "$(KCPATH)" = "/proc/config.gz" ]; then \
+ gunzip -c $(KCPATH) >$(KENVFN); \
+ elif [ "$(KCPATH)" != "" ]; then \
+ cat $(KCPATH) >$(KENVFN); \
+ fi
+ @sed -i -e 's/^CONFIG_/export CONFIG_/' $(KENVFN)
+
+ @for i in $(IPVERS); do \
+ o=`echo $$i | sed -e 's/iproute2\///'`; \
+ echo -n "Running $@ [$$o/`uname -r`]: "; \
+ TMP_ERR=`mktemp /tmp/tc_testsuite.XXXXXX`; \
+ TMP_OUT=`mktemp /tmp/tc_testsuite.XXXXXX`; \
+ . $(KENVFN); \
+ STD_ERR="$$TMP_ERR" STD_OUT="$$TMP_OUT" \
+ TC="$$i/tc/tc" IP="$$i/ip/ip" SS=$$i/misc/ss BRIDGE="$$i/bridge/bridge" \
+ DEV="$(DEV)" IPVER="$@" SNAME="$$i" \
+ ERRF="$(RESULTS_DIR)/$@.$$o.err" $(PREFIX) tests/$@ > $(RESULTS_DIR)/$@.$$o.out; \
+ if [ "$$?" = "127" ]; then \
+ printf "\033[1;35mSKIPPED\033[0m\n"; \
+ elif [ -e "$(RESULTS_DIR)/$@.$$o.err" ]; then \
+ printf "\033[0;31mFAILED\033[0m\n"; \
+ else \
+ printf "\033[0;32mPASS\033[0m\n"; \
+ fi; \
+ rm "$$TMP_ERR" "$$TMP_OUT"; \
+ sudo dmesg > $(RESULTS_DIR)/$@.$$o.dmesg; \
+ done
diff --git a/testsuite/iproute2/Makefile b/testsuite/iproute2/Makefile
new file mode 100644
index 0000000..f894605
--- /dev/null
+++ b/testsuite/iproute2/Makefile
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0
+SUBDIRS := $(filter-out Makefile,$(wildcard *))
+.PHONY: all configure clean distclean show $(SUBDIRS)
+
+all: configure
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir; \
+ done
+
+link:
+ @if [ ! -L iproute2-this ]; then \
+ ln -s ../.. iproute2-this; \
+ fi
+
+configure: link
+ @for dir in $(SUBDIRS); do \
+ echo "Entering $$dir" && cd $$dir && if [ -f configure ]; then ./configure; fi && cd ..; \
+ done
+
+clean: link
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir clean; \
+ done
+
+distclean: clean
+ @for dir in $(SUBDIRS); do \
+ $(MAKE) -C $$dir distclean; \
+ done
+
+show: link
+ @echo "$(SUBDIRS)"
+
+$(SUBDIRS):
+ cd $@ && $(MAKE)
diff --git a/testsuite/lib/generic.sh b/testsuite/lib/generic.sh
new file mode 100644
index 0000000..8b339ec
--- /dev/null
+++ b/testsuite/lib/generic.sh
@@ -0,0 +1,134 @@
+export DEST="127.0.0.1"
+
+ts_log()
+{
+ echo "$@"
+}
+
+ts_err()
+{
+ ts_log "$@" | tee >> $ERRF
+}
+
+ts_cat()
+{
+ cat "$@"
+}
+
+ts_err_cat()
+{
+ ts_cat "$@" | tee >> $ERRF
+}
+
+ts_skip()
+{
+ exit 127
+}
+
+__ts_cmd()
+{
+ CMD=$1; shift
+ SCRIPT=$1; shift
+ DESC=$1; shift
+
+ $CMD $@ 2> $STD_ERR > $STD_OUT
+
+ if [ -s $STD_ERR ]; then
+ ts_err "${SCRIPT}: ${DESC} failed:"
+ ts_err "command: $CMD $@"
+ ts_err "stderr output:"
+ ts_err_cat $STD_ERR
+ if [ -s $STD_OUT ]; then
+ ts_err "stdout output:"
+ ts_err_cat $STD_OUT
+ fi
+ elif [ -s $STD_OUT ]; then
+ echo "${SCRIPT}: ${DESC} succeeded with output:"
+ cat $STD_OUT
+ else
+ echo "${SCRIPT}: ${DESC} succeeded"
+ fi
+}
+
+ts_tc()
+{
+ __ts_cmd "$TC" "$@"
+}
+
+ts_ip()
+{
+ __ts_cmd "$IP" "$@"
+}
+
+ts_ss()
+{
+ __ts_cmd "$SS" "$@"
+}
+
+ts_bridge()
+{
+ __ts_cmd "$BRIDGE" "$@"
+}
+
+ts_qdisc_available()
+{
+ HELPOUT=`$TC qdisc add $1 help 2>&1`
+ if [ "`echo $HELPOUT | grep \"^Unknown qdisc\"`" ]; then
+ return 0;
+ else
+ return 1;
+ fi
+}
+
+rand_dev()
+{
+ rnd=""
+ while [ ${#rnd} -ne 6 ]; do
+ rnd="$(head -c 250 /dev/urandom | tr -dc '[:alpha:]' | head -c 6)"
+ done
+ echo "dev-$rnd"
+}
+
+pr_failed()
+{
+ echo " [FAILED]"
+ ts_err "matching failed"
+}
+
+pr_success()
+{
+ echo " [SUCCESS]"
+}
+
+test_on()
+{
+ echo -n "test on: \"$1\""
+ if cat "$STD_OUT" | grep -qE "$1"
+ then
+ pr_success
+ else
+ pr_failed
+ fi
+}
+
+test_on_not()
+{
+ echo -n "test on: \"$1\""
+ if cat "$STD_OUT" | grep -vqE "$1"
+ then
+ pr_success
+ else
+ pr_failed
+ fi
+}
+
+test_lines_count()
+{
+ echo -n "test on lines count ($1): "
+ if [ $(cat "$STD_OUT" | wc -l) -eq "$1" ]
+ then
+ pr_success
+ else
+ pr_failed
+ fi
+}
diff --git a/testsuite/tests/bridge/vlan/show.t b/testsuite/tests/bridge/vlan/show.t
new file mode 100755
index 0000000..3def202
--- /dev/null
+++ b/testsuite/tests/bridge/vlan/show.t
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing vlan show]"
+
+BR_DEV="$(rand_dev)"
+VX0_DEV="$(rand_dev)"
+VX1_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $BR_DEV bridge interface" link add $BR_DEV type bridge
+
+ts_ip "$0" "Add $VX0_DEV vxlan interface" \
+ link add $VX0_DEV type vxlan dstport 4789 external
+ts_ip "$0" "Enslave $VX0_DEV under $BR_DEV" \
+ link set dev $VX0_DEV master $BR_DEV
+ts_bridge "$0" "Delete default vlan from $VX0_DEV" \
+ vlan del dev $VX0_DEV vid 1
+ts_ip "$0" "Add $VX1_DEV vxlan interface" \
+ link add $VX1_DEV type vxlan dstport 4790 external
+ts_ip "$0" "Enslave $VX1_DEV under $BR_DEV" \
+ link set dev $VX1_DEV master $BR_DEV
+
+# Test that bridge ports without vlans do not appear in the output
+ts_bridge "$0" "Show vlan" vlan
+test_on_not "$VX0_DEV"
+
+# Test that bridge ports without tunnels do not appear in the output
+ts_bridge "$0" "Show vlan tunnel info" vlan tunnelshow
+test_lines_count 1 # header only
diff --git a/testsuite/tests/bridge/vlan/tunnelshow.t b/testsuite/tests/bridge/vlan/tunnelshow.t
new file mode 100755
index 0000000..3e9c12a
--- /dev/null
+++ b/testsuite/tests/bridge/vlan/tunnelshow.t
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing tunnelshow]"
+
+BR_DEV="$(rand_dev)"
+VX_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $BR_DEV bridge interface" link add $BR_DEV type bridge
+
+ts_ip "$0" "Add $VX_DEV vxlan interface" \
+ link add $VX_DEV type vxlan dstport 4789 external
+ts_ip "$0" "Enslave $VX_DEV under $BR_DEV" \
+ link set dev $VX_DEV master $BR_DEV
+ts_ip "$0" "Set vlan_tunnel on $VX_DEV" \
+ link set dev $VX_DEV type bridge_slave vlan_tunnel on
+
+ts_bridge "$0" "Add single vlan" vlan add dev $VX_DEV vid 1000
+ts_bridge "$0" "Add single tunnel" \
+ vlan add dev $VX_DEV vid 1000 tunnel_info id 1000
+ts_bridge "$0" "Add vlan range" vlan add dev $VX_DEV vid 1010-1020
+ts_bridge "$0" "Add tunnel range" \
+ vlan add dev $VX_DEV vid 1010-1020 tunnel_info id 1010-1020
+ts_bridge "$0" "Add single vlan" vlan add dev $VX_DEV vid 1030
+ts_bridge "$0" "Add tunnel with vni > 16k" \
+ vlan add dev $VX_DEV vid 1030 tunnel_info id 65556
+
+ts_bridge "$0" "Show tunnel info" vlan tunnelshow dev $VX_DEV
+test_on "1030\s+65556"
+test_lines_count 4
+
+ts_bridge "$0" "Dump tunnel info" -j vlan tunnelshow dev $VX_DEV
diff --git a/testsuite/tests/ip/link/add_type_bareudp.t b/testsuite/tests/ip/link/add_type_bareudp.t
new file mode 100755
index 0000000..8a2a1ed
--- /dev/null
+++ b/testsuite/tests/ip/link/add_type_bareudp.t
@@ -0,0 +1,86 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing Add BareUDP interface (unicast MPLS)]"
+NEW_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $NEW_DEV BareUDP interface (unicast MPLS)" link add dev $NEW_DEV type bareudp dstport 6635 ethertype mpls_uc
+
+ts_ip "$0" "Show $NEW_DEV BareUDP interface (unicast MPLS)" -d link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_on "dstport 6635"
+test_on "ethertype mpls_uc"
+test_on "nomultiproto"
+
+ts_ip "$0" "Del $NEW_DEV BareUDP interface (unicast MPLS)" link del dev $NEW_DEV
+
+
+ts_log "[Testing Add BareUDP interface (multicast MPLS)]"
+NEW_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $NEW_DEV BareUDP interface (multicast MPLS)" link add dev $NEW_DEV type bareudp dstport 6635 ethertype mpls_mc
+
+ts_ip "$0" "Show $NEW_DEV BareUDP interface (multicast MPLS)" -d link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_on "dstport 6635"
+test_on "ethertype mpls_mc"
+test_on "nomultiproto"
+
+ts_ip "$0" "Del $NEW_DEV BareUDP interface (multicast MPLS)" link del dev $NEW_DEV
+
+
+ts_log "[Testing Add BareUDP interface (unicast and multicast MPLS)]"
+NEW_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $NEW_DEV BareUDP interface (unicast and multicast MPLS)" link add dev $NEW_DEV type bareudp dstport 6635 ethertype mpls_uc multiproto
+
+ts_ip "$0" "Show $NEW_DEV BareUDP interface (unicast and multicast MPLS)" -d link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_on "dstport 6635"
+test_on "ethertype mpls_uc"
+test_on "multiproto"
+
+ts_ip "$0" "Del $NEW_DEV BareUDP interface (unicast and multicast MPLS)" link del dev $NEW_DEV
+
+
+ts_log "[Testing Add BareUDP interface (IPv4)]"
+NEW_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $NEW_DEV BareUDP interface (IPv4)" link add dev $NEW_DEV type bareudp dstport 6635 ethertype ipv4
+
+ts_ip "$0" "Show $NEW_DEV BareUDP interface (IPv4)" -d link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_on "dstport 6635"
+test_on "ethertype ip"
+test_on "nomultiproto"
+
+ts_ip "$0" "Del $NEW_DEV BareUDP interface (IPv4)" link del dev $NEW_DEV
+
+
+ts_log "[Testing Add BareUDP interface (IPv6)]"
+NEW_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $NEW_DEV BareUDP interface (IPv6)" link add dev $NEW_DEV type bareudp dstport 6635 ethertype ipv6
+
+ts_ip "$0" "Show $NEW_DEV BareUDP interface (IPv6)" -d link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_on "dstport 6635"
+test_on "ethertype ipv6"
+test_on "nomultiproto"
+
+ts_ip "$0" "Del $NEW_DEV BareUDP interface (IPv6)" link del dev $NEW_DEV
+
+
+ts_log "[Testing Add BareUDP interface (IPv4 and IPv6)]"
+NEW_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $NEW_DEV BareUDP interface (IPv4 and IPv6)" link add dev $NEW_DEV type bareudp dstport 6635 ethertype ipv4 multiproto
+
+ts_ip "$0" "Show $NEW_DEV BareUDP interface (IPv4 and IPv6)" -d link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_on "dstport 6635"
+test_on "ethertype ip"
+test_on "multiproto"
+
+ts_ip "$0" "Del $NEW_DEV BareUDP interface (IPv4 and IPv6)" link del dev $NEW_DEV
diff --git a/testsuite/tests/ip/link/add_type_xfrm.t b/testsuite/tests/ip/link/add_type_xfrm.t
new file mode 100755
index 0000000..caba0e4
--- /dev/null
+++ b/testsuite/tests/ip/link/add_type_xfrm.t
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing Add XFRM Interface, With IF-ID]"
+
+PHYS_DEV="lo"
+NEW_DEV="$(rand_dev)"
+IF_ID="0xf"
+
+ts_ip "$0" "Add $NEW_DEV xfrm interface" link add dev $NEW_DEV type xfrm dev $PHYS_DEV if_id $IF_ID
+
+ts_ip "$0" "Show $NEW_DEV xfrm interface" -d link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_on "if_id $IF_ID"
+
+ts_ip "$0" "Del $NEW_DEV xfrm interface" link del dev $NEW_DEV
diff --git a/testsuite/tests/ip/link/new_link.t b/testsuite/tests/ip/link/new_link.t
new file mode 100755
index 0000000..c17650a
--- /dev/null
+++ b/testsuite/tests/ip/link/new_link.t
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing add/del virtual links]"
+
+NEW_DEV="$(rand_dev)"
+
+ts_ip "$0" "Add $NEW_DEV dummy interface" link add dev $NEW_DEV type dummy
+
+ts_ip "$0" "Show $NEW_DEV dummy interface" link show dev $NEW_DEV
+test_on "$NEW_DEV"
+test_lines_count 2
+
+ts_ip "$0" "Del $NEW_DEV dummy interface" link del dev $NEW_DEV
diff --git a/testsuite/tests/ip/link/show_dev_wo_vf_rate.t b/testsuite/tests/ip/link/show_dev_wo_vf_rate.t
new file mode 100755
index 0000000..5b3c004
--- /dev/null
+++ b/testsuite/tests/ip/link/show_dev_wo_vf_rate.t
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+NL_FILE="tests/ip/link/dev_wo_vf_rate.nl"
+ts_ip "$0" "Show VF devices w/o VF rate info" -d monitor file $NL_FILE
diff --git a/testsuite/tests/ip/netns/set_nsid.t b/testsuite/tests/ip/netns/set_nsid.t
new file mode 100755
index 0000000..8f8c779
--- /dev/null
+++ b/testsuite/tests/ip/netns/set_nsid.t
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing netns nsid]"
+
+NS=testnsid
+NSID=99
+
+ts_ip "$0" "Add new netns $NS" netns add $NS
+ts_ip "$0" "Set $NS nsid to $NSID" netns set $NS $NSID
+
+ts_ip "$0" "List netns" netns list
+test_on "$NS \(id: $NSID\)"
+
+ts_ip "$0" "List netns without explicit list or show" netns
+test_on "$NS \(id: $NSID\)"
+
+ts_ip "$0" "List nsid" netns list-id
+test_on "$NSID \(iproute2 netns name: $NS\)"
+
+ts_ip "$0" "Delete netns $NS" netns del $NS
diff --git a/testsuite/tests/ip/netns/set_nsid_batch.t b/testsuite/tests/ip/netns/set_nsid_batch.t
new file mode 100755
index 0000000..196fd4b
--- /dev/null
+++ b/testsuite/tests/ip/netns/set_nsid_batch.t
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing netns nsid in batch mode]"
+
+NS=testnsid
+NSID=99
+BATCHFILE=`mktemp`
+
+echo "netns add $NS" >> $BATCHFILE
+echo "netns set $NS $NSID" >> $BATCHFILE
+echo "netns list-id" >> $BATCHFILE
+ts_ip "$0" "Add ns, set nsid and list in batch mode" -b $BATCHFILE
+test_on "nsid $NSID \(iproute2 netns name: $NS\)"
+rm -f $BATCHFILE
+
+ts_ip "$0" "Delete netns $NS" netns del $NS
diff --git a/testsuite/tests/ip/route/add_default_route.t b/testsuite/tests/ip/route/add_default_route.t
new file mode 100755
index 0000000..ded4edc
--- /dev/null
+++ b/testsuite/tests/ip/route/add_default_route.t
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing add default route]"
+
+DEV=dummy0
+
+ts_ip "$0" "Add new interface $DEV" link add $DEV type dummy
+ts_ip "$0" "Set $DEV into UP state" link set up dev $DEV
+
+ts_ip "$0" "Add 1.1.1.1/24 addr on $DEV" addr add 1.1.1.1/24 dev $DEV
+ts_ip "$0" "Add default route via 1.1.1.2" route add default via 1.1.1.2
+
+ts_ip "$0" "Show IPv4 default route" -4 route show default
+test_on "default via 1.1.1.2 dev $DEV"
+test_lines_count 1
+
+ts_ip "$0" "Add another IPv4 route dst 2.2.2.0/24" -4 route add 2.2.2.0/24 dev $DEV
+ts_ip "$0" "Show IPv4 default route" -4 route show default
+test_on "default via 1.1.1.2 dev $DEV"
+test_lines_count 1
+
+ts_ip "$0" "Add dead:beef::1/64 addr on $DEV" -6 addr add dead:beef::1/64 dev $DEV
+ts_ip "$0" "Add default route via dead:beef::2" route add default via dead:beef::2
+ts_ip "$0" "Show IPv6 default route" -6 route show default
+test_on "default via dead:beef::2 dev $DEV"
+test_lines_count 1
+
+ts_ip "$0" "Add another IPv6 route dst cafe:babe::/64" -6 route add cafe:babe::/64 dev $DEV
+ts_ip "$0" "Show IPv6 default route" -6 route show default
+test_on "default via dead:beef::2 dev $DEV"
+test_lines_count 1
+
+ts_ip "$0" "Del $DEV dummy interface" link del dev $DEV
diff --git a/testsuite/tests/ip/rule/dsfield.t b/testsuite/tests/ip/rule/dsfield.t
new file mode 100755
index 0000000..79ad4e2
--- /dev/null
+++ b/testsuite/tests/ip/rule/dsfield.t
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+ts_log "[Testing rule with option dsfield/tos]"
+
+ts_ip "$0" "Add IPv4 rule with dsfield 0x10" -4 rule add dsfield 0x10
+ts_ip "$0" "Show IPv4 rule with dsfield 0x10" -4 rule show dsfield 0x10
+test_on "tos 0x10"
+test_lines_count 1
+ts_ip "$0" "Delete IPv4 rule with dsfield 0x10" -4 rule del dsfield 0x10
+
+ts_ip "$0" "Add IPv4 rule with tos 0x10" -4 rule add tos 0x10
+ts_ip "$0" "Show IPv4 rule with tos 0x10" -4 rule show tos 0x10
+test_on "tos 0x10"
+test_lines_count 1
+ts_ip "$0" "Delete IPv4 rule with tos 0x10" -4 rule del tos 0x10
+
+ts_ip "$0" "Add IPv6 rule with dsfield 0x10" -6 rule add dsfield 0x10
+ts_ip "$0" "Show IPv6 rule with dsfield 0x10" -6 rule show dsfield 0x10
+test_on "tos 0x10"
+test_lines_count 1
+ts_ip "$0" "Delete IPv6 rule with dsfield 0x10" -6 rule del dsfield 0x10
+
+ts_ip "$0" "Add IPv6 rule with tos 0x10" -6 rule add tos 0x10
+ts_ip "$0" "Show IPv6 rule with tos 0x10" -6 rule show tos 0x10
+test_on "tos 0x10"
+test_lines_count 1
+ts_ip "$0" "Delete IPv6 rule with tos 0x10" -6 rule del tos 0x10
diff --git a/testsuite/tests/ip/tunnel/add_tunnel.t b/testsuite/tests/ip/tunnel/add_tunnel.t
new file mode 100755
index 0000000..65db431
--- /dev/null
+++ b/testsuite/tests/ip/tunnel/add_tunnel.t
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+TUNNEL_NAME="tunnel_test_ip"
+KMODS="ip6_gre ip6_tunnel ip_gre ip_tunnel gre"
+
+# unload kernel modules to remove dummy interfaces only if they were not in use beforehand
+kmods_remove=
+# note that checkbashism reports command -v, but dash supports it and it's POSIX 2008 compliant
+if command -v lsmod >/dev/null 2>&1 && command -v rmmod >/dev/null 2>&1; then
+ for i in $KMODS; do
+ lsmod | grep -q "^$i" || kmods_remove="$kmods_remove $i";
+ done
+fi
+
+ts_log "[Testing add/del tunnels]"
+
+ts_ip "$0" "Add GRE tunnel over IPv4" tunnel add name $TUNNEL_NAME mode gre local 1.1.1.1 remote 2.2.2.2
+ts_ip "$0" "Del GRE tunnel over IPv4" tunnel del $TUNNEL_NAME
+
+ts_ip "$0" "Add GRE tunnel over IPv6" tunnel add name $TUNNEL_NAME mode ip6gre local dead:beef::1 remote dead:beef::2
+ts_ip "$0" "Del GRE tunnel over IPv6" tunnel del $TUNNEL_NAME
+
+for mod in $kmods_remove; do
+ sudo rmmod "$mod"
+done
diff --git a/testsuite/tests/ss/ss1.dump b/testsuite/tests/ss/ss1.dump
new file mode 100644
index 0000000..9c27323
--- /dev/null
+++ b/testsuite/tests/ss/ss1.dump
Binary files differ
diff --git a/testsuite/tests/ss/ssfilter.t b/testsuite/tests/ss/ssfilter.t
new file mode 100755
index 0000000..4c2315c
--- /dev/null
+++ b/testsuite/tests/ss/ssfilter.t
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+# % ./misc/ss -Htna
+# LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
+# ESTAB 0 0 10.0.0.1:22 10.0.0.1:36266
+# ESTAB 0 0 10.0.0.1:36266 10.0.0.1:22
+# ESTAB 0 0 10.0.0.1:22 10.0.0.2:50312
+export TCPDIAG_FILE="$(dirname $0)/ss1.dump"
+
+ts_log "[Testing ssfilter]"
+
+ts_ss "$0" "Match dport = 22" -Htna dport = 22
+test_on "ESTAB 0 0 10.0.0.1:36266 10.0.0.1:22"
+
+ts_ss "$0" "Match dport 22" -Htna dport 22
+test_on "ESTAB 0 0 10.0.0.1:36266 10.0.0.1:22"
+
+ts_ss "$0" "Match (dport)" -Htna '( dport = 22 )'
+test_on "ESTAB 0 0 10.0.0.1:36266 10.0.0.1:22"
+
+ts_ss "$0" "Match src = 0.0.0.0" -Htna src = 0.0.0.0
+test_on "LISTEN 0 128 0.0.0.0:22 0.0.0.0:\*"
+
+ts_ss "$0" "Match src 0.0.0.0" -Htna src 0.0.0.0
+test_on "LISTEN 0 128 0.0.0.0:22 0.0.0.0:\*"
+
+ts_ss "$0" "Match src sport" -Htna src 0.0.0.0 sport = 22
+test_on "LISTEN 0 128 0.0.0.0:22 0.0.0.0:\*"
+
+ts_ss "$0" "Match src and sport" -Htna src 0.0.0.0 and sport = 22
+test_on "LISTEN 0 128 0.0.0.0:22 0.0.0.0:\*"
+
+ts_ss "$0" "Match src and sport and dport" -Htna src 10.0.0.1 and sport = 22 and dport = 50312
+test_on "ESTAB 0 0 10.0.0.1:22 10.0.0.2:50312"
+
+ts_ss "$0" "Match src and sport and (dport)" -Htna 'src 10.0.0.1 and sport = 22 and ( dport = 50312 )'
+test_on "ESTAB 0 0 10.0.0.1:22 10.0.0.2:50312"
+
+ts_ss "$0" "Match src and (sport and dport)" -Htna 'src 10.0.0.1 and ( sport = 22 and dport = 50312 )'
+test_on "ESTAB 0 0 10.0.0.1:22 10.0.0.2:50312"
+
+ts_ss "$0" "Match (src and sport) and dport" -Htna '( src 10.0.0.1 and sport = 22 ) and dport = 50312'
+test_on "ESTAB 0 0 10.0.0.1:22 10.0.0.2:50312"
+
+ts_ss "$0" "Match (src or src) and dst" -Htna '( src 0.0.0.0 or src 10.0.0.1 ) and dst 10.0.0.2'
+test_on "ESTAB 0 0 10.0.0.1:22 10.0.0.2:50312"
diff --git a/testsuite/tests/tc/batch.t b/testsuite/tests/tc/batch.t
new file mode 100755
index 0000000..50e7ba3
--- /dev/null
+++ b/testsuite/tests/tc/batch.t
@@ -0,0 +1,23 @@
+#!/bin/sh
+. lib/generic.sh
+
+DEV="$(rand_dev)"
+ts_ip "$0" "Add $DEV dummy interface" link add dev $DEV type dummy
+ts_ip "$0" "Enable $DEV" link set $DEV up
+ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV clsact
+
+TMP="$(mktemp)"
+echo filt add dev $DEV ingress pref 1000 matchall action pass >> "$TMP"
+echo filt add dev $DEV ingress pref 1000 matchall action pass >> "$TMP"
+
+"$TC" -b "$TMP" 2> $STD_ERR > $STD_OUT
+if [ $? -eq 0 ]; then
+ ts_err "$0: batch passed when it should have failed"
+elif [ ! -s $STD_ERR ]; then
+ ts_err "$0: batch produced no error message"
+else
+ echo "$0: batch failed, as expected"
+fi
+
+rm "$TMP"
+ts_ip "$0" "Del $DEV dummy interface" link del dev $DEV
diff --git a/testsuite/tests/tc/cbq.t b/testsuite/tests/tc/cbq.t
new file mode 100755
index 0000000..bff814b
--- /dev/null
+++ b/testsuite/tests/tc/cbq.t
@@ -0,0 +1,10 @@
+#!/bin/sh
+$TC qdisc del dev $DEV root >/dev/null 2>&1
+$TC qdisc add dev $DEV root handle 10:0 cbq bandwidth 100Mbit avpkt 1400 mpu 64
+$TC class add dev $DEV parent 10:0 classid 10:12 cbq bandwidth 100mbit rate 100mbit allot 1514 prio 3 maxburst 1 avpkt 500 bounded
+$TC qdisc list dev $DEV
+$TC qdisc del dev $DEV root
+$TC qdisc list dev $DEV
+$TC qdisc add dev $DEV root handle 10:0 cbq bandwidth 100Mbit avpkt 1400 mpu 64
+$TC class add dev $DEV parent 10:0 classid 10:12 cbq bandwidth 100mbit rate 100mbit allot 1514 prio 3 maxburst 1 avpkt 500 bounded
+$TC qdisc del dev $DEV root
diff --git a/testsuite/tests/tc/dsmark.t b/testsuite/tests/tc/dsmark.t
new file mode 100755
index 0000000..3f1d5ef
--- /dev/null
+++ b/testsuite/tests/tc/dsmark.t
@@ -0,0 +1,31 @@
+#!/bin/sh
+# vim: ft=sh
+
+. lib/generic.sh
+
+ts_qdisc_available "dsmark"
+if [ $? -eq 0 ]; then
+ ts_log "dsmark: Unsupported by $TC, skipping"
+ exit 127
+fi
+
+ts_tc "dsmark" "dsmark root qdisc creation" \
+ qdisc add dev $DEV root handle 10:0 \
+ dsmark indices 64 default_index 1 set_tc_index
+
+ts_tc "dsmark" "dsmark class 1 creation" \
+ class change dev $DEV parent 10:0 classid 10:12 \
+ dsmark mask 0xff value 2
+
+ts_tc "dsmark" "dsmark class 2 creation" \
+ class change dev $DEV parent 10:0 classid 10:13 \
+ dsmark mask 0xfc value 4
+
+ts_tc "dsmark" "dsmark dump qdisc" \
+ qdisc list dev $DEV
+
+ts_tc "dsmark" "dsmark dump class" \
+ class list dev $DEV parent 10:0
+
+ts_tc "dsmark" "generic qdisc tree deletion" \
+ qdisc del dev $DEV root
diff --git a/testsuite/tests/tc/flower_mpls.t b/testsuite/tests/tc/flower_mpls.t
new file mode 100755
index 0000000..430ed13
--- /dev/null
+++ b/testsuite/tests/tc/flower_mpls.t
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+DEV="$(rand_dev)"
+ts_ip "$0" "Add $DEV dummy interface" link add dev $DEV up type dummy
+ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+
+reset_qdisc()
+{
+ ts_tc "$0" "Remove ingress qdisc" qdisc del dev $DEV ingress
+ ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+}
+
+ts_tc "$0" "Add MPLS filter matching first LSE with minimal values" \
+ filter add dev $DEV ingress protocol mpls_uc flower \
+ mpls_label 0 mpls_tc 0 mpls_bos 0 mpls_ttl 0 \
+ action drop
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls_label 0"
+test_on "mpls_tc 0"
+test_on "mpls_bos 0"
+test_on "mpls_ttl 0"
+
+reset_qdisc
+ts_tc "$0" "Add MPLS filter matching first LSE with maximal values" \
+ filter add dev $DEV ingress protocol mpls_uc flower \
+ mpls_label 1048575 mpls_tc 7 mpls_bos 1 mpls_ttl 255 \
+ action drop
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls_label 1048575"
+test_on "mpls_tc 7"
+test_on "mpls_bos 1"
+test_on "mpls_ttl 255"
+
+reset_qdisc
+ts_tc "$0" "Add MPLS filter matching second LSE with minimal values" \
+ filter add dev $DEV ingress protocol mpls_uc flower \
+ mpls lse depth 2 label 0 tc 0 bos 0 ttl 0 \
+ action drop
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "lse"
+test_on "depth 2"
+test_on "label 0"
+test_on "tc 0"
+test_on "bos 0"
+test_on "ttl 0"
+
+reset_qdisc
+ts_tc "$0" "Add MPLS filter matching second LSE with maximal values" \
+ filter add dev $DEV ingress protocol mpls_uc flower \
+ mpls lse depth 2 label 1048575 tc 7 bos 1 ttl 255 \
+ action drop
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "lse"
+test_on "depth 2"
+test_on "label 1048575"
+test_on "tc 7"
+test_on "bos 1"
+test_on "ttl 255"
+
+reset_qdisc
+ts_tc "$0" "Add MPLS filter matching two LSEs" \
+ filter add dev $DEV ingress protocol mpls_uc flower mpls \
+ lse depth 1 label 0 tc 0 bos 0 ttl 0 \
+ lse depth 2 label 1048575 tc 7 bos 1 ttl 255 \
+ action drop
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "lse"
+test_on "depth 1"
+test_on "label 0"
+test_on "tc 0"
+test_on "bos 0"
+test_on "ttl 0"
+test_on "depth 2"
+test_on "label 1048575"
+test_on "tc 7"
+test_on "bos 1"
+test_on "ttl 255"
diff --git a/testsuite/tests/tc/mpls.t b/testsuite/tests/tc/mpls.t
new file mode 100755
index 0000000..cb25f36
--- /dev/null
+++ b/testsuite/tests/tc/mpls.t
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+DEV="$(rand_dev)"
+ts_ip "$0" "Add $DEV dummy interface" link add dev $DEV up type dummy
+ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+
+reset_qdisc()
+{
+ ts_tc "$0" "Remove ingress qdisc" qdisc del dev $DEV ingress
+ ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+}
+
+ts_tc "$0" "Add mpls action pop" \
+ filter add dev $DEV ingress protocol mpls_uc matchall \
+ action mpls pop protocol ip
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "pop protocol ip pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action push" \
+ filter add dev $DEV ingress protocol ip matchall \
+ action mpls push protocol mpls_uc label 20 tc 3 bos 1 ttl 64
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "push"
+test_on "protocol mpls_uc"
+test_on "label 20"
+test_on "tc 3"
+test_on "bos 1"
+test_on "ttl 64"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action mac_push" \
+ filter add dev $DEV ingress matchall \
+ action mpls mac_push protocol mpls_uc label 20 tc 3 bos 1 ttl 64
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "mac_push"
+test_on "protocol mpls_uc"
+test_on "label 20"
+test_on "tc 3"
+test_on "bos 1"
+test_on "ttl 64"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action modify" \
+ filter add dev $DEV ingress protocol mpls_uc matchall \
+ action mpls modify label 20 tc 3 ttl 64
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "modify"
+test_on "label 20"
+test_on "tc 3"
+test_on "ttl 64"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add mpls action dec_ttl" \
+ filter add dev $DEV ingress protocol mpls_uc matchall \
+ action mpls dec_ttl
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "mpls"
+test_on "dec_ttl"
+test_on "pipe"
diff --git a/testsuite/tests/tc/pedit.t b/testsuite/tests/tc/pedit.t
new file mode 100755
index 0000000..8d531a0
--- /dev/null
+++ b/testsuite/tests/tc/pedit.t
@@ -0,0 +1,217 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+DEV="$(rand_dev)"
+ts_ip "$0" "Add $DEV dummy interface" link add dev $DEV type dummy
+ts_ip "$0" "Enable $DEV" link set $DEV up
+ts_tc "pedit" "Add ingress qdisc" qdisc add dev $DEV ingress
+
+
+do_pedit() {
+ ts_tc "pedit" "Drop ingress qdisc" \
+ qdisc del dev $DEV ingress
+ ts_tc "pedit" "Add ingress qdisc" \
+ qdisc add dev $DEV ingress
+ ts_tc "pedit" "Add pedit action $*" \
+ filter add dev $DEV parent ffff: \
+ u32 match u32 0 0 \
+ action pedit munge $@
+ ts_tc "pedit" "Show ingress filters" \
+ filter show dev $DEV parent ffff:
+}
+
+do_pedit offset 12 u32 set 0x12345678
+test_on "key #0 at 12: val 12345678 mask 00000000"
+do_pedit offset 12 u16 set 0x1234
+test_on "key #0 at 12: val 12340000 mask 0000ffff"
+do_pedit offset 14 u16 set 0x1234
+test_on "key #0 at 12: val 00001234 mask ffff0000"
+do_pedit offset 12 u8 set 0x23
+test_on "key #0 at 12: val 23000000 mask 00ffffff"
+do_pedit offset 13 u8 set 0x23
+test_on "key #0 at 12: val 00230000 mask ff00ffff"
+do_pedit offset 14 u8 set 0x23
+test_on "key #0 at 12: val 00002300 mask ffff00ff"
+do_pedit offset 15 u8 set 0x23
+test_on "key #0 at 12: val 00000023 mask ffffff00"
+
+do_pedit offset 13 u8 invert
+test_on "key #0 at 12: val 00ff0000 mask ffffffff"
+do_pedit offset 13 u8 clear
+test_on "key #0 at 12: val 00000000 mask ff00ffff"
+do_pedit offset 13 u8 preserve
+test_on "key #0 at 12: val 00000000 mask ffffffff"
+
+# the following set of tests has been auto-generated by running this little
+# shell script:
+#
+# do_it() {
+# echo "do_pedit $@"
+# tc qd del dev veth0 ingress >/dev/null 2>&1
+# tc qd add dev veth0 ingress >/dev/null 2>&1
+# tc filter add dev veth0 parent ffff: u32 \
+# match u32 0 0 \
+# action pedit munge $@ >/dev/null 2>&1
+# tc filter show dev veth0 parent ffff: | \
+# sed -n 's/^[\t ]*\(key #0.*\)/test_on "\1"/p'
+# }
+#
+# do_it_all() { # (field, val1 [, val2, ...])
+# local field=$1
+# shift
+# for val in $@; do
+# do_it ip $field set $val
+# done
+# for i in preserve invert clear; do
+# do_it ip $field $i
+# done
+# }
+#
+# do_it_all ihl 0x04 0x40
+# do_it_all src 1.2.3.4
+# do_it_all dst 1.2.3.4
+# do_it_all tos 0x1 0x10
+# do_it_all protocol 0x23
+# do_it_all nofrag 0x23 0xf4
+# do_it_all firstfrag 0x03 0xfa
+# do_it_all ce 0x23 0x04 0xf3
+# do_it_all df 0x23 0x04 0xf3
+# do_it_all mf 0x23 0x04 0xf3
+# do_it_all dport 0x1234
+# do_it_all sport 0x1234
+# do_it_all icmp_type 0x23
+# do_it_all icmp_code 0x23
+
+do_pedit ip ihl set 0x04
+test_on "key #0 at 0: val 04000000 mask f0ffffff"
+do_pedit ip ihl set 0x40
+test_on "key #0 at 0: val 00000000 mask f0ffffff"
+do_pedit ip ihl preserve
+test_on "key #0 at 0: val 00000000 mask ffffffff"
+do_pedit ip ihl invert
+test_on "key #0 at 0: val 0f000000 mask ffffffff"
+do_pedit ip ihl clear
+test_on "key #0 at 0: val 00000000 mask f0ffffff"
+do_pedit ip src set 1.2.3.4
+test_on "key #0 at 12: val 01020304 mask 00000000"
+do_pedit ip src preserve
+test_on "key #0 at 12: val 00000000 mask ffffffff"
+do_pedit ip src invert
+test_on "key #0 at 12: val ffffffff mask ffffffff"
+do_pedit ip src clear
+test_on "key #0 at 12: val 00000000 mask 00000000"
+do_pedit ip dst set 1.2.3.4
+test_on "key #0 at 16: val 01020304 mask 00000000"
+do_pedit ip dst preserve
+test_on "key #0 at 16: val 00000000 mask ffffffff"
+do_pedit ip dst invert
+test_on "key #0 at 16: val ffffffff mask ffffffff"
+do_pedit ip dst clear
+test_on "key #0 at 16: val 00000000 mask 00000000"
+do_pedit ip tos set 0x1
+test_on "key #0 at 0: val 00010000 mask ff00ffff"
+do_pedit ip tos set 0x10
+test_on "key #0 at 0: val 00100000 mask ff00ffff"
+do_pedit ip tos preserve
+test_on "key #0 at 0: val 00000000 mask ffffffff"
+do_pedit ip tos invert
+test_on "key #0 at 0: val 00ff0000 mask ffffffff"
+do_pedit ip tos clear
+test_on "key #0 at 0: val 00000000 mask ff00ffff"
+do_pedit ip protocol set 0x23
+test_on "key #0 at 8: val 00230000 mask ff00ffff"
+do_pedit ip protocol preserve
+test_on "key #0 at 8: val 00000000 mask ffffffff"
+do_pedit ip protocol invert
+test_on "key #0 at 8: val 00ff0000 mask ffffffff"
+do_pedit ip protocol clear
+test_on "key #0 at 8: val 00000000 mask ff00ffff"
+do_pedit ip nofrag set 0x23
+test_on "key #0 at 4: val 00002300 mask ffffc0ff"
+do_pedit ip nofrag set 0xf4
+test_on "key #0 at 4: val 00003400 mask ffffc0ff"
+do_pedit ip nofrag preserve
+test_on "key #0 at 4: val 00000000 mask ffffffff"
+do_pedit ip nofrag invert
+test_on "key #0 at 4: val 00003f00 mask ffffffff"
+do_pedit ip nofrag clear
+test_on "key #0 at 4: val 00000000 mask ffffc0ff"
+do_pedit ip firstfrag set 0x03
+test_on "key #0 at 4: val 00000300 mask ffffe0ff"
+do_pedit ip firstfrag set 0xfa
+test_on "key #0 at 4: val 00001a00 mask ffffe0ff"
+do_pedit ip firstfrag preserve
+test_on "key #0 at 4: val 00000000 mask ffffffff"
+do_pedit ip firstfrag invert
+test_on "key #0 at 4: val 00001f00 mask ffffffff"
+do_pedit ip firstfrag clear
+test_on "key #0 at 4: val 00000000 mask ffffe0ff"
+do_pedit ip ce set 0x23
+test_on "key #0 at 4: val 00000000 mask ffff7fff"
+do_pedit ip ce set 0x04
+test_on "key #0 at 4: val 00000000 mask ffff7fff"
+do_pedit ip ce set 0xf3
+test_on "key #0 at 4: val 00008000 mask ffff7fff"
+do_pedit ip ce preserve
+test_on "key #0 at 4: val 00000000 mask ffffffff"
+do_pedit ip ce invert
+test_on "key #0 at 4: val 00008000 mask ffffffff"
+do_pedit ip ce clear
+test_on "key #0 at 4: val 00000000 mask ffff7fff"
+do_pedit ip df set 0x23
+test_on "key #0 at 4: val 00000000 mask ffffbfff"
+do_pedit ip df set 0x04
+test_on "key #0 at 4: val 00000000 mask ffffbfff"
+do_pedit ip df set 0xf3
+test_on "key #0 at 4: val 00004000 mask ffffbfff"
+do_pedit ip df preserve
+test_on "key #0 at 4: val 00000000 mask ffffffff"
+do_pedit ip df invert
+test_on "key #0 at 4: val 00004000 mask ffffffff"
+do_pedit ip df clear
+test_on "key #0 at 4: val 00000000 mask ffffbfff"
+do_pedit ip mf set 0x23
+test_on "key #0 at 4: val 00002000 mask ffffdfff"
+do_pedit ip mf set 0x04
+test_on "key #0 at 4: val 00000000 mask ffffdfff"
+do_pedit ip mf set 0xf3
+test_on "key #0 at 4: val 00002000 mask ffffdfff"
+do_pedit ip mf preserve
+test_on "key #0 at 4: val 00000000 mask ffffffff"
+do_pedit ip mf invert
+test_on "key #0 at 4: val 00002000 mask ffffffff"
+do_pedit ip mf clear
+test_on "key #0 at 4: val 00000000 mask ffffdfff"
+do_pedit ip dport set 0x1234
+test_on "key #0 at 20: val 00001234 mask ffff0000"
+do_pedit ip dport preserve
+test_on "key #0 at 20: val 00000000 mask ffffffff"
+do_pedit ip dport invert
+test_on "key #0 at 20: val 0000ffff mask ffffffff"
+do_pedit ip dport clear
+test_on "key #0 at 20: val 00000000 mask ffff0000"
+do_pedit ip sport set 0x1234
+test_on "key #0 at 20: val 12340000 mask 0000ffff"
+do_pedit ip sport preserve
+test_on "key #0 at 20: val 00000000 mask ffffffff"
+do_pedit ip sport invert
+test_on "key #0 at 20: val ffff0000 mask ffffffff"
+do_pedit ip sport clear
+test_on "key #0 at 20: val 00000000 mask 0000ffff"
+do_pedit ip icmp_type set 0x23
+test_on "key #0 at 20: val 23000000 mask 00ffffff"
+do_pedit ip icmp_type preserve
+test_on "key #0 at 20: val 00000000 mask ffffffff"
+do_pedit ip icmp_type invert
+test_on "key #0 at 20: val ff000000 mask ffffffff"
+do_pedit ip icmp_type clear
+test_on "key #0 at 20: val 00000000 mask 00ffffff"
+do_pedit ip icmp_code set 0x23
+test_on "key #0 at 20: val 23000000 mask 00ffffff"
+do_pedit ip icmp_code preserve
+test_on "key #0 at 20: val 00000000 mask ffffffff"
+do_pedit ip icmp_code invert
+test_on "key #0 at 20: val ff000000 mask ffffffff"
+do_pedit ip icmp_code clear
+test_on "key #0 at 20: val 00000000 mask 00ffffff"
diff --git a/testsuite/tests/tc/policer.t b/testsuite/tests/tc/policer.t
new file mode 100755
index 0000000..eaf16ac
--- /dev/null
+++ b/testsuite/tests/tc/policer.t
@@ -0,0 +1,13 @@
+#!/bin/sh
+$TC qdisc del dev $DEV root >/dev/null 2>&1
+$TC qdisc add dev $DEV root handle 10:0 cbq bandwidth 100Mbit avpkt 1400 mpu 64
+$TC class add dev $DEV parent 10:0 classid 10:12 cbq bandwidth 100mbit rate 100mbit allot 1514 prio 3 maxburst 1 avpkt 500 bounded
+$TC filter add dev $DEV parent 10:0 protocol ip prio 10 u32 match ip protocol 1 0xff police rate 2kbit buffer 10k drop flowid 10:12
+$TC qdisc list dev $DEV
+$TC filter list dev $DEV parent 10:0
+$TC qdisc del dev $DEV root
+$TC qdisc list dev $DEV
+$TC qdisc add dev $DEV root handle 10:0 cbq bandwidth 100Mbit avpkt 1400 mpu 64
+$TC class add dev $DEV parent 10:0 classid 10:12 cbq bandwidth 100mbit rate 100mbit allot 1514 prio 3 maxburst 1 avpkt 500 bounded
+$TC filter add dev $DEV parent 10:0 protocol ip prio 10 u32 match ip protocol 1 0xff police rate 2kbit buffer 10k drop flowid 10:12
+$TC qdisc del dev $DEV root
diff --git a/testsuite/tests/tc/vlan.t b/testsuite/tests/tc/vlan.t
new file mode 100755
index 0000000..51529b2
--- /dev/null
+++ b/testsuite/tests/tc/vlan.t
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+. lib/generic.sh
+
+DEV="$(rand_dev)"
+ts_ip "$0" "Add $DEV dummy interface" link add dev $DEV up type dummy
+ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+
+reset_qdisc()
+{
+ ts_tc "$0" "Remove ingress qdisc" qdisc del dev $DEV ingress
+ ts_tc "$0" "Add ingress qdisc" qdisc add dev $DEV ingress
+}
+
+ts_tc "$0" "Add vlan action pop" \
+ filter add dev $DEV ingress matchall action vlan pop
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "vlan"
+test_on "pop"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add vlan action push (default parameters)" \
+ filter add dev $DEV ingress matchall action vlan push id 5
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "vlan"
+test_on "push"
+test_on "id 5"
+test_on "protocol 802.1Q"
+test_on "priority 0"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add vlan action push (explicit parameters)" \
+ filter add dev $DEV ingress matchall \
+ action vlan push id 5 protocol 802.1ad priority 2
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "vlan"
+test_on "push"
+test_on "id 5"
+test_on "protocol 802.1ad"
+test_on "priority 2"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add vlan action modify (default parameters)" \
+ filter add dev $DEV ingress matchall action vlan modify id 5
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "vlan"
+test_on "modify"
+test_on "id 5"
+test_on "protocol 802.1Q"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add vlan action modify (explicit parameters)" \
+ filter add dev $DEV ingress matchall \
+ action vlan modify id 5 protocol 802.1ad priority 2
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "vlan"
+test_on "modify"
+test_on "id 5"
+test_on "protocol 802.1ad"
+test_on "priority 2"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add vlan action pop_eth" \
+ filter add dev $DEV ingress matchall action vlan pop_eth
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "vlan"
+test_on "pop_eth"
+test_on "pipe"
+
+reset_qdisc
+ts_tc "$0" "Add vlan action push_eth" \
+ filter add dev $DEV ingress matchall \
+ action vlan push_eth dst_mac 02:00:00:00:00:02 \
+ src_mac 02:00:00:00:00:01
+ts_tc "$0" "Show ingress filters" filter show dev $DEV ingress
+test_on "vlan"
+test_on "push_eth"
+test_on "dst_mac 02:00:00:00:00:02"
+test_on "src_mac 02:00:00:00:00:01"
+test_on "pipe"
diff --git a/testsuite/tools/Makefile b/testsuite/tools/Makefile
new file mode 100644
index 0000000..e0162cc
--- /dev/null
+++ b/testsuite/tools/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+CFLAGS=
+include ../../config.mk
+
+generate_nlmsg: generate_nlmsg.c ../../lib/libnetlink.a ../../lib/libutil.a
+ $(QUIET_CC)$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) -I../../include -I../../include/uapi -include../../include/uapi/linux/netlink.h -o $@ $^ -lmnl -lcap
+
+clean:
+ rm -f generate_nlmsg
diff --git a/testsuite/tools/generate_nlmsg.c b/testsuite/tools/generate_nlmsg.c
new file mode 100644
index 0000000..fe96f26
--- /dev/null
+++ b/testsuite/tools/generate_nlmsg.c
@@ -0,0 +1,116 @@
+/*
+ * generate_nlmsg.c Testsuite helper generating nlmsg blob
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Phil Sutter <phil@nwl.cc>
+ */
+
+#include <netinet/ether.h>
+#include <libnetlink.h>
+#include <sys/socket.h>
+#include <linux/if.h>
+#include <errno.h>
+#include <stdio.h>
+
+int fill_vf_rate_test(void *buf, size_t buflen)
+{
+ char bcmac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ struct ifla_vf_mac vf_mac = {
+ .mac = { 0x0, 0x26, 0x6c, 0xff, 0xb5, 0xc0 },
+ };
+ struct ifla_vf_link_state vf_link_state = { 0 };
+ struct ifla_vf_tx_rate vf_tx_rate = { 0 };
+ struct ifla_vf_spoofchk vf_spoofchk = {
+ .setting = 1,
+ };
+ struct ifla_vf_vlan vf_vlan = { 0 };
+ struct rtattr *vfinfo_list, *vfinfo;
+ struct nlmsghdr *h = buf;
+ struct ifinfomsg *ifi;
+
+ h->nlmsg_type = RTM_NEWLINK;
+ h->nlmsg_len = NLMSG_LENGTH(sizeof(*ifi));
+
+ ifi = NLMSG_DATA(h);
+ ifi->ifi_type = ARPHRD_ETHER;
+ ifi->ifi_index = 1;
+ ifi->ifi_flags = IFF_RUNNING | IFF_BROADCAST |
+ IFF_MULTICAST | IFF_UP | IFF_LOWER_UP;
+
+#define ASSERT(x) if (x < 0) return -1
+#define ATTR_L(t, v, l) ASSERT(addattr_l(h, buflen, t, v, l))
+#define ATTR_8(t, v) ASSERT(addattr8(h, buflen, t, v))
+#define ATTR_32(t, v) ASSERT(addattr32(h, buflen, t, v))
+#define ATTR_STRZ(t, v) ASSERT(addattrstrz(h, buflen, t, v))
+
+#define NEST(t) addattr_nest(h, buflen, t)
+#define NEST_END(t) addattr_nest_end(h, t)
+
+ ATTR_STRZ(IFLA_IFNAME, "eth0");
+ ATTR_32(IFLA_TXQLEN, 10000);
+ ATTR_8(IFLA_OPERSTATE, 6);
+ ATTR_8(IFLA_LINKMODE, 0);
+ ATTR_32(IFLA_MTU, 9000);
+ ATTR_32(IFLA_GROUP, 0);
+ ATTR_32(IFLA_PROMISCUITY, 0);
+ ATTR_32(IFLA_NUM_TX_QUEUES, 8);
+ ATTR_32(IFLA_NUM_RX_QUEUES, 8);
+ ATTR_8(IFLA_CARRIER, 1);
+ ATTR_STRZ(IFLA_QDISC, "mq");
+ ATTR_L(IFLA_ADDRESS, vf_mac.mac, ETH_ALEN);
+ ATTR_L(IFLA_BROADCAST, bcmac, sizeof(bcmac));
+ ATTR_32(IFLA_NUM_VF, 2);
+
+ vfinfo_list = NEST(IFLA_VFINFO_LIST);
+
+ vfinfo = NEST(IFLA_VF_INFO);
+ ATTR_L(IFLA_VF_MAC, &vf_mac, sizeof(vf_mac));
+ ATTR_L(IFLA_VF_VLAN, &vf_vlan, sizeof(vf_vlan));
+ ATTR_L(IFLA_VF_TX_RATE, &vf_tx_rate, sizeof(vf_tx_rate));
+ ATTR_L(IFLA_VF_SPOOFCHK, &vf_spoofchk, sizeof(vf_spoofchk));
+ ATTR_L(IFLA_VF_LINK_STATE, &vf_link_state, sizeof(vf_link_state));
+ NEST_END(vfinfo);
+
+ vf_mac.vf = vf_vlan.vf = vf_tx_rate.vf = 1;
+ vf_spoofchk.vf = vf_link_state.vf = 1;
+
+ vfinfo = NEST(IFLA_VF_INFO);
+ ATTR_L(IFLA_VF_MAC, &vf_mac, sizeof(vf_mac));
+ ATTR_L(IFLA_VF_VLAN, &vf_vlan, sizeof(vf_vlan));
+ ATTR_L(IFLA_VF_TX_RATE, &vf_tx_rate, sizeof(vf_tx_rate));
+ ATTR_L(IFLA_VF_SPOOFCHK, &vf_spoofchk, sizeof(vf_spoofchk));
+ ATTR_L(IFLA_VF_LINK_STATE, &vf_link_state, sizeof(vf_link_state));
+ NEST_END(vfinfo);
+
+ NEST_END(vfinfo_list);
+
+ return h->nlmsg_len;
+}
+
+int main(void)
+{
+ char buf[16384] = { 0 };
+ int msglen;
+ FILE *fp;
+
+ msglen = fill_vf_rate_test(buf, sizeof(buf));
+ if (msglen < 0) {
+ fprintf(stderr, "fill_vf_rate_test() failed!\n");
+ return 1;
+ }
+ fp = fopen("tests/ip/link/dev_wo_vf_rate.nl", "w");
+ if (!fp) {
+ perror("fopen()");
+ return 1;
+ }
+ if (fwrite(buf, msglen, 1, fp) != 1) {
+ perror("fwrite()");
+ return 1;
+ }
+ fclose(fp);
+ return 0;
+}