nic_router: clear ARP cache when domain is down

Whenever a domain looses all its interfaces or the link state of all attached
interfaces is down at once, the domain potentially moves to another Ethernet
segment and should therefore consider its ARP cache to be outdated.

RFC 826 states that "... If a host moves, any connections initiated by that
host will work, assuming its own address resolution table is cleared when it
moves. ...".

Therefore, this commit introduces clearing the ARP cache and the initially
stated events.

This commit was motivated by an issue with the PinePhone Modem and USB NIC.
On the PinePhone, the Modem has its own OS and acts as direct gateway to the
outer world for the USB NIC that is driven by Genode. However, whenever the
Modem gets restarted, Modem and USB NIC receive a new MAC address. This used
to conflict with the NIC routers ARP entry for the Modem that didn't cease to
be valid.

With this commit, the integrator of such a scenario at least has a convenient
way of fixing this by ensuring that all interfaces at the USB NIC domain go
down when resetting (e.g. by ensuring that the USB NIC is the only interface at
that domain).

Fixes #4558
This commit is contained in:
Martin Stein 2022-07-09 15:54:08 +02:00 committed by Christian Helmuth
parent 64c81e2846
commit d5b1d9466a
4 changed files with 22 additions and 2 deletions

View File

@ -105,3 +105,17 @@ void Arp_cache::destroy_entries_with_mac(Mac_address const &mac)
} catch (Arp_cache_entry_slot::Deref_unconstructed_object) { }
}
}
void Arp_cache::destroy_all_entries()
{
if (_domain.config().verbose()) {
log("[", _domain, "] destroy all ARP entries");
}
while (Arp_cache_entry *entry = first()) {
remove(entry);
}
for (unsigned curr = 0; curr < NR_OF_ENTRIES; curr++) {
_entries[curr].destruct();
}
}

View File

@ -92,6 +92,8 @@ class Net::Arp_cache : public Genode::Avl_tree<Arp_cache_entry>
void destroy_entries_with_mac(Mac_address const &mac);
Arp_cache_entry const &find_by_ip(Ipv4_address const &ip) const;
void destroy_all_entries();
};
#endif /* _ARP_CACHE_H_ */

View File

@ -364,9 +364,12 @@ void Domain::detach_interface(Interface &interface)
{
_interfaces.remove(&interface);
_interface_cnt--;
if (!_interface_cnt && _ip_config_dynamic) {
if (!_interface_cnt) {
_arp_cache.destroy_all_entries();
if (_ip_config_dynamic) {
discard_ip_config();
}
}
if (_config.verbose_domain_state()) {
log("[", *this, "] NIC sessions: ", _interface_cnt);
}

View File

@ -930,6 +930,7 @@ void Interface::handle_interface_link_state()
throw Keep_ip_config(); }
});
domain_.discard_ip_config();
domain_.arp_cache().destroy_all_entries();
}
}
catch (Pointer<Domain>::Invalid) { }