device: fix IPv6 DAD to re-check whether address really failed DAD

In device_ipx_changed() we remember the addresses for which it appears
that DAD failed. Later, on an idle handler, we process them during
queued_ip6_config_change().

Note that nm_plaform_ip6_address_sync() might very well decide to remove
some or all addresses and re-add them immidiately later. It might do so,
to get the address priority/ordering right. At that point, we already
emit platform signals that the device disappeared, and track them in
dad6_failed_addrs.

Hence, later during queued_ip6_config_change() we must check again
whether the address is really not there and not still doing DAD.
Otherwise, we wrongly claim that DAD failed and remove the address,
generate a new one, and the same issue might happen again.
This commit is contained in:
Thomas Haller 2018-02-09 13:19:49 +01:00
parent ede4dd70f3
commit 6d8a636563
2 changed files with 27 additions and 3 deletions

View file

@ -11529,6 +11529,7 @@ queued_ip6_config_change (gpointer user_data)
NMDevicePrivate *priv;
GSList *iter;
gboolean need_ipv6ll = FALSE;
NMPlatform *platform;
g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE);
@ -11555,11 +11556,24 @@ queued_ip6_config_change (gpointer user_data)
} else
update_ip_config (self, AF_INET6, FALSE);
if (priv->state < NM_DEVICE_STATE_DEACTIVATING
&& nm_platform_link_get (nm_device_get_platform (self), priv->ifindex)) {
if ( priv->state < NM_DEVICE_STATE_DEACTIVATING
&& (platform = nm_device_get_platform (self))
&& nm_platform_link_get (platform, priv->ifindex)) {
/* Handle DAD failures */
for (iter = priv->dad6_failed_addrs; iter; iter = iter->next) {
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (iter->data);
const NMPObject *obj = iter->data;
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (obj);
const NMPlatformIP6Address *addr2;
addr2 = NMP_OBJECT_CAST_IP6_ADDRESS (nm_platform_lookup_obj (platform,
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
obj));
if ( addr2
&& ( NM_FLAGS_HAS (addr2->n_ifa_flags, IFA_F_SECONDARY)
|| !NM_FLAGS_HAS (addr2->n_ifa_flags, IFA_F_DADFAILED))) {
/* the address still/again exists and is not in DADFAILED state. Skip it. */
continue;
}
_LOGI (LOGD_IP6, "ipv6: duplicate address check failed for the %s address",
nm_platform_ip6_address_to_string (addr, NULL, 0));

View file

@ -730,6 +730,16 @@ const NMDedupMultiEntry *nm_platform_lookup_entry (NMPlatform *platform,
NMPCacheIdType cache_id_type,
const NMPObject *obj);
static inline const NMPObject *
nm_platform_lookup_obj (NMPlatform *platform,
NMPCacheIdType cache_id_type,
const NMPObject *obj)
{
return nm_dedup_multi_entry_get_obj (nm_platform_lookup_entry (platform,
cache_id_type,
obj));
}
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_obj_type (NMPlatform *platform,
NMPObjectType obj_type)