mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-21 02:01:38 +00:00
nic_router: find forward rules w/o exceptions
Replaces the former implementation of the 'find_longest_prefix_match' method at the data structure for direct 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
This commit is contained in:
parent
5d14adebb5
commit
0f6714c6d7
@ -55,31 +55,3 @@ Forward_rule::Forward_rule(Domain_tree &domains, Xml_node const node)
|
||||
if (_port == Port(0) || !_to_ip.valid() || dynamic_port(_port)) {
|
||||
throw Invalid(); }
|
||||
}
|
||||
|
||||
|
||||
Forward_rule const &Forward_rule::find_by_port(Port const port) const
|
||||
{
|
||||
if (port == _port) {
|
||||
return *this; }
|
||||
|
||||
Forward_rule *const rule =
|
||||
Avl_node<Forward_rule>::child(port.value > _port.value);
|
||||
|
||||
if (!rule) {
|
||||
throw Forward_rule_tree::No_match(); }
|
||||
|
||||
return rule->find_by_port(port);
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** Forward_rule_tree **
|
||||
***********************/
|
||||
|
||||
Forward_rule const &Forward_rule_tree::find_by_port(Port const port) const
|
||||
{
|
||||
if (!first()) {
|
||||
throw No_match(); }
|
||||
|
||||
return first()->find_by_port(port);
|
||||
}
|
||||
|
@ -54,7 +54,32 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
|
||||
|
||||
Forward_rule(Domain_tree &domains, Genode::Xml_node const node);
|
||||
|
||||
Forward_rule const &find_by_port(Port const port) const;
|
||||
template <typename HANDLE_MATCH_FN,
|
||||
typename HANDLE_NO_MATCH_FN>
|
||||
|
||||
void find_by_port(Port const port,
|
||||
HANDLE_MATCH_FN && handle_match,
|
||||
HANDLE_NO_MATCH_FN && handle_no_match) const
|
||||
{
|
||||
if (port.value != _port.value) {
|
||||
|
||||
Forward_rule *const rule_ptr {
|
||||
Avl_node<Forward_rule>::child(port.value > _port.value) };
|
||||
|
||||
if (rule_ptr != nullptr) {
|
||||
|
||||
rule_ptr->find_by_port(
|
||||
port, handle_match, handle_no_match);
|
||||
|
||||
} else {
|
||||
|
||||
handle_no_match();
|
||||
}
|
||||
} else {
|
||||
|
||||
handle_match(*this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********
|
||||
@ -84,9 +109,22 @@ class Net::Forward_rule : public Genode::Avl_node<Forward_rule>
|
||||
|
||||
struct Net::Forward_rule_tree : Avl_tree<Forward_rule>
|
||||
{
|
||||
struct No_match : Genode::Exception { };
|
||||
template <typename HANDLE_MATCH_FN,
|
||||
typename HANDLE_NO_MATCH_FN>
|
||||
|
||||
Forward_rule const &find_by_port(Port const port) const;
|
||||
void find_by_port(Port const port,
|
||||
HANDLE_MATCH_FN && handle_match,
|
||||
HANDLE_NO_MATCH_FN && handle_no_match) const
|
||||
{
|
||||
if (first() != nullptr) {
|
||||
|
||||
first()->find_by_port(port, handle_match, handle_no_match);
|
||||
|
||||
} else {
|
||||
|
||||
handle_no_match();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _FORWARD_RULE_H_ */
|
||||
|
@ -1260,25 +1260,32 @@ void Interface::_handle_ip(Ethernet_frame ð,
|
||||
|
||||
/* try to route via forward rules */
|
||||
if (local_id.dst_ip == local_intf.address) {
|
||||
try {
|
||||
Forward_rule const &rule =
|
||||
_forward_rules(local_domain, prot).find_by_port(local_id.dst_port);
|
||||
|
||||
if(_config().verbose()) {
|
||||
log("[", local_domain, "] using forward rule: ",
|
||||
l3_protocol_name(prot), " ", rule);
|
||||
}
|
||||
Domain &remote_domain = rule.domain();
|
||||
_adapt_eth(eth, rule.to_ip(), pkt, remote_domain);
|
||||
ip.dst(rule.to_ip());
|
||||
if (!(rule.to_port() == Port(0))) {
|
||||
_dst_port(prot, prot_base, rule.to_port());
|
||||
}
|
||||
_nat_link_and_pass(eth, size_guard, ip, prot, prot_base,
|
||||
prot_size, local_id, local_domain, remote_domain);
|
||||
_forward_rules(local_domain, prot).find_by_port(
|
||||
local_id.dst_port,
|
||||
[&] /* handle_match */ (Forward_rule const &rule)
|
||||
{
|
||||
if(_config().verbose()) {
|
||||
log("[", local_domain, "] using forward rule: ",
|
||||
l3_protocol_name(prot), " ", rule);
|
||||
}
|
||||
Domain &remote_domain = rule.domain();
|
||||
_adapt_eth(eth, rule.to_ip(), pkt, remote_domain);
|
||||
ip.dst(rule.to_ip());
|
||||
if (!(rule.to_port() == Port(0))) {
|
||||
_dst_port(prot, prot_base, rule.to_port());
|
||||
}
|
||||
_nat_link_and_pass(
|
||||
eth, size_guard, ip, prot, prot_base, prot_size,
|
||||
local_id, local_domain, remote_domain);
|
||||
|
||||
done = true;
|
||||
},
|
||||
[&] /* handle_no_match */ () { }
|
||||
);
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
catch (Forward_rule_tree::No_match) { }
|
||||
}
|
||||
/* try to route via transport and permit rules */
|
||||
try {
|
||||
@ -1884,68 +1891,71 @@ void Interface::_update_udp_tcp_links(L3_protocol prot,
|
||||
Domain &cln_dom)
|
||||
{
|
||||
links(prot).for_each([&] (Link &link) {
|
||||
|
||||
try {
|
||||
/* try to find forward rule that matches the server port */
|
||||
Forward_rule const &rule =
|
||||
_forward_rules(cln_dom, prot).
|
||||
find_by_port(link.client().dst_port());
|
||||
|
||||
/* if destination IP of forwarding changed, dismiss link */
|
||||
if (rule.to_ip() != link.server().src_ip()) {
|
||||
_dismiss_link_log(link, "other forward-rule to");
|
||||
throw Dismiss_link();
|
||||
}
|
||||
/*
|
||||
* If destination port of forwarding was set and then was
|
||||
* modified or unset, dismiss link
|
||||
*/
|
||||
if (!(link.server().src_port() == link.client().dst_port())) {
|
||||
if (!(rule.to_port() == link.server().src_port())) {
|
||||
_dismiss_link_log(link, "other forward-rule to_port");
|
||||
throw Dismiss_link();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If destination port of forwarding was not set and then was
|
||||
* set, dismiss link
|
||||
*/
|
||||
else {
|
||||
if (!(rule.to_port() == link.server().src_port()) &&
|
||||
!(rule.to_port() == Port(0)))
|
||||
_forward_rules(cln_dom, prot).find_by_port(
|
||||
link.client().dst_port(),
|
||||
[&] /* handle_match */ (Forward_rule const &rule)
|
||||
{
|
||||
_dismiss_link_log(link, "new forward-rule to_port");
|
||||
throw Dismiss_link();
|
||||
}
|
||||
}
|
||||
_update_link_check_nat(link, rule.domain(), prot, cln_dom);
|
||||
return;
|
||||
}
|
||||
catch (Forward_rule_tree::No_match) {
|
||||
try {
|
||||
/* try to find transport rule that matches the server IP */
|
||||
bool done { false };
|
||||
_transport_rules(cln_dom, prot).find_longest_prefix_match(
|
||||
link.client().dst_ip(),
|
||||
[&] /* handle_match */ (Transport_rule const &transport_rule)
|
||||
{
|
||||
/* try to find permit rule that matches the server port */
|
||||
Permit_rule const &permit_rule =
|
||||
transport_rule.permit_rule(link.client().dst_port());
|
||||
|
||||
_update_link_check_nat(link, permit_rule.domain(), prot, cln_dom);
|
||||
done = true;
|
||||
},
|
||||
[&] /* handle_no_match */ ()
|
||||
{
|
||||
_dismiss_link_log(link, "no transport/forward rule");
|
||||
/* if destination IP of forwarding changed, dismiss link */
|
||||
if (rule.to_ip() != link.server().src_ip()) {
|
||||
_dismiss_link_log(link, "other forward-rule to");
|
||||
throw Dismiss_link();
|
||||
}
|
||||
);
|
||||
if (done) {
|
||||
/*
|
||||
* If destination port of forwarding was set and then was
|
||||
* modified or unset, dismiss link
|
||||
*/
|
||||
if (!(link.server().src_port() == link.client().dst_port())) {
|
||||
if (!(rule.to_port() == link.server().src_port())) {
|
||||
_dismiss_link_log(link, "other forward-rule to_port");
|
||||
throw Dismiss_link();
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If destination port of forwarding was not set and then was
|
||||
* set, dismiss link
|
||||
*/
|
||||
else {
|
||||
if (!(rule.to_port() == link.server().src_port()) &&
|
||||
!(rule.to_port() == Port(0)))
|
||||
{
|
||||
_dismiss_link_log(link, "new forward-rule to_port");
|
||||
throw Dismiss_link();
|
||||
}
|
||||
}
|
||||
_update_link_check_nat(link, rule.domain(), prot, cln_dom);
|
||||
return;
|
||||
},
|
||||
[&] /* handle_no_match */ () {
|
||||
try {
|
||||
/* try to find transport rule that matches the server IP */
|
||||
bool done { false };
|
||||
_transport_rules(cln_dom, prot).find_longest_prefix_match(
|
||||
link.client().dst_ip(),
|
||||
[&] /* handle_match */ (Transport_rule const &transport_rule)
|
||||
{
|
||||
/* try to find permit rule that matches the server port */
|
||||
Permit_rule const &permit_rule =
|
||||
transport_rule.permit_rule(link.client().dst_port());
|
||||
|
||||
_update_link_check_nat(link, permit_rule.domain(), prot, cln_dom);
|
||||
done = true;
|
||||
},
|
||||
[&] /* handle_no_match */ ()
|
||||
{
|
||||
_dismiss_link_log(link, "no transport/forward rule");
|
||||
}
|
||||
);
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Permit_single_rule_tree::No_match) { _dismiss_link_log(link, "no permit rule"); }
|
||||
catch (Dismiss_link) { }
|
||||
}
|
||||
}
|
||||
catch (Permit_single_rule_tree::No_match) { _dismiss_link_log(link, "no permit rule"); }
|
||||
catch (Dismiss_link) { }
|
||||
);
|
||||
}
|
||||
catch (Dismiss_link) { }
|
||||
_destroy_link(link);
|
||||
|
Loading…
x
Reference in New Issue
Block a user