nic_router: remove use of exception handling

Remove the use of C++ exception as much as possible from the router as C++
exception handling can be resource intensive and can make code hard to
understand.

This also removes the garbage collection that the router used to do when a
session ran out of quota. This is motivated by the fact that the garbage
collection was rather simple and removed connection states regardless of their
current state, thereby causing broken connections. The change is part of this
commit as the approach to integrating garbage collection relied strongly on
exception handling.

The user story behind removing garbage collection: The router emergency-dropped
an established TCP connection (with NAPT) and on the next matching packet
re-created it with a different NAPT port, thereby breaking the connection. With
this commit, existing connections are prioritized over new ones during resource
exhaustion and the packets that attempt to create a new connection in such a
state are dropped with a warning in the log (verbose_packet_drop="yes").

Note that the state resolves itself with time as existing connections time out
or are closed by peers.

Ref #4729
This commit is contained in:
Martin Stein 2024-05-02 13:25:26 +02:00 committed by Norman Feske
parent 0faec6afaa
commit ac42ade48c
49 changed files with 1727 additions and 1913 deletions

View File

@ -205,26 +205,19 @@ class Net::Dhcp_packet
/** /**
* Domain name server option * 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 <typename T>
void with_option(auto const &found_fn, auto const &not_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 <typename T>
void with_option(auto const &fn) const { with_option<T>(fn, []{}); }
/*************** /***************
** Accessors ** ** Accessors **

View File

@ -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) void Arp_cache::destroy_entries_with_mac(Mac_address const &mac)
{ {
for (unsigned curr = 0; curr < NR_OF_ENTRIES; curr++) { for (unsigned curr = 0; curr < NR_OF_ENTRIES; curr++) {
try { if (_entries[curr].constructed()) {
Arp_cache_entry &entry = *_entries[curr]; Arp_cache_entry &entry = *_entries[curr];
if (entry.mac() != mac) { if (entry.mac() != mac) {
continue; continue;
@ -79,8 +79,7 @@ void Arp_cache::destroy_entries_with_mac(Mac_address const &mac)
} }
remove(&entry); remove(&entry);
_entries[curr].destruct(); _entries[curr].destruct();
}
} catch (Arp_cache_entry_slot::Deref_unconstructed_object) { }
} }
} }

View File

@ -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 <base/log.h>
#include <base/sleep.h>
#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_ */

View File

@ -17,6 +17,9 @@
/* Genode includes */ /* Genode includes */
#include <base/allocator.h> #include <base/allocator.h>
/* local includes */
#include <assertion.h>
namespace Genode { namespace Genode {
class Bit_array_dynamic; class Bit_array_dynamic;
@ -26,14 +29,6 @@ namespace Genode {
class Genode::Bit_array_dynamic 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: protected:
enum { enum {
@ -50,13 +45,14 @@ class Genode::Bit_array_dynamic
addr_t _word(addr_t index) const { addr_t _word(addr_t index) const {
return index / BITS_PER_WORD; } return index / BITS_PER_WORD; }
void _check_range(addr_t const index, [[nodiscard]] bool _check_range(addr_t const index,
addr_t const width) const addr_t const width) const
{ {
if ((index >= _word_cnt * BITS_PER_WORD) || if ((index >= _word_cnt * BITS_PER_WORD) ||
width > _word_cnt * BITS_PER_WORD || width > _word_cnt * BITS_PER_WORD ||
_word_cnt * BITS_PER_WORD - width < index) _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, addr_t _mask(addr_t const index, addr_t const width,
@ -71,9 +67,10 @@ class Genode::Bit_array_dynamic
: ((1UL << width) - 1) << shift; : ((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; addr_t rest, word, mask;
do { do {
@ -82,17 +79,18 @@ class Genode::Bit_array_dynamic
if (free) { if (free) {
if ((_words[word] & mask) != mask) if ((_words[word] & mask) != mask)
throw Invalid_clear(); return false;
_words[word] &= ~mask; _words[word] &= ~mask;
} else { } else {
if (_words[word] & mask) if (_words[word] & mask)
throw Invalid_set(); return false;
_words[word] |= mask; _words[word] |= mask;
} }
index = (_word(index) + 1) * BITS_PER_WORD; index = (_word(index) + 1) * BITS_PER_WORD;
width = rest; width = rest;
} while (rest); } while (rest);
return true;
} }
public: public:
@ -103,7 +101,8 @@ class Genode::Bit_array_dynamic
*/ */
bool get(addr_t index, addr_t width) const bool get(addr_t index, addr_t width) const
{ {
_check_range(index, width); if (!_check_range(index, width))
return false;
bool used = false; bool used = false;
addr_t rest, mask; addr_t rest, mask;
@ -117,23 +116,18 @@ class Genode::Bit_array_dynamic
return used; return used;
} }
void set(addr_t const index, addr_t const width) { [[nodiscard]] bool set(addr_t const index, addr_t const width) {
_set(index, width, false); } return _set(index, width, false); }
void clear(addr_t const index, addr_t const width) { [[nodiscard]] bool clear(addr_t const index, addr_t const width) {
_set(index, width, true); } return _set(index, width, true); }
Bit_array_dynamic(addr_t *addr, unsigned bits) Bit_array_dynamic(addr_t *addr, unsigned bits)
: _bit_cnt(bits), _word_cnt(_bit_cnt / BITS_PER_WORD), : _bit_cnt(bits), _word_cnt(_bit_cnt / BITS_PER_WORD),
_words(addr) _words(addr)
{ {
if (!bits || bits % BITS_PER_WORD) ASSERT(bits && bits % BITS_PER_WORD == 0);
throw Invalid_bit_count();
memset(_words, 0, sizeof(addr_t)*_word_cnt); 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 * \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 size_t _ram_size() const
@ -178,50 +172,53 @@ class Genode::Bit_allocator_dynamic
public: public:
struct Out_of_indices : Exception { }; struct Alloc_error { };
struct Range_conflict : Exception { }; using Alloc_result = Attempt<Genode::addr_t, Alloc_error>;
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; addr_t max = ~0UL;
do { do {
try { for (addr_t i = _next & ~(step - 1); i < max; i += step) {
/* throws exception if array is accessed outside bounds */ if (_array.get(i, step))
for (addr_t i = _next & ~(step - 1); i < max; i += step) { continue;
if (_array.get(i, step))
continue;
_array.set(i, step); if (!_array.set(i, step))
_next = i + step; break;
return i;
}
} catch (Bit_array_dynamic::Invalid_index_access) { }
_next = i + step;
return i;
}
max = _next; max = _next;
_next = 0; _next = 0;
} while (max != 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)) 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; _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; _next = bit_start;
return true;
} }
Bit_allocator_dynamic(Allocator &alloc, unsigned bits) Bit_allocator_dynamic(Allocator &alloc, unsigned bits)
@ -233,7 +230,7 @@ class Genode::Bit_allocator_dynamic
_ram((addr_t *)_alloc.alloc(_ram_size())), _ram((addr_t *)_alloc.alloc(_ram_size())),
_array(_ram, _bits_aligned) _array(_ram, _bits_aligned)
{ {
_reserve(bits, _bits_aligned - bits); ASSERT(_reserve(bits, _bits_aligned - bits));
} }
~Bit_allocator_dynamic() ~Bit_allocator_dynamic()

View File

@ -63,31 +63,20 @@ void Configuration::_invalid_domain(Domain &domain,
Icmp_packet::Code Icmp_packet::Code
Configuration::_init_icmp_type_3_code_on_fragm_ipv4(Xml_node const &node) const 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" }; using Attribute_string = String<16>;
try { Icmp_packet::Code result = Icmp_packet::Code::INVALID;
Xml_attribute const &attr { node.attribute(attr_name) }; Attribute_string attr_str = node.attribute_value("icmp_type_3_code_on_fragm_ipv4", Attribute_string());
if (attr.has_value("no")) { if (attr_str == "no" || attr_str == Attribute_string())
return Icmp_packet::Code::INVALID;
}
uint8_t attr_val { };
bool const attr_transl_succeeded { attr.value<uint8_t>(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;
}
return result; 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) { warning("attribute 'icmp_type_3_code_on_fragm_ipv4' has invalid value");
return Icmp_packet::Code::INVALID; return result;
}
} }
@ -120,119 +109,101 @@ Configuration::Configuration(Env &env,
{ {
/* do parts of domain initialization that do not lookup other domains */ /* do parts of domain initialization that do not lookup other domains */
node.for_each_sub_node("domain", [&] (Xml_node const node) { node.for_each_sub_node("domain", [&] (Xml_node const node) {
try { Domain_name const name {
Domain_name const name { node.attribute_value("name", Domain_name { }) };
node.attribute_value("name", Domain_name { }) };
_domains.with_element( _domains.with_element(
name, name,
[&] /* match_fn */ (Domain &other_domain) [&] /* match_fn */ (Domain &other_domain)
{ {
if (_verbose) { if (_verbose) {
log("[", name, log("[", name,
"] invalid domain (name not unique) "); "] invalid domain (name not unique) ");
log("[", other_domain, log("[", other_domain,
"] invalid domain (name not unique) "); "] invalid domain (name not unique) ");
}
destroy(_alloc, &other_domain);
},
[&] /* no_match_fn */ ()
{
new (_alloc) Domain {
*this, node, name, _alloc, _domains };
} }
); destroy(_alloc, &other_domain);
} },
catch (Domain::Invalid) { } [&] /* 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 */ /* do parts of domain initialization that may lookup other domains */
while (true) { while (true) {
Domain *invalid_domain_ptr { };
_domains.for_each([&] (Domain &domain) {
if (invalid_domain_ptr)
return;
struct Retry_without_domain : Genode::Exception if (!domain.init(_domains)) {
{ invalid_domain_ptr = &domain;
Domain &domain; return;
}
if (_verbose) {
log("[", domain, "] initiated domain"); }
});
if (!invalid_domain_ptr)
break;
Retry_without_domain(Domain &domain) : domain(domain) { } /* destroy domain that became invalid during initialization */
}; destroy(_alloc, invalid_domain_ptr);
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 */ /* deinitialize the remaining domains again */
destroy(_alloc, &exception.domain); _domains.for_each([&] (Domain &domain) {
domain.deinit();
/* deinitialize the remaining domains again */ if (_verbose) {
_domains.for_each([&] (Domain &domain) { log("[", domain, "] deinitiated domain"); }
domain.deinit(); });
if (_verbose) {
log("[", domain, "] deinitiated domain"); }
});
/* retry to initialize the remaining domains */
continue;
}
break;
} }
try { node.with_optional_sub_node("report", [&] (Xml_node const &report_node) {
/* check whether we shall create a report generator */ if (old_config._reporter_ptr) {
Xml_node const report_node = node.sub_node("report"); /* re-use existing reporter */
try { _reporter_ptr = old_config._reporter_ptr;
/* try to re-use existing reporter */ old_config._reporter_ptr = nullptr;
_reporter = old_config._reporter(); } else {
old_config._reporter = Pointer<Reporter>();
}
catch (Pointer<Reporter>::Invalid) {
/* there is no reporter by now, create a new one */ /* 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 */ /* create report generator */
_report = *new (_alloc) _report.construct(
Report { _verbose, report_node, timer, _domains, shared_quota, env.pd(),
_verbose, report_node, timer, _domains, shared_quota, env.pd(), *_reporter_ptr, report_signal_cap);
_reporter(), report_signal_cap }; });
}
catch (Genode::Xml_node::Nonexistent_sub_node) { }
/* initialize NIC clients */ /* initialize NIC clients */
_node.for_each_sub_node("nic-client", [&] (Xml_node const node) { _node.for_each_sub_node("nic-client", [&] (Xml_node const node) {
try { Session_label const label {
Session_label const label { node.attribute_value("label", Session_label::String { }) };
node.attribute_value("label", Session_label::String { }) };
Domain_name const domain { Domain_name const domain {
node.attribute_value("domain", Domain_name { }) }; node.attribute_value("domain", Domain_name { }) };
_nic_clients.with_element( _nic_clients.with_element(
label, label,
[&] /* match */ (Nic_client &nic_client) [&] /* match */ (Nic_client &nic_client)
{ {
if (_verbose) { if (_verbose) {
log("[", domain, "] invalid NIC client: ", log("[", domain, "] invalid NIC client: ",
label, " (label not unique)"); label, " (label not unique)");
log("[", nic_client.domain(), "] invalid NIC client: ", log("[", nic_client.domain(), "] invalid NIC client: ",
nic_client.label(), " (label not unique)"); 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 };
} }
); destroy(_alloc, &nic_client);
} },
catch (Nic_client::Invalid) { } [&] /* 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 * Destroy old NIC clients to ensure that NIC client interfaces that were
@ -248,12 +219,8 @@ Configuration::~Configuration()
_nic_clients.destroy_each(_alloc); _nic_clients.destroy_each(_alloc);
/* destroy reporter */ /* destroy reporter */
try { destroy(_alloc, &_reporter()); } if (_reporter_ptr)
catch (Pointer<Reporter>::Invalid) { } destroy(_alloc, _reporter_ptr);
/* destroy report generator */
try { destroy(_alloc, &_report()); }
catch (Pointer<Report>::Invalid) { }
/* destroy domains */ /* destroy domains */
_domains.destroy_each(_alloc); _domains.destroy_each(_alloc);

View File

@ -33,27 +33,33 @@ class Net::Configuration
using Mac_string = Genode::String<17>; using Mac_string = Genode::String<17>;
Genode::Allocator &_alloc; Genode::Allocator &_alloc;
unsigned long const _max_packets_per_signal; unsigned long const _max_packets_per_signal;
bool const _verbose; bool const _verbose;
bool const _verbose_packets; bool const _verbose_packets;
bool const _verbose_packet_drop; bool const _verbose_packet_drop;
bool const _verbose_domain_state; bool const _verbose_domain_state;
bool const _trace_packets; bool const _trace_packets;
bool const _icmp_echo_server; bool const _icmp_echo_server;
Icmp_packet::Code const _icmp_type_3_code_on_fragm_ipv4; Icmp_packet::Code const _icmp_type_3_code_on_fragm_ipv4;
Genode::Microseconds const _dhcp_discover_timeout; Genode::Microseconds const _dhcp_discover_timeout;
Genode::Microseconds const _dhcp_request_timeout; Genode::Microseconds const _dhcp_request_timeout;
Genode::Microseconds const _dhcp_offer_timeout; Genode::Microseconds const _dhcp_offer_timeout;
Genode::Microseconds const _icmp_idle_timeout; Genode::Microseconds const _icmp_idle_timeout;
Genode::Microseconds const _udp_idle_timeout; Genode::Microseconds const _udp_idle_timeout;
Genode::Microseconds const _tcp_idle_timeout; Genode::Microseconds const _tcp_idle_timeout;
Genode::Microseconds const _tcp_max_segm_lifetime; Genode::Microseconds const _tcp_max_segm_lifetime;
Pointer<Report> _report { }; Genode::Constructible<Report> _report { };
Pointer<Genode::Reporter> _reporter { }; Genode::Reporter *_reporter_ptr { };
Domain_dict _domains { }; Domain_dict _domains { };
Nic_client_dict _nic_clients { }; Nic_client_dict _nic_clients { };
Genode::Xml_node const _node; Genode::Xml_node const _node;
/*
* Noncopyable
*/
Configuration(Configuration const &);
Configuration &operator = (Configuration const &);
Icmp_packet::Code Icmp_packet::Code
_init_icmp_type_3_code_on_fragm_ipv4(Genode::Xml_node const &node) const; _init_icmp_type_3_code_on_fragm_ipv4(Genode::Xml_node const &node) const;
@ -77,6 +83,8 @@ class Net::Configuration
~Configuration(); ~Configuration();
void with_report(auto const &fn) { if (_report.constructed()) fn(*_report); }
/*************** /***************
** Accessors ** ** Accessors **
@ -98,7 +106,6 @@ class Net::Configuration
Genode::Microseconds tcp_idle_timeout() const { return _tcp_idle_timeout; } Genode::Microseconds tcp_idle_timeout() const { return _tcp_idle_timeout; }
Genode::Microseconds tcp_max_segm_lifetime() const { return _tcp_max_segm_lifetime; } Genode::Microseconds tcp_max_segm_lifetime() const { return _tcp_max_segm_lifetime; }
Domain_dict &domains() { return _domains; } Domain_dict &domains() { return _domains; }
Report &report() { return _report(); }
Genode::Xml_node node() const { return _node; } Genode::Xml_node node() const { return _node; }
}; };

View File

@ -22,8 +22,9 @@ namespace Net {
template <typename T> template <typename T>
static Ipv4_address dhcp_ipv4_option(Dhcp_packet &dhcp) static Ipv4_address dhcp_ipv4_option(Dhcp_packet &dhcp)
{ {
try { return dhcp.option<T>().value(); } Ipv4_address result = { };
catch (Dhcp_packet::Option_not_found) { return Ipv4_address { }; } dhcp.with_option<T>([&] (auto opt) { result = opt.value(); });
return result;
} }
} }

View File

@ -20,7 +20,6 @@
using namespace Genode; using namespace Genode;
using namespace Net; using namespace Net;
using Message_type = Dhcp_packet::Message_type; using Message_type = Dhcp_packet::Message_type;
using Drop_packet = Net::Interface::Drop_packet;
using Dhcp_options = Dhcp_packet::Options_aggregator<Size_guard>; using Dhcp_options = Dhcp_packet::Options_aggregator<Size_guard>;
@ -46,12 +45,6 @@ void append_param_req_list(Dhcp_options &dhcp_opts)
** Dhcp_client ** ** Dhcp_client **
*****************/ *****************/
Configuration &Dhcp_client::_config() { return _domain().config(); };
Domain &Dhcp_client::_domain() { return _interface.domain(); }
Dhcp_client::Dhcp_client(Cached_timer &timer, Dhcp_client::Dhcp_client(Cached_timer &timer,
Interface &interface) Interface &interface)
: :
@ -63,17 +56,17 @@ Dhcp_client::Dhcp_client(Cached_timer &timer,
void Dhcp_client::discover() void Dhcp_client::discover()
{ {
enum { DISCOVER_PKT_SIZE = 309 }; 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(), _send(Message_type::DISCOVER, Ipv4_address(), Ipv4_address(),
Ipv4_address(), DISCOVER_PKT_SIZE); 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 }; enum { REREQUEST_PKT_SIZE = 309 };
_set_state(next_state, _rerequest_timeout(2)); _set_state(next_state, _rerequest_timeout(2, domain));
Ipv4_address const client_ip = _domain().ip_config().interface().address; Ipv4_address client_ip = domain.ip_config().interface().address;
_send(Message_type::REQUEST, client_ip, Ipv4_address(), client_ip, _send(Message_type::REQUEST, client_ip, Ipv4_address(), client_ip,
REREQUEST_PKT_SIZE); 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 */ /* FIXME limit the time because of shortcomings in timeout framework */
enum { MAX_TIMEOUT_SEC = 3600 }; 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) { if (timeout_sec > MAX_TIMEOUT_SEC) {
timeout_sec = MAX_TIMEOUT_SEC; timeout_sec = MAX_TIMEOUT_SEC;
if (_interface.config().verbose()) { if (_interface.config().verbose())
try { log("[", domain, "] prune re-request timeout of DHCP client");
log("[", _interface.domain(), "] prune re-request timeout of "
"DHCP client");
}
catch (Pointer<Domain>::Invalid) {
log("[?] prune re-request timeout of DHCP client"); }
}
} }
return Microseconds(timeout_sec * 1000 * 1000); 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) void Dhcp_client::_handle_timeout(Duration)
{ {
switch (_state) { _interface.with_domain(
case State::BOUND: _rerequest(State::RENEW); break; [&] /* domain_fn */ (Domain &domain) {
case State::RENEW: _rerequest(State::REBIND); break; switch (_state) {
case State::REBIND: _domain().discard_ip_config(); [[fallthrough]]; case State::BOUND: _rerequest(State::RENEW, domain); break;
default: discover(); 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 { Packet_result result { };
Message_type const msg_type = auto no_msg_type_fn = [&] { result = packet_drop("DHCP request misses option \"Message Type\""); };
dhcp.option<Dhcp_packet::Message_type_option>().value(); auto msg_type_fn = [&] (Dhcp_packet::Message_type_option const &msg_type) {
if (_interface.config().verbose_domain_state()) { if (_interface.config().verbose_domain_state()) {
if (msg_type == Message_type::OFFER) { if (msg_type.value() == Message_type::OFFER) {
Ipv4_address dns_server; Ipv4_address dns_server, subnet_mask, router_ip;
Ipv4_address subnet_mask; dhcp.with_option<Dhcp_packet::Dns_server_ipv4>([&] (auto opt) { dns_server = opt.value(); });
Ipv4_address router_ip; dhcp.with_option<Dhcp_packet::Subnet_mask>([&] (auto opt) { subnet_mask = opt.value(); });
dhcp.with_option<Dhcp_packet::Router_ipv4>([&] (auto opt) { router_ip = opt.value(); });
try { dns_server = dhcp.option<Dhcp_packet::Dns_server_ipv4>().value(); } log("[", domain, "] dhcp offer from ",
catch (Dhcp_packet::Option_not_found) { }
try { subnet_mask = dhcp.option<Dhcp_packet::Subnet_mask>().value(); }
catch (Dhcp_packet::Option_not_found) { }
try { router_ip = dhcp.option<Dhcp_packet::Router_ipv4>().value(); }
catch (Net::Dhcp_packet::Option_not_found) { }
log("[", _interface.domain(), "] dhcp offer from ",
dhcp.siaddr(), dhcp.siaddr(),
", offering ", dhcp.yiaddr(), ", offering ", dhcp.yiaddr(),
", subnet-mask ", subnet_mask, ", subnet-mask ", subnet_mask,
@ -145,38 +137,40 @@ void Dhcp_client::handle_dhcp_reply(Dhcp_packet &dhcp)
", DNS server ", dns_server); ", DNS server ", dns_server);
} }
} }
switch (_state) { switch (_state) {
case State::SELECT: case State::SELECT:
if (msg_type != Message_type::OFFER) { if (msg_type.value() != Message_type::OFFER) {
throw Drop_packet("DHCP client expects an offer"); result = packet_drop("DHCP client expects an offer");
break;
} }
enum { REQUEST_PKT_SIZE = 321 }; 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(), _send(Message_type::REQUEST, Ipv4_address(),
dhcp.option<Dhcp_packet::Server_ipv4>().value(), dhcp.option<Dhcp_packet::Server_ipv4>().value(),
dhcp.yiaddr(), REQUEST_PKT_SIZE); dhcp.yiaddr(), REQUEST_PKT_SIZE);
result = packet_handled();
break; break;
case State::REQUEST: case State::REQUEST:
case State::RENEW: case State::RENEW:
case State::REBIND: case State::REBIND:
{ {
if (msg_type != Message_type::ACK) { if (msg_type.value() != Message_type::ACK) {
throw Drop_packet("DHCP client expects an acknowledgement"); result = packet_drop("DHCP client expects an acknowledgement");
break;
} }
_lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value(); _lease_time_sec = dhcp.option<Dhcp_packet::Ip_lease_time>().value();
_set_state(State::BOUND, _rerequest_timeout(1)); _set_state(State::BOUND, _rerequest_timeout(1, domain));
_domain().ip_config_from_dhcp_ack(dhcp); domain.ip_config_from_dhcp_ack(dhcp);
result = packet_handled();
break; 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) { dhcp.with_option<Dhcp_packet::Message_type_option>(msg_type_fn, no_msg_type_fn);
throw Drop_packet("DHCP reply misses required option"); return result;
}
} }
@ -243,8 +237,7 @@ void Dhcp_client::_send(Message_type msg_type,
} }
break; break;
default: default: ASSERT_NEVER_REACHED;
throw Interface::Bad_send_dhcp_args();
} }
dhcp_opts.append_option<Dhcp_packet::Options_end>(); dhcp_opts.append_option<Dhcp_packet::Options_end>();

View File

@ -16,6 +16,7 @@
/* local includes */ /* local includes */
#include <cached_timer.h> #include <cached_timer.h>
#include <packet_result.h>
/* Genode includes */ /* Genode includes */
#include <net/dhcp.h> #include <net/dhcp.h>
@ -45,9 +46,9 @@ class Net::Dhcp_client
void _handle_timeout(Genode::Duration); 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); void _set_state(State state, Genode::Microseconds timeout);
@ -57,16 +58,12 @@ class Net::Dhcp_client
Ipv4_address requested_ip, Ipv4_address requested_ip,
Genode::size_t pkt_size); Genode::size_t pkt_size);
Configuration &_config();
Domain &_domain();
public: public:
Dhcp_client(Cached_timer &timer, Dhcp_client(Cached_timer &timer,
Interface &interface); Interface &interface);
void handle_dhcp_reply(Dhcp_packet &dhcp); [[nodiscard]] Packet_result handle_dhcp_reply(Dhcp_packet &dhcp, Domain &domain);
void discover(); void discover();
}; };

View File

@ -26,26 +26,31 @@ using namespace Genode;
** Dhcp_server_base ** ** Dhcp_server_base **
**********************/ **********************/
Dhcp_server_base::Dhcp_server_base(Xml_node const &node, Dhcp_server_base::Dhcp_server_base(Allocator &alloc) : _alloc { alloc } { }
Domain const &domain,
Allocator &alloc)
: bool Dhcp_server_base::finish_construction(Xml_node const &node, Domain const &domain)
_alloc { alloc }
{ {
bool result = true;
node.for_each_sub_node("dns-server", [&] (Xml_node const &sub_node) { node.for_each_sub_node("dns-server", [&] (Xml_node const &sub_node) {
if (!result)
return;
Dns_server::construct( Dns_server::construct(
alloc, sub_node.attribute_value("ip", Ipv4_address { }), _alloc, sub_node.attribute_value("ip", Ipv4_address { }),
[&] /* handle_success */ (Dns_server &server) [&] /* handle_success */ (Dns_server &server)
{ {
_dns_servers.insert_as_tail(server); _dns_servers.insert_as_tail(server);
}, },
[&] /* handle_failure */ () [&] /* 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) { node.with_optional_sub_node("dns-domain", [&] (Xml_node const &sub_node) {
xml_node_with_attribute(sub_node, "name", [&] (Xml_attribute const &attr) { xml_node_with_attribute(sub_node, "name", [&] (Xml_attribute const &attr) {
_dns_domain_name.set_to(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) char const *reason)
{ {
if (domain.config().verbose()) { if (domain.config().verbose()) {
log("[", domain, "] invalid DHCP server (", reason, ")"); } 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 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 _resolve_dns_config_from().dns_servers_empty();
}
return _dns_servers.empty(); return _dns_servers.empty();
} }
Dhcp_server::Dhcp_server(Xml_node const node, Dhcp_server::Dhcp_server(Xml_node const node, Allocator &alloc)
Domain &domain,
Allocator &alloc,
Ipv4_address_prefix const &interface,
Domain_dict &domains)
: :
Dhcp_server_base(node, domain, alloc), Dhcp_server_base(alloc),
_dns_config_from(_init_dns_config_from(node, domains)),
_ip_lease_time (_init_ip_lease_time(node)), _ip_lease_time (_init_ip_lease_time(node)),
_ip_first(node.attribute_value("ip_first", Ipv4_address())), _ip_first(node.attribute_value("ip_first", Ipv4_address())),
_ip_last(node.attribute_value("ip_last", Ipv4_address())), _ip_last(node.attribute_value("ip_last", Ipv4_address())),
_ip_first_raw(_ip_first.to_uint32_little_endian()), _ip_first_raw(_ip_first.to_uint32_little_endian()),
_ip_count(_ip_last.to_uint32_little_endian() - _ip_first_raw + 1), _ip_count(_ip_last.to_uint32_little_endian() - _ip_first_raw + 1),
_ip_alloc(alloc, _ip_count) _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)) { 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)) { 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)) { 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) { _dns_domain_name.with_string([&] (Dns_domain_name::String const &str) {
Genode::print(output, "DNS domain name ", str, ", "); Genode::print(output, "DNS domain name ", str, ", ");
}); });
try { Genode::print(output, "DNS config from ", _dns_config_from(), ", "); } with_dns_config_from([&] (Domain &domain) {
catch (Pointer<Domain>::Invalid) { } Genode::print(output, "DNS config from ", domain, ", "); });
Genode::print(output, "IP first ", _ip_first, Genode::print(output, "IP first ", _ip_first,
", last ", _ip_last, ", 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 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 { Alloc_ip_result result = Alloc_ip_error();
return Ipv4_address::from_uint32_little_endian(_ip_alloc.alloc() + _ip_alloc.alloc().with_result(
_ip_first_raw); [&] (addr_t ip_raw) { result = Alloc_ip_result(Ipv4_address::from_uint32_little_endian(ip_raw + _ip_first_raw)); },
} [&] (auto) { });
catch (Bit_allocator_dynamic::Out_of_indices) { return result;
throw Alloc_ip_failed();
}
} }
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); } return _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(); }
} }
void Dhcp_server::free_ip(Domain const &domain, void Dhcp_server::free_ip(Ipv4_address const &ip)
Ipv4_address const &ip)
{ {
/* ASSERT(_ip_alloc.free(ip.to_uint32_little_endian() - _ip_first_raw));
* 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<Domain> 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>();
}
Domain_name dns_config_from =
node.attribute_value("dns_config_from", Domain_name());
if (dns_config_from == Domain_name()) {
return Pointer<Domain>();
}
return domains.deprecated_find_by_name<Invalid>(dns_config_from);
} }
bool Dhcp_server::has_invalid_remote_dns_cfg() const bool Dhcp_server::has_invalid_remote_dns_cfg() const
{ {
if (_dns_config_from.valid()) { if (_dns_config_from_ptr)
return !_dns_config_from().ip_config().valid(); return !_dns_config_from_ptr->ip_config().valid();
}
return false; 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 void Dhcp_allocation::print(Output &output) const
{ {
Genode::print(output, "MAC ", _mac, " IP ", _ip); Genode::print(output, "MAC ", _mac, " IP ", _ip);
@ -292,17 +260,3 @@ void Dhcp_allocation::_handle_timeout(Duration)
{ {
_interface.dhcp_allocation_expired(*this); _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);
}

View File

@ -17,7 +17,6 @@
/* local includes */ /* local includes */
#include <bit_allocator_dynamic.h> #include <bit_allocator_dynamic.h>
#include <list.h> #include <list.h>
#include <pointer.h>
#include <dns.h> #include <dns.h>
#include <ipv4_config.h> #include <ipv4_config.h>
#include <cached_timer.h> #include <cached_timer.h>
@ -52,14 +51,15 @@ class Net::Dhcp_server_base
Dns_server_list _dns_servers { }; Dns_server_list _dns_servers { };
Dns_domain_name _dns_domain_name { _alloc }; Dns_domain_name _dns_domain_name { _alloc };
void _invalid(Domain const &domain, [[nodiscard]] bool _invalid(Domain const &domain,
char const *reason); char const *reason);
public: public:
Dhcp_server_base(Genode::Xml_node const &node, Dhcp_server_base(Genode::Allocator &alloc);
Domain const &domain,
Genode::Allocator &alloc); [[nodiscard]] bool finish_construction(Genode::Xml_node const &node,
Domain const &domain);
~Dhcp_server_base(); ~Dhcp_server_base();
}; };
@ -70,7 +70,7 @@ class Net::Dhcp_server : private Genode::Noncopyable,
{ {
private: private:
Pointer<Domain> const _dns_config_from; Domain *_dns_config_from_ptr { };
Genode::Microseconds const _ip_lease_time; Genode::Microseconds const _ip_lease_time;
Ipv4_address const _ip_first; Ipv4_address const _ip_first;
Ipv4_address const _ip_last; 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); Genode::Microseconds _init_ip_lease_time(Genode::Xml_node const node);
Pointer<Domain> _init_dns_config_from(Genode::Xml_node const node,
Domain_dict &domains);
Ipv4_config const &_resolve_dns_config_from() const; Ipv4_config const &_resolve_dns_config_from() const;
/*
* Noncopyable
*/
Dhcp_server(Dhcp_server const &);
Dhcp_server &operator = (Dhcp_server const &);
public: public:
enum { DEFAULT_IP_LEASE_TIME_SEC = 3600 }; 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, Dhcp_server(Genode::Xml_node const node,
Domain &domain, Genode::Allocator &alloc);
Genode::Allocator &alloc,
Ipv4_address_prefix const &interface,
Domain_dict &domains);
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<Ipv4_address, Alloc_ip_error>;
void free_ip(Domain const &domain, [[nodiscard]] Alloc_ip_result alloc_ip();
Ipv4_address const &ip);
[[nodiscard]] bool alloc_ip(Ipv4_address const &ip);
void free_ip(Ipv4_address const &ip);
bool has_invalid_remote_dns_cfg() const; bool has_invalid_remote_dns_cfg() const;
template <typename FUNC> template <typename FUNC>
void for_each_dns_server_ip(FUNC && functor) const 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( _resolve_dns_config_from().for_each_dns_server(
[&] (Dns_server const &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 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 _resolve_dns_config_from().dns_domain_name();
} }
return _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; 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 ** ** log **
@ -149,7 +161,6 @@ class Net::Dhcp_server : private Genode::Noncopyable,
** Accessors ** ** Accessors **
***************/ ***************/
Domain &dns_config_from() { return _dns_config_from(); }
Genode::Microseconds ip_lease_time() const { return _ip_lease_time; } 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(); ~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); void lifetime(Genode::Microseconds lifetime);
@ -218,9 +240,13 @@ struct Net::Dhcp_allocation_tree
public: public:
struct No_match : Genode::Exception { }; void find_by_mac(Mac_address const &mac, auto const &match_fn, auto const &no_match_fn) const
{
Dhcp_allocation &find_by_mac(Mac_address const &mac) 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) void insert(Dhcp_allocation &dhcp_alloc)
{ {

View File

@ -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 <direct_rule.h>
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);
}

View File

@ -40,16 +40,14 @@ class Net::Direct_rule_base
public: public:
struct Invalid : Genode::Exception { }; Direct_rule_base(Ipv4_address_prefix const dst) : _dst(dst) { }
Direct_rule_base(Genode::Xml_node const node);
/********* /*********
** log ** ** log **
*********/ *********/
void print(Genode::Output &output) const; void print(Genode::Output &output) const { Genode::print(output, "dst ", _dst); }
/*************** /***************
@ -64,7 +62,7 @@ template <typename T>
struct Net::Direct_rule : Direct_rule_base, struct Net::Direct_rule : Direct_rule_base,
Direct_rule_list<T>::Element Direct_rule_list<T>::Element
{ {
Direct_rule(Genode::Xml_node const node) : Direct_rule_base(node) { } Direct_rule(Ipv4_address_prefix const &dst) : Direct_rule_base(dst) { }
}; };

View File

@ -47,10 +47,10 @@ void Dns_domain_name::set_to(Dns_domain_name const &name)
{ {
if (name.valid()) { if (name.valid()) {
name.with_string([&] (String const &string) { name.with_string([&] (String const &string) {
if (_string.valid()) { if (_string_ptr) {
_string() = string; *_string_ptr = string;
} else { } else {
_string = *new (_alloc) String { string }; _string_ptr = new (_alloc) String { string };
} }
}); });
} else { } 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) { name_attr.with_raw_value([&] (char const *base, size_t size) {
if (size < STRING_CAPACITY) { if (size < STRING_CAPACITY) {
if (_string.valid()) { if (_string_ptr) {
_string() = Cstring { base, size }; *_string_ptr = Cstring { base, size };
} else { } else {
_string = *new (_alloc) String { Cstring { base, size } }; _string_ptr = new (_alloc) String { Cstring { base, size } };
} }
} else { } else {
set_invalid(); 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) { name_option.with_string([&] (char const *base, size_t size) {
if (size < STRING_CAPACITY) { if (size < STRING_CAPACITY) {
if (_string.valid()) { if (_string_ptr) {
_string() = Cstring { base, size }; *_string_ptr = Cstring { base, size };
} else { } else {
_string = *new (_alloc) String { Cstring { base, size } }; _string_ptr = new (_alloc) String { Cstring { base, size } };
} }
} else { } else {
set_invalid(); 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() void Dns_domain_name::set_invalid()
{ {
if (_string.valid()) { if (_string_ptr) {
_alloc.free(&_string(), sizeof(String)); _alloc.free(_string_ptr, sizeof(String));
_string = { }; _string_ptr = nullptr;
} }
} }
bool Dns_domain_name::equal_to(Dns_domain_name const &other) const bool Dns_domain_name::equal_to(Dns_domain_name const &other) const
{ {
if (_string.valid()) { if (_string_ptr) {
if (other._string.valid()) { if (other._string_ptr)
return _string() == other._string(); return *_string_ptr == *other._string_ptr;
}
return false; return false;
} }
return !other._string.valid(); return !other._string_ptr;
} }

View File

@ -16,7 +16,6 @@
/* local includes */ /* local includes */
#include <list.h> #include <list.h>
#include <pointer.h>
/* Genode includes */ /* Genode includes */
#include <util/reconstructible.h> #include <util/reconstructible.h>
@ -84,7 +83,13 @@ class Net::Dns_domain_name : private Genode::Noncopyable
private: private:
Genode::Allocator &_alloc; Genode::Allocator &_alloc;
Pointer<String> _string { }; String *_string_ptr { };
/*
* Noncopyable
*/
Dns_domain_name(Dns_domain_name const &);
Dns_domain_name &operator = (Dns_domain_name const &);
public: public:
@ -100,14 +105,13 @@ class Net::Dns_domain_name : private Genode::Noncopyable
void set_invalid(); void set_invalid();
bool valid() const { return _string.valid(); } bool valid() const { return _string_ptr; }
template <typename FUNC> template <typename FUNC>
void with_string(FUNC && func) const void with_string(FUNC && func) const
{ {
if (_string.valid()) { if (_string_ptr)
func(_string()); func(*_string_ptr);
}
} }
bool equal_to(Dns_domain_name const &other) const; bool equal_to(Dns_domain_name const &other) const;

View File

@ -41,10 +41,9 @@ void Domain::_log_ip_config() const
bool Domain::ready() const bool Domain::ready() const
{ {
if (_dhcp_server.valid()) { if (_dhcp_server_ptr) {
if (_dhcp_server().has_invalid_remote_dns_cfg()) { if (_dhcp_server_ptr->has_invalid_remote_dns_cfg())
return false; return false;
}
} }
return true; return true;
} }
@ -61,8 +60,7 @@ void Domain::update_ready_state()
void Domain::_prepare_reconstructing_ip_config() void Domain::_prepare_reconstructing_ip_config()
{ {
if (!_ip_config_dynamic) { ASSERT(_ip_config_dynamic);
throw Ip_config_static(); }
/* discard old IP config if any */ /* discard old IP config if any */
if (ip_config().valid()) { if (ip_config().valid()) {
@ -124,8 +122,7 @@ void Domain::_finish_reconstructing_ip_config()
}); });
} }
/* force report if configured */ /* force report if configured */
try { _config.report().handle_config(); } _config.with_report([&] (Report &r) { r.handle_config(); });
catch (Pointer<Report>::Invalid) { }
} }
@ -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, Domain_dict &domains,
Xml_node const node, Xml_node const node,
char const *type, char const *type,
Forward_rule_tree &rules) Forward_rule_tree &rules)
{ {
bool result = true;
node.for_each_sub_node(type, [&] (Xml_node const node) { node.for_each_sub_node(type, [&] (Xml_node const node) {
try { if (!result)
Forward_rule &rule = *new (_alloc) Forward_rule(domains, node); return;
rules.insert(&rule);
if (_config.verbose()) { Port port = node.attribute_value("port", Port(0));
log("[", *this, "] ", protocol, " forward rule: ", rule); } 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()) { if (_config.verbose()) {
log("[", *this, "] invalid domain (", reason, ")"); } 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, Domain_dict &domains,
Xml_node const node, Xml_node const node,
char const *type, char const *type,
Transport_rule_list &rules) Transport_rule_list &rules)
{ {
bool result = true;
node.for_each_sub_node(type, [&] (Xml_node const node) { node.for_each_sub_node(type, [&] (Xml_node const node) {
try { if (!result)
rules.insert(*new (_alloc) return;
Transport_rule(domains, node, _alloc, protocol, _config, *this));
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"); } Transport_rule &rule = *new (_alloc) Transport_rule(dst, _alloc);
catch (Permit_any_rule::Invalid) { _invalid("invalid permit-any rule"); } if (!rule.finish_construction(domains, node, protocol, _config, *this)) {
catch (Permit_single_rule::Invalid) { _invalid("invalid permit rule"); } 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() } String<160>()).string() }
{ {
_log_ip_config(); _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()) { if (_config.verbose_domain_state()) {
log("[", *this, "] NIC sessions: ", _interface_cnt); } 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::TCP: return _tcp_links;
case L3_protocol::UDP: return _udp_links; case L3_protocol::UDP: return _udp_links;
case L3_protocol::ICMP: return _icmp_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() bool Domain::init(Domain_dict &domains)
{
Dhcp_server &dhcp_server = _dhcp_server();
if (dhcp_server.has_invalid_remote_dns_cfg()) {
throw Pointer<Dhcp_server>::Invalid();
}
return dhcp_server;
}
void Domain::init(Domain_dict &domains)
{ {
/* read DHCP server configuration */ /* read DHCP server configuration */
try { bool result = true;
Xml_node const dhcp_server_node = _node.sub_node("dhcp-server"); _node.with_optional_sub_node("dhcp-server", [&] (Xml_node const &dhcp_server_node) {
if (_ip_config_dynamic) { if (_ip_config_dynamic) {
_invalid("DHCP server and client at once"); } result = _invalid("DHCP server and client at once");
return;
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<Domain>::Invalid) { }
_dhcp_server = dhcp_server;
if (_config.verbose()) {
log("[", *this, "] DHCP server: ", _dhcp_server()); }
} }
catch (Bit_allocator_dynamic::Out_of_indices) { 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");
* This message is printed independent from the routers return;
* 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.with_dns_config_from([&] (Domain &domain) {
catch (Xml_node::Nonexistent_sub_node) { } domain.ip_config_dependents().insert(this); });
catch (Dhcp_server::Invalid) { _invalid("invalid DHCP server"); }
/* read forward rules */ _dhcp_server_ptr = &dhcp_server;
_read_forward_rules(tcp_name(), domains, _node, "tcp-forward", if (_config.verbose()) {
_tcp_forward_rules); log("[", *this, "] DHCP server: ", dhcp_server); }
_read_forward_rules(udp_name(), domains, _node, "udp-forward", });
_udp_forward_rules); if (!result)
return result;
/* read UDP and TCP rules */ /* read forward and transport rules */
_read_transport_rules(tcp_name(), domains, _node, "tcp", _tcp_rules); if (!_read_forward_rules(tcp_name(), domains, _node, "tcp-forward", _tcp_forward_rules) ||
_read_transport_rules(udp_name(), domains, _node, "udp", _udp_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 */ /* read NAT rules */
_node.for_each_sub_node("nat", [&] (Xml_node const node) { _node.for_each_sub_node("nat", [&] (Xml_node const node) {
try { if (!result)
Nat_rule &rule = *new (_alloc) return;
Nat_rule(domains, _tcp_port_alloc, _udp_port_alloc,
_icmp_port_alloc, node, _config.verbose()); domains.find_by_domain_attr(node,
_nat_rules.insert(&rule); [&] (Domain &domain) {
if (_config.verbose()) { Nat_rule &rule = *new (_alloc)
log("[", *this, "] NAT rule: ", rule); } Nat_rule(domain, _tcp_port_alloc, _udp_port_alloc,
} _icmp_port_alloc, node, _config.verbose());
catch (Nat_rule::Invalid) { _invalid("invalid NAT rule"); } _nat_rules.insert(&rule);
if (_config.verbose())
log("[", *this, "] NAT rule: ", rule); },
[&] { result = _invalid("invalid NAT rule"); });
}); });
if (!result)
return result;
/* read ICMP rules */ /* read ICMP rules */
_node.for_each_sub_node("icmp", [&] (Xml_node const node) { _node.for_each_sub_node("icmp", [&] (Xml_node const node) {
try { _icmp_rules.insert(*new (_alloc) Ip_rule(domains, node)); } if (!result)
catch (Ip_rule::Invalid) { _invalid("invalid ICMP rule"); } 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 */ /* read IP rules */
_node.for_each_sub_node("ip", [&] (Xml_node const node) { _node.for_each_sub_node("ip", [&] (Xml_node const node) {
try { _ip_rules.insert(*new (_alloc) Ip_rule(domains, node)); } if (!result)
catch (Ip_rule::Invalid) { _invalid("invalid IP rule"); } 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); _tcp_rules.destroy_each(_alloc);
_udp_forward_rules.destroy_each(_alloc); _udp_forward_rules.destroy_each(_alloc);
_tcp_forward_rules.destroy_each(_alloc); _tcp_forward_rules.destroy_each(_alloc);
try { with_dhcp_server([&] (Dhcp_server &dhcp_server) {
Dhcp_server &dhcp_server = _dhcp_server(); _dhcp_server_ptr = nullptr;
_dhcp_server = Pointer<Dhcp_server>(); dhcp_server.with_dns_config_from([&] (Domain &domain) {
try { dhcp_server.dns_config_from().ip_config_dependents().remove(this); } domain.ip_config_dependents().remove(this); });
catch (Pointer<Domain>::Invalid) { } destroy(_alloc, &dhcp_server); });
destroy(_alloc, &dhcp_server);
}
catch (Pointer<Dhcp_server>::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();
} }
@ -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 bytes = report_cfg.bytes();
bool empty = true; bool cfg = report_cfg.config();
xml.attribute("name", name()); bool stats = report_cfg.stats() && (
if (_config.report().bytes()) { !_tcp_stats.report_empty() || !_udp_stats.report_empty() ||
xml.attribute("rx_bytes", _tx_bytes); !_icmp_stats.report_empty() || !_arp_stats.report_empty() || _dhcp_stats.report_empty());
xml.attribute("tx_bytes", _rx_bytes); bool fragm_ip = report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4;
empty = false; bool interfaces = false;
} _interfaces.for_each([&] (Interface const &interface) {
if (_config.report().config()) { if (!interface.report_empty(report_cfg))
xml.attribute("ipv4", String<19>(ip_config().interface())); interfaces = true; });
xml.attribute("gw", String<16>(ip_config().gateway()));
ip_config().for_each_dns_server([&] (Dns_server const &dns_server) { return !bytes && !cfg && !stats && !fragm_ip && !interfaces;
xml.node("dns", [&] () { }
xml.attribute("ip", String<16>(dns_server.ip()));
});
}); void Domain::report(Xml_generator &xml, Report const &report_cfg) const
ip_config().dns_domain_name().with_string( {
[&] (Dns_domain_name::String const &str) xml.attribute("name", name());
{ if (report_cfg.bytes()) {
xml.node("dns-domain", [&] () { xml.attribute("rx_bytes", _tx_bytes);
xml.attribute("name", str); xml.attribute("tx_bytes", _rx_bytes);
}); }
}); if (report_cfg.config()) {
empty = false; xml.attribute("ipv4", String<19>(ip_config().interface()));
} xml.attribute("gw", String<16>(ip_config().gateway()));
if (_config.report().stats()) { ip_config().for_each_dns_server([&] (Dns_server const &dns_server) {
try { xml.node("tcp-links", [&] () { _tcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } xml.node("dns", [&] () {
try { xml.node("udp-links", [&] () { _udp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } xml.attribute("ip", String<16>(dns_server.ip())); }); });
try { xml.node("icmp-links", [&] () { _icmp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } ip_config().dns_domain_name().with_string([&] (Dns_domain_name::String const &str) {
try { xml.node("arp-waiters", [&] () { _arp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } xml.node("dns-domain", [&] () {
try { xml.node("dhcp-allocations", [&] () { _dhcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { } xml.attribute("name", str); }); });
} }
if (_config.report().dropped_fragm_ipv4() && _dropped_fragm_ipv4) { if (report_cfg.stats()) {
xml.node("dropped-fragm-ipv4", [&] () { if (!_tcp_stats.report_empty()) xml.node("tcp-links", [&] { _tcp_stats.report(xml); });
xml.attribute("value", _dropped_fragm_ipv4); 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); });
empty = false; 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); });
_interfaces.for_each([&] (Interface &interface) { }
try { if (report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4)
interface.report(xml); xml.node("dropped-fragm-ipv4", [&] () {
empty = false; xml.attribute("value", _dropped_fragm_ipv4); });
} catch (Report::Empty) { } _interfaces.for_each([&] (Interface const &interface) {
}); if (!interface.report_empty(report_cfg))
if (empty) { xml.node("interface", [&] { interface.report(xml, report_cfg); });
throw Report::Empty(); }
}); });
} }
@ -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); });
if (refused_for_ports) xml.node("refused_for_ports", [&] { xml.attribute("value", refused_for_ports); });
if (refused_for_ram) { xml.node("refused_for_ram", [&] () { xml.attribute("value", refused_for_ram); }); empty = false; } if (destroyed) xml.node("destroyed", [&] { xml.attribute("value", destroyed); });
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(); }
} }
@ -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); });
if (destroyed) { xml.node("destroyed", [&] () { xml.attribute("value", destroyed); }); empty = false; }
if (empty) { throw Report::Empty(); }
} }

View File

@ -21,7 +21,6 @@
#include <ip_rule.h> #include <ip_rule.h>
#include <arp_cache.h> #include <arp_cache.h>
#include <port_allocator.h> #include <port_allocator.h>
#include <pointer.h>
#include <ipv4_config.h> #include <ipv4_config.h>
#include <dhcp_server.h> #include <dhcp_server.h>
#include <interface.h> #include <interface.h>
@ -54,7 +53,8 @@ struct Net::Domain_object_stats
void dissolve_interface(Interface_object_stats const &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 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<Domain, Domain_name>
{ {
public: public:
template <typename NO_MATCH_EXCEPTION> void find_by_domain_attr(Genode::Xml_node const &node, auto const &ok_fn, auto const &failed_fn)
Domain &deprecated_find_by_name(Domain_name const &domain_name)
{ {
Domain *dom_ptr { nullptr }; with_element(node.attribute_value("domain", Domain_name()),
with_element( [&] (Domain &domain) { ok_fn(domain); }, [&] { failed_fn(); });
domain_name,
[&] /* match_fn */ (Domain &dom) { dom_ptr = &dom; },
[&] /* no_match_fn */ () { throw NO_MATCH_EXCEPTION { }; }
);
return *dom_ptr;
} }
template <typename NO_MATCH_EXCEPTION>
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<NO_MATCH_EXCEPTION>(domain_name);
}
}; };
@ -117,7 +104,7 @@ class Net::Domain : public List<Domain>::Element,
Nat_rule_tree _nat_rules { }; Nat_rule_tree _nat_rules { };
Interface_list _interfaces { }; Interface_list _interfaces { };
unsigned long _interface_cnt { 0 }; unsigned long _interface_cnt { 0 };
Pointer<Dhcp_server> _dhcp_server { }; Dhcp_server *_dhcp_server_ptr { };
Genode::Reconstructible<Ipv4_config> _ip_config; Genode::Reconstructible<Ipv4_config> _ip_config;
bool const _ip_config_dynamic { !ip_config().valid() }; bool const _ip_config_dynamic { !ip_config().valid() };
List<Domain> _ip_config_dependents { }; List<Domain> _ip_config_dependents { };
@ -141,19 +128,19 @@ class Net::Domain : public List<Domain>::Element,
Domain_object_stats _dhcp_stats { }; Domain_object_stats _dhcp_stats { };
unsigned long _dropped_fragm_ipv4 { 0 }; unsigned long _dropped_fragm_ipv4 { 0 };
void _read_forward_rules(Genode::Cstring const &protocol, [[nodiscard]] bool _read_forward_rules(Genode::Cstring const &protocol,
Domain_dict &domains, Domain_dict &domains,
Genode::Xml_node const node, Genode::Xml_node const node,
char const *type, char const *type,
Forward_rule_tree &rules); Forward_rule_tree &rules);
void _read_transport_rules(Genode::Cstring const &protocol, [[nodiscard]] bool _read_transport_rules(Genode::Cstring const &protocol,
Domain_dict &domains, Domain_dict &domains,
Genode::Xml_node const node, Genode::Xml_node const node,
char const *type, char const *type,
Transport_rule_list &rules); Transport_rule_list &rules);
void _invalid(char const *reason) const; [[nodiscard]] bool _invalid(char const *reason) const;
void _log_ip_config() const; void _log_ip_config() const;
@ -171,11 +158,15 @@ class Net::Domain : public List<Domain>::Element,
void __FIXME__dissolve_foreign_arp_waiters(); void __FIXME__dissolve_foreign_arp_waiters();
/*
* Noncopyable
*/
Domain(Domain const &);
Domain &operator = (Domain const &);
public: public:
struct Invalid : Genode::Exception { }; struct Invalid : Genode::Exception { };
struct Ip_config_static : Genode::Exception { };
struct No_next_hop : Genode::Exception { };
Domain(Configuration &config, Domain(Configuration &config,
Genode::Xml_node const &node, Genode::Xml_node const &node,
@ -185,11 +176,21 @@ class Net::Domain : public List<Domain>::Element,
~Domain(); ~Domain();
void init(Domain_dict &domains); [[nodiscard]] bool finish_construction() const;
[[nodiscard]] bool init(Domain_dict &domains);
void deinit(); 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); void ip_config_from_dhcp_ack(Dhcp_packet &dhcp_ack);
@ -209,7 +210,9 @@ class Net::Domain : public List<Domain>::Element,
void raise_tx_bytes(Genode::size_t bytes) { _tx_bytes += bytes; } 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); void add_dropped_fragm_ipv4(unsigned long dropped_fragm_ipv4);
@ -217,6 +220,20 @@ class Net::Domain : public List<Domain>::Element,
void update_ready_state(); 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 ** ** log **
@ -247,7 +264,6 @@ class Net::Domain : public List<Domain>::Element,
Nat_rule_tree &nat_rules() { return _nat_rules; } Nat_rule_tree &nat_rules() { return _nat_rules; }
Interface_list &interfaces() { return _interfaces; } Interface_list &interfaces() { return _interfaces; }
Configuration &config() const { return _config; } Configuration &config() const { return _config; }
Dhcp_server &dhcp_server();
Arp_cache &arp_cache() { return _arp_cache; } Arp_cache &arp_cache() { return _arp_cache; }
Arp_waiter_list &foreign_arp_waiters() { return _foreign_arp_waiters; } Arp_waiter_list &foreign_arp_waiters() { return _foreign_arp_waiters; }
Link_side_tree &tcp_links() { return _tcp_links; } Link_side_tree &tcp_links() { return _tcp_links; }

View File

@ -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)) }, _port { port },
_to_ip { node.attribute_value("to", Ipv4_address()) }, _to_ip { to_ip },
_to_port { node.attribute_value("to_port", Port(0)) }, _to_port { to_port },
_domain { domains.deprecated_find_by_domain_attr<Invalid>(node) } _domain { domain }
{ { }
if (_port == Port(0) || !_to_ip.valid() || dynamic_port(_port)) {
throw Invalid(); }
}

View File

@ -49,7 +49,7 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
struct Invalid : Genode::Exception { }; 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 <typename HANDLE_MATCH_FN, template <typename HANDLE_MATCH_FN,
typename HANDLE_NO_MATCH_FN> typename HANDLE_NO_MATCH_FN>

File diff suppressed because it is too large Load Diff

View File

@ -68,7 +68,8 @@ struct Net::Interface_object_stats
Genode::size_t alive { 0 }; Genode::size_t alive { 0 };
Genode::size_t destroyed { 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(); ~Interface_object_stats();
}; };
@ -89,13 +90,14 @@ struct Net::Interface_link_stats
Genode::size_t dissolved_no_timeout { 0 }; Genode::size_t dissolved_no_timeout { 0 };
Genode::size_t destroyed { 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(); ~Interface_link_stats();
}; };
struct Net::Interface_policy struct Net::Interface_policy : Genode::Interface
{ {
virtual Domain_name determine_domain_name() const = 0; virtual Domain_name determine_domain_name() const = 0;
@ -107,7 +109,9 @@ struct Net::Interface_policy
virtual bool interface_link_state() const = 0; 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() { } virtual ~Interface_policy() { }
}; };
@ -126,9 +130,6 @@ class Net::Interface : private Interface_list::Element
enum { IPV4_TIME_TO_LIVE = 64 }; enum { IPV4_TIME_TO_LIVE = 64 };
enum { MAX_FREE_OPS_PER_EMERGENCY = 1024 }; enum { MAX_FREE_OPS_PER_EMERGENCY = 1024 };
struct Dismiss_link : Genode::Exception { };
struct Dismiss_arp_waiter : Genode::Exception { };
struct Update_domain struct Update_domain
{ {
Domain &old_domain; Domain &old_domain;
@ -151,7 +152,7 @@ class Net::Interface : private Interface_list::Element
Interface_policy &_policy; Interface_policy &_policy;
Cached_timer &_timer; Cached_timer &_timer;
Genode::Allocator &_alloc; Genode::Allocator &_alloc;
Pointer<Domain> _domain { }; Domain *_domain_ptr { };
Arp_waiter_list _own_arp_waiters { }; Arp_waiter_list _own_arp_waiters { };
Link_list _tcp_links { }; Link_list _tcp_links { };
Link_list _udp_links { }; Link_list _udp_links { };
@ -171,11 +172,18 @@ class Net::Interface : private Interface_list::Element
Interface_object_stats _dhcp_stats { }; Interface_object_stats _dhcp_stats { };
unsigned long _dropped_fragm_ipv4 { 0 }; unsigned long _dropped_fragm_ipv4 { 0 };
void _new_link(L3_protocol const protocol, /*
Link_side_id const &local_id, * Noncopyable
Pointer<Port_allocator_guard> remote_port_alloc, */
Domain &remote_domain, Interface(Interface const &);
Link_side_id const &remote_id); 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); 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, void _release_dhcp_allocation(Dhcp_allocation &allocation,
Domain &local_domain); Domain &local_domain);
void _new_dhcp_allocation(Ethernet_frame &eth, [[nodiscard]] Packet_result _new_dhcp_allocation(Ethernet_frame &eth,
Dhcp_packet &dhcp, Dhcp_packet &dhcp,
Dhcp_server &dhcp_srv, Dhcp_server &dhcp_srv,
Domain &local_domain); Domain &local_domain);
void _send_dhcp_reply(Dhcp_server const &dhcp_srv, void _send_dhcp_reply(Dhcp_server const &dhcp_srv,
Mac_address const &eth_dst, Mac_address const &eth_dst,
@ -204,84 +212,79 @@ class Net::Interface : private Interface_list::Element
Genode::size_t icmp_sz, Genode::size_t icmp_sz,
Size_guard &size_guard); Size_guard &size_guard);
Forward_rule_tree &_forward_rules(Domain &local_domain, [[nodiscard]] Packet_result _handle_arp(Ethernet_frame &eth,
L3_protocol const prot) const; Size_guard &size_guard,
Domain &local_domain);
Transport_rule_list &_transport_rules(Domain &local_domain,
L3_protocol const prot) const;
void _handle_arp(Ethernet_frame &eth,
Size_guard &size_guard,
Domain &local_domain);
void _handle_arp_reply(Ethernet_frame &eth, void _handle_arp_reply(Ethernet_frame &eth,
Size_guard &size_guard, Size_guard &size_guard,
Arp_packet &arp, Arp_packet &arp,
Domain &local_domain); Domain &local_domain);
void _handle_arp_request(Ethernet_frame &eth, [[nodiscard]] Packet_result _handle_arp_request(Ethernet_frame &eth,
Size_guard &size_guard, Size_guard &size_guard,
Arp_packet &arp, Arp_packet &arp,
Domain &local_domain); Domain &local_domain);
void _send_arp_reply(Ethernet_frame &request_eth, void _send_arp_reply(Ethernet_frame &request_eth,
Arp_packet &request_arp); Arp_packet &request_arp);
void _handle_dhcp_request(Ethernet_frame &eth, [[nodiscard]] Packet_result _handle_dhcp_request(Ethernet_frame &eth,
Dhcp_packet &dhcp, Dhcp_server &dhcp_srv,
Domain &local_domain, Dhcp_packet &dhcp,
Ipv4_address_prefix const &local_intf); Domain &local_domain,
Ipv4_address_prefix const &local_intf);
void _handle_ip(Ethernet_frame &eth, [[nodiscard]] Packet_result _handle_ip(Ethernet_frame &eth,
Size_guard &size_guard, Size_guard &size_guard,
Packet_descriptor const &pkt, Packet_descriptor const &pkt,
Domain &local_domain); Domain &local_domain);
void _handle_icmp_query(Ethernet_frame &eth, [[nodiscard]] Packet_result _handle_icmp_query(Ethernet_frame &eth,
Size_guard &size_guard, Size_guard &size_guard,
Ipv4_packet &ip, Ipv4_packet &ip,
Internet_checksum_diff &ip_icd, Internet_checksum_diff &ip_icd,
Packet_descriptor const &pkt, Packet_descriptor const &pkt,
L3_protocol prot, L3_protocol prot,
void *prot_base, void *prot_base,
Genode::size_t prot_size, Genode::size_t prot_size,
Domain &local_domain); Domain &local_domain);
void _handle_icmp_error(Ethernet_frame &eth, [[nodiscard]] Packet_result _handle_icmp_error(Ethernet_frame &eth,
Size_guard &size_guard, Size_guard &size_guard,
Ipv4_packet &ip, Ipv4_packet &ip,
Internet_checksum_diff &ip_icd, Internet_checksum_diff &ip_icd,
Packet_descriptor const &pkt, Packet_descriptor const &pkt,
Domain &local_domain, Domain &local_domain,
Icmp_packet &icmp, Icmp_packet &icmp,
Genode::size_t icmp_sz); Genode::size_t icmp_sz);
void _handle_icmp(Ethernet_frame &eth, [[nodiscard]] Packet_result _handle_icmp(Ethernet_frame &eth,
Size_guard &size_guard, Size_guard &size_guard,
Ipv4_packet &ip, Ipv4_packet &ip,
Internet_checksum_diff &ip_icd, Internet_checksum_diff &ip_icd,
Packet_descriptor const &pkt, Packet_descriptor const &pkt,
L3_protocol prot, L3_protocol prot,
void *prot_base, void *prot_base,
Genode::size_t prot_size, Genode::size_t prot_size,
Domain &local_domain, Domain &local_domain,
Ipv4_address_prefix const &local_intf); Ipv4_address_prefix const &local_intf);
void _adapt_eth(Ethernet_frame &eth, [[nodiscard]] Packet_result _adapt_eth(Ethernet_frame &eth,
Ipv4_address const &dst_ip, Ipv4_address const &dst_ip,
Packet_descriptor const &pkt, Packet_descriptor const &pkt,
Domain &remote_domain); Domain &remote_domain);
void _nat_link_and_pass(Ethernet_frame &eth, [[nodiscard]] Packet_result _nat_link_and_pass(Ethernet_frame &eth,
Size_guard &size_guard, Size_guard &size_guard,
Ipv4_packet &ip, Ipv4_packet &ip,
Internet_checksum_diff &ip_icd, Internet_checksum_diff &ip_icd,
L3_protocol const prot, L3_protocol const prot,
void *const prot_base, void *const prot_base,
Genode::size_t const prot_size, Genode::size_t const prot_size,
Link_side_id const &local_id, Link_side_id const &local_id,
Domain &local_domain, Domain &local_domain,
Domain &remote_domain); Domain &remote_domain);
void _broadcast_arp_request(Ipv4_address const &src_ip, void _broadcast_arp_request(Ipv4_address const &src_ip,
Ipv4_address const &dst_ip); Ipv4_address const &dst_ip);
@ -301,19 +304,20 @@ class Net::Interface : private Interface_list::Element
void _handle_pkt(); void _handle_pkt();
void _continue_handle_eth(Domain const &domain, void _continue_handle_eth(Packet_descriptor const &pkt);
Packet_descriptor const &pkt);
Ipv4_address const &_router_ip() const; Ipv4_address const &_router_ip() const;
void _handle_eth(void *const eth_base, void _drop_packet(Packet_descriptor const &pkt, char const *reason);
Size_guard &size_guard,
Packet_descriptor const &pkt);
void _handle_eth(Ethernet_frame &eth, [[nodiscard]] Packet_result _handle_eth(void *const eth_base,
Size_guard &size_guard, Size_guard &size_guard,
Packet_descriptor const &pkt, Packet_descriptor const &pkt);
Domain &local_domain);
[[nodiscard]] Packet_result _handle_eth(Ethernet_frame &eth,
Size_guard &size_guard,
Packet_descriptor const &pkt,
Domain &local_domain);
void _ack_packet(Packet_descriptor const &pkt); void _ack_packet(Packet_descriptor const &pkt);
@ -369,20 +373,6 @@ class Net::Interface : private Interface_list::Element
public: 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, Interface(Genode::Entrypoint &ep,
Cached_timer &timer, Cached_timer &timer,
Mac_address const router_mac, Mac_address const router_mac,
@ -454,19 +444,30 @@ class Net::Interface : private Interface_list::Element
void handle_interface_link_state(); 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 handle_domain_ready_state(bool state);
void destroy_link(Link &link); 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 ** ** Accessors **
***************/ ***************/
Configuration const &config() const { return _config(); } Configuration const &config() const { return _config(); }
Domain &domain() { return _domain(); }
Mac_address const &router_mac() const { return _router_mac; } Mac_address const &router_mac() const { return _router_mac; }
Mac_address const &mac() const { return _mac; } Mac_address const &mac() const { return _mac; }
Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; } Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; }

View File

@ -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 <ip_rule.h>
#include <domain.h>
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<Invalid>(node) }
{ }

View File

@ -35,7 +35,7 @@ class Net::Ip_rule : public Direct_rule<Ip_rule>
public: 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) { }
/*************** /***************

View File

@ -90,10 +90,7 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
dhcp_ipv4_option<Dhcp_packet::Subnet_mask>(dhcp_ack) }, dhcp_ipv4_option<Dhcp_packet::Subnet_mask>(dhcp_ack) },
_gateway { dhcp_ipv4_option<Dhcp_packet::Router_ipv4>(dhcp_ack) } _gateway { dhcp_ipv4_option<Dhcp_packet::Router_ipv4>(dhcp_ack) }
{ {
try { dhcp_ack.with_option<Dhcp_packet::Dns_server>([&] (Dhcp_packet::Dns_server const &dns_server) {
Dhcp_packet::Dns_server const &dns_server {
dhcp_ack.option<Dhcp_packet::Dns_server>() };
dns_server.for_each_address([&] (Ipv4_address const &addr) { dns_server.for_each_address([&] (Ipv4_address const &addr) {
Dns_server::construct( Dns_server::construct(
alloc, addr, alloc, addr,
@ -104,10 +101,9 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
[&] /* handle_failure */ () { } [&] /* handle_failure */ () { }
); );
}); });
} });
catch (Dhcp_packet::Option_not_found) { } dhcp_ack.with_option<Dhcp_packet::Domain_name>([&] (Dhcp_packet::Domain_name const &domain_name) {
try { _dns_domain_name.set_to(domain_name);
_dns_domain_name.set_to(dhcp_ack.option<Dhcp_packet::Domain_name>());
if (domain.config().verbose() && if (domain.config().verbose() &&
!_dns_domain_name.valid()) { !_dns_domain_name.valid()) {
@ -115,8 +111,7 @@ Ipv4_config::Ipv4_config(Dhcp_packet &dhcp_ack,
log("[", domain, "] rejecting oversized DNS " log("[", domain, "] rejecting oversized DNS "
"domain name from DHCP reply"); "domain name from DHCP reply");
} }
} });
catch (Dhcp_packet::Option_not_found) { }
} }

View File

@ -35,5 +35,5 @@ char const *Net::l3_protocol_name(L3_protocol protocol)
case L3_protocol::TCP: return tcp_name(); case L3_protocol::TCP: return tcp_name();
case L3_protocol::UDP: return udp_name(); case L3_protocol::UDP: return udp_name();
case L3_protocol::ICMP: return icmp_name(); case L3_protocol::ICMP: return icmp_name();
default: throw Interface::Bad_transport_protocol(); } default: ASSERT_NEVER_REACHED; }
} }

View File

@ -86,8 +86,9 @@ void Link::print(Output &output) const
Link::Link(Interface &cln_interface, Link::Link(Interface &cln_interface,
Domain &cln_domain,
Link_side_id const &cln_id, Link_side_id const &cln_id,
Pointer<Port_allocator_guard> srv_port_alloc, Port_allocator_guard *srv_port_alloc_ptr,
Domain &srv_domain, Domain &srv_domain,
Link_side_id const &srv_id, Link_side_id const &srv_id,
Cached_timer &timer, Cached_timer &timer,
@ -98,12 +99,12 @@ Link::Link(Interface &cln_interface,
: :
_config(config), _config(config),
_client_interface(cln_interface), _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, _dissolve_timeout(timer, *this, &Link::_handle_dissolve_timeout,
Microseconds { 100 * 1000 }), Microseconds { 100 * 1000 }),
_dissolve_timeout_us(dissolve_timeout), _dissolve_timeout_us(dissolve_timeout),
_protocol(protocol), _protocol(protocol),
_client(cln_interface.domain(), cln_id, *this), _client(cln_domain, cln_id, *this),
_server(srv_domain, srv_id, *this), _server(srv_domain, srv_id, *this),
_stats(stats), _stats(stats),
_stats_curr(stats.opening) _stats_curr(stats.opening)
@ -146,30 +147,29 @@ void Link::dissolve(bool timeout)
if (_config().verbose()) { if (_config().verbose()) {
log("Dissolve ", l3_protocol_name(_protocol), " link: ", *this); } log("Dissolve ", l3_protocol_name(_protocol), " link: ", *this); }
try { if (_server_port_alloc_ptr) {
if (_config().verbose()) { if (_config().verbose()) {
log("Free ", l3_protocol_name(_protocol), log("Free ", l3_protocol_name(_protocol),
" port ", _server.dst_port(), " port ", _server.dst_port(),
" at ", _server.domain(), " at ", _server.domain(),
" that was used by ", _client.domain()); " that was used by ", _client.domain());
} }
_server_port_alloc().free(_server.dst_port()); _server_port_alloc_ptr->free(_server.dst_port());
} }
catch (Pointer<Port_allocator_guard>::Invalid) { }
} }
void Link::handle_config(Domain &cln_domain, void Link::handle_config(Domain &cln_domain,
Domain &srv_domain, Domain &srv_domain,
Pointer<Port_allocator_guard> srv_port_alloc, Port_allocator_guard *srv_port_alloc_ptr,
Configuration &config) Configuration &config)
{ {
Microseconds dissolve_timeout_us(0); Microseconds dissolve_timeout_us(0);
switch (_protocol) { switch (_protocol) {
case L3_protocol::TCP: dissolve_timeout_us = config.tcp_idle_timeout(); break; 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::UDP: dissolve_timeout_us = config.udp_idle_timeout(); break;
case L3_protocol::ICMP: dissolve_timeout_us = config.icmp_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_us = dissolve_timeout_us;
_dissolve_timeout.schedule(_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); _client.domain().links(_protocol).remove(&_client);
_server.domain().links(_protocol).remove(&_server); _server.domain().links(_protocol).remove(&_server);
_config = config; _config = config;
_client._domain = cln_domain; _client._domain = cln_domain;
_server._domain = srv_domain; _server._domain = srv_domain;
_server_port_alloc = srv_port_alloc; _server_port_alloc_ptr = srv_port_alloc_ptr;
cln_domain.links(_protocol).insert(&_client); cln_domain.links(_protocol).insert(&_client);
srv_domain.links(_protocol).insert(&_server); srv_domain.links(_protocol).insert(&_server);
@ -196,17 +196,18 @@ void Link::handle_config(Domain &cln_domain,
** Tcp_link ** ** Tcp_link **
**************/ **************/
Tcp_link::Tcp_link(Interface &cln_interface, Tcp_link::Tcp_link(Interface &cln_interface,
Link_side_id const &cln_id, Domain &cln_domain,
Pointer<Port_allocator_guard> srv_port_alloc, Link_side_id const &cln_id,
Domain &srv_domain, Port_allocator_guard *srv_port_alloc_ptr,
Link_side_id const &srv_id, Domain &srv_domain,
Cached_timer &timer, Link_side_id const &srv_id,
Configuration &config, Cached_timer &timer,
L3_protocol const protocol, Configuration &config,
Interface_link_stats &stats) 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) 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::Udp_link(Interface &cln_interface, Udp_link::Udp_link(Interface &cln_interface,
Link_side_id const &cln_id, Domain &cln_domain,
Pointer<Port_allocator_guard> srv_port_alloc, Link_side_id const &cln_id,
Domain &srv_domain, Port_allocator_guard *srv_port_alloc_ptr,
Link_side_id const &srv_id, Domain &srv_domain,
Cached_timer &timer, Link_side_id const &srv_id,
Configuration &config, Cached_timer &timer,
L3_protocol const protocol, Configuration &config,
Interface_link_stats &stats) 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) config, protocol, config.udp_idle_timeout(), stats)
{ } { }
@ -308,17 +310,18 @@ void Udp_link::server_packet()
** Icmp_link ** ** Icmp_link **
***************/ ***************/
Icmp_link::Icmp_link(Interface &cln_interface, Icmp_link::Icmp_link(Interface &cln_interface,
Link_side_id const &cln_id, Domain &cln_domain,
Pointer<Port_allocator_guard> srv_port_alloc, Link_side_id const &cln_id,
Domain &srv_domain, Port_allocator_guard *srv_port_alloc_ptr,
Link_side_id const &srv_id, Domain &srv_domain,
Cached_timer &timer, Link_side_id const &srv_id,
Configuration &config, Cached_timer &timer,
L3_protocol const protocol, Configuration &config,
Interface_link_stats &stats) 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) config, protocol, config.icmp_idle_timeout(), stats)
{ } { }

View File

@ -40,7 +40,6 @@
/* local includes */ /* local includes */
#include <list.h> #include <list.h>
#include <reference.h> #include <reference.h>
#include <pointer.h>
#include <l3_protocol.h> #include <l3_protocol.h>
#include <lazy_one_shot_timeout.h> #include <lazy_one_shot_timeout.h>
@ -187,7 +186,7 @@ class Net::Link : public Link_list::Element
Reference<Configuration> _config; Reference<Configuration> _config;
Interface &_client_interface; Interface &_client_interface;
Pointer<Port_allocator_guard> _server_port_alloc; Port_allocator_guard *_server_port_alloc_ptr;
Lazy_one_shot_timeout<Link> _dissolve_timeout; Lazy_one_shot_timeout<Link> _dissolve_timeout;
Genode::Microseconds _dissolve_timeout_us; Genode::Microseconds _dissolve_timeout_us;
L3_protocol const _protocol; L3_protocol const _protocol;
@ -201,29 +200,36 @@ class Net::Link : public Link_list::Element
void _packet() { _dissolve_timeout.schedule(_dissolve_timeout_us); } void _packet() { _dissolve_timeout.schedule(_dissolve_timeout_us); }
/*
* Noncopyable
*/
Link(Link const &);
Link &operator = (Link const &);
public: public:
struct No_port_allocator : Genode::Exception { }; struct No_port_allocator : Genode::Exception { };
Link(Interface &cln_interface, Link(Interface &cln_interface,
Link_side_id const &cln_id, Domain &cln_domain,
Pointer<Port_allocator_guard> srv_port_alloc, Link_side_id const &cln_id,
Domain &srv_domain, Port_allocator_guard *srv_port_alloc_ptr,
Link_side_id const &srv_id, Domain &srv_domain,
Cached_timer &timer, Link_side_id const &srv_id,
Configuration &config, Cached_timer &timer,
L3_protocol const protocol, Configuration &config,
Genode::Microseconds const dissolve_timeout, L3_protocol const protocol,
Interface_link_stats &stats); Genode::Microseconds const dissolve_timeout,
Interface_link_stats &stats);
~Link(); ~Link();
void dissolve(bool timeout); void dissolve(bool timeout);
void handle_config(Domain &cln_domain, void handle_config(Domain &cln_domain,
Domain &srv_domain, Domain &srv_domain,
Pointer<Port_allocator_guard> srv_port_alloc, Port_allocator_guard *srv_port_alloc_ptr,
Configuration &config); Configuration &config);
/********* /*********
** Log ** ** Log **
@ -273,8 +279,9 @@ class Net::Tcp_link : public Link
public: public:
Tcp_link(Interface &cln_interface, Tcp_link(Interface &cln_interface,
Domain &cln_domain,
Link_side_id const &cln_id, Link_side_id const &cln_id,
Pointer<Port_allocator_guard> srv_port_alloc, Port_allocator_guard *srv_port_alloc_ptr,
Domain &srv_domain, Domain &srv_domain,
Link_side_id const &srv_id, Link_side_id const &srv_id,
Cached_timer &timer, Cached_timer &timer,
@ -291,8 +298,9 @@ class Net::Tcp_link : public Link
struct Net::Udp_link : Link struct Net::Udp_link : Link
{ {
Udp_link(Interface &cln_interface, Udp_link(Interface &cln_interface,
Domain &cln_domain,
Link_side_id const &cln_id, Link_side_id const &cln_id,
Pointer<Port_allocator_guard> srv_port_alloc, Port_allocator_guard *srv_port_alloc_ptr,
Domain &srv_domain, Domain &srv_domain,
Link_side_id const &srv_id, Link_side_id const &srv_id,
Cached_timer &timer, Cached_timer &timer,
@ -308,15 +316,16 @@ struct Net::Udp_link : Link
struct Net::Icmp_link : Link struct Net::Icmp_link : Link
{ {
Icmp_link(Interface &cln_interface, Icmp_link(Interface &cln_interface,
Link_side_id const &cln_id, Domain &cln_domain,
Pointer<Port_allocator_guard> srv_port_alloc, Link_side_id const &cln_id,
Domain &srv_domain, Port_allocator_guard *srv_port_alloc_ptr,
Link_side_id const &srv_id, Domain &srv_domain,
Cached_timer &timer, Link_side_id const &srv_id,
Configuration &config, Cached_timer &timer,
L3_protocol const protocol, Configuration &config,
Interface_link_stats &stats); L3_protocol const protocol,
Interface_link_stats &stats);
void client_packet() { _packet(); } void client_packet() { _packet(); }

View File

@ -17,6 +17,7 @@
/* Genode includes */ /* Genode includes */
#include <base/exception.h> #include <base/exception.h>
#include <net/mac_address.h> #include <net/mac_address.h>
#include <util/attempt.h>
namespace Net { class Mac_allocator; } namespace Net { class Mac_allocator; }
@ -30,14 +31,15 @@ class Net::Mac_allocator
public: public:
struct Alloc_failed : Genode::Exception {};
Mac_allocator(Mac_address base) : _base(base) Mac_allocator(Mac_address base) : _base(base)
{ {
Genode::memset(&_free, true, sizeof(_free)); Genode::memset(&_free, true, sizeof(_free));
} }
Mac_address alloc() struct Alloc_error { };
using Alloc_result = Genode::Attempt<Mac_address, Alloc_error>;
Alloc_result alloc()
{ {
for (unsigned id = 0; id < sizeof(_free) / sizeof(_free[0]); id++) { for (unsigned id = 0; id < sizeof(_free) / sizeof(_free[0]); id++) {
if (!_free[id]) { if (!_free[id]) {
@ -48,7 +50,7 @@ class Net::Mac_allocator
mac.addr[5] = id; mac.addr[5] = id;
return mac; return mac;
} }
throw Alloc_failed(); return Alloc_error();
} }
void free(Mac_address mac) { _free[mac.addr[5]] = true; } void free(Mac_address mac) { _free[mac.addr[5]] = true; }

View File

@ -70,9 +70,7 @@ class Net::Main
void Main::_handle_report() void Main::_handle_report()
{ {
try { _config().report().generate(); } _config().with_report([&] (Report &r) { r.generate(); });
catch (Pointer<Report>::Invalid) { }
} }

View File

@ -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 &tcp_port_alloc,
Port_allocator &udp_port_alloc, Port_allocator &udp_port_alloc,
Port_allocator &icmp_port_alloc, Port_allocator &icmp_port_alloc,
Xml_node const node, Xml_node const node,
bool const verbose) bool const verbose)
: :
_domain { domains.deprecated_find_by_domain_attr<Invalid>(node) }, _domain { domain },
_tcp_port_alloc { tcp_port_alloc, node.attribute_value("tcp-ports", 0U), verbose }, _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 }, _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 } _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::TCP: return _tcp_port_alloc;
case L3_protocol::UDP: return _udp_port_alloc; case L3_protocol::UDP: return _udp_port_alloc;
case L3_protocol::ICMP: return _icmp_port_alloc; case L3_protocol::ICMP: return _icmp_port_alloc;
default: throw Interface::Bad_transport_protocol(); } default: ASSERT_NEVER_REACHED; }
} }

View File

@ -44,7 +44,7 @@ class Net::Nat_rule : public Genode::Avl_node<Nat_rule>
struct Invalid : Genode::Exception { }; struct Invalid : Genode::Exception { };
Nat_rule(Domain_dict &domains, Nat_rule(Domain &domain,
Port_allocator &tcp_port_alloc, Port_allocator &tcp_port_alloc,
Port_allocator &udp_port_alloc, Port_allocator &udp_port_alloc,
Port_allocator &icmp_port_alloc, Port_allocator &icmp_port_alloc,

View File

@ -26,72 +26,68 @@ using namespace Genode;
** Nic_client ** ** 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, Net::Nic_client::Nic_client(Session_label const &label_arg,
Domain_name const &domain_arg, Domain_name const &domain_arg,
Allocator &alloc, Allocator &alloc,
Nic_client_dict &old_nic_clients,
Nic_client_dict &new_nic_clients, Nic_client_dict &new_nic_clients,
Env &env,
Cached_timer &timer,
Interface_list &interfaces,
Configuration &config) Configuration &config)
: :
Nic_client_dict::Element { new_nic_clients, label_arg }, Nic_client_dict::Element { new_nic_clients, label_arg },
_alloc { alloc }, _alloc { alloc },
_config { config }, _config { config },
_domain { domain_arg } _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( old_nic_clients.with_element(
label(), label(),
[&] /* handle_match */ (Nic_client &old_nic_client) [&] /* handle_match */ (Nic_client &old_nic_client)
{ {
/* reuse existing interface */ /* reuse existing interface */
Nic_client_interface &interface = old_nic_client._interface(); Nic_client_interface &interface = *old_nic_client._crit->interface_ptr;
old_nic_client._interface = Pointer<Nic_client_interface>(); old_nic_client._crit->interface_ptr = nullptr;
interface.domain_name(domain()); interface.domain_name(domain());
_interface = interface; _crit.construct(&interface);
}, },
[&] /* handle_no_match */ () [&] /* handle_no_match */ ()
{ {
/* create a new interface */ /* create a new interface */
if (config.verbose()) { if (_config.verbose()) {
log("[", domain(), "] create NIC client: ", label()); } log("[", domain(), "] create NIC client: ", label()); }
try { try {
_interface = *new (_alloc) _crit.construct(new (_alloc)
Nic_client_interface { Nic_client_interface(env, timer, _alloc, interfaces, _config, domain(), label()));
env, timer, alloc, interfaces, config, domain(),
label() };
} }
catch (Insufficient_ram_quota) { _invalid("NIC session RAM quota"); } catch (Insufficient_ram_quota) { error = "NIC session RAM quota"; }
catch (Insufficient_cap_quota) { _invalid("NIC session CAP quota"); } catch (Insufficient_cap_quota) { error = "NIC session CAP quota"; }
catch (Service_denied) { _invalid("NIC session denied"); } 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() Net::Nic_client::~Nic_client()
{ {
if (!_crit.constructed())
return;
/* if the interface was yet not reused by another NIC client, destroy it */ /* if the interface was yet not reused by another NIC client, destroy it */
try { if (_crit->interface_ptr) {
Nic_client_interface &interface = _interface();
if (_config.verbose()) { if (_config.verbose()) {
log("[", domain(), "] destroy NIC client: ", label()); } log("[", domain(), "] destroy NIC client: ", label()); }
destroy(_alloc, _crit->interface_ptr);
destroy(_alloc, &interface);
} }
catch (Pointer<Nic_client_interface>::Invalid) { }
} }

View File

@ -41,29 +41,31 @@ class Net::Nic_client : private Nic_client_dict::Element
private: private:
Genode::Allocator &_alloc; struct Critical { Nic_client_interface *interface_ptr; };
Configuration const &_config;
Domain_name const _domain;
Pointer<Nic_client_interface> _interface { };
void _invalid(char const *reason) const; Genode::Allocator &_alloc;
Configuration &_config;
Domain_name const _domain;
Genode::Constructible<Critical> _crit { };
/*
* Noncopyable
*/
Nic_client(Nic_client const &);
Nic_client &operator = (Nic_client const &);
public: public:
struct Invalid : Genode::Exception { };
Nic_client(Genode::Session_label const &label_arg, Nic_client(Genode::Session_label const &label_arg,
Domain_name const &domain_arg, Domain_name const &domain_arg,
Genode::Allocator &alloc, Genode::Allocator &alloc,
Nic_client_dict &old_nic_clients,
Nic_client_dict &new_nic_clients, Nic_client_dict &new_nic_clients,
Genode::Env &env,
Cached_timer &timer,
Interface_list &interfaces,
Configuration &config); Configuration &config);
~Nic_client(); ~Nic_client();
[[nodiscard]] bool finish_construction(Genode::Env &, Cached_timer &, Interface_list &, Nic_client_dict &);
/************** /**************
** Acessors ** ** Acessors **
@ -93,6 +95,8 @@ class Net::Nic_client_interface_base : public Interface_policy
Genode::Session_label const &label() const override { return _label; } Genode::Session_label const &label() const override { return _label; }
void handle_domain_ready_state(bool state) override; void handle_domain_ready_state(bool state) override;
bool interface_link_state() const override; bool interface_link_state() const override;
bool report_empty() const override { return true; };
void report(Genode::Xml_generator &) const override { };
public: public:

View File

@ -60,21 +60,17 @@ Interface_policy::Interface_policy(Genode::Session_label const &label,
Domain_name Domain_name
Net::Nic_session_component::Interface_policy::determine_domain_name() const Net::Nic_session_component::Interface_policy::determine_domain_name() const
{ {
Domain_name domain_name; Domain_name domain_name { };
try { try {
Session_policy policy(_label, _config().node()); Session_policy policy(_label, _config().node());
domain_name = policy.attribute_value("domain", Domain_name()); 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) { catch (Session_policy::No_policy_defined) {
if (_config().verbose()) { if (_config().verbose()) {
log("[?] no policy for downlink label \"", _label, "\""); } 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; 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: return false;
case UP_DOWN_UP: return true; case UP_DOWN_UP: return true;
} }
class Never_reached : Exception { }; ASSERT_NEVER_REACHED;
throw Never_reached { };
} }
@ -216,8 +211,7 @@ Net::Nic_session_component::Interface_policy::read_and_ack_session_link_state()
_session_link_state_transition(DOWN_UP); _session_link_state_transition(DOWN_UP);
return true; return true;
} }
class Never_reached { }; ASSERT_NEVER_REACHED;
throw Never_reached { };
} }
@ -296,11 +290,14 @@ Net::Nic_session_root::Nic_session_root(Env &env,
_env { env }, _env { env },
_timer { timer }, _timer { timer },
_mac_alloc { MAC_ALLOC_BASE }, _mac_alloc { MAC_ALLOC_BASE },
_router_mac { _mac_alloc.alloc() },
_config { config }, _config { config },
_shared_quota { shared_quota }, _shared_quota { shared_quota },
_interfaces { interfaces } _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) 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, _env, _shared_quota, args,
[&] (Session_env &session_env, void *session_at, Ram_dataspace_capability ram_ds) [&] (Session_env &session_env, void *session_at, Ram_dataspace_capability ram_ds)
{ {
Nic_session_component *result { };
Session_label const label { label_from_args(args) }; Session_label const label { label_from_args(args) };
Mac_address const mac { _mac_alloc.alloc() }; _mac_alloc.alloc().with_result(
try { [&] (auto mac) {
return construct_at<Nic_session_component>( try {
session_at, session_env, result = construct_at<Nic_session_component>(
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0), session_at, session_env,
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0), Arg_string::find_arg(args, "tx_buf_size").ulong_value(0),
_timer, mac, _router_mac, label, _interfaces, Arg_string::find_arg(args, "rx_buf_size").ulong_value(0),
_config(), ram_ds); _timer, mac, *_router_mac, label, _interfaces,
} _config(), ram_ds);
catch (...) { }
_mac_alloc.free(mac); catch (...) {
throw; _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) { catch (Region_map::Invalid_dataspace) {
_invalid_downlink("Failed to attach RAM"); _invalid_downlink("Failed to attach RAM");
throw Service_denied(); throw Service_denied();

View File

@ -117,6 +117,7 @@ class Net::Nic_session_component : private Nic_session_component_base,
Domain_name determine_domain_name() const override; Domain_name determine_domain_name() const override;
void handle_config(Configuration const &config) override { _config = config; } void handle_config(Configuration const &config) override { _config = config; }
Genode::Session_label const &label() const override { return _label; } 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 report(Genode::Xml_generator &xml) const override { _session_env.report(xml); };
void handle_domain_ready_state(bool state) override; void handle_domain_ready_state(bool state) override;
bool interface_link_state() const override; bool interface_link_state() const override;
@ -167,13 +168,13 @@ class Net::Nic_session_root
enum { MAC_ALLOC_BASE = 0x02 }; enum { MAC_ALLOC_BASE = 0x02 };
Genode::Env &_env; Genode::Env &_env;
Cached_timer &_timer; Cached_timer &_timer;
Mac_allocator _mac_alloc; Mac_allocator _mac_alloc;
Mac_address const _router_mac; Genode::Constructible<Mac_address> _router_mac { };
Reference<Configuration> _config; Reference<Configuration> _config;
Quota &_shared_quota; Quota &_shared_quota;
Interface_list &_interfaces; Interface_list &_interfaces;
void _invalid_downlink(char const *reason); void _invalid_downlink(char const *reason);

View File

@ -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_ */

View File

@ -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_any_rule::Permit_any_rule(Domain &domain) : Permit_rule { domain } { }
:
Permit_rule { domains.deprecated_find_by_domain_attr<Invalid>(node) }
{ }
/************************ /************************
@ -55,12 +52,8 @@ void Permit_single_rule::print(Output &output) const
} }
Permit_single_rule::Permit_single_rule(Domain_dict &domains, Permit_single_rule::Permit_single_rule(Port port, Domain &domain)
Xml_node const node)
: :
Permit_rule { domains.deprecated_find_by_domain_attr<Invalid>(node) }, Permit_rule { domain },
_port { node.attribute_value("port", Port(0)) } _port { port }
{ { }
if (_port == Port(0) || dynamic_port(_port)) {
throw Invalid(); }
}

View File

@ -16,10 +16,10 @@
/* local includes */ /* local includes */
#include <avl_tree.h> #include <avl_tree.h>
#include <port_allocator.h>
/* Genode includes */ /* Genode includes */
#include <util/avl_tree.h> #include <util/avl_tree.h>
#include <net/port.h>
namespace Genode { namespace Genode {
@ -72,9 +72,7 @@ struct Net::Permit_any_rule : Permit_rule
{ {
public: public:
struct Invalid : Genode::Exception { }; Permit_any_rule(Domain &domain);
Permit_any_rule(Domain_dict &domains, Genode::Xml_node const node);
/********* /*********
@ -99,10 +97,7 @@ class Net::Permit_single_rule : public Permit_rule,
public: public:
struct Invalid : Genode::Exception { }; Permit_single_rule(Port port, Domain &domain);
Permit_single_rule(Domain_dict &domains,
Genode::Xml_node const node);
template <typename HANDLE_MATCH_FN, template <typename HANDLE_MATCH_FN,
typename HANDLE_NO_MATCH_FN> typename HANDLE_NO_MATCH_FN>

View File

@ -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 <base/exception.h>
namespace Net {
template <typename> class Pointer;
template <typename> class Const_pointer;
}
template <typename T>
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 <typename T>
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_ */

View File

@ -31,7 +31,7 @@ bool Net::dynamic_port(Port const port)
** Port_allocator ** ** Port_allocator **
********************/ ********************/
Port Net::Port_allocator::alloc() Net::Port_allocator::Alloc_result Net::Port_allocator::alloc()
{ {
for (unsigned nr_of_trials { 0 }; for (unsigned nr_of_trials { 0 };
nr_of_trials < NR_OF_PORTS; nr_of_trials < NR_OF_PORTS;
@ -45,19 +45,18 @@ Port Net::Port_allocator::alloc()
} }
catch (Bit_allocator<NR_OF_PORTS>::Range_conflict) { } catch (Bit_allocator<NR_OF_PORTS>::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 { try {
_bit_allocator.alloc_addr(port.value - FIRST_PORT); _bit_allocator.alloc_addr(port.value - FIRST_PORT);
return true;
} }
catch (Bit_allocator<NR_OF_PORTS>::Range_conflict) { catch (Bit_allocator<NR_OF_PORTS>::Range_conflict) { }
return false;
throw Allocation_conflict();
}
} }
@ -71,29 +70,30 @@ void Port_allocator::free(Port const port)
** Port_allocator_guard ** ** 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) { if (_used_nr_of_ports == _max_nr_of_ports) {
throw Out_of_indices(); return Alloc_error();
}
try {
Port const port = _port_alloc.alloc();
_used_nr_of_ports++;
return port;
}
catch (Port_allocator::Out_of_indices) {
throw Out_of_indices();
} }
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) { if (_used_nr_of_ports == _max_nr_of_ports)
throw Out_of_indices(); return false;
}
_port_alloc.alloc(port); if (!_port_alloc.alloc(port))
return false;
_used_nr_of_ports++; _used_nr_of_ports++;
return true;
} }

View File

@ -17,6 +17,7 @@
/* Genode includes */ /* Genode includes */
#include <net/port.h> #include <net/port.h>
#include <util/attempt.h>
/* local includes */ /* local includes */
#include <util/bit_allocator.h> #include <util/bit_allocator.h>
@ -43,12 +44,12 @@ class Net::Port_allocator
public: public:
struct Allocation_conflict : Genode::Exception { }; struct Alloc_error { };
struct Out_of_indices : Genode::Exception { }; using Alloc_result = Genode::Attempt<Port, Alloc_error>;
Port alloc(); [[nodiscard]] Alloc_result alloc();
void alloc(Port const port); [[nodiscard]] bool alloc(Port const port);
void free(Port const port); void free(Port const port);
}; };
@ -64,11 +65,12 @@ class Net::Port_allocator_guard
public: 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); void free(Port const port);

View File

@ -50,26 +50,25 @@ Net::Report::Report(bool const &verbose,
} }
void Net::Report::generate() void Net::Report::generate() const
{ {
try { try {
Reporter::Xml_generator xml(_reporter, [&] () { Reporter::Xml_generator xml(_reporter, [&] {
if (_quota) { if (_quota) {
xml.node("ram", [&] () { xml.node("ram", [&] {
xml.attribute("quota", _pd.ram_quota().value); xml.attribute("quota", _pd.ram_quota().value);
xml.attribute("used", _pd.used_ram().value); xml.attribute("used", _pd.used_ram().value);
xml.attribute("shared", _shared_quota.ram); xml.attribute("shared", _shared_quota.ram);
}); });
xml.node("cap", [&] () { xml.node("cap", [&] {
xml.attribute("quota", _pd.cap_quota().value); xml.attribute("quota", _pd.cap_quota().value);
xml.attribute("used", _pd.used_caps().value); xml.attribute("used", _pd.used_caps().value);
xml.attribute("shared", _shared_quota.cap); xml.attribute("shared", _shared_quota.cap);
}); });
} }
_domains.for_each([&] (Domain &domain) { _domains.for_each([&] (Domain const &domain) {
try { domain.report(xml); } if (!domain.report_empty(*this))
catch (Empty) { } xml.node("domain", [&] { domain.report(xml, *this); }); });
});
}); });
} catch (Xml_generator::Buffer_exceeded) { } catch (Xml_generator::Buffer_exceeded) {
if (_verbose) { if (_verbose) {

View File

@ -65,8 +65,6 @@ class Net::Report
public: public:
struct Empty : Genode::Exception { };
Report(bool const &verbose, Report(bool const &verbose,
Genode::Xml_node const node, Genode::Xml_node const node,
Cached_timer &timer, Cached_timer &timer,
@ -80,7 +78,7 @@ class Net::Report
void handle_interface_link_state(); void handle_interface_link_state();
void generate(); void generate() const;
/*************** /***************

View File

@ -169,6 +169,8 @@ class Genode::Session_env : public Ram_allocator,
return ptr; return ptr;
}; };
bool report_empty() const { return false; }
void report(Genode::Xml_generator &xml) const void report(Genode::Xml_generator &xml) const
{ {
xml.node("ram-quota", [&] () { xml.node("ram-quota", [&] () {

View File

@ -4,7 +4,6 @@ LIBS += base net
SRC_CC += \ SRC_CC += \
arp_waiter.cc \ arp_waiter.cc \
ip_rule.cc \
ipv4_address_prefix.cc \ ipv4_address_prefix.cc \
nic_session_root.cc \ nic_session_root.cc \
port_allocator.cc \ port_allocator.cc \
@ -18,7 +17,6 @@ SRC_CC += \
configuration.cc \ configuration.cc \
domain.cc \ domain.cc \
l3_protocol.cc \ l3_protocol.cc \
direct_rule.cc \
link.cc \ link.cc \
transport_rule.cc \ transport_rule.cc \
permit_rule.cc \ permit_rule.cc \

View File

@ -24,63 +24,63 @@ using namespace Net;
using namespace Genode; using namespace Genode;
Pointer<Permit_any_rule> Transport_rule::Transport_rule(Ipv4_address_prefix const &dst,
Transport_rule::_read_permit_any_rule(Domain_dict &domains, Allocator &alloc)
Xml_node const node,
Allocator &alloc)
{
try {
Xml_node sub_node = node.sub_node("permit-any");
return Pointer<Permit_any_rule>(*new (alloc)
Permit_any_rule(domains, sub_node));
}
catch (Xml_node::Nonexistent_sub_node) { }
return Pointer<Permit_any_rule>();
}
Transport_rule::Transport_rule(Domain_dict &domains,
Xml_node const node,
Allocator &alloc,
Cstring const &protocol,
Configuration &config,
Domain const &domain)
: :
Direct_rule(node), Direct_rule(dst),
_alloc(alloc), _alloc(alloc)
_permit_any_rule(_read_permit_any_rule(domains, node, 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 to find a permit-any rule first */
try { bool error = false;
Permit_any_rule &permit_any_rule = _permit_any_rule(); node.with_optional_sub_node("permit-any", [&] (Xml_node const &permit_any_node) {
if (config.verbose()) { domains.find_by_domain_attr(permit_any_node,
log("[", domain, "] ", protocol, " permit-any rule: ", permit_any_rule); [&] (Domain &remote_domain) { _permit_any_rule_ptr = new (_alloc) Permit_any_rule(remote_domain); },
log("[", domain, "] ", protocol, " rule: dst ", _dst); [&] { error = true; });
}
return;
} catch (Pointer<Permit_any_rule>::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); }
}); });
/* drop the transport rule if it has no permitted ports */ if (error)
if (!_permit_single_rules.first()) { return false;
throw Invalid(); }
if (config.verbose()) { /* skip specific permit rules if all ports are permitted anyway */
log("[", domain, "] ", protocol, " rule: dst ", _dst); } 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() Transport_rule::~Transport_rule()
{ {
_permit_single_rules.destroy_each(_alloc); _permit_single_rules.destroy_each(_alloc);
try { destroy(_alloc, &_permit_any_rule()); } if (_permit_any_rule_ptr)
catch (Pointer<Permit_any_rule>::Invalid) { } destroy(_alloc, _permit_any_rule_ptr);
} }

View File

@ -17,7 +17,6 @@
/* local includes */ /* local includes */
#include <direct_rule.h> #include <direct_rule.h>
#include <permit_rule.h> #include <permit_rule.h>
#include <pointer.h>
namespace Genode { class Allocator; } namespace Genode { class Allocator; }
@ -33,23 +32,25 @@ class Net::Transport_rule : public Direct_rule<Transport_rule>
{ {
private: private:
Genode::Allocator &_alloc; Genode::Allocator &_alloc;
Pointer<Permit_any_rule> const _permit_any_rule; Permit_any_rule *_permit_any_rule_ptr { };
Permit_single_rule_tree _permit_single_rules { }; Permit_single_rule_tree _permit_single_rules { };
static Pointer<Permit_any_rule> static Permit_any_rule *
_read_permit_any_rule(Domain_dict &domains, _read_permit_any_rule(Domain_dict &domains,
Genode::Xml_node const node, Genode::Xml_node const node,
Genode::Allocator &alloc); Genode::Allocator &alloc);
/*
* Noncopyable
*/
Transport_rule(Transport_rule const &);
Transport_rule &operator = (Transport_rule const &);
public: public:
Transport_rule(Domain_dict &domains, Transport_rule(Ipv4_address_prefix const &dst,
Genode::Xml_node const node, Genode::Allocator &alloc);
Genode::Allocator &alloc,
Genode::Cstring const &protocol,
Configuration &config,
Domain const &domain);
~Transport_rule(); ~Transport_rule();
@ -60,9 +61,9 @@ class Net::Transport_rule : public Direct_rule<Transport_rule>
HANDLE_MATCH_FN && handle_match, HANDLE_MATCH_FN && handle_match,
HANDLE_NO_MATCH_FN && handle_no_match) const 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 { } else {
@ -70,6 +71,12 @@ class Net::Transport_rule : public Direct_rule<Transport_rule>
port, handle_match, handle_no_match); 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);
}; };

View File

@ -62,17 +62,13 @@ Net::Uplink_session_component::Interface_policy::determine_domain_name() const
try { try {
Session_policy policy(_label, _config().node()); Session_policy policy(_label, _config().node());
domain_name = policy.attribute_value("domain", Domain_name()); 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) { catch (Session_policy::No_policy_defined) {
if (_config().verbose()) { if (_config().verbose()) {
log("[?] no policy for downlink label \"", _label, "\""); } 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; return domain_name;
} }

View File

@ -81,6 +81,7 @@ class Net::Uplink_session_component : private Uplink_session_component_base,
Domain_name determine_domain_name() const override; Domain_name determine_domain_name() const override;
void handle_config(Configuration const &config) override { _config = config; } void handle_config(Configuration const &config) override { _config = config; }
Genode::Session_label const &label() const override { return _label; } 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 report(Genode::Xml_generator &xml) const override { _session_env.report(xml); };
void handle_domain_ready_state(bool /* state */) override { } void handle_domain_ready_state(bool /* state */) override { }
bool interface_link_state() const override { return true; } bool interface_link_state() const override { return true; }