From 4753ea38c382912662a3735d7d10350534abe19c 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') (cherry picked from commit d86dd9a0fe20d49601188b935b7aeffc3d80b3b5) --- 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 d159a1153a5d8962c6bf2fc94f70abfc7f9294e8 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. (cherry picked from commit 72385f363c2bbb7a9b26e7d50f0c61ffc50fdd0b) --- 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 6cabee270b..442ac72eed 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 058bf25ac4db3c9118c844d29cefa9dad3414a0f 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. (cherry picked from commit 056470a4ba7e000618f6d73437e38a96e348b81b) --- 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 442ac72eed..f8faf714e1 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 e09674280994919068afe766b991108a89cb75e5 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. (cherry picked from commit 39b72572087a1243725a48d47d53131591417aec) --- 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 f8faf714e1..e9a588ce2e 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 97de744afdb9557167cf6bb1151820e3028aa424 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. (cherry picked from commit 505d2adbc29d8a7d8b325fbff4f4bd8953afe805) --- 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 e9a588ce2e..000d781399 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))