l3cfg: fix nm_l3_config_data_new_clone() to make exact copy

We use the merge function to initialize the cloned instance.
Previously, merge did not always copy all properties, so the
cloned instance might not have been identical. Fix that.
This commit is contained in:
Thomas Haller
2021-05-12 22:42:57 +02:00
parent 71eefff6e7
commit 55b722820d
2 changed files with 70 additions and 26 deletions

View File

@@ -1780,13 +1780,16 @@ _dedup_multi_index_cmp(const NML3ConfigData *a, const NML3ConfigData *b, NMPObje
}
int
nm_l3_config_data_cmp(const NML3ConfigData *a, const NML3ConfigData *b)
nm_l3_config_data_cmp_full(const NML3ConfigData *a,
const NML3ConfigData *b,
NML3ConfigCmpFlags cmp_flags)
{
int IS_IPv4;
NM_CMP_SELF(a, b);
NM_CMP_DIRECT(a->ifindex, b->ifindex);
if (!NM_FLAGS_HAS(cmp_flags, NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX))
NM_CMP_DIRECT(a->ifindex, b->ifindex);
NM_CMP_DIRECT(a->flags, b->flags);
@@ -2534,6 +2537,9 @@ nm_l3_config_data_merge(NML3ConfigData * self,
nm_assert(default_route_table_x[1] != 0);
nm_assert(default_route_metric_x[0] != 0); /* IPv6 route metric cannot be zero. */
nm_assert(!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)
|| nm_utils_is_power_of_two(merge_flags));
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 =
@@ -2588,28 +2594,31 @@ nm_l3_config_data_merge(NML3ConfigData * self,
} \
G_STMT_END
if (r_src->table_any) {
_ensure_r();
r.rx.table_any = FALSE;
r.rx.table_coerced = default_route_table_x[IS_IPv4];
}
if (r_src->metric_any) {
_ensure_r();
r.rx.metric_any = FALSE;
r.rx.metric = nm_add_clamped_u32(r.rx.metric, default_route_metric_x[IS_IPv4]);
}
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) {
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) {
if (!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) {
if (r_src->table_any) {
_ensure_r();
r.rx.table_any = FALSE;
r.rx.table_coerced = default_route_table_x[IS_IPv4];
}
if (r_src->metric_any) {
_ensure_r();
r.rx.metric_any = FALSE;
r.rx.metric =
nm_utils_ip_route_metric_penalize(r.rx.metric,
default_route_penalty_x[IS_IPv4]);
nm_add_clamped_u32(r.rx.metric, default_route_metric_x[IS_IPv4]);
}
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT(r_src)) {
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) {
_ensure_r();
r.rx.metric =
nm_utils_ip_route_metric_penalize(r.rx.metric,
default_route_penalty_x[IS_IPv4]);
}
}
}
@@ -2689,8 +2698,16 @@ nm_l3_config_data_merge(NML3ConfigData * self,
if (self->ip6_mtu == 0u)
self->ip6_mtu = src->ip6_mtu;
/* self->source does not get merged. */
/* self->dhcp_lease_x does not get merged. */
if (NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE)) {
_nm_unused nm_auto_unref_dhcplease NMDhcpLease *dhcp_lease_6 =
g_steal_pointer(&self->dhcp_lease_x[0]);
_nm_unused nm_auto_unref_dhcplease NMDhcpLease *dhcp_lease_4 =
g_steal_pointer(&self->dhcp_lease_x[1]);
self->source = src->source;
self->dhcp_lease_x[0] = nm_dhcp_lease_ref(self->dhcp_lease_x[0]);
self->dhcp_lease_x[1] = nm_dhcp_lease_ref(self->dhcp_lease_x[1]);
}
}
NML3ConfigData *
@@ -2707,6 +2724,17 @@ nm_l3_config_data_new_clone(const NML3ConfigData *src, int ifindex)
ifindex = src->ifindex;
self = nm_l3_config_data_new(src->multi_idx, ifindex);
nm_l3_config_data_merge(self, src, NM_L3_CONFIG_MERGE_FLAGS_NONE, NULL, NULL, NULL, NULL, NULL);
nm_l3_config_data_merge(self,
src,
NM_L3_CONFIG_MERGE_FLAGS_CLONE,
NULL,
NULL,
NULL,
NULL,
NULL);
nm_assert(nm_l3_config_data_cmp_full(src, self, NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX) == 0);
nm_assert(nm_l3_config_data_get_ifindex(self) == ifindex);
return self;
}

View File

@@ -60,6 +60,8 @@ typedef enum {
* 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_CLONE: clone is also implemented via "merge".
* In that case, it takes all settings.
*/
typedef enum _nm_packed {
NM_L3_CONFIG_MERGE_FLAGS_NONE = 0,
@@ -67,6 +69,7 @@ typedef enum _nm_packed {
NM_L3_CONFIG_MERGE_FLAGS_NO_ROUTES = (1LL << 1),
NM_L3_CONFIG_MERGE_FLAGS_NO_DEFAULT_ROUTES = (1LL << 2),
NM_L3_CONFIG_MERGE_FLAGS_NO_DNS = (1LL << 3),
NM_L3_CONFIG_MERGE_FLAGS_CLONE = (1LL << 4),
} NML3ConfigMergeFlags;
/*****************************************************************************/
@@ -191,7 +194,20 @@ NMDedupMultiIndex *nm_l3_config_data_get_multi_idx(const NML3ConfigData *self);
/*****************************************************************************/
int nm_l3_config_data_cmp(const NML3ConfigData *a, const NML3ConfigData *b);
typedef enum {
NM_L3_CONFIG_CMP_FLAGS_NONE,
NM_L3_CONFIG_CMP_FLAGS_IGNORE_IFINDEX = (1LL << 0),
} NML3ConfigCmpFlags;
int nm_l3_config_data_cmp_full(const NML3ConfigData *a,
const NML3ConfigData *b,
NML3ConfigCmpFlags cmp_flags);
static inline int
nm_l3_config_data_cmp(const NML3ConfigData *a, const NML3ConfigData *b)
{
return nm_l3_config_data_cmp_full(a, b, NM_L3_CONFIG_CMP_FLAGS_NONE);
}
static inline gboolean
nm_l3_config_data_equal(const NML3ConfigData *a, const NML3ConfigData *b)