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 ff5a820fda

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 is_dynamic_dirty : 1;
} ObjStateData;
G_STATIC_ASSERT(G_STRUCT_OFFSET(ObjStateData, obj) == 0);
@ -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,
.is_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,6 +1017,7 @@ _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)));
@ -1064,7 +1073,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;
}
@ -1194,6 +1203,52 @@ _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->is_dynamic_dirty = TRUE;
}
}
static void
_obj_states_dynamic_remove_track(NML3Cfg *self)
{
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 (!obj_state->os_dynamic)
continue;
if (!obj_state->is_dynamic_dirty)
continue;
if (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 dynamic zombie: %s",
_obj_state_data_to_string(obj_state, sbuf, sizeof(sbuf)));
continue;
}
_LOGD("obj-state: dynamic 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);
}
}
static void
_commit_collect_routes(NML3Cfg *self,
int addr_family,
@ -1273,6 +1328,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 +1336,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->is_dynamic_dirty = FALSE;
if (!_obj_states_sync_filter(self, obj, commit_type))
continue;
@ -4893,6 +4951,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_dynamic_remove_track(self);
if (commit_type == NM_L3_CFG_COMMIT_TYPE_REAPPLY) {
gs_unref_array GArray *ipv6_temp_addrs_keep = NULL;