As discussed on calls, I've been investigating Avocado as a possible replacement for our hand-rolled shell test framework. This is a third draft proof-of-concept conversion of a few of the tests to the Avocado framework. Specifically, the static checkers, the build tests and the pasta transfer tests are converted. This third version completely avoids the avocado/unittest built in setUp() and tearDown() functions. Instead it uses Python's with statement and context managers. This is more Pythonic, and avoids some really cryptic multiple inheritance confusion when we want to mix and match tests with different environment setups. Promising things: * I remain happy with the speed improvement (under half the time of the equivalent old tests) * The fact that it's no longer dependent on the host network is great * I'm cautiously optimistic about the helper library making it relatively easy to add a bunch more tests with further coverage Concerning things: * Using context managers instead of setUp/tearDown significantly mitigates it, but the OO/jUnit patterns still make things uglier. Changes since RFCv2: * Remove all setUp() and tearDown() implementations * Remove the weird 'subsetup' stuff we were using along with those Changes since RFCv1: * Sweeping rework of the test library * Started using tags to split between the "real" tests (run with "make avocado") and "meta" tests (run with "make avocado-meta"). The latter are tests for the test infrastructure and helpers themselves, rather than testing anything in passt or pasta David Gibson (20): avocado: Make a duplicate copy of testsuite for comparison purposes avocado: Don't double download assets for test/ and oldtest/ avocado: Move static checkers to avocado avocado/tasst: Helper functions for executing commands in different places avocado/tasst: Type checking helpers avocado: Convert build tests to avocado avocado/tasst: Add helpers for running background commands on sites avocado/tasst: Add helper to get network interface names for a site avocado/tasst: Add helpers to run commands with nstool avocado/tasst: Add ifup and network address helpers to Site avocado/tasst: Helper for creating veth devices between namespaces avocado/tasst: Add helper for getting MTU of a network interface avocado/tasst: Add helper to wait for IP address to appear avocado/tasst: Add helpers for getting a site's routes avocado/tasst: Helpers for test transferring data between sites avocado/tasst: IP address allocation helpers avocado/tasst: Helpers for testing NDP behaviour avocado/tasst: Helpers for testing DHCP & DHCPv6 behaviour avocado/tasst: Helpers to construct a simple network environment for tests avocado: Convert basic pasta tests Makefile | 19 + avocado/.gitignore | 1 + avocado/build.py | 81 +++ avocado/pasta.py | 195 ++++++ avocado/static_checkers/clang-tidy.sh | 3 + avocado/static_checkers/cppcheck.sh | 3 + avocado/tasst/__init__.py | 22 + avocado/tasst/address.py | 89 +++ avocado/tasst/dhcp.py | 152 +++++ avocado/tasst/dhcpv6.py | 135 +++++ avocado/tasst/meta/__init__.py | 16 + avocado/tasst/meta/static_ifup.py | 59 ++ avocado/tasst/meta/veth.py | 95 +++ avocado/tasst/ndp.py | 137 +++++ avocado/tasst/nstool.py | 199 +++++++ avocado/tasst/scenario/__init__.py | 11 + avocado/tasst/scenario/simple.py | 98 +++ avocado/tasst/site.py | 226 +++++++ avocado/tasst/transfer.py | 224 +++++++ avocado/tasst/typing.py | 23 + oldtest/.gitignore | 11 + oldtest/Makefile | 119 ++++ oldtest/README.md | 137 +++++ {test => oldtest}/build/all | 0 {test => oldtest}/build/clang_tidy | 0 {test => oldtest}/build/cppcheck | 0 oldtest/ci | 1 + oldtest/demo/passt | 245 ++++++++ oldtest/demo/pasta | 274 +++++++++ oldtest/demo/podman | 819 ++++++++++++++++++++++++++ oldtest/distro/debian | 252 ++++++++ oldtest/distro/fedora | 396 +++++++++++++ oldtest/distro/opensuse | 208 +++++++ oldtest/distro/ubuntu | 216 +++++++ oldtest/env/mate-terminal.profile | 42 ++ oldtest/find-arm64-firmware.sh | 13 + oldtest/lib/context | 130 ++++ oldtest/lib/layout | 259 ++++++++ oldtest/lib/layout_ugly | 113 ++++ oldtest/lib/perf_report | 272 +++++++++ oldtest/lib/setup | 385 ++++++++++++ oldtest/lib/setup_ugly | 58 ++ oldtest/lib/term | 750 +++++++++++++++++++++++ oldtest/lib/test | 398 +++++++++++++ oldtest/lib/util | 133 +++++ oldtest/lib/video | 152 +++++ oldtest/memory/passt | 187 ++++++ oldtest/nstool.c | 565 ++++++++++++++++++ oldtest/passt.mbuto | 83 +++ oldtest/passt.mem.mbuto | 44 ++ oldtest/passt/dhcp | 70 +++ oldtest/passt/ndp | 33 ++ oldtest/passt/shutdown | 19 + oldtest/passt/tcp | 76 +++ oldtest/passt/udp | 46 ++ oldtest/passt_in_ns/icmp | 32 + oldtest/passt_in_ns/shutdown | 19 + oldtest/passt_in_ns/tcp | 256 ++++++++ oldtest/passt_in_ns/udp | 138 +++++ {test => oldtest}/pasta/dhcp | 0 {test => oldtest}/pasta/ndp | 0 {test => oldtest}/pasta/tcp | 0 {test => oldtest}/pasta/udp | 0 oldtest/pasta_options/log_to_file | 93 +++ oldtest/perf/passt_tcp | 215 +++++++ oldtest/perf/passt_udp | 165 ++++++ oldtest/perf/pasta_tcp | 300 ++++++++++ oldtest/perf/pasta_udp | 219 +++++++ oldtest/prepare-distro-img.sh | 18 + oldtest/run | 238 ++++++++ oldtest/run_demo | 1 + oldtest/two_guests/basic | 80 +++ oldtest/valgrind.supp | 9 + test/lib/layout | 31 - test/lib/setup | 47 -- test/run | 14 - 76 files changed, 10077 insertions(+), 92 deletions(-) create mode 100644 avocado/.gitignore create mode 100644 avocado/build.py create mode 100644 avocado/pasta.py create mode 100755 avocado/static_checkers/clang-tidy.sh create mode 100755 avocado/static_checkers/cppcheck.sh create mode 100644 avocado/tasst/__init__.py create mode 100644 avocado/tasst/address.py create mode 100644 avocado/tasst/dhcp.py create mode 100644 avocado/tasst/dhcpv6.py create mode 100644 avocado/tasst/meta/__init__.py create mode 100644 avocado/tasst/meta/static_ifup.py create mode 100644 avocado/tasst/meta/veth.py create mode 100644 avocado/tasst/ndp.py create mode 100644 avocado/tasst/nstool.py create mode 100644 avocado/tasst/scenario/__init__.py create mode 100644 avocado/tasst/scenario/simple.py create mode 100644 avocado/tasst/site.py create mode 100644 avocado/tasst/transfer.py create mode 100644 avocado/tasst/typing.py create mode 100644 oldtest/.gitignore create mode 100644 oldtest/Makefile create mode 100644 oldtest/README.md rename {test => oldtest}/build/all (100%) rename {test => oldtest}/build/clang_tidy (100%) rename {test => oldtest}/build/cppcheck (100%) create mode 120000 oldtest/ci create mode 100644 oldtest/demo/passt create mode 100644 oldtest/demo/pasta create mode 100644 oldtest/demo/podman create mode 100644 oldtest/distro/debian create mode 100644 oldtest/distro/fedora create mode 100644 oldtest/distro/opensuse create mode 100644 oldtest/distro/ubuntu create mode 100644 oldtest/env/mate-terminal.profile create mode 100755 oldtest/find-arm64-firmware.sh create mode 100644 oldtest/lib/context create mode 100644 oldtest/lib/layout create mode 100644 oldtest/lib/layout_ugly create mode 100755 oldtest/lib/perf_report create mode 100755 oldtest/lib/setup create mode 100755 oldtest/lib/setup_ugly create mode 100755 oldtest/lib/term create mode 100755 oldtest/lib/test create mode 100755 oldtest/lib/util create mode 100755 oldtest/lib/video create mode 100644 oldtest/memory/passt create mode 100644 oldtest/nstool.c create mode 100755 oldtest/passt.mbuto create mode 100755 oldtest/passt.mem.mbuto create mode 100644 oldtest/passt/dhcp create mode 100644 oldtest/passt/ndp create mode 100644 oldtest/passt/shutdown create mode 100644 oldtest/passt/tcp create mode 100644 oldtest/passt/udp create mode 100644 oldtest/passt_in_ns/icmp create mode 100644 oldtest/passt_in_ns/shutdown create mode 100644 oldtest/passt_in_ns/tcp create mode 100644 oldtest/passt_in_ns/udp rename {test => oldtest}/pasta/dhcp (100%) rename {test => oldtest}/pasta/ndp (100%) rename {test => oldtest}/pasta/tcp (100%) rename {test => oldtest}/pasta/udp (100%) create mode 100644 oldtest/pasta_options/log_to_file create mode 100644 oldtest/perf/passt_tcp create mode 100644 oldtest/perf/passt_udp create mode 100644 oldtest/perf/pasta_tcp create mode 100644 oldtest/perf/pasta_udp create mode 100755 oldtest/prepare-distro-img.sh create mode 100755 oldtest/run create mode 120000 oldtest/run_demo create mode 100644 oldtest/two_guests/basic create mode 100644 oldtest/valgrind.supp -- 2.40.1
oldtest/ is a snapshot of test/ for comparison purposes. However this means its Makefile will make an additional download of everything we download in test/, which takes rather a lot of space. Alter oldtest/Makefile to re-use the downloads from test/ via symlinks. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- oldtest/.gitignore | 2 +- oldtest/Makefile | 94 +++------------------------------------------- 2 files changed, 6 insertions(+), 90 deletions(-) diff --git a/oldtest/.gitignore b/oldtest/.gitignore index 4837402..2652ce7 100644 --- a/oldtest/.gitignore +++ b/oldtest/.gitignore @@ -1,5 +1,5 @@ test_logs/ -mbuto/ +mbuto *.img QEMU_EFI.fd *.qcow2 diff --git a/oldtest/Makefile b/oldtest/Makefile index 7b00bef..7949ced 100644 --- a/oldtest/Makefile +++ b/oldtest/Makefile @@ -67,9 +67,6 @@ CFLAGS = -Wall -Werror -Wextra -pedantic -std=c99 assets: $(ASSETS) -mbuto: - git clone git://mbuto.sh/mbuto - guest-key guest-key.pub: ssh-keygen -f guest-key -N '' @@ -113,91 +110,10 @@ clean: rm -f $(LOCAL_ASSETS) rm -rf test_logs rm -f prepared-*.qcow2 prepared-*.img - -realclean: clean rm -rf $(DOWNLOAD_ASSETS) -# Debian downloads -debian-8.11.0-openstack-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/OpenStack/archive/8.11.0/debian-8.11.… - -debian-9-nocloud-%-daily-20200210-166.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/stretch/daily/20200210-166/debian-9-n… - -debian-10-nocloud-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-nocloud-$*.qc… - -debian-10-generic-ppc64el-20220911-1135.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/20220911-1135/debian-10-generi… - -debian-10-generic-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-generic-$*.qc… - -debian-11-nocloud-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-nocloud-$*.… - -debian-11-generic-%.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-$*.… - -debian-sid-nocloud-%-daily.qcow2: - $(WGET) -O $@ https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-nocloud-$… - -# Fedora downloads -Fedora-Cloud-Base-26-1.5.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/26/Clou… - -Fedora-Cloud-Base-27-1.6.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/27/Clou… - -Fedora-Cloud-Base-28-1.1.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/28/Clou… - -Fedora-Cloud-Base-29-1.2.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/29/Clou… - -Fedora-Cloud-Base-30-1.2.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/30/Clou… - -Fedora-Cloud-Base-31-1.9.%.qcow2: - $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/31/Clou… - -Fedora-Cloud-Base-32-1.6.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/32/Clo… - -Fedora-Cloud-Base-33-1.2.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/33/Clo… - -Fedora-Cloud-Base-34-1.2.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Clo… - -Fedora-Cloud-Base-35-1.2.%.qcow2: - $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/35/Clo… - -# OpenSuSE downloads -openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2: - $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.1/jeos/openSUSE-Leap-15.… - -openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2: - $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.2/appliances/openSUSE-Le… - -openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2: - $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.3/appliances/openSUSE-Le… - -openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz: - $(WGET) -O $@ http://download.opensuse.org/ports/aarch64/tumbleweed/appliances/openSUSE-T… - -openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz: - $(WGET) -O $@ http://download.opensuse.org/ports/armv7hl/tumbleweed/appliances/openSUSE-T… - -openSUSE-Tumbleweed-JeOS.x86_64-kvm-and-xen.qcow2: - $(WGET) -O $@ https://download.opensuse.org/tumbleweed/appliances/openSUSE-Tumbleweed-JeO… - -# Ubuntu downloads -trusty-server-cloudimg-%-disk1.img: - $(WGET) -O $@ https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-$*-di… - -xenial-server-cloudimg-powerpc-disk1.img: - $(WGET) -O $@ https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-power… - -jammy-server-cloudimg-s390x.img: - $(WGET) -O $@ https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-s390x.i… +# "Downloads" +$(DOWNLOAD_ASSETS): %: +#debian-%.qcow2 Fedora-%.qcow2 openSUSE-%.qcow2 openSUSE-%.raw.xz trusty-%.img xenial-%.img jammy-%.img: + $(MAKE) -C ../test $@ + ln -s ../test/$@ $@ -- 2.40.1
Move these, the simplest of our tests, to be run from avocado rather than our hand-rolled test harness. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- Makefile | 9 +++++++++ avocado/static_checkers/clang-tidy.sh | 3 +++ avocado/static_checkers/cppcheck.sh | 3 +++ oldtest/run | 4 ++-- test/build/clang_tidy | 17 ----------------- test/build/cppcheck | 17 ----------------- test/run | 2 -- 7 files changed, 17 insertions(+), 38 deletions(-) create mode 100755 avocado/static_checkers/clang-tidy.sh create mode 100755 avocado/static_checkers/cppcheck.sh delete mode 100644 test/build/clang_tidy delete mode 100644 test/build/cppcheck diff --git a/Makefile b/Makefile index a5256f5..d2daaa1 100644 --- a/Makefile +++ b/Makefile @@ -294,3 +294,12 @@ cppcheck: $(SRCS) $(HEADERS) --suppress=unusedStructMember \ $(filter -D%,$(FLAGS) $(CFLAGS) $(CPPFLAGS)) \ . + +AVOCADO = avocado + +.PHONY: avocado +avocado: + $(AVOCADO) run avocado + +check: avocado + $(MAKE) -C test check diff --git a/avocado/static_checkers/clang-tidy.sh b/avocado/static_checkers/clang-tidy.sh new file mode 100755 index 0000000..67bcf27 --- /dev/null +++ b/avocado/static_checkers/clang-tidy.sh @@ -0,0 +1,3 @@ +#! /bin/sh + +make clang-tidy diff --git a/avocado/static_checkers/cppcheck.sh b/avocado/static_checkers/cppcheck.sh new file mode 100755 index 0000000..2c6d396 --- /dev/null +++ b/avocado/static_checkers/cppcheck.sh @@ -0,0 +1,3 @@ +#! /bin/sh + +make cppcheck diff --git a/oldtest/run b/oldtest/run index 75309f6..56fcd1b 100755 --- a/oldtest/run +++ b/oldtest/run @@ -66,8 +66,8 @@ run() { setup build # test build/all -# test build/cppcheck -# test build/clang_tidy + test build/cppcheck + test build/clang_tidy teardown build # setup pasta diff --git a/test/build/clang_tidy b/test/build/clang_tidy deleted file mode 100644 index 40573bf..0000000 --- a/test/build/clang_tidy +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/build/clang_tidy - Run source through clang-tidy(1) linter -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio(a)redhat.com> - -htools clang-tidy - -test Run clang-tidy -host make clang-tidy diff --git a/test/build/cppcheck b/test/build/cppcheck deleted file mode 100644 index 0e1dbce..0000000 --- a/test/build/cppcheck +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/build/cppcheck - Run source through cppcheck(1) linter -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio(a)redhat.com> - -htools cppcheck - -test Run cppcheck -host make cppcheck diff --git a/test/run b/test/run index 8f4f845..ce24f44 100755 --- a/test/run +++ b/test/run @@ -66,8 +66,6 @@ run() { setup build test build/all - test build/cppcheck - test build/clang_tidy teardown build setup pasta -- 2.40.1
Add a library "tasst" for use in avocado tests of passt & pasta. We start by adding the outline of logic to run commands in various places (e.g. namespaces, VMs). We add some avocado tests for the test library itself, tagged 'meta' to distinguish it from tests for passt/pasta proper. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- Makefile | 11 +++- avocado/.gitignore | 1 + avocado/tasst/__init__.py | 17 ++++++ avocado/tasst/site.py | 106 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 avocado/.gitignore create mode 100644 avocado/tasst/__init__.py create mode 100644 avocado/tasst/site.py diff --git a/Makefile b/Makefile index d2daaa1..fc83cd2 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,7 @@ clean: $(RM) $(BIN) *~ *.o seccomp.h pasta.1 \ passt.tar passt.tar.gz *.deb *.rpm \ passt.pid README.plain.md + $(RM) -r avocado/__pycache__ install: $(BIN) $(MANPAGES) docs mkdir -p $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir) @@ -297,9 +298,15 @@ cppcheck: $(SRCS) $(HEADERS) AVOCADO = avocado +avocado-%: + PYTHONPATH=./avocado $(AVOCADO) run avocado --filter-by-tags=$* + +avocado-all: + PYTHONPATH=./avocado $(AVOCADO) run avocado + +# Default avocado tests to run, everything except the "meta" tests .PHONY: avocado -avocado: - $(AVOCADO) run avocado +avocado: avocado--meta check: avocado $(MAKE) -C test check diff --git a/avocado/.gitignore b/avocado/.gitignore new file mode 100644 index 0000000..c18dd8d --- /dev/null +++ b/avocado/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/avocado/tasst/__init__.py b/avocado/tasst/__init__.py new file mode 100644 index 0000000..3bbde84 --- /dev/null +++ b/avocado/tasst/__init__.py @@ -0,0 +1,17 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import avocado + + +# Base class for avocado-based passt/pasta tests +class Tasst(avocado.Test): + # Fairly short default timeout + timeout = 10.0 diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py new file mode 100644 index 0000000..415a953 --- /dev/null +++ b/avocado/tasst/site.py @@ -0,0 +1,106 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/site.py - Manage simulated network sites for testing +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib + +import avocado +from avocado.utils.process import CmdError + +from tasst import Tasst + + +class Site(contextlib.AbstractContextManager): + """ + A (usually virtual or simulated) location where we can execute + commands and configure networks. + + """ + + def __init__(self, name): + self.name = name # For debugging + + def __enter__(self): + raise NotImplementedError + + def __exit__(self, *exc_details): + raise NotImplementedError + + def output(self, cmd, **kwargs): + raise NotImplementedError + + def fg(self, cmd, **kwargs): + self.output(cmd, **kwargs) + + def require_cmds(self, *cmds): + missing = [c for c in cmds + if self.fg('type {}'.format(c), ignore_status=True) != 0] + if missing: + raise avocado.TestCancel("Missing commands {} on {}" + .format(', '.join(missing), self.name)) + + +class SiteTasst(Tasst): + """ + Basic tests for executing commands on sites + + :avocado: disable + :avocado: tags=meta + """ + timeout = 1.0 + + # Derived classes must redefine this + def setup_site(self): + raise NotImplementedError("{} must implement setup_site() method".format(type(self).__name__)) + + def test_true(self): + with self.setup_site() as site: + site.fg('true') + + def test_false(self): + with self.setup_site() as site: + self.assertRaises(CmdError, site.fg, 'false') + + def test_echo(self): + with self.setup_site() as site: + s = 'Hello tasst' + out = site.output('echo {}'.format(s)) + self.assertEquals(out, s.encode('utf-8')) + + +# Represents the host on which the tests are running, as opposed to +# some simulated host created by the tests +class RealHost(Site): + def __init__(self): + super().__init__('REAL_HOST') + + def __enter__(self): + return self + + def __exit__(self, *exc_details): + pass + + def output(self, cmd, sudo=False, **kwargs): + assert not sudo, "BUG: Shouldn't run commands with privilege on host" + return avocado.utils.process.system_output(cmd, **kwargs) + + def fg(self, cmd, sudo=False, **kwargs): + assert not sudo, "BUG: Shouldn't run commands with privilege on host" + return avocado.utils.process.system(cmd, **kwargs) + + +REAL_HOST = RealHost() + + +class RealHostTasst(SiteTasst): + def setup_site(self): + return REAL_HOST + -- 2.40.1
Add some helper functions for typechecking parameters. We will be using these so that accidentally misusing some of the upcoming test helpers will result in more useful error messages. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/typing.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 avocado/tasst/typing.py diff --git a/avocado/tasst/typing.py b/avocado/tasst/typing.py new file mode 100644 index 0000000..2021b0b --- /dev/null +++ b/avocado/tasst/typing.py @@ -0,0 +1,23 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/typing.py - Type checking and related helpers +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + + +def typecheck(val, ty_): + if not isinstance(val, ty_): + raise TypeError("Expected {} instead of {}".format(ty_, type(val))) + return val + + +def typecheck_default(val, ty_, default): + if val is None: + return default + return typecheck(val, ty_) -- 2.40.1
Move the build and make install tests from the old hand-rolled test harness to avocado. The avocado versions are safer, in that they make a private copy of the sources before building, so they won't interfere with concurrent tests or builds in the original source tree. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> # Conflicts: # avocado/tasst/site.py --- avocado/build.py | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ oldtest/run | 2 +- test/build/all | 61 ------------------------------------ test/lib/setup | 7 ----- test/run | 4 --- 5 files changed, 82 insertions(+), 73 deletions(-) create mode 100644 avocado/build.py delete mode 100644 test/build/all diff --git a/avocado/build.py b/avocado/build.py new file mode 100644 index 0000000..5efbc88 --- /dev/null +++ b/avocado/build.py @@ -0,0 +1,81 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# avocado/build.py - Test various make targets +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import os +import os.path +import shutil +import sys +import tempfile + +import tasst +from tasst.site import CmdError, REAL_HOST + + +(a)contextlib.contextmanager +def clone_source_tree(where): + REAL_HOST.require_cmds('git', 'make') + + with tempfile.TemporaryDirectory(dir=where, ignore_cleanup_errors=False) as tmpdir: + # Make a temporary copy of the sources + srcfiles = REAL_HOST.output('git ls-files').decode('utf-8').splitlines() + for src in srcfiles: + dst = os.path.join(tmpdir, src) + os.makedirs(os.path.dirname(dst), exist_ok=True) + shutil.copy(src, dst) + os.chdir(tmpdir) + yield tmpdir + + +class BuildTasst(tasst.Tasst): + # Some of these can take a little while + timeout = 60.0 + + def build_target(self, target, outputs): + with clone_source_tree(self.workdir): + self.assertFalse(any(os.path.exists(o) for o in outputs)) + REAL_HOST.fg('make {} CFLAGS="-Werror"'.format(target)) + self.assertTrue(all(os.path.exists(o) for o in outputs)) + REAL_HOST.fg('make clean') + self.assertFalse(any(os.path.exists(o) for o in outputs)) + + def test_make_passt(self): + self.build_target('passt', ['passt']) + + def test_make_pasta(self): + self.build_target('pasta', ['pasta']) + + def test_make_qrap(self): + self.build_target('qrap', ['qrap']) + + def test_make_all(self): + self.build_target('all', ['passt', 'pasta', 'qrap']) + + def test_make_install_uninstall(self): + with clone_source_tree(self.workdir): + with tempfile.TemporaryDirectory(dir=self.workdir, + ignore_cleanup_errors=False) as prefix: + bindir = os.path.join(prefix, 'bin') + mandir = os.path.join(prefix, 'share', 'man') + exes = ['passt', 'pasta', 'qrap'] + + # Install + REAL_HOST.fg('make install CFLAGS="-Werror" prefix={}'.format(prefix)) + + for t in exes: + self.assertTrue(os.path.isfile(os.path.join(bindir, t))) + REAL_HOST.fg('man -M {} -W passt'.format(mandir)) + + # Uninstall + REAL_HOST.fg('make uninstall prefix={}'.format(prefix)) + + for t in exes: + self.assertFalse(os.path.exists(os.path.join(bindir, t))) + self.assertRaises(CmdError, REAL_HOST.fg, + 'man -M {} -W passt'.format(mandir)) diff --git a/oldtest/run b/oldtest/run index 56fcd1b..a16bc49 100755 --- a/oldtest/run +++ b/oldtest/run @@ -65,7 +65,7 @@ run() { [ ${CI} -eq 1 ] && video_start ci setup build -# test build/all + test build/all test build/cppcheck test build/clang_tidy teardown build diff --git a/test/build/all b/test/build/all deleted file mode 100644 index 1f79e0d..0000000 --- a/test/build/all +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/build/all - Build targets, one by one, then all together, check output -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio(a)redhat.com> - -htools make cc rm uname getconf mkdir cp rm man - -test Build passt -host make clean -check ! [ -e passt ] -host CFLAGS="-Werror" make passt -check [ -f passt ] - -test Build pasta -host make clean -check ! [ -e pasta ] -host CFLAGS="-Werror" make pasta -check [ -h pasta ] - -test Build qrap -host make clean -check ! [ -e qrap ] -host CFLAGS="-Werror" make qrap -check [ -f qrap ] - -test Build all -host make clean -check ! [ -e passt ] -check ! [ -e pasta ] -check ! [ -e qrap ] -host CFLAGS="-Werror" make -check [ -f passt ] -check [ -h pasta ] -check [ -f qrap ] - -test Install -host mkdir __STATEDIR__/prefix -host prefix=__STATEDIR__/prefix make install -check [ -f __STATEDIR__/prefix/bin/passt ] -check [ -h __STATEDIR__/prefix/bin/pasta ] -check [ -f __STATEDIR__/prefix/bin/qrap ] -check man -M __STATEDIR__/prefix/share/man -W passt -check man -M __STATEDIR__/prefix/share/man -W pasta -check man -M __STATEDIR__/prefix/share/man -W qrap - -test Uninstall -host prefix=__STATEDIR__/prefix make uninstall -check ! [ -f __STATEDIR__/prefix/bin/passt ] -check ! [ -h __STATEDIR__/prefix/bin/pasta ] -check ! [ -f __STATEDIR__/prefix/bin/qrap ] -check ! man -M __STATEDIR__/prefix/share/man -W passt 2>/dev/null -check ! man -M __STATEDIR__/prefix/share/man -W pasta 2>/dev/null -check ! man -M __STATEDIR__/prefix/share/man -W qrap 2>/dev/null diff --git a/test/lib/setup b/test/lib/setup index 9b39b9f..5386805 100755 --- a/test/lib/setup +++ b/test/lib/setup @@ -18,13 +18,6 @@ VCPUS="$( [ $(nproc) -ge 8 ] && echo 6 || echo $(( $(nproc) / 2 + 1 )) )" __mem_kib="$(sed -n 's/MemTotal:[ ]*\([0-9]*\) kB/\1/p' /proc/meminfo)" VMEM="$((${__mem_kib} / 1024 / 4))" -# setup_build() - Set up pane layout for build tests -setup_build() { - context_setup_host host - - layout_host -} - # setup_passt() - Start qemu and passt setup_passt() { context_setup_host host diff --git a/test/run b/test/run index ce24f44..b800022 100755 --- a/test/run +++ b/test/run @@ -64,10 +64,6 @@ run() { perf_init [ ${CI} -eq 1 ] && video_start ci - setup build - test build/all - teardown build - setup pasta test pasta/ndp test pasta/dhcp -- 2.40.1
Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/site.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index 415a953..6aa83c4 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -40,6 +40,9 @@ class Site(contextlib.AbstractContextManager): def fg(self, cmd, **kwargs): self.output(cmd, **kwargs) + def bg(self, cmd, **kwargs): + raise NotImplementedError + def require_cmds(self, *cmds): missing = [c for c in cmds if self.fg('type {}'.format(c), ignore_status=True) != 0] @@ -75,6 +78,18 @@ class SiteTasst(Tasst): out = site.output('echo {}'.format(s)) self.assertEquals(out, s.encode('utf-8')) + def test_bg_true(self): + with self.setup_site() as site: + with site.bg('true') as proc: + status = proc.wait() + self.assertEquals(status, 0) + + def test_bg_false(self): + with self.setup_site() as site: + with site.bg('false') as proc: + status = proc.wait() + self.assertNotEquals(status, 0) + # Represents the host on which the tests are running, as opposed to # some simulated host created by the tests @@ -96,6 +111,16 @@ class RealHost(Site): assert not sudo, "BUG: Shouldn't run commands with privilege on host" return avocado.utils.process.system(cmd, **kwargs) + @contextlib.contextmanager + def bg(self, cmd, sudo=False, **kwargs): + assert not sudo, "BUG: Shouldn't run commands with privilege on host" + try: + proc = avocado.utils.process.SubProcess(cmd, **kwargs) + proc.start() + yield proc + finally: + proc.stop() + REAL_HOST = RealHost() -- 2.40.1
Start adding convenience functions for handling sites as places with network setup with a simple helper which lists the network interface names for a site. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/site.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index 6aa83c4..6450944 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -11,6 +11,7 @@ # Author: David Gibson <david(a)gibson.dropbear.id.au> import contextlib +import json import avocado from avocado.utils.process import CmdError @@ -50,6 +51,11 @@ class Site(contextlib.AbstractContextManager): raise avocado.TestCancel("Missing commands {} on {}" .format(', '.join(missing), self.name)) + def ifs(self): + self.require_cmds('ip') + info = json.loads(self.output('ip -j link show')) + return [i['ifname'] for i in info] + class SiteTasst(Tasst): """ @@ -90,6 +96,10 @@ class SiteTasst(Tasst): status = proc.wait() self.assertNotEquals(status, 0) + def test_has_lo(self): + with self.setup_site() as site: + self.assertIn('lo', site.ifs()) + # Represents the host on which the tests are running, as opposed to # some simulated host created by the tests -- 2.40.1
Use our existing nstool C helper, add python wrappers to easily run commands in various namespaces. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- Makefile | 7 +- avocado/tasst/nstool.py | 182 ++++++++++++++++++++++++++++++++++++++++ avocado/tasst/site.py | 16 +++- 3 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 avocado/tasst/nstool.py diff --git a/Makefile b/Makefile index fc83cd2..9add0a4 100644 --- a/Makefile +++ b/Makefile @@ -298,10 +298,13 @@ cppcheck: $(SRCS) $(HEADERS) AVOCADO = avocado -avocado-%: +avocado-assets: + $(MAKE) -C test nstool + +avocado-%: avocado-assets PYTHONPATH=./avocado $(AVOCADO) run avocado --filter-by-tags=$* -avocado-all: +avocado-all: avocado-assets PYTHONPATH=./avocado $(AVOCADO) run avocado # Default avocado tests to run, everything except the "meta" tests diff --git a/avocado/tasst/nstool.py b/avocado/tasst/nstool.py new file mode 100644 index 0000000..020e8a0 --- /dev/null +++ b/avocado/tasst/nstool.py @@ -0,0 +1,182 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/nstool.py - Run commands in namespaces via 'nstool' +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import os +import sys +import tempfile + +import avocado +from avocado.utils.process import CmdError + +from tasst import Tasst +from tasst.site import IsolatedSiteTasst, SiteTasst, Site, REAL_HOST +from tasst.typing import typecheck + +# FIXME: Can this be made more portable? +UNIX_PATH_MAX = 108 + + +class NsToolSite(Site): + NST_BIN = './test/nstool' + + def __init__(self, name, sockpath): + if len(sockpath) > UNIX_PATH_MAX: + raise ValueError('Unix domain socket path \"{}\" is too long'.format(sockpath)) + + super().__init__(name) + self.sockpath = sockpath + + def __enter__(self): + self._pid = int(REAL_HOST.output('{} info -wp {}'.format(self.NST_BIN, self.sockpath), timeout=1)) + return self + + def __exit__(self, *exc_details): + pass + + # PID of the nstool hold process as seen by the test host + def pid(self): + return self._pid + + # PID of the nstool hold process as seen by another site + # (important when using PID namespaces) + def relative_pid(self, relative_to): + cmd = '{} info -p {}'.format(self.NST_BIN, self.sockpath) + return int(relative_to.output(cmd)) + + def _nst_cmd(self, cmd, sudo=False): + nst_args = self.sockpath + if sudo: + nst_args = '--keep-caps ' + nst_args + return '{} exec {} -- {}'.format(self.NST_BIN, nst_args, cmd) + + def output(self, cmd, sudo=False, **kwargs): + return REAL_HOST.output(self._nst_cmd(cmd, sudo), **kwargs) + + def fg(self, cmd, sudo=False, **kwargs): + return REAL_HOST.fg(self._nst_cmd(cmd, sudo), **kwargs) + + def bg(self, cmd, sudo=False, **kwargs): + return REAL_HOST.bg(self._nst_cmd(cmd, sudo), **kwargs) + + +# Create path for temporary nstool Unix socket +# +# The obvious choice would be to use Avocado's workdir, but that often +# gives paths that are too long for Unix sockets +def temp_sockpath(name): + tmpd = tempfile.mkdtemp(suffix=name) + return os.path.join(tmpd, 's') + + +class UnshareSite(NsToolSite): + def __init__(self, name, unshare_opts, parent=REAL_HOST, sudo=False): + sockpath = temp_sockpath(name) + parent.require_cmds('unshare', self.NST_BIN) + + super().__init__(name, sockpath) + + self.parent = typecheck(parent, Site) + self.holdcmd = 'unshare {} -- {} hold {}'.format(unshare_opts, + self.NST_BIN, sockpath) + self.sudo = typecheck(sudo, bool) + + def __enter__(self): + self.holder = self.parent.bg(self.holdcmd, sudo=self.sudo) + self.holder.__enter__() + return super().__enter__() + + def __exit__(self, *exc_details): + super().__exit__(*exc_details) + + try: + self.parent.fg('{} stop {}'.format(self.NST_BIN, self.sockpath)) + finally: + self.holder.__exit__(*exc_details) + + try: + os.remove(self.sockpath) + except FileNotFoundError: + pass + + os.rmdir(os.path.dirname(self.sockpath)) + + +class UserNetNsTasst(IsolatedSiteTasst): + """ + Test creating a userns+netns together + + :avocado: tags=meta + """ + + def setup_site(self): + return UnshareSite(type(self).__name__, '-Ucn') + + def test_userns(self): + REAL_HOST.require_cmds('capsh') + with self.setup_site() as ns: + ns.require_cmds('capsh') + capcmd = 'capsh --has-p=CAP_SETUID' + self.assertRaises(CmdError, REAL_HOST.fg, capcmd) + ns.fg(capcmd, sudo=True) + + +class NestedNsTasst(IsolatedSiteTasst): + """ + Test creating userns with a netns nested within + + :avocado: tags=meta + """ + + @contextlib.contextmanager + def setup_site(self): + name = type(self).__name__ + with UnshareSite(name + '.userns', '-Uc') as userns: + with UnshareSite(name + '.netns', '-n', parent=userns, sudo=True) as netns: + yield netns + + +class PidNsTasst(IsolatedSiteTasst): + """ + Test unsing unshare -p to create a pidns + + :avocado: tags=meta + """ + + def setup_site(self): + return UnshareSite(type(self).__name__, '-Upfn') + + def test_relative_pid(self): + with self.setup_site() as site: + # The holder is init (pid 1) within its own pidns + self.assertEquals(site.relative_pid(site), 1) + + +class ConnectNsToolTasst(SiteTasst): + """ + Test connecting to a pre-existing nstool + + :avocado: tags=meta + """ + + @contextlib.contextmanager + def setup_site(self): + sockpath = temp_sockpath(type(self).__name__) + holdcmd = '{} hold {}'.format(NsToolSite.NST_BIN, sockpath) + with REAL_HOST.bg(holdcmd) as holder: + with NsToolSite("fake ns", sockpath) as site: + yield site + + try: + os.remove(sockpath) + finally: + os.rmdir(os.path.dirname(sockpath)) diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index 6450944..900e945 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -101,6 +101,19 @@ class SiteTasst(Tasst): self.assertIn('lo', site.ifs()) +class IsolatedSiteTasst(SiteTasst): + """ + Test a site with isolated network (loopback only) + + :avocado: disable + :avocado: tags=meta + """ + + def test_isolated_net(self): + with self.setup_site() as site: + self.assertEquals(site.ifs(), ['lo']) + + # Represents the host on which the tests are running, as opposed to # some simulated host created by the tests class RealHost(Site): @@ -129,7 +142,8 @@ class RealHost(Site): proc.start() yield proc finally: - proc.stop() + if proc.poll() is None: + proc.stop() REAL_HOST = RealHost() -- 2.40.1
Add a helper to bring network interfaces up on a site, and to retrieve configured IP addresses. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/nstool.py | 11 +++++++++-- avocado/tasst/site.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/avocado/tasst/nstool.py b/avocado/tasst/nstool.py index 020e8a0..50598a5 100644 --- a/avocado/tasst/nstool.py +++ b/avocado/tasst/nstool.py @@ -118,8 +118,11 @@ class UserNetNsTasst(IsolatedSiteTasst): :avocado: tags=meta """ + @contextlib.contextmanager def setup_site(self): - return UnshareSite(type(self).__name__, '-Ucn') + with UnshareSite(type(self).__name__, '-Ucn') as ns: + ns.ifup('lo') + yield ns def test_userns(self): REAL_HOST.require_cmds('capsh') @@ -142,6 +145,7 @@ class NestedNsTasst(IsolatedSiteTasst): name = type(self).__name__ with UnshareSite(name + '.userns', '-Uc') as userns: with UnshareSite(name + '.netns', '-n', parent=userns, sudo=True) as netns: + netns.ifup('lo') yield netns @@ -152,8 +156,11 @@ class PidNsTasst(IsolatedSiteTasst): :avocado: tags=meta """ + @contextlib.contextmanager def setup_site(self): - return UnshareSite(type(self).__name__, '-Upfn') + with UnshareSite(type(self).__name__, '-Upfn') as ns: + ns.ifup('lo') + yield ns def test_relative_pid(self): with self.setup_site() as site: diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index 900e945..3cb3721 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -11,6 +11,7 @@ # Author: David Gibson <david(a)gibson.dropbear.id.au> import contextlib +import ipaddress import json import avocado @@ -56,6 +57,28 @@ class Site(contextlib.AbstractContextManager): info = json.loads(self.output('ip -j link show')) return [i['ifname'] for i in info] + def ifup(self, ifname): + self.require_cmds('ip') + self.fg('ip link set {} up'.format(ifname), sudo=True) + + def addrinfos(self, ifname, **filter): + self.require_cmds('ip') + info = json.loads(self.output('ip -j addr show {}'.format(ifname))) + assert len(info) == 1 # We specified a specific interface + + ais = [ai for ai in info[0]['addr_info']] + for key, value in filter.items(): + ais = [ai for ai in ais if key in ai and ai[key] == value] + + return ais + + def addrs(self, ifname, **filter): + self.require_cmds('ip') + # Return just the parsed, non-tentative addresses + return [ipaddress.ip_interface('{}/{}'.format(ai['local'], ai['prefixlen'])) + for ai in self.addrinfos(ifname, **filter) + if not 'tentative' in ai] + class SiteTasst(Tasst): """ @@ -100,6 +123,12 @@ class SiteTasst(Tasst): with self.setup_site() as site: self.assertIn('lo', site.ifs()) + def test_lo_addrs(self): + with self.setup_site() as site: + expected = [ipaddress.ip_interface(a) + for a in ['127.0.0.1/8', '::1/128']] + self.assertCountEqual(site.addrs('lo'), expected) + class IsolatedSiteTasst(SiteTasst): """ -- 2.40.1
Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/meta/__init__.py | 16 +++++++++++++ avocado/tasst/meta/veth.py | 43 ++++++++++++++++++++++++++++++++++ avocado/tasst/nstool.py | 10 ++++++++ 3 files changed, 69 insertions(+) create mode 100644 avocado/tasst/meta/__init__.py create mode 100644 avocado/tasst/meta/veth.py diff --git a/avocado/tasst/meta/__init__.py b/avocado/tasst/meta/__init__.py new file mode 100644 index 0000000..6582554 --- /dev/null +++ b/avocado/tasst/meta/__init__.py @@ -0,0 +1,16 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/meta - Test pieces of the test infrastructure. +# +# Usually, tests for the test infrastructure should go next to the +# implementation of the thing being tested. Sometimes that's not +# possible (usually because it would cause a circular module +# dependency). In that case those tests can go here. +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> diff --git a/avocado/tasst/meta/veth.py b/avocado/tasst/meta/veth.py new file mode 100644 index 0000000..c4cdcf7 --- /dev/null +++ b/avocado/tasst/meta/veth.py @@ -0,0 +1,43 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/metatest/veth - Test the veth creation helper +# +# These test code from tasst.site, but require additional support from +# tasst.nstool. +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib + +import avocado + +from tasst import Tasst +from tasst.site import REAL_HOST +from tasst.nstool import UnshareSite + + +class VethTasst(Tasst): + """ + Test helpers for creating veths between namespaces + + :avocado: tags=meta + """ + + @contextlib.contextmanager + def setup_veth(self): + with UnshareSite(type(self).__name__ + '.1', '-Un') as ns1: + with UnshareSite(type(self).__name__ + '.2', '-n', + parent=ns1, sudo=True) as ns2: + ns1.veth('veth1', 'veth2', ns2) + yield (ns1, ns2) + + def test_ifs(self): + with self.setup_veth() as (ns1, ns2): + self.assertCountEqual(ns1.ifs(), ['lo', 'veth1']) + self.assertCountEqual(ns2.ifs(), ['lo', 'veth2']) diff --git a/avocado/tasst/nstool.py b/avocado/tasst/nstool.py index 50598a5..6f1d96b 100644 --- a/avocado/tasst/nstool.py +++ b/avocado/tasst/nstool.py @@ -68,6 +68,16 @@ class NsToolSite(Site): def bg(self, cmd, sudo=False, **kwargs): return REAL_HOST.bg(self._nst_cmd(cmd, sudo), **kwargs) + def veth(self, ifname, peername, peer=None): + self.fg('ip link add {} type veth peer name {}'.format(ifname, peername), + sudo=True) + if peer is not None: + if not isinstance(peer, NsToolSite): + raise TypeError + self.fg('ip link set {} netns {}'.format(peername, + peer.relative_pid(self)), + sudo=True) + # Create path for temporary nstool Unix socket # -- 2.40.1
Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/meta/veth.py | 5 +++++ avocado/tasst/site.py | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/avocado/tasst/meta/veth.py b/avocado/tasst/meta/veth.py index c4cdcf7..301ccb9 100644 --- a/avocado/tasst/meta/veth.py +++ b/avocado/tasst/meta/veth.py @@ -41,3 +41,8 @@ class VethTasst(Tasst): with self.setup_veth() as (ns1, ns2): self.assertCountEqual(ns1.ifs(), ['lo', 'veth1']) self.assertCountEqual(ns2.ifs(), ['lo', 'veth2']) + + def test_mtu(self): + with self.setup_veth() as (ns1, ns2): + self.assertEquals(ns1.mtu('veth1'), 1500) + self.assertEquals(ns2.mtu('veth2'), 1500) diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index 3cb3721..f19a3fc 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -61,6 +61,11 @@ class Site(contextlib.AbstractContextManager): self.require_cmds('ip') self.fg('ip link set {} up'.format(ifname), sudo=True) + def mtu(self, ifname): + self.require_cmds('ip') + (info,) = json.loads(self.output('ip -j link show {}'.format(ifname))) + return info['mtu'] + def addrinfos(self, ifname, **filter): self.require_cmds('ip') info = json.loads(self.output('ip -j addr show {}'.format(ifname))) @@ -129,6 +134,10 @@ class SiteTasst(Tasst): for a in ['127.0.0.1/8', '::1/128']] self.assertCountEqual(site.addrs('lo'), expected) + def test_lo_mtu(self): + with self.setup_site() as site: + self.assertEqual(site.mtu('lo'), 65536) + class IsolatedSiteTasst(SiteTasst): """ -- 2.40.1
Add a helper to the Site() class to wait for an address with specified characteristics to be ready on an interface. In particular this is useful for waiting for IPv6 SLAAC & DAD (Duplicate Address Detection) to complete. Because DAD is not going to be useful in many of our scenarios, also extend Site.ifup() to allow DAD to be switched to optimistic mode or disabled. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/meta/static_ifup.py | 46 +++++++++++++++++++++++++++++++ avocado/tasst/meta/veth.py | 20 ++++++++++++++ avocado/tasst/site.py | 22 ++++++++++++++- 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 avocado/tasst/meta/static_ifup.py diff --git a/avocado/tasst/meta/static_ifup.py b/avocado/tasst/meta/static_ifup.py new file mode 100644 index 0000000..eba8fef --- /dev/null +++ b/avocado/tasst/meta/static_ifup.py @@ -0,0 +1,46 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/metatest/static_ifup - Static address configuration +# +# These test code from tasst.site, but require additional support from +# tasst.nstool. +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import ipaddress + +import avocado + +from tasst import Tasst +from tasst.nstool import UnshareSite + + +class StaticNetTasst(Tasst): + """ + Test helpers for static network configuration + + :avocado: tags=meta + """ + + IFNAME = 'testveth' + TEST_IPS = [ipaddress.ip_interface('192.0.2.1/24'), + ipaddress.ip_interface('2001:db8:9a55::1/112'), + ipaddress.ip_interface('10.1.2.3/8')] + + @contextlib.contextmanager + def setup_ns(self): + with UnshareSite(type(self).__name__, '-Un') as ns: + ns.veth(self.IFNAME, self.IFNAME + 'peer') + ns.ifup(self.IFNAME, *self.TEST_IPS, dad='disable') + yield ns + + def test_addr(self): + with self.setup_ns() as ns: + self.assertCountEqual(ns.addrs(self.IFNAME, scope='global'), self.TEST_IPS) diff --git a/avocado/tasst/meta/veth.py b/avocado/tasst/meta/veth.py index 301ccb9..4dfb15a 100644 --- a/avocado/tasst/meta/veth.py +++ b/avocado/tasst/meta/veth.py @@ -14,6 +14,7 @@ # Author: David Gibson <david(a)gibson.dropbear.id.au> import contextlib +import ipaddress import avocado @@ -46,3 +47,22 @@ class VethTasst(Tasst): with self.setup_veth() as (ns1, ns2): self.assertEquals(ns1.mtu('veth1'), 1500) self.assertEquals(ns2.mtu('veth2'), 1500) + + def test_slaac(self, dad=None): + TESTMAC = '02:aa:bb:cc:dd:ee' + TESTIP = ipaddress.ip_interface('fe80::aa:bbff:fecc:ddee/64') + + with self.setup_veth() as (ns1, ns2): + ns1.fg('ip link set dev veth1 address {}'.format(TESTMAC), sudo=True) + + ns1.ifup('veth1', dad=dad) + ns2.ifup('veth2') + + addrs = ns1.addr_wait('veth1', family='inet6', scope='link') + self.assertEqual(addrs, [TESTIP]) + + def test_optimistic_dad(self): + self.test_slaac(dad='optimistic') + + def test_no_dad(self): + self.test_slaac(dad='disable') diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index f19a3fc..f064a22 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -57,8 +57,22 @@ class Site(contextlib.AbstractContextManager): info = json.loads(self.output('ip -j link show')) return [i['ifname'] for i in info] - def ifup(self, ifname): + def ifup(self, ifname, *addrs, dad=None): self.require_cmds('ip') + + if dad == 'disable': + self.fg('sysctl net.ipv6.conf.{}.accept_dad=0'.format(ifname), sudo=True) + elif dad == 'optimistic': + self.fg('sysctl net.ipv6.conf.{}.optimistic_dad=1'.format(ifname), sudo=True) + elif dad is not None: + raise ValueError + + for a in addrs: + if (not isinstance(a, ipaddress.IPv4Interface) + and not isinstance(a, ipaddress.IPv6Interface)): + raise TypeError + self.fg('ip addr add {} dev {}'.format(a.with_prefixlen, ifname), sudo=True) + self.fg('ip link set {} up'.format(ifname), sudo=True) def mtu(self, ifname): @@ -84,6 +98,12 @@ class Site(contextlib.AbstractContextManager): for ai in self.addrinfos(ifname, **filter) if not 'tentative' in ai] + def addr_wait(self, ifname, **filter): + while True: + addrs = self.addrs(ifname, **filter) + if addrs: + return addrs + class SiteTasst(Tasst): """ -- 2.40.1
Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/meta/static_ifup.py | 13 +++++++++++++ avocado/tasst/site.py | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/avocado/tasst/meta/static_ifup.py b/avocado/tasst/meta/static_ifup.py index eba8fef..ce6ecaf 100644 --- a/avocado/tasst/meta/static_ifup.py +++ b/avocado/tasst/meta/static_ifup.py @@ -44,3 +44,16 @@ class StaticNetTasst(Tasst): def test_addr(self): with self.setup_ns() as ns: self.assertCountEqual(ns.addrs(self.IFNAME, scope='global'), self.TEST_IPS) + + def _test_routes(self, class_): + expected_routes = [i.network for i in TEST_IPS + if isinstance(i, class_)] + actual_routes = [class_(r['dst']).network + for r in self.ns.routes(dev=self.IFNAME))] + self.assertCountEqual(expected_routes, actual_routes) + + def test_routes4(self): + self._test_routes(IPv4Interface) + + def test_routes6(self): + self._test_routes(IPv6Interface) diff --git a/avocado/tasst/site.py b/avocado/tasst/site.py index f064a22..f9cac86 100644 --- a/avocado/tasst/site.py +++ b/avocado/tasst/site.py @@ -104,6 +104,19 @@ class Site(contextlib.AbstractContextManager): if addrs: return addrs + def _routes(self, ipv, **filter): + routes = json.loads(self.output('ip -j -{} route'.format(ipv))) + for key, value in filter.items(): + routes = [r for r in routes if key in r and r[key] == value] + + return routes + + def routes4(self, **filter): + return self._routes('4', **filter) + + def routes6(self, **filter): + return self._routes('6', **filter) + class SiteTasst(Tasst): """ -- 2.40.1
Many of our existing tests are based on using socat to transfer between various locations connected via pasta or passt. Add helpers to make avocado tests performing similar transfers. Add meta tests to verify those work as expected when we don't have pasta or passt involved yet. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- Makefile | 2 +- avocado/tasst/__init__.py | 5 + avocado/tasst/transfer.py | 223 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 avocado/tasst/transfer.py diff --git a/Makefile b/Makefile index 9add0a4..8eaae0f 100644 --- a/Makefile +++ b/Makefile @@ -299,7 +299,7 @@ cppcheck: $(SRCS) $(HEADERS) AVOCADO = avocado avocado-assets: - $(MAKE) -C test nstool + $(MAKE) -C test nstool small.bin avocado-%: avocado-assets PYTHONPATH=./avocado $(AVOCADO) run avocado --filter-by-tags=$* diff --git a/avocado/tasst/__init__.py b/avocado/tasst/__init__.py index 3bbde84..bfe71a8 100644 --- a/avocado/tasst/__init__.py +++ b/avocado/tasst/__init__.py @@ -11,6 +11,11 @@ import avocado +class TasstSubData: + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + # Base class for avocado-based passt/pasta tests class Tasst(avocado.Test): # Fairly short default timeout diff --git a/avocado/tasst/transfer.py b/avocado/tasst/transfer.py new file mode 100644 index 0000000..576219e --- /dev/null +++ b/avocado/tasst/transfer.py @@ -0,0 +1,223 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/transfer.py - Helpers for testing data transfers +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import ipaddress +import time + +import avocado + +from tasst import Tasst, TasstSubData +from tasst.site import Site +from tasst.nstool import UnshareSite +from tasst.typing import typecheck, typecheck_default + + +# HACK: how long to wait for the server to be ready and listening (s) +SERVER_READY_DELAY = 0.05 # 1/20th of a second + + +# socat needs IPv6 addresses in square brackets +def socat_fmt(ip): + if isinstance(ip, ipaddress.IPv6Address): + return '[{}]'.format(ip) + elif isinstance(ip, ipaddress.IPv4Address): + return '{}'.format(ip) + else: + raise TypeError + + +class TransferTasstInfo: + def __init__(self, datafile, cs, ss, ip4, ip6, port, + listen_ip4=None, listen_ip6=None, listenport=None, + from_ip4=None, from_ip6=None): + self.datafile = typecheck(datafile, str) + self.cs = typecheck(cs, Site) + self.ss = typecheck(ss, Site) + self.ip4 = typecheck(ip4, ipaddress.IPv4Address) + self.ip6 = typecheck(ip6, ipaddress.IPv6Address) + self.port = typecheck(port, int) + self.listen_ip4 = typecheck_default(listen_ip4, ipaddress.IPv4Address, None) + self.listen_ip6 = typecheck_default(listen_ip6, ipaddress.IPv6Address, None) + self.listenport = typecheck_default(listenport, int, port) + self.from_ip4 = typecheck_default(from_ip4, ipaddress.IPv4Address, None) + self.from_ip6 = typecheck_default(from_ip6, ipaddress.IPv6Address, None) + + cs.require_cmds('socat', 'cat') + ss.require_cmds('socat', 'cat') + + +class BaseTransferTasst(Tasst): + def socat_upload(self, datafile, cs, ss, connect, listen): + with ss.bg('socat -u {} STDOUT'.format(listen), verbose=False) as server: + time.sleep(SERVER_READY_DELAY) + cs.fg('socat -u OPEN:{} {}'.format(datafile, connect)) + res = server.run() + self.assertEquals(res.exit_status, 0) + srcdata = cs.output('cat {}'.format(datafile), verbose=False) + self.assertEquals(srcdata, res.stdout) + + def socat_download(self, datafile, cs, ss, connect, listen): + with ss.bg('socat -u OPEN:{} {}'.format(datafile, listen)) as server: + time.sleep(SERVER_READY_DELAY) + dstdata = cs.output('socat -u {} STDOUT'.format(connect), verbose=False) + res = server.run() + self.assertEquals(res.exit_status, 0) + srcdata = ss.output('cat {}'.format(datafile), verbose=False) + self.assertEquals(srcdata, dstdata) + + def _tcp_socat(self, datafile, connectip, connectport, + listenip, listenport, fromip): + v6 = isinstance(connectip, ipaddress.IPv6Address) + if listenport is None: + listenport = connectport + if v6: + connect = 'TCP6:[{}]:{},ipv6only'.format(connectip, connectport) + listen = 'TCP6-LISTEN:{},ipv6only'.format(listenport) + else: + connect = 'TCP4:{}:{}'.format(connectip, connectport) + listen = 'TCP4-LISTEN:{}'.format(listenport) + if listenip is not None: + listen += ',bind=' + socat_fmt(listenip) + if fromip is not None: + connect += ',bind=' + socat_fmt(fromip) + return (connect, listen) + + def tcp_upload(self, datafile, cs, ss, connectip, connectport, + listenip=None, listenport=None, fromip=None): + connect, listen = self._tcp_socat(datafile, connectip, connectport, + listenip, listenport, fromip) + self.socat_upload(datafile, cs, ss, connect, listen) + + def tcp_download(self, datafile, cs, ss, connectip, connectport, + listenip=None, listenport=None, fromip=None): + connect, listen = self._tcp_socat(datafile, connectip, connectport, + listenip, listenport, fromip) + self.socat_download(datafile, cs, ss, connect, listen) + + def udp_transfer(self, datafile, cs, ss, connectip, connectport, + listenip=None, listenport=None, fromip=None): + v6 = isinstance(connectip, ipaddress.IPv6Address) + if listenport is None: + listenport = connectport + if v6: + connect = 'UDP6:[{}]:{},ipv6only,shut-null'.format(connectip, connectport) + listen = 'UDP6-LISTEN:{},ipv6only,null-eof'.format(listenport) + if listenip is not None: + assert isinstance(listenip, ipaddress.IPv6Address) + listen += ',bind=[{}]'.format(listenip) + else: + connect = 'UDP4:{}:{},shut-null'.format(connectip, connectport) + listen = 'UDP4-LISTEN:{},null-eof'.format(listenport) + if listenip is not None: + assert isinstance(listenip, ipaddress.IPv4Address) + listen += ',bind={}'.format(listenip) + + self.socat_upload(datafile, cs, ss, connect, listen) + + def setup_transfer(self): + raise NotImplementedError("{} must implement setup_transfer() method".format(type(self).__name__)) + + @contextlib.contextmanager + def check_setup_transfer(self): + with self.setup_transfer() as tti: + if not isinstance(tti, TransferTasstInfo): + raise TypeError("{}.setup_tranfer() must yield a TransferTasstInfo instance".format(type(self).__name__)) + yield tti + + +class TcpUploadTasst(BaseTransferTasst): + """ + :avocado: disable + """ + + def test_tcp4_upload(self): + with self.check_setup_transfer() as tti: + self.tcp_upload(tti.datafile, tti.cs, tti.ss, tti.ip4, tti.port, + listenip=tti.listen_ip4, listenport=tti.listenport, + fromip=tti.from_ip4) + + def test_tcp6_upload(self): + with self.check_setup_transfer() as tti: + self.tcp_upload(tti.datafile, tti.cs, tti.ss, tti.ip6, tti.port, + listenip=tti.listen_ip6, listenport=tti.listenport, + fromip=tti.from_ip6) + + +class MetaTcpUploadTasst(TcpUploadTasst): + """Ugly workaround for + https://github.com/avocado-framework/avocado/issues/5680. + Explicitly apply the "meta" tag to the tests in TransferTasst. + + :avocado: disable + :avocado: tags=meta + + """ + + def test_tcp4_upload(self): + super().test_tcp4_upload() + + def test_tcp6_upload(self): + super().test_tcp6_upload() + + +class UdpTransferTasst(BaseTransferTasst): + """ + :avocado: disable + """ + + def test_udp4_transfer(self): + with self.check_setup_transfer() as tti: + self.udp_transfer(tti.datafile, tti.cs, tti.ss, tti.ip4, tti.port, + listenip=tti.listen_ip4, listenport=tti.listenport, + fromip=tti.from_ip4) + + def test_udp6_transfer(self): + with self.check_setup_transfer() as tti: + self.udp_transfer(tti.datafile, tti.cs, tti.ss, tti.ip6, tti.port, + listenip=tti.listen_ip6, listenport=tti.listenport, + fromip=tti.from_ip6) + + +class MetaUdpTransferTasst(UdpTransferTasst): + """Ugly workaround for + https://github.com/avocado-framework/avocado/issues/5680. + Explicitly apply the "meta" tag to the tests in TransferTasst. + + :avocado: disable + :avocado: tags=meta + + """ + + def test_udp4_transfer(self): + super().test_udp4_transfer() + + def test_udp6_transfer(self): + super().test_udp6_transfer() + + +LOOPBACK4 = ipaddress.ip_address('127.0.0.1') +LOOPBACK6 = ipaddress.ip_address('::1') + + +class LocalTransferTasst(MetaTcpUploadTasst, MetaUdpTransferTasst): + """Test the transfer helpers + """ + + PORT = 10000 + + @contextlib.contextmanager + def setup_transfer(self): + with UnshareSite(type(self).__name__ + '.netns', '-Un') as ns: + ns.ifup('lo') + yield TransferTasstInfo('test/small.bin', ns, ns, + LOOPBACK4, LOOPBACK6, self.PORT) -- 2.40.1
A bunch of our test scenarious will require us to allocate IPv4 and IPv6 addresses in example networks. Make helpers to do this easily. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/address.py | 89 ++++++++++++++++++++++++++++++++++++++ avocado/tasst/meta/veth.py | 41 +++++++++++++++--- avocado/tasst/transfer.py | 1 + 3 files changed, 124 insertions(+), 7 deletions(-) create mode 100644 avocado/tasst/address.py diff --git a/avocado/tasst/address.py b/avocado/tasst/address.py new file mode 100644 index 0000000..6a6e025 --- /dev/null +++ b/avocado/tasst/address.py @@ -0,0 +1,89 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/address.py - Address allocation helpers +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import ipaddress + +import avocado + +from tasst import Tasst + + +# Loopback addresses, for convenience +LOOPBACK4 = ipaddress.ip_address('127.0.0.1') +LOOPBACK6 = ipaddress.ip_address('::1') + +# Documentation test networks defined by RFC 5737 +TEST_NET_1 = ipaddress.ip_network('192.0.2.0/24') +TEST_NET_2 = ipaddress.ip_network('198.51.100.0/24') +TEST_NET_3 = ipaddress.ip_network('203.0.113.0/24') + +# Documentation test network defined by RFC 3849 +TEST_NET6 = ipaddress.ip_network('2001:db8::/32') +# Some subnets of that for our usage +TEST_NET6_TASST_A = ipaddress.ip_network('2001:db8:9a55:aaaa::/64') +TEST_NET6_TASST_B = ipaddress.ip_network('2001:db8:9a55:bbbb::/64') +TEST_NET6_TASST_C = ipaddress.ip_network('2001:db8:9a55:cccc::/64') + + +class IpiAllocator: + DEFAULT_NETS = [TEST_NET_1, TEST_NET6_TASST_A] + + def __init__(self, *nets): + if not nets: + nets = self.DEFAULT_NETS + + self.nets = [ipaddress.ip_network(n) for n in nets] + self.hostses = [n.hosts() for n in self.nets] + + def next_ipis(self): + addrs = [next(h) for h in self.hostses] + return [ipaddress.ip_interface('{}/{}'.format(a, n.prefixlen)) + for a, n in zip(addrs, self.nets)] + + +class IpiAllocatorTasst(Tasst): + """ + :avocado: tags=meta + """ + + COUNT = 12 # Allocate this many addresses + NETS = None # From these networks (None means use default) + + def test(self): + if self.NETS is not None: + ipa = IpiAllocator(*self.NETS) + nets = self.NETS + else: + ipa = IpiAllocator() + nets = IpiAllocator.DEFAULT_NETS + + addrsets = [set() for i in range(len(nets))] + for i in range(self.COUNT): + addrs = ipa.next_ipis() + # Check we got as many addresses as expected + self.assertEquals(len(addrs), len(nets)) + for s, a, n in zip(addrsets, addrs, nets): + # Check the addresses belong to the right network + self.assertEquals(a.network, ipaddress.ip_network(n)) + s.add(a) + + print(addrsets) + # Check the addresses are unique + for s in addrsets: + self.assertEquals(len(s), self.COUNT) + +class IpiAllocatorCustomTasst(IpiAllocatorTasst): + """ + :avocado: tags=meta + """ + + NETS = ['10.55.0.0/16', '192.168.55.0/24', 'fd00:9a57:a000::/48'] diff --git a/avocado/tasst/meta/veth.py b/avocado/tasst/meta/veth.py index 4dfb15a..b886bfe 100644 --- a/avocado/tasst/meta/veth.py +++ b/avocado/tasst/meta/veth.py @@ -21,15 +21,11 @@ import avocado from tasst import Tasst from tasst.site import REAL_HOST from tasst.nstool import UnshareSite +from tasst.transfer import BaseTransferTasst, MetaTcpUploadTasst, MetaUdpTransferTasst, TransferTasstInfo +from tasst.address import IpiAllocator -class VethTasst(Tasst): - """ - Test helpers for creating veths between namespaces - - :avocado: tags=meta - """ - +class BaseVethTasst(Tasst): @contextlib.contextmanager def setup_veth(self): with UnshareSite(type(self).__name__ + '.1', '-Un') as ns1: @@ -38,6 +34,13 @@ class VethTasst(Tasst): ns1.veth('veth1', 'veth2', ns2) yield (ns1, ns2) + +class VethTasst(BaseVethTasst): + """ + Test helpers for creating veths between namespaces + + :avocado: tags=meta + """ def test_ifs(self): with self.setup_veth() as (ns1, ns2): self.assertCountEqual(ns1.ifs(), ['lo', 'veth1']) @@ -66,3 +69,27 @@ class VethTasst(Tasst): def test_no_dad(self): self.test_slaac(dad='disable') + + +class VethTransferTasst(BaseVethTasst, MetaTcpUploadTasst, MetaUdpTransferTasst): + """ + Test basic transfers over veth + + :avocado: tags=meta + """ + + @contextlib.contextmanager + def setup_transfer(self): + with self.setup_veth() as (ns1, ns2): + ipa = IpiAllocator() + + ns1_ip4, ns1_ip6 = ipa.next_ipis() + ns1.ifup('lo') + ns1.ifup('veth1', ns1_ip4, ns1_ip6, dad='disable') + + ns2_ip4, ns2_ip6 = ipa.next_ipis() + ns2.ifup('lo') + ns2.ifup('veth2', ns2_ip4, ns2_ip6, dad='disable') + + yield TransferTasstInfo('test/small.bin', ns1, ns2, + ns2_ip4.ip, ns2_ip6.ip, 10000) diff --git a/avocado/tasst/transfer.py b/avocado/tasst/transfer.py index 576219e..c9bffb1 100644 --- a/avocado/tasst/transfer.py +++ b/avocado/tasst/transfer.py @@ -17,6 +17,7 @@ import time import avocado from tasst import Tasst, TasstSubData +from tasst.address import LOOPBACK4, LOOPBACK6 from tasst.site import Site from tasst.nstool import UnshareSite from tasst.typing import typecheck, typecheck_default -- 2.40.1
Signed-iff-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/ndp.py | 137 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 avocado/tasst/ndp.py diff --git a/avocado/tasst/ndp.py b/avocado/tasst/ndp.py new file mode 100644 index 0000000..771cba8 --- /dev/null +++ b/avocado/tasst/ndp.py @@ -0,0 +1,137 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/ndp.py - Helpers for testing NDP +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import ipaddress +import os + +from tasst import Tasst, TasstSubData +from tasst.address import IpiAllocator, TEST_NET6_TASST_A +from tasst.nstool import UnshareSite +from tasst.site import Site +from tasst.typing import typecheck + + +class NdpTasstInfo: + def __init__(self, site, ifname, net, gw): + self.site = typecheck(site, Site) + self.ifname = typecheck(ifname, str) + self.net = typecheck(net, ipaddress.IPv6Network) + self.gw = typecheck(gw, ipaddress.IPv6Address) + + site.require_cmds('ip') + + +class BaseNdpTasst(Tasst): + """ + Test NDP behaviour. + + :avocado: disable + """ + + def setup_ndp(self): + raise NotImplementedError("{} must implement setup_ndp() method".format(type(self).__name__)) + + @contextlib.contextmanager + def check_setup_ndp(self): + with self.setup_ndp() as ndp: + if not isinstance(ndp, NdpTasstInfo): + raise TypeError("{}.setup_ndp() must yield a NdpTasstInfo instance".format(type(self).__name__)) + yield ndp + + def test_addr(self): + with self.check_setup_ndp() as ndp: + # Wait for NDP to do its thing + (addr,) = ndp.site.addr_wait(ndp.ifname, family='inet6', scope='global') + + # The SLAAC address is derived from the guest ns MAC, so + # probably won't exactly match the host address (we need + # DHCPv6 for that). It should be in the right network though. + self.assertEquals(addr.network, ndp.net) + + def test_route(self): + with self.check_setup_ndp() as ndp: + defroutes = ndp.site.routes6(dst='default') + while not defroutes: + defroutes = ndp.site.routes6(dst='default') + + self.assertEquals(len(defroutes), 1) + gateway = ipaddress.ip_address(defroutes[0]['gateway']) + self.assertEquals(gateway, ndp.gw) + + +class MetaNdpTasst(BaseNdpTasst): + """Ugly workaround for + https://github.com/avocado-framework/avocado/issues/5680. + Explicitly apply the "meta" tag to inherited tests + + :avocado: disable + :avocado: tags=meta + + """ + + def test_addr(self): + super().test_addr() + + def test_route(self): + super().test_route() + + +class RadvdNdpTasst(MetaNdpTasst): + timeout = 15.0 + + @contextlib.contextmanager + def setup_ndp(self): + ifname = 'clientif' + router_ifname = 'routerif' + prefix = TEST_NET6_TASST_A + + with UnshareSite(type(self).__name__ + '.client', '-Un') as client, \ + UnshareSite(type(self).__name__ + '.router', '-n', parent=client, sudo=True) as router: + router.require_cmds('radvd') + + client.veth(ifname, router_ifname, router) + + # Configure the simulated router + ipa = IpiAllocator(prefix) + (router_ip6,) = ipa.next_ipis() + + confpath = os.path.join(self.workdir, 'radvd.conf') + pidpath = os.path.join(self.workdir, 'radvd.pid') + open(confpath, 'w').write( + ''' + interface {} {{ + AdvSendAdvert on; + prefix {} {{ + }}; + }}; + '''.format(router_ifname, prefix)) + + router.ifup('lo') + router.ifup('routerif', router_ip6) + + # Configure the client + client.ifup('lo') + client.ifup(ifname) + + # Get the router's link-local-address + (router_ll,) = router.addr_wait(router_ifname, family='inet6', scope='link') + + # Run radvd + router.fg('radvd -c -C {}'.format(confpath)) + with router.bg('radvd -C {} -p {} -n -d 5'.format(confpath, pidpath), sudo=True) as radvd: + yield NdpTasstInfo(client, ifname, prefix, router_ll.ip) + + pid = int(open(pidpath).read()) + router.fg('kill {}'.format(pid)) + status = radvd.wait() + self.assertEquals(status, 0) -- 2.40.1
Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/dhcp.py | 152 ++++++++++++++++++++++++++++++++++++++++ avocado/tasst/dhcpv6.py | 135 +++++++++++++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 avocado/tasst/dhcp.py create mode 100644 avocado/tasst/dhcpv6.py diff --git a/avocado/tasst/dhcp.py b/avocado/tasst/dhcp.py new file mode 100644 index 0000000..be226e4 --- /dev/null +++ b/avocado/tasst/dhcp.py @@ -0,0 +1,152 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/dhcp.py - Helpers for testing DHCP +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import ipaddress +import os + +from tasst import Tasst, TasstSubData +from tasst.address import IpiAllocator, TEST_NET_1 +from tasst.nstool import UnshareSite +from tasst.site import Site +from tasst.typing import typecheck + + +class DhcpTasstInfo: + def __init__(self, site, ifname, addr, gw, mtu): + self.site = typecheck(site, Site) + self.ifname = typecheck(ifname, str) + self.addr = typecheck(addr, ipaddress.IPv4Address) + self.gw = typecheck(gw, ipaddress.IPv4Address) + self.mtu = typecheck(mtu, int) + + site.require_cmds('ip') + + +class BaseDhcpTasst(Tasst): + """ + Test DHCP behaviour. + + :avocado: disable + """ + + DHCLIENT = '/sbin/dhclient' + + def setup_dhcp(self): + raise NotImplementedError("{} must implement setup_dhcp() method".format(type(self).__name__)) + + @contextlib.contextmanager + def dhclient(self): + with self.setup_dhcp() as dti: + dti = typecheck(dti, DhcpTasstInfo) + + dti.site.require_cmds(self.DHCLIENT, 'cat', 'kill') + + pidfile = os.path.join(self.workdir, 'dhclient.pid') + leasefile = os.path.join(self.workdir, 'dhclient.leases') + + # We need '-nc' because we may be running with + # capabilities but not UID 0. Without -nc dhclient drops + # capabilities before invoking dhclient-script, so it's + # unable to actually configure the interface + dti.site.fg('{} -4 -v -nc -pf {} -lf {} {}' + .format(self.DHCLIENT, pidfile, leasefile, dti.ifname), sudo=True) + + try: + yield dti + finally: + pid = int(dti.site.output('cat {}'.format(pidfile))) + dti.site.fg('kill {}'.format(pid)) + + def test_addr(self): + with self.dhclient() as dti: + (addr,) = dti.site.addrs(dti.ifname, family='inet', scope='global') + self.assertEquals(addr.ip, dti.addr) + + def test_route(self): + with self.dhclient() as dti: + (defroute,) = dti.site.routes4(dst='default') + self.assertEquals(ipaddress.ip_address(defroute['gateway']), dti.gw) + + def test_mtu(self): + with self.dhclient() as dti: + self.assertEquals(dti.site.mtu(dti.ifname), dti.mtu) + + +class MetaDhcpTasst(BaseDhcpTasst): + """Ugly workaround for + https://github.com/avocado-framework/avocado/issues/5680. + Explicitly apply the "meta" tag to inherited tests + + :avocado: disable + :avocado: tags=meta + + """ + + def test_addr(self): + super().test_addr() + + def test_route(self): + super().test_route() + + def test_mtu(self): + super().test_mtu() + + +class DhcpdTasst(MetaDhcpTasst): + DHCPD = 'dhcpd' + SUBNET = TEST_NET_1 + + @contextlib.contextmanager + def setup_dhcp(self): + ifname = 'clientif' + server_ifname = 'serverif' + + with UnshareSite(type(self).__name__ + '.client', '-Un') as client, \ + UnshareSite(type(self).__name__ + '.server', '-n', + parent=client, sudo=True) as server: + + server.require_cmds(self.DHCPD) + + client.veth(ifname, server_ifname, server) + + # Configure the DHCP server + ipa = IpiAllocator(self.SUBNET) + (server_ip4,) = ipa.next_ipis() + (client_ip4,) = ipa.next_ipis() + + confpath = os.path.join(self.workdir, 'dhcpd.conf') + open(confpath, 'w').write(''' + subnet {} netmask {} {{ + option routers {}; + range {} {}; + }} + '''.format(self.SUBNET.network_address, self.SUBNET.netmask, + server_ip4.ip, client_ip4.ip, client_ip4.ip)) + pidpath = os.path.join(self.workdir, 'dhcpd.pid') + leasepath = os.path.join(self.workdir, 'dhcpd.leases') + open(leasepath, 'w').write('') + + server.ifup('lo') + server.ifup(server_ifname, server_ip4) + + opts = ('-f -d -4 -cf {} -lf {} -pf {}'.format(confpath, leasepath, pidpath)) + server.fg('{} -t {}'.format(self.DHCPD, opts)) # test config + with server.bg('{} {}'.format(self.DHCPD, opts), sudo=True) as dhcpd: + # Configure the client + client.ifup('lo') + + yield DhcpTasstInfo(client, ifname, client_ip4.ip, server_ip4.ip, 1500) + + pid = int(open(pidpath).read()) + server.fg('kill {}'.format(pid)) + status = dhcpd.wait() diff --git a/avocado/tasst/dhcpv6.py b/avocado/tasst/dhcpv6.py new file mode 100644 index 0000000..5a0c166 --- /dev/null +++ b/avocado/tasst/dhcpv6.py @@ -0,0 +1,135 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/dhcpv6.py - Helpers for testing DHCPv6 +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import ipaddress +import os + +from tasst import Tasst, TasstSubData +from tasst.address import IpiAllocator, TEST_NET6_TASST_A +from tasst.nstool import UnshareSite +from tasst.site import Site +from tasst.typing import typecheck + + +class Dhcpv6TasstInfo: + def __init__(self, site, ifname, addr): + self.site = typecheck(site, Site) + self.ifname = typecheck(ifname, str) + self.addr = typecheck(addr, ipaddress.IPv6Address) + + site.require_cmds('ip') + + +class BaseDhcpv6Tasst(Tasst): + """ + Test DHCPv6 behaviour. + + :avocado: disable + """ + + DHCLIENT = '/sbin/dhclient' + + def setup_dhcpv6(self): + raise NotImplementedError("{} must implement setup_dhcpv6() method".format(type(self).__name__)) + + @contextlib.contextmanager + def dhclientv6(self): + with self.setup_dhcpv6() as d6ti: + d6ti.site.require_cmds(self.DHCLIENT) + + pidfile = os.path.join(self.workdir, 'dhclient.pid') + leasefile = os.path.join(self.workdir, 'dhclient.leases') + + # We need '-nc' because we may be running with + # capabilities but not UID 0. Without -nc dhclient drops + # capabilities before invoking dhclient-script, so it's + # unable to actually configure the interface + d6ti.site.fg('{} -6 -v -nc -pf {} -lf {} {}' + .format(self.DHCLIENT, pidfile, leasefile, d6ti.ifname), sudo=True) + + yield d6ti + + pid = int(d6ti.site.output('cat {}'.format(pidfile))) + d6ti.site.fg('kill {}'.format(pid)) + + def test_addr(self): + with self.dhclientv6() as d6ti: + addrs = [a.ip for a in d6ti.site.addrs(d6ti.ifname, family='inet6', scope='global')] + self.assertIn(d6ti.addr, addrs) # Might also have a SLAAC address + + +class MetaDhcpv6Tasst(BaseDhcpv6Tasst): + """Ugly workaround for + https://github.com/avocado-framework/avocado/issues/5680. + Explicitly apply the "meta" tag to inherited tests + + :avocado: disable + :avocado: tags=meta + + """ + + def test_addr(self): + super().test_addr() + + +class Dhcpd6Tasst(MetaDhcpv6Tasst): + """ + :avocado: tags=meta + """ + + DHCPD = 'dhcpd' + SUBNET = TEST_NET6_TASST_A + + @contextlib.contextmanager + def setup_dhcpv6(self): + ifname = 'clientif' + server_ifname = 'serverif' + + with UnshareSite(type(self).__name__ + '.client', '-Un') as client, \ + UnshareSite(type(self).__name__ + '.server', '-n', + parent=client, sudo=True) as server: + server.require_cmds(self.DHCPD) + + client.veth(ifname, server_ifname, server) + + # Allocate IPs, and sort out link local addressing + ipa = IpiAllocator(self.SUBNET) + (server_ip6,) = ipa.next_ipis() + (client_ip6,) = ipa.next_ipis() + + server.ifup('lo') + server.ifup(server_ifname, server_ip6) + client.ifup('lo') + client.ifup(ifname) + (server_ip6_ll,) = server.addr_wait(server_ifname, family='inet6', scope='link') + + # Configure the DHCP server + confpath = os.path.join(self.workdir, 'dhcpd.conf') + open(confpath, 'w').write(''' + subnet6 {} {{ + range6 {} {}; + }} + '''.format(self.SUBNET, client_ip6.ip, client_ip6.ip)) + pidpath = os.path.join(self.workdir, 'dhcpd.pid') + leasepath = os.path.join(self.workdir, 'dhcpd.leases') + open(leasepath, 'w').write('') + + opts = ('-f -d -6 -cf {} -lf {} -pf {}'.format(confpath, leasepath, pidpath)) + server.fg('{} -t {}'.format(self.DHCPD, opts)) # test config + with server.bg('{} {}'.format(self.DHCPD, opts), sudo=True) as dhcpd: + yield Dhcpv6TasstInfo(client, ifname, client_ip6.ip) + + pid = int(open(pidpath).read()) + server.fg('kill {}'.format(pid)) + status = dhcpd.wait() + -- 2.40.1
This constructs essentially the simplest sensible network for passt/pasta to operate in. We have one netns "simhost" to represent the host where we will run passt or pasta, and a second "gw" to represent its default gateway. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- avocado/tasst/scenario/__init__.py | 11 ++++ avocado/tasst/scenario/simple.py | 98 ++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 avocado/tasst/scenario/__init__.py create mode 100644 avocado/tasst/scenario/simple.py diff --git a/avocado/tasst/scenario/__init__.py b/avocado/tasst/scenario/__init__.py new file mode 100644 index 0000000..8ca64a6 --- /dev/null +++ b/avocado/tasst/scenario/__init__.py @@ -0,0 +1,11 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/scenario - Helpers to set up various sample network topologies +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> diff --git a/avocado/tasst/scenario/simple.py b/avocado/tasst/scenario/simple.py new file mode 100644 index 0000000..272d959 --- /dev/null +++ b/avocado/tasst/scenario/simple.py @@ -0,0 +1,98 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# tasst - Test A Simple Socket Transport +# library of test helpers for passt & pasta +# +# tasst/scenario/simple - Smallest sensible network to use passt/pasta +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib + +from tasst import Tasst +from tasst.nstool import UnshareSite +from tasst.address import IpiAllocator, TEST_NET_2, TEST_NET6_TASST_B +from tasst.site import Site +from tasst.transfer import MetaTcpUploadTasst, MetaUdpTransferTasst, TransferTasstInfo +from tasst.typing import typecheck + + +class __SimpleNet: + """A simple network setup scenario + + The sample network has 2 sites (network namespaces) connected with + a veth link: + [simhost] <-veth-> [gw] + + gw is set up as the default router for simhost. + + simhost has addresses: + self.ip4 (IPv4), self.ip6 (IPv6), self.ip6_ll (IPv6 link local) + + gw has addresses: + self.gw_ip4 (IPv4), self.gw_ip6 (IPv6), self.gw_ip6_ll (IPv6 link local) + self.remote_ip4 (IPv4), self.remote_ip6 (IPv6) + + The "remote" addresses are on a different subnet from the others, + so the only way for simhost to reach them is via its default + route. This helps to exercise that we're actually using that, + rather than just local net routes. + + """ + + def __init__(self, hostsite, gwsite): + self.simhost = typecheck(hostsite, Site) + self.gw = typecheck(gwsite, Site) + + self.ifname = 'veth' + self.gw_ifname = 'gw' + self.ifname + self.simhost.veth(self.ifname, self.gw_ifname, self.gw) + + ipa_local = IpiAllocator() + self.ip4, self.ip6 = ipa_local.next_ipis() + self.gw_ip4, self.gw_ip6 = ipa_local.next_ipis() + + ipa_remote = IpiAllocator(TEST_NET_2, TEST_NET6_TASST_B) + self.remote_ip4, self.remote_ip6 = ipa_remote.next_ipis() + + self.gw.ifup('lo') + self.gw.ifup(self.gw_ifname, self.gw_ip4, self.gw_ip6, + self.remote_ip4, self.remote_ip6) + + self.simhost.ifup('lo') + self.simhost.ifup(self.ifname, self.ip4, self.ip6) + + # Once link is up on both sides, SLAAC will run + self.gw_ip6_ll = self.gw.addr_wait(self.gw_ifname, family='inet6', scope='link')[0] + self.ip6_ll = self.simhost.addr_wait(self.ifname, family='inet6', scope='link')[0] + + # Set up the default route + self.simhost.fg('ip -4 route add default via {}'.format(self.gw_ip4.ip), sudo=True) + self.simhost.fg('ip -6 route add default via {} dev {}' + .format(self.gw_ip6_ll.ip, self.ifname), sudo=True) + +(a)contextlib.contextmanager +def simple_net(name): + name = typecheck(name, str) + with UnshareSite(name + '.simhost', '-Ucnpf --mount-proc') as simhost, \ + UnshareSite(name + '.gw', '-n', parent=simhost, sudo=True) as gw: + yield __SimpleNet(simhost, gw) + + +class SimpleNetConnectivityTasst(MetaTcpUploadTasst, MetaUdpTransferTasst): + """ + Check connectivity between the simulated host and the gateway, + before involving passt/pasta. + + :avocado: tags=meta + + """ + + @contextlib.contextmanager + def setup_transfer(self): + with simple_net(type(self).__name__) as simnet: + yield TransferTasstInfo('test/small.bin', simnet.simhost, simnet.gw, + simnet.remote_ip4.ip, simnet.remote_ip6.ip, 10000) -- 2.40.1
Convert the old-style tests for pasta (DHCP, NDP, TCP and UDP transfers) to using avocado. There are a few differences in what we test, but this should generally improve coverage: * We run in a constructed network environment, so we no longer depend on the real host's networking configuration * We do independent setup for each individual test * We add explicit tests for --config-net, which we use to accelerate that setup for the TCP and UDP tests * The TCP and UDP tests now test transfers between the guest and a (simulated) remote site that's on a different network from the simulated pasta host. This better matches the typical passt/pasta usecase Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- Makefile | 4 +- avocado/pasta.py | 195 +++++++++++++++++++++++++++++++++++++++++++++++ oldtest/run | 14 ++-- test/lib/layout | 31 -------- test/lib/setup | 40 ---------- test/pasta/dhcp | 46 ----------- test/pasta/ndp | 33 -------- test/pasta/tcp | 96 ----------------------- test/pasta/udp | 59 -------------- test/run | 8 -- 10 files changed, 204 insertions(+), 322 deletions(-) create mode 100644 avocado/pasta.py delete mode 100644 test/pasta/dhcp delete mode 100644 test/pasta/ndp delete mode 100644 test/pasta/tcp delete mode 100644 test/pasta/udp diff --git a/Makefile b/Makefile index 8eaae0f..00c52c6 100644 --- a/Makefile +++ b/Makefile @@ -298,8 +298,8 @@ cppcheck: $(SRCS) $(HEADERS) AVOCADO = avocado -avocado-assets: - $(MAKE) -C test nstool small.bin +avocado-assets: pasta + $(MAKE) -C test nstool small.bin big.bin medium.bin avocado-%: avocado-assets PYTHONPATH=./avocado $(AVOCADO) run avocado --filter-by-tags=$* diff --git a/avocado/pasta.py b/avocado/pasta.py new file mode 100644 index 0000000..39f71d4 --- /dev/null +++ b/avocado/pasta.py @@ -0,0 +1,195 @@ +#! /usr/bin/python3 + +# SPDX-License-Identifier: GPL-2.0-or-later +# +# avocado/pasta.py - Basic tests for pasta mode +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +import contextlib +import ipaddress +import os + +from tasst import Tasst +from tasst.address import LOOPBACK4, LOOPBACK6 +from tasst.dhcp import BaseDhcpTasst, DhcpTasstInfo +from tasst.dhcpv6 import BaseDhcpv6Tasst, Dhcpv6TasstInfo +from tasst.ndp import BaseNdpTasst, NdpTasstInfo +from tasst.nstool import UnshareSite +from tasst.scenario.simple import simple_net +from tasst.transfer import BaseTransferTasst, TcpUploadTasst, UdpTransferTasst, TransferTasstInfo +from tasst.typing import typecheck + + +PASTA_BIN = './pasta' + + +class BasePastaTasst(Tasst): + IN_FWD_PORT = 10002 + SPLICE_FWD_PORT = 10003 + + @contextlib.contextmanager + def setup_pasta(self, configure=False): + name = type(self).__name__ + with simple_net(name) as simnet: + with UnshareSite(name + '.guestns', '-Ucnpf --mount-proc', + parent=simnet.simhost, sudo=True) as simnet.guestns: + + relpid = simnet.guestns.relative_pid(simnet.simhost) + + pidfile = os.path.join(self.workdir, 'pasta.pid') + + extra = '' + if configure: + extra = '--config-net' + + pastacmd = ('{} -f -t {} -u {} -T {} -U {} -P {} {} {}' + .format(PASTA_BIN, self.IN_FWD_PORT, self.IN_FWD_PORT, + self.SPLICE_FWD_PORT, self.SPLICE_FWD_PORT, + pidfile, extra, relpid)) + + with simnet.simhost.bg(pastacmd) as pasta: + # Wait for the pidfile to be written + while not os.path.exists(pidfile) or not open(pidfile).read(): + pass + # PID of pasta process in simhost namespace + pid = int(open(pidfile).read()) + + yield simnet + + simnet.simhost.fg('kill -TERM {}'.format(pid)) + rc = pasta.wait(timeout=1.0) + self.assertEquals(rc, 0) + + +class PastaTasst(BasePastaTasst): + def test_ifname(self): + with self.setup_pasta() as simnet: + self.assertCountEqual(simnet.guestns.ifs(), ('lo', simnet.ifname)) + + +class PastaNdpTasst(BasePastaTasst, BaseNdpTasst): + @contextlib.contextmanager + def setup_ndp(self): + with self.setup_pasta() as simnet: + simnet.guestns.ifup(simnet.ifname) + yield NdpTasstInfo(simnet.guestns, simnet.ifname, simnet.ip6.network, simnet.gw_ip6_ll.ip) + + +class PastaDhcpTasst(BasePastaTasst, BaseDhcpTasst): + @contextlib.contextmanager + def setup_dhcp(self): + with self.setup_pasta() as simnet: + yield DhcpTasstInfo(simnet.guestns, simnet.ifname, simnet.ip4.ip, simnet.gw_ip4.ip, 65520) + + +class PastaDhcpv6Tasst(BasePastaTasst, BaseDhcpv6Tasst): + @contextlib.contextmanager + def setup_dhcpv6(self): + with self.setup_pasta() as simnet: + yield Dhcpv6TasstInfo(simnet.guestns, simnet.ifname, simnet.ip6.ip) + + +class PastaConfigNetTasst(BasePastaTasst): + def test_addr(self): + with self.setup_pasta(configure=True) as simnet: + addrs = simnet.guestns.addrs(simnet.ifname, scope='global') + self.assertCountEqual(addrs, [simnet.ip4, simnet.ip6]) + + def test_route4(self): + with self.setup_pasta(configure=True) as simnet: + (defroute,) = simnet.guestns.routes4(dst='default') + gateway = ipaddress.ip_address(defroute['gateway']) + self.assertEquals(gateway, simnet.gw_ip4.ip) + + def test_route6(self): + with self.setup_pasta(configure=True) as simnet: + (defroute,) = simnet.guestns.routes6(dst='default') + gateway = ipaddress.ip_address(defroute['gateway']) + self.assertEquals(gateway, simnet.gw_ip6_ll.ip) + + def test_mtu(self): + with self.setup_pasta(configure=True) as simnet: + mtu = simnet.guestns.mtu(simnet.ifname) + self.assertEquals(mtu, 65520) + + +class PastaOutwardTransferTasst(BasePastaTasst, BaseTransferTasst): + """ + :avocado: disable + """ + + OUT_CONNECT_PORT = 10000 + + @contextlib.contextmanager + def setup_transfer(self): + with self.setup_pasta(configure=True) as simnet: + yield TransferTasstInfo(self.DATAFILE, simnet.guestns, simnet.gw, + simnet.remote_ip4.ip, simnet.remote_ip6.ip, + self.OUT_CONNECT_PORT) + + +class PastaOutwardSmallTcpUploadTasst(PastaOutwardTransferTasst, TcpUploadTasst): + DATAFILE = './test/small.bin' + + +class PastaOutwardBigTcpUploadTasst(PastaOutwardSmallTcpUploadTasst): + DATAFILE = './test/big.bin' + timeout = 30.0 + + +class PastaOutwardUdpTransferTasst(PastaOutwardTransferTasst, UdpTransferTasst): + DATAFILE = './test/medium.bin' + + +class PastaInwardTransferTasst(BasePastaTasst, BaseTransferTasst): + """ + :avocado: disable + """ + + @contextlib.contextmanager + def setup_transfer(self): + with self.setup_pasta(configure=True) as simnet: + yield TransferTasstInfo(self.DATAFILE, simnet.gw, simnet.guestns, + simnet.ip4.ip, simnet.ip6.ip, self.IN_FWD_PORT, + from_ip4=simnet.remote_ip4.ip, from_ip6=simnet.remote_ip6.ip) + + +class PastaInwardSmallTcpUploadTasst(PastaInwardTransferTasst, TcpUploadTasst): + DATAFILE = './test/small.bin' + + +class PastaInwardBigTcpUploadTasst(PastaInwardSmallTcpUploadTasst): + DATAFILE = './test/big.bin' + timeout = 30.0 + + +class PastaInwardUdpTransferTasst(PastaInwardTransferTasst, UdpTransferTasst): + DATAFILE = './test/medium.bin' + + +class PastaSplicedTransferTasst(BasePastaTasst, BaseTransferTasst): + """ + :avocado: disable + """ + + @contextlib.contextmanager + def setup_transfer(self): + with self.setup_pasta(configure=True) as simnet: + yield TransferTasstInfo(self.DATAFILE, simnet.guestns, simnet.simhost, + LOOPBACK4, LOOPBACK6, self.SPLICE_FWD_PORT, + listen_ip4=LOOPBACK4, listen_ip6=LOOPBACK6) + + +class PastaSplicedSmallTcpUploadTasst(PastaSplicedTransferTasst, TcpUploadTasst): + DATAFILE = './test/small.bin' + + +class PastaSplicedBigTcpUploadTasst(PastaSplicedSmallTcpUploadTasst): + DATAFILE = './test/big.bin' + timeout = 30.0 + + +class PastaSplicedUdpTransferTasst(PastaSplicedTransferTasst, UdpTransferTasst): + DATAFILE = './test/medium.bin' diff --git a/oldtest/run b/oldtest/run index a16bc49..f1157f9 100755 --- a/oldtest/run +++ b/oldtest/run @@ -70,13 +70,13 @@ run() { test build/clang_tidy teardown build -# setup pasta -# test pasta/ndp -# test pasta/dhcp -# test pasta/tcp -# test pasta/udp -# test passt/shutdown -# teardown pasta + setup pasta + test pasta/ndp + test pasta/dhcp + test pasta/tcp + test pasta/udp + test passt/shutdown + teardown pasta # setup pasta_options # test pasta_options/log_to_file diff --git a/test/lib/layout b/test/lib/layout index f9a1cf1..e2b1db0 100644 --- a/test/lib/layout +++ b/test/lib/layout @@ -13,37 +13,6 @@ # Copyright (c) 2021 Red Hat GmbH # Author: Stefano Brivio <sbrivio(a)redhat.com> -# layout_pasta() - Panes for host, pasta, and separate one for namespace -layout_pasta() { - sleep 3 - - tmux kill-pane -a -t 0 - cmd_write 0 clear - - tmux split-window -v -t passt_test - tmux split-window -h -t passt_test - tmux split-window -h -l '42%' -t passt_test:1.0 - - PANE_NS=0 - PANE_INFO=1 - PANE_HOST=2 - PANE_PASST=3 - - get_info_cols - - tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' - tmux send-keys -t ${PANE_INFO} -N 100 C-m - tmux select-pane -t ${PANE_INFO} -T "test log" - - pane_watch_contexts ${PANE_HOST} host host - pane_watch_contexts ${PANE_PASST} pasta passt - pane_watch_contexts ${PANE_NS} "namespace" unshare ns - - info_layout "single pasta instance with namespace" - - sleep 1 -} - # layout_passt() - Panes for host, passt, and guest layout_passt() { sleep 3 diff --git a/test/lib/setup b/test/lib/setup index 5386805..7abf206 100755 --- a/test/lib/setup +++ b/test/lib/setup @@ -61,36 +61,6 @@ setup_passt() { context_setup_guest guest $GUEST_CID } -# setup_pasta() - Create a network and user namespace, connect pasta to it -setup_pasta() { - context_setup_host host - context_setup_host passt - context_setup_host unshare - - layout_pasta - - context_run_bg unshare "unshare -rUnpf ${NSTOOL} hold ${STATESETUP}/ns.hold" - - context_setup_nstool ns ${STATESETUP}/ns.hold - - # Ports: - # - # ns | host - # ------------------|--------------------- - # 10002 as server | spliced to ns - # 10003 spliced to init | as server - - __opts= - [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta.pcap" - [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" - [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" - - context_run_bg passt "./pasta ${__opts} -f -t 10002 -T 10003 -u 10002 -U 10003 -P ${STATESETUP}/passt.pid $(${NSTOOL} info -pw ${STATESETUP}/ns.hold)" - - # pidfile isn't created until pasta is ready - wait_for [ -f "${STATESETUP}/passt.pid" ] -} - # setup_passt_in_ns() - Set up namespace (with pasta), run qemu and passt into it setup_passt_in_ns() { context_setup_host host @@ -270,16 +240,6 @@ teardown_passt() { teardown_context_watch ${PANE_GUEST} qemu guest } -# teardown_pasta() - Exit namespace, kill pasta process -teardown_pasta() { - ${NSTOOL} stop "${STATESETUP}/ns.hold" - context_wait unshare - - teardown_context_watch ${PANE_HOST} host - teardown_context_watch ${PANE_PASST} passt - teardown_context_watch ${PANE_NS} unshare ns -} - # teardown_passt_in_ns() - Exit namespace, kill qemu and pasta, remove pid file teardown_passt_in_ns() { context_run ns kill $(cat "${STATESETUP}/qemu.pid") diff --git a/test/pasta/dhcp b/test/pasta/dhcp deleted file mode 100644 index 309001b..0000000 --- a/test/pasta/dhcp +++ /dev/null @@ -1,46 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/pasta/dhcp - Check DHCP and DHCPv6 functionality in pasta mode -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio(a)redhat.com> - -nstools ip jq /sbin/dhclient -htools ip jq - -test Interface name -nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' -check [ -n "__IFNAME__" ] - -test DHCP: address -ns /sbin/dhclient -4 --no-pid __IFNAME__ -nsout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' -hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' -check [ __ADDR__ = __HOST_ADDR__ ] - -test DHCP: route -nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' -hout HOST_GW ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' -check [ __GW__ = __HOST_GW__ ] - -test DHCP: MTU -nsout MTU ip -j link show | jq -rM '.[] | select(.ifname == "__IFNAME__").mtu' -check [ __MTU__ = 65520 ] - -test DHCPv6: address -ns /sbin/dhclient -6 --no-pid __IFNAME__ -hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' -nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local' -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' -check [ __ADDR6__ = __HOST_ADDR6__ ] - -test DHCPv6: route -nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' -hout HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' -check [ __GW6__ = __HOST_GW6__ ] diff --git a/test/pasta/ndp b/test/pasta/ndp deleted file mode 100644 index bb33110..0000000 --- a/test/pasta/ndp +++ /dev/null @@ -1,33 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/pasta/ndp - Check DHCP and DHCPv6 functionality in pasta mode -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio(a)redhat.com> - -nstools ip jq sipcalc grep cut -htools ip jq sipcalc grep cut - -test Interface name -nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' -check [ -n "__IFNAME__" ] -ns ip link set dev __IFNAME__ up -sleep 2 - -test SLAAC: prefix -nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local' -nsout PREFIX6 sipcalc __ADDR6__/64 | grep prefix | cut -d' ' -f4 -hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local' -hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 -check [ "__PREFIX6__" = "__HOST_PREFIX6__" ] - -test SLAAC: route -nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' -hout HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' -check [ __GW6__ = __HOST_GW6__ ] diff --git a/test/pasta/tcp b/test/pasta/tcp deleted file mode 100644 index 6ab18c5..0000000 --- a/test/pasta/tcp +++ /dev/null @@ -1,96 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/pasta/tcp - Check TCP functionality for pasta -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio(a)redhat.com> - -htools socat ip jq -nstools socat ip jq - -set TEMP_BIG __STATEDIR__/test_big.bin -set TEMP_NS_BIG __STATEDIR__/test_ns_big.bin -set TEMP_SMALL __STATEDIR__/test_small.bin -set TEMP_NS_SMALL __STATEDIR__/test_ns_small.bin - -test TCP/IPv4: host to ns: big transfer -nsb socat -u TCP4-LISTEN:10002,bind=127.0.0.1 OPEN:__TEMP_NS_BIG__,create,trunc -host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10002 -nsw -check cmp __BASEPATH__/big.bin __TEMP_NS_BIG__ - -test TCP/IPv4: ns to host (spliced): big transfer -hostb socat -u TCP4-LISTEN:10003,bind=127.0.0.1 OPEN:__TEMP_BIG__,create,trunc -ns socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10003 -hostw -check cmp __BASEPATH__/big.bin __TEMP_BIG__ - -test TCP/IPv4: ns to host (via tap): big transfer -hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc -nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' -ns socat -u OPEN:__BASEPATH__/big.bin TCP4:__GW__:10003 -hostw -check cmp __BASEPATH__/big.bin __TEMP_BIG__ - -test TCP/IPv4: host to ns: small transfer -nsb socat -u TCP4-LISTEN:10002,bind=127.0.0.1 OPEN:__TEMP_NS_SMALL__,create,trunc -host socat OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10002 -nsw -check cmp __BASEPATH__/small.bin __TEMP_NS_SMALL__ - -test TCP/IPv4: ns to host (spliced): small transfer -hostb socat -u TCP4-LISTEN:10003,bind=127.0.0.1 OPEN:__TEMP_SMALL__,create,trunc -ns socat OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10003 -hostw -check cmp __BASEPATH__/small.bin __TEMP_SMALL__ - -test TCP/IPv4: ns to host (via tap): small transfer -hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc -nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' -ns socat -u OPEN:__BASEPATH__/small.bin TCP4:__GW__:10003 -hostw -check cmp __BASEPATH__/small.bin __TEMP_SMALL__ - -test TCP/IPv6: host to ns: big transfer -nsb socat -u TCP6-LISTEN:10002,bind=[::1] OPEN:__TEMP_NS_BIG__,create,trunc -host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10002 -nsw -check cmp __BASEPATH__/big.bin __TEMP_NS_BIG__ - -test TCP/IPv6: ns to host (spliced): big transfer -hostb socat -u TCP6-LISTEN:10003,bind=[::1] OPEN:__TEMP_BIG__,create,trunc -ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10003 -hostw -check cmp __BASEPATH__/big.bin __TEMP_BIG__ - -test TCP/IPv6: ns to host (via tap): big transfer -hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc -nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' -nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' -ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__GW6__%__IFNAME__]:10003 -hostw -check cmp __BASEPATH__/big.bin __TEMP_BIG__ - -test TCP/IPv6: host to ns: small transfer -nsb socat -u TCP6-LISTEN:10002,bind=[::1] OPEN:__TEMP_NS_SMALL__,create,trunc -host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10002 -nsw -check cmp __BASEPATH__/small.bin __TEMP_NS_SMALL__ - -test TCP/IPv6: ns to host (spliced): small transfer -hostb socat -u TCP6-LISTEN:10003,bind=[::1] OPEN:__TEMP_SMALL__,create,trunc -ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10003 -hostw -check cmp __BASEPATH__/small.bin __TEMP_SMALL__ - -test TCP/IPv6: ns to host (via tap): small transfer -hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc -ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[__GW6__%__IFNAME__]:10003 -hostw -check cmp __BASEPATH__/small.bin __TEMP_SMALL__ diff --git a/test/pasta/udp b/test/pasta/udp deleted file mode 100644 index 30e3a85..0000000 --- a/test/pasta/udp +++ /dev/null @@ -1,59 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later -# -# PASST - Plug A Simple Socket Transport -# for qemu/UNIX domain socket mode -# -# PASTA - Pack A Subtle Tap Abstraction -# for network namespace/tap device mode -# -# test/pasta/udp - Check UDP functionality for pasta -# -# Copyright (c) 2021 Red Hat GmbH -# Author: Stefano Brivio <sbrivio(a)redhat.com> - -nstools socat ip jq -htools dd socat ip jq - -set TEMP __STATEDIR__/test.bin -set TEMP_NS __STATEDIR__/test_ns.bin - -test UDP/IPv4: host to ns -nsb socat -u UDP4-LISTEN:10002,bind=127.0.0.1,null-eof OPEN:__TEMP_NS__,create,trunc -host socat OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10002,shut-null -nsw -check cmp __BASEPATH__/medium.bin __TEMP_NS__ - -test UDP/IPv4: ns to host (recvmmsg/sendmmsg) -hostb socat -u UDP4-LISTEN:10003,bind=127.0.0.1,null-eof OPEN:__TEMP__,create,trunc -sleep 1 -ns socat OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10003,shut-null -hostw -check cmp __BASEPATH__/medium.bin __TEMP__ - -test UDP/IPv4: ns to host (via tap) -hostb socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc -nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' -ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:__GW__:10003,shut-null -hostw -check cmp __BASEPATH__/medium.bin __TEMP__ - -test UDP/IPv6: host to ns -nsb socat -u UDP6-LISTEN:10002,bind=[::1],null-eof OPEN:__TEMP_NS__,create,trunc -host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10002,shut-null -nsw -check cmp __BASEPATH__/medium.bin __TEMP_NS__ - -test UDP/IPv6: ns to host (recvmmsg/sendmmsg) -hostb socat -u UDP6-LISTEN:10003,bind=[::1],null-eof OPEN:__TEMP__,create,trunc -sleep 1 -ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10003,shut-null -hostw -check cmp __BASEPATH__/medium.bin __TEMP__ - -test UDP/IPv6: ns to host (via tap) -hostb socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc -nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' -nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' -ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null -hostw -check cmp __BASEPATH__/medium.bin __TEMP__ diff --git a/test/run b/test/run index b800022..f4f5fc8 100755 --- a/test/run +++ b/test/run @@ -64,14 +64,6 @@ run() { perf_init [ ${CI} -eq 1 ] && video_start ci - setup pasta - test pasta/ndp - test pasta/dhcp - test pasta/tcp - test pasta/udp - test passt/shutdown - teardown pasta - setup pasta_options test pasta_options/log_to_file teardown pasta_options -- 2.40.1
Subsequent patches will start converting various parts of the testsuite to use Avocado, rather than our hand-rolled testsuite. While we're in transition, it will be useful to run the equivalent tests side by side in Avocado and the old suite. To that end, take a snapshot of the old testsuite in the new directory oldtest/. Apart from referencing files in the new directory, the only difference is that for now all tests are skipped. As we convert tests, the old versions will be added to oldtest/run so that a reasonably equivalent side by side comparison of the two frameworks can be made. Signed-off-by: David Gibson <david(a)gibson.dropbear.id.au> --- oldtest/.gitignore | 11 + oldtest/Makefile | 203 ++++++++ oldtest/README.md | 137 +++++ oldtest/build/all | 61 +++ oldtest/build/clang_tidy | 17 + oldtest/build/cppcheck | 17 + oldtest/ci | 1 + oldtest/demo/passt | 245 +++++++++ oldtest/demo/pasta | 274 ++++++++++ oldtest/demo/podman | 819 ++++++++++++++++++++++++++++++ oldtest/distro/debian | 252 +++++++++ oldtest/distro/fedora | 396 +++++++++++++++ oldtest/distro/opensuse | 208 ++++++++ oldtest/distro/ubuntu | 216 ++++++++ oldtest/env/mate-terminal.profile | 42 ++ oldtest/find-arm64-firmware.sh | 13 + oldtest/lib/context | 130 +++++ oldtest/lib/layout | 259 ++++++++++ oldtest/lib/layout_ugly | 113 +++++ oldtest/lib/perf_report | 272 ++++++++++ oldtest/lib/setup | 385 ++++++++++++++ oldtest/lib/setup_ugly | 58 +++ oldtest/lib/term | 750 +++++++++++++++++++++++++++ oldtest/lib/test | 398 +++++++++++++++ oldtest/lib/util | 133 +++++ oldtest/lib/video | 152 ++++++ oldtest/memory/passt | 187 +++++++ oldtest/nstool.c | 565 +++++++++++++++++++++ oldtest/passt.mbuto | 83 +++ oldtest/passt.mem.mbuto | 44 ++ oldtest/passt/dhcp | 70 +++ oldtest/passt/ndp | 33 ++ oldtest/passt/shutdown | 19 + oldtest/passt/tcp | 76 +++ oldtest/passt/udp | 46 ++ oldtest/passt_in_ns/icmp | 32 ++ oldtest/passt_in_ns/shutdown | 19 + oldtest/passt_in_ns/tcp | 256 ++++++++++ oldtest/passt_in_ns/udp | 138 +++++ oldtest/pasta/dhcp | 46 ++ oldtest/pasta/ndp | 33 ++ oldtest/pasta/tcp | 96 ++++ oldtest/pasta/udp | 59 +++ oldtest/pasta_options/log_to_file | 93 ++++ oldtest/perf/passt_tcp | 215 ++++++++ oldtest/perf/passt_udp | 165 ++++++ oldtest/perf/pasta_tcp | 300 +++++++++++ oldtest/perf/pasta_udp | 219 ++++++++ oldtest/prepare-distro-img.sh | 18 + oldtest/run | 238 +++++++++ oldtest/run_demo | 1 + oldtest/two_guests/basic | 80 +++ oldtest/valgrind.supp | 9 + 53 files changed, 8702 insertions(+) create mode 100644 oldtest/.gitignore create mode 100644 oldtest/Makefile create mode 100644 oldtest/README.md create mode 100644 oldtest/build/all create mode 100644 oldtest/build/clang_tidy create mode 100644 oldtest/build/cppcheck create mode 120000 oldtest/ci create mode 100644 oldtest/demo/passt create mode 100644 oldtest/demo/pasta create mode 100644 oldtest/demo/podman create mode 100644 oldtest/distro/debian create mode 100644 oldtest/distro/fedora create mode 100644 oldtest/distro/opensuse create mode 100644 oldtest/distro/ubuntu create mode 100644 oldtest/env/mate-terminal.profile create mode 100755 oldtest/find-arm64-firmware.sh create mode 100644 oldtest/lib/context create mode 100644 oldtest/lib/layout create mode 100644 oldtest/lib/layout_ugly create mode 100755 oldtest/lib/perf_report create mode 100755 oldtest/lib/setup create mode 100755 oldtest/lib/setup_ugly create mode 100755 oldtest/lib/term create mode 100755 oldtest/lib/test create mode 100755 oldtest/lib/util create mode 100755 oldtest/lib/video create mode 100644 oldtest/memory/passt create mode 100644 oldtest/nstool.c create mode 100755 oldtest/passt.mbuto create mode 100755 oldtest/passt.mem.mbuto create mode 100644 oldtest/passt/dhcp create mode 100644 oldtest/passt/ndp create mode 100644 oldtest/passt/shutdown create mode 100644 oldtest/passt/tcp create mode 100644 oldtest/passt/udp create mode 100644 oldtest/passt_in_ns/icmp create mode 100644 oldtest/passt_in_ns/shutdown create mode 100644 oldtest/passt_in_ns/tcp create mode 100644 oldtest/passt_in_ns/udp create mode 100644 oldtest/pasta/dhcp create mode 100644 oldtest/pasta/ndp create mode 100644 oldtest/pasta/tcp create mode 100644 oldtest/pasta/udp create mode 100644 oldtest/pasta_options/log_to_file create mode 100644 oldtest/perf/passt_tcp create mode 100644 oldtest/perf/passt_udp create mode 100644 oldtest/perf/pasta_tcp create mode 100644 oldtest/perf/pasta_udp create mode 100755 oldtest/prepare-distro-img.sh create mode 100755 oldtest/run create mode 120000 oldtest/run_demo create mode 100644 oldtest/two_guests/basic create mode 100644 oldtest/valgrind.supp diff --git a/oldtest/.gitignore b/oldtest/.gitignore new file mode 100644 index 0000000..4837402 --- /dev/null +++ b/oldtest/.gitignore @@ -0,0 +1,11 @@ +test_logs/ +mbuto/ +*.img +QEMU_EFI.fd +*.qcow2 +*.raw +*.raw.xz +*.bin +nstool +guest-key +guest-key.pub diff --git a/oldtest/Makefile b/oldtest/Makefile new file mode 100644 index 0000000..7b00bef --- /dev/null +++ b/oldtest/Makefile @@ -0,0 +1,203 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Tests makefile +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +WGET = wget -c + +DEBIAN_IMGS = debian-8.11.0-openstack-amd64.qcow2 \ + debian-9-nocloud-amd64-daily-20200210-166.qcow2 \ + debian-10-nocloud-amd64.qcow2 \ + debian-10-generic-arm64.qcow2 \ + debian-10-generic-ppc64el-20220911-1135.qcow2 \ + debian-11-nocloud-amd64.qcow2 \ + debian-11-generic-arm64.qcow2 \ + debian-11-generic-ppc64el.qcow2 \ + debian-sid-nocloud-amd64-daily.qcow2 \ + debian-sid-nocloud-arm64-daily.qcow2 \ + debian-sid-nocloud-ppc64el-daily.qcow2 + +FEDORA_IMGS = Fedora-Cloud-Base-26-1.5.x86_64.qcow2 \ + Fedora-Cloud-Base-27-1.6.x86_64.qcow2 \ + Fedora-Cloud-Base-28-1.1.x86_64.qcow2 \ + Fedora-Cloud-Base-28-1.1.aarch64.qcow2 \ + Fedora-Cloud-Base-29-1.2.x86_64.qcow2 \ + Fedora-Cloud-Base-29-1.2.aarch64.qcow2 \ + Fedora-Cloud-Base-30-1.2.x86_64.qcow2 \ + Fedora-Cloud-Base-30-1.2.aarch64.qcow2 \ + Fedora-Cloud-Base-31-1.9.x86_64.qcow2 \ + Fedora-Cloud-Base-31-1.9.aarch64.qcow2 \ + Fedora-Cloud-Base-32-1.6.x86_64.qcow2 \ + Fedora-Cloud-Base-32-1.6.aarch64.qcow2 \ + Fedora-Cloud-Base-33-1.2.x86_64.qcow2 \ + Fedora-Cloud-Base-33-1.2.aarch64.qcow2 \ + Fedora-Cloud-Base-34-1.2.x86_64.qcow2 \ + Fedora-Cloud-Base-34-1.2.aarch64.qcow2 \ + Fedora-Cloud-Base-35-1.2.x86_64.qcow2 \ + Fedora-Cloud-Base-35-1.2.aarch64.qcow2 + +OPENSUSE_IMGS = openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2 \ + openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2 \ + openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2 \ + openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz \ + openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz \ + openSUSE-Tumbleweed-JeOS.x86_64-kvm-and-xen.qcow2 + +UBUNTU_OLD_IMGS = trusty-server-cloudimg-amd64-disk1.img \ + trusty-server-cloudimg-i386-disk1.img \ + trusty-server-cloudimg-ppc64el-disk1.img +UBUNTU_NEW_IMGS = xenial-server-cloudimg-powerpc-disk1.img \ + jammy-server-cloudimg-s390x.img +UBUNTU_IMGS = $(UBUNTU_OLD_IMGS) $(UBUNTU_NEW_IMGS) + +DOWNLOAD_ASSETS = mbuto \ + $(DEBIAN_IMGS) $(FEDORA_IMGS) $(OPENSUSE_IMGS) $(UBUNTU_IMGS) +TESTDATA_ASSETS = small.bin big.bin medium.bin +LOCAL_ASSETS = mbuto.img mbuto.mem.img QEMU_EFI.fd \ + $(DEBIAN_IMGS:%=prepared-%) $(FEDORA_IMGS:%=prepared-%) \ + $(UBUNTU_NEW_IMGS:%=prepared-%) \ + nstool guest-key guest-key.pub \ + $(TESTDATA_ASSETS) + +ASSETS = $(DOWNLOAD_ASSETS) $(LOCAL_ASSETS) + +CFLAGS = -Wall -Werror -Wextra -pedantic -std=c99 + +assets: $(ASSETS) + +mbuto: + git clone git://mbuto.sh/mbuto + +guest-key guest-key.pub: + ssh-keygen -f guest-key -N '' + +mbuto.img: passt.mbuto mbuto guest-key.pub $(TESTDATA_ASSETS) + ./mbuto/mbuto -p ./$< -c lz4 -f $@ + +mbuto.mem.img: passt.mem.mbuto mbuto ../passt.avx2 + ./mbuto/mbuto -p ./$< -c lz4 -f $@ + +nstool: nstool.c + $(CC) $(CFLAGS) -o $@ $^ + +QEMU_EFI.fd: + ./find-arm64-firmware.sh $@ + +prepared-%.qcow2: %.qcow2 ./prepare-distro-img.sh + qemu-img create -f qcow2 -F qcow2 -b $< $@ + ./prepare-distro-img.sh $@ + +prepared-%.img: %.img ./prepare-distro-img.sh + qemu-img create -f qcow2 -F qcow2 -b $< $@ + ./prepare-distro-img.sh $(IMGTYPE) $@ + +small.bin: + dd if=/dev/urandom bs=2k count=1 of=$@ + +medium.bin: + dd if=/dev/urandom bs=1k count=5 of=$@ + +big.bin: + dd if=/dev/urandom bs=1M count=10 of=$@ + +check: assets + ./run + +debug: assets + DEBUG=1 ./run + +clean: + rm -f perf.js *~ + rm -f $(LOCAL_ASSETS) + rm -rf test_logs + rm -f prepared-*.qcow2 prepared-*.img + +realclean: clean + rm -rf $(DOWNLOAD_ASSETS) + +# Debian downloads +debian-8.11.0-openstack-%.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/OpenStack/archive/8.11.0/debian-8.11.… + +debian-9-nocloud-%-daily-20200210-166.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/stretch/daily/20200210-166/debian-9-n… + +debian-10-nocloud-%.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-nocloud-$*.qc… + +debian-10-generic-ppc64el-20220911-1135.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/20220911-1135/debian-10-generi… + +debian-10-generic-%.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/buster/latest/debian-10-generic-$*.qc… + +debian-11-nocloud-%.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-nocloud-$*.… + +debian-11-generic-%.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-$*.… + +debian-sid-nocloud-%-daily.qcow2: + $(WGET) -O $@ https://cloud.debian.org/images/cloud/sid/daily/latest/debian-sid-nocloud-$… + +# Fedora downloads +Fedora-Cloud-Base-26-1.5.%.qcow2: + $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/26/Clou… + +Fedora-Cloud-Base-27-1.6.%.qcow2: + $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/27/Clou… + +Fedora-Cloud-Base-28-1.1.%.qcow2: + $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/28/Clou… + +Fedora-Cloud-Base-29-1.2.%.qcow2: + $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/29/Clou… + +Fedora-Cloud-Base-30-1.2.%.qcow2: + $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/30/Clou… + +Fedora-Cloud-Base-31-1.9.%.qcow2: + $(WGET) -O $@ http://archives.fedoraproject.org/pub/archive/fedora/linux/releases/31/Clou… + +Fedora-Cloud-Base-32-1.6.%.qcow2: + $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/32/Clo… + +Fedora-Cloud-Base-33-1.2.%.qcow2: + $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/33/Clo… + +Fedora-Cloud-Base-34-1.2.%.qcow2: + $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/34/Clo… + +Fedora-Cloud-Base-35-1.2.%.qcow2: + $(WGET) -O $@ https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/35/Clo… + +# OpenSuSE downloads +openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2: + $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.1/jeos/openSUSE-Leap-15.… + +openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2: + $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.2/appliances/openSUSE-Le… + +openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2: + $(WGET) -O $@ https://download.opensuse.org/distribution/leap/15.3/appliances/openSUSE-Le… + +openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz: + $(WGET) -O $@ http://download.opensuse.org/ports/aarch64/tumbleweed/appliances/openSUSE-T… + +openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz: + $(WGET) -O $@ http://download.opensuse.org/ports/armv7hl/tumbleweed/appliances/openSUSE-T… + +openSUSE-Tumbleweed-JeOS.x86_64-kvm-and-xen.qcow2: + $(WGET) -O $@ https://download.opensuse.org/tumbleweed/appliances/openSUSE-Tumbleweed-JeO… + +# Ubuntu downloads +trusty-server-cloudimg-%-disk1.img: + $(WGET) -O $@ https://cloud-images.ubuntu.com/trusty/current/trusty-server-cloudimg-$*-di… + +xenial-server-cloudimg-powerpc-disk1.img: + $(WGET) -O $@ https://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-power… + +jammy-server-cloudimg-s390x.img: + $(WGET) -O $@ https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-s390x.i… diff --git a/oldtest/README.md b/oldtest/README.md new file mode 100644 index 0000000..03c7f57 --- /dev/null +++ b/oldtest/README.md @@ -0,0 +1,137 @@ +<!--- +SPDX-License-Identifier: GPL-2.0-or-later +Copyright (c) 2021-2022 Red Hat GmbH +Author: Stefano Brivio <sbrivio(a)redhat.com> +--> + +# Scope + +This directory contains test cases for _passt_ and _pasta_ and a simple +POSIX shell-based framework to define them, and run them as a suite. + +These tests can be run as part of a continuous integration workflow, and are +also used to provide short usage demos, with video recording, for _passt_ and +_pasta_ basic use cases. + +# Run + +## Dependencies + +### Packages + +The tests require some package dependencies commonly available in Linux +distributions. If some packages are not available, the test groups that need +them will be selectively skipped. + +This is a non-exhaustive list of packages that might not commonly be installed +on a system, i.e. common utilities such as a shell are not included here. + +Example for Debian, and possibly most Debian-based distributions: + + build-essential git jq strace iperf3 qemu-system-x86 tmux sipcalc bc + clang-tidy cppcheck isc-dhcp-common psmisc linux-cpupower socat + netcat-openbsd fakeroot lz4 lm-sensors qemu-system-arm qemu-system-ppc + qemu-system-misc qemu-system-x86 valgrind + +NOTE: the tests need a qemu version >= 7.2, or one that contains commit +13c6be96618c ("net: stream: add unix socket"): this change introduces support +for UNIX domain sockets as network device back-end, which qemu uses to connect +to passt. + +### Other tools + +Test measuring request-response and connect-request-response latencies use +`neper`, which is not commonly packaged by distributions and needs to be built +and installed manually: + + git clone https://github.com/google/neper + cd neper; make + cp tcp_crr tcp_rr udp_rr /usr/local/bin + +Virtual machine images are built during test executions using +[mbuto](https://mbuto.lameexcu.se/), the shell script is sourced via _git_ +as needed, so there's no need to actually install it. + +### Kernel parameters + +Performance tests use iperf3 with rather large TCP receiving and sending +windows, to decrease the likelihood of iperf3 itself becoming the bottleneck. +These values need to be allowed by the kernel of the host running the tests. +Example for /etc/sysctl.conf: + + net.core.rmem_max = 134217728 + net.core.wmem_max = 134217728 + +Further, the passt demo uses perf(1), relying on hardware events for performance +counters, to display syscall overhead. The kernel needs to allow unprivileged +users to access these events. Suggested entry for /etc/sysctl.conf: + + kernel.perf_event_paranoid = -1 + +### Special requirements for continuous integration and demo modes + +Running the test suite as continuous integration or demo modes will record the +terminal with the steps being executed, using asciinema(1), and create binary +packages. + +The following additional packages are commonly needed: + + alien asciinema linux-perf tshark + +## Regular test + +Just issue: + + ./run + +from the `test` directory. Elevated privileges are not needed. Environment +variable settings: DEBUG=1 enables debugging messages, TRACE=1 enables tracing +(further debugging messages), PCAP=1 enables packet captures. Example: + + PCAP=1 TRACE=1 ./run + +## Running selected tests + +Rudimentary support to run a list of selected tests, without support for +dependencies, is available. Tests need to have a setup function corresponding to +their path. For example: + + ./run passt/ndp passt/dhcp pasta/ndp + +will call the 'passt' setup function (from lib/setup), run the two corresponding +tests, call the 'passt' teardown function, the 'pasta' setup, run the pasta/ndp +test, and finally tear down the 'pasta' setup. + +Note that requirements on steps implemented by related tests are not handled. +For example, if the 'passt/tcp' needs guest connectivity set up by the +'passt/ndp' and 'passt/dhcp' tests, those need to be listed explicitly. + +## Continuous integration + +Issuing: + + ./ci + +will run the whole test suite while recording the execution, and it will also +build JavaScript fragments used on http://passt.top/ for performance data tables +and links to specific offsets in the captures. + +## Demo mode + +Issuing: + + ./demo + +will run the demo cases under `demo`, with terminal captures as well. + +# Framework + +The implementation of the testing framework is under `lib`, and it provides +facilities for terminal and _tmux_ session management, interpretation of test +directives, video recording, and suchlike. Test cases are organised in the +remaining directories. + +Test cases can be implemented as POSIX shell scripts, or as a set of directives, +which are not formally documented here, but should be clear enough from the +existing cases. The entry point for interpretation of test directives is +implemented in `lib/test`. diff --git a/oldtest/build/all b/oldtest/build/all new file mode 100644 index 0000000..1f79e0d --- /dev/null +++ b/oldtest/build/all @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/build/all - Build targets, one by one, then all together, check output +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +htools make cc rm uname getconf mkdir cp rm man + +test Build passt +host make clean +check ! [ -e passt ] +host CFLAGS="-Werror" make passt +check [ -f passt ] + +test Build pasta +host make clean +check ! [ -e pasta ] +host CFLAGS="-Werror" make pasta +check [ -h pasta ] + +test Build qrap +host make clean +check ! [ -e qrap ] +host CFLAGS="-Werror" make qrap +check [ -f qrap ] + +test Build all +host make clean +check ! [ -e passt ] +check ! [ -e pasta ] +check ! [ -e qrap ] +host CFLAGS="-Werror" make +check [ -f passt ] +check [ -h pasta ] +check [ -f qrap ] + +test Install +host mkdir __STATEDIR__/prefix +host prefix=__STATEDIR__/prefix make install +check [ -f __STATEDIR__/prefix/bin/passt ] +check [ -h __STATEDIR__/prefix/bin/pasta ] +check [ -f __STATEDIR__/prefix/bin/qrap ] +check man -M __STATEDIR__/prefix/share/man -W passt +check man -M __STATEDIR__/prefix/share/man -W pasta +check man -M __STATEDIR__/prefix/share/man -W qrap + +test Uninstall +host prefix=__STATEDIR__/prefix make uninstall +check ! [ -f __STATEDIR__/prefix/bin/passt ] +check ! [ -h __STATEDIR__/prefix/bin/pasta ] +check ! [ -f __STATEDIR__/prefix/bin/qrap ] +check ! man -M __STATEDIR__/prefix/share/man -W passt 2>/dev/null +check ! man -M __STATEDIR__/prefix/share/man -W pasta 2>/dev/null +check ! man -M __STATEDIR__/prefix/share/man -W qrap 2>/dev/null diff --git a/oldtest/build/clang_tidy b/oldtest/build/clang_tidy new file mode 100644 index 0000000..40573bf --- /dev/null +++ b/oldtest/build/clang_tidy @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/build/clang_tidy - Run source through clang-tidy(1) linter +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +htools clang-tidy + +test Run clang-tidy +host make clang-tidy diff --git a/oldtest/build/cppcheck b/oldtest/build/cppcheck new file mode 100644 index 0000000..0e1dbce --- /dev/null +++ b/oldtest/build/cppcheck @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/build/cppcheck - Run source through cppcheck(1) linter +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +htools cppcheck + +test Run cppcheck +host make cppcheck diff --git a/oldtest/ci b/oldtest/ci new file mode 120000 index 0000000..e5224d5 --- /dev/null +++ b/oldtest/ci @@ -0,0 +1 @@ +run \ No newline at end of file diff --git a/oldtest/demo/passt b/oldtest/demo/passt new file mode 100644 index 0000000..a3c18b8 --- /dev/null +++ b/oldtest/demo/passt @@ -0,0 +1,245 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/demo/passt - Quick introduction to passt +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +say This is a short introduction to +em passt +say . +nl +nl +sleep 3 + +say Let's fetch the source +sleep 1 +host cd __STATEDIR__ +host git clone git://passt.top/passt +sleep 1 + +say and build it. +sleep 1 +host cd passt +host make +sleep 1 + +nl +nl +say A quick look at the man page... +sleep 1 +hostb man ./passt.1 +sleep 5 +hostb /ports +sleep 2 +hostb n +sleep 2 +hostb n +sleep 10 + +nl +say '-t' to forward TCP ports. +sleep 3 +host q + +nl +nl +say Let's create a small initramfs image for the guest. +guest cd __STATEDIR__ +guest git clone git://mbuto.sh/mbuto +guest ./mbuto/mbuto -f passt.img -p passt/test/passt.mbuto -c lz4 +sleep 2 + +nl +nl +say We want to isolate passt and guest in a +nl +say network namespace. For convenience, we'll +nl +say create it with 'pasta', see also the +nl +say 'pasta' demo above. +sleep 3 + +passt cd __STATEDIR__/passt +passtb ./pasta -P pasta.pid +sleep 3 +passt /sbin/dhclient -4 --no-pid +sleep 2 +passt /sbin/dhclient -6 --no-pid +sleep 2 + +nl +nl +say Now let's run 'passt' in the new namespace, and +nl +say enter this namespace from the guest terminal too. +sleep 3 +guest cd passt +gout TARGET_PID pgrep -P $(cat pasta.pid) +sleep 1 + +passtb ./passt -f -t 10001,10003 -s __STATEDIR__/passt.socket +sleep 2 + +guest nsenter -t __TARGET_PID__ -U -n --preserve-credentials +sleep 5 + +nl +nl +say We're ready to start qemu +nl +sleep 2 +hout VMLINUZ echo "/boot/vmlinuz-$(uname -r)" +guest qemu-system-x86_64 -enable-kvm -m 4096 -cpu host -smp 4 -kernel __VMLINUZ__ -initrd ../passt.img -nographic -serial stdio -nodefaults -append "console=ttyS0" -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +sleep 10 + +nl +nl +guest ip link show +sleep 3 +say Guest is up. Let's configure IPv4 first... +sleep 2 +guest ip link set dev eth0 up +sleep 2 +guest dhclient -4 +sleep 2 +guest ip addr show +sleep 5 + +nl +say SLAAC is already done, but we can also +nl +say get another address via DHCPv6. +sleep 3 +guest dhclient -6 +sleep 3 + +nl +nl +say Let's try to communicate between host and guest. +sleep 2 +guestb socat TCP6-LISTEN:10001 STDIO +sleep 2 +host echo "Hello from the host" | socat -u STDIN TCP6:[::1]:10001 +sleep 5 + +nl +nl +say Now the other way around... using +nl +say the address of the default gateway. +sleep 2 +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +sleep 5 +hostb socat TCP4-LISTEN:31337 STDIO +sleep 2 +guest echo "Hello from the guest" | socat -u STDIN TCP4:__GW__:31337 +sleep 3 + +nl +nl +say Let's have a (quick!) look at performance +nl +say more in the "Performance" section below. +sleep 3 + +host nsenter -t __TARGET_PID__ -U -n --preserve-credentials + +guest /sbin/sysctl -w net.core.rmem_max=536870912 +guest /sbin/sysctl -w net.core.wmem_max=536870912 +guest /sbin/sysctl -w net.core.rmem_default=33554432 +guest /sbin/sysctl -w net.core.wmem_default=33554432 +guest /sbin/sysctl -w net.ipv4.tcp_rmem="4096 131072 268435456" +guest /sbin/sysctl -w net.ipv4.tcp_wmem="4096 131072 268435456" +guest /sbin/sysctl -w net.ipv4.tcp_timestamps=0 + +host sysctl -w net.ipv4.tcp_rmem="4096 524288 134217728" +host sysctl -w net.ipv4.tcp_wmem="4096 524288 134217728" +host sysctl -w net.ipv4.tcp_timestamps=0 + +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +nl +nl +info Throughput in Gbps, latency in µs +th flow host>guest guest>host + +set OPTS -P4 -w 64M -l 1M -i1 --pacing-timer 100000 + +tr TCP/IPv6 throughput +hostb sleep 10; iperf3 -c ::1 -p 10001 __OPTS__ +gout BW iperf3 -s1J -p 10001 | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 2.0 3.0 +sleep 5 +guestb sleep 10; iperf3 -c __GW6__%__IFNAME__ -p 10002 __OPTS__ -O3 +hout BW iperf3 -s1J -p 10002 | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 2.0 3.0 + +tl TCP/IPv6 RR latency +guestb tcp_rr -C 10001 -P 10003 -6 --nolog +sleep 2 +hout LAT tcp_rr -C 10001 -P 10003 --nolog -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 +hostb tcp_rr -6 --nolog +sleep 2 +gout LAT tcp_rr --nolog -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 + +tl TCP/IPv6 CRR latency +guestb tcp_crr -C 10001 -P 10003 -6 --nolog +sleep 2 +hout LAT tcp_crr -C 10001 -P 10003 --nolog -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 +hostb tcp_crr -6 --nolog +sleep 2 +gout LAT tcp_crr --nolog -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 + +tr TCP/IPv4 throughput +hostb sleep 10; iperf3 -c 127.0.0.1 -p 10001 __OPTS__ +gout BW iperf3 -p 10001 -s1J | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 2.0 3.0 +sleep 5 +guestb sleep 10; iperf3 -c __GW__ -p 10002 __OPTS__ -O3 +hout BW iperf3 -s1J -p 10002 | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 2.0 3.0 + +tl TCP/IPv4 RR latency +guestb tcp_rr -C 10001 -P 10003 -4 --nolog +sleep 2 +hout LAT tcp_rr -C 10001 -P 10003 --nolog -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 +hostb tcp_rr -4 --nolog +sleep 2 +gout LAT tcp_rr --nolog -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 + +tl TCP/IPv4 CRR latency +guestb tcp_crr -C 10001 -P 10003 -4 --nolog +sleep 2 +hout LAT tcp_crr -C 10001 -P 10003 --nolog -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 +hostb tcp_crr -4 --nolog +sleep 2 +gout LAT tcp_crr --nolog -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 800 +sleep 2 + +nl +nl +say Thanks for watching! +sleep 5 diff --git a/oldtest/demo/pasta b/oldtest/demo/pasta new file mode 100644 index 0000000..f48585d --- /dev/null +++ b/oldtest/demo/pasta @@ -0,0 +1,274 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/demo/pasta - Quick introduction to pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +say This is a short introduction to +em pasta +say . +nl +nl +sleep 3 + +say Let's fetch the source +sleep 1 +host cd __STATEDIR__ +host git clone git://passt.top/passt +sleep 1 + +say and build it. +sleep 1 +host cd passt +host make +sleep 1 + +nl +nl +say A quick look at the man page... +sleep 1 +hostb man ./pasta.1 +sleep 5 +hostb /pasta +sleep 2 +hostb n +sleep 2 +hostb n +sleep 10 + +nl +say without PID, it will create a namespace. +sleep 3 +passt cd __STATEDIR__/passt +passtb ./pasta -P pasta.pid +sleep 3 + +nl +nl +say For convenience, let's enter this namespace +nl +say from another terminal. +sleep 3 +ns cd __STATEDIR__/passt +nsout TARGET_PID pgrep -P $(cat pasta.pid) +sleep 1 + +ns nsenter -t __TARGET_PID__ -U -n --preserve-credentials +sleep 5 + +nl +nl +say Now, we're ready to configure networking. +sleep 2 +host q + +nl +nl +ns ip link show +sleep 3 +say Let's configure IPv4 first... +sleep 2 +ns /sbin/dhclient -4 --no-pid +sleep 2 +ns ip addr show +sleep 5 + +nl +say SLAAC is already done, but we can also +nl +say get another address via DHCPv6. +sleep 3 +ns /sbin/dhclient -6 --no-pid +sleep 3 + +nl +nl +say Let's try to communicate between host and namespace +sleep 2 +nl +say ...there's no need to configure port forwarding, +nl +say pasta detects bound ports and forwards them. +sleep 3 + +nsb socat TCP6-LISTEN:31337,bind=[::1] STDOUT +sleep 2 +host echo "Hello from the host" | socat -u STDIN TCP6:[::1]:31337 +sleep 5 + +nl +nl +say Now the other way around... +nl +say we can use a loopback address +sleep 2 +hostb socat TCP6-LISTEN:31337,bind=[::1] STDIO +sleep 2 +ns echo "Hello from the namespace" | socat -u STDIN TCP6:[::1]:31337 +sleep 5 + +nl +say or the address of the default gateway. +sleep 2 +nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +sleep 5 +hostb socat TCP4-LISTEN:31337 STDIO +sleep 2 +ns echo "Hello from the namespace" | socat -u STDIN TCP4:__GW__:31337 +sleep 3 + +nl +nl +say UDP... +sleep 2 +ns host -t A passt.top +sleep 3 +say seems to work too. +sleep 3 + +nl +nl +em pasta +say can also take packet captures. +sleep 3 +passt exit +sleep 2 +passtb ./pasta -p ../demo_pasta.pcap +sleep 2 +passt +passt /sbin/dhclient -4 --no-pid +sleep 2 +hostb tshark -r ../demo_pasta.pcap +sleep 5 + +nl +nl +say And there are tons of totally useless +sleep 1 +bsp 14 +say absolutely useful features +nl +say you can find described in the man page. +sleep 5 + +nl +nl +say Let's have a (quick!) look at performance +nl +say more in the "Performance" section below. +sleep 3 +ns exit +passt exit +passt make clean +passt CFLAGS="-g" make +sleep 2 +passtb perf record -g ./pasta -P pasta.pid +sleep 2 + +nsout TARGET_PID pgrep -P $(cat pasta.pid) +sleep 1 +ns nsenter -t __TARGET_PID__ -U -n --preserve-credentials +sleep 5 + +nl +nl +info Throughput in Gbps, latency in µs +th flow init>ns ns>init + +set OPTS -P4 -l 1M -w 32M -i1 --pacing-timer 100000 + +tr TCP/IPv6 throughput +hostb sleep 10; iperf3 -c ::1 -p 10001 __OPTS__ +nsout BW iperf3 -s1J -p 10001 | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 10.0 20.0 +sleep 5 +nsb sleep 10; iperf3 -c ::1 -p 10001 __OPTS__ +hout BW iperf3 -s1J -p 10001 | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 10.0 20.0 + +tl TCP/IPv6 RR latency +nsb tcp_rr -6 --nolog +sleep 2 +hout LAT tcp_rr --nolog -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 +hostb tcp_rr -6 --nolog +sleep 2 +nsout LAT tcp_rr --nolog -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 + +tl TCP/IPv6 CRR latency +nsb tcp_crr -6 --nolog +sleep 2 +hout LAT tcp_crr --nolog -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 +hostb tcp_crr -6 --nolog +sleep 2 +nsout LAT tcp_crr --nolog -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 + +tr TCP/IPv4 throughput +hostb sleep 10; iperf3 -c 127.0.0.1 -p 10001 __OPTS__ +nsout BW iperf3 -s1J -p 10001 | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 10.0 20.0 +sleep 5 +nsb sleep 10; iperf3 -c 127.0.0.1 -p 10001 __OPTS__ +hout BW iperf3 -s1J -p 10001 | jq -rM ".end.sum_received.bits_per_second" +bw __BW__ 10.0 20.0 + +tl TCP/IPv4 RR latency +nsb tcp_rr -4 --nolog +sleep 2 +hout LAT tcp_rr --nolog -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 +hostb tcp_rr -4 --nolog +sleep 2 +nsout LAT tcp_rr --nolog -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 + +tl TCP/IPv4 CRR latency +nsb tcp_crr -4 --nolog +sleep 2 +hout LAT tcp_crr --nolog -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 +hostb tcp_crr -4 --nolog +sleep 2 +nsout LAT tcp_crr --nolog -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 1000 500 +sleep 2 + +sleep 5 +passt exit +sleep 2 +killp PASST +killp HOST +sleep 2 +nsb perf report -g --max-stack 3 +sleep 10 + +nl +nl +say I +em knew +say it. +em syscalls +say . +sleep 5 + +nl +nl +say Thanks for watching! +sleep 5 diff --git a/oldtest/demo/podman b/oldtest/demo/podman new file mode 100644 index 0000000..edd403a --- /dev/null +++ b/oldtest/demo/podman @@ -0,0 +1,819 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/demo/podman - Show pasta operation with Podman +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +set OPTS -Z -w 4M -l 1M -P 2 -t10 --pacing-timer 10000 + +say This is an overview of +em Podman +say using +em pasta +say . +nl +nl +sleep 3 + +say Let's fetch Podman +sleep 1 +host git -C __STATEDIR__ clone https://github.com/containers/podman.git +sleep 1 + +say , patch it +sleep 1 +host cp ../contrib/podman/0001-libpod-Add-pasta-networking-mode.patch __STATEDIR__/podman +host cd __STATEDIR__/podman +host git am -3 0001-libpod-Add-pasta-networking-mode.patch +sleep 1 + +say , and build it. +host go get github.com/pkg/errors@v0.9.1 +host go mod vendor +host make +sleep 1 + +nl +nl +say By default, for +em rootless +say mode, Podman will pick +nl +em slirp4netns +say to operate the network. +nl +nl +say Let's start a container with it +sleep 1 + +ns1 cd __STATEDIR__/podman +ns1b ./bin/podman run --rm -ti alpine sh +sleep 2 + +say , +nl +say and one with +em pasta +say instead. + +ns2 cd __STATEDIR__/podman +ns2b ./bin/podman run --net=pasta --rm -ti alpine sh +sleep 2 + +nl +nl +say We can observe some practical differences: +nl + +ns1b ip addr show +sleep 3 +say - slirp4netns uses a predefined IPv4 address +hl NS1 +sleep 2 + +ns2b ip addr show +sleep 3 +say , +nl +say pasta copies addresses from the host +hl NS2 +sleep 2 + +nl +say - slirp4netns uses +em tap0 +say as interface name +hl NS1 +sleep 2 + +say , pasta +nl +say takes an interface name from the host +hl NS2 +sleep 2 + +nl +say - same for routes: + +ns1b ip route show +sleep 3 +say slirp4netns defines its own +nl +say gateway address +hl NS1 +sleep 2 + +say , pasta copies it from the host +ns2b ip route show +ns2b ip -6 route show +sleep 5 + +nl +nl +say Let's check connectivity... +sleep 2 +ns1b wget risotto.milane.se +ns2b wget myfinge.rs +sleep 2 +say fine. +sleep 5 +nl +nl + +say Let's run a service in the container, +nl +say configuring port forwarding first +sleep 5 + +ns1b exit +sleep 2 +ns1b podman run --rm -p 8080:8080/tcp -ti alpine sh +sleep 5 + +ns2b exit +sleep 2 +ns2b ./bin/podman run --net=pasta --rm -p 8081:8081/tcp -ti alpine sh +sleep 5 + +nl +nl +say ...and now actually start the service +ns1b apk add thttpd +ns2b apk add thttpd +ns1b >index.html cat << EOF +ns1b <!doctype html><body>Hello via slirp4netns</body> +ns1b EOF +ns2b >index.html cat << EOF +ns2b <!doctype html><body>Hello via pasta</body> +ns2b EOF +ns1b thttpd -p 8080 +ns2b thttpd -p 8081 + +sleep 3 +say , then check +nl +say that it's accessible. +sleep 3 + +hostb lynx http://127.0.0.1:8080/ +sleep 5 +hostb q +hostb lynx http://[::1]:8081/ +sleep 5 +hostb q +sleep 2 + +nl +nl +say What about performance, you might ask. +nl +say For simplicity, we'll measure between init +nl +say namespace (the "host") and container. To do +nl +say that, we need to allow the container direct +nl +say access to the host, which needs an extra option +nl +say in slirp4netns. Let's restart that container, +nl +say while also mapping ports for iperf3 and neper. +nl +sleep 3 + +ns1 exit + +ns1b podman run --rm --net=slirp4netns:allow_host_loopback=true,enable_ipv6=true -p 5221-5222:5221-5222/tcp -p 5221-5222:5221-5222/udp -ti alpine sh +sleep 5 +nl +nl +say pasta allows that by default, so we wouldn't need +nl +say to touch the container using pasta, but let's +nl +say take the chance to look at passing extra options +nl +say there as well. +nl +nl +ns2 exit + +say Options after '--net=pasta:' are the same as +nl +say documented for the command line of pasta(1). +nl +say For example, we can enable packet captures +sleep 3 +ns2b ./bin/podman run --net=pasta:--pcap,demo.pcap --rm -ti alpine sh +sleep 5 + +say , +nl +say and generate some traffic we can look at. +nl +sleep 2 +ns2b wget -O - lameexcu.se +sleep 2 +hostb tshark -r demo.pcap tcp +sleep 5 + +nl +say But back to performance now. By the way, +nl +say pasta can also forward ports through the +nl +say loopback interface for improved throughput. +nl +say Let's configure that. +nl +sleep 2 +ns2b exit +sleep 1 +ns2b ./bin/podman run --net=pasta:-T,5213-5214,-U,5213-5214 -p 5223-5224:5223-5224/tcp -p 5223-5224:5223-5224/udp --rm -ti alpine sh +sleep 5 + +nl +say In slirp4netns mode, Podman enables by +nl +say default the port forwarder from 'rootlesskit' +nl +say for better performance. +nl +say However, it can't be used for non-local +nl +say mappings (traffic without loopback source +nl +em and +say destination) because it doesn't preserve +nl +say the correct source address as it forwards +nl +say packets to the container. +sleep 3 +nl +nl +say We'll check non-loopback mappings first for +nl +say both pasta and slirp4netns, then restart the +nl +say slirp4netns container with rootlesskit and +nl +say switch to loopback mappings. pasta doesn't +nl +say have this limitation. +nl +nl +say One last note: slirp4netns doesn't support +nl +say forwarding of IPv6 ports (to the container): +nl +say github.com/rootless-containers/slirp4netns/issues/253 +nl +say so we'll skip IPv6 tests for slirp4netns as +nl +say port forwarder (on the path to the container). + +sleep 5 +ns1 exit +ns1b podman run --rm --net=slirp4netns:allow_host_loopback=true,enable_ipv6=true,port_handler=slirp4netns -p 5221-5222:5221-5222/tcp -p 5221-5222:5221-5222/udp -ti alpine sh +sleep 3 + +nl +nl +say We'll use iperf3(1) for throughput +sleep 2 +ns1b apk add iperf3 jq bc +ns2b apk add iperf3 jq bc +sleep 2 +say and static +nl +say builds of neper (github.com/google/neper) for +nl +say latency. +ns1 wget lameexcu.se/tcp_rr; chmod 755 tcp_rr +ns2 wget lameexcu.se/tcp_rr; chmod 755 tcp_rr +ns1 wget lameexcu.se/tcp_crr; chmod 755 tcp_crr +ns2 wget lameexcu.se/tcp_crr; chmod 755 tcp_crr +ns1 wget lameexcu.se/udp_rr; chmod 755 udp_rr +ns2 wget lameexcu.se/udp_rr; chmod 755 udp_rr +sleep 5 + +nl +nl +say Everything is set now, let's start +sleep 2 +hout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +hout ADDR4 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local' +hout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local' +hout GW4 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +hout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' + +nl +nl +resize INFO D 15 +info Throughput in Gbps, latency in µs +info non-loopback (tap) connections +th mode slirp4netns pasta + +tr TCP/IPv6 to ns +#ns1b iperf3 -s1J -p 5221 | jq -rM ".end.sum_received.bits_per_second" >t1 +#hostb iperf3 -c __ADDR6__ -p 5221 __OPTS__ +#ns1out BW cat t1 +#bw __BW__ 0.0 0.0 +bw - +ns2b iperf3 -s1J -p 5223 | jq -rM ".end.sum_received.bits_per_second" >t1 +hostb iperf3 -c __ADDR6__ -p 5223 __OPTS__ +sleep 12 +ns2b +ns2out BW cat t1 +bw __BW__ 0.0 0.0 +hostb + +tl RR latency +#ns1b ./tcp_rr -6 --nolog -C 5221 -P 5222 +#sleep 2 +#hout LAT tcp_rr --nolog -c -H __ADDR6__ -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +#lat __LAT__ 100000 100000 +lat - +ns2b ./tcp_rr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_rr --nolog -c -H __ADDR6__ -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +#ns1b ./tcp_crr -6 --nolog -C 5221 -P 5222 +#sleep 2 +#hout LAT tcp_crr --nolog -c -H __ADDR6__ -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +#lat __LAT__ 100000 100000 +lat - +ns2b ./tcp_crr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_crr --nolog -c -H __ADDR6__ -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl TCP/IPv4 to ns +ns1b iperf3 -s1J -p 5221 | jq -rM ".end.sum_received.bits_per_second" >t1 +hostb iperf3 -c __ADDR4__ -p 5221 __OPTS__ +sleep 12 +ns1b +ns1out BW cat t1 +bw __BW__ 0.0 0.0 +ns2b iperf3 -s1J -p 5223 | jq -rM ".end.sum_received.bits_per_second" >t1 +hostb iperf3 -c __ADDR4__ -p 5223 __OPTS__ +sleep 12 +ns2b +ns2out BW cat t1 +bw __BW__ 0.0 0.0 +hostb + +tl RR latency +ns1b ./tcp_rr -4 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT tcp_rr --nolog -c -H __ADDR4__ -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./tcp_rr -4 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_rr --nolog -c -H __ADDR4__ -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +ns1b ./tcp_crr -4 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT tcp_crr --nolog -c -H __ADDR4__ -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./tcp_crr -4 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_crr --nolog -c -H __ADDR4__ -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tr TCP/IPv6 to host +hostb iperf3 -s1J -p 5211 | jq -rM ".end.sum_received.bits_per_second" >t1 +ns1b iperf3 -c fd00::2 -p 5211 __OPTS__ +sleep 12 +hostb +hout BW cat t1 +bw __BW__ 0.0 0.0 +hostb iperf3 -s1J -p 5213 | jq -rM ".end.sum_received.bits_per_second" >t1 +ns2b iperf3 -c __GW6__%__IFNAME__ -p 5213 __OPTS__ +sleep 12 +hostb +hout BW cat t1 +bw __BW__ 0.0 0.0 +ns1b +ns2b + +tl RR latency +hostb tcp_rr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_rr --nolog -c -H fd00::2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_rr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_rr --nolog -c -H __GW6__%__IFNAME__ -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +hostb tcp_crr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_crr --nolog -c -H fd00::2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_crr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_crr --nolog -c -H __GW6__%__IFNAME__ -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl TCP/IPv4 to host +hostb iperf3 -s1J -p 5211 | jq -rM ".end.sum_received.bits_per_second" >t1 +ns1b iperf3 -c 10.0.2.2 -p 5211 __OPTS__ +sleep 12 +hostb +hout BW cat t1 +bw __BW__ 0.0 0.0 +hostb iperf3 -s1J -p 5213 | jq -rM ".end.sum_received.bits_per_second" >t1 +ns2b iperf3 -c __GW4__ -p 5213 __OPTS__ +sleep 10 +hostb +hout BW cat t1 +bw __BW__ 0.0 0.0 +ns1b +ns2b + +tl RR latency +hostb tcp_rr -4 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_rr --nolog -c -H 10.0.2.2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_rr -4 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_rr --nolog -c -H __GW4__ -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +hostb tcp_crr -4 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_crr --nolog -c -H 10.0.2.2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_crr -4 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_crr --nolog -c -H __GW4__ -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +sleep 5 + + +tr UDP/IPv6 to ns +#ns1b iperf3 -s1J -p 5221 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +#hostb iperf3 -u -c __ADDR6__ -p 5221 -t5 -b 35G +#sleep 10 +#ns1out BW cat t1 +#bw __BW__ 0.0 0.0 +bw - +ns2b iperf3 -s1J -p 5224 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +hostb iperf3 -u -c __ADDR6__ -p 5224 -t5 -b 35G +sleep 10 +ns2out BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +#ns1b ./udp_rr -6 --nolog -C 5221 -P 5222 +#sleep 2 +#hout LAT udp_rr --nolog -c -H __ADDR6__ -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +#lat __LAT__ 100000 100000 +lat - +ns2b ./udp_rr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT udp_rr --nolog -c -H __ADDR6__ -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl UDP/IPv4 to ns +ns1b iperf3 -s1J -p 5221 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +hostb iperf3 -u -c __ADDR4__ -p 5221 -t5 -b 35G +sleep 10 +ns1out BW cat t1 +bw __BW__ 0.0 0.0 +ns2b iperf3 -s1J -p 5224 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +hostb iperf3 -u -c __ADDR4__ -p 5224 -t5 -b 35G +sleep 10 +ns2out BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +ns1b ./udp_rr -6 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT udp_rr --nolog -c -H __ADDR4__ -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./udp_rr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT udp_rr --nolog -c -H __ADDR4__ -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tr UDP/IPv6 to host +hostb iperf3 -s1J -p 5211 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns1b iperf3 -u -c fd00::2 -p 5211 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 +hostb iperf3 -s1J -p 5214 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns2b iperf3 -u -c __GW6__%__IFNAME__ -p 5214 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +hostb udp_rr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./udp_rr --nolog -c -H fd00::2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb udp_rr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./udp_rr --nolog -c -H __GW6__%__IFNAME__ -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl UDP/IPv4 to host +hostb iperf3 -s1J -p 5211 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns1b iperf3 -u -c 10.0.2.2 -p 5211 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 +hostb iperf3 -s1J -p 5214 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns2b iperf3 -u -c __GW4__ -p 5214 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +hostb udp_rr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./udp_rr --nolog -c -H 10.0.2.2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb udp_rr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./udp_rr --nolog -c -H __GW4__ -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + + +ns1 exit +ns1 podman run --rm --net=slirp4netns:allow_host_loopback=true,enable_ipv6=true -p 5221-5222:5221-5222/tcp -p 5221-5222:5221-5222/udp -ti alpine sh +ns1 apk add iperf3 jq bc +ns1 wget lameexcu.se/tcp_rr; chmod 755 tcp_rr +ns1 wget lameexcu.se/tcp_crr; chmod 755 tcp_crr +ns1 wget lameexcu.se/udp_rr; chmod 755 udp_rr +info +info +info loopback (lo) connections +th mode rootlesskit pasta + + +tr TCP/IPv6 to ns +ns1b (iperf3 -s1J -p 5221 | jq -rM ".end.sum_received.bits_per_second" >t1) & +ns1b iperf3 -s1J -p 5222 | jq -rM ".end.sum_received.bits_per_second" >t2 +hostb iperf3 -c ::1 -p 5221 __OPTS__ & iperf3 -c ::1 -p 5222 __OPTS__ +sleep 12 +ns1b +ns1out BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +ns2b (iperf3 -s1J -p 5223 | jq -rM ".end.sum_received.bits_per_second" >t1) & +ns2b iperf3 -s1J -p 5224 | jq -rM ".end.sum_received.bits_per_second" >t2 +hostb iperf3 -c ::1 -p 5223 __OPTS__ & iperf3 -c ::1 -p 5224 __OPTS__ +sleep 12 +ns2b +ns2out BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +hostb + +tl RR latency +ns1b ./tcp_rr -6 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT tcp_rr --nolog -c -H ::1 -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./tcp_rr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_rr --nolog -c -H ::1 -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +ns1b ./tcp_crr -6 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT tcp_crr --nolog -c -H ::1 -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./tcp_crr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_crr --nolog -c -H ::1 -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl TCP/IPv4 to ns +ns1b (iperf3 -s1J -p 5221 | jq -rM ".end.sum_received.bits_per_second" >t1) & +ns1b iperf3 -s1J -p 5222 | jq -rM ".end.sum_received.bits_per_second" >t2 +hostb iperf3 -c 127.0.0.1 -p 5221 __OPTS__ & iperf3 -c 127.0.0.1 -p 5222 __OPTS__ +sleep 12 +ns1b +ns1out BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +ns2b (iperf3 -s1J -p 5223 | jq -rM ".end.sum_received.bits_per_second" >t1) & +ns2b iperf3 -s1J -p 5224 | jq -rM ".end.sum_received.bits_per_second" >t2 +hostb iperf3 -c 127.0.0.1 -p 5223 __OPTS__ & iperf3 -c 127.0.0.1 -p 5224 __OPTS__ +sleep 12 +ns2b +ns2out BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +hostb + +tl RR latency +ns1b ./tcp_rr -4 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT tcp_rr --nolog -c -H 127.0.0.1 -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./tcp_rr -4 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_rr --nolog -c -H 127.0.0.1 -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +ns1b ./tcp_crr -4 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT tcp_crr --nolog -c -H 127.0.0.1 -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./tcp_crr -4 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT tcp_crr --nolog -c -H 127.0.0.1 -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tr TCP/IPv6 to host +hostb (iperf3 -s1J -p 5211 | jq -rM ".end.sum_received.bits_per_second" >t1) & +hostb iperf3 -s1J -p 5212 | jq -rM ".end.sum_received.bits_per_second" >t2 +ns1b iperf3 -c fd00::2 -p 5211 __OPTS__ & iperf3 -c fd00::2 -p 5212 __OPTS__ +sleep 12 +hostb +hout BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +hostb (iperf3 -s1J -p 5213 | jq -rM ".end.sum_received.bits_per_second" >t1) & +hostb iperf3 -s1J -p 5214 | jq -rM ".end.sum_received.bits_per_second" >t2 +ns2b iperf3 -c ::1 -p 5213 __OPTS__ & iperf3 -c ::1 -p 5214 __OPTS__ +sleep 12 +hostb +hout BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +ns1b +ns2b + +tl RR latency +hostb tcp_rr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_rr --nolog -c -H fd00::2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_rr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_rr --nolog -c -H ::1 -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +hostb tcp_crr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_crr --nolog -c -H fd00::2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_crr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_crr --nolog -c -H ::1 -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl TCP/IPv4 to host +hostb (iperf3 -s1J -p 5211 | jq -rM ".end.sum_received.bits_per_second" >t1) & +hostb iperf3 -s1J -p 5212 | jq -rM ".end.sum_received.bits_per_second" >t2 +ns1b iperf3 -c 10.0.2.2 -p 5211 __OPTS__ & iperf3 -c 10.0.2.2 -p 5212 __OPTS__ +sleep 12 +hostb +hout BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +hostb (iperf3 -s1J -p 5213 | jq -rM ".end.sum_received.bits_per_second" >t1) & +hostb iperf3 -s1J -p 5214 | jq -rM ".end.sum_received.bits_per_second" >t2 +ns2b iperf3 -c 127.0.0.1 -p 5213 __OPTS__ & iperf3 -c 127.0.0.1 -p 5214 __OPTS__ +sleep 12 +hostb +hout BW echo "$(cat t1) + $(cat t2)" | bc -l +bw __BW__ 0.0 0.0 +ns1b +ns2b + +tl RR latency +hostb tcp_rr -4 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_rr --nolog -c -H 10.0.2.2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_rr -4 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_rr --nolog -c -H 127.0.0.1 -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl CRR latency +hostb tcp_crr -4 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./tcp_crr --nolog -c -H 10.0.2.2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb tcp_crr -4 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./tcp_crr --nolog -c -H 127.0.0.1 -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +sleep 5 + + +tr UDP/IPv6 to ns +ns1b iperf3 -s1J -p 5221 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +hostb iperf3 -u -c ::1 -p 5221 -t5 -b 35G +sleep 10 +ns1out BW cat t1 +bw __BW__ 0.0 0.0 +ns2b iperf3 -s1J -p 5224 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +hostb iperf3 -u -c ::1 -p 5224 -t5 -b 35G +sleep 10 +ns2out BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +ns1b ./udp_rr -6 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT udp_rr --nolog -c -H ::1 -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./udp_rr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT udp_rr --nolog -c -H ::1 -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl UDP/IPv4 to ns +ns1b iperf3 -s1J -p 5221 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +hostb iperf3 -u -c 127.0.0.1 -p 5221 -t5 -b 35G +sleep 10 +ns1out BW cat t1 +bw __BW__ 0.0 0.0 +ns2b iperf3 -s1J -p 5224 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +hostb iperf3 -u -c 127.0.0.1 -p 5224 -t5 -b 35G +sleep 10 +ns2out BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +ns1b ./udp_rr -6 --nolog -C 5221 -P 5222 +sleep 2 +hout LAT udp_rr --nolog -c -H 127.0.0.1 -C 5221 -P 5222 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +ns2b ./udp_rr -6 --nolog -C 5223 -P 5224 +sleep 2 +hout LAT udp_rr --nolog -c -H 127.0.0.1 -C 5223 -P 5224 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tr UDP/IPv6 to host +hostb iperf3 -s1J -p 5211 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns1b iperf3 -u -c fd00::2 -p 5211 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 +hostb iperf3 -s1J -p 5214 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns2b iperf3 -u -c ::1 -p 5214 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +hostb udp_rr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./udp_rr --nolog -c -H fd00::2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb udp_rr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./udp_rr --nolog -c -H ::1 -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + +tl UDP/IPv4 to host +hostb iperf3 -s1J -p 5211 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns1b iperf3 -u -c 10.0.2.2 -p 5211 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 +hostb iperf3 -s1J -p 5214 | jq -rM ".intervals[0].sum.bits_per_second" >t1 +ns2b iperf3 -u -c 127.0.0.1 -p 5214 -t5 -b 35G +sleep 10 +hout BW cat t1 +bw __BW__ 0.0 0.0 + +tl RR latency +hostb udp_rr -6 --nolog -C 5211 -P 5212 +sleep 2 +ns1out LAT ./udp_rr --nolog -c -H 10.0.2.2 -C 5211 -P 5212 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 +hostb udp_rr -6 --nolog -C 5213 -P 5214 +sleep 2 +ns2out LAT ./udp_rr --nolog -c -H 127.0.0.1 -C 5213 -P 5214 -l 5 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 100000 100000 + + +nl +nl +say Thanks for watching! +sleep 15 diff --git a/oldtest/distro/debian b/oldtest/distro/debian new file mode 100644 index 0000000..42914f8 --- /dev/null +++ b/oldtest/distro/debian @@ -0,0 +1,252 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/distro/debian - Debian builds, get packages via passt, test pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +set PIDFILE __STATEDIR__/passt.pid +htools cat kill qemu-system-x86_64 qemu-system-aarch64 qemu-system-ppc64 + +# Quick pasta test: send message from init to ns, and from ns to init +def distro_quick_pasta_test +host export SHELL="/bin/dash" +host dash +host (socat -u TCP6-LISTEN:10000 OPEN:/tmp/init_msg,create,trunc; echo "from_init" | socat -u STDIN TCP6:[::1]:9999) & +hostb ./pasta +sleep 1 +host socat -u TCP6-LISTEN:9999 OPEN:/tmp/ns_msg,create,trunc & +sleep 2 +host echo "from_ns" | socat -u STDIN TCP6:[::1]:10000 +sleep 2 +host echo +sleep 1 +hout NS_MSG cat /tmp/ns_msg +check [ __NS_MSG__ = "from_init" ] +hostb exit +host echo +hout INIT_MSG cat /tmp/init_msg +check [ __INIT_MSG__ = "from_ns" ] +endef + +# Start passt, set common variables +hostb ./passt -s __STATEDIR__/passt.socket -P __PIDFILE__ & +sleep 1 +host echo + + +test Debian GNU/Linux 8 (jessie), amd64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none -drive file=__BASEPATH__/prepared-debian-8.11.0-openstack-amd64.qcow2,if=virtio -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Wno-missing-field-initializers -Wno-missing-braces -Wno-type-limits" make + +# TODO: pasta test skipped for the moment: clone() as called by NS_CALL hangs +# with wrapper provided by glibc 2.19, probably wrong argument order. + +hint +sleep 1 + +# PIDFILE is cleaned up when the next test starts, read it now +hout PID cat __PIDFILE__ + + +test Debian GNU/Linux 9 (stretch, oldoldstable), amd64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-9-nocloud-amd64-daily-20200210-166.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +host sysctl -w kernel.unprivileged_userns_clone=1 +distro_quick_pasta_test + +hint +sleep 1 + + +test Debian GNU/Linux 10 (buster, oldstable), amd64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-10-nocloud-amd64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +host sysctl -w kernel.unprivileged_userns_clone=1 +distro_quick_pasta_test + +hint +sleep 1 + + +test Debian GNU/Linux 10 (buster, oldstable), aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-10-generic-arm64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +host sysctl -w kernel.unprivileged_userns_clone=1 +distro_quick_pasta_test + +hint +sleep 1 + + +test Debian GNU/Linux 10 (buster, oldstable), ppc64le + +host qemu-system-ppc64 -m 2048 -smp 2 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-10-generic-ppc64el-20220911-1135.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +host sysctl -w kernel.unprivileged_userns_clone=1 +distro_quick_pasta_test + +hint +sleep 1 +hostb reset + + +test Debian GNU/Linux 11 (bullseye, stable), amd64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-11-nocloud-amd64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test Debian GNU/Linux 11 (bullseye, stable), aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-11-generic-arm64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test Debian GNU/Linux 11 (bullseye, stable), ppc64le + +host qemu-system-ppc64 -m 2048 -smp 2 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-11-generic-ppc64el.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset + + +# HACK: We need some additional space to install gcc-12 on 'sid' images for +# amd64 and aarch64, but if we use virt-resize to call resize2fs in the +# preparation step, partitions will be rearranged and we would also need to +# adjust boot parameters. Instead, resize the images offline first, and expand +# partitions and filesystems online, later. + +test Debian GNU/Linux sid (experimental), amd64 + +host qemu-img resize __BASEPATH__/prepared-debian-sid-nocloud-amd64-daily.qcow2 4G +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-sid-nocloud-amd64-daily.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +sleep 2 +host growpart /dev/sda 1 +host resize2fs -p /dev/sda1 +host export DEBIAN_FRONTEND=noninteractive +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test Debian GNU/Linux sid (experimental), aarch64 + +host qemu-img resize __BASEPATH__/prepared-debian-sid-nocloud-arm64-daily.qcow2 4G +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-sid-nocloud-arm64-daily.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +sleep 2 +host growpart /dev/vda 1 +host resize2fs -p /dev/vda1 +host export DEBIAN_FRONTEND=noninteractive +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test Debian GNU/Linux sid (experimental), ppc64le + +host qemu-system-ppc64 -m 2048 -smp 2 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-debian-sid-nocloud-ppc64el-daily.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +sleep 2 +host export DEBIAN_FRONTEND=noninteractive +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset + + +sleep 1 +host kill __PID__ diff --git a/oldtest/distro/fedora b/oldtest/distro/fedora new file mode 100644 index 0000000..331f90b --- /dev/null +++ b/oldtest/distro/fedora @@ -0,0 +1,396 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/distro/fedora - Fedora builds, get packages via passt, test pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +set PIDFILE __STATEDIR__/passt.pid +htools cat kill qemu-system-x86_64 + +# Quick pasta test: send message from init to ns, and from ns to init +def distro_quick_pasta_test +host (socat -u TCP6-LISTEN:10000,bind=[::1] OPEN:/tmp/init_msg,create,trunc; echo "from_init" | socat -u STDIN TCP6:[::1]:9999) & +hostb ./pasta +sleep 1 +host PS1='$ ' +host socat -u TCP6-LISTEN:9999,bind=[::1] OPEN:/tmp/ns_msg,create,trunc & +sleep 2 +host echo "from_ns" | socat -u STDIN TCP6:[::1]:10000 +sleep 2 +host echo +sleep 1 +hout NS_MSG cat /tmp/ns_msg +check [ __NS_MSG__ = "from_init" ] +hostb exit +host echo +hout INIT_MSG cat /tmp/init_msg +check [ __INIT_MSG__ = "from_ns" ] +endef + +# Bracketed paste mode off, needed from Fedora 34 +def distro_quick_pasta_test_fedora34 +host bind 'set enable-bracketed-paste off' +host (socat -u TCP6-LISTEN:10000,bind=[::1] OPEN:/tmp/init_msg,create,trunc; echo "from_init" | socat -u STDIN TCP6:[::1]:9999) & +hostb ./pasta +sleep 1 +host PS1='$ ' +host bind 'set enable-bracketed-paste off' +host socat -u TCP6-LISTEN:9999,bind=[::1] OPEN:/tmp/ns_msg,create,trunc & +sleep 2 +host echo "from_ns" | socat -u STDIN TCP6:[::1]:10000 +sleep 2 +host echo +hout NS_MSG cat /tmp/ns_msg +check [ __NS_MSG__ = "from_init" ] +hostb exit +host echo +hout INIT_MSG cat /tmp/init_msg +check [ __INIT_MSG__ = "from_ns" ] +endef + +# Start passt, set common variables +hostb ./passt -s __STATEDIR__/passt.socket -P __PIDFILE__ & +sleep 1 +host echo + +test Fedora 26, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-26-1.5.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + +# PIDFILE is cleaned up when the next test starts, read it now +hout PID cat __PIDFILE__ + + +test Fedora 27, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-27-1.6.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + + +test Fedora 28, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-28-1.1.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + + +test Fedora 28, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-28-1.1.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Fedora 29, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-29-1.2.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + + +test Fedora 29, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-29-1.2.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Fedora 30, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-30-1.2.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + + +test Fedora 30, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-30-1.2.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Fedora 31, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-31-1.9.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + + +test Fedora 31, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-31-1.9.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Fedora 32, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-32-1.6.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + + +test Fedora 32, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-32-1.6.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Fedora 33, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-33-1.2.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 + + +test Fedora 33, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-33-1.2.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Fedora 34, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-34-1.2.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test_fedora34 + +hint +sleep 1 + + +test Fedora 34, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-34-1.2.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test_fedora34 + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Fedora 35, x86_64 + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __BASEPATH__/prepared-Fedora-Cloud-Base-35-1.2.x86_64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test_fedora34 + +hint +sleep 1 + + +test Fedora 35, aarch64 + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __BASEPATH__/prepared-Fedora-Cloud-Base-35-1.2.aarch64.qcow2 -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-pci -snapshot +host PS1='$ ' +sleep 2 +host yum -y install make gcc socat + +host make clean +hout RET CFLAGS="-Werror" make; echo $? +check [ __RET__ -eq 0 ] + +distro_quick_pasta_test_fedora34 + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +host kill __PID__ diff --git a/oldtest/distro/opensuse b/oldtest/distro/opensuse new file mode 100644 index 0000000..eab722b --- /dev/null +++ b/oldtest/distro/opensuse @@ -0,0 +1,208 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/distro/opensuse - OpenSUSE builds, get packages via passt, test pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +set PIDFILE __STATEDIR__/passt.pid +htools qemu-img virt-edit guestfish head sed cat kill qemu-system-x86_64 qemu-system-aarch64 xzcat tr + +# Quick pasta test: send message from init to ns, and from ns to init +def distro_quick_pasta_test +host (socat -u TCP6-LISTEN:10000 OPEN:/tmp/init_msg,create,trunc; echo "from_init" | socat -u STDIN TCP6:[::1]:9999) & +hostb ./pasta +sleep 1 +host PS1='$ ' +host socat -u TCP6-LISTEN:9999 OPEN:/tmp/ns_msg,create,trunc & +sleep 2 +host echo "from_ns" | socat -u STDIN TCP6:[::1]:10000 +sleep 2 +host echo +sleep 1 +hout NS_MSG cat /tmp/ns_msg +check [ __NS_MSG__ = "from_init" ] +hostb exit +host echo +hout INIT_MSG cat /tmp/init_msg +check [ __INIT_MSG__ = "from_ns" ] +endef + +# Start passt, set common variables +hostb ./passt -s __STATEDIR__/passt.socket -P __PIDFILE__ & +sleep 1 +host echo +hout DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | head -1 +hout GUEST_FILES ls -1 *.c *.h *.sh passt.1 qrap.1 Makefile README.md | tr '\n' ' '; echo + + +test OpenSUSE Leap 15.1 + +set IMG __STATEDIR__/opensuse-15.1-x86_64.img +host qemu-img create -f qcow2 -F qcow2 -b __BASEPATH__/openSUSE-Leap-15.1-JeOS.x86_64-kvm-and-xen.qcow2 __IMG__ +host guestfish --rw -a __IMG__ -i rm '/usr/lib/systemd/system/systemd-journald.service' +host guestfish --rw -a __IMG__ -i rm /etc/systemd/system/default.target.wants/jeos-firstboot.service +host virt-edit -a __IMG__ /etc/systemd/system/getty.target.wants/getty(a)tty1.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --timeout 5000 --autologin root -i -8 --keep-baud 115200,38400,9600 ttyS0 $TERM/g' +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __IMG__ -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +host PS1='$ ' +host ip link set eth0 up +sleep 2 +host echo "DNSSERVERS='__DNS6__'" | netconfig modify -s dns_resolver -i eth0 +# zypper sometimes segfaults, hence the retries +host for i in $(seq 1 10); do zypper install -y gcc make socat && break; done; echo + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + +# PIDFILE is cleaned up when the next test starts, read it now +hout PID cat __PIDFILE__ + + +test OpenSUSE Leap 15.2 + +set IMG __STATEDIR__/opensuse-15.2-x86_64.img +host qemu-img create -f qcow2 -F qcow2 -b __BASEPATH__/openSUSE-Leap-15.2-JeOS.x86_64-kvm-and-xen.qcow2 __IMG__ +host guestfish --rw -a __IMG__ -i rm '/usr/lib/systemd/system/systemd-journald.service' +host guestfish --rw -a __IMG__ -i rm /etc/systemd/system/default.target.wants/jeos-firstboot.service +host virt-edit -a __IMG__ /etc/systemd/system/getty.target.wants/getty(a)tty1.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --timeout 5000 --autologin root -i -8 --keep-baud 115200,38400,9600 ttyS0 $TERM/g' +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __IMG__ -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +host PS1='$ ' +host ip link set eth0 up +sleep 2 +host echo "DNSSERVERS='__DNS6__'" | netconfig modify -s dns_resolver -i eth0 +# zypper sometimes segfaults, hence the retries +host for i in $(seq 1 10); do zypper install -y gcc make socat && break; done; echo + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test OpenSUSE Leap 15.3 + +set IMG __STATEDIR__/opensuse-15.3-x86_64.img +host qemu-img create -f qcow2 -F qcow2 -b __BASEPATH__/openSUSE-Leap-15.3-JeOS.x86_64-kvm-and-xen.qcow2 __IMG__ +host guestfish --rw -a __IMG__ -i rm '/usr/lib/systemd/system/systemd-journald.service' +host guestfish --rw -a __IMG__ -i rm /etc/systemd/system/default.target.wants/jeos-firstboot.service +host virt-edit -a __IMG__ /etc/systemd/system/getty.target.wants/getty(a)tty1.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --timeout 5000 --autologin root -i -8 --keep-baud 115200,38400,9600 ttyS0 $TERM/g' +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __IMG__ -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +# Multiple prompt logins might come up here +sleep 10 +host PS1='$ ' +host ip link set eth0 up +sleep 2 +host echo "DNSSERVERS='__DNS6__'" | netconfig modify -s dns_resolver -i eth0 +# zypper sometimes segfaults, hence the retries +host for i in $(seq 1 10); do zypper install -y gcc make socat && break; done; echo + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test OpenSUSE Tumbleweed aarch64 + +set IMG __STATEDIR__/opensuse-tumbleweed-aarch64.img +host xzcat __BASEPATH__/openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64.raw.xz > __IMG__ +host virt-edit -a __IMG__ -m /dev/sda3 /usr/lib/systemd/system/serial-getty@.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --timeout 5000 --autologin root -i -8 --keep-baud 115200,38400,9600 %I $TERM/g' +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios __BASEPATH__/QEMU_EFI.fd -nodefaults -nographic -vga none -serial stdio __IMG__ -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +host PS1='$ ' +host ip link set enp0s1 up +sleep 10 +host echo "DNSSERVERS='__DNS6__'" | netconfig modify -s dns_resolver -i enp0s1 +sleep 10 +# No segfaults ever seen with this +host zypper install -y gcc make socat; echo + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test OpenSUSE Tumbleweed armv7l + +set IMG __STATEDIR__/opensuse-tumbleweed-armv7l.img +set ZIMAGE __STATEDIR__/opensuse-tumbleweed-armv7l.zimage +set INITRD __STATEDIR__/opensuse-tumbleweed-armv7l.initrd +host xzcat __BASEPATH__/openSUSE-Tumbleweed-ARM-JeOS-efi.armv7l.raw.xz > __IMG__ +host guestfish -a __IMG__ -i download /boot/zImage __ZIMAGE__ +host guestfish -a __IMG__ -i download /boot/initrd __INITRD__ +host virt-edit -a __IMG__ -m /dev/sda3 /usr/lib/systemd/system/serial-getty@.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --timeout 5000 --autologin root -i -8 --keep-baud 115200,38400,9600 %I $TERM/g' +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-arm -M virt -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none -kernel __ZIMAGE__ -initrd __INITRD__ -append 'root=/dev/sda3' -drive if=none,file=__IMG__,format=raw,id=hd,media=disk -device virtio-scsi-device -device scsi-hd,drive=hd -netdev socket,fd=5,id=passt -device virtio-net-device,netdev=passt +host PS1='$ ' +host ip link set eth0 up +sleep 10 +host echo "DNSSERVERS='__DNS6__'" | netconfig modify -s dns_resolver -i eth0 +sleep 10 +host zypper install -y gcc make socat; echo + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +test OpenSUSE Tumbleweed + +set IMG __STATEDIR__/opensuse-tumbleweed-x86_64.img +host qemu-img create -f qcow2 -F qcow2 -b __BASEPATH__/openSUSE-Tumbleweed-JeOS.x86_64-kvm-and-xen.qcow2 __IMG__ +host guestfish --rw -a __IMG__ -i rm /usr/lib/systemd/system/systemd-journald.service +host guestfish --rw -a __IMG__ -i rm /etc/systemd/system/default.target.wants/jeos-firstboot.service +host guestfish --rw -a __IMG__ -i rm /usr/lib/systemd/system/serial-getty@.service +host virt-edit -a __IMG__ /etc/systemd/system/getty.target.wants/getty(a)tty1.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --timeout 5000 --autologin root -i -8 --keep-baud 115200,38400,9600 ttyS0 $TERM/g' +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __IMG__ -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +host PS1='$ ' +host ip link set ens2 up +sleep 2 +host echo "DNSSERVERS='__DNS6__'" | netconfig modify -s dns_resolver -i ens2 +# zypper sometimes segfaults, hence the retries +host for i in $(seq 1 10); do zypper install -y gcc make socat && break; done; echo + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test + +hint +sleep 1 + + +host kill __PID__ diff --git a/oldtest/distro/ubuntu b/oldtest/distro/ubuntu new file mode 100644 index 0000000..8750455 --- /dev/null +++ b/oldtest/distro/ubuntu @@ -0,0 +1,216 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/distro/ubuntu - Ubuntu builds, get packages via passt, test pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +set PIDFILE __STATEDIR__/passt.pid +htools qemu-img virt-edit guestfish cat kill qemu-system-x86_64 qemu-system-ppc64 qemu-system-s390x + +# Quick pasta test: send message from init to ns, and from ns to init +def distro_quick_pasta_test +host (socat -u TCP6-LISTEN:10000 OPEN:/tmp/init_msg,create,trunc; echo "from_init" | socat -u STDIN TCP6:[::1]:9999) & +hostb ./pasta +sleep 1 +host PS1='$ ' +host socat -u TCP6-LISTEN:9999 OPEN:/tmp/ns_msg,create,trunc & +sleep 2 +host echo "from_ns" | socat -u STDIN TCP6:[::1]:10000 +sleep 2 +host echo +sleep 1 +hout NS_MSG cat /tmp/ns_msg +check [ __NS_MSG__ = "from_init" ] +hostb exit +host echo +hout INIT_MSG cat /tmp/init_msg +check [ __INIT_MSG__ = "from_ns" ] +endef + +# Quick pasta test: netcat-openbsd version for Ubuntu 16.04 ppc64 +def distro_quick_pasta_test_netcat +host (nc -w1 -6 -l -p 10000 > /tmp/init_msg; echo "from_init" | nc -q0 ::1 9999) & +hostb ./pasta +sleep 1 +host PS1='$ ' +host nc -w1 -6 -l -p 9999 > /tmp/ns_msg & +sleep 2 +host echo "from_ns" | nc -q0 ::1 10000 +sleep 2 +host echo +sleep 1 +hout NS_MSG cat /tmp/ns_msg +check [ __NS_MSG__ = "from_init" ] +hostb exit +host echo +hout INIT_MSG cat /tmp/init_msg +check [ __INIT_MSG__ = "from_ns" ] +endef + +# With systemd-resolved and TCG, DNS might take a while to work +def dns_ready_wait +host r=10; while [ \${r} -gt 0 ]; do host ubuntu.com && break; sleep 5; r=\$((r - 1)); done +endef + +# Start passt, set common variables +hostb ./passt -s __STATEDIR__/passt.socket -P __PIDFILE__ & +sleep 1 +host echo +hout GUEST_FILES ls -1 *.c *.h *.sh passt.1 qrap.1 Makefile README.md | tr '\n' ' '; echo + + +test Ubuntu 14.04.5 LTS (Trusty Tahr), amd64 + +set IMG __STATEDIR__/ubuntu-14.04-amd64.img +host qemu-img create -f qcow2 -F qcow2 -b __BASEPATH__/trusty-server-cloudimg-amd64-disk1.img __IMG__ +host virt-edit -a __IMG__ /etc/init/ttyS0.conf -e 's/\/getty/\/getty --autologin root/' +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-config.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-final.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-container.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-local.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-nonet.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-log-shutdown.conf +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none -drive file=__IMG__,if=virtio -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Wno-missing-field-initializers -Wno-missing-braces -Wno-type-limits" make + +# TODO: pasta test skipped for the moment: clone() as called by NS_CALL hangs +# with wrapper provided by glibc 2.19, probably wrong argument order. + +hint +sleep 1 + +# PIDFILE is cleaned up when the next test starts, read it now +hout PID cat __PIDFILE__ + + +test Ubuntu 14.04.5 LTS (Trusty Tahr), i386 + +set IMG __STATEDIR__/ubuntu-14.04-i386.img +host qemu-img create -f qcow2 -F qcow2 -b __BASEPATH__/trusty-server-cloudimg-i386-disk1.img __IMG__ +host virt-edit -a __IMG__ /etc/init/ttyS0.conf -e 's/\/getty/\/getty --autologin root/' +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-config.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-final.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-container.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-local.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-nonet.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-log-shutdown.conf +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-x86_64 -M pc,accel=kvm:tcg -m 1024 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none -drive file=__IMG__,if=virtio -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Wno-missing-field-initializers -Wno-missing-braces -Wno-type-limits -Wno-sign-compare" make + +# TODO: pasta test skipped for the moment: clone() as called by NS_CALL hangs +# with wrapper provided by glibc 2.19, probably wrong argument order. + +hint +sleep 1 + + +test Ubuntu 14.04.5 LTS (Trusty Tahr), ppc64le + +set IMG __STATEDIR__/ubuntu-14.04-ppc64le.img +host qemu-img create -f qcow2 -F qcow2 -b __BASEPATH__/trusty-server-cloudimg-ppc64el-disk1.img __IMG__ +host virt-edit -a __IMG__ /etc/init/hvc0.conf -e 's/\/getty/\/getty --autologin root/' +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-config.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-final.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-container.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-local.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init-nonet.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-init.conf +host guestfish --rw -a __IMG__ -i rm /etc/init/cloud-log-shutdown.conf +host guestfish --rw -a __IMG__ -i copy-in __GUEST_FILES__ /root/ + +host qemu-system-ppc64 -m 2048 -smp 2 -nographic -serial stdio -nodefaults -no-reboot -nographic -vga none __IMG__ -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket +host PS1='$ ' +sleep 2 +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Wno-missing-field-initializers -Wno-missing-braces -Wno-type-limits -Wno-sign-compare" make + +# TODO: pasta test skipped for the moment: clone() as called by NS_CALL hangs +# with wrapper provided by glibc 2.19, probably wrong argument order. + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Ubuntu 16.04 LTS (Xenial Xerus), ppc64 (be) + +host qemu-system-ppc64 -m 1024 -M pseries -nographic -nodefaults -serial stdio -no-reboot -nographic -vga none -hda __BASEPATH__/prepared-xenial-server-cloudimg-powerpc-disk1.img -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -snapshot +host PS1='$ ' +host dhclient -4 +# Skip apt-get update here: some updates to xenial-updates around 2022-01-30 +# broke dependencies for libc6 and gcc-5 -- note that powerpc is not officially +# supported on this version + +# socat not available: install netcat-openbsd and run the test with it +host apt-get -y install make gcc netcat-openbsd + +host make clean +host CFLAGS="-Werror" make + +distro_quick_pasta_test_netcat + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +test Ubuntu 22.04 (Jammy Jellyfish), s390x + +host qemu-system-s390x -m 2048 -smp 2 -serial stdio -nodefaults -nographic __BASEPATH__/prepared-jammy-server-cloudimg-s390x.img -device virtio-net-pci,netdev=s0 -netdev stream,id=s0,server=off,addr.type=unix,addr.path=__STATEDIR__/passt.socket -device virtio-rng-ccw -snapshot + +host export DEBIAN_FRONTEND=noninteractive +host service systemd-networkd stop +host service systemd-resolved stop +host rm /etc/dhcp/dhclient-enter-hooks.d/resolved-enter +host dhclient -4 +dns_ready_wait +host apt-get update +host apt-get -y install make gcc socat + +host make clean +host CFLAGS="-Werror" make + +host export SHELL="/bin/dash" +host dash +distro_quick_pasta_test + +hint +sleep 1 +hostb reset +sleep 1 +host echo + + +host kill __PID__ diff --git a/oldtest/env/mate-terminal.profile b/oldtest/env/mate-terminal.profile new file mode 100644 index 0000000..a4ce899 --- /dev/null +++ b/oldtest/env/mate-terminal.profile @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2021 Red Hat GmbH <sbrivio(a)redhat.com> +# SPDX-License-Identifier: GPL-2.0-or-later + +[/] +allow-bold=true +background-color='#121212121212' +background-darkness=0.5 +background-image='' +background-type='solid' +backspace-binding='ascii-del' +bold-color='#000000000000' +bold-color-same-as-fg=true +copy-selection=false +cursor-blink-mode='on' +cursor-shape='block' +custom-command='' +default-show-menubar=true +default-size-columns=180 +default-size-rows=40 +delete-binding='escape-sequence' +exit-action='close' +font='Bitstream Vera Sans Mono 9' +foreground-color='#504FA2A26160' +login-shell=false +palette='#000000000000:#FFFF8F8F8F8F:#504FA2A26160:#CBCB6C6C0505:#8E8EA3A2FFFF:#C4C45959C4C4:#0000AAAAAAAA:#AAAAAAAAAAAA:#555455545554:#FFFF8F8F8F8F:#504FA2A26160:#CBCB6C6C0505:#8E8EA3A2FFFF:#C4C45959C4C4:#5554FFFFFFFF:#FFFFFFFFFFFF' +scroll-background=true +scroll-on-keystroke=true +scroll-on-output=false +scrollback-lines=512 +scrollback-unlimited=true +scrollbar-position='hidden' +silent-bell=false +title='Terminal' +title-mode='replace' +use-custom-command=false +use-custom-default-size=true +use-skey=true +use-system-font=false +use-theme-colors=false +use-urls=true +visible-name='passt_ci' +word-chars='-A-Za-z0-9,./?%&#:_=+@~' diff --git a/oldtest/find-arm64-firmware.sh b/oldtest/find-arm64-firmware.sh new file mode 100755 index 0000000..3182620 --- /dev/null +++ b/oldtest/find-arm64-firmware.sh @@ -0,0 +1,13 @@ +#! /bin/sh + +LOCATIONS="/usr/share/qemu-efi-aarch64 /usr/share/edk2/aarch64" + +for l in $LOCATIONS; do + if [ -f "$l/QEMU_EFI.fd" ]; then + ln -s "$l/QEMU_EFI.fd" "$1" + exit 0 + fi +done + +echo "Couldn't find QEMU_EFI.fd" >&2 +exit 1 diff --git a/oldtest/lib/context b/oldtest/lib/context new file mode 100644 index 0000000..4741a55 --- /dev/null +++ b/oldtest/lib/context @@ -0,0 +1,130 @@ +#! /bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/context - Run commands in different contexts (host, guest, namespace etc.) +# +# Copyright Red Hat +# Author: David Gibson <david(a)gibson.dropbear.id.au> + +NSTOOL="${BASEPATH}/nstool" + +# context_setup_common() - Create outline of a new context +# $1: Context name +context_setup_common() { + __name="$1" + __log="${LOGDIR}/context_${__name}.log" + echo -n "${__name}$ " > "${__log}" +} + +# context_setup_host() - Create a new context for running commands on the host +# $1: Context name +context_setup_host() { + __name="$1" + __enter="${STATESETUP}/context_${__name}.enter" + context_setup_common "${__name}" + echo sh -c > "${__enter}" +} + +# context_setup_nstool() - Create a new context for running commands with nstool exec +# $1: Context name +# $2: nstool control socket +context_setup_nstool() { + __name="$1" + __sock="$2" + __enter="${STATESETUP}/context_${__name}.enter" + # Wait for the ns to be ready + ${NSTOOL} info -w "${__sock}" > /dev/null + context_setup_common "${__name}" + echo "${NSTOOL} exec ${__sock} -- sh -c" > "${__enter}" +} + +# context_setup_guest() - Create a new context for running commands in a guest +# $1: Context name +# $2: CID to use for vsock +context_setup_guest() { + __name="$1" + __cid="$2" + __enter="${STATESETUP}/context_${__name}.enter" + __ssh="${STATESETUP}/context_${__name}.ssh" + context_setup_common "${__name}" + + cat > "${__ssh}" <<EOF +Host ${__name} + User root + UserKnownHostsFile ${STATESETUP}/context_${__name}.hosts + StrictHostKeyChecking no + IdentityFile ${BASEPATH}/guest-key + IdentityAgent none + ProxyCommand socat - VSOCK-CONNECT:${__cid}:22 +EOF + echo "ssh -F ${__ssh} ${__name}" > "${__enter}" + + # Wait for the guest to be booted and accepting connections + wait_for ssh -F "${__ssh}" "${__name}" : +} + +# context_teardown() - Remove a context (leave log files intact) +# $1: Context name +context_teardown() { + __name="$1" + __prefix="${STATESETUP}/context_${__name}" + rm -f "${__prefix}.enter" "${__prefix}.ssh" "${__prefix}.hosts" +} + +# context_exists() - Test if a context currently exists +# $1: Context name +context_exists() { + __name="$1" + __enter="${STATESETUP}/context_${__name}.enter" + [ -f "${__enter}" ] +} + +# context_run() - Run a shell command in a context, and wait for it to finish +# $1: Context name +# $*: Command to start +context_run() { + __name="$1" + __log="${LOGDIR}/context_${__name}.log" + __enter="${STATESETUP}/context_${__name}.enter" + __stdout="$(mktemp -u "${STATESETUP}/context_${__name}.stdout.XXXXXXXX")" + __stderr="$(mktemp -u "${STATESETUP}/context_${__name}.stderr.XXXXXXXX")" + shift + echo "$*" >> "${__log}" + mkfifo "${__stdout}" "${__stderr}" + tee -a "${__log}" < "${__stdout}" & + tee -a "${__log}" < "${__stderr}" >&2 & + $(cat ${__enter}) "$*" >> "${__stdout}" 2>> "${__stderr}" + rc=$? + rm "${__stdout}" "${__stderr}" + [ ${DEBUG} -eq 1 ] && echo "[Exit code: $rc]" >> "${__log}" + echo -n "${__name}$ " >> "${__log}" + return $rc +} + +# context_run_bg() - Start a shell command in a context +# $1: Context name +# $*: Command to start +context_run_bg() { + __name="$1" + __pidfile="${STATESETUP}/context_${__name}.pid" + context_run "$@" & + echo $! > "${__pidfile}" +} + +# context_wait() - Wait for background command in a context to complete +# $1: Context name +# Returns the status of the completed command +context_wait() { + __name="$1" + __pidfile="${STATESETUP}/context_${__name}.pid" + __pid=$(cat "${__pidfile}") + rm "${__pidfile}" + wait ${__pid} +} diff --git a/oldtest/lib/layout b/oldtest/lib/layout new file mode 100644 index 0000000..f9a1cf1 --- /dev/null +++ b/oldtest/lib/layout @@ -0,0 +1,259 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/layout - tmux pane layouts +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +# layout_pasta() - Panes for host, pasta, and separate one for namespace +layout_pasta() { + sleep 3 + + tmux kill-pane -a -t 0 + cmd_write 0 clear + + tmux split-window -v -t passt_test + tmux split-window -h -t passt_test + tmux split-window -h -l '42%' -t passt_test:1.0 + + PANE_NS=0 + PANE_INFO=1 + PANE_HOST=2 + PANE_PASST=3 + + get_info_cols + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "test log" + + pane_watch_contexts ${PANE_HOST} host host + pane_watch_contexts ${PANE_PASST} pasta passt + pane_watch_contexts ${PANE_NS} "namespace" unshare ns + + info_layout "single pasta instance with namespace" + + sleep 1 +} + +# layout_passt() - Panes for host, passt, and guest +layout_passt() { + sleep 3 + + tmux kill-pane -a -t 0 + cmd_write 0 clear + + tmux split-window -v -t passt_test + tmux split-window -h -t passt_test + tmux split-window -h -l '42%' -t passt_test:1.0 + + PANE_GUEST=0 + PANE_INFO=1 + PANE_HOST=2 + PANE_PASST=3 + + get_info_cols + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "test log" + + pane_watch_contexts ${PANE_HOST} host host + pane_watch_contexts ${PANE_PASST} passt passt + pane_watch_contexts ${PANE_GUEST} guest qemu guest + + info_layout "single passt instance with guest" + + sleep 1 +} + +# layout_passt_in_pasta() - Host, passt within pasta, namespace and guest +layout_passt_in_pasta() { + sleep 3 + + tmux kill-pane -a -t 0 + cmd_write 0 clear + + tmux split-window -v -l '45%' -t passt_test + tmux split-window -h -t passt_test + tmux split-window -h -l '42%' -t passt_test:1.0 + tmux split-window -v -t passt_test:1.0 + + PANE_GUEST=0 + PANE_NS=1 + PANE_INFO=2 + PANE_HOST=3 + PANE_PASST=4 + + get_info_cols + + pane_watch_contexts ${PANE_GUEST} "guest" qemu guest + pane_watch_contexts ${PANE_NS} "namespace" ns + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "test log" + + pane_watch_contexts ${PANE_HOST} host host + + pane_watch_contexts ${PANE_PASST} "passt in pasta (namespace)" pasta passt + + info_layout "passt and guest in namespace, connected by pasta" + + sleep 1 +} + +# layout_two_guests() - Two guest panes, two passt panes, plus host and log +layout_two_guests() { + sleep 3 + + tmux kill-pane -a -t 0 + cmd_write 0 clear + + tmux split-window -v -t passt_test + tmux split-window -h -l '33%' + tmux split-window -h -t passt_test:1.1 + + tmux split-window -h -l '35%' -t passt_test:1.0 + tmux split-window -v -t passt_test:1.0 + + PANE_GUEST_1=0 + PANE_GUEST_2=1 + PANE_INFO=2 + PANE_HOST=3 + PANE_PASST_1=4 + PANE_PASST_2=5 + + get_info_cols + + pane_watch_contexts ${PANE_GUEST_1} "guest #1 in namespace #1" qemu_1 guest_1 + pane_watch_contexts ${PANE_GUEST_2} "guest #2 in namespace #2" qemu_2 guest_2 + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "test log" + + pane_watch_contexts ${PANE_HOST} host host + pane_watch_contexts ${PANE_PASST_1} "passt #1 in namespace #1" pasta_1 passt_1 + pane_watch_contexts ${PANE_PASST_2} "passt #2 in namespace #2" pasta_2 passt_2 + + info_layout "two guests, two passt instances, in namespaces" + + sleep 1 +} + +# layout_demo_pasta() - Four panes for pasta demo +layout_demo_pasta() { + sleep 3 + + cmd_write 0 cd ${BASEPATH} + cmd_write 0 clear + sleep 1 + cmd_write 0 clear + + tmux split-window -v -t passt_test + tmux split-window -h -t passt_test + tmux split-window -h -l '42%' -t passt_test:1.0 + + PANE_NS=0 + PANE_INFO=1 + PANE_HOST=2 + PANE_PASST=3 + + get_info_cols + + tmux pipe-pane -O -t ${PANE_NS} "cat >> ${LOGDIR}/pane_ns.log" + tmux select-pane -t ${PANE_NS} -T "namespace" + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "" + + tmux pipe-pane -O -t ${PANE_HOST} "cat >> ${LOGDIR}/pane_host.log" + tmux select-pane -t ${PANE_HOST} -T "host" + + tmux pipe-pane -O -t ${PANE_PASST} "cat >> ${LOGDIR}/pane_passt.log" + tmux select-pane -t ${PANE_PASST} -T "pasta" + + sleep 1 +} + +# layout_demo_passt() - Four panes for passt demo +layout_demo_passt() { + sleep 3 + + cmd_write 0 cd ${BASEPATH} + cmd_write 0 clear + sleep 1 + cmd_write 0 clear + + tmux split-window -v -t passt_test + tmux split-window -h -t passt_test + tmux split-window -h -l '42%' -t passt_test:1.0 + + PANE_GUEST=0 + PANE_INFO=1 + PANE_HOST=2 + PANE_PASST=3 + + get_info_cols + + tmux pipe-pane -O -t ${PANE_GUEST} "cat >> ${LOGDIR}/pane_guest.log" + tmux select-pane -t ${PANE_GUEST} -T "guest" + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "" + + tmux pipe-pane -O -t ${PANE_HOST} "cat >> ${LOGDIR}/pane_host.log" + tmux select-pane -t ${PANE_HOST} -T "host" + + tmux pipe-pane -O -t ${PANE_PASST} "cat >> ${LOGDIR}/pane_passt.log" + tmux select-pane -t ${PANE_PASST} -T "passt in pasta (namespace)" + + sleep 1 +} + +# layout_demo_podman() - Four panes for pasta demo with Podman +layout_demo_podman() { + sleep 3 + + cmd_write 0 cd ${BASEPATH} + cmd_write 0 clear + sleep 1 + cmd_write 0 clear + + tmux split-window -v -l '65%' -t passt_test + tmux split-window -h -t passt_test + tmux split-window -h -l '42%' -t passt_test:1.0 + + PANE_HOST=0 + PANE_INFO=1 + PANE_NS1=2 + PANE_NS2=3 + + get_info_cols + + tmux pipe-pane -O -t ${PANE_NS1} "cat >> ${LOGDIR}/pane_ns1.log" + tmux select-pane -t ${PANE_NS1} -T "Podman with slirp4netns" + + tmux pipe-pane -O -t ${PANE_NS2} "cat >> ${LOGDIR}/pane_ns2.log" + tmux select-pane -t ${PANE_NS2} -T "Podman with pasta" + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "" + + tmux pipe-pane -O -t ${PANE_HOST} "cat >> ${LOGDIR}/pane_host.log" + tmux select-pane -t ${PANE_HOST} -T "host" + + sleep 1 +} diff --git a/oldtest/lib/layout_ugly b/oldtest/lib/layout_ugly new file mode 100644 index 0000000..2aaf1ec --- /dev/null +++ b/oldtest/lib/layout_ugly @@ -0,0 +1,113 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/layout_ugly - screen-scraped tmux pane layouts +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +# layout_host() - Simple host commands layout with info and host panes +layout_host() { + sleep 3 + + tmux kill-pane -a -t 0 + cmd_write 0 clear + + tmux split-window -h -l '35%' -t passt_test:1.0 + + PANE_HOST=0 + PANE_INFO=1 + + get_info_cols + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "test log" + + if context_exists host; then + pane_watch_contexts 0 host host + else + tmux pipe-pane -O -t ${PANE_HOST} "cat >> ${LOGDIR}/pane_host.log" + tmux select-pane -t ${PANE_HOST} -T "host" + fi + + info_layout "host commands only" + + sleep 1 +} + +# layout_pasta_simple() - Panes for host and pasta +layout_pasta_simple() { + sleep 3 + + tmux kill-pane -a -t 0 + cmd_write 0 clear + + tmux split-window -v -t passt_test + tmux split-window -h -t passt_test + + PANE_PASST=0 + PANE_HOST=1 + PANE_INFO=2 + + get_info_cols + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "test log" + + if context_exists host; then + pane_watch_contexts ${PANE_HOST} host host + else + tmux pipe-pane -O -t ${PANE_HOST} "cat >> ${LOGDIR}/pane_host.log" + tmux select-pane -t ${PANE_HOST} -T "host" + fi + + if context_exists passt; then + pane_watch_contexts ${PANE_PASST} host host + else + tmux pipe-pane -O -t ${PANE_PASST} "cat >> ${LOGDIR}/pane_passt.log" + tmux select-pane -t ${PANE_PASST} -T "pasta" + fi + + info_layout "single pasta instance" + + sleep 1 +} + +# layout_memory() - Screen-scraped panes for memory usage tests, big guest pane +layout_memory() { + sleep 3 + + tmux kill-pane -a -t 0 + cmd_write 0 clear + + tmux split-window -h -l '35%' -t passt_test + + PANE_GUEST=0 + PANE_INFO=1 + + get_info_cols + + tmux send-keys -l -t ${PANE_INFO} 'while cat '"$STATEBASE/log_pipe"'; do :; done' + tmux send-keys -t ${PANE_INFO} -N 100 C-m + tmux select-pane -t ${PANE_INFO} -T "test log" + + if context_exists guest; then + pane_watch_contexts ${PANE_GUEST} guest guest + else + tmux pipe-pane -O -t ${PANE_GUEST} "cat >> ${LOGDIR}/pane_guest.log" + tmux select-pane -t ${PANE_GUEST} -T "guest" + fi + + info_layout "memory usage" + + sleep 1 +} diff --git a/oldtest/lib/perf_report b/oldtest/lib/perf_report new file mode 100755 index 0000000..d51a2b4 --- /dev/null +++ b/oldtest/lib/perf_report @@ -0,0 +1,272 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/perf_report - Prepare JavaScript report for performance tests +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +PERF_INIT=0 +PERF_LINK_COUNT=0 +PERF_JS="${LOGDIR}/web/perf.js" + +PERF_TEMPLATE_HTML="document.write('"' +Throughput in Gbps, latency in µs. Threads are <span style="font-family: monospace;">iperf3</span> processes, <i>passt</i> and <i>pasta</i> are currently single-threaded.<br/> +Click on numbers to show test execution. Measured at head, commit <span style="font-family: monospace;">__commit__</span>. + +<style type="text/CSS"> +table.passt td { border: 0px solid; padding: 6px; line-height: 1; } +table.passt td { text-align: right; } +table.passt th { text-align: center; font-weight: bold; } +table.passt tr:not(:first-of-type) td:not(:first-of-type) { font-family: monospace; font-weight: bolder; } +table.passt tr:nth-child(3n+0) { background-color: #112315; } +table.passt tr:not(:nth-child(3n+0)) td { background-color: #101010; } +table.passt td:nth-child(6n+7) { background-color: #603302; } +table.passt tr:nth-child(1) { background-color: #363e61; } +td:empty { visibility: hidden; } +</style> + +<ul> +<li><p>passt</p> +<table class="passt" width="70%"> + <tr> + <th/> + <th id="perf_passt_tcp" colspan="__passt_tcp_cols__">TCP, __passt_tcp_threads__ at __passt_tcp_freq__ GHz</th> + <th id="perf_passt_udp" colspan="__passt_udp_cols__">UDP, __passt_udp_threads__ at __passt_udp_freq__ GHz</th> + </tr> + <tr> + <td align="right">MTU:</td> + __passt_tcp_header__ + __passt_udp_header__ + </tr> + __passt_tcp_LINE__ __passt_udp_LINE__ +</table> + +<style type="text/CSS"> +table.pasta td { border: 0px solid; padding: 6px; line-height: 1; } +table.pasta td { text-align: right; } +table.pasta th { text-align: center; font-weight: bold; } +table.pasta tr:not(:first-of-type) td:not(:first-of-type) { font-family: monospace; font-weight: bolder; } +table.pasta tr:nth-child(3n+0) { background-color: #112315; } +table.pasta tr:not(:nth-child(3n+0)) td { background-color: #101010; } +table.pasta td:nth-child(4n+5) { background-color: #603302; } +table.pasta tr:nth-child(1) { background-color: #363e61; } +td:empty { visibility: hidden; } +</style> + +</li><li><p>pasta: local connections/traffic</p> +<table class="pasta" width="70%"> + <tr> + <th/> + <th id="perf_pasta_lo_tcp" colspan="__pasta_lo_tcp_cols__">TCP, __pasta_lo_tcp_threads__ at __pasta_lo_tcp_freq__ GHz</th> + <th id="perf_pasta_lo_udp" colspan="__pasta_lo_udp_cols__">UDP, __pasta_lo_udp_threads__ at __pasta_lo_udp_freq__ GHz</th> + </th> + <tr> + <td align="right">MTU:</td> + __pasta_lo_tcp_header__ + __pasta_lo_udp_header__ + </tr> + __pasta_lo_tcp_LINE__ __pasta_lo_udp_LINE__ +</table> + +</li><li><p>pasta: connections/traffic via tap</p> +<table class="pasta" width="70%"> + <tr> + <th/> + <th id="perf_pasta_tap_tcp" colspan="__pasta_tap_tcp_cols__">TCP, __pasta_tap_tcp_threads__ at __pasta_tap_tcp_freq__ GHz</th> + <th id="perf_pasta_tap_udp" colspan="__pasta_tap_udp_cols__">UDP, __pasta_tap_udp_threads__ at __pasta_tap_udp_freq__ GHz</th> + </tr> + <tr> + <td align="right">MTU:</td> + __pasta_tap_tcp_header__ + __pasta_tap_udp_header__ + </tr> + __pasta_tap_tcp_LINE__ __pasta_tap_udp_LINE__ +</table> + +</li></ul>' + +PERF_TEMPLATE_JS="'); + +var perf_links = [ +" + +PERF_TEMPLATE_POST=']; + +for (var i = 0; i < perf_links.length; i++) { + var obj = document.getElementById(perf_links[i][0]); + + obj.addEventListener("click", function(event) { + var ci_video = document.getElementById("ci"); + var top = ci_video.offsetTop - 5; + var seek; + + for (var i = 0; i < perf_links.length; i++) { + if (this.id == perf_links[i][0]) { + seek = perf_links[i][1]; + } + } + + event.preventDefault(); + ci_player.dispose(); + ci_player = AsciinemaPlayer.create("/builds/latest/web/ci.cast", + ci_video, + { cols: 240, rows: 51, poster: "npt:999:0", startAt: seek, autoplay: true }); + + window.scrollTo({ top: top, behavior: "smooth" }) + }, false); +} +' + +# perf_init() - Process first part of template +perf_init() { + mkdir -p "$(dirname "${PERF_JS}")" + echo "${PERF_TEMPLATE_HTML}" > "${PERF_JS}" + perf_report_sub commit "$(echo ${COMMIT} | sed "s/'/\\\'/g")" + PERF_INIT=1 +} + +# perf_fill_lines() - Fill multiple "LINE" directives in template, matching rows +perf_fill_lines() { + while true; do + __file_line="$(sed -n '/__.*_LINE__/{=;q}' "${PERF_JS}")" + [ -z "${__file_line}" ] && break + + __line_no=0 + __done=0 + __line_buf="<tr>" + while true; do + __match_first_td=0 + for __t in $(sed -n '/__.*_LINE__/{p;q}' "${PERF_JS}"); do + if [ ${__match_first_td} -eq 1 ]; then + __matching_line_no=0 + while true; do + __line_part= + __var_name="$(echo $__t | sed -n 's/__\(.*\)__/\1_'"${__matching_line_no}"'/p')" + [ -z "$(eval echo \$${__var_name})" ] && break + __line_part="$(eval echo \$${__var_name})" + __td_check="$(echo "${__line_part}" | sed -n 's/^<td>\([^>]*\)<\/td>.*$/\1/p')" + if [ "${__td_check}" = "${__td_match}" ]; then + __line_part="$(echo "${__line_part}" | sed -n 's/^<td>[^>]*<\/td>\(.*\)$/\1/p')" + break + fi + __matching_line_no=$((__matching_line_no + 1)) + done + else + __var_name="$(echo $__t | sed -n 's/__\(.*\)__/\1_'"${__line_no}"'/p')" + [ -z "$(eval echo \$${__var_name})" ] && __done=1 && break + __line_part="$(eval echo \$${__var_name})" + __td_match="$(echo "${__line_part}" | sed -n 's/^<td>\([^>]*\)<\/td>.*$/\1/p')" + fi + __line_buf="${__line_buf}${__line_part}" + __match_first_td=1 + done + [ ${__done} -eq 1 ] && break + __line_no=$((__line_no + 1)) + __line_buf="${__line_buf}</tr><tr>" + done + __line_buf="${__line_buf}</tr>" + __line_buf="$(printf '%s\n' "${__line_buf}" | sed -e 's/[]\/$*.^[]/\\&/g')" + sed -i "${__file_line}s/.*/${__line_buf}/" "${PERF_JS}" + done +} + +# perf_finish() - Add trailing backslashes and process ending templates +perf_finish() { + PERF_INIT=0 + perf_fill_lines + sed -i 's/^.*$/&\\/g' "${PERF_JS}" + echo "${PERF_TEMPLATE_JS}" >> "${PERF_JS}" + echo "${PERF_TEMPLATE_POST}" >> "${PERF_JS}" +} + +# perf_report_sub() - Apply simple substitutions in template +perf_report_sub() { + __et="$(printf '%s\n' "${1}" | sed -e 's/[\/&]/\\&/g')" + __es="$(printf '%s\n' "${2}" | sed -e 's/[]\/$*.^[]/\\&/g')" + + sed -i 's/__'"${__et}"'__/'"${__es}"'/g' "${PERF_JS}" +} + +# perf_report_append_js() - Append generic string to current template buffer +perf_report_append_js() { + PERF_TEMPLATE_JS="${PERF_TEMPLATE_JS}${@}" +} + +# perf_report() - Start of single test report +perf_report() { + __mode="${1}" + __proto="${2}" + __threads="${3}" + __freq="${4}" + + REPORT_IN="${__mode}_${__proto}" + + [ ${__threads} -eq 1 ] && __threads="one thread" || __threads="${__threads} threads" + perf_report_sub "${__mode}_${__proto}_threads" "${__threads}" + perf_report_sub "${__mode}_${__proto}_freq" "${__freq}" + + perf_report_append_js "[ 'perf_${__mode}_${__proto}', $(video_time_now) ]," +} + +# perf_th() - Table header for a set of tests +perf_th() { + [ ${PERF_INIT} -eq 0 ] && return + + shift + + __th_buf= + __cols_count=0 + for __arg; do + __th_buf="${__th_buf}<td>${__arg}</td>" + __cols_count=$((__cols_count + 1)) + done + perf_report_sub "${REPORT_IN}_header" "${__th_buf}" + perf_report_sub "${REPORT_IN}_cols" ${__cols_count} +} + +# perf_tr() - Main table row +perf_tr() { + [ ${PERF_INIT} -eq 0 ] && return + + __line_no=0 + shift + while true; do + [ -z "$(eval echo \$${REPORT_IN}_LINE_${__line_no})" ] && break + __line_no=$((__line_no + 1)) + done + eval ${REPORT_IN}_LINE_${__line_no}="\"<td>${@}</td>\"" +} + +# perf_td() - Single cell with test result +perf_td() { + [ ${PERF_INIT} -eq 0 ] && return + + __rewind="${1}" + shift + + __line_no=0 + while true; do + [ -z "$(eval echo \$${REPORT_IN}_LINE_${__line_no})" ] && break + __line_no=$((__line_no + 1)) + done + __line_no=$((__line_no - 1)) + [ -z "${1}" ] && __id=0 || __id="perf_${PERF_LINK_COUNT}" + eval ${REPORT_IN}_LINE_${__line_no}=\""\${${REPORT_IN}_LINE_${__line_no}}<td id=\"${__id}\">${1}</td>"\" + [ -z "${1}" ] && return + + perf_report_append_js "[ '${__id}', $(($(video_time_now) - ${__rewind})) ]," + PERF_LINK_COUNT=$((PERF_LINK_COUNT + 1)) +} + +# perf_te() - End of a table, currently unused +pert_te() { + : +} diff --git a/oldtest/lib/setup b/oldtest/lib/setup new file mode 100755 index 0000000..9b39b9f --- /dev/null +++ b/oldtest/lib/setup @@ -0,0 +1,385 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/setup - Set up and tear down passt and pasta environments +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +INITRAMFS="${BASEPATH}/mbuto.img" +VCPUS="$( [ $(nproc) -ge 8 ] && echo 6 || echo $(( $(nproc) / 2 + 1 )) )" +__mem_kib="$(sed -n 's/MemTotal:[ ]*\([0-9]*\) kB/\1/p' /proc/meminfo)" +VMEM="$((${__mem_kib} / 1024 / 4))" + +# setup_build() - Set up pane layout for build tests +setup_build() { + context_setup_host host + + layout_host +} + +# setup_passt() - Start qemu and passt +setup_passt() { + context_setup_host host + context_setup_host passt + context_setup_host qemu + + layout_passt + + # Ports: + # + # guest | host + # --------------|--------------------- + # 10001 as server | forwarded to guest + # 10003 | as server + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + + context_run passt "make clean" + context_run passt "make valgrind" + context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt ${__opts} -s ${STATESETUP}/passt.socket -f -t 10001 -u 10001 -P ${STATESETUP}/passt.pid" + + # pidfile isn't created until passt is listening + wait_for [ -f "${STATESETUP}/passt.pid" ] + + GUEST_CID=94557 + context_run_bg qemu 'qemu-system-$(uname -m)' \ + ' -machine accel=kvm' \ + ' -m '${VMEM}' -cpu host -smp '${VCPUS} \ + ' -kernel ' "/boot/vmlinuz-$(uname -r)" \ + ' -initrd '${INITRAMFS}' -nographic -serial stdio' \ + ' -nodefaults' \ + ' -append "console=ttyS0 mitigations=off apparmor=0" ' \ + ' -device virtio-net-pci,netdev=s0 ' \ + " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt.socket " \ + " -pidfile ${STATESETUP}/qemu.pid" \ + " -device vhost-vsock-pci,guest-cid=$GUEST_CID" + + context_setup_guest guest $GUEST_CID +} + +# setup_pasta() - Create a network and user namespace, connect pasta to it +setup_pasta() { + context_setup_host host + context_setup_host passt + context_setup_host unshare + + layout_pasta + + context_run_bg unshare "unshare -rUnpf ${NSTOOL} hold ${STATESETUP}/ns.hold" + + context_setup_nstool ns ${STATESETUP}/ns.hold + + # Ports: + # + # ns | host + # ------------------|--------------------- + # 10002 as server | spliced to ns + # 10003 spliced to init | as server + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + + context_run_bg passt "./pasta ${__opts} -f -t 10002 -T 10003 -u 10002 -U 10003 -P ${STATESETUP}/passt.pid $(${NSTOOL} info -pw ${STATESETUP}/ns.hold)" + + # pidfile isn't created until pasta is ready + wait_for [ -f "${STATESETUP}/passt.pid" ] +} + +# setup_passt_in_ns() - Set up namespace (with pasta), run qemu and passt into it +setup_passt_in_ns() { + context_setup_host host + context_setup_host pasta + + layout_passt_in_pasta + + # Ports: + # + # guest | ns | host + # -------------|--------------------|----------------- + # 10001 as server | forwarded to guest | spliced to ns + # 10002 | as server | spliced to ns + # 10003 | spliced to init | as server + # 10011 as server | forwarded to guest | spliced to ns + # 10012 | as server | spliced to ns + # 10013 | spliced to init | as server + # + # 10021 as server | forwarded to guest | + # 10031 as server | forwarded to guest | + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta_with_passt.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + + context_run_bg pasta "./pasta ${__opts} -t 10001,10002,10011,10012 -T 10003,10013 -u 10001,10002,10011,10012 -U 10003,10013 -P ${STATESETUP}/pasta.pid --config-net ${NSTOOL} hold ${STATESETUP}/ns.hold" + wait_for [ -f "${STATESETUP}/pasta.pid" ] + + context_setup_nstool qemu ${STATESETUP}/ns.hold + context_setup_nstool ns ${STATESETUP}/ns.hold + context_setup_nstool passt ${STATESETUP}/ns.hold + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_in_pasta.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + + if [ ${VALGRIND} -eq 1 ]; then + context_run passt "make clean" + context_run passt "make valgrind" + context_run_bg passt "valgrind --max-stackframe=$((4 * 1024 * 1024)) --trace-children=yes --vgdb=no --error-exitcode=1 --suppressions=test/valgrind.supp ./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid" + else + context_run passt "make clean" + context_run passt "make" + context_run_bg passt "./passt -f ${__opts} -s ${STATESETUP}/passt.socket -t 10001,10011,10021,10031 -u 10001,10011,10021,10031 -P ${STATESETUP}/passt.pid" + fi + wait_for [ -f "${STATESETUP}/passt.pid" ] + + GUEST_CID=94557 + context_run_bg qemu 'qemu-system-$(uname -m)' \ + ' -machine accel=kvm' \ + ' -M accel=kvm:tcg' \ + ' -m '${VMEM}' -cpu host -smp '${VCPUS} \ + ' -kernel ' "/boot/vmlinuz-$(uname -r)" \ + ' -initrd '${INITRAMFS}' -nographic -serial stdio' \ + ' -nodefaults' \ + ' -append "console=ttyS0 mitigations=off apparmor=0" ' \ + ' -device virtio-net-pci,netdev=s0 ' \ + " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt.socket " \ + " -pidfile ${STATESETUP}/qemu.pid" \ + " -device vhost-vsock-pci,guest-cid=$GUEST_CID" + + context_setup_guest guest $GUEST_CID +} + +# setup_two_guests() - Set up two namespace, run qemu and passt in both of them +setup_two_guests() { + context_setup_host host + context_setup_host pasta_1 + context_setup_host pasta_2 + + layout_two_guests + + # Ports: + # + # guest #1 | guest #2 | ns #1 | ns #2 | host + # --------- |-----------|-----------|------------|------------ + # 10001 as server | | to guest | to init | to ns #1 + # 10002 | | as server | | to ns #1 + # 10003 | | to init | to init | as server + # 10004 | as server | to init | to guest | to ns #2 + # 10005 | | | as server | to ns #2 + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta_1.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + context_run_bg pasta_1 "./pasta ${__opts} --trace -l /tmp/pasta1.log -P ${STATESETUP}/pasta_1.pid -t 10001,10002 -T 10003,10004 -u 10001,10002 -U 10003,10004 --config-net ${NSTOOL} hold ${STATESETUP}/ns1.hold" + context_setup_nstool passt_1 ${STATESETUP}/ns1.hold + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/pasta_2.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + context_run_bg pasta_2 "./pasta ${__opts} --trace -l /tmp/pasta2.log -P ${STATESETUP}/pasta_2.pid -t 10004,10005 -T 10003,10001 -u 10004,10005 -U 10003,10001 --config-net ${NSTOOL} hold ${STATESETUP}/ns2.hold" + context_setup_nstool passt_2 ${STATESETUP}/ns2.hold + + context_setup_nstool qemu_1 ${STATESETUP}/ns1.hold + context_setup_nstool qemu_2 ${STATESETUP}/ns2.hold + + __ifname="$(context_run qemu_1 "ip -j link show | jq -rM '.[] | select(.link_type == \"ether\").ifname'")" + + sleep 1 + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_1.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + + context_run_bg passt_1 "./passt -s ${STATESETUP}/passt_1.socket -P ${STATESETUP}/passt_1.pid -f ${__opts} -t 10001 -u 10001" + wait_for [ -f "${STATESETUP}/passt_1.pid" ] + + __opts= + [ ${PCAP} -eq 1 ] && __opts="${__opts} -p ${LOGDIR}/passt_2.pcap" + [ ${DEBUG} -eq 1 ] && __opts="${__opts} -d" + [ ${TRACE} -eq 1 ] && __opts="${__opts} --trace" + + context_run_bg passt_2 "./passt -s ${STATESETUP}/passt_2.socket -P ${STATESETUP}/passt_2.pid -f ${__opts} -t 10004 -u 10004" + wait_for [ -f "${STATESETUP}/passt_2.pid" ] + + GUEST_1_CID=94557 + context_run_bg qemu_1 'qemu-system-$(uname -m)' \ + ' -M accel=kvm:tcg' \ + ' -m '${VMEM}' -cpu host -smp '${VCPUS} \ + ' -kernel ' "/boot/vmlinuz-$(uname -r)" \ + ' -initrd '${INITRAMFS}' -nographic -serial stdio' \ + ' -nodefaults' \ + ' -append "console=ttyS0 mitigations=off apparmor=0" ' \ + ' -device virtio-net-pci,netdev=s0 ' \ + " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt_1.socket " \ + " -pidfile ${STATESETUP}/qemu_1.pid" \ + " -device vhost-vsock-pci,guest-cid=$GUEST_1_CID" + + GUEST_2_CID=94558 + context_run_bg qemu_2 'qemu-system-$(uname -m)' \ + ' -M accel=kvm:tcg' \ + ' -m '${VMEM}' -cpu host -smp '${VCPUS} \ + ' -kernel ' "/boot/vmlinuz-$(uname -r)" \ + ' -initrd '${INITRAMFS}' -nographic -serial stdio' \ + ' -nodefaults' \ + ' -append "console=ttyS0 mitigations=off apparmor=0" ' \ + ' -device virtio-net-pci,netdev=s0 ' \ + " -netdev stream,id=s0,server=off,addr.type=unix,addr.path=${STATESETUP}/passt_2.socket " \ + " -pidfile ${STATESETUP}/qemu_2.pid" \ + " -device vhost-vsock-pci,guest-cid=$GUEST_2_CID" + + context_setup_guest guest_1 ${GUEST_1_CID} + context_setup_guest guest_2 ${GUEST_2_CID} +} + +# teardown_context_watch() - Remove contexts and stop panes watching them +# $1: Pane number watching +# $@: Context names +teardown_context_watch() { + __pane="$1" + shift + for __c; do + context_teardown "${__c}" + done + tmux send-keys -t ${__pane} "C-c" +} + +# teardown_build() - Nothing to do, yet +teardown_build() { + teardown_context_watch ${PANE_HOST} host +} + +# teardown_passt() - Kill qemu, remove passt PID file +teardown_passt() { + kill $(cat "${STATESETUP}/qemu.pid") + + rm "${STATESETUP}/passt.pid" + + teardown_context_watch ${PANE_HOST} host + teardown_context_watch ${PANE_PASST} passt + teardown_context_watch ${PANE_GUEST} qemu guest +} + +# teardown_pasta() - Exit namespace, kill pasta process +teardown_pasta() { + ${NSTOOL} stop "${STATESETUP}/ns.hold" + context_wait unshare + + teardown_context_watch ${PANE_HOST} host + teardown_context_watch ${PANE_PASST} passt + teardown_context_watch ${PANE_NS} unshare ns +} + +# teardown_passt_in_ns() - Exit namespace, kill qemu and pasta, remove pid file +teardown_passt_in_ns() { + context_run ns kill $(cat "${STATESETUP}/qemu.pid") + context_wait qemu + + ${NSTOOL} stop "${STATESETUP}/ns.hold" + context_wait pasta + + rm "${STATESETUP}/passt.pid" "${STATESETUP}/pasta.pid" + + teardown_context_watch ${PANE_HOST} host + teardown_context_watch ${PANE_PASST} pasta passt + teardown_context_watch ${PANE_NS} ns + teardown_context_watch ${PANE_GUEST} qemu guest +} + +# teardown_two_guests() - Exit namespaces, kill qemu processes, passt and pasta +teardown_two_guests() { + ${NSTOOL} exec ${STATESETUP}/ns1.hold -- kill $(cat "${STATESETUP}/qemu_1.pid") + ${NSTOOL} exec ${STATESETUP}/ns2.hold -- kill $(cat "${STATESETUP}/qemu_2.pid") + context_wait qemu_1 + context_wait qemu_2 + + ${NSTOOL} exec ${STATESETUP}/ns1.hold -- kill $(cat "${STATESETUP}/passt_1.pid") + ${NSTOOL} exec ${STATESETUP}/ns2.hold -- kill $(cat "${STATESETUP}/passt_2.pid") + context_wait passt_1 + context_wait passt_2 + ${NSTOOL} stop "${STATESETUP}/ns1.hold" + ${NSTOOL} stop "${STATESETUP}/ns2.hold" + context_wait pasta_1 + context_wait pasta_2 + + rm -f "${STATESETUP}/passt__[12].pid" "${STATESETUP}/pasta_[12].pid" + + teardown_context_watch ${PANE_HOST} host + teardown_context_watch ${PANE_GUEST_1} qemu_1 guest_1 + teardown_context_watch ${PANE_GUEST_2} qemu_2 guest_2 + teardown_context_watch ${PANE_PASST_1} pasta_1 passt_1 + teardown_context_watch ${PANE_PASST_2} pasta_2 passt_2 +} + +# teardown_demo_passt() - Exit namespace, kill qemu, passt and pasta +teardown_demo_passt() { + tmux send-keys -t ${PANE_GUEST} "C-c" + pane_wait GUEST + + tmux send-keys -t ${PANE_GUEST} "C-d" + tmux send-keys -t ${PANE_PASST} "C-c" + + pane_wait GUEST + pane_wait HOST + pane_wait PASST + + tmux kill-pane -a -t 0 + tmux send-keys -t 0 "C-c" +} + +# teardown_demo_pasta() - Exit perf and namespace from remaining pane +teardown_demo_pasta() { + tmux send-keys -t ${PANE_NS} "q" + pane_wait NS + tmux send-keys -t ${PANE_NS} "C-d" + pane_wait NS + + tmux kill-pane -a -t 0 + tmux send-keys -t 0 "C-c" +} + +# teardown_demo_podman() - Exit namespaces +teardown_demo_podman() { + tmux send-keys -t ${PANE_NS1} "C-d" + tmux send-keys -t ${PANE_NS2} "C-d" + pane_wait NS1 + pane_wait NS2 + + tmux kill-pane -a -t 0 + tmux send-keys -t 0 "C-c" +} + +# setup() - Run setup_*() functions +# $*: Suffix list of setup_*() functions to be called +setup() { + for arg do + STATESETUP="${STATEBASE}/${arg}" + mkdir -p "${STATESETUP}" + eval setup_${arg} + done +} + +# teardown() - Run teardown_*() functions +# $*: Suffix list of teardown_*() functions to be called +teardown() { + for arg do + eval teardown_${arg} + done +} diff --git a/oldtest/lib/setup_ugly b/oldtest/lib/setup_ugly new file mode 100755 index 0000000..4b2a077 --- /dev/null +++ b/oldtest/lib/setup_ugly @@ -0,0 +1,58 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/setup_ugly - Setup functions using screen-scraping instead of context +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +INITRAMFS_MEM="${BASEPATH}/mbuto.mem.img" + +# setup_distro() - Set up pane layout for distro tests +setup_distro() { + layout_host +} + +# setup_pasta_options() - Set up layout and host context without starting pasta +setup_pasta_options() { + context_setup_host host + + layout_pasta_simple +} + +# setup_memory() - Start qemu in guest pane, and passt in passt context +setup_memory() { + layout_memory + + pane_or_context_run guest 'qemu-system-$(uname -m)' \ + ' -machine accel=kvm' \ + ' -m '${VMEM}' -cpu host -smp '${VCPUS} \ + ' -kernel ' "/boot/vmlinuz-$(uname -r)" \ + ' -initrd '${INITRAMFS_MEM}' -nographic -serial stdio' \ + ' -nodefaults' \ + ' -append "console=ttyS0 mitigations=off apparmor=0"' \ + " -pidfile ${STATESETUP}/qemu.pid" +} + +# teardown_distro() - Nothing to do, yet +teardown_distro() { + : +} + +# teardown_pasta_options() - Tear down pasta and host context, no namespace +teardown_pasta_options() { + teardown_context_watch ${PANE_HOST} host + teardown_context_watch ${PANE_PASST} passt +} + +# teardown_passt() - Kill qemu with ^C, remove passt PID file +teardown_memory() { + kill $(cat "${STATESETUP}/qemu.pid") +} diff --git a/oldtest/lib/term b/oldtest/lib/term new file mode 100755 index 0000000..aa05bf1 --- /dev/null +++ b/oldtest/lib/term @@ -0,0 +1,750 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/term - Set up tmux sessions and panes, handle terminals and logs +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +STATUS_FILE= +STATUS_FILE_NTESTS= +STATUS_FILE_INDEX=0 +STATUS_COLS= +STATUS_PASS=0 +STATUS_FAIL=0 + +PR_RED='\033[1;31m' +PR_GREEN='\033[1;32m' +PR_YELLOW='\033[1;33m' +PR_BLUE='\033[1;34m' +PR_NC='\033[0m' +PR_DELAY_INIT=100 # ms + +# info() - Highlight test log pane, print message to it and to log file +# $@: Message to print +info() { + tmux select-pane -t ${PANE_INFO} + echo "${@}" >> $STATEBASE/log_pipe + echo "${@}" >> "${LOGFILE}" +} + +# info_n() - Highlight, print message to pane and to log file without newline +# $@: Message to print +info_n() { + tmux select-pane -t ${PANE_INFO} + printf "${@}" >> $STATEBASE/log_pipe + printf "${@}" >> "${LOGFILE}" +} + +# info_nolog() - Highlight test log pane, print message to it +# $@: Message to print +info_nolog() { + tmux select-pane -t ${PANE_INFO} + echo "${@}" >> $STATEBASE/log_pipe +} + +# info_nolog() - Print message to log file +# $@: Message to print +log() { + echo "${@}" >> "${LOGFILE}" +} + +# info_nolog_n() - Send message to pane without highlighting it, without newline +# $@: Message to print +info_nolog_n() { + tmux send-keys -l -t ${PANE_INFO} "${@}" +} + +# info_sep() - Print given separator, horizontally filling test log pane +# $1: Separator character +info_sep() { + tmux send-keys -l -N ${STATUS_COLS} -t ${PANE_INFO} "${1}" + tmux send-keys -t ${PANE_INFO} C-m +} + +# sleep_char() - Sleep for typed characted resembling interactive input +# $1: Character typed to pane +sleep_char() { + [ ${FAST} -eq 1 ] && return + + if [ "${1}" = " " ]; then + PR_DELAY=$((PR_DELAY + 40)) + elif [ -n "$(printf '%s' "${1}" | tr -d [:alnum:])" ]; then + PR_DELAY=$((PR_DELAY + 30)) + elif [ ${PR_DELAY} -ge 30 ]; then + PR_DELAY=$((PR_DELAY / 3 * 2)) + fi + + sleep "$(printf 0.%03i ${PR_DELAY})" || sleep 1 +} + +# display_delay() - Simple delay, omitted if $FAST is set +display_delay() { + [ ${FAST} -eq 1 ] && return + + sleep "${1}" || sleep 1 +} + +# switch_pane() - Highlight given pane and reset character delay +# $1: Pane number +switch_pane() { + tmux select-pane -t ${1} + PR_DELAY=${PR_DELAY_INIT} + display_delay "0.2" +} + +# cmd_write() - Write a command to a pane, letter by letter, and execute it +# $1: Pane number +# $@: Command to issue +cmd_write() { + __pane_no=${1} + shift + + switch_pane ${__pane_no} + + __str="${@}" + while [ -n "${__str}" ]; do + __rem="${__str#?}" + __first="${__str%"$__rem"}" + if [ "${__first}" = ";" ]; then + tmux send-keys -t ${__pane_no} -l '\;' + else + tmux send-keys -t ${__pane_no} -l "${__first}" + fi + sleep_char "${__first}" + __str="${__rem}" + done + tmux send-keys -t ${__pane_no} "C-m" +} + +# text_write() - Write text to info pane, letter by letter +# $1: Pane number +# $@: Command to issue +text_write() { + __str="${@}" + while [ -n "${__str}" ]; do + __rem="${__str#?}" + __first="${__str%"$__rem"}" + if [ "${__first}" = ";" ]; then + tmux send-keys -t ${PANE_INFO} -l '\;' + else + tmux send-keys -t ${PANE_INFO} -l "${__first}" + fi + sleep_char "${__first}" + __str="${__rem}" + done +} + +# text_backspace() - Slow backspace motion for demo +# $1: Number of backspace characters +text_backspace() { + for __count in $(seq 0 ${1}); do + tmux send-keys -t ${PANE_INFO} Bspace + sleep 0.1 + done +} + +# em_write() - Write to log pane in red, for demo +# $@: Text +em_write() { + info_n "${PR_RED}${@}${PR_NC}" +} + +# pane_kill() - Kill a single pane given its name +# $1: Pane name +pane_kill() { + __pane_number=$(eval echo \$PANE_${1}) + tmux kill-pane -t ${__pane_number} +} + +# pane_highlight() - Highlight a single pane given its name +# $1: Pane name +pane_highlight() { + __pane_number=$(eval echo \$PANE_${1}) + switch_pane ${__pane_number} + sleep 3 +} + +# pane_resize() - Resize a pane given its name +# $1: Pane name +# $2: Direction: U, D, L, or R +# $3: Adjustment in lines or columns +pane_resize() { + __pane_number=$(eval echo \$PANE_${1}) + tmux resize-pane -${2} -t ${__pane_number} ${3} +} + +# pane_run() - Issue a command in given pane name +# $1: Pane name +# $@: Command to issue +pane_run() { + __pane_name="${1}" + shift + + __pane_number=$(eval echo \$PANE_${__pane_name}) + + eval ${__pane_name}_LAST_CMD=\"\${@}\" + + cmd_write ${__pane_number} "${@}" +} + +# pane_wait() - Wait for command to be done in given pane name +# $1: Pane name +pane_wait() { + __lc="$(echo "${1}" | tr [A-Z] [a-z])" + sleep 0.1 || sleep 1 + + __done=0 + while + __l="$(tail -1 ${LOGDIR}/pane_${__lc}.log | tr -d [:cntrl:])" + case ${__l} in + '$ ' | '# ' | '# # ' | *"$ " | *"# ") return ;; + *" #[m " | *" #[m [K" | *"]# ["*) return ;; + *' $ [6n' | *' # [6n' ) return ;; + esac + do sleep 0.1 || sleep 1; done +} + +# pane_parse() - Print last line, @EMPTY@ if command had no output +# $1: Pane name +pane_parse() { + __pane_lc="$(echo "${1}" | tr [A-Z] [a-z])" + + __buf="$(tail -n2 ${LOGDIR}/pane_${__pane_lc}.log | head -n1 | sed 's/^[^\r]*\r\([^\r]\)/\1/' | tr -d '\r\n')" + + [ "# $(eval printf '%s' \"\$${1}_LAST_CMD\")" != "${__buf}" ] && \ + [ "$ $(eval printf '%s' \"\$${1}_LAST_CMD\")" != "${__buf}" ] && + printf '%s' "${__buf}" || printf '@EMPTY@' +} + +# pane_status() - Wait for command to complete and return its exit status +# $1: Pane name +pane_status() { + pane_wait "${1}" + + [ ${DEMO} -eq 1 ] && return 0 + + __status="$(pane_parse "${1}")" + while ! [ "${__status}" -eq "${__status}" ] 2>/dev/null; do + sleep 1 + pane_run "${1}" 'echo $?' + pane_wait "${1}" + __status="$(pane_parse "${1}")" + done + return ${__status} +} + +# pane_watch_context() - Set up pane to watch commands executing in context(s) +# $1: Pane number +# $2: Description (for pane label) +# $@: Context name or names +pane_watch_contexts() { + __pane_number="${1}" + __desc="${2}" + shift 2 + __name="${2}" + + tmux select-pane -t ${__pane_number} -T "${__desc}" + __cmd="tail -f --retry" + for c; do + __cmd="${__cmd} ${LOGDIR}/context_${c}.log" + done + cmd_write ${__pane_number} "${__cmd}" +} + +# pane_or_context_run() - Issue a command in given context or pane +# $1: Context or lower-case pane name +# $@: Command to issue +pane_or_context_run() { + __name="${1}" + shift + if context_exists "${__name}"; then + # Redirect stdin to stop ssh from eating the test instructions file we have on stdin + context_run "${__name}" "$@" >/dev/null 2>&1 < /dev/null + else + __uc="$(echo "${__name}" | tr [a-z] [A-Z])" + pane_run "${__uc}" "$@" + pane_status "${__uc}" + fi +} + +# pane_or_context_run_bg() - Issue a background command in given context or pane +# $1: Context or lower-case pane name +# $@: Command to issue +pane_or_context_run_bg() { + __name="${1}" + shift + if context_exists "${__name}"; then + # Redirect stdin to stop ssh from eating the test instructions file we have on stdin + context_run_bg "${__name}" "$@" >/dev/null 2>&1 < /dev/null + else + __uc="$(echo "${__name}" | tr [a-z] [A-Z])" + pane_run "${__uc}" "$@" + fi +} + +# pane_or_context_output() - Get output from a command in a context or pane +# $1: Context or lower-case pane name +# $@: Command to issue +pane_or_context_output() { + __name="${1}" + shift + if context_exists "${__name}"; then + # Redirect stdin to stop ssh from eating the test instructions file we have on stdin + __output=$(context_run "${__name}" "$@" 2>/dev/null </dev/null) + if [ -z "${__output}" ]; then + echo "@EMPTY@" + else + echo "${__output}" + fi + else + __uc="$(echo "${__name}" | tr [a-z] [A-Z])" + pane_run "${__uc}" "$@" + pane_wait "${__uc}" + pane_parse "${__uc}" + fi +} + +# pane_or_context_wait() - Wait for a command to be done in a context or pane +# $1: Context or lower-case pane name +pane_or_context_wait() { + __name="${1}" + shift + if context_exists "${__name}"; then + context_wait "${__name}" + else + __uc="$(echo "${__name}" | tr [a-z] [A-Z])" + pane_wait "${__uc}" + fi +} + +# status_file_end() - Display and log messages when tests from one file are done +status_file_end() { + [ -z "${STATUS_FILE}" ] && return + + info_sep "=" + log + tmux select-pane -t ${PANE_INFO} -T "" + STATUS_FILE= +} + +# status_file_start() - Display and log messages when tests from one file start +status_file_start() { + switch_pane ${PANE_INFO} + + status_file_end + + info_nolog "Starting tests in file: ${1}\n" + log "=== ${1}" + tmux select-pane -t ${PANE_INFO} -T "${1}" + + STATUS_FILE="${1}" + STATUS_FILE_NTESTS="${2}" + STATUS_FILE_INDEX=0 +} + +# status_file_start() - Display and log messages when a single test starts +status_test_start() { + switch_pane ${PANE_INFO} + + info_nolog "Starting test: ${1}" + log "> ${1}" + + STATUS_FILE_INDEX=$((STATUS_FILE_INDEX + 1)) + tmux select-pane -t ${PANE_INFO} -T "${STATUS_FILE} [${STATUS_FILE_INDEX}/${STATUS_FILE_NTESTS}] - ${1}" +} + +# info_check() - Display and log messages for a single test condition check +info_check() { + switch_pane ${PANE_INFO} + + printf "${PR_YELLOW}?${PR_NC} ${@}" >> $STATEBASE/log_pipe + printf "? ${@}" >> "${LOGFILE}" +} + +# info_check_passed() - Display and log a new line when a check passes +info_check_passed() { + switch_pane ${PANE_INFO} + + printf "\n" >> $STATEBASE/log_pipe + printf "\n" >> ${LOGFILE} +} + +# info_check_failed() - Display and log messages when a check fails +info_check_failed() { + switch_pane ${PANE_INFO} + + printf " ${PR_RED}!${PR_NC}\n" >> $STATEBASE/log_pipe + printf " < failed.\n" >> "${LOGFILE}" +} + +# info_passed() - Display, log, and make status bar blink when a test passes +info_passed() { + switch_pane ${PANE_INFO} + + info_nolog "...${PR_GREEN}passed${PR_NC}.\n" + log "...passed." + log + + for i in `seq 1 3`; do + tmux set status-right-style 'bg=colour1 fg=colour2 bold' + sleep "0.1" + tmux set status-right-style 'bg=colour1 fg=colour233 bold' + sleep "0.1" + done +} + +# info_failed() - Display, log, and make status bar blink when a test passes +info_failed() { + switch_pane ${PANE_INFO} + + info_nolog "...${PR_RED}failed${PR_NC}.\n" + log "...failed." + log + + for i in `seq 1 3`; do + tmux set status-right-style 'bg=colour1 fg=colour196 bold' + sleep "0.1" + tmux set status-right-style 'bg=colour1 fg=colour233 bold' + sleep "0.1" + done + + pause_continue \ + "Press any key to pause test session" \ + "Resuming in " \ + "Paused, press any key to continue" \ + 5 +} + +# info_skipped() - Display and log skipped test +info_skipped() { + switch_pane ${PANE_INFO} + + info_nolog "...${PR_YELLOW}skipped${PR_NC}.\n" + log "...skipped." + log +} + +# info_layout() - Display string for new test layout +info_layout() { + switch_pane ${PANE_INFO} + + info_nolog "Test layout: ${PR_BLUE}${(a)}${PR_NC}.\n" +} + +# status_test_ok() - Update counter of passed tests, log and display message +status_test_ok() { + STATUS_PASS=$((STATUS_PASS + 1)) + tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | #(TZ="UTC" date -Iseconds)" + info_passed +} + +# status_test_fail() - Update counter of failed tests, log and display message +status_test_fail() { + STATUS_FAIL=$((STATUS_FAIL + 1)) + tmux set status-right "PASS: ${STATUS_PASS} | FAIL: ${STATUS_FAIL} | #(TZ="UTC" date -Iseconds)" + info_failed +} + +# status_test_fail() - Update counter of failed tests, log and display message +status_test_skip() { + info_skipped +} + +# table_header() - Print table header to log pane +# $1: Header description +# $@: Column headers +table_header() { + perf_th ${@} + + __ifs="${IFS}" + IFS=" " + + __desc="${1}" + shift + + __max_len=4 + __count=0 + for __h in ${@}; do + [ ${#__h} -gt ${__max_len} ] && __max_len=${#__h} + __count=$((__count + 1)) + done + + # > xxxx |< + __outer_len=$((__max_len + 3)) + __width_fields=$((__outer_len * __count + 1)) + + TABLE_HEADER_LEFT=$((STATUS_COLS - __width_fields)) + TABLE_CELL_SIZE=$((__max_len + 2)) + TABLE_COLS=${__count} + + __pad_left=$((TABLE_HEADER_LEFT - ${#__desc} - 2)) + __buf="$(printf %-${__pad_left}s%s "" "${__desc}: ")" + for __h in ${@}; do + __pad_left=$(( (TABLE_CELL_SIZE - ${#__h} + 1) / 2)) + __pad_right=$(( (TABLE_CELL_SIZE - ${#__h}) / 2)) + __buf="${__buf}$(printf "|%-${__pad_left}s%s%-${__pad_right}s" "" ${__h} "")" + done + + info_n "${__buf}|" + + IFS="${__ifs}" +} + +# table_row() - Print main table row to log pane +# $@: Column headers +table_row() { + perf_tr ${@} + + __line="${@}" + __buf="$(printf %-${TABLE_HEADER_LEFT}s "")" + for __i in $(seq 1 ${TABLE_COLS}); do + __buf="${__buf}|" + for __j in $(seq 1 ${TABLE_CELL_SIZE}); do + __buf="${__buf}-" + done + done + info_n "\n${__buf}|\n" + + __pad_left=$(( (TABLE_HEADER_LEFT - ${#__line} + 1) / 2)) + __pad_right=$(( (TABLE_HEADER_LEFT - ${#__line}) / 2)) + info_n "$(printf "%-${__pad_left}s%s%-${__pad_right}s|" "" "${__line}" "")" +} + +# table_line() - Print simple line to log pane +# $@: Column headers +table_line() { + perf_tr ${@} + + __line="${@}" + info_n "\n" + + __pad_left=$(( (TABLE_HEADER_LEFT - ${#__line} + 1) / 2)) + __pad_right=$(( (TABLE_HEADER_LEFT - ${#__line}) / 2)) + info_n "$(printf "%-${__pad_left}s%s%-${__pad_right}s|" "" "${__line}" "")" +} + +table_cell() { + __len="${1}" + shift + + __content="${@}" + + __pad_left=$((TABLE_CELL_SIZE - __len - 1)) + info_n "$(printf "%-${__pad_left}s%s |" "" "${__content}")" +} + +table_end() { + __buf="$(printf %-${TABLE_HEADER_LEFT}s "")" + for __i in $(seq 1 ${TABLE_COLS}); do + __buf="${__buf}'" + for __j in $(seq 1 ${TABLE_CELL_SIZE}); do + __buf="${__buf}-" + done + done + info_n "\n${__buf}'\n" +} + +# table_value() - Print generic table value in its own cell +# $1: Value, can be '-' to indicate a filler +# $2: Scale, exponent of 10 +# $3: Error value, scaled: if value is less than this, print in red +# $4: Warning value, scaled: if value is less than this, print in yellow +table_value() { + [ "${1}" = "-" ] && table_cell 1 "-" && perf_td 0 "" && return 0 + if [ "${2}" != "0" ]; then + __v="$(echo "scale=1; x=( ${1} + 10^$((${2} - 1)) / 2 ) / 10^${2}; if ( x < 1 && x > 0 ) print 0; x" | bc -l)" + else + __v="${1}" + fi + perf_td 0 "${__v}" + + __red="${3}" + __yellow="${4}" + if [ "$(echo "${__v} < ${__red}" | bc -l)" = "1" ]; then + table_cell ${#__v} "${PR_RED}${__v}${PR_NC}" + return 1 + elif [ "$(echo "${__v} < ${__yellow}" | bc -l)" = "1" ]; then + table_cell ${#__v} "${PR_YELLOW}${__v}${PR_NC}" + return 1 + else + table_cell ${#__v} "${PR_GREEN}${__v}${PR_NC}" + return 0 + fi +} + +table_value_throughput() { + [ "${1}" = "-" ] && table_cell 1 "-" && perf_td 0 "" && return 0 + __v="$(echo "scale=1; x=( ${1} + 10^8 / 2 ) / 10^9; if ( x < 1 && x > 0 ) print 0; x" | bc -l)" + perf_td 31 "${__v}" + + __red="${2}" + __yellow="${3}" + if [ "$(echo "${__v} < ${__red}" | bc -l)" = "1" ]; then + table_cell ${#__v} "${PR_RED}${__v}${PR_NC}" + return 1 + elif [ "$(echo "${__v} < ${__yellow}" | bc -l)" = "1" ]; then + table_cell ${#__v} "${PR_YELLOW}${__v}${PR_NC}" + return 1 + else + table_cell ${#__v} "${PR_GREEN}${__v}${PR_NC}" + return 0 + fi +} + +table_value_latency() { + [ "${1}" = "-" ] && table_cell 1 "-" && perf_td 0 "" && return 0 + + __v="$(echo "scale=6; 1 / ${1} * 10^6" | bc -l)" + __v="${__v%.*}" + + perf_td 11 "${__v}" + + __red="${2}" + __yellow="${3}" + if [ "$(echo "${__v} > ${__red}" | bc -l)" = "1" ]; then + table_cell ${#__v} "${PR_RED}${__v}${PR_NC}" + return 1 + elif [ "$(echo "${__v} > ${__yellow}" | bc -l)" = "1" ]; then + table_cell ${#__v} "${PR_YELLOW}${__v}${PR_NC}" + return 1 + else + table_cell ${#__v} "${PR_GREEN}${__v}${PR_NC}" + return 0 + fi +} + +# pause_continue() - Pause for a while, wait for keystroke, resume on second one +pause_continue() { + tmux select-pane -t ${PANE_INFO} + info_nolog "${1}" + info_nolog_n "${2}" + + __pause_tmp="${STATEBASE}/pause.tmp" + echo > "${__pause_tmp}" + tmux pipe-pane -O -t ${PANE_INFO} "cat >> ${__pause_tmp}" + __pane_buf= + __wait=0 + sleep 1 + for __i in $(seq ${4} -1 0); do + if [ "$(tail -n1 ${__pause_tmp} | tr -d -c [:print:])" != "${__pane_buf}" ]; then + __wait=1 + break + fi + + if [ ${__i} -ne ${4} ]; then + tmux send-keys -t ${PANE_INFO} Bspace + tmux send-keys -t ${PANE_INFO} Bspace + __pane_buf="${__pane_buf} " + fi + info_nolog_n "${__i} " + __pane_buf="${__pane_buf}${__i} " + sleep 1 + done + + if [ ${__wait} -eq 1 ]; then + tmux send-keys -t ${PANE_INFO} Bspace + tmux send-keys -t ${PANE_INFO} Bspace + info_nolog "" + info_nolog "${3}" + __pane_buf="$(tail -n1 ${__pause_tmp})" + while true; do + [ "$(tail -n1 ${__pause_tmp})" != "${__pane_buf}" ] && break + sleep 1 + done + fi + tmux pipe-pane -O -t ${PANE_INFO} "" + rm "${__pause_tmp}" + info_nolog "" +} + +# run_term() - Start tmux session, running entry point, with recording if needed +run_term() { + TMUX="tmux new-session -s passt_test -eSTATEBASE=$STATEBASE -ePCAP=$PCAP -eDEBUG=$DEBUG" + + if [ ${CI} -eq 1 ]; then + printf '\e[8;50;240t' + asciinema rec --overwrite "${STATEBASE}/ci.uncut" -c "$TMUX /bin/sh -c './ci from_term'" + video_postprocess "${STATEBASE}/ci.uncut" + elif [ ${DEMO} -eq 1 ]; then + printf '\e[8;40;130t' + asciinema rec --overwrite "${STATEBASE}/demo.uncut" -c "$TMUX /bin/sh -c './run_demo from_term'" + video_postprocess "${STATEBASE}/demo.uncut" + else + $TMUX /bin/sh -c "./run from_term ${*}" + fi +} + +# term() - Set up terminal window and panes for regular tests or CI +term() { + tmux set-option default-shell "/bin/sh" + + tmux set status-interval 1 + tmux rename-window '' + + tmux set window-status-format '#W' + tmux set window-status-current-format '#W' + tmux set status-left '' + tmux set window-status-separator '' + + tmux set window-status-style 'bg=colour1 fg=colour233 bold' + tmux set status-style 'bg=colour1 fg=colour233 bold' + tmux set status-right-style 'bg=colour1 fg=colour233 bold' + + tmux new-window -n "Testing commit: ${COMMIT}" + + tmux set window-status-format '#W' + tmux set window-status-current-format '#W' + tmux set status-left '' + tmux set window-status-separator '' + + tmux set window-status-current-style 'bg=colour1 fg=colour233 bold' + tmux set status-right '#(TZ="UTC" date -Iseconds)' + tmux set status-right-length 50 + tmux set status-right-style 'bg=colour1 fg=colour233 bold' + + tmux set history-limit 500000 + tmux select-pane -t 0 -T '' + tmux set pane-border-format '#T' + tmux set pane-border-style 'fg=colour2 bg=colour233' + tmux set pane-active-border-style 'fg=colour233 bg=colour4 bold' + tmux set pane-border-status bottom +} + +# term_demo() - Set up terminal window and panes for demo +term_demo() { + tmux set-option default-shell "/bin/sh" + + tmux set status-interval 1 + tmux rename-window '' + + tmux set window-status-format '#W' + tmux set window-status-current-format '#W' + tmux set status-left '' + tmux set window-status-separator '' + + tmux set window-status-style 'bg=colour1 fg=colour15 bold' + tmux set status-right '' + tmux set status-style 'bg=colour1 fg=colour15 bold' + tmux set status-right-style 'bg=colour1 fg=colour15 bold' + + tmux new-window -n "Demo at commit: ${COMMIT}" + + tmux set window-status-format '#W' + tmux set window-status-current-format '#W' + tmux set status-left '' + tmux set window-status-separator '' + + tmux select-pane -t 0 -T '' + tmux set pane-border-format '#T' + tmux set pane-border-style 'fg=colour2 bg=colour233' + tmux set pane-active-border-style 'fg=colour15 bg=colour4 bold' + tmux set pane-border-status bottom +} diff --git a/oldtest/lib/test b/oldtest/lib/test new file mode 100755 index 0000000..60bdae9 --- /dev/null +++ b/oldtest/lib/test @@ -0,0 +1,398 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/test - List tests and run them, evaluating directives from files +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +# test_iperf3() - Ugly helper for iperf3 directive +# $1: Variable name: to put the measure bandwidth into +# $2: Source/client context +# $3: Destination/server context +# $4: Destination name or address for client +# $5: Port number, ${i} is translated to process index +# $6: Number of processes to run in parallel +# $7: Run time, in seconds +# $@: Client options +test_iperf3() { + __var="${1}"; shift + __cctx="${1}"; shift + __sctx="${1}"; shift + __dest="${1}"; shift + __port="${1}"; shift + __procs="$((${1} - 1))"; shift + __time="${1}"; shift + + pane_or_context_run "${__sctx}" 'rm -f s*.json' + + pane_or_context_run_bg "${__sctx}" \ + 'for i in $(seq 0 '${__procs}'); do' \ + ' (iperf3 -s1J -p'${__port}' -i'${__time} \ + ' > s${i}.json) &' \ + ' echo $! > s${i}.pid &' \ + 'done' \ + + sleep 1 # Wait for server to be ready + + pane_or_context_run_bg "${__cctx}" \ + '(' \ + ' for i in $(seq 0 '${__procs}'); do' \ + ' iperf3 -c '${__dest}' -p '${__port} \ + ' -t'${__time}' -i0 -T s${i} '"${@}"' &' \ + ' done;' \ + ' wait' \ + ')' + + sleep $((__time + 5)) + + # If client fails to deliver control message, tell server we're done + pane_or_context_run "${__sctx}" 'kill -INT $(cat s*.pid); rm s*.pid' + + sleep 1 # ...and wait for output to be flushed + + __jval=".end.sum_received.bits_per_second" + for __opt in ${@}; do + # UDP test + [ "${__opt}" = "-u" ] && __jval=".intervals[0].sum.bits_per_second" + done + + __bw=$(pane_or_context_output "${__sctx}" \ + 'cat s*.json | jq -rMs "map('${__jval}') | add"') + + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__var}__" "${__bw}" )" + + sleep 3 # Wait for kernel to free up ports +} + +test_one_line() { + __line="${1}" + + [ ${DEBUG} -eq 1 ] && info DEBUG: "${__line}" + + # Strip comments + __line="${__line%%#*}" + + if [ -n "${TEST_ONE_in_def}" ]; then + [ "${__line}" = "endef" ] && TEST_ONE_in_def= && return + # Append $__line to variable TEST_ONE_DEF_<definition name> + __ifs="${IFS}" + IFS= + eval TEST_ONE_DEF_$TEST_ONE_in_def=\"\$\(printf \"%s\\n%s\" \"\$TEST_ONE_DEF_$TEST_ONE_in_def\" \"$__line\"\)\" + IFS="${__ifs}" + return + fi + + # tab-split command and arguments, apply variable substitutions + __cmd="${__line%%$(printf '\t')*}" + __arg="${__line#*$(printf '\t')*}" + __arg="$(subs_apply "${TEST_ONE_subs}" "${__arg}")" + + [ ${TEST_ONE_nok} -eq 1 ] && [ "${__cmd}" != "test" ] && continue + case ${__cmd} in + "def") + TEST_ONE_in_def="${__arg}" + # Clear variable TEST_ONE_DEF_<definition name> + __ifs="${IFS}" + IFS= eval TEST_ONE_DEF_$TEST_ONE_in_def= + IFS="${__ifs}" + ;; + "test") + [ ${TEST_ONE_perf_nok} -eq 0 ] || TEST_ONE_nok=1 + [ ${TEST_ONE_nok} -eq 1 ] && status_test_fail + [ ${TEST_ONE_nok} -eq 0 ] && status_test_ok + + status_test_start "${__arg}" + TEST_ONE_nok=0 + TEST_ONE_perf_nok=0 + ;; + "host") + pane_or_context_run host "${__arg}" || TEST_ONE_nok=1 + ;; + "hostb") + pane_or_context_run_bg host "${__arg}" + ;; + "hostw") + pane_or_context_wait host || TEST_ONE_nok=1 + ;; + "hint") + tmux send-keys -t ${PANE_HOST} "C-c" + ;; + "htools") + pane_or_context_run host 'which '"${__arg}"' >/dev/null' || TEST_ONE_skip=1 + ;; + "passt") + pane_or_context_run passt "${__arg}" || TEST_ONE_nok=1 + ;; + "passtb") + pane_or_context_run_bg passt "${__arg}" + ;; + "passtw") + pane_or_context_wait passt || TEST_ONE_nok=1 + ;; + "pint") + tmux send-keys -t ${PANE_PASST} "C-c" + ;; + "pout") + __varname="${__arg%% *}" + __output="$(pane_or_context_output passt "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "guest") + pane_or_context_run guest "${__arg}" || TEST_ONE_nok=1 + ;; + "guestb") + pane_or_context_run_bg guest "${__arg}" + ;; + "guestw") + pane_or_context_wait guest || TEST_ONE_nok=1 + ;; + "guest1") + pane_or_context_run guest_1 "${__arg}" || TEST_ONE_nok=1 + ;; + "guest1b") + pane_or_context_run_bg guest_1 "${__arg}" + ;; + "guest1w") + pane_or_context_wait guest_1 || TEST_ONE_nok=1 + ;; + "gtools") + pane_or_context_run guest 'which '"${__arg}"' >/dev/null' || TEST_ONE_skip=1 + ;; + "g1tools") + pane_or_context_run guest_1 'which '"${__arg}"' >/dev/null' || TEST_ONE_skip=1 + ;; + "g2tools") + pane_or_context_run guest_2 'which '"${__arg}"' >/dev/null' || TEST_ONE_skip=1 + ;; + "guest2") + pane_or_context_run guest_2 "${__arg}" || TEST_ONE_nok=1 + ;; + "guest2b") + pane_or_context_run_bg guest_2 "${__arg}" + ;; + "guest2w") + pane_or_context_wait guest_2 || TEST_ONE_nok=1 + ;; + "ns") + pane_or_context_run ns "${__arg}" || TEST_ONE_nok=1 + ;; + "ns1") + pane_or_context_run ns1 "${__arg}" || TEST_ONE_nok=1 + ;; + "ns2") + pane_or_context_run ns2 "${__arg}" || TEST_ONE_nok=1 + ;; + "nsb") + pane_or_context_run_bg ns "${__arg}" + ;; + "ns1b") + pane_or_context_run_bg ns1 "${__arg}" + ;; + "ns2b") + pane_or_context_run_bg ns2 "${__arg}" + ;; + "nsw") + pane_or_context_wait ns || TEST_ONE_nok=1 + ;; + "ns1w") + pane_or_context_wait ns1 || TEST_ONE_nok=1 + ;; + "ns2w") + pane_or_context_wait ns2 || TEST_ONE_nok=1 + ;; + "nstools") + pane_or_context_run ns 'which '"${__arg}"' >/dev/null' || TEST_ONE_skip=1 + ;; + "gout") + __varname="${__arg%% *}" + __output="$(pane_or_context_output guest "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "g1out") + __varname="${__arg%% *}" + __output="$(pane_or_context_output guest_1 "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "g2out") + __varname="${__arg%% *}" + __output="$(pane_or_context_output guest_2 "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "hout") + __varname="${__arg%% *}" + __output="$(pane_or_context_output host "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "nsout") + __varname="${__arg%% *}" + __output="$(pane_or_context_output ns "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "ns1out") + __varname="${__arg%% *}" + __output="$(pane_or_context_output ns1 "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "ns2out") + __varname="${__arg%% *}" + __output="$(pane_or_context_output ns2 "${__arg#* }")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__varname}__" "${__output}")" + ;; + "check") + info_check "${__arg}" + __nok=0 + eval "${__arg} || __nok=1" + if [ ${__nok} -eq 1 ]; then + TEST_ONE_nok=1 + info_check_failed + else + info_check_passed + fi + ;; + "sleep") + sleep "${__arg}" + ;; + "info") + info "${__arg}" + ;; + "report") + perf_report ${__arg} + ;; + "th") + table_header ${__arg} + ;; + "tr") + table_row "${__arg}" + ;; + "tl") + table_line "${__arg}" + ;; + "te") + table_end + ;; + "td") + table_value ${__arg} || TEST_ONE_perf_nok=1 + ;; + "bw") + table_value_throughput ${__arg} || TEST_ONE_perf_nok=1 + ;; + "lat") + table_value_latency ${__arg} || TEST_ONE_perf_nok=1 + ;; + "iperf3") + test_iperf3 ${__arg} + ;; + "set") + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__${__arg%% *}__" "${__arg#* }")" + ;; + + # Demo commands + "say") + text_write "${__arg}" + ;; + "em") + em_write "${__arg}" + ;; + "nl") + info_nolog "" + ;; + "hl") + pane_highlight "${__arg}" + ;; + "bsp") + text_backspace "${__arg}" + ;; + "killp") + pane_kill "${__arg}" + ;; + "resize") + pane_resize ${__arg} + ;; + *) + __def_body="$(eval printf \"\$TEST_ONE_DEF_$__cmd\")" + if [ -n "${__def_body}" ]; then + __ifs="${IFS}" + IFS=' +' + for __def_line in ${__def_body}; do + IFS="${__ifs}" test_one_line "${__def_line}" + done + IFS="${__ifs}" + fi + ;; + esac +} + +# test_one() - Run a single test file evaluating directives +# $1: Name of test file, relative to oldtest/ directory +test_one() { + TEST_ONE_dirclean= + __test_file="oldtest/${1}" + + __type="$(file -b --mime-type ${__test_file})" + if [ "${__type}" = "text/x-shellscript" ]; then + status_file_start "${1}" 1 + "${__test_file}" && status_test_ok || status_test_fail + return + fi + + if [ ${DEMO} -eq 0 ]; then + __ntests="$(grep -c "^test$(printf '\t')" "${__test_file}")" + status_file_start "${1}" "${__ntests}" + fi + + [ ${CI} -eq 1 ] && video_link "${1}" + + TEST_ONE_subs="$(list_add_pair "" "__BASEPATH__" "${BASEPATH}")" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__STATESETUP__" "${STATESETUP}")" + STATEDIR="${STATEBASE}/${1}" + mkdir -p "${STATEDIR}" + TEST_ONE_subs="$(list_add_pair "${TEST_ONE_subs}" "__STATEDIR__" "${STATEDIR}")" + TEST_ONE_nok=-1 + TEST_ONE_perf_nok=0 + TEST_ONE_skip=0 + TEST_ONE_in_def= + while IFS= read -r __line; do + test_one_line "${__line}" + [ ${TEST_ONE_skip} -eq 1 ] && break + done < "${__test_file}" + + for __d in ${TEST_ONE_dirclean}; do + rm -rf ${__d} + done + + [ ${DEMO} -eq 1 ] && return + + [ ${TEST_ONE_skip} -eq 1 ] && status_test_skip && return + [ ${TEST_ONE_perf_nok} -eq 0 ] || TEST_ONE_nok=1 + [ ${TEST_ONE_nok} -eq 0 ] && status_test_ok || status_test_fail +} + +# test() - Build list of tests to run, in order, then issue test_one() +# $@: Test files to run, relative to oldtest/ +test() { + __list= + + cd test + for __f; do + __type="$(file -b --mime-type ${__f})" + if [ "${__type}" = "text/x-shellscript" ]; then + __list="$(list_add "${__list}" "${__f}")" + continue + fi + __list="$(list_add "${__list}" "${__f}")" + done + cd .. + + for __f in ${__list}; do + test_one "${__f}" + done +} diff --git a/oldtest/lib/util b/oldtest/lib/util new file mode 100755 index 0000000..98cb9d8 --- /dev/null +++ b/oldtest/lib/util @@ -0,0 +1,133 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/util - Convenience functions +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +# list_has() - Check whether a tab-separated list contains a given token +# $1: List +# $2: Token +# Return: 0 if token was found or is empty, 1 otherwise +list_has() { + [ -z "${2}" ] && return 0 + + __ifs="${IFS}" + IFS=' ' + for __t in ${1}; do + [ "${__t}" = "${2}" ] && IFS="${__ifs}" && return 0 + done + + IFS="${__ifs}" + return 1 +} + +# list_add() - Add token to tab-separated list, unless it's already present +# $1: List +# $2: Token +list_add() { + list_has "${1}" "${2}" && return + [ -n "${1}" ] && printf '%s\t%s\n' "${1}" "${2}" || printf '%s\n' "${2}" +} + +# list_remove_pair() - Drop pair with given key if present +# $1: List +# $2: Key +list_remove_pair() +{ + __ifs="${IFS}" + IFS=' ' + __skip_next=0 + for __t in ${1}; do + [ ${__skip_next} -eq 1 ] && __skip_next=0 && continue + [ "${__t}" = "${2}" ] && __skip_next=1 && continue + printf '%s\t' "${__t}" + done + printf "\n" + IFS="${__ifs}" +} + +# list_add_pair() - Add token pair to list, replace if the first one is present +# $1: List +# $2: First token +# $3: Second token +list_add_pair() { + [ -z "${3}" ] && return + + + if [ -n "${1}" ]; then + __new_list="$(list_remove_pair "${1}" "${2}")" + printf '%s\t%s\t%s' "${__new_list}" "${2}" "${3}" + else + printf '%s\t%s' "${2}" "${3}" + fi + printf "\n" +} + +# list_has_all() - Check whether a list contains all given IFS-separated tokens +# $1: List +# $2: List of tokens +# Return: 0 if list of tokens was found or is empty, 1 otherwise +list_has_all() { + [ -z "${2}" ] && return 0 + + for __i in ${2}; do + list_has "${1}" "${__i}" || return 1 + done + return 0 +} + +# file_def() - List of tokens tab-separated line from file, starting with key +# $1: Filename +# $2: Token +file_def() { + sed -n 's/^'"${2}"'\t\(.*\)/\1/p' "${1}" | tr ' ' '\t' +} + +# subs_apply() - Apply substitutions using a list of token pairs +# $1: List of substitutions +# $2: String where substitutions have to be applied +subs_apply() { + __ifs="${IFS}" + IFS=' ' + __newarg="${2}" + __s= + for __t in ${1}; do + [ -z "${__s}" ] && __s="${__t}" && continue + + __et="$(printf '%s\n' "$__t" | sed -e 's/[\/&]/\\&/g')" + __es="$(printf '%s\n' "$__s" | sed -e 's/[]\/$*.^[]/\\&/g')" + + __newarg="$(printf '%s' "${__newarg}" | sed "s/${__es}/${__et}/g")" + __s= + done + + printf '%s' "${__newarg}" + IFS="${__ifs}" +} + +# get_info_cols() - Get number of columns for info pane +get_info_cols() { + __log_pane_cols= + __j=0 + for __i in $(tmux list-panes -t passt_test:1.0 -F "#{pane_width}"); do + [ ${__j} -eq ${PANE_INFO} ] && STATUS_COLS=${__i} && break + __j=$((__j + 1)) + done +} + +# wait_for() - Retry a command until it succeeds +# $@: Command to run +wait_for() { + while ! "$@"; do + sleep 0.1 || sleep 1 + done +} diff --git a/oldtest/lib/video b/oldtest/lib/video new file mode 100755 index 0000000..320d4a0 --- /dev/null +++ b/oldtest/lib/video @@ -0,0 +1,152 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/lib/video - Session recording, JavaScript fragments with links +# +# Copyright (c) 2021-2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +VIDEO_START_SECONDS= +VIDEO_NAME= + +VIDEO_LINKS_TEMPLATE="document.write('"' + Skip to: +' + +VIDEO_LINKS_TEMPLATE_JS=" +'); + +var video___VIDEO_NAME__links = [ +" + +VIDEO_LINKS_TEMPLATE_POST=']; + +for (var i = 0; i < video___VIDEO_NAME__links.length; i++) { + var obj = document.getElementById(video___VIDEO_NAME__links[i][0]); + + obj.addEventListener("click", function(event) { + var __VIDEO_NAME___div = document.getElementById("__VIDEO_NAME__"); + var top = __VIDEO_NAME___div.offsetTop - 5; + var seek; + + for (var i = 0; i < video___VIDEO_NAME__links.length; i++) { + if (this.id == video___VIDEO_NAME__links[i][0]) { + seek = video___VIDEO_NAME__links[i][1]; + } + } + + event.preventDefault(); + __VIDEO_NAME___player.dispose(); + __VIDEO_NAME___player = AsciinemaPlayer.create( + "/builds/latest/web/__VIDEO_NAME__.cast", + __VIDEO_NAME___div, + { cols: 240, rows: 51, poster: "npt:999:0", startAt: seek, autoplay: true }); + + window.scrollTo({ top: top, behavior: "smooth" }) + }, false); +} +' + +VIDEO_LINKS_BUF= +VIDEO_LINKS_COUNT=0 + +# video_append_links() - Append generic string to JavaScript links file +video_append_links() +{ + __web="${LOGDIR}/web" + printf "${@}" >> "${__web}/${VIDEO_NAME}.js" +} + +# video_append_links() - Append generic string to buffer for links +video_append_links_js() +{ + VIDEO_LINKS_BUF="${VIDEO_LINKS_BUF}${@}" +} + +# video_start() - Mark start of a test in capture, record start timestamp +video_start() { + VIDEO_NAME="${1}" + __web="${LOGDIR}/web" + mkdir -p "${__web}" + echo "${VIDEO_LINKS_TEMPLATE}" > "${__web}/${VIDEO_NAME}.js" + VIDEO_START_SECONDS=$(sed -n 's/\([0-9]*\).[0-9]* [0-9]*.[0-9]*/\1/p' /proc/uptime) + + sync + [ ${DEMO} -eq 1 ] && tail -1 "${STATEBASE}/demo.uncut" > "${STATEBASE}/${VIDEO_NAME}.start" + [ ${CI} -eq 1 ] && tail -1 "${STATEBASE}/ci.uncut" > "${STATEBASE}/${VIDEO_NAME}.start" + sync + + tmux refresh-client +} + +# video_stop() - Mark stop of a test in capture, finalise JavaScript fragments +video_stop() { + __web="${LOGDIR}/web" + tmux refresh-client + + sync + [ ${DEMO} -eq 1 ] && tail -1 "${STATEBASE}/demo.uncut" > "${STATEBASE}/${VIDEO_NAME}.stop" + [ ${CI} -eq 1 ] && tail -1 "${STATEBASE}/ci.uncut" > "${STATEBASE}/${VIDEO_NAME}.stop" + sync + + sed -i 's/^.*$/&\\/g' "${__web}/${VIDEO_NAME}.js" + echo "${VIDEO_LINKS_TEMPLATE_JS}" | sed "s/__VIDEO_NAME__/${VIDEO_NAME}/g" >> "${__web}/${VIDEO_NAME}.js" + echo "${VIDEO_LINKS_BUF}" >> "${__web}/${VIDEO_NAME}.js" + echo "${VIDEO_LINKS_TEMPLATE_POST}" | sed "s/__VIDEO_NAME__/${VIDEO_NAME}/g" >> "${__web}/${VIDEO_NAME}.js" +} + +# video_postprocess() - Cut terminal recordings based on .start and .stop files +video_postprocess() { + IFS=' +' + __web="${LOGDIR}/web" + __cast_name= + for __l in $(cat ${1}); do + [ -z "${__header}" ] && __header="${__l}" && continue + + if [ -z "${__cast_name}" ]; then + for __cast_cut in "${STATEBASE}/"*.start; do + [ "${__l}" != "$(cat "${__cast_cut}")" ] && continue + __cast_name="$(basename "${__cast_cut}")" + __cast_name="${__cast_name%.start}" + __cast_offset= + __stop_line="$(cat "${STATEBASE}/${__cast_name}.stop")" + echo "${__header}" > "${__web}/${__cast_name}.cast" + break + done + continue + fi + + [ "${__l}" = "${__stop_line}" ] && __cast_name= && continue + + __l_offset="$(echo ${__l%%.*}|tr -c -d '[:digit:]')" + __l_rest="${__l#*.}" + [ -z "${__cast_offset}" ] && __cast_offset=${__l_offset} + __l_offset=$((__l_offset - __cast_offset)) + printf '[%s.%s\n' "${__l_offset}" "${__l_rest}" >> "${__web}/${__cast_name}".cast + done + unset IFS +} + +# video_time_now() - Print current video timestamp, in seconds +video_time_now() { + __now=$(sed -n 's/\([0-9]*\).[0-9]* [0-9]*.[0-9]*/\1/p' /proc/uptime) + echo $((__now - VIDEO_START_SECONDS)) +} + +# video_link() - Append single link to given video chapter +video_link() { + [ ${VIDEO_LINKS_COUNT} -eq 0 ] && __sep="" || __sep=" |" + __id="video_link_${VIDEO_LINKS_COUNT}" + video_append_links "${__sep} <a id=\"${__id}\" href=\"${1}\">${1}</a>" + video_append_links_js "[ '${__id}', $(($(video_time_now) - 1)) ]," + + VIDEO_LINKS_COUNT=$((VIDEO_LINKS_COUNT + 1)) +} diff --git a/oldtest/memory/passt b/oldtest/memory/passt new file mode 100644 index 0000000..1193af8 --- /dev/null +++ b/oldtest/memory/passt @@ -0,0 +1,187 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/memory/passt - Show memory usage of passt in kernel and userspace +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools sed cat diff nm sort kill tee head tail chroot unshare mount mkdir cp + +def meminfo_row +gout DIFF meminfo_diff /tmp/meminfo.before /tmp/meminfo.after __WHAT__ +tl __NAME__ +td __DIFF__ 3 0 0 +endef + +def meminfo_reverse_row +gout DIFF meminfo_diff /tmp/meminfo.after /tmp/meminfo.before __WHAT__ +tl __NAME__ +td __DIFF__ 3 0 0 +endef + +def nm_row +gout SIZE nm_size /tmp/nm.size __WHAT__ +tl __WHAT__ +td __SIZE__ 6 0 0 +endef + +def slab_row +gout COUNT slab_diff_count /tmp/slabinfo.before /tmp/slabinfo.after __WHAT__ +gout SIZE slab_size /tmp/slabinfo.before __WHAT__ +gout DIFF slab_diff_size /tmp/slabinfo.before /tmp/slabinfo.after __WHAT__ +tl __WHAT__ +td __COUNT__ 0 0 0 +td __SIZE__ 0 0 0 +td __DIFF__ 6 0 0 +endef + +def start_stop_diff +guest sed /proc/slabinfo -ne 's/^\([^ ]* *[^ ]* *[^ ]* *[^ ]*\).*/\\\1/p' > /tmp/slabinfo.before +guest cat /proc/meminfo > /tmp/meminfo.before +guest /bin/passt.avx2 -l /tmp/log -s /tmp/sock -P /tmp/pid __OPTS__ --netns-only +sleep 2 +guest cat /proc/meminfo > /tmp/meminfo.after +guest sed /proc/slabinfo -ne 's/^\([^ ]* *[^ ]* *[^ ]* *[^ ]*\).*/\\\1/p' > /tmp/slabinfo.after +guest kill \$(cat /tmp/pid) +guest diff -y --suppress-common-lines /tmp/meminfo.before /tmp/meminfo.after || : +guest nm -td -Sr --size-sort -P /bin/passt.avx2 | head -30 | tee /tmp/nm.size +guest sed /proc/slabinfo -ne 's/\(.*<objsize>\).*$/\1/p' | tail -1; (diff -y --suppress-common-lines /tmp/slabinfo.before /tmp/slabinfo.after | sort -grk8) +endef + +def summary +info Memory usage summary +info +th type MiB +set WHAT MemFree +set NAME used +meminfo_reverse_row +set WHAT AnonPages +set NAME userspace +meminfo_row +set WHAT Slab +set NAME kernel +meminfo_row +te +endef + + +guest mkdir /test +guest mount -t tmpfs none /test +guest mkdir /test/proc /test/dev /test/tmp +guest mount -o bind /proc /test/proc +guest mount -o bind /dev /test/dev +guest cp -Lr /bin /lib /lib64 /usr /sbin /test/ + +guest ulimit -Hn 300000 +guest unshare -rUm -R /test +guest chroot . + +guest meminfo_size() { grep "^$2:" $1 | tr -s ' ' | cut -f2 -d ' '; } +guest meminfo_diff() { echo $(( $(meminfo_size $2 $3) - $(meminfo_size $1 $3) )); } + +guest nm_size() { grep -m1 "^$2 " $1 | cut -f4 -d ' '; } + +guest slab_count() { grep "^$2 " $1 | tr -s ' ' | cut -f3 -d ' '; } +guest slab_size() { grep "^$2 " $1 | tr -s ' ' | cut -f4 -d ' '; } +guest slab_diff_count() { echo $(( $(slab_count $2 $3) - $(slab_count $1 $3) )); } +guest slab_diff_size() { echo $(( $(slab_count $2 $3) * $(slab_size $2 $3) - $(slab_count $1 $3) * $(slab_size $1 $3) )); } + + +test Memory usage: all TCP and UDP ports forwarded, IPv4 and IPv6 +set OPTS -t all -u all +start_stop_diff +summary + +info Userspace memory detail +info +th symbol MiB +set WHAT tcp_buf_discard +nm_row +set WHAT tcp6_l2_buf +nm_row +set WHAT tcp4_l2_buf +nm_row +set WHAT tc +nm_row +set WHAT pkt_buf +nm_row +set WHAT udp_splice_map +nm_row +set WHAT udp6_l2_buf +nm_row +set WHAT udp4_l2_buf +nm_row +set WHAT udp_tap_map +nm_row +set WHAT icmp_id_map +nm_row +set WHAT udp_splice_buf +nm_row +set WHAT tc_hash +nm_row +set WHAT pool_tap6_storage +nm_row +set WHAT pool_tap4_storage +nm_row +set WHAT tap6_l4 +nm_row +set WHAT tap4_l4 +nm_row +te + +info Kernel memory detail +info +th objects count size MiB +set WHAT pid +slab_row +set WHAT dentry +slab_row +set WHAT Acpi-Parse +slab_row +set WHAT kmalloc-64 +slab_row +set WHAT kmalloc-32 +slab_row +set WHAT lsm_file_cache +slab_row +set WHAT filp +slab_row +set WHAT anon_vma_chain +slab_row +set WHAT ep_head +slab_row +set WHAT sock_inode_cache +slab_row +set WHAT signal_cache +slab_row +set WHAT TCPv6 +slab_row +set WHAT TCP +slab_row +set WHAT UDPv6 +slab_row +te + + +test Memory usage: all TCP ports forwarded, IPv4 +set OPTS -t all -4 +start_stop_diff +summary + + +test Memory usage: all TCP and UDP ports forwarded, IPv4 +set OPTS -t all -u all -4 +start_stop_diff +summary + + +test Memory usage: no ports forwarded +set OPTS -t none -u none +start_stop_diff +summary diff --git a/oldtest/nstool.c b/oldtest/nstool.c new file mode 100644 index 0000000..e6d7d37 --- /dev/null +++ b/oldtest/nstool.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* nstool - maintain a namespace to be entered by other processes + * + * Copyright Red Hat + * Author: David Gibson <david(a)gibson.dropbear.id.au> + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdbool.h> +#include <stdint.h> +#include <errno.h> +#include <unistd.h> +#include <getopt.h> +#include <stdarg.h> +#include <limits.h> +#include <fcntl.h> +#include <limits.h> +#include <unistd.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <sys/syscall.h> +#include <sys/prctl.h> +#include <linux/un.h> +#include <sched.h> +#include <linux/capability.h> + +#define ARRAY_SIZE(a) ((int)(sizeof(a) / sizeof((a)[0]))) + +#define die(...) \ + do { \ + fprintf(stderr, __VA_ARGS__); \ + exit(1); \ + } while (0) + +struct ns_type { + int flag; + const char *name; +}; + +const struct ns_type nstypes[] = { + { CLONE_NEWCGROUP, "cgroup" }, + { CLONE_NEWIPC, "ipc" }, + { CLONE_NEWNET, "net" }, + { CLONE_NEWNS, "mnt" }, + { CLONE_NEWPID, "pid" }, + { CLONE_NEWTIME, "time" }, + { CLONE_NEWUSER, "user" }, + { CLONE_NEWUTS, "uts" }, +}; + +#define for_each_nst(_nst, _flags) \ + for ((_nst) = &nstypes[0]; \ + ((_nst) - nstypes) < ARRAY_SIZE(nstypes); \ + (_nst)++) \ + if ((_flags) & (_nst)->flag) + +#define for_every_nst(_nst) for_each_nst(_nst, INT_MAX) + +#define NSTOOL_MAGIC 0x7570017575601d75ULL + +struct holder_info { + uint64_t magic; + pid_t pid; + uid_t uid; + gid_t gid; + char cwd[PATH_MAX]; +}; + +static void usage(void) +{ + die("Usage:\n" + " nstool hold SOCK\n" + " Run within a set of namespaces, open a Unix domain socket\n" + " (the \"control socket\") at SOCK and wait for requests from\n" + " other nstool subcommands.\n" + " nstool info [-pw] pid SOCK\n" + " Print information about the nstool hold process with control\n" + " socket at SOCK\n" + " -p Print just the holder's PID as seen by the caller\n" + " -w Retry connecting to SOCK until it is ready\n" + " nstool exec [--keep-caps] SOCK [COMMAND [ARGS...]]\n" + " Execute command or shell in the namespaces of the nstool hold\n" + " with control socket at SOCK\n" + " --keep-caps Give all possible capabilities to COMMAND via\n" + " the ambient capability mask\n" + " nstool stop SOCK\n" + " Instruct the nstool hold with control socket at SOCK to\n" + " terminate.\n"); +} + +static int connect_ctl(const char *sockpath, bool wait, + struct holder_info *info, + struct ucred *peercred) +{ + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNIX); + struct sockaddr_un addr = { + .sun_family = AF_UNIX, + }; + struct holder_info discard; + ssize_t len; + int rc; + + if (fd < 0) + die("socket(): %s\n", strerror(errno)); + + strncpy(addr.sun_path, sockpath, UNIX_PATH_MAX); + + do { + rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (rc < 0 && + (!wait || (errno != ENOENT && errno != ECONNREFUSED))) + die("connect() to %s: %s\n", sockpath, strerror(errno)); + } while (rc < 0); + + if (!info) + info = &discard; + + /* Always read the info structure, even if we don't need it, + * so that the holder doesn't get a broken pipe error + */ + len = read(fd, info, sizeof(*info)); + if (len < 0) + die("read() on control socket %s: %s\n", sockpath, strerror(errno)); + if ((size_t)len < sizeof(*info)) + die("short read() on control socket %s\n", sockpath); + + if (info->magic != NSTOOL_MAGIC) + die("Control socket %s doesn't appear to belong to nstool\n", + sockpath); + + if (peercred) { + socklen_t optlen = sizeof(*peercred); + + rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, + peercred, &optlen); + if (rc < 0) + die("getsockopet(SO_PEERCRED) %s: %s\n", + sockpath, strerror(errno)); + } + + return fd; +} + +static void cmd_hold(int argc, char *argv[]) +{ + int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, PF_UNIX); + struct sockaddr_un addr = { + .sun_family = AF_UNIX, + }; + const char *sockpath = argv[1]; + struct holder_info info; + int rc; + + if (argc != 2) + usage(); + + if (fd < 0) + die("socket(): %s\n", strerror(errno)); + + strncpy(addr.sun_path, sockpath, UNIX_PATH_MAX); + + rc = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (rc < 0) + die("bind() to %s: %s\n", sockpath, strerror(errno)); + + rc = listen(fd, 0); + if (rc < 0) + die("listen() on %s: %s\n", sockpath, strerror(errno)); + + info.magic = NSTOOL_MAGIC; + info.pid = getpid(); + info.uid = getuid(); + info.gid = getgid(); + if (!getcwd(info.cwd, sizeof(info.cwd))) + die("getcwd(): %s\n", strerror(errno)); + + do { + int afd = accept(fd, NULL, NULL); + char buf; + + if (afd < 0) + die("accept(): %s\n", strerror(errno)); + + rc = write(afd, &info, sizeof(info)); + if (rc < 0) + die("write(): %s\n", strerror(errno)); + if ((size_t)rc < sizeof(info)) + die("short write() on control socket\n"); + + rc = read(afd, &buf, sizeof(buf)); + if (rc < 0) + die("read(): %s\n", strerror(errno)); + } while (rc == 0); + + unlink(sockpath); +} + +static ssize_t getlink(char *buf, size_t bufsiz, const char *fmt, ...) +{ + char linkpath[PATH_MAX]; + ssize_t linklen; + va_list ap; + + va_start(ap, fmt); + if (vsnprintf(linkpath, sizeof(linkpath), fmt, ap) >= PATH_MAX) + die("Truncated path \"%s\"\n", linkpath); + va_end(ap); + + linklen = readlink(linkpath, buf, bufsiz); + if (linklen < 0) + die("readlink() on %s: %s\n", linkpath, strerror(errno)); + if ((size_t)linklen >= bufsiz) + die("Target of symbolic link %s is too long\n", linkpath); + + return linklen; +} + +static int detect_namespaces(pid_t pid) +{ + const struct ns_type *nst; + int flags = 0; + + for_every_nst(nst) { + char selflink[PATH_MAX], pidlink[PATH_MAX]; + ssize_t selflen, pidlen; + + selflen = getlink(selflink, sizeof(selflink), + "/proc/self/ns/%s", nst->name); + pidlen = getlink(pidlink, sizeof(pidlink), + "/proc/%d/ns/%s", pid, nst->name); + + if ((selflen != pidlen) || memcmp(selflink, pidlink, selflen)) + flags |= nst->flag; + } + + return flags; +} + +static void print_nstypes(int flags) +{ + const struct ns_type *nst; + bool first = true; + + for_each_nst(nst, flags) { + printf("%s%s", first ? "" : ", " , nst->name); + first = false; + flags &= ~nst->flag; + } + + if (flags) + printf("%s0x%x", first ? "" : ", ", flags); +} + +static void cmd_info(int argc, char *argv[]) +{ + const struct option options[] = { + {"pid", no_argument, NULL, 'p' }, + {"wait", no_argument, NULL, 'w' }, + { 0 }, + }; + bool pidonly = false, waitforsock = false; + const char *optstring = "pw"; + struct holder_info info; + struct ucred peercred; + const char *sockpath; + int fd, opt; + + do { + opt = getopt_long(argc, argv, optstring, options, NULL); + + switch (opt) { + case 'p': + pidonly = true; + break; + case 'w': + waitforsock = true; + break; + case -1: + break; + default: + usage(); + } + } while (opt != -1); + + if (optind != argc - 1) { + usage(); + } + + sockpath = argv[optind]; + + fd = connect_ctl(sockpath, waitforsock, &info, &peercred); + + close(fd); + + if (pidonly) { + printf("%d\n", peercred.pid); + } else { + int flags = detect_namespaces(peercred.pid); + + printf("Namespaces: "); + print_nstypes(flags); + printf("\n"); + + printf("As seen from calling context:\n"); + printf("\tPID:\t%d\n", peercred.pid); + printf("\tUID:\t%u\n", peercred.uid); + printf("\tGID:\t%u\n", peercred.gid); + + printf("As seen from holding context:\n"); + printf("\tPID:\t%d\n", info.pid); + printf("\tUID:\t%u\n", info.uid); + printf("\tGID:\t%u\n", info.gid); + printf("\tCWD:\t%s\n", info.cwd); + } +} + +static int openns(const char *fmt, ...) +{ + char nspath[PATH_MAX]; + va_list ap; + int fd; + + va_start(ap, fmt); + if (vsnprintf(nspath, sizeof(nspath), fmt, ap) >= PATH_MAX) + die("Truncated path \"%s\"\n", nspath); + va_end(ap); + + fd = open(nspath, O_RDONLY | O_CLOEXEC); + if (fd < 0) + die("open() %s: %s\n", nspath, strerror(errno)); + + return fd; +} + +static void wait_for_child(pid_t pid) +{ + int status; + + /* Match the child's exit status, if possible */ + for (;;) { + pid_t rc; + + rc = waitpid(pid, &status, WUNTRACED); + if (rc < 0) + die("waitpid() on %d: %s\n", pid, strerror(errno)); + if (rc != pid) + die("waitpid() on %d returned %d", pid, rc); + if (WIFSTOPPED(status)) { + /* Stop the parent to patch */ + kill(getpid(), SIGSTOP); + /* We must have resumed, resume the child */ + kill(pid, SIGCONT); + continue; + } + + break; + } + + if (WIFEXITED(status)) + exit(WEXITSTATUS(status)); + else if (WIFSIGNALED(status)) + kill(getpid(), WTERMSIG(status)); + + die("Unexpected status for child %d\n", pid); +} + +static void caps_to_ambient(void) +{ + /* Use raw system calls to avoid the overly complex caps + * libraries. */ + struct __user_cap_header_struct header = { + .version = _LINUX_CAPABILITY_VERSION_3, + .pid = 0, + }; + struct __user_cap_data_struct payload[_LINUX_CAPABILITY_U32S_3] = + {{ 0 }}; + uint64_t effective, cap; + + if (syscall(SYS_capget, &header, payload) < 0) + die("capget(): %s\n", strerror(errno)); + + /* First make caps inheritable */ + payload[0].inheritable = payload[0].permitted; + payload[1].inheritable = payload[1].permitted; + + if (syscall(SYS_capset, &header, payload) < 0) + die("capset(): %s\n", strerror(errno)); + + effective = ((uint64_t)payload[1].effective << 32) | (uint64_t)payload[0].effective; + + for (cap = 0; cap < (sizeof(effective) * 8); cap++) { + /* Skip non-existent caps */ + if (prctl(PR_CAPBSET_READ, cap, 0, 0, 0) < 0) + continue; + + if ((effective & (1 << cap)) + && prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0) < 0) + die("prctl(PR_CAP_AMBIENT): %s\n", strerror(errno)); + } +} + +static void cmd_exec(int argc, char *argv[]) +{ + enum { + OPT_EXEC_KEEPCAPS = CHAR_MAX + 1, + }; + const struct option options[] = { + {"keep-caps", no_argument, NULL, OPT_EXEC_KEEPCAPS }, + { 0 }, + }; + const char *shargs[] = { NULL, NULL }; + const char *sockpath = argv[1]; + int nfd[ARRAY_SIZE(nstypes)]; + const char *optstring = ""; + const struct ns_type *nst; + int ctlfd, flags, opt, rc; + const char *const *xargs; + struct holder_info info; + bool keepcaps = false; + struct ucred peercred; + const char *exe; + pid_t xpid; + + do { + opt = getopt_long(argc, argv, optstring, options, NULL); + + switch (opt) { + case OPT_EXEC_KEEPCAPS: + keepcaps = true; + break; + case -1: + break; + default: + usage(); + } + } while (opt != -1); + + if (argc < optind + 1) + usage(); + + sockpath = argv[optind]; + + ctlfd = connect_ctl(sockpath, false, &info, &peercred); + + flags = detect_namespaces(peercred.pid); + + for_each_nst(nst, flags) { + int *fd = &nfd[nst - nstypes]; + *fd = openns("/proc/%d/ns/%s", peercred.pid, nst->name); + } + + /* First pass, will get things where we need the privileges of + * the initial userns */ + for_each_nst(nst, flags) { + int fd = nfd[nst - nstypes]; + + rc = setns(fd, nst->flag); + if (rc == 0) { + flags &= ~nst->flag; + } + } + + /* Second pass, will get things where we need the privileges + * of the target userns */ + for_each_nst(nst, flags) { + int fd = nfd[nst - nstypes]; + + rc = setns(fd, nst->flag); + if (rc < 0) + die("setns() type %s: %s\n", + nst->name, strerror(errno)); + } + + /* If we've entered a mount ns, our cwd has changed to /. + * Switch to the cwd of the holder, which is probably less + * surprising. */ + if (flags & CLONE_NEWNS) { + rc = chdir(info.cwd); + if (rc < 0) + die("chdir(\"%s\"): %s\n", info.cwd, strerror(errno)); + } + + /* Fork to properly enter PID namespace */ + xpid = fork(); + if (xpid < 0) + die("fork(): %s\n", strerror(errno)); + + if (xpid > 0) { + /* Close the control socket so the waiting parent + * doesn't block the holder */ + close(ctlfd); + wait_for_child(xpid); + } + + /* CHILD */ + if (argc > optind + 1) { + exe = argv[optind + 1]; + xargs = (const char * const*)(argv + optind + 1); + } else { + exe = getenv("SHELL"); + if (!exe) + exe = "/bin/sh"; + + shargs[0] = exe; + + xargs = shargs; + } + + if (keepcaps) + caps_to_ambient(); + + rc = execvp(exe, (char *const *)xargs); + if (rc < 0) + die("execv() %s: %s\n", exe, strerror(errno)); + die("Returned from exec()\n"); +} + +static void cmd_stop(int argc, char *argv[]) +{ + const char *sockpath = argv[1]; + int fd, rc; + char buf = 'Q'; + + if (argc != 2) + usage(); + + fd = connect_ctl(sockpath, false, NULL, NULL); + + rc = write(fd, &buf, sizeof(buf)); + if (rc < 0) + die("write() to %s: %s\n", sockpath, strerror(errno)); + + close(fd); +} + +int main(int argc, char *argv[]) +{ + const char *subcmd = argv[1]; + int fd; + + if (argc < 2) + usage(); + + fd = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); + if (fd < 0) + die("socket(): %s\n", strerror(errno)); + + if (strcmp(subcmd, "hold") == 0) + cmd_hold(argc - 1, argv + 1); + else if (strcmp(subcmd, "info") == 0) + cmd_info(argc - 1, argv + 1); + else if (strcmp(subcmd, "exec") == 0) + cmd_exec(argc - 1, argv + 1); + else if (strcmp(subcmd, "stop") == 0) + cmd_stop(argc - 1, argv + 1); + else + usage(); + + exit(0); +} diff --git a/oldtest/passt.mbuto b/oldtest/passt.mbuto new file mode 100755 index 0000000..90816d2 --- /dev/null +++ b/oldtest/passt.mbuto @@ -0,0 +1,83 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# test/passt.mbuto - mbuto (https://mbuto.sh) profile for test images +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +PROGS="${PROGS:-ash,dash,bash ip mount ls insmod mkdir ln cat chmod lsmod + modprobe find grep mknod mv rm umount jq iperf3 dhclient hostname + sed tr chown sipcalc cut socat dd strace ping tail killall sleep sysctl + nproc tcp_rr tcp_crr udp_rr which tee seq bc sshd ssh-keygen cmp}" + +KMODS="${KMODS:- virtio_net virtio_pci vmw_vsock_virtio_transport}" + +LINKS="${LINKS:- + ash,dash,bash /init + ash,dash,bash /bin/sh}" + +DIRS="${DIRS} /tmp /sbin /usr/share /var/log /var/lib /etc/ssh /run/sshd /root/.ssh" + +COPIES="${COPIES} small.bin,/root/small.bin medium.bin,/root/medium.bin big.bin,/root/big.bin" + +FIXUP="${FIXUP}"' + cat > /sbin/dhclient-script << EOF +#!/bin/sh +LOG=/var/log/dhclient-script.log +echo \${reason} \${interface} >> \$LOG +set >> \$LOG + +[ -n "\${new_interface_mtu}" ] && ip link set dev \${interface} mtu \${new_interface_mtu} + +[ -n "\${new_ip_address}" ] && ip addr add \${new_ip_address}/\${new_subnet_mask} dev \${interface} +[ -n "\${new_routers}" ] && for r in \${new_routers}; do ip route add default via \${r} dev \${interface}; done +:> /etc/resolv.conf +[ -n "\${new_domain_name_servers}" ] && for d in \${new_domain_name_servers}; do echo "nameserver \${d}" >> /etc/resolv.conf; done +[ -n "\${new_domain_name}" ] && echo "search \${new_domain_name}" >> /etc/resolf.conf +[ -n "\${new_domain_search}" ] && (printf "search"; for d in \${new_domain_search}; do printf " %s" "\${d}"; done; printf "\n") >> /etc/resolv.conf +[ -n "\${new_ip6_address}" ] && ip addr add \${new_ip6_address}/\${new_ip6_prefixlen} dev \${interface} +[ -n "\${new_dhcp6_name_servers}" ] && for d in \${new_dhcp6_name_servers}; do echo "nameserver \${d}%\${interface}" >> /etc/resolv.conf; done +[ -n "\${new_dhcp6_domain_search}" ] && (printf "search"; for d in \${new_dhcp6_domain_search}; do printf " %s" "\${d}"; done; printf "\n") >> /etc/resolv.conf +[ -n "\${new_host_name}" ] && hostname "\${new_host_name}" +exit 0 +EOF + chmod 755 /sbin/dhclient-script + ln -s /sbin /usr/sbin + ln -s /bin /usr/bin + ln -s /run /var/run + :> /etc/fstab + + # sshd(dropbear) via vsock + cat > /etc/passwd << EOF +root:x:0:0:root:/root:/bin/sh +sshd:x:100:100:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin +EOF + cat > /etc/shadow << EOF +root:::0:99999:7::: +EOF + chmod 000 /etc/shadow + + :> /etc/ssh/sshd_config + ssh-keygen -A + chmod 700 /root/.ssh + chmod 700 /run/sshd + # Alternative location for the priv separation dir + ln -s /run/sshd /usr/share/empty.sshd + + cat > /root/.ssh/authorized_keys <<EOF +'"$(cat guest-key.pub 2>/dev/null || :)"' +EOF + chmod 600 /root/.ssh/authorized_keys + chmod 700 /root + socat VSOCK-LISTEN:22,fork EXEC:"sshd -i -e" 2> /var/log/vsock-ssh.log & + sh +m +' + +OUTPUT="KERNEL=__KERNEL__ +INITRD=__INITRD__ +" diff --git a/oldtest/passt.mem.mbuto b/oldtest/passt.mem.mbuto new file mode 100755 index 0000000..56f5139 --- /dev/null +++ b/oldtest/passt.mem.mbuto @@ -0,0 +1,44 @@ +#!/bin/sh +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# test/passt.mem.mbuto - mbuto (https://mbuto.sh) profile for memory usage tests +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +PROGS="${PROGS:-ash,dash,bash chmod ip mount insmod mkdir ln cat chmod modprobe + grep mknod sed chown sleep bc ls ps mount unshare chroot cp kill diff + head tail sort tr tee cut nm which}" + +KMODS="${KMODS:- dummy}" + +NODES="${NODES:-console kmsg null ptmx random urandom zero}" + +LINKS="${LINKS:- + ash,dash,bash /init + ash,dash,bash /bin/sh}" + +DIRS="${DIRS} /tmp /sbin" + +COPIES="${COPIES} ../passt.avx2,/bin/passt.avx2" + +FIXUP="${FIXUP}"' +ln -s /bin /usr/bin +chmod 777 /tmp +ip link add eth0 type dummy +ip link set eth0 up +ip address add 192.0.2.2/24 dev eth0 +ip address add 2001:db8::2/64 dev eth0 +ip route add default via 192.0.2.1 +ip -6 route add default via 2001:db8::1 dev eth0 +sleep 2 +sh +m +' + +OUTPUT="KERNEL=__KERNEL__ +INITRD=__INITRD__ +" diff --git a/oldtest/passt/dhcp b/oldtest/passt/dhcp new file mode 100644 index 0000000..7272755 --- /dev/null +++ b/oldtest/passt/dhcp @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt/dhcp - Check DHCP and DHCPv6 functionality in passt mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools ip jq dhclient sed tr +htools ip jq sed tr head + +test Interface name +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +check [ -n "__IFNAME__" ] + +test DHCP: address +guest /sbin/dhclient -4 __IFNAME__ +gout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local' +check [ "__ADDR__" = "__HOST_ADDR__" ] + +test DHCP: route +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +hout HOST_GW ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' +check [ "__GW__" = "__HOST_GW__" ] + +test DHCP: MTU +gout MTU ip -j link show | jq -rM '.[] | select(.ifname == "__IFNAME__").mtu' +check [ __MTU__ = 65520 ] + +test DHCP: DNS +gout DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/' +hout HOST_DNS sed -n 's/^nameserver \([0-9]*\.\)\(.*\)/\1\2/p' /etc/resolv.conf | head -n3 | tr '\n' ',' | sed 's/,$//;s/$/\n/' +check [ "__DNS__" = "__HOST_DNS__" ] || [ "__DNS__" = "__HOST_GW__" -a "__HOST_DNS__" = "127.0.0.1" ] + +# FQDNs should be terminated by dots, but the guest DHCP client might omit them: +# strip them first +test DHCP: search list +gout SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/' +hout HOST_SEARCH sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/' +check [ "__SEARCH__" = "__HOST_SEARCH__" ] + +test DHCPv6: address +guest /sbin/dhclient -6 __IFNAME__ +gout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local' +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' +check [ "__ADDR6__" = "__HOST_ADDR6__" ] + +test DHCPv6: route +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +hout HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' +check [ "__GW6__" = "__HOST_GW6__" ] + +# Strip interface specifier: interface names might differ between host and guest +test DHCPv6: DNS +gout DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/' +hout HOST_DNS6 sed -n 's/^nameserver \([^:]*:\)\([^%]*\).*/\1\2/p' /etc/resolv.conf | tr '\n' ',' | sed 's/,$//;s/$/\n/' +check [ "__DNS6__" = "__HOST_DNS6__" ] || [ "__DNS6__" = "__HOST_GW6__" -a "__HOST_DNS6__" = "::1" ] + +test DHCPv6: search list +gout SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/' +hout HOST_SEARCH6 sed 's/\. / /g' /etc/resolv.conf | sed 's/\.$//g' | sed -n 's/^search \(.*\)/\1/p' | tr ' \n' ',' | sed 's/,$//;s/$/\n/' +check [ "__SEARCH6__" = "__HOST_SEARCH6__" ] diff --git a/oldtest/passt/ndp b/oldtest/passt/ndp new file mode 100644 index 0000000..6de4081 --- /dev/null +++ b/oldtest/passt/ndp @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt/ndp - Check NDP functionality in passt mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools ip jq sipcalc grep +htools ip jq sipcalc grep cut + +test Interface name +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +guest ip link set dev __IFNAME__ up && sleep 2 +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +check [ -n "__IFNAME__" ] + +test SLAAC: prefix +gout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local' +gout PREFIX6 sipcalc __ADDR6__/64 | grep prefix | cut -d' ' -f4 +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' +hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 +check [ "__PREFIX6__" = "__HOST_PREFIX6__" ] + +test SLAAC: route +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +hout HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' +check [ __GW6__ = __HOST_GW6__ ] diff --git a/oldtest/passt/shutdown b/oldtest/passt/shutdown new file mode 100644 index 0000000..02c6c10 --- /dev/null +++ b/oldtest/passt/shutdown @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt/shutdown - Shut down passt (or pasta) and check exit code (will +# detect valgrind errors amongst others) +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +test shutdown: exit code + +hout PASST_PID cat __STATESETUP__/passt.pid +host kill __PASST_PID__ +passtw diff --git a/oldtest/passt/tcp b/oldtest/passt/tcp new file mode 100644 index 0000000..91e49e0 --- /dev/null +++ b/oldtest/passt/tcp @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt/tcp - Check TCP functionality in passt mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools socat ip jq cmp +htools socat ip jq + +set TEMP_BIG __STATEDIR__/test_big.bin +set TEMP_SMALL __STATEDIR__/test_small.bin + +test TCP/IPv4: host to guest: big transfer +guestb socat -u TCP4-LISTEN:10001,reuseaddr OPEN:test_big.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10001 +guestw +guest cmp /root/big.bin test_big.bin + +test TCP/IPv4: guest to host: big transfer +hostb socat -u TCP4-LISTEN:10003,bind=127.0.0.1,reuseaddr OPEN:__TEMP_BIG__,create,trunc +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +guest socat -u OPEN:/root/big.bin TCP4:__GW__:10003 +hostw +check cmp __BASEPATH__/big.bin __TEMP_BIG__ + +test TCP/IPv4: host to guest: small transfer +guestb socat -u TCP4-LISTEN:10001,reuseaddr OPEN:test_small.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10001 +guestw +guest cmp /root/small.bin test_small.bin + +test TCP/IPv4: guest to host: small transfer +hostb socat -u TCP4-LISTEN:10003,bind=127.0.0.1,reuseaddr OPEN:__TEMP_SMALL__,create,trunc +sleep 1 +guest socat -u OPEN:/root/small.bin TCP4:__GW__:10003 +hostw +check cmp __BASEPATH__/small.bin __TEMP_SMALL__ + + +test TCP/IPv6: host to guest: big transfer +guestb socat -u TCP6-LISTEN:10001,reuseaddr OPEN:test_big.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10001 +guestw +guest cmp /root/big.bin test_big.bin + +test TCP/IPv6: guest to host: big transfer +hostb socat -u TCP6-LISTEN:10003,bind=[::1],reuseaddr OPEN:__TEMP_BIG__,create,trunc +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +guest socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __BASEPATH__/big.bin __TEMP_BIG__ + +test TCP/IPv6: host to guest: small transfer +guestb socat -u TCP6-LISTEN:10001,reuseaddr OPEN:test_small.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10001 +guestw +guest cmp /root/small.bin test_small.bin + +test TCP/IPv6: guest to host: small transfer +hostb socat -u TCP6-LISTEN:10003,bind=[::1],reuseaddr OPEN:__TEMP_SMALL__,create,trunc +sleep 1 +guest socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __BASEPATH__/small.bin __TEMP_SMALL__ diff --git a/oldtest/passt/udp b/oldtest/passt/udp new file mode 100644 index 0000000..80d0fa3 --- /dev/null +++ b/oldtest/passt/udp @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt/udp - Check UDP functionality in passt mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools socat ip jq cmp +htools socat jq + +set TEMP __STATEDIR__/test.bin + +test UDP/IPv4: host to guest +guestb socat -u UDP4-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10001,shut-null +guestw +guest cmp /root/medium.bin test.bin + +test UDP/IPv4: guest to host +hostb socat -u UDP4-LISTEN:10003,bind=127.0.0.1,null-eof OPEN:__TEMP__,create,trunc +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +guest socat -u OPEN:/root/medium.bin UDP4:__GW__:10003,shut-null +hostw +check cmp __BASEPATH__/medium.bin __TEMP__ + +test UDP/IPv6: host to guest +guestb socat -u UDP6-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10001,shut-null +guestw +guest cmp /root/medium.bin test.bin + +test UDP/IPv6: guest to host +hostb socat -u UDP6-LISTEN:10003,bind=[::1],null-eof OPEN:__TEMP__,create,trunc +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +guest socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null +hostw +check cmp __BASEPATH__/medium.bin __TEMP__ diff --git a/oldtest/passt_in_ns/icmp b/oldtest/passt_in_ns/icmp new file mode 100644 index 0000000..a2697db --- /dev/null +++ b/oldtest/passt_in_ns/icmp @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt_in_ns/icmp - Check ICMP/ICMPv6 functionality for passt in ns +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> +# +# These tests can work reliably only within an isolated namespace: the host +# might have a net.ipv4.ping_group_range sysctl value not allowing pasta's gid +# to create "ping" sockets. Inside the namespace, there's a single group, which +# is allowed by default to create them. + +nstools ip jq sleep +gtools ping ip jq + +test ICMP echo: guest to ns +nsout IFNAME_NS ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +ns ip addr add 192.0.2.1/32 dev __IFNAME_NS__ +guest ping -c1 -w1 192.0.2.1 +ns ip addr del 192.0.2.1/32 dev __IFNAME_NS__ + +test ICMPv6 echo: guest to ns +ns ip addr add 2001:db8::1 dev __IFNAME_NS__ && sleep 2 # DAD +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +guest ping -c1 -w1 2001:db8::1 +ns ip addr del 2001:db8::1 dev __IFNAME_NS__ diff --git a/oldtest/passt_in_ns/shutdown b/oldtest/passt_in_ns/shutdown new file mode 100644 index 0000000..cd6cb19 --- /dev/null +++ b/oldtest/passt_in_ns/shutdown @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt_in_ns/shutdown - Shut down passt and check exit code (will detect +# valgrind errors amongst others) +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +test shutdown: exit code + +nsout PASST_PID cat __STATESETUP__/passt.pid +ns kill __PASST_PID__ +passtw diff --git a/oldtest/passt_in_ns/tcp b/oldtest/passt_in_ns/tcp new file mode 100644 index 0000000..cdb7060 --- /dev/null +++ b/oldtest/passt_in_ns/tcp @@ -0,0 +1,256 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt_in_ns/tcp - Check TCP functionality for passt in ns with pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools socat ip jq +htools socat ip jq +nstools socat ip jq + +set TEMP_BIG __STATEDIR__/test_big.bin +set TEMP_SMALL __STATEDIR__/test_small.bin +set TEMP_NS_BIG __STATEDIR__/test_ns_big.bin +set TEMP_NS_SMALL __STATEDIR__/test_ns_small.bin + +test TCP/IPv4: host to guest: big transfer +guestb socat -u TCP4-LISTEN:10001 OPEN:test_big.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10001 +guestw +guest cmp test_big.bin /root/big.bin + +test TCP/IPv4: host to ns: big transfer +nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10002 +nsw +check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin + +test TCP/IPv4: guest to host: big transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +sleep 1 +guest socat -u OPEN:/root/big.bin TCP4:__GW__:10003 +hostw +check cmp __TEMP_BIG__ __BASEPATH__/big.bin + +test TCP/IPv4: guest to ns: big transfer +nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc +sleep 1 +guest socat -u OPEN:/root/big.bin TCP4:__GW__:10002 +nsw +check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin + +test TCP/IPv4: ns to host (spliced): big transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10003 +hostw +check cmp __TEMP_BIG__ __BASEPATH__/big.bin + +test TCP/IPv4: ns to host (via tap): big transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP4:__GW__:10003 +hostw +check cmp __TEMP_BIG__ __BASEPATH__/big.bin + +test TCP/IPv4: ns to guest (using loopback address): big transfer +guestb socat -u TCP4-LISTEN:10001 OPEN:test_big.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10001 +guestw +guest cmp test_big.bin /root/big.bin + +test TCP/IPv4: ns to guest (using namespace address): big transfer +guestb socat -u TCP4-LISTEN:10001 OPEN:test_big.bin,create,trunc +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +nsout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP4:__ADDR__:10001 +guestw +guest cmp test_big.bin /root/big.bin + +test TCP/IPv4: host to guest: small transfer +guestb socat -u TCP4-LISTEN:10001 OPEN:test_small.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10001 +guestw +guest cmp test_small.bin /root/small.bin + +test TCP/IPv4: host to ns: small transfer +nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10002 +nsw +check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv4: guest to host: small transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +sleep 1 +guest socat -u OPEN:/root/small.bin TCP4:__GW__:10003 +hostw +check cmp __TEMP_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv4: guest to ns: small transfer +nsb socat -u TCP4-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc +sleep 1 +guest socat -u OPEN:/root/small.bin TCP4:__GW__:10002 +nsw +check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv4: ns to host (spliced): small transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10003 +hostw +check cmp __TEMP_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv4: ns to host (via tap): small transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP4:__GW__:10003 +hostw +check cmp __TEMP_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv4: ns to guest (using loopback address): small transfer +guestb socat -u TCP4-LISTEN:10001 OPEN:test_small.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10001 +guestw +guest cmp test_small.bin /root/small.bin + +test TCP/IPv4: ns to guest (using namespace address): small transfer +guestb socat -u TCP4-LISTEN:10001 OPEN:test_small.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP4:__ADDR__:10001 +guestw +guest cmp test_small.bin /root/small.bin + +test TCP/IPv6: host to guest: big transfer +guestb socat -u TCP6-LISTEN:10001 OPEN:test_big.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10001 +guestw +guest cmp test_big.bin /root/big.bin + +test TCP/IPv6: host to ns: big transfer +nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10002 +nsw +check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin + +test TCP/IPv6: guest to host: big transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +sleep 1 +guest socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __TEMP_BIG__ __BASEPATH__/big.bin + +test TCP/IPv6: guest to ns: big transfer +nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_BIG__,create,trunc +sleep 1 +guest socat -u OPEN:/root/big.bin TCP6:[__GW6__%__IFNAME__]:10002 +nsw +check cmp __TEMP_NS_BIG__ __BASEPATH__/big.bin + +test TCP/IPv6: ns to host (spliced): big transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10003 +hostw +check cmp __TEMP_BIG__ __BASEPATH__/big.bin + +test TCP/IPv6: ns to host (via tap): big transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __TEMP_BIG__ __BASEPATH__/big.bin + +test TCP/IPv6: ns to guest (using loopback address): big transfer +guestb socat -u TCP6-LISTEN:10001 OPEN:test_big.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10001 +guestw +guest cmp test_big.bin /root/big.bin + +test TCP/IPv6: ns to guest (using namespace address): big transfer +guestb socat -u TCP6-LISTEN:10001 OPEN:test_big.bin,create,trunc +nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +sleep 1 +ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__ADDR6__]:10001 +guestw +guest cmp test_big.bin /root/big.bin + +test TCP/IPv6: host to guest: small transfer +guestb socat -u TCP6-LISTEN:10001 OPEN:test_small.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10001 +guestw +guest cmp test_small.bin /root/small.bin + +test TCP/IPv6: host to ns: small transfer +nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_SMALL__,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10002 +nsw +check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv6: guest to host: small transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +sleep 1 +guest socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __TEMP_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv6: guest to ns: small transfer +nsb socat -u TCP6-LISTEN:10002 OPEN:__TEMP_NS_SMALL__ +sleep 1 +guest socat -u OPEN:/root/small.bin TCP6:[__GW6__%__IFNAME__]:10002 +nsw +check cmp __TEMP_NS_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv6: ns to host (spliced): small transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10003 +hostw +check cmp __TEMP_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv6: ns to host (via tap): small transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __TEMP_SMALL__ __BASEPATH__/small.bin + +test TCP/IPv6: ns to guest (using loopback address): small transfer +guestb socat -u TCP6-LISTEN:10001 OPEN:test_small.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10001 +guestw +guest cmp test_small.bin /root/small.bin + +test TCP/IPv6: ns to guest (using namespace address): small transfer +guestb socat -u TCP6-LISTEN:10001 OPEN:test_small.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[__ADDR6__]:10001 +guestw +guest cmp test_small.bin /root/small.bin diff --git a/oldtest/passt_in_ns/udp b/oldtest/passt_in_ns/udp new file mode 100644 index 0000000..8a02513 --- /dev/null +++ b/oldtest/passt_in_ns/udp @@ -0,0 +1,138 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/passt_in_ns/udp - Check UDP functionality for passt in ns and pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools socat ip jq +nstools socat ip jq +htools socat ip jq + +set TEMP __STATEDIR__/test.bin +set TEMP_NS __STATEDIR__/test_ns.bin + +test UDP/IPv4: host to guest +guestb socat -u UDP4-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10001,shut-null +guestw +guest cmp test.bin /root/medium.bin + +test UDP/IPv4: host to ns +nsb socat -u UDP4-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10002,shut-null +nsw +check cmp __TEMP_NS__ __BASEPATH__/medium.bin + +test UDP/IPv4: guest to host +hostb socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +sleep 1 +guest socat -u OPEN:/root/medium.bin UDP4:__GW__:10003,shut-null +hostw +check cmp __TEMP__ __BASEPATH__/medium.bin + +test UDP/IPv4: guest to ns +nsb socat -u UDP4-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc +sleep 1 +guest socat -u OPEN:/root/medium.bin UDP4:__GW__:10002,shut-null +nsw +check cmp __TEMP_NS__ __BASEPATH__/medium.bin + +test UDP/IPv4: ns to host (recvmmsg/sendmmsg) +hostb socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10003,shut-null +hostw +check cmp __TEMP__ __BASEPATH__/medium.bin + +test UDP/IPv4: ns to host (via tap) +hostb socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:__GW__:10003,shut-null +hostw +check cmp __TEMP__ __BASEPATH__/medium.bin + +test UDP/IPv4: ns to guest (using loopback address) +guestb socat -u UDP4-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10001,shut-null +guestw +guest cmp test.bin /root/medium.bin + +test UDP/IPv4: ns to guest (using namespace address) +guestb socat -u UDP4-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +nsout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:__ADDR__:10001,shut-null +guestw +guest cmp test.bin /root/medium.bin + +test UDP/IPv6: host to guest +guestb socat -u UDP6-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10001,shut-null +guestw +guest cmp test.bin /root/medium.bin + +test UDP/IPv6: host to ns +nsb socat -u UDP6-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc +sleep 1 +host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10002,shut-null +nsw +check cmp __TEMP_NS__ __BASEPATH__/medium.bin + +test UDP/IPv6: guest to host +hostb socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +sleep 1 +guest socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null +hostw +check cmp __TEMP__ __BASEPATH__/medium.bin + +test UDP/IPv6: guest to ns +nsb socat -u UDP6-LISTEN:10002,null-eof OPEN:__TEMP_NS__,create,trunc +sleep 1 +guest socat -u OPEN:/root/medium.bin UDP6:[__GW6__%__IFNAME__]:10002,shut-null +nsw +check cmp __TEMP_NS__ __BASEPATH__/medium.bin + +test UDP/IPv6: ns to host (recvmmsg/sendmmsg) +hostb socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10003,shut-null +hostw +check cmp __TEMP__ __BASEPATH__/medium.bin + +test UDP/IPv6: ns to host (via tap) +hostb socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null +hostw +check cmp __TEMP__ __BASEPATH__/medium.bin + +test UDP/IPv6: ns to guest (using loopback address) +guestb socat -u UDP6-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10001,shut-null +guestw +guest cmp test.bin /root/medium.bin + +test UDP/IPv6: ns to guest (using namespace address) +guestb socat -u UDP6-LISTEN:10001,null-eof OPEN:test.bin,create,trunc +nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__ADDR6__]:10001,shut-null +guestw +guest cmp test.bin /root/medium.bin diff --git a/oldtest/pasta/dhcp b/oldtest/pasta/dhcp new file mode 100644 index 0000000..309001b --- /dev/null +++ b/oldtest/pasta/dhcp @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/pasta/dhcp - Check DHCP and DHCPv6 functionality in pasta mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +nstools ip jq /sbin/dhclient +htools ip jq + +test Interface name +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +check [ -n "__IFNAME__" ] + +test DHCP: address +ns /sbin/dhclient -4 --no-pid __IFNAME__ +nsout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +check [ __ADDR__ = __HOST_ADDR__ ] + +test DHCP: route +nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +hout HOST_GW ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' +check [ __GW__ = __HOST_GW__ ] + +test DHCP: MTU +nsout MTU ip -j link show | jq -rM '.[] | select(.ifname == "__IFNAME__").mtu' +check [ __MTU__ = 65520 ] + +test DHCPv6: address +ns /sbin/dhclient -6 --no-pid __IFNAME__ +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.prefixlen == 128).local' +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' +check [ __ADDR6__ = __HOST_ADDR6__ ] + +test DHCPv6: route +nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +hout HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' +check [ __GW6__ = __HOST_GW6__ ] diff --git a/oldtest/pasta/ndp b/oldtest/pasta/ndp new file mode 100644 index 0000000..bb33110 --- /dev/null +++ b/oldtest/pasta/ndp @@ -0,0 +1,33 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/pasta/ndp - Check DHCP and DHCPv6 functionality in pasta mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +nstools ip jq sipcalc grep cut +htools ip jq sipcalc grep cut + +test Interface name +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +check [ -n "__IFNAME__" ] +ns ip link set dev __IFNAME__ up +sleep 2 + +test SLAAC: prefix +nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local' +nsout PREFIX6 sipcalc __ADDR6__/64 | grep prefix | cut -d' ' -f4 +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global").local' +hout HOST_PREFIX6 sipcalc __HOST_ADDR6__/64 | grep prefix | cut -d' ' -f4 +check [ "__PREFIX6__" = "__HOST_PREFIX6__" ] + +test SLAAC: route +nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +hout HOST_GW6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").gateway] | .[0]' +check [ __GW6__ = __HOST_GW6__ ] diff --git a/oldtest/pasta/tcp b/oldtest/pasta/tcp new file mode 100644 index 0000000..6ab18c5 --- /dev/null +++ b/oldtest/pasta/tcp @@ -0,0 +1,96 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/pasta/tcp - Check TCP functionality for pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +htools socat ip jq +nstools socat ip jq + +set TEMP_BIG __STATEDIR__/test_big.bin +set TEMP_NS_BIG __STATEDIR__/test_ns_big.bin +set TEMP_SMALL __STATEDIR__/test_small.bin +set TEMP_NS_SMALL __STATEDIR__/test_ns_small.bin + +test TCP/IPv4: host to ns: big transfer +nsb socat -u TCP4-LISTEN:10002,bind=127.0.0.1 OPEN:__TEMP_NS_BIG__,create,trunc +host socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10002 +nsw +check cmp __BASEPATH__/big.bin __TEMP_NS_BIG__ + +test TCP/IPv4: ns to host (spliced): big transfer +hostb socat -u TCP4-LISTEN:10003,bind=127.0.0.1 OPEN:__TEMP_BIG__,create,trunc +ns socat -u OPEN:__BASEPATH__/big.bin TCP4:127.0.0.1:10003 +hostw +check cmp __BASEPATH__/big.bin __TEMP_BIG__ + +test TCP/IPv4: ns to host (via tap): big transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +ns socat -u OPEN:__BASEPATH__/big.bin TCP4:__GW__:10003 +hostw +check cmp __BASEPATH__/big.bin __TEMP_BIG__ + +test TCP/IPv4: host to ns: small transfer +nsb socat -u TCP4-LISTEN:10002,bind=127.0.0.1 OPEN:__TEMP_NS_SMALL__,create,trunc +host socat OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10002 +nsw +check cmp __BASEPATH__/small.bin __TEMP_NS_SMALL__ + +test TCP/IPv4: ns to host (spliced): small transfer +hostb socat -u TCP4-LISTEN:10003,bind=127.0.0.1 OPEN:__TEMP_SMALL__,create,trunc +ns socat OPEN:__BASEPATH__/small.bin TCP4:127.0.0.1:10003 +hostw +check cmp __BASEPATH__/small.bin __TEMP_SMALL__ + +test TCP/IPv4: ns to host (via tap): small transfer +hostb socat -u TCP4-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +ns socat -u OPEN:__BASEPATH__/small.bin TCP4:__GW__:10003 +hostw +check cmp __BASEPATH__/small.bin __TEMP_SMALL__ + +test TCP/IPv6: host to ns: big transfer +nsb socat -u TCP6-LISTEN:10002,bind=[::1] OPEN:__TEMP_NS_BIG__,create,trunc +host socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10002 +nsw +check cmp __BASEPATH__/big.bin __TEMP_NS_BIG__ + +test TCP/IPv6: ns to host (spliced): big transfer +hostb socat -u TCP6-LISTEN:10003,bind=[::1] OPEN:__TEMP_BIG__,create,trunc +ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[::1]:10003 +hostw +check cmp __BASEPATH__/big.bin __TEMP_BIG__ + +test TCP/IPv6: ns to host (via tap): big transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_BIG__,create,trunc +nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +ns socat -u OPEN:__BASEPATH__/big.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __BASEPATH__/big.bin __TEMP_BIG__ + +test TCP/IPv6: host to ns: small transfer +nsb socat -u TCP6-LISTEN:10002,bind=[::1] OPEN:__TEMP_NS_SMALL__,create,trunc +host socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10002 +nsw +check cmp __BASEPATH__/small.bin __TEMP_NS_SMALL__ + +test TCP/IPv6: ns to host (spliced): small transfer +hostb socat -u TCP6-LISTEN:10003,bind=[::1] OPEN:__TEMP_SMALL__,create,trunc +ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[::1]:10003 +hostw +check cmp __BASEPATH__/small.bin __TEMP_SMALL__ + +test TCP/IPv6: ns to host (via tap): small transfer +hostb socat -u TCP6-LISTEN:10003 OPEN:__TEMP_SMALL__,create,trunc +ns socat -u OPEN:__BASEPATH__/small.bin TCP6:[__GW6__%__IFNAME__]:10003 +hostw +check cmp __BASEPATH__/small.bin __TEMP_SMALL__ diff --git a/oldtest/pasta/udp b/oldtest/pasta/udp new file mode 100644 index 0000000..30e3a85 --- /dev/null +++ b/oldtest/pasta/udp @@ -0,0 +1,59 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/pasta/udp - Check UDP functionality for pasta +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +nstools socat ip jq +htools dd socat ip jq + +set TEMP __STATEDIR__/test.bin +set TEMP_NS __STATEDIR__/test_ns.bin + +test UDP/IPv4: host to ns +nsb socat -u UDP4-LISTEN:10002,bind=127.0.0.1,null-eof OPEN:__TEMP_NS__,create,trunc +host socat OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10002,shut-null +nsw +check cmp __BASEPATH__/medium.bin __TEMP_NS__ + +test UDP/IPv4: ns to host (recvmmsg/sendmmsg) +hostb socat -u UDP4-LISTEN:10003,bind=127.0.0.1,null-eof OPEN:__TEMP__,create,trunc +sleep 1 +ns socat OPEN:__BASEPATH__/medium.bin UDP4:127.0.0.1:10003,shut-null +hostw +check cmp __BASEPATH__/medium.bin __TEMP__ + +test UDP/IPv4: ns to host (via tap) +hostb socat -u UDP4-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +ns socat -u OPEN:__BASEPATH__/medium.bin UDP4:__GW__:10003,shut-null +hostw +check cmp __BASEPATH__/medium.bin __TEMP__ + +test UDP/IPv6: host to ns +nsb socat -u UDP6-LISTEN:10002,bind=[::1],null-eof OPEN:__TEMP_NS__,create,trunc +host socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10002,shut-null +nsw +check cmp __BASEPATH__/medium.bin __TEMP_NS__ + +test UDP/IPv6: ns to host (recvmmsg/sendmmsg) +hostb socat -u UDP6-LISTEN:10003,bind=[::1],null-eof OPEN:__TEMP__,create,trunc +sleep 1 +ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[::1]:10003,shut-null +hostw +check cmp __BASEPATH__/medium.bin __TEMP__ + +test UDP/IPv6: ns to host (via tap) +hostb socat -u UDP6-LISTEN:10003,null-eof OPEN:__TEMP__,create,trunc +nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +ns socat -u OPEN:__BASEPATH__/medium.bin UDP6:[__GW6__%__IFNAME__]:10003,shut-null +hostw +check cmp __BASEPATH__/medium.bin __TEMP__ diff --git a/oldtest/pasta_options/log_to_file b/oldtest/pasta_options/log_to_file new file mode 100644 index 0000000..fcdd553 --- /dev/null +++ b/oldtest/pasta_options/log_to_file @@ -0,0 +1,93 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/pasta_options/log_to_file - Check log creation, rotations and consistency +# +# Copyright (c) 2022 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +htools wc tcp_rr tail cut tr sort + +def flood_log_server +passtb tcp_crr --nolog -P 10001 -C 10002 -6 +sleep 1 +endef + +def flood_log_client +host tcp_crr --nolog -P 10001 -C 10002 -6 -c -H ::1 +endef + +def check_log_size_mountns +pout SIZE cat __LOG_FILE__ | wc -c +check [ __SIZE__ -gt $((50 * 1024)) ] +check [ __SIZE__ -lt $((100 * 1024)) ] +endef + +test Log creation + +set PORTS -t 10001,10002 -u 10001,10002 +set LOG_FILE __STATEDIR__/pasta.log + +passt ./pasta -l __LOG_FILE__ +passtb exit +sleep 1 +check [ -s __LOG_FILE__ ] + +test Log truncated on creation +passt ./pasta -l __LOG_FILE__ +passtb exit +sleep 1 +check [ $(cat __LOG_FILE__ | wc -l) -eq 1 ] + +test Maximum log size +passtb ./pasta --config-net -d -f -l __LOG_FILE__ --log-size $((100 * 1024)) -- sh -c 'while true; do tcp_crr --nolog -P 10001 -C 10002 -6; done' +sleep 1 + +flood_log_client +check [ $(cat __LOG_FILE__ | wc -c) -gt $((50 * 1024)) ] +check [ $(cat __LOG_FILE__ | wc -c) -lt $((100 * 1024)) ] + +flood_log_client +check [ $(cat __LOG_FILE__ | wc -c) -gt $((50 * 1024)) ] +check [ $(cat __LOG_FILE__ | wc -c) -lt $((100 * 1024)) ] + +flood_log_client +check [ $(cat __LOG_FILE__ | wc -c) -gt $((50 * 1024)) ] +check [ $(cat __LOG_FILE__ | wc -c) -lt $((100 * 1024)) ] + +pint + +test Timestamp consistency after rotations +check tail -n +2 __LOG_FILE__ | cut -f1 -d' ' | tr -d [.:] | sort -c + +test Maximum log size on tmpfs (no FALLOC_FL_COLLAPSE_RANGE) +passt unshare -rUm +passt mkdir __STATEDIR__/t +passt mount -t tmpfs none __STATEDIR__/t +set LOG_FILE __STATEDIR__/t/log +passt ./pasta --config-net -d -l __LOG_FILE__ --log-size $((100 * 1024)) + +flood_log_server +flood_log_client +check_log_size_mountns + +flood_log_server +flood_log_client +check_log_size_mountns + +flood_log_server +flood_log_client +check_log_size_mountns + +test Timestamp consistency after rotations (no FALLOC_FL_COLLAPSE_RANGE) +check tail -n +2 __LOG_FILE__ | cut -f1 -d' ' | tr -d [.:] | sort -c + +passtb exit +sleep 1 +passt umount __STATEDIR__/t +passt exit diff --git a/oldtest/perf/passt_tcp b/oldtest/perf/passt_tcp new file mode 100644 index 0000000..7046f3c --- /dev/null +++ b/oldtest/perf/passt_tcp @@ -0,0 +1,215 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/perf/passt_tcp - Check TCP performance in passt mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools /sbin/sysctl ip jq nproc seq sleep iperf3 tcp_rr tcp_crr # From neper +nstools /sbin/sysctl ip jq nproc seq sleep iperf3 tcp_rr tcp_crr +htools bc head sed seq + +test passt: throughput and latency + +guest /sbin/sysctl -w net.core.rmem_max=536870912 +guest /sbin/sysctl -w net.core.wmem_max=536870912 +guest /sbin/sysctl -w net.core.rmem_default=33554432 +guest /sbin/sysctl -w net.core.wmem_default=33554432 +guest /sbin/sysctl -w net.ipv4.tcp_rmem="4096 131072 268435456" +guest /sbin/sysctl -w net.ipv4.tcp_wmem="4096 131072 268435456" +guest /sbin/sysctl -w net.ipv4.tcp_timestamps=0 + +ns /sbin/sysctl -w net.ipv4.tcp_rmem="4096 524288 134217728" +ns /sbin/sysctl -w net.ipv4.tcp_wmem="4096 524288 134217728" +ns /sbin/sysctl -w net.ipv4.tcp_timestamps=0 + +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' + +hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1 +hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) ) | bc -l +hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__ + +set THREADS 1 +set STREAMS 8 +set TIME 10 +hout OMIT echo __TIME__ / 6 | bc -l +set OPTS -Z -P __STREAMS__ -l 1M -O__OMIT__ --pacing-timer 1000000 + +info Throughput in Gbps, latency in µs, one thread at __FREQ__ GHz, __STREAMS__ streams +report passt tcp __THREADS__ __FREQ__ + +th MTU 256B 576B 1280B 1500B 9000B 65520B + + +tr TCP throughput over IPv6: guest to host +bw - +bw - + +guest ip link set dev __IFNAME__ mtu 1280 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M +bw __BW__ 1.2 1.5 +guest ip link set dev __IFNAME__ mtu 1500 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M +bw __BW__ 1.6 1.8 +guest ip link set dev __IFNAME__ mtu 9000 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M +bw __BW__ 4.0 5.0 +guest ip link set dev __IFNAME__ mtu 65520 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M +bw __BW__ 7.0 8.0 + +tl TCP RR latency over IPv6: guest to host +lat - +lat - +lat - +lat - +lat - +nsb tcp_rr --nolog -6 +gout LAT tcp_rr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 + +tl TCP CRR latency over IPv6: guest to host +lat - +lat - +lat - +lat - +lat - +nsb tcp_crr --nolog -6 +gout LAT tcp_crr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 500 400 + + +tr TCP throughput over IPv4: guest to host +guest ip link set dev __IFNAME__ mtu 256 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 1M +bw __BW__ 0.2 0.3 +guest ip link set dev __IFNAME__ mtu 576 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 1M +bw __BW__ 0.5 0.8 +guest ip link set dev __IFNAME__ mtu 1280 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M +bw __BW__ 1.2 1.5 +guest ip link set dev __IFNAME__ mtu 1500 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 4M +bw __BW__ 1.6 1.8 +guest ip link set dev __IFNAME__ mtu 9000 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 8M +bw __BW__ 4.0 5.0 +guest ip link set dev __IFNAME__ mtu 65520 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -w 16M +bw __BW__ 7.0 8.0 + +tl TCP RR latency over IPv4: guest to host +lat - +lat - +lat - +lat - +lat - +nsb tcp_rr --nolog -4 +gout LAT tcp_rr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 + +tl TCP CRR latency over IPv4: guest to host +lat - +lat - +lat - +lat - +lat - +nsb tcp_crr --nolog -4 +gout LAT tcp_crr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 500 400 + + +tr TCP throughput over IPv6: host to guest +bw - +bw - +ns ip link set dev lo mtu 1280 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 1.0 1.2 +ns ip link set dev lo mtu 1500 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 2.0 3.0 +ns ip link set dev lo mtu 9000 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 5.0 6.0 +ns ip link set dev lo mtu 65520 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 6.0 6.8 +ns ip link set dev lo mtu 65535 + +tl TCP RR latency over IPv6: host to guest +lat - +lat - +lat - +lat - +lat - +guestb tcp_rr --nolog -P 10001 -C 10011 -6 +sleep 1 +nsout LAT tcp_rr --nolog -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 + +tl TCP CRR latency over IPv6: host to guest +lat - +lat - +lat - +lat - +lat - +guestb tcp_crr --nolog -P 10001 -C 10011 -6 +sleep 1 +nsout LAT tcp_crr --nolog -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 500 350 + + +tr TCP throughput over IPv4: host to guest +ns ip link set dev lo mtu 256 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 0.3 0.5 +ns ip link set dev lo mtu 576 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 0.5 1.0 +ns ip link set dev lo mtu 1280 +ns ip addr add ::1 dev lo +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 2.0 3.0 +ns ip link set dev lo mtu 1500 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 2.0 3.0 +ns ip link set dev lo mtu 9000 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 5.0 6.0 +ns ip link set dev lo mtu 65520 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 6.0 6.8 +ns ip link set dev lo mtu 65535 + +tl TCP RR latency over IPv4: host to guest +lat - +lat - +lat - +lat - +lat - +guestb tcp_rr --nolog -P 10001 -C 10011 -4 +sleep 1 +nsout LAT tcp_rr --nolog -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 + +tl TCP CRR latency over IPv6: host to guest +lat - +lat - +lat - +lat - +lat - +guestb tcp_crr --nolog -P 10001 -C 10011 -4 +sleep 1 +nsout LAT tcp_crr --nolog -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 500 300 + +te diff --git a/oldtest/perf/passt_udp b/oldtest/perf/passt_udp new file mode 100644 index 0000000..a117b6a --- /dev/null +++ b/oldtest/perf/passt_udp @@ -0,0 +1,165 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/perf/passt_udp - Check UDP performance in passt mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +gtools /sbin/sysctl ip jq nproc sleep iperf3 udp_rr # From neper +nstools ip jq sleep iperf3 udp_rr +htools bc head sed + +test passt: throughput and latency + +guest /sbin/sysctl -w net.core.rmem_max=16777216 +guest /sbin/sysctl -w net.core.wmem_max=16777216 +guest /sbin/sysctl -w net.core.rmem_default=16777216 +guest /sbin/sysctl -w net.core.wmem_default=16777216 + +gout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +gout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' + +hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1 +hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) ) | bc -l +hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__ + +set THREADS 4 +set STREAMS 1 +set TIME 10 +set OPTS -u -P __STREAMS__ --pacing-timer 1000 + +info Throughput in Gbps, latency in µs, __THREADS__ threads at __FREQ__ GHz, one stream each + +report passt udp __THREADS__ __FREQ__ + +th MTU 256B 576B 1280B 1500B 9000B 65520B + + +tr UDP throughput over IPv6: guest to host +bw - +bw - +guest ip link set dev __IFNAME__ mtu 1280 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G +bw __BW__ 0.8 1.2 +guest ip link set dev __IFNAME__ mtu 1500 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 1.0 1.5 +guest ip link set dev __IFNAME__ mtu 9000 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 5G +bw __BW__ 4.0 5.0 +guest ip link set dev __IFNAME__ mtu 65520 +iperf3 BW guest ns __GW6__%__IFNAME__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G +bw __BW__ 4.0 5.0 + +tl UDP RR latency over IPv6: guest to host +lat - +lat - +lat - +lat - +lat - +nsb udp_rr --nolog -6 +gout LAT udp_rr --nolog -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 + + +tr UDP throughput over IPv4: guest to host +guest ip link set dev __IFNAME__ mtu 256 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 500M +bw __BW__ 0.0 0.0 +guest ip link set dev __IFNAME__ mtu 576 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 1G +bw __BW__ 0.4 0.6 +guest ip link set dev __IFNAME__ mtu 1280 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 2G +bw __BW__ 0.8 1.2 +guest ip link set dev __IFNAME__ mtu 1500 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 1.0 1.5 +guest ip link set dev __IFNAME__ mtu 9000 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 6G +bw __BW__ 4.0 5.0 +guest ip link set dev __IFNAME__ mtu 65520 +iperf3 BW guest ns __GW__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 7G +bw __BW__ 4.0 5.0 + +tl UDP RR latency over IPv4: guest to host +lat - +lat - +lat - +lat - +lat - +nsb udp_rr --nolog -4 +gout LAT udp_rr --nolog -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 + + +tr UDP throughput over IPv6: host to guest +bw - +bw - +ns ip link set dev lo mtu 1280 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 2G +bw __BW__ 0.8 1.2 +ns ip link set dev lo mtu 1500 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 2G +bw __BW__ 1.0 1.5 +ns ip link set dev lo mtu 9000 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 3.0 4.0 +ns ip link set dev lo mtu 65520 +iperf3 BW ns guest ::1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 3.0 4.0 + +tl UDP RR latency over IPv6: host to guest +lat - +lat - +lat - +lat - +lat - +guestb udp_rr --nolog -P 10001 -C 10011 -6 +sleep 1 +nsout LAT udp_rr --nolog -P 10001 -C 10011 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 +ns ip link set dev lo mtu 65535 + + +tr UDP throughput over IPv4: host to guest +ns ip link set dev lo mtu 256 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 1G +bw __BW__ 0.0 0.0 +ns ip link set dev lo mtu 576 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 1G +bw __BW__ 0.4 0.6 +ns ip link set dev lo mtu 1280 +ns ip addr add ::1 dev lo +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 0.8 1.2 +ns ip link set dev lo mtu 1500 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 1.0 1.5 +ns ip link set dev lo mtu 9000 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 3.0 4.0 +ns ip link set dev lo mtu 65520 +iperf3 BW ns guest 127.0.0.1 100${i}1 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 3.0 4.0 + +tl UDP RR latency over IPv4: host to guest +lat - +lat - +lat - +lat - +lat - +guestb udp_rr --nolog -P 10001 -C 10011 -4 +sleep 1 +nsout LAT udp_rr --nolog -P 10001 -C 10011 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +lat __LAT__ 200 150 +ns ip link set dev lo mtu 65535 + +te diff --git a/oldtest/perf/pasta_tcp b/oldtest/perf/pasta_tcp new file mode 100644 index 0000000..4b13384 --- /dev/null +++ b/oldtest/perf/pasta_tcp @@ -0,0 +1,300 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/perf/pasta_tcp - Check TCP performance in pasta mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +htools head ip seq bc sleep iperf3 tcp_rr tcp_crr jq sed +nstools /sbin/sysctl nproc ip seq sleep iperf3 tcp_rr tcp_crr jq sed + +test pasta: throughput and latency (local connections) + +ns /sbin/sysctl -w net.ipv4.tcp_rmem="131072 524288 134217728" +ns /sbin/sysctl -w net.ipv4.tcp_wmem="131072 524288 134217728" +ns /sbin/sysctl -w net.ipv4.tcp_timestamps=0 + + +set THREADS 2 +set STREAMS 2 +set TIME 10 +hout OMIT echo __TIME__ / 6 | bc -l +set OPTS -Z -w 4M -l 1M -P __STREAMS__ -O__OMIT__ --pacing-timer 10000 + +hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1 +hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) ) | bc -l +hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__ + + +info Throughput in Gbps, latency in µs, __THREADS__ threads at __FREQ__ GHz, __STREAMS__ streams each +report pasta lo_tcp __THREADS__ __FREQ__ + +th MTU 1500B 4000B 16384B 65535B + + +tr TCP throughput over IPv6: ns to host +ns ip link set dev lo mtu 1500 +iperf3 BW ns host ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 +ns ip link set dev lo mtu 4000 +iperf3c ns ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ +iperf3s BW host 100${i}3 __THREADS__ +bw __BW__ 15.0 20.0 +ns ip link set dev lo mtu 16384 +iperf3 BW ns host ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 +ns ip link set dev lo mtu 65535 +iperf3 BW ns host ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 + +tl TCP RR latency over IPv6: ns to host +lat - +lat - +lat - +hostb tcp_rr --nolog -P 10003 -C 10013 -6 +nsout LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv6: ns to host +lat - +lat - +lat - +hostb tcp_crr --nolog -P 10003 -C 10013 -6 +nsout LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 500 350 + + +tr TCP throughput over IPv4: ns to host +ns ip link set dev lo mtu 1500 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 +ns ip link set dev lo mtu 4000 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 +ns ip link set dev lo mtu 16384 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 +ns ip link set dev lo mtu 65535 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 + +tl TCP RR latency over IPv4: ns to host +lat - +lat - +lat - +hostb tcp_rr --nolog -P 10003 -C 10013 -4 +nsout LAT tcp_rr --nolog -P 10003 -C 10013 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv4: ns to host +lat - +lat - +lat - +hostb tcp_crr --nolog -P 10003 -C 10013 -4 +nsout LAT tcp_crr --nolog -P 10003 -C 10013 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 500 350 + + +tr TCP throughput over IPv6: host to ns +bw - +bw - +bw - +iperf3 BW host ns ::1 100${i}2 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 + +tl TCP RR latency over IPv6: host to ns +lat - +lat - +lat - +nsb tcp_rr --nolog -P 10002 -C 10012 -6 +hout LAT tcp_rr --nolog -P 10002 -C 10012 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv6: host to ns +lat - +lat - +lat - +nsb tcp_crr --nolog -P 10002 -C 10012 -6 +hout LAT tcp_crr --nolog -P 10002 -C 10012 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 1000 700 + + +tr TCP throughput over IPv4: host to ns +bw - +bw - +bw - +iperf3 BW host ns 127.0.0.1 100${i}2 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 15.0 20.0 + +tl TCP RR latency over IPv4: host to ns +lat - +lat - +lat - +nsb tcp_rr --nolog -P 10002 -C 10012 -4 +hout LAT tcp_rr --nolog -P 10002 -C 10012 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv4: host to ns +lat - +lat - +lat - +sleep 1 +nsb tcp_crr --nolog -P 10002 -C 10012 -4 +hout LAT tcp_crr --nolog -P 10002 -C 10012 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 1000 700 + +te + + +test pasta: throughput and latency (connections via tap) + +nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +set THREADS 1 +set STREAMS 2 +set OPTS -Z -P __STREAMS__ -i1 -O__OMIT__ --pacing-timer 100000 + +info Throughput in Gbps, latency in µs, one thread at __FREQ__ GHz, __STREAMS__ streams +report pasta tap_tcp __THREADS__ __FREQ__ + +th MTU 1500B 4000B 16384B 65520B + + +tr TCP throughput over IPv6: ns to host +ns ip link set dev __IFNAME__ mtu 1500 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k +bw __BW__ 0.2 0.4 +ns ip link set dev __IFNAME__ mtu 4000 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M +bw __BW__ 0.3 0.5 +ns ip link set dev __IFNAME__ mtu 16384 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M +bw __BW__ 1.5 2.0 +ns ip link set dev __IFNAME__ mtu 65520 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M +bw __BW__ 2.0 2.5 + +tl TCP RR latency over IPv6: ns to host +lat - +lat - +lat - +hostb tcp_rr --nolog -P 10003 -C 10013 -6 +nsout LAT tcp_rr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv6: ns to host +lat - +lat - +lat - +hostb tcp_crr --nolog -P 10003 -C 10013 -6 +nsout LAT tcp_crr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 1500 500 + + +tr TCP throughput over IPv4: ns to host +ns ip link set dev __IFNAME__ mtu 1500 +iperf3 BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 512k +bw __BW__ 0.2 0.4 +ns ip link set dev __IFNAME__ mtu 4000 +iperf3s BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 1M +bw __BW__ 0.3 0.5 +ns ip link set dev __IFNAME__ mtu 16384 +iperf3 BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M +bw __BW__ 1.5 2.0 +ns ip link set dev __IFNAME__ mtu 65520 +iperf3 BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -w 8M +bw __BW__ 2.0 2.5 + +tl TCP RR latency over IPv4: ns to host +lat - +lat - +lat - +hostb tcp_rr --nolog -P 10003 -C 10013 -4 +nsout LAT tcp_rr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv4: ns to host +lat - +lat - +lat - +hostb tcp_crr --nolog -P 10003 -C 10013 -4 +nsout LAT tcp_crr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 1500 500 + + +tr TCP throughput over IPv6: host to ns +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local' +bw - +bw - +bw - +iperf3 BW host ns __ADDR6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 8.0 10.0 + +tl TCP RR latency over IPv6: host to ns +lat - +lat - +lat - +nsb tcp_rr --nolog -P 10002 -C 10012 -6 +hout LAT tcp_rr --nolog -P 10002 -C 10012 -6 -c -H __ADDR6__ | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv6: host to ns +lat - +lat - +lat - +sleep 1 +nsb tcp_crr --nolog -P 10002 -C 10012 -6 +hout LAT tcp_crr --nolog -P 10002 -C 10012 -6 -c -H __ADDR6__ | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 5000 10000 + + +tr TCP throughput over IPv4: host to ns +nsout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +bw - +bw - +bw - +iperf3 BW host ns __ADDR__ 100${i}2 __THREADS__ __TIME__ __OPTS__ +bw __BW__ 8.0 10.0 + +tl TCP RR latency over IPv4: host to ns +lat - +lat - +lat - +nsb tcp_rr --nolog -P 10002 -C 10012 -4 +hout LAT tcp_rr --nolog -P 10002 -C 10012 -4 -c -H __ADDR__ | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 150 100 + +tl TCP CRR latency over IPv4: host to ns +lat - +lat - +lat - +sleep 1 +nsb tcp_crr --nolog -P 10002 -C 10012 -4 +hout LAT tcp_crr --nolog -P 10002 -C 10012 -4 -c -H __ADDR__ | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 5000 10000 + +te diff --git a/oldtest/perf/pasta_udp b/oldtest/perf/pasta_udp new file mode 100644 index 0000000..7007b6f --- /dev/null +++ b/oldtest/perf/pasta_udp @@ -0,0 +1,219 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/perf/pasta_udp - Check UDP performance in pasta mode +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +htools bc head ip sleep iperf3 udp_rr jq sed +nstools ip sleep iperf3 udp_rr jq sed + +test pasta: throughput and latency (local traffic) + +hout FREQ_PROCFS (echo "scale=1"; sed -n 's/cpu MHz.*: \([0-9]*\)\..*$/(\1+10^2\/2)\/10^3/p' /proc/cpuinfo) | bc -l | head -n1 +hout FREQ_CPUFREQ (echo "scale=1"; printf '( %i + 10^5 / 2 ) / 10^6\n' $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq) ) | bc -l +hout FREQ [ -n "__FREQ_CPUFREQ__" ] && echo __FREQ_CPUFREQ__ || echo __FREQ_PROCFS__ + +set THREADS 1 +set STREAMS 4 +set TIME 10 +set OPTS -u -P __STREAMS__ + +info Throughput in Gbps, latency in µs, one thread at __FREQ__ GHz, __STREAMS__ streams + +report pasta lo_udp 1 __FREQ__ + +th MTU 1500B 4000B 16384B 65535B + + +tr UDP throughput over IPv6: ns to host +ns ip link set dev lo mtu 1500 +iperf3 BW ns host ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 1.0 1.5 +ns ip link set dev lo mtu 4000 +iperf3 BW ns host ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 1.2 1.8 +ns ip link set dev lo mtu 16384 +iperf3 BW ns host ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 10G +bw __BW__ 5.0 6.0 +ns ip link set dev lo mtu 65535 +iperf3 BW ns host ::1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 15G +bw __BW__ 7.0 9.0 + +tl UDP RR latency over IPv6: ns to host +lat - +lat - +lat - +hostb udp_rr --nolog -P 10003 -C 10013 -6 +nsout LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 200 150 + + +tr UDP throughput over IPv4: ns to host +ns ip link set dev lo mtu 1500 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 1.0 1.5 +ns ip link set dev lo mtu 4000 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 1.2 1.8 +ns ip link set dev lo mtu 16384 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 10G +bw __BW__ 5.0 6.0 +ns ip link set dev lo mtu 65535 +iperf3 BW ns host 127.0.0.1 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 15G +bw __BW__ 7.0 9.0 + +tl UDP RR latency over IPv4: ns to host +lat - +lat - +lat - +hostb udp_rr --nolog -P 10003 -C 10013 -4 +nsout LAT udp_rr --nolog -P 10003 -C 10013 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 200 150 + + +tr UDP throughput over IPv6: host to ns +bw - +bw - +bw - +#iperf3c host ::1 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 15G +#iperf3s BW ns 100${i}2 __THREADS__ +iperf3 BW host ns ::1 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 15G +bw __BW__ 7.0 9.0 + +tl UDP RR latency over IPv6: host to ns +lat - +lat - +lat - +nsb udp_rr --nolog -P 10002 -C 10012 -6 +hout LAT udp_rr --nolog -P 10002 -C 10012 -6 -c -H ::1 | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 200 150 + + +tr UDP throughput over IPv4: host to ns +bw - +bw - +bw - +#iperf3c host 127.0.0.1 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 15G +#iperf3s BW ns 100${i}2 __THREADS__ +iperf3 BW host ns 127.0.0.1 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 15G +bw __BW__ 7.0 9.0 + +tl UDP RR latency over IPv4: host to ns +lat - +lat - +lat - +nsb udp_rr --nolog -P 10002 -C 10012 -4 +hout LAT udp_rr --nolog -P 10002 -C 10012 -4 -c -H 127.0.0.1 | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 200 150 + +te + + + +test pasta: throughput and latency (traffic via tap) + +nsout GW ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +nsout GW6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' + +info Throughput in Gbps, latency in µs, one thread at __FREQ__ GHz, __STREAMS__ streams +report pasta tap_udp 1 __FREQ__ + +th MTU 1500B 4000B 16384B 65520B + +tr UDP throughput over IPv6: ns to host +ns ip link set dev __IFNAME__ mtu 1500 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G +bw __BW__ 0.3 0.5 +ns ip link set dev __IFNAME__ mtu 4000 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 0.5 0.8 +ns ip link set dev __IFNAME__ mtu 16384 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G +bw __BW__ 3.0 4.0 +ns ip link set dev __IFNAME__ mtu 65520 +iperf3 BW ns host __GW6__%__IFNAME__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G +bw __BW__ 6.0 7.0 + +tl UDP RR latency over IPv6: ns to host +lat - +lat - +lat - +hostb udp_rr --nolog -P 10003 -C 10013 -6 +nsout LAT udp_rr --nolog -P 10003 -C 10013 -6 -c -H __GW6__%__IFNAME__ | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 200 150 + + +tr UDP throughput over IPv4: ns to host +ns ip link set dev __IFNAME__ mtu 1500 +iperf3 BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 2G +bw __BW__ 0.3 0.5 +ns ip link set dev __IFNAME__ mtu 4000 +iperf3 BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 3G +bw __BW__ 0.5 0.8 +ns ip link set dev __IFNAME__ mtu 16384 +iperf3 BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 4G +bw __BW__ 3.0 4.0 +ns ip link set dev __IFNAME__ mtu 65520 +iperf3 BW ns host __GW__ 100${i}3 __THREADS__ __TIME__ __OPTS__ -b 6G +bw __BW__ 6.0 7.0 + +tl UDP RR latency over IPv4: ns to host +lat - +lat - +lat - +hostb udp_rr --nolog -P 10003 -C 10013 -4 +nsout LAT udp_rr --nolog -P 10003 -C 10013 -4 -c -H __GW__ | sed -n 's/^throughput=\(.*\)/\1/p' +hostw +lat __LAT__ 200 150 + + +tr UDP throughput over IPv6: host to ns +nsout IFNAME ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +nsout ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[] | select(.scope == "global" and .prefixlen == 64).local' +bw - +bw - +bw - +iperf3 BW host ns __ADDR6__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 15G +bw __BW__ 7.0 9.0 + +tl UDP RR latency over IPv6: host to ns +lat - +lat - +lat - +nsb udp_rr --nolog -P 10002 -C 10012 -6 +hout LAT udp_rr --nolog -P 10002 -C 10012 -6 -c -H __ADDR6__ | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 200 150 + + +tr UDP throughput over IPv4: host to ns +nsout ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME__").addr_info[0].local' +bw - +bw - +bw - +iperf3 BW host ns __ADDR__ 100${i}2 __THREADS__ __TIME__ __OPTS__ -b 15G +bw __BW__ 7.0 9.0 + +tl UDP RR latency over IPv4: host to ns +lat - +lat - +lat - +nsb udp_rr --nolog -P 10002 -C 10012 -4 +hout LAT udp_rr --nolog -P 10002 -C 10012 -4 -c -H __ADDR__ | sed -n 's/^throughput=\(.*\)/\1/p' +nsw +lat __LAT__ 200 150 + +te diff --git a/oldtest/prepare-distro-img.sh b/oldtest/prepare-distro-img.sh new file mode 100755 index 0000000..46bc126 --- /dev/null +++ b/oldtest/prepare-distro-img.sh @@ -0,0 +1,18 @@ +#! /bin/sh -e + +IMG="$1" +PASST_FILES="$(echo ../*.c ../*.h ../*.sh ../*.1 ../Makefile ../README.md)" + +virt-edit -a $IMG /lib/systemd/system/serial-getty@.service -e 's/ExecStart=.*/ExecStart=\/sbin\/agetty --autologin root -8 --keep-baud 115200,38400,9600 %I $TERM/g' + +guestfish --rw -a $IMG -i <<EOF +rm-f /usr/lib/systemd/system/cloud-config.service +rm-f /usr/lib/systemd/system/cloud-init.service +rm-f /usr/lib/systemd/system/cloud-init-local.service +rm-f /usr/lib/systemd/system/cloud-final.service +rm-f /etc/init.d/cloud-config +rm-f /etc/init.d/cloud-final +rm-f /etc/init.d/cloud-init +rm-f /etc/init.d/cloud-init-local +copy-in $PASST_FILES /root/ +EOF diff --git a/oldtest/run b/oldtest/run new file mode 100755 index 0000000..75309f6 --- /dev/null +++ b/oldtest/run @@ -0,0 +1,238 @@ +#!/bin/sh -e +# +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/run - Entry point to run test cases and demo +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +# Start an X terminal and capture a video of the test run (also set for ./ci) +CI=${CI:-0} + +# Start an X terminal and show the demo (also set for ./demo) +DEMO=${DEMO:-0} + +# Base path for output files +BASEPATH=${BASEPATH:-"$(pwd)"} + +# Location of log files for test run +LOGDIR=${LOGDIR:-"${BASEPATH}/test_logs"} +LOGFILE=${LOGFILE:-"${LOGDIR}/test.log"} + +# If set, skip typing delays while issuing commands in panes +FAST=${FAST:-1} + +# If set, run passt and pasta with debug options +DEBUG=${DEBUG:-0} + +# If set, run passt and pasta with trace options +TRACE=${TRACE:-0} + +# If set, tell passt and pasta to take packet captures +PCAP=${PCAP:-0} + +COMMIT="$(git log --oneline --no-decorate -1)" + +. lib/util +. lib/context +. lib/setup +. lib/setup_ugly +. lib/term +. lib/perf_report +. lib/layout +. lib/layout_ugly +. lib/test +. lib/video + +# cleanup() - Remove temporary files +cleanup() { + [ ${DEBUG} -eq 1 ] || rm -rf "${STATEBASE}" +} + +# run() - Call setup functions, run tests, handle exit from test session +run() { + mkfifo $STATEBASE/log_pipe + + term + perf_init + [ ${CI} -eq 1 ] && video_start ci + + setup build +# test build/all +# test build/cppcheck +# test build/clang_tidy + teardown build + +# setup pasta +# test pasta/ndp +# test pasta/dhcp +# test pasta/tcp +# test pasta/udp +# test passt/shutdown +# teardown pasta + +# setup pasta_options +# test pasta_options/log_to_file +# teardown pasta_options + +# setup memory +# test memory/passt +# teardown memory + +# setup passt +# test passt/ndp +# test passt/dhcp +# test passt/tcp +# test passt/udp +# test passt/shutdown +# teardown passt + +# VALGRIND=1 +# setup passt_in_ns +# test passt/ndp +# test passt/dhcp +# test passt_in_ns/icmp +# test passt_in_ns/tcp +# test passt_in_ns/udp +# test passt_in_ns/shutdown +# teardown passt_in_ns + +# setup two_guests +# test two_guests/basic +# teardown two_guests + +# VALGRIND=0 +# setup passt_in_ns +# test passt/ndp +# test passt/dhcp +# test perf/passt_tcp +# test perf/passt_udp +# test perf/pasta_tcp +# test perf/pasta_udp +# test passt_in_ns/shutdown +# teardown passt_in_ns + + # TODO: Make those faster by at least pre-installing gcc and make on + # non-x86 images, then re-enable. +skip_distro() { + setup distro + test distro/debian + test distro/fedora + test distro/opensuse + test distro/ubuntu + teardown distro +} + + perf_finish + [ ${CI} -eq 1 ] && video_stop + + log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}" + + pause_continue \ + "Press any key to keep test session open" \ + "Closing in " \ + "Interrupted, press any key to quit" \ + 9 + + return 0 +} + +# run_selected() - Run list of tests, with setup/teardown based on test path +# $@: List of tests +run_selected() { + mkfifo $STATEBASE/log_pipe + + term + VALGRIND=1 + + __setup= + for __test; do + if [ "${__test%%/*}" != "${__setup}" ]; then + [ -n "${__setup}" ] && teardown "${__setup}" + __setup="${__test%%/*}" + setup "${__setup}" + fi + + test "${__test}" + done + teardown "${__setup}" + + log "PASS: ${STATUS_PASS}, FAIL: ${STATUS_FAIL}" + + pause_continue \ + "Press any key to keep test session open" \ + "Closing in " \ + "Interrupted, press any key to quit" \ + 9 + + return 0 +} + +# demo() - Simpler path for demo purposes +demo() { + mkfifo $STATEBASE/log_pipe + + FAST=0 + + term_demo + + layout_demo_passt + video_start demo_passt + test demo/passt + video_stop + teardown demo_passt + + layout_demo_pasta + video_start demo_pasta + test demo/pasta + video_stop + teardown demo_pasta + + layout_demo_podman + video_start demo_podman + test demo/podman + video_stop + teardown_demo_podman + + return 0 +} + +[ "$(basename "${0}")" = "ci" ] && CI=1 +[ "$(basename "${0}")" = "run_demo" ] && DEMO=1 + +if [ "${1}" = "from_term" ]; then + shift + + exec > ${LOGDIR}/script.log 2>&1 + [ ${DEBUG} -eq 1 ] && set -x + cd .. + if [ ${DEMO} -eq 1 ]; then + demo + elif [ -n "${1}" ]; then + run_selected ${*} + else + run + fi + tmux kill-session -t passt_test + exit +else + rm -rf "${LOGDIR}" + mkdir -p "${LOGDIR}" + :> "${LOGFILE}" + STATEBASE="$(mktemp -d --tmpdir passt-tests-XXXXXX)" + trap "cleanup" EXIT + run_term ${*} +fi + +[ ${DEMO} -eq 1 ] && exit 0 + +tail -n1 ${LOGFILE} +echo "Log at ${LOGFILE}" +exit $(tail -n1 ${LOGFILE} | sed -n 's/.*FAIL: \(.*\)$/\1/p') diff --git a/oldtest/run_demo b/oldtest/run_demo new file mode 120000 index 0000000..e5224d5 --- /dev/null +++ b/oldtest/run_demo @@ -0,0 +1 @@ +run \ No newline at end of file diff --git a/oldtest/two_guests/basic b/oldtest/two_guests/basic new file mode 100644 index 0000000..09fbd3e --- /dev/null +++ b/oldtest/two_guests/basic @@ -0,0 +1,80 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# PASST - Plug A Simple Socket Transport +# for qemu/UNIX domain socket mode +# +# PASTA - Pack A Subtle Tap Abstraction +# for network namespace/tap device mode +# +# test/two_guests/basic - Check basic functionality with two guests +# +# Copyright (c) 2021 Red Hat GmbH +# Author: Stefano Brivio <sbrivio(a)redhat.com> + +g1tools ip jq dhclient socat cat +g2tools ip jq dhclient socat cat +htools ip jq + +test Interface names +g1out IFNAME1 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +g2out IFNAME2 ip -j link show | jq -rM '.[] | select(.link_type == "ether").ifname' +hout HOST_IFNAME ip -j -4 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +hout HOST_IFNAME6 ip -j -6 route show|jq -rM '[.[] | select(.dst == "default").dev] | .[0]' +check [ -n "__IFNAME1__" ] +check [ -n "__IFNAME2__" ] + +test DHCP: addresses +guest1 ip link set dev __IFNAME1__ up +guest1 /sbin/dhclient -4 __IFNAME1__ +guest2 ip link set dev __IFNAME2__ up +guest2 /sbin/dhclient -4 __IFNAME2__ +g1out ADDR1 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[0].local' +g2out ADDR2 ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__IFNAME2__").addr_info[0].local' +hout HOST_ADDR ip -j -4 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME__").addr_info[0].local' +check [ "__ADDR1__" = "__HOST_ADDR__" ] +check [ "__ADDR2__" = "__HOST_ADDR__" ] + +test DHCPv6: addresses +# Link is up now, wait for DAD to complete +sleep 2 +guest1 /sbin/dhclient -6 __IFNAME1__ +guest2 /sbin/dhclient -6 __IFNAME2__ +g1out ADDR1_6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME1__").addr_info[] | select(.prefixlen == 128).local' +g2out ADDR2_6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__IFNAME2__").addr_info[] | select(.prefixlen == 128).local' +hout HOST_ADDR6 ip -j -6 addr show|jq -rM '.[] | select(.ifname == "__HOST_IFNAME6__").addr_info[] | select(.scope == "global").local' +check [ "__ADDR1_6__" = "__HOST_ADDR6__" ] +check [ "__ADDR2_6__" = "__HOST_ADDR6__" ] + +test TCP/IPv4: guest 1 > guest 2 +g1out GW1 ip -j -4 route show|jq -rM '.[] | select(.dst == "default").gateway' +guest2b socat -u TCP4-LISTEN:10004 OPEN:msg,create,trunc +guest1 echo "Hello_from_guest_1" | socat -u STDIN TCP4:__GW1__:10004 +guest2w +sleep 1 +g2out MSG2 cat msg +check [ "__MSG2__" = "Hello_from_guest_1" ] + +test TCP/IPv6: guest 2 > guest 1 +g2out GW2_6 ip -j -6 route show|jq -rM '.[] | select(.dst == "default").gateway' +guest1b socat -u TCP6-LISTEN:10001 OPEN:msg,create,trunc +guest2 echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__GW2_6__%__IFNAME2__]:10001 +guest1w +sleep 1 +g1out MSG1 cat msg +check [ "__MSG1__" = "Hello_from_guest_2" ] + +test UDP/IPv4: guest 1 > guest 2 +guest2b socat -u TCP4-LISTEN:10004 OPEN:msg,create,trunc +guest1 echo "Hello_from_guest_1" | socat -u STDIN TCP4:__GW1__:10004 +guest2w +sleep 1 +g2out MSG2 cat msg +check [ "__MSG2__" = "Hello_from_guest_1" ] + +test UDP/IPv6: guest 2 > guest 1 +guest1b socat -u TCP6-LISTEN:10001 OPEN:msg,create,trunc +guest2 echo "Hello_from_guest_2" | socat -u STDIN TCP6:[__GW2_6__%__IFNAME2__]:10001 +guest1w +sleep 1 +g1out MSG1 cat msg +check [ "__MSG1__" = "Hello_from_guest_2" ] diff --git a/oldtest/valgrind.supp b/oldtest/valgrind.supp new file mode 100644 index 0000000..1228056 --- /dev/null +++ b/oldtest/valgrind.supp @@ -0,0 +1,9 @@ +# tcp_sock_consume() calls recv() with MSG_TRUNC and no buffer to discard data +{ + passt_recv_MSG_TRUNC_into_NULL_buffer + Memcheck:Param + socketcall.recvfrom(buf) + fun:recv + ... + fun:tcp_sock_consume* +} -- 2.40.1