diff --git a/src/nm-l3-config-data.c b/src/nm-l3-config-data.c index 78a0e332fd..1dec11ed89 100644 --- a/src/nm-l3-config-data.c +++ b/src/nm-l3-config-data.c @@ -143,6 +143,44 @@ _garray_inaddr_clone (const GArray *src, return dst; } +static void +_garray_inaddr_merge (GArray **p_dst, + const GArray *src, + int addr_family) +{ + guint dst_initial_len; + const char *p_dst_arr; + const char *p_src; + gsize elt_size; + guint i; + guint j; + + if (nm_g_array_len (src) == 0) + return; + + if (!*p_dst) { + *p_dst = _garray_inaddr_clone (src, addr_family); + return; + } + + elt_size = nm_utils_addr_family_to_size (addr_family); + + dst_initial_len = (*p_dst)->len; + p_dst_arr = (*p_dst)->data; + p_src = src->data; + + for (i = 0; i < src->len; i++, p_src += elt_size) { + for (j = 0; j < dst_initial_len; j++) { + if (memcmp (&p_dst_arr[j * elt_size], p_src, elt_size) == 0) + goto next; + } + g_array_append_vals (*p_dst, p_src, 1); + p_dst_arr = (*p_dst)->data; +next: + ; + } +} + static gssize _garray_inaddr_find (GArray *arr, int addr_family, @@ -204,6 +242,36 @@ _garray_inaddr_cmp (const GArray *a, const GArray *b, int addr_family) return 0; } +static void +_strv_ptrarray_merge (GPtrArray **p_dst, const GPtrArray *src) +{ + guint dst_initial_len; + guint i; + + if (nm_g_ptr_array_len (src) == 0) + return; + + if (!*p_dst) { + /* we trust src to contain unique strings. Just clone it. */ + *p_dst = nm_strv_ptrarray_clone (src, TRUE); + return; + } + + nm_strv_ptrarray_ensure (p_dst); + + dst_initial_len = (*p_dst)->len; + + for (i = 0; i < src->len; i++) { + const char *s = src->pdata[i]; + + if ( dst_initial_len > 0 + && nm_utils_strv_find_first ((char **) ((*p_dst)->pdata), dst_initial_len, s) >= 0) + continue; + + g_ptr_array_add (*p_dst, g_strdup (s)); + } +} + /*****************************************************************************/ static gboolean @@ -1316,13 +1384,143 @@ 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 */) +{ + NMDedupMultiIter iter; + const NMPObject *obj; + int IS_IPv4; + + nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE)); + nm_assert (_NM_IS_L3_CONFIG_DATA (src, TRUE)); + + for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + const int addr_family = IS_IPv4 ? AF_INET : AF_INET6; + const NML3ConfigDatFlags has_dns_priority_flag = NM_L3_CONFIG_DAT_FLAGS_HAS_DNS_PRIORITY (IS_IPv4); + + nm_l3_config_data_iter_obj_for_each (iter, + src, + obj, + NMP_OBJECT_TYPE_IP_ADDRESS (IS_IPv4)) { + if ( NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_EXTERNAL) + && !NMP_OBJECT_CAST_IP_ADDRESS (obj)->external) { + NMPlatformIPXAddress a; + + if (IS_IPv4) + a.a4 = *NMP_OBJECT_CAST_IP4_ADDRESS (obj); + else + a.a6 = *NMP_OBJECT_CAST_IP6_ADDRESS (obj); + a.ax.ifindex = self->ifindex; + a.ax.external = TRUE; + nm_l3_config_data_add_address_full (self, + addr_family, + NULL, + &a.ax, + NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, + NULL); + continue; + } + + nm_l3_config_data_add_address_full (self, + addr_family, + obj, + NULL, + NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, + NULL); + } + + if (!NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES)) { + nm_l3_config_data_iter_obj_for_each (iter, + src, + obj, + NMP_OBJECT_TYPE_IP_ROUTE (IS_IPv4)) { + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (NMP_OBJECT_CAST_IP_ROUTE (obj))) { + if ( NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES) + && !NM_FLAGS_HAS (src->flags, NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES)) + continue; + + if ( default_route_penalty_x + && default_route_penalty_x[IS_IPv4] > 0) { + NMPlatformIPXRoute r; + + if (IS_IPv4) + r.r4 = *NMP_OBJECT_CAST_IP4_ROUTE (obj); + else + r.r6 = *NMP_OBJECT_CAST_IP6_ROUTE (obj); + r.rx.ifindex = self->ifindex; + r.rx.metric = nm_utils_ip_route_metric_penalize (r.rx.metric, default_route_penalty_x[IS_IPv4]); + nm_l3_config_data_add_route_full (self, + addr_family, + NULL, + &r.rx, + NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, + NULL, + NULL); + continue; + } + } + nm_l3_config_data_add_route_full (self, + addr_family, + obj, + NULL, + NM_L3_CONFIG_ADD_FLAGS_EXCLUSIVE, + NULL, + NULL); + } + } + + if (!NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) + _garray_inaddr_merge (&self->nameservers_x[IS_IPv4], src->nameservers_x[IS_IPv4], addr_family); + + if (!NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) + _strv_ptrarray_merge (&self->domains_x[IS_IPv4], src->domains_x[IS_IPv4]); + + if (!NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) + _strv_ptrarray_merge (&self->searches_x[IS_IPv4], src->searches_x[IS_IPv4]); + + if (!NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) + _strv_ptrarray_merge (&self->dns_options_x[IS_IPv4], src->dns_options_x[IS_IPv4]); + + if ( !NM_FLAGS_ANY (self->flags, has_dns_priority_flag) + && NM_FLAGS_ANY (src->flags, has_dns_priority_flag)) { + self->dns_priority_x[IS_IPv4] = src->dns_priority_x[IS_IPv4]; + self->flags |= has_dns_priority_flag; + } + } + + if (!NM_FLAGS_HAS (merge_flags, NM_L3_CONFIG_MERGE_FLAGS_NO_DNS)) { + _garray_inaddr_merge (&self->wins, src->wins, AF_INET); + _garray_inaddr_merge (&self->nis_servers, src->nis_servers, AF_INET); + + if ( !self->nis_domain + && src->nis_domain) + self->nis_domain = g_strdup (src->nis_domain); + } + + if (self->mdns == NM_SETTING_CONNECTION_MDNS_DEFAULT) + self->mdns = src->mdns; + + if (self->llmnr == NM_SETTING_CONNECTION_LLMNR_DEFAULT) + self->llmnr = src->llmnr; + + if (self->metered == NM_TERNARY_DEFAULT) + self->metered = src->metered; + + if ( !NM_FLAGS_HAS (self->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_MTU) + && NM_FLAGS_HAS (src->flags, NM_L3_CONFIG_DAT_FLAGS_HAS_MTU)) { + self->mtu = src->mtu; + self->flags |= NM_L3_CONFIG_DAT_FLAGS_HAS_MTU; + } +} + NML3ConfigData * nm_l3_config_data_new_clone (const NML3ConfigData *src, int ifindex) { NML3ConfigData *self; - NMDedupMultiIter iter; - const NMPObject *obj; nm_assert (_NM_IS_L3_CONFIG_DATA (src, TRUE)); @@ -1333,34 +1531,30 @@ 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; +} - nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP4_ADDRESS) - nm_l3_config_data_add_address (self, AF_INET, obj, NULL); - nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP6_ADDRESS) - nm_l3_config_data_add_address (self, AF_INET6, obj, NULL); - nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP4_ROUTE) - nm_l3_config_data_add_route (self, AF_INET, obj, NULL); - nm_l3_config_data_iter_obj_for_each (iter, src, obj, NMP_OBJECT_TYPE_IP6_ROUTE) - nm_l3_config_data_add_route (self, AF_INET6, obj, NULL); +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 (self->best_default_route_4 == src->best_default_route_4); - nm_assert (self->best_default_route_6 == src->best_default_route_6); + nm_assert (multi_idx); + nm_assert (ifindex > 0); - self->wins = _garray_inaddr_clone (src->wins, AF_INET); - self->nameservers_4 = _garray_inaddr_clone (src->nameservers_4, AF_INET); - self->nameservers_6 = _garray_inaddr_clone (src->nameservers_6, AF_INET6); - self->domains_4 = nm_strv_ptrarray_clone (src->domains_4, TRUE); - self->domains_6 = nm_strv_ptrarray_clone (src->domains_6, TRUE); - self->searches_4 = nm_strv_ptrarray_clone (src->searches_4, TRUE); - self->searches_6 = nm_strv_ptrarray_clone (src->searches_6, TRUE); - self->dns_options_4 = nm_strv_ptrarray_clone (src->dns_options_4, TRUE); - self->dns_options_6 = nm_strv_ptrarray_clone (src->dns_options_6, TRUE); - self->dns_priority_4 = src->dns_priority_4; - self->dns_priority_6 = src->dns_priority_6; - self->mdns = src->mdns; - self->llmnr = src->llmnr; + self = nm_l3_config_data_new (multi_idx, ifindex); - /* TODO: some fields are not cloned. Will be done next. */ + for (i = 0; i < merge_infos_len; i++) { + _init_merge (self, + merge_infos[i]->l3cfg, + merge_infos[i]->merge_flags, + merge_infos[i]->default_route_penalty_x); + } return self; } diff --git a/src/nm-l3-config-data.h b/src/nm-l3-config-data.h index e8649e83e1..09b46a2ce4 100644 --- a/src/nm-l3-config-data.h +++ b/src/nm-l3-config-data.h @@ -43,10 +43,40 @@ typedef enum { NM_L3_CONFIG_ADD_FLAGS_APPEND_FORCE = (1ull << 2), } NML3ConfigAddFlags; +/** + * NML3ConfigMergeFlags: + * @NM_L3_CONFIG_MERGE_FLAGS_NONE: no flags set + * @NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES: don't merge routes + * @NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES: don't merge default routes. + * Note that if the respective NML3ConfigData has NM_L3_CONFIG_DAT_FLAGS_IGNORE_MERGE_NO_DEFAULT_ROUTES + * set, this flag gets ignored during merge. + * @NM_L3_CONFIG_MERGE_FLAGS_NO_DNS: don't merge DNS information + * @NM_L3_CONFIG_MERGE_FLAGS_EXTERNAL: mark new addresses as external + */ +typedef enum { + NM_L3_CONFIG_MERGE_FLAGS_NONE = 0, + NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 0), + NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 1), + NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 2), + NM_L3_CONFIG_MERGE_FLAGS_EXTERNAL = (1LL << 3), +} NML3ConfigMergeFlags; + /*****************************************************************************/ typedef struct _NML3ConfigData NML3ConfigData; +typedef struct { + const NML3ConfigData *l3cfg; + 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); @@ -76,6 +106,11 @@ 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); + /*****************************************************************************/ int nm_l3_config_data_get_ifindex (const NML3ConfigData *self); diff --git a/src/nm-l3cfg.c b/src/nm-l3cfg.c index aefaef1cd8..3709ff7dbc 100644 --- a/src/nm-l3cfg.c +++ b/src/nm-l3cfg.c @@ -10,6 +10,16 @@ /*****************************************************************************/ +typedef struct { + NML3ConfigDatMergeInfo merge_info; + gconstpointer tag; + guint64 pseudo_timestamp; + int priority; + bool dirty:1; +} L3ConfigData; + +/*****************************************************************************/ + NM_GOBJECT_PROPERTIES_DEFINE (NML3Cfg, PROP_NETNS, PROP_IFINDEX, @@ -17,6 +27,9 @@ NM_GOBJECT_PROPERTIES_DEFINE (NML3Cfg, typedef struct _NML3CfgPrivate { GArray *property_emit_list; + GArray *l3_config_datas; + const NML3ConfigData *combined_l3cfg; + guint64 pseudo_timestamp_counter; } NML3CfgPrivate; struct _NML3CfgClass { @@ -226,6 +239,331 @@ nm_l3cfg_property_emit_unregister (NML3Cfg *self, /*****************************************************************************/ +static GArray * +_l3_config_datas_ensure (GArray **p_arr) +{ + if (!*p_arr) + *p_arr = g_array_new (FALSE, FALSE, sizeof (L3ConfigData)); + return *p_arr; +} + +#define _l3_config_datas_at(l3_config_datas, idx) \ + (&g_array_index ((l3_config_datas), L3ConfigData, (idx))) + +static gssize +_l3_config_datas_find_next (GArray *l3_config_datas, + guint start_idx, + gconstpointer needle_tag, + const NML3ConfigData *needle_l3cfg) +{ + guint i; + + nm_assert (l3_config_datas); + nm_assert (start_idx <= l3_config_datas->len); + + for (i = start_idx; i < l3_config_datas->len; i++) { + 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_l3cfg, NULL, l3_config_data->merge_info.l3cfg)) + return i; + } + return -1; +} + +static void +_l3_config_datas_remove_index_fast (GArray *arr, + guint idx) +{ + L3ConfigData *l3_config_data; + + nm_assert (arr); + nm_assert (idx < arr->len); + + l3_config_data = _l3_config_datas_at (arr, idx); + + nm_l3_config_data_unref (l3_config_data->merge_info.l3cfg); + + g_array_remove_index_fast (arr, idx); +} + +void +nm_l3cfg_mark_config_dirty (NML3Cfg *self, + gconstpointer tag, + gboolean dirty) +{ + GArray *l3_config_datas; + gssize idx; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (tag); + + l3_config_datas = self->priv.p->l3_config_datas; + if (!l3_config_datas) + return; + + idx = 0; + while (TRUE) { + idx = _l3_config_datas_find_next (l3_config_datas, + idx, + tag, + NULL); + if (idx < 0) + return; + + _l3_config_datas_at (l3_config_datas, idx)->dirty = dirty; + idx++; + } +} + +void +nm_l3cfg_add_config (NML3Cfg *self, + gconstpointer tag, + gboolean replace_same_tag, + const NML3ConfigData *l3cfg, + int priority, + guint32 default_route_penalty_4, + guint32 default_route_penalty_6, + NML3ConfigMergeFlags merge_flags) +{ + GArray *l3_config_datas; + L3ConfigData *l3_config_data; + gssize idx; + gboolean changed = FALSE; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (tag); + nm_assert (l3cfg); + nm_assert (nm_l3_config_data_get_ifindex (l3cfg) == self->priv.ifindex); + + l3_config_datas = _l3_config_datas_ensure (&self->priv.p->l3_config_datas); + + idx = _l3_config_datas_find_next (l3_config_datas, + 0, + tag, + replace_same_tag ? NULL : l3cfg); + + if (replace_same_tag) { + gssize idx2; + + idx2 = idx; + idx = -1; + while (TRUE) { + l3_config_data = _l3_config_datas_at (l3_config_datas, idx2); + + if (l3_config_data->merge_info.l3cfg == l3cfg) { + nm_assert (idx == -1); + idx = idx2; + continue; + } + + changed = TRUE; + _l3_config_datas_remove_index_fast (l3_config_datas, idx2); + + idx2 = _l3_config_datas_find_next (l3_config_datas, idx2, tag, NULL); + if (idx2 < 0) + break; + } + } + + if (idx < 0) { + l3_config_data = nm_g_array_append_new (l3_config_datas, L3ConfigData); + *l3_config_data = (L3ConfigData) { + .tag = tag, + .merge_info.l3cfg = nm_l3_config_data_ref_and_seal (l3cfg), + .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, + }; + 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.l3cfg == l3cfg); + 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; + 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; + 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; + changed = TRUE; + } + } + + if (changed) + self->priv.changed_configs = TRUE; +} + +static void +_l3cfg_remove_config (NML3Cfg *self, + gconstpointer tag, + gboolean only_dirty, + const NML3ConfigData *l3cfg) +{ + GArray *l3_config_datas; + gssize idx; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (tag); + + l3_config_datas = self->priv.p->l3_config_datas; + if (!l3_config_datas) + return; + + idx = 0; + while (TRUE) { + idx = _l3_config_datas_find_next (l3_config_datas, + idx, + tag, + l3cfg); + if (idx < 0) + return; + + if ( only_dirty + && !_l3_config_datas_at (l3_config_datas, idx)->dirty) { + idx++; + continue; + } + + self->priv.changed_configs = TRUE; + _l3_config_datas_remove_index_fast (l3_config_datas, idx); + if (!l3cfg) + return; + } +} + +void +nm_l3cfg_remove_config (NML3Cfg *self, + gconstpointer tag, + const NML3ConfigData *ifcfg) +{ + nm_assert (ifcfg); + + _l3cfg_remove_config (self, tag, FALSE, ifcfg); +} + +void +nm_l3cfg_remove_config_all (NML3Cfg *self, + gconstpointer tag, + gboolean only_dirty) +{ + _l3cfg_remove_config (self, tag, only_dirty, NULL); +} + +/*****************************************************************************/ + +static int +_l3_config_combine_sort_fcn (gconstpointer p_a, + gconstpointer p_b, + gpointer user_data) +{ + const L3ConfigData *a = *((L3ConfigData **) p_a); + const L3ConfigData *b = *((L3ConfigData **) p_b); + + nm_assert (a); + nm_assert (b); + nm_assert (nm_l3_config_data_get_ifindex (a->merge_info.l3cfg) == nm_l3_config_data_get_ifindex (b->merge_info.l3cfg)); + + /* we sort the entries with higher priority (more important, lower numerical value) + * first. */ + NM_CMP_FIELD (a, b, priority); + + /* if the priority is not unique, we sort them in the order they were added, + * with the oldest first (lower numerical value). */ + NM_CMP_FIELD (a, b, pseudo_timestamp); + + 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 *l3cfg; + 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.l3cfg); + + 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]); + + l3cfg = nm_l3_config_data_new_combined (multi_idx, + ifindex, + (const NML3ConfigDatMergeInfo *const*) infos, + l3_config_datas->len); + + nm_assert (l3cfg); + nm_assert (nm_l3_config_data_get_ifindex (l3cfg) == ifindex); + + return nm_l3_config_data_seal (l3cfg); +} + +_nm_unused +static gboolean +_l3cfg_update_combined_config (NML3Cfg *self, + const NML3ConfigData **out_old /* transfer reference */) +{ + nm_auto_unref_l3cfg const NML3ConfigData *l3cfg_old = NULL; + nm_auto_unref_l3cfg const NML3ConfigData *l3cfg = NULL; + + nm_assert (NM_IS_L3CFG (self)); + nm_assert (!out_old || !*out_old); + + if (!self->priv.changed_configs) + return FALSE; + + self->priv.changed_configs = FALSE; + + l3cfg = _l3cfg_combine_config (self->priv.p->l3_config_datas, + nm_platform_get_multi_idx (self->priv.platform), + self->priv.ifindex); + + if (nm_l3_config_data_equal (l3cfg, self->priv.p->combined_l3cfg)) + return FALSE; + + l3cfg_old = g_steal_pointer (&self->priv.p->combined_l3cfg); + self->priv.p->combined_l3cfg = nm_l3_config_data_seal (g_steal_pointer (&l3cfg)); + NM_SET_OUT (out_old, nm_l3_config_data_ref (self->priv.p->combined_l3cfg)); + return TRUE; +} + +/*****************************************************************************/ + static void set_property (GObject *object, guint prop_id, @@ -304,6 +642,8 @@ finalize (GObject *object) g_clear_object (&self->priv.netns); g_clear_object (&self->priv.platform); + nm_clear_pointer (&self->priv.p->combined_l3cfg, nm_l3_config_data_unref); + nm_clear_pointer (&self->priv.pllink, nmp_object_unref); _LOGT ("finalized"); diff --git a/src/nm-l3cfg.h b/src/nm-l3cfg.h index 7fc4b4b7d2..0c2b9c814a 100644 --- a/src/nm-l3cfg.h +++ b/src/nm-l3cfg.h @@ -4,6 +4,7 @@ #define __NM_L3CFG_H__ #include "platform/nmp-object.h" +#include "nm-l3-config-data.h" #define NM_TYPE_L3CFG (nm_l3cfg_get_type ()) #define NM_L3CFG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_L3CFG, NML3Cfg)) @@ -20,11 +21,12 @@ struct _NML3CfgPrivate; struct _NML3Cfg { GObject parent; struct { + struct _NML3CfgPrivate *p; NMNetns *netns; NMPlatform *platform; - int ifindex; const NMPObject *pllink; - struct _NML3CfgPrivate *p; + int ifindex; + bool changed_configs:1; } priv; }; @@ -89,4 +91,27 @@ void nm_l3cfg_property_emit_unregister (NML3Cfg *self, GObject *target_obj, const GParamSpec *target_property); +/*****************************************************************************/ + +void nm_l3cfg_mark_config_dirty (NML3Cfg *self, + gconstpointer tag, + gboolean dirty); + +void nm_l3cfg_add_config (NML3Cfg *self, + gconstpointer tag, + gboolean replace_same_tag, + const NML3ConfigData *l3cfg, + int priority, + guint32 default_route_penalty_4, + guint32 default_route_penalty_6, + NML3ConfigMergeFlags merge_flags); + +void nm_l3cfg_remove_config (NML3Cfg *self, + gconstpointer tag, + const NML3ConfigData *ifcfg); + +void nm_l3cfg_remove_config_all (NML3Cfg *self, + gconstpointer tag, + gboolean only_dirty); + #endif /* __NM_L3CFG_H__ */