summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2020-09-19 12:20:45 +0200
committerThomas Haller <thaller@redhat.com>2020-09-24 09:44:01 +0200
commit042112ea2d0855132c8b8c7c15279098ae1e129a (patch)
treec2f9ea68511d0e2c152571cdd374644a4aecf4d3
parentd627ec7075eb97ebf8994b621558fb4f0260a4c2 (diff)
downloadNetworkManager-042112ea2d0855132c8b8c7c15279098ae1e129a.tar.gz
l3cfg: various fixes for l3cfg
-rw-r--r--src/devices/nm-device.c20
-rw-r--r--src/nm-l3-config-data.c23
-rw-r--r--src/nm-l3cfg.c327
-rw-r--r--src/nm-l3cfg.h20
-rw-r--r--src/nm-netns.c1
5 files changed, 244 insertions, 147 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 4d9f1c0ef4..ebff5f1cf8 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -2967,12 +2967,7 @@ _dev_l3_platform_commit (NMDevice *self)
if (nm_device_sys_iface_state_is_external (self))
return TRUE;
- success = nm_l3cfg_platform_commit (priv->l3cfg,
- nm_device_sys_iface_state_is_external_or_assume (self)
- ? NM_L3_CFG_COMMIT_TYPE_ASSUME
- : NM_L3_CFG_COMMIT_TYPE_UPDATE,
- AF_UNSPEC,
- NULL);
+ success = nm_l3cfg_platform_commit (priv->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO);
return success;
}
@@ -2993,11 +2988,16 @@ _dev_l3_cfg_notify_cb (NML3Cfg *l3cfg,
nm_assert (l3cfg == priv->l3cfg);
switch ((NML3ConfigNotifyType) notify_type_i) {
- case NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED: {
- const NML3ConfigNotifyPayloadAcdFailedSource *sources = payload->acd_failed.sources;
- guint sources_len = payload->acd_failed.sources_len;
+ case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED: {
+ const NML3ConfigNotifyPayloadAcdFailedSource *sources = payload->acd_completed.sources;
+ guint sources_len = payload->acd_completed.sources_len;
guint i;
+ if (payload->acd_completed.probe_result) {
+ /* FIXME(l3cfg) */
+ return;
+ }
+
for (i = 0; i < sources_len; i++) {
L3ConfigDataType l3cd_type = _dev_l3_config_data_tag_to_type (self, sources[i].tag);
@@ -3011,7 +3011,7 @@ _dev_l3_cfg_notify_cb (NML3Cfg *l3cfg,
_dev_l3_cfg_acd_maybe_comlete (self);
return;
}
- case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
+ case NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT:
_dev_l3_cfg_acd_maybe_comlete (self);
return;
case NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE:
diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c
index 2de59963c6..4d2b99eba7 100644
--- a/src/nm-l3-config-data.c
+++ b/src/nm-l3-config-data.c
@@ -683,7 +683,7 @@ nm_l3_config_data_new (NMDedupMultiIndex *multi_idx,
};
_idx_type_init (&self->idx_addresses_4, NMP_OBJECT_TYPE_IP4_ADDRESS);
- _idx_type_init (&self->idx_addresses_6, NMP_OBJECT_TYPE_IP4_ADDRESS);
+ _idx_type_init (&self->idx_addresses_6, NMP_OBJECT_TYPE_IP6_ADDRESS);
_idx_type_init (&self->idx_routes_4, NMP_OBJECT_TYPE_IP4_ROUTE);
_idx_type_init (&self->idx_routes_6, NMP_OBJECT_TYPE_IP6_ROUTE);
@@ -1859,7 +1859,7 @@ _dedup_multi_index_cmp (const NML3ConfigData *a,
have_a = nm_platform_dedup_multi_iter_next_obj (&iter_a, &obj_a, obj_type);
if (!have_a) {
nm_assert (!nm_platform_dedup_multi_iter_next_obj (&iter_b, &obj_b, obj_type));
- break;
+ return 0;
}
have_b = nm_platform_dedup_multi_iter_next_obj (&iter_b, &obj_b, obj_type);
@@ -1867,8 +1867,6 @@ _dedup_multi_index_cmp (const NML3ConfigData *a,
NM_CMP_RETURN (nmp_object_cmp (obj_a, obj_b));
}
-
- return 0;
}
int
@@ -1882,10 +1880,10 @@ nm_l3_config_data_cmp (const NML3ConfigData *a, const NML3ConfigData *b)
NM_CMP_DIRECT (a->flags, b->flags);
- _dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ADDRESS);
- _dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ADDRESS);
- _dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ROUTE);
- _dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ROUTE);
+ NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ADDRESS));
+ NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ADDRESS));
+ NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP4_ROUTE));
+ NM_CMP_RETURN (_dedup_multi_index_cmp (a, b, NMP_OBJECT_TYPE_IP6_ROUTE));
for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) {
const int addr_family = IS_IPv4 ? AF_INET : AF_INET6;
@@ -2705,17 +2703,20 @@ nm_l3_config_data_merge (NML3ConfigData *self,
if (self->ip6_privacy == NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN)
self->ip6_privacy = src->ip6_privacy;
- if (!self->ndisc_hop_limit_set) {
+ if ( !self->ndisc_hop_limit_set
+ && src->ndisc_hop_limit_set) {
self->ndisc_hop_limit_set = TRUE;
self->ndisc_hop_limit_val = src->ndisc_hop_limit_val;
}
- if (!self->ndisc_reachable_time_msec_set) {
+ if ( !self->ndisc_reachable_time_msec_set
+ && src->ndisc_reachable_time_msec_set) {
self->ndisc_reachable_time_msec_set = TRUE;
self->ndisc_reachable_time_msec_val = src->ndisc_reachable_time_msec_val;
}
- if (!self->ndisc_retrans_timer_msec_set) {
+ if ( !self->ndisc_retrans_timer_msec_set
+ && src->ndisc_retrans_timer_msec_set) {
self->ndisc_retrans_timer_msec_set = TRUE;
self->ndisc_retrans_timer_msec_val = src->ndisc_retrans_timer_msec_val;
}
diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c
index 272b79e3d6..c1ac8a6a81 100644
--- a/src/nm-l3cfg.c
+++ b/src/nm-l3cfg.c
@@ -29,7 +29,7 @@ ACD_ADDR_SKIP (in_addr_t addr)
return addr == 0u;
}
-#define ACD_TRACK_FMT "["NM_HASH_OBFUSCATE_PTR_FMT","NM_HASH_OBFUSCATE_PTR_FMT","NM_HASH_OBFUSCATE_PTR_FMT"]"
+#define ACD_TRACK_FMT "[l3cd="NM_HASH_OBFUSCATE_PTR_FMT",obj="NM_HASH_OBFUSCATE_PTR_FMT",tag="NM_HASH_OBFUSCATE_PTR_FMT"]"
#define ACD_TRACK_PTR2(l3cd, obj, tag) NM_HASH_OBFUSCATE_PTR (l3cd), NM_HASH_OBFUSCATE_PTR (obj), NM_HASH_OBFUSCATE_PTR (tag)
#define ACD_TRACK_PTR(acd_track) ACD_TRACK_PTR2 ((acd_track)->l3cd, (acd_track)->obj, (acd_track)->tag)
@@ -74,6 +74,7 @@ typedef struct {
guint32 probing_timeout_msec;
CList acd_lst;
+ CList acd_notify_complete_lst;
CList acd_track_lst_head;
NML3Cfg *self;
@@ -94,6 +95,8 @@ typedef struct {
bool probe_result:1;
bool announcing_failed_is_retrying:1;
+
+ bool initializing:1;
} AcdData;
struct _NML3CfgCommitTypeHandle {
@@ -151,6 +154,8 @@ typedef struct _NML3CfgPrivate {
GHashTable *acd_lst_hash;
CList acd_lst_head;
+ CList acd_notify_complete_lst_head;
+
NAcd *nacd;
GSource *nacd_source;
@@ -179,6 +184,8 @@ typedef struct _NML3CfgPrivate {
guint routes_temporary_not_available_id;
+ bool commit_type_update_sticky:1;
+
bool acd_is_pending:1;
bool acd_is_announcing:1;
@@ -219,6 +226,8 @@ G_DEFINE_TYPE (NML3Cfg, nm_l3cfg, G_TYPE_OBJECT)
static void _property_emit_notify (NML3Cfg *self, NML3CfgPropertyEmitType emit_type);
+static void _l3_acd_data_notify_acd_completed_all (NML3Cfg *self);
+
static gboolean _acd_has_valid_link (const NMPObject *obj,
const guint8 **out_addr_bin,
gboolean *out_acd_not_supported);
@@ -249,21 +258,70 @@ NM_UTILS_ENUM2STR_DEFINE (_l3_cfg_commit_type_to_string, NML3CfgCommitType,
NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_REAPPLY, "reapply"),
);
+static
+NM_UTILS_ENUM2STR_DEFINE (_l3_config_notify_type_to_string, NML3ConfigNotifyType,
+ NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, "acd-complete"),
+ NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE, "platform-change-on-idle"),
+ NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, "post-commit"),
+ NM_UTILS_ENUM2STR (NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED, "routes-temporary-not-available-expired"),
+ NM_UTILS_ENUM2STR_IGNORE (_NM_L3_CONFIG_NOTIFY_TYPE_NUM),
+);
+
/*****************************************************************************/
-static void
-_l3cfg_emit_signal_notify (NML3Cfg *self,
- NML3ConfigNotifyType notify_type,
- const NML3ConfigNotifyPayload *pay_load)
+static const char *
+_l3_config_notify_type_and_payload_to_string (NML3ConfigNotifyType notify_type,
+ const NML3ConfigNotifyPayload *payload,
+ char *sbuf,
+ gsize sbuf_size)
{
+ char sbuf_addr[NM_UTILS_INET_ADDRSTRLEN];
+ char *s = sbuf;
+ gsize l = sbuf_size;
+
+ nm_assert (sbuf);
+ nm_assert (sbuf_size > 0);
+
+ _l3_config_notify_type_to_string (notify_type, s, l);
+ nm_utils_strbuf_seek_end (&s, &l);
+
+ switch (notify_type) {
+ case NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED:
+ nm_utils_strbuf_append (&s, &l, ", addr=%s, probe-result=%d",
+ _nm_utils_inet4_ntop (payload->acd_completed.addr, sbuf_addr),
+ (int) payload->acd_completed.probe_result);
+ break;
+ case NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE:
+ nm_utils_strbuf_append (&s, &l, ", obj-type-flags=0x%x",
+ payload->platform_change_on_idle.obj_type_flags);
+ break;
+ default:
+ break;
+ }
+
+ return sbuf;
+}
+
+void
+_nm_l3cfg_emit_signal_notify (NML3Cfg *self,
+ NML3ConfigNotifyType notify_type,
+ const NML3ConfigNotifyPayload *payload)
+{
+ char sbuf[100];
+
nm_assert (_NM_INT_NOT_NEGATIVE (notify_type));
nm_assert (notify_type < _NM_L3_CONFIG_NOTIFY_TYPE_NUM);
+ nm_assert ((!!payload) == NM_IN_SET (notify_type, NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE));
+
+ _LOGT ("emit signal (%s)",
+ _l3_config_notify_type_and_payload_to_string (notify_type, payload, sbuf, sizeof (sbuf)));
g_signal_emit (self,
signals[SIGNAL_NOTIFY],
0,
(int) notify_type,
- pay_load);
+ payload);
}
/*****************************************************************************/
@@ -271,6 +329,7 @@ _l3cfg_emit_signal_notify (NML3Cfg *self,
static void
_l3_changed_configs_set_dirty (NML3Cfg *self)
{
+ _LOGT ("configuration changed");
self->priv.changed_configs = TRUE;
}
@@ -378,49 +437,17 @@ _l3cfg_externally_removed_objs_counter (NML3Cfg *self,
}
static void
-_l3cfg_externally_removed_objs_drop (NML3Cfg *self,
- int addr_family)
+_l3cfg_externally_removed_objs_drop (NML3Cfg *self)
{
- const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family);
- GHashTableIter iter;
- const NMPObject *obj;
-
nm_assert (NM_IS_L3CFG (self));
- nm_assert (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET, AF_INET6));
-
- if (addr_family == AF_UNSPEC) {
- self->priv.p->externally_removed_objs_cnt_addresses_4 = 0;
- self->priv.p->externally_removed_objs_cnt_addresses_6 = 0;
- self->priv.p->externally_removed_objs_cnt_routes_4 = 0;
- self->priv.p->externally_removed_objs_cnt_routes_6 = 0;
- if (g_hash_table_size (self->priv.p->externally_removed_objs_hash) > 0)
- _LOGD ("externally-removed: untrack all");
- nm_clear_pointer (&self->priv.p->externally_removed_objs_hash, g_hash_table_unref);
- return;
- }
-
- if ( self->priv.p->externally_removed_objs_cnt_addresses_x[IS_IPv4] == 0
- && self->priv.p->externally_removed_objs_cnt_routes_x[IS_IPv4] == 0)
- return;
-
- _LOGD ("externally-removed: untrack IPv%c",
- nm_utils_addr_family_to_char (addr_family));
-
- g_hash_table_iter_init (&iter, self->priv.p->externally_removed_objs_hash);
- while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) {
- nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ADDRESS,
- NMP_OBJECT_TYPE_IP6_ADDRESS,
- NMP_OBJECT_TYPE_IP4_ROUTE,
- NMP_OBJECT_TYPE_IP6_ROUTE));
- if (NMP_OBJECT_GET_ADDR_FAMILY (obj) != addr_family)
- g_hash_table_iter_remove (&iter);
- }
- self->priv.p->externally_removed_objs_cnt_addresses_x[IS_IPv4] = 0;
- self->priv.p->externally_removed_objs_cnt_routes_x[IS_IPv4] = 0;
- if ( self->priv.p->externally_removed_objs_cnt_addresses_x[!IS_IPv4] == 0
- && self->priv.p->externally_removed_objs_cnt_routes_x[!IS_IPv4] == 0)
- nm_clear_pointer (&self->priv.p->externally_removed_objs_hash, g_hash_table_unref);
+ self->priv.p->externally_removed_objs_cnt_addresses_4 = 0;
+ self->priv.p->externally_removed_objs_cnt_addresses_6 = 0;
+ self->priv.p->externally_removed_objs_cnt_routes_4 = 0;
+ self->priv.p->externally_removed_objs_cnt_routes_6 = 0;
+ if (nm_g_hash_table_size (self->priv.p->externally_removed_objs_hash) > 0)
+ _LOGD ("externally-removed: untrack all");
+ nm_clear_pointer (&self->priv.p->externally_removed_objs_hash, g_hash_table_unref);
}
static void
@@ -436,7 +463,7 @@ _l3cfg_externally_removed_objs_drop_unused (NML3Cfg *self)
return;
if (!self->priv.p->combined_l3cd_commited) {
- _l3cfg_externally_removed_objs_drop (self, AF_UNSPEC);
+ _l3cfg_externally_removed_objs_drop (self);
return;
}
@@ -482,8 +509,8 @@ _l3cfg_externally_removed_objs_track (NML3Cfg *self,
return;
}
- if (!nm_l3_config_data_lookup_route_obj (self->priv.p->combined_l3cd_commited,
- obj)) {
+ if (!nm_l3_config_data_lookup_obj (self->priv.p->combined_l3cd_commited,
+ obj)) {
/* we don't care about this object, so there is nothing to hide hide */
return;
}
@@ -630,9 +657,11 @@ _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags)
.obj_type_flags = obj_type_flags,
},
};
- _l3cfg_emit_signal_notify (self,
- NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE,
- &payload);
+ _nm_l3cfg_emit_signal_notify (self,
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE,
+ &payload);
+
+ _l3_acd_data_notify_acd_completed_all (self);
if (NM_FLAGS_ANY (obj_type_flags, nmp_object_type_to_flags (NMP_OBJECT_TYPE_IP4_ROUTE)))
_property_emit_notify (self, NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE);
@@ -909,11 +938,8 @@ _l3_acd_platform_commit_acd_update (NML3Cfg *self)
*
* This makes the mechanism also suitable for internally triggering a commit when ACD completes. */
_LOGT ("acd: acd update now");
- _l3_changed_configs_set_dirty (self);
nm_l3cfg_platform_commit (self,
- NM_L3_CFG_COMMIT_TYPE_AUTO,
- AF_INET,
- NULL);
+ NM_L3_CFG_COMMIT_TYPE_AUTO);
}
static gboolean
@@ -950,6 +976,7 @@ _l3_acd_nacd_event (int fd,
gpointer user_data)
{
NML3Cfg *self = user_data;
+ gboolean success = FALSE;
int r;
nm_assert (NM_IS_L3CFG (self));
@@ -958,7 +985,7 @@ _l3_acd_nacd_event (int fd,
r = n_acd_dispatch (self->priv.p->nacd);
if (!NM_IN_SET (r, 0, N_ACD_E_PREEMPTED)) {
_LOGT ("acd: dispatch failed with error %d", r);
- goto handle_failure;
+ goto out;
}
while (TRUE) {
@@ -968,10 +995,12 @@ _l3_acd_nacd_event (int fd,
r = n_acd_pop_event (self->priv.p->nacd, &event);
if (r) {
_LOGT ("acd: pop-event failed with error %d", r);
- goto handle_failure;
+ goto out;
+ }
+ if (!event) {
+ success = TRUE;
+ goto out;
}
- if (!event)
- return G_SOURCE_CONTINUE;
#define _acd_event_payload used
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NAcdEvent, _acd_event_payload) == G_STRUCT_OFFSET (NAcdEvent, defended));
@@ -1040,10 +1069,15 @@ _l3_acd_nacd_event (int fd,
nm_assert_not_reached ();
-handle_failure:
- /* Something is seriously wrong with our nacd instance. We handle that by resetting the
- * ACD instance. */
- _l3_acd_nacd_instance_reset (self, NM_TERNARY_TRUE, TRUE);
+out:
+ if (!success) {
+ /* Something is seriously wrong with our nacd instance. We handle that by resetting the
+ * ACD instance. */
+ _l3_acd_nacd_instance_reset (self, NM_TERNARY_TRUE, TRUE);
+ }
+
+ _l3_acd_data_notify_acd_completed_all (self);
+
return G_SOURCE_CONTINUE;
}
@@ -1054,6 +1088,7 @@ _l3_acd_nacd_instance_ensure_retry_cb (gpointer user_data)
nm_clear_g_source_inst (&self->priv.p->nacd_instance_ensure_retry);
+ _l3_changed_configs_set_dirty (self);
_l3_acd_platform_commit_acd_update (self);
return G_SOURCE_REMOVE;
@@ -1294,12 +1329,14 @@ _l3_acd_data_add (NML3Cfg *self,
acd_data = g_slice_new (AcdData);
*acd_data = (AcdData) {
- .self = self,
- .addr = addr,
- .acd_track_lst_head = C_LIST_INIT (acd_data->acd_track_lst_head),
- .acd_state = ACD_STATE_INIT,
- .probing_timestamp_msec = 0,
- .probe_result = FALSE,
+ .self = self,
+ .addr = addr,
+ .acd_track_lst_head = C_LIST_INIT (acd_data->acd_track_lst_head),
+ .acd_notify_complete_lst = C_LIST_INIT (acd_data->acd_notify_complete_lst),
+ .acd_state = ACD_STATE_INIT,
+ .probing_timestamp_msec = 0,
+ .probe_result = FALSE,
+ .initializing = TRUE,
};
c_list_link_tail (&self->priv.p->acd_lst_head, &acd_data->acd_lst);
if (!g_hash_table_add (self->priv.p->acd_lst_hash, acd_data))
@@ -1480,9 +1517,9 @@ _l3_acd_data_timeout_schedule_announce_restart (AcdData *acd_data,
}
static void
-_l3_acd_data_notify_acd_failed (NML3Cfg *self,
- AcdData *acd_data,
- gboolean force_all)
+_l3_acd_data_notify_acd_completed (NML3Cfg *self,
+ AcdData *acd_data,
+ gboolean force_all)
{
gs_free NML3ConfigNotifyPayloadAcdFailedSource *sources_free = NULL;
NML3ConfigNotifyPayloadAcdFailedSource *sources = NULL;
@@ -1533,14 +1570,17 @@ _l3_acd_data_notify_acd_failed (NML3Cfg *self,
nm_assert (i == n);
payload = (NML3ConfigNotifyPayload) {
- .acd_failed = {
- .addr = acd_data->addr,
- .sources_len = n,
- .sources = sources,
+ .acd_completed = {
+ .addr = acd_data->addr,
+ .probe_result = acd_data->probe_result,
+ .sources_len = n,
+ .sources = sources,
},
};
- _l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED, &payload);
+ _nm_l3cfg_emit_signal_notify (self,
+ NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
+ &payload);
for (i = 0; i < n; i++) {
nmp_object_unref (sources[i].obj);
@@ -1549,6 +1589,30 @@ _l3_acd_data_notify_acd_failed (NML3Cfg *self,
}
static void
+_l3_acd_data_notify_acd_completed_queue (NML3Cfg *self, AcdData *acd_data)
+{
+ if (!c_list_is_empty (&acd_data->acd_notify_complete_lst)) {
+ nm_assert (c_list_contains (&self->priv.p->acd_notify_complete_lst_head, &acd_data->acd_notify_complete_lst));
+ return;
+ }
+ c_list_link_tail (&self->priv.p->acd_notify_complete_lst_head, &acd_data->acd_notify_complete_lst);
+}
+
+static void
+_l3_acd_data_notify_acd_completed_all (NML3Cfg *self)
+{
+ gs_unref_object NML3Cfg *self_keep_alive = NULL;
+ AcdData *acd_data;
+
+ while ((acd_data = c_list_first_entry (&self->priv.p->acd_notify_complete_lst_head, AcdData, acd_notify_complete_lst))) {
+ if (!self_keep_alive)
+ self_keep_alive = g_object_ref (self);
+ c_list_unlink (&acd_data->acd_notify_complete_lst);
+ _l3_acd_data_notify_acd_completed (self, acd_data, TRUE);
+ }
+}
+
+static void
_l3_acd_data_state_change (NML3Cfg *self,
AcdData *acd_data,
AcdStateChangeMode state_change_mode,
@@ -1634,14 +1698,12 @@ _l3_acd_data_state_change (NML3Cfg *self,
* ACD_STATE_PROBE_DONE and configure the address right away. This avoids
* that we go through another hop.
*/
- _LOGT_acd (acd_data,
- "state: probe-done good (ACD disabled by configuration from the start)");
- acd_data->acd_state = ACD_STATE_PROBE_DONE;
- acd_data->probe_result = TRUE;
- return;
+ log_reason = "ACD disabled by configuration from the start";
+ goto handle_probing_acd_good;
}
case ACD_STATE_CHANGE_MODE_POST_COMMIT:
+ acd_data->initializing = FALSE;
goto handle_post_commit;
case ACD_STATE_CHANGE_MODE_TIMEOUT: {
@@ -1865,6 +1927,7 @@ _l3_acd_data_state_change (NML3Cfg *self,
return;
case ACD_STATE_CHANGE_MODE_INSTANCE_RESET:
+ nm_utils_get_monotonic_timestamp_msec_cached (&now_msec);
if (acd_data->acd_state <= ACD_STATE_PROBING) {
nm_assert (acd_data->acd_state == ACD_STATE_PROBING);
@@ -1890,7 +1953,7 @@ _l3_acd_data_state_change (NML3Cfg *self,
acd_data->nacd_probe = n_acd_probe_free (acd_data->nacd_probe);
acd_data->acd_state = ACD_STATE_PROBE_DONE;
_l3_acd_data_timeout_schedule (acd_data, now_msec, now_msec, TRUE);
- break;
+ return;
}
nm_assert_not_reached ();
@@ -2045,7 +2108,7 @@ handle_probing_acd_good:
switch (acd_data->acd_state) {
case ACD_STATE_INIT:
_LOGT_acd (acd_data,
- "state: probe-done good (%s, inializingbcwin)",
+ "state: probe-done good (%s, initializing)",
log_reason);
acd_data->acd_state = ACD_STATE_PROBE_DONE;
acd_data->probe_result = TRUE;
@@ -2080,7 +2143,7 @@ handle_probe_done:
nm_assert (NM_IN_SET (acd_data->acd_state, ACD_STATE_PROBE_DONE,
ACD_STATE_ANNOUNCING));
- if (state_change_mode == ACD_STATE_CHANGE_MODE_INIT)
+ if (acd_data->initializing)
return;
if (acd_data->acd_state >= ACD_STATE_ANNOUNCING) {
@@ -2100,7 +2163,7 @@ handle_probe_done:
acd_data->probing_timestamp_msec = nm_utils_get_monotonic_timestamp_msec_cached (&now_msec);
_l3_acd_data_timeout_schedule_probing_full_restart (acd_data, now_msec);
}
- _l3_acd_data_notify_acd_failed (self, acd_data, was_probing);
+ _l3_acd_data_notify_acd_completed_queue (self, acd_data);
return;
}
@@ -2109,8 +2172,10 @@ handle_probe_done:
/* probing just completed. Schedule handling the change. */
_LOGT_acd (acd_data,
"state: acd probe succeed");
+ _l3_acd_data_notify_acd_completed_queue (self, acd_data);
if (!self->priv.p->acd_ready_on_idle_source) {
- _l3_changed_configs_set_dirty (self);
+ if (state_change_mode != ACD_STATE_CHANGE_MODE_POST_COMMIT)
+ _l3_changed_configs_set_dirty (self);
self->priv.p->acd_ready_on_idle_source = nm_g_idle_source_new (G_PRIORITY_DEFAULT,
_l3_acd_ready_on_idle_cb,
self,
@@ -2187,6 +2252,8 @@ _l3_acd_data_process_changes (NML3Cfg *self)
if ( !acd_is_pending
&& !acd_is_announcing)
_l3_acd_nacd_instance_reset (self, NM_TERNARY_DEFAULT, FALSE);
+
+ _l3_acd_data_notify_acd_completed_all (self);
}
/*****************************************************************************/
@@ -2359,7 +2426,8 @@ nm_l3cfg_add_config (NML3Cfg *self,
tag,
replace_same_tag ? NULL : l3cd);
- if (replace_same_tag) {
+ if ( replace_same_tag
+ && idx >= 0) {
gssize idx2;
idx2 = idx;
@@ -2663,7 +2731,7 @@ _routes_temporary_not_available_timeout (gpointer user_data)
if (any_expired) {
/* a route expired. We emit a signal, but we don't schedule it again. That will
* only happen if the user calls nm_l3cfg_platform_commit() again. */
- _l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED, NULL);
+ _nm_l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED, NULL);
return G_SOURCE_REMOVE;
}
@@ -2921,48 +2989,65 @@ _platform_commit (NML3Cfg *self,
gboolean
nm_l3cfg_platform_commit (NML3Cfg *self,
- NML3CfgCommitType commit_type,
- int addr_family,
- gboolean *out_final_failure_for_temporary_not_available)
+ NML3CfgCommitType commit_type)
{
+ gboolean commit_type_detected = FALSE;
gboolean success = TRUE;
- gboolean acd_was_pending;
+ char sbuf_ct[30];
g_return_val_if_fail (NM_IS_L3CFG (self), FALSE);
- nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_AUTO,
- NM_L3_CFG_COMMIT_TYPE_NONE,
- NM_L3_CFG_COMMIT_TYPE_REAPPLY,
+ nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_NONE,
+ NM_L3_CFG_COMMIT_TYPE_AUTO,
+ NM_L3_CFG_COMMIT_TYPE_ASSUME,
NM_L3_CFG_COMMIT_TYPE_UPDATE,
- NM_L3_CFG_COMMIT_TYPE_ASSUME));
+ NM_L3_CFG_COMMIT_TYPE_REAPPLY));
- NM_SET_OUT (out_final_failure_for_temporary_not_available, FALSE);
+ switch (commit_type) {
+ case NM_L3_CFG_COMMIT_TYPE_AUTO:
+ /* if in "AUTO" mode we currently have commit-type "UPDATE", that
+ * causes also the following update to still be "UPDATE". Either
+ * the same commit */
+ commit_type_detected = TRUE;
+ commit_type = nm_l3cfg_commit_type_get (self);
+ if (commit_type == NM_L3_CFG_COMMIT_TYPE_UPDATE)
+ self->priv.p->commit_type_update_sticky = TRUE;
+ else if (self->priv.p->commit_type_update_sticky) {
+ self->priv.p->commit_type_update_sticky = FALSE;
+ commit_type = NM_L3_CFG_COMMIT_TYPE_UPDATE;
+ }
+ break;
+ case NM_L3_CFG_COMMIT_TYPE_ASSUME:
+ break;
+ case NM_L3_CFG_COMMIT_TYPE_REAPPLY:
+ case NM_L3_CFG_COMMIT_TYPE_UPDATE:
+ self->priv.p->commit_type_update_sticky = FALSE;
+ break;
+ case NM_L3_CFG_COMMIT_TYPE_NONE:
+ break;
+ }
- acd_was_pending = self->priv.p->acd_is_pending;
+ _LOGT ("platform-commit %s%s",
+ _l3_cfg_commit_type_to_string (commit_type, sbuf_ct, sizeof (sbuf_ct)),
+ commit_type_detected ? " (auto)" : "");
- if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET))
- nm_clear_g_source_inst (&self->priv.p->acd_ready_on_idle_source);
+ if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE)
+ return TRUE;
- if (commit_type == NM_L3_CFG_COMMIT_TYPE_AUTO)
- commit_type = nm_l3cfg_commit_type_get (self);
+ nm_clear_g_source_inst (&self->priv.p->acd_ready_on_idle_source);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY)
- _l3cfg_externally_removed_objs_drop (self, addr_family);
+ _l3cfg_externally_removed_objs_drop (self);
- if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET)) {
- if (!_platform_commit (self, AF_INET, commit_type, out_final_failure_for_temporary_not_available))
- success = FALSE;
- }
- if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6)) {
- if (!_platform_commit (self, AF_INET6, commit_type, out_final_failure_for_temporary_not_available))
- success = FALSE;
- }
+ /* FIXME(l3cfg): handle items currently not configurable in kernel. */
- if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET))
- _l3_acd_data_process_changes (self);
+ if (!_platform_commit (self, AF_INET, commit_type, NULL))
+ success = FALSE;
+ if (!_platform_commit (self, AF_INET6, commit_type, NULL))
+ success = FALSE;
+
+ _l3_acd_data_process_changes (self);
- if ( acd_was_pending
- && !self->priv.p->acd_is_pending)
- _l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED, NULL);
+ _nm_l3cfg_emit_signal_notify (self, NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT, NULL);
return success;
}
@@ -3009,8 +3094,7 @@ nm_l3cfg_commit_type_register (NML3Cfg *self,
nm_assert (NM_IS_L3CFG (self));
nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_NONE,
NM_L3_CFG_COMMIT_TYPE_ASSUME,
- NM_L3_CFG_COMMIT_TYPE_UPDATE,
- NM_L3_CFG_COMMIT_TYPE_REAPPLY));
+ NM_L3_CFG_COMMIT_TYPE_UPDATE));
nm_assert ( !existing_handle
|| c_list_contains (&self->priv.p->commit_type_lst_head, &existing_handle->commit_type_lst));
@@ -3037,6 +3121,7 @@ nm_l3cfg_commit_type_register (NML3Cfg *self,
if (handle->commit_type >= h->commit_type) {
c_list_link_before (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst);
linked = TRUE;
+ break;
}
}
if (!linked)
@@ -3175,6 +3260,7 @@ nm_l3cfg_init (NML3Cfg *self)
self->priv.p = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_L3CFG, NML3CfgPrivate);
c_list_init (&self->priv.p->acd_lst_head);
+ c_list_init (&self->priv.p->acd_notify_complete_lst_head);
c_list_init (&self->priv.p->commit_type_lst_head);
}
@@ -3223,6 +3309,7 @@ finalize (GObject *object)
_l3_acd_data_prune (self, TRUE);
nm_assert (c_list_is_empty (&self->priv.p->acd_lst_head));
+ nm_assert (c_list_is_empty (&self->priv.p->acd_notify_complete_lst_head));
nm_assert (nm_g_hash_table_size (self->priv.p->acd_lst_hash) == 0);
nm_clear_pointer (&self->priv.p->acd_lst_hash, g_hash_table_unref);
diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h
index 1a598d1af4..9bf7f233a1 100644
--- a/src/nm-l3cfg.h
+++ b/src/nm-l3cfg.h
@@ -20,14 +20,17 @@
typedef enum {
NM_L3_CONFIG_NOTIFY_TYPE_ROUTES_TEMPORARY_NOT_AVAILABLE_EXPIRED,
- NM_L3_CONFIG_NOTIFY_TYPE_ACD_FAILED,
+
NM_L3_CONFIG_NOTIFY_TYPE_ACD_COMPLETED,
+ /* emitted at the end of nm_l3cfg_platform_commit(). */
+ NM_L3_CONFIG_NOTIFY_TYPE_POST_COMMIT,
+
/* NML3Cfg hooks to the NMPlatform signals for link, addresses and routes.
* It re-emits the signal on an idle handler. The purpose is for something
* like NMDevice which is already subscribed to these signals, it can get the
* notifications without also subscribing directly to the platform. */
- NM_L3_CONFIG_NOTIFY_TYPE_NOTIFY_PLATFORM_CHANGE_ON_IDLE,
+ NM_L3_CONFIG_NOTIFY_TYPE_PLATFORM_CHANGE_ON_IDLE,
_NM_L3_CONFIG_NOTIFY_TYPE_NUM,
} NML3ConfigNotifyType;
@@ -43,8 +46,9 @@ typedef struct {
struct {
in_addr_t addr;
guint sources_len;
+ bool probe_result:1;
const NML3ConfigNotifyPayloadAcdFailedSource *sources;
- } acd_failed;
+ } acd_completed;
struct {
guint32 obj_type_flags;
@@ -140,6 +144,12 @@ gboolean nm_l3cfg_get_acd_is_pending (NML3Cfg *self);
/*****************************************************************************/
+void _nm_l3cfg_emit_signal_notify (NML3Cfg *self,
+ NML3ConfigNotifyType notify_type,
+ const NML3ConfigNotifyPayload *pay_load);
+
+/*****************************************************************************/
+
typedef enum {
NM_L3CFG_PROPERTY_EMIT_TYPE_ANY,
NM_L3CFG_PROPERTY_EMIT_TYPE_IP4_ROUTE,
@@ -212,9 +222,7 @@ typedef enum _nm_packed {
} NML3CfgCommitType;
gboolean nm_l3cfg_platform_commit (NML3Cfg *self,
- NML3CfgCommitType commit_type,
- int addr_family,
- gboolean *out_final_failure_for_temporary_not_available);
+ NML3CfgCommitType commit_type);
/*****************************************************************************/
diff --git a/src/nm-netns.c b/src/nm-netns.c
index 53414af6a8..b4b5ae2b3e 100644
--- a/src/nm-netns.c
+++ b/src/nm-netns.c
@@ -192,6 +192,7 @@ _platform_signal_on_idle_cb (gpointer user_data)
c_list_splice (&work_list, &priv->l3cfg_signal_pending_lst_head);
while ((l3cfg_data = c_list_first_entry (&work_list, L3CfgData, signal_pending_lst))) {
+ nm_assert (NM_IS_L3CFG (l3cfg_data->l3cfg));
c_list_unlink (&l3cfg_data->signal_pending_lst);
_nm_l3cfg_notify_platform_change_on_idle (l3cfg_data->l3cfg,
nm_steal_int (&l3cfg_data->signal_pending_flag));