nic_router: fix lifetime of DHCP clients

Let the DHCP client be a constructible member of Interface that is constructed
only as long as the interface is attached to a domain with a dynamic IP config.
This prevents DHCP client timeouts from a period with dynamic IP config to
trigger after a reconfiguration to a static IP config. Furthermore, handle
DHCP-reply packets at an interface only when the DHCP client its constructed.
Otherwise drop such packets.

Ref #3681
This commit is contained in:
Martin Stein 2020-03-04 15:09:21 +01:00 committed by Christian Helmuth
parent f842c92ee1
commit a68f3b05aa
3 changed files with 73 additions and 21 deletions

View File

@ -224,6 +224,7 @@ class Net::Domain : public Domain_base,
Domain_link_stats &icmp_stats() { return _icmp_stats; } Domain_link_stats &icmp_stats() { return _icmp_stats; }
Domain_object_stats &arp_stats() { return _arp_stats; } Domain_object_stats &arp_stats() { return _arp_stats; }
Domain_object_stats &dhcp_stats() { return _dhcp_stats; } Domain_object_stats &dhcp_stats() { return _dhcp_stats; }
bool ip_config_dynamic() const { return _ip_config_dynamic; };
}; };
#endif /* _DOMAIN_H_ */ #endif /* _DOMAIN_H_ */

View File

@ -343,9 +343,15 @@ void Interface::_detach_from_domain_raw()
void Interface::attach_to_domain() void Interface::attach_to_domain()
{ {
try { try {
_attach_to_domain_raw(_config().domains().find_by_name( Domain &domain =
_policy.determine_domain_name())); _config().domains().find_by_name(_policy.determine_domain_name());
_attach_to_domain_raw(domain);
/* construct DHCP client if the new domain needs it */
if (domain.ip_config_dynamic()) {
_dhcp_client.construct(_alloc, _timer, *this);
}
attach_to_domain_finish(); attach_to_domain_finish();
} }
catch (Domain_tree::No_match) { } catch (Domain_tree::No_match) { }
@ -361,7 +367,7 @@ void Interface::attach_to_domain_finish()
Domain &domain = _domain(); Domain &domain = _domain();
Ipv4_config const &ip_config = domain.ip_config(); Ipv4_config const &ip_config = domain.ip_config();
if (!ip_config.valid) { if (!ip_config.valid) {
_dhcp_client.discover(); _dhcp_client->discover();
return; return;
} }
attach_to_ip_config(domain, ip_config); attach_to_ip_config(domain, ip_config);
@ -1101,7 +1107,10 @@ void Interface::_handle_ip(Ethernet_frame &eth,
} }
catch (Pointer<Dhcp_server>::Invalid) { } catch (Pointer<Dhcp_server>::Invalid) { }
} else { } else {
_dhcp_client.handle_ip(eth, size_guard); if (!_dhcp_client.constructed()) {
throw Drop_packet("DHCP client not active");
}
_dhcp_client->handle_ip(eth, size_guard);
return; return;
} }
} }
@ -1466,7 +1475,12 @@ void Interface::_handle_eth(Ethernet_frame &eth,
} else { } else {
switch (eth.type()) { switch (eth.type()) {
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(eth, size_guard); break; case Ethernet_frame::Type::IPV4:
if (!_dhcp_client.constructed()) {
throw Drop_packet("DHCP client not active");
}
_dhcp_client->handle_ip(eth, size_guard);
break;
default: throw Bad_network_protocol(); } default: throw Bad_network_protocol(); }
} }
} }
@ -1912,31 +1926,68 @@ void Interface::handle_config_2()
{ {
Domain_name const &new_domain_name = _policy.determine_domain_name(); Domain_name const &new_domain_name = _policy.determine_domain_name();
try { try {
/* if the domains differ, detach completely from the domain */
Domain &old_domain = domain(); Domain &old_domain = domain();
Domain &new_domain = _config().domains().find_by_name(new_domain_name); try {
if (old_domain.name() != new_domain_name) { Domain &new_domain = _config().domains().find_by_name(new_domain_name);
_detach_from_domain();
/* 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(_alloc, _timer, *this);
}
return;
}
/* move to new domain object without considering any state objects */
_detach_from_domain_raw();
_attach_to_domain_raw(new_domain); _attach_to_domain_raw(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(_alloc, _timer, *this);
}
/* remember that the interface stays attached to the same domain */
_update_domain.construct(old_domain, new_domain);
return; return;
} }
/* move to new domain object without considering any state objects */ catch (Domain_tree::No_match) {
_detach_from_domain_raw();
_attach_to_domain_raw(new_domain);
/* remember that the interface stays attached to the same domain */ /* the interface no longer has a domain */
_update_domain.construct(old_domain, new_domain); _detach_from_domain();
return;
}
catch (Domain_tree::No_match) {
/* the interface no longer has a domain */ /* destruct DHCP client if it was constructed */
_detach_from_domain(); if (old_domain.ip_config_dynamic()) {
_dhcp_client.destruct();
}
}
} }
catch (Pointer<Domain>::Invalid) { catch (Pointer<Domain>::Invalid) {
/* the interface had no domain but now it may get one */ /* the interface had no domain but now it may get one */
try { _attach_to_domain_raw(_config().domains().find_by_name(new_domain_name)); } try {
Domain &new_domain = _config().domains().find_by_name(new_domain_name);
_attach_to_domain_raw(new_domain);
/* construct DHCP client if the new domain needs it */
if (new_domain.ip_config_dynamic()) {
_dhcp_client.construct(_alloc, _timer, *this);
}
}
catch (Domain_tree::No_match) { } catch (Domain_tree::No_match) { }
} }
} }

View File

@ -151,7 +151,7 @@ class Net::Interface : private Interface_list::Element
Link_list _dissolved_icmp_links { }; Link_list _dissolved_icmp_links { };
Dhcp_allocation_tree _dhcp_allocations { }; Dhcp_allocation_tree _dhcp_allocations { };
Dhcp_allocation_list _released_dhcp_allocations { }; Dhcp_allocation_list _released_dhcp_allocations { };
Dhcp_client _dhcp_client { _alloc, _timer, *this }; Genode::Constructible<Dhcp_client> _dhcp_client { };
Interface_list &_interfaces; Interface_list &_interfaces;
Genode::Constructible<Update_domain> _update_domain { }; Genode::Constructible<Update_domain> _update_domain { };
Interface_link_stats _udp_stats { }; Interface_link_stats _udp_stats { };