mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-18 13:26:27 +00:00
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:
parent
0faec6afaa
commit
ac42ade48c
@ -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 ¬_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 **
|
||||
|
@ -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) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
35
repos/os/src/server/nic_router/assertion.h
Normal file
35
repos/os/src/server/nic_router/assertion.h
Normal 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_ */
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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>();
|
||||
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
@ -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) { }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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); });
|
||||
}
|
||||
|
@ -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; }
|
||||
|
@ -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 }
|
||||
{ }
|
||||
|
@ -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
@ -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 ð,
|
||||
Dhcp_packet &dhcp,
|
||||
Dhcp_server &dhcp_srv,
|
||||
Domain &local_domain);
|
||||
[[nodiscard]] Packet_result _new_dhcp_allocation(Ethernet_frame ð,
|
||||
Dhcp_packet &dhcp,
|
||||
Dhcp_server &dhcp_srv,
|
||||
Domain &local_domain);
|
||||
|
||||
void _send_dhcp_reply(Dhcp_server const &dhcp_srv,
|
||||
Mac_address const ð_dst,
|
||||
@ -204,84 +212,79 @@ class Net::Interface : private Interface_list::Element
|
||||
Genode::size_t icmp_sz,
|
||||
Size_guard &size_guard);
|
||||
|
||||
Forward_rule_tree &_forward_rules(Domain &local_domain,
|
||||
L3_protocol const prot) const;
|
||||
|
||||
Transport_rule_list &_transport_rules(Domain &local_domain,
|
||||
L3_protocol const prot) const;
|
||||
|
||||
void _handle_arp(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Domain &local_domain);
|
||||
[[nodiscard]] Packet_result _handle_arp(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Domain &local_domain);
|
||||
|
||||
void _handle_arp_reply(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Arp_packet &arp,
|
||||
Domain &local_domain);
|
||||
|
||||
void _handle_arp_request(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Arp_packet &arp,
|
||||
Domain &local_domain);
|
||||
[[nodiscard]] Packet_result _handle_arp_request(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Arp_packet &arp,
|
||||
Domain &local_domain);
|
||||
|
||||
void _send_arp_reply(Ethernet_frame &request_eth,
|
||||
Arp_packet &request_arp);
|
||||
|
||||
void _handle_dhcp_request(Ethernet_frame ð,
|
||||
Dhcp_packet &dhcp,
|
||||
Domain &local_domain,
|
||||
Ipv4_address_prefix const &local_intf);
|
||||
[[nodiscard]] Packet_result _handle_dhcp_request(Ethernet_frame ð,
|
||||
Dhcp_server &dhcp_srv,
|
||||
Dhcp_packet &dhcp,
|
||||
Domain &local_domain,
|
||||
Ipv4_address_prefix const &local_intf);
|
||||
|
||||
void _handle_ip(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain);
|
||||
[[nodiscard]] Packet_result _handle_ip(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain);
|
||||
|
||||
void _handle_icmp_query(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
Packet_descriptor const &pkt,
|
||||
L3_protocol prot,
|
||||
void *prot_base,
|
||||
Genode::size_t prot_size,
|
||||
Domain &local_domain);
|
||||
[[nodiscard]] Packet_result _handle_icmp_query(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
Packet_descriptor const &pkt,
|
||||
L3_protocol prot,
|
||||
void *prot_base,
|
||||
Genode::size_t prot_size,
|
||||
Domain &local_domain);
|
||||
|
||||
void _handle_icmp_error(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain,
|
||||
Icmp_packet &icmp,
|
||||
Genode::size_t icmp_sz);
|
||||
[[nodiscard]] Packet_result _handle_icmp_error(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain,
|
||||
Icmp_packet &icmp,
|
||||
Genode::size_t icmp_sz);
|
||||
|
||||
void _handle_icmp(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
Packet_descriptor const &pkt,
|
||||
L3_protocol prot,
|
||||
void *prot_base,
|
||||
Genode::size_t prot_size,
|
||||
Domain &local_domain,
|
||||
Ipv4_address_prefix const &local_intf);
|
||||
[[nodiscard]] Packet_result _handle_icmp(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
Packet_descriptor const &pkt,
|
||||
L3_protocol prot,
|
||||
void *prot_base,
|
||||
Genode::size_t prot_size,
|
||||
Domain &local_domain,
|
||||
Ipv4_address_prefix const &local_intf);
|
||||
|
||||
void _adapt_eth(Ethernet_frame ð,
|
||||
Ipv4_address const &dst_ip,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &remote_domain);
|
||||
[[nodiscard]] Packet_result _adapt_eth(Ethernet_frame ð,
|
||||
Ipv4_address const &dst_ip,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &remote_domain);
|
||||
|
||||
void _nat_link_and_pass(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
L3_protocol const prot,
|
||||
void *const prot_base,
|
||||
Genode::size_t const prot_size,
|
||||
Link_side_id const &local_id,
|
||||
Domain &local_domain,
|
||||
Domain &remote_domain);
|
||||
[[nodiscard]] Packet_result _nat_link_and_pass(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Ipv4_packet &ip,
|
||||
Internet_checksum_diff &ip_icd,
|
||||
L3_protocol const prot,
|
||||
void *const prot_base,
|
||||
Genode::size_t const prot_size,
|
||||
Link_side_id const &local_id,
|
||||
Domain &local_domain,
|
||||
Domain &remote_domain);
|
||||
|
||||
void _broadcast_arp_request(Ipv4_address const &src_ip,
|
||||
Ipv4_address const &dst_ip);
|
||||
@ -301,19 +304,20 @@ class Net::Interface : private Interface_list::Element
|
||||
|
||||
void _handle_pkt();
|
||||
|
||||
void _continue_handle_eth(Domain const &domain,
|
||||
Packet_descriptor const &pkt);
|
||||
void _continue_handle_eth(Packet_descriptor const &pkt);
|
||||
|
||||
Ipv4_address const &_router_ip() const;
|
||||
|
||||
void _handle_eth(void *const eth_base,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt);
|
||||
void _drop_packet(Packet_descriptor const &pkt, char const *reason);
|
||||
|
||||
void _handle_eth(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain);
|
||||
[[nodiscard]] Packet_result _handle_eth(void *const eth_base,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt);
|
||||
|
||||
[[nodiscard]] Packet_result _handle_eth(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain);
|
||||
|
||||
void _ack_packet(Packet_descriptor const &pkt);
|
||||
|
||||
@ -369,20 +373,6 @@ class Net::Interface : private Interface_list::Element
|
||||
|
||||
public:
|
||||
|
||||
struct Free_resources_and_retry_handle_eth : Genode::Exception { L3_protocol prot; Free_resources_and_retry_handle_eth(L3_protocol prot = (L3_protocol)0) : prot(prot) { } };
|
||||
struct Bad_send_dhcp_args : Genode::Exception { };
|
||||
struct Bad_transport_protocol : Genode::Exception { };
|
||||
struct Bad_network_protocol : Genode::Exception { };
|
||||
struct Packet_postponed : Genode::Exception { };
|
||||
struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { };
|
||||
|
||||
struct Drop_packet : Genode::Exception
|
||||
{
|
||||
char const *reason;
|
||||
|
||||
Drop_packet(char const *reason) : reason(reason) { }
|
||||
};
|
||||
|
||||
Interface(Genode::Entrypoint &ep,
|
||||
Cached_timer &timer,
|
||||
Mac_address const router_mac,
|
||||
@ -454,19 +444,30 @@ class Net::Interface : private Interface_list::Element
|
||||
|
||||
void handle_interface_link_state();
|
||||
|
||||
void report(Genode::Xml_generator &xml);
|
||||
bool report_empty(Report const &report_cfg) const;
|
||||
|
||||
void report(Genode::Xml_generator &xml, Report const &report_cfg) const;
|
||||
|
||||
void handle_domain_ready_state(bool state);
|
||||
|
||||
void destroy_link(Link &link);
|
||||
|
||||
void with_domain(auto const &domain_fn, auto const &no_domain_fn)
|
||||
{
|
||||
if (_domain_ptr)
|
||||
domain_fn(*_domain_ptr);
|
||||
else
|
||||
no_domain_fn();
|
||||
}
|
||||
|
||||
void with_domain(auto const &fn) { with_domain(fn, []{}); }
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
Configuration const &config() const { return _config(); }
|
||||
Domain &domain() { return _domain(); }
|
||||
Mac_address const &router_mac() const { return _router_mac; }
|
||||
Mac_address const &mac() const { return _mac; }
|
||||
Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; }
|
||||
|
@ -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) }
|
||||
{ }
|
@ -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) { }
|
||||
|
||||
|
||||
/***************
|
||||
|
@ -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) { }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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)
|
||||
{ }
|
||||
|
||||
|
@ -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(); }
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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(); });
|
||||
}
|
||||
|
||||
|
||||
|
@ -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; }
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) { }
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
34
repos/os/src/server/nic_router/packet_result.h
Normal file
34
repos/os/src/server/nic_router/packet_result.h
Normal 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_ */
|
@ -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 }
|
||||
{ }
|
||||
|
@ -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>
|
||||
|
@ -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_ */
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
||||
/***************
|
||||
|
@ -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", [&] () {
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
Loading…
Reference in New Issue
Block a user