diff --git a/repos/os/recipes/src/ping/used_apis b/repos/os/recipes/src/ping/used_apis
index 7b044429d1..a1972aef72 100644
--- a/repos/os/recipes/src/ping/used_apis
+++ b/repos/os/recipes/src/ping/used_apis
@@ -2,3 +2,4 @@ base
os
net
nic_session
+report_session
diff --git a/repos/os/run/ping.run b/repos/os/run/ping.run
index 07a2b9f27a..a119c3358f 100644
--- a/repos/os/run/ping.run
+++ b/repos/os/run/ping.run
@@ -58,6 +58,7 @@ create_boot_directory
import_from_depot [depot_user]/src/[base_src] \
[depot_user]/pkg/[drivers_nic_pkg] \
[depot_user]/src/init \
+ [depot_user]/src/report_rom \
[depot_user]/src/nic_router
build { app/ping }
@@ -114,6 +115,15 @@ append config {
+
+
+
+
+
+
+
+
+
@@ -168,9 +178,11 @@ append config {
+
diff --git a/repos/os/src/app/ping/README b/repos/os/src/app/ping/README
index 4019a9b9fa..10f0bf95d4 100644
--- a/repos/os/src/app/ping/README
+++ b/repos/os/src/app/ping/README
@@ -16,6 +16,7 @@ value for each attribute except 'config.dst_ip' and 'config.interface':
! protocol="icmp"
! period_sec="5"
! verbose="no"
+! report="yes"
! count="5" />
This is a short description of the tags and attributes:
@@ -36,6 +37,9 @@ This is a short description of the tags and attributes:
:config.verbose:
Optional. Toggles wether the component shall log debugging information.
+:config.report:
+ Optional. Toggles wether the component shall report results.
+
:config.count:
Optional. After how many successful pings the component exits successfully.
@@ -46,6 +50,30 @@ This is a short description of the tags and attributes:
Optional. Protocol to ping with. Can be one of 'icmp', 'udp'.
+Report
+~~~~~~
+
+If config attribute 'report' is set, the component generates a report named
+"last_received" that looks like this if the expected reply was received:
+
+:ICMP:
+!
+
+:UDP:
+!
+
+When an ICMP error "destination unreachable" was received instead, the report
+looks like this:
+
+:ICMP:
+!
+
+:UDP:
+!
+
+The id attribute in the report is incremented with each result.
+
+
Sessions
~~~~~~~~
@@ -53,6 +81,7 @@ This is an overview of the sessions required and provided by the
component apart from the environment sessions:
* Requires one Timer session.
+* Requires one Report session if config attribute report is set.
Examples
diff --git a/repos/os/src/app/ping/config.xsd b/repos/os/src/app/ping/config.xsd
index f8c6e92b7c..5777f6fa5c 100644
--- a/repos/os/src/app/ping/config.xsd
+++ b/repos/os/src/app/ping/config.xsd
@@ -15,6 +15,7 @@
+
diff --git a/repos/os/src/app/ping/main.cc b/repos/os/src/app/ping/main.cc
index ad2c411ded..1cd9673a84 100644
--- a/repos/os/src/app/ping/main.cc
+++ b/repos/os/src/app/ping/main.cc
@@ -18,6 +18,7 @@
#include
/* Genode includes */
+#include
#include
#include
#include
@@ -58,26 +59,29 @@ class Main : public Nic_handler,
enum { DEFAULT_PERIOD_SEC = 5 };
enum { SRC_PORT = 50000 };
- Env &_env;
- Attached_rom_dataspace _config_rom { _env, "config" };
- Xml_node _config { _config_rom.xml() };
- Timer::Connection _timer { _env };
- Microseconds _send_time { 0 };
- Microseconds _period_us { read_sec_attr(_config, "period_sec", (uint64_t)DEFAULT_PERIOD_SEC) };
- Constructible _period { };
- Heap _heap { &_env.ram(), &_env.rm() };
- bool const _verbose { _config.attribute_value("verbose", false) };
- Net::Nic _nic { _env, _heap, *this, _verbose };
- Ipv4_address const _dst_ip { _config.attribute_value("dst_ip", Ipv4_address()) };
- Mac_address _dst_mac { };
- uint16_t _icmp_seq { 1 };
- unsigned long _count { _config.attribute_value("count", (unsigned long)DEFAULT_COUNT) };
- Constructible _dhcp_client { };
- Reconstructible _ip_config { _config.attribute_value("interface", Ipv4_address_prefix()),
- _config.attribute_value("gateway", Ipv4_address()),
- Ipv4_address() };
- Protocol const _protocol { _config.attribute_value("protocol", Protocol::ICMP) };
- Port const _dst_port { _config.attribute_value("dst_port", Port(DEFAULT_DST_PORT)) };
+ Env &_env;
+ Attached_rom_dataspace _config_rom { _env, "config" };
+ Xml_node _config { _config_rom.xml() };
+ Timer::Connection _timer { _env };
+ Microseconds _send_time { 0 };
+ Microseconds _period_us { read_sec_attr(_config, "period_sec", (uint64_t)DEFAULT_PERIOD_SEC) };
+ Constructible _period { };
+ Heap _heap { &_env.ram(), &_env.rm() };
+ bool const _verbose { _config.attribute_value("verbose", false) };
+ bool const _report { _config.attribute_value("report", false) };
+ unsigned long _report_id { 0 };
+ Constructible _reporter { };
+ Net::Nic _nic { _env, _heap, *this, _verbose };
+ Ipv4_address const _dst_ip { _config.attribute_value("dst_ip", Ipv4_address()) };
+ Mac_address _dst_mac { };
+ uint16_t _icmp_seq { 1 };
+ unsigned long _count { _config.attribute_value("count", (unsigned long)DEFAULT_COUNT) };
+ Constructible _dhcp_client { };
+ Reconstructible _ip_config { _config.attribute_value("interface", Ipv4_address_prefix()),
+ _config.attribute_value("gateway", Ipv4_address()),
+ Ipv4_address() };
+ Protocol const _protocol { _config.attribute_value("protocol", Protocol::ICMP) };
+ Port const _dst_port { _config.attribute_value("dst_port", Port(DEFAULT_DST_PORT)) };
void _handle_ip(Ethernet_frame ð,
Size_guard &size_guard);
@@ -156,6 +160,9 @@ Main::Main(Env &env) : _env(env)
/* else, start the DHCP client for requesting an IP config */
else {
_dhcp_client.construct(_timer, _nic, *this); }
+
+ if (_report)
+ _reporter.construct(env, "result", "result");
}
@@ -281,6 +288,16 @@ void Main::_handle_icmp_echo_reply(Ipv4_packet &ip,
": icmp_seq=", icmp_seq, " ttl=", (uint64_t)IPV4_TIME_TO_LIVE,
" time=", time_ms, ".", time_us ," ms");
+ if (_report)
+ _reporter->generate([&] (Xml_generator &xml) {
+ xml.attribute("id", _report_id++);
+ xml.attribute("type", "reply");
+ xml.attribute("bytes", ICMP_DATA_SIZE + sizeof(Icmp_packet));
+ xml.attribute("from", String<32>(ip.src()));
+ xml.attribute("ttl", (uint64_t)IPV4_TIME_TO_LIVE);
+ xml.attribute("time_ms", String<32>(time_ms, ".", time_us));
+ xml.attribute("icmp_seq", icmp_seq); });
+
/* raise ICMP sequence number and check exit condition */
_icmp_seq++;
_count--;
@@ -325,6 +342,12 @@ void Main::_handle_icmp_dst_unreachbl(Ipv4_packet &ip,
return;
}
log("From ", ip.src(), " icmp_seq=", embed_icmp_seq, " Destination Unreachable");
+ if (_report)
+ _reporter->generate([&] (Xml_generator &xml) {
+ xml.attribute("id", _report_id++);
+ xml.attribute("type", "destination_unreachable");
+ xml.attribute("from", String<32>(ip.src()));
+ xml.attribute("icmp_seq", embed_icmp_seq); });
break;
}
case Protocol::UDP:
@@ -349,6 +372,11 @@ void Main::_handle_icmp_dst_unreachbl(Ipv4_packet &ip,
return;
}
log("From ", ip.src(), " Destination Unreachable");
+ if (_report)
+ _reporter->generate([&] (Xml_generator &xml) {
+ xml.attribute("id", _report_id++);
+ xml.attribute("type", "destination_unreachable");
+ xml.attribute("from", String<32>(ip.src())); });
break;
}
}
@@ -414,6 +442,15 @@ void Main::_handle_udp(Ipv4_packet &ip,
log(udp.length(), " bytes from ", ip.src(), " ttl=", (uint64_t)IPV4_TIME_TO_LIVE,
" time=", time_ms, ".", time_us ," ms");
+ if (_report)
+ _reporter->generate([&] (Xml_generator &xml) {
+ xml.attribute("id", _report_id++);
+ xml.attribute("type", "reply");
+ xml.attribute("bytes", udp.length());
+ xml.attribute("from", String<32>(ip.src()));
+ xml.attribute("ttl", (uint64_t)IPV4_TIME_TO_LIVE);
+ xml.attribute("time_ms", String<32>(time_ms, ".", time_us)); });
+
/* check exit condition */
_count--;
if (!_count) {