l3cfg: rework merging NML3ConfigData to give more control over how to merge

NML3Cfg will need more control about how to merge the NML3ConfigData
instances. For example, it will need to intercept IPv4 addresses to
perform ACD.

For that, move the bulk of the merging code to NML3Cfg and expose the
low-level function nm_l3_config_data_merge().

Also, add a callback function to nm_l3_config_data_merge(), to give
control over how to merge.
This commit is contained in:
Thomas Haller 2020-08-03 17:19:27 +02:00
parent 25d404dadb
commit 79db3972d7
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
3 changed files with 97 additions and 116 deletions

View file

@ -1894,11 +1894,13 @@ nm_l3_config_data_new_from_platform (NMDedupMultiIndex *multi_idx,
/*****************************************************************************/
static void
_init_merge (NML3ConfigData *self,
const NML3ConfigData *src,
NML3ConfigMergeFlags merge_flags,
const guint32 *default_route_penalty_x /* length 2, for IS_IPv4 */)
void
nm_l3_config_data_merge (NML3ConfigData *self,
const NML3ConfigData *src,
NML3ConfigMergeFlags merge_flags,
const guint32 *default_route_penalty_x /* length 2, for IS_IPv4 */,
NML3ConfigMergeHookAddObj hook_add_addr,
gpointer hook_user_data)
{
NMDedupMultiIter iter;
const NMPObject *obj;
@ -1915,6 +1917,11 @@ _init_merge (NML3ConfigData *self,
src,
obj,
NMP_OBJECT_TYPE_IP_ADDRESS (IS_IPv4)) {
if ( hook_add_addr
&& !hook_add_addr (src, obj, hook_user_data))
continue;
if ( NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_EXTERNAL)
&& !NMP_OBJECT_CAST_IP_ADDRESS (obj)->external) {
NMPlatformIPXAddress a;
@ -2043,30 +2050,6 @@ nm_l3_config_data_new_clone (const NML3ConfigData *src,
ifindex = src->ifindex;
self = nm_l3_config_data_new (src->multi_idx, ifindex);
_init_merge (self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL);
return self;
}
NML3ConfigData *
nm_l3_config_data_new_combined (NMDedupMultiIndex *multi_idx,
int ifindex,
const NML3ConfigDatMergeInfo *const*merge_infos,
guint merge_infos_len)
{
NML3ConfigData *self;
guint i;
nm_assert (multi_idx);
nm_assert (ifindex > 0);
self = nm_l3_config_data_new (multi_idx, ifindex);
for (i = 0; i < merge_infos_len; i++) {
_init_merge (self,
merge_infos[i]->l3cd,
merge_infos[i]->merge_flags,
merge_infos[i]->default_route_penalty_x);
}
nm_l3_config_data_merge (self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL, NULL, NULL);
return self;
}

View file

@ -63,18 +63,6 @@ typedef enum {
/*****************************************************************************/
typedef struct {
const NML3ConfigData *l3cd;
NML3ConfigMergeFlags merge_flags;
union {
struct {
guint32 default_route_penalty_6;
guint32 default_route_penalty_4;
};
guint32 default_route_penalty_x[2];
};
} NML3ConfigDatMergeInfo;
NML3ConfigData *nm_l3_config_data_new (NMDedupMultiIndex *multi_idx,
int ifindex);
const NML3ConfigData *nm_l3_config_data_ref (const NML3ConfigData *self);
@ -106,10 +94,16 @@ NML3ConfigData *nm_l3_config_data_new_from_platform (NMDedupMultiIndex *multi_id
NMPlatform *platform,
NMSettingIP6ConfigPrivacy ipv6_privacy_rfc4941);
NML3ConfigData *nm_l3_config_data_new_combined (NMDedupMultiIndex *multi_idx,
int ifindex,
const NML3ConfigDatMergeInfo *const*merge_infos,
guint merge_infos_len);
typedef gboolean (*NML3ConfigMergeHookAddObj) (const NML3ConfigData *l3cd,
const NMPObject *obj,
gpointer user_data);
void nm_l3_config_data_merge (NML3ConfigData *self,
const NML3ConfigData *src,
NML3ConfigMergeFlags merge_flags,
const guint32 *default_route_penalty_x /* length 2, for IS_IPv4 */,
NML3ConfigMergeHookAddObj hook_add_addr,
gpointer hook_user_data);
void nm_l3_config_data_add_dependent_routes (NML3ConfigData *self,
int addr_family,

View file

@ -11,7 +11,15 @@
/*****************************************************************************/
typedef struct {
NML3ConfigDatMergeInfo merge_info;
const NML3ConfigData *l3cd;
NML3ConfigMergeFlags merge_flags;
union {
struct {
guint32 default_route_penalty_6;
guint32 default_route_penalty_4;
};
guint32 default_route_penalty_x[2];
};
gconstpointer tag;
guint64 pseudo_timestamp;
int priority;
@ -525,7 +533,7 @@ _l3_config_datas_find_next (GArray *l3_config_datas,
const L3ConfigData *l3_config_data = _l3_config_datas_at (l3_config_datas, i);
if ( NM_IN_SET (needle_tag, NULL, l3_config_data->tag)
&& NM_IN_SET (needle_l3cd, NULL, l3_config_data->merge_info.l3cd))
&& NM_IN_SET (needle_l3cd, NULL, l3_config_data->l3cd))
return i;
}
return -1;
@ -542,7 +550,7 @@ _l3_config_datas_remove_index_fast (GArray *arr,
l3_config_data = _l3_config_datas_at (arr, idx);
nm_l3_config_data_unref (l3_config_data->merge_info.l3cd);
nm_l3_config_data_unref (l3_config_data->l3cd);
g_array_remove_index_fast (arr, idx);
}
@ -611,7 +619,7 @@ nm_l3cfg_add_config (NML3Cfg *self,
while (TRUE) {
l3_config_data = _l3_config_datas_at (l3_config_datas, idx2);
if (l3_config_data->merge_info.l3cd == l3cd) {
if (l3_config_data->l3cd == l3cd) {
nm_assert (idx == -1);
idx = idx2;
continue;
@ -629,35 +637,35 @@ nm_l3cfg_add_config (NML3Cfg *self,
if (idx < 0) {
l3_config_data = nm_g_array_append_new (l3_config_datas, L3ConfigData);
*l3_config_data = (L3ConfigData) {
.tag = tag,
.merge_info.l3cd = nm_l3_config_data_ref_and_seal (l3cd),
.merge_info.merge_flags = merge_flags,
.merge_info.default_route_penalty_4 = default_route_penalty_4,
.merge_info.default_route_penalty_6 = default_route_penalty_6,
.priority = priority,
.pseudo_timestamp = ++self->priv.p->pseudo_timestamp_counter,
.dirty = FALSE,
.tag = tag,
.l3cd = nm_l3_config_data_ref_and_seal (l3cd),
.merge_flags = merge_flags,
.default_route_penalty_4 = default_route_penalty_4,
.default_route_penalty_6 = default_route_penalty_6,
.priority = priority,
.pseudo_timestamp = ++self->priv.p->pseudo_timestamp_counter,
.dirty = FALSE,
};
changed = TRUE;
} else {
l3_config_data = _l3_config_datas_at (l3_config_datas, idx);
l3_config_data->dirty = FALSE;
nm_assert (l3_config_data->tag == tag);
nm_assert (l3_config_data->merge_info.l3cd == l3cd);
nm_assert (l3_config_data->l3cd == l3cd);
if (l3_config_data->priority != priority) {
l3_config_data->priority = priority;
changed = TRUE;
}
if (l3_config_data->merge_info.merge_flags != merge_flags) {
l3_config_data->merge_info.merge_flags = merge_flags;
if (l3_config_data->merge_flags != merge_flags) {
l3_config_data->merge_flags = merge_flags;
changed = TRUE;
}
if (l3_config_data->merge_info.default_route_penalty_4 != default_route_penalty_4) {
l3_config_data->merge_info.default_route_penalty_4 = default_route_penalty_4;
if (l3_config_data->default_route_penalty_4 != default_route_penalty_4) {
l3_config_data->default_route_penalty_4 = default_route_penalty_4;
changed = TRUE;
}
if (l3_config_data->merge_info.default_route_penalty_6 != default_route_penalty_6) {
l3_config_data->merge_info.default_route_penalty_6 = default_route_penalty_6;
if (l3_config_data->default_route_penalty_6 != default_route_penalty_6) {
l3_config_data->default_route_penalty_6 = default_route_penalty_6;
changed = TRUE;
}
}
@ -734,7 +742,7 @@ _l3_config_combine_sort_fcn (gconstpointer p_a,
nm_assert (a);
nm_assert (b);
nm_assert (nm_l3_config_data_get_ifindex (a->merge_info.l3cd) == nm_l3_config_data_get_ifindex (b->merge_info.l3cd));
nm_assert (nm_l3_config_data_get_ifindex (a->l3cd) == nm_l3_config_data_get_ifindex (b->l3cd));
/* we sort the entries with higher priority (more important, lower numerical value)
* first. */
@ -747,58 +755,17 @@ _l3_config_combine_sort_fcn (gconstpointer p_a,
return nm_assert_unreachable_val (0);
}
static const NML3ConfigData *
_l3cfg_combine_config (GArray *l3_config_datas,
NMDedupMultiIndex *multi_idx,
int ifindex)
{
gs_free L3ConfigData **infos_heap = NULL;
NML3ConfigData *l3cd;
L3ConfigData **infos;
guint i;
if ( !l3_config_datas
|| l3_config_datas->len == 0)
return NULL;
if (l3_config_datas->len == 1)
return nm_l3_config_data_ref (_l3_config_datas_at (l3_config_datas, 0)->merge_info.l3cd);
if (l3_config_datas->len < 300 / sizeof (infos[0]))
infos = g_alloca (l3_config_datas->len * sizeof (infos[0]));
else {
infos_heap = g_new (L3ConfigData *, l3_config_datas->len);
infos = infos_heap;
}
for (i = 0; i < l3_config_datas->len; i++)
infos[i] = _l3_config_datas_at (l3_config_datas, i);
g_qsort_with_data (infos,
l3_config_datas->len,
sizeof (infos[0]),
_l3_config_combine_sort_fcn,
NULL);
nm_assert (&infos[0]->merge_info == (NML3ConfigDatMergeInfo *) infos[0]);
l3cd = nm_l3_config_data_new_combined (multi_idx,
ifindex,
(const NML3ConfigDatMergeInfo *const*) infos,
l3_config_datas->len);
nm_assert (l3cd);
nm_assert (nm_l3_config_data_get_ifindex (l3cd) == ifindex);
return nm_l3_config_data_seal (l3cd);
}
static gboolean
_l3cfg_update_combined_config (NML3Cfg *self,
const NML3ConfigData **out_old /* transfer reference */)
{
nm_auto_unref_l3cd const NML3ConfigData *l3cd_old = NULL;
nm_auto_unref_l3cd const NML3ConfigData *l3cd = NULL;
nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL;
NMDedupMultiIndex *multi_idx;
gs_free L3ConfigData **infos_heap = NULL;
L3ConfigData **infos;
GArray *l3_config_datas;
guint i;
nm_assert (NM_IS_L3CFG (self));
nm_assert (!out_old || !*out_old);
@ -808,9 +775,46 @@ _l3cfg_update_combined_config (NML3Cfg *self,
self->priv.changed_configs = FALSE;
l3cd = _l3cfg_combine_config (self->priv.p->l3_config_datas,
nm_platform_get_multi_idx (self->priv.platform),
self->priv.ifindex);
multi_idx = nm_platform_get_multi_idx (self->priv.platform);
l3_config_datas = self->priv.p->l3_config_datas;
if ( l3_config_datas
&& l3_config_datas->len > 0) {
l3cd = nm_l3_config_data_new (multi_idx, self->priv.ifindex);
if (l3_config_datas->len < 300 / sizeof (infos[0]))
infos = g_alloca (l3_config_datas->len * sizeof (infos[0]));
else {
infos_heap = g_new (L3ConfigData *, l3_config_datas->len);
infos = infos_heap;
}
for (i = 0; i < l3_config_datas->len; i++)
infos[i] = _l3_config_datas_at (l3_config_datas, i);
g_qsort_with_data (infos,
l3_config_datas->len,
sizeof (infos[0]),
_l3_config_combine_sort_fcn,
NULL);
for (i = 0; i < l3_config_datas->len; i++) {
nm_l3_config_data_merge (l3cd,
infos[i]->l3cd,
infos[i]->merge_flags,
infos[i]->default_route_penalty_x,
NULL,
NULL);
}
nm_assert (l3cd);
nm_assert (nm_l3_config_data_get_ifindex (l3cd) == self->priv.ifindex);
nm_l3_config_data_seal (l3cd);
}
if (nm_l3_config_data_equal (l3cd, self->priv.p->combined_l3cd))
return FALSE;