diff --git a/src/core/nm-l3-ipv4ll.c b/src/core/nm-l3-ipv4ll.c index d48b95ee4f..bcc6931896 100644 --- a/src/core/nm-l3-ipv4ll.c +++ b/src/core/nm-l3-ipv4ll.c @@ -602,7 +602,7 @@ _l3cd_config_add(NML3IPv4LL *self) self->l3cfg_commit_handle = nm_l3cfg_commit_type_register(self->l3cfg, NM_L3_CFG_COMMIT_TYPE_ASSUME, self->l3cfg_commit_handle); - nm_l3cfg_commit_on_idle_schedule(self->l3cfg); + nm_l3cfg_commit_on_idle_schedule(self->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); } static gboolean @@ -624,7 +624,7 @@ _l3cd_config_remove(NML3IPv4LL *self) nm_assert_not_reached(); nm_l3cfg_commit_type_unregister(self->l3cfg, g_steal_pointer(&self->l3cfg_commit_handle)); - nm_l3cfg_commit_on_idle_schedule(self->l3cfg); + nm_l3cfg_commit_on_idle_schedule(self->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); return TRUE; } @@ -1028,7 +1028,7 @@ nm_l3_ipv4ll_unref(NML3IPv4LL *self) nm_assert_not_reached(); nm_l3cfg_commit_type_unregister(self->l3cfg, g_steal_pointer(&self->l3cfg_commit_handle)); - nm_l3cfg_commit_on_idle_schedule(self->l3cfg); + nm_l3cfg_commit_on_idle_schedule(self->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); } else nm_assert(!self->l3cfg_commit_handle); diff --git a/src/core/nm-l3-ipv6ll.c b/src/core/nm-l3-ipv6ll.c index f494eb2ad0..49c59ae57a 100644 --- a/src/core/nm-l3-ipv6ll.c +++ b/src/core/nm-l3-ipv6ll.c @@ -433,7 +433,7 @@ _lladdr_handle_changed(NML3IPv6LL *self) self->l3cfg_commit_handle); if (changed) - nm_l3cfg_commit_on_idle_schedule(self->l3cfg); + nm_l3cfg_commit_on_idle_schedule(self->l3cfg, NM_L3_CFG_COMMIT_TYPE_AUTO); if (!self->emit_changed_idle_source) { _LOGT("schedule changed signal on idle"); diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index 7add5e9ac8..99611a1fc0 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -256,6 +256,8 @@ typedef struct _NML3CfgPrivate { GSource *obj_state_temporary_not_available_timeout_source; + NML3CfgCommitType commit_on_idle_type; + gint8 commit_reentrant_count; bool commit_type_update_sticky : 1; @@ -1616,7 +1618,7 @@ _l3_acd_nacd_instance_reset(NML3Cfg *self, NMTernary start_timer, gboolean acd_d switch (start_timer) { case NM_TERNARY_FALSE: _l3_changed_configs_set_dirty(self); - nm_l3cfg_commit_on_idle_schedule(self); + nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); break; case NM_TERNARY_TRUE: self->priv.p->nacd_instance_ensure_retry = @@ -2124,7 +2126,7 @@ _nm_printf(5, 6) static void _l3_acd_data_state_set_full(NML3Cfg * self, /* The availability of an address just changed (and we are instructed to * trigger a new commit). Do it. */ _l3_changed_configs_set_dirty(self); - nm_l3cfg_commit_on_idle_schedule(self); + nm_l3cfg_commit_on_idle_schedule(self, NM_L3_CFG_COMMIT_TYPE_AUTO); } } @@ -2970,27 +2972,46 @@ nm_l3cfg_check_ready(NML3Cfg *self, const NML3ConfigData *l3cd, NML3CfgCheckRead static gboolean _l3_commit_on_idle_cb(gpointer user_data) { + NML3CfgCommitType commit_type; + NML3Cfg *self = user_data; - nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source); + commit_type = self->priv.p->commit_on_idle_type; - _LOGT("commit on idle"); - _l3_commit(self, NM_L3_CFG_COMMIT_TYPE_AUTO, TRUE); + nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source); + self->priv.p->commit_on_idle_type = NM_L3_CFG_COMMIT_TYPE_AUTO; + + _l3_commit(self, commit_type, TRUE); return G_SOURCE_REMOVE; } gboolean -nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self) +nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self, NML3CfgCommitType commit_type) { + char sbuf_commit_type[50]; + nm_assert(NM_IS_L3CFG(self)); + nm_assert(NM_IN_SET(commit_type, + NM_L3_CFG_COMMIT_TYPE_AUTO, + NM_L3_CFG_COMMIT_TYPE_ASSUME, + NM_L3_CFG_COMMIT_TYPE_UPDATE, + NM_L3_CFG_COMMIT_TYPE_REAPPLY)); - if (self->priv.p->commit_on_idle_source) + if (self->priv.p->commit_on_idle_source) { + if (self->priv.p->commit_on_idle_type < commit_type) { + _LOGT("commit on idle (scheduled) (update to %s)", + _l3_cfg_commit_type_to_string(commit_type, + sbuf_commit_type, + sizeof(sbuf_commit_type))); + self->priv.p->commit_on_idle_type = commit_type; + } return FALSE; + } - _LOGT("commit on idle (scheduled)"); - self->priv.p->commit_on_idle_source = - nm_g_idle_source_new(G_PRIORITY_DEFAULT, _l3_commit_on_idle_cb, self, NULL); - g_source_attach(self->priv.p->commit_on_idle_source, NULL); + _LOGT("commit on idle (scheduled) (%s)", + _l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type))); + self->priv.p->commit_on_idle_source = nm_g_idle_add_source(_l3_commit_on_idle_cb, self); + self->priv.p->commit_on_idle_type = commit_type; return TRUE; } @@ -3797,8 +3818,10 @@ _l3_commit_one(NML3Cfg * self, static void _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) { - nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; - gboolean commit_type_detected = FALSE; + nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL; + NML3CfgCommitType commit_type_auto; + gboolean commit_type_from_auto = FALSE; + gboolean is_sticky_update = FALSE; char sbuf_ct[30]; gboolean changed_combined_l3cd; @@ -3811,50 +3834,50 @@ _l3_commit(NML3Cfg *self, NML3CfgCommitType commit_type, gboolean is_idle) NM_L3_CFG_COMMIT_TYPE_REAPPLY)); nm_assert(self->priv.p->commit_reentrant_count == 0); - 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; + /* The actual commit type is always the maximum of what is requested + * and what is registered via nm_l3cfg_commit_type_register(). */ + commit_type_auto = nm_l3cfg_commit_type_get(self); + if (commit_type == NM_L3_CFG_COMMIT_TYPE_AUTO || commit_type_auto > commit_type) { + commit_type_from_auto = TRUE; + commit_type = commit_type_auto; } - _LOGT("commit %s%s%s", + /* UPDATE and higher are sticky. That means, when do perform such a commit + * type, then the next one will at least be of level "UPDATE". The idea is + * that if the current commit adds an address, then the following needs + * to do at least "UPDATE" level to remove it again. Even if in the meantime + * the "UPDATE" is unregistered (nm_l3cfg_commit_type_unregister()). */ + if (commit_type < NM_L3_CFG_COMMIT_TYPE_UPDATE) { + if (self->priv.p->commit_type_update_sticky) { + self->priv.p->commit_type_update_sticky = FALSE; + commit_type = NM_L3_CFG_COMMIT_TYPE_UPDATE; + is_sticky_update = TRUE; + } + } else + self->priv.p->commit_type_update_sticky = TRUE; + + _LOGT("commit %s%s%s%s", _l3_cfg_commit_type_to_string(commit_type, sbuf_ct, sizeof(sbuf_ct)), - commit_type_detected ? " (auto)" : "", + commit_type_from_auto ? " (auto)" : "", + is_sticky_update ? " (sticky-update)" : "", is_idle ? " (idle handler)" : ""); - if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE) + nm_assert(commit_type > NM_L3_CFG_COMMIT_TYPE_AUTO); + + nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source); + self->priv.p->commit_on_idle_type = NM_L3_CFG_COMMIT_TYPE_AUTO; + + if (commit_type <= NM_L3_CFG_COMMIT_TYPE_NONE) return; self->priv.p->commit_reentrant_count++; - nm_clear_g_source_inst(&self->priv.p->commit_on_idle_source); - _l3cfg_update_combined_config(self, TRUE, commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY, &l3cd_old, &changed_combined_l3cd); - /* FIXME(l3cfg): handle items currently not configurable in kernel. */ - _l3_commit_one(self, AF_INET, commit_type, changed_combined_l3cd, l3cd_old); _l3_commit_one(self, AF_INET6, commit_type, changed_combined_l3cd, l3cd_old); diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 05acbc8633..b5da926ece 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -367,7 +367,7 @@ typedef enum _nm_packed { void nm_l3cfg_commit(NML3Cfg *self, NML3CfgCommitType commit_type); -gboolean nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self); +gboolean nm_l3cfg_commit_on_idle_schedule(NML3Cfg *self, NML3CfgCommitType commit_type); gboolean nm_l3cfg_commit_on_idle_is_scheduled(NML3Cfg *self); diff --git a/src/core/tests/test-l3cfg.c b/src/core/tests/test-l3cfg.c index 4a76c083fd..82b515d0f2 100644 --- a/src/core/tests/test-l3cfg.c +++ b/src/core/tests/test-l3cfg.c @@ -606,7 +606,8 @@ _test_l3_ipv4ll_signal_notify(NML3Cfg * l3cfg, NM_L3CFG_CONFIG_FLAGS_NONE, NM_L3_CONFIG_MERGE_FLAGS_NONE)) g_assert_not_reached(); - nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll)); + nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll), + NM_L3_CFG_COMMIT_TYPE_AUTO); tdata->l3cfg_commit_type_1 = nm_l3cfg_commit_type_register(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll), @@ -626,7 +627,8 @@ _test_l3_ipv4ll_signal_notify(NML3Cfg * l3cfg, if (!nm_l3cfg_remove_config_all(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll), TEST_L3_IPV4LL_TAG(tdata, 1))) g_assert_not_reached(); - nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll)); + nm_l3cfg_commit_on_idle_schedule(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll), + NM_L3_CFG_COMMIT_TYPE_AUTO); nm_l3cfg_commit_type_unregister(nm_l3_ipv4ll_get_l3cfg(tdata->l3ipv4ll), g_steal_pointer(&tdata->l3cfg_commit_type_1)); }