summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-08-31 13:39:04 +0200
committerThomas Haller <thaller@redhat.com>2017-09-08 11:11:21 +0200
commit0918b4914d03ec14f71b3e56178c44a6ec648b34 (patch)
treecaea55c278b80dff68ab754fb1a65351ae9695b4
parenta214f398e7b17cacad335f70462a606affc2ad63 (diff)
downloadNetworkManager-0918b4914d03ec14f71b3e56178c44a6ec648b34.tar.gz
core: support tracking default-route in NMIP4Config/NMIP6Config
Default-routes are for the most part like regular routes. Add support to track them like regular routes in NMIP4Config/NMIP6Config. One thing is, sometimes we need to figure out whether an ip-config instance has a default-route. For that, keep track of the best default-route (there might be multiple) and expose it. That is the most complicated part of this patch, because there are so many places where the list of routes gets modified (replace, intersect, subtract, merge, add), and they all need to take care of updating the best default-route. In a next patch, NMDefaultRouteManager will be dropped and default-routes will be tracked by NMIP4Config/NMIP6Config.
-rw-r--r--src/dns/nm-dns-dnsmasq.c12
-rw-r--r--src/nm-dispatcher.c4
-rw-r--r--src/nm-ip4-config.c257
-rw-r--r--src/nm-ip4-config.h27
-rw-r--r--src/nm-ip6-config.c196
-rw-r--r--src/nm-ip6-config.h8
-rw-r--r--src/nm-pacrunner-manager.c4
7 files changed, 439 insertions, 69 deletions
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c
index cb311dffda..3ec1fd2de8 100644
--- a/src/dns/nm-dns-dnsmasq.c
+++ b/src/dns/nm-dns-dnsmasq.c
@@ -91,8 +91,10 @@ get_ip4_rdns_domains (NMIP4Config *ip4)
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address)
nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
- nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route)
- nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
+ nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
+ if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
+ }
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);
@@ -119,8 +121,10 @@ get_ip6_rdns_domains (NMIP6Config *ip6)
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address)
nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
- nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route)
- nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
+ nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
+ if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
+ }
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);
diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c
index cb7bb3c5a3..b5b11812e0 100644
--- a/src/nm-dispatcher.c
+++ b/src/nm-dispatcher.c
@@ -166,6 +166,8 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder)
/* Static routes */
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau"));
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ continue;
array[0] = route->network;
array[1] = route->plen;
array[2] = route->gateway;
@@ -235,6 +237,8 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder)
/* Static routes */
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)"));
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ continue;
ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
&route->network,
sizeof (struct in6_addr), 1);
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 9037c2d6f2..cf8435414a 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -377,6 +377,7 @@ typedef struct {
GVariant *route_data_variant;
GVariant *routes_variant;
NMDedupMultiIndex *multi_idx;
+ const NMPObject *best_default_route;
union {
NMIPConfigDedupMultiIdxType idx_ip4_addresses_;
NMDedupMultiIdxType idx_ip4_addresses;
@@ -471,6 +472,95 @@ nm_ip_config_iter_ip4_route_init (NMDedupMultiIter *ipconf_iter, const NMIP4Conf
/*****************************************************************************/
+const NMPObject *
+_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp)
+{
+ int addr_family;
+ int c;
+ guint metric_cur, metric_cmp;
+
+ nm_assert ( !obj_cur
+ || NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cur), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
+ nm_assert ( !obj_cmp
+ || ( !obj_cur
+ && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cmp), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE))
+ || NMP_OBJECT_GET_TYPE (obj_cur) == NMP_OBJECT_GET_TYPE (obj_cmp));
+ nm_assert ( !obj_cur
+ || nm_ip_config_best_default_route_is (obj_cur));
+
+ /* assumes that @obj_cur is already the best default route (or NULL). It checks whether
+ * @obj_cmp is also a default route and returns the best of both. */
+ if ( obj_cmp
+ && nm_ip_config_best_default_route_is (obj_cmp)) {
+ if (!obj_cur)
+ return obj_cmp;
+
+ addr_family = NMP_OBJECT_GET_CLASS (obj_cmp)->addr_family;
+ metric_cur = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cur)->metric);
+ metric_cmp = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cmp)->metric);
+
+ if (metric_cmp < metric_cur)
+ return obj_cmp;
+
+ if (metric_cmp == metric_cur) {
+ /* Routes have the same metric. We still want to deterministically
+ * prefer one or the other. It's important to consistently choose one
+ * or the other, so that the order doesn't matter how routes are added
+ * (and merged). */
+ c = nmp_object_cmp (obj_cur, obj_cmp);
+ if (c != 0)
+ return c < 0 ? obj_cur : obj_cmp;
+
+ /* as last resort, compare pointers. */
+ if (obj_cmp < obj_cur)
+ return obj_cmp;
+ }
+ }
+ return obj_cur;
+}
+
+gboolean
+_nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate)
+{
+ if (new_candidate == *best_default_route)
+ return FALSE;
+ nmp_object_ref (new_candidate);
+ nm_clear_nmp_object (best_default_route);
+ *best_default_route = new_candidate;
+ return TRUE;
+}
+
+gboolean
+_nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate)
+{
+ new_candidate = _nm_ip_config_best_default_route_find_better (*best_default_route,
+ new_candidate);
+ return _nm_ip_config_best_default_route_set (best_default_route, new_candidate);
+}
+
+const NMPObject *
+nm_ip4_config_best_default_route_get (const NMIP4Config *self)
+{
+ g_return_val_if_fail (NM_IS_IP4_CONFIG (self), NULL);
+
+ return NM_IP4_CONFIG_GET_PRIVATE (self)->best_default_route;
+}
+
+const NMPObject *
+_nm_ip4_config_best_default_route_find (const NMIP4Config *self)
+{
+ NMDedupMultiIter ipconf_iter;
+ const NMPObject *new_best_default_route = NULL;
+
+ nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, NULL) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route,
+ ipconf_iter.current->obj);
+ }
+ return new_best_default_route;
+}
+
+/*****************************************************************************/
+
static void
_notify_addresses (NMIP4Config *self)
{
@@ -487,6 +577,7 @@ _notify_routes (NMIP4Config *self)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ nm_assert (priv->best_default_route == _nm_ip4_config_best_default_route_find (self));
nm_clear_g_variant (&priv->route_data_variant);
nm_clear_g_variant (&priv->routes_variant);
_notify (self, PROP_ROUTE_DATA);
@@ -1056,8 +1147,7 @@ nm_ip4_config_create_setting (const NMIP4Config *self)
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) {
NMIPRoute *s_route;
- /* Ignore default route. */
- if (!route->plen)
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
/* Ignore routes provided by external sources */
@@ -1133,10 +1223,8 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
- const NMPlatformIP4Route *route;
-
- nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &route)
- _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL, NULL);
+ nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, NULL)
+ _add_route (dst, ipconf_iter.current->obj, NULL, NULL);
}
if (dst_priv->route_metric == -1)
@@ -1310,6 +1398,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
const NMPlatformIP4Route *r;
NMDedupMultiIter ipconf_iter;
gboolean changed;
+ gboolean changed_default_route;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
@@ -1349,12 +1438,24 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
/* routes */
changed = FALSE;
+ changed_default_route = FALSE;
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) {
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+
if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx,
&dst_priv->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r),
- NULL))
+ (gconstpointer *) &obj_old)) {
+ if (dst_priv->best_default_route == obj_old) {
+ nm_clear_nmp_object (&dst_priv->best_default_route);
+ changed_default_route = TRUE;
+ }
changed = TRUE;
+ }
+ }
+ if (changed_default_route) {
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route,
+ _nm_ip4_config_best_default_route_find (dst));
}
if (changed)
_notify_routes (dst);
@@ -1421,16 +1522,17 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Address *a;
const NMPlatformIP4Route *r;
+ const NMPObject *new_best_default_route;
gboolean changed;
g_return_if_fail (src);
g_return_if_fail (dst);
- g_object_freeze_notify (G_OBJECT (dst));
-
dst_priv = NM_IP4_CONFIG_GET_PRIVATE (dst);
src_priv = NM_IP4_CONFIG_GET_PRIVATE (src);
+ g_object_freeze_notify (G_OBJECT (dst));
+
/* addresses */
changed = FALSE;
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) {
@@ -1459,17 +1561,24 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
/* routes */
changed = FALSE;
+ new_best_default_route = NULL;
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) {
+ const NMPObject *o = NMP_OBJECT_UP_CAST (r);
+
if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx,
&src_priv->idx_ip4_routes,
- NMP_OBJECT_UP_CAST (r)))
+ o)) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o);
continue;
+ }
if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx,
ipconf_iter.current) != 1)
nm_assert_not_reached ();
changed = TRUE;
}
+ if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
+ nm_assert (changed);
if (changed)
_notify_routes (dst);
@@ -1509,6 +1618,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
const NMIP4ConfigPrivate *src_priv;
NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst;
const NMDedupMultiHeadEntry *head_entry_src;
+ const NMPObject *new_best_default_route;
g_return_val_if_fail (src != NULL, FALSE);
g_return_val_if_fail (dst != NULL, FALSE);
@@ -1627,19 +1737,25 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
}
if (!are_equal) {
has_minor_changes = TRUE;
+ new_best_default_route = NULL;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes);
nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) {
+ const NMPObject *o = ipconf_iter_src.current->obj;
+ const NMPObject *obj_new;
+
_nm_ip_config_add_obj (dst_priv->multi_idx,
&dst_priv->idx_ip4_routes_,
dst_priv->ifindex,
- ipconf_iter_src.current->obj,
+ o,
NULL,
FALSE,
TRUE,
NULL,
- NULL);
+ &obj_new);
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, FALSE);
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route);
_notify_routes (dst);
}
@@ -2028,18 +2144,12 @@ nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *new)
void
_nmtst_ip4_config_del_address (NMIP4Config *self, guint i)
{
- NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
const NMPlatformIP4Address *a;
a = _nmtst_ip4_config_get_address (self, i);
- g_return_if_fail (a);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip4_addresses,
- NMP_OBJECT_UP_CAST (a),
- NULL) != 1)
- g_return_if_reached ();
- _notify_addresses (self);
+ if (!nm_ip4_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (a)))
+ g_assert_not_reached ();
}
guint
@@ -2121,8 +2231,10 @@ nm_ip4_config_reset_routes (NMIP4Config *self)
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
- &priv->idx_ip4_routes) > 0)
+ &priv->idx_ip4_routes) > 0) {
+ nm_clear_nmp_object (&priv->best_default_route);
_notify_routes (self);
+ }
}
static void
@@ -2132,6 +2244,7 @@ _add_route (NMIP4Config *self,
const NMPObject **out_obj_new)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
const NMPObject *obj_new_2;
nm_assert ((!new) != (!obj_new));
@@ -2145,8 +2258,12 @@ _add_route (NMIP4Config *self,
(const NMPlatformObject *) new,
TRUE,
FALSE,
- NULL,
+ &obj_old,
&obj_new_2)) {
+ if ( priv->best_default_route == obj_old
+ && obj_old != obj_new_2)
+ nm_clear_nmp_object (&priv->best_default_route);
+ _nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2);
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
_notify_routes (self);
} else
@@ -2172,7 +2289,7 @@ nm_ip4_config_add_route (NMIP4Config *self,
{
g_return_if_fail (self);
g_return_if_fail (new);
- g_return_if_fail (new->plen > 0 && new->plen <= 32);
+ g_return_if_fail (new->plen <= 32);
g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (self)->ifindex > 0);
_add_route (self, NULL, new, out_obj_new);
@@ -2181,18 +2298,12 @@ nm_ip4_config_add_route (NMIP4Config *self,
void
_nmtst_ip4_config_del_route (NMIP4Config *self, guint i)
{
- NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
const NMPlatformIP4Route *r;
r = _nmtst_ip4_config_get_route (self, i);
- g_return_if_fail (r);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip4_routes,
- NMP_OBJECT_UP_CAST (r),
- NULL) != 1)
- g_return_if_reached ();
- _notify_routes (self);
+ if (!nm_ip4_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (r)))
+ g_assert_not_reached ();
}
guint
@@ -2701,6 +2812,84 @@ nm_ip4_config_get_metered (const NMIP4Config *self)
/*****************************************************************************/
+const NMPObject *
+nm_ip4_config_nmpobj_lookup (const NMIP4Config *self, const NMPObject *needle)
+{
+ const NMIP4ConfigPrivate *priv;
+ const NMDedupMultiIdxType *idx_type;
+
+ g_return_val_if_fail (NM_IS_IP4_CONFIG (self), NULL);
+
+ priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP4_ADDRESS:
+ idx_type = &priv->idx_ip4_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ idx_type = &priv->idx_ip4_routes;
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ return nm_dedup_multi_entry_get_obj (nm_dedup_multi_index_lookup_obj (priv->multi_idx,
+ idx_type,
+ needle));
+}
+
+gboolean
+nm_ip4_config_nmpobj_remove (NMIP4Config *self,
+ const NMPObject *needle)
+{
+ NMIP4ConfigPrivate *priv;
+ NMDedupMultiIdxType *idx_type;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ guint n;
+
+ g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE);
+
+ priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP4_ADDRESS:
+ idx_type = &priv->idx_ip4_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ idx_type = &priv->idx_ip4_routes;
+ break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ n = nm_dedup_multi_index_remove_obj (priv->multi_idx,
+ idx_type,
+ needle,
+ (gconstpointer *) &obj_old);
+ if (n != 1) {
+ nm_assert (n == 0);
+ return FALSE;
+ }
+
+ nm_assert (NMP_OBJECT_GET_TYPE (obj_old) == NMP_OBJECT_GET_TYPE (needle));
+
+ switch (NMP_OBJECT_GET_TYPE (obj_old)) {
+ case NMP_OBJECT_TYPE_IP4_ADDRESS:
+ _notify_addresses (self);
+ break;
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ if (priv->best_default_route == obj_old) {
+ _nm_ip_config_best_default_route_set (&priv->best_default_route,
+ _nm_ip4_config_best_default_route_find (self));
+ }
+ _notify_routes (self);
+ break;
+ default:
+ nm_assert_not_reached ();
+ }
+ return TRUE;
+}
+
+/*****************************************************************************/
+
static inline void
hash_u32 (GChecksum *sum, guint32 n)
{
@@ -3056,6 +3245,8 @@ finalize (GObject *object)
NMIP4Config *self = NM_IP4_CONFIG (object);
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ nm_clear_nmp_object (&priv->best_default_route);
+
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip4_addresses);
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip4_routes);
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index 1113c9928e..7db858b7b5 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -75,6 +75,25 @@ nm_ip_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatfor
/*****************************************************************************/
+static inline gboolean
+nm_ip_config_best_default_route_is (const NMPObject *obj)
+{
+ const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj);
+
+ /* return whether @obj is considered a default-route, that is, a route
+ * as added by NetworkManager. E.g. if the route is not in the main-table,
+ * it's considered just like a regular route. */
+ return r
+ && !r->table_coerced
+ && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r);
+}
+
+const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp);
+gboolean _nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate);
+gboolean _nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate);
+
+/*****************************************************************************/
+
gboolean nm_ip_config_obj_id_equal_ip4_address (const NMPlatformIP4Address *a,
const NMPlatformIP4Address *b);
gboolean nm_ip_config_obj_id_equal_ip6_address (const NMPlatformIP6Address *a,
@@ -163,6 +182,9 @@ gboolean nm_ip4_config_has_gateway (const NMIP4Config *self);
guint32 nm_ip4_config_get_gateway (const NMIP4Config *self);
gint64 nm_ip4_config_get_route_metric (const NMIP4Config *self);
+const NMPObject *nm_ip4_config_best_default_route_get (const NMIP4Config *self);
+const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self);
+
const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self);
void nm_ip4_config_reset_addresses (NMIP4Config *self);
void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address);
@@ -234,6 +256,11 @@ NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *self);
void nm_ip4_config_set_metered (NMIP4Config *self, gboolean metered);
gboolean nm_ip4_config_get_metered (const NMIP4Config *self);
+const NMPObject *nm_ip4_config_nmpobj_lookup (const NMIP4Config *self,
+ const NMPObject *needle);
+gboolean nm_ip4_config_nmpobj_remove (NMIP4Config *self,
+ const NMPObject *needle);
+
void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only);
gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 641e734340..0aad49d54d 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -72,6 +72,7 @@ typedef struct {
GVariant *route_data_variant;
GVariant *routes_variant;
NMDedupMultiIndex *multi_idx;
+ const NMPObject *best_default_route;
union {
NMIPConfigDedupMultiIdxType idx_ip6_addresses_;
NMDedupMultiIdxType idx_ip6_addresses;
@@ -177,6 +178,29 @@ nm_ip_config_iter_ip6_route_init (NMDedupMultiIter *ipconf_iter, const NMIP6Conf
/*****************************************************************************/
+const NMPObject *
+nm_ip6_config_best_default_route_get (const NMIP6Config *self)
+{
+ g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL);
+
+ return NM_IP6_CONFIG_GET_PRIVATE (self)->best_default_route;
+}
+
+const NMPObject *
+_nm_ip6_config_best_default_route_find (const NMIP6Config *self)
+{
+ NMDedupMultiIter ipconf_iter;
+ const NMPObject *new_best_default_route = NULL;
+
+ nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, NULL) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route,
+ ipconf_iter.current->obj);
+ }
+ return new_best_default_route;
+}
+
+/*****************************************************************************/
+
static void
_notify_addresses (NMIP6Config *self)
{
@@ -193,6 +217,7 @@ _notify_routes (NMIP6Config *self)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ nm_assert (priv->best_default_route == _nm_ip6_config_best_default_route_find (self));
nm_clear_g_variant (&priv->route_data_variant);
nm_clear_g_variant (&priv->routes_variant);
_notify (self, PROP_ROUTE_DATA);
@@ -781,8 +806,7 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
if (IN6_IS_ADDR_LINKLOCAL (&route->network))
continue;
- /* Ignore default route. */
- if (!route->plen)
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
/* Ignore routes provided by external sources */
@@ -857,10 +881,8 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
- const NMPlatformIP6Route *route;
-
- nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &route)
- _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL, NULL);
+ nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, NULL)
+ _add_route (dst, ipconf_iter.current->obj, NULL, NULL);
}
if (dst_priv->route_metric == -1)
@@ -997,6 +1019,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
NMDedupMultiIter ipconf_iter;
const struct in6_addr *dst_tmp, *src_tmp;
gboolean changed;
+ gboolean changed_default_route;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
@@ -1037,12 +1060,24 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
/* routes */
changed = FALSE;
+ changed_default_route = FALSE;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) {
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+
if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r),
- NULL))
+ (gconstpointer *) &obj_old)) {
+ if (dst_priv->best_default_route == obj_old) {
+ nm_clear_nmp_object (&dst_priv->best_default_route);
+ changed_default_route = TRUE;
+ }
changed = TRUE;
+ }
+ }
+ if (changed_default_route) {
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route,
+ _nm_ip6_config_best_default_route_find (dst));
}
if (changed)
_notify_routes (dst);
@@ -1088,6 +1123,7 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
const NMPlatformIP6Address *a;
const NMPlatformIP6Route *r;
gboolean changed;
+ const NMPObject *new_best_default_route;
g_return_if_fail (src);
g_return_if_fail (dst);
@@ -1128,17 +1164,24 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
/* routes */
changed = FALSE;
+ new_best_default_route = NULL;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) {
+ const NMPObject *o = NMP_OBJECT_UP_CAST (r);
+
if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx,
&src_priv->idx_ip6_routes,
- NMP_OBJECT_UP_CAST (r)))
+ o)) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o);
continue;
+ }
if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx,
ipconf_iter.current) != 1)
nm_assert_not_reached ();
changed = TRUE;
}
+ if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
+ nm_assert (changed);
if (changed)
_notify_routes (dst);
@@ -1175,6 +1218,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
const NMIP6ConfigPrivate *src_priv;
NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst;
const NMDedupMultiHeadEntry *head_entry_src;
+ const NMPObject *new_best_default_route;
g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE);
g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE);
@@ -1293,19 +1337,25 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
}
if (!are_equal) {
has_minor_changes = TRUE;
+ new_best_default_route = NULL;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes);
nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) {
+ const NMPObject *o = ipconf_iter_src.current->obj;
+ const NMPObject *obj_new;
+
_nm_ip_config_add_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes_,
dst_priv->ifindex,
- ipconf_iter_src.current->obj,
+ o,
NULL,
FALSE,
TRUE,
NULL,
- NULL);
+ &obj_new);
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE);
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route);
_notify_routes (dst);
}
@@ -1631,18 +1681,12 @@ nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *new)
void
_nmtst_ip6_config_del_address (NMIP6Config *self, guint i)
{
- NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
const NMPlatformIP6Address *a;
a = _nmtst_ip6_config_get_address (self, i);
- g_return_if_fail (a);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip6_addresses,
- NMP_OBJECT_UP_CAST (a),
- NULL) != 1)
- g_return_if_reached ();
- _notify_addresses (self);
+ if (!nm_ip6_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (a)))
+ g_assert_not_reached ();
}
guint
@@ -1767,6 +1811,7 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
NMIP6ConfigPrivate *priv;
guint i;
gboolean changed = FALSE;
+ const NMPObject *new_best_default_route;
g_return_if_fail (NM_IS_IP6_CONFIG (self));
@@ -1776,9 +1821,11 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
nm_dedup_multi_index_dirty_set_idx (priv->multi_idx, &priv->idx_ip6_routes);
+ new_best_default_route = NULL;
for (i = 0; i < routes_n; i++) {
const NMNDiscRoute *ndisc_route = &routes[i];
NMPObject obj;
+ const NMPObject *obj_new;
NMPlatformIP6Route *r;
nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
@@ -1798,10 +1845,14 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
FALSE,
TRUE,
NULL,
- NULL))
+ &obj_new))
changed = TRUE;
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
}
+ if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route))
+ changed = TRUE;
+
if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0)
changed = TRUE;
@@ -1815,8 +1866,10 @@ nm_ip6_config_reset_routes (NMIP6Config *self)
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
- &priv->idx_ip6_routes) > 0)
+ &priv->idx_ip6_routes) > 0) {
+ nm_clear_nmp_object (&priv->best_default_route);
_notify_routes (self);
+ }
}
static void
@@ -1826,6 +1879,7 @@ _add_route (NMIP6Config *self,
const NMPObject **out_obj_new)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
const NMPObject *obj_new_2;
nm_assert ((!new) != (!obj_new));
@@ -1839,8 +1893,12 @@ _add_route (NMIP6Config *self,
(const NMPlatformObject *) new,
TRUE,
FALSE,
- NULL,
+ &obj_old,
&obj_new_2)) {
+ if ( priv->best_default_route == obj_old
+ && obj_old != obj_new_2)
+ nm_clear_nmp_object (&priv->best_default_route);
+ _nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2);
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
_notify_routes (self);
} else
@@ -1866,7 +1924,7 @@ nm_ip6_config_add_route (NMIP6Config *self,
{
g_return_if_fail (self);
g_return_if_fail (new);
- g_return_if_fail (new->plen > 0 && new->plen <= 128);
+ g_return_if_fail (new->plen <= 128);
g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (self)->ifindex > 0);
_add_route (self, NULL, new, out_obj_new);
@@ -1875,18 +1933,12 @@ nm_ip6_config_add_route (NMIP6Config *self,
void
_nmtst_ip6_config_del_route (NMIP6Config *self, guint i)
{
- NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
const NMPlatformIP6Route *r;
r = _nmtst_ip6_config_get_route (self, i);
- g_return_if_fail (r);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip6_routes,
- NMP_OBJECT_UP_CAST (r),
- NULL) != 1)
- g_return_if_reached ();
- _notify_routes (self);
+ if (!nm_ip6_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (r)))
+ g_assert_not_reached ();
}
guint
@@ -2251,6 +2303,84 @@ nm_ip6_config_get_mss (const NMIP6Config *self)
/*****************************************************************************/
+const NMPObject *
+nm_ip6_config_nmpobj_lookup (const NMIP6Config *self, const NMPObject *needle)
+{
+ const NMIP6ConfigPrivate *priv;
+ const NMDedupMultiIdxType *idx_type;
+
+ g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL);
+
+ priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP6_ADDRESS:
+ idx_type = &priv->idx_ip6_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ idx_type = &priv->idx_ip6_routes;
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ return nm_dedup_multi_entry_get_obj (nm_dedup_multi_index_lookup_obj (priv->multi_idx,
+ idx_type,
+ needle));
+}
+
+gboolean
+nm_ip6_config_nmpobj_remove (NMIP6Config *self,
+ const NMPObject *needle)
+{
+ NMIP6ConfigPrivate *priv;
+ NMDedupMultiIdxType *idx_type;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ guint n;
+
+ g_return_val_if_fail (NM_IS_IP6_CONFIG (self), FALSE);
+
+ priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP6_ADDRESS:
+ idx_type = &priv->idx_ip6_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ idx_type = &priv->idx_ip6_routes;
+ break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ n = nm_dedup_multi_index_remove_obj (priv->multi_idx,
+ idx_type,
+ needle,
+ (gconstpointer *) &obj_old);
+ if (n != 1) {
+ nm_assert (n == 0);
+ return FALSE;
+ }
+
+ nm_assert (NMP_OBJECT_GET_TYPE (obj_old) == NMP_OBJECT_GET_TYPE (needle));
+
+ switch (NMP_OBJECT_GET_TYPE (obj_old)) {
+ case NMP_OBJECT_TYPE_IP6_ADDRESS:
+ _notify_addresses (self);
+ break;
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ if (priv->best_default_route == obj_old) {
+ _nm_ip_config_best_default_route_set (&priv->best_default_route,
+ _nm_ip6_config_best_default_route_find (self));
+ }
+ _notify_routes (self);
+ break;
+ default:
+ nm_assert_not_reached ();
+ }
+ return TRUE;
+}
+
+/*****************************************************************************/
+
static inline void
hash_u32 (GChecksum *sum, guint32 n)
{
@@ -2611,6 +2741,8 @@ finalize (GObject *object)
NMIP6Config *self = NM_IP6_CONFIG (object);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ nm_clear_nmp_object (&priv->best_default_route);
+
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_addresses);
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_routes);
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index 0a7fe17498..ec8bee881d 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -127,6 +127,9 @@ void nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *);
const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *self);
gint64 nm_ip6_config_get_route_metric (const NMIP6Config *self);
+const NMPObject *nm_ip6_config_best_default_route_get (const NMIP6Config *self);
+const NMPObject *_nm_ip6_config_best_default_route_find (const NMIP6Config *self);
+
const NMDedupMultiHeadEntry *nm_ip6_config_lookup_addresses (const NMIP6Config *self);
void nm_ip6_config_reset_addresses (NMIP6Config *self);
void nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *address);
@@ -184,6 +187,11 @@ gint nm_ip6_config_get_dns_priority (const NMIP6Config *self);
void nm_ip6_config_set_mss (NMIP6Config *self, guint32 mss);
guint32 nm_ip6_config_get_mss (const NMIP6Config *self);
+const NMPObject *nm_ip6_config_nmpobj_lookup (const NMIP6Config *self,
+ const NMPObject *needle);
+gboolean nm_ip6_config_nmpobj_remove (NMIP6Config *self,
+ const NMPObject *needle);
+
void nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only);
gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b);
diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c
index 2558ca0f30..08e10e40db 100644
--- a/src/nm-pacrunner-manager.c
+++ b/src/nm-pacrunner-manager.c
@@ -192,6 +192,8 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4)
}
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &routes) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes))
+ continue;
cidr = g_strdup_printf ("%s/%u",
nm_utils_inet4_ntop (routes->network, NULL),
routes->plen);
@@ -225,6 +227,8 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6)
}
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes))
+ continue;
cidr = g_strdup_printf ("%s/%u",
nm_utils_inet6_ntop (&routes->network, NULL),
routes->plen);