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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -26,26 +26,31 @@ using namespace Genode;
** Dhcp_server_base **
**********************/
Dhcp_server_base::Dhcp_server_base(Xml_node const &node,
Domain const &domain,
Allocator &alloc)
:
_alloc { alloc }
Dhcp_server_base::Dhcp_server_base(Allocator &alloc) : _alloc { alloc } { }
bool Dhcp_server_base::finish_construction(Xml_node const &node, Domain const &domain)
{
bool result = true;
node.for_each_sub_node("dns-server", [&] (Xml_node const &sub_node) {
if (!result)
return;
Dns_server::construct(
alloc, sub_node.attribute_value("ip", Ipv4_address { }),
_alloc, sub_node.attribute_value("ip", Ipv4_address { }),
[&] /* handle_success */ (Dns_server &server)
{
_dns_servers.insert_as_tail(server);
},
[&] /* handle_failure */ ()
{
_invalid(domain, "invalid DNS server entry");
result = _invalid(domain, "invalid DNS server entry");
}
);
});
if (!result)
return result;
node.with_optional_sub_node("dns-domain", [&] (Xml_node const &sub_node) {
xml_node_with_attribute(sub_node, "name", [&] (Xml_attribute const &attr) {
_dns_domain_name.set_to(attr);
@ -58,6 +63,7 @@ Dhcp_server_base::Dhcp_server_base(Xml_node const &node,
}
});
});
return result;
}
@ -67,13 +73,13 @@ Dhcp_server_base::~Dhcp_server_base()
}
void Dhcp_server_base::_invalid(Domain const &domain,
bool Dhcp_server_base::_invalid(Domain const &domain,
char const *reason)
{
if (domain.config().verbose()) {
log("[", domain, "] invalid DHCP server (", reason, ")"); }
throw Domain::Invalid();
return false;
}
@ -83,37 +89,53 @@ void Dhcp_server_base::_invalid(Domain const &domain,
bool Dhcp_server::dns_servers_empty() const
{
if (_dns_config_from.valid()) {
if (_dns_config_from_ptr)
return _resolve_dns_config_from().dns_servers_empty();
}
return _dns_servers.empty();
}
Dhcp_server::Dhcp_server(Xml_node const node,
Domain &domain,
Allocator &alloc,
Ipv4_address_prefix const &interface,
Domain_dict &domains)
Dhcp_server::Dhcp_server(Xml_node const node, Allocator &alloc)
:
Dhcp_server_base(node, domain, alloc),
_dns_config_from(_init_dns_config_from(node, domains)),
Dhcp_server_base(alloc),
_ip_lease_time (_init_ip_lease_time(node)),
_ip_first(node.attribute_value("ip_first", Ipv4_address())),
_ip_last(node.attribute_value("ip_last", Ipv4_address())),
_ip_first_raw(_ip_first.to_uint32_little_endian()),
_ip_count(_ip_last.to_uint32_little_endian() - _ip_first_raw + 1),
_ip_alloc(alloc, _ip_count)
{ }
bool Dhcp_server::finish_construction(Xml_node const node,
Domain_dict &domains,
Domain &domain,
Ipv4_address_prefix const &interface)
{
if (!Dhcp_server_base::finish_construction(node, domain))
return false;
if (_dns_servers.empty() && !_dns_domain_name.valid()) {
Domain_name dns_config_from = node.attribute_value("dns_config_from", Domain_name());
if (dns_config_from != Domain_name()) {
bool result = true;
domains.with_element(dns_config_from,
[&] (Domain &remote_domain) { _dns_config_from_ptr = &remote_domain; },
[&] { result = _invalid(domain, "invalid dns_config_from attribute"); });
if (!result)
return result;
}
}
if (!interface.prefix_matches(_ip_first)) {
_invalid(domain, "first IP does not match domain subnet"); }
return _invalid(domain, "first IP does not match domain subnet"); }
if (!interface.prefix_matches(_ip_last)) {
_invalid(domain, "last IP does not match domain subnet"); }
return _invalid(domain, "last IP does not match domain subnet"); }
if (interface.address.is_in_range(_ip_first, _ip_last)) {
_invalid(domain, "IP range contains IP address of domain"); }
return _invalid(domain, "IP range contains IP address of domain"); }
return true;
}
@ -137,8 +159,8 @@ void Dhcp_server::print(Output &output) const
_dns_domain_name.with_string([&] (Dns_domain_name::String const &str) {
Genode::print(output, "DNS domain name ", str, ", ");
});
try { Genode::print(output, "DNS config from ", _dns_config_from(), ", "); }
catch (Pointer<Domain>::Invalid) { }
with_dns_config_from([&] (Domain &domain) {
Genode::print(output, "DNS config from ", domain, ", "); });
Genode::print(output, "IP first ", _ip_first,
", last ", _ip_last,
@ -157,77 +179,36 @@ bool Dhcp_server::config_equal_to_that_of(Dhcp_server const &other) const
Ipv4_config const &Dhcp_server::_resolve_dns_config_from() const
{
return _dns_config_from().ip_config();
return _dns_config_from_ptr->ip_config();
}
Ipv4_address Dhcp_server::alloc_ip()
Dhcp_server::Alloc_ip_result Dhcp_server::alloc_ip()
{
try {
return Ipv4_address::from_uint32_little_endian(_ip_alloc.alloc() +
_ip_first_raw);
}
catch (Bit_allocator_dynamic::Out_of_indices) {
throw Alloc_ip_failed();
}
Alloc_ip_result result = Alloc_ip_error();
_ip_alloc.alloc().with_result(
[&] (addr_t ip_raw) { result = Alloc_ip_result(Ipv4_address::from_uint32_little_endian(ip_raw + _ip_first_raw)); },
[&] (auto) { });
return result;
}
void Dhcp_server::alloc_ip(Ipv4_address const &ip)
bool Dhcp_server::alloc_ip(Ipv4_address const &ip)
{
try { _ip_alloc.alloc_addr(ip.to_uint32_little_endian() - _ip_first_raw); }
catch (Bit_allocator_dynamic::Range_conflict) { throw Alloc_ip_failed(); }
catch (Bit_array_dynamic::Invalid_index_access) { throw Alloc_ip_failed(); }
return _ip_alloc.alloc_addr(ip.to_uint32_little_endian() - _ip_first_raw);
}
void Dhcp_server::free_ip(Domain const &domain,
Ipv4_address const &ip)
void Dhcp_server::free_ip(Ipv4_address const &ip)
{
/*
* The messages in the catch directives are printed as errors and
* independent from the routers verbosity configuration because the
* exceptions they indicate should never be thrown.
*/
try {
_ip_alloc.free(ip.to_uint32_little_endian() - _ip_first_raw);
}
catch (Bit_allocator_dynamic::Out_of_indices) {
error("[", domain, "] DHCP server: out of indices while freeing IP ",
ip, " (IP range: first ", _ip_first, " last ", _ip_last, ")");
}
catch (Bit_array_dynamic::Invalid_index_access) {
error("[", domain, "] DHCP server: invalid index while freeing IP ",
ip, " (IP range: first ", _ip_first, " last ", _ip_last, ")");
}
}
Pointer<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);
ASSERT(_ip_alloc.free(ip.to_uint32_little_endian() - _ip_first_raw));
}
bool Dhcp_server::has_invalid_remote_dns_cfg() const
{
if (_dns_config_from.valid()) {
return !_dns_config_from().ip_config().valid();
}
if (_dns_config_from_ptr)
return !_dns_config_from_ptr->ip_config().valid();
return false;
}
@ -269,19 +250,6 @@ bool Dhcp_allocation::_higher(Mac_address const &mac) const
}
Dhcp_allocation &Dhcp_allocation::find_by_mac(Mac_address const &mac)
{
if (mac == _mac) {
return *this; }
Dhcp_allocation *const allocation = child(_higher(mac));
if (!allocation) {
throw Dhcp_allocation_tree::No_match(); }
return allocation->find_by_mac(mac);
}
void Dhcp_allocation::print(Output &output) const
{
Genode::print(output, "MAC ", _mac, " IP ", _ip);
@ -292,17 +260,3 @@ void Dhcp_allocation::_handle_timeout(Duration)
{
_interface.dhcp_allocation_expired(*this);
}
/**************************
** Dhcp_allocation_tree **
**************************/
Dhcp_allocation &
Dhcp_allocation_tree::find_by_mac(Mac_address const &mac) const
{
if (!_tree.first()) {
throw No_match(); }
return _tree.first()->find_by_mac(mac);
}

View File

@ -17,7 +17,6 @@
/* local includes */
#include <bit_allocator_dynamic.h>
#include <list.h>
#include <pointer.h>
#include <dns.h>
#include <ipv4_config.h>
#include <cached_timer.h>
@ -52,14 +51,15 @@ class Net::Dhcp_server_base
Dns_server_list _dns_servers { };
Dns_domain_name _dns_domain_name { _alloc };
void _invalid(Domain const &domain,
char const *reason);
[[nodiscard]] bool _invalid(Domain const &domain,
char const *reason);
public:
Dhcp_server_base(Genode::Xml_node const &node,
Domain const &domain,
Genode::Allocator &alloc);
Dhcp_server_base(Genode::Allocator &alloc);
[[nodiscard]] bool finish_construction(Genode::Xml_node const &node,
Domain const &domain);
~Dhcp_server_base();
};
@ -70,7 +70,7 @@ class Net::Dhcp_server : private Genode::Noncopyable,
{
private:
Pointer<Domain> const _dns_config_from;
Domain *_dns_config_from_ptr { };
Genode::Microseconds const _ip_lease_time;
Ipv4_address const _ip_first;
Ipv4_address const _ip_last;
@ -80,37 +80,43 @@ class Net::Dhcp_server : private Genode::Noncopyable,
Genode::Microseconds _init_ip_lease_time(Genode::Xml_node const node);
Pointer<Domain> _init_dns_config_from(Genode::Xml_node const node,
Domain_dict &domains);
Ipv4_config const &_resolve_dns_config_from() const;
/*
* Noncopyable
*/
Dhcp_server(Dhcp_server const &);
Dhcp_server &operator = (Dhcp_server const &);
public:
enum { DEFAULT_IP_LEASE_TIME_SEC = 3600 };
struct Alloc_ip_failed : Genode::Exception { };
struct Invalid : Genode::Exception { };
struct Invalid : Genode::Exception { };
Dhcp_server(Genode::Xml_node const node,
Domain &domain,
Genode::Allocator &alloc,
Ipv4_address_prefix const &interface,
Domain_dict &domains);
Dhcp_server(Genode::Xml_node const node,
Genode::Allocator &alloc);
Ipv4_address alloc_ip();
[[nodiscard]] bool finish_construction(Genode::Xml_node const node,
Domain_dict &domains,
Domain &domain,
Ipv4_address_prefix const &interface);
void alloc_ip(Ipv4_address const &ip);
struct Alloc_ip_error { };
using Alloc_ip_result = Genode::Attempt<Ipv4_address, Alloc_ip_error>;
void free_ip(Domain const &domain,
Ipv4_address const &ip);
[[nodiscard]] Alloc_ip_result alloc_ip();
[[nodiscard]] bool alloc_ip(Ipv4_address const &ip);
void free_ip(Ipv4_address const &ip);
bool has_invalid_remote_dns_cfg() const;
template <typename FUNC>
void for_each_dns_server_ip(FUNC && functor) const
{
if (_dns_config_from.valid()) {
if (_dns_config_from_ptr) {
_resolve_dns_config_from().for_each_dns_server(
[&] (Dns_server const &dns_server) {
@ -129,7 +135,7 @@ class Net::Dhcp_server : private Genode::Noncopyable,
Dns_domain_name const &dns_domain_name() const
{
if (_dns_config_from.valid()) {
if (_dns_config_from_ptr) {
return _resolve_dns_config_from().dns_domain_name();
}
return _dns_domain_name;
@ -137,6 +143,12 @@ class Net::Dhcp_server : private Genode::Noncopyable,
bool config_equal_to_that_of(Dhcp_server const &dhcp_server) const;
void with_dns_config_from(auto const &fn) const
{
if (_dns_config_from_ptr)
fn(*_dns_config_from_ptr);
}
/*********
** log **
@ -149,7 +161,6 @@ class Net::Dhcp_server : private Genode::Noncopyable,
** Accessors **
***************/
Domain &dns_config_from() { return _dns_config_from(); }
Genode::Microseconds ip_lease_time() const { return _ip_lease_time; }
};
@ -179,7 +190,18 @@ class Net::Dhcp_allocation : public Genode::Avl_node<Dhcp_allocation>,
~Dhcp_allocation();
Dhcp_allocation &find_by_mac(Mac_address const &mac);
void find_by_mac(Mac_address const &mac, auto const &match_fn, auto const &no_match_fn)
{
if (mac == _mac) {
match_fn(*this);
return;
}
Dhcp_allocation *allocation_ptr = child(_higher(mac));
if (allocation_ptr)
allocation_ptr->find_by_mac(mac, match_fn, no_match_fn);
else
no_match_fn();
}
void lifetime(Genode::Microseconds lifetime);
@ -218,9 +240,13 @@ struct Net::Dhcp_allocation_tree
public:
struct No_match : Genode::Exception { };
Dhcp_allocation &find_by_mac(Mac_address const &mac) const;
void find_by_mac(Mac_address const &mac, auto const &match_fn, auto const &no_match_fn) const
{
if (_tree.first())
_tree.first()->find_by_mac(mac, match_fn, no_match_fn);
else
no_match_fn();
}
void insert(Dhcp_allocation &dhcp_alloc)
{

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:
struct Invalid : Genode::Exception { };
Direct_rule_base(Genode::Xml_node const node);
Direct_rule_base(Ipv4_address_prefix const dst) : _dst(dst) { }
/*********
** log **
*********/
void print(Genode::Output &output) const;
void print(Genode::Output &output) const { Genode::print(output, "dst ", _dst); }
/***************
@ -64,7 +62,7 @@ template <typename T>
struct Net::Direct_rule : Direct_rule_base,
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()) {
name.with_string([&] (String const &string) {
if (_string.valid()) {
_string() = string;
if (_string_ptr) {
*_string_ptr = string;
} else {
_string = *new (_alloc) String { string };
_string_ptr = new (_alloc) String { string };
}
});
} else {
@ -63,10 +63,10 @@ void Dns_domain_name::set_to(Xml_attribute const &name_attr)
{
name_attr.with_raw_value([&] (char const *base, size_t size) {
if (size < STRING_CAPACITY) {
if (_string.valid()) {
_string() = Cstring { base, size };
if (_string_ptr) {
*_string_ptr = Cstring { base, size };
} else {
_string = *new (_alloc) String { Cstring { base, size } };
_string_ptr = new (_alloc) String { Cstring { base, size } };
}
} else {
set_invalid();
@ -79,10 +79,10 @@ void Dns_domain_name::set_to(Dhcp_packet::Domain_name const &name_option)
{
name_option.with_string([&] (char const *base, size_t size) {
if (size < STRING_CAPACITY) {
if (_string.valid()) {
_string() = Cstring { base, size };
if (_string_ptr) {
*_string_ptr = Cstring { base, size };
} else {
_string = *new (_alloc) String { Cstring { base, size } };
_string_ptr = new (_alloc) String { Cstring { base, size } };
}
} else {
set_invalid();
@ -93,22 +93,21 @@ void Dns_domain_name::set_to(Dhcp_packet::Domain_name const &name_option)
void Dns_domain_name::set_invalid()
{
if (_string.valid()) {
_alloc.free(&_string(), sizeof(String));
_string = { };
if (_string_ptr) {
_alloc.free(_string_ptr, sizeof(String));
_string_ptr = nullptr;
}
}
bool Dns_domain_name::equal_to(Dns_domain_name const &other) const
{
if (_string.valid()) {
if (other._string.valid()) {
return _string() == other._string();
}
if (_string_ptr) {
if (other._string_ptr)
return *_string_ptr == *other._string_ptr;
return false;
}
return !other._string.valid();
return !other._string_ptr;
}

View File

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

View File

@ -41,10 +41,9 @@ void Domain::_log_ip_config() const
bool Domain::ready() const
{
if (_dhcp_server.valid()) {
if (_dhcp_server().has_invalid_remote_dns_cfg()) {
if (_dhcp_server_ptr) {
if (_dhcp_server_ptr->has_invalid_remote_dns_cfg())
return false;
}
}
return true;
}
@ -61,8 +60,7 @@ void Domain::update_ready_state()
void Domain::_prepare_reconstructing_ip_config()
{
if (!_ip_config_dynamic) {
throw Ip_config_static(); }
ASSERT(_ip_config_dynamic);
/* discard old IP config if any */
if (ip_config().valid()) {
@ -124,8 +122,7 @@ void Domain::_finish_reconstructing_ip_config()
});
}
/* force report if configured */
try { _config.report().handle_config(); }
catch (Pointer<Report>::Invalid) { }
_config.with_report([&] (Report &r) { r.handle_config(); });
}
@ -168,47 +165,75 @@ void Domain::try_reuse_ip_config(Domain const &domain)
}
void Domain::_read_forward_rules(Cstring const &protocol,
bool Domain::_read_forward_rules(Cstring const &protocol,
Domain_dict &domains,
Xml_node const node,
char const *type,
Forward_rule_tree &rules)
{
bool result = true;
node.for_each_sub_node(type, [&] (Xml_node const node) {
try {
Forward_rule &rule = *new (_alloc) Forward_rule(domains, node);
rules.insert(&rule);
if (_config.verbose()) {
log("[", *this, "] ", protocol, " forward rule: ", rule); }
if (!result)
return;
Port port = node.attribute_value("port", Port(0));
if (port == Port(0) || dynamic_port(port)) {
result = _invalid("invalid forward rule");
return;
}
catch (Forward_rule::Invalid) { _invalid("invalid forward rule"); }
Ipv4_address to_ip = node.attribute_value("to", Ipv4_address());
if (!to_ip.valid()) {
result = _invalid("invalid forward rule");
return;
}
domains.find_by_domain_attr(node,
[&] (Domain &domain) {
Forward_rule &rule = *new (_alloc)
Forward_rule(port, to_ip, node.attribute_value("to_port", Port(0)), domain);
rules.insert(&rule);
if (_config.verbose())
log("[", *this, "] ", protocol, " forward rule: ", rule); },
[&] { result = _invalid("invalid forward rule"); });
});
return result;
}
void Domain::_invalid(char const *reason) const
bool Domain::_invalid(char const *reason) const
{
if (_config.verbose()) {
log("[", *this, "] invalid domain (", reason, ")"); }
throw Invalid();
return false;
}
void Domain::_read_transport_rules(Cstring const &protocol,
bool Domain::_read_transport_rules(Cstring const &protocol,
Domain_dict &domains,
Xml_node const node,
char const *type,
Transport_rule_list &rules)
{
bool result = true;
node.for_each_sub_node(type, [&] (Xml_node const node) {
try {
rules.insert(*new (_alloc)
Transport_rule(domains, node, _alloc, protocol, _config, *this));
if (!result)
return;
Ipv4_address_prefix dst = node.attribute_value("dst", Ipv4_address_prefix());
if (!dst.valid()) {
result = _invalid("invalid transport rule");
return;
}
catch (Transport_rule::Invalid) { _invalid("invalid transport rule"); }
catch (Permit_any_rule::Invalid) { _invalid("invalid permit-any rule"); }
catch (Permit_single_rule::Invalid) { _invalid("invalid permit rule"); }
Transport_rule &rule = *new (_alloc) Transport_rule(dst, _alloc);
if (!rule.finish_construction(domains, node, protocol, _config, *this)) {
destroy(_alloc, &rule);
result = _invalid("invalid transport rule");
return;
}
rules.insert(rule);
if (_config.verbose())
log("[", *this, "] ", protocol, " rule: ", rule);
});
return result;
}
@ -245,12 +270,18 @@ Domain::Domain(Configuration &config,
String<160>()).string() }
{
_log_ip_config();
}
if (Domain::name() == Domain_name()) {
_invalid("missing name attribute"); }
bool Domain::finish_construction() const
{
if (Domain::name() == Domain_name())
return _invalid("missing name attribute");
if (_config.verbose_domain_state()) {
log("[", *this, "] NIC sessions: ", _interface_cnt); }
return true;
}
@ -260,7 +291,7 @@ Link_side_tree &Domain::links(L3_protocol const protocol)
case L3_protocol::TCP: return _tcp_links;
case L3_protocol::UDP: return _udp_links;
case L3_protocol::ICMP: return _icmp_links;
default: throw Interface::Bad_transport_protocol(); }
default: ASSERT_NEVER_REACHED; }
}
@ -271,96 +302,84 @@ Domain::~Domain()
}
Dhcp_server &Domain::dhcp_server()
{
Dhcp_server &dhcp_server = _dhcp_server();
if (dhcp_server.has_invalid_remote_dns_cfg()) {
throw Pointer<Dhcp_server>::Invalid();
}
return dhcp_server;
}
void Domain::init(Domain_dict &domains)
bool Domain::init(Domain_dict &domains)
{
/* read DHCP server configuration */
try {
Xml_node const dhcp_server_node = _node.sub_node("dhcp-server");
bool result = true;
_node.with_optional_sub_node("dhcp-server", [&] (Xml_node const &dhcp_server_node) {
if (_ip_config_dynamic) {
_invalid("DHCP server and client at once"); }
try {
Dhcp_server &dhcp_server = *new (_alloc)
Dhcp_server(dhcp_server_node, *this, _alloc,
ip_config().interface(), domains);
try {
dhcp_server.
dns_config_from().ip_config_dependents().insert(this);
}
catch (Pointer<Domain>::Invalid) { }
_dhcp_server = dhcp_server;
if (_config.verbose()) {
log("[", *this, "] DHCP server: ", _dhcp_server()); }
result = _invalid("DHCP server and client at once");
return;
}
catch (Bit_allocator_dynamic::Out_of_indices) {
/*
* This message is printed independent from the routers
* verbosity configuration in order to track down an exception
* of type Bit_allocator_dynamic::Out_of_indices that was
* previously not caught. We have observed this exception once,
* but without a specific use pattern that would
* enable for a systematic reproduction of the issue.
* The uncaught exception was observed in a 21.03 Sculpt OS
* with a manually configured router, re-configuration involved.
*/
log("[", *this, "] DHCP server: failed to initialize ",
"(IP range: first ",
dhcp_server_node.attribute_value("ip_first", Ipv4_address()),
" last ",
dhcp_server_node.attribute_value("ip_last", Ipv4_address()),
")");
throw Dhcp_server::Invalid { };
Dhcp_server &dhcp_server = *new (_alloc) Dhcp_server(dhcp_server_node, _alloc);
if (!dhcp_server.finish_construction(dhcp_server_node, domains, *this, ip_config().interface())) {
result = _invalid("invalid DHCP server");
return;
}
}
catch (Xml_node::Nonexistent_sub_node) { }
catch (Dhcp_server::Invalid) { _invalid("invalid DHCP server"); }
dhcp_server.with_dns_config_from([&] (Domain &domain) {
domain.ip_config_dependents().insert(this); });
/* read forward rules */
_read_forward_rules(tcp_name(), domains, _node, "tcp-forward",
_tcp_forward_rules);
_read_forward_rules(udp_name(), domains, _node, "udp-forward",
_udp_forward_rules);
_dhcp_server_ptr = &dhcp_server;
if (_config.verbose()) {
log("[", *this, "] DHCP server: ", dhcp_server); }
});
if (!result)
return result;
/* read UDP and TCP rules */
_read_transport_rules(tcp_name(), domains, _node, "tcp", _tcp_rules);
_read_transport_rules(udp_name(), domains, _node, "udp", _udp_rules);
/* read forward and transport rules */
if (!_read_forward_rules(tcp_name(), domains, _node, "tcp-forward", _tcp_forward_rules) ||
!_read_forward_rules(udp_name(), domains, _node, "udp-forward", _udp_forward_rules) ||
!_read_transport_rules(tcp_name(), domains, _node, "tcp", _tcp_rules) ||
!_read_transport_rules(udp_name(), domains, _node, "udp", _udp_rules))
return false;
/* read NAT rules */
_node.for_each_sub_node("nat", [&] (Xml_node const node) {
try {
Nat_rule &rule = *new (_alloc)
Nat_rule(domains, _tcp_port_alloc, _udp_port_alloc,
_icmp_port_alloc, node, _config.verbose());
_nat_rules.insert(&rule);
if (_config.verbose()) {
log("[", *this, "] NAT rule: ", rule); }
}
catch (Nat_rule::Invalid) { _invalid("invalid NAT rule"); }
if (!result)
return;
domains.find_by_domain_attr(node,
[&] (Domain &domain) {
Nat_rule &rule = *new (_alloc)
Nat_rule(domain, _tcp_port_alloc, _udp_port_alloc,
_icmp_port_alloc, node, _config.verbose());
_nat_rules.insert(&rule);
if (_config.verbose())
log("[", *this, "] NAT rule: ", rule); },
[&] { result = _invalid("invalid NAT rule"); });
});
if (!result)
return result;
/* read ICMP rules */
_node.for_each_sub_node("icmp", [&] (Xml_node const node) {
try { _icmp_rules.insert(*new (_alloc) Ip_rule(domains, node)); }
catch (Ip_rule::Invalid) { _invalid("invalid ICMP rule"); }
if (!result)
return;
Ipv4_address_prefix dst = node.attribute_value("dst", Ipv4_address_prefix());
if (!dst.valid()) {
result = _invalid("invalid ICMP rule");
return;
}
domains.find_by_domain_attr(node,
[&] (Domain &domain) { _icmp_rules.insert(*new (_alloc) Ip_rule(dst, domain)); },
[&] { result = _invalid("invalid ICMP rule"); });
});
/* read IP rules */
_node.for_each_sub_node("ip", [&] (Xml_node const node) {
try { _ip_rules.insert(*new (_alloc) Ip_rule(domains, node)); }
catch (Ip_rule::Invalid) { _invalid("invalid IP rule"); }
if (!result)
return;
Ipv4_address_prefix dst = node.attribute_value("dst", Ipv4_address_prefix());
if (!dst.valid()) {
result = _invalid("invalid IP rule");
return;
}
domains.find_by_domain_attr(node,
[&] (Domain &domain) { _ip_rules.insert(*new (_alloc) Ip_rule(dst, domain)); },
[&] { result = _invalid("invalid IP rule"); });
});
return result;
}
@ -373,22 +392,11 @@ void Domain::deinit()
_tcp_rules.destroy_each(_alloc);
_udp_forward_rules.destroy_each(_alloc);
_tcp_forward_rules.destroy_each(_alloc);
try {
Dhcp_server &dhcp_server = _dhcp_server();
_dhcp_server = Pointer<Dhcp_server>();
try { dhcp_server.dns_config_from().ip_config_dependents().remove(this); }
catch (Pointer<Domain>::Invalid) { }
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();
with_dhcp_server([&] (Dhcp_server &dhcp_server) {
_dhcp_server_ptr = nullptr;
dhcp_server.with_dns_config_from([&] (Domain &domain) {
domain.ip_config_dependents().remove(this); });
destroy(_alloc, &dhcp_server); });
}
@ -424,54 +432,53 @@ void Domain::interface_updates_domain_object(Interface &interface)
}
void Domain::report(Xml_generator &xml)
bool Domain::report_empty(Report const &report_cfg) const
{
xml.node("domain", [&] () {
bool empty = true;
xml.attribute("name", name());
if (_config.report().bytes()) {
xml.attribute("rx_bytes", _tx_bytes);
xml.attribute("tx_bytes", _rx_bytes);
empty = false;
}
if (_config.report().config()) {
xml.attribute("ipv4", String<19>(ip_config().interface()));
xml.attribute("gw", String<16>(ip_config().gateway()));
ip_config().for_each_dns_server([&] (Dns_server const &dns_server) {
xml.node("dns", [&] () {
xml.attribute("ip", String<16>(dns_server.ip()));
});
});
ip_config().dns_domain_name().with_string(
[&] (Dns_domain_name::String const &str)
{
xml.node("dns-domain", [&] () {
xml.attribute("name", str);
});
});
empty = false;
}
if (_config.report().stats()) {
try { xml.node("tcp-links", [&] () { _tcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { }
try { xml.node("udp-links", [&] () { _udp_stats.report(xml); }); empty = false; } catch (Report::Empty) { }
try { xml.node("icmp-links", [&] () { _icmp_stats.report(xml); }); empty = false; } catch (Report::Empty) { }
try { xml.node("arp-waiters", [&] () { _arp_stats.report(xml); }); empty = false; } catch (Report::Empty) { }
try { xml.node("dhcp-allocations", [&] () { _dhcp_stats.report(xml); }); empty = false; } catch (Report::Empty) { }
}
if (_config.report().dropped_fragm_ipv4() && _dropped_fragm_ipv4) {
xml.node("dropped-fragm-ipv4", [&] () {
xml.attribute("value", _dropped_fragm_ipv4);
});
empty = false;
}
_interfaces.for_each([&] (Interface &interface) {
try {
interface.report(xml);
empty = false;
} catch (Report::Empty) { }
});
if (empty) {
throw Report::Empty(); }
bool bytes = report_cfg.bytes();
bool cfg = report_cfg.config();
bool stats = report_cfg.stats() && (
!_tcp_stats.report_empty() || !_udp_stats.report_empty() ||
!_icmp_stats.report_empty() || !_arp_stats.report_empty() || _dhcp_stats.report_empty());
bool fragm_ip = report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4;
bool interfaces = false;
_interfaces.for_each([&] (Interface const &interface) {
if (!interface.report_empty(report_cfg))
interfaces = true; });
return !bytes && !cfg && !stats && !fragm_ip && !interfaces;
}
void Domain::report(Xml_generator &xml, Report const &report_cfg) const
{
xml.attribute("name", name());
if (report_cfg.bytes()) {
xml.attribute("rx_bytes", _tx_bytes);
xml.attribute("tx_bytes", _rx_bytes);
}
if (report_cfg.config()) {
xml.attribute("ipv4", String<19>(ip_config().interface()));
xml.attribute("gw", String<16>(ip_config().gateway()));
ip_config().for_each_dns_server([&] (Dns_server const &dns_server) {
xml.node("dns", [&] () {
xml.attribute("ip", String<16>(dns_server.ip())); }); });
ip_config().dns_domain_name().with_string([&] (Dns_domain_name::String const &str) {
xml.node("dns-domain", [&] () {
xml.attribute("name", str); }); });
}
if (report_cfg.stats()) {
if (!_tcp_stats.report_empty()) xml.node("tcp-links", [&] { _tcp_stats.report(xml); });
if (!_udp_stats.report_empty()) xml.node("udp-links", [&] { _udp_stats.report(xml); });
if (!_icmp_stats.report_empty()) xml.node("icmp-links", [&] { _icmp_stats.report(xml); });
if (!_arp_stats.report_empty()) xml.node("arp-waiters", [&] { _arp_stats.report(xml); });
if (!_dhcp_stats.report_empty()) xml.node("dhcp-allocations", [&] { _dhcp_stats.report(xml); });
}
if (report_cfg.dropped_fragm_ipv4() && _dropped_fragm_ipv4)
xml.node("dropped-fragm-ipv4", [&] () {
xml.attribute("value", _dropped_fragm_ipv4); });
_interfaces.for_each([&] (Interface const &interface) {
if (!interface.report_empty(report_cfg))
xml.node("interface", [&] { interface.report(xml, report_cfg); });
});
}
@ -495,15 +502,14 @@ Domain_link_stats::dissolve_interface(Interface_link_stats const &stats)
}
void Domain_link_stats::report(Genode::Xml_generator &xml)
bool Domain_link_stats::report_empty() const { return !refused_for_ram && !refused_for_ports && !destroyed; }
void Domain_link_stats::report(Genode::Xml_generator &xml) const
{
bool empty = true;
if (refused_for_ram) { xml.node("refused_for_ram", [&] () { xml.attribute("value", refused_for_ram); }); empty = false; }
if (refused_for_ports) { xml.node("refused_for_ports", [&] () { xml.attribute("value", refused_for_ports); }); empty = false; }
if (destroyed) { xml.node("destroyed", [&] () { xml.attribute("value", destroyed); }); empty = false; }
if (empty) { throw Report::Empty(); }
if (refused_for_ram) xml.node("refused_for_ram", [&] { xml.attribute("value", refused_for_ram); });
if (refused_for_ports) xml.node("refused_for_ports", [&] { xml.attribute("value", refused_for_ports); });
if (destroyed) xml.node("destroyed", [&] { xml.attribute("value", destroyed); });
}
@ -518,9 +524,10 @@ Domain_object_stats::dissolve_interface(Interface_object_stats const &stats)
}
void Domain_object_stats::report(Genode::Xml_generator &xml)
bool Domain_object_stats::report_empty() const { return !destroyed; }
void Domain_object_stats::report(Genode::Xml_generator &xml) const
{
bool empty = true;
if (destroyed) { xml.node("destroyed", [&] () { xml.attribute("value", destroyed); }); empty = false; }
if (empty) { throw Report::Empty(); }
if (destroyed) xml.node("destroyed", [&] { xml.attribute("value", destroyed); });
}

View File

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

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

View File

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

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

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

View File

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

View File

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

View File

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

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 &udp_port_alloc,
Port_allocator &icmp_port_alloc,
Xml_node const node,
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 },
_udp_port_alloc { udp_port_alloc, node.attribute_value("udp-ports", 0U), verbose },
_icmp_port_alloc { icmp_port_alloc, node.attribute_value("icmp-ids", 0U), verbose }
@ -61,5 +61,5 @@ Port_allocator_guard &Nat_rule::port_alloc(L3_protocol const prot)
case L3_protocol::TCP: return _tcp_port_alloc;
case L3_protocol::UDP: return _udp_port_alloc;
case L3_protocol::ICMP: return _icmp_port_alloc;
default: throw Interface::Bad_transport_protocol(); }
default: ASSERT_NEVER_REACHED; }
}

View File

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

View File

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

View File

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

View File

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

View File

@ -117,6 +117,7 @@ class Net::Nic_session_component : private Nic_session_component_base,
Domain_name determine_domain_name() const override;
void handle_config(Configuration const &config) override { _config = config; }
Genode::Session_label const &label() const override { return _label; }
bool report_empty() const override { return _session_env.report_empty(); };
void report(Genode::Xml_generator &xml) const override { _session_env.report(xml); };
void handle_domain_ready_state(bool state) override;
bool interface_link_state() const override;
@ -167,13 +168,13 @@ class Net::Nic_session_root
enum { MAC_ALLOC_BASE = 0x02 };
Genode::Env &_env;
Cached_timer &_timer;
Mac_allocator _mac_alloc;
Mac_address const _router_mac;
Reference<Configuration> _config;
Quota &_shared_quota;
Interface_list &_interfaces;
Genode::Env &_env;
Cached_timer &_timer;
Mac_allocator _mac_alloc;
Genode::Constructible<Mac_address> _router_mac { };
Reference<Configuration> _config;
Quota &_shared_quota;
Interface_list &_interfaces;
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_rule { domains.deprecated_find_by_domain_attr<Invalid>(node) }
{ }
Permit_any_rule::Permit_any_rule(Domain &domain) : Permit_rule { domain } { }
/************************
@ -55,12 +52,8 @@ void Permit_single_rule::print(Output &output) const
}
Permit_single_rule::Permit_single_rule(Domain_dict &domains,
Xml_node const node)
Permit_single_rule::Permit_single_rule(Port port, Domain &domain)
:
Permit_rule { domains.deprecated_find_by_domain_attr<Invalid>(node) },
_port { node.attribute_value("port", Port(0)) }
{
if (_port == Port(0) || dynamic_port(_port)) {
throw Invalid(); }
}
Permit_rule { domain },
_port { port }
{ }

View File

@ -16,10 +16,10 @@
/* local includes */
#include <avl_tree.h>
#include <port_allocator.h>
/* Genode includes */
#include <util/avl_tree.h>
#include <net/port.h>
namespace Genode {
@ -72,9 +72,7 @@ struct Net::Permit_any_rule : Permit_rule
{
public:
struct Invalid : Genode::Exception { };
Permit_any_rule(Domain_dict &domains, Genode::Xml_node const node);
Permit_any_rule(Domain &domain);
/*********
@ -99,10 +97,7 @@ class Net::Permit_single_rule : public Permit_rule,
public:
struct Invalid : Genode::Exception { };
Permit_single_rule(Domain_dict &domains,
Genode::Xml_node const node);
Permit_single_rule(Port port, Domain &domain);
template <typename HANDLE_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 Net::Port_allocator::alloc()
Net::Port_allocator::Alloc_result Net::Port_allocator::alloc()
{
for (unsigned nr_of_trials { 0 };
nr_of_trials < NR_OF_PORTS;
@ -45,19 +45,18 @@ Port Net::Port_allocator::alloc()
}
catch (Bit_allocator<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 {
_bit_allocator.alloc_addr(port.value - FIRST_PORT);
return true;
}
catch (Bit_allocator<NR_OF_PORTS>::Range_conflict) {
throw Allocation_conflict();
}
catch (Bit_allocator<NR_OF_PORTS>::Range_conflict) { }
return false;
}
@ -71,29 +70,30 @@ void Port_allocator::free(Port const port)
** Port_allocator_guard **
**************************/
Port Port_allocator_guard::alloc()
Port_allocator_guard::Alloc_result Port_allocator_guard::alloc()
{
if (_used_nr_of_ports == _max_nr_of_ports) {
throw Out_of_indices();
}
try {
Port const port = _port_alloc.alloc();
_used_nr_of_ports++;
return port;
}
catch (Port_allocator::Out_of_indices) {
throw Out_of_indices();
return Alloc_error();
}
Alloc_result const result = _port_alloc.alloc();
if (result.failed())
return result;
_used_nr_of_ports++;
return result;
}
void Port_allocator_guard::alloc(Port const port)
bool Port_allocator_guard::alloc(Port const port)
{
if (_used_nr_of_ports == _max_nr_of_ports) {
throw Out_of_indices();
}
_port_alloc.alloc(port);
if (_used_nr_of_ports == _max_nr_of_ports)
return false;
if (!_port_alloc.alloc(port))
return false;
_used_nr_of_ports++;
return true;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -62,17 +62,13 @@ Net::Uplink_session_component::Interface_policy::determine_domain_name() const
try {
Session_policy policy(_label, _config().node());
domain_name = policy.attribute_value("domain", Domain_name());
if (domain_name == Domain_name() && _config().verbose())
log("[?] no domain attribute in policy for downlink label \"", _label, "\"");
}
catch (Session_policy::No_policy_defined) {
if (_config().verbose()) {
log("[?] no policy for downlink label \"", _label, "\""); }
}
catch (Xml_node::Nonexistent_attribute) {
if (_config().verbose()) {
log("[?] no domain attribute in policy for downlink label \"",
_label, "\"");
}
}
return domain_name;
}

View File

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