From d86dd9a0fe20d49601188b935b7aeffc3d80b3b5 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 8 Mar 2019 18:19:00 +0100 Subject: [PATCH 1/5] core: fix _nm_ip4_config_intersect_helper() Fixes: 8f07b3ac4f68 ('ip-config: add @intersect_routes argument to intersect functions') --- src/nm-ip4-config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 5286a0e65a..028cd2d0ba 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -1599,12 +1599,12 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, _notify (dst, PROP_GATEWAY); } -skip_routes: if (changed) { _notify_routes (dst); result = TRUE; } +skip_routes: /* ignore domains */ /* ignore dns searches */ /* ignore dns options */ From 72385f363c2bbb7a9b26e7d50f0c61ffc50fdd0b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 8 Mar 2019 18:42:19 +0100 Subject: [PATCH 2/5] device: don't try to add IPv6LL address to a down interface When the interface is down DAD failures becomes irrelevant and we shouldn't try to add a link-local address even if the configuration contains other IPv6 addresses. --- src/devices/nm-device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 918481128b..90bc4bdc0d 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -12892,6 +12892,7 @@ queued_ip_config_change (NMDevice *self, int addr_family) if (!IS_IPv4) { NMPlatform *platform; GSList *dad6_failed_addrs, *iter; + const NMPlatformLink *pllink; dad6_failed_addrs = g_steal_pointer (&priv->dad6_failed_addrs); @@ -12900,7 +12901,8 @@ queued_ip_config_change (NMDevice *self, int addr_family) && priv->ifindex > 0 && !nm_device_sys_iface_state_is_external (self) && (platform = nm_device_get_platform (self)) - && nm_platform_link_get (platform, priv->ifindex)) { + && (pllink = nm_platform_link_get (platform, priv->ifindex)) + && (pllink->n_ifi_flags & IFF_UP)) { gboolean need_ipv6ll = FALSE; NMNDiscConfigMap ndisc_config_changed = NM_NDISC_CONFIG_NONE; From 056470a4ba7e000618f6d73437e38a96e348b81b Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 8 Mar 2019 15:26:47 +0100 Subject: [PATCH 3/5] device: reset the ipv6 DAD counter when the link comes up We can detect false DAD failures if the link goes down. Don't try to prevent them, but just reset the counter if the link goes down. --- src/devices/nm-device.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 90bc4bdc0d..e13ca4b8df 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3884,6 +3884,8 @@ device_link_changed (NMDevice *self) if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) _LOGW (LOGD_IP4, "failed applying IP4 config after link comes up again"); } + + priv->linklocal6_dad_counter = 0; if (priv->ip_state_6 == NM_DEVICE_IP_STATE_DONE) { if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) _LOGW (LOGD_IP6, "failed applying IP6 config after link comes up again"); From 39b72572087a1243725a48d47d53131591417aec Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 8 Mar 2019 15:50:39 +0100 Subject: [PATCH 4/5] core: allow ignoring addresses when intersecting ip configs Add a new argument to nm_ip_config_* helpers to also ignore addresses similarly to what we already do for routes. This will be used in the next commit; no change in behavior here. --- src/devices/nm-device.c | 28 +++++++++++------- src/nm-ip4-config.c | 60 ++++++++++++++++++++++++++------------- src/nm-ip4-config.h | 7 +++++ src/nm-ip6-config.c | 63 +++++++++++++++++++++++++++-------------- src/nm-ip6-config.h | 2 ++ 5 files changed, 109 insertions(+), 51 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index e13ca4b8df..737175f2d6 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -12669,6 +12669,7 @@ nm_device_get_firmware_missing (NMDevice *self) static void intersect_ext_config (NMDevice *self, AppliedConfig *config, + gboolean intersect_addresses, gboolean intersect_routes) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -12685,11 +12686,16 @@ intersect_ext_config (NMDevice *self, ? (NMIPConfig *) priv->ext_ip_config_4 : (NMIPConfig *) priv->ext_ip_config_6; - if (config->current) - nm_ip_config_intersect (config->current, ext, intersect_routes, penalty); - else { + if (config->current) { + nm_ip_config_intersect (config->current, + ext, + intersect_addresses, + intersect_routes, + penalty); + } else { config->current = nm_ip_config_intersect_alloc (config->orig, ext, + intersect_addresses, intersect_routes, penalty); } @@ -12725,15 +12731,16 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config * by the user. */ if (priv->con_ip_config_4) { nm_ip4_config_intersect (priv->con_ip_config_4, priv->ext_ip_config_4, + TRUE, is_up, default_route_metric_penalty_get (self, AF_INET)); } - intersect_ext_config (self, &priv->dev_ip_config_4, is_up); - intersect_ext_config (self, &priv->dev2_ip_config_4, is_up); + intersect_ext_config (self, &priv->dev_ip_config_4, TRUE, is_up); + intersect_ext_config (self, &priv->dev2_ip_config_4, TRUE, is_up); for (iter = priv->vpn_configs_4; iter; iter = iter->next) - nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, is_up, 0); + nm_ip4_config_intersect (iter->data, priv->ext_ip_config_4, TRUE, is_up, 0); } /* Remove parts from ext_ip_config_4 to only contain the information that @@ -12777,16 +12784,17 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config * by the user. */ if (priv->con_ip_config_6) { nm_ip6_config_intersect (priv->con_ip_config_6, priv->ext_ip_config_6, + TRUE, is_up, default_route_metric_penalty_get (self, AF_INET6)); } - intersect_ext_config (self, &priv->ac_ip6_config, is_up); - intersect_ext_config (self, &priv->dhcp6.ip6_config, is_up); - intersect_ext_config (self, &priv->dev2_ip_config_6, is_up); + intersect_ext_config (self, &priv->ac_ip6_config, TRUE, is_up); + intersect_ext_config (self, &priv->dhcp6.ip6_config, TRUE, is_up); + intersect_ext_config (self, &priv->dev2_ip_config_6, TRUE, is_up); for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, is_up, 0); + nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, TRUE, is_up, 0); if ( priv->ipv6ll_has && !nm_ip6_config_lookup_address (priv->ext_ip_config_6, &priv->ipv6ll_addr)) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 028cd2d0ba..1c06a42ce9 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -1511,6 +1511,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, static gboolean _nm_ip4_config_intersect_helper (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty, gboolean update_dst) @@ -1533,24 +1534,26 @@ _nm_ip4_config_intersect_helper (NMIP4Config *dst, g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - changed = FALSE; - nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) { - if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, - &src_priv->idx_ip4_addresses, - NMP_OBJECT_UP_CAST (a))) - continue; + if (intersect_addresses) { + changed = FALSE; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) { + if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, + &src_priv->idx_ip4_addresses, + NMP_OBJECT_UP_CAST (a))) + continue; - if (!update_dst) - return TRUE; + if (!update_dst) + return TRUE; - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, - ipconf_iter.current) != 1) - nm_assert_not_reached (); - changed = TRUE; - } - if (changed) { - _notify_addresses (dst); - result = TRUE; + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, + ipconf_iter.current) != 1) + nm_assert_not_reached (); + changed = TRUE; + } + if (changed) { + _notify_addresses (dst); + result = TRUE; + } } /* ignore nameservers */ @@ -1622,6 +1625,8 @@ skip_routes: * nm_ip4_config_intersect: * @dst: a configuration to be updated * @src: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @src and @dst and updates @dst in place @@ -1630,16 +1635,24 @@ skip_routes: void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { - _nm_ip4_config_intersect_helper (dst, src, intersect_routes, default_route_metric_penalty, TRUE); + _nm_ip4_config_intersect_helper (dst, + src, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); } /** * nm_ip4_config_intersect_alloc: * @a: a configuration * @b: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @a and @b and returns the result in a newly @@ -1654,17 +1667,24 @@ nm_ip4_config_intersect (NMIP4Config *dst, NMIP4Config * nm_ip4_config_intersect_alloc (const NMIP4Config *a, const NMIP4Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { NMIP4Config *a_copy; if (_nm_ip4_config_intersect_helper ((NMIP4Config *) a, b, + intersect_addresses, intersect_routes, - default_route_metric_penalty, FALSE)) { + default_route_metric_penalty, + FALSE)) { a_copy = nm_ip4_config_clone (a); - _nm_ip4_config_intersect_helper (a_copy, b, intersect_routes, - default_route_metric_penalty, TRUE); + _nm_ip4_config_intersect_helper (a_copy, + b, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); return a_copy; } else return NULL; diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 07fb7f12a2..6b4bfd64e6 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -189,10 +189,12 @@ void nm_ip4_config_subtract (NMIP4Config *dst, guint32 default_route_metric_penalty); void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); NMIP4Config *nm_ip4_config_intersect_alloc (const NMIP4Config *a, const NMIP4Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); @@ -543,12 +545,14 @@ nm_ip_config_best_default_route_get (const NMIPConfig *self) static inline void nm_ip_config_intersect (NMIPConfig *dst, const NMIPConfig *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { _NM_IP_CONFIG_DISPATCH_SET_OP (, dst, src, nm_ip4_config_intersect, nm_ip6_config_intersect, + intersect_addresses, intersect_routes, default_route_metric_penalty); } @@ -591,6 +595,7 @@ nm_ip_config_replace (NMIPConfig *dst, static inline NMIPConfig * nm_ip_config_intersect_alloc (const NMIPConfig *a, const NMIPConfig *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { @@ -598,6 +603,7 @@ nm_ip_config_intersect_alloc (const NMIPConfig *a, nm_assert (NM_IS_IP4_CONFIG (b)); return (NMIPConfig *) nm_ip4_config_intersect_alloc ((const NMIP4Config *) a, (const NMIP4Config *) b, + intersect_addresses, intersect_routes, default_route_metric_penalty); } else { @@ -605,6 +611,7 @@ nm_ip_config_intersect_alloc (const NMIPConfig *a, nm_assert (NM_IS_IP6_CONFIG (b)); return (NMIPConfig *) nm_ip6_config_intersect_alloc ((const NMIP6Config *) a, (const NMIP6Config *) b, + intersect_addresses, intersect_routes, default_route_metric_penalty); } diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index d63968cf0d..99a9ff8886 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -1086,6 +1086,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, static gboolean _nm_ip6_config_intersect_helper (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty, gboolean update_dst) @@ -1108,24 +1109,26 @@ _nm_ip6_config_intersect_helper (NMIP6Config *dst, g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - changed = FALSE; - nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, dst, &a) { - if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, - &src_priv->idx_ip6_addresses, - NMP_OBJECT_UP_CAST (a))) - continue; + if (intersect_addresses) { + changed = FALSE; + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, dst, &a) { + if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx, + &src_priv->idx_ip6_addresses, + NMP_OBJECT_UP_CAST (a))) + continue; - if (!update_dst) - return TRUE; + if (!update_dst) + return TRUE; - if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, - ipconf_iter.current) != 1) - nm_assert_not_reached (); - changed = TRUE; - } - if (changed) { - _notify_addresses (dst); - result = TRUE; + if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx, + ipconf_iter.current) != 1) + nm_assert_not_reached (); + changed = TRUE; + } + if (changed) { + _notify_addresses (dst); + result = TRUE; + } } /* ignore nameservers */ @@ -1193,6 +1196,8 @@ skip_routes: * nm_ip6_config_intersect: * @dst: a configuration to be updated * @src: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @src and @dst and updates @dst in place @@ -1201,16 +1206,24 @@ skip_routes: void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { - _nm_ip6_config_intersect_helper (dst, src, intersect_routes, default_route_metric_penalty, TRUE); + _nm_ip6_config_intersect_helper (dst, + src, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); } /** * nm_ip6_config_intersect_alloc: * @a: a configuration * @b: another configuration + * @intersect_addresses: whether addresses should be intersected + * @intersect_routes: whether routes should be intersected * @default_route_metric_penalty: the default route metric penalty * * Computes the intersection between @a and @b and returns the result in a newly @@ -1225,17 +1238,25 @@ nm_ip6_config_intersect (NMIP6Config *dst, NMIP6Config * nm_ip6_config_intersect_alloc (const NMIP6Config *a, const NMIP6Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty) { NMIP6Config *a_copy; - if (_nm_ip6_config_intersect_helper ((NMIP6Config *) a, b, + if (_nm_ip6_config_intersect_helper ((NMIP6Config *) a, + b, + intersect_addresses, intersect_routes, - default_route_metric_penalty, FALSE)) { + default_route_metric_penalty, + FALSE)) { a_copy = nm_ip6_config_clone (a); - _nm_ip6_config_intersect_helper (a_copy, b, intersect_routes, - default_route_metric_penalty, TRUE); + _nm_ip6_config_intersect_helper (a_copy, + b, + intersect_addresses, + intersect_routes, + default_route_metric_penalty, + TRUE); return a_copy; } else return NULL; diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 862f237de0..557e379604 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -130,10 +130,12 @@ void nm_ip6_config_subtract (NMIP6Config *dst, guint32 default_route_metric_penalty); void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); NMIP6Config *nm_ip6_config_intersect_alloc (const NMIP6Config *a, const NMIP6Config *b, + gboolean intersect_addresses, gboolean intersect_routes, guint32 default_route_metric_penalty); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); From 505d2adbc29d8a7d8b325fbff4f4bd8953afe805 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Fri, 8 Mar 2019 18:26:30 +0100 Subject: [PATCH 5/5] device: restore IPv6 addresses when the link comes up When the link goes down the kernel removes IPv6 addresses from the interface. In update_ext_ip_config() we detect that addresses were removed externally and drop them from various internal configurations. Don't do that if the link is down so that those addresses will be restored again on link up. --- src/devices/nm-device.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 737175f2d6..7514fa784b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -12784,17 +12784,17 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean intersect_config * by the user. */ if (priv->con_ip_config_6) { nm_ip6_config_intersect (priv->con_ip_config_6, priv->ext_ip_config_6, - TRUE, + is_up, is_up, default_route_metric_penalty_get (self, AF_INET6)); } - intersect_ext_config (self, &priv->ac_ip6_config, TRUE, is_up); - intersect_ext_config (self, &priv->dhcp6.ip6_config, TRUE, is_up); - intersect_ext_config (self, &priv->dev2_ip_config_6, TRUE, is_up); + intersect_ext_config (self, &priv->ac_ip6_config, is_up, is_up); + intersect_ext_config (self, &priv->dhcp6.ip6_config, is_up, is_up); + intersect_ext_config (self, &priv->dev2_ip_config_6, is_up, is_up); for (iter = priv->vpn_configs_6; iter; iter = iter->next) - nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, TRUE, is_up, 0); + nm_ip6_config_intersect (iter->data, priv->ext_ip_config_6, is_up, is_up, 0); if ( priv->ipv6ll_has && !nm_ip6_config_lookup_address (priv->ext_ip_config_6, &priv->ipv6ll_addr))