nic_router: fix bad connection states on IP change

When a domain receives a new dynamic router IP address and that domain has
active connection states (TCP/UDP/ICMP) from another domain with NAT applied,
the connection states used to stay active while becoming obsolete. They
become obsolete because their identification and their packet processor
use the old routers IP address due to NAT.

One consequence was that connections became dysfunctional when the server
domain received a new dynamic router IP address. Request packets were still
routed from client to server, but when entering the server, their source IP
address was the outdated router address. Consequently, the server responses
used the outdated address as destination and the router dropped the responses
because it did not know this address anymore.

This commit fixes the problem by letting a domain destroy all its connection
states that were initiated from within other domains whenever it detaches from
its current IP configuration.

Strictly speaking, it is not necessary to destroy all connection states, only
those that the domain applies NAT to. However, the Genode AVL tree is not built
for removing a selection of nodes and trying to do it anyways is complicated.
So, for now, we simply destroy all connection states.

Note that the other way around was handled correctly already. When a domain
detaches from its IP config, all interfaces of that domain destroy all the
connection states they created (towards other domains).

Fixes #4696
This commit is contained in:
Martin Stein 2022-12-14 10:02:42 +01:00 committed by Christian Helmuth
parent 7a7cac57d9
commit 1b1a9ca95c
4 changed files with 30 additions and 9 deletions

View File

@ -82,6 +82,26 @@ void Domain::_prepare_reconstructing_ip_config()
Arp_waiter &waiter = *_foreign_arp_waiters.first()->object();
waiter.src().cancel_arp_waiting(waiter);
}
/*
* Destroy all link states
*
* Strictly speaking, it is not necessary to destroy all link states,
* only those that this domain applies NAT to. However, the Genode AVL
* tree is not built for removing a selection of nodes and trying to do
* it anyways is complicated. So, for now, we simply destroy all links.
*/
while (Link_side *link_side = _icmp_links.first()) {
Link &link { link_side->link() };
link.client_interface().destroy_link(link);
}
while (Link_side *link_side = _tcp_links.first()) {
Link &link { link_side->link() };
link.client_interface().destroy_link(link);
}
while (Link_side *link_side = _udp_links.first()) {
Link &link { link_side->link() };
link.client_interface().destroy_link(link);
}
}
}

View File

@ -283,7 +283,7 @@ void Interface_object_stats::report(Genode::Xml_generator &xml)
** Interface **
***************/
void Interface::_destroy_link(Link &link)
void Interface::destroy_link(Link &link)
{
L3_protocol const prot = link.protocol();
switch (prot) {
@ -2050,7 +2050,7 @@ void Interface::_update_udp_tcp_links(L3_protocol prot,
);
}
catch (Dismiss_link) { }
_destroy_link(link);
destroy_link(link);
});
}
@ -2078,7 +2078,7 @@ void Interface::_update_icmp_links(Domain &cln_dom)
}
}
catch (Dismiss_link) { }
_destroy_link(link);
destroy_link(link);
});
}

View File

@ -339,8 +339,6 @@ class Net::Interface : private Interface_list::Element
void _dismiss_link_log(Link &link,
char const *reason);
void _destroy_link(Link &link);
void _update_domain_object(Domain &new_domain);
void _detach_from_domain_raw();
@ -461,6 +459,8 @@ class Net::Interface : private Interface_list::Element
void handle_domain_ready_state(bool state);
void destroy_link(Link &link);
/***************
** Accessors **

View File

@ -236,10 +236,11 @@ class Net::Link : public Link_list::Element
** Accessors **
***************/
Link_side &client() { return _client; }
Link_side &server() { return _server; }
Configuration &config() { return _config(); }
L3_protocol protocol() const { return _protocol; }
Link_side &client() { return _client; }
Link_side &server() { return _server; }
Configuration &config() { return _config(); }
L3_protocol protocol() const { return _protocol; }
Interface &client_interface() { return _client_interface; };
};