mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-07 19:34:56 +00:00
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:
parent
e2086ac8e4
commit
433029c3a6
@ -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++) {
|
||||
|
@ -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();
|
||||
};
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user