l3cfg: add nm_l3cfg_commit_type*() API for tracking the level for committing changes

NML3Cfg manages one ifindex. In the future, we may want that multiple
NMDevice and/or NMVpnConnection instances independently contribute their
NML3ConfigData to the NML3Cfg instance.

That means, at any time somebody may want to call nm_l3cfg_platform_commit()
to apply the changes. Even ACD internally may do that, when configuration
changes (e.g. an IP address passes ACD check). We thus need to know
whether we are assuming, updating or reapplying the settings.

Add API so users can register their "commit" preference.
This commit is contained in:
Thomas Haller 2020-09-03 12:24:08 +02:00
parent 4c07d34505
commit 47e2ff0a71
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
2 changed files with 143 additions and 4 deletions

View file

@ -95,6 +95,11 @@ typedef struct {
bool announcing_failed_is_retrying:1;
} AcdData;
struct _NML3CfgCommitTypeHandle {
CList commit_type_lst;
NML3CfgCommitType commit_type;
};
typedef struct {
const NML3ConfigData *l3cd;
NML3ConfigMergeFlags merge_flags;
@ -131,6 +136,8 @@ typedef struct _NML3CfgPrivate {
GArray *l3_config_datas;
const NML3ConfigData *combined_l3cd;
CList commit_type_lst_head;
GHashTable *routes_temporary_not_available_hash;
GHashTable *externally_removed_objs_hash;
@ -231,6 +238,8 @@ static AcdData *_l3_acd_data_find (NML3Cfg *self,
static
NM_UTILS_ENUM2STR_DEFINE (_l3_cfg_commit_type_to_string, NML3CfgCommitType,
NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_AUTO, "auto"),
NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_NONE, "none"),
NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_ASSUME, "assume"),
NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_UPDATE, "update"),
NM_UTILS_ENUM2STR (NM_L3_CFG_COMMIT_TYPE_REAPPLY, "reapply"),
@ -878,7 +887,7 @@ _l3_acd_platform_commit_acd_update (NML3Cfg *self)
_LOGT ("acd: acd update now");
self->priv.changed_configs = TRUE;
nm_l3cfg_platform_commit (self,
NM_L3_CFG_COMMIT_TYPE_UPDATE,
NM_L3_CFG_COMMIT_TYPE_AUTO,
AF_INET,
NULL);
}
@ -2756,7 +2765,8 @@ _platform_commit (NML3Cfg *self,
gboolean success = TRUE;
nm_assert (NM_IS_L3CFG (self));
nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY,
nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_NONE,
NM_L3_CFG_COMMIT_TYPE_REAPPLY,
NM_L3_CFG_COMMIT_TYPE_UPDATE,
NM_L3_CFG_COMMIT_TYPE_ASSUME));
nm_assert_addr_family (addr_family);
@ -2873,7 +2883,9 @@ nm_l3cfg_platform_commit (NML3Cfg *self,
gboolean acd_was_pending;
g_return_val_if_fail (NM_IS_L3CFG (self), FALSE);
nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY,
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_L3_CFG_COMMIT_TYPE_UPDATE,
NM_L3_CFG_COMMIT_TYPE_ASSUME));
@ -2884,6 +2896,9 @@ nm_l3cfg_platform_commit (NML3Cfg *self,
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_AUTO)
commit_type = nm_l3cfg_commit_type_get (self);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY)
_l3cfg_externally_removed_objs_drop (self, addr_family);
@ -2908,6 +2923,101 @@ nm_l3cfg_platform_commit (NML3Cfg *self,
/*****************************************************************************/
NML3CfgCommitType
nm_l3cfg_commit_type_get (NML3Cfg *self)
{
NML3CfgCommitTypeHandle *handle;
nm_assert (NM_IS_L3CFG (self));
handle = c_list_first_entry (&self->priv.p->commit_type_lst_head, NML3CfgCommitTypeHandle, commit_type_lst);
return handle
? handle->commit_type
: NM_L3_CFG_COMMIT_TYPE_NONE;
}
/**
* nm_l3cfg_commit_type_register:
* @self: the #NML3Cfg
* @commit_type: the commit type to register
* @existing_handle: instead of being a new registration, update an existing handle.
* This may be %NULL, which is like having no previous registration.
*
* NML3Cfg needs to know whether it is in charge of an interface (and how "much").
* By default, it is not in charge, but various users can register themself with
* a certain @commit_type. The "higher" commit type is the used one when calling
* nm_l3cfg_platform_commit() with %NM_L3_CFG_COMMIT_TYPE_AUTO.
*
* Returns: a handle tracking the registration, or %NULL of @commit_type
* is %NM_L3_CFG_COMMIT_TYPE_NONE.
*/
NML3CfgCommitTypeHandle *
nm_l3cfg_commit_type_register (NML3Cfg *self,
NML3CfgCommitType commit_type,
NML3CfgCommitTypeHandle *existing_handle)
{
NML3CfgCommitTypeHandle *handle;
NML3CfgCommitTypeHandle *h;
gboolean linked;
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_assert ( !existing_handle
|| c_list_contains (&self->priv.p->commit_type_lst_head, &existing_handle->commit_type_lst));
if (existing_handle) {
if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE) {
nm_l3cfg_commit_type_unregister (self, existing_handle);
return NULL;
}
if (existing_handle->commit_type == commit_type)
return existing_handle;
c_list_unlink_stale (&existing_handle->commit_type_lst);
handle = existing_handle;
} else {
if (commit_type == NM_L3_CFG_COMMIT_TYPE_NONE)
return NULL;
handle = g_slice_new (NML3CfgCommitTypeHandle);
handle->commit_type = commit_type;
if (c_list_is_empty (&self->priv.p->commit_type_lst_head))
g_object_ref (self);
}
linked = FALSE;
c_list_for_each_entry (h, &self->priv.p->commit_type_lst_head, commit_type_lst) {
if (handle->commit_type >= h->commit_type) {
c_list_link_before (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst);
linked = TRUE;
}
}
if (!linked)
c_list_link_tail (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst);
return handle;
}
void
nm_l3cfg_commit_type_unregister (NML3Cfg *self,
NML3CfgCommitTypeHandle *handle)
{
nm_assert (NM_IS_L3CFG (self));
if (!handle)
return;
nm_assert (c_list_contains (&self->priv.p->commit_type_lst_head, &handle->commit_type_lst));
c_list_unlink_stale (&handle->commit_type_lst);
if (c_list_is_empty (&self->priv.p->commit_type_lst_head))
g_object_unref (self);
nm_g_slice_free (handle);
}
/*****************************************************************************/
static void
set_property (GObject *object,
guint prop_id,
@ -2941,6 +3051,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->commit_type_lst_head);
}
static void
@ -2979,6 +3090,8 @@ finalize (GObject *object)
{
NML3Cfg *self = NM_L3CFG (object);
nm_assert (c_list_is_empty (&self->priv.p->commit_type_lst_head));
nm_clear_g_source_inst (&self->priv.p->acd_ready_on_idle_source);
nm_assert (nm_g_array_len (self->priv.p->property_emit_list) == 0u);

View file

@ -148,7 +148,18 @@ gboolean nm_l3cfg_remove_config_all (NML3Cfg *self,
/*****************************************************************************/
typedef enum {
/* The numeric values of the enum matters: higher number mean more "important".
* E.g. "assume" tries to preserve the most settings, while "reapply" forces
* all configuration to match. */
typedef enum _nm_packed {
/* the NML3Cfg instance tracks with nm_l3cfg_commit_setup_register() the requested commit type.
* Use _NM_L3_CFG_COMMIT_TYPE_AUTO to automatically choose the level as requested. */
NM_L3_CFG_COMMIT_TYPE_AUTO,
/* Don't touch the interface. */
NM_L3_CFG_COMMIT_TYPE_NONE,
/* ASSUME means to keep any pre-existing extra routes/addresses, while
* also not adding routes/addresses that are not present yet. This is to
* gracefully take over after restart, where the existing IP configuration
@ -172,4 +183,19 @@ gboolean nm_l3cfg_platform_commit (NML3Cfg *self,
int addr_family,
gboolean *out_final_failure_for_temporary_not_available);
/*****************************************************************************/
NML3CfgCommitType nm_l3cfg_commit_type_get (NML3Cfg *self);
typedef struct _NML3CfgCommitTypeHandle NML3CfgCommitTypeHandle;
NML3CfgCommitTypeHandle *nm_l3cfg_commit_type_register (NML3Cfg *self,
NML3CfgCommitType commit_type,
NML3CfgCommitTypeHandle *existing_handle);
void nm_l3cfg_commit_type_unregister (NML3Cfg *self,
NML3CfgCommitTypeHandle *handle);
/*****************************************************************************/
#endif /* __NM_L3CFG_H__ */