From 6575df84c5c0e3f3ad246dfe4fd4b28d5ed79b3d Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Fri, 19 Jan 2018 14:51:27 +0100 Subject: [PATCH] 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 --- repos/os/src/server/nic_router/arp_cache.cc | 36 +++++++++++++++++++-- repos/os/src/server/nic_router/arp_cache.h | 20 ++++++++++-- repos/os/src/server/nic_router/domain.h | 2 +- repos/os/src/server/nic_router/interface.cc | 2 ++ 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/repos/os/src/server/nic_router/arp_cache.cc b/repos/os/src/server/nic_router/arp_cache.cc index 5bf6805b4d..500e858f6e 100644 --- a/repos/os/src/server/nic_router/arp_cache.cc +++ b/repos/os/src/server/nic_router/arp_cache.cc @@ -13,6 +13,8 @@ /* local includes */ #include +#include +#include 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) { } + } +} diff --git a/repos/os/src/server/nic_router/arp_cache.h b/repos/os/src/server/nic_router/arp_cache.h index 1a03b0bd4a..3982fc88e1 100644 --- a/repos/os/src/server/nic_router/arp_cache.h +++ b/repos/os/src/server/nic_router/arp_cache.h @@ -22,6 +22,7 @@ namespace Net { + class Domain; class Arp_cache; class Arp_cache_entry; using Arp_cache_entry_slot = Genode::Constructible; @@ -56,6 +57,14 @@ class Net::Arp_cache_entry : public Genode::Avl_node ***************/ 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 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; }; diff --git a/repos/os/src/server/nic_router/domain.h b/repos/os/src/server/nic_router/domain.h index 19db122052..f8fb944279 100644 --- a/repos/os/src/server/nic_router/domain.h +++ b/repos/os/src/server/nic_router/domain.h @@ -98,7 +98,7 @@ class Net::Domain : public Domain_base unsigned long _interface_cnt { 0 }; Pointer _dhcp_server { }; Genode::Reconstructible _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 { }; diff --git a/repos/os/src/server/nic_router/interface.cc b/repos/os/src/server/nic_router/interface.cc index cf7d904ad0..8f1a487095 100644 --- a/repos/os/src/server/nic_router/interface.cc +++ b/repos/os/src/server/nic_router/interface.cc @@ -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); }