diff --git a/run/udp_log.run b/run/udp_log.run
new file mode 100644
index 0000000..03fd8c9
--- /dev/null
+++ b/run/udp_log.run
@@ -0,0 +1,77 @@
+if {[expr [have_spec linux]]} {
+ puts "\n Run script is not supported on this platform. \n"; exit 0 }
+
+#
+# Test logging to file system
+#
+
+set build_components {
+ core init timer
+ proxy/udp_log
+ test/bomb
+ drivers/nic
+}
+
+source ${genode_dir}/repos/base/run/platform_drv.inc
+append_platform_drv_build_components
+
+build $build_components
+
+create_boot_directory
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+append boot_modules {
+ core init ld.lib.so bomb timer udp_log
+ } [nic_drv_binary] {
+}
+
+append_platform_drv_boot_modules
+build_boot_image $boot_modules
+
+append qemu_args " -nographic"
+append qemu_args " -net tap,ifname=tap2 "
+
+run_genode_until forever
diff --git a/src/proxy/udp_log/README b/src/proxy/udp_log/README
new file mode 100644
index 0000000..850efc8
--- /dev/null
+++ b/src/proxy/udp_log/README
@@ -0,0 +1,20 @@
+udp_log is a LOG server that sends client log messages as UDP
+packets to a destination IP and port.
+
+This component implements the standard notion of session policies.
+The policy specifies the destination IP, UDP port and MAC address
+as shown in the following example that shows the default values.
+
+!
+!
+!
+!
+!
+!
+!
+
+The component also gets its source IP address from the config ROM.
+The verbose mode acts as a pass-through mode of the LOG messages to the
+component's LOG session.
+
+The UDP packets can be received with netcat or with log_udp.
diff --git a/src/proxy/udp_log/logger.h b/src/proxy/udp_log/logger.h
new file mode 100644
index 0000000..1001304
--- /dev/null
+++ b/src/proxy/udp_log/logger.h
@@ -0,0 +1,187 @@
+/*
+ * \brief Network logger
+ * \author Johannes Schlatow
+ * \date 2018-11-01
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#include
+#include
+
+#include
+#include
+#include
+
+using namespace Net;
+
+namespace Udp_log {
+ using Genode::size_t;
+ using Genode::Xml_node;
+ using Nic::Packet_stream_source;
+ using Nic::Packet_descriptor;
+
+ class Payload;
+ template class Logger;
+};
+
+class Udp_log::Payload
+{
+ private:
+ char _data[0];
+
+ public:
+
+ void set(char const *p, size_t plen, char const *s, size_t len, Size_guard &size_guard)
+ {
+ /* write prefix */
+ size_guard.consume_head(plen);
+ Genode::memcpy(_data, p, plen);
+
+ /* write string */
+ size_guard.consume_head(len);
+ Genode::memcpy(&_data[plen], s, len);
+
+ /* zero-out unconsumed data */
+ size_t const unconsumed = size_guard.unconsumed();
+ size_guard.consume_head(unconsumed);
+ Genode::memset(&_data[plen+len], 0, unconsumed);
+ }
+};
+
+template
+class Udp_log::Logger
+{
+ private:
+ enum {
+ PACKET_SIZE = 512,
+ BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE
+ };
+
+ Ipv4_address const _default_ip_address { (Genode::uint8_t)0x00 };
+
+ Nic::Packet_allocator _tx_block_alloc;
+ Nic::Connection _nic;
+
+ Mac_address _src_mac { _nic.mac_address() };
+ Ipv4_address _src_ip;
+ Port const _src_port { 51234 };
+
+ bool _verbose { false };
+ bool _chksum_offload { false };
+
+ Genode::Signal_handler _source_ack;
+ Genode::Signal_handler _source_submit;
+
+ /**
+ * acknowledgement queue not empty anymore
+ */
+ void _ready_to_ack()
+ {
+ /* check for acknowledgements */
+ while (source()->ack_avail())
+ source()->release_packet(source()->get_acked_packet());
+ }
+
+ /**
+ * submit queue not full anymore
+ *
+ * by now, packets are dropped if submit queue is full
+ */
+ void _packet_avail() { }
+
+ Packet_stream_source< ::Nic::Session::Policy> * source() {
+ return _nic.tx(); }
+
+ public:
+ Logger(Genode::Env &env, Genode::Allocator &alloc, Xml_node config)
+ :
+ _tx_block_alloc(&alloc),
+ _nic(env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE),
+ _src_ip (config.attribute_value("src_ip", _default_ip_address)),
+ _verbose(config.attribute_value("verbose", _verbose)),
+ _chksum_offload(config.attribute_value("chksum_offload", _chksum_offload)),
+ _source_ack(env.ep(), *this, &Logger::_ready_to_ack),
+ _source_submit(env.ep(), *this, &Logger::_packet_avail)
+ {
+ _nic.tx_channel()->sigh_ack_avail(_source_ack);
+ _nic.tx_channel()->sigh_ready_to_submit(_source_submit);
+ }
+
+ size_t write(PREFIX const &prefix, MSG const &string,
+ Ipv4_address const &ipaddr,
+ Port const &port,
+ Mac_address const &mac)
+ {
+ if (!_nic.link_state()) {
+ return 0;
+ }
+
+ enum {
+ HDR_SZ = sizeof(Ethernet_frame) + sizeof(Ipv4_packet) + sizeof(Udp_packet),
+ MIN_DATA_SZ = Ethernet_frame::MIN_SIZE - HDR_SZ,
+ };
+
+ size_t const packet_size = HDR_SZ + Genode::max((size_t)MIN_DATA_SZ,
+ string.size() + prefix.length());
+
+ try {
+
+ /* copy and submit packet */
+ Packet_descriptor packet = source()->alloc_packet(packet_size);
+ Size_guard size_guard(packet_size);
+ void *base = source()->packet_content(packet);
+
+ /* create ETH header */
+ Ethernet_frame ð = Ethernet_frame::construct_at(base, size_guard);
+ eth.dst(mac);
+ eth.src(_src_mac);
+ eth.type(Ethernet_frame::Type::IPV4);
+
+ /* create IP header */
+ enum { IPV4_TIME_TO_LIVE = 64 };
+ size_t const ip_off = size_guard.head_size();
+ Ipv4_packet &ip = eth.construct_at_data(size_guard);
+ ip.header_length(sizeof(Ipv4_packet) / 4);
+ ip.version(4);
+ ip.time_to_live(IPV4_TIME_TO_LIVE);
+ ip.protocol(Ipv4_packet::Protocol::UDP);
+ ip.src(_src_ip);
+ ip.dst(ipaddr);
+
+ /* create UDP header */
+ size_t const udp_off = size_guard.head_size();
+ Udp_packet &udp = ip.construct_at_data(size_guard);
+ udp.src_port(_src_port);
+ udp.dst_port(port);
+
+ /* write payload */
+ Payload &payload = udp.construct_at_data(size_guard);
+ payload.set(prefix.string(), prefix.length()-1,
+ string.string(), string.size(), size_guard);
+
+ /* fill in header values that need the packet to be complete already */
+ udp.length(size_guard.head_size() - udp_off);
+ if (!_chksum_offload)
+ udp.update_checksum(ip.src(), ip.dst());
+ ip.total_length(size_guard.head_size() - ip_off);
+ ip.update_checksum();
+
+ source()->submit_packet(packet);
+ } catch(Packet_stream_source::Packet_alloc_failed) {
+ Genode::warning("Packet dropped");
+ }
+
+ if (_verbose)
+ Genode::log(prefix, Genode::Cstring(string.string(), string.size()-2));
+
+ return string.size();
+ }
+
+
+};
diff --git a/src/proxy/udp_log/main.cc b/src/proxy/udp_log/main.cc
new file mode 100644
index 0000000..7a7cdb4
--- /dev/null
+++ b/src/proxy/udp_log/main.cc
@@ -0,0 +1,162 @@
+/*
+ * \brief LOG server that sends data via UDP.
+ * \author Johannes Schlatow
+ * \date 2018-11-01
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU General Public License version 2.
+ */
+
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+#include "logger.h"
+
+using namespace Net;
+
+namespace Udp_log {
+ using Genode::size_t;
+ using Genode::Attached_rom_dataspace;
+ using Genode::Xml_node;
+ using Genode::Log_session;
+
+ class Session_component;
+ class Root;
+ struct Main;
+};
+
+class Udp_log::Session_component : public Genode::Rpc_object
+{
+ public:
+ typedef Genode::String Prefix;
+
+ private:
+
+ Genode::Env &_env;
+ Logger &_logger;
+
+ Prefix _prefix;
+
+ Mac_address const _default_mac_address { (Genode::uint8_t)0xff };
+ Ipv4_address const _default_ip_address { (Genode::uint8_t)0x00 };
+ Port const _default_port { 9 };
+
+ Mac_address const _dst_mac;
+ Ipv4_address const _dst_ip;
+ Port const _dst_port;
+
+ public:
+
+ Session_component(Genode::Env &env, Logger &logger,
+ Genode::Session_label const &label,
+ Xml_node policy)
+ :
+ _env(env), _logger(logger), _prefix("[", label.string(), "] "),
+ _dst_mac (policy.attribute_value("mac", _default_mac_address)),
+ _dst_ip (policy.attribute_value("ip", _default_ip_address)),
+ _dst_port(policy.attribute_value("port", _default_port))
+ { }
+
+ /* LOG session implementation */
+
+ size_t write(String const &string) override
+ {
+ /* TODO implement ARP, i.e. do not send LOG packets until MAC is known
+ * for this we need the following modifications:
+ * - add optional gateway attribute to config to allow specifying the next hop
+ * if the dst_ip is not the next hop
+ * - implement an Arp_resolver class on root level that send ARP requests using
+ * the logger and handles ARP responses
+ * - ARP responses are delivered to all session components
+ * - a session component stores a single address
+ * - a session component stores uses the broadcast MAC until the address is resolved
+ */
+
+ return _logger.write(_prefix, string, _dst_ip, _dst_port, _dst_mac);
+ }
+
+};
+
+
+class Udp_log::Root : public Genode::Root_component
+{
+ private:
+
+ Genode::Env &_env;
+ Genode::Allocator &_alloc;
+ Attached_rom_dataspace _config = { _env, "config" };
+ Logger
+ _logger = { _env, _alloc, _config.xml() };
+
+ protected:
+
+ Session_component *_create_session(const char *args) override
+ {
+ using namespace Genode;
+
+ try {
+ Session_label const label = label_from_args(args);
+ Session_policy policy(label, _config.xml());
+
+ return new (Root::md_alloc())
+ Session_component(_env, _logger, label, policy);
+ }
+ catch (Session_policy::No_policy_defined) {
+ Genode::warning("Missing policy.");
+ return 0;
+ }
+ catch (Out_of_ram) {
+ Genode::warning("insufficient 'ram_quota'");
+ throw Insufficient_ram_quota();
+ }
+ catch (Out_of_caps) {
+ Genode::warning("insufficient 'cap_quota'");
+ throw Insufficient_cap_quota();
+ }
+ }
+
+ public:
+
+ Root(Genode::Env &env, Genode::Allocator &md_alloc)
+ : Genode::Root_component(&env.ep().rpc_ep(), &md_alloc),
+ _env(env), _alloc(md_alloc)
+ { }
+};
+
+struct Udp_log::Main
+{
+ Genode::Env &env;
+ Genode::Heap heap = { &env.ram(), &env.rm() };
+ Root root = { env, heap };
+
+ Main(Genode::Env &env) : env(env)
+ {
+ env.parent().announce(env.ep().manage(root));
+ }
+
+};
+
+namespace Component {
+ Genode::size_t stack_size() { return 2*1024*sizeof(long); }
+ void construct(Genode::Env &env)
+ {
+ env.exec_static_constructors();
+ static Udp_log::Main main(env);
+ }
+}
diff --git a/src/proxy/udp_log/target.mk b/src/proxy/udp_log/target.mk
new file mode 100644
index 0000000..062dabc
--- /dev/null
+++ b/src/proxy/udp_log/target.mk
@@ -0,0 +1,3 @@
+TARGET = udp_log
+SRC_CC = main.cc
+LIBS = base net