nic_router: fix domain invalidation during init

Previously we were doing the initialization once over all domains,
remembered which of them became invalid and destroyed those afterwards.
This isn't sufficient. As soon as one domain becomes invalid we have to
dissolve/destroy this one, deinitialize all other domains again (as they
could contain references to the invalid domain) and retry to initialize
them from the beginning. We proceed with this until we have one run
without a domain becoming invalid. Then we can be sure that the last
initialization run did not create references to any invalid domain.

Issue #2840
This commit is contained in:
Martin Stein 2018-06-02 00:18:02 +02:00 committed by Christian Helmuth
parent 410652d42a
commit 4630c4b9ff
3 changed files with 50 additions and 25 deletions

View File

@ -65,7 +65,7 @@ Configuration::Configuration(Env &env,
_tcp_max_segm_lifetime(read_sec_attr(node, "tcp_max_segm_lifetime_sec", DEFAULT_TCP_MAX_SEGM_LIFETIME_SEC)),
_node(node)
{
/* read domains */
/* do parts of domain initialization that do not lookup other domains */
node.for_each_sub_node("domain", [&] (Xml_node const node) {
try {
Domain &domain = *new (_alloc) Domain(*this, node, _alloc);
@ -77,20 +77,40 @@ Configuration::Configuration(Env &env,
}
catch (Domain::Invalid) { log("[?] invalid domain"); }
});
/* do those parts of domain init that require the domain tree to be complete */
List<Domain> invalid_domains;
_domains.for_each([&] (Domain &domain) {
/* do parts of domain initialization that may lookup other domains */
while (true) {
struct Retry_without_domain : Genode::Exception
{
Domain &domain;
Retry_without_domain(Domain &domain) : domain(domain) { }
};
try {
domain.init(_domains);
if (_verbose) {
log("[", domain, "] initiated domain"); }
_domains.for_each([&] (Domain &domain) {
try { domain.init(_domains); }
catch (Domain::Invalid) { throw Retry_without_domain(domain); }
if (_verbose) {
log("[", domain, "] initiated domain"); }
});
}
catch (Domain::Invalid) { invalid_domains.insert(&domain); }
});
invalid_domains.for_each([&] (Domain &domain) {
_domains.remove(domain);
destroy(_alloc, &domain);
});
catch (Retry_without_domain exception) {
/* deinitialize all domains again */
_domains.for_each([&] (Domain &domain) {
domain.deinit();
if (_verbose) {
log("[", domain, "] deinitiated domain"); }
});
/* destroy domain that became invalid during initialization */
_domains.remove(exception.domain);
destroy(_alloc, &exception.domain);
/* retry to initialize the remaining domains */
continue;
}
break;
}
try {
/* check whether we shall create a report generator */
Xml_node const report_node = node.sub_node("report");

View File

@ -204,18 +204,7 @@ Link_side_tree &Domain::links(L3_protocol const protocol)
Domain::~Domain()
{
/* destroy rules */
_ip_rules.destroy_each(_alloc);
_nat_rules.destroy_each(_alloc);
_icmp_rules.destroy_each(_alloc);
_udp_rules.destroy_each(_alloc);
_tcp_rules.destroy_each(_alloc);
_udp_forward_rules.destroy_each(_alloc);
_tcp_forward_rules.destroy_each(_alloc);
/* destroy DHCP server and IP config */
try { destroy(_alloc, &_dhcp_server()); }
catch (Pointer<Dhcp_server>::Invalid) { }
deinit();
_ip_config.destruct();
}
@ -297,6 +286,20 @@ void Domain::init(Domain_tree &domains)
}
void Domain::deinit()
{
_ip_rules.destroy_each(_alloc);
_nat_rules.destroy_each(_alloc);
_icmp_rules.destroy_each(_alloc);
_udp_rules.destroy_each(_alloc);
_tcp_rules.destroy_each(_alloc);
_udp_forward_rules.destroy_each(_alloc);
_tcp_forward_rules.destroy_each(_alloc);
try { 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; }

View File

@ -125,6 +125,8 @@ class Net::Domain : public Domain_base,
void init(Domain_tree &domains);
void deinit();
Ipv4_address const &next_hop(Ipv4_address const &ip) const;
void ip_config(Ipv4_config const &ip_config);