diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index cbf8ebb44..5d3ed9424 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -1477,10 +1477,11 @@ nm_ip4_config_subtract (NMIP4Config *dst, g_object_thaw_notify (G_OBJECT (dst)); } -void -nm_ip4_config_intersect (NMIP4Config *dst, - const NMIP4Config *src, - guint32 default_route_metric_penalty) +static gboolean +_nm_ip4_config_intersect_helper (NMIP4Config *dst, + const NMIP4Config *src, + guint32 default_route_metric_penalty, + gboolean update_dst) { NMIP4ConfigPrivate *dst_priv; const NMIP4ConfigPrivate *src_priv; @@ -1488,15 +1489,16 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMPlatformIP4Address *a; const NMPlatformIP4Route *r; const NMPObject *new_best_default_route; - gboolean changed; + gboolean changed, result = FALSE; - g_return_if_fail (src); - g_return_if_fail (dst); + g_return_val_if_fail (src, FALSE); + g_return_val_if_fail (dst, FALSE); dst_priv = NM_IP4_CONFIG_GET_PRIVATE (dst); src_priv = NM_IP4_CONFIG_GET_PRIVATE (src); - g_object_freeze_notify (G_OBJECT (dst)); + if (update_dst) + g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ changed = FALSE; @@ -1506,13 +1508,18 @@ nm_ip4_config_intersect (NMIP4Config *dst, NMP_OBJECT_UP_CAST (a))) continue; + if (!update_dst) + return TRUE; + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); changed = TRUE; } - if (changed) + if (changed) { _notify_addresses (dst); + result = TRUE; + } /* ignore nameservers */ @@ -1544,6 +1551,9 @@ nm_ip4_config_intersect (NMIP4Config *dst, continue; } + if (!update_dst) + return TRUE; + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); @@ -1553,8 +1563,11 @@ nm_ip4_config_intersect (NMIP4Config *dst, nm_assert (changed); _notify (dst, PROP_GATEWAY); } - if (changed) + + if (changed) { _notify_routes (dst); + result = TRUE; + } /* ignore domains */ /* ignore dns searches */ @@ -1562,9 +1575,58 @@ nm_ip4_config_intersect (NMIP4Config *dst, /* ignore NIS */ /* ignore WINS */ - g_object_thaw_notify (G_OBJECT (dst)); + if (update_dst) + g_object_thaw_notify (G_OBJECT (dst)); + return result; } +/** + * nm_ip4_config_intersect: + * @dst: a configuration to be updated + * @src: another configuration + * @default_route_metric_penalty: the default route metric penalty + * + * Computes the intersection between @src and @dst and updates @dst in place + * with the result. + */ +void +nm_ip4_config_intersect (NMIP4Config *dst, + const NMIP4Config *src, + guint32 default_route_metric_penalty) +{ + _nm_ip4_config_intersect_helper (dst, src, default_route_metric_penalty, TRUE); +} + +/** + * nm_ip4_config_intersect_alloc: + * @a: a configuration + * @b: another configuration + * @default_route_metric_penalty: the default route metric penalty + * + * Computes the intersection between @a and @b and returns the result in a newly + * allocated configuration. As a special case, if @a and @b are identical (with + * respect to the only properties considered - addresses and routes) the + * functions returns NULL so that one of existing configuration can be reused + * without allocation. + * + * Returns: the intersection between @a and @b, or %NULL if the result is equal + * to @a and @b. + */ +NMIP4Config * +nm_ip4_config_intersect_alloc (const NMIP4Config *a, + const NMIP4Config *b, + guint32 default_route_metric_penalty) +{ + NMIP4Config *a_copy; + + if (_nm_ip4_config_intersect_helper ((NMIP4Config *) a, b, + default_route_metric_penalty, FALSE)) { + a_copy = nm_ip4_config_clone (a); + _nm_ip4_config_intersect_helper (a_copy, b, default_route_metric_penalty, TRUE); + return a_copy; + } else + return NULL; +} /** * nm_ip4_config_replace: diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index f53ba0200..c614863d0 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -187,6 +187,9 @@ void nm_ip4_config_subtract (NMIP4Config *dst, void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, guint32 default_route_metric_penalty); +NMIP4Config *nm_ip4_config_intersect_alloc (const NMIP4Config *a, + const NMIP4Config *b, + guint32 default_route_metric_penalty); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); void nm_ip4_config_dump (const NMIP4Config *self, const char *detail); @@ -455,4 +458,23 @@ nm_ip_config_merge (NMIPConfig *dst, default_route_metric_penalty); } +static inline NMIPConfig * +nm_ip_config_intersect_alloc (const NMIPConfig *a, + const NMIPConfig *b, + guint32 default_route_metric_penalty) +{ + int family; + + family = nm_ip_config_get_addr_family (a); + nm_assert (family == nm_ip_config_get_addr_family (b)); + + if (family == AF_INET) + return (NMIPConfig *) nm_ip4_config_intersect_alloc ((const NMIP4Config *) a, + (const NMIP4Config *) b, + default_route_metric_penalty); + else + return (NMIPConfig *) nm_ip6_config_intersect_alloc ((const NMIP6Config *) a, + (const NMIP6Config *) b, + default_route_metric_penalty); +} #endif /* __NETWORKMANAGER_IP4_CONFIG_H__ */ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 36901ce7a..d3c963aab 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1081,26 +1081,28 @@ nm_ip6_config_subtract (NMIP6Config *dst, g_object_thaw_notify (G_OBJECT (dst)); } -void -nm_ip6_config_intersect (NMIP6Config *dst, - const NMIP6Config *src, - guint32 default_route_metric_penalty) +static gboolean +_nm_ip6_config_intersect_helper (NMIP6Config *dst, + const NMIP6Config *src, + guint32 default_route_metric_penalty, + gboolean update_dst) { NMIP6ConfigPrivate *dst_priv; const NMIP6ConfigPrivate *src_priv; NMDedupMultiIter ipconf_iter; const NMPlatformIP6Address *a; const NMPlatformIP6Route *r; - gboolean changed; + gboolean changed, result = FALSE; const NMPObject *new_best_default_route; - g_return_if_fail (src); - g_return_if_fail (dst); + g_return_val_if_fail (src, FALSE); + g_return_val_if_fail (dst, FALSE); dst_priv = NM_IP6_CONFIG_GET_PRIVATE (dst); src_priv = NM_IP6_CONFIG_GET_PRIVATE (src); - g_object_freeze_notify (G_OBJECT (dst)); + if (update_dst) + g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ changed = FALSE; @@ -1110,13 +1112,18 @@ nm_ip6_config_intersect (NMIP6Config *dst, NMP_OBJECT_UP_CAST (a))) continue; + if (!update_dst) + return TRUE; + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); changed = TRUE; } - if (changed) + if (changed) { _notify_addresses (dst); + result = TRUE; + } /* ignore nameservers */ @@ -1148,6 +1155,9 @@ nm_ip6_config_intersect (NMIP6Config *dst, continue; } + if (!update_dst) + return TRUE; + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); @@ -1157,14 +1167,67 @@ nm_ip6_config_intersect (NMIP6Config *dst, nm_assert (changed); _notify (dst, PROP_GATEWAY); } - if (changed) + if (changed) { _notify_routes (dst); + result = TRUE; + } /* ignore domains */ /* ignore dns searches */ /* ignore dns options */ - g_object_thaw_notify (G_OBJECT (dst)); + if (update_dst) + g_object_thaw_notify (G_OBJECT (dst)); + + return result; +} + +/** + * nm_ip6_config_intersect: + * @dst: a configuration to be updated + * @src: another configuration + * @default_route_metric_penalty: the default route metric penalty + * + * Computes the intersection between @src and @dst and updates @dst in place + * with the result. + */ +void +nm_ip6_config_intersect (NMIP6Config *dst, + const NMIP6Config *src, + guint32 default_route_metric_penalty) +{ + _nm_ip6_config_intersect_helper (dst, src, default_route_metric_penalty, TRUE); +} + +/** + * nm_ip6_config_intersect_alloc: + * @a: a configuration + * @b: another configuration + * @default_route_metric_penalty: the default route metric penalty + * + * Computes the intersection between @a and @b and returns the result in a newly + * allocated configuration. As a special case, if @a and @b are identical (with + * respect to the only properties considered - addresses and routes) the + * functions returns NULL so that one of existing configuration can be reused + * without allocation. + * + * Returns: the intersection between @a and @b, or %NULL if the result is equal + * to @a and @b. + */ +NMIP6Config * +nm_ip6_config_intersect_alloc (const NMIP6Config *a, + const NMIP6Config *b, + guint32 default_route_metric_penalty) +{ + NMIP6Config *a_copy; + + if (_nm_ip6_config_intersect_helper ((NMIP6Config *) a, b, + default_route_metric_penalty, FALSE)) { + a_copy = nm_ip6_config_clone (a); + _nm_ip6_config_intersect_helper (a_copy, b, default_route_metric_penalty, TRUE); + return a_copy; + } else + return NULL; } /** diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 509a42d68..34d98b034 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -134,6 +134,9 @@ void nm_ip6_config_subtract (NMIP6Config *dst, void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, guint32 default_route_metric_penalty); +NMIP6Config *nm_ip6_config_intersect_alloc (const NMIP6Config *a, + const NMIP6Config *b, + guint32 default_route_metric_penalty); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); void nm_ip6_config_dump (const NMIP6Config *self, const char *detail);