nic_router: destroy timed out ARP waiters

The only object that is dynamically allocated by a network interface and that
was not equipped with a self-destruct timeout was the ARP waiter. This commit
closes this gap by adding a timeout to each ARP waiter that is set to 10
seconds by default but can be configured via the new <config> attribute
'arp_request_timeout_sec'.

Ref #4729
This commit is contained in:
Martin Stein 2024-06-03 12:23:00 +02:00 committed by Norman Feske
parent 20371d0445
commit 09b3fa389d
9 changed files with 66 additions and 13 deletions

View File

@ -843,8 +843,8 @@ When set to zero, the limit is deactivated, meaning that the router always
handles all available packets of an interface.
Disable requesting address resolutions via ARP
----------------------------------------------
Configuring ARP
---------------
By default, the NIC router requests required IP-to-MAC address resolutions at a
domain using ARP. However this may be a problem in certain environments, e.g.,
@ -862,6 +862,14 @@ MAC-address of the packet (instead of requesting the destination MAC-address
via ARP). This behavior was observed in common Linux-based systems at network
interfaces with the 'NOARP' flag set.
If ARP is enabled, however, one can configure the request timeout through the
following attribute (default value shown):
! <config arp_request_timeout_sec="10">
When the router does not receive a reply for a sent ARP request within this
timeout, the packet that caused the ARP request and the ARP request state are
dropped in order to re-use the resources.
Behavior regarding the NIC-session link state
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -23,26 +23,42 @@ using namespace Genode;
Arp_waiter::Arp_waiter(Interface &src,
Domain &dst,
Ipv4_address const &ip,
Packet_descriptor const &packet)
Packet_descriptor const &packet,
Microseconds timeout,
Cached_timer &timer)
:
_src_le(this), _src(src), _dst_le(this), _dst_ptr(&dst), _ip(ip),
_packet(packet)
_packet(packet), _timeout(timer, *this, &Arp_waiter::_handle_timeout, timeout)
{
_src.arp_stats().alive++;
_src.own_arp_waiters().insert(&_src_le);
_dst_ptr->foreign_arp_waiters().insert(&_dst_le);
_timeout.schedule(timeout);
}
Arp_waiter::~Arp_waiter()
{
_dissolve();
_src.arp_stats().alive--;
_src.arp_stats().destroyed++;
}
void Arp_waiter::_dissolve()
{
_src.own_arp_waiters().remove(&_src_le);
_dst_ptr->foreign_arp_waiters().remove(&_dst_le);
}
void Arp_waiter::_handle_timeout(Duration)
{
_dissolve();
_src.timed_out_arp_waiters().insert(&_src_le);
}
void Arp_waiter::handle_config(Domain &dst)
{
_dst_ptr->foreign_arp_waiters().remove(&_dst_le);

View File

@ -16,6 +16,7 @@
/* local includes */
#include <list.h>
#include <lazy_one_shot_timeout.h>
/* Genode includes */
#include <net/ipv4.h>
@ -38,12 +39,13 @@ class Net::Arp_waiter
{
private:
Arp_waiter_list_element _src_le;
Interface &_src;
Arp_waiter_list_element _dst_le;
Domain *_dst_ptr;
Ipv4_address const _ip;
Packet_descriptor const _packet;
Arp_waiter_list_element _src_le;
Interface &_src;
Arp_waiter_list_element _dst_le;
Domain *_dst_ptr;
Ipv4_address const _ip;
Packet_descriptor const _packet;
Lazy_one_shot_timeout<Arp_waiter> _timeout;
/*
* Noncopyable
@ -51,12 +53,18 @@ class Net::Arp_waiter
Arp_waiter(Arp_waiter const &);
Arp_waiter &operator = (Arp_waiter const &);
void _handle_timeout(Genode::Duration);
void _dissolve();
public:
Arp_waiter(Interface &src,
Domain &dst,
Ipv4_address const &ip,
Packet_descriptor const &packet);
Packet_descriptor const &packet,
Genode::Microseconds dissolve_timeout,
Cached_timer &timer);
~Arp_waiter();

View File

@ -189,6 +189,7 @@
<xs:attribute name="dhcp_request_timeout_sec" type="Seconds" />
<xs:attribute name="dhcp_offer_timeout_sec" type="Seconds" />
<xs:attribute name="udp_idle_timeout_sec" type="Seconds" />
<xs:attribute name="arp_request_timeout_sec" type="Seconds" />
<xs:attribute name="tcp_idle_timeout_sec" type="Seconds" />
<xs:attribute name="icmp_idle_timeout_sec" type="Seconds" />
<xs:attribute name="tcp_max_segm_lifetime_sec" type="Seconds" />

View File

@ -46,6 +46,7 @@ Configuration::Configuration(Xml_node const node,
_udp_idle_timeout { 0 },
_tcp_idle_timeout { 0 },
_tcp_max_segm_lifetime { 0 },
_arp_request_timeout { 0 },
_node { node }
{ }
@ -105,6 +106,7 @@ Configuration::Configuration(Env &env,
_udp_idle_timeout { read_sec_attr(node, "udp_idle_timeout_sec", 30) },
_tcp_idle_timeout { read_sec_attr(node, "tcp_idle_timeout_sec", 600) },
_tcp_max_segm_lifetime { read_sec_attr(node, "tcp_max_segm_lifetime_sec", 15) },
_arp_request_timeout { read_sec_attr(node, "arp_request_timeout_sec", 10) },
_node { node }
{
/* do parts of domain initialization that do not lookup other domains */

View File

@ -49,6 +49,7 @@ class Net::Configuration
Genode::Microseconds const _udp_idle_timeout;
Genode::Microseconds const _tcp_idle_timeout;
Genode::Microseconds const _tcp_max_segm_lifetime;
Genode::Microseconds const _arp_request_timeout;
Genode::Constructible<Report> _report { };
Genode::Reporter *_reporter_ptr { };
Domain_dict _domains { };
@ -105,6 +106,7 @@ class Net::Configuration
Genode::Microseconds udp_idle_timeout() const { return _udp_idle_timeout; }
Genode::Microseconds tcp_idle_timeout() const { return _tcp_idle_timeout; }
Genode::Microseconds tcp_max_segm_lifetime() const { return _tcp_max_segm_lifetime; }
Genode::Microseconds arp_request_timeout() const { return _arp_request_timeout; }
Domain_dict &domains() { return _domains; }
Genode::Xml_node node() const { return _node; }
};

View File

@ -612,7 +612,7 @@ Packet_result Interface::_adapt_eth(Ethernet_frame &eth,
});
retry_once<Out_of_ram, Out_of_caps>(
[&] {
new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt };
new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt, _config_ptr->arp_request_timeout(), _timer };
result = packet_postponed();
},
[&] { _try_emergency_free_quota(); },
@ -1733,6 +1733,17 @@ void Interface::_destroy_released_dhcp_allocations(Domain &local_domain)
}
void Interface::_destroy_timed_out_arp_waiters()
{
while (Arp_waiter_list_element *le = _timed_out_arp_waiters.first()) {
Arp_waiter &waiter = *le->object();
_drop_packet(waiter.packet(), "ARP request timed out");
_timed_out_arp_waiters.remove(le);
destroy(_alloc, &waiter);
}
}
Packet_result Interface::_handle_eth(Ethernet_frame &eth,
Size_guard &size_guard,
Packet_descriptor const &pkt,
@ -1806,6 +1817,7 @@ Packet_result Interface::_handle_eth(void *const eth_base,
_destroy_dissolved_links<Icmp_link>(_dissolved_icmp_links, _alloc);
_destroy_dissolved_links<Udp_link>(_dissolved_udp_links, _alloc);
_destroy_dissolved_links<Tcp_link>(_dissolved_tcp_links, _alloc);
_destroy_timed_out_arp_waiters();
_destroy_released_dhcp_allocations(domain);
/* log received packet if desired */
@ -2089,6 +2101,7 @@ void Interface::handle_config_1(Configuration &config)
_destroy_dissolved_links<Icmp_link>(_dissolved_icmp_links, _alloc);
_destroy_dissolved_links<Udp_link> (_dissolved_udp_links, _alloc);
_destroy_dissolved_links<Tcp_link> (_dissolved_tcp_links, _alloc);
_destroy_timed_out_arp_waiters();
_destroy_released_dhcp_allocations(old_domain);
/* do not consider to reuse IP config if the domains differ */

View File

@ -154,6 +154,7 @@ class Net::Interface : private Interface_list::Element
Genode::Allocator &_alloc;
Domain *_domain_ptr { };
Arp_waiter_list _own_arp_waiters { };
Arp_waiter_list _timed_out_arp_waiters { };
Link_list _tcp_links { };
Link_list _udp_links { };
Link_list _icmp_links { };
@ -196,6 +197,8 @@ class Net::Interface : private Interface_list::Element
void _try_emergency_free_quota();
void _destroy_timed_out_arp_waiters();
[[nodiscard]] Packet_result _new_dhcp_allocation(Ethernet_frame &eth,
Dhcp_packet &dhcp,
Dhcp_server &dhcp_srv,
@ -474,6 +477,7 @@ class Net::Interface : private Interface_list::Element
Mac_address const &router_mac() const { return _router_mac; }
Mac_address const &mac() const { return _mac; }
Arp_waiter_list &own_arp_waiters() { return _own_arp_waiters; }
Arp_waiter_list &timed_out_arp_waiters() { return _timed_out_arp_waiters; }
Signal_context_capability pkt_stream_signal_handler() const { return _pkt_stream_signal_handler; }
Interface_link_stats &udp_stats() { return _udp_stats; }
Interface_link_stats &tcp_stats() { return _tcp_stats; }

View File

@ -31,7 +31,6 @@
#define _LINK_H_
/* Genode includes */
#include <timer_session/connection.h>
#include <util/avl_tree.h>
#include <util/list.h>
#include <net/ipv4.h>