l3cfg: handle dynamic added routes tracking and deletion

Dynamic added routes i.e ECMP single-hop routes, are not managed by l3cd
as the other ones. Therefore, they need to be tracked properly and
marked as dirty when they are.

This way, NetworkManager makes sure there are no leftovers from merging
ECMP multi-hop routes.
This commit is contained in:
Fernando Fernandez Mancera 2023-11-27 20:23:20 +01:00
parent 37703b6176
commit 3dbe8234df

View file

@ -166,6 +166,12 @@ typedef struct {
/* This flag is only used temporarily to do a bulk update and
* clear all the ones that are no longer in used. */
bool os_dirty : 1;
/* Indicates whether this is configured dynamically or statically on l3cd. */
bool os_dynamic : 1;
/* Indicates that this dynamic obj-state is marked as dirty. */
bool os_dynamic_dirty : 1;
} ObjStateData;
G_STATIC_ASSERT(G_STRUCT_OFFSET(ObjStateData, obj) == 0);
@ -804,7 +810,7 @@ _nm_n_acd_data_probe_new(NML3Cfg *self, in_addr_t addr, guint32 timeout_msec, gp
NMP_CACHE_ID_TYPE_OBJECT_TYPE, \
_obj_state->obj)); \
nm_assert( \
c_list_is_empty(&obj_state->os_zombie_lst) \
c_list_is_empty(&obj_state->os_zombie_lst) && !obj_state->os_dynamic \
? (_obj_state->obj \
== nm_dedup_multi_entry_get_obj(nm_l3_config_data_lookup_obj( \
_self->priv.p->combined_l3cd_commited, \
@ -831,6 +837,8 @@ _obj_state_data_new(const NMPObject *obj, const NMPObject *plobj)
.os_was_in_platform = !!plobj,
.os_nm_configured = FALSE,
.os_dirty = FALSE,
.os_dynamic = FALSE,
.os_dynamic_dirty = FALSE,
.os_failedobj_expiry_msec = 0,
.os_failedobj_prioq_idx = NM_PRIOQ_IDX_NULL,
.os_zombie_lst = C_LIST_INIT(obj_state->os_zombie_lst),
@ -1001,7 +1009,7 @@ out:
}
static void
_obj_states_track_new(NML3Cfg *self, const NMPObject *obj)
_obj_states_track_new(NML3Cfg *self, const NMPObject *obj, bool is_dynamic)
{
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
ObjStateData *obj_state;
@ -1009,12 +1017,51 @@ _obj_states_track_new(NML3Cfg *self, const NMPObject *obj)
obj_state = _obj_state_data_new(
obj,
nm_platform_lookup_obj(self->priv.platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj));
obj_state->os_dynamic = is_dynamic;
c_list_link_tail(&self->priv.p->obj_state_lst_head, &obj_state->os_lst);
g_hash_table_add(self->priv.p->obj_state_hash, obj_state);
_LOGD("obj-state: track: %s", _obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
nm_assert_obj_state(self, obj_state);
}
static void
_obj_states_remove_track(NML3Cfg *self, bool dynamics)
{
GHashTableIter h_iter;
ObjStateData *obj_state;
char sbuf[NM_UTILS_TO_STRING_BUFFER_SIZE];
g_hash_table_iter_init(&h_iter, self->priv.p->obj_state_hash);
while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_state, NULL)) {
if (!c_list_is_empty(&obj_state->os_zombie_lst))
continue;
if (!dynamics && !obj_state->os_dirty)
continue;
if (dynamics && !obj_state->os_dynamic)
continue;
if (dynamics && !obj_state->os_dynamic_dirty)
continue;
if (obj_state->os_plobj && obj_state->os_nm_configured) {
nm_assert(obj_state->os_failedobj_prioq_idx == NM_PRIOQ_IDX_NULL);
c_list_link_tail(&self->priv.p->obj_state_zombie_lst_head, &obj_state->os_zombie_lst);
obj_state->os_zombie_count = ZOMBIE_COUNT_START;
_LOGD("obj-state: now%s zombie: %s",
dynamics ? " dynamic" : "",
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
continue;
}
_LOGD("obj-state:%s untrack: %s",
dynamics ? " dynamic" : "",
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
nm_prioq_remove(&self->priv.p->failedobj_prioq,
obj_state,
&obj_state->os_failedobj_prioq_idx);
g_hash_table_iter_remove(&h_iter);
}
}
static void
_obj_states_update_all(NML3Cfg *self)
{
@ -1064,7 +1111,7 @@ _obj_states_update_all(NML3Cfg *self)
}
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj);
if (!obj_state) {
_obj_states_track_new(self, obj);
_obj_states_track_new(self, obj, FALSE);
continue;
}
@ -1078,32 +1125,7 @@ _obj_states_update_all(NML3Cfg *self)
}
if (any_dirty) {
GHashTableIter h_iter;
g_hash_table_iter_init(&h_iter, self->priv.p->obj_state_hash);
while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_state, NULL)) {
if (!c_list_is_empty(&obj_state->os_zombie_lst))
continue;
if (!obj_state->os_dirty)
continue;
if (obj_state->os_plobj && obj_state->os_nm_configured) {
nm_assert(obj_state->os_failedobj_prioq_idx == NM_PRIOQ_IDX_NULL);
c_list_link_tail(&self->priv.p->obj_state_zombie_lst_head,
&obj_state->os_zombie_lst);
obj_state->os_zombie_count = ZOMBIE_COUNT_START;
_LOGD("obj-state: now zombie: %s",
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
continue;
}
_LOGD("obj-state: untrack: %s",
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
nm_prioq_remove(&self->priv.p->failedobj_prioq,
obj_state,
&obj_state->os_failedobj_prioq_idx);
g_hash_table_iter_remove(&h_iter);
}
_obj_states_remove_track(self, FALSE);
}
}
@ -1194,6 +1216,18 @@ _commit_collect_addresses(NML3Cfg *self, int addr_family, NML3CfgCommitType comm
(gpointer) &sync_filter_data);
}
static void
_obj_states_mark_dynamic_as_dirty(NML3Cfg *self)
{
ObjStateData *obj_state;
c_list_for_each_entry (obj_state, &self->priv.p->obj_state_lst_head, os_lst) {
if (!obj_state->os_dynamic)
continue;
obj_state->os_dynamic_dirty = TRUE;
}
}
static void
_commit_collect_routes(NML3Cfg *self,
int addr_family,
@ -1273,6 +1307,7 @@ loop_done:
&singlehop_routes,
NM_IN_SET(commit_type, NM_L3_CFG_COMMIT_TYPE_REAPPLY));
_obj_states_mark_dynamic_as_dirty(self);
if (singlehop_routes) {
for (i = 0; i < singlehop_routes->len; i++) {
const NMPObject *obj = singlehop_routes->pdata[i];
@ -1280,7 +1315,9 @@ loop_done:
obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj);
if (!obj_state)
_obj_states_track_new(self, obj);
_obj_states_track_new(self, obj, TRUE);
else
obj_state->os_dynamic_dirty = FALSE;
if (!_obj_states_sync_filter(self, obj, commit_type))
continue;
@ -4893,6 +4930,9 @@ _l3_commit_one(NML3Cfg *self,
if (route_table_sync == NM_IP_ROUTE_TABLE_SYNC_MODE_NONE)
route_table_sync = NM_IP_ROUTE_TABLE_SYNC_MODE_MAIN;
if (IS_IPv4)
_obj_states_remove_track(self, TRUE);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
gs_unref_array GArray *ipv6_temp_addrs_keep = NULL;