mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-29 18:30:11 +01:00
core: merge branch 'bg/ipv6-dad'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1366
This commit is contained in:
commit
63f4783c59
9 changed files with 268 additions and 103 deletions
|
|
@ -4135,18 +4135,30 @@ _dev_l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, N
|
|||
/* Check if AC6 addresses completed DAD */
|
||||
if (NM_FLAGS_ANY(notify_data->platform_change_on_idle.obj_type_flags,
|
||||
nmp_object_type_to_flags(NMP_OBJECT_TYPE_IP6_ADDRESS))
|
||||
&& priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd
|
||||
&& nm_l3cfg_check_ready(l3cfg,
|
||||
priv->ipac6_data.l3cd,
|
||||
AF_INET6,
|
||||
NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY,
|
||||
NULL)) {
|
||||
if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6))
|
||||
_dev_l3_cfg_commit(self, FALSE);
|
||||
&& priv->ipac6_data.state == NM_DEVICE_IP_STATE_PENDING && priv->ipac6_data.l3cd) {
|
||||
gs_unref_array GArray *conflicts = NULL;
|
||||
gboolean ready;
|
||||
|
||||
nm_clear_l3cd(&priv->ipac6_data.l3cd);
|
||||
_dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY);
|
||||
_dev_ip_state_check_async(self, AF_INET6);
|
||||
ready = nm_l3cfg_check_ready(l3cfg,
|
||||
priv->ipac6_data.l3cd,
|
||||
AF_INET6,
|
||||
NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY,
|
||||
&conflicts);
|
||||
if (conflicts) {
|
||||
/* nm_ndisc_dad_failed() will emit a new "NDisc:config-received"
|
||||
* signal; _dev_ipac6_ndisc_config_changed() will be called
|
||||
* synchronously to update the current state and schedule a commit. */
|
||||
nm_ndisc_dad_failed(priv->ipac6_data.ndisc, conflicts, TRUE);
|
||||
} else if (ready) {
|
||||
if (nm_l3cfg_has_temp_not_available_obj(priv->l3cfg, AF_INET6))
|
||||
_dev_l3_cfg_commit(self, FALSE);
|
||||
|
||||
nm_clear_l3cd(&priv->ipac6_data.l3cd);
|
||||
_dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY);
|
||||
_dev_ip_state_check_async(self, AF_INET6);
|
||||
} else {
|
||||
/* wait */
|
||||
}
|
||||
}
|
||||
|
||||
_dev_ipmanual_check_ready(self);
|
||||
|
|
@ -10079,7 +10091,7 @@ _dev_ipmanual_check_ready(NMDevice *self)
|
|||
gboolean has_carrier;
|
||||
NML3CfgCheckReadyFlags flags;
|
||||
gboolean ready;
|
||||
gboolean acd_used = FALSE;
|
||||
gs_unref_array GArray *conflicts = NULL;
|
||||
int IS_IPv4;
|
||||
|
||||
if (priv->ipmanual_data.state_4 != NM_DEVICE_IP_STATE_PENDING
|
||||
|
|
@ -10122,8 +10134,8 @@ _dev_ipmanual_check_ready(NMDevice *self)
|
|||
priv->l3cds[L3_CONFIG_DATA_TYPE_MANUALIP].d,
|
||||
addr_family,
|
||||
flags,
|
||||
&acd_used);
|
||||
if (acd_used) {
|
||||
&conflicts);
|
||||
if (conflicts) {
|
||||
_dev_ipmanual_set_state(self, addr_family, NM_DEVICE_IP_STATE_FAILED);
|
||||
_dev_ip_state_check_async(self, AF_UNSPEC);
|
||||
} else if (ready) {
|
||||
|
|
@ -11432,10 +11444,14 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc,
|
|||
const NML3ConfigData *l3cd,
|
||||
NMDevice *self)
|
||||
{
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
gboolean ready = TRUE;
|
||||
NMDedupMultiIter iter;
|
||||
const NMPObject *obj;
|
||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self);
|
||||
gboolean ready;
|
||||
|
||||
/* The ndisc configuration changes when we receive a new RA or
|
||||
* when a lifetime expires; but also when DAD fails for a
|
||||
* SLAAC address and we need to regenerate new stable-privacy
|
||||
* addresses. In all these cases we update the AC6 configuration,
|
||||
* schedule a commit and update the AC state. */
|
||||
|
||||
_dev_ipac6_grace_period_start(self, 0, TRUE);
|
||||
|
||||
|
|
@ -11446,22 +11462,11 @@ _dev_ipac6_ndisc_config_changed(NMNDisc *ndisc,
|
|||
FALSE);
|
||||
|
||||
nm_clear_l3cd(&priv->ipac6_data.l3cd);
|
||||
|
||||
/* wait that addresses are committed to platform and
|
||||
* become non-tentative before declaring AC6 is ready.*/
|
||||
nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) {
|
||||
const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS(obj);
|
||||
const NMPlatformIP6Address *plat_addr;
|
||||
|
||||
plat_addr = nm_platform_ip6_address_get(nm_device_get_platform(self),
|
||||
nm_device_get_ip_ifindex(self),
|
||||
&addr->address);
|
||||
if (!plat_addr || (plat_addr->n_ifa_flags & IFA_F_TENTATIVE)) {
|
||||
ready = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ready = nm_l3cfg_check_ready(priv->l3cfg,
|
||||
l3cd,
|
||||
AF_INET6,
|
||||
NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY,
|
||||
NULL);
|
||||
if (ready) {
|
||||
_dev_ipac6_set_state(self, NM_DEVICE_IP_STATE_READY);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1039,35 +1039,33 @@ ipv6_lladdr_find(NMDhcpClient *self)
|
|||
static void
|
||||
ipv6_tentative_addr_check(NMDhcpClient *self,
|
||||
GPtrArray **tentative,
|
||||
GPtrArray **missing,
|
||||
GPtrArray **dadfailed,
|
||||
const NMPlatformIP6Address **valid)
|
||||
{
|
||||
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
|
||||
NMDedupMultiIter iter;
|
||||
const NMPlatformIP6Address *addr;
|
||||
NML3Cfg *l3cfg = priv->config.l3cfg;
|
||||
NML3Cfg *l3cfg = priv->config.l3cfg;
|
||||
NMPlatform *platform = nm_l3cfg_get_platform(l3cfg);
|
||||
int ifindex = nm_l3cfg_get_ifindex(l3cfg);
|
||||
|
||||
/* For each address in the lease, check whether it's tentative
|
||||
* in platform. */
|
||||
* or dad-failed in platform. */
|
||||
nm_l3_config_data_iter_ip6_address_for_each (&iter, priv->l3cd_curr, &addr) {
|
||||
const NMPlatformIP6Address *pladdr;
|
||||
NMPObject needle;
|
||||
|
||||
nmp_object_stackinit_id_ip6_address(&needle, nm_l3cfg_get_ifindex(l3cfg), &addr->address);
|
||||
pladdr = NMP_OBJECT_CAST_IP6_ADDRESS(nm_platform_lookup_obj(nm_l3cfg_get_platform(l3cfg),
|
||||
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||
&needle));
|
||||
if (!pladdr) {
|
||||
/* address removed: we assume that's because DAD failed */
|
||||
if (missing) {
|
||||
if (!*missing)
|
||||
*missing = g_ptr_array_new();
|
||||
g_ptr_array_add(*missing, (gpointer) addr);
|
||||
pladdr = nm_platform_ip6_address_get(platform, ifindex, &addr->address);
|
||||
if ((pladdr && NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_DADFAILED))
|
||||
|| (!pladdr && nm_platform_ip6_dadfailed_check(platform, ifindex, &addr->address))) {
|
||||
if (dadfailed) {
|
||||
if (!*dadfailed)
|
||||
*dadfailed = g_ptr_array_new();
|
||||
g_ptr_array_add(*dadfailed, (gpointer) addr);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE)
|
||||
if (pladdr && NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_TENTATIVE)
|
||||
&& !NM_FLAGS_HAS(pladdr->n_ifa_flags, IFA_F_OPTIMISTIC)) {
|
||||
if (tentative) {
|
||||
if (!*tentative)
|
||||
|
|
@ -1076,6 +1074,9 @@ ipv6_tentative_addr_check(NMDhcpClient *self,
|
|||
}
|
||||
}
|
||||
|
||||
/* Here the address is non-tentative or it was removed externally by the user.
|
||||
* In both cases it has completed DAD.
|
||||
*/
|
||||
NM_SET_OUT(valid, addr);
|
||||
}
|
||||
}
|
||||
|
|
@ -1115,13 +1116,13 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp
|
|||
if (notify_data->notify_type == NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE
|
||||
&& priv->l3cfg_notify.wait_ipv6_dad) {
|
||||
gs_unref_ptrarray GPtrArray *tentative = NULL;
|
||||
gs_unref_ptrarray GPtrArray *missing = NULL;
|
||||
gs_unref_ptrarray GPtrArray *dadfailed = NULL;
|
||||
const NMPlatformIP6Address *valid = NULL;
|
||||
char str[NM_UTILS_TO_STRING_BUFFER_SIZE];
|
||||
guint i;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
ipv6_tentative_addr_check(self, &tentative, &missing, &valid);
|
||||
ipv6_tentative_addr_check(self, &tentative, &dadfailed, &valid);
|
||||
if (tentative) {
|
||||
for (i = 0; i < tentative->len; i++) {
|
||||
_LOGD("still waiting DAD for address: %s",
|
||||
|
|
@ -1134,10 +1135,10 @@ l3_cfg_notify_cb(NML3Cfg *l3cfg, const NML3ConfigNotifyData *notify_data, NMDhcp
|
|||
nm_clear_g_source_inst(&priv->v6.dad_timeout_source);
|
||||
l3_cfg_notify_check_connected(self);
|
||||
|
||||
if (missing) {
|
||||
for (i = 0; i < missing->len; i++) {
|
||||
if (dadfailed) {
|
||||
for (i = 0; i < dadfailed->len; i++) {
|
||||
_LOGE("DAD failed for address: %s",
|
||||
nm_platform_ip6_address_to_string(missing->pdata[i], str, sizeof(str)));
|
||||
nm_platform_ip6_address_to_string(dadfailed->pdata[i], str, sizeof(str)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -476,12 +476,12 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr)
|
|||
priv->config.network_id,
|
||||
addr->dad_counter++,
|
||||
&error)) {
|
||||
_LOGW("complete-address: failed to generate an stable-privacy address: %s",
|
||||
_LOGW("complete-address: failed to generate a stable-privacy address: %s",
|
||||
error->message);
|
||||
g_clear_error(&error);
|
||||
return FALSE;
|
||||
}
|
||||
_LOGD("complete-address: using an stable-privacy address");
|
||||
_LOGD("complete-address: using a stable-privacy address");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -496,7 +496,7 @@ complete_address(NMNDisc *ndisc, NMNDiscAddress *addr)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
_LOGW("complete-address: can't generate a new_item EUI-64 address");
|
||||
_LOGW("complete-address: can't generate a new EUI-64 address");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -1221,28 +1221,35 @@ nm_ndisc_stop(NMNDisc *ndisc)
|
|||
}
|
||||
|
||||
NMNDiscConfigMap
|
||||
nm_ndisc_dad_failed(NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal)
|
||||
nm_ndisc_dad_failed(NMNDisc *ndisc, GArray *addresses, gboolean emit_changed_signal)
|
||||
{
|
||||
NMNDiscDataInternal *rdata;
|
||||
guint i;
|
||||
guint j;
|
||||
gboolean changed = FALSE;
|
||||
|
||||
g_return_val_if_fail(addresses, NM_NDISC_CONFIG_NONE);
|
||||
|
||||
rdata = &NM_NDISC_GET_PRIVATE(ndisc)->rdata;
|
||||
|
||||
for (i = 0; i < rdata->addresses->len;) {
|
||||
NMNDiscAddress *item = &nm_g_array_index(rdata->addresses, NMNDiscAddress, i);
|
||||
for (i = 0; i < addresses->len; i++) {
|
||||
const struct in6_addr *addr = &nm_g_array_index(addresses, struct in6_addr, i);
|
||||
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, address)) {
|
||||
char sbuf[NM_INET_ADDRSTRLEN];
|
||||
for (j = 0; j < rdata->addresses->len;) {
|
||||
NMNDiscAddress *item = &nm_g_array_index(rdata->addresses, NMNDiscAddress, j);
|
||||
|
||||
_LOGD("DAD failed for discovered address %s", nm_inet6_ntop(address, sbuf));
|
||||
changed = TRUE;
|
||||
if (!complete_address(ndisc, item)) {
|
||||
g_array_remove_index(rdata->addresses, i);
|
||||
continue;
|
||||
if (IN6_ARE_ADDR_EQUAL(&item->address, addr)) {
|
||||
char sbuf[NM_INET_ADDRSTRLEN];
|
||||
|
||||
_LOGI("DAD failed for discovered address %s", nm_inet6_ntop(addr, sbuf));
|
||||
changed = TRUE;
|
||||
if (!complete_address(ndisc, item)) {
|
||||
g_array_remove_index(rdata->addresses, j);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (emit_changed_signal && changed)
|
||||
|
|
|
|||
|
|
@ -228,9 +228,9 @@ NMNDiscNodeType nm_ndisc_get_node_type(NMNDisc *self);
|
|||
gboolean nm_ndisc_set_iid(NMNDisc *ndisc, const NMUtilsIPv6IfaceId iid, gboolean is_token);
|
||||
void nm_ndisc_start(NMNDisc *ndisc);
|
||||
void nm_ndisc_stop(NMNDisc *ndisc);
|
||||
void nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd);
|
||||
NMNDiscConfigMap
|
||||
nm_ndisc_dad_failed(NMNDisc *ndisc, const struct in6_addr *address, gboolean emit_changed_signal);
|
||||
void nm_ndisc_set_config(NMNDisc *ndisc, const NML3ConfigData *l3cd);
|
||||
nm_ndisc_dad_failed(NMNDisc *ndisc, GArray *addresses, gboolean emit_changed_signal);
|
||||
|
||||
NMPlatform *nm_ndisc_get_platform(NMNDisc *self);
|
||||
NMPNetns *nm_ndisc_netns_get(NMNDisc *self);
|
||||
|
|
|
|||
|
|
@ -2990,68 +2990,103 @@ nm_l3cfg_check_ready(NML3Cfg *self,
|
|||
const NML3ConfigData *l3cd,
|
||||
int addr_family,
|
||||
NML3CfgCheckReadyFlags flags,
|
||||
gboolean *acd_used)
|
||||
GArray **conflicts)
|
||||
{
|
||||
NMDedupMultiIter iter;
|
||||
const NMPObject *obj;
|
||||
gboolean ready = TRUE;
|
||||
|
||||
nm_assert(NM_IS_L3CFG(self));
|
||||
nm_assert_addr_family_or_unspec(addr_family);
|
||||
|
||||
NM_SET_OUT(acd_used, FALSE);
|
||||
nm_assert_addr_family(addr_family);
|
||||
nm_assert(!conflicts || !*conflicts);
|
||||
|
||||
if (!l3cd)
|
||||
return TRUE;
|
||||
|
||||
if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)
|
||||
&& NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY)) {
|
||||
gboolean pending = FALSE;
|
||||
if (addr_family == AF_INET) {
|
||||
if (NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP4_ACD_READY)) {
|
||||
nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP4_ADDRESS) {
|
||||
const NML3AcdAddrInfo *addr_info;
|
||||
|
||||
nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP4_ADDRESS) {
|
||||
const NML3AcdAddrInfo *addr_info;
|
||||
|
||||
addr_info = nm_l3cfg_get_acd_addr_info(self, NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address);
|
||||
if (!addr_info) {
|
||||
/* We don't track the this address? That's odd. Not ready. */
|
||||
pending = TRUE;
|
||||
} else {
|
||||
if (addr_info->state <= NM_L3_ACD_ADDR_STATE_PROBING) {
|
||||
/* Still probing. Not ready. */
|
||||
pending = TRUE;
|
||||
} else if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) {
|
||||
NM_SET_OUT(acd_used, TRUE);
|
||||
addr_info =
|
||||
nm_l3cfg_get_acd_addr_info(self, NMP_OBJECT_CAST_IP4_ADDRESS(obj)->address);
|
||||
if (!addr_info) {
|
||||
/* We don't track the this address? That's odd. Not ready. */
|
||||
ready = FALSE;
|
||||
} else {
|
||||
if (addr_info->state <= NM_L3_ACD_ADDR_STATE_PROBING) {
|
||||
/* Still probing. Not ready. */
|
||||
ready = FALSE;
|
||||
} else if (addr_info->state == NM_L3_ACD_ADDR_STATE_USED) {
|
||||
if (conflicts) {
|
||||
if (!*conflicts)
|
||||
*conflicts = g_array_new(FALSE,
|
||||
FALSE,
|
||||
nm_utils_addr_family_to_size(addr_family));
|
||||
g_array_append_val(*conflicts, addr_info->addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we only care that we don't have ACD still pending. Otherwise we are ready,
|
||||
* including if we have no addr_info about this address or the address is in use. */
|
||||
}
|
||||
/* we only care that we don't have ACD still pending. Otherwise we are ready,
|
||||
* including if we have no addr_info about this address or the address is in use. */
|
||||
}
|
||||
if (pending)
|
||||
return FALSE;
|
||||
return ready;
|
||||
}
|
||||
|
||||
if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)
|
||||
&& NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY)) {
|
||||
/* AF_INET6 */
|
||||
if (NM_FLAGS_HAS(flags, NM_L3CFG_CHECK_READY_FLAGS_IP6_DAD_READY)) {
|
||||
nm_l3_config_data_iter_obj_for_each (&iter, l3cd, &obj, NMP_OBJECT_TYPE_IP6_ADDRESS) {
|
||||
ObjStateData *obj_state;
|
||||
gboolean dadfailed = FALSE;
|
||||
|
||||
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj);
|
||||
|
||||
if (!obj_state) {
|
||||
/* Hm, we don't track this object? That is odd. Not ready. */
|
||||
return FALSE;
|
||||
ready = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!obj_state->os_nm_configured && !obj_state->os_plobj) {
|
||||
/* We didn't (yet) configure this address and it also is not in platform.
|
||||
* Not ready. */
|
||||
return FALSE;
|
||||
ready = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj_state->os_plobj
|
||||
&& NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags,
|
||||
IFA_F_DADFAILED)) {
|
||||
/* The address is still present with DADFAILED flag. */
|
||||
dadfailed = TRUE;
|
||||
} else if (obj_state->os_nm_configured && !obj_state->os_plobj
|
||||
&& nm_platform_ip6_dadfailed_check(
|
||||
self->priv.platform,
|
||||
self->priv.ifindex,
|
||||
&NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address)) {
|
||||
/* We configured the address and kernel removed it with DADFAILED flag. */
|
||||
dadfailed = TRUE;
|
||||
}
|
||||
|
||||
if (dadfailed) {
|
||||
if (conflicts) {
|
||||
if (!*conflicts) {
|
||||
*conflicts =
|
||||
g_array_new(FALSE, FALSE, nm_utils_addr_family_to_size(addr_family));
|
||||
}
|
||||
g_array_append_val(*conflicts,
|
||||
NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->obj)->address);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj_state->os_plobj
|
||||
&& NM_FLAGS_HAS(NMP_OBJECT_CAST_IP6_ADDRESS(obj_state->os_plobj)->n_ifa_flags,
|
||||
IFA_F_TENTATIVE)) {
|
||||
/* The address is configured in kernel, but still tentative. Not ready. */
|
||||
return FALSE;
|
||||
ready = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This address is ready. Even if it is not (not anymore) configured in kernel (as
|
||||
|
|
@ -3060,7 +3095,7 @@ nm_l3cfg_check_ready(NML3Cfg *self,
|
|||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
return ready;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ gboolean nm_l3cfg_check_ready(NML3Cfg *self,
|
|||
const NML3ConfigData *l3cd,
|
||||
int addr_family,
|
||||
NML3CfgCheckReadyFlags flags,
|
||||
gboolean *acd_used);
|
||||
GArray **conflicts);
|
||||
|
||||
gboolean nm_l3cfg_has_temp_not_available_obj(NML3Cfg *self, int addr_family);
|
||||
|
||||
|
|
|
|||
|
|
@ -6759,6 +6759,14 @@ cache_prune_one_type(NMPlatform *platform, const NMPLookup *lookup)
|
|||
|
||||
obj = main_entry->obj;
|
||||
|
||||
if (NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP6_ADDRESS) {
|
||||
const NMPlatformIP6Address *pladdr = NMP_OBJECT_CAST_IP6_ADDRESS(obj);
|
||||
|
||||
if (pladdr->n_ifa_flags & IFA_F_TENTATIVE) {
|
||||
nm_platform_ip6_dadfailed_set(platform, pladdr->ifindex, &pladdr->address, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
_LOGt("cache-prune: prune %s",
|
||||
nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_ALL, sbuf, sizeof(sbuf)));
|
||||
|
||||
|
|
@ -7672,6 +7680,14 @@ _rtnl_handle_msg(NMPlatform *platform, const struct nl_msg_lite *msg)
|
|||
}
|
||||
|
||||
case RTM_DELADDR:
|
||||
if (NMP_OBJECT_GET_TYPE(obj) == NMP_OBJECT_TYPE_IP6_ADDRESS) {
|
||||
const NMPlatformIP6Address *ip6 = NMP_OBJECT_CAST_IP6_ADDRESS(obj);
|
||||
|
||||
if (ip6->n_ifa_flags & IFA_F_DADFAILED) {
|
||||
nm_platform_ip6_dadfailed_set(platform, ip6->ifindex, &ip6->address, TRUE);
|
||||
}
|
||||
}
|
||||
/* fall-through */
|
||||
case RTM_DELLINK:
|
||||
case RTM_DELQDISC:
|
||||
case RTM_DELROUTE:
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ typedef struct _NMPlatformPrivate {
|
|||
guint ip4_dev_route_blacklist_check_id;
|
||||
guint ip4_dev_route_blacklist_gc_timeout_id;
|
||||
GHashTable *ip4_dev_route_blacklist_hash;
|
||||
CList ip6_dadfailed_lst_head;
|
||||
NMDedupMultiIndex *multi_idx;
|
||||
NMPCache *cache;
|
||||
} NMPlatformPrivate;
|
||||
|
|
@ -3607,6 +3608,9 @@ nm_platform_ip6_address_add(NMPlatform *self,
|
|||
_LOG3D("address: adding or updating IPv6 address: %s",
|
||||
nm_platform_ip6_address_to_string(&addr, sbuf, sizeof(sbuf)));
|
||||
}
|
||||
|
||||
nm_platform_ip6_dadfailed_set(self, ifindex, &address, FALSE);
|
||||
|
||||
return klass
|
||||
->ip6_address_add(self, ifindex, address, plen, peer_address, lifetime, preferred, flags);
|
||||
}
|
||||
|
|
@ -9089,6 +9093,92 @@ nm_platform_netns_push(NMPlatform *self, NMPNetns **netns)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
struct in6_addr address;
|
||||
CList lst;
|
||||
gint64 timestamp_nsec;
|
||||
int ifindex;
|
||||
} IP6DadFailedAddr;
|
||||
|
||||
static void
|
||||
ip6_dadfailed_addr_free(IP6DadFailedAddr *addr)
|
||||
{
|
||||
c_list_unlink_stale(&addr->lst);
|
||||
nm_g_slice_free(addr);
|
||||
}
|
||||
|
||||
static void
|
||||
ip6_dadfailed_prune_old(NMPlatform *self, gint64 now_nsec)
|
||||
{
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
IP6DadFailedAddr *addr;
|
||||
IP6DadFailedAddr *safe;
|
||||
|
||||
c_list_for_each_entry_safe (addr, safe, &priv->ip6_dadfailed_lst_head, lst) {
|
||||
if (addr->timestamp_nsec + (10 * NM_UTILS_NSEC_PER_SEC) > now_nsec)
|
||||
break;
|
||||
ip6_dadfailed_addr_free(addr);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_platform_ip6_dadfailed_check(NMPlatform *self, int ifindex, const struct in6_addr *ip6)
|
||||
{
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
IP6DadFailedAddr *addr;
|
||||
|
||||
ip6_dadfailed_prune_old(self, nm_utils_get_monotonic_timestamp_nsec());
|
||||
|
||||
c_list_for_each_entry_prev (addr, &priv->ip6_dadfailed_lst_head, lst) {
|
||||
if (addr->ifindex == ifindex && IN6_ARE_ADDR_EQUAL(&addr->address, ip6)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* If an IPv6 address fails DAD and has infinite lifetime, kernel just
|
||||
* sets the DADFAILED flag. However when the address has a finite
|
||||
* lifetime kernel deletes it immediately and the RTM_DELLINK netlink
|
||||
* message contains the DADFAILED flag. In the second case, we remove
|
||||
* the address from the platform cache and there is no way for
|
||||
* platform's clients to check whether DAD failed. To work around
|
||||
* this, we store all deleted-with-DADFAILED addresses and provide a
|
||||
* mechanism to access them.
|
||||
*/
|
||||
void
|
||||
nm_platform_ip6_dadfailed_set(NMPlatform *self,
|
||||
int ifindex,
|
||||
const struct in6_addr *ip6,
|
||||
gboolean failed)
|
||||
{
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
gint64 now_nsec = nm_utils_get_monotonic_timestamp_nsec();
|
||||
IP6DadFailedAddr *addr;
|
||||
IP6DadFailedAddr *safe;
|
||||
|
||||
ip6_dadfailed_prune_old(self, now_nsec);
|
||||
|
||||
if (failed) {
|
||||
addr = g_slice_new(IP6DadFailedAddr);
|
||||
*addr = (IP6DadFailedAddr){
|
||||
.address = *ip6,
|
||||
.ifindex = ifindex,
|
||||
.timestamp_nsec = now_nsec,
|
||||
};
|
||||
c_list_link_tail(&priv->ip6_dadfailed_lst_head, &addr->lst);
|
||||
} else {
|
||||
c_list_for_each_entry_safe (addr, safe, &priv->ip6_dadfailed_lst_head, lst) {
|
||||
if (addr->ifindex == ifindex && IN6_ARE_ADDR_EQUAL(&addr->address, ip6)) {
|
||||
ip6_dadfailed_addr_free(addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
|
||||
.v4 =
|
||||
{
|
||||
|
|
@ -9174,8 +9264,8 @@ constructor(GType type, guint n_construct_params, GObjectConstructParam *constru
|
|||
priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
|
||||
priv->multi_idx = nm_dedup_multi_index_new();
|
||||
|
||||
priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev);
|
||||
priv->cache = nmp_cache_new(priv->multi_idx, priv->use_udev);
|
||||
c_list_init(&priv->ip6_dadfailed_lst_head);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
|
@ -9185,6 +9275,7 @@ finalize(GObject *object)
|
|||
{
|
||||
NMPlatform *self = NM_PLATFORM(object);
|
||||
NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
|
||||
IP6DadFailedAddr *addr;
|
||||
|
||||
nm_clear_g_source(&priv->ip4_dev_route_blacklist_check_id);
|
||||
nm_clear_g_source(&priv->ip4_dev_route_blacklist_gc_timeout_id);
|
||||
|
|
@ -9193,6 +9284,10 @@ finalize(GObject *object)
|
|||
nm_dedup_multi_index_unref(priv->multi_idx);
|
||||
nmp_cache_free(priv->cache);
|
||||
|
||||
while ((addr = c_list_first_entry(&priv->ip6_dadfailed_lst_head, IP6DadFailedAddr, lst))) {
|
||||
ip6_dadfailed_addr_free(addr);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS(nm_platform_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2386,4 +2386,10 @@ nm_platform_mptcp_addr_update(NMPlatform *self, NMOptionBool add, const NMPlatfo
|
|||
|
||||
GPtrArray *nm_platform_mptcp_addrs_dump(NMPlatform *self);
|
||||
|
||||
gboolean nm_platform_ip6_dadfailed_check(NMPlatform *self, int ifindex, const struct in6_addr *ip6);
|
||||
void nm_platform_ip6_dadfailed_set(NMPlatform *self,
|
||||
int ifindex,
|
||||
const struct in6_addr *ip6,
|
||||
gboolean failed);
|
||||
|
||||
#endif /* __NETWORKMANAGER_PLATFORM_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue