mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 22:47:50 +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 "
|
append qemu_args " -net user -nographic "
|
||||||
|
|
||||||
set done_string ""
|
run_genode_until {.*ping\] 64 bytes from 10\.0\.2\.2: icmp_seq=30 .*\n} 120
|
||||||
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
|
|
||||||
|
@ -362,9 +362,8 @@ Interface::_new_link(L3_protocol const protocol,
|
|||||||
remote, _timer, _config(), protocol };
|
remote, _timer, _config(), protocol };
|
||||||
}
|
}
|
||||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||||
throw Drop_packet(
|
throw Free_resources_and_retry_handle_eth(); }
|
||||||
"RAM quota exhausted during allocation of TCP link");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case L3_protocol::UDP:
|
case L3_protocol::UDP:
|
||||||
try {
|
try {
|
||||||
@ -373,9 +372,8 @@ Interface::_new_link(L3_protocol const protocol,
|
|||||||
remote, _timer, _config(), protocol };
|
remote, _timer, _config(), protocol };
|
||||||
}
|
}
|
||||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||||
throw Drop_packet(
|
throw Free_resources_and_retry_handle_eth(); }
|
||||||
"RAM quota exhausted during allocation of UDP link");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case L3_protocol::ICMP:
|
case L3_protocol::ICMP:
|
||||||
try {
|
try {
|
||||||
@ -384,9 +382,8 @@ Interface::_new_link(L3_protocol const protocol,
|
|||||||
remote, _timer, _config(), protocol };
|
remote, _timer, _config(), protocol };
|
||||||
}
|
}
|
||||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||||
throw Drop_packet(
|
throw Free_resources_and_retry_handle_eth(); }
|
||||||
"RAM quota exhausted during allocation of ICMP link");
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default: throw Bad_transport_protocol(); }
|
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 }; }
|
try { new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt }; }
|
||||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||||
throw Drop_packet(
|
throw Free_resources_and_retry_handle_eth(); }
|
||||||
"RAM quota exhausted during allocation of ARP waiter");
|
|
||||||
}
|
|
||||||
throw Packet_postponed();
|
throw Packet_postponed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -577,9 +573,7 @@ void Interface::_new_dhcp_allocation(Ethernet_frame ð,
|
|||||||
local_domain.ip_config().interface);
|
local_domain.ip_config().interface);
|
||||||
}
|
}
|
||||||
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
catch (Quota_guard<Ram_quota>::Limit_exceeded) {
|
||||||
throw Drop_packet(
|
throw Free_resources_and_retry_handle_eth(); }
|
||||||
"RAM quota exhausted during allocation of DHCP allocation");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1289,10 +1283,12 @@ void Interface::_ready_to_submit()
|
|||||||
while (_sink.packet_avail()) {
|
while (_sink.packet_avail()) {
|
||||||
Packet_descriptor const pkt = _sink.get_packet();
|
Packet_descriptor const pkt = _sink.get_packet();
|
||||||
Size_guard size_guard(pkt.size());
|
Size_guard size_guard(pkt.size());
|
||||||
try { _handle_eth(_sink.packet_content(pkt), size_guard, pkt); }
|
try {
|
||||||
catch (Packet_postponed) { continue; }
|
_handle_eth(_sink.packet_content(pkt), size_guard, pkt);
|
||||||
_ack_packet(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,
|
void Interface::_handle_eth(void *const eth_base,
|
||||||
Size_guard &size_guard,
|
Size_guard &size_guard,
|
||||||
Packet_descriptor const &pkt)
|
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_dissolved_links<Tcp_link>(_dissolved_tcp_links, _alloc);
|
||||||
_destroy_released_dhcp_allocations(local_domain);
|
_destroy_released_dhcp_allocations(local_domain);
|
||||||
|
|
||||||
|
/* log received packet if desired */
|
||||||
if (local_domain.verbose_packets()) {
|
if (local_domain.verbose_packets()) {
|
||||||
log("[", local_domain, "] rcv ", eth); }
|
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()) {
|
/* resources do not suffice, destroy all links */
|
||||||
case Ethernet_frame::Type::ARP: _handle_arp(eth, size_guard, local_domain); break;
|
_destroy_links<Tcp_link> (_tcp_links, _dissolved_tcp_links, _alloc);
|
||||||
case Ethernet_frame::Type::IPV4: _handle_ip(eth, size_guard, pkt, local_domain); break;
|
_destroy_links<Udp_link> (_udp_links, _dissolved_udp_links, _alloc);
|
||||||
default: throw Bad_network_protocol(); }
|
_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()) {
|
/* give up if the resources still not suffice */
|
||||||
case Ethernet_frame::Type::IPV4: _dhcp_client.handle_ip(eth, size_guard); break;
|
throw Drop_packet("insufficient resources");
|
||||||
default: throw Bad_network_protocol(); }
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Dhcp_server::Alloc_ip_failed) {
|
catch (Dhcp_server::Alloc_ip_failed) {
|
||||||
|
@ -248,6 +248,11 @@ class Net::Interface : private Interface_list::Element
|
|||||||
Size_guard &size_guard,
|
Size_guard &size_guard,
|
||||||
Packet_descriptor const &pkt);
|
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 _ack_packet(Packet_descriptor const &pkt);
|
||||||
|
|
||||||
void _send_alloc_pkt(Genode::Packet_descriptor &pkt,
|
void _send_alloc_pkt(Genode::Packet_descriptor &pkt,
|
||||||
@ -307,6 +312,7 @@ class Net::Interface : private Interface_list::Element
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
struct Free_resources_and_retry_handle_eth : Genode::Exception { };
|
||||||
struct Bad_send_dhcp_args : Genode::Exception { };
|
struct Bad_send_dhcp_args : Genode::Exception { };
|
||||||
struct Bad_transport_protocol : Genode::Exception { };
|
struct Bad_transport_protocol : Genode::Exception { };
|
||||||
struct Bad_network_protocol : Genode::Exception { };
|
struct Bad_network_protocol : Genode::Exception { };
|
||||||
|
Loading…
Reference in New Issue
Block a user