summaryrefslogtreecommitdiff
path: root/src/nm-ip6-config.c
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-10-10 09:01:07 +0200
committerThomas Haller <thaller@redhat.com>2017-10-10 09:03:05 +0200
commite037c66b6a14d4465cd0f2219bfe5320e72ef743 (patch)
tree259470cd32be8d0c78e4f4f88bad2ef83e8574a8 /src/nm-ip6-config.c
parent2776606aa35d9808880e64c40acbc7048f970957 (diff)
parent5c299454b49b165f645c25fd3e083c0bb747ad91 (diff)
downloadNetworkManager-e037c66b6a14d4465cd0f2219bfe5320e72ef743.tar.gz
all: merge branch 'th/policy-routing-pt2-rh1436531' (part 2)
Extend policy-routing and replace previously added route-table-sync setting with a route-table setting. The route table can now be configured per connection profile and affects all routes. This branch breaks API/ABI on development branch by dropping ipv4.route-table-sync from libnm. https://bugzilla.redhat.com/show_bug.cgi?id=1436531
Diffstat (limited to 'src/nm-ip6-config.c')
-rw-r--r--src/nm-ip6-config.c557
1 files changed, 222 insertions, 335 deletions
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 699c60d3b2..81b443c67e 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -25,6 +25,8 @@
#include <string.h>
#include <arpa/inet.h>
+#include <resolv.h>
+#include <linux/rtnetlink.h>
#include "nm-utils/nm-dedup-multi.h"
@@ -56,13 +58,9 @@ _route_valid (const NMPlatformIP6Route *r)
/*****************************************************************************/
typedef struct {
- bool never_default:1;
- guint32 mss;
int ifindex;
int dns_priority;
NMSettingIP6ConfigPrivacy privacy;
- gint64 route_metric;
- struct in6_addr gateway;
GArray *nameservers;
GPtrArray *domains;
GPtrArray *searches;
@@ -229,72 +227,6 @@ _notify_routes (NMIP6Config *self)
/*****************************************************************************/
-/**
- * nm_ip6_config_capture_resolv_conf():
- * @nameservers: array of struct in6_addr
- * @rc_contents: the contents of a resolv.conf or %NULL to read /etc/resolv.conf
- *
- * Reads all resolv.conf IPv6 nameservers and adds them to @nameservers.
- *
- * Returns: %TRUE if nameservers were added, %FALSE if @nameservers is unchanged
- */
-gboolean
-nm_ip6_config_capture_resolv_conf (GArray *nameservers,
- GPtrArray *dns_options,
- const char *rc_contents)
-{
- GPtrArray *read_ns, *read_options;
- guint i, j;
- gboolean changed = FALSE;
-
- g_return_val_if_fail (nameservers != NULL, FALSE);
-
- read_ns = nm_utils_read_resolv_conf_nameservers (rc_contents);
- if (!read_ns)
- return FALSE;
-
- for (i = 0; i < read_ns->len; i++) {
- const char *s = g_ptr_array_index (read_ns, i);
- struct in6_addr ns = IN6ADDR_ANY_INIT;
-
- if (!inet_pton (AF_INET6, s, (void *) &ns) || IN6_IS_ADDR_UNSPECIFIED (&ns))
- continue;
-
- /* Ignore duplicates */
- for (j = 0; j < nameservers->len; j++) {
- struct in6_addr *t = &g_array_index (nameservers, struct in6_addr, j);
-
- if (IN6_ARE_ADDR_EQUAL (t, &ns))
- break;
- }
-
- if (j == nameservers->len) {
- g_array_append_val (nameservers, ns);
- changed = TRUE;
- }
- }
- g_ptr_array_unref (read_ns);
-
- if (dns_options) {
- read_options = nm_utils_read_resolv_conf_dns_options (rc_contents);
- if (!read_options)
- return changed;
-
- for (i = 0; i < read_options->len; i++) {
- const char *s = g_ptr_array_index (read_options, i);
-
- if (_nm_utils_dns_option_validate (s, NULL, NULL, TRUE, _nm_utils_dns_option_descs) &&
- _nm_utils_dns_option_find_idx (dns_options, s) < 0) {
- g_ptr_array_add (dns_options, g_strdup (s));
- changed = TRUE;
- }
- }
- g_ptr_array_unref (read_options);
- }
-
- return changed;
-}
-
static gint
_addresses_sort_cmp_get_prio (const struct in6_addr *addr)
{
@@ -438,13 +370,9 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
{
NMIP6Config *self;
NMIP6ConfigPrivate *priv;
- guint32 lowest_metric = G_MAXUINT32;
- struct in6_addr old_gateway = IN6ADDR_ANY_INIT;
- gboolean has_gateway;
const NMDedupMultiHeadEntry *head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
- gboolean notify_nameservers = FALSE;
gboolean has_addresses = FALSE;
nm_assert (ifindex > 0);
@@ -478,62 +406,44 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
nm_dedup_multi_head_entry_sort (head_entry,
sort_captured_addresses,
GINT_TO_POINTER (use_temporary));
+ _notify_addresses (self);
}
head_entry = nm_platform_lookup_addrroute (platform,
NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex);
- /* Extract gateway from default route */
- old_gateway = priv->gateway;
-
- lowest_metric = G_MAXUINT32;
- has_gateway = FALSE;
- nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
- const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj);
-
- if ( !route->table_coerced
- && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)
- && route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) {
- if (route->metric < lowest_metric) {
- priv->gateway = route->gateway;
- lowest_metric = route->metric;
- }
- has_gateway = TRUE;
- }
-
+ nmp_cache_iter_for_each (&iter, head_entry, &plobj)
_add_route (self, plobj, NULL, NULL);
- }
-
- /* we detect the route metric based on the default route. All non-default
- * routes have their route metrics explicitly set. */
- priv->route_metric = has_gateway ? (gint64) lowest_metric : (gint64) -1;
/* If the interface has the default route, and has IPv6 addresses, capture
* nameservers from /etc/resolv.conf.
*/
- if (has_addresses && has_gateway && capture_resolv_conf)
- notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers,
- priv->dns_options,
- NULL);
-
- /* actually, nobody should be connected to the signal, just to be sure, notify */
- if (notify_nameservers)
- _notify (self, PROP_NAMESERVERS);
- _notify_addresses (self);
- _notify_routes (self);
- if (!IN6_ARE_ADDR_EQUAL (&priv->gateway, &old_gateway))
- _notify (self, PROP_GATEWAY);
+ if ( has_addresses
+ && priv->best_default_route
+ && capture_resolv_conf) {
+ gs_free char *rc_contents = NULL;
+
+ if (g_file_get_contents (_PATH_RESCONF, &rc_contents, NULL, NULL)) {
+ if (nm_utils_resolve_conf_parse (AF_INET6,
+ rc_contents,
+ priv->nameservers,
+ priv->dns_options))
+ _notify (self, PROP_NAMESERVERS);
+ }
+ }
return self;
}
void
-nm_ip6_config_add_device_routes (NMIP6Config *self,
- guint32 default_route_metric)
+nm_ip6_config_add_dependent_routes (NMIP6Config *self,
+ guint32 route_table,
+ guint32 route_metric)
{
const NMIP6ConfigPrivate *priv;
- const NMPlatformIP6Address *addr;
+ const NMPlatformIP6Address *my_addr;
+ const NMPlatformIP6Route *my_route;
int ifindex;
NMDedupMultiIter iter;
@@ -549,21 +459,21 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
*
* For manually added IPv6 routes, add the device routes explicitly. */
- nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) {
+ nm_ip_config_iter_ip6_address_for_each (&iter, self, &my_addr) {
NMPObject *r;
NMPlatformIP6Route *route;
gboolean has_peer;
int routes_n, routes_i;
- if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_NOPREFIXROUTE))
+ if (NM_FLAGS_HAS (my_addr->n_ifa_flags, IFA_F_NOPREFIXROUTE))
continue;
- has_peer = !IN6_IS_ADDR_UNSPECIFIED (&addr->peer_address);
+ has_peer = !IN6_IS_ADDR_UNSPECIFIED (&my_addr->peer_address);
/* If we have an IPv6 peer, we add two /128 routes
* (unless, both addresses are identical). */
routes_n = ( has_peer
- && !IN6_ARE_ADDR_EQUAL (&addr->address, &addr->peer_address))
+ && !IN6_ARE_ADDR_EQUAL (&my_addr->address, &my_addr->peer_address))
? 2 : 1;
for (routes_i = 0; routes_i < routes_n; routes_i++) {
@@ -573,17 +483,18 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
route->ifindex = ifindex;
route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
- route->metric = default_route_metric;
+ route->table_coerced = nm_platform_route_table_coerce (route_table);
+ route->metric = route_metric;
if (has_peer) {
if (routes_i == 0)
- route->network = addr->address;
+ route->network = my_addr->address;
else
- route->network = addr->peer_address;
+ route->network = my_addr->peer_address;
route->plen = 128;
} else {
- nm_utils_ip6_address_clear_host_address (&route->network, &addr->address, addr->plen);
- route->plen = addr->plen;
+ nm_utils_ip6_address_clear_host_address (&route->network, &my_addr->address, my_addr->plen);
+ route->plen = my_addr->plen;
}
nm_platform_ip_route_normalize (AF_INET6, (NMPlatformIPRoute *) route);
@@ -597,6 +508,27 @@ nm_ip6_config_add_device_routes (NMIP6Config *self,
_add_route (self, r, NULL, NULL);
}
}
+
+again:
+ nm_ip_config_iter_ip6_route_for_each (&iter, self, &my_route) {
+ NMPlatformIP6Route rt;
+
+ if ( !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (my_route)
+ || IN6_IS_ADDR_UNSPECIFIED (&my_route->gateway)
+ || NM_IS_IP_CONFIG_SOURCE_RTPROT (my_route->rt_source)
+ || nm_ip6_config_get_direct_route_for_host (self,
+ &my_route->gateway,
+ nm_platform_route_table_uncoerce (my_route->table_coerced, TRUE)))
+ continue;
+
+ rt = *my_route;
+ rt.network = my_route->gateway;
+ rt.plen = 128;
+ rt.gateway = in6addr_any;
+ _add_route (self, NULL, &rt, NULL);
+ /* adding the route might have invalidated the iteration. Start again. */
+ goto again;
+ }
}
gboolean
@@ -641,9 +573,12 @@ nm_ip6_config_commit (const NMIP6Config *self,
}
static void
-merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r)
+merge_route_attributes (NMIPRoute *s_route,
+ NMPlatformIP6Route *r,
+ guint32 route_table)
{
GVariant *variant;
+ guint32 u32;
struct in6_addr addr;
#define GET_ATTR(name, field, variant_type, type) \
@@ -651,9 +586,11 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r)
if (variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_ ## variant_type)) \
r->field = g_variant_get_ ## type (variant);
- r->table_coerced = 254 /* RT_TABLE_MAIN */;
- GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_TABLE, table_coerced, UINT32, uint32);
- r->table_coerced = nm_platform_route_table_coerce (r->table_coerced);
+ variant = nm_ip_route_get_attribute (s_route, NM_IP_ROUTE_ATTRIBUTE_TABLE);
+ u32 = variant && g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)
+ ? g_variant_get_uint32 (variant)
+ : 0;
+ r->table_coerced = nm_platform_route_table_coerce (u32 ?: (route_table ?: RT_TABLE_MAIN));
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, window, UINT32, uint32);
GET_ATTR (NM_IP_ROUTE_ATTRIBUTE_CWND, cwnd, UINT32, uint32);
@@ -695,11 +632,15 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r)
}
void
-nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric)
+nm_ip6_config_merge_setting (NMIP6Config *self,
+ NMSettingIPConfig *setting,
+ guint32 route_table,
+ guint32 route_metric)
{
NMIP6ConfigPrivate *priv;
guint naddresses, nroutes, nnameservers, nsearches;
const char *gateway_str;
+ struct in6_addr gateway_bin;
int i, priority;
if (!setting)
@@ -717,21 +658,20 @@ nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guin
g_object_freeze_notify (G_OBJECT (self));
/* Gateway */
- if (nm_setting_ip_config_get_never_default (setting))
- nm_ip6_config_set_never_default (self, TRUE);
- else if (nm_setting_ip_config_get_ignore_auto_routes (setting))
- nm_ip6_config_set_never_default (self, FALSE);
- gateway_str = nm_setting_ip_config_get_gateway (setting);
- if (gateway_str) {
- struct in6_addr gateway;
+ if ( !nm_setting_ip_config_get_never_default (setting)
+ && (gateway_str = nm_setting_ip_config_get_gateway (setting))
+ && inet_pton (AF_INET6, gateway_str, &gateway_bin) == 1
+ && !IN6_IS_ADDR_UNSPECIFIED (&gateway_bin)) {
+ const NMPlatformIP6Route r = {
+ .rt_source = NM_IP_CONFIG_SOURCE_USER,
+ .gateway = gateway_bin,
+ .table_coerced = nm_platform_route_table_coerce (route_table),
+ .metric = route_metric,
+ };
- inet_pton (AF_INET6, gateway_str, &gateway);
- nm_ip6_config_set_gateway (self, &gateway);
+ _add_route (self, NULL, &r, NULL);
}
- if (priv->route_metric == -1)
- priv->route_metric = nm_setting_ip_config_get_route_metric (setting);
-
/* Addresses */
for (i = 0; i < naddresses; i++) {
NMIPAddress *s_addr = nm_setting_ip_config_get_address (setting, i);
@@ -770,14 +710,14 @@ nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guin
nm_ip_route_get_next_hop_binary (s_route, &route.gateway);
if (nm_ip_route_get_metric (s_route) == -1)
- route.metric = default_route_metric;
+ route.metric = route_metric;
else
route.metric = nm_ip_route_get_metric (s_route);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen);
- merge_route_attributes (s_route, &route);
+ merge_route_attributes (s_route, &route, route_table);
_add_route (self, NULL, &route, NULL);
}
@@ -812,12 +752,11 @@ nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guin
NMSetting *
nm_ip6_config_create_setting (const NMIP6Config *self)
{
+ const NMIP6ConfigPrivate *priv;
NMSettingIPConfig *s_ip6;
- const struct in6_addr *gateway;
guint nnameservers, nsearches, noptions;
const char *method = NULL;
int i;
- gint64 route_metric;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Address *address;
const NMPlatformIP6Route *route;
@@ -831,11 +770,11 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
return NM_SETTING (s_ip6);
}
- gateway = nm_ip6_config_get_gateway (self);
+ priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+
nnameservers = nm_ip6_config_get_num_nameservers (self);
nsearches = nm_ip6_config_get_num_searches (self);
noptions = nm_ip6_config_get_num_dns_options (self);
- route_metric = nm_ip6_config_get_route_metric (self);
/* Addresses */
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) {
@@ -864,10 +803,12 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
}
/* Gateway */
- if ( gateway
+ if ( priv->best_default_route
&& nm_setting_ip_config_get_num_addresses (s_ip6) > 0) {
g_object_set (s_ip6,
- NM_SETTING_IP_CONFIG_GATEWAY, nm_utils_inet6_ntop (gateway, NULL),
+ NM_SETTING_IP_CONFIG_GATEWAY,
+ nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway,
+ NULL),
NULL);
}
@@ -877,7 +818,6 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
g_object_set (s_ip6,
NM_SETTING_IP_CONFIG_METHOD, method,
- NM_SETTING_IP_CONFIG_ROUTE_METRIC, (gint64) route_metric,
NULL);
/* Routes */
@@ -931,7 +871,10 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
/*****************************************************************************/
void
-nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFlags merge_flags)
+nm_ip6_config_merge (NMIP6Config *dst,
+ const NMIP6Config *src,
+ NMIPConfigMergeFlags merge_flags,
+ guint32 default_route_metric_penalty)
{
NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv;
@@ -957,21 +900,26 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
nm_ip6_config_add_nameserver (dst, nm_ip6_config_get_nameserver (src, i));
}
- /* default gateway */
- if (nm_ip6_config_get_gateway (src))
- nm_ip6_config_set_gateway (dst, nm_ip6_config_get_gateway (src));
-
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
- nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, NULL)
+ const NMPlatformIP6Route *r_src;
+
+ nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r_src) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r_src)) {
+ if (NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES))
+ continue;
+ if (default_route_metric_penalty) {
+ NMPlatformIP6Route r = *r_src;
+
+ r.metric = nm_utils_ip_route_metric_penalize (AF_INET6, r.metric, default_route_metric_penalty);
+ _add_route (dst, NULL, &r, NULL);
+ continue;
+ }
+ }
_add_route (dst, ipconf_iter.current->obj, NULL, NULL);
+ }
}
- if (dst_priv->route_metric == -1)
- dst_priv->route_metric = src_priv->route_metric;
- else if (src_priv->route_metric != -1)
- dst_priv->route_metric = MIN (dst_priv->route_metric, src_priv->route_metric);
-
/* domains */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) {
for (i = 0; i < nm_ip6_config_get_num_domains (src); i++)
@@ -990,9 +938,6 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
nm_ip6_config_add_dns_option (dst, nm_ip6_config_get_dns_option (src, i));
}
- if (nm_ip6_config_get_mss (src))
- nm_ip6_config_set_mss (dst, nm_ip6_config_get_mss (src));
-
/* DNS priority */
if (nm_ip6_config_get_dns_priority (src))
nm_ip6_config_set_dns_priority (dst, nm_ip6_config_get_dns_priority (src));
@@ -1000,25 +945,6 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
g_object_thaw_notify (G_OBJECT (dst));
}
-gboolean
-nm_ip6_config_destination_is_direct (const NMIP6Config *self, const struct in6_addr *network, guint8 plen)
-{
- const NMPlatformIP6Address *item;
- NMDedupMultiIter iter;
-
- nm_assert (network);
- nm_assert (plen <= 128);
-
- nm_ip_config_iter_ip6_address_for_each (&iter, self, &item) {
- if ( item->plen <= plen
- && !NM_FLAGS_HAS (item->n_ifa_flags, IFA_F_NOPREFIXROUTE)
- && nm_utils_ip6_address_same_prefix (&item->address, network, item->plen))
- return TRUE;
- }
-
- return FALSE;
-}
-
/*****************************************************************************/
static int
@@ -1087,11 +1013,17 @@ _dns_options_get_index (const NMIP6Config *self, const char *option)
* nm_ip6_config_subtract:
* @dst: config from which to remove everything in @src
* @src: config to remove from @dst
- *
+ * @default_route_metric_penalty: pretend that on source we applied
+ * a route penalty on the default-route. It means, for default routes
+ * we don't remove routes that match exactly, but those with a lower
+ * metric (with the penalty removed).
+*
* Removes everything in @src from @dst.
*/
void
-nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
+nm_ip6_config_subtract (NMIP6Config *dst,
+ const NMIP6Config *src,
+ guint32 default_route_metric_penalty)
{
NMIP6ConfigPrivate *dst_priv;
guint i;
@@ -1099,7 +1031,6 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
const NMPlatformIP6Address *a;
const NMPlatformIP6Route *r;
NMDedupMultiIter ipconf_iter;
- const struct in6_addr *dst_tmp, *src_tmp;
gboolean changed;
gboolean changed_default_route;
@@ -1129,26 +1060,31 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
nm_ip6_config_del_nameserver (dst, idx);
}
- /* default gateway */
- src_tmp = nm_ip6_config_get_gateway (src);
- dst_tmp = nm_ip6_config_get_gateway (dst);
- if (src_tmp && dst_tmp && IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp))
- nm_ip6_config_set_gateway (dst, NULL);
-
- if (!nm_ip6_config_get_num_addresses (dst))
- nm_ip6_config_set_gateway (dst, NULL);
-
- /* ignore route_metric */
-
/* routes */
changed = FALSE;
changed_default_route = FALSE;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) {
+ const NMPObject *o_src = NMP_OBJECT_UP_CAST (r);
+ NMPObject o_lookup_copy;
+ const NMPObject *o_lookup;
nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
+ && default_route_metric_penalty) {
+ NMPlatformIP6Route *rr;
+
+ /* the default route was penalized when merging it to the combined ip-config.
+ * When subtracting the routes, we must re-do that process when comparing
+ * the routes. */
+ o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_src);
+ rr = NMP_OBJECT_CAST_IP6_ROUTE (&o_lookup_copy);
+ rr->metric = nm_utils_ip_route_metric_penalize (AF_INET6, rr->metric, default_route_metric_penalty);
+ } else
+ o_lookup = o_src;
+
if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes,
- NMP_OBJECT_UP_CAST (r),
+ o_lookup,
(gconstpointer *) &obj_old)) {
if (dst_priv->best_default_route == obj_old) {
nm_clear_nmp_object (&dst_priv->best_default_route);
@@ -1160,6 +1096,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
if (changed_default_route) {
_nm_ip_config_best_default_route_set (&dst_priv->best_default_route,
_nm_ip6_config_best_default_route_find (dst));
+ _notify (dst, PROP_GATEWAY);
}
if (changed)
_notify_routes (dst);
@@ -1185,9 +1122,6 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
nm_ip6_config_del_dns_option (dst, idx);
}
- if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst))
- nm_ip6_config_set_mss (dst, 0);
-
/* DNS priority */
if (nm_ip6_config_get_dns_priority (src) == nm_ip6_config_get_dns_priority (dst))
nm_ip6_config_set_dns_priority (dst, 0);
@@ -1196,11 +1130,12 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
}
void
-nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
+nm_ip6_config_intersect (NMIP6Config *dst,
+ const NMIP6Config *src,
+ guint32 default_route_metric_penalty)
{
NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv;
- const struct in6_addr *dst_tmp, *src_tmp;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Address *a;
const NMPlatformIP6Route *r;
@@ -1231,29 +1166,33 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
if (changed)
_notify_addresses (dst);
- /* ignore route_metric */
/* ignore nameservers */
- /* default gateway */
- dst_tmp = nm_ip6_config_get_gateway (dst);
- if (dst_tmp) {
- src_tmp = nm_ip6_config_get_gateway (src);
- if ( !nm_ip6_config_get_num_addresses (dst)
- || !src_tmp
- || !IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp))
- nm_ip6_config_set_gateway (dst, NULL);
- }
-
/* 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);
+ const NMPObject *o_dst = NMP_OBJECT_UP_CAST (r);
+ const NMPObject *o_lookup;
+ NMPObject o_lookup_copy;
+
+ if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
+ && default_route_metric_penalty) {
+ NMPlatformIP6Route *rr;
+
+ /* the default route was penalized when merging it to the combined ip-config.
+ * When intersecting the routes, we must re-do that process when comparing
+ * the routes. */
+ o_lookup = nmp_object_stackinit_obj (&o_lookup_copy, o_dst);
+ rr = NMP_OBJECT_CAST_IP6_ROUTE (&o_lookup_copy);
+ rr->metric = nm_utils_ip_route_metric_penalize (AF_INET6, rr->metric, default_route_metric_penalty);
+ } else
+ o_lookup = o_dst;
if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx,
&src_priv->idx_ip6_routes,
- o)) {
- new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o);
+ o_lookup)) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o_dst);
continue;
}
@@ -1262,8 +1201,10 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
nm_assert_not_reached ();
changed = TRUE;
}
- if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
+ if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route)) {
nm_assert (changed);
+ _notify (dst, PROP_GATEWAY);
+ }
if (changed)
_notify_routes (dst);
@@ -1323,23 +1264,6 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
has_minor_changes = TRUE;
}
- /* never_default */
- if (src_priv->never_default != dst_priv->never_default) {
- dst_priv->never_default = src_priv->never_default;
- has_minor_changes = TRUE;
- }
-
- /* default gateway */
- if (!IN6_ARE_ADDR_EQUAL (&src_priv->gateway, &dst_priv->gateway)) {
- nm_ip6_config_set_gateway (dst, &src_priv->gateway);
- has_relevant_changes = TRUE;
- }
-
- if (src_priv->route_metric != dst_priv->route_metric) {
- dst_priv->route_metric = src_priv->route_metric;
- has_minor_changes = TRUE;
- }
-
/* addresses */
head_entry_src = nm_ip6_config_lookup_addresses (src);
nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src);
@@ -1438,7 +1362,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
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);
+ if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
+ _notify (dst, PROP_GATEWAY);
_notify_routes (dst);
}
@@ -1518,12 +1443,6 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
has_relevant_changes = TRUE;
}
- /* mss */
- if (src_priv->mss != dst_priv->mss) {
- nm_ip6_config_set_mss (dst, src_priv->mss);
- has_minor_changes = TRUE;
- }
-
/* DNS priority */
if (src_priv->dns_priority != dst_priv->dns_priority) {
nm_ip6_config_set_dns_priority (dst, src_priv->dns_priority);
@@ -1571,11 +1490,6 @@ nm_ip6_config_dump (const NMIP6Config *self, const char *detail)
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address)
g_message (" a: %s", nm_platform_ip6_address_to_string (address, NULL, 0));
- /* default gateway */
- tmp = nm_ip6_config_get_gateway (self);
- if (tmp)
- g_message (" gw: %s", nm_utils_inet6_ntop (tmp, NULL));
-
/* nameservers */
for (i = 0; i < nm_ip6_config_get_num_nameservers (self); i++) {
tmp = nm_ip6_config_get_nameserver (self, i);
@@ -1599,60 +1513,6 @@ nm_ip6_config_dump (const NMIP6Config *self, const char *detail)
g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (self, i));
g_message (" dnspri: %d", nm_ip6_config_get_dns_priority (self));
-
- g_message (" mss: %"G_GUINT32_FORMAT, nm_ip6_config_get_mss (self));
- g_message (" n-dflt: %d", nm_ip6_config_get_never_default (self));
-}
-
-/*****************************************************************************/
-
-void
-nm_ip6_config_set_never_default (NMIP6Config *self, gboolean never_default)
-{
- NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
-
- priv->never_default = never_default;
-}
-
-gboolean
-nm_ip6_config_get_never_default (const NMIP6Config *self)
-{
- const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
-
- return priv->never_default;
-}
-
-void
-nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *gateway)
-{
- NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
-
- if (gateway) {
- if (IN6_ARE_ADDR_EQUAL (&priv->gateway, gateway))
- return;
- priv->gateway = *gateway;
- } else {
- if (IN6_IS_ADDR_UNSPECIFIED (&priv->gateway))
- return;
- memset (&priv->gateway, 0, sizeof (priv->gateway));
- }
- _notify (self, PROP_GATEWAY);
-}
-
-const struct in6_addr *
-nm_ip6_config_get_gateway (const NMIP6Config *self)
-{
- const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
-
- return IN6_IS_ADDR_UNSPECIFIED (&priv->gateway) ? NULL : &priv->gateway;
-}
-
-gint64
-nm_ip6_config_get_route_metric (const NMIP6Config *self)
-{
- const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
-
- return priv->route_metric;
}
/*****************************************************************************/
@@ -1905,9 +1765,12 @@ _lookup_route (const NMIP6Config *self,
void
nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
+ const NMNDiscGateway *gateways,
+ guint gateways_n,
const NMNDiscRoute *routes,
guint routes_n,
- guint32 metric)
+ guint32 route_table,
+ guint32 route_metric)
{
NMIP6ConfigPrivate *priv;
guint i;
@@ -1936,7 +1799,8 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
r->plen = ndisc_route->plen;
r->gateway = ndisc_route->gateway;
r->rt_source = NM_IP_CONFIG_SOURCE_NDISC;
- r->metric = metric;
+ r->table_coerced = nm_platform_route_table_coerce (route_table);
+ r->metric = route_metric;
if (_nm_ip_config_add_obj (priv->multi_idx,
&priv->idx_ip6_routes_,
@@ -1951,12 +1815,38 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
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;
+ /* Use the first gateway as ordered in neighbor discovery cache. */
+ if (gateways_n) {
+ const NMPObject *obj_new;
+ const NMPlatformIP6Route r = {
+ .rt_source = NM_IP_CONFIG_SOURCE_NDISC,
+ .ifindex = priv->ifindex,
+ .gateway = gateways[0].address,
+ .table_coerced = nm_platform_route_table_coerce (route_table),
+ .metric = route_metric,
+ };
+
+ if (_nm_ip_config_add_obj (priv->multi_idx,
+ &priv->idx_ip6_routes_,
+ priv->ifindex,
+ NULL,
+ (const NMPlatformObject *) &r,
+ FALSE,
+ TRUE,
+ 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_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0)
changed = TRUE;
+ if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route)) {
+ changed = TRUE;
+ _notify (self, PROP_GATEWAY);
+ }
+
if (changed)
_notify_routes (self);
}
@@ -1968,7 +1858,8 @@ nm_ip6_config_reset_routes (NMIP6Config *self)
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
&priv->idx_ip6_routes) > 0) {
- nm_clear_nmp_object (&priv->best_default_route);
+ if (nm_clear_nmp_object (&priv->best_default_route))
+ _notify (self, PROP_GATEWAY);
_notify_routes (self);
}
}
@@ -1996,11 +1887,19 @@ _add_route (NMIP6Config *self,
FALSE,
&obj_old,
&obj_new_2)) {
+ gboolean changed_default_route = FALSE;
+
if ( priv->best_default_route == obj_old
- && obj_old != obj_new_2)
+ && obj_old != obj_new_2) {
+ changed_default_route = TRUE;
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));
+ if (_nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2))
+ changed_default_route = TRUE;
+
+ if (changed_default_route)
+ _notify (self, PROP_GATEWAY);
_notify_routes (self);
} else
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
@@ -2069,7 +1968,9 @@ _nmtst_ip6_config_get_route (const NMIP6Config *self, guint i)
}
const NMPlatformIP6Route *
-nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host)
+nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self,
+ const struct in6_addr *host,
+ guint32 route_table)
{
const NMPlatformIP6Route *best_route = NULL;
const NMPlatformIP6Route *item;
@@ -2084,6 +1985,9 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct i
if (best_route && best_route->plen > item->plen)
continue;
+ if (nm_platform_route_table_uncoerce (item->table_coerced, TRUE) != route_table)
+ continue;
+
if (!nm_utils_ip6_address_same_prefix (host, &item->network, item->plen))
continue;
@@ -2386,24 +2290,6 @@ nm_ip6_config_get_dns_priority (const NMIP6Config *self)
/*****************************************************************************/
-void
-nm_ip6_config_set_mss (NMIP6Config *self, guint32 mss)
-{
- NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
-
- priv->mss = mss;
-}
-
-guint32
-nm_ip6_config_get_mss (const NMIP6Config *self)
-{
- const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
-
- return priv->mss;
-}
-
-/*****************************************************************************/
-
const NMPObject *
nm_ip6_config_nmpobj_lookup (const NMIP6Config *self, const NMPObject *needle)
{
@@ -2469,8 +2355,9 @@ nm_ip6_config_nmpobj_remove (NMIP6Config *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));
+ if (_nm_ip_config_best_default_route_set (&priv->best_default_route,
+ _nm_ip6_config_best_default_route_find (self)))
+ _notify (self, PROP_GATEWAY);
}
_notify_routes (self);
break;
@@ -2510,8 +2397,6 @@ nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only)
g_return_if_fail (sum);
if (dns_only == FALSE) {
- hash_in6addr (sum, nm_ip6_config_get_gateway (self));
-
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) {
hash_in6addr (sum, &address->address);
hash_u32 (sum, address->plen);
@@ -2670,9 +2555,10 @@ get_property (GObject *object, guint prop_id,
&address->address, 16, 1),
address->plen,
g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
- i == 0
- ? (nm_ip6_config_get_gateway (self) ?: &in6addr_any)
- : &in6addr_any,
+ ( i == 0
+ && priv->best_default_route)
+ ? &NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway
+ : &in6addr_any,
16, 1));
}
}
@@ -2748,9 +2634,11 @@ out_routes_cached:
priv->routes_variant);
break;
case PROP_GATEWAY:
- if (!IN6_IS_ADDR_UNSPECIFIED (&priv->gateway))
- g_value_set_string (value, nm_utils_inet6_ntop (&priv->gateway, NULL));
- else
+ if (priv->best_default_route) {
+ g_value_set_string (value,
+ nm_utils_inet6_ntop (&NMP_OBJECT_CAST_IP6_ROUTE (priv->best_default_route)->gateway,
+ NULL));
+ } else
g_value_set_string (value, NULL);
break;
case PROP_NAMESERVERS:
@@ -2817,7 +2705,6 @@ nm_ip6_config_init (NMIP6Config *self)
priv->domains = g_ptr_array_new_with_free_func (g_free);
priv->searches = g_ptr_array_new_with_free_func (g_free);
priv->dns_options = g_ptr_array_new_with_free_func (g_free);
- priv->route_metric = -1;
}
NMIP6Config *