diff --git a/repos/os/include/net/dhcp.h b/repos/os/include/net/dhcp.h index f53a30a09b..56b8fa94bc 100644 --- a/repos/os/include/net/dhcp.h +++ b/repos/os/include/net/dhcp.h @@ -205,26 +205,19 @@ class Net::Dhcp_packet /** * Domain name server option */ - class Dns_server : public Option + struct Dns_server : public Option { - private: + static constexpr Code CODE = Code::DNS_SERVER; - Ipv4_address _dns_servers[0]; + Dns_server(Genode::size_t len) : Option(CODE, (Genode::uint8_t)len) { } - public: + void for_each_address(auto const &fn) const + { + Ipv4_address const *dns_servers = (Ipv4_address const *)((Genode::addr_t)this + sizeof(*this)); + for (unsigned idx = 0; idx < len() / sizeof(*dns_servers); idx++) + fn(dns_servers[idx]); + } - static constexpr Code CODE = Code::DNS_SERVER; - - Dns_server(Genode::size_t len) : Option(CODE, (Genode::uint8_t)len) { } - - void for_each_address(auto const &fn) const - { - for (unsigned idx = 0; - idx < len() / sizeof(_dns_servers[0]); idx++) { - - fn(_dns_servers[idx]); - } - } }; /** @@ -516,6 +509,24 @@ class Net::Dhcp_packet } } + template + void with_option(auto const &found_fn, auto const ¬_found_fn) const + { + bool found = false; + for_each_option([&] (Option const &opt) { + if (found || opt.code() != T::CODE) + return; + + found = true; + found_fn(*(T const *)(&opt)); + }); + if (!found) + not_found_fn(); + } + + template + void with_option(auto const &fn) const { with_option(fn, []{}); } + /*************** ** Accessors ** diff --git a/repos/os/src/server/nic_router/arp_cache.cc b/repos/os/src/server/nic_router/arp_cache.cc index 6493abf6af..51ec24647e 100644 --- a/repos/os/src/server/nic_router/arp_cache.cc +++ b/repos/os/src/server/nic_router/arp_cache.cc @@ -69,7 +69,7 @@ void Arp_cache::new_entry(Ipv4_address const &ip, Mac_address const &mac) void Arp_cache::destroy_entries_with_mac(Mac_address const &mac) { for (unsigned curr = 0; curr < NR_OF_ENTRIES; curr++) { - try { + if (_entries[curr].constructed()) { Arp_cache_entry &entry = *_entries[curr]; if (entry.mac() != mac) { continue; @@ -79,8 +79,7 @@ void Arp_cache::destroy_entries_with_mac(Mac_address const &mac) } remove(&entry); _entries[curr].destruct(); - - } catch (Arp_cache_entry_slot::Deref_unconstructed_object) { } + } } } diff --git a/repos/os/src/server/nic_router/assertion.h b/repos/os/src/server/nic_router/assertion.h new file mode 100644 index 0000000000..5271a99ea7 --- /dev/null +++ b/repos/os/src/server/nic_router/assertion.h @@ -0,0 +1,35 @@ +/* + * \brief Assertion macros + * \author Martin Stein + * \date 2023-06-09 + */ + +/* + * Copyright (C) 2023 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. + */ + +#ifndef _ASSERTION_H_ +#define _ASSERTION_H_ + +/* base includes */ +#include +#include + +#define ASSERT(condition) \ + do { \ + if (!(condition)) { \ + Genode::error(__FILE__, ":", __LINE__, ": ", " assertion \"", #condition, "\" failed "); \ + Genode::sleep_forever(); \ + } \ + } while (false) + +#define ASSERT_NEVER_REACHED \ + do { \ + Genode::error(__FILE__, ":", __LINE__, ": ", " should have never been reached"); \ + Genode::sleep_forever(); \ + } while (false) + +#endif /* _ASSERTION_H_ */ diff --git a/repos/os/src/server/nic_router/bit_allocator_dynamic.h b/repos/os/src/server/nic_router/bit_allocator_dynamic.h index c1db6d55ce..bcd159061c 100644 --- a/repos/os/src/server/nic_router/bit_allocator_dynamic.h +++ b/repos/os/src/server/nic_router/bit_allocator_dynamic.h @@ -17,6 +17,9 @@ /* Genode includes */ #include +/* local includes */ +#include + namespace Genode { class Bit_array_dynamic; @@ -26,14 +29,6 @@ namespace Genode { class Genode::Bit_array_dynamic { - public: - - struct Invalid_bit_count : Exception { }; - struct Invalid_index_access : Exception { }; - struct Invalid_clear : Exception { }; - struct Invalid_set : Exception { }; - struct Count_of_bits_not_word_aligned : Exception { }; - protected: enum { @@ -50,13 +45,14 @@ class Genode::Bit_array_dynamic addr_t _word(addr_t index) const { return index / BITS_PER_WORD; } - void _check_range(addr_t const index, - addr_t const width) const + [[nodiscard]] bool _check_range(addr_t const index, + addr_t const width) const { if ((index >= _word_cnt * BITS_PER_WORD) || width > _word_cnt * BITS_PER_WORD || _word_cnt * BITS_PER_WORD - width < index) - throw Invalid_index_access(); + return false; + return true; } addr_t _mask(addr_t const index, addr_t const width, @@ -71,9 +67,10 @@ class Genode::Bit_array_dynamic : ((1UL << width) - 1) << shift; } - void _set(addr_t index, addr_t width, bool free) + [[nodiscard]] bool _set(addr_t index, addr_t width, bool free) { - _check_range(index, width); + if (!_check_range(index, width)) + return false; addr_t rest, word, mask; do { @@ -82,17 +79,18 @@ class Genode::Bit_array_dynamic if (free) { if ((_words[word] & mask) != mask) - throw Invalid_clear(); + return false; _words[word] &= ~mask; } else { if (_words[word] & mask) - throw Invalid_set(); + return false; _words[word] |= mask; } index = (_word(index) + 1) * BITS_PER_WORD; width = rest; } while (rest); + return true; } public: @@ -103,7 +101,8 @@ class Genode::Bit_array_dynamic */ bool get(addr_t index, addr_t width) const { - _check_range(index, width); + if (!_check_range(index, width)) + return false; bool used = false; addr_t rest, mask; @@ -117,23 +116,18 @@ class Genode::Bit_array_dynamic return used; } - void set(addr_t const index, addr_t const width) { - _set(index, width, false); } + [[nodiscard]] bool set(addr_t const index, addr_t const width) { + return _set(index, width, false); } - void clear(addr_t const index, addr_t const width) { - _set(index, width, true); } + [[nodiscard]] bool clear(addr_t const index, addr_t const width) { + return _set(index, width, true); } Bit_array_dynamic(addr_t *addr, unsigned bits) : _bit_cnt(bits), _word_cnt(_bit_cnt / BITS_PER_WORD), _words(addr) { - if (!bits || bits % BITS_PER_WORD) - throw Invalid_bit_count(); - + ASSERT(bits && bits % BITS_PER_WORD == 0); memset(_words, 0, sizeof(addr_t)*_word_cnt); - - if (bits % BITS_PER_WORD) - throw Count_of_bits_not_word_aligned(); } }; @@ -164,11 +158,11 @@ class Genode::Bit_allocator_dynamic * * \noapi */ - void _reserve(addr_t bit_start, size_t const num) + [[nodiscard]] bool _reserve(addr_t bit_start, size_t const num) { - if (!num) return; + if (!num) return true; - _array.set(bit_start, num); + return _array.set(bit_start, num); } size_t _ram_size() const @@ -178,50 +172,53 @@ class Genode::Bit_allocator_dynamic public: - struct Out_of_indices : Exception { }; - struct Range_conflict : Exception { }; + struct Alloc_error { }; + using Alloc_result = Attempt; - addr_t alloc(size_t const num_log2 = 0) + [[nodiscard]] Alloc_result alloc() { - addr_t const step = 1UL << num_log2; + addr_t const step = 1UL; addr_t max = ~0UL; do { - try { - /* throws exception if array is accessed outside bounds */ - for (addr_t i = _next & ~(step - 1); i < max; i += step) { - if (_array.get(i, step)) - continue; + for (addr_t i = _next & ~(step - 1); i < max; i += step) { + if (_array.get(i, step)) + continue; - _array.set(i, step); - _next = i + step; - return i; - } - } catch (Bit_array_dynamic::Invalid_index_access) { } + if (!_array.set(i, step)) + break; + _next = i + step; + return i; + } max = _next; _next = 0; } while (max != 0); - throw Out_of_indices(); + return Alloc_error(); } - void alloc_addr(addr_t const bit_start, size_t const num_log2 = 0) + [[nodiscard]] bool alloc_addr(addr_t const bit_start) { - addr_t const step = 1UL << num_log2; + addr_t const step = 1UL; if (_array.get(bit_start, step)) - throw Range_conflict(); + return false; + + if (!_array.set(bit_start, step)) + return false; - _array.set(bit_start, step); _next = bit_start + step; - return; + return true; } - void free(addr_t const bit_start, size_t const num_log2 = 0) + [[nodiscard]] bool free(addr_t const bit_start) { - _array.clear(bit_start, 1UL << num_log2); + if (!_array.clear(bit_start, 1UL)) + return false; + _next = bit_start; + return true; } Bit_allocator_dynamic(Allocator &alloc, unsigned bits) @@ -233,7 +230,7 @@ class Genode::Bit_allocator_dynamic _ram((addr_t *)_alloc.alloc(_ram_size())), _array(_ram, _bits_aligned) { - _reserve(bits, _bits_aligned - bits); + ASSERT(_reserve(bits, _bits_aligned - bits)); } ~Bit_allocator_dynamic() diff --git a/repos/os/src/server/nic_router/configuration.cc b/repos/os/src/server/nic_router/configuration.cc index 4549bd8877..25f03e865b 100644 --- a/repos/os/src/server/nic_router/configuration.cc +++ b/repos/os/src/server/nic_router/configuration.cc @@ -63,31 +63,20 @@ void Configuration::_invalid_domain(Domain &domain, Icmp_packet::Code Configuration::_init_icmp_type_3_code_on_fragm_ipv4(Xml_node const &node) const { - char const *const attr_name { "icmp_type_3_code_on_fragm_ipv4" }; - try { - Xml_attribute const &attr { node.attribute(attr_name) }; - if (attr.has_value("no")) { - return Icmp_packet::Code::INVALID; - } - uint8_t attr_val { }; - bool const attr_transl_succeeded { attr.value(attr_val) }; - Icmp_packet::Code const result { - Icmp_packet::code_from_uint8( - Icmp_packet::Type::DST_UNREACHABLE, attr_val) }; - - if (!attr_transl_succeeded || - result == Icmp_packet::Code::INVALID) { - - warning("attribute 'icmp_type_3_code_on_fragm_ipv4' has invalid " - "value, assuming value \"no\""); - - return Icmp_packet::Code::INVALID; - } + using Attribute_string = String<16>; + Icmp_packet::Code result = Icmp_packet::Code::INVALID; + Attribute_string attr_str = node.attribute_value("icmp_type_3_code_on_fragm_ipv4", Attribute_string()); + if (attr_str == "no" || attr_str == Attribute_string()) return result; + + uint8_t attr_u8 { }; + if (Genode::ascii_to(attr_str.string(), attr_u8) == attr_str.length() - 1) { + result = Icmp_packet::code_from_uint8(Icmp_packet::Type::DST_UNREACHABLE, attr_u8); + if (result != Icmp_packet::Code::INVALID) + return result; } - catch (Xml_node::Nonexistent_attribute) { - return Icmp_packet::Code::INVALID; - } + warning("attribute 'icmp_type_3_code_on_fragm_ipv4' has invalid value"); + return result; } @@ -120,119 +109,101 @@ Configuration::Configuration(Env &env, { /* do parts of domain initialization that do not lookup other domains */ node.for_each_sub_node("domain", [&] (Xml_node const node) { - try { - Domain_name const name { - node.attribute_value("name", Domain_name { }) }; + Domain_name const name { + node.attribute_value("name", Domain_name { }) }; - _domains.with_element( - name, - [&] /* match_fn */ (Domain &other_domain) - { - if (_verbose) { + _domains.with_element( + name, + [&] /* match_fn */ (Domain &other_domain) + { + if (_verbose) { - log("[", name, - "] invalid domain (name not unique) "); + log("[", name, + "] invalid domain (name not unique) "); - log("[", other_domain, - "] invalid domain (name not unique) "); - } - destroy(_alloc, &other_domain); - }, - [&] /* no_match_fn */ () - { - new (_alloc) Domain { - *this, node, name, _alloc, _domains }; + log("[", other_domain, + "] invalid domain (name not unique) "); } - ); - } - catch (Domain::Invalid) { } + destroy(_alloc, &other_domain); + }, + [&] /* no_match_fn */ () + { + Domain &domain = *new (_alloc) Domain { *this, node, name, _alloc, _domains }; + if (!domain.finish_construction()) + destroy(_alloc, &domain); + } + ); }); /* do parts of domain initialization that may lookup other domains */ while (true) { + Domain *invalid_domain_ptr { }; + _domains.for_each([&] (Domain &domain) { + if (invalid_domain_ptr) + return; - struct Retry_without_domain : Genode::Exception - { - Domain &domain; + if (!domain.init(_domains)) { + invalid_domain_ptr = &domain; + return; + } + if (_verbose) { + log("[", domain, "] initiated domain"); } + }); + if (!invalid_domain_ptr) + break; - Retry_without_domain(Domain &domain) : domain(domain) { } - }; - try { - _domains.for_each([&] (Domain &domain) { - try { domain.init(_domains); } - catch (Domain::Invalid) { throw Retry_without_domain(domain); } - if (_verbose) { - log("[", domain, "] initiated domain"); } - }); - } - catch (Retry_without_domain exception) { + /* destroy domain that became invalid during initialization */ + destroy(_alloc, invalid_domain_ptr); - /* destroy domain that became invalid during initialization */ - destroy(_alloc, &exception.domain); - - /* deinitialize the remaining domains again */ - _domains.for_each([&] (Domain &domain) { - domain.deinit(); - if (_verbose) { - log("[", domain, "] deinitiated domain"); } - }); - /* retry to initialize the remaining domains */ - continue; - } - break; + /* deinitialize the remaining domains again */ + _domains.for_each([&] (Domain &domain) { + domain.deinit(); + if (_verbose) { + log("[", domain, "] deinitiated domain"); } + }); } - try { - /* check whether we shall create a report generator */ - Xml_node const report_node = node.sub_node("report"); - try { - /* try to re-use existing reporter */ - _reporter = old_config._reporter(); - old_config._reporter = Pointer(); - } - catch (Pointer::Invalid) { - + node.with_optional_sub_node("report", [&] (Xml_node const &report_node) { + if (old_config._reporter_ptr) { + /* re-use existing reporter */ + _reporter_ptr = old_config._reporter_ptr; + old_config._reporter_ptr = nullptr; + } else { /* there is no reporter by now, create a new one */ - _reporter = *new (_alloc) Reporter(env, "state", nullptr, 4096 * 4); + _reporter_ptr = new (_alloc) Reporter(env, "state", nullptr, 4096 * 4); } /* create report generator */ - _report = *new (_alloc) - Report { - _verbose, report_node, timer, _domains, shared_quota, env.pd(), - _reporter(), report_signal_cap }; - } - catch (Genode::Xml_node::Nonexistent_sub_node) { } - + _report.construct( + _verbose, report_node, timer, _domains, shared_quota, env.pd(), + *_reporter_ptr, report_signal_cap); + }); /* initialize NIC clients */ _node.for_each_sub_node("nic-client", [&] (Xml_node const node) { - try { - Session_label const label { - node.attribute_value("label", Session_label::String { }) }; + Session_label const label { + node.attribute_value("label", Session_label::String { }) }; - Domain_name const domain { - node.attribute_value("domain", Domain_name { }) }; + Domain_name const domain { + node.attribute_value("domain", Domain_name { }) }; - _nic_clients.with_element( - label, - [&] /* match */ (Nic_client &nic_client) - { - if (_verbose) { + _nic_clients.with_element( + label, + [&] /* match */ (Nic_client &nic_client) + { + if (_verbose) { - log("[", domain, "] invalid NIC client: ", - label, " (label not unique)"); + log("[", domain, "] invalid NIC client: ", + label, " (label not unique)"); - log("[", nic_client.domain(), "] invalid NIC client: ", - nic_client.label(), " (label not unique)"); - } - destroy(_alloc, &nic_client); - }, - [&] /* no_match */ () - { - new (_alloc) Nic_client { - label, domain, alloc, old_config._nic_clients, - _nic_clients, env, timer, interfaces, *this }; + log("[", nic_client.domain(), "] invalid NIC client: ", + nic_client.label(), " (label not unique)"); } - ); - } - catch (Nic_client::Invalid) { } + destroy(_alloc, &nic_client); + }, + [&] /* no_match */ () + { + Nic_client &nic_client = *new (_alloc) Nic_client { label, domain, alloc, _nic_clients, *this }; + if (!nic_client.finish_construction(env, timer, interfaces, old_config._nic_clients)) + destroy(_alloc, &nic_client); + } + ); }); /* * Destroy old NIC clients to ensure that NIC client interfaces that were @@ -248,12 +219,8 @@ Configuration::~Configuration() _nic_clients.destroy_each(_alloc); /* destroy reporter */ - try { destroy(_alloc, &_reporter()); } - catch (Pointer::Invalid) { } - - /* destroy report generator */ - try { destroy(_alloc, &_report()); } - catch (Pointer::Invalid) { } + if (_reporter_ptr) + destroy(_alloc, _reporter_ptr); /* destroy domains */ _domains.destroy_each(_alloc); diff --git a/repos/os/src/server/nic_router/configuration.h b/repos/os/src/server/nic_router/configuration.h index a6c4fca841..2c6679707c 100644 --- a/repos/os/src/server/nic_router/configuration.h +++ b/repos/os/src/server/nic_router/configuration.h @@ -33,27 +33,33 @@ class Net::Configuration using Mac_string = Genode::String<17>; - Genode::Allocator &_alloc; - unsigned long const _max_packets_per_signal; - bool const _verbose; - bool const _verbose_packets; - bool const _verbose_packet_drop; - bool const _verbose_domain_state; - bool const _trace_packets; - bool const _icmp_echo_server; - Icmp_packet::Code const _icmp_type_3_code_on_fragm_ipv4; - Genode::Microseconds const _dhcp_discover_timeout; - Genode::Microseconds const _dhcp_request_timeout; - Genode::Microseconds const _dhcp_offer_timeout; - Genode::Microseconds const _icmp_idle_timeout; - Genode::Microseconds const _udp_idle_timeout; - Genode::Microseconds const _tcp_idle_timeout; - Genode::Microseconds const _tcp_max_segm_lifetime; - Pointer _report { }; - Pointer _reporter { }; - Domain_dict _domains { }; - Nic_client_dict _nic_clients { }; - Genode::Xml_node const _node; + Genode::Allocator &_alloc; + unsigned long const _max_packets_per_signal; + bool const _verbose; + bool const _verbose_packets; + bool const _verbose_packet_drop; + bool const _verbose_domain_state; + bool const _trace_packets; + bool const _icmp_echo_server; + Icmp_packet::Code const _icmp_type_3_code_on_fragm_ipv4; + Genode::Microseconds const _dhcp_discover_timeout; + Genode::Microseconds const _dhcp_request_timeout; + Genode::Microseconds const _dhcp_offer_timeout; + Genode::Microseconds const _icmp_idle_timeout; + Genode::Microseconds const _udp_idle_timeout; + Genode::Microseconds const _tcp_idle_timeout; + Genode::Microseconds const _tcp_max_segm_lifetime; + Genode::Constructible _report { }; + Genode::Reporter *_reporter_ptr { }; + Domain_dict _domains { }; + Nic_client_dict _nic_clients { }; + Genode::Xml_node const _node; + + /* + * Noncopyable + */ + Configuration(Configuration const &); + Configuration &operator = (Configuration const &); Icmp_packet::Code _init_icmp_type_3_code_on_fragm_ipv4(Genode::Xml_node const &node) const; @@ -77,6 +83,8 @@ class Net::Configuration ~Configuration(); + void with_report(auto const &fn) { if (_report.constructed()) fn(*_report); } + /*************** ** Accessors ** @@ -98,7 +106,6 @@ class Net::Configuration Genode::Microseconds tcp_idle_timeout() const { return _tcp_idle_timeout; } Genode::Microseconds tcp_max_segm_lifetime() const { return _tcp_max_segm_lifetime; } Domain_dict &domains() { return _domains; } - Report &report() { return _report(); } Genode::Xml_node node() const { return _node; } }; diff --git a/repos/os/src/server/nic_router/dhcp.h b/repos/os/src/server/nic_router/dhcp.h index 87e52162ab..7325bc3b59 100644 --- a/repos/os/src/server/nic_router/dhcp.h +++ b/repos/os/src/server/nic_router/dhcp.h @@ -22,8 +22,9 @@ namespace Net { template static Ipv4_address dhcp_ipv4_option(Dhcp_packet &dhcp) { - try { return dhcp.option().value(); } - catch (Dhcp_packet::Option_not_found) { return Ipv4_address { }; } + Ipv4_address result = { }; + dhcp.with_option([&] (auto opt) { result = opt.value(); }); + return result; } } diff --git a/repos/os/src/server/nic_router/dhcp_client.cc b/repos/os/src/server/nic_router/dhcp_client.cc index dd8553897f..04ded4570f 100644 --- a/repos/os/src/server/nic_router/dhcp_client.cc +++ b/repos/os/src/server/nic_router/dhcp_client.cc @@ -20,7 +20,6 @@ using namespace Genode; using namespace Net; using Message_type = Dhcp_packet::Message_type; -using Drop_packet = Net::Interface::Drop_packet; using Dhcp_options = Dhcp_packet::Options_aggregator; @@ -46,12 +45,6 @@ void append_param_req_list(Dhcp_options &dhcp_opts) ** Dhcp_client ** *****************/ -Configuration &Dhcp_client::_config() { return _domain().config(); }; - - -Domain &Dhcp_client::_domain() { return _interface.domain(); } - - Dhcp_client::Dhcp_client(Cached_timer &timer, Interface &interface) : @@ -63,17 +56,17 @@ Dhcp_client::Dhcp_client(Cached_timer &timer, void Dhcp_client::discover() { enum { DISCOVER_PKT_SIZE = 309 }; - _set_state(State::SELECT, _config().dhcp_discover_timeout()); + _set_state(State::SELECT, _interface.config().dhcp_discover_timeout()); _send(Message_type::DISCOVER, Ipv4_address(), Ipv4_address(), Ipv4_address(), DISCOVER_PKT_SIZE); } -void Dhcp_client::_rerequest(State next_state) +void Dhcp_client::_rerequest(State next_state, Domain &domain) { enum { REREQUEST_PKT_SIZE = 309 }; - _set_state(next_state, _rerequest_timeout(2)); - Ipv4_address const client_ip = _domain().ip_config().interface().address; + _set_state(next_state, _rerequest_timeout(2, domain)); + Ipv4_address client_ip = domain.ip_config().interface().address; _send(Message_type::REQUEST, client_ip, Ipv4_address(), client_ip, REREQUEST_PKT_SIZE); } @@ -86,7 +79,7 @@ void Dhcp_client::_set_state(State state, Microseconds timeout) } -Microseconds Dhcp_client::_rerequest_timeout(unsigned lease_time_div_log2) +Microseconds Dhcp_client::_rerequest_timeout(unsigned lease_time_div_log2, Domain &domain) { /* FIXME limit the time because of shortcomings in timeout framework */ enum { MAX_TIMEOUT_SEC = 3600 }; @@ -94,14 +87,8 @@ Microseconds Dhcp_client::_rerequest_timeout(unsigned lease_time_div_log2) if (timeout_sec > MAX_TIMEOUT_SEC) { timeout_sec = MAX_TIMEOUT_SEC; - if (_interface.config().verbose()) { - try { - log("[", _interface.domain(), "] prune re-request timeout of " - "DHCP client"); - } - catch (Pointer::Invalid) { - log("[?] prune re-request timeout of DHCP client"); } - } + if (_interface.config().verbose()) + log("[", domain, "] prune re-request timeout of DHCP client"); } return Microseconds(timeout_sec * 1000 * 1000); } @@ -109,35 +96,40 @@ Microseconds Dhcp_client::_rerequest_timeout(unsigned lease_time_div_log2) void Dhcp_client::_handle_timeout(Duration) { - switch (_state) { - case State::BOUND: _rerequest(State::RENEW); break; - case State::RENEW: _rerequest(State::REBIND); break; - case State::REBIND: _domain().discard_ip_config(); [[fallthrough]]; - default: discover(); - } + _interface.with_domain( + [&] /* domain_fn */ (Domain &domain) { + switch (_state) { + case State::BOUND: _rerequest(State::RENEW, domain); break; + case State::RENEW: _rerequest(State::REBIND, domain); break; + case State::REBIND: + + domain.discard_ip_config(); + discover(); + break; + + default: discover(); break; + } + }, + [&] /* no_domain_fn */ { + if (_interface.config().verbose()) + log("[?] no domain on DHCP timeout"); }); } -void Dhcp_client::handle_dhcp_reply(Dhcp_packet &dhcp) +Packet_result Dhcp_client::handle_dhcp_reply(Dhcp_packet &dhcp, Domain &domain) { - try { - Message_type const msg_type = - dhcp.option().value(); + Packet_result result { }; + auto no_msg_type_fn = [&] { result = packet_drop("DHCP request misses option \"Message Type\""); }; + auto msg_type_fn = [&] (Dhcp_packet::Message_type_option const &msg_type) { if (_interface.config().verbose_domain_state()) { - if (msg_type == Message_type::OFFER) { - Ipv4_address dns_server; - Ipv4_address subnet_mask; - Ipv4_address router_ip; + if (msg_type.value() == Message_type::OFFER) { + Ipv4_address dns_server, subnet_mask, router_ip; + dhcp.with_option([&] (auto opt) { dns_server = opt.value(); }); + dhcp.with_option([&] (auto opt) { subnet_mask = opt.value(); }); + dhcp.with_option([&] (auto opt) { router_ip = opt.value(); }); - try { dns_server = dhcp.option().value(); } - catch (Dhcp_packet::Option_not_found) { } - try { subnet_mask = dhcp.option().value(); } - catch (Dhcp_packet::Option_not_found) { } - try { router_ip = dhcp.option().value(); } - catch (Net::Dhcp_packet::Option_not_found) { } - - log("[", _interface.domain(), "] dhcp offer from ", + log("[", domain, "] dhcp offer from ", dhcp.siaddr(), ", offering ", dhcp.yiaddr(), ", subnet-mask ", subnet_mask, @@ -145,38 +137,40 @@ void Dhcp_client::handle_dhcp_reply(Dhcp_packet &dhcp) ", DNS server ", dns_server); } } - switch (_state) { case State::SELECT: - if (msg_type != Message_type::OFFER) { - throw Drop_packet("DHCP client expects an offer"); + if (msg_type.value() != Message_type::OFFER) { + result = packet_drop("DHCP client expects an offer"); + break; } enum { REQUEST_PKT_SIZE = 321 }; - _set_state(State::REQUEST, _config().dhcp_request_timeout()); + _set_state(State::REQUEST, _interface.config().dhcp_request_timeout()); _send(Message_type::REQUEST, Ipv4_address(), dhcp.option().value(), dhcp.yiaddr(), REQUEST_PKT_SIZE); + result = packet_handled(); break; case State::REQUEST: case State::RENEW: case State::REBIND: { - if (msg_type != Message_type::ACK) { - throw Drop_packet("DHCP client expects an acknowledgement"); + if (msg_type.value() != Message_type::ACK) { + result = packet_drop("DHCP client expects an acknowledgement"); + break; } _lease_time_sec = dhcp.option().value(); - _set_state(State::BOUND, _rerequest_timeout(1)); - _domain().ip_config_from_dhcp_ack(dhcp); + _set_state(State::BOUND, _rerequest_timeout(1, domain)); + domain.ip_config_from_dhcp_ack(dhcp); + result = packet_handled(); break; } - default: throw Drop_packet("DHCP client doesn't expect a packet"); + default: result = packet_drop("DHCP client doesn't expect a packet"); break; } - } - catch (Dhcp_packet::Option_not_found) { - throw Drop_packet("DHCP reply misses required option"); - } + }; + dhcp.with_option(msg_type_fn, no_msg_type_fn); + return result; } @@ -243,8 +237,7 @@ void Dhcp_client::_send(Message_type msg_type, } break; - default: - throw Interface::Bad_send_dhcp_args(); + default: ASSERT_NEVER_REACHED; } dhcp_opts.append_option(); diff --git a/repos/os/src/server/nic_router/dhcp_client.h b/repos/os/src/server/nic_router/dhcp_client.h index 066cdc726a..ab1e0dd453 100644 --- a/repos/os/src/server/nic_router/dhcp_client.h +++ b/repos/os/src/server/nic_router/dhcp_client.h @@ -16,6 +16,7 @@ /* local includes */ #include +#include /* Genode includes */ #include @@ -45,9 +46,9 @@ class Net::Dhcp_client void _handle_timeout(Genode::Duration); - void _rerequest(State next_state); + void _rerequest(State next_state, Domain &domain); - Genode::Microseconds _rerequest_timeout(unsigned lease_time_div_log2); + Genode::Microseconds _rerequest_timeout(unsigned lease_time_div_log2, Domain &domain); void _set_state(State state, Genode::Microseconds timeout); @@ -57,16 +58,12 @@ class Net::Dhcp_client Ipv4_address requested_ip, Genode::size_t pkt_size); - Configuration &_config(); - - Domain &_domain(); - public: Dhcp_client(Cached_timer &timer, Interface &interface); - void handle_dhcp_reply(Dhcp_packet &dhcp); + [[nodiscard]] Packet_result handle_dhcp_reply(Dhcp_packet &dhcp, Domain &domain); void discover(); }; diff --git a/repos/os/src/server/nic_router/dhcp_server.cc b/repos/os/src/server/nic_router/dhcp_server.cc index 756c22cb0e..2692c80e49 100644 --- a/repos/os/src/server/nic_router/dhcp_server.cc +++ b/repos/os/src/server/nic_router/dhcp_server.cc @@ -26,26 +26,31 @@ using namespace Genode; ** Dhcp_server_base ** **********************/ -Dhcp_server_base::Dhcp_server_base(Xml_node const &node, - Domain const &domain, - Allocator &alloc) -: - _alloc { alloc } +Dhcp_server_base::Dhcp_server_base(Allocator &alloc) : _alloc { alloc } { } + + +bool Dhcp_server_base::finish_construction(Xml_node const &node, Domain const &domain) { + bool result = true; node.for_each_sub_node("dns-server", [&] (Xml_node const &sub_node) { + if (!result) + return; Dns_server::construct( - alloc, sub_node.attribute_value("ip", Ipv4_address { }), + _alloc, sub_node.attribute_value("ip", Ipv4_address { }), [&] /* handle_success */ (Dns_server &server) { _dns_servers.insert_as_tail(server); }, [&] /* handle_failure */ () { - _invalid(domain, "invalid DNS server entry"); + result = _invalid(domain, "invalid DNS server entry"); } ); }); + if (!result) + return result; + node.with_optional_sub_node("dns-domain", [&] (Xml_node const &sub_node) { xml_node_with_attribute(sub_node, "name", [&] (Xml_attribute const &attr) { _dns_domain_name.set_to(attr); @@ -58,6 +63,7 @@ Dhcp_server_base::Dhcp_server_base(Xml_node const &node, } }); }); + return result; } @@ -67,13 +73,13 @@ Dhcp_server_base::~Dhcp_server_base() } -void Dhcp_server_base::_invalid(Domain const &domain, +bool Dhcp_server_base::_invalid(Domain const &domain, char const *reason) { if (domain.config().verbose()) { log("[", domain, "] invalid DHCP server (", reason, ")"); } - throw Domain::Invalid(); + return false; } @@ -83,37 +89,53 @@ void Dhcp_server_base::_invalid(Domain const &domain, bool Dhcp_server::dns_servers_empty() const { - if (_dns_config_from.valid()) { - + if (_dns_config_from_ptr) return _resolve_dns_config_from().dns_servers_empty(); - } return _dns_servers.empty(); } -Dhcp_server::Dhcp_server(Xml_node const node, - Domain &domain, - Allocator &alloc, - Ipv4_address_prefix const &interface, - Domain_dict &domains) +Dhcp_server::Dhcp_server(Xml_node const node, Allocator &alloc) : - Dhcp_server_base(node, domain, alloc), - _dns_config_from(_init_dns_config_from(node, domains)), + Dhcp_server_base(alloc), _ip_lease_time (_init_ip_lease_time(node)), _ip_first(node.attribute_value("ip_first", Ipv4_address())), _ip_last(node.attribute_value("ip_last", Ipv4_address())), _ip_first_raw(_ip_first.to_uint32_little_endian()), _ip_count(_ip_last.to_uint32_little_endian() - _ip_first_raw + 1), _ip_alloc(alloc, _ip_count) +{ } + + +bool Dhcp_server::finish_construction(Xml_node const node, + Domain_dict &domains, + Domain &domain, + Ipv4_address_prefix const &interface) { + if (!Dhcp_server_base::finish_construction(node, domain)) + return false; + + if (_dns_servers.empty() && !_dns_domain_name.valid()) { + Domain_name dns_config_from = node.attribute_value("dns_config_from", Domain_name()); + if (dns_config_from != Domain_name()) { + bool result = true; + domains.with_element(dns_config_from, + [&] (Domain &remote_domain) { _dns_config_from_ptr = &remote_domain; }, + [&] { result = _invalid(domain, "invalid dns_config_from attribute"); }); + if (!result) + return result; + } + } if (!interface.prefix_matches(_ip_first)) { - _invalid(domain, "first IP does not match domain subnet"); } + return _invalid(domain, "first IP does not match domain subnet"); } if (!interface.prefix_matches(_ip_last)) { - _invalid(domain, "last IP does not match domain subnet"); } + return _invalid(domain, "last IP does not match domain subnet"); } if (interface.address.is_in_range(_ip_first, _ip_last)) { - _invalid(domain, "IP range contains IP address of domain"); } + return _invalid(domain, "IP range contains IP address of domain"); } + + return true; } @@ -137,8 +159,8 @@ void Dhcp_server::print(Output &output) const _dns_domain_name.with_string([&] (Dns_domain_name::String const &str) { Genode::print(output, "DNS domain name ", str, ", "); }); - try { Genode::print(output, "DNS config from ", _dns_config_from(), ", "); } - catch (Pointer::Invalid) { } + with_dns_config_from([&] (Domain &domain) { + Genode::print(output, "DNS config from ", domain, ", "); }); Genode::print(output, "IP first ", _ip_first, ", last ", _ip_last, @@ -157,77 +179,36 @@ bool Dhcp_server::config_equal_to_that_of(Dhcp_server const &other) const Ipv4_config const &Dhcp_server::_resolve_dns_config_from() const { - return _dns_config_from().ip_config(); + return _dns_config_from_ptr->ip_config(); } -Ipv4_address Dhcp_server::alloc_ip() +Dhcp_server::Alloc_ip_result Dhcp_server::alloc_ip() { - try { - return Ipv4_address::from_uint32_little_endian(_ip_alloc.alloc() + - _ip_first_raw); - } - catch (Bit_allocator_dynamic::Out_of_indices) { - throw Alloc_ip_failed(); - } + Alloc_ip_result result = Alloc_ip_error(); + _ip_alloc.alloc().with_result( + [&] (addr_t ip_raw) { result = Alloc_ip_result(Ipv4_address::from_uint32_little_endian(ip_raw + _ip_first_raw)); }, + [&] (auto) { }); + return result; } -void Dhcp_server::alloc_ip(Ipv4_address const &ip) +bool Dhcp_server::alloc_ip(Ipv4_address const &ip) { - try { _ip_alloc.alloc_addr(ip.to_uint32_little_endian() - _ip_first_raw); } - catch (Bit_allocator_dynamic::Range_conflict) { throw Alloc_ip_failed(); } - catch (Bit_array_dynamic::Invalid_index_access) { throw Alloc_ip_failed(); } + return _ip_alloc.alloc_addr(ip.to_uint32_little_endian() - _ip_first_raw); } -void Dhcp_server::free_ip(Domain const &domain, - Ipv4_address const &ip) +void Dhcp_server::free_ip(Ipv4_address const &ip) { - /* - * The messages in the catch directives are printed as errors and - * independent from the routers verbosity configuration because the - * exceptions they indicate should never be thrown. - */ - try { - _ip_alloc.free(ip.to_uint32_little_endian() - _ip_first_raw); - } - catch (Bit_allocator_dynamic::Out_of_indices) { - - error("[", domain, "] DHCP server: out of indices while freeing IP ", - ip, " (IP range: first ", _ip_first, " last ", _ip_last, ")"); - } - catch (Bit_array_dynamic::Invalid_index_access) { - - error("[", domain, "] DHCP server: invalid index while freeing IP ", - ip, " (IP range: first ", _ip_first, " last ", _ip_last, ")"); - } -} - - -Pointer Dhcp_server::_init_dns_config_from(Genode::Xml_node const node, - Domain_dict &domains) -{ - if (!_dns_servers.empty() || - _dns_domain_name.valid()) { - - return Pointer(); - } - Domain_name dns_config_from = - node.attribute_value("dns_config_from", Domain_name()); - - if (dns_config_from == Domain_name()) { - return Pointer(); - } - return domains.deprecated_find_by_name(dns_config_from); + ASSERT(_ip_alloc.free(ip.to_uint32_little_endian() - _ip_first_raw)); } bool Dhcp_server::has_invalid_remote_dns_cfg() const { - if (_dns_config_from.valid()) { - return !_dns_config_from().ip_config().valid(); - } + if (_dns_config_from_ptr) + return !_dns_config_from_ptr->ip_config().valid(); return false; } @@ -269,19 +250,6 @@ bool Dhcp_allocation::_higher(Mac_address const &mac) const } -Dhcp_allocation &Dhcp_allocation::find_by_mac(Mac_address const &mac) -{ - if (mac == _mac) { - return *this; } - - Dhcp_allocation *const allocation = child(_higher(mac)); - if (!allocation) { - throw Dhcp_allocation_tree::No_match(); } - - return allocation->find_by_mac(mac); -} - - void Dhcp_allocation::print(Output &output) const { Genode::print(output, "MAC ", _mac, " IP ", _ip); @@ -292,17 +260,3 @@ void Dhcp_allocation::_handle_timeout(Duration) { _interface.dhcp_allocation_expired(*this); } - - -/************************** - ** Dhcp_allocation_tree ** - **************************/ - -Dhcp_allocation & -Dhcp_allocation_tree::find_by_mac(Mac_address const &mac) const -{ - if (!_tree.first()) { - throw No_match(); } - - return _tree.first()->find_by_mac(mac); -} diff --git a/repos/os/src/server/nic_router/dhcp_server.h b/repos/os/src/server/nic_router/dhcp_server.h index 6022272797..e48cc25f01 100644 --- a/repos/os/src/server/nic_router/dhcp_server.h +++ b/repos/os/src/server/nic_router/dhcp_server.h @@ -17,7 +17,6 @@ /* local includes */ #include #include -#include #include #include #include @@ -52,14 +51,15 @@ class Net::Dhcp_server_base Dns_server_list _dns_servers { }; Dns_domain_name _dns_domain_name { _alloc }; - void _invalid(Domain const &domain, - char const *reason); + [[nodiscard]] bool _invalid(Domain const &domain, + char const *reason); public: - Dhcp_server_base(Genode::Xml_node const &node, - Domain const &domain, - Genode::Allocator &alloc); + Dhcp_server_base(Genode::Allocator &alloc); + + [[nodiscard]] bool finish_construction(Genode::Xml_node const &node, + Domain const &domain); ~Dhcp_server_base(); }; @@ -70,7 +70,7 @@ class Net::Dhcp_server : private Genode::Noncopyable, { private: - Pointer const _dns_config_from; + Domain *_dns_config_from_ptr { }; Genode::Microseconds const _ip_lease_time; Ipv4_address const _ip_first; Ipv4_address const _ip_last; @@ -80,37 +80,43 @@ class Net::Dhcp_server : private Genode::Noncopyable, Genode::Microseconds _init_ip_lease_time(Genode::Xml_node const node); - Pointer _init_dns_config_from(Genode::Xml_node const node, - Domain_dict &domains); - Ipv4_config const &_resolve_dns_config_from() const; + /* + * Noncopyable + */ + Dhcp_server(Dhcp_server const &); + Dhcp_server &operator = (Dhcp_server const &); + public: enum { DEFAULT_IP_LEASE_TIME_SEC = 3600 }; - struct Alloc_ip_failed : Genode::Exception { }; - struct Invalid : Genode::Exception { }; + struct Invalid : Genode::Exception { }; - Dhcp_server(Genode::Xml_node const node, - Domain &domain, - Genode::Allocator &alloc, - Ipv4_address_prefix const &interface, - Domain_dict &domains); + Dhcp_server(Genode::Xml_node const node, + Genode::Allocator &alloc); - Ipv4_address alloc_ip(); + [[nodiscard]] bool finish_construction(Genode::Xml_node const node, + Domain_dict &domains, + Domain &domain, + Ipv4_address_prefix const &interface); - void alloc_ip(Ipv4_address const &ip); + struct Alloc_ip_error { }; + using Alloc_ip_result = Genode::Attempt; - void free_ip(Domain const &domain, - Ipv4_address const &ip); + [[nodiscard]] Alloc_ip_result alloc_ip(); + + [[nodiscard]] bool alloc_ip(Ipv4_address const &ip); + + void free_ip(Ipv4_address const &ip); bool has_invalid_remote_dns_cfg() const; template void for_each_dns_server_ip(FUNC && functor) const { - if (_dns_config_from.valid()) { + if (_dns_config_from_ptr) { _resolve_dns_config_from().for_each_dns_server( [&] (Dns_server const &dns_server) { @@ -129,7 +135,7 @@ class Net::Dhcp_server : private Genode::Noncopyable, Dns_domain_name const &dns_domain_name() const { - if (_dns_config_from.valid()) { + if (_dns_config_from_ptr) { return _resolve_dns_config_from().dns_domain_name(); } return _dns_domain_name; @@ -137,6 +143,12 @@ class Net::Dhcp_server : private Genode::Noncopyable, bool config_equal_to_that_of(Dhcp_server const &dhcp_server) const; + void with_dns_config_from(auto const &fn) const + { + if (_dns_config_from_ptr) + fn(*_dns_config_from_ptr); + } + /********* ** log ** @@ -149,7 +161,6 @@ class Net::Dhcp_server : private Genode::Noncopyable, ** Accessors ** ***************/ - Domain &dns_config_from() { return _dns_config_from(); } Genode::Microseconds ip_lease_time() const { return _ip_lease_time; } }; @@ -179,7 +190,18 @@ class Net::Dhcp_allocation : public Genode::Avl_node, ~Dhcp_allocation(); - Dhcp_allocation &find_by_mac(Mac_address const &mac); + void find_by_mac(Mac_address const &mac, auto const &match_fn, auto const &no_match_fn) + { + if (mac == _mac) { + match_fn(*this); + return; + } + Dhcp_allocation *allocation_ptr = child(_higher(mac)); + if (allocation_ptr) + allocation_ptr->find_by_mac(mac, match_fn, no_match_fn); + else + no_match_fn(); + } void lifetime(Genode::Microseconds lifetime); @@ -218,9 +240,13 @@ struct Net::Dhcp_allocation_tree public: - struct No_match : Genode::Exception { }; - - Dhcp_allocation &find_by_mac(Mac_address const &mac) const; + void find_by_mac(Mac_address const &mac, auto const &match_fn, auto const &no_match_fn) const + { + if (_tree.first()) + _tree.first()->find_by_mac(mac, match_fn, no_match_fn); + else + no_match_fn(); + } void insert(Dhcp_allocation &dhcp_alloc) { diff --git a/repos/os/src/server/nic_router/direct_rule.cc b/repos/os/src/server/nic_router/direct_rule.cc deleted file mode 100644 index 3700124cd7..0000000000 --- a/repos/os/src/server/nic_router/direct_rule.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* - * \brief Routing rule for direct traffic between two interfaces - * \author Martin Stein - * \date 2016-08-19 - */ - -/* - * Copyright (C) 2016-2017 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. - */ - -/* local includes */ -#include - -using namespace Net; -using namespace Genode; - - -Direct_rule_base::Direct_rule_base(Xml_node const node) -: - _dst(node.attribute_value("dst", Ipv4_address_prefix())) -{ - if (!_dst.valid()) { - throw Invalid(); } -} - - -void Direct_rule_base::print(Output &output) const -{ - Genode::print(output, _dst); -} diff --git a/repos/os/src/server/nic_router/direct_rule.h b/repos/os/src/server/nic_router/direct_rule.h index a33bb69590..0c6c4c924b 100644 --- a/repos/os/src/server/nic_router/direct_rule.h +++ b/repos/os/src/server/nic_router/direct_rule.h @@ -40,16 +40,14 @@ class Net::Direct_rule_base public: - struct Invalid : Genode::Exception { }; - - Direct_rule_base(Genode::Xml_node const node); + Direct_rule_base(Ipv4_address_prefix const dst) : _dst(dst) { } /********* ** log ** *********/ - void print(Genode::Output &output) const; + void print(Genode::Output &output) const { Genode::print(output, "dst ", _dst); } /*************** @@ -64,7 +62,7 @@ template struct Net::Direct_rule : Direct_rule_base, Direct_rule_list::Element { - Direct_rule(Genode::Xml_node const node) : Direct_rule_base(node) { } + Direct_rule(Ipv4_address_prefix const &dst) : Direct_rule_base(dst) { } }; diff --git a/repos/os/src/server/nic_router/dns.cc b/repos/os/src/server/nic_router/dns.cc index d4cbe71f83..874e2eb010 100644 --- a/repos/os/src/server/nic_router/dns.cc +++ b/repos/os/src/server/nic_router/dns.cc @@ -47,10 +47,10 @@ void Dns_domain_name::set_to(Dns_domain_name const &name) { if (name.valid()) { name.with_string([&] (String const &string) { - if (_string.valid()) { - _string() = string; + if (_string_ptr) { + *_string_ptr = string; } else { - _string = *new (_alloc) String { string }; + _string_ptr = new (_alloc) String { string }; } }); } else { @@ -63,10 +63,10 @@ void Dns_domain_name::set_to(Xml_attribute const &name_attr) { name_attr.with_raw_value([&] (char const *base, size_t size) { if (size < STRING_CAPACITY) { - if (_string.valid()) { - _string() = Cstring { base, size }; + if (_string_ptr) { + *_string_ptr = Cstring { base, size }; } else { - _string = *new (_alloc) String { Cstring { base, size } }; + _string_ptr = new (_alloc) String { Cstring { base, size } }; } } else { set_invalid(); @@ -79,10 +79,10 @@ void Dns_domain_name::set_to(Dhcp_packet::Domain_name const &name_option) { name_option.with_string([&] (char const *base, size_t size) { if (size < STRING_CAPACITY) { - if (_string.valid()) { - _string() = Cstring { base, size }; + if (_string_ptr) { + *_string_ptr = Cstring { base, size }; } else { - _string = *new (_alloc) String { Cstring { base, size } }; + _string_ptr = new (_alloc) String { Cstring { base, size } }; } } else { set_invalid(); @@ -93,22 +93,21 @@ void Dns_domain_name::set_to(Dhcp_packet::Domain_name const &name_option) void Dns_domain_name::set_invalid() { - if (_string.valid()) { - _alloc.free(&_string(), sizeof(String)); - _string = { }; + if (_string_ptr) { + _alloc.free(_string_ptr, sizeof(String)); + _string_ptr = nullptr; } } bool Dns_domain_name::equal_to(Dns_domain_name const &other) const { - if (_string.valid()) { - if (other._string.valid()) { - return _string() == other._string(); - } + if (_string_ptr) { + if (other._string_ptr) + return *_string_ptr == *other._string_ptr; return false; } - return !other._string.valid(); + return !other._string_ptr; } diff --git a/repos/os/src/server/nic_router/dns.h b/repos/os/src/server/nic_router/dns.h index 2f8fb6e2a8..3f530194b3 100644 --- a/repos/os/src/server/nic_router/dns.h +++ b/repos/os/src/server/nic_router/dns.h @@ -16,7 +16,6 @@ /* local includes */ #include -#include /* Genode includes */ #include @@ -84,7 +83,13 @@ class Net::Dns_domain_name : private Genode::Noncopyable private: Genode::Allocator &_alloc; - Pointer _string { }; + String *_string_ptr { }; + + /* + * Noncopyable + */ + Dns_domain_name(Dns_domain_name const &); + Dns_domain_name &operator = (Dns_domain_name const &); public: @@ -100,14 +105,13 @@ class Net::Dns_domain_name : private Genode::Noncopyable void set_invalid(); - bool valid() const { return _string.valid(); } + bool valid() const { return _string_ptr; } template void with_string(FUNC && func) const { - if (_string.valid()) { - func(_string()); - } + if (_string_ptr) + func(*_string_ptr); } bool equal_to(Dns_domain_name const &other) const; diff --git a/repos/os/src/server/nic_router/domain.cc b/repos/os/src/server/nic_router/domain.cc index 491c8a1a6c..0fc0bb3559 100644 --- a/repos/os/src/server/nic_router/domain.cc +++ b/repos/os/src/server/nic_router/domain.cc @@ -41,10 +41,9 @@ void Domain::_log_ip_config() const bool Domain::ready() const { - if (_dhcp_server.valid()) { - if (_dhcp_server().has_invalid_remote_dns_cfg()) { + if (_dhcp_server_ptr) { + if (_dhcp_server_ptr->has_invalid_remote_dns_cfg()) return false; - } } return true; } @@ -61,8 +60,7 @@ void Domain::update_ready_state() void Domain::_prepare_reconstructing_ip_config() { - if (!_ip_config_dynamic) { - throw Ip_config_static(); } + ASSERT(_ip_config_dynamic); /* discard old IP config if any */ if (ip_config().valid()) { @@ -124,8 +122,7 @@ void Domain::_finish_reconstructing_ip_config() }); } /* force report if configured */ - try { _config.report().handle_config(); } - catch (Pointer::Invalid) { } + _config.with_report([&] (Report &r) { r.handle_config(); }); } @@ -168,47 +165,75 @@ void Domain::try_reuse_ip_config(Domain const &domain) } -void Domain::_read_forward_rules(Cstring const &protocol, +bool Domain::_read_forward_rules(Cstring const &protocol, Domain_dict &domains, Xml_node const node, char const *type, Forward_rule_tree &rules) { + bool result = true; node.for_each_sub_node(type, [&] (Xml_node const node) { - try { - Forward_rule &rule = *new (_alloc) Forward_rule(domains, node); - rules.insert(&rule); - if (_config.verbose()) { - log("[", *this, "] ", protocol, " forward rule: ", rule); } + if (!result) + return; + + Port port = node.attribute_value("port", Port(0)); + if (port == Port(0) || dynamic_port(port)) { + result = _invalid("invalid forward rule"); + return; } - catch (Forward_rule::Invalid) { _invalid("invalid forward rule"); } + Ipv4_address to_ip = node.attribute_value("to", Ipv4_address()); + if (!to_ip.valid()) { + result = _invalid("invalid forward rule"); + return; + } + domains.find_by_domain_attr(node, + [&] (Domain &domain) { + Forward_rule &rule = *new (_alloc) + Forward_rule(port, to_ip, node.attribute_value("to_port", Port(0)), domain); + rules.insert(&rule); + if (_config.verbose()) + log("[", *this, "] ", protocol, " forward rule: ", rule); }, + [&] { result = _invalid("invalid forward rule"); }); }); + return result; } -void Domain::_invalid(char const *reason) const +bool Domain::_invalid(char const *reason) const { if (_config.verbose()) { log("[", *this, "] invalid domain (", reason, ")"); } - throw Invalid(); + return false; } -void Domain::_read_transport_rules(Cstring const &protocol, +bool Domain::_read_transport_rules(Cstring const &protocol, Domain_dict &domains, Xml_node const node, char const *type, Transport_rule_list &rules) { + bool result = true; node.for_each_sub_node(type, [&] (Xml_node const node) { - try { - rules.insert(*new (_alloc) - Transport_rule(domains, node, _alloc, protocol, _config, *this)); + if (!result) + return; + + Ipv4_address_prefix dst = node.attribute_value("dst", Ipv4_address_prefix()); + if (!dst.valid()) { + result = _invalid("invalid transport rule"); + return; } - catch (Transport_rule::Invalid) { _invalid("invalid transport rule"); } - catch (Permit_any_rule::Invalid) { _invalid("invalid permit-any rule"); } - catch (Permit_single_rule::Invalid) { _invalid("invalid permit rule"); } + Transport_rule &rule = *new (_alloc) Transport_rule(dst, _alloc); + if (!rule.finish_construction(domains, node, protocol, _config, *this)) { + destroy(_alloc, &rule); + result = _invalid("invalid transport rule"); + return; + } + rules.insert(rule); + if (_config.verbose()) + log("[", *this, "] ", protocol, " rule: ", rule); }); + return result; } @@ -245,12 +270,18 @@ Domain::Domain(Configuration &config, String<160>()).string() } { _log_ip_config(); +} - if (Domain::name() == Domain_name()) { - _invalid("missing name attribute"); } + +bool Domain::finish_construction() const +{ + if (Domain::name() == Domain_name()) + return _invalid("missing name attribute"); if (_config.verbose_domain_state()) { log("[", *this, "] NIC sessions: ", _interface_cnt); } + + return true; } @@ -260,7 +291,7 @@ Link_side_tree &Domain::links(L3_protocol const protocol) case L3_protocol::TCP: return _tcp_links; case L3_protocol::UDP: return _udp_links; case L3_protocol::ICMP: return _icmp_links; - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -271,96 +302,84 @@ Domain::~Domain() } -Dhcp_server &Domain::dhcp_server() -{ - Dhcp_server &dhcp_server = _dhcp_server(); - if (dhcp_server.has_invalid_remote_dns_cfg()) { - throw Pointer::Invalid(); - } - return dhcp_server; -} - - -void Domain::init(Domain_dict &domains) +bool Domain::init(Domain_dict &domains) { /* read DHCP server configuration */ - try { - Xml_node const dhcp_server_node = _node.sub_node("dhcp-server"); + bool result = true; + _node.with_optional_sub_node("dhcp-server", [&] (Xml_node const &dhcp_server_node) { if (_ip_config_dynamic) { - _invalid("DHCP server and client at once"); } - - try { - Dhcp_server &dhcp_server = *new (_alloc) - Dhcp_server(dhcp_server_node, *this, _alloc, - ip_config().interface(), domains); - - try { - dhcp_server. - dns_config_from().ip_config_dependents().insert(this); - } - catch (Pointer::Invalid) { } - - _dhcp_server = dhcp_server; - if (_config.verbose()) { - log("[", *this, "] DHCP server: ", _dhcp_server()); } + result = _invalid("DHCP server and client at once"); + return; } - catch (Bit_allocator_dynamic::Out_of_indices) { - - /* - * This message is printed independent from the routers - * verbosity configuration in order to track down an exception - * of type Bit_allocator_dynamic::Out_of_indices that was - * previously not caught. We have observed this exception once, - * but without a specific use pattern that would - * enable for a systematic reproduction of the issue. - * The uncaught exception was observed in a 21.03 Sculpt OS - * with a manually configured router, re-configuration involved. - */ - log("[", *this, "] DHCP server: failed to initialize ", - "(IP range: first ", - dhcp_server_node.attribute_value("ip_first", Ipv4_address()), - " last ", - dhcp_server_node.attribute_value("ip_last", Ipv4_address()), - ")"); - - throw Dhcp_server::Invalid { }; + Dhcp_server &dhcp_server = *new (_alloc) Dhcp_server(dhcp_server_node, _alloc); + if (!dhcp_server.finish_construction(dhcp_server_node, domains, *this, ip_config().interface())) { + result = _invalid("invalid DHCP server"); + return; } - } - catch (Xml_node::Nonexistent_sub_node) { } - catch (Dhcp_server::Invalid) { _invalid("invalid DHCP server"); } + dhcp_server.with_dns_config_from([&] (Domain &domain) { + domain.ip_config_dependents().insert(this); }); - /* read forward rules */ - _read_forward_rules(tcp_name(), domains, _node, "tcp-forward", - _tcp_forward_rules); - _read_forward_rules(udp_name(), domains, _node, "udp-forward", - _udp_forward_rules); + _dhcp_server_ptr = &dhcp_server; + if (_config.verbose()) { + log("[", *this, "] DHCP server: ", dhcp_server); } + }); + if (!result) + return result; - /* read UDP and TCP rules */ - _read_transport_rules(tcp_name(), domains, _node, "tcp", _tcp_rules); - _read_transport_rules(udp_name(), domains, _node, "udp", _udp_rules); + /* read forward and transport rules */ + if (!_read_forward_rules(tcp_name(), domains, _node, "tcp-forward", _tcp_forward_rules) || + !_read_forward_rules(udp_name(), domains, _node, "udp-forward", _udp_forward_rules) || + !_read_transport_rules(tcp_name(), domains, _node, "tcp", _tcp_rules) || + !_read_transport_rules(udp_name(), domains, _node, "udp", _udp_rules)) + return false; /* read NAT rules */ _node.for_each_sub_node("nat", [&] (Xml_node const node) { - try { - Nat_rule &rule = *new (_alloc) - Nat_rule(domains, _tcp_port_alloc, _udp_port_alloc, - _icmp_port_alloc, node, _config.verbose()); - _nat_rules.insert(&rule); - if (_config.verbose()) { - log("[", *this, "] NAT rule: ", rule); } - } - catch (Nat_rule::Invalid) { _invalid("invalid NAT rule"); } + if (!result) + return; + + domains.find_by_domain_attr(node, + [&] (Domain &domain) { + Nat_rule &rule = *new (_alloc) + Nat_rule(domain, _tcp_port_alloc, _udp_port_alloc, + _icmp_port_alloc, node, _config.verbose()); + _nat_rules.insert(&rule); + if (_config.verbose()) + log("[", *this, "] NAT rule: ", rule); }, + [&] { result = _invalid("invalid NAT rule"); }); }); + if (!result) + return result; + /* read ICMP rules */ _node.for_each_sub_node("icmp", [&] (Xml_node const node) { - try { _icmp_rules.insert(*new (_alloc) Ip_rule(domains, node)); } - catch (Ip_rule::Invalid) { _invalid("invalid ICMP rule"); } + if (!result) + return; + + Ipv4_address_prefix dst = node.attribute_value("dst", Ipv4_address_prefix()); + if (!dst.valid()) { + result = _invalid("invalid ICMP rule"); + return; + } + domains.find_by_domain_attr(node, + [&] (Domain &domain) { _icmp_rules.insert(*new (_alloc) Ip_rule(dst, domain)); }, + [&] { result = _invalid("invalid ICMP rule"); }); }); /* read IP rules */ _node.for_each_sub_node("ip", [&] (Xml_node const node) { - try { _ip_rules.insert(*new (_alloc) Ip_rule(domains, node)); } - catch (Ip_rule::Invalid) { _invalid("invalid IP rule"); } + if (!result) + return; + + Ipv4_address_prefix dst = node.attribute_value("dst", Ipv4_address_prefix()); + if (!dst.valid()) { + result = _invalid("invalid IP rule"); + return; + } + domains.find_by_domain_attr(node, + [&] (Domain &domain) { _ip_rules.insert(*new (_alloc) Ip_rule(dst, domain)); }, + [&] { result = _invalid("invalid IP rule"); }); }); + return result; } @@ -373,22 +392,11 @@ void Domain::deinit() _tcp_rules.destroy_each(_alloc); _udp_forward_rules.destroy_each(_alloc); _tcp_forward_rules.destroy_each(_alloc); - try { - Dhcp_server &dhcp_server = _dhcp_server(); - _dhcp_server = Pointer(); - try { dhcp_server.dns_config_from().ip_config_dependents().remove(this); } - catch (Pointer::Invalid) { } - destroy(_alloc, &dhcp_server); - } - catch (Pointer::Invalid) { } -} - - -Ipv4_address const &Domain::next_hop(Ipv4_address const &ip) const -{ - if (ip_config().interface().prefix_matches(ip)) { return ip; } - if (ip_config().gateway_valid()) { return ip_config().gateway(); } - throw No_next_hop(); + with_dhcp_server([&] (Dhcp_server &dhcp_server) { + _dhcp_server_ptr = nullptr; + dhcp_server.with_dns_config_from([&] (Domain &domain) { + domain.ip_config_dependents().remove(this); }); + destroy(_alloc, &dhcp_server); }); } @@ -424,54 +432,53 @@ void Domain::interface_updates_domain_object(Interface &interface) } -void Domain::report(Xml_generator &xml) +bool Domain::report_empty(Report const &report_cfg) const { - xml.node("domain", [&] () { - bool empty = true; - xml.attribute("name", name()); - if (_config.report().bytes()) { - xml.attribute("rx_bytes", _tx_bytes); - xml.attribute("tx_bytes", _rx_bytes); - empty = false; - } - if (_config.report().config()) { - xml.attribute("ipv4", String<19>(ip_config().interface())); - xml.attribute("gw", String<16>(ip_config().gateway())); - ip_config().for_each_dns_server([&] (Dns_server const &dns_server) { - xml.node("dns", [&] () { - xml.attribute("ip", String<16>(dns_server.ip())); - }); - }); - ip_config().dns_domain_name().with_string( - [&] (Dns_domain_name::String const &str) - { - xml.node("dns-domain", [&] () { - xml.attribute("name", str); - }); - }); - empty = false; - } - if (_config.report().stats()) { - try { xml.node("tcp-links", [&] () { _tcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("udp-links", [&] () { _udp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("icmp-links", [&] () { _icmp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("arp-waiters", [&] () { _arp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("dhcp-allocations", [&] () { _dhcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - } - if (_config.report().dropped_fragm_ipv4() && _dropped_fragm_ipv4) { - xml.node("dropped-fragm-ipv4", [&] () { - xml.attribute("value", _dropped_fragm_ipv4); - }); - empty = false; - } - _interfaces.for_each([&] (Interface &interface) { - try { - interface.report(xml); - empty = false; - } catch (Report::Empty) { } - }); - if (empty) { - throw Report::Empty(); } + bool bytes = report_cfg.bytes(); + bool cfg = report_cfg.config(); + bool stats = report_cfg.stats() && ( + !_tcp_stats.report_empty() || !_udp_stats.report_empty() || + !_icmp_stats.report_empty() || !_arp_stats.report_empty() || _dhcp_stats.report_empty()); + bool fragm_ip = report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4; + bool interfaces = false; + _interfaces.for_each([&] (Interface const &interface) { + if (!interface.report_empty(report_cfg)) + interfaces = true; }); + + return !bytes && !cfg && !stats && !fragm_ip && !interfaces; +} + + +void Domain::report(Xml_generator &xml, Report const &report_cfg) const +{ + xml.attribute("name", name()); + if (report_cfg.bytes()) { + xml.attribute("rx_bytes", _tx_bytes); + xml.attribute("tx_bytes", _rx_bytes); + } + if (report_cfg.config()) { + xml.attribute("ipv4", String<19>(ip_config().interface())); + xml.attribute("gw", String<16>(ip_config().gateway())); + ip_config().for_each_dns_server([&] (Dns_server const &dns_server) { + xml.node("dns", [&] () { + xml.attribute("ip", String<16>(dns_server.ip())); }); }); + ip_config().dns_domain_name().with_string([&] (Dns_domain_name::String const &str) { + xml.node("dns-domain", [&] () { + xml.attribute("name", str); }); }); + } + if (report_cfg.stats()) { + if (!_tcp_stats.report_empty()) xml.node("tcp-links", [&] { _tcp_stats.report(xml); }); + if (!_udp_stats.report_empty()) xml.node("udp-links", [&] { _udp_stats.report(xml); }); + if (!_icmp_stats.report_empty()) xml.node("icmp-links", [&] { _icmp_stats.report(xml); }); + if (!_arp_stats.report_empty()) xml.node("arp-waiters", [&] { _arp_stats.report(xml); }); + if (!_dhcp_stats.report_empty()) xml.node("dhcp-allocations", [&] { _dhcp_stats.report(xml); }); + } + if (report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4) + xml.node("dropped-fragm-ipv4", [&] () { + xml.attribute("value", _dropped_fragm_ipv4); }); + _interfaces.for_each([&] (Interface const &interface) { + if (!interface.report_empty(report_cfg)) + xml.node("interface", [&] { interface.report(xml, report_cfg); }); }); } @@ -495,15 +502,14 @@ Domain_link_stats::dissolve_interface(Interface_link_stats const &stats) } -void Domain_link_stats::report(Genode::Xml_generator &xml) +bool Domain_link_stats::report_empty() const { return !refused_for_ram && !refused_for_ports && !destroyed; } + + +void Domain_link_stats::report(Genode::Xml_generator &xml) const { - bool empty = true; - - if (refused_for_ram) { xml.node("refused_for_ram", [&] () { xml.attribute("value", refused_for_ram); }); empty = false; } - if (refused_for_ports) { xml.node("refused_for_ports", [&] () { xml.attribute("value", refused_for_ports); }); empty = false; } - if (destroyed) { xml.node("destroyed", [&] () { xml.attribute("value", destroyed); }); empty = false; } - - if (empty) { throw Report::Empty(); } + if (refused_for_ram) xml.node("refused_for_ram", [&] { xml.attribute("value", refused_for_ram); }); + if (refused_for_ports) xml.node("refused_for_ports", [&] { xml.attribute("value", refused_for_ports); }); + if (destroyed) xml.node("destroyed", [&] { xml.attribute("value", destroyed); }); } @@ -518,9 +524,10 @@ Domain_object_stats::dissolve_interface(Interface_object_stats const &stats) } -void Domain_object_stats::report(Genode::Xml_generator &xml) +bool Domain_object_stats::report_empty() const { return !destroyed; } + + +void Domain_object_stats::report(Genode::Xml_generator &xml) const { - bool empty = true; - if (destroyed) { xml.node("destroyed", [&] () { xml.attribute("value", destroyed); }); empty = false; } - if (empty) { throw Report::Empty(); } + if (destroyed) xml.node("destroyed", [&] { xml.attribute("value", destroyed); }); } diff --git a/repos/os/src/server/nic_router/domain.h b/repos/os/src/server/nic_router/domain.h index fb8ce11403..c097046747 100644 --- a/repos/os/src/server/nic_router/domain.h +++ b/repos/os/src/server/nic_router/domain.h @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include @@ -54,7 +53,8 @@ struct Net::Domain_object_stats void dissolve_interface(Interface_object_stats const &stats); - void report(Genode::Xml_generator &xml); + bool report_empty() const; + void report(Genode::Xml_generator &xml) const; }; @@ -66,7 +66,8 @@ struct Net::Domain_link_stats : Domain_object_stats void dissolve_interface(Interface_link_stats const &stats); - void report(Genode::Xml_generator &xml); + bool report_empty() const; + void report(Genode::Xml_generator &xml) const; }; @@ -74,26 +75,12 @@ class Net::Domain_dict : public Dictionary { public: - template - Domain &deprecated_find_by_name(Domain_name const &domain_name) + void find_by_domain_attr(Genode::Xml_node const &node, auto const &ok_fn, auto const &failed_fn) { - Domain *dom_ptr { nullptr }; - with_element( - domain_name, - [&] /* match_fn */ (Domain &dom) { dom_ptr = &dom; }, - [&] /* no_match_fn */ () { throw NO_MATCH_EXCEPTION { }; } - ); - return *dom_ptr; + with_element(node.attribute_value("domain", Domain_name()), + [&] (Domain &domain) { ok_fn(domain); }, [&] { failed_fn(); }); } - template - Domain &deprecated_find_by_domain_attr(Genode::Xml_node const &node) - { - Domain_name const domain_name { - node.attribute_value("domain", Domain_name { }) }; - - return deprecated_find_by_name(domain_name); - } }; @@ -117,7 +104,7 @@ class Net::Domain : public List::Element, Nat_rule_tree _nat_rules { }; Interface_list _interfaces { }; unsigned long _interface_cnt { 0 }; - Pointer _dhcp_server { }; + Dhcp_server *_dhcp_server_ptr { }; Genode::Reconstructible _ip_config; bool const _ip_config_dynamic { !ip_config().valid() }; List _ip_config_dependents { }; @@ -141,19 +128,19 @@ class Net::Domain : public List::Element, Domain_object_stats _dhcp_stats { }; unsigned long _dropped_fragm_ipv4 { 0 }; - void _read_forward_rules(Genode::Cstring const &protocol, - Domain_dict &domains, - Genode::Xml_node const node, - char const *type, - Forward_rule_tree &rules); + [[nodiscard]] bool _read_forward_rules(Genode::Cstring const &protocol, + Domain_dict &domains, + Genode::Xml_node const node, + char const *type, + Forward_rule_tree &rules); - void _read_transport_rules(Genode::Cstring const &protocol, - Domain_dict &domains, - Genode::Xml_node const node, - char const *type, - Transport_rule_list &rules); + [[nodiscard]] bool _read_transport_rules(Genode::Cstring const &protocol, + Domain_dict &domains, + Genode::Xml_node const node, + char const *type, + Transport_rule_list &rules); - void _invalid(char const *reason) const; + [[nodiscard]] bool _invalid(char const *reason) const; void _log_ip_config() const; @@ -171,11 +158,15 @@ class Net::Domain : public List::Element, void __FIXME__dissolve_foreign_arp_waiters(); + /* + * Noncopyable + */ + Domain(Domain const &); + Domain &operator = (Domain const &); + public: - struct Invalid : Genode::Exception { }; - struct Ip_config_static : Genode::Exception { }; - struct No_next_hop : Genode::Exception { }; + struct Invalid : Genode::Exception { }; Domain(Configuration &config, Genode::Xml_node const &node, @@ -185,11 +176,21 @@ class Net::Domain : public List::Element, ~Domain(); - void init(Domain_dict &domains); + [[nodiscard]] bool finish_construction() const; + + [[nodiscard]] bool init(Domain_dict &domains); void deinit(); - Ipv4_address const &next_hop(Ipv4_address const &ip) const; + void with_next_hop(Ipv4_address const &ip, auto const &ok_fn, auto const &error_fn) const + { + if (ip_config().interface().prefix_matches(ip)) + ok_fn(ip); + else if (ip_config().gateway_valid()) + ok_fn(ip_config().gateway()); + else + error_fn(); + } void ip_config_from_dhcp_ack(Dhcp_packet &dhcp_ack); @@ -209,7 +210,9 @@ class Net::Domain : public List::Element, void raise_tx_bytes(Genode::size_t bytes) { _tx_bytes += bytes; } - void report(Genode::Xml_generator &xml); + bool report_empty(Report const &) const; + + void report(Genode::Xml_generator &xml, Report const &) const; void add_dropped_fragm_ipv4(unsigned long dropped_fragm_ipv4); @@ -217,6 +220,20 @@ class Net::Domain : public List::Element, void update_ready_state(); + void with_dhcp_server(auto const &dhcp_server_fn, auto const &no_dhcp_server_fn) + { + if (!_dhcp_server_ptr) { + no_dhcp_server_fn(); + return; + } + if (_dhcp_server_ptr->has_invalid_remote_dns_cfg()) { + no_dhcp_server_fn(); + return; + } + dhcp_server_fn(*_dhcp_server_ptr); + } + + void with_dhcp_server(auto const &fn) { with_dhcp_server(fn, []{}); } /********* ** log ** @@ -247,7 +264,6 @@ class Net::Domain : public List::Element, Nat_rule_tree &nat_rules() { return _nat_rules; } Interface_list &interfaces() { return _interfaces; } Configuration &config() const { return _config; } - Dhcp_server &dhcp_server(); Arp_cache &arp_cache() { return _arp_cache; } Arp_waiter_list &foreign_arp_waiters() { return _foreign_arp_waiters; } Link_side_tree &tcp_links() { return _tcp_links; } diff --git a/repos/os/src/server/nic_router/forward_rule.cc b/repos/os/src/server/nic_router/forward_rule.cc index 24bfc8d751..af160b793f 100644 --- a/repos/os/src/server/nic_router/forward_rule.cc +++ b/repos/os/src/server/nic_router/forward_rule.cc @@ -33,13 +33,10 @@ void Forward_rule::print(Output &output) const } -Forward_rule::Forward_rule(Domain_dict &domains, Xml_node const node) +Forward_rule::Forward_rule(Port port, Ipv4_address to_ip, Port to_port, Domain &domain) : - _port { node.attribute_value("port", Port(0)) }, - _to_ip { node.attribute_value("to", Ipv4_address()) }, - _to_port { node.attribute_value("to_port", Port(0)) }, - _domain { domains.deprecated_find_by_domain_attr(node) } -{ - if (_port == Port(0) || !_to_ip.valid() || dynamic_port(_port)) { - throw Invalid(); } -} + _port { port }, + _to_ip { to_ip }, + _to_port { to_port }, + _domain { domain } +{ } diff --git a/repos/os/src/server/nic_router/forward_rule.h b/repos/os/src/server/nic_router/forward_rule.h index fde85bdb19..b6a6805019 100644 --- a/repos/os/src/server/nic_router/forward_rule.h +++ b/repos/os/src/server/nic_router/forward_rule.h @@ -49,7 +49,7 @@ class Net::Forward_rule : public Genode::Avl_node struct Invalid : Genode::Exception { }; - Forward_rule(Domain_dict &domains, Genode::Xml_node const node); + Forward_rule(Port port, Ipv4_address to_ip, Port to_port, Domain &domain); template diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index a90985e826..d859a004b9 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -23,6 +23,7 @@ #include #include #include +#include using namespace Net; using Genode::Deallocator; @@ -151,7 +152,7 @@ static void _link_packet(L3_protocol const prot, return; } return; - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -176,7 +177,7 @@ static void _update_checksum(L3_protocol const prot, sizeof(Icmp_packet)); return; } - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -186,7 +187,7 @@ static Port _dst_port(L3_protocol const prot, void *const prot_base) case L3_protocol::TCP: return (*(Tcp_packet *)prot_base).dst_port(); case L3_protocol::UDP: return (*(Udp_packet *)prot_base).dst_port(); case L3_protocol::ICMP: return Port((*(Icmp_packet *)prot_base).query_id()); - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -198,7 +199,7 @@ static void _dst_port(L3_protocol const prot, case L3_protocol::TCP: (*(Tcp_packet *)prot_base).dst_port(port); return; case L3_protocol::UDP: (*(Udp_packet *)prot_base).dst_port(port); return; case L3_protocol::ICMP: (*(Icmp_packet *)prot_base).query_id(port.value); return; - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -208,7 +209,7 @@ static Port _src_port(L3_protocol const prot, void *const prot_base) case L3_protocol::TCP: return (*(Tcp_packet *)prot_base).src_port(); case L3_protocol::UDP: return (*(Udp_packet *)prot_base).src_port(); case L3_protocol::ICMP: return Port((*(Icmp_packet *)prot_base).query_id()); - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -220,7 +221,7 @@ static void _src_port(L3_protocol const prot, case L3_protocol::TCP: ((Tcp_packet *)prot_base)->src_port(port); return; case L3_protocol::UDP: ((Udp_packet *)prot_base)->src_port(port); return; case L3_protocol::ICMP: ((Icmp_packet *)prot_base)->query_id(port.value); return; - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -232,35 +233,62 @@ static void *_prot_base(L3_protocol const prot, case L3_protocol::TCP: return &ip.data(size_guard); case L3_protocol::UDP: return &ip.data(size_guard); case L3_protocol::ICMP: return &ip.data(size_guard); - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } +static bool _supported_transport_prot(L3_protocol prot) +{ + return + prot == L3_protocol::TCP || + prot == L3_protocol::UDP || + prot == L3_protocol::ICMP; +} + + +static void _with_forward_rule(Domain &dom, L3_protocol prot, Port port, auto const &fn) +{ + switch (prot) { + case L3_protocol::TCP: dom.tcp_forward_rules().find_by_port(port, [&] (Forward_rule const &r) { fn(r); }, []{}); break; + case L3_protocol::UDP: dom.udp_forward_rules().find_by_port(port, [&] (Forward_rule const &r) { fn(r); }, []{}); break; + default: break; } +} + + +static void _with_transport_rule(Domain &dom, L3_protocol prot, Ipv4_address const &ip, Port port, auto const &fn) +{ + switch (prot) { + case L3_protocol::TCP: dom.tcp_rules().find_best_match(ip, port, [&] (Transport_rule const &tr, Permit_rule const &pr) { fn(tr, pr); }, []{}); break; + case L3_protocol::UDP: dom.udp_rules().find_best_match(ip, port, [&] (Transport_rule const &tr, Permit_rule const &pr) { fn(tr, pr); }, []{}); break; + default: break; } +} + /************************** ** Interface_link_stats ** **************************/ -void Interface_link_stats::report(Genode::Xml_generator &xml) +bool Interface_link_stats::report_empty() const { - bool empty = true; + return + !refused_for_ram && !refused_for_ports && !opening && !open && !closing && !closed && !dissolved_timeout_opening && + !dissolved_timeout_open && !dissolved_timeout_closing && !dissolved_timeout_closed && !dissolved_no_timeout && !destroyed; +} - if (refused_for_ram) { xml.node("refused_for_ram", [&] () { xml.attribute("value", refused_for_ram); }); empty = false; } - if (refused_for_ports) { xml.node("refused_for_ports", [&] () { xml.attribute("value", refused_for_ports); }); empty = false; } - if (opening) { xml.node("opening", [&] () { xml.attribute("value", opening); }); empty = false; } - if (open) { xml.node("open", [&] () { xml.attribute("value", open); }); empty = false; } - if (closing) { xml.node("closing", [&] () { xml.attribute("value", closing); }); empty = false; } - if (closed) { xml.node("closed", [&] () { xml.attribute("value", closed); }); empty = false; } - - if (dissolved_timeout_opening) { xml.node("dissolved_timeout_opening", [&] () { xml.attribute("value", dissolved_timeout_opening); }); empty = false; } - if (dissolved_timeout_open) { xml.node("dissolved_timeout_open", [&] () { xml.attribute("value", dissolved_timeout_open); }); empty = false; } - if (dissolved_timeout_closing) { xml.node("dissolved_timeout_closing", [&] () { xml.attribute("value", dissolved_timeout_closing); }); empty = false; } - if (dissolved_timeout_closed) { xml.node("dissolved_timeout_closed", [&] () { xml.attribute("value", dissolved_timeout_closed); }); empty = false; } - if (dissolved_no_timeout) { xml.node("dissolved_no_timeout", [&] () { xml.attribute("value", dissolved_no_timeout); }); empty = false; } - - if (destroyed) { xml.node("destroyed", [&] () { xml.attribute("value", destroyed); }); empty = false; } - - if (empty) { throw Report::Empty(); } +void Interface_link_stats::report(Genode::Xml_generator &xml) const +{ + if (refused_for_ram) xml.node("refused_for_ram", [&] { xml.attribute("value", refused_for_ram); }); + if (refused_for_ports) xml.node("refused_for_ports", [&] { xml.attribute("value", refused_for_ports); }); + if (opening) xml.node("opening", [&] { xml.attribute("value", opening); }); + if (open) xml.node("open", [&] { xml.attribute("value", open); }); + if (closing) xml.node("closing", [&] { xml.attribute("value", closing); }); + if (closed) xml.node("closed", [&] { xml.attribute("value", closed); }); + if (dissolved_timeout_opening) xml.node("dissolved_timeout_opening", [&] { xml.attribute("value", dissolved_timeout_opening); }); + if (dissolved_timeout_open) xml.node("dissolved_timeout_open", [&] { xml.attribute("value", dissolved_timeout_open); }); + if (dissolved_timeout_closing) xml.node("dissolved_timeout_closing", [&] { xml.attribute("value", dissolved_timeout_closing); }); + if (dissolved_timeout_closed) xml.node("dissolved_timeout_closed", [&] { xml.attribute("value", dissolved_timeout_closed); }); + if (dissolved_no_timeout) xml.node("dissolved_no_timeout", [&] { xml.attribute("value", dissolved_no_timeout); }); + if (destroyed) xml.node("destroyed", [&] { xml.attribute("value", destroyed); }); } @@ -268,14 +296,13 @@ void Interface_link_stats::report(Genode::Xml_generator &xml) ** Interface_object_stats ** ****************************/ -void Interface_object_stats::report(Genode::Xml_generator &xml) +bool Interface_object_stats::report_empty() const { return !alive && !destroyed; } + + +void Interface_object_stats::report(Genode::Xml_generator &xml) const { - bool empty = true; - - if (alive) { xml.node("alive", [&] () { xml.attribute("value", alive); }); empty = false; } - if (destroyed) { xml.node("destroyed", [&] () { xml.attribute("value", destroyed); }); empty = false; } - - if (empty) { throw Report::Empty(); } + if (alive) xml.node("alive", [&] { xml.attribute("value", alive); }); + if (destroyed) xml.node("destroyed", [&] { xml.attribute("value", destroyed); }); } @@ -290,7 +317,7 @@ void Interface::destroy_link(Link &link) case L3_protocol::TCP: ::_destroy_link(link, links(prot), _alloc); break; case L3_protocol::UDP: ::_destroy_link(link, links(prot), _alloc); break; case L3_protocol::ICMP: ::_destroy_link(link, links(prot), _alloc); break; - default: throw Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -318,29 +345,9 @@ void Interface::_pass_prot_to_domain(Domain &domain, } -Forward_rule_tree & -Interface::_forward_rules(Domain &local_domain, L3_protocol const prot) const -{ - switch (prot) { - case L3_protocol::TCP: return local_domain.tcp_forward_rules(); - case L3_protocol::UDP: return local_domain.udp_forward_rules(); - default: throw Bad_transport_protocol(); } -} - - -Transport_rule_list & -Interface::_transport_rules(Domain &local_domain, L3_protocol const prot) const -{ - switch (prot) { - case L3_protocol::TCP: return local_domain.tcp_rules(); - case L3_protocol::UDP: return local_domain.udp_rules(); - default: throw Bad_transport_protocol(); } -} - - void Interface::_attach_to_domain_raw(Domain &domain) { - _domain = domain; + _domain_ptr = &domain; _refetch_domain_ready_state(); _interfaces.remove(this); domain.attach_interface(*this); @@ -349,10 +356,10 @@ void Interface::_attach_to_domain_raw(Domain &domain) void Interface::_detach_from_domain_raw() { - Domain &domain = _domain(); + Domain &domain = *_domain_ptr; domain.detach_interface(*this); _interfaces.insert(this); - _domain = Pointer(); + _domain_ptr = nullptr; _refetch_domain_ready_state(); domain.add_dropped_fragm_ipv4(_dropped_fragm_ipv4); @@ -367,10 +374,10 @@ void Interface::_detach_from_domain_raw() void Interface::_update_domain_object(Domain &new_domain) { /* detach raw */ - Domain &old_domain = _domain(); + Domain &old_domain = *_domain_ptr; old_domain.interface_updates_domain_object(*this); _interfaces.insert(this); - _domain = Pointer(); + _domain_ptr = nullptr; _refetch_domain_ready_state(); old_domain.add_dropped_fragm_ipv4(_dropped_fragm_ipv4); @@ -381,7 +388,7 @@ void Interface::_update_domain_object(Domain &new_domain) { old_domain.dhcp_stats().dissolve_interface(_dhcp_stats); /* attach raw */ - _domain = new_domain; + _domain_ptr = &new_domain; _refetch_domain_ready_state(); _interfaces.remove(this); new_domain.attach_interface(*this); @@ -413,7 +420,7 @@ void Interface::attach_to_domain_finish() return; } /* if domain has yet no IP config, participate in requesting one */ - Domain &domain = _domain(); + Domain &domain = *_domain_ptr; Ipv4_config const &ip_config = domain.ip_config(); if (!ip_config.valid()) { _dhcp_client->discover(); @@ -464,11 +471,10 @@ void Interface::handle_domain_ready_state(bool state) void Interface::_refetch_domain_ready_state() { - if (_domain.valid()) { - handle_domain_ready_state(_domain().ready()); - } else { + if (_domain_ptr) + handle_domain_ready_state(_domain_ptr->ready()); + else handle_domain_ready_state(false); - } } @@ -481,59 +487,74 @@ void Interface::_reset_and_refetch_domain_ready_state() void Interface::_detach_from_domain() { - try { - detach_from_ip_config(domain()); - _detach_from_domain_raw(); - } - catch (Pointer::Invalid) { } + with_domain([&] (Domain &domain) { + detach_from_ip_config(domain); + _detach_from_domain_raw(); }); } -void -Interface::_new_link(L3_protocol const protocol, - Link_side_id const &local, - Pointer remote_port_alloc, - Domain &remote_domain, - Link_side_id const &remote) +Packet_result Interface::_new_link(L3_protocol const protocol, + Domain &local_domain, + Link_side_id const &local, + Port_allocator_guard *remote_port_alloc_ptr, + Domain &remote_domain, + Link_side_id const &remote) { + Packet_result result { }; switch (protocol) { case L3_protocol::TCP: try { new (_alloc) - Tcp_link { *this, local, remote_port_alloc, remote_domain, + Tcp_link { *this, local_domain, local, remote_port_alloc_ptr, remote_domain, remote, _timer, _config(), protocol, _tcp_stats }; } - catch (Out_of_ram) { throw Free_resources_and_retry_handle_eth(L3_protocol::TCP); } - catch (Out_of_caps) { throw Free_resources_and_retry_handle_eth(L3_protocol::TCP); } - + catch (Out_of_ram) { + _tcp_stats.refused_for_ram++; + result = packet_drop("out of RAM while creating TCP link"); + } + catch (Out_of_caps) { + _tcp_stats.refused_for_ram++; + result = packet_drop("out of CAPs while creating TCP link"); + } break; case L3_protocol::UDP: try { new (_alloc) - Udp_link { *this, local, remote_port_alloc, remote_domain, + Udp_link { *this, local_domain, local, remote_port_alloc_ptr, remote_domain, remote, _timer, _config(), protocol, _udp_stats }; } - catch (Out_of_ram) { throw Free_resources_and_retry_handle_eth(L3_protocol::UDP); } - catch (Out_of_caps) { throw Free_resources_and_retry_handle_eth(L3_protocol::UDP); } - + catch (Out_of_ram) { + _udp_stats.refused_for_ram++; + result = packet_drop("out of RAM while creating UDP link"); + } + catch (Out_of_caps) { + _udp_stats.refused_for_ram++; + result = packet_drop("out of CAPs while creating UDP link"); + } break; case L3_protocol::ICMP: try { new (_alloc) - Icmp_link { *this, local, remote_port_alloc, remote_domain, + Icmp_link { *this, local_domain, local, remote_port_alloc_ptr, remote_domain, remote, _timer, _config(), protocol, _icmp_stats }; } - catch (Out_of_ram) { throw Free_resources_and_retry_handle_eth(L3_protocol::ICMP); } - catch (Out_of_caps) { throw Free_resources_and_retry_handle_eth(L3_protocol::ICMP); } - + catch (Out_of_ram) { + _icmp_stats.refused_for_ram++; + result = packet_drop("out of RAM while creating ICMP link"); + } + catch (Out_of_caps) { + _icmp_stats.refused_for_ram++; + result = packet_drop("out of CAPs while creating ICMP link"); + } break; - default: throw Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } + return result; } void Interface::dhcp_allocation_expired(Dhcp_allocation &allocation) { - _release_dhcp_allocation(allocation, _domain()); + _release_dhcp_allocation(allocation, *_domain_ptr); _released_dhcp_allocations.insert(&allocation); } @@ -544,7 +565,7 @@ Link_list &Interface::links(L3_protocol const protocol) case L3_protocol::TCP: return _tcp_links; case L3_protocol::UDP: return _udp_links; case L3_protocol::ICMP: return _icmp_links; - default: throw Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } @@ -554,22 +575,24 @@ Link_list &Interface::dissolved_links(L3_protocol const protocol) case L3_protocol::TCP: return _dissolved_tcp_links; case L3_protocol::UDP: return _dissolved_udp_links; case L3_protocol::ICMP: return _dissolved_icmp_links; - default: throw Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } -void Interface::_adapt_eth(Ethernet_frame ð, - Ipv4_address const &dst_ip, - Packet_descriptor const &pkt, - Domain &remote_domain) +Packet_result Interface::_adapt_eth(Ethernet_frame ð, + Ipv4_address const &dst_ip, + Packet_descriptor const &pkt, + Domain &remote_domain) { + Packet_result result { }; Ipv4_config const &remote_ip_cfg = remote_domain.ip_config(); if (!remote_ip_cfg.valid()) { - throw Drop_packet("target domain has yet no IP config"); + result = packet_drop("target domain has yet no IP config"); } - if (remote_domain.use_arp()) { + if (!remote_domain.use_arp()) + return result; - Ipv4_address const &hop_ip = remote_domain.next_hop(dst_ip); + auto with_next_hop = [&] (Ipv4_address const &hop_ip) { remote_domain.arp_cache().find_by_ip( hop_ip, [&] /* handle_match */ (Arp_cache_entry const &entry) @@ -583,56 +606,68 @@ void Interface::_adapt_eth(Ethernet_frame ð, interface._broadcast_arp_request( remote_ip_cfg.interface().address, hop_ip); }); - try { new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt }; } - catch (Out_of_ram) { throw Free_resources_and_retry_handle_eth(); } - catch (Out_of_caps) { throw Free_resources_and_retry_handle_eth(); } - throw Packet_postponed(); + try { + new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt }; + result = packet_postponed(); + } + catch (Out_of_ram) { result = packet_drop("out of RAM while creating ARP waiter"); } + catch (Out_of_caps) { result = packet_drop("out of CAPs while creating ARP waiter"); } } ); - } + }; + auto without_next_hop = [&] { result = packet_drop("cannot find next hop"); }; + remote_domain.with_next_hop(dst_ip, with_next_hop, without_next_hop); + return result; } -void Interface::_nat_link_and_pass(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - L3_protocol const prot, - void *const prot_base, - size_t const prot_size, - Link_side_id const &local_id, - Domain &local_domain, - Domain &remote_domain) +Packet_result Interface::_nat_link_and_pass(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + L3_protocol const prot, + void *const prot_base, + size_t const prot_size, + Link_side_id const &local_id, + Domain &local_domain, + Domain &remote_domain) { - try { - Pointer remote_port_alloc; - remote_domain.nat_rules().find_by_domain( - local_domain, - [&] /* handle_match */ (Nat_rule &nat) - { - if(_config().verbose()) { - log("[", local_domain, "] using NAT rule: ", nat); } + Packet_result result { }; + Port_allocator_guard *remote_port_alloc_ptr { }; + remote_domain.nat_rules().find_by_domain( + local_domain, + [&] /* handle_match */ (Nat_rule &nat) + { + if(_config().verbose()) { + log("[", local_domain, "] using NAT rule: ", nat); } - _src_port(prot, prot_base, nat.port_alloc(prot).alloc()); - ip.src(remote_domain.ip_config().interface().address, ip_icd); - remote_port_alloc = nat.port_alloc(prot); - }, - [&] /* no_match */ () { } - ); - Link_side_id const remote_id = { ip.dst(), _dst_port(prot, prot_base), - ip.src(), _src_port(prot, prot_base) }; - _new_link(prot, local_id, remote_port_alloc, remote_domain, remote_id); - _pass_prot_to_domain( - remote_domain, eth, size_guard, ip, ip_icd, prot, prot_base, - prot_size); + Port src_port(0); + nat.port_alloc(prot).alloc().with_result( + [&] (Port src_port) { + _src_port(prot, prot_base, src_port); + ip.src(remote_domain.ip_config().interface().address, ip_icd); + remote_port_alloc_ptr = &nat.port_alloc(prot); }, + [&] (auto) { + result = packet_drop("no available NAT ports"); + switch (prot) { + case L3_protocol::TCP: _tcp_stats.refused_for_ports++; break; + case L3_protocol::UDP: _udp_stats.refused_for_ports++; break; + case L3_protocol::ICMP: _icmp_stats.refused_for_ports++; break; + default: ASSERT_NEVER_REACHED; } }); + }, + [&] /* no_match */ () { } + ); + if (result.valid()) + return result; - } catch (Port_allocator_guard::Out_of_indices) { - switch (prot) { - case L3_protocol::TCP: _tcp_stats.refused_for_ports++; break; - case L3_protocol::UDP: _udp_stats.refused_for_ports++; break; - case L3_protocol::ICMP: _icmp_stats.refused_for_ports++; break; - default: throw Bad_transport_protocol(); } - } + Link_side_id const remote_id = { ip.dst(), _dst_port(prot, prot_base), + ip.src(), _src_port(prot, prot_base) }; + result = _new_link(prot, local_domain, local_id, remote_port_alloc_ptr, remote_domain, remote_id); + if (result.valid()) + return result; + + _pass_prot_to_domain(remote_domain, eth, size_guard, ip, ip_icd, prot, prot_base, prot_size); + return packet_handled(); } @@ -733,14 +768,15 @@ void Interface::_release_dhcp_allocation(Dhcp_allocation &allocation, } -void Interface::_new_dhcp_allocation(Ethernet_frame ð, - Dhcp_packet &dhcp, - Dhcp_server &dhcp_srv, - Domain &local_domain) +Packet_result Interface::_new_dhcp_allocation(Ethernet_frame ð, + Dhcp_packet &dhcp, + Dhcp_server &dhcp_srv, + Domain &local_domain) { - try { + Packet_result result { }; + auto ok_fn = [&] (Ipv4_address const &ip) { Dhcp_allocation &allocation = *new (_alloc) - Dhcp_allocation { *this, dhcp_srv.alloc_ip(), dhcp.client_mac(), + Dhcp_allocation { *this, ip, dhcp.client_mac(), _timer, _config().dhcp_offer_timeout() }; _dhcp_allocations.insert(allocation); @@ -752,38 +788,37 @@ void Interface::_new_dhcp_allocation(Ethernet_frame ð, Dhcp_packet::Message_type::OFFER, dhcp.xid(), local_domain.ip_config().interface()); - } - catch (Out_of_ram) { throw Free_resources_and_retry_handle_eth(); } - catch (Out_of_caps) { throw Free_resources_and_retry_handle_eth(); } + + result = packet_handled(); + }; + try { dhcp_srv.alloc_ip().with_result(ok_fn, [&] (auto) { result = packet_drop("failed to allocate IP for DHCP client"); }); } + catch (Out_of_ram) { result = packet_drop("out of RAM while creating DHCP allocation"); } + catch (Out_of_caps) { result = packet_drop("out of CAPs while creating DHCP allocation"); } + return result; } -void Interface::_handle_dhcp_request(Ethernet_frame ð, - Dhcp_packet &dhcp, - Domain &local_domain, - Ipv4_address_prefix const &local_intf) +Packet_result Interface::_handle_dhcp_request(Ethernet_frame ð, + Dhcp_server &dhcp_srv, + Dhcp_packet &dhcp, + Domain &local_domain, + Ipv4_address_prefix const &local_intf) { - try { - /* try to get the DHCP server config of this interface */ - Dhcp_server &dhcp_srv = local_domain.dhcp_server(); + Packet_result result { }; + auto no_msg_type_fn = [&] { result = packet_drop("DHCP request misses option \"Message Type\""); }; + auto msg_type_fn = [&] (Dhcp_packet::Message_type_option const &msg_type) { - /* determine type of DHCP request */ - Dhcp_packet::Message_type const msg_type = - dhcp.option().value(); + /* look up existing DHCP configuration for client */ + auto dhcp_allocation_fn = [&] (Dhcp_allocation &allocation) { - try { - /* look up existing DHCP configuration for client */ - Dhcp_allocation &allocation = - _dhcp_allocations.find_by_mac(dhcp.client_mac()); - - switch (msg_type) { + switch (msg_type.value()) { case Dhcp_packet::Message_type::DISCOVER: if (allocation.bound()) { _release_dhcp_allocation(allocation, local_domain); _destroy_dhcp_allocation(allocation, local_domain); - _new_dhcp_allocation(eth, dhcp, dhcp_srv, local_domain); + result = _new_dhcp_allocation(eth, dhcp, dhcp_srv, local_domain); return; } else { @@ -792,6 +827,7 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, allocation.ip(), Dhcp_packet::Message_type::OFFER, dhcp.xid(), local_intf); + result = packet_handled(); return; } case Dhcp_packet::Message_type::REQUEST: @@ -802,32 +838,39 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, allocation.ip(), Dhcp_packet::Message_type::ACK, dhcp.xid(), local_intf); + result = packet_handled(); return; } else { - Dhcp_packet::Server_ipv4 &dhcp_srv_ip = - dhcp.option(); - if (dhcp_srv_ip.value() == local_intf.address) - { - allocation.set_bound(); - allocation.lifetime(dhcp_srv.ip_lease_time()); - if (_config().verbose()) { - log("[", local_domain, "] bind DHCP allocation: ", - allocation); + auto no_server_ipv4_fn = [&] { result = packet_drop("DHCP request misses option \"Server IPv4\""); }; + auto server_ipv4_fn = [&] (Dhcp_packet::Server_ipv4 const &dhcp_srv_ip) { + + if (dhcp_srv_ip.value() == local_intf.address) + { + allocation.set_bound(); + allocation.lifetime(dhcp_srv.ip_lease_time()); + if (_config().verbose()) { + log("[", local_domain, "] bind DHCP allocation: ", + allocation); + } + _send_dhcp_reply(dhcp_srv, eth.src(), dhcp.client_mac(), + allocation.ip(), + Dhcp_packet::Message_type::ACK, + dhcp.xid(), local_intf); + result = packet_handled(); + return; + + } else { + + _release_dhcp_allocation(allocation, local_domain); + _destroy_dhcp_allocation(allocation, local_domain); + result = packet_handled(); + return; } - _send_dhcp_reply(dhcp_srv, eth.src(), dhcp.client_mac(), - allocation.ip(), - Dhcp_packet::Message_type::ACK, - dhcp.xid(), local_intf); - return; - - } else { - - _release_dhcp_allocation(allocation, local_domain); - _destroy_dhcp_allocation(allocation, local_domain); - return; - } + }; + dhcp.with_option(server_ipv4_fn, no_server_ipv4_fn); + return; } case Dhcp_packet::Message_type::INFORM: @@ -835,6 +878,7 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, allocation.ip(), Dhcp_packet::Message_type::ACK, dhcp.xid(), local_intf); + result = packet_handled(); return; case Dhcp_packet::Message_type::DECLINE: @@ -842,20 +886,21 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, _release_dhcp_allocation(allocation, local_domain); _destroy_dhcp_allocation(allocation, local_domain); + result = packet_handled(); return; - case Dhcp_packet::Message_type::NAK: throw Drop_packet("DHCP NAK from client"); - case Dhcp_packet::Message_type::OFFER: throw Drop_packet("DHCP OFFER from client"); - case Dhcp_packet::Message_type::ACK: throw Drop_packet("DHCP ACK from client"); - default: throw Drop_packet("DHCP request with broken message type"); + case Dhcp_packet::Message_type::NAK: result = packet_drop("DHCP NAK from client"); return; + case Dhcp_packet::Message_type::OFFER: result = packet_drop("DHCP OFFER from client"); return; + case Dhcp_packet::Message_type::ACK: result = packet_drop("DHCP ACK from client"); return; + default: result = packet_drop("DHCP request with broken message type"); return; } - } - catch (Dhcp_allocation_tree::No_match) { + }; + auto no_dhcp_allocation_fn = [&] { - switch (msg_type) { + switch (msg_type.value()) { case Dhcp_packet::Message_type::DISCOVER: - _new_dhcp_allocation(eth, dhcp, dhcp_srv, local_domain); + result = _new_dhcp_allocation(eth, dhcp, dhcp_srv, local_domain); return; case Dhcp_packet::Message_type::REQUEST: @@ -864,19 +909,21 @@ void Interface::_handle_dhcp_request(Ethernet_frame ð, Ipv4_address { }, Dhcp_packet::Message_type::NAK, dhcp.xid(), local_intf); + result = packet_handled(); return; - case Dhcp_packet::Message_type::DECLINE: throw Drop_packet("DHCP DECLINE from client without offered/acked IP"); - case Dhcp_packet::Message_type::RELEASE: throw Drop_packet("DHCP RELEASE from client without offered/acked IP"); - case Dhcp_packet::Message_type::NAK: throw Drop_packet("DHCP NAK from client"); - case Dhcp_packet::Message_type::OFFER: throw Drop_packet("DHCP OFFER from client"); - case Dhcp_packet::Message_type::ACK: throw Drop_packet("DHCP ACK from client"); - default: throw Drop_packet("DHCP request with broken message type"); + case Dhcp_packet::Message_type::DECLINE: result = packet_drop("DHCP DECLINE from client without offered/acked IP"); return; + case Dhcp_packet::Message_type::RELEASE: result = packet_drop("DHCP RELEASE from client without offered/acked IP"); return; + case Dhcp_packet::Message_type::NAK: result = packet_drop("DHCP NAK from client"); return; + case Dhcp_packet::Message_type::OFFER: result = packet_drop("DHCP OFFER from client"); return; + case Dhcp_packet::Message_type::ACK: result = packet_drop("DHCP ACK from client"); return; + default: result = packet_drop("DHCP request with broken message type"); return; } - } - } - catch (Dhcp_packet::Option_not_found exception) { - throw Drop_packet("DHCP request misses required option"); } + }; + _dhcp_allocations.find_by_mac(dhcp.client_mac(), dhcp_allocation_fn, no_dhcp_allocation_fn); + }; + dhcp.with_option(msg_type_fn, no_msg_type_fn); + return result; } @@ -947,28 +994,23 @@ bool Interface::link_state() const void Interface::handle_interface_link_state() { - struct Keep_ip_config : Exception { }; - try { - attach_to_domain_finish(); + attach_to_domain_finish(); - /* if the whole domain is down, discard IP config */ - Domain &domain_ = domain(); - if (!link_state() && domain_.ip_config().valid()) { - domain_.interfaces().for_each([&] (Interface &interface) { - if (interface.link_state()) { - throw Keep_ip_config(); } - }); - domain_.discard_ip_config(); - domain_.arp_cache().destroy_all_entries(); + /* discard dynamic IP config if the entire domain is down */ + with_domain([&] (Domain &domain) { + if (domain.ip_config_dynamic() && !link_state() && domain.ip_config().valid()) { + bool discard_ip_config = true; + domain.interfaces().for_each([&] (Interface &interface) { + if (interface.link_state()) + discard_ip_config = false; }); + if (discard_ip_config) { + domain.discard_ip_config(); + domain.arp_cache().destroy_all_entries(); + } } - } - catch (Pointer::Invalid) { } - catch (Domain::Ip_config_static) { } - catch (Keep_ip_config) { } - + }); /* force report if configured */ - try { _config().report().handle_interface_link_state(); } - catch (Pointer::Invalid) { } + _config().with_report([&] (Report &r) { r.handle_interface_link_state(); }); } @@ -1003,21 +1045,21 @@ void Interface::_send_icmp_echo_reply(Ethernet_frame ð, } -void Interface::_handle_icmp_query(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - Packet_descriptor const &pkt, - L3_protocol prot, - void *prot_base, - size_t prot_size, - Domain &local_domain) +Packet_result Interface::_handle_icmp_query(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + Packet_descriptor const &pkt, + L3_protocol prot, + void *prot_base, + size_t prot_size, + Domain &local_domain) { + Packet_result result { }; Link_side_id const local_id = { ip.src(), _src_port(prot, prot_base), ip.dst(), _dst_port(prot, prot_base) }; /* try to route via existing ICMP links */ - bool done { false }; local_domain.links(prot).find_by_id( local_id, [&] /* handle_match */ (Link_side const &local_side) @@ -1030,7 +1072,9 @@ void Interface::_handle_icmp_query(Ethernet_frame ð, log("[", local_domain, "] using ", l3_protocol_name(prot), " link: ", link); } - _adapt_eth(eth, remote_side.src_ip(), pkt, remote_domain); + result = _adapt_eth(eth, remote_side.src_ip(), pkt, remote_domain); + if (result.valid()) + return; ip.src(remote_side.dst_ip(), ip_icd); ip.dst(remote_side.src_ip(), ip_icd); _src_port(prot, prot_base, remote_side.dst_port()); @@ -1040,13 +1084,12 @@ void Interface::_handle_icmp_query(Ethernet_frame ð, prot_base, prot_size); _link_packet(prot, prot_base, link, client); - done = true; + result = packet_handled(); }, [&] /* handle_no_match */ () { } ); - if (done) { - return; - } + if (result.valid()) + return result; /* try to route via ICMP rules */ local_domain.icmp_rules().find_longest_prefix_match( @@ -1057,38 +1100,34 @@ void Interface::_handle_icmp_query(Ethernet_frame ð, log("[", local_domain, "] using ICMP rule: ", rule); } Domain &remote_domain = rule.domain(); - _adapt_eth(eth, local_id.dst_ip, pkt, remote_domain); - _nat_link_and_pass(eth, size_guard, ip, ip_icd, prot, prot_base, - prot_size, local_id, local_domain, - remote_domain); - - done = true; + result = _adapt_eth(eth, local_id.dst_ip, pkt, remote_domain); + if (result.valid()) + return; + result = _nat_link_and_pass( + eth, size_guard, ip, ip_icd, prot, prot_base, prot_size, local_id, local_domain, remote_domain); }, [&] /* handle_no_match */ () { } ); - if (done) { - return; - } - - throw Bad_transport_protocol(); + return result; } -void Interface::_handle_icmp_error(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - Packet_descriptor const &pkt, - Domain &local_domain, - Icmp_packet &icmp, - size_t icmp_sz) +Packet_result Interface::_handle_icmp_error(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + Packet_descriptor const &pkt, + Domain &local_domain, + Icmp_packet &icmp, + size_t icmp_sz) { + Packet_result result { }; Ipv4_packet &embed_ip { icmp.data(size_guard) }; Internet_checksum_diff embed_ip_icd { }; /* drop packet if embedded IP checksum invalid */ if (embed_ip.checksum_error()) { - throw Drop_packet("bad checksum in IP packet embedded in ICMP error"); + return packet_drop("bad checksum in IP packet embedded in ICMP error"); } /* get link identity of the embeddeded transport packet */ L3_protocol const embed_prot = embed_ip.protocol(); @@ -1112,7 +1151,9 @@ void Interface::_handle_icmp_error(Ethernet_frame ð, l3_protocol_name(embed_prot), " link: ", link); } /* adapt source and destination of Ethernet frame and IP packet */ - _adapt_eth(eth, remote_side.src_ip(), pkt, remote_domain); + result = _adapt_eth(eth, remote_side.src_ip(), pkt, remote_domain); + if (result.valid()) + return; if (remote_side.dst_ip() == remote_domain.ip_config().interface().address) { ip.src(remote_side.dst_ip(), ip_icd); } @@ -1136,31 +1177,33 @@ void Interface::_handle_icmp_error(Ethernet_frame ð, /* refresh link only if the error is not about an ICMP query */ if (embed_prot != L3_protocol::ICMP) { _link_packet(embed_prot, embed_prot_base, link, client); } + result = packet_handled(); }, [&] /* handle_no_match */ () { - throw Drop_packet("no link that matches packet embedded in " - "ICMP error"); + result = packet_drop("no link that matches packet embedded in ICMP error"); } ); + return result; } -void Interface::_handle_icmp(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - Packet_descriptor const &pkt, - L3_protocol prot, - void *prot_base, - size_t prot_size, - Domain &local_domain, - Ipv4_address_prefix const &local_intf) +Packet_result Interface::_handle_icmp(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + Packet_descriptor const &pkt, + L3_protocol prot, + void *prot_base, + size_t prot_size, + Domain &local_domain, + Ipv4_address_prefix const &local_intf) { /* drop packet if ICMP checksum is invalid */ + Packet_result result { }; Icmp_packet &icmp = *reinterpret_cast(prot_base); if (icmp.checksum_error(size_guard.unconsumed())) { - throw Drop_packet("bad ICMP checksum"); } + return packet_drop("bad ICMP checksum"); } /* try to act as ICMP Echo server */ if (icmp.type() == Icmp_packet::Type::ECHO_REQUEST && @@ -1171,22 +1214,24 @@ void Interface::_handle_icmp(Ethernet_frame ð, log("[", local_domain, "] act as ICMP Echo server"); } _send_icmp_echo_reply(eth, ip, icmp, prot_size, size_guard); - return; + return packet_handled(); } /* try to act as ICMP router */ switch (icmp.type()) { case Icmp_packet::Type::ECHO_REPLY: - case Icmp_packet::Type::ECHO_REQUEST: _handle_icmp_query(eth, size_guard, ip, ip_icd, pkt, prot, prot_base, prot_size, local_domain); break; - case Icmp_packet::Type::DST_UNREACHABLE: _handle_icmp_error(eth, size_guard, ip, ip_icd, pkt, local_domain, icmp, prot_size); break; - default: Drop_packet("unhandled type in ICMP"); } + case Icmp_packet::Type::ECHO_REQUEST: result = _handle_icmp_query(eth, size_guard, ip, ip_icd, pkt, prot, prot_base, prot_size, local_domain); break; + case Icmp_packet::Type::DST_UNREACHABLE: result = _handle_icmp_error(eth, size_guard, ip, ip_icd, pkt, local_domain, icmp, prot_size); break; + default: result = packet_drop("unhandled type in ICMP"); } + return result; } -void Interface::_handle_ip(Ethernet_frame ð, - Size_guard &size_guard, - Packet_descriptor const &pkt, - Domain &local_domain) +Packet_result Interface::_handle_ip(Ethernet_frame ð, + Size_guard &size_guard, + Packet_descriptor const &pkt, + Domain &local_domain) { + Packet_result result { }; Ipv4_packet &ip { eth.data(size_guard) }; Internet_checksum_diff ip_icd { }; @@ -1200,7 +1245,7 @@ void Interface::_handle_ip(Ethernet_frame ð, _send_icmp_dst_unreachable( local_intf, eth, ip, _config().icmp_type_3_code_on_fragm_ipv4()); } - throw Drop_packet("fragmented IPv4 not supported"); + return packet_drop("fragmented IPv4 not supported"); } /* try handling subnet-local IP packets */ if (local_intf.prefix_matches(ip.dst()) && @@ -1211,15 +1256,15 @@ void Interface::_handle_ip(Ethernet_frame ð, * the router. Thus, forward it to all other interfaces of the domain. */ _domain_broadcast(eth, size_guard, local_domain); - return; + return packet_handled(); } /* try to route via transport layer rules */ - bool done { false }; - try { - L3_protocol const prot = ip.protocol(); - size_t const prot_size = size_guard.unconsumed(); - void *const prot_base = _prot_base(prot, size_guard, ip); + L3_protocol const prot = ip.protocol(); + if (_supported_transport_prot(prot)) { + + size_t const prot_size = size_guard.unconsumed(); + void *const prot_base = _prot_base(prot, size_guard, ip); /* try handling DHCP requests before trying any routing */ if (prot == L3_protocol::UDP) { @@ -1232,135 +1277,116 @@ void Interface::_handle_ip(Ethernet_frame ð, switch (dhcp.op()) { case Dhcp_packet::REQUEST: - try { - _handle_dhcp_request( - eth, dhcp, local_domain, local_intf); - } - catch (Pointer::Invalid) { - throw Drop_packet("DHCP request while DHCP server inactive"); - } - return; + local_domain.with_dhcp_server( + [&] /* dhcp_server_fn */ (Dhcp_server &srv) { + result = _handle_dhcp_request(eth, srv, dhcp, local_domain, local_intf); }, + [&] /* no_dhcp_server_fn */ { + result = packet_drop("DHCP request while DHCP server inactive"); }); + return result; case Dhcp_packet::REPLY: if (eth.dst() != router_mac() && eth.dst() != Mac_address(0xff)) { - throw Drop_packet("Ethernet of DHCP reply doesn't target router"); } + return packet_drop("Ethernet of DHCP reply doesn't target router"); } if (dhcp.client_mac() != router_mac()) { - throw Drop_packet("DHCP reply doesn't target router"); } + return packet_drop("DHCP reply doesn't target router"); } if (!_dhcp_client.constructed()) { - throw Drop_packet("DHCP reply while DHCP client inactive"); } + return packet_drop("DHCP reply while DHCP client inactive"); } - _dhcp_client->handle_dhcp_reply(dhcp); - return; + return _dhcp_client->handle_dhcp_reply(dhcp, local_domain); - default: - - throw Drop_packet("Bad DHCP opcode"); + default: return packet_drop("Bad DHCP opcode"); } } } - else if (prot == L3_protocol::ICMP) { - _handle_icmp(eth, size_guard, ip, ip_icd, pkt, prot, prot_base, - prot_size, local_domain, local_intf); - return; - } + if (prot == L3_protocol::ICMP) { + result = _handle_icmp(eth, size_guard, ip, ip_icd, pkt, prot, prot_base, + prot_size, local_domain, local_intf); + } else { - Link_side_id const local_id = { ip.src(), _src_port(prot, prot_base), - ip.dst(), _dst_port(prot, prot_base) }; + Link_side_id const local_id = { ip.src(), _src_port(prot, prot_base), + ip.dst(), _dst_port(prot, prot_base) }; - /* try to route via existing UDP/TCP links */ - local_domain.links(prot).find_by_id( - local_id, - [&] /* handle_match */ (Link_side const &local_side) - { - Link &link = local_side.link(); - bool const client = local_side.is_client(); - Link_side &remote_side = - client ? link.server() : link.client(); - - Domain &remote_domain = remote_side.domain(); - if (_config().verbose()) { - log("[", local_domain, "] using ", l3_protocol_name(prot), - " link: ", link); - } - _adapt_eth(eth, remote_side.src_ip(), pkt, remote_domain); - ip.src(remote_side.dst_ip(), ip_icd); - ip.dst(remote_side.src_ip(), ip_icd); - _src_port(prot, prot_base, remote_side.dst_port()); - _dst_port(prot, prot_base, remote_side.src_port()); - _pass_prot_to_domain( - remote_domain, eth, size_guard, ip, ip_icd, prot, - prot_base, prot_size); - - _link_packet(prot, prot_base, link, client); - done = true; - }, - [&] /* handle_no_match */ () { } - ); - if (done) { - return; - } - - /* try to route via forward rules */ - if (local_id.dst_ip == local_intf.address) { - - _forward_rules(local_domain, prot).find_by_port( - local_id.dst_port, - [&] /* handle_match */ (Forward_rule const &rule) + /* try to route via existing UDP/TCP links */ + local_domain.links(prot).find_by_id( + local_id, + [&] /* handle_match */ (Link_side const &local_side) { + Link &link = local_side.link(); + bool const client = local_side.is_client(); + Link_side &remote_side = + client ? link.server() : link.client(); + + Domain &remote_domain = remote_side.domain(); + if (_config().verbose()) { + log("[", local_domain, "] using ", l3_protocol_name(prot), + " link: ", link); + } + result = _adapt_eth(eth, remote_side.src_ip(), pkt, remote_domain); + if (result.valid()) + return; + ip.src(remote_side.dst_ip(), ip_icd); + ip.dst(remote_side.src_ip(), ip_icd); + _src_port(prot, prot_base, remote_side.dst_port()); + _dst_port(prot, prot_base, remote_side.src_port()); + _pass_prot_to_domain( + remote_domain, eth, size_guard, ip, ip_icd, prot, + prot_base, prot_size); + + _link_packet(prot, prot_base, link, client); + result = packet_handled(); + }, + [&] /* handle_no_match */ () { } + ); + if (result.valid()) + return result; + + /* try to route via forward rules */ + if (local_id.dst_ip == local_intf.address) { + _with_forward_rule(local_domain, prot, local_id.dst_port, [&] (Forward_rule const &rule) { if(_config().verbose()) { log("[", local_domain, "] using forward rule: ", - l3_protocol_name(prot), " ", rule); + l3_protocol_name(prot), " ", rule); } Domain &remote_domain = rule.domain(); - _adapt_eth(eth, rule.to_ip(), pkt, remote_domain); + result = _adapt_eth(eth, rule.to_ip(), pkt, remote_domain); + if (result.valid()) + return; ip.dst(rule.to_ip(), ip_icd); if (!(rule.to_port() == Port(0))) { _dst_port(prot, prot_base, rule.to_port()); } - _nat_link_and_pass( + result = _nat_link_and_pass( eth, size_guard, ip, ip_icd, prot, prot_base, prot_size, local_id, local_domain, remote_domain); - - done = true; - }, - [&] /* handle_no_match */ () { } - ); - if (done) { - return; + }); + if (result.valid()) + return result; } - } - /* try to route via transport and permit rules */ - _transport_rules(local_domain, prot).find_best_match( - local_id.dst_ip, - local_id.dst_port, - [&] /* handle_match */ (Transport_rule const &transport_rule, - Permit_rule const &permit_rule) - { - if(_config().verbose()) { - log("[", local_domain, "] using ", - l3_protocol_name(prot), " rule: ", - transport_rule, " ", permit_rule); - } - Domain &remote_domain = permit_rule.domain(); - _adapt_eth(eth, local_id.dst_ip, pkt, remote_domain); - _nat_link_and_pass( - eth, size_guard, ip, ip_icd, prot, prot_base, prot_size, - local_id, local_domain, remote_domain); - - done = true; - }, - [&] /* handle_no_match */ () { } - ); - if (done) { - return; + /* try to route via transport and permit rules */ + _with_transport_rule(local_domain, prot, local_id.dst_ip, local_id.dst_port, + [&] (Transport_rule const &transport_rule, Permit_rule const &permit_rule) { + if(_config().verbose()) { + log("[", local_domain, "] using ", + l3_protocol_name(prot), " rule: ", + transport_rule, " ", permit_rule); + } + Domain &remote_domain = permit_rule.domain(); + result = _adapt_eth(eth, local_id.dst_ip, pkt, remote_domain); + if (result.valid()) + return; + result = _nat_link_and_pass( + eth, size_guard, ip, ip_icd, prot, prot_base, prot_size, + local_id, local_domain, remote_domain); + }); } } - catch (Interface::Bad_transport_protocol) { } + if (result.valid()) + return result; /* try to route via IP rules */ local_domain.ip_rules().find_longest_prefix_match( @@ -1371,17 +1397,18 @@ void Interface::_handle_ip(Ethernet_frame ð, log("[", local_domain, "] using IP rule: ", rule); } Domain &remote_domain = rule.domain(); - _adapt_eth(eth, ip.dst(), pkt, remote_domain); + result = _adapt_eth(eth, ip.dst(), pkt, remote_domain); + if (result.valid()) + return; remote_domain.interfaces().for_each([&] (Interface &interface) { interface.send(eth, size_guard); }); - done = true; + result = packet_handled(); }, [&] /* handle_no_match */ () { } ); - if (done) { - return; - } + if (result.valid()) + return result; /* * Give up and drop packet. According to RFC 1812 section 4.3.2.7, an ICMP @@ -1398,8 +1425,7 @@ void Interface::_handle_ip(Ethernet_frame ð, _send_icmp_dst_unreachable(local_intf, eth, ip, Icmp_packet::Code::DST_HOST_UNREACHABLE); } - if (_config().verbose()) { - log("[", local_domain, "] unroutable packet"); } + return packet_drop("unroutable"); } @@ -1455,7 +1481,7 @@ void Interface::_handle_arp_reply(Ethernet_frame ð, Arp_waiter &waiter = *waiter_le->object(); waiter_le = waiter_le->next(); if (ip != waiter.ip()) { continue; } - waiter.src()._continue_handle_eth(local_domain, waiter.packet()); + waiter.src()._continue_handle_eth(waiter.packet()); destroy(waiter.src()._alloc, &waiter); } } @@ -1504,10 +1530,10 @@ void Interface::_send_arp_reply(Ethernet_frame &request_eth, } -void Interface::_handle_arp_request(Ethernet_frame ð, - Size_guard &size_guard, - Arp_packet &arp, - Domain &local_domain) +Packet_result Interface::_handle_arp_request(Ethernet_frame ð, + Size_guard &size_guard, + Arp_packet &arp, + Domain &local_domain) { Ipv4_config const &local_ip_cfg = local_domain.ip_config(); Ipv4_address_prefix const &local_intf = local_ip_cfg.interface(); @@ -1517,7 +1543,7 @@ void Interface::_handle_arp_request(Ethernet_frame ð, if (arp.src_ip() == arp.dst_ip()) { /* gratuitous ARP requests are not really necessary */ - throw Drop_packet("gratuitous ARP request"); + return packet_drop("gratuitous ARP request"); } else if (arp.dst_ip() == local_intf.address) { @@ -1542,7 +1568,7 @@ void Interface::_handle_arp_request(Ethernet_frame ð, if (local_ip_cfg.gateway_valid()) { /* leave request up to the gateway of the domain */ - throw Drop_packet("leave ARP request up to gateway"); + return packet_drop("leave ARP request up to gateway"); } else { @@ -1553,35 +1579,54 @@ void Interface::_handle_arp_request(Ethernet_frame ð, _send_arp_reply(eth, arp); } } + return packet_handled(); } -void Interface::_handle_arp(Ethernet_frame ð, - Size_guard &size_guard, - Domain &local_domain) +Packet_result Interface::_handle_arp(Ethernet_frame ð, + Size_guard &size_guard, + Domain &local_domain) { /* ignore ARP regarding protocols other than IPv4 via ethernet */ Arp_packet &arp = eth.data(size_guard); if (!arp.ethernet_ipv4()) { - throw Drop_packet("ARP for unknown protocol"); } + return packet_drop("ARP for unknown protocol"); } switch (arp.opcode()) { - case Arp_packet::REPLY: _handle_arp_reply(eth, size_guard, arp, local_domain); break; - case Arp_packet::REQUEST: _handle_arp_request(eth, size_guard, arp, local_domain); break; - default: throw Drop_packet("unknown ARP operation"); } + case Arp_packet::REPLY: _handle_arp_reply(eth, size_guard, arp, local_domain); break; + case Arp_packet::REQUEST: return _handle_arp_request(eth, size_guard, arp, local_domain); + default: return packet_drop("unknown ARP operation"); } + return packet_handled(); +} + + +void Interface::_drop_packet(Packet_descriptor const &pkt, char const *reason) +{ + _ack_packet(pkt); + with_domain( + [&] /* domain_fn */ (Domain &domain) { + if (domain .verbose_packet_drop()) + log("[", domain, "] drop packet (", reason, ")"); }, + [&] /* no_domain_fn */ { + if (_config().verbose()) + log("[?] drop packet (", reason, ")"); }); } void Interface::_handle_pkt() { Packet_descriptor const pkt = _sink.get_packet(); - Size_guard size_guard(pkt.size()); - try { - _handle_eth(_sink.packet_content(pkt), size_guard, pkt); - _ack_packet(pkt); + if (!_sink.packet_valid(pkt) || pkt.size() < sizeof(Packet_stream_sink::Content_type)) { + _drop_packet(pkt, "invalid Nic packet"); + return; } - catch (Packet_postponed) { } - catch (Genode::Packet_descriptor::Invalid_packet) { } + Size_guard size_guard(pkt.size()); + Packet_result result = _handle_eth(_sink.packet_content(pkt), size_guard, pkt); + switch (result.type) { + case Packet_result::HANDLED: _ack_packet(pkt); break; + case Packet_result::POSTPONED: break; + case Packet_result::DROP: _drop_packet(pkt, result.drop_reason); break; + case Packet_result::INVALID: ASSERT_NEVER_REACHED; } } @@ -1644,29 +1689,27 @@ void Interface::_handle_pkt_stream_signal() } -void Interface::_continue_handle_eth(Domain const &domain, - Packet_descriptor const &pkt) +void Interface::_continue_handle_eth(Packet_descriptor const &pkt) { + if (!_sink.packet_valid(pkt) || pkt.size() < sizeof(Packet_stream_sink::Content_type)) { + _drop_packet(pkt, "invalid Nic packet"); + return; + } Size_guard size_guard(pkt.size()); - try { _handle_eth(_sink.packet_content(pkt), size_guard, pkt); } - catch (Packet_postponed) { - if (domain.verbose_packet_drop()) { - log("[", domain, "] drop packet (handling postponed twice)"); } - } - catch (Genode::Packet_descriptor::Invalid_packet) { - if (domain.verbose_packet_drop()) { - log("[", domain, "] invalid Nic packet received"); - } - } - _ack_packet(pkt); + Packet_result result = _handle_eth(_sink.packet_content(pkt), size_guard, pkt); + switch (result.type) { + case Packet_result::HANDLED: _ack_packet(pkt); break; + case Packet_result::POSTPONED: _drop_packet(pkt, "postponed twice"); break; + case Packet_result::DROP: _drop_packet(pkt, result.drop_reason); break; + case Packet_result::INVALID: ASSERT_NEVER_REACHED; } } void Interface::_destroy_dhcp_allocation(Dhcp_allocation &allocation, Domain &local_domain) { - try { local_domain.dhcp_server().free_ip(local_domain, allocation.ip()); } - catch (Pointer::Invalid) { } + local_domain.with_dhcp_server([&] (Dhcp_server &srv) { + srv.free_ip(allocation.ip()); }); destroy(_alloc, &allocation); } @@ -1680,17 +1723,17 @@ void Interface::_destroy_released_dhcp_allocations(Domain &local_domain) } -void Interface::_handle_eth(Ethernet_frame ð, - Size_guard &size_guard, - Packet_descriptor const &pkt, - Domain &local_domain) +Packet_result Interface::_handle_eth(Ethernet_frame ð, + Size_guard &size_guard, + Packet_descriptor const &pkt, + Domain &local_domain) { if (local_domain.ip_config().valid()) { switch (eth.type()) { - case Ethernet_frame::Type::ARP: _handle_arp(eth, size_guard, local_domain); break; - case Ethernet_frame::Type::IPV4: _handle_ip(eth, size_guard, pkt, local_domain); break; - default: throw Bad_network_protocol(); } + case Ethernet_frame::Type::ARP: return _handle_arp(eth, size_guard, local_domain); + case Ethernet_frame::Type::IPV4: return _handle_ip(eth, size_guard, pkt, local_domain); + default: return packet_drop("unknown network layer protocol"); } } else { @@ -1700,161 +1743,81 @@ void Interface::_handle_eth(Ethernet_frame ð, if (eth.dst() != router_mac() && eth.dst() != Mac_address(0xff)) { - throw Drop_packet("Expecting Ethernet targeting the router"); } + return packet_drop("Expecting Ethernet targeting the router"); } Ipv4_packet &ip = eth.data(size_guard); if (ip.protocol() != Ipv4_packet::Protocol::UDP) { - throw Drop_packet("Expecting UDP packet"); } + return packet_drop("Expecting UDP packet"); } Udp_packet &udp = ip.data(size_guard); if (!Dhcp_packet::is_dhcp(&udp)) { - throw Drop_packet("Expecting DHCP packet"); } + return packet_drop("Expecting DHCP packet"); } Dhcp_packet &dhcp = udp.data(size_guard); switch (dhcp.op()) { case Dhcp_packet::REPLY: if (dhcp.client_mac() != router_mac()) { - throw Drop_packet("Expecting DHCP targeting the router"); } + return packet_drop("Expecting DHCP targeting the router"); } if (!_dhcp_client.constructed()) { - throw Drop_packet("Expecting DHCP client to be active"); } + return packet_drop("Expecting DHCP client to be active"); } - _dhcp_client->handle_dhcp_reply(dhcp); - break; + return _dhcp_client->handle_dhcp_reply(dhcp, local_domain); default: - throw Drop_packet("Expecting DHCP reply"); + return packet_drop("Expecting DHCP reply"); } break; } case Ethernet_frame::Type::ARP: { - throw Drop_packet("Ignore ARP request on unconfigured interface"); + return packet_drop("Ignore ARP request on unconfigured interface"); } - default: - - throw Bad_network_protocol(); + default: return packet_drop("unknown network layer protocol"); } } + ASSERT_NEVER_REACHED; } -void Interface::_handle_eth(void *const eth_base, - Size_guard &size_guard, - Packet_descriptor const &pkt) +Packet_result Interface::_handle_eth(void *const eth_base, + Size_guard &size_guard, + Packet_descriptor const &pkt) { + Packet_result result { }; try { - Domain &local_domain = _domain(); - local_domain.raise_rx_bytes(size_guard.total_size()); - try { - Ethernet_frame ð = Ethernet_frame::cast_from(eth_base, size_guard); - try { - /* do garbage collection over transport-layer links and DHCP allocations */ - _destroy_dissolved_links(_dissolved_icmp_links, _alloc); - _destroy_dissolved_links(_dissolved_udp_links, _alloc); - _destroy_dissolved_links(_dissolved_tcp_links, _alloc); - _destroy_released_dhcp_allocations(local_domain); + Ethernet_frame ð = Ethernet_frame::cast_from(eth_base, size_guard); + auto domain_fn = [&] (Domain &domain) { - /* log received packet if desired */ - if (local_domain.verbose_packets()) { - log("[", local_domain, "] rcv ", eth); } + domain.raise_rx_bytes(size_guard.total_size()); - if (local_domain.trace_packets()) - Genode::Trace::Ethernet_packet(local_domain.name().string(), - Genode::Trace::Ethernet_packet::Direction::RECV, - eth_base, - size_guard.total_size()); + /* do garbage collection over transport-layer links and DHCP allocations */ + _destroy_dissolved_links(_dissolved_icmp_links, _alloc); + _destroy_dissolved_links(_dissolved_udp_links, _alloc); + _destroy_dissolved_links(_dissolved_tcp_links, _alloc); + _destroy_released_dhcp_allocations(domain); - /* try to handle ethernet frame */ - try { _handle_eth(eth, size_guard, pkt, local_domain); } - catch (Free_resources_and_retry_handle_eth) { - try { - if (_config().verbose()) { - log("[", local_domain, "] free resources and retry to handle packet"); } + /* log received packet if desired */ + if (domain.verbose_packets()) { + log("[", domain, "] rcv ", eth); } - /* - * Resources do not suffice, destroy some links - * - * Limit number of links to destroy because otherwise, - * this could block the router for a significant - * amount of time. - */ - unsigned long max = MAX_FREE_OPS_PER_EMERGENCY; - _destroy_some_links (_tcp_links, _dissolved_tcp_links, _alloc, max); - _destroy_some_links (_udp_links, _dissolved_udp_links, _alloc, max); - _destroy_some_links(_icmp_links, _dissolved_icmp_links, _alloc, max); + if (domain.trace_packets()) + Genode::Trace::Ethernet_packet( + domain.name().string(), Genode::Trace::Ethernet_packet::Direction::RECV, + eth_base, size_guard.total_size()); - /* retry to handle ethernet frame */ - _handle_eth(eth, size_guard, pkt, local_domain); - } - catch (Free_resources_and_retry_handle_eth exception) { - if (exception.prot != (L3_protocol)0) { - switch (exception.prot) { - case L3_protocol::TCP: _tcp_stats.refused_for_ram++; break; - case L3_protocol::UDP: _udp_stats.refused_for_ram++; break; - case L3_protocol::ICMP: _icmp_stats.refused_for_ram++; break; - default: throw Bad_transport_protocol(); } - } - - /* give up if the resources still not suffice */ - throw Drop_packet("insufficient resources"); - } - } - } - catch (Dhcp_server::Alloc_ip_failed) { - if (_config().verbose()) { - log("[", local_domain, "] failed to allocate IP for DHCP " - "client"); - } - } - catch (Port_allocator_guard::Out_of_indices) { - if (_config().verbose()) { - log("[", local_domain, "] no available NAT ports"); } - } - catch (Domain::No_next_hop) { - if (_config().verbose()) { - log("[", local_domain, "] cannot find next hop"); } - } - catch (Alloc_dhcp_msg_buffer_failed) { - if (_config().verbose()) { - log("[", local_domain, "] failed to allocate buffer for " - "DHCP reply"); - } - } - catch (Bad_network_protocol) { - if (_config().verbose()) { - log("[", local_domain, "] unknown network layer " - "protocol"); - } - } - catch (Drop_packet exception) { - if (local_domain.verbose_packet_drop()) { - log("[", local_domain, "] drop packet (", - exception.reason, ")"); - } - } - } - catch (Size_guard::Exceeded) { - if (_config().verbose()) { - log("[", local_domain, "] drop packet: packet size-guard " - "exceeded"); - } - } - } - catch (Pointer::Invalid) { - try { - Ethernet_frame ð = Ethernet_frame::cast_from(eth_base, size_guard); - if (_config().verbose_packets()) { - log("[?] rcv ", eth); } - } - catch (Size_guard::Exceeded) { - if (_config().verbose_packets()) { - log("[?] rcv ?"); } - } - if (_config().verbose()) { - log("[?] drop packet: no domain"); } + result = _handle_eth(eth, size_guard, pkt, domain); + }; + auto no_domain_fn = [&] /* no_domain_fn */ { + if (_config().verbose_packets()) + log("[?] rcv ", eth); + result = packet_drop("no domain"); + }; + with_domain(domain_fn, no_domain_fn); } + catch (Size_guard::Exceeded) { result = packet_drop("packet size-guard exceeded"); } + return result; } @@ -1871,7 +1834,7 @@ void Interface::_send_submit_pkt(Packet_descriptor &pkt, void * &pkt_base, size_t pkt_size) { - Domain &local_domain = _domain(); + Domain &local_domain = *_domain_ptr; local_domain.raise_tx_bytes(pkt_size); if (local_domain.verbose_packets()) { try { @@ -1915,8 +1878,7 @@ Interface::Interface(Genode::Entrypoint &ep, _interfaces { interfaces } { _interfaces.insert(this); - try { _config().report().handle_interface_link_state(); } - catch (Pointer::Invalid) { } + _config().with_report([&] (Report &r) { r.handle_interface_link_state(); }); } @@ -1941,11 +1903,7 @@ bool Interface::_try_update_link(Link &link, return false; if (link.client().src_ip() == link.server().dst_ip()) { - - link.handle_config( - cln_dom, new_srv_dom, Pointer { }, - _config()); - + link.handle_config(cln_dom, new_srv_dom, nullptr, _config()); return true; } if (link.server().dst_ip() != new_srv_dom.ip_config().interface().address) @@ -1957,13 +1915,10 @@ bool Interface::_try_update_link(Link &link, [&] /* handle_match */ (Nat_rule &nat) { Port_allocator_guard &remote_port_alloc { nat.port_alloc(prot) }; - try { remote_port_alloc.alloc(link.server().dst_port()); } - catch (Port_allocator::Allocation_conflict) { return; } - catch (Port_allocator_guard::Out_of_indices) { return; } - - link.handle_config( - cln_dom, new_srv_dom, remote_port_alloc, _config()); + if (!remote_port_alloc.alloc(link.server().dst_port())) + return; + link.handle_config(cln_dom, new_srv_dom, &remote_port_alloc, _config()); keep_link = true; }, [&] /* handle_no_match */ () { } @@ -1977,49 +1932,35 @@ void Interface::_update_udp_tcp_links(L3_protocol prot, { links(prot).for_each([&] (Link &link) { - bool link_has_been_updated { false }; + bool link_updated { false }; if (link.server().src_ip() != link.client().dst_ip()) { - _forward_rules(cln_dom, prot).find_by_port( - link.client().dst_port(), - [&] /* handle_match */ (Forward_rule const &rule) - { - if (rule.to_ip() != link.server().src_ip()) + _with_forward_rule(cln_dom, prot, link.client().dst_port(), [&] (Forward_rule const &rule) { + if (rule.to_ip() != link.server().src_ip()) + return; + + if (rule.to_port() == Port { 0 }) { + + if (link.server().src_port() != + link.client().dst_port()) return; - if (rule.to_port() == Port { 0 }) { + } else { - if (link.server().src_port() != - link.client().dst_port()) - return; - - } else { - - if (rule.to_port() != link.server().src_port()) - return; - } - link_has_been_updated = - _try_update_link(link, rule.domain(), prot, cln_dom); - }, - [&] /* handle_no_match */ () { } - ); + if (rule.to_port() != link.server().src_port()) + return; + } + link_updated = _try_update_link(link, rule.domain(), prot, cln_dom); + }); } else { - _transport_rules(cln_dom, prot).find_best_match( - link.client().dst_ip(), - link.client().dst_port(), - [&] /* handle_match */ (Transport_rule const &, - Permit_rule const &rule) - { - link_has_been_updated = - _try_update_link(link, rule.domain(), prot, cln_dom); - }, - [&] /* handle_no_match */ () { } - ); + _with_transport_rule(cln_dom, prot, link.client().dst_ip(), link.client().dst_port(), + [&] (Transport_rule const &, Permit_rule const &rule) { + link_updated = _try_update_link(link, rule.domain(), prot, cln_dom); }); } - if (link_has_been_updated) + if (link_updated) return; _dismiss_link(link); @@ -2055,51 +1996,37 @@ void Interface::_update_dhcp_allocations(Domain &old_domain, Domain &new_domain) { bool dhcp_clients_outdated { false }; - try { - Dhcp_server &old_dhcp_srv = old_domain.dhcp_server(); - Dhcp_server &new_dhcp_srv = new_domain.dhcp_server(); - if (!old_dhcp_srv.config_equal_to_that_of(new_dhcp_srv)) { - throw Pointer::Invalid(); - } - _dhcp_allocations.for_each([&] (Dhcp_allocation &allocation) { - try { - new_dhcp_srv.alloc_ip(allocation.ip()); + old_domain.with_dhcp_server([&] (Dhcp_server &old_dhcp_srv) { + new_domain.with_dhcp_server([&] (Dhcp_server &new_dhcp_srv) { + if (old_dhcp_srv.config_equal_to_that_of(new_dhcp_srv)) { + /* try to re-use existing DHCP allocations */ + _dhcp_allocations.for_each([&] (Dhcp_allocation &allocation) { + if (!new_dhcp_srv.alloc_ip(allocation.ip())) { + if (_config().verbose()) + log("[", new_domain, "] dismiss DHCP allocation: ", allocation, " (no IP)"); - /* keep DHCP allocation */ - if (_config().verbose()) { - log("[", new_domain, "] update DHCP allocation: ", - allocation); + dhcp_clients_outdated = true; + _dhcp_allocations.remove(allocation); + _destroy_dhcp_allocation(allocation, old_domain); + return; } - return; - } - catch (Dhcp_server::Alloc_ip_failed) { - if (_config().verbose()) { - log("[", new_domain, "] dismiss DHCP allocation: ", - allocation, " (no IP)"); - } - } - /* dismiss DHCP allocation */ + if (_config().verbose()) + log("[", new_domain, "] update DHCP allocation: ", allocation); + }); + } else { + /* dismiss all DHCP allocations */ dhcp_clients_outdated = true; - _dhcp_allocations.remove(allocation); - _destroy_dhcp_allocation(allocation, old_domain); - }); - } - catch (Pointer::Invalid) { - - /* dismiss all DHCP allocations */ - dhcp_clients_outdated = true; - while (Dhcp_allocation *allocation = _dhcp_allocations.first()) { - if (_config().verbose()) { - log("[", new_domain, "] dismiss DHCP allocation: ", - *allocation, " (other/no DHCP server)"); + while (Dhcp_allocation *allocation = _dhcp_allocations.first()) { + if (_config().verbose()) + log("[", new_domain, "] dismiss DHCP allocation: ", + *allocation, " (other/no DHCP server)"); + _dhcp_allocations.remove(*allocation); + _destroy_dhcp_allocation(*allocation, old_domain); } - _dhcp_allocations.remove(*allocation); - _destroy_dhcp_allocation(*allocation, old_domain); } - } - if (dhcp_clients_outdated) { - _reset_and_refetch_domain_ready_state(); - } + if (dhcp_clients_outdated) + _reset_and_refetch_domain_ready_state(); + });}); } @@ -2146,9 +2073,9 @@ void Interface::handle_config_1(Configuration &config) _config = config; _policy.handle_config(config); Domain_name const &new_domain_name = _policy.determine_domain_name(); - try { + with_domain([&] (Domain &old_domain) { + /* destroy state objects that are not needed anymore */ - Domain &old_domain = domain(); _destroy_dissolved_links(_dissolved_icmp_links, _alloc); _destroy_dissolved_links (_dissolved_udp_links, _alloc); _destroy_dissolved_links (_dissolved_tcp_links, _alloc); @@ -2167,37 +2094,35 @@ void Interface::handle_config_1(Configuration &config) }, [&] /* no_match_fn */ () { } ); - } - catch (Pointer::Invalid) { } + }); } void Interface::_failed_to_send_packet_link() { if (_config().verbose()) { - log("[", _domain(), "] failed to send packet (link down)"); } + log("[", *_domain_ptr, "] failed to send packet (link down)"); } } void Interface::_failed_to_send_packet_submit() { if (_config().verbose()) { - log("[", _domain(), "] failed to send packet (queue full)"); } + log("[", *_domain_ptr, "] failed to send packet (queue full)"); } } void Interface::_failed_to_send_packet_alloc() { if (_config().verbose()) { - log("[", _domain(), "] failed to send packet (packet alloc failed)"); } + log("[", *_domain_ptr, "] failed to send packet (packet alloc failed)"); } } void Interface::handle_config_2() { Domain_name const &new_domain_name = _policy.determine_domain_name(); - try { - Domain &old_domain = domain(); + auto domain_fn = [&] (Domain &old_domain) { _config().domains().with_element( new_domain_name, [&] /* match_fn */ (Domain &new_domain) @@ -2245,9 +2170,8 @@ void Interface::handle_config_2() } } ); - } - catch (Pointer::Invalid) { - + }; + auto no_domain_fn = [&] { /* the interface had no domain but now it may get one */ _config().domains().with_element( new_domain_name, @@ -2262,13 +2186,14 @@ void Interface::handle_config_2() }, [&] /* no_match_fn */ () { } ); - } + }; + with_domain(domain_fn, no_domain_fn); } void Interface::handle_config_3() { - try { + if (_update_domain.constructed()) { /* * Update the domain object only if handle_config_2 determined that * the interface stays attached to the same domain. Otherwise the @@ -2296,13 +2221,9 @@ void Interface::handle_config_3() _update_icmp_links(new_domain); _update_dhcp_allocations(old_domain, new_domain); _update_own_arp_waiters(new_domain); - } - catch (Constructible::Deref_unconstructed_object) { - + } else /* if the interface moved to another domain, finish the operation */ - try { attach_to_domain_finish(); } - catch (Pointer::Invalid) { } - } + with_domain([&] (Domain &) { attach_to_domain_finish(); }); } @@ -2310,7 +2231,7 @@ void Interface::_ack_packet(Packet_descriptor const &pkt) { if (!_sink.try_ack_packet(pkt)) { if (_config().verbose()) { - log("[", _domain(), "] leak packet (sink not ready to " + log("[", *_domain_ptr, "] leak packet (sink not ready to " "acknowledge)"); } return; @@ -2320,59 +2241,48 @@ void Interface::_ack_packet(Packet_descriptor const &pkt) void Interface::cancel_arp_waiting(Arp_waiter &waiter) { - try { - Domain &domain = _domain(); - if (domain.verbose_packet_drop()) { - log("[", domain, "] drop packet (ARP got cancelled)"); } - } - catch (Pointer::Invalid) { - if (_config().verbose_packet_drop()) { - log("[?] drop packet (ARP got cancelled)"); } - } - _ack_packet(waiter.packet()); + _drop_packet(waiter.packet(), "ARP got cancelled"); destroy(_alloc, &waiter); } Interface::~Interface() { - try { _config().report().handle_interface_link_state(); } - catch (Pointer::Invalid) { } + _config().with_report([&] (Report &r) { r.handle_interface_link_state(); }); _detach_from_domain(); _interfaces.remove(this); } -void Interface::report(Genode::Xml_generator &xml) -{ - xml.node("interface", [&] () { - bool empty { true }; - xml.attribute("label", _policy.label()); - if (_config().report().link_state()) { - xml.attribute("link_state", link_state()); - empty = false; - } - if (_config().report().stats()) { - try { - _policy.report(xml); - empty = false; - } - catch (Report::Empty) { } - try { xml.node("tcp-links", [&] () { _tcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("udp-links", [&] () { _udp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("icmp-links", [&] () { _icmp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("arp-waiters", [&] () { _arp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - try { xml.node("dhcp-allocations", [&] () { _dhcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } - } - if (_config().report().dropped_fragm_ipv4() && _dropped_fragm_ipv4) { - xml.node("dropped-fragm-ipv4", [&] () { - xml.attribute("value", _dropped_fragm_ipv4); - }); - empty = false; - } - if (empty) { throw Report::Empty(); } - }); +bool Interface::report_empty(Report const &report_cfg) const +{ + bool stats = report_cfg.stats() && ( + !_policy.report_empty() || !_tcp_stats.report_empty() || !_udp_stats.report_empty() || + !_icmp_stats.report_empty() || !_arp_stats.report_empty() || _dhcp_stats.report_empty()); + bool lnk_state = report_cfg.link_state(); + bool fragm_ip = report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4; + return !lnk_state && !stats && !fragm_ip; +} + + +void Interface::report(Genode::Xml_generator &xml, Report const &report_cfg) const +{ + xml.attribute("label", _policy.label()); + if (report_cfg.link_state()) + xml.attribute("link_state", link_state()); + + if (report_cfg.stats()) { + _policy.report(xml); + if (!_tcp_stats.report_empty()) xml.node("tcp-links", [&] { _tcp_stats.report(xml); }); + if (!_udp_stats.report_empty()) xml.node("udp-links", [&] { _udp_stats.report(xml); }); + if (!_icmp_stats.report_empty()) xml.node("icmp-links", [&] { _icmp_stats.report(xml); }); + if (!_arp_stats.report_empty()) xml.node("arp-waiters", [&] { _arp_stats.report(xml); }); + if (!_dhcp_stats.report_empty()) xml.node("dhcp-allocations", [&] { _dhcp_stats.report(xml); }); + } + if (report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4) + xml.node("dropped-fragm-ipv4", [&] { + xml.attribute("value", _dropped_fragm_ipv4); }); } diff --git a/repos/os/src/server/nic_router/interface.h b/repos/os/src/server/nic_router/interface.h index 99da02c662..beea19c9a3 100644 --- a/repos/os/src/server/nic_router/interface.h +++ b/repos/os/src/server/nic_router/interface.h @@ -68,7 +68,8 @@ struct Net::Interface_object_stats Genode::size_t alive { 0 }; Genode::size_t destroyed { 0 }; - void report(Genode::Xml_generator &xml); + bool report_empty() const; + void report(Genode::Xml_generator &xml) const; ~Interface_object_stats(); }; @@ -89,13 +90,14 @@ struct Net::Interface_link_stats Genode::size_t dissolved_no_timeout { 0 }; Genode::size_t destroyed { 0 }; - void report(Genode::Xml_generator &xml); + bool report_empty() const; + void report(Genode::Xml_generator &xml) const; ~Interface_link_stats(); }; -struct Net::Interface_policy +struct Net::Interface_policy : Genode::Interface { virtual Domain_name determine_domain_name() const = 0; @@ -107,7 +109,9 @@ struct Net::Interface_policy virtual bool interface_link_state() const = 0; - virtual void report(Genode::Xml_generator &) const { throw Report::Empty(); } + virtual bool report_empty() const = 0; + + virtual void report(Genode::Xml_generator &) const = 0; virtual ~Interface_policy() { } }; @@ -126,9 +130,6 @@ class Net::Interface : private Interface_list::Element enum { IPV4_TIME_TO_LIVE = 64 }; enum { MAX_FREE_OPS_PER_EMERGENCY = 1024 }; - struct Dismiss_link : Genode::Exception { }; - struct Dismiss_arp_waiter : Genode::Exception { }; - struct Update_domain { Domain &old_domain; @@ -151,7 +152,7 @@ class Net::Interface : private Interface_list::Element Interface_policy &_policy; Cached_timer &_timer; Genode::Allocator &_alloc; - Pointer _domain { }; + Domain *_domain_ptr { }; Arp_waiter_list _own_arp_waiters { }; Link_list _tcp_links { }; Link_list _udp_links { }; @@ -171,11 +172,18 @@ class Net::Interface : private Interface_list::Element Interface_object_stats _dhcp_stats { }; unsigned long _dropped_fragm_ipv4 { 0 }; - void _new_link(L3_protocol const protocol, - Link_side_id const &local_id, - Pointer remote_port_alloc, - Domain &remote_domain, - Link_side_id const &remote_id); + /* + * Noncopyable + */ + Interface(Interface const &); + Interface &operator = (Interface const &); + + [[nodiscard]] Packet_result _new_link(L3_protocol const protocol, + Domain &local_domain, + Link_side_id const &local_id, + Port_allocator_guard *remote_port_alloc_ptr, + Domain &remote_domain, + Link_side_id const &remote_id); void _destroy_released_dhcp_allocations(Domain &local_domain); @@ -185,10 +193,10 @@ class Net::Interface : private Interface_list::Element void _release_dhcp_allocation(Dhcp_allocation &allocation, Domain &local_domain); - void _new_dhcp_allocation(Ethernet_frame ð, - Dhcp_packet &dhcp, - Dhcp_server &dhcp_srv, - Domain &local_domain); + [[nodiscard]] Packet_result _new_dhcp_allocation(Ethernet_frame ð, + Dhcp_packet &dhcp, + Dhcp_server &dhcp_srv, + Domain &local_domain); void _send_dhcp_reply(Dhcp_server const &dhcp_srv, Mac_address const ð_dst, @@ -204,84 +212,79 @@ class Net::Interface : private Interface_list::Element Genode::size_t icmp_sz, Size_guard &size_guard); - Forward_rule_tree &_forward_rules(Domain &local_domain, - L3_protocol const prot) const; - - Transport_rule_list &_transport_rules(Domain &local_domain, - L3_protocol const prot) const; - - void _handle_arp(Ethernet_frame ð, - Size_guard &size_guard, - Domain &local_domain); + [[nodiscard]] Packet_result _handle_arp(Ethernet_frame ð, + Size_guard &size_guard, + Domain &local_domain); void _handle_arp_reply(Ethernet_frame ð, Size_guard &size_guard, Arp_packet &arp, Domain &local_domain); - void _handle_arp_request(Ethernet_frame ð, - Size_guard &size_guard, - Arp_packet &arp, - Domain &local_domain); + [[nodiscard]] Packet_result _handle_arp_request(Ethernet_frame ð, + Size_guard &size_guard, + Arp_packet &arp, + Domain &local_domain); void _send_arp_reply(Ethernet_frame &request_eth, Arp_packet &request_arp); - void _handle_dhcp_request(Ethernet_frame ð, - Dhcp_packet &dhcp, - Domain &local_domain, - Ipv4_address_prefix const &local_intf); + [[nodiscard]] Packet_result _handle_dhcp_request(Ethernet_frame ð, + Dhcp_server &dhcp_srv, + Dhcp_packet &dhcp, + Domain &local_domain, + Ipv4_address_prefix const &local_intf); - void _handle_ip(Ethernet_frame ð, - Size_guard &size_guard, - Packet_descriptor const &pkt, - Domain &local_domain); + [[nodiscard]] Packet_result _handle_ip(Ethernet_frame ð, + Size_guard &size_guard, + Packet_descriptor const &pkt, + Domain &local_domain); - void _handle_icmp_query(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - Packet_descriptor const &pkt, - L3_protocol prot, - void *prot_base, - Genode::size_t prot_size, - Domain &local_domain); + [[nodiscard]] Packet_result _handle_icmp_query(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + Packet_descriptor const &pkt, + L3_protocol prot, + void *prot_base, + Genode::size_t prot_size, + Domain &local_domain); - void _handle_icmp_error(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - Packet_descriptor const &pkt, - Domain &local_domain, - Icmp_packet &icmp, - Genode::size_t icmp_sz); + [[nodiscard]] Packet_result _handle_icmp_error(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + Packet_descriptor const &pkt, + Domain &local_domain, + Icmp_packet &icmp, + Genode::size_t icmp_sz); - void _handle_icmp(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - Packet_descriptor const &pkt, - L3_protocol prot, - void *prot_base, - Genode::size_t prot_size, - Domain &local_domain, - Ipv4_address_prefix const &local_intf); + [[nodiscard]] Packet_result _handle_icmp(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + Packet_descriptor const &pkt, + L3_protocol prot, + void *prot_base, + Genode::size_t prot_size, + Domain &local_domain, + Ipv4_address_prefix const &local_intf); - void _adapt_eth(Ethernet_frame ð, - Ipv4_address const &dst_ip, - Packet_descriptor const &pkt, - Domain &remote_domain); + [[nodiscard]] Packet_result _adapt_eth(Ethernet_frame ð, + Ipv4_address const &dst_ip, + Packet_descriptor const &pkt, + Domain &remote_domain); - void _nat_link_and_pass(Ethernet_frame ð, - Size_guard &size_guard, - Ipv4_packet &ip, - Internet_checksum_diff &ip_icd, - L3_protocol const prot, - void *const prot_base, - Genode::size_t const prot_size, - Link_side_id const &local_id, - Domain &local_domain, - Domain &remote_domain); + [[nodiscard]] Packet_result _nat_link_and_pass(Ethernet_frame ð, + Size_guard &size_guard, + Ipv4_packet &ip, + Internet_checksum_diff &ip_icd, + L3_protocol const prot, + void *const prot_base, + Genode::size_t const prot_size, + Link_side_id const &local_id, + Domain &local_domain, + Domain &remote_domain); void _broadcast_arp_request(Ipv4_address const &src_ip, Ipv4_address const &dst_ip); @@ -301,19 +304,20 @@ class Net::Interface : private Interface_list::Element void _handle_pkt(); - void _continue_handle_eth(Domain const &domain, - Packet_descriptor const &pkt); + void _continue_handle_eth(Packet_descriptor const &pkt); Ipv4_address const &_router_ip() const; - void _handle_eth(void *const eth_base, - Size_guard &size_guard, - Packet_descriptor const &pkt); + void _drop_packet(Packet_descriptor const &pkt, char const *reason); - void _handle_eth(Ethernet_frame ð, - Size_guard &size_guard, - Packet_descriptor const &pkt, - Domain &local_domain); + [[nodiscard]] Packet_result _handle_eth(void *const eth_base, + Size_guard &size_guard, + Packet_descriptor const &pkt); + + [[nodiscard]] Packet_result _handle_eth(Ethernet_frame ð, + Size_guard &size_guard, + Packet_descriptor const &pkt, + Domain &local_domain); void _ack_packet(Packet_descriptor const &pkt); @@ -369,20 +373,6 @@ class Net::Interface : private Interface_list::Element public: - struct Free_resources_and_retry_handle_eth : Genode::Exception { L3_protocol prot; Free_resources_and_retry_handle_eth(L3_protocol prot = (L3_protocol)0) : prot(prot) { } }; - struct Bad_send_dhcp_args : Genode::Exception { }; - struct Bad_transport_protocol : Genode::Exception { }; - struct Bad_network_protocol : Genode::Exception { }; - struct Packet_postponed : Genode::Exception { }; - struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { }; - - struct Drop_packet : Genode::Exception - { - char const *reason; - - Drop_packet(char const *reason) : reason(reason) { } - }; - Interface(Genode::Entrypoint &ep, Cached_timer &timer, Mac_address const router_mac, @@ -454,19 +444,30 @@ class Net::Interface : private Interface_list::Element void handle_interface_link_state(); - void report(Genode::Xml_generator &xml); + bool report_empty(Report const &report_cfg) const; + + void report(Genode::Xml_generator &xml, Report const &report_cfg) const; void handle_domain_ready_state(bool state); void destroy_link(Link &link); + void with_domain(auto const &domain_fn, auto const &no_domain_fn) + { + if (_domain_ptr) + domain_fn(*_domain_ptr); + else + no_domain_fn(); + } + + void with_domain(auto const &fn) { with_domain(fn, []{}); } + /*************** ** Accessors ** ***************/ Configuration const &config() const { return _config(); } - Domain &domain() { return _domain(); } Mac_address const &router_mac() const { return _router_mac; } Mac_address const &mac() const { return _mac; } Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; } diff --git a/repos/os/src/server/nic_router/ip_rule.cc b/repos/os/src/server/nic_router/ip_rule.cc deleted file mode 100644 index b808afee32..0000000000 --- a/repos/os/src/server/nic_router/ip_rule.cc +++ /dev/null @@ -1,26 +0,0 @@ -/* - * \brief IP routing entry - * \author Martin Stein - * \date 2016-08-19 - */ - -/* - * Copyright (C) 2016-2017 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. - */ - -/* local includes */ -#include -#include - -using namespace Net; -using namespace Genode; - - -Ip_rule::Ip_rule(Domain_dict &domains, Xml_node const node) -: - Direct_rule { node }, - _domain { domains.deprecated_find_by_domain_attr(node) } -{ } diff --git a/repos/os/src/server/nic_router/ip_rule.h b/repos/os/src/server/nic_router/ip_rule.h index 8340231155..443c0e8485 100644 --- a/repos/os/src/server/nic_router/ip_rule.h +++ b/repos/os/src/server/nic_router/ip_rule.h @@ -35,7 +35,7 @@ class Net::Ip_rule : public Direct_rule public: - Ip_rule(Domain_dict &domains, Genode::Xml_node const node); + Ip_rule(Ipv4_address_prefix const &dst, Domain &domain) : Direct_rule(dst), _domain(domain) { } /*************** diff --git a/repos/os/src/server/nic_router/ipv4_config.cc b/repos/os/src/server/nic_router/ipv4_config.cc index 00a131e807..6dd6e3cbdf 100644 --- a/repos/os/src/server/nic_router/ipv4_config.cc +++ b/repos/os/src/server/nic_router/ipv4_config.cc @@ -90,10 +90,7 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack, dhcp_ipv4_option(dhcp_ack) }, _gateway { dhcp_ipv4_option(dhcp_ack) } { - try { - Dhcp_packet::Dns_server const &dns_server { - dhcp_ack.option() }; - + dhcp_ack.with_option([&] (Dhcp_packet::Dns_server const &dns_server) { dns_server.for_each_address([&] (Ipv4_address const &addr) { Dns_server::construct( alloc, addr, @@ -104,10 +101,9 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack, [&] /* handle_failure */ () { } ); }); - } - catch (Dhcp_packet::Option_not_found) { } - try { - _dns_domain_name.set_to(dhcp_ack.option()); + }); + dhcp_ack.with_option([&] (Dhcp_packet::Domain_name const &domain_name) { + _dns_domain_name.set_to(domain_name); if (domain.config().verbose() && !_dns_domain_name.valid()) { @@ -115,8 +111,7 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack, log("[", domain, "] rejecting oversized DNS " "domain name from DHCP reply"); } - } - catch (Dhcp_packet::Option_not_found) { } + }); } diff --git a/repos/os/src/server/nic_router/l3_protocol.cc b/repos/os/src/server/nic_router/l3_protocol.cc index 4abc94f881..f2a37fd9e9 100644 --- a/repos/os/src/server/nic_router/l3_protocol.cc +++ b/repos/os/src/server/nic_router/l3_protocol.cc @@ -35,5 +35,5 @@ char const *Net::l3_protocol_name(L3_protocol protocol) case L3_protocol::TCP: return tcp_name(); case L3_protocol::UDP: return udp_name(); case L3_protocol::ICMP: return icmp_name(); - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } diff --git a/repos/os/src/server/nic_router/link.cc b/repos/os/src/server/nic_router/link.cc index 0d287ceb7e..68930ea87f 100644 --- a/repos/os/src/server/nic_router/link.cc +++ b/repos/os/src/server/nic_router/link.cc @@ -86,8 +86,9 @@ void Link::print(Output &output) const Link::Link(Interface &cln_interface, + Domain &cln_domain, Link_side_id const &cln_id, - Pointer srv_port_alloc, + Port_allocator_guard *srv_port_alloc_ptr, Domain &srv_domain, Link_side_id const &srv_id, Cached_timer &timer, @@ -98,12 +99,12 @@ Link::Link(Interface &cln_interface, : _config(config), _client_interface(cln_interface), - _server_port_alloc(srv_port_alloc), + _server_port_alloc_ptr(srv_port_alloc_ptr), _dissolve_timeout(timer, *this, &Link::_handle_dissolve_timeout, Microseconds { 100 * 1000 }), _dissolve_timeout_us(dissolve_timeout), _protocol(protocol), - _client(cln_interface.domain(), cln_id, *this), + _client(cln_domain, cln_id, *this), _server(srv_domain, srv_id, *this), _stats(stats), _stats_curr(stats.opening) @@ -146,30 +147,29 @@ void Link::dissolve(bool timeout) if (_config().verbose()) { log("Dissolve ", l3_protocol_name(_protocol), " link: ", *this); } - try { + if (_server_port_alloc_ptr) { if (_config().verbose()) { log("Free ", l3_protocol_name(_protocol), " port ", _server.dst_port(), " at ", _server.domain(), " that was used by ", _client.domain()); } - _server_port_alloc().free(_server.dst_port()); + _server_port_alloc_ptr->free(_server.dst_port()); } - catch (Pointer::Invalid) { } } -void Link::handle_config(Domain &cln_domain, - Domain &srv_domain, - Pointer srv_port_alloc, - Configuration &config) +void Link::handle_config(Domain &cln_domain, + Domain &srv_domain, + Port_allocator_guard *srv_port_alloc_ptr, + Configuration &config) { Microseconds dissolve_timeout_us(0); switch (_protocol) { case L3_protocol::TCP: dissolve_timeout_us = config.tcp_idle_timeout(); break; case L3_protocol::UDP: dissolve_timeout_us = config.udp_idle_timeout(); break; case L3_protocol::ICMP: dissolve_timeout_us = config.icmp_idle_timeout(); break; - default: throw Interface::Bad_transport_protocol(); + default: ASSERT_NEVER_REACHED; } _dissolve_timeout_us = dissolve_timeout_us; _dissolve_timeout.schedule(_dissolve_timeout_us); @@ -177,10 +177,10 @@ void Link::handle_config(Domain &cln_domain, _client.domain().links(_protocol).remove(&_client); _server.domain().links(_protocol).remove(&_server); - _config = config; - _client._domain = cln_domain; - _server._domain = srv_domain; - _server_port_alloc = srv_port_alloc; + _config = config; + _client._domain = cln_domain; + _server._domain = srv_domain; + _server_port_alloc_ptr = srv_port_alloc_ptr; cln_domain.links(_protocol).insert(&_client); srv_domain.links(_protocol).insert(&_server); @@ -196,17 +196,18 @@ void Link::handle_config(Domain &cln_domain, ** Tcp_link ** **************/ -Tcp_link::Tcp_link(Interface &cln_interface, - Link_side_id const &cln_id, - Pointer srv_port_alloc, - Domain &srv_domain, - Link_side_id const &srv_id, - Cached_timer &timer, - Configuration &config, - L3_protocol const protocol, - Interface_link_stats &stats) +Tcp_link::Tcp_link(Interface &cln_interface, + Domain &cln_domain, + Link_side_id const &cln_id, + Port_allocator_guard *srv_port_alloc_ptr, + Domain &srv_domain, + Link_side_id const &srv_id, + Cached_timer &timer, + Configuration &config, + L3_protocol const protocol, + Interface_link_stats &stats) : - Link(cln_interface, cln_id, srv_port_alloc, srv_domain, srv_id, timer, + Link(cln_interface, cln_domain, cln_id, srv_port_alloc_ptr, srv_domain, srv_id, timer, config, protocol, config.tcp_idle_timeout(), stats) { } @@ -277,17 +278,18 @@ void Tcp_link::server_packet(Tcp_packet &tcp) ** Udp_link ** **************/ -Udp_link::Udp_link(Interface &cln_interface, - Link_side_id const &cln_id, - Pointer srv_port_alloc, - Domain &srv_domain, - Link_side_id const &srv_id, - Cached_timer &timer, - Configuration &config, - L3_protocol const protocol, - Interface_link_stats &stats) +Udp_link::Udp_link(Interface &cln_interface, + Domain &cln_domain, + Link_side_id const &cln_id, + Port_allocator_guard *srv_port_alloc_ptr, + Domain &srv_domain, + Link_side_id const &srv_id, + Cached_timer &timer, + Configuration &config, + L3_protocol const protocol, + Interface_link_stats &stats) : - Link(cln_interface, cln_id, srv_port_alloc, srv_domain, srv_id, timer, + Link(cln_interface, cln_domain, cln_id, srv_port_alloc_ptr, srv_domain, srv_id, timer, config, protocol, config.udp_idle_timeout(), stats) { } @@ -308,17 +310,18 @@ void Udp_link::server_packet() ** Icmp_link ** ***************/ -Icmp_link::Icmp_link(Interface &cln_interface, - Link_side_id const &cln_id, - Pointer srv_port_alloc, - Domain &srv_domain, - Link_side_id const &srv_id, - Cached_timer &timer, - Configuration &config, - L3_protocol const protocol, - Interface_link_stats &stats) +Icmp_link::Icmp_link(Interface &cln_interface, + Domain &cln_domain, + Link_side_id const &cln_id, + Port_allocator_guard *srv_port_alloc_ptr, + Domain &srv_domain, + Link_side_id const &srv_id, + Cached_timer &timer, + Configuration &config, + L3_protocol const protocol, + Interface_link_stats &stats) : - Link(cln_interface, cln_id, srv_port_alloc, srv_domain, srv_id, timer, + Link(cln_interface, cln_domain, cln_id, srv_port_alloc_ptr, srv_domain, srv_id, timer, config, protocol, config.icmp_idle_timeout(), stats) { } diff --git a/repos/os/src/server/nic_router/link.h b/repos/os/src/server/nic_router/link.h index 1a999165f0..45c8681d06 100644 --- a/repos/os/src/server/nic_router/link.h +++ b/repos/os/src/server/nic_router/link.h @@ -40,7 +40,6 @@ /* local includes */ #include #include -#include #include #include @@ -187,7 +186,7 @@ class Net::Link : public Link_list::Element Reference _config; Interface &_client_interface; - Pointer _server_port_alloc; + Port_allocator_guard *_server_port_alloc_ptr; Lazy_one_shot_timeout _dissolve_timeout; Genode::Microseconds _dissolve_timeout_us; L3_protocol const _protocol; @@ -201,29 +200,36 @@ class Net::Link : public Link_list::Element void _packet() { _dissolve_timeout.schedule(_dissolve_timeout_us); } + /* + * Noncopyable + */ + Link(Link const &); + Link &operator = (Link const &); + public: struct No_port_allocator : Genode::Exception { }; - Link(Interface &cln_interface, - Link_side_id const &cln_id, - Pointer srv_port_alloc, - Domain &srv_domain, - Link_side_id const &srv_id, - Cached_timer &timer, - Configuration &config, - L3_protocol const protocol, - Genode::Microseconds const dissolve_timeout, - Interface_link_stats &stats); + Link(Interface &cln_interface, + Domain &cln_domain, + Link_side_id const &cln_id, + Port_allocator_guard *srv_port_alloc_ptr, + Domain &srv_domain, + Link_side_id const &srv_id, + Cached_timer &timer, + Configuration &config, + L3_protocol const protocol, + Genode::Microseconds const dissolve_timeout, + Interface_link_stats &stats); ~Link(); void dissolve(bool timeout); - void handle_config(Domain &cln_domain, - Domain &srv_domain, - Pointer srv_port_alloc, - Configuration &config); + void handle_config(Domain &cln_domain, + Domain &srv_domain, + Port_allocator_guard *srv_port_alloc_ptr, + Configuration &config); /********* ** Log ** @@ -273,8 +279,9 @@ class Net::Tcp_link : public Link public: Tcp_link(Interface &cln_interface, + Domain &cln_domain, Link_side_id const &cln_id, - Pointer srv_port_alloc, + Port_allocator_guard *srv_port_alloc_ptr, Domain &srv_domain, Link_side_id const &srv_id, Cached_timer &timer, @@ -291,8 +298,9 @@ class Net::Tcp_link : public Link struct Net::Udp_link : Link { Udp_link(Interface &cln_interface, + Domain &cln_domain, Link_side_id const &cln_id, - Pointer srv_port_alloc, + Port_allocator_guard *srv_port_alloc_ptr, Domain &srv_domain, Link_side_id const &srv_id, Cached_timer &timer, @@ -308,15 +316,16 @@ struct Net::Udp_link : Link struct Net::Icmp_link : Link { - Icmp_link(Interface &cln_interface, - Link_side_id const &cln_id, - Pointer srv_port_alloc, - Domain &srv_domain, - Link_side_id const &srv_id, - Cached_timer &timer, - Configuration &config, - L3_protocol const protocol, - Interface_link_stats &stats); + Icmp_link(Interface &cln_interface, + Domain &cln_domain, + Link_side_id const &cln_id, + Port_allocator_guard *srv_port_alloc_ptr, + Domain &srv_domain, + Link_side_id const &srv_id, + Cached_timer &timer, + Configuration &config, + L3_protocol const protocol, + Interface_link_stats &stats); void client_packet() { _packet(); } diff --git a/repos/os/src/server/nic_router/mac_allocator.h b/repos/os/src/server/nic_router/mac_allocator.h index 69892b399c..10d26e09e4 100644 --- a/repos/os/src/server/nic_router/mac_allocator.h +++ b/repos/os/src/server/nic_router/mac_allocator.h @@ -17,6 +17,7 @@ /* Genode includes */ #include #include +#include namespace Net { class Mac_allocator; } @@ -30,14 +31,15 @@ class Net::Mac_allocator public: - struct Alloc_failed : Genode::Exception {}; - Mac_allocator(Mac_address base) : _base(base) { Genode::memset(&_free, true, sizeof(_free)); } - Mac_address alloc() + struct Alloc_error { }; + using Alloc_result = Genode::Attempt; + + Alloc_result alloc() { for (unsigned id = 0; id < sizeof(_free) / sizeof(_free[0]); id++) { if (!_free[id]) { @@ -48,7 +50,7 @@ class Net::Mac_allocator mac.addr[5] = id; return mac; } - throw Alloc_failed(); + return Alloc_error(); } void free(Mac_address mac) { _free[mac.addr[5]] = true; } diff --git a/repos/os/src/server/nic_router/main.cc b/repos/os/src/server/nic_router/main.cc index 179fd75567..0d64a9d14e 100644 --- a/repos/os/src/server/nic_router/main.cc +++ b/repos/os/src/server/nic_router/main.cc @@ -70,9 +70,7 @@ class Net::Main void Main::_handle_report() { - try { _config().report().generate(); } - catch (Pointer::Invalid) { } - + _config().with_report([&] (Report &r) { r.generate(); }); } diff --git a/repos/os/src/server/nic_router/nat_rule.cc b/repos/os/src/server/nic_router/nat_rule.cc index b7a3ff445b..e4f791e087 100644 --- a/repos/os/src/server/nic_router/nat_rule.cc +++ b/repos/os/src/server/nic_router/nat_rule.cc @@ -32,14 +32,14 @@ bool Nat_rule::higher(Nat_rule *rule) } -Nat_rule::Nat_rule(Domain_dict &domains, +Nat_rule::Nat_rule(Domain &domain, Port_allocator &tcp_port_alloc, Port_allocator &udp_port_alloc, Port_allocator &icmp_port_alloc, Xml_node const node, bool const verbose) : - _domain { domains.deprecated_find_by_domain_attr(node) }, + _domain { domain }, _tcp_port_alloc { tcp_port_alloc, node.attribute_value("tcp-ports", 0U), verbose }, _udp_port_alloc { udp_port_alloc, node.attribute_value("udp-ports", 0U), verbose }, _icmp_port_alloc { icmp_port_alloc, node.attribute_value("icmp-ids", 0U), verbose } @@ -61,5 +61,5 @@ Port_allocator_guard &Nat_rule::port_alloc(L3_protocol const prot) case L3_protocol::TCP: return _tcp_port_alloc; case L3_protocol::UDP: return _udp_port_alloc; case L3_protocol::ICMP: return _icmp_port_alloc; - default: throw Interface::Bad_transport_protocol(); } + default: ASSERT_NEVER_REACHED; } } diff --git a/repos/os/src/server/nic_router/nat_rule.h b/repos/os/src/server/nic_router/nat_rule.h index 4df5e5d79e..a87069db9c 100644 --- a/repos/os/src/server/nic_router/nat_rule.h +++ b/repos/os/src/server/nic_router/nat_rule.h @@ -44,7 +44,7 @@ class Net::Nat_rule : public Genode::Avl_node struct Invalid : Genode::Exception { }; - Nat_rule(Domain_dict &domains, + Nat_rule(Domain &domain, Port_allocator &tcp_port_alloc, Port_allocator &udp_port_alloc, Port_allocator &icmp_port_alloc, diff --git a/repos/os/src/server/nic_router/nic_client.cc b/repos/os/src/server/nic_router/nic_client.cc index e289318cc1..ba15391fda 100644 --- a/repos/os/src/server/nic_router/nic_client.cc +++ b/repos/os/src/server/nic_router/nic_client.cc @@ -26,72 +26,68 @@ using namespace Genode; ** Nic_client ** ****************/ -void Nic_client::_invalid(char const *reason) const -{ - if (_config.verbose()) { - log("[", domain(), "] invalid NIC client: ", label(), - " (", reason, ")"); - } - throw Invalid(); -} - - Net::Nic_client::Nic_client(Session_label const &label_arg, Domain_name const &domain_arg, Allocator &alloc, - Nic_client_dict &old_nic_clients, Nic_client_dict &new_nic_clients, - Env &env, - Cached_timer &timer, - Interface_list &interfaces, Configuration &config) : Nic_client_dict::Element { new_nic_clients, label_arg }, _alloc { alloc }, _config { config }, _domain { domain_arg } +{ } + + +bool Nic_client::finish_construction(Env &env, Cached_timer &timer, Interface_list &interfaces, + Nic_client_dict &old_nic_clients) { + char const *error = ""; old_nic_clients.with_element( label(), [&] /* handle_match */ (Nic_client &old_nic_client) { /* reuse existing interface */ - Nic_client_interface &interface = old_nic_client._interface(); - old_nic_client._interface = Pointer(); + Nic_client_interface &interface = *old_nic_client._crit->interface_ptr; + old_nic_client._crit->interface_ptr = nullptr; interface.domain_name(domain()); - _interface = interface; + _crit.construct(&interface); }, [&] /* handle_no_match */ () { /* create a new interface */ - if (config.verbose()) { + if (_config.verbose()) { log("[", domain(), "] create NIC client: ", label()); } try { - _interface = *new (_alloc) - Nic_client_interface { - env, timer, alloc, interfaces, config, domain(), - label() }; + _crit.construct(new (_alloc) + Nic_client_interface(env, timer, _alloc, interfaces, _config, domain(), label())); } - catch (Insufficient_ram_quota) { _invalid("NIC session RAM quota"); } - catch (Insufficient_cap_quota) { _invalid("NIC session CAP quota"); } - catch (Service_denied) { _invalid("NIC session denied"); } + catch (Insufficient_ram_quota) { error = "NIC session RAM quota"; } + catch (Insufficient_cap_quota) { error = "NIC session CAP quota"; } + catch (Service_denied) { error = "NIC session denied"; } } ); + if (_crit.constructed()) + return true; + + if (_config.verbose()) + log("[", domain(), "] invalid NIC client: ", label(), " (", error, ")"); + return false; } Net::Nic_client::~Nic_client() { + if (!_crit.constructed()) + return; + /* if the interface was yet not reused by another NIC client, destroy it */ - try { - Nic_client_interface &interface = _interface(); + if (_crit->interface_ptr) { if (_config.verbose()) { log("[", domain(), "] destroy NIC client: ", label()); } - - destroy(_alloc, &interface); + destroy(_alloc, _crit->interface_ptr); } - catch (Pointer::Invalid) { } } diff --git a/repos/os/src/server/nic_router/nic_client.h b/repos/os/src/server/nic_router/nic_client.h index 6e7b650315..78b4879834 100644 --- a/repos/os/src/server/nic_router/nic_client.h +++ b/repos/os/src/server/nic_router/nic_client.h @@ -41,29 +41,31 @@ class Net::Nic_client : private Nic_client_dict::Element private: - Genode::Allocator &_alloc; - Configuration const &_config; - Domain_name const _domain; - Pointer _interface { }; + struct Critical { Nic_client_interface *interface_ptr; }; - void _invalid(char const *reason) const; + Genode::Allocator &_alloc; + Configuration &_config; + Domain_name const _domain; + Genode::Constructible _crit { }; + + /* + * Noncopyable + */ + Nic_client(Nic_client const &); + Nic_client &operator = (Nic_client const &); public: - struct Invalid : Genode::Exception { }; - Nic_client(Genode::Session_label const &label_arg, Domain_name const &domain_arg, Genode::Allocator &alloc, - Nic_client_dict &old_nic_clients, Nic_client_dict &new_nic_clients, - Genode::Env &env, - Cached_timer &timer, - Interface_list &interfaces, Configuration &config); ~Nic_client(); + [[nodiscard]] bool finish_construction(Genode::Env &, Cached_timer &, Interface_list &, Nic_client_dict &); + /************** ** Acessors ** @@ -93,6 +95,8 @@ class Net::Nic_client_interface_base : public Interface_policy Genode::Session_label const &label() const override { return _label; } void handle_domain_ready_state(bool state) override; bool interface_link_state() const override; + bool report_empty() const override { return true; }; + void report(Genode::Xml_generator &) const override { }; public: diff --git a/repos/os/src/server/nic_router/nic_session_root.cc b/repos/os/src/server/nic_router/nic_session_root.cc index e6dfbfca6d..8d0c8a49dd 100644 --- a/repos/os/src/server/nic_router/nic_session_root.cc +++ b/repos/os/src/server/nic_router/nic_session_root.cc @@ -60,21 +60,17 @@ Interface_policy::Interface_policy(Genode::Session_label const &label, Domain_name Net::Nic_session_component::Interface_policy::determine_domain_name() const { - Domain_name domain_name; + Domain_name domain_name { }; try { Session_policy policy(_label, _config().node()); domain_name = policy.attribute_value("domain", Domain_name()); + if (domain_name == Domain_name() && _config().verbose()) + log("[?] no domain attribute in policy for downlink label \"", _label, "\""); } catch (Session_policy::No_policy_defined) { if (_config().verbose()) { log("[?] no policy for downlink label \"", _label, "\""); } } - catch (Xml_node::Nonexistent_attribute) { - if (_config().verbose()) { - log("[?] no domain attribute in policy for downlink label \"", - _label, "\""); - } - } return domain_name; } @@ -169,8 +165,7 @@ Net::Nic_session_component::Interface_policy::interface_link_state() const case UP_DOWN: return false; case UP_DOWN_UP: return true; } - class Never_reached : Exception { }; - throw Never_reached { }; + ASSERT_NEVER_REACHED; } @@ -216,8 +211,7 @@ Net::Nic_session_component::Interface_policy::read_and_ack_session_link_state() _session_link_state_transition(DOWN_UP); return true; } - class Never_reached { }; - throw Never_reached { }; + ASSERT_NEVER_REACHED; } @@ -296,11 +290,14 @@ Net::Nic_session_root::Nic_session_root(Env &env, _env { env }, _timer { timer }, _mac_alloc { MAC_ALLOC_BASE }, - _router_mac { _mac_alloc.alloc() }, _config { config }, _shared_quota { shared_quota }, _interfaces { interfaces } -{ } +{ + _mac_alloc.alloc().with_result( + [&] (Mac_address const &mac){ _router_mac.construct(mac); }, + [] (auto) { ASSERT_NEVER_REACHED; }); +} Nic_session_component *Net::Nic_session_root::_create_session(char const *args) @@ -311,26 +308,30 @@ Nic_session_component *Net::Nic_session_root::_create_session(char const *args) _env, _shared_quota, args, [&] (Session_env &session_env, void *session_at, Ram_dataspace_capability ram_ds) { + Nic_session_component *result { }; Session_label const label { label_from_args(args) }; - Mac_address const mac { _mac_alloc.alloc() }; - try { - return construct_at( - session_at, session_env, - Arg_string::find_arg(args, "tx_buf_size").ulong_value(0), - Arg_string::find_arg(args, "rx_buf_size").ulong_value(0), - _timer, mac, _router_mac, label, _interfaces, - _config(), ram_ds); - } - catch (...) { - _mac_alloc.free(mac); - throw; - } + _mac_alloc.alloc().with_result( + [&] (auto mac) { + try { + result = construct_at( + session_at, session_env, + Arg_string::find_arg(args, "tx_buf_size").ulong_value(0), + Arg_string::find_arg(args, "rx_buf_size").ulong_value(0), + _timer, mac, *_router_mac, label, _interfaces, + _config(), ram_ds); + } + catch (...) { + _mac_alloc.free(mac); + throw; + } + }, + [&] (auto) { + _invalid_downlink("failed to allocate MAC address"); + throw Service_denied(); + }); + return result; }); } - catch (Mac_allocator::Alloc_failed) { - _invalid_downlink("failed to allocate MAC address"); - throw Service_denied(); - } catch (Region_map::Invalid_dataspace) { _invalid_downlink("Failed to attach RAM"); throw Service_denied(); diff --git a/repos/os/src/server/nic_router/nic_session_root.h b/repos/os/src/server/nic_router/nic_session_root.h index 81d45c5b90..de651e20d0 100644 --- a/repos/os/src/server/nic_router/nic_session_root.h +++ b/repos/os/src/server/nic_router/nic_session_root.h @@ -117,6 +117,7 @@ class Net::Nic_session_component : private Nic_session_component_base, Domain_name determine_domain_name() const override; void handle_config(Configuration const &config) override { _config = config; } Genode::Session_label const &label() const override { return _label; } + bool report_empty() const override { return _session_env.report_empty(); }; void report(Genode::Xml_generator &xml) const override { _session_env.report(xml); }; void handle_domain_ready_state(bool state) override; bool interface_link_state() const override; @@ -167,13 +168,13 @@ class Net::Nic_session_root enum { MAC_ALLOC_BASE = 0x02 }; - Genode::Env &_env; - Cached_timer &_timer; - Mac_allocator _mac_alloc; - Mac_address const _router_mac; - Reference _config; - Quota &_shared_quota; - Interface_list &_interfaces; + Genode::Env &_env; + Cached_timer &_timer; + Mac_allocator _mac_alloc; + Genode::Constructible _router_mac { }; + Reference _config; + Quota &_shared_quota; + Interface_list &_interfaces; void _invalid_downlink(char const *reason); diff --git a/repos/os/src/server/nic_router/packet_result.h b/repos/os/src/server/nic_router/packet_result.h new file mode 100644 index 0000000000..e98e2f58c7 --- /dev/null +++ b/repos/os/src/server/nic_router/packet_result.h @@ -0,0 +1,34 @@ +/* + * \brief Result of handling a packet + * \author Martin Stein + * \date 2024-05-23 + */ + +/* + * Copyright (C) 2024 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. + */ + +#ifndef _PACKET_RESULT_H_ +#define _PACKET_RESULT_H_ + +namespace Net { + + struct Packet_result + { + enum Type { INVALID, DROP, POSTPONED, HANDLED } type { INVALID }; + char const *drop_reason { "" }; + + bool valid() const { return type != INVALID; } + }; + + inline Packet_result packet_drop(char const *reason) { return { Packet_result::DROP, reason }; } + + inline Packet_result packet_postponed() { return { Packet_result::POSTPONED, "" }; } + + inline Packet_result packet_handled() { return { Packet_result::HANDLED, "" }; } +} + +#endif /* _PACKET_RESULT_H_ */ diff --git a/repos/os/src/server/nic_router/permit_rule.cc b/repos/os/src/server/nic_router/permit_rule.cc index fe5a73b830..d71ef096a0 100644 --- a/repos/os/src/server/nic_router/permit_rule.cc +++ b/repos/os/src/server/nic_router/permit_rule.cc @@ -32,10 +32,7 @@ void Permit_any_rule::print(Output &output) const } -Permit_any_rule::Permit_any_rule(Domain_dict &domains, Xml_node const node) -: - Permit_rule { domains.deprecated_find_by_domain_attr(node) } -{ } +Permit_any_rule::Permit_any_rule(Domain &domain) : Permit_rule { domain } { } /************************ @@ -55,12 +52,8 @@ void Permit_single_rule::print(Output &output) const } -Permit_single_rule::Permit_single_rule(Domain_dict &domains, - Xml_node const node) +Permit_single_rule::Permit_single_rule(Port port, Domain &domain) : - Permit_rule { domains.deprecated_find_by_domain_attr(node) }, - _port { node.attribute_value("port", Port(0)) } -{ - if (_port == Port(0) || dynamic_port(_port)) { - throw Invalid(); } -} + Permit_rule { domain }, + _port { port } +{ } diff --git a/repos/os/src/server/nic_router/permit_rule.h b/repos/os/src/server/nic_router/permit_rule.h index db2cbb49a0..7eddde7766 100644 --- a/repos/os/src/server/nic_router/permit_rule.h +++ b/repos/os/src/server/nic_router/permit_rule.h @@ -16,10 +16,10 @@ /* local includes */ #include +#include /* Genode includes */ #include -#include namespace Genode { @@ -72,9 +72,7 @@ struct Net::Permit_any_rule : Permit_rule { public: - struct Invalid : Genode::Exception { }; - - Permit_any_rule(Domain_dict &domains, Genode::Xml_node const node); + Permit_any_rule(Domain &domain); /********* @@ -99,10 +97,7 @@ class Net::Permit_single_rule : public Permit_rule, public: - struct Invalid : Genode::Exception { }; - - Permit_single_rule(Domain_dict &domains, - Genode::Xml_node const node); + Permit_single_rule(Port port, Domain &domain); template diff --git a/repos/os/src/server/nic_router/pointer.h b/repos/os/src/server/nic_router/pointer.h deleted file mode 100644 index abfd744760..0000000000 --- a/repos/os/src/server/nic_router/pointer.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * \brief Pointer that can be dereferenced only when valid - * \author Martin Stein - * \date 2016-08-24 - */ - -/* - * Copyright (C) 2016-2017 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. - */ - -#ifndef _POINTER_H_ -#define _POINTER_H_ - -/* Genode includes */ -#include - -namespace Net { - - template class Pointer; - template class Const_pointer; -} - - -template -class Net::Pointer -{ - private: - - T *_obj; - - public: - - struct Invalid : Genode::Exception { }; - - Pointer() : _obj(nullptr) { } - - Pointer(T &obj) : _obj(&obj) { } - - T &operator () () const - { - if (_obj == nullptr) - throw Invalid(); - - return *_obj; - } - - bool valid() const { return _obj != nullptr; } -}; - - -template -class Net::Const_pointer -{ - private: - - T const *_obj; - - public: - - struct Invalid : Genode::Exception { }; - - Const_pointer() : _obj(nullptr) { } - - Const_pointer(T const &obj) : _obj(&obj) { } - - T const &operator () () const - { - if (_obj == nullptr) - throw Invalid(); - - return *_obj; - } - - bool valid() const { return _obj != nullptr; } -}; - -#endif /* _POINTER_H_ */ diff --git a/repos/os/src/server/nic_router/port_allocator.cc b/repos/os/src/server/nic_router/port_allocator.cc index d43b18216f..cc8e70af90 100644 --- a/repos/os/src/server/nic_router/port_allocator.cc +++ b/repos/os/src/server/nic_router/port_allocator.cc @@ -31,7 +31,7 @@ bool Net::dynamic_port(Port const port) ** Port_allocator ** ********************/ -Port Net::Port_allocator::alloc() +Net::Port_allocator::Alloc_result Net::Port_allocator::alloc() { for (unsigned nr_of_trials { 0 }; nr_of_trials < NR_OF_PORTS; @@ -45,19 +45,18 @@ Port Net::Port_allocator::alloc() } catch (Bit_allocator::Range_conflict) { } } - throw Out_of_indices(); + return Alloc_error(); } -void Net::Port_allocator::alloc(Port const port) +bool Net::Port_allocator::alloc(Port const port) { try { _bit_allocator.alloc_addr(port.value - FIRST_PORT); + return true; } - catch (Bit_allocator::Range_conflict) { - - throw Allocation_conflict(); - } + catch (Bit_allocator::Range_conflict) { } + return false; } @@ -71,29 +70,30 @@ void Port_allocator::free(Port const port) ** Port_allocator_guard ** **************************/ -Port Port_allocator_guard::alloc() +Port_allocator_guard::Alloc_result Port_allocator_guard::alloc() { if (_used_nr_of_ports == _max_nr_of_ports) { - throw Out_of_indices(); - } - try { - Port const port = _port_alloc.alloc(); - _used_nr_of_ports++; - return port; - } - catch (Port_allocator::Out_of_indices) { - throw Out_of_indices(); + return Alloc_error(); } + Alloc_result const result = _port_alloc.alloc(); + if (result.failed()) + return result; + + _used_nr_of_ports++; + return result; } -void Port_allocator_guard::alloc(Port const port) +bool Port_allocator_guard::alloc(Port const port) { - if (_used_nr_of_ports == _max_nr_of_ports) { - throw Out_of_indices(); - } - _port_alloc.alloc(port); + if (_used_nr_of_ports == _max_nr_of_ports) + return false; + + if (!_port_alloc.alloc(port)) + return false; + _used_nr_of_ports++; + return true; } diff --git a/repos/os/src/server/nic_router/port_allocator.h b/repos/os/src/server/nic_router/port_allocator.h index a2b7b65cd0..b85f783cef 100644 --- a/repos/os/src/server/nic_router/port_allocator.h +++ b/repos/os/src/server/nic_router/port_allocator.h @@ -17,6 +17,7 @@ /* Genode includes */ #include +#include /* local includes */ #include @@ -43,12 +44,12 @@ class Net::Port_allocator public: - struct Allocation_conflict : Genode::Exception { }; - struct Out_of_indices : Genode::Exception { }; + struct Alloc_error { }; + using Alloc_result = Genode::Attempt; - Port alloc(); + [[nodiscard]] Alloc_result alloc(); - void alloc(Port const port); + [[nodiscard]] bool alloc(Port const port); void free(Port const port); }; @@ -64,11 +65,12 @@ class Net::Port_allocator_guard public: - class Out_of_indices : Genode::Exception {}; + using Alloc_error = Port_allocator::Alloc_error; + using Alloc_result = Port_allocator::Alloc_result; - Port alloc(); + [[nodiscard]] Alloc_result alloc(); - void alloc(Port const port); + [[nodiscard]] bool alloc(Port const port); void free(Port const port); diff --git a/repos/os/src/server/nic_router/report.cc b/repos/os/src/server/nic_router/report.cc index e5d93a8835..31073811f3 100644 --- a/repos/os/src/server/nic_router/report.cc +++ b/repos/os/src/server/nic_router/report.cc @@ -50,26 +50,25 @@ Net::Report::Report(bool const &verbose, } -void Net::Report::generate() +void Net::Report::generate() const { try { - Reporter::Xml_generator xml(_reporter, [&] () { + Reporter::Xml_generator xml(_reporter, [&] { if (_quota) { - xml.node("ram", [&] () { + xml.node("ram", [&] { xml.attribute("quota", _pd.ram_quota().value); xml.attribute("used", _pd.used_ram().value); xml.attribute("shared", _shared_quota.ram); }); - xml.node("cap", [&] () { + xml.node("cap", [&] { xml.attribute("quota", _pd.cap_quota().value); xml.attribute("used", _pd.used_caps().value); xml.attribute("shared", _shared_quota.cap); }); } - _domains.for_each([&] (Domain &domain) { - try { domain.report(xml); } - catch (Empty) { } - }); + _domains.for_each([&] (Domain const &domain) { + if (!domain.report_empty(*this)) + xml.node("domain", [&] { domain.report(xml, *this); }); }); }); } catch (Xml_generator::Buffer_exceeded) { if (_verbose) { diff --git a/repos/os/src/server/nic_router/report.h b/repos/os/src/server/nic_router/report.h index 407f511356..8981c4bcb3 100644 --- a/repos/os/src/server/nic_router/report.h +++ b/repos/os/src/server/nic_router/report.h @@ -65,8 +65,6 @@ class Net::Report public: - struct Empty : Genode::Exception { }; - Report(bool const &verbose, Genode::Xml_node const node, Cached_timer &timer, @@ -80,7 +78,7 @@ class Net::Report void handle_interface_link_state(); - void generate(); + void generate() const; /*************** diff --git a/repos/os/src/server/nic_router/session_env.h b/repos/os/src/server/nic_router/session_env.h index 8b5fa4061b..6a7d853dac 100644 --- a/repos/os/src/server/nic_router/session_env.h +++ b/repos/os/src/server/nic_router/session_env.h @@ -169,6 +169,8 @@ class Genode::Session_env : public Ram_allocator, return ptr; }; + bool report_empty() const { return false; } + void report(Genode::Xml_generator &xml) const { xml.node("ram-quota", [&] () { diff --git a/repos/os/src/server/nic_router/target.mk b/repos/os/src/server/nic_router/target.mk index 2267411d94..3c41f52089 100644 --- a/repos/os/src/server/nic_router/target.mk +++ b/repos/os/src/server/nic_router/target.mk @@ -4,7 +4,6 @@ LIBS += base net SRC_CC += \ arp_waiter.cc \ - ip_rule.cc \ ipv4_address_prefix.cc \ nic_session_root.cc \ port_allocator.cc \ @@ -18,7 +17,6 @@ SRC_CC += \ configuration.cc \ domain.cc \ l3_protocol.cc \ - direct_rule.cc \ link.cc \ transport_rule.cc \ permit_rule.cc \ diff --git a/repos/os/src/server/nic_router/transport_rule.cc b/repos/os/src/server/nic_router/transport_rule.cc index 70721cf01a..2992a4e8a8 100644 --- a/repos/os/src/server/nic_router/transport_rule.cc +++ b/repos/os/src/server/nic_router/transport_rule.cc @@ -24,63 +24,63 @@ using namespace Net; using namespace Genode; -Pointer -Transport_rule::_read_permit_any_rule(Domain_dict &domains, - Xml_node const node, - Allocator &alloc) -{ - try { - Xml_node sub_node = node.sub_node("permit-any"); - return Pointer(*new (alloc) - Permit_any_rule(domains, sub_node)); - } - catch (Xml_node::Nonexistent_sub_node) { } - return Pointer(); -} - - -Transport_rule::Transport_rule(Domain_dict &domains, - Xml_node const node, - Allocator &alloc, - Cstring const &protocol, - Configuration &config, - Domain const &domain) +Transport_rule::Transport_rule(Ipv4_address_prefix const &dst, + Allocator &alloc) : - Direct_rule(node), - _alloc(alloc), - _permit_any_rule(_read_permit_any_rule(domains, node, alloc)) + Direct_rule(dst), + _alloc(alloc) +{ } + + +bool Transport_rule::finish_construction(Domain_dict &domains, + Xml_node const node, + Cstring const &protocol, + Configuration &config, + Domain const &local_domain) { - /* skip specific permit rules if all ports are permitted anyway */ - try { - Permit_any_rule &permit_any_rule = _permit_any_rule(); - if (config.verbose()) { - log("[", domain, "] ", protocol, " permit-any rule: ", permit_any_rule); - log("[", domain, "] ", protocol, " rule: dst ", _dst); - } - return; - } catch (Pointer::Invalid) { } - - /* read specific permit rules */ - node.for_each_sub_node("permit", [&] (Xml_node const node) { - Permit_single_rule &rule = *new (alloc) - Permit_single_rule(domains, node); - - _permit_single_rules.insert(&rule); - if (config.verbose()) { - log("[", domain, "] ", protocol, " permit rule: ", rule); } + /* try to find a permit-any rule first */ + bool error = false; + node.with_optional_sub_node("permit-any", [&] (Xml_node const &permit_any_node) { + domains.find_by_domain_attr(permit_any_node, + [&] (Domain &remote_domain) { _permit_any_rule_ptr = new (_alloc) Permit_any_rule(remote_domain); }, + [&] { error = true; }); }); - /* drop the transport rule if it has no permitted ports */ - if (!_permit_single_rules.first()) { - throw Invalid(); } + if (error) + return false; - if (config.verbose()) { - log("[", domain, "] ", protocol, " rule: dst ", _dst); } + /* skip specific permit rules if all ports are permitted anyway */ + if (_permit_any_rule_ptr) { + if (config.verbose()) { + log("[", local_domain, "] ", protocol, " permit-any rule: ", *_permit_any_rule_ptr); + log("[", local_domain, "] ", protocol, " rule: dst ", _dst); + } + return true; + } + /* read specific permit rules */ + node.for_each_sub_node("permit", [&] (Xml_node const permit_node) { + if (error) + return; + + Port port = permit_node.attribute_value("port", Port(0)); + if (port == Port(0) || dynamic_port(port)) { + error = true; + return; + } + domains.find_by_domain_attr(permit_node, + [&] (Domain &remote_domain) { + Permit_single_rule &rule = *new (_alloc) Permit_single_rule(port, remote_domain); + _permit_single_rules.insert(&rule); + if (config.verbose()) + log("[", local_domain, "] ", protocol, " permit rule: ", rule); }, + [&] { error = true; }); + }); + return !error && (_permit_any_rule_ptr || _permit_single_rules.first()); } Transport_rule::~Transport_rule() { _permit_single_rules.destroy_each(_alloc); - try { destroy(_alloc, &_permit_any_rule()); } - catch (Pointer::Invalid) { } + if (_permit_any_rule_ptr) + destroy(_alloc, _permit_any_rule_ptr); } diff --git a/repos/os/src/server/nic_router/transport_rule.h b/repos/os/src/server/nic_router/transport_rule.h index abc34b8ac2..edae6eeb78 100644 --- a/repos/os/src/server/nic_router/transport_rule.h +++ b/repos/os/src/server/nic_router/transport_rule.h @@ -17,7 +17,6 @@ /* local includes */ #include #include -#include namespace Genode { class Allocator; } @@ -33,23 +32,25 @@ class Net::Transport_rule : public Direct_rule { private: - Genode::Allocator &_alloc; - Pointer const _permit_any_rule; - Permit_single_rule_tree _permit_single_rules { }; + Genode::Allocator &_alloc; + Permit_any_rule *_permit_any_rule_ptr { }; + Permit_single_rule_tree _permit_single_rules { }; - static Pointer + static Permit_any_rule * _read_permit_any_rule(Domain_dict &domains, Genode::Xml_node const node, Genode::Allocator &alloc); + /* + * Noncopyable + */ + Transport_rule(Transport_rule const &); + Transport_rule &operator = (Transport_rule const &); + public: - Transport_rule(Domain_dict &domains, - Genode::Xml_node const node, - Genode::Allocator &alloc, - Genode::Cstring const &protocol, - Configuration &config, - Domain const &domain); + Transport_rule(Ipv4_address_prefix const &dst, + Genode::Allocator &alloc); ~Transport_rule(); @@ -60,9 +61,9 @@ class Net::Transport_rule : public Direct_rule HANDLE_MATCH_FN && handle_match, HANDLE_NO_MATCH_FN && handle_no_match) const { - if (_permit_any_rule.valid()) { + if (_permit_any_rule_ptr) { - handle_match(_permit_any_rule()); + handle_match(*_permit_any_rule_ptr); } else { @@ -70,6 +71,12 @@ class Net::Transport_rule : public Direct_rule port, handle_match, handle_no_match); } } + + [[nodiscard]] bool finish_construction(Domain_dict &domains, + Genode::Xml_node const node, + Genode::Cstring const &protocol, + Configuration &config, + Domain const &domain); }; diff --git a/repos/os/src/server/nic_router/uplink_session_root.cc b/repos/os/src/server/nic_router/uplink_session_root.cc index fda142b129..f93edd071d 100644 --- a/repos/os/src/server/nic_router/uplink_session_root.cc +++ b/repos/os/src/server/nic_router/uplink_session_root.cc @@ -62,17 +62,13 @@ Net::Uplink_session_component::Interface_policy::determine_domain_name() const try { Session_policy policy(_label, _config().node()); domain_name = policy.attribute_value("domain", Domain_name()); + if (domain_name == Domain_name() && _config().verbose()) + log("[?] no domain attribute in policy for downlink label \"", _label, "\""); } catch (Session_policy::No_policy_defined) { if (_config().verbose()) { log("[?] no policy for downlink label \"", _label, "\""); } } - catch (Xml_node::Nonexistent_attribute) { - if (_config().verbose()) { - log("[?] no domain attribute in policy for downlink label \"", - _label, "\""); - } - } return domain_name; } diff --git a/repos/os/src/server/nic_router/uplink_session_root.h b/repos/os/src/server/nic_router/uplink_session_root.h index a43142496b..360872ebe9 100644 --- a/repos/os/src/server/nic_router/uplink_session_root.h +++ b/repos/os/src/server/nic_router/uplink_session_root.h @@ -81,6 +81,7 @@ class Net::Uplink_session_component : private Uplink_session_component_base, Domain_name determine_domain_name() const override; void handle_config(Configuration const &config) override { _config = config; } Genode::Session_label const &label() const override { return _label; } + bool report_empty() const override { return _session_env.report_empty(); }; void report(Genode::Xml_generator &xml) const override { _session_env.report(xml); }; void handle_domain_ready_state(bool /* state */) override { } bool interface_link_state() const override { return true; }