Commit 03e1cc96 authored by Thomas Haller's avatar Thomas Haller
Browse files

core: fix handling IPv6 device-route and use correct route metric

Before commit 6698bf58, we would rely on
kernel to add the device-route for manual IPv6 routes. We broke that and now
kernel would still add the device-route, however nm_platform_ip_route_sync()
would delete it immediately after.
That is because previously nm_platform_ip_route_sync() would ignore routes
with rtm_protocol RTPRO_KERNEL. Now, it will sync and delete those too.

Fix that by adding the device-route like we do it for IPv4. This also
fixes an actual issue where the automatically added route always had
route-metric 256. Instead, we now use the metric from ipv6.route-metric
setting.

Fixes: 6698bf58
parent 39d30a17
......@@ -6290,6 +6290,7 @@ ip6_config_merge_and_apply (NMDevice *self,
NMConnection *connection;
gboolean success;
NMIP6Config *composite;
const guint32 default_route_metric = nm_device_get_ip6_route_metric (self);
const struct in6_addr *gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean ignore_auto_routes = FALSE;
......@@ -6423,8 +6424,7 @@ ip6_config_merge_and_apply (NMDevice *self,
memset (&default_route, 0, sizeof (default_route));
default_route.rt_source = NM_IP_CONFIG_SOURCE_USER;
default_route.gateway = *gateway;
default_route.metric = route_metric_with_penalty (self,
nm_device_get_ip6_route_metric (self));
default_route.metric = route_metric_with_penalty (self, default_route_metric);
default_route.mss = nm_ip6_config_get_mss (composite);
nm_clear_nmp_object (&priv->default_route6);
nm_ip6_config_add_route (composite, &default_route, &priv->default_route6);
......@@ -6447,6 +6447,11 @@ END_ADD_DEFAULT_ROUTE:
nm_ip6_config_add_route (composite, NMP_OBJECT_CAST_IP6_ROUTE (priv->default_routegw6), NULL);
}
if (commit) {
nm_ip6_config_add_device_routes (composite,
default_route_metric);
}
/* Allow setting MTU etc */
if (commit) {
NMUtilsIPv6IfaceId iid;
......
......@@ -226,6 +226,8 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
}
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
nm_ip6_config_add_device_routes (existing,
global_opt.priority_v6);
if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, NULL))
_LOGW (LOGD_IP6, "failed to apply IPv6 config");
}
......
......@@ -245,13 +245,23 @@ _nm_ip_config_lookup_ip_route (const NMDedupMultiIndex *multi_idx,
if (!entry)
return NULL;
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)
nm_assert (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj), NMP_OBJECT_CAST_IP4_ROUTE (needle), cmp_type) == 0);
else {
if (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj),
NMP_OBJECT_CAST_IP4_ROUTE (needle),
cmp_type) != 0)
return NULL;
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
nm_assert ( ( NMP_OBJECT_GET_TYPE (needle) == NMP_OBJECT_TYPE_IP4_ROUTE
&& nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj), NMP_OBJECT_CAST_IP4_ROUTE (needle), cmp_type) == 0)
|| ( NMP_OBJECT_GET_TYPE (needle) == NMP_OBJECT_TYPE_IP6_ROUTE
&& nm_platform_ip6_route_cmp (NMP_OBJECT_CAST_IP6_ROUTE (entry->obj), NMP_OBJECT_CAST_IP6_ROUTE (needle), cmp_type) == 0));
} else {
if (NMP_OBJECT_GET_TYPE (needle) == NMP_OBJECT_TYPE_IP4_ROUTE) {
if (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj),
NMP_OBJECT_CAST_IP4_ROUTE (needle),
cmp_type) != 0)
return NULL;
} else {
if (nm_platform_ip6_route_cmp (NMP_OBJECT_CAST_IP6_ROUTE (entry->obj),
NMP_OBJECT_CAST_IP6_ROUTE (needle),
cmp_type) != 0)
return NULL;
}
}
return entry;
}
......@@ -740,9 +750,8 @@ nm_ip4_config_add_device_routes (NMIP4Config *self,
ifindex = nm_ip4_config_get_ifindex (self);
g_return_if_fail (ifindex > 0);
/* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config.
* As we don't do that for IPv4, add it here shortly before syncing
* the routes. */
/* For IPv6 slaac, we explicitly add the device-routes (onlink) to NMIP6Config.
* As we don't do that for IPv4 (and manual IPv6 addresses), add them explicitly. */
nm_ip_config_iter_ip4_address_for_each (&iter, self, &addr) {
nm_auto_nmpobj NMPObject *r = NULL;
......
......@@ -115,6 +115,9 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config,
static void _add_address (NMIP6Config *self, const NMPObject *obj_new, const NMPlatformIP6Address *new);
static void _add_route (NMIP6Config *self, const NMPObject *obj_new, const NMPlatformIP6Route *new, const NMPObject **out_obj_new);
static const NMDedupMultiEntry *_lookup_route (const NMIP6Config *self,
const NMPObject *needle,
NMPlatformIPRouteCmpType cmp_type);
/*****************************************************************************/
......@@ -527,6 +530,77 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
return self;
}
void
nm_ip6_config_add_device_routes (NMIP6Config *self,
guint32 default_route_metric)
{
const NMIP6ConfigPrivate *priv;
const NMPlatformIP6Address *addr;
int ifindex;
NMDedupMultiIter iter;
g_return_if_fail (NM_IS_IP6_CONFIG (self));
priv = NM_IP6_CONFIG_GET_PRIVATE (self);
ifindex = nm_ip6_config_get_ifindex (self);
g_return_if_fail (ifindex > 0);
/* For IPv6 addresses received via SLAAC/autoconf, we explicitly add the
* device-routes (onlink) to NMIP6Config.
*
* For manually added IPv6 routes, add the device routes explicitly. */
nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) {
NMPObject *r;
NMPlatformIP6Route *route;
gboolean has_peer;
int routes_n, routes_i;
if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_NOPREFIXROUTE))
continue;
has_peer = !IN6_IS_ADDR_UNSPECIFIED (&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))
? 2 : 1;
for (routes_i = 0; routes_i < routes_n; routes_i++) {
r = nmp_object_new (NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
route = NMP_OBJECT_CAST_IP6_ROUTE (r);
route->ifindex = ifindex;
route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
route->metric = default_route_metric;
if (has_peer) {
if (routes_i == 0)
route->network = addr->address;
else
route->network = 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_platform_ip_route_normalize (AF_INET6, (NMPlatformIPRoute *) route);
if (_lookup_route (self,
r,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
/* we already track this route. Don't add it again. */
nmp_object_unref (r);
} else
_add_route (self, r, NULL, NULL);
}
}
}
gboolean
nm_ip6_config_commit (const NMIP6Config *self,
NMPlatform *platform,
......@@ -1801,6 +1875,24 @@ nm_ip6_config_has_any_dad_pending (const NMIP6Config *self,
/*****************************************************************************/
static const NMDedupMultiEntry *
_lookup_route (const NMIP6Config *self,
const NMPObject *needle,
NMPlatformIPRouteCmpType cmp_type)
{
const NMIP6ConfigPrivate *priv;
nm_assert (NM_IS_IP6_CONFIG (self));
nm_assert (NMP_OBJECT_GET_TYPE (needle) == NMP_OBJECT_TYPE_IP6_ROUTE);
priv = NM_IP6_CONFIG_GET_PRIVATE (self);
return _nm_ip_config_lookup_ip_route (priv->multi_idx,
&priv->idx_ip6_routes_,
needle,
cmp_type);
}
void
nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
const NMNDiscRoute *routes,
......
......@@ -107,6 +107,10 @@ struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx (const NMIP6Config *self)
NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex,
gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
void nm_ip6_config_add_device_routes (NMIP6Config *self,
guint32 default_route_metric);
gboolean nm_ip6_config_commit (const NMIP6Config *self,
NMPlatform *platform,
GPtrArray **out_temporary_not_available);
......
......@@ -3479,6 +3479,7 @@ nm_platform_ip6_address_sync (NMPlatform *self,
gint32 now = nm_utils_get_monotonic_timestamp_s ();
guint i;
NMPLookup lookup;
guint32 ifa_flags;
/* Delete unknown addresses */
plat_addresses = nm_platform_lookup_clone (self,
......@@ -3502,6 +3503,10 @@ nm_platform_ip6_address_sync (NMPlatform *self,
if (!known_addresses)
return TRUE;
ifa_flags = nm_platform_check_support_kernel_extended_ifa_flags (self)
? IFA_F_NOPREFIXROUTE
: 0;
/* Add missing addresses */
for (i = 0; i < known_addresses->len; i++) {
const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i]);
......@@ -3518,7 +3523,8 @@ nm_platform_ip6_address_sync (NMPlatform *self,
if (!nm_platform_ip6_address_add (self, ifindex, known_address->address,
known_address->plen, known_address->peer_address,
lifetime, preferred, known_address->n_ifa_flags))
lifetime, preferred,
ifa_flags | known_address->n_ifa_flags))
return FALSE;
}
......
......@@ -1786,6 +1786,9 @@ next:
nm_ip6_config_add_route (config, &r, NULL);
}
nm_ip6_config_add_device_routes (config,
nm_vpn_connection_get_ip6_route_metric (self));
if (priv->ip6_config) {
nm_ip6_config_replace (priv->ip6_config, config, NULL);
g_object_unref (config);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment