The autopkgtests [0][1] are relevant in an upstream context because an Open vSwitch contributor may want to have a quick way of running the upstream system testsuites on recent Debian/Ubuntu releases in an automated and contained manner.
During the Debian/Ubuntu/upstream package source sync work [2], a relatively naive autopkgtest was added. It had been around since Open vSwitch was initially packaged many years ago. Replace the autopkgtest with a test that runs all the upstream system testsuites instead. To run the autopkgtest, take a look at [1] for prerequisites then: ./boot.sh && ./configure && make debian-source autopkgtest \ --test-name kernel \ --env DEB_BUILD_OPTIONS="nocheck parallel=32 nodpdk" \ ../openvswitch_3.1.90-1.dsc \ -- qemu \ --cpus 32 \ --ram-size 8129 \ autopkgtest-mantic-amd64.img 0: https://wiki.debian.org/ContinuousIntegration/autopkgtest 1: https://packaging.ubuntu.com/html/auto-pkg-test.html 2: https://mail.openvswitch.org/pipermail/ovs-dev/2022-July/396219.html Signed-off-by: Frode Nordahl <frode.nord...@canonical.com> --- debian/automake.mk | 26 ++++- debian/rules | 8 ++ debian/tests/afxdp | 1 + debian/tests/afxdp-skip-tests.txt | 2 + debian/tests/control | 38 +++++-- debian/tests/dpdk | 46 +------- debian/tests/kernel | 1 + debian/tests/offloads | 1 + debian/tests/offloads-skip-tests.txt | 2 + debian/tests/openflow.py | 66 ------------ debian/tests/run-tests.sh | 151 +++++++++++++++++++++++++++ debian/tests/system-userspace | 1 + debian/tests/testlist.py | 74 +++++++++++++ debian/tests/vanilla | 29 ----- 14 files changed, 296 insertions(+), 150 deletions(-) create mode 120000 debian/tests/afxdp create mode 100644 debian/tests/afxdp-skip-tests.txt mode change 100755 => 120000 debian/tests/dpdk create mode 120000 debian/tests/kernel create mode 120000 debian/tests/offloads create mode 100644 debian/tests/offloads-skip-tests.txt delete mode 100755 debian/tests/openflow.py create mode 100755 debian/tests/run-tests.sh create mode 120000 debian/tests/system-userspace create mode 100755 debian/tests/testlist.py delete mode 100755 debian/tests/vanilla diff --git a/debian/automake.mk b/debian/automake.mk index 7b2afafae..89341fccc 100644 --- a/debian/automake.mk +++ b/debian/automake.mk @@ -61,10 +61,16 @@ EXTRA_DIST += \ debian/rules \ debian/source/format \ debian/source/lintian-overrides \ + debian/tests/afxdp \ + debian/tests/afxdp-skip-tests.txt \ debian/tests/control \ debian/tests/dpdk \ - debian/tests/openflow.py \ - debian/tests/vanilla \ + debian/tests/kernel \ + debian/tests/offloads \ + debian/tests/offloads-skip-tests.txt \ + debian/tests/run-tests.sh \ + debian/tests/system-userspace \ + debian/tests/testlist.py \ debian/watch check-debian-changelog-version: @@ -113,7 +119,6 @@ CLEANFILES += debian/control debian: debian/copyright debian/control .PHONY: debian - debian-deb: debian @if test X"$(srcdir)" != X"$(top_builddir)"; then \ echo "Debian packages should be built from $(abs_srcdir)/"; \ @@ -130,3 +135,18 @@ else $(AM_V_GEN) DEB_BUILD_OPTIONS="nocheck parallel=`nproc` nodpdk" \ fakeroot debian/rules binary endif + +debian-source: debian + @if test X"$(srcdir)" != X"$(top_builddir)"; then \ + echo "Debian packages should be built from $(abs_srcdir)/"; \ + exit 1; \ + fi + $(MAKE) distclean + $(update_deb_copyright) + $(update_deb_control) + $(AM_V_GEN) fakeroot debian/rules clean + tar -cvzf ../openvswitch_$(PACKAGE_VERSION).orig.tar.gz \ + --exclude .git \ + --transform 's,^\.,openvswitch-$(PACKAGE_VERSION),' \ + . + dpkg-source -b . diff --git a/debian/rules b/debian/rules index 28c249d07..f4c69651e 100755 --- a/debian/rules +++ b/debian/rules @@ -91,6 +91,14 @@ endif execute_before_dh_auto_clean: find . -name "*.pyc" -delete + if [ -f debian/control ]; then \ + cp debian/control debian/control.save; \ + fi + +execute_after_dh_auto_clean: + if [ -f debian/control.save ]; then \ + mv debian/control.save debian/control; \ + fi override_dh_auto_install: dh_auto_install --sourcedirectory=_debian diff --git a/debian/tests/afxdp b/debian/tests/afxdp new file mode 120000 index 000000000..7080a3249 --- /dev/null +++ b/debian/tests/afxdp @@ -0,0 +1 @@ +run-tests.sh \ No newline at end of file diff --git a/debian/tests/afxdp-skip-tests.txt b/debian/tests/afxdp-skip-tests.txt new file mode 100644 index 000000000..9140b2d52 --- /dev/null +++ b/debian/tests/afxdp-skip-tests.txt @@ -0,0 +1,2 @@ +# LP: #2020679 +ICMP from different source related with NAT diff --git a/debian/tests/control b/debian/tests/control index b481ed53c..29a65fb12 100644 --- a/debian/tests/control +++ b/debian/tests/control @@ -1,8 +1,32 @@ -Tests: vanilla dpdk +Tests: afxdp, kernel, offloads, system-userspace Depends: - iperf, - mininet (>= 2.2.0~), - openvswitch-switch, - openvswitch-switch-dpdk [amd64 i386], - openvswitch-testcontroller, -Restrictions: needs-root rw-build-tree isolation-machine + @, + @builddeps@, + conntrack, + net-tools, + netcat-openbsd, + tcpdump, + python3-pyftpdlib, +Restrictions: + allow-stderr, + isolation-machine, + needs-root, + rw-build-tree, + +# The dpdk tests are marked `skippable`, because they have environment specific +# requirements which may or may not be available at runtime (hugepages setup). +Tests: dpdk +Depends: + @, + @builddeps@, + conntrack, + dpdk-dev [amd64 i386 ppc64el arm64 riscv64], + net-tools, + netcat-openbsd, + tcpdump, + python3-pyftpdlib, +Restrictions: + allow-stderr, + isolation-machine, + needs-root, + skippable, diff --git a/debian/tests/dpdk b/debian/tests/dpdk deleted file mode 100755 index 2aabae050..000000000 --- a/debian/tests/dpdk +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -set -e - -if [ ! -x /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk ]; then - echo "DPDK enabled binary not detected - skipping" - exit 0 -fi - -sse3flag=$(sed -n "/^flags.*sse3/p" < /proc/cpuinfo | wc -l) -if [ "${sse3flag}" -eq 0 ]; then - echo "sse3 not available in test environment" - echo "for adt-virt-qemu please consider adding --qemu-options='-cpu qemu64,+ssse3'" - echo "SKIPPING" - exit 0 -fi - -update-alternatives --set ovs-vswitchd \ - /usr/lib/openvswitch-switch-dpdk/ovs-vswitchd-dpdk -service openvswitch-switch restart - -modprobe openvswitch || true - -echo "kernel modules loaded: " -# Check that ovs loaded -lsmod | grep "openvswitch" -echo "OK" - -echo "Checking daemons: " -pgrep ovs-vswitchd -pgrep ovsdb-server -echo "OK" - -echo "stop conflicting openvswitch testcontroller" -systemctl stop openvswitch-testcontroller || true - -if dpkg --compare-versions "$(dpkg-query --showformat '${Version}\n' --show mininet)" ge "2.3.0-1"; then - PYCMD="python3" -else - PYCMD="python2" -fi - -printf "running openflow tests using mininet" -${PYCMD} `dirname $0`/openflow.py 2>&1 -echo "OK" diff --git a/debian/tests/dpdk b/debian/tests/dpdk new file mode 120000 index 000000000..7080a3249 --- /dev/null +++ b/debian/tests/dpdk @@ -0,0 +1 @@ +run-tests.sh \ No newline at end of file diff --git a/debian/tests/kernel b/debian/tests/kernel new file mode 120000 index 000000000..7080a3249 --- /dev/null +++ b/debian/tests/kernel @@ -0,0 +1 @@ +run-tests.sh \ No newline at end of file diff --git a/debian/tests/offloads b/debian/tests/offloads new file mode 120000 index 000000000..7080a3249 --- /dev/null +++ b/debian/tests/offloads @@ -0,0 +1 @@ +run-tests.sh \ No newline at end of file diff --git a/debian/tests/offloads-skip-tests.txt b/debian/tests/offloads-skip-tests.txt new file mode 100644 index 000000000..91a4a5591 --- /dev/null +++ b/debian/tests/offloads-skip-tests.txt @@ -0,0 +1,2 @@ +# LP: #2020677 +check interface meter offloading diff --git a/debian/tests/openflow.py b/debian/tests/openflow.py deleted file mode 100755 index 216b57cf4..000000000 --- a/debian/tests/openflow.py +++ /dev/null @@ -1,66 +0,0 @@ -import unittest -import logging -from mininet.net import Mininet -import mininet.log as log -from mininet.node import OVSController, OVSKernelSwitch - -Switch = OVSKernelSwitch -Controller = OVSController -logging.basicConfig(level=logging.DEBUG) -log.setLogLevel('info') - - -class BasicOpenflowTest(unittest.TestCase): - - def addHost(self, N): - logging.debug("Creating host h%s and add to net.", N) - name = 'h%d' % N - ip = '10.0.0.%d' % N - return self.net.addHost(name, ip=ip) - - def setUp(self): - self.net = Mininet(controller=Controller, switch=Switch) - - logging.info("Creating controllers") - self.net.addController('c1', command='ovs-testcontroller') - - logging.info("Creating switches") - s1 = self.net.addSwitch('s1', protocols="OpenFlow10") - s2 = self.net.addSwitch('s2', protocols="OpenFlow10") - - logging.info("Creating hosts (7 on each switch)") - hosts1 = [self.addHost(n) for n in (1, 2, 3, 4, 5, 6, 7)] - hosts2 = [self.addHost(n) for n in (8, 9, 10, 11, 12, 13, 14)] - - logging.info("Creating links") - for h in hosts1: - self.net.addLink(s1, h) - for h in hosts2: - self.net.addLink(s2, h) - self.net.addLink(s1, s2) - - logging.info("Starting network") - self.net.start() - - def testPingAll(self): - logging.info("Testing network") - packetLoss = self.net.pingAll() - self.assertTrue( - packetLoss == 0, - "Packet loss during ping test %s" % - packetLoss) - - def testIPerfTCP(self): - logging.info("Running TCP performance test") - self.net.iperf() - - def testIPerfUDP(self): - logging.info("Running UDP performance test") - self.net.iperf(l4Type='UDP') - - def tearDown(self): - logging.info("Stopping network") - self.net.stop() - -if __name__ == '__main__': - unittest.main() diff --git a/debian/tests/run-tests.sh b/debian/tests/run-tests.sh new file mode 100755 index 000000000..abc23694f --- /dev/null +++ b/debian/tests/run-tests.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +set -ex + +PROGRAM=`basename $0` +TARGET=check-${PROGRAM} + +# The autopkgtests are run in throwaway environments, let's be good citizens +# regardless, and attempt to clean up any environment modifications. +function cleanup { + rc=$? + + set +e + + # Dump the log to console on error + if [ $rc -ne 0 ]; then + case "${PROGRAM}" in + kernel) + # For historical reasons the log for the system kernel + # datapath testsuite has a deviant name. + logname="kmod" + ;; + *) + logname="${PROGRAM}" + ;; + esac + if [ -f _debian/tests/system-${logname}-testsuite.log ]; then + cat _debian/tests/system-${logname}-testsuite.log + fi + fi + + # The DPDK test requires post-test cleanup steps. + if [ "$PROGRAM" = "dpdk" ]; then + mv /etc/dpdk/dpdk.conf.bak /etc/dpdk/dpdk.conf + systemctl restart dpdk + + if dirs +1 > /dev/null 2>&1; then + popd + umount ${BIND_MOUNT_DIR} + rmdir ${BIND_MOUNT_DIR} + fi + fi + + exit $rc +} +trap cleanup EXIT + +# The DPDK test requires preparing steps. +if [ "$PROGRAM" = "dpdk" ]; then + ARCH=$(dpkg --print-architecture) + echo "Check required features on arch: ${ARCH}" + case "${ARCH}" in + amd64) + # For amd64 the OVS DPDK support works with ssse3 + # https://github.com/openvswitch/ovs/blob/8045c0f8de5192355ca438ed7eef77457c3c1625/acinclude.m4#LL441C52-L441C52 + if ! grep -q '^flags.*sse3' /proc/cpuinfo; then + echo "Missing ssse3 on ${ARCH} - not supported, SKIP test" + exit 77 + fi + ;; + arm64) + if ! grep -q '^Features.*crc32' /proc/cpuinfo; then + echo "Missing crc32 on ${ARCH} - not supported, SKIP test" + exit 77 + fi + ;; + esac + echo "no known missing feature on ${ARCH}, continue test" + + # Allocate hugepages, use 2M pages when possible because of higher + # probability of successful allocation at runtime and smaller test + # footprint in CI virtual machines. + # + # If the tests are to be run on real physical hardware, you may need + # to adjust these variables depending on CPU architecture and topology. + numa_node=$(lscpu | awk '/NUMA node\(s\)/{print$3}') + if [ -z "$numa_node" -o "$numa_node" -eq 0 ]; then + numa_node=1 + fi + DPDK_NR_1G_PAGES=${DPDK_NR_1G_PAGES:-0} + DPDK_NR_2M_PAGES=${DPDK_NR_2M_PAGES:-$((${numa_node} * (2667 + 512) / 2))} + + printf "Determine hugepage allocation for %s NUMA Node(s) on arch: %s" \ + ${numa_node} ${ARCH} + echo "DPDK_NR_2M_PAGES=${DPDK_NR_2M_PAGES}" + echo "DPDK_NR_1G_PAGES=${DPDK_NR_1G_PAGES}" + + mv /etc/dpdk/dpdk.conf /etc/dpdk/dpdk.conf.bak + cat << EOF > /etc/dpdk/dpdk.conf +NR_1G_PAGES=${DPDK_NR_1G_PAGES} +NR_2M_PAGES=${DPDK_NR_2M_PAGES} +DROPCACHE_BEFORE_HP_ALLOC=1 +EOF + systemctl restart dpdk + realhp_2m=$(cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages) + realhp_1g=$(cat /sys/kernel/mm/hugepages/hugepages-1048576kB/nr_hugepages) + if [ "$realhp_2m" != "$DPDK_NR_2M_PAGES" -o \ + "$realhp_1g" != "$DPDK_NR_1G_PAGES" ]; then + echo "Unable to allocate huge pages required for the test, SKIP test" + exit 77 + fi + + # Long log messages from DPDK library overflow and is written as multiple + # lines. This does not play well with the OVS testsuite assertions. Even + # a tmp directory in /tmp will make the paths too long. + # + # Realpaths from build will be embedded in testsuite artifacts, so we do + # this before the build, and use a bind mount to avoid copying data around + # (using a symlink would not be sufficient). + # + # Ensure we use a short path for running the testsuite (LP:# 2019069). + BIND_MOUNT_DIR=$(mktemp -d /XXX) + mount --bind . ${BIND_MOUNT_DIR} + pushd ${BIND_MOUNT_DIR} +fi + +# A built source tree is required in order to make use of the system level +# testsuites. +# +# We build it here instead of using the `build-needed` Restriction field, +# because we need to pass in additional environment variables in order to +# avoid running the build time checks yet another time (they would have just +# run as part of the package under test build process anyway). +export DEB_BUILD_OPTIONS="nocheck $DEB_BUILD_OPTIONS" +debian/rules build + +# Ensure none of the Open vSwitch daemons are running. +systemctl stop \ + openvswitch-ipsec \ + openvswitch-testcontroller \ + ovs-vswitchd \ + ovsdb-server + +# Optionally build list of tests to run, an empty list means run all tests. +TEST_LIST="" +if [ -f debian/tests/${PROGRAM}-skip-tests.txt ]; then + TEST_LIST=$(cat debian/tests/${PROGRAM}-skip-tests.txt | \ + debian/tests/testlist.py - tests/system-${PROGRAM}-testsuite) +fi + +# Run the testsuite. +# +# By not having paths from build directory in AUTOTEST_PATH, apart from +# `tests`, will ensure binaries are executed from system PATH, i.e. from the +# binary package under test, and not the built source tree. +make \ + -C _debian \ + ${TARGET} \ + AUTOTEST_PATH=tests \ + TESTSUITEFLAGS="-j1 ${TEST_LIST}" \ + RECHECK=yes diff --git a/debian/tests/system-userspace b/debian/tests/system-userspace new file mode 120000 index 000000000..7080a3249 --- /dev/null +++ b/debian/tests/system-userspace @@ -0,0 +1 @@ +run-tests.sh \ No newline at end of file diff --git a/debian/tests/testlist.py b/debian/tests/testlist.py new file mode 100755 index 000000000..bc351261a --- /dev/null +++ b/debian/tests/testlist.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 +import enum +import itertools +import os +import sys + + +if len(sys.argv) < 3: + print( + "usage: {} skipdescriptionlist|- testsuite\n" + "\n" + "This program reads two files, a skiplist containing the \n" + "description of tests to skip separated by newline, and a \n" + "generated testsuite script.\n" + "\n" + "From this it produces string with range of tests to execute \n" + "which can be provided to the testsuite script.\n".format(sys.argv[0]), + file=sys.stderr, + ) + sys.exit(os.EX_USAGE) + + +SKIP_TEST_STRINGS = [] +with open(sys.argv[1]) if sys.argv[1] != "-" else sys.stdin as fin: + SKIP_TEST_STRINGS = [ + line.rstrip() for line in fin.readlines() if not line.startswith("#") + ] + + +@enum.unique +class State(enum.Enum): + INIT = enum.auto() + AT_HELP_ALL = enum.auto() + + +SKIP_TESTS = set() +TESTS = set() +with open(sys.argv[2]) as fin: + state = State.INIT + last_test = 0 + for line in fin.readlines(): + if state == State.INIT: + if not line.startswith('at_help_all="'): + continue + else: + state = State.AT_HELP_ALL + data = line.split('"')[1].rstrip().split(";") + elif state == State.AT_HELP_ALL: + if line.startswith('"'): + break + data = line.rstrip().split(";") + test_nr = int(data[0]) + if last_test < test_nr: + last_test = test_nr + for skip_string in SKIP_TEST_STRINGS: + if skip_string in data[2]: + SKIP_TESTS.add(test_nr) + else: + TESTS.add(test_nr) + + +def ranges(testlist): + for a, b in itertools.groupby( + enumerate(list(testlist)), lambda pair: pair[1] - pair[0] + ): + b = list(b) + yield b[0][1], b[-1][1] + + +testranges = [ + "{}-{}".format(testrange[0], testrange[1]) + for testrange in ranges(TESTS - SKIP_TESTS) +] +print(" ".join(testranges)) diff --git a/debian/tests/vanilla b/debian/tests/vanilla deleted file mode 100755 index 80304f4df..000000000 --- a/debian/tests/vanilla +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/sh - -set -e - -echo "Checking service status right after install: " -# for transparency we want to see all status and then fail if one is inactive -systemctl status ovsdb-server.service || true -systemctl status ovs-vswitchd.service || true -systemctl status openvswitch-switch.service || true -systemctl is-active ovs-vswitchd.service ovsdb-server.service openvswitch-switch.service -echo "OK" - -echo "Checking daemon pids to exist: " -pgrep ovs-vswitchd -pgrep ovsdb-server -echo "OK" - -echo "stop conflicting openvswitch testcontroller" -systemctl stop openvswitch-testcontroller || true - -if dpkg --compare-versions "$(dpkg-query --showformat '${Version}\n' --show mininet)" ge "2.3.0-1"; then - PYCMD="python3" -else - PYCMD="python2" -fi - -printf "running openflow tests using mininet" -${PYCMD} `dirname $0`/openflow.py 2>&1 -echo "OK" -- 2.40.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev