diff options
author | Thomas Haller <thaller@redhat.com> | 2017-09-12 18:34:14 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-09-13 09:11:05 +0200 |
commit | 9246281d504892f7257bb58ed826fb0ac5fcbbfb (patch) | |
tree | a4884bbfd403b3a394ea44fd13bd2bd06dc0585b | |
parent | 6698bf58bb53fb07838c52ca67293dd5352ec31c (diff) | |
download | NetworkManager-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.c | 27 | ||||
-rw-r--r-- | src/nm-iface-helper.c | 2 | ||||
-rw-r--r-- | src/nm-ip4-config.c | 1 | ||||
-rw-r--r-- | src/nm-ip6-config.c | 6 | ||||
-rw-r--r-- | src/nm-ip6-config.h | 3 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 53 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 3 | ||||
-rw-r--r-- | src/vpn/nm-vpn-connection.c | 3 |
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; } |