network: re-solicit RAs when the link MAC changes

A MAC change can mean the link joined another network, e.g. on an
active-backup bond failover with FailOverMACPolicy=active. NDisc only
solicits when it starts, so IPv6 sat stale until the next unsolicited
RA. Restart NDisc to solicit immediately.
This commit is contained in:
r-vdp
2026-08-20 04:05:12 +09:00
committed by Yu Watanabe
parent fc08ae472c
commit dc4108c43c
3 changed files with 62 additions and 13 deletions
+6 -6
View File
@@ -2490,12 +2490,6 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
if (r < 0)
return log_link_debug_errno(link, r, "Could not update MAC address for Router Advertisement: %m");
if (link->ndisc && link->hw_addr.length == ETH_ALEN) {
r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
if (r < 0)
return log_link_debug_errno(link, r, "Could not update MAC for NDisc: %m");
}
if (link->lldp_rx) {
r = sd_lldp_rx_set_filter_address(link->lldp_rx, &link->hw_addr.ether);
if (r < 0)
@@ -2508,6 +2502,12 @@ static int link_update_hardware_address(Link *link, sd_netlink_message *message)
return log_link_debug_errno(link, r, "Could not update MAC address for LLDP Tx: %m");
}
/* Do this at the end so that we can fail the link in case we don't manage to restart NDisc. */
r = ndisc_update_mac(link);
if (r < 0)
return log_link_warning_errno(
link, r, "Could not restart IPv6 Router Discovery after MAC change: %m");
return 1; /* needs reconfigure */
}
+55 -7
View File
@@ -2971,18 +2971,27 @@ static int ndisc_configure(Link *link) {
return 0;
}
static bool ndisc_can_start(Link *link) {
assert(link);
if (!link->ndisc || !link->dhcp6_client)
return false;
if (!link_has_carrier(link))
return false;
if (in6_addr_is_null(&link->ipv6ll_address))
return false;
return true;
}
int ndisc_start(Link *link) {
int r;
assert(link);
if (!link->ndisc || !link->dhcp6_client)
return 0;
if (!link_has_carrier(link))
return 0;
if (in6_addr_is_null(&link->ipv6ll_address))
if (!ndisc_can_start(link))
return 0;
r = sd_ndisc_set_link_local_address(link->ndisc, &link->ipv6ll_address);
@@ -2998,6 +3007,45 @@ int ndisc_start(Link *link) {
return 1;
}
int ndisc_update_mac(Link *link) {
int r;
assert(link);
if (!link->ndisc || link->hw_addr.length != ETH_ALEN)
return 0;
r = sd_ndisc_set_mac(link->ndisc, &link->hw_addr.ether);
if (r < 0)
return r;
if (sd_ndisc_is_running(link->ndisc) <= 0)
return 0;
/* Only restart if a start is possible right now. Otherwise keep the running client,
* whatever makes the conditions true again should also restart discovery. */
if (!ndisc_can_start(link)) {
log_link_debug(link, "MAC address changed, but not restarting IPv6 Router Discovery now.");
return 0;
}
/* A changed MAC can mean a changed network, e.g. on a bond failover. Restart discovery to
* solicit RAs instead of waiting for the next unsolicited one. Keep learned state, so use
* sd_ndisc_stop() rather than ndisc_stop(). */
r = sd_ndisc_stop(link->ndisc);
if (r < 0)
return r;
r = ndisc_start(link);
if (r < 0)
return r;
/* Should be unreachable, otherwise check ndisc_can_start(). */
if (r == 0)
log_link_debug(link, "MAC address changed, but IPv6 Router Discovery was not restarted.");
return 0;
}
static int ndisc_process_request(Request *req, Link *link, void *userdata) {
int r;
+1
View File
@@ -61,6 +61,7 @@ void network_adjust_ndisc(Network *network);
int ndisc_start(Link *link);
int ndisc_stop(Link *link);
int ndisc_update_mac(Link *link);
void ndisc_flush(Link *link);
int link_request_ndisc(Link *link);