From 433029c3a6549ca534616af51b100481d4773a35 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Tue, 28 Jun 2022 22:14:26 +0200 Subject: [PATCH] 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 --- repos/os/src/server/nic_router/arp_cache.cc | 22 ------ repos/os/src/server/nic_router/arp_cache.h | 47 +++++++++++-- repos/os/src/server/nic_router/interface.cc | 76 ++++++++++++--------- 3 files changed, 86 insertions(+), 59 deletions(-) diff --git a/repos/os/src/server/nic_router/arp_cache.cc b/repos/os/src/server/nic_router/arp_cache.cc index 6f8e0b1b0e..6493abf6af 100644 --- a/repos/os/src/server/nic_router/arp_cache.cc +++ b/repos/os/src/server/nic_router/arp_cache.cc @@ -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++) { diff --git a/repos/os/src/server/nic_router/arp_cache.h b/repos/os/src/server/nic_router/arp_cache.h index e1fca9f484..18a5042f76 100644 --- a/repos/os/src/server/nic_router/arp_cache.h +++ b/repos/os/src/server/nic_router/arp_cache.h @@ -42,7 +42,33 @@ class Net::Arp_cache_entry : public Genode::Avl_node Arp_cache_entry(Ipv4_address const &ip, Mac_address const &mac); - Arp_cache_entry const &find_by_ip(Ipv4_address const &ip) const; + template + + 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::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 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 + + 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(); }; diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index 83c869ad19..24e6d7b270 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -558,18 +558,25 @@ void Interface::_adapt_eth(Ethernet_frame ð, 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 ð, 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)