mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-07-25 04:04:36 +00:00
l3cfg: track externally removed addresses/routes
We want to allow the user to externally remove IP addresses and routes, and NetworkManager not re-adding them until a full reapply happens. For that, we need to keep track of IP addresses that were present, but no longer are.
This commit is contained in:
parent
3ac668bc1a
commit
e50597559b
|
@ -528,36 +528,60 @@ nm_l3_config_data_lookup_route (const NML3ConfigData *self,
|
|||
nmp_object_stackinit (&obj_stack, NMP_OBJECT_TYPE_IP_ROUTE (IS_IPv4), needle));
|
||||
}
|
||||
|
||||
const NMDedupMultiHeadEntry *
|
||||
nm_l3_config_data_lookup_objs (const NML3ConfigData *self, NMPObjectType obj_type)
|
||||
const NMDedupMultiIdxType *
|
||||
nm_l3_config_data_lookup_index (const NML3ConfigData *self, NMPObjectType obj_type)
|
||||
{
|
||||
const DedupMultiIdxType *idx;
|
||||
|
||||
nm_assert (_NM_IS_L3_CONFIG_DATA (self, TRUE));
|
||||
|
||||
switch (obj_type) {
|
||||
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
||||
idx = &self->idx_addresses_4;
|
||||
break;
|
||||
return &self->idx_addresses_4.parent;
|
||||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
idx = &self->idx_addresses_6;
|
||||
break;
|
||||
return &self->idx_addresses_6.parent;
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
idx = &self->idx_routes_4;
|
||||
break;
|
||||
return &self->idx_routes_4.parent;
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
idx = &self->idx_routes_6;
|
||||
break;
|
||||
return &self->idx_routes_6.parent;
|
||||
default:
|
||||
nm_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return nm_dedup_multi_index_lookup_head (self->multi_idx, &idx->parent, NULL);
|
||||
const NMDedupMultiHeadEntry *
|
||||
nm_l3_config_data_lookup_objs (const NML3ConfigData *self, NMPObjectType obj_type)
|
||||
{
|
||||
return nm_dedup_multi_index_lookup_head (self->multi_idx,
|
||||
nm_l3_config_data_lookup_index (self, obj_type),
|
||||
NULL);
|
||||
}
|
||||
|
||||
const NMDedupMultiEntry *
|
||||
nm_l3_config_data_lookup_obj (const NML3ConfigData *self,
|
||||
const NMPObject *obj)
|
||||
{
|
||||
const NMDedupMultiIdxType *idx;
|
||||
|
||||
nm_assert (_NM_IS_L3_CONFIG_DATA (self, TRUE));
|
||||
|
||||
idx = nm_l3_config_data_lookup_index (self,
|
||||
NMP_OBJECT_GET_TYPE (obj));
|
||||
|
||||
return nm_dedup_multi_index_lookup_obj (self->multi_idx,
|
||||
idx,
|
||||
obj);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMDedupMultiIndex *
|
||||
nm_l3_config_data_get_multi_idx (const NML3ConfigData *self)
|
||||
{
|
||||
nm_assert (_NM_IS_L3_CONFIG_DATA (self, TRUE));
|
||||
|
||||
return self->multi_idx;
|
||||
}
|
||||
|
||||
int
|
||||
nm_l3_config_data_get_ifindex (const NML3ConfigData *self)
|
||||
{
|
||||
|
|
|
@ -122,6 +122,8 @@ void nm_l3_config_data_add_dependent_routes (NML3ConfigData *self,
|
|||
|
||||
int nm_l3_config_data_get_ifindex (const NML3ConfigData *self);
|
||||
|
||||
NMDedupMultiIndex *nm_l3_config_data_get_multi_idx (const NML3ConfigData *self);
|
||||
|
||||
static inline gboolean
|
||||
NM_IS_L3_CONFIG_DATA (const NML3ConfigData *self)
|
||||
{
|
||||
|
@ -147,6 +149,12 @@ nm_l3_config_data_equal (const NML3ConfigData *a, const NML3ConfigData *b)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
const NMDedupMultiIdxType *nm_l3_config_data_lookup_index (const NML3ConfigData *self,
|
||||
NMPObjectType obj_type);
|
||||
|
||||
const NMDedupMultiEntry *nm_l3_config_data_lookup_obj (const NML3ConfigData *self,
|
||||
const NMPObject *obj);
|
||||
|
||||
const NMDedupMultiEntry *nm_l3_config_data_lookup_route_obj (const NML3ConfigData *self,
|
||||
const NMPObject *needle);
|
||||
|
||||
|
|
323
src/nm-l3cfg.c
323
src/nm-l3cfg.c
|
@ -41,8 +41,26 @@ typedef struct _NML3CfgPrivate {
|
|||
|
||||
GHashTable *routes_temporary_not_available_hash;
|
||||
|
||||
GHashTable *externally_removed_objs_hash;
|
||||
|
||||
guint64 pseudo_timestamp_counter;
|
||||
|
||||
union {
|
||||
struct {
|
||||
guint externally_removed_objs_cnt_addresses_6;
|
||||
guint externally_removed_objs_cnt_addresses_4;
|
||||
};
|
||||
guint externally_removed_objs_cnt_addresses_x[2];
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
guint externally_removed_objs_cnt_routes_6;
|
||||
guint externally_removed_objs_cnt_routes_4;
|
||||
};
|
||||
guint externally_removed_objs_cnt_routes_x[2];
|
||||
};
|
||||
|
||||
guint routes_temporary_not_available_id;
|
||||
} NML3CfgPrivate;
|
||||
|
||||
|
@ -71,6 +89,15 @@ static void _property_emit_notify (NML3Cfg *self, NML3CfgPropertyEmitType emit_t
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static
|
||||
NM_UTILS_ENUM2STR_DEFINE (_l3_cfg_commit_type_to_string, NML3CfgCommitType,
|
||||
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"),
|
||||
);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_l3cfg_emit_signal_notify (NML3Cfg *self,
|
||||
NML3ConfigNotifyType notify_type,
|
||||
|
@ -88,6 +115,188 @@ _l3cfg_emit_signal_notify (NML3Cfg *self,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static guint *
|
||||
_l3cfg_externally_removed_objs_counter (NML3Cfg *self,
|
||||
NMPObjectType obj_type)
|
||||
{
|
||||
switch (obj_type) {
|
||||
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
||||
return &self->priv.p->externally_removed_objs_cnt_addresses_4;
|
||||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
return &self->priv.p->externally_removed_objs_cnt_addresses_6;
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
return &self->priv.p->externally_removed_objs_cnt_routes_4;
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
return &self->priv.p->externally_removed_objs_cnt_routes_6;
|
||||
default:
|
||||
return nm_assert_unreachable_val (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_l3cfg_externally_removed_objs_drop (NML3Cfg *self,
|
||||
int addr_family)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
static void
|
||||
_l3cfg_externally_removed_objs_drop_unused (NML3Cfg *self)
|
||||
{
|
||||
GHashTableIter h_iter;
|
||||
const NMPObject *obj;
|
||||
char sbuf[sizeof (_nm_utils_to_string_buffer)];
|
||||
|
||||
nm_assert (NM_IS_L3CFG (self));
|
||||
|
||||
if (!self->priv.p->externally_removed_objs_hash)
|
||||
return;
|
||||
|
||||
if (!self->priv.p->combined_l3cfg) {
|
||||
_l3cfg_externally_removed_objs_drop (self, AF_UNSPEC);
|
||||
return;
|
||||
}
|
||||
|
||||
g_hash_table_iter_init (&h_iter, self->priv.p->externally_removed_objs_hash);
|
||||
while (g_hash_table_iter_next (&h_iter, (gpointer *) &obj, NULL)) {
|
||||
if (!nm_l3_config_data_lookup_route_obj (self->priv.p->combined_l3cfg,
|
||||
obj)) {
|
||||
/* The object is no longer tracked in the configuration.
|
||||
* The externally_removed_objs_hash is to prevent adding entires that were
|
||||
* removed externally, so if we don't plan to add the entry, we no longer need to track
|
||||
* it. */
|
||||
(*(_l3cfg_externally_removed_objs_counter (self, NMP_OBJECT_GET_TYPE (obj))))--;
|
||||
g_hash_table_iter_remove (&h_iter);
|
||||
_LOGD ("externally-removed: untrack %s",
|
||||
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof (sbuf)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_l3cfg_externally_removed_objs_track (NML3Cfg *self,
|
||||
const NMPObject *obj,
|
||||
gboolean is_removed)
|
||||
{
|
||||
char sbuf[1000];
|
||||
|
||||
nm_assert (NM_IS_L3CFG (self));
|
||||
|
||||
if (!self->priv.p->combined_l3cfg)
|
||||
return;
|
||||
|
||||
if (!is_removed) {
|
||||
/* the object is still (or again) present. It no longer gets hidden. */
|
||||
if (self->priv.p->externally_removed_objs_hash) {
|
||||
if (g_hash_table_remove (self->priv.p->externally_removed_objs_hash,
|
||||
obj)) {
|
||||
(*(_l3cfg_externally_removed_objs_counter (self,
|
||||
NMP_OBJECT_GET_TYPE (obj))))--;
|
||||
_LOGD ("externally-removed: untrack %s",
|
||||
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof (sbuf)));
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nm_l3_config_data_lookup_route_obj (self->priv.p->combined_l3cfg,
|
||||
obj)) {
|
||||
/* we don't care about this object, so there is nothing to hide hide */
|
||||
return;
|
||||
}
|
||||
|
||||
if (G_UNLIKELY (!self->priv.p->externally_removed_objs_hash)) {
|
||||
self->priv.p->externally_removed_objs_hash = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash,
|
||||
(GEqualFunc) nmp_object_id_equal,
|
||||
(GDestroyNotify) nmp_object_unref,
|
||||
NULL);
|
||||
}
|
||||
|
||||
if (g_hash_table_add (self->priv.p->externally_removed_objs_hash,
|
||||
(gpointer) nmp_object_ref (obj))) {
|
||||
(*(_l3cfg_externally_removed_objs_counter (self,
|
||||
NMP_OBJECT_GET_TYPE (obj))))++;
|
||||
_LOGD ("externally-removed: track %s",
|
||||
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf, sizeof (sbuf)));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_l3cfg_externally_removed_objs_pickup (NML3Cfg *self,
|
||||
int addr_family)
|
||||
{
|
||||
const gboolean IS_IPv4 = NM_IS_IPv4 (addr_family);
|
||||
NMDedupMultiIter iter;
|
||||
const NMPObject *obj;
|
||||
|
||||
if (!self->priv.p->combined_l3cfg)
|
||||
return;
|
||||
|
||||
nm_l3_config_data_iter_obj_for_each (iter, self->priv.p->combined_l3cfg, obj, NMP_OBJECT_TYPE_IP_ADDRESS (IS_IPv4)) {
|
||||
if (!nm_platform_lookup_entry (self->priv.platform,
|
||||
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||
obj))
|
||||
_l3cfg_externally_removed_objs_track (self, obj, TRUE);
|
||||
}
|
||||
nm_l3_config_data_iter_obj_for_each (iter, self->priv.p->combined_l3cfg, obj, NMP_OBJECT_TYPE_IP_ROUTE (IS_IPv4)) {
|
||||
if (!nm_platform_lookup_entry (self->priv.platform,
|
||||
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
|
||||
obj))
|
||||
_l3cfg_externally_removed_objs_track (self, obj, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_l3cfg_externally_removed_objs_filter (/* const NMDedupMultiObj * */ gconstpointer o,
|
||||
gpointer user_data)
|
||||
{
|
||||
const NMPObject *obj = o;
|
||||
GHashTable *externally_removed_objs_hash = user_data;
|
||||
|
||||
return !g_hash_table_contains (externally_removed_objs_hash, obj);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_load_link (NML3Cfg *self, gboolean initial)
|
||||
{
|
||||
|
@ -131,6 +340,26 @@ _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags)
|
|||
_property_emit_notify (self, NM_L3CFG_PROPERTY_EMIT_TYPE_IP6_ROUTE);
|
||||
}
|
||||
|
||||
void
|
||||
_nm_l3cfg_notify_platform_change (NML3Cfg *self,
|
||||
NMPlatformSignalChangeType change_type,
|
||||
const NMPObject *obj)
|
||||
{
|
||||
nm_assert (NMP_OBJECT_IS_VALID (obj));
|
||||
|
||||
switch (NMP_OBJECT_GET_TYPE (obj)) {
|
||||
case NMP_OBJECT_TYPE_IP4_ADDRESS:
|
||||
case NMP_OBJECT_TYPE_IP6_ADDRESS:
|
||||
case NMP_OBJECT_TYPE_IP4_ROUTE:
|
||||
case NMP_OBJECT_TYPE_IP6_ROUTE:
|
||||
_l3cfg_externally_removed_objs_track (self,
|
||||
obj,
|
||||
change_type == NM_PLATFORM_SIGNAL_REMOVED);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
|
@ -775,26 +1004,37 @@ out_prune:
|
|||
|
||||
gboolean
|
||||
nm_l3cfg_platform_commit (NML3Cfg *self,
|
||||
NML3CfgCommitType commit_type,
|
||||
int addr_family,
|
||||
gboolean *out_final_failure_for_temporary_not_available)
|
||||
{
|
||||
nm_auto_unref_l3cfg const NML3ConfigData *l3cfg_old = NULL;
|
||||
gs_unref_ptrarray GPtrArray *addresses = NULL;
|
||||
gs_unref_ptrarray GPtrArray *routes = NULL;
|
||||
gs_unref_ptrarray GPtrArray *addresses_prune = NULL;
|
||||
gs_unref_ptrarray GPtrArray *routes_prune = NULL;
|
||||
gs_unref_ptrarray GPtrArray *routes_temporary_not_available_arr = NULL;
|
||||
NMIPRouteTableSyncMode route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_NONE;
|
||||
gboolean final_failure_for_temporary_not_available = FALSE;
|
||||
char sbuf_commit_type[50];
|
||||
gboolean combined_changed;
|
||||
gboolean success = TRUE;
|
||||
int IS_IPv4;
|
||||
|
||||
g_return_val_if_fail (NM_IS_L3CFG (self), FALSE);
|
||||
nm_assert (NM_IN_SET (commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY,
|
||||
NM_L3_CFG_COMMIT_TYPE_UPDATE,
|
||||
NM_L3_CFG_COMMIT_TYPE_ASSUME));
|
||||
|
||||
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY)
|
||||
_l3cfg_externally_removed_objs_drop (self, addr_family);
|
||||
|
||||
if (addr_family == AF_UNSPEC) {
|
||||
gboolean final_failure_for_temporary_not_available_6 = FALSE;
|
||||
|
||||
if (!nm_l3cfg_platform_commit (self, AF_INET, &final_failure_for_temporary_not_available))
|
||||
if (!nm_l3cfg_platform_commit (self, AF_INET, commit_type, &final_failure_for_temporary_not_available))
|
||||
success = FALSE;
|
||||
if (!nm_l3cfg_platform_commit (self, AF_INET6, &final_failure_for_temporary_not_available_6))
|
||||
if (!nm_l3cfg_platform_commit (self, AF_INET6, commit_type, &final_failure_for_temporary_not_available_6))
|
||||
success = FALSE;
|
||||
NM_SET_OUT (out_final_failure_for_temporary_not_available,
|
||||
( final_failure_for_temporary_not_available
|
||||
|
@ -802,20 +1042,47 @@ nm_l3cfg_platform_commit (NML3Cfg *self,
|
|||
return success;
|
||||
}
|
||||
|
||||
_l3cfg_update_combined_config (self, NULL);
|
||||
_LOGT ("committing IPv%c configuration (%s)",
|
||||
nm_utils_addr_family_to_char (addr_family),
|
||||
_l3_cfg_commit_type_to_string (commit_type, sbuf_commit_type, sizeof (sbuf_commit_type)));
|
||||
|
||||
combined_changed = _l3cfg_update_combined_config (self, &l3cfg_old);
|
||||
|
||||
IS_IPv4 = NM_IS_IPv4 (addr_family);
|
||||
|
||||
_LOGT ("committing IPv%c configuration...", nm_utils_addr_family_to_char (addr_family));
|
||||
if (combined_changed) {
|
||||
/* our combined configuration changed. We may track entries in externally_removed_objs_hash,
|
||||
* which are not longer to be considered by our configuration. We need to forget about them. */
|
||||
_l3cfg_externally_removed_objs_drop_unused (self);
|
||||
}
|
||||
|
||||
if (commit_type == NM_L3_CFG_COMMIT_TYPE_ASSUME) {
|
||||
/* we need to artificially pre-populate the externally remove hash. */
|
||||
_l3cfg_externally_removed_objs_pickup (self, addr_family);
|
||||
}
|
||||
|
||||
if (self->priv.p->combined_l3cfg) {
|
||||
NMDedupMultiFcnSelectPredicate predicate;
|
||||
|
||||
if ( commit_type != NM_L3_CFG_COMMIT_TYPE_REAPPLY
|
||||
&& self->priv.p->externally_removed_objs_cnt_addresses_x[IS_IPv4] > 0)
|
||||
predicate = _l3cfg_externally_removed_objs_filter;
|
||||
else
|
||||
predicate = NULL;
|
||||
addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_l3_config_data_lookup_objs (self->priv.p->combined_l3cfg,
|
||||
NMP_OBJECT_TYPE_IP_ADDRESS (IS_IPv4)),
|
||||
NULL, NULL);
|
||||
predicate,
|
||||
self->priv.p->externally_removed_objs_hash);
|
||||
|
||||
if ( commit_type != NM_L3_CFG_COMMIT_TYPE_REAPPLY
|
||||
&& self->priv.p->externally_removed_objs_cnt_routes_x[IS_IPv4] > 0)
|
||||
predicate = _l3cfg_externally_removed_objs_filter;
|
||||
else
|
||||
predicate = NULL;
|
||||
routes = nm_dedup_multi_objs_to_ptr_array_head (nm_l3_config_data_lookup_objs (self->priv.p->combined_l3cfg,
|
||||
NMP_OBJECT_TYPE_IP_ROUTE (IS_IPv4)),
|
||||
NULL, NULL);
|
||||
predicate,
|
||||
self->priv.p->externally_removed_objs_hash);
|
||||
|
||||
route_table_sync = nm_l3_config_data_get_route_table_sync (self->priv.p->combined_l3cfg, addr_family);
|
||||
}
|
||||
|
@ -823,14 +1090,42 @@ nm_l3cfg_platform_commit (NML3Cfg *self,
|
|||
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE)
|
||||
route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_ALL;
|
||||
|
||||
routes_prune = nm_platform_ip_route_get_prune_list (self->priv.platform,
|
||||
addr_family,
|
||||
self->priv.ifindex,
|
||||
route_table_sync);
|
||||
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
|
||||
addresses_prune = nm_platform_ip_address_get_prune_list (self->priv.platform,
|
||||
addr_family,
|
||||
self->priv.ifindex,
|
||||
TRUE);
|
||||
routes_prune = nm_platform_ip_route_get_prune_list (self->priv.platform,
|
||||
addr_family,
|
||||
self->priv.ifindex,
|
||||
route_table_sync);
|
||||
} else if (commit_type == NM_L3_CFG_COMMIT_TYPE_UPDATE) {
|
||||
/* during update, we do a cross with the previous configuration.
|
||||
*
|
||||
* Of course, if an entry is both to be pruned and to be added, then
|
||||
* the latter wins. So, this works just nicely. */
|
||||
if (l3cfg_old) {
|
||||
const NMDedupMultiHeadEntry *head_entry;
|
||||
|
||||
nm_platform_ip4_address_sync (self->priv.platform,
|
||||
self->priv.ifindex,
|
||||
addresses);
|
||||
head_entry = nm_l3_config_data_lookup_objs (l3cfg_old,
|
||||
NMP_OBJECT_TYPE_IP_ADDRESS (IS_IPv4));
|
||||
addresses_prune = nm_dedup_multi_objs_to_ptr_array_head (head_entry,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
head_entry = nm_l3_config_data_lookup_objs (l3cfg_old,
|
||||
NMP_OBJECT_TYPE_IP_ROUTE (IS_IPv4));
|
||||
addresses_prune = nm_dedup_multi_objs_to_ptr_array_head (head_entry,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
nm_platform_ip_address_sync (self->priv.platform,
|
||||
addr_family,
|
||||
self->priv.ifindex,
|
||||
addresses,
|
||||
addresses_prune);
|
||||
|
||||
if (!nm_platform_ip_route_sync (self->priv.platform,
|
||||
addr_family,
|
||||
|
@ -930,6 +1225,8 @@ finalize (GObject *object)
|
|||
nm_clear_g_source (&self->priv.p->routes_temporary_not_available_id);
|
||||
nm_clear_pointer (&self->priv.p->routes_temporary_not_available_hash, g_hash_table_unref);
|
||||
|
||||
nm_clear_pointer (&self->priv.p->externally_removed_objs_hash, g_hash_table_unref);
|
||||
|
||||
g_clear_object (&self->priv.netns);
|
||||
g_clear_object (&self->priv.platform);
|
||||
|
||||
|
|
|
@ -49,6 +49,10 @@ NML3Cfg *nm_l3cfg_new (NMNetns *netns, int ifindex);
|
|||
|
||||
void _nm_l3cfg_notify_platform_change_on_idle (NML3Cfg *self, guint32 obj_type_flags);
|
||||
|
||||
void _nm_l3cfg_notify_platform_change (NML3Cfg *self,
|
||||
NMPlatformSignalChangeType change_type,
|
||||
const NMPObject *obj);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static inline int
|
||||
|
@ -125,7 +129,26 @@ void nm_l3cfg_remove_config_all (NML3Cfg *self,
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
/* 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
|
||||
* should not change. */
|
||||
NM_L3_CFG_COMMIT_TYPE_ASSUME,
|
||||
|
||||
/* UPDATE means to add new addresses/routes, while also removing addresses/routes
|
||||
* that are no longer present (but were previously configured by NetworkManager).
|
||||
* Routes/addresses that were removed externally won't be re-added, and routes/addresses
|
||||
* that are added externally won't be removed. */
|
||||
NM_L3_CFG_COMMIT_TYPE_UPDATE,
|
||||
|
||||
/* This is a full sync. It configures the IP addresses/routes that are indicated,
|
||||
* while removing the existing ones from the interface. */
|
||||
NM_L3_CFG_COMMIT_TYPE_REAPPLY,
|
||||
} NML3CfgCommitType;
|
||||
|
||||
gboolean nm_l3cfg_platform_commit (NML3Cfg *self,
|
||||
NML3CfgCommitType commit_type,
|
||||
int addr_family,
|
||||
gboolean *out_final_failure_for_temporary_not_available);
|
||||
|
||||
|
|
|
@ -196,6 +196,7 @@ _platform_signal_cb (NMPlatform *platform,
|
|||
NMNetns *self = NM_NETNS (*p_self);
|
||||
NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self);
|
||||
const NMPObjectType obj_type = obj_type_i;
|
||||
const NMPlatformSignalChangeType change_type = change_type_i;
|
||||
L3CfgData *l3cfg_data;
|
||||
|
||||
l3cfg_data = g_hash_table_lookup (priv->l3cfgs, &ifindex);
|
||||
|
@ -204,12 +205,15 @@ _platform_signal_cb (NMPlatform *platform,
|
|||
|
||||
l3cfg_data->signal_pending_flag |= nmp_object_type_to_flags (obj_type);
|
||||
|
||||
if (!c_list_is_empty (&l3cfg_data->signal_pending_lst))
|
||||
return;
|
||||
if (c_list_is_empty (&l3cfg_data->signal_pending_lst)) {
|
||||
c_list_link_tail (&priv->l3cfg_signal_pending_lst_head, &l3cfg_data->signal_pending_lst);
|
||||
if (priv->signal_pending_idle_id == 0)
|
||||
priv->signal_pending_idle_id = g_idle_add (_platform_signal_on_idle_cb, self);
|
||||
}
|
||||
|
||||
c_list_link_tail (&priv->l3cfg_signal_pending_lst_head, &l3cfg_data->signal_pending_lst);
|
||||
if (priv->signal_pending_idle_id == 0)
|
||||
priv->signal_pending_idle_id = g_idle_add (_platform_signal_on_idle_cb, self);
|
||||
_nm_l3cfg_notify_platform_change (l3cfg_data->l3cfg,
|
||||
change_type,
|
||||
NMP_OBJECT_UP_CAST (platform_object));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
@ -288,6 +292,8 @@ constructed (GObject *object)
|
|||
g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data);
|
||||
g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data);
|
||||
g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data);
|
||||
g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data);
|
||||
g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_platform_signal_cb), &priv->_self_signal_user_data);
|
||||
}
|
||||
|
||||
NMNetns *
|
||||
|
|
Loading…
Reference in a new issue