diff --git a/.gitignore b/.gitignore index 3501099..fd68477 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .dir-locals.el .flake8rc *~ +*.csv *.decode *.log *.pcap @@ -28,3 +29,7 @@ __pycache__/ /venv /sandbox/* !/sandbox/*.c +/future/ +/old/ +/results/ +/FlameGraph/ diff --git a/Makefile b/Makefile index 5815de2..90a32c4 100644 --- a/Makefile +++ b/Makefile @@ -107,12 +107,15 @@ $(PERFFILE): PERF := ../output-buildroot/target/usr/bin/perf -/tmp/out.perf: $(PERFFILE) +FlameGraph: + git clone https://github.com/brendangregg/FlameGraph + +/tmp/out.perf: FlameGraph $(PERFFILE) (cd FlameGraph && $(PERF) script --vmlinux ../output-linux/vmlinux -i $< > /tmp/out.perf) -/tmp/out.perf-folded: /tmp/out.perf +/tmp/out.perf-folded: FlameGraph /tmp/out.perf (cd FlameGraph && cat /tmp/out.perf | ./stackcollapse-perf.pl > /tmp/out.perf-folded) -flame.svg: /tmp/out.perf-folded +flame.svg: FlameGraph /tmp/out.perf-folded (cd FlameGraph && ./flamegraph.pl --height=16 --fontsize=6 $< > ../$@) diff --git a/scripts/feat2str.py b/scripts/feat2str.py new file mode 100644 index 0000000..b3d2a95 --- /dev/null +++ b/scripts/feat2str.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# +# September 14 2023, Christian Hopps +# +# Copyright (c) 2023, LabN Consulting, L.L.C. +# +"Convert an integer to linux kernel features flags" +import argparse +import logging + +flag_strings = [ + "SG_BIT", + "IP_CSUM_BIT", + "__UNUSED_1", + "HW_CSUM_BIT", + "IPV6_CSUM_BIT", + "HIGHDMA_BIT", + "FRAGLIST_BIT", + "HW_VLAN_CTAG_TX_BIT", + "HW_VLAN_CTAG_RX_BIT", + "HW_VLAN_CTAG_FILTER_BIT", + "VLAN_CHALLENGED_BIT", + "GSO_BIT", + "LLTX_BIT", + "NETNS_LOCAL_BIT", + "GRO_BIT", + "LRO_BIT", + "TSO_BIT", + "GSO_ROBUST_BIT", + "TSO_ECN_BIT", + "TSO_MANGLEID_BIT", + "TSO6_BIT", + "FSO_BIT", + "GSO_GRE_BIT", + "GSO_GRE_CSUM_BIT", + "GSO_IPXIP4_BIT", + "GSO_IPXIP6_BIT", + "GSO_UDP_TUNNEL_BIT", + "GSO_UDP_TUNNEL_CSUM_BIT", + "GSO_PARTIAL_BIT", + "GSO_TUNNEL_REMCSUM_BIT", + "GSO_SCTP_BIT", + "GSO_ESP_BIT", + "GSO_UDP_BIT", + "GSO_UDP_L4_BIT", + "GSO_FRAGLIST_BIT", + "FCOE_CRC_BIT", + "SCTP_CRC_BIT", + "FCOE_MTU_BIT", + "NTUPLE_BIT", + "RXHASH_BIT", + "RXCSUM_BIT", + "NOCACHE_COPY_BIT", + "LOOPBACK_BIT", + "RXFCS_BIT", + "RXALL_BIT", + "HW_VLAN_STAG_TX_BIT", + "HW_VLAN_STAG_RX_BIT", + "HW_VLAN_STAG_FILTER_BIT", + "HW_L2FW_DOFFLOAD_BIT", + "HW_TC_BIT", + "HW_ESP_BIT", + "HW_ESP_TX_CSUM_BIT", + "RX_UDP_TUNNEL_PORT_BIT", + "HW_TLS_TX_BIT", + "HW_TLS_RX_BIT", + "GRO_HW_BIT", + "HW_TLS_RECORD_BIT", + "GRO_FRAGLIST_BIT", + "HW_MACSEC_BIT", + "GRO_UDP_FWD_BIT", + "HW_HSR_TAG_INS_BIT", + "HW_HSR_TAG_RM_BIT", + "HW_HSR_FWD_BIT", + "HW_HSR_DUP_BIT", +] + + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--verbose", action="store_true", help='Be verbose') + parser.add_argument("flags", help='integer to convert to flag strings') + args = parser.parse_args() + + level = logging.DEBUG if args.verbose else logging.INFO + logging.basicConfig(level=level, format="%(asctime)s %(levelname)s: %(message)s") + + flags = int(args.flags, 16) + set_flags = [] + for i, flag in enumerate(flag_strings): + if (1 << i) & flags: + set_flags.append(flag) + + print(set_flags) + + +if __name__ == "__main__": + main() diff --git a/tests-trex/stress/test_find_max.py b/tests-trex/stress/test_find_max.py new file mode 100644 index 0000000..c09315d --- /dev/null +++ b/tests-trex/stress/test_find_max.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# +# September 16 2023, Christian Hopps +# +# Copyright (c) 2023, LabN Consulting, L.L.C. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; see the file COPYING; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +"Find max rate using physical ethernet interfaces." +import logging +import os + +import pytest +from munet.testing.fixtures import _unet_impl +from stress import _network_up, _test_policy_imix, _test_policy_small_pkt + +# All tests are coroutines +pytestmark = pytest.mark.asyncio + + +SRCDIR = os.path.dirname(os.path.abspath(__file__)) + +# 192.168.0.0/24 +# --+--------------------+------ mgmt0 -------+ +# | .1 | .2 | .3 +# +----+ +----+ +----+ +# |trex| ---- p2p ---- | r1 | --- net1 --- | r2 | +# | | .1 .2 +----+ .2 .3 +----+ +# | | 1l.0.0.0/24 10.0.1.0/24 | .3 +# | | | +# | | ---- p2p ----------------------------+ +# | | .1 12.0.0.0/24 +# +----+ + + +@pytest.fixture(scope="module", autouse=True) +async def checkrun(pytestconfig): + if not pytestconfig.option.enable_physical: + pytest.skip( + "Physical interface test being skipped, pass --enable-physical", + allow_module_level=True, + ) + + +@pytest.fixture(scope="module", name="unet") +async def _unet(rundir_module, pytestconfig): + async for x in _unet_impl( + rundir_module, + pytestconfig, + param="munet_phy", + unshare=True, + top_level_pidns=False, + ): + yield x + + +@pytest.fixture(scope="module", autouse=True) +async def network_up(unet): + await _network_up(unet) + + +async def test_net_up(unet): + r1 = unet.hosts["r1"] + r2 = unet.hosts["r2"] + # r1 (qemu side) pings r2 (qemu side) + logging.debug(r1.conrepl.cmd_raises("ping -w1 -i.2 -c1 10.0.1.3")) + + # r2 (qemu side) pings r1 (qemu side) + logging.debug(r2.conrepl.cmd_raises("ping -w1 -i.2 -c1 10.0.1.2")) + + # Unfortunately TREX with physical interfaces does not reply to PINGs + # so we cannot ping test those ports + + +async def test_policy_small_pkt(unet, pytestconfig): + try: + await _test_policy_small_pkt(unet, pytestconfig, default_rate="100M") + except Exception as ex: + breakpoint() + print("Got excpetion: ", ex) + else: + print("Clean run") + + +async def test_policy_imix(unet, pytestconfig): + try: + await _test_policy_imix(unet, pytestconfig, default_rate="1G") + except Exception as ex: + breakpoint() + print("Got excpetion: ", ex) + else: + print("Clean run") diff --git a/tests/ike/test_swan2.py b/tests/ike/test_swan2.py new file mode 100644 index 0000000..6001496 --- /dev/null +++ b/tests/ike/test_swan2.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 eval: (blacken-mode 1) -*- +# +# August 15 2023, Christian Hopps +# +# Copyright (c) 2023, LabN Consulting, L.L.C. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; see the file COPYING; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# +"Test IKE using strongswan" +import logging +import os +from pathlib import Path + +import pytest +from common.config import _network_up +from common.tests import _test_net_up +from getikeconf import get_ike_config + +srcdir = Path(__file__).absolute().parent +etcdir = srcdir / "etc" + + +@pytest.fixture(scope="module", autouse=True) +async def network_up(unet, pytestconfig): + ipv6 = pytestconfig.getoption("--enable-ipv6", False) + + # # Copy new configs then reload swanctl + # logging.info("copying strongswan config files") + # for rname, confargs in (("r1", (2, 3)), ("r2", (3, 2))): + # rn = unet.hosts[rname] + # args = "-q -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null" + # args += f" -i {srcdir}/../../root-key" + # unet.cmd_raises(f"scp {args} -pr {etcdir}/* root@{rname}:/etc") + + logging.info("copying strongswan config files") + for rname, confargs in (("r1", (2, 3)), ("r2", (3, 2))): + logging.info("Configuring IKE on %s", rname) + rn = unet.hosts[rname] + conf = get_ike_config(*confargs) + rn.cmd_raises("cat > /etc/swanctl/conf.d/tunnel.conf", stdin=conf) + o = rn.cmd_raises("swanctl --load-all") + logging.info("loaded: %s", o) + + await _network_up(unet, ipv6=ipv6) + + logging.info("Running swanctl on r1") + r1 = unet.hosts["r1"] + o = r1.cmd_raises("swanctl --initiate --child linux-1") + logging.info("swantctl returns: %s", o) + + +async def test_net_up(unet): + await _test_net_up(unet) + + +# async def test_strongswan(unet, astepf, pytestconfig): +# pass