nic_router: find ARP cache entries w/o exceptions

Replaces the former implementation of the 'find_by_ip' method at the data
structure for ARP cache entries. This method used to return a reference to the
found object and threw an exception if no matching object was found.

The new implementation doesn't return anything and doesn't throw exceptions. It
takes two lambda arguments instead. One for handling the case that a match was
found with a reference to the matching object as argument and another for
handling the case that no object matches.

This way, expensive exception handling can be avoided and object references
stay in a local scope.

Ref #4555
This commit is contained in:
Martin Stein 2022-06-28 22:14:26 +02:00 committed by Christian Helmuth
parent e2086ac8e4
commit 433029c3a6
3 changed files with 86 additions and 59 deletions

View File

@ -37,19 +37,6 @@ bool Arp_cache_entry::_higher(Ipv4_address const &ip) const
}
Arp_cache_entry const &
Arp_cache_entry::find_by_ip(Ipv4_address const &ip) const
{
if (ip == _ip) {
return *this; }
Arp_cache_entry const *const entry = child(_higher(ip));
if (!entry) {
throw Arp_cache::No_match(); }
return entry->find_by_ip(ip);
}
void Arp_cache_entry::print(Output &output) const
{
Genode::print(output, _ip, " > ", _mac);
@ -79,15 +66,6 @@ void Arp_cache::new_entry(Ipv4_address const &ip, Mac_address const &mac)
}
Arp_cache_entry const &Arp_cache::find_by_ip(Ipv4_address const &ip) const
{
if (!first()) {
throw No_match(); }
return first()->find_by_ip(ip);
}
void Arp_cache::destroy_entries_with_mac(Mac_address const &mac)
{
for (unsigned curr = 0; curr < NR_OF_ENTRIES; curr++) {

View File

@ -42,7 +42,33 @@ class Net::Arp_cache_entry : public Genode::Avl_node<Arp_cache_entry>
Arp_cache_entry(Ipv4_address const &ip, Mac_address const &mac);
Arp_cache_entry const &find_by_ip(Ipv4_address const &ip) const;
template <typename HANDLE_MATCH_FN,
typename HANDLE_NO_MATCH_FN>
void find_by_ip(Ipv4_address const &ip,
HANDLE_MATCH_FN && handle_match,
HANDLE_NO_MATCH_FN && handle_no_match) const
{
if (ip != _ip) {
Arp_cache_entry *const entry_ptr {
Avl_node<Arp_cache_entry>::child(
_higher(ip)) };
if (entry_ptr != nullptr) {
entry_ptr->find_by_ip(
ip, handle_match, handle_no_match);
} else {
handle_no_match();
}
} else {
handle_match(*this);
}
}
/**************
@ -83,15 +109,28 @@ class Net::Arp_cache : public Genode::Avl_tree<Arp_cache_entry>
public:
struct No_match : Genode::Exception { };
Arp_cache(Domain const &domain) : _domain(domain) { }
void new_entry(Ipv4_address const &ip, Mac_address const &mac);
void destroy_entries_with_mac(Mac_address const &mac);
Arp_cache_entry const &find_by_ip(Ipv4_address const &ip) const;
template <typename HANDLE_MATCH_FN,
typename HANDLE_NO_MATCH_FN>
void find_by_ip(Ipv4_address const &ip,
HANDLE_MATCH_FN && handle_match,
HANDLE_NO_MATCH_FN && handle_no_match) const
{
if (first() != nullptr) {
first()->find_by_ip(ip, handle_match, handle_no_match);
} else {
handle_no_match();
}
}
void destroy_all_entries();
};

View File

@ -558,18 +558,25 @@ void Interface::_adapt_eth(Ethernet_frame &eth,
if (remote_domain.use_arp()) {
Ipv4_address const &hop_ip = remote_domain.next_hop(dst_ip);
try { eth.dst(remote_domain.arp_cache().find_by_ip(hop_ip).mac()); }
catch (Arp_cache::No_match) {
remote_domain.interfaces().for_each([&] (Interface &interface) {
interface._broadcast_arp_request(remote_ip_cfg.interface().address,
hop_ip);
});
try { new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt }; }
catch (Out_of_ram) { throw Free_resources_and_retry_handle_eth(); }
catch (Out_of_caps) { throw Free_resources_and_retry_handle_eth(); }
throw Packet_postponed();
}
remote_domain.arp_cache().find_by_ip(
hop_ip,
[&] /* handle_match */ (Arp_cache_entry const &entry)
{
eth.dst(entry.mac());
},
[&] /* handle_no_match */ ()
{
remote_domain.interfaces().for_each([&] (Interface &interface)
{
interface._broadcast_arp_request(
remote_ip_cfg.interface().address, hop_ip);
});
try { new (_alloc) Arp_waiter { *this, remote_domain, hop_ip, pkt }; }
catch (Out_of_ram) { throw Free_resources_and_retry_handle_eth(); }
catch (Out_of_caps) { throw Free_resources_and_retry_handle_eth(); }
throw Packet_postponed();
}
);
}
}
@ -1416,29 +1423,32 @@ void Interface::_handle_arp_reply(Ethernet_frame &eth,
Arp_packet &arp,
Domain &local_domain)
{
try {
/* check wether a matching ARP cache entry already exists */
local_domain.arp_cache().find_by_ip(arp.src_ip());
if (_config().verbose()) {
log("[", local_domain, "] ARP entry already exists"); }
}
catch (Arp_cache::No_match) {
/* by now, no matching ARP cache entry exists, so create one */
Ipv4_address const ip = arp.src_ip();
local_domain.arp_cache().new_entry(ip, arp.src_mac());
/* continue handling of packets that waited for the entry */
for (Arp_waiter_list_element *waiter_le = local_domain.foreign_arp_waiters().first();
waiter_le; )
local_domain.arp_cache().find_by_ip(
arp.src_ip(),
[&] /* handle_match */ (Arp_cache_entry const &)
{
Arp_waiter &waiter = *waiter_le->object();
waiter_le = waiter_le->next();
if (ip != waiter.ip()) { continue; }
waiter.src()._continue_handle_eth(local_domain, waiter.packet());
destroy(waiter.src()._alloc, &waiter);
/* check wether a matching ARP cache entry already exists */
if (_config().verbose()) {
log("[", local_domain, "] ARP entry already exists"); }
},
[&] /* handle_no_match */ ()
{
/* by now, no matching ARP cache entry exists, so create one */
Ipv4_address const ip = arp.src_ip();
local_domain.arp_cache().new_entry(ip, arp.src_mac());
/* continue handling of packets that waited for the entry */
for (Arp_waiter_list_element *waiter_le = local_domain.foreign_arp_waiters().first();
waiter_le; )
{
Arp_waiter &waiter = *waiter_le->object();
waiter_le = waiter_le->next();
if (ip != waiter.ip()) { continue; }
waiter.src()._continue_handle_eth(local_domain, waiter.packet());
destroy(waiter.src()._alloc, &waiter);
}
}
}
);
Ipv4_address_prefix const &local_intf = local_domain.ip_config().interface();
if (local_intf.prefix_matches(arp.dst_ip()) &&
arp.dst_ip() != local_intf.address)