summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 cb311dffd..3ec1fd2de 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 cb7bb3c5a..b5b11812e 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 9037c2d6f..cf8435414 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 1113c9928..7db858b7b 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 641e73434..0aad49d54 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 0a7fe1749..ec8bee881 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 2558ca0f3..08e10e40d 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);