nic_router: find AVL string nodes w/o exceptions

Replaces the former use of the 'find_by_name' method of the AVL string tree.
This method returned a reference to the found object and threw an exception if
no matching object was found.

The locally implemented replacement doesn't return anything and doesn't throw
exceptions. It takes two lambda arguments instead. One for handling the case
that a match was found with a reference to the matching object as argument and
another for handling the case that no object matches.

This way, expensive exception handling can be avoided and object references
stay in a local scope.

Furthermore, this commit modifies the local wrapper for the  insert method of
the AVL string tree, so, that it follows the above mentioned concept as well.

Ref #4536
This commit is contained in:
Martin Stein 2022-06-28 15:17:52 +02:00 committed by Christian Helmuth
parent 6294167eff
commit 925d229d67
14 changed files with 238 additions and 219 deletions

View File

@ -33,29 +33,65 @@ class Net::Avl_string_tree : public Genode::Avl_tree<Genode::Avl_string_base>
using Node = Genode::Avl_string_base;
using Tree = Genode::Avl_tree<Genode::Avl_string_base>;
OBJECT &_find_by_name(char const *name)
template <typename HANDLE_MATCH_FN,
typename HANDLE_NO_MATCH_FN>
void _node_find_by_name(Node &node,
char const *name_ptr,
HANDLE_MATCH_FN && handle_match,
HANDLE_NO_MATCH_FN && handle_no_match)
{
if (!first()) {
throw No_match(); }
int const name_diff {
Genode::strcmp(name_ptr, node.name()) };
Node *node = first()->find_by_name(name);
if (!node) {
throw No_match(); }
if (name_diff != 0) {
return *static_cast<OBJECT *>(node);
Node *child_ptr { node.child(name_diff > 0) };
if (child_ptr != nullptr) {
_node_find_by_name(
*child_ptr, name_ptr, handle_match, handle_no_match);
} else {
handle_no_match();
}
} else {
handle_match(*static_cast<OBJECT *>(&node));
}
}
template <typename HANDLE_MATCH_FN,
typename HANDLE_NO_MATCH_FN>
void _find_by_name(char const *name_ptr,
HANDLE_MATCH_FN && handle_match,
HANDLE_NO_MATCH_FN && handle_no_match)
{
if (first() != nullptr) {
_node_find_by_name(
*first(), name_ptr, handle_match, handle_no_match);
} else {
handle_no_match();
}
}
public:
struct No_match : Genode::Exception { };
struct Name_not_unique : Genode::Exception
template <typename HANDLE_MATCH_FN,
typename HANDLE_NO_MATCH_FN>
void find_by_name(NAME const &name,
HANDLE_MATCH_FN && handle_match,
HANDLE_NO_MATCH_FN && handle_no_match)
{
OBJECT &object;
Name_not_unique(OBJECT &object) : object(object) { }
};
OBJECT &find_by_name(NAME const &name) { return _find_by_name(name.string()); }
_find_by_name(name.string(), handle_match, handle_no_match);
}
template <typename FUNCTOR>
void for_each(FUNCTOR && functor) const {
@ -81,10 +117,19 @@ class Net::Avl_string_tree : public Genode::Avl_tree<Genode::Avl_string_base>
}
}
void insert(OBJECT &object)
template <typename HANDLE_NAME_NOT_UNIQUE_FN>
void insert(OBJECT &obj,
HANDLE_NAME_NOT_UNIQUE_FN && handle_name_not_unique)
{
try { throw Name_not_unique(_find_by_name(static_cast<Node *>(&object)->name())); }
catch (No_match) { Tree::insert(&object); }
_find_by_name(
static_cast<Node *>(&obj)->name(),
[&] /* handle_match */ (OBJECT &other_obj)
{
handle_name_not_unique(other_obj);
},
[&] /* handle_no_match */ () { Tree::insert(&obj); }
);
}
void remove(OBJECT &object) { Tree::remove(&object); }

View File

@ -131,11 +131,14 @@ Configuration::Configuration(Env &env,
node.for_each_sub_node("domain", [&] (Xml_node const node) {
try {
Domain &domain = *new (_alloc) Domain(*this, node, _alloc);
try { _domains.insert(domain); }
catch (Domain_tree::Name_not_unique exception) {
_invalid_domain(domain, "name not unique");
_invalid_domain(exception.object, "name not unique");
}
_domains.insert(
domain,
[&] /* handle_name_not_unique */ (Domain &other_domain)
{
_invalid_domain(domain, "name not unique");
_invalid_domain(other_domain, "name not unique");
}
);
}
catch (Domain::Invalid) { }
});
@ -200,11 +203,14 @@ Configuration::Configuration(Env &env,
Nic_client { node, alloc, old_config._nic_clients, env, timer,
interfaces, *this };
try { _nic_clients.insert(nic_client); }
catch (Nic_client_tree::Name_not_unique exception) {
_invalid_nic_client(nic_client, "label not unique");
_invalid_nic_client(exception.object, "label not unique");
}
_nic_clients.insert(
nic_client,
[&] /* handle_name_not_unique */ (Nic_client &other_nic_client)
{
_invalid_nic_client(nic_client, "label not unique");
_invalid_nic_client(other_nic_client, "label not unique");
}
);
}
catch (Nic_client::Invalid) { }
});

View File

@ -206,8 +206,7 @@ Pointer<Domain> Dhcp_server::_init_dns_config_from(Genode::Xml_node const node,
if (dns_config_from == Domain_name()) {
return Pointer<Domain>();
}
try { return domains.find_by_name(dns_config_from); }
catch (Domain_tree::No_match) { throw Invalid(); }
return domains.deprecated_find_by_name<Invalid>(dns_config_from);
}

View File

@ -71,7 +71,31 @@ struct Net::Domain_link_stats : Domain_object_stats
};
class Net::Domain_tree : public Avl_string_tree<Domain, Domain_name> { };
class Net::Domain_tree : public Avl_string_tree<Domain, Domain_name>
{
public:
template <typename NO_MATCH_EXCEPTION>
Domain &deprecated_find_by_name(Domain_name const &name)
{
Domain *dom_ptr { nullptr };
find_by_name(
name,
[&] /* handle_match */ (Domain &dom) { dom_ptr = &dom; },
[&] /* handle_no_match */ () { throw NO_MATCH_EXCEPTION { }; }
);
return *dom_ptr;
}
template <typename NO_MATCH_EXCEPTION>
Domain &deprecated_find_by_domain_attr(Genode::Xml_node const &node)
{
Domain_name const name {
node.attribute_value("domain", Domain_name { }) };
return deprecated_find_by_name<NO_MATCH_EXCEPTION>(name);
}
};
class Net::Domain_base

View File

@ -26,18 +26,6 @@ using namespace Genode;
** Forward_rule **
******************/
Domain &Forward_rule::_find_domain(Domain_tree &domains,
Xml_node const node)
{
try {
Domain_name const domain_name = node.attribute_value("domain", Domain_name());
return domains.find_by_name(domain_name);
}
catch (Domain_tree::No_match) { throw Invalid(); }
}
void Forward_rule::print(Output &output) const
{
Genode::print(output, "port ", _port, " domain ", _domain, " to ip ",
@ -50,7 +38,7 @@ Forward_rule::Forward_rule(Domain_tree &domains, Xml_node const node)
_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 { _find_domain(domains, node) }
_domain { domains.deprecated_find_by_domain_attr<Invalid>(node) }
{
if (_port == Port(0) || !_to_ip.valid() || dynamic_port(_port)) {
throw Invalid(); }

View File

@ -45,9 +45,6 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
Port const _to_port;
Domain &_domain;
static Domain &_find_domain(Domain_tree &domains,
Genode::Xml_node const node);
public:
struct Invalid : Genode::Exception { };

View File

@ -390,19 +390,20 @@ void Interface::_update_domain_object(Domain &new_domain) {
void Interface::attach_to_domain()
{
try {
Domain &domain =
_config().domains().find_by_name(_policy.determine_domain_name());
_config().domains().find_by_name(
_policy.determine_domain_name(),
[&] /* handle_match */ (Domain &domain)
{
_attach_to_domain_raw(domain);
_attach_to_domain_raw(domain);
/* construct DHCP client if the new domain needs it */
if (domain.ip_config_dynamic()) {
_dhcp_client.construct(_timer, *this);
}
attach_to_domain_finish();
}
catch (Domain_tree::No_match) { }
/* construct DHCP client if the new domain needs it */
if (domain.ip_config_dynamic()) {
_dhcp_client.construct(_timer, *this);
}
attach_to_domain_finish();
},
[&] /* handle_no_match */ () { }
);
}
@ -2056,34 +2057,37 @@ void Interface::_update_dhcp_allocations(Domain &old_domain,
void Interface::_update_own_arp_waiters(Domain &domain)
{
bool const verbose = _config().verbose();
_own_arp_waiters.for_each([&] (Arp_waiter_list_element &le) {
Arp_waiter &arp_waiter = *le.object();
try {
Domain &dst = _config().domains().find_by_name(arp_waiter.dst().name());
if (dst.ip_config() != arp_waiter.dst().ip_config()) {
if (verbose) {
log("[", domain, "] dismiss ARP waiter: ", arp_waiter,
" (IP config changed)");
bool const verbose { _config().verbose() };
_own_arp_waiters.for_each([&] (Arp_waiter_list_element &le)
{
Arp_waiter &arp_waiter { *le.object() };
bool dismiss_arp_waiter { true };
_config().domains().find_by_name(
arp_waiter.dst().name(),
[&] /* handle_match */ (Domain &dst)
{
/* dismiss ARP waiter if IP config of target domain changed */
if (dst.ip_config() != arp_waiter.dst().ip_config()) {
return;
}
throw Dismiss_arp_waiter();
/* keep ARP waiter */
arp_waiter.handle_config(dst);
if (verbose) {
log("[", domain, "] update ARP waiter: ", arp_waiter);
}
dismiss_arp_waiter = false;
},
[&] /* handle_no_match */ ()
{
/* dismiss ARP waiter as the target domain disappeared */
}
/* keep ARP waiter */
arp_waiter.handle_config(dst);
);
if (dismiss_arp_waiter) {
if (verbose) {
log("[", domain, "] update ARP waiter: ", arp_waiter);
log("[", domain, "] dismiss ARP waiter: ", arp_waiter);
}
return;
cancel_arp_waiting(*_own_arp_waiters.first()->object());
}
/* dismiss ARP waiter */
catch (Domain_tree::No_match) {
if (verbose) {
log("[", domain, "] dismiss ARP waiter: ", arp_waiter,
" (domain disappeared)");
}
}
catch (Dismiss_arp_waiter) { }
cancel_arp_waiting(*_own_arp_waiters.first()->object());
});
}
@ -2107,11 +2111,15 @@ void Interface::handle_config_1(Configuration &config)
return; }
/* interface stays with its domain, so, try to reuse IP config */
Domain &new_domain = config.domains().find_by_name(new_domain_name);
new_domain.try_reuse_ip_config(old_domain);
return;
config.domains().find_by_name(
new_domain_name,
[&] /* handle_match */ (Domain &new_domain)
{
new_domain.try_reuse_ip_config(old_domain);
},
[&] /* handle_no_match */ () { }
);
}
catch (Domain_tree::No_match) { }
catch (Pointer<Domain>::Invalid) { }
}
@ -2135,66 +2143,70 @@ void Interface::handle_config_2()
Domain_name const &new_domain_name = _policy.determine_domain_name();
try {
Domain &old_domain = domain();
try {
Domain &new_domain = _config().domains().find_by_name(new_domain_name);
_config().domains().find_by_name(
new_domain_name,
[&] /* handle_match */ (Domain &new_domain)
{
/* if the domains differ, detach completely from the domain */
if (old_domain.name() != new_domain_name) {
/* if the domains differ, detach completely from the domain */
if (old_domain.name() != new_domain_name) {
_detach_from_domain();
_attach_to_domain_raw(new_domain);
/* destruct and construct DHCP client if required */
if (old_domain.ip_config_dynamic()) {
_dhcp_client.destruct();
}
if (new_domain.ip_config_dynamic()) {
_dhcp_client.construct(_timer, *this);
}
return;
}
_update_domain_object(new_domain);
/* destruct or construct DHCP client if IP-config type changes */
if (old_domain.ip_config_dynamic() &&
!new_domain.ip_config_dynamic())
{
_dhcp_client.destruct();
}
if (!old_domain.ip_config_dynamic() &&
new_domain.ip_config_dynamic())
{
_dhcp_client.construct(_timer, *this);
}
/* remember that the interface stays attached to the same domain */
_update_domain.construct(old_domain, new_domain);
},
[&] /* handle_no_match */ ()
{
/* the interface no longer has a domain */
_detach_from_domain();
_attach_to_domain_raw(new_domain);
/* destruct and construct DHCP client if required */
/* destruct DHCP client if it was constructed */
if (old_domain.ip_config_dynamic()) {
_dhcp_client.destruct();
}
if (new_domain.ip_config_dynamic()) {
_dhcp_client.construct(_timer, *this);
}
return;
}
_update_domain_object(new_domain);
/* destruct or construct DHCP client if IP-config type changes */
if (old_domain.ip_config_dynamic() &&
!new_domain.ip_config_dynamic())
{
_dhcp_client.destruct();
}
if (!old_domain.ip_config_dynamic() &&
new_domain.ip_config_dynamic())
{
_dhcp_client.construct(_timer, *this);
}
/* remember that the interface stays attached to the same domain */
_update_domain.construct(old_domain, new_domain);
return;
}
catch (Domain_tree::No_match) {
/* the interface no longer has a domain */
_detach_from_domain();
/* destruct DHCP client if it was constructed */
if (old_domain.ip_config_dynamic()) {
_dhcp_client.destruct();
}
}
);
}
catch (Pointer<Domain>::Invalid) {
/* the interface had no domain but now it may get one */
try {
Domain &new_domain = _config().domains().find_by_name(new_domain_name);
_attach_to_domain_raw(new_domain);
_config().domains().find_by_name(
new_domain_name,
[&] /* handle_match */ (Domain &new_domain)
{
_attach_to_domain_raw(new_domain);
/* construct DHCP client if the new domain needs it */
if (new_domain.ip_config_dynamic()) {
_dhcp_client.construct(_timer, *this);
}
}
catch (Domain_tree::No_match) { }
/* construct DHCP client if the new domain needs it */
if (new_domain.ip_config_dynamic()) {
_dhcp_client.construct(_timer, *this);
}
},
[&] /* handle_no_match */ () { }
);
}
}

View File

@ -19,19 +19,8 @@ using namespace Net;
using namespace Genode;
Domain &Ip_rule::_find_domain(Domain_tree &domains,
Xml_node const node)
{
try {
return domains.find_by_name(
node.attribute_value("domain", Domain_name()));
}
catch (Domain_tree::No_match) { throw Invalid(); }
}
Ip_rule::Ip_rule(Domain_tree &domains, Xml_node const node)
:
Direct_rule(node),
_domain(_find_domain(domains, node))
Direct_rule { node },
_domain { domains.deprecated_find_by_domain_attr<Invalid>(node) }
{ }

View File

@ -33,9 +33,6 @@ class Net::Ip_rule : public Direct_rule<Ip_rule>
Domain &_domain;
static Domain &_find_domain(Domain_tree &domains,
Genode::Xml_node const node);
public:
Ip_rule(Domain_tree &domains, Genode::Xml_node const node);

View File

@ -26,17 +26,6 @@ using namespace Net;
using namespace Genode;
Domain &Nat_rule::_find_domain(Domain_tree &domains,
Xml_node const node)
{
try {
return domains.find_by_name(
node.attribute_value("domain", Domain_name()));
}
catch (Domain_tree::No_match) { throw Invalid(); }
}
bool Nat_rule::higher(Nat_rule *rule)
{
return (addr_t)&rule->domain() > (addr_t)&_domain;
@ -50,10 +39,10 @@ Nat_rule::Nat_rule(Domain_tree &domains,
Xml_node const node,
bool const verbose)
:
_domain(_find_domain(domains, node)),
_tcp_port_alloc (tcp_port_alloc, node.attribute_value("tcp-ports", 0UL), verbose),
_udp_port_alloc (udp_port_alloc, node.attribute_value("udp-ports", 0UL), verbose),
_icmp_port_alloc(icmp_port_alloc, node.attribute_value("icmp-ids", 0UL), verbose)
_domain { domains.deprecated_find_by_domain_attr<Invalid>(node) },
_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 }
{ }

View File

@ -43,9 +43,6 @@ class Net::Nat_rule : public Genode::Avl_node<Nat_rule>
Port_allocator_guard _udp_port_alloc;
Port_allocator_guard _icmp_port_alloc;
static Domain &_find_domain(Domain_tree &domains,
Genode::Xml_node const node);
public:
struct Invalid : Genode::Exception { };

View File

@ -59,28 +59,33 @@ Net::Nic_client::Nic_client(Xml_node const &node,
_alloc { alloc },
_config { config }
{
/* if an interface with this label already exists, reuse it */
try {
Nic_client &old_nic_client = old_nic_clients.find_by_name(label());
Nic_client_interface &interface = old_nic_client._interface();
old_nic_client._interface = Pointer<Nic_client_interface>();
interface.domain_name(domain());
_interface = interface;
}
/* if not, create a new one */
catch (Nic_client_tree::No_match) {
if (config.verbose()) {
log("[", domain(), "] create NIC client: ", *this); }
old_nic_clients.find_by_name(
label(),
[&] /* handle_match */ (Nic_client &old_nic_client)
{
/* reuse existing interface */
Nic_client_interface &interface = old_nic_client._interface();
old_nic_client._interface = Pointer<Nic_client_interface>();
interface.domain_name(domain());
_interface = interface;
},
[&] /* handle_no_match */ ()
{
/* create a new interface */
if (config.verbose()) {
log("[", domain(), "] create NIC client: ", *this); }
try {
_interface = *new (_alloc)
Nic_client_interface { env, timer, alloc, interfaces, config,
domain(), label() };
try {
_interface = *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) { _invalid("NIC session RAM quota"); }
catch (Insufficient_cap_quota) { _invalid("NIC session CAP quota"); }
catch (Service_denied) { _invalid("NIC session denied"); }
}
);
}

View File

@ -26,17 +26,6 @@ using namespace Genode;
** Permit_any_rule **
*********************/
Domain &Permit_any_rule::_find_domain(Domain_tree &domains,
Xml_node const node)
{
try {
return domains.find_by_name(
node.attribute_value("domain", Domain_name()));
}
catch (Domain_tree::No_match) { throw Invalid(); }
}
void Permit_any_rule::print(Output &output) const
{
Genode::print(output, "domain ", domain());
@ -45,7 +34,7 @@ void Permit_any_rule::print(Output &output) const
Permit_any_rule::Permit_any_rule(Domain_tree &domains, Xml_node const node)
:
Permit_rule(_find_domain(domains, node))
Permit_rule { domains.deprecated_find_by_domain_attr<Invalid>(node) }
{ }
@ -53,16 +42,6 @@ Permit_any_rule::Permit_any_rule(Domain_tree &domains, Xml_node const node)
** Permit_single_rule **
************************/
Domain &Permit_single_rule::_find_domain(Domain_tree &domains,
Xml_node const node)
{
try {
return domains.find_by_name(
node.attribute_value("domain", Domain_name()));
}
catch (Domain_tree::No_match) { throw Invalid(); }
}
bool Permit_single_rule::higher(Permit_single_rule *rule)
{
@ -79,8 +58,8 @@ void Permit_single_rule::print(Output &output) const
Permit_single_rule::Permit_single_rule(Domain_tree &domains,
Xml_node const node)
:
Permit_rule(_find_domain(domains, node)),
_port(node.attribute_value("port", Port(0)))
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(); }

View File

@ -70,11 +70,6 @@ struct Net::Permit_rule : public Genode::Interface
struct Net::Permit_any_rule : Permit_rule
{
private:
static Domain &_find_domain(Domain_tree &domains,
Genode::Xml_node const node);
public:
struct Invalid : Genode::Exception { };
@ -102,9 +97,6 @@ class Net::Permit_single_rule : public Permit_rule,
Port const _port;
static Domain &_find_domain(Domain_tree &domains,
Genode::Xml_node const node);
public:
struct Invalid : Genode::Exception { };