summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-09-12 18:34:14 +0200
committerThomas Haller <thaller@redhat.com>2017-09-13 09:11:05 +0200
commit9246281d504892f7257bb58ed826fb0ac5fcbbfb (patch)
treea4884bbfd403b3a394ea44fd13bd2bd06dc0585b
parent6698bf58bb53fb07838c52ca67293dd5352ec31c (diff)
downloadNetworkManager-th/ip-config-route-id.tar.gz
WIP: core: workaround configuring IPv6 routes with "src" (RTA_PREFSRC)th/ip-config-route-id
https://bugzilla.redhat.com/show_bug.cgi?id=1452684
-rw-r--r--src/devices/nm-device.c27
-rw-r--r--src/nm-iface-helper.c2
-rw-r--r--src/nm-ip4-config.c1
-rw-r--r--src/nm-ip6-config.c6
-rw-r--r--src/nm-ip6-config.h3
-rw-r--r--src/platform/nm-platform.c53
-rw-r--r--src/platform/nm-platform.h3
-rw-r--r--src/vpn/nm-vpn-connection.c3
8 files changed, 88 insertions, 10 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index cd523b9dad..78bab194cb 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -421,6 +421,8 @@ typedef struct _NMDevicePrivate {
bool nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */
NMIP6Config * dad6_ip6_config;
+ GPtrArray * ipv6_routes_temporary_not_available;
+
NMNDisc * ndisc;
gulong ndisc_changed_id;
gulong ndisc_timeout_id;
@@ -6284,6 +6286,7 @@ ip6_config_merge_and_apply (NMDevice *self,
const char *token = NULL;
GSList *iter;
NMPlatformIP6Route default_route;
+ guint i;
/* Apply ignore-auto-routes and ignore-auto-dns settings */
connection = nm_device_get_applied_connection (self);
@@ -6350,6 +6353,14 @@ ip6_config_merge_and_apply (NMDevice *self,
| (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0));
}
+ if (priv->ipv6_routes_temporary_not_available) {
+ for (i = 0; i < priv->ipv6_routes_temporary_not_available->len; i++) {
+ nm_ip6_config_add_route (composite,
+ NMP_OBJECT_CAST_IP6_ROUTE (priv->ipv6_routes_temporary_not_available->pdata[i]),
+ NULL);
+ }
+ }
+
/* Merge user overrides into the composite config. For assumed connections,
* con_ip6_config is empty. */
if (priv->con_ip6_config)
@@ -7452,6 +7463,8 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
priv->ac_ip6_config = NULL;
}
+ g_clear_pointer (&priv->ipv6_routes_temporary_not_available, g_ptr_array_unref);
+
s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting_ip6_config (connection));
g_assert (s_ip6);
@@ -7505,6 +7518,7 @@ addrconf6_cleanup (NMDevice *self)
nm_device_remove_pending_action (self, NM_PENDING_ACTION_AUTOCONF6, FALSE);
g_clear_object (&priv->ac_ip6_config);
+ g_clear_pointer (&priv->ipv6_routes_temporary_not_available, g_ptr_array_unref);
g_clear_object (&priv->ndisc);
}
@@ -9942,8 +9956,17 @@ nm_device_set_ip6_config (NMDevice *self,
/* Always commit to nm-platform to update lifetimes */
if (commit && new_config) {
_commit_mtu (self, priv->ip4_config);
+
+ if (priv->ipv6_routes_temporary_not_available)
+ g_ptr_array_set_size (priv->ipv6_routes_temporary_not_available, 0);
+
success = nm_ip6_config_commit (new_config,
- nm_device_get_platform (self));
+ nm_device_get_platform (self),
+ &priv->ipv6_routes_temporary_not_available);
+
+ if ( priv->ipv6_routes_temporary_not_available
+ && priv->ipv6_routes_temporary_not_available->len == 0)
+ g_clear_pointer (&priv->ipv6_routes_temporary_not_available, g_ptr_array_unref);
}
if (new_config) {
@@ -12016,6 +12039,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
g_clear_object (&priv->ip6_config);
g_clear_object (&priv->dad6_ip6_config);
+ g_clear_pointer (&priv->ipv6_routes_temporary_not_available, g_ptr_array_unref);
+
g_slist_free_full (priv->vpn4_configs, g_object_unref);
priv->vpn4_configs = NULL;
g_slist_free_full (priv->vpn6_configs, g_object_unref);
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index ae76ee94ef..43c2ae478b 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -226,7 +226,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
}
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
- if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET))
+ if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, NULL))
_LOGW (LOGD_IP6, "failed to apply IPv6 config");
}
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index f3d87814ee..90407e34a1 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -837,6 +837,7 @@ nm_ip4_config_commit (const NMIP4Config *self,
ifindex,
routes,
nm_platform_lookup_predicate_routes_main,
+ NULL,
NULL))
success = FALSE;
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index ce77394256..acb9ccb646 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -529,7 +529,8 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
gboolean
nm_ip6_config_commit (const NMIP6Config *self,
- NMPlatform *platform)
+ NMPlatform *platform,
+ GPtrArray **out_temporary_not_available)
{
gs_unref_ptrarray GPtrArray *addresses = NULL;
gs_unref_ptrarray GPtrArray *routes = NULL;
@@ -552,7 +553,8 @@ nm_ip6_config_commit (const NMIP6Config *self,
ifindex,
routes,
nm_platform_lookup_predicate_routes_main,
- NULL))
+ NULL,
+ out_temporary_not_available))
success = FALSE;
return success;
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index ec8bee881d..71ae1e469c 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -108,7 +108,8 @@ 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);
gboolean nm_ip6_config_commit (const NMIP6Config *self,
- NMPlatform *platform);
+ NMPlatform *platform,
+ GPtrArray **out_temporary_not_available);
void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self);
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 47ac8bfd52..39c3e02f71 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -3547,6 +3547,41 @@ nm_platform_ip_address_flush (NMPlatform *self,
/*****************************************************************************/
+static gboolean
+_err_inval_due_to_ipv6_tentative_pref_src (NMPlatform *self, const NMPObject *obj)
+{
+ const NMPlatformIP6Route *r;
+ const NMPlatformIP6Address *a;
+
+ nm_assert (NM_IS_PLATFORM (self));
+ nm_assert (NMP_OBJECT_IS_VALID (obj));
+
+ /* trying to add an IPv6 route with pref-src fails, if the address is
+ * still tentative (rh#1452684). We need to hack around that.
+ *
+ * Detect it, by guessing whether that's the case. */
+
+ if (NMP_OBJECT_GET_TYPE (obj) != NMP_OBJECT_TYPE_IP6_ROUTE)
+ return FALSE;
+
+ r = NMP_OBJECT_CAST_IP6_ROUTE (obj);
+
+ /* we only allow this workaround for routes added manually by the user. */
+ if (r->rt_source != NM_IP_CONFIG_SOURCE_USER)
+ return FALSE;
+
+ if (IN6_IS_ADDR_UNSPECIFIED (&r->pref_src))
+ return FALSE;
+
+ a = nm_platform_ip6_address_get (self, r->ifindex, r->pref_src);
+ if (!a)
+ return FALSE;
+ if (!NM_FLAGS_HAS (a->n_ifa_flags, IFA_F_TENTATIVE))
+ return FALSE;
+
+ return TRUE;
+}
+
/**
* nm_platform_ip_route_sync:
* @self: the #NMPlatform instance.
@@ -3560,6 +3595,8 @@ nm_platform_ip_address_flush (NMPlatform *self,
* routes. For example by passing @nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
* routes with "proto kernel" will be left untouched.
* @kernel_delete_userdata: user data for @kernel_delete_predicate.
+ * @out_temporary_not_available: (allow-none): (out): routes that could
+ * currently not be synced. The caller shall keep them and try later again.
*
* Returns: %TRUE on success.
*/
@@ -3569,7 +3606,8 @@ nm_platform_ip_route_sync (NMPlatform *self,
int ifindex,
GPtrArray *routes,
NMPObjectPredicateFunc kernel_delete_predicate,
- gpointer kernel_delete_userdata)
+ gpointer kernel_delete_userdata,
+ GPtrArray **out_temporary_not_available)
{
const NMPlatformVTableRoute *vt;
gs_unref_ptrarray GPtrArray *plat_routes = NULL;
@@ -3662,6 +3700,15 @@ nm_platform_ip_route_sync (NMPlatform *self,
nmp_object_to_string (plat_entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, sbuf2, sizeof (sbuf2)));
}
}
+ } else if ( -((int) plerr) == EINVAL
+ && out_temporary_not_available
+ && _err_inval_due_to_ipv6_tentative_pref_src (self, conf_o)) {
+ _LOGD ("route-sync: ignore failure to add IPv6 route with tentative IPv6 pref-src: %s: %s",
+ nmp_object_to_string (conf_o, NMP_OBJECT_TO_STRING_PUBLIC, sbuf1, sizeof (sbuf1)),
+ nm_platform_error_to_string (plerr, sbuf_err, sizeof (sbuf_err)));
+ if (!*out_temporary_not_available)
+ *out_temporary_not_available = g_ptr_array_new_full (0, (GDestroyNotify) nmp_object_unref);
+ g_ptr_array_add (*out_temporary_not_available, (gpointer) nmp_object_ref (conf_o));
} else if (NMP_OBJECT_CAST_IP_ROUTE (conf_o)->rt_source < NM_IP_CONFIG_SOURCE_USER) {
_LOGD ("route-sync: ignore failure to add IPv%c route: %s: %s",
vt->is_ip4 ? '4' : '6',
@@ -3723,9 +3770,9 @@ nm_platform_ip_route_flush (NMPlatform *self,
AF_INET6));
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET))
- success &= nm_platform_ip_route_sync (self, AF_INET, ifindex, NULL, NULL, NULL);
+ success &= nm_platform_ip_route_sync (self, AF_INET, ifindex, NULL, NULL, NULL, NULL);
if (NM_IN_SET (addr_family, AF_UNSPEC, AF_INET6))
- success &= nm_platform_ip_route_sync (self, AF_INET6, ifindex, NULL, NULL, NULL);
+ success &= nm_platform_ip_route_sync (self, AF_INET6, ifindex, NULL, NULL, NULL, NULL);
return success;
}
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 917f623d01..e68457ca2b 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -1177,7 +1177,8 @@ gboolean nm_platform_ip_route_sync (NMPlatform *self,
int ifindex,
GPtrArray *routes,
NMPObjectPredicateFunc kernel_delete_predicate,
- gpointer kernel_delete_userdata);
+ gpointer kernel_delete_userdata,
+ GPtrArray **out_temporary_not_available);
gboolean nm_platform_ip_route_flush (NMPlatform *self,
int addr_family,
int ifindex);
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index 517e7eb97a..0006cf3cc2 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -1159,7 +1159,8 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
if (priv->ip6_config) {
nm_assert (priv->ip_ifindex == nm_ip6_config_get_ifindex (priv->ip6_config));
if (!nm_ip6_config_commit (priv->ip6_config,
- nm_netns_get_platform (priv->netns)))
+ nm_netns_get_platform (priv->netns),
+ NULL))
return FALSE;
}