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
This commit is contained in:
Dan Williams 2014-12-03 12:47:30 -06:00
parent 5f04324f8b
commit 5fb20d8038
2 changed files with 73 additions and 15 deletions

View file

@ -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:

View file

@ -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,