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)