diff --git a/repos/os/run/nic_bridge_stress.run b/repos/os/run/nic_bridge_stress.run
new file mode 100644
index 0000000000..b7e6714526
--- /dev/null
+++ b/repos/os/run/nic_bridge_stress.run
@@ -0,0 +1,2 @@
+set type "nic_bridge"
+source ${genode_dir}/repos/os/run/nic_stress.inc
diff --git a/repos/os/run/nic_router_stress.run b/repos/os/run/nic_router_stress.run
new file mode 100644
index 0000000000..0a5cbc371b
--- /dev/null
+++ b/repos/os/run/nic_router_stress.run
@@ -0,0 +1,2 @@
+set type "nic_router"
+source ${genode_dir}/repos/os/run/nic_stress.inc
diff --git a/repos/os/run/nic_stress.inc b/repos/os/run/nic_stress.inc
new file mode 100644
index 0000000000..fe47cbd38d
--- /dev/null
+++ b/repos/os/run/nic_stress.inc
@@ -0,0 +1,167 @@
+append build_components {
+ core init timer
+ server/nic_router
+ test/nic_stress
+}
+
+append_if [string equal $type "nic_bridge"] build_components { server/nic_bridge }
+
+proc exit_support {} {
+ if {[have_spec fiasco]} {
+ return "no"
+ }
+ return "yes"
+}
+
+proc done_string {} {
+ set done_string ""
+ if {[have_spec fiasco]} {
+ append done_string {.*?finished NIC stress test}
+ append done_string {.*?\n}
+ append done_string {.*?finished NIC stress test}
+ append done_string {.*?\n}
+ } else {
+ append done_string {.*?"nic_stress_." exited with exit value 0}
+ append done_string {.*?\n}
+ append done_string {.*?"nic_stress_." exited with exit value 0}
+ append done_string {.*?\n}
+ }
+ return $done_string
+}
+
+proc nr_of_rounds { test_id } {
+ if {[have_spec sel4]} {
+ switch $test_id {
+ 1 { return 19 }
+ 2 { return 12 }
+ }
+ } else {
+ switch $test_id {
+ 1 { return 22 }
+ 2 { return 16 }
+ }
+ }
+ return 0
+}
+
+proc nr_of_sessions { test_id } {
+ switch $test_id {
+ 1 { return 11 }
+ 2 { return 17 }
+ }
+ return 0
+}
+
+build $build_components
+
+create_boot_directory
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [string equal $type "nic_router"] config {
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [string equal $type "nic_bridge"] config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+append boot_modules {
+ core init timer
+ nic_router
+ test-nic_stress
+ ld.lib.so
+}
+
+append_if [string equal $type "nic_bridge"] boot_modules { nic_bridge }
+
+build_boot_image $boot_modules
+
+append qemu_args " -nographic "
+
+run_genode_until [done_string] 300
diff --git a/repos/os/src/server/nic_bridge/address_node.h b/repos/os/src/server/nic_bridge/address_node.h
index bfb0637136..c084c964cb 100644
--- a/repos/os/src/server/nic_bridge/address_node.h
+++ b/repos/os/src/server/nic_bridge/address_node.h
@@ -68,7 +68,7 @@ class Net::Address_node : public Genode::Avl_node >,
***************/
void addr(Address addr) { _addr = addr; }
- Address addr() { return _addr; }
+ Address addr() const { return _addr; }
Session_component &component() { return _component; }
diff --git a/repos/os/src/server/nic_bridge/component.h b/repos/os/src/server/nic_bridge/component.h
index 957a211982..42170f829b 100644
--- a/repos/os/src/server/nic_bridge/component.h
+++ b/repos/os/src/server/nic_bridge/component.h
@@ -191,6 +191,8 @@ class Net::Session_component : private Net::Stream_allocator,
Size_guard &size_guard) override;
void finalize_packet(Ethernet_frame *, Genode::size_t) override;
+
+ Mac_address vmac() const { return _mac_node.addr(); }
};
@@ -240,6 +242,13 @@ class Net::Root : public Genode::Root_component
policy.attribute_value("ip_addr", Session_component::Ip_addr()));
}
+
+ void _destroy_session(Session_component *session) override
+ {
+ _mac_alloc.free(session->vmac());
+ Genode::destroy(md_alloc(), session);
+ }
+
public:
Root(Genode::Env &env,
diff --git a/repos/os/src/server/nic_router/component.cc b/repos/os/src/server/nic_router/component.cc
index ee1b875098..c1ac984d5b 100644
--- a/repos/os/src/server/nic_router/component.cc
+++ b/repos/os/src/server/nic_router/component.cc
@@ -223,6 +223,8 @@ Session_component *Net::Root::_create_session(char const *args)
void Net::Root::_destroy_session(Session_component *session)
{
+ Mac_address const mac = session->mac_address();
+
/* read out initial dataspace and session env and destruct session */
Ram_dataspace_capability ram_ds { session->ram_ds() };
Session_env const &session_env { session->session_env() };
@@ -235,6 +237,8 @@ void Net::Root::_destroy_session(Session_component *session)
session_env_stack.detach(&session_env);
session_env_stack.free(ram_ds);
+ _mac_alloc.free(mac);
+
/* check for leaked quota */
if (session_env_stack.ram_guard().used().value) {
error("NIC session component \"", session_label, "\" leaks RAM quota of ",
diff --git a/repos/os/src/test/nic_stress/config.xsd b/repos/os/src/test/nic_stress/config.xsd
new file mode 100644
index 0000000000..4a73bf1286
--- /dev/null
+++ b/repos/os/src/test/nic_stress/config.xsd
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/repos/os/src/test/nic_stress/main.cc b/repos/os/src/test/nic_stress/main.cc
new file mode 100644
index 0000000000..c65469368d
--- /dev/null
+++ b/repos/os/src/test/nic_stress/main.cc
@@ -0,0 +1,149 @@
+/*
+ * \brief Stress test for low level NIC interactions
+ * \author Martin Stein
+ * \date 2019-03-15
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Local {
+
+ using namespace Genode;
+ struct Construct_destruct_test;
+ struct Main;
+}
+
+
+struct Local::Construct_destruct_test
+{
+ enum { DEFAULT_NR_OF_ROUNDS = 10 };
+ enum { DEFAULT_NR_OF_SESSIONS = 10 };
+ enum { PKT_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE };
+ enum { BUF_SIZE = 100 * PKT_SIZE };
+
+ using Nic_slot = Constructible;
+
+ Env &_env;
+ Allocator &_alloc;
+ Signal_context_capability &_completed_sigh;
+ Xml_node const &_config;
+ Nic::Packet_allocator _pkt_alloc { &_alloc };
+ bool const _config_exists { _config.has_sub_node("construct_destruct") };
+
+ unsigned long const _nr_of_rounds {
+ _config_exists ?
+ _config.sub_node("construct_destruct").
+ attribute_value("nr_of_rounds",
+ (unsigned long)DEFAULT_NR_OF_ROUNDS) :
+ (unsigned long)DEFAULT_NR_OF_ROUNDS };
+
+ unsigned long const _nr_of_sessions {
+ _config_exists ?
+ _config.sub_node("construct_destruct").
+ attribute_value("nr_of_sessions",
+ (unsigned long)DEFAULT_NR_OF_SESSIONS) :
+ (unsigned long)DEFAULT_NR_OF_SESSIONS };
+
+ void construct_all(Nic_slot *const nic,
+ unsigned const round)
+ {
+ for (unsigned idx = 0; idx < _nr_of_sessions; idx++) {
+ try {
+ nic[idx].construct(_env, &_pkt_alloc, BUF_SIZE, BUF_SIZE);
+ log("round ", round + 1, "/", _nr_of_rounds, " nic ", idx + 1,
+ "/", _nr_of_sessions, " mac ", nic[idx]->mac_address());
+ }
+ catch (...) {
+ for (unsigned destruct_idx = 0; destruct_idx < idx; destruct_idx++) {
+ nic[destruct_idx].destruct();
+ throw;
+ }
+ }
+ }
+ }
+
+ void destruct_all(Nic_slot *const nic)
+ {
+ for (unsigned idx = 0; idx < _nr_of_sessions; idx++) {
+ nic[idx].destruct();
+ }
+ }
+
+ Construct_destruct_test(Env &env,
+ Allocator &alloc,
+ Signal_context_capability completed_sigh,
+ Xml_node const &config)
+ :
+ _env { env },
+ _alloc { alloc },
+ _completed_sigh { completed_sigh },
+ _config { config }
+ {
+ if (!_nr_of_rounds && !_nr_of_sessions) {
+ Signal_transmitter(_completed_sigh).submit(); }
+
+ size_t const ram_size { _nr_of_sessions * sizeof(Nic_slot) };
+ Attached_ram_dataspace ram_ds { _env.ram(), _env.rm(), ram_size };
+ Nic_slot *const nic { ram_ds.local_addr() };
+
+ try {
+ for (unsigned round = 0; round < _nr_of_rounds; round++) {
+ construct_all(nic, round);
+ destruct_all(nic);
+ }
+ Signal_transmitter(_completed_sigh).submit();
+ }
+ catch (...) {
+ error("Construct_destruct_test failed"); }
+ }
+};
+
+
+struct Local::Main
+{
+ Env &_env;
+ Heap _heap { &_env.ram(), &_env.rm() };
+ Attached_rom_dataspace _config_rom { _env, "config" };
+ Xml_node const _config { _config_rom.xml() };
+ Constructible _test_1 { };
+
+ bool const _exit_support {
+ _config.attribute_value("exit_support", true) };
+
+ Signal_handler _test_completed_handler {
+ _env.ep(), *this, &Main::_handle_test_completed };
+
+ void _handle_test_completed()
+ {
+ if (_test_1.constructed()) {
+ _test_1.destruct();
+ log("--- finished NIC stress test ---");
+ if (_exit_support) {
+ _env.parent().exit(0); }
+ return;
+ }
+ }
+
+ Main(Env &env) : _env(env)
+ {
+ log("--- NIC stress test ---");
+ _test_1.construct(_env, _heap, _test_completed_handler, _config);
+ }
+};
+
+
+void Component::construct(Genode::Env &env) { static Local::Main main(env); }
diff --git a/repos/os/src/test/nic_stress/target.mk b/repos/os/src/test/nic_stress/target.mk
new file mode 100644
index 0000000000..0a26a14e98
--- /dev/null
+++ b/repos/os/src/test/nic_stress/target.mk
@@ -0,0 +1,4 @@
+TARGET = test-nic_stress
+SRC_CC = main.cc
+LIBS = base
+CONFIG_XSD = config.xsd
diff --git a/tool/autopilot.list b/tool/autopilot.list
index aa0076903a..8d4dd6b3ce 100644
--- a/tool/autopilot.list
+++ b/tool/autopilot.list
@@ -33,9 +33,11 @@ netperf_lxip_router
netperf_lxip_usb30
netperf_lxip_wifi
nic_bridge
+nic_bridge_stress
nic_dump
nic_router
nic_router_flood
+nic_router_stress
nic_router_uplinks
noux
noux_tool_chain_auto