diff --git a/include/remote_rom/backend_base.h b/include/remote_rom/backend_base.h index b715467..8d85996 100644 --- a/include/remote_rom/backend_base.h +++ b/include/remote_rom/backend_base.h @@ -14,6 +14,8 @@ #ifndef __INCLUDE__REMOTE_ROM__BACKEND_BASE_H_ #define __INCLUDE__REMOTE_ROM__BACKEND_BASE_H_ +#include + #include #include @@ -22,17 +24,19 @@ namespace Remote_rom { struct Backend_client_base; class Exception : public ::Genode::Exception { }; - Backend_server_base &backend_init_server(Genode::Env &env, Genode::Allocator &alloc); - Backend_client_base &backend_init_client(Genode::Env &env, Genode::Allocator &alloc); + Backend_server_base &backend_init_server(Genode::Env &env, + Genode::Allocator &alloc); + Backend_client_base &backend_init_client(Genode::Env &env, + Genode::Allocator &alloc); }; -struct Remote_rom::Backend_server_base +struct Remote_rom::Backend_server_base : Genode::Interface { virtual void send_update() = 0; virtual void register_forwarder(Rom_forwarder_base *forwarder) = 0; }; -struct Remote_rom::Backend_client_base +struct Remote_rom::Backend_client_base : Genode::Interface { virtual void register_receiver(Rom_receiver_base *receiver) = 0; }; diff --git a/include/remote_rom/rom_forwarder.h b/include/remote_rom/rom_forwarder.h index 2c8d988..5a32b26 100644 --- a/include/remote_rom/rom_forwarder.h +++ b/include/remote_rom/rom_forwarder.h @@ -15,17 +15,19 @@ #define __INCLUDE__REMOTE_ROM__ROM_FORWARDER_H_ #include +#include namespace Remote_rom { using Genode::size_t; struct Rom_forwarder_base; } -struct Remote_rom::Rom_forwarder_base +struct Remote_rom::Rom_forwarder_base : Genode::Interface { virtual const char *module_name() const = 0; virtual size_t content_size() const = 0; - virtual size_t transfer_content(char *dst, size_t dst_len, size_t offset=0) const = 0; + virtual size_t transfer_content(char *dst, size_t dst_len, + size_t offset=0) const = 0; }; #endif diff --git a/include/remote_rom/rom_receiver.h b/include/remote_rom/rom_receiver.h index 735905c..82fe489 100644 --- a/include/remote_rom/rom_receiver.h +++ b/include/remote_rom/rom_receiver.h @@ -15,13 +15,14 @@ #define __INCLUDE__REMOTE_ROM__ROM_RECEIVER_H_ #include +#include namespace Remote_rom { using Genode::size_t; struct Rom_receiver_base; } -struct Remote_rom::Rom_receiver_base +struct Remote_rom::Rom_receiver_base : Genode::Interface { virtual const char *module_name() const = 0; virtual char* start_new_content(size_t len) = 0; diff --git a/lib/mk/remote_rom_backend_nic_ip.mk b/lib/mk/remote_rom_backend_nic_ip.mk index df3255b..43c5553 100644 --- a/lib/mk/remote_rom_backend_nic_ip.mk +++ b/lib/mk/remote_rom_backend_nic_ip.mk @@ -1,11 +1,10 @@ # \author Johannes Schlatow # \date 2016-03-19 -SRC_CC += backend/nic_ip/backend.cc +SRC_CC += backend/nic_ip/client.cc backend/nic_ip/server.cc +INC_DIR += $(REP_DIR)/src/lib/remote_rom/backend/nic_ip LIBS += base net # include less specificuration include $(REP_DIR)/lib/mk/remote_rom_backend.inc - -CC_CXX_WARN_STRICT = diff --git a/run/remote_rom_backend_nic_ip.run b/run/remote_rom_backend_nic_ip.run index 2905669..1ee37ec 100644 --- a/run/remote_rom_backend_nic_ip.run +++ b/run/remote_rom_backend_nic_ip.run @@ -64,12 +64,15 @@ install_config { - + + + - + @@ -79,7 +82,9 @@ install_config { - + + + @@ -112,7 +117,9 @@ install_config { - + + + diff --git a/run/remote_rom_backend_nic_ip_client.run b/run/remote_rom_backend_nic_ip_client.run index a036453..a1cf944 100644 --- a/run/remote_rom_backend_nic_ip_client.run +++ b/run/remote_rom_backend_nic_ip_client.run @@ -45,7 +45,9 @@ install_config { - + + + diff --git a/run/remote_rom_backend_nic_ip_server.run b/run/remote_rom_backend_nic_ip_server.run index 2b0115b..47b0946 100644 --- a/run/remote_rom_backend_nic_ip_server.run +++ b/run/remote_rom_backend_nic_ip_server.run @@ -62,12 +62,15 @@ install_config { - + + + - + diff --git a/src/lib/remote_rom/backend/nic_ip/backend.cc b/src/lib/remote_rom/backend/nic_ip/backend.cc deleted file mode 100644 index 5c257e8..0000000 --- a/src/lib/remote_rom/backend/nic_ip/backend.cc +++ /dev/null @@ -1,554 +0,0 @@ -/* - * \brief TODO - * \author Johannes Schlatow - * \date 2016-02-18 - */ - -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include - -namespace Remote_rom { - bool verbose = false; - using Genode::size_t; - using Genode::uint16_t; - using Genode::uint32_t; - using Genode::Cstring; - using Genode::Packet_descriptor; - using Genode::env; - using Net::Ethernet_frame; - using Net::Ipv4_packet; - using Net::Mac_address; - using Net::Ipv4_address; - - template - class Backend_base; - class Backend_server; - class Backend_client; - - struct Packet_base; - struct SignalPacket; - struct UpdatePacket; - struct DataPacket; -}; - -/* Packet format we use for inter-system communication */ -/* FIXME do not inherit from Ethernet_frame and Ipv4_packet but use construct_at_data with size_guard */ -class Remote_rom::Packet_base : public Ethernet_frame, public Ipv4_packet -{ - public: - enum { - MAX_NAME_LEN = 64 /* maximum length of the module name */ - }; - - typedef enum { - SIGNAL = 1, /* signal that ROM content has changed */ - UPDATE = 2, /* request transmission of updated content */ - DATA = 3, /* first data packet */ - DATA_CONT = 4, /* following data packets */ - } Type; - - protected: - char _module_name[MAX_NAME_LEN]; /* the ROM module name */ - Type _type; /* packet type */ - uint32_t _content_size; /* ROM content size in bytes */ - uint32_t _offset; /* offset in bytes */ - uint16_t _payload_size; /* payload size in bytes */ - - /***************************************************** - ** 'payload' must be the last member of this class ** - *****************************************************/ - - char payload[0]; - - public: - - Packet_base(size_t size) - : - Ethernet_frame(), - Ipv4_packet(), - _payload_size(size) - { } - - void const * base() const { return &payload; } - - /** - * Return type of the packet - */ - Type type() const { return _type; } - - /** - * Return size of the packet - */ - size_t size() const { return _payload_size + sizeof(Packet_base); } - - /** - * Return content_size of the packet - */ - size_t content_size() const { return _content_size; } - - /** - * Return offset of the packet - */ - size_t offset() const { return _offset; } - - /** - * Return module_name of the packet - */ - char* module_name() { return _module_name; } - - /** - * Set payload size of the packet - */ - void payload_size(Genode::size_t payload_size) - { - _payload_size = payload_size; - Ipv4_packet::total_length(size() - sizeof(Ethernet_frame)); - } - - /** - * Return payload size of the packet - */ - size_t payload_size() const { return _payload_size; } - - /** - * Return address of the payload - */ - void *addr() { return payload; } - - void prepare_ethernet(const Mac_address &src, const Mac_address &dst=Ethernet_frame::broadcast()) - { - Ethernet_frame::src(src); - Ethernet_frame::dst(dst); - Ethernet_frame::type(Ethernet_frame::Type::IPV4); - } - - void prepare_ipv4(const Ipv4_address &src, const Ipv4_address &dst=Ipv4_packet::broadcast()) - { - Ipv4_packet::version(4); - Ipv4_packet::header_length(5); - Ipv4_packet::time_to_live(10); - Ipv4_packet::src(src); - Ipv4_packet::dst(dst); - Ipv4_packet::total_length(size() - sizeof(Ethernet_frame)); - } - - void set_checksums() - { - Ipv4_packet::update_checksum(); - } - - /** - * Placement new. - */ - void * operator new(__SIZE_TYPE__ size, void* addr) { return addr; } - -} __attribute__((packed)); - -class Remote_rom::SignalPacket : public Packet_base -{ - public: - SignalPacket() : Packet_base(0) - { } - - void prepare(const char *module) - { - Genode::strncpy(_module_name, module, MAX_NAME_LEN); - _type = SIGNAL; - _payload_size = 0; - } -} __attribute__((packed)); - -class Remote_rom::UpdatePacket : public Packet_base -{ - public: - UpdatePacket() : Packet_base(0) - { } - - void prepare(const char *module) - { - Genode::strncpy(_module_name, module, MAX_NAME_LEN); - _type = UPDATE; - _payload_size = 0; - } -} __attribute__((packed)); - -class Remote_rom::DataPacket : public Packet_base -{ - public: - enum { MAX_PAYLOAD_SIZE = 1024 }; - - char payload[MAX_PAYLOAD_SIZE]; - - DataPacket() : Packet_base(MAX_PAYLOAD_SIZE) - { } - - void prepare(const char* module, size_t offset, size_t content_size) - { - Genode::strncpy(_module_name, module, MAX_NAME_LEN); - - _payload_size = MAX_PAYLOAD_SIZE; - _offset = offset; - _content_size = content_size; - - if (offset == 0) - _type = DATA; - else - _type = DATA_CONT; - } - - /** - * Return packet size for given payload - */ - static size_t packet_size(size_t payload) { return sizeof(Packet_base) + Genode::min(payload, MAX_PAYLOAD_SIZE); } - -} __attribute__((packed)); - -template -class Remote_rom::Backend_base -{ - protected: - enum { - PACKET_SIZE = 1024, - BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE - }; - - class Rx_thread : public Genode::Thread - { - protected: - Ipv4_address &_accept_ip; - Nic::Connection &_nic; - HANDLER &_handler; - - Genode::Signal_receiver _sig_rec; - Genode::Signal_dispatcher _link_state_dispatcher; - Genode::Signal_dispatcher _rx_packet_avail_dispatcher; - Genode::Signal_dispatcher _rx_ready_to_ack_dispatcher; - - void _handle_rx_packet_avail(unsigned) - { - while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) { - Packet_descriptor _rx_packet = _nic.rx()->get_packet(); - - char *content = _nic.rx()->packet_content(_rx_packet); - - /* check IP */ - Ipv4_packet &ip_packet = *(Packet_base*)content; - if (_accept_ip == Ipv4_packet::broadcast() || _accept_ip == ip_packet.dst()) - _handler.receive(*(Packet_base*)content); - - _nic.rx()->acknowledge_packet(_rx_packet); - } - } - - void _handle_rx_ready_to_ack(unsigned) { _handle_rx_packet_avail(0); } - - void _handle_link_state(unsigned) - { - Genode::log("link state changed"); - } - - public: - Rx_thread(Nic::Connection &nic, HANDLER &handler, Ipv4_address &ip) - : Genode::Thread(Weight::DEFAULT_WEIGHT, "backend_nic_rx", 8192), - _accept_ip(ip), - _nic(nic), _handler(handler), - _link_state_dispatcher(_sig_rec, *this, &Rx_thread::_handle_link_state), - _rx_packet_avail_dispatcher(_sig_rec, *this, &Rx_thread::_handle_rx_packet_avail), - _rx_ready_to_ack_dispatcher(_sig_rec, *this, &Rx_thread::_handle_rx_ready_to_ack) - { - _nic.link_state_sigh(_link_state_dispatcher); - _nic.rx_channel()->sigh_packet_avail(_rx_packet_avail_dispatcher); - _nic.rx_channel()->sigh_ready_to_ack(_rx_ready_to_ack_dispatcher); - } - - void entry() - { - while(true) - { - Genode::Signal sig = _sig_rec.wait_for_signal(); - int num = sig.num(); - - Genode::Signal_dispatcher_base *dispatcher; - dispatcher = dynamic_cast(sig.context()); - dispatcher->dispatch(num); - } - } - }; - - Nic::Packet_allocator _tx_block_alloc; - Nic::Connection _nic; - Rx_thread _rx_thread; - Mac_address _mac_address; - Ipv4_address _src_ip; - Ipv4_address _accept_ip; - Ipv4_address _dst_ip; - - protected: - void _tx_ack(bool block = false) - { - /* check for acknowledgements */ - while (_nic.tx()->ack_avail() || block) { - Nic::Packet_descriptor acked_packet = _nic.tx()->get_acked_packet(); - _nic.tx()->release_packet(acked_packet); - block = false; - } - } - - public: - explicit Backend_base(Genode::Env &env, Genode::Allocator &alloc, HANDLER &handler) - : - _tx_block_alloc(&alloc), _nic(env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE), - _rx_thread(_nic, handler, _accept_ip) - { - /* start dispatcher thread */ - _rx_thread.start(); - - /* store mac address */ - _mac_address = _nic.mac_address(); - - Genode::Attached_rom_dataspace config = {env, "config"}; - - try { - char ip_string[15]; - Genode::Xml_node remoterom = config.xml().sub_node("remote_rom"); - remoterom.attribute("src").value(ip_string, sizeof(ip_string)); - _src_ip = Ipv4_packet::ip_from_string(ip_string); - - remoterom.attribute("dst").value(ip_string, sizeof(ip_string)); - _dst_ip = Ipv4_packet::ip_from_string(ip_string); - - _accept_ip = _src_ip; - } catch (...) { - Genode::warning("No IP configured, falling back to broadcast mode!"); - _src_ip = Ipv4_packet::current(); - _dst_ip = Ipv4_packet::broadcast(); - _accept_ip = Ipv4_packet::broadcast(); - } - } - - Nic::Packet_descriptor alloc_tx_packet(Genode::size_t size) - { - while (true) { - try { - Nic::Packet_descriptor packet = _nic.tx()->alloc_packet(size); - return packet; - } catch(Nic::Session::Tx::Source::Packet_alloc_failed) { - /* packet allocator exhausted, wait for acknowledgements */ - _tx_ack(true); - } - } - } - - void submit_tx_packet(Nic::Packet_descriptor packet) - { - _nic.tx()->submit_packet(packet); - /* check for acknowledgements */ - _tx_ack(); - } -}; - -class Remote_rom::Backend_server : public Backend_server_base, public Backend_base -{ - private: - Rom_forwarder_base *_forwarder; - - void send_data() - { - if (!_forwarder) return; - - size_t offset = 0; - size_t size = _forwarder->content_size(); - while (offset < size) - { - /* create and transmit packet via NIC session */ - Nic::Packet_descriptor pd = alloc_tx_packet(DataPacket::packet_size(size)); - DataPacket *packet = new (_nic.tx()->packet_content(pd)) DataPacket(); - - packet->prepare_ethernet(_mac_address, Ethernet_frame::broadcast()); - packet->prepare_ipv4(_src_ip, _dst_ip); - packet->prepare(_forwarder->module_name(), offset, size); - - packet->payload_size(_forwarder->transfer_content((char*)packet->addr(), DataPacket::MAX_PAYLOAD_SIZE, offset)); - packet->set_checksums(); - - submit_tx_packet(pd); - - offset += packet->payload_size(); - } - } - - public: - Backend_server(Genode::Env &env, Genode::Allocator &alloc) : Backend_base(env, alloc, *this), _forwarder(nullptr) - { } - - void register_forwarder(Rom_forwarder_base *forwarder) - { - _forwarder = forwarder; - } - - void send_update() - { - if (!_forwarder) return; - - /* create and transmit packet via NIC session */ - Nic::Packet_descriptor pd = alloc_tx_packet(sizeof(SignalPacket)); - SignalPacket *packet = new (_nic.tx()->packet_content(pd)) SignalPacket(); - - packet->prepare_ethernet(_mac_address); - packet->prepare_ipv4(_src_ip, _dst_ip); - packet->prepare(_forwarder->module_name()); - packet->set_checksums(); - - submit_tx_packet(pd); - } - - void receive(Packet_base &packet) - { - switch (packet.type()) - { - case Packet_base::UPDATE: - if (verbose) - Genode::log("receiving UPDATE (", Cstring(packet.module_name()), ") packet"); - - if (!_forwarder) - return; - - /* check module name */ - if (Genode::strcmp(packet.module_name(), _forwarder->module_name())) - return; - - /* TODO (optional) dont send data within Rx_Thread's context */ - send_data(); - - break; - default: - break; - } - } -}; - -class Remote_rom::Backend_client : public Backend_client_base, public Backend_base -{ - private: - Rom_receiver_base *_receiver; - char *_write_ptr; - size_t _buf_size; - - - void write(char *data, size_t offset, size_t size) - { - if (!_write_ptr) return; - - size_t const len = Genode::min(size, _buf_size-offset); - Genode::memcpy(_write_ptr+offset, data, len); - - if (offset + len >= _buf_size) - _receiver->commit_new_content(); - } - - public: - Backend_client(Genode::Env &env, Genode::Allocator &alloc) : Backend_base(env, alloc, *this), _receiver(nullptr), _write_ptr(nullptr), _buf_size(0) - { - } - - void register_receiver(Rom_receiver_base *receiver) - { - /* TODO support multiple receivers (ROM names) */ - _receiver = receiver; - - /* FIXME request update on startup (occasionally triggers invalid signal-context capability) */ -// if (_receiver) -// update(_receiver->module_name()); - } - - - void update(const char* module_name) - { - if (!_receiver) return; - - /* check module name */ - if (Genode::strcmp(module_name, _receiver->module_name())) - return; - - /* create and transmit packet via NIC session */ - Nic::Packet_descriptor pd = alloc_tx_packet(sizeof(UpdatePacket)); - UpdatePacket *packet = (UpdatePacket*)_nic.tx()->packet_content(pd); - - packet->prepare_ethernet(_mac_address); - packet->prepare_ipv4(_src_ip, _dst_ip); - packet->prepare(_receiver->module_name()); - packet->set_checksums(); - - submit_tx_packet(pd); - } - - void receive(Packet_base &packet) - { - switch (packet.type()) - { - case Packet_base::SIGNAL: - if (verbose) - Genode::log("receiving SIGNAL(", Cstring(packet.module_name()), ") packet"); - - /* send update request */ - update(packet.module_name()); - - break; - case Packet_base::DATA: - if (verbose) - Genode::log("receiving DATA(", Cstring(packet.module_name()), ") packet"); - - /* write into buffer */ - if (!_receiver) return; - - /* check module name */ - if (Genode::strcmp(packet.module_name(), _receiver->module_name())) - return; - - _write_ptr = _receiver->start_new_content(packet.content_size()); - _buf_size = (_write_ptr) ? packet.content_size() : 0; - - write((char*)packet.addr(), packet.offset(), packet.payload_size()); - - break; - case Packet_base::DATA_CONT: - if (verbose) - Genode::log("receiving DATA_CONT(", Cstring(packet.module_name()), ") packet"); - - if (!_receiver) return; - - /* check module name */ - if (Genode::strcmp(packet.module_name(), _receiver->module_name())) - return; - - /* write into buffer */ - write((char*)packet.addr(), packet.offset(), packet.payload_size()); - - break; - default: - break; - } - } -}; - -Remote_rom::Backend_server_base &Remote_rom::backend_init_server(Genode::Env &env, Genode::Allocator &alloc) -{ - static Backend_server backend(env, alloc); - return backend; -} - -Remote_rom::Backend_client_base &Remote_rom::backend_init_client(Genode::Env &env, Genode::Allocator &alloc) -{ - static Backend_client backend(env, alloc); - return backend; -} diff --git a/src/lib/remote_rom/backend/nic_ip/base.h b/src/lib/remote_rom/backend/nic_ip/base.h new file mode 100644 index 0000000..7d59344 --- /dev/null +++ b/src/lib/remote_rom/backend/nic_ip/base.h @@ -0,0 +1,195 @@ +/* + * \brief Common base for client and server + * \author Johannes Schlatow + * \date 2016-02-18 + */ + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#ifndef __INCLUDE__REMOTE_ROM__BASE_H_ +#define __INCLUDE__REMOTE_ROM__BASE_H_ + +namespace Remote_rom { + using Genode::Packet_descriptor; + using Genode::env; + using Net::Ethernet_frame; + using Net::Ipv4_packet; + using Net::Mac_address; + using Net::Ipv4_address; + using Net::Size_guard; + + class Backend_base; +}; + + +class Remote_rom::Backend_base : public Genode::Interface +{ + private: + + Genode::Signal_handler _link_state_handler; + Genode::Signal_handler _rx_packet_handler; + + void _handle_rx_packet() + { + while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) { + Packet_descriptor _rx_packet = _nic.rx()->get_packet(); + + char *content = _nic.rx()->packet_content(_rx_packet); + Size_guard edguard(_rx_packet.size()); + Ethernet_frame ð = Ethernet_frame::cast_from(content, edguard); + + /* check IP */ + Ipv4_packet &ip_packet = eth.data(edguard); + if (_accept_ip == Ipv4_packet::broadcast() + || _accept_ip == ip_packet.dst()) + receive(ip_packet.data(edguard), edguard); + + _nic.rx()->acknowledge_packet(_rx_packet); + } + } + + void _handle_link_state() + { + Genode::log("link state changed"); + } + + void _tx_ack(bool block = false) + { + /* check for acknowledgements */ + while (_nic.tx()->ack_avail() || block) { + Nic::Packet_descriptor acked_packet = _nic.tx()->get_acked_packet(); + _nic.tx()->release_packet(acked_packet); + block = false; + } + } + + protected: + + enum { + PACKET_SIZE = 1024, + BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE + }; + + const bool _verbose = false; + Nic::Packet_allocator _tx_block_alloc; + Nic::Connection _nic; + Mac_address _mac_address; + Ipv4_address _src_ip; + Ipv4_address _accept_ip; + Ipv4_address _dst_ip; + + /** + * Handle accepted network packet from the other side + */ + virtual void receive(Packet &packet, Size_guard &) = 0; + + Ipv4_packet &_prepare_upper_layers(void *base, Size_guard &size_guard) + { + Ethernet_frame ð = Ethernet_frame::construct_at(base, size_guard); + eth.src(_mac_address); + eth.dst(Ethernet_frame::broadcast()); + eth.type(Ethernet_frame::Type::IPV4); + + Ipv4_packet &ip = eth.construct_at_data(size_guard); + ip.version(4); + ip.header_length(5); + ip.time_to_live(10); + ip.src(_src_ip); + ip.dst(_dst_ip); + + return ip; + } + + size_t _upper_layer_size(size_t size) + { + return sizeof(Ethernet_frame) + sizeof(Ipv4_packet) + size; + } + + void _finish_ipv4(Ipv4_packet &ip, size_t payload) + { + ip.total_length(sizeof(ip) + payload); + ip.update_checksum(); + } + + template + void _transmit_notification_packet(Packet::Type type, T *frontend) + { + size_t frame_size = _upper_layer_size(sizeof(Packet)); + Nic::Packet_descriptor pd = alloc_tx_packet(frame_size); + Size_guard size_guard(pd.size()); + + char *content = _nic.tx()->packet_content(pd); + Ipv4_packet &ip = _prepare_upper_layers(content, size_guard); + Packet &pak = ip.construct_at_data(size_guard); + pak.type(type); + pak.module_name(frontend->module_name()); + _finish_ipv4(ip, sizeof(Packet)); + + submit_tx_packet(pd); + } + + explicit Backend_base(Genode::Env &env, Genode::Allocator &alloc) + : + _link_state_handler(env.ep(), *this, &Backend_base::_handle_link_state), + _rx_packet_handler(env.ep(), *this, &Backend_base::_handle_rx_packet), + + _tx_block_alloc(&alloc), + _nic(env, &_tx_block_alloc, BUF_SIZE, BUF_SIZE), + + _mac_address(_nic.mac_address()), + _src_ip(Ipv4_packet::current()), + _accept_ip(Ipv4_packet::broadcast()), + _dst_ip(Ipv4_packet::broadcast()) + { + _nic.link_state_sigh(_link_state_handler); + _nic.rx_channel()->sigh_packet_avail(_rx_packet_handler); + _nic.rx_channel()->sigh_ready_to_ack(_rx_packet_handler); + + Genode::Attached_rom_dataspace config = {env, "config"}; + try { + char ip_string[15]; + Genode::Xml_node remoterom = config.xml().sub_node("remote_rom"); + remoterom.attribute("src").value(ip_string, sizeof(ip_string)); + _src_ip = Ipv4_packet::ip_from_string(ip_string); + + remoterom.attribute("dst").value(ip_string, sizeof(ip_string)); + _dst_ip = Ipv4_packet::ip_from_string(ip_string); + + _accept_ip = _src_ip; + } catch (...) { + Genode::warning("No IP configured, falling back to broadcast mode!"); + } + } + + Nic::Packet_descriptor alloc_tx_packet(Genode::size_t size) + { + while (true) { + try { + Nic::Packet_descriptor packet = _nic.tx()->alloc_packet(size); + return packet; + } catch(Nic::Session::Tx::Source::Packet_alloc_failed) { + /* packet allocator exhausted, wait for acknowledgements */ + _tx_ack(true); + } + } + } + + void submit_tx_packet(Nic::Packet_descriptor packet) + { + _nic.tx()->submit_packet(packet); + /* check for acknowledgements */ + _tx_ack(); + } +}; + +#endif diff --git a/src/lib/remote_rom/backend/nic_ip/client.cc b/src/lib/remote_rom/backend/nic_ip/client.cc new file mode 100644 index 0000000..3bfa31c --- /dev/null +++ b/src/lib/remote_rom/backend/nic_ip/client.cc @@ -0,0 +1,131 @@ +/* + * \brief Client implementation + * \author Johannes Schlatow + * \date 2018-11-06 + */ + +#include +#include + +namespace Remote_rom { + using Genode::Cstring; + + struct Backend_client; +}; + +class Remote_rom::Backend_client : + public Backend_client_base, + public Backend_base +{ + private: + + Rom_receiver_base *_receiver; + char *_write_ptr; + size_t _buf_size; + + Backend_client(Backend_client &); + Backend_client &operator= (Backend_client &); + + void write(const void *data, size_t offset, size_t size) + { + if (!_write_ptr) return; + + + size_t const len = Genode::min(size, _buf_size-offset); + Genode::memcpy(_write_ptr+offset, data, len); + + if (offset + len >= _buf_size) + _receiver->commit_new_content(); + } + + + void update(const char* module_name) + { + if (!_receiver) return; + + /* check module name */ + if (Genode::strcmp(module_name, _receiver->module_name())) + return; + + _transmit_notification_packet(Packet::UPDATE, _receiver); + } + + + void receive(Packet &packet, Size_guard &size_guard) + { + switch (packet.type()) + { + case Packet::SIGNAL: + if (_verbose) + Genode::log("receiving SIGNAL(", + Cstring(packet.module_name()), + ") packet"); + + /* send update request */ + update(packet.module_name()); + + break; + case Packet::DATA: + { + if (_verbose) + Genode::log("receiving DATA(", + Cstring(packet.module_name()), + ") packet"); + + /* write into buffer */ + if (!_receiver) return; + + /* check module name */ + if (Genode::strcmp(packet.module_name(), _receiver->module_name())) + return; + + const DataPacket &data = packet.data(size_guard); + size_guard.consume_head(data.payload_size()); + + if (!data.offset()) { + _write_ptr = _receiver->start_new_content(data.content_size()); + _buf_size = (_write_ptr) ? data.content_size() : 0; + } + + write(data.addr(), data.offset(), data.payload_size()); + + break; + } + default: + break; + } + } + + public: + + Backend_client(Genode::Env &env, Genode::Allocator &alloc) : + Backend_base(env, alloc), + _receiver(nullptr), _write_ptr(nullptr), + _buf_size(0) + { } + + + void register_receiver(Rom_receiver_base *receiver) + { + /* TODO support multiple receivers (ROM names) */ + _receiver = receiver; + + /* + * FIXME request update on startup + * (occasionally triggers invalid signal-context capability) + * */ +// if (_receiver) +// update(_receiver->module_name()); + } +}; + +namespace Remote_rom { + using Genode::Env; + using Genode::Allocator; + + Backend_client_base &backend_init_client(Env &env, Allocator &alloc) + { + static Backend_client backend(env, alloc); + return backend; + } +}; diff --git a/src/lib/remote_rom/backend/nic_ip/packet.h b/src/lib/remote_rom/backend/nic_ip/packet.h new file mode 100644 index 0000000..c94c41e --- /dev/null +++ b/src/lib/remote_rom/backend/nic_ip/packet.h @@ -0,0 +1,143 @@ +/* + * \brief Packet format we use for inter-system communication + * \author Johannes Schlatow + * \date 2018-11-05 + */ + +#include +#include +#include + +#ifndef __INCLUDE__REMOTE_ROM__PACKET_H_ +#define __INCLUDE__REMOTE_ROM__PACKET_H_ + +namespace Remote_rom { + using Genode::size_t; + using Genode::uint16_t; + using Genode::uint32_t; + + struct Packet; + struct DataPacket; +} + +class Remote_rom::Packet +{ + public: + enum { + MAX_NAME_LEN = 64 /* maximum length of the module name */ + }; + + typedef enum { + SIGNAL = 1, /* signal that ROM content has changed */ + UPDATE = 2, /* request transmission of updated content */ + DATA = 3, /* data packet */ + } Type; + + private: + char _module_name[MAX_NAME_LEN]; /* the ROM module name */ + Type _type; /* packet type */ + + /***************************************************** + ** 'payload' must be the last member of this class ** + *****************************************************/ + + char payload[0]; + + public: + /** + * Return type of the packet + */ + Type type() const { return _type; } + + /** + * Return module_name of the packet + */ + const char *module_name() { return _module_name; } + + void type(Type type) + { + _type = type; + } + + void module_name(const char *module) + { + Genode::strncpy(_module_name, module, MAX_NAME_LEN); + } + + template + T const &data(Net::Size_guard &size_guard) const + { + size_guard.consume_head(sizeof(T)); + return *(T const *)(payload); + } + + template + T &construct_at_data(Net::Size_guard &size_guard) + { + size_guard.consume_head(sizeof(T)); + return *Genode::construct_at(payload); + } + +} __attribute__((packed)); + + +class Remote_rom::DataPacket +{ + public: + static const size_t MAX_PAYLOAD_SIZE = 1024; + + private: + uint32_t _content_size; /* ROM content size in bytes */ + uint32_t _offset; /* offset in bytes */ + uint16_t _payload_size; /* payload size in bytes */ + + char payload[0]; + + public: + /** + * Return size of the packet + */ + size_t size() const { return _payload_size + sizeof(*this); } + + /** + * Return content_size of the packet + */ + size_t content_size() const { return _content_size; } + + /** + * Return offset of the packet + */ + size_t offset() const { return _offset; } + + void content_size(size_t size) { _content_size = size; } + void offset(size_t offset) { _offset = offset; } + + /** + * Set payload size of the packet + */ + void payload_size(Genode::size_t payload_size) + { + _payload_size = payload_size; + } + + /** + * Return payload size of the packet + */ + size_t payload_size() const { return _payload_size; } + + /** + * Return address of the payload + */ + void *addr() { return payload; } + const void *addr() const { return payload; } + + /** + * Return packet size for given payload + */ + static size_t packet_size(size_t payload) { + return sizeof(DataPacket) + Genode::min(payload, MAX_PAYLOAD_SIZE); + } + +} __attribute__((packed)); + +#endif diff --git a/src/lib/remote_rom/backend/nic_ip/server.cc b/src/lib/remote_rom/backend/nic_ip/server.cc new file mode 100644 index 0000000..86c4984 --- /dev/null +++ b/src/lib/remote_rom/backend/nic_ip/server.cc @@ -0,0 +1,119 @@ +/* + * \brief Server implementation + * \author Johannes Schlatow + * \date 2018-11-06 + */ + +#include +#include + +namespace Remote_rom { + using Genode::Cstring; + + struct Backend_server; +}; + +class Remote_rom::Backend_server : + public Backend_server_base, + public Backend_base +{ + private: + + Rom_forwarder_base *_forwarder; + + Backend_server(Backend_server &); + Backend_server &operator= (Backend_server &); + + void send_data() + { + if (!_forwarder) return; + + size_t offset = 0; + size_t size = _forwarder->content_size(); + while (offset < size) + { + /* create and transmit packet via NIC session */ + size_t max_size = _upper_layer_size(sizeof(Packet) + + DataPacket::packet_size(size)); + Nic::Packet_descriptor pd = alloc_tx_packet(max_size); + Size_guard size_guard(pd.size()); + + char *content = _nic.tx()->packet_content(pd); + Ipv4_packet &ip = _prepare_upper_layers(content, size_guard); + Packet &pak = ip.construct_at_data(size_guard); + pak.type(Packet::DATA); + pak.module_name(_forwarder->module_name()); + + DataPacket &data = pak.construct_at_data(size_guard); + data.offset(offset); + data.content_size(size); + + const size_t max = DataPacket::MAX_PAYLOAD_SIZE; + data.payload_size(_forwarder->transfer_content((char*)data.addr(), + max, + offset)); + _finish_ipv4(ip, sizeof(Packet) + data.size()); + + submit_tx_packet(pd); + + offset += data.payload_size(); + } + } + + + void receive(Packet &packet, Size_guard &) + { + switch (packet.type()) + { + case Packet::UPDATE: + if (_verbose) + Genode::log("receiving UPDATE (", + Cstring(packet.module_name()), + ") packet"); + + if (!_forwarder) + return; + + /* check module name */ + if (Genode::strcmp(packet.module_name(), _forwarder->module_name())) + return; + + send_data(); + + break; + default: + break; + } + } + + public: + + Backend_server(Genode::Env &env, Genode::Allocator &alloc) : + Backend_base(env, alloc), + _forwarder(nullptr) + { } + + + void register_forwarder(Rom_forwarder_base *forwarder) + { + _forwarder = forwarder; + } + + + void send_update() + { + if (!_forwarder) return; + _transmit_notification_packet(Packet::SIGNAL, _forwarder); + } +}; + +namespace Remote_rom { + using Genode::Env; + using Genode::Allocator; + + Backend_server_base &backend_init_server(Env &env, Allocator &alloc) + { + static Backend_server backend(env, alloc); + return backend; + } +}; diff --git a/src/proxy/remote_rom/README b/src/proxy/remote_rom/README index d2517c7..8dc387c 100644 --- a/src/proxy/remote_rom/README +++ b/src/proxy/remote_rom/README @@ -1,32 +1,35 @@ -The remote ROM allows providing ROM services over a network or similar communication -medium and thus implements publisher/subscriber communication in a distributed system. +The remote ROM allows providing ROM services over a network or similar +communication medium and thus implements publisher/subscriber communication in +a distributed system. -The remote_rom server connects to a local ROM service and provides a remote ROM service -via the specified backend. The remote_rom client connects to a remote ROM service via -the specified backend and provides a ROM service via local RPC. +The remote_rom server connects to a local ROM service and provides a remote ROM +service via the specified backend. The remote_rom client connects to a remote +ROM service via the specified backend and provides a ROM service via local RPC. Backends -------- -The remote_rom can be compiled with one of multiple back ends that use different session -interfaces or libraries to forward and receive the packets. By exchanging the backend, -we can also easily change the publication strategy (e.g., notification+polling vs. multicast). -Furthermore, a back end is responsible for access control and optionally allows the -specification of a policy for this. +The remote_rom can be compiled with one of multiple back ends that use +different session interfaces or libraries to forward and receive the packets. +By exchanging the backend, we can also easily change the publication strategy +(e.g., notification+polling vs. multicast). Furthermore, a back end is +responsible for access control and optionally allows the specification of a +policy for this. :'nic_ip': - This back end uses a Nic_session to transmit network packets with IPv4 headers. + This back end uses a Nic_session to transmit network packets with IPv4 + headers. Configuration ------------- -Both the client and the server evaluate the '' node of their config. -The _name_ attribute specifies the ROMs module name. The '' node may -further contain a '' node that can be used to populate the ROM with a default -content. +Both the client and the server evaluate the '' node of their +config. The _name_ attribute specifies the ROMs module name. The +'' node may further contain a '' node that can be used to +populate the ROM with a default content. Example ~~~~~~~ -For an example that illustrates the use of these components, please refer to the -_run/remote_rom_backend_nic_ip.run_ script. +For an example that illustrates the use of these components, please refer to +the _run/remote_rom_backend_nic_ip.run_ script. diff --git a/src/proxy/remote_rom/backend/nic_ip/client/target.mk b/src/proxy/remote_rom/backend/nic_ip/client/target.mk index 24febca..6712492 100644 --- a/src/proxy/remote_rom/backend/nic_ip/client/target.mk +++ b/src/proxy/remote_rom/backend/nic_ip/client/target.mk @@ -1,4 +1,2 @@ include $(PRG_DIR)/../target.inc include $(PRG_DIR)/../../../client/target.inc - -CC_CXX_WARN_STRICT = diff --git a/src/proxy/remote_rom/backend/nic_ip/server/target.mk b/src/proxy/remote_rom/backend/nic_ip/server/target.mk index 003b34d..ca0fc73 100644 --- a/src/proxy/remote_rom/backend/nic_ip/server/target.mk +++ b/src/proxy/remote_rom/backend/nic_ip/server/target.mk @@ -1,4 +1,2 @@ include $(PRG_DIR)/../target.inc include $(PRG_DIR)/../../../server/target.inc - -CC_CXX_WARN_STRICT = diff --git a/src/proxy/remote_rom/client/main.cc b/src/proxy/remote_rom/client/main.cc index 7b0036a..f39ceac 100644 --- a/src/proxy/remote_rom/client/main.cc +++ b/src/proxy/remote_rom/client/main.cc @@ -4,10 +4,10 @@ * \date 2016-02-15 * * Usage scenario: - * __________ ________________ _________________ __________ - * | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client | - * | | | server | | client | | | - * ---------- ---------------- ----------------- ---------- + * __________ ______________ ______________ __________ + * | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client | + * | | | server | | client | | | + * ---------- -------------- -------------- ---------- */ /* @@ -44,21 +44,23 @@ namespace Remote_rom { struct Main; struct Read_buffer; - typedef Genode::List Session_list; + typedef Genode::List_element Session_element; + typedef Genode::List Session_list; }; /** - * Interface used by the sessions to obtain the ROM data received from the remote server + * Interface used by the sessions to obtain the ROM data received from the + * remote server */ -struct Remote_rom::Read_buffer +struct Remote_rom::Read_buffer : Genode::Interface { virtual size_t content_size() const = 0; virtual size_t export_content(char *dst, size_t dst_len) const = 0; }; -class Remote_rom::Session_component : public Genode::Rpc_object, - public Session_list::Element +class Remote_rom::Session_component : + public Genode::Rpc_object { private: Genode::Env &_env; @@ -68,6 +70,7 @@ class Remote_rom::Session_component : public Genode::Rpc_object _ram_ds; @@ -75,14 +78,16 @@ class Remote_rom::Session_component : public Genode::Rpc_object protected: - Session_component *_create_session(const char *args) + Session_component *_create_session(const char *) { using namespace Genode; - /* TODO compare requested module name with provided module name (config) */ + /* + * TODO compare requested module name with provided module name (config) + * */ return new (Root::md_alloc()) Session_component(_env, _sessions, _buffer); @@ -149,17 +156,21 @@ class Remote_rom::Root : public Genode::Root_component public: Root(Genode::Env &env, Genode::Allocator &md_alloc, Read_buffer &buffer) - : Genode::Root_component(&env.ep().rpc_ep(), &md_alloc), _env(env), _buffer(buffer) + : + Genode::Root_component(&env.ep().rpc_ep(), &md_alloc), + _env(env), + _buffer(buffer), + _sessions() { } void notify_clients() { - for (Session_component *s = _sessions.first(); s; s = s->next()) - s->notify_client(); + for (Session_element *s = _sessions.first(); s; s = s->next()) + s->object()->notify_client(); } }; -struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom_receiver_base +struct Remote_rom::Main : public Read_buffer, public Rom_receiver_base { Genode::Env &env; Genode::Heap heap = { &env.ram(), &env.rm() }; @@ -174,7 +185,9 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom char remotename[255]; - Main(Genode::Env &env) : env(env), _ds_content_size(1024), _backend(backend_init_client(env, heap)) + Main(Genode::Env &env) : + env(env), _ds(), _ds_content_size(1024), + _backend(backend_init_client(env, heap)) { try { Genode::Xml_node remote_rom = _config.xml().sub_node("remote_rom"); @@ -223,7 +236,9 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom else { /* transfer default content if set */ try { - Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default"); + Genode::Xml_node default_content = _config.xml(). + sub_node("remote_rom"). + sub_node("default"); return default_content.content_size(); } catch (...) { } } @@ -241,8 +256,11 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom else { /* transfer default content if set */ try { - Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default"); - size_t const len = Genode::min(dst_len, default_content.content_size()); + Genode::Xml_node default_content = _config.xml(). + sub_node("remote_rom"). + sub_node("default"); + size_t const len = Genode::min(dst_len, + default_content.content_size()); Genode::memcpy(dst, default_content.content_base(), len); return len; } catch (...) { } @@ -252,10 +270,9 @@ struct Remote_rom::Main : public Remote_rom::Read_buffer, public Remote_rom::Rom }; namespace Component { - Genode::size_t stack_size() { return 2*1024*sizeof(long); } + Genode::size_t stack_size() { return 2*1024*sizeof(long); } void construct(Genode::Env &env) { - env.exec_static_constructors(); static Remote_rom::Main main(env); } } diff --git a/src/proxy/remote_rom/server/main.cc b/src/proxy/remote_rom/server/main.cc index b77d8bc..e8cdd9c 100644 --- a/src/proxy/remote_rom/server/main.cc +++ b/src/proxy/remote_rom/server/main.cc @@ -4,10 +4,10 @@ * \date 2016-02-15 * * Usage scenario: - * __________ ________________ _________________ __________ - * | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client | - * | | | server | | client | | | - * ---------- ---------------- ----------------- ---------- + * __________ ______________ ______________ __________ + * | server | -> | remote_rom | -> (network) -> | remote_rom | -> | client | + * | | | server | | client | | | + * ---------- -------------- -------------- ---------- */ /* @@ -46,7 +46,8 @@ struct Remote_rom::Rom_forwarder : Rom_forwarder_base Attached_rom_dataspace &_config; - Rom_forwarder(Attached_rom_dataspace &rom, Backend_server_base &backend, Attached_rom_dataspace &config) + Rom_forwarder(Attached_rom_dataspace &rom, Backend_server_base &backend, + Attached_rom_dataspace &config) : _rom(rom), _backend(backend), _config(config) { _backend.register_forwarder(this); @@ -74,11 +75,14 @@ struct Remote_rom::Rom_forwarder : Rom_forwarder_base if (binary) return _rom.size(); else - return Genode::min(1+Genode::strlen(_rom.local_addr()), _rom.size()); + return Genode::min(1+Genode::strlen(_rom.local_addr()), + _rom.size()); } else { try { - Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default"); + Genode::Xml_node default_content = _config.xml(). + sub_node("remote_rom"). + sub_node("default"); return default_content.content_size(); } catch (...) { } } @@ -95,8 +99,11 @@ struct Remote_rom::Rom_forwarder : Rom_forwarder_base else { /* transfer default content if set */ try { - Genode::Xml_node default_content = _config.xml().sub_node("remote_rom").sub_node("default"); - size_t const len = Genode::min(dst_len, default_content.content_size()-offset); + Genode::Xml_node default_content = _config.xml(). + sub_node("remote_rom"). + sub_node("default"); + size_t const remainder = default_content.content_size()-offset; + size_t const len = Genode::min(dst_len, remainder); Genode::memcpy(dst, default_content.content_base() + offset, len); return len; } catch (...) { } @@ -115,7 +122,8 @@ struct Remote_rom::Main Attached_rom_dataspace _rom; Rom_forwarder _forwarder; - Genode::Signal_handler _dispatcher = { _env.ep(), _forwarder, &Rom_forwarder::update }; + Genode::Signal_handler _dispatcher = {_env.ep(), _forwarder, + &Rom_forwarder::update}; Main(Genode::Env &env) : _env(env), @@ -133,17 +141,19 @@ namespace Component { void construct(Genode::Env &env) { - env.exec_static_constructors(); + using Remote_rom::modulename; + using Remote_rom::remotename; Genode::Attached_rom_dataspace config = { env, "config" }; try { Genode::Xml_node remote_rom = config.xml().sub_node("remote_rom"); if (remote_rom.has_attribute("localname")) - remote_rom.attribute("localname").value(Remote_rom::modulename, sizeof(Remote_rom::modulename)); + remote_rom.attribute("localname").value(modulename, + sizeof(modulename)); else - remote_rom.attribute("name").value(Remote_rom::modulename, sizeof(Remote_rom::modulename)); + remote_rom.attribute("name").value(modulename, sizeof(modulename)); - remote_rom.attribute("name").value(Remote_rom::remotename, sizeof(Remote_rom::remotename)); + remote_rom.attribute("name").value(remotename, sizeof(remotename)); try { remote_rom.attribute("binary").value(&Remote_rom::binary); } catch (...) { }