diff --git a/01-ci/README.md b/01-ci/README.md index aac689d5..a81ede2c 100644 --- a/01-ci/README.md +++ b/01-ci/README.md @@ -39,3 +39,13 @@ Run all unittests at once on an iotlab-m3 node. ### Result All tests run successfully. (Output says: "OK (xyz tests)" + +Task #05 - Unittests on native64 +================================ +### Description + +Run all unittests at once in native64. + +### Result + +All tests run successfully. (Output says: "OK (xyz tests)" diff --git a/01-ci/test_spec01.py b/01-ci/test_spec01.py index a287f1ef..2f6c6989 100644 --- a/01-ci/test_spec01.py +++ b/01-ci/test_spec01.py @@ -3,7 +3,6 @@ import pytest - APP = 'tests/unittests' TESTS_SUITES = sorted( d.name @@ -47,3 +46,8 @@ def test_task03(nodes, log_nodes, riotbase, test_suite): @pytest.mark.parametrize('nodes', [pytest.param(['iotlab-m3'])], indirect=['nodes']) def test_task04(nodes, log_nodes, riotbase): run_unittests('all', nodes, log_nodes, os.path.join(riotbase, APP)) + +# nodes passed to nodes fixture +@pytest.mark.parametrize('nodes', [pytest.param(['native64'])], indirect=['nodes']) +def test_task05(nodes, log_nodes, riotbase): + run_unittests('all', nodes, log_nodes, os.path.join(riotbase, APP)) diff --git a/02-tests/README.md b/02-tests/README.md index d27d7fdf..908e1b47 100644 --- a/02-tests/README.md +++ b/02-tests/README.md @@ -40,3 +40,13 @@ Perform a subset of tests (!= subset from Task #02) on samr21-xpro node. ### Result All tests succeed. + +Task #04 - Subset of tests on native64 +======================================= +### Description + +Perform a subset of tests on native64 and check their output. + +### Result + +All tests succeed. diff --git a/03-single-hop-ipv6-icmp/README.md b/03-single-hop-ipv6-icmp/README.md index 4d320b6b..be304742 100644 --- a/03-single-hop-ipv6-icmp/README.md +++ b/03-single-hop-ipv6-icmp/README.md @@ -97,3 +97,21 @@ both the fragmented and reassembled requests/replies). ### Result <1% packets lost on the pinging node. + +Task #07 - ICMPv6 stress test on native64 (1 hour) +================================================ +### Description + +Rapid ICMPv6 echo request/reply exchange from 10 host ping applications (same +host, e.g. Linux host) simultaneously to one native64 node for 1 hour. +* Stack configuration: IPv6 (default) +* Count: Infinity +* Interval: 0ms +* Payload: 1452B +* Destination Address: Link local unicast (fe80::.../64) + +### Result + +All nodes are still running, reachable, and the packet buffer is empty 10 +seconds after completions (use module `shell_cmd_gnrc_pktbuf`). +Packet loss is irrelevant in this stress test. diff --git a/03-single-hop-ipv6-icmp/test_spec03.py b/03-single-hop-ipv6-icmp/test_spec03.py index 5664dbdf..c046e1c5 100644 --- a/03-single-hop-ipv6-icmp/test_spec03.py +++ b/03-single-hop-ipv6-icmp/test_spec03.py @@ -3,14 +3,11 @@ import pexpect import pexpect.replwrap import pytest - from riotctrl_shell.gnrc import GNRCICMPv6Echo, GNRCPktbufStats from riotctrl_shell.netif import Ifconfig - -from testutils.asyncio import wait_for_futures, timeout_futures -from testutils.native import bridged, bridge, get_ping_cmd, interface_exists -from testutils.shell import ping6, lladdr, check_pktbuf - +from testutils.asyncio import timeout_futures, wait_for_futures +from testutils.native import bridge, bridged, get_ping_cmd, interface_exists +from testutils.shell import check_pktbuf, lladdr, ping6 APP = 'tests/net/gnrc_udp' TASK05_NODES = 11 @@ -163,3 +160,40 @@ def test_task06(riot_ctrl): assert res['stats']['packet_loss'] < 1 check_pktbuf(pinged, pinger) + +@pytest.mark.skipif(not interface_exists("tap0"), reason="tap0 does not exist") +@pytest.mark.sudo_only # ping -f requires root +@pytest.mark.parametrize( + 'nodes', [pytest.param(['native64'] * TASK05_NODES)], indirect=['nodes'] +) +def test_task07(riot_ctrl, log_nodes): + node = riot_ctrl(0, APP, Shell, port='tap0') + pingers = [pexpect.replwrap.bash() for _ in range(10)] + + _, pinged_addr = lladdr(node.ifconfig_list()) + assert pinged_addr.startswith("fe80::") + iface = bridge('tap0') + pinged_addr += f"%{iface}" + ping_cmd = get_ping_cmd() + + futures = [] + try: + for pinger in pingers: + if log_nodes: + pinger.child.logfile = sys.stdout + out = pinger.run_command( + f"{ping_cmd} -f -s 1452 {pinged_addr}" + # pipe to /dev/null because output can go + # into MiB of data ;-) + " 2>&1 > /dev/null", + async_=True, + timeout=60 * 60, + ) + futures.append(out) + timeout_futures(futures, 60 * 60) + finally: + for pinger in pingers: + # interrupt prevailing `ping6`s + pinger.child.sendintr() + + check_pktbuf(node) diff --git a/05-single-hop-route/README.md b/05-single-hop-route/README.md index 038b1507..74ee76fe 100644 --- a/05-single-hop-route/README.md +++ b/05-single-hop-route/README.md @@ -43,7 +43,29 @@ advertisements for this task). <10% packets lost on the pinging node. No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). -Task #03 - ICMPv6 echo unicast addresess on native (specific route) +Task #03 - ICMPv6 echo unicast addresess on native64 (default route) +==================================================================== +### Description + +ICMPv6 echo request/reply exchange between two native64 nodes both with global +unicast addresses. A static default route has to be used +(`nib route add :: `, also remember to deactivate router +advertisements on both ends *beforehand* with `ifconfig -rtr_adv`, +otherwise default routes and address resolution will be auto-configured). +* Stack configuration: IPv6 (default) +* Count: 100 +* Interval: 10ms +* Payload: 1kB +* Sender Address: beef::2/64 +* Destination Address: beef::1/64 + +### Result + +<1% packets lost on the pinging node. +No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). + + +Task #04 - ICMPv6 echo unicast addresess on native (specific route) =================================================================== ### Description @@ -64,7 +86,7 @@ otherwise default routes and address resolution will be auto-configured ). <1% packets lost on the pinging node. No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). -Task #04 - ICMPv6 echo unicast addresess on iotlab-m3 (static route) +Task #05 - ICMPv6 echo unicast addresess on iotlab-m3 (static route) ==================================================================== ### Description diff --git a/05-single-hop-route/test_spec05.py b/05-single-hop-route/test_spec05.py index 3211afc6..04b686cb 100644 --- a/05-single-hop-route/test_spec05.py +++ b/05-single-hop-route/test_spec05.py @@ -1,11 +1,8 @@ import pytest - from riotctrl_shell.gnrc import GNRCICMPv6Echo, GNRCIPv6NIB, GNRCPktbufStats from riotctrl_shell.netif import Ifconfig - from testutils.native import bridged -from testutils.shell import ping6, lladdr, check_pktbuf - +from testutils.shell import check_pktbuf, lladdr, ping6 APP = 'examples/gnrc_networking' pytestmark = pytest.mark.rc_only() @@ -66,12 +63,38 @@ def test_task02(riot_ctrl): check_pktbuf(pinged, pinger) +@pytest.mark.skipif(not bridged(["tap0", "tap1"]), reason="tap0 and tap1 not bridged") +# nodes passed to riot_ctrl fixture +@pytest.mark.parametrize( + 'nodes', [pytest.param(['native64', 'native64'])], indirect=['nodes'] +) +def test_task03(riot_ctrl): + pinger, pinged = ( + riot_ctrl(0, APP, Shell, modules=["shell_cmd_gnrc_pktbuf"], port="tap0"), + riot_ctrl(1, APP, Shell, modules=["shell_cmd_gnrc_pktbuf"], port="tap1"), + ) + + pinged_netif, pinged_lladdr = lladdr(pinged.ifconfig_list()) + pinged.ifconfig_flag(pinged_netif, "rtr_adv", False) + pinged.ifconfig_add(pinged_netif, "beef::1/64") + pinger_netif, pinger_lladdr = lladdr(pinger.ifconfig_list()) + pinger.ifconfig_flag(pinger_netif, "rtr_adv", False) + pinger.ifconfig_add(pinger_netif, "beef::2/64") + + pinged.nib_route_add(pinged_netif, "::", pinger_lladdr) + pinger.nib_route_add(pinger_netif, "::", pinged_lladdr) + + res = ping6(pinger, "beef::1", count=100, interval=10, packet_size=1024) + assert res['stats']['packet_loss'] < 1 + + check_pktbuf(pinged, pinger) + @pytest.mark.skipif(not bridged(["tap0", "tap1"]), reason="tap0 and tap1 not bridged") @pytest.mark.parametrize( 'nodes', [pytest.param(['native', 'native'])], indirect=['nodes'] ) -def test_task03(riot_ctrl): +def test_task04(riot_ctrl): pinger, pinged = ( riot_ctrl(0, APP, Shell, modules=["shell_cmd_gnrc_pktbuf"], port="tap0"), riot_ctrl(1, APP, Shell, modules=["shell_cmd_gnrc_pktbuf"], port="tap1"), @@ -97,7 +120,7 @@ def test_task03(riot_ctrl): @pytest.mark.parametrize( 'nodes', [pytest.param(['native', 'native'])], indirect=['nodes'] ) -def test_task04(riot_ctrl): +def test_task05(riot_ctrl): pinger, pinged = ( riot_ctrl(0, APP, Shell, modules=["shell_cmd_gnrc_pktbuf"], port="tap0"), riot_ctrl(1, APP, Shell, modules=["shell_cmd_gnrc_pktbuf"], port="tap1"), diff --git a/06-single-hop-udp/README.md b/06-single-hop-udp/README.md index 8312867b..11bb2051 100644 --- a/06-single-hop-udp/README.md +++ b/06-single-hop-udp/README.md @@ -71,7 +71,24 @@ Sending UDP from one iotlab-m3 node to a non-existent neighbor. No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). Packet loss is irrelevant for this test. -Task #05 - Empty UDP on native +Task #05 - UDP on native64 (non-existent neighbor) +================================================== +### Description + +Sending UDP from one native64 node to a non-existent neighbor. +* Stack configuration: IPv6 (default) +* Count: 1000 +* Interval: 0us +* Port: 1337 +* Payload: 8B +* Destination Address: Non-existent link local unicast (e.g fe80::bd:b7ec) + +### Result + +No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). +Packet loss is irrelevant for this test. + +Task #06 - Empty UDP on native ============================== ### Description @@ -88,7 +105,7 @@ Sending UDP between two native nodes. <=10% packets lost on the receiving node. No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). -Task #06 - Empty UDP on iotlab-m3 +Task #07 - Empty UDP on iotlab-m3 ================================= ### Description @@ -105,3 +122,22 @@ Sending UDP between two iotlab-m3 nodes. <=10% packets lost on the receiving node. No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). + +Task #10 - Empty UDP on native64 +================================ +### Description + +Sending UDP between two native64 nodes. +* Stack configuration: IPv6 (default) +* Count: 10 +* Interval: 100ms +* Port: 1337 +* Payload: 0B +* Destination Address: Link local unicast (fe80::.../64) + +### Result + +<=10% packets lost on the receiving node. +No leaks in the packet buffer (check with `shell_cmd_gnrc_pktbuf`). + + diff --git a/06-single-hop-udp/test_spec06.py b/06-single-hop-udp/test_spec06.py index d154040f..9a8522ae 100644 --- a/06-single-hop-udp/test_spec06.py +++ b/06-single-hop-udp/test_spec06.py @@ -1,11 +1,8 @@ import pytest - from riotctrl_shell.gnrc import GNRCPktbufStats from riotctrl_shell.netif import Ifconfig - from testutils.native import bridged -from testutils.shell import lladdr, GNRCUDP, check_pktbuf - +from testutils.shell import GNRCUDP, check_pktbuf, lladdr APP = 'tests/net/gnrc_udp' pytestmark = pytest.mark.rc_only() @@ -92,12 +89,18 @@ def test_task04(riot_ctrl): node.udp_client_send("fe80::db:b7ec", 1337, count=1000, delay_ms=0, payload=8) check_pktbuf(node) +@pytest.mark.skipif(not bridged(["tap0"]), reason="tap0 not bridged") +@pytest.mark.parametrize('nodes', [pytest.param(['native64'])], indirect=['nodes']) +def test_task05(riot_ctrl): + node = riot_ctrl(0, APP, Shell, port="tap0") + node.udp_client_send("fe80::db:b7ec", 1337, count=1000, delay_ms=0, payload=8) + check_pktbuf(node) @pytest.mark.skipif(not bridged(["tap0", "tap1"]), reason="tap0 and tap1 not bridged") @pytest.mark.parametrize( 'nodes', [pytest.param(['native', 'native'])], indirect=['nodes'] ) -def test_task05(riot_ctrl): +def test_task06(riot_ctrl): nodes = ( riot_ctrl(0, APP, Shell, port="tap0"), riot_ctrl(1, APP, Shell, port="tap1"), @@ -122,7 +125,7 @@ def test_task05(riot_ctrl): @pytest.mark.parametrize( 'nodes', [pytest.param(['iotlab-m3', 'iotlab-m3'])], indirect=['nodes'] ) -def test_task06(riot_ctrl): +def test_task07(riot_ctrl): nodes = ( riot_ctrl(0, APP, Shell), riot_ctrl(1, APP, Shell), @@ -143,3 +146,26 @@ def test_task06(riot_ctrl): server.udp_server_stop() check_pktbuf(*nodes) + +@pytest.mark.skipif(not bridged(["tap0", "tap1"]), reason="tap0 and tap1 not bridged") +@pytest.mark.parametrize( + 'nodes', [pytest.param(['native64', 'native64'])], indirect=['nodes'] +) +def test_task08(riot_ctrl): + nodes = ( + riot_ctrl(0, APP, Shell, port="tap0"), + riot_ctrl(1, APP, Shell, port="tap1"), + ) + + for client, server in zip(nodes, reversed(nodes)): + _, server_addr = lladdr(server.ifconfig_list()) + assert server_addr.startswith("fe80::") + + server.udp_server_start(1337) + + client.udp_client_send(server_addr, 1337, count=100, delay_ms=100, payload=0) + packet_loss = server.udp_server_check_output(count=100, delay_ms=100) + assert packet_loss <= 10 + server.udp_server_stop() + + check_pktbuf(*nodes) diff --git a/08-interop/README.md b/08-interop/README.md index 4d5fd69b..676150f9 100644 --- a/08-interop/README.md +++ b/08-interop/README.md @@ -7,14 +7,21 @@ Task #01 - ICMPv6 echo between native and Linux ICMPv6 echo request/reply exchange between a RIOT native node and the Linux host. -Task #02 - ICMPv6 echo between iotlab-m3 and Linux with 6LowPAN +Task #02 - ICMPv6 echo between native64 and Linux +=============================================== +### Description + +ICMPv6 echo request/reply exchange between a RIOT native64 node and the Linux +host. + +Task #03 - ICMPv6 echo between iotlab-m3 and Linux with 6LowPAN =============================================================== ### Description ICMPv6 echo request/reply exchange between an iotlab-m3 node running RIOT and a Raspberry Pi running Linux with 6LoWPAN support. -Task #03 - ICMPv6 echo between RIOT and Contiki-NG +Task #04 - ICMPv6 echo between RIOT and Contiki-NG ===================================================== ### Description @@ -143,7 +150,7 @@ ping fe80::f6ce:36c6:d8d1:e340 Every packet should be echoed by the target node and printed to the console. -Task #04 - ICMPv6 echo between iotlab-m3 and Internet host through Linux with 6LowPAN +Task #05 - ICMPv6 echo between iotlab-m3 and Internet host through Linux with 6LowPAN ===================================================================================== ### Description @@ -155,7 +162,7 @@ Since Linux' 6Lo implementation doesn't support 6Lo-ND DAD yet, the RIOT image needs to be compiled with `CFLAGS += -DGNRC_IPV6_NIB_CONF_SLAAC=1` to be able to fall back to classic SLAAC + DAD. -Task #05 - ICMPv6 echo between iotlab-m3 and Internet host through RIOT border router +Task #06 - ICMPv6 echo between iotlab-m3 and Internet host through RIOT border router ===================================================================================== ### Description @@ -163,7 +170,7 @@ ICMPv6 echo request/reply exchange between an iotlab-m3 node running RIOT and an Linux Internet host using a RIOT node as border router. Routes are configured statically. -Task #06 - UDP between iotlab-m3 and Internet host through RIOT border router +Task #07 - UDP between iotlab-m3 and Internet host through RIOT border router ============================================================================= ### Description @@ -171,7 +178,7 @@ UDP over IPv6 packet exchange (payload length 8) between an iotlab-m3 node runni RIOT with GNRC and an Linux Internet host using a RIOT node as border router. Routes are configured statically. -Task #07 - UDP between iotlab-m3 and Internet host through RIOT border router (200b payload) +Task #08 - UDP between iotlab-m3 and Internet host through RIOT border router (200b payload) ============================================================================================ ### Description @@ -179,7 +186,7 @@ UDP over IPv6 packet exchange (payload length 200) between an iotlab-m3 node running RIOT with GNRC and an Linux Internet host using a RIOT node as border router. Routes are configured statically. -Task #08 - UDP between GNRC and lwIP on iotlab-m3 +Task #09 - UDP between GNRC and lwIP on iotlab-m3 ================================================= ### Description diff --git a/08-interop/test_spec08.py b/08-interop/test_spec08.py index 835ade5f..0d1b6483 100755 --- a/08-interop/test_spec08.py +++ b/08-interop/test_spec08.py @@ -2,17 +2,14 @@ import re import sys - import pexpect.replwrap import pytest - import riotctrl.shell from riotctrl_shell.gnrc import GNRCICMPv6Echo from riotctrl_shell.netif import Ifconfig - -from testutils.native import bridge, get_link_local, get_ping_cmd, interface_exists -from testutils.shell import lladdr, ping6, GNRCUDP - +from testutils.native import (bridge, get_link_local, get_ping_cmd, + interface_exists) +from testutils.shell import GNRCUDP, lladdr, ping6 GNRC_APP = 'examples/gnrc_networking' LWIP_APP = 'tests/pkg/lwip' @@ -50,6 +47,34 @@ def test_task01(riot_ctrl, log_nodes): ) assert res["stats"]["packet_loss"] < 1 +@pytest.mark.skipif(not interface_exists("tap0"), reason="tap0 does not exist") +# nodes passed to riot_ctrl fixture +@pytest.mark.parametrize('nodes', [pytest.param(['native64'])], indirect=['nodes']) +def test_task02(riot_ctrl, log_nodes): + node = riot_ctrl(0, GNRC_APP, Shell, port='tap0') + linux = pexpect.replwrap.bash() + + node_iface, node_addr = lladdr(node.ifconfig_list()) + assert node_addr.startswith("fe80::") + linux_iface = bridge('tap0') + linux_addr = get_link_local(linux_iface) + assert linux_addr.startswith("fe80::") + ping_cmd = get_ping_cmd() + + if log_nodes: + linux.child.logfile = sys.stdout + out = linux.run_command( + f"{ping_cmd} -c 20 -i .5 {node_addr}%{linux_iface}", timeout=20 + ) + m = re.search(r"\b(\d+)% packet loss", out) + assert m is not None + assert int(m.group(1)) < 1 + res = ping6( + node, f"{linux_addr}%{node_iface}", count=20, interval=100, packet_size=8 + ) + assert res["stats"]["packet_loss"] < 1 + + @pytest.mark.flaky(reruns=1, reruns_delay=30) @pytest.mark.iotlab_creds