From 6294167eff7d7e60a45d3503a84f6056e5f9f4ff Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Mon, 27 Jun 2022 21:19:17 +0200 Subject: [PATCH] nic_router: find nat rules w/o exceptions Replaces the former implementation of the 'find_by_domain' method at the data structure for NAT rules. This method used to return a reference to the found object and threw an exception if no matching object was found. The new implementation 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. Ref #4536 --- repos/os/src/server/nic_router/interface.cc | 49 ++++++++++++++------- repos/os/src/server/nic_router/nat_rule.cc | 24 ---------- repos/os/src/server/nic_router/nat_rule.h | 46 ++++++++++++++++++- 3 files changed, 77 insertions(+), 42 deletions(-) diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index 781bbe239d..4e989fc922 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -589,16 +589,19 @@ void Interface::_nat_link_and_pass(Ethernet_frame ð, { try { Pointer remote_port_alloc; - try { - Nat_rule &nat = remote_domain.nat_rules().find_by_domain(local_domain); - if(_config().verbose()) { - log("[", local_domain, "] using NAT rule: ", nat); } + remote_domain.nat_rules().find_by_domain( + local_domain, + [&] /* handle_match */ (Nat_rule &nat) + { + if(_config().verbose()) { + log("[", local_domain, "] using NAT rule: ", nat); } - _src_port(prot, prot_base, nat.port_alloc(prot).alloc()); - ip.src(remote_domain.ip_config().interface().address); - remote_port_alloc = nat.port_alloc(prot); - } - catch (Nat_rule_tree::No_match) { } + _src_port(prot, prot_base, nat.port_alloc(prot).alloc()); + ip.src(remote_domain.ip_config().interface().address); + remote_port_alloc = nat.port_alloc(prot); + }, + [&] /* no_match */ () { } + ); Link_side_id const remote_id = { ip.dst(), _dst_port(prot, prot_base), ip.src(), _src_port(prot, prot_base) }; _new_link(prot, local_id, remote_port_alloc, remote_domain, remote_id); @@ -1869,14 +1872,28 @@ void Interface::_update_link_check_nat(Link &link, _dismiss_link_log(link, "NAT IP"); throw Dismiss_link(); } - Nat_rule &nat = new_srv_dom.nat_rules().find_by_domain(cln_dom); - Port_allocator_guard &remote_port_alloc = nat.port_alloc(prot); - remote_port_alloc.alloc(link.server().dst_port()); - remote_port_alloc_ptr = remote_port_alloc; - link.handle_config(cln_dom, new_srv_dom, remote_port_alloc_ptr, _config()); - return; + bool done { false }; + new_srv_dom.nat_rules().find_by_domain( + cln_dom, + [&] /* handle_match */ (Nat_rule &nat) + { + Port_allocator_guard &remote_port_alloc = nat.port_alloc(prot); + remote_port_alloc.alloc(link.server().dst_port()); + remote_port_alloc_ptr = remote_port_alloc; + link.handle_config( + cln_dom, new_srv_dom, remote_port_alloc_ptr, _config()); + + done = true; + }, + [&] /* handle_no_match */ () + { + _dismiss_link_log(link, "no NAT rule"); + } + ); + if (done) { + return; + } } - catch (Nat_rule_tree::No_match) { _dismiss_link_log(link, "no NAT rule"); } catch (Port_allocator::Allocation_conflict) { _dismiss_link_log(link, "no NAT-port"); } catch (Port_allocator_guard::Out_of_indices) { _dismiss_link_log(link, "no NAT-port quota"); } throw Dismiss_link(); diff --git a/repos/os/src/server/nic_router/nat_rule.cc b/repos/os/src/server/nic_router/nat_rule.cc index 1839b8ce22..3395f60196 100644 --- a/repos/os/src/server/nic_router/nat_rule.cc +++ b/repos/os/src/server/nic_router/nat_rule.cc @@ -57,30 +57,6 @@ Nat_rule::Nat_rule(Domain_tree &domains, { } -Nat_rule &Nat_rule::find_by_domain(Domain &domain) -{ - if (&domain == &_domain) { - return *this; } - - bool const side = (addr_t)&domain > (addr_t)&_domain; - Nat_rule *const rule = Avl_node::child(side); - if (!rule) { - throw Nat_rule_tree::No_match(); } - - return rule->find_by_domain(domain); -} - - -Nat_rule &Nat_rule_tree::find_by_domain(Domain &domain) -{ - Nat_rule *const rule = first(); - if (!rule) { - throw No_match(); } - - return rule->find_by_domain(domain); -} - - void Nat_rule::print(Output &output) const { Genode::print(output, "domain ", _domain, diff --git a/repos/os/src/server/nic_router/nat_rule.h b/repos/os/src/server/nic_router/nat_rule.h index 500d444106..4f6853ce3a 100644 --- a/repos/os/src/server/nic_router/nat_rule.h +++ b/repos/os/src/server/nic_router/nat_rule.h @@ -59,6 +59,35 @@ class Net::Nat_rule : public Genode::Avl_node Nat_rule &find_by_domain(Domain &domain); + template + + void find_by_domain(Domain &domain, + HANDLE_MATCH_FN && handle_match, + HANDLE_NO_MATCH_FN && handle_no_match) + { + if (&domain != &_domain) { + + Nat_rule *const rule_ptr { + Avl_node::child( + (Genode::addr_t)&domain > (Genode::addr_t)&_domain) }; + + if (rule_ptr != nullptr) { + + rule_ptr->find_by_domain( + domain, handle_match, handle_no_match); + + } else { + + handle_no_match(); + } + + } else { + + handle_match(*this); + } + } + Port_allocator_guard &port_alloc(L3_protocol const prot); @@ -89,9 +118,22 @@ class Net::Nat_rule : public Genode::Avl_node struct Net::Nat_rule_tree : Avl_tree { - struct No_match : Genode::Exception { }; + template - Nat_rule &find_by_domain(Domain &domain); + void find_by_domain(Domain &domain, + HANDLE_MATCH_FN && handle_match, + HANDLE_NO_MATCH_FN && handle_no_match) + { + if (first() != nullptr) { + + first()->find_by_domain(domain, handle_match, handle_no_match); + + } else { + + handle_no_match(); + } + } }; #endif /* _NAT_RULE_H_ */