From 5fb20d80389ca42eb3d655c292e0b517f3a83ea8 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 3 Dec 2014 12:47:30 -0600 Subject: core: don't manage externally created software devices until IFF_UP (rh #1030947) (bgo #725647) Externally created software devices would be managed/assumed immediately upon creation, which includes setting them IFF_UP and possibly turning on NM-managed IPv6LL. With this commit, expected behavior for external software devices is: 1) created: unmanaged state, no further action 2) IP address added but !IFF_UP: connection assumed, but device is not set IFF_UP 3) slave attached but !IFF_UP: connection assumed, but master is not set IFF_UP 3) set IFF_UP: connection assumed (if any), if not -> DISCONNECTED This branch ensures that external software devices are not set IFF_UP by NetworkManager when they are discovered. It additionally ensures that they are not set IFF_UP during connection assumption. They may be set IFF_UP later through specific user action. https://bugzilla.gnome.org/show_bug.cgi?id=725647 https://bugzilla.redhat.com/show_bug.cgi?id=1030947 --- src/devices/nm-device.c | 76 ++++++++++++++++++++++++++++++++++++++++++------- src/devices/nm-device.h | 12 ++++---- 2 files changed, 73 insertions(+), 15 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c04a973877..c8cd66c6a0 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -977,6 +977,13 @@ nm_device_release_one_slave (NMDevice *self, NMDevice *slave, gboolean configure return success; } +static gboolean +is_software_external (NMDevice *self) +{ + return nm_device_is_software (self) + && !nm_device_get_is_nm_owned (self); +} + /** * nm_device_finish_init: * @self: the master device @@ -989,6 +996,12 @@ nm_device_finish_init (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + /* Do not manage externally created software devices until they are IFF_UP */ + if ( is_software_external (self) + && !nm_platform_link_is_up (priv->ifindex) + && priv->ifindex > 0) + nm_device_set_initial_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN, TRUE); + if (priv->master) nm_device_enslave_slave (priv->master, self, NULL); } @@ -1228,10 +1241,41 @@ device_link_changed (NMDevice *self, NMPlatformLink *info) if (klass->link_changed) klass->link_changed (self, info); - /* Update DHCP, etc, if needed */ if (ip_ifname_changed) update_for_ip_ifname_change (self); + + /* Manage externally-created software interfaces only when they are IFF_UP */ + if ( is_software_external (self) + && (nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) + && priv->ifindex > 0) { + gboolean external_down = nm_device_get_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN); + + if (external_down && info->up) { + /* Ensure the assume check is queued before any queued state changes + * from the transition to UNAVAILABLE. + */ + nm_device_queue_recheck_assume (self); + + /* Resetting the EXTERNAL_DOWN flag may change the device's state + * to UNAVAILABLE. To ensure that the state change doesn't touch + * the device before assumption occurs, pass + * NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED as the reason. + */ + nm_device_set_unmanaged (self, + NM_UNMANAGED_EXTERNAL_DOWN, + FALSE, + NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); + } else if (!external_down && !info->up) { + /* If the device is already disconnected and is set !IFF_UP, + * unmanage it. + */ + nm_device_set_unmanaged (self, + NM_UNMANAGED_EXTERNAL_DOWN, + TRUE, + NM_DEVICE_STATE_REASON_USER_REQUESTED); + } + } } static void @@ -6607,7 +6651,7 @@ nm_device_get_managed (NMDevice *self) gboolean nm_device_get_unmanaged_flag (NMDevice *self, NMUnmanagedFlags flag) { - return NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags & flag; + return NM_FLAGS_ANY (NM_DEVICE_GET_PRIVATE (self)->unmanaged_flags, flag); } /** @@ -7352,6 +7396,17 @@ notify_ip_properties (NMDevice *self) g_object_notify (G_OBJECT (self), NM_DEVICE_DHCP6_CONFIG); } +static void +ip6_managed_setup (NMDevice *self) +{ + set_nm_ipv6ll (self, TRUE); + set_disable_ipv6 (self, "1"); + nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); + nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); + nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); +} + static void _set_state_full (NMDevice *self, NMDeviceState state, @@ -7428,14 +7483,8 @@ _set_state_full (NMDevice *self, case NM_DEVICE_STATE_UNAVAILABLE: if (old_state == NM_DEVICE_STATE_UNMANAGED) { save_ip6_properties (self); - if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) { - set_nm_ipv6ll (self, TRUE); - set_disable_ipv6 (self, "1"); - nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0"); - nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0"); - nm_device_ipv6_sysctl_set (self, "use_tempaddr", "0"); - } + if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) + ip6_managed_setup (self); } if (old_state == NM_DEVICE_STATE_UNMANAGED || priv->firmware_missing) { @@ -7462,6 +7511,13 @@ _set_state_full (NMDevice *self, set_nm_ipv6ll (self, TRUE); nm_device_cleanup (self, reason); + } else if (old_state < NM_DEVICE_STATE_DISCONNECTED) { + if (reason != NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED) { + /* Ensure IPv6 is set up as it may not have been done when + * entering the UNAVAILABLE state depending on the reason. + */ + ip6_managed_setup (self); + } } break; case NM_DEVICE_STATE_NEED_AUTH: diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index 38eddaa8df..b3855c7446 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -304,13 +304,15 @@ RfKillType nm_device_get_rfkill_type (NMDevice *device); * because NM is sleeping or not managed for some other reason) * @NM_UNMANAGED_USER: %TRUE when unmanaged by user decision (via unmanaged-specs) * @NM_UNMANAGED_PARENT: %TRUE when unmanaged due to parent device being unmanaged + * @NM_UNMANAGED_EXTERNAL_DOWN: %TRUE when unmanaged because !IFF_UP and not created by NM */ typedef enum { - NM_UNMANAGED_NONE = 0x00, - NM_UNMANAGED_DEFAULT = 0x01, - NM_UNMANAGED_INTERNAL = 0x02, - NM_UNMANAGED_USER = 0x04, - NM_UNMANAGED_PARENT = 0x08, + NM_UNMANAGED_NONE = 0x00, + NM_UNMANAGED_DEFAULT = 0x01, + NM_UNMANAGED_INTERNAL = 0x02, + NM_UNMANAGED_USER = 0x04, + NM_UNMANAGED_PARENT = 0x08, + NM_UNMANAGED_EXTERNAL_DOWN = 0x10, /* Boundary value */ __NM_UNMANAGED_LAST, -- cgit v1.2.1