mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
nic_router: destroy links on insufficient resource
If the NIC router has insufficient CAP or RAM quota for the creation of a state object for an interface, it tries to destroy a certain amount of existing state objects of this interface to free resources. Afterwards, it retries handling the current packet once. If it does fail again, the router drops the packet. Issue #2953
This commit is contained in:
parent
4442c79526
commit
d6c6549354
@ -196,10 +196,4 @@ append_if [have_spec lan9118] qemu_args " -net nic,model=lan9118 "
|
||||
|
||||
append qemu_args " -net user -nographic "
|
||||
|
||||
set done_string ""
|
||||
for {set i 0} {$i < 2} {incr i 1} {
|
||||
append done_string {.*nic_router\] \[flood_links\] drop packet \(RAM quota exhausted.*\n}
|
||||
append done_string {.*ping\] 64 bytes from 10\.0\.2\.2.*\n}
|
||||
}
|
||||
|
||||
run_genode_until $done_string 120
|
||||
run_genode_until {.*ping\] 64 bytes from 10\.0\.2\.2: icmp_seq=30 .*\n} 120
|
||||
|
@ -362,9 +362,8 @@ Interface::_new_link(L3_protocol const protocol,
|
||||
remote, _timer, _config(), protocol };
|
||||
}
|
||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||
throw Drop_packet(
|
||||
"RAM quota exhausted during allocation of TCP link");
|
||||
}
|
||||
throw Free_resources_and_retry_handle_eth(); }
|
||||
|
||||
break;
|
||||
case L3_protocol::UDP:
|
||||
try {
|
||||
@ -373,9 +372,8 @@ Interface::_new_link(L3_protocol const protocol,
|
||||
remote, _timer, _config(), protocol };
|
||||
}
|
||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||
throw Drop_packet(
|
||||
"RAM quota exhausted during allocation of UDP link");
|
||||
}
|
||||
throw Free_resources_and_retry_handle_eth(); }
|
||||
|
||||
break;
|
||||
case L3_protocol::ICMP:
|
||||
try {
|
||||
@ -384,9 +382,8 @@ Interface::_new_link(L3_protocol const protocol,
|
||||
remote, _timer, _config(), protocol };
|
||||
}
|
||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||
throw Drop_packet(
|
||||
"RAM quota exhausted during allocation of ICMP link");
|
||||
}
|
||||
throw Free_resources_and_retry_handle_eth(); }
|
||||
|
||||
break;
|
||||
default: throw Bad_transport_protocol(); }
|
||||
}
|
||||
@ -437,9 +434,8 @@ void Interface::_adapt_eth(Ethernet_frame ð,
|
||||
});
|
||||
try { new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt }; }
|
||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||
throw Drop_packet(
|
||||
"RAM quota exhausted during allocation of ARP waiter");
|
||||
}
|
||||
throw Free_resources_and_retry_handle_eth(); }
|
||||
|
||||
throw Packet_postponed();
|
||||
}
|
||||
}
|
||||
@ -577,9 +573,7 @@ void Interface::_new_dhcp_allocation(Ethernet_frame ð,
|
||||
local_domain.ip_config().interface);
|
||||
}
|
||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||
throw Drop_packet(
|
||||
"RAM quota exhausted during allocation of DHCP allocation");
|
||||
}
|
||||
throw Free_resources_and_retry_handle_eth(); }
|
||||
}
|
||||
|
||||
|
||||
@ -1289,9 +1283,11 @@ void Interface::_ready_to_submit()
|
||||
while (_sink.packet_avail()) {
|
||||
Packet_descriptor const pkt = _sink.get_packet();
|
||||
Size_guard size_guard(pkt.size());
|
||||
try { _handle_eth(_sink.packet_content(pkt), size_guard, pkt); }
|
||||
catch (Packet_postponed) { continue; }
|
||||
_ack_packet(pkt);
|
||||
try {
|
||||
_handle_eth(_sink.packet_content(pkt), size_guard, pkt);
|
||||
_ack_packet(pkt);
|
||||
}
|
||||
catch (Packet_postponed) { }
|
||||
}
|
||||
}
|
||||
|
||||
@ -1334,6 +1330,27 @@ void Interface::_destroy_released_dhcp_allocations(Domain &local_domain)
|
||||
}
|
||||
|
||||
|
||||
void Interface::_handle_eth(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain)
|
||||
{
|
||||
if (local_domain.ip_config().valid) {
|
||||
|
||||
switch (eth.type()) {
|
||||
case Ethernet_frame::Type::ARP: _handle_arp(eth, size_guard, local_domain); break;
|
||||
case Ethernet_frame::Type::IPV4: _handle_ip(eth, size_guard, pkt, local_domain); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
|
||||
} else {
|
||||
|
||||
switch (eth.type()) {
|
||||
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(eth, size_guard); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Interface::_handle_eth(void *const eth_base,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt)
|
||||
@ -1350,21 +1367,30 @@ void Interface::_handle_eth(void *const eth_base,
|
||||
_destroy_dissolved_links<Tcp_link>(_dissolved_tcp_links, _alloc);
|
||||
_destroy_released_dhcp_allocations(local_domain);
|
||||
|
||||
/* log received packet if desired */
|
||||
if (local_domain.verbose_packets()) {
|
||||
log("[", local_domain, "] rcv ", eth); }
|
||||
|
||||
if (local_domain.ip_config().valid) {
|
||||
/* try to handle ethernet frame */
|
||||
try { _handle_eth(eth, size_guard, pkt, local_domain); }
|
||||
catch (Free_resources_and_retry_handle_eth) {
|
||||
try {
|
||||
if (_config().verbose()) {
|
||||
log("[", local_domain, "] free resources and retry to handle packet"); }
|
||||
|
||||
switch (eth.type()) {
|
||||
case Ethernet_frame::Type::ARP: _handle_arp(eth, size_guard, local_domain); break;
|
||||
case Ethernet_frame::Type::IPV4: _handle_ip(eth, size_guard, pkt, local_domain); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
/* resources do not suffice, destroy all links */
|
||||
_destroy_links<Tcp_link> (_tcp_links, _dissolved_tcp_links, _alloc);
|
||||
_destroy_links<Udp_link> (_udp_links, _dissolved_udp_links, _alloc);
|
||||
_destroy_links<Icmp_link>(_icmp_links, _dissolved_icmp_links, _alloc);
|
||||
|
||||
} else {
|
||||
/* retry to handle ethernet frame */
|
||||
_handle_eth(eth, size_guard, pkt, local_domain);
|
||||
}
|
||||
catch (Free_resources_and_retry_handle_eth) {
|
||||
|
||||
switch (eth.type()) {
|
||||
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(eth, size_guard); break;
|
||||
default: throw Bad_network_protocol(); }
|
||||
/* give up if the resources still not suffice */
|
||||
throw Drop_packet("insufficient resources");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Dhcp_server::Alloc_ip_failed) {
|
||||
|
@ -248,6 +248,11 @@ class Net::Interface : private Interface_list::Element
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt);
|
||||
|
||||
void _handle_eth(Ethernet_frame ð,
|
||||
Size_guard &size_guard,
|
||||
Packet_descriptor const &pkt,
|
||||
Domain &local_domain);
|
||||
|
||||
void _ack_packet(Packet_descriptor const &pkt);
|
||||
|
||||
void _send_alloc_pkt(Genode::Packet_descriptor &pkt,
|
||||
@ -307,11 +312,12 @@ class Net::Interface : private Interface_list::Element
|
||||
|
||||
public:
|
||||
|
||||
struct Bad_send_dhcp_args : Genode::Exception { };
|
||||
struct Bad_transport_protocol : Genode::Exception { };
|
||||
struct Bad_network_protocol : Genode::Exception { };
|
||||
struct Packet_postponed : Genode::Exception { };
|
||||
struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { };
|
||||
struct Free_resources_and_retry_handle_eth : Genode::Exception { };
|
||||
struct Bad_send_dhcp_args : Genode::Exception { };
|
||||
struct Bad_transport_protocol : Genode::Exception { };
|
||||
struct Bad_network_protocol : Genode::Exception { };
|
||||
struct Packet_postponed : Genode::Exception { };
|
||||
struct Alloc_dhcp_msg_buffer_failed : Genode::Exception { };
|
||||
|
||||
struct Drop_packet : Genode::Exception
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user