nic_router: fix use of outdated ARP-cache entries

When a NIC session is destructed at the router, we have to remove all ARP
cache entries that match the MAC address of that session. Otherwise the
outdated entries might be re-applied later, leading to wrong destination
MAC addresses in routed packets.

Fixes #2637
This commit is contained in:
Martin Stein 2018-01-19 14:51:27 +01:00 committed by Norman Feske
parent 0423eb4499
commit 6575df84c5
4 changed files with 54 additions and 6 deletions

View File

@ -13,6 +13,8 @@
/* local includes */
#include <arp_cache.h>
#include <domain.h>
#include <configuration.h>
using namespace Net;
using namespace Genode;
@ -48,6 +50,11 @@ Arp_cache_entry::find_by_ip(Ipv4_address const &ip) const
return entry->find_by_ip(ip);
}
void Arp_cache_entry::print(Output &output) const
{
Genode::print(output, _ip, " > ", _mac);
}
/***************
** Arp_cache **
@ -55,9 +62,15 @@ Arp_cache_entry::find_by_ip(Ipv4_address const &ip) const
void Arp_cache::new_entry(Ipv4_address const &ip, Mac_address const &mac)
{
if (_entries[_curr].constructed()) { remove(&(*_entries[_curr])); }
if (_entries[_curr].constructed()) {
remove(&(*_entries[_curr]));
}
_entries[_curr].construct(ip, mac);
insert(&(*_entries[_curr]));
Arp_cache_entry &entry = *_entries[_curr];
insert(&entry);
if (_domain.config().verbose()) {
log("[", _domain, "] new ARP entry ", entry);
}
if (_curr < NR_OF_ENTRIES - 1) {
_curr++;
} else {
@ -73,3 +86,22 @@ Arp_cache_entry const &Arp_cache::find_by_ip(Ipv4_address const &ip) const
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++) {
try {
Arp_cache_entry &entry = *_entries[curr];
if (entry.mac() != mac) {
continue;
}
if (_domain.config().verbose()) {
log("[", _domain, "] destroy ARP entry ", entry);
}
remove(&entry);
_entries[curr].destruct();
} catch (Arp_cache_entry_slot::Deref_unconstructed_object) { }
}
}

View File

@ -22,6 +22,7 @@
namespace Net {
class Domain;
class Arp_cache;
class Arp_cache_entry;
using Arp_cache_entry_slot = Genode::Constructible<Arp_cache_entry>;
@ -56,6 +57,14 @@ class Net::Arp_cache_entry : public Genode::Avl_node<Arp_cache_entry>
***************/
Mac_address const &mac() const { return _mac; }
Ipv4_address const &ip() const { return _ip; }
/*********
** log **
*********/
void print(Genode::Output &output) const;
};
@ -68,16 +77,21 @@ class Net::Arp_cache : public Genode::Avl_tree<Arp_cache_entry>
NR_OF_ENTRIES = ENTRIES_SIZE / sizeof(Arp_cache_entry),
};
Arp_cache_entry_slot _entries[NR_OF_ENTRIES];
bool _init = true;
unsigned _curr = 0;
Domain const &_domain;
Arp_cache_entry_slot _entries[NR_OF_ENTRIES];
bool _init = true;
unsigned _curr = 0;
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;
};

View File

@ -98,7 +98,7 @@ class Net::Domain : public Domain_base
unsigned long _interface_cnt { 0 };
Pointer<Dhcp_server> _dhcp_server { };
Genode::Reconstructible<Ipv4_config> _ip_config;
Arp_cache _arp_cache { };
Arp_cache _arp_cache { *this };
Arp_waiter_list _foreign_arp_waiters { };
Link_side_tree _tcp_links { };
Link_side_tree _udp_links { };

View File

@ -1022,6 +1022,8 @@ Interface::~Interface()
_dhcp_allocations.remove(allocation);
_destroy_dhcp_allocation(*allocation);
}
/* dissolve ARP cache entries with the MAC address of this interface */
_domain.arp_cache().destroy_entries_with_mac(_mac);
}