summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-09-24 16:58:07 -0500
committerDan Williams <dcbw@redhat.com>2015-05-15 09:46:38 -0500
commit4e20195e5769a76f628bf43c75c80c4ec884209f (patch)
tree021e92a77589fe77ddd75728606882de53175830
parent2ac0e142300dbc81e04fc49199ad22a30ad640a9 (diff)
downloadNetworkManager-4e20195e5769a76f628bf43c75c80c4ec884209f.tar.gz
core: create devices first and realize them later
Unrealized devices aren't backed by kernel resources and so won't know all of their attributes. That means three things: 1) they must update their attributes when they become realized 2) they must clear those attributes when unrealized 3) they must be looser in checking compatible connections until they are realized
-rw-r--r--src/devices/nm-device-bridge.c2
-rw-r--r--src/devices/nm-device-ethernet.c6
-rw-r--r--src/devices/nm-device-generic.c6
-rw-r--r--src/devices/nm-device-infiniband.c5
-rw-r--r--src/devices/nm-device-tun.c6
-rw-r--r--src/devices/nm-device-vlan.c31
-rw-r--r--src/devices/nm-device-vxlan.c6
-rw-r--r--src/devices/nm-device.c96
-rw-r--r--src/devices/nm-device.h22
-rw-r--r--src/devices/wifi/nm-device-wifi.c6
-rw-r--r--src/nm-active-connection.c5
-rw-r--r--src/nm-manager.c330
12 files changed, 288 insertions, 233 deletions
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index 43122b312e..034f9cfe68 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -103,7 +103,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
return FALSE;
mac_address = nm_setting_bridge_get_mac_address (s_bridge);
- if (mac_address) {
+ if (mac_address && nm_device_is_real (device)) {
const char *hw_addr;
hw_addr = nm_device_get_hw_address (device);
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 6675594f85..c3912d63da 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -309,9 +309,9 @@ nm_device_ethernet_init (NMDeviceEthernet *self)
}
static void
-setup (NMDevice *device, NMPlatformLink *plink)
+setup_start (NMDevice *device, NMPlatformLink *plink)
{
- NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->setup (device, plink);
+ NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->setup_start (device, plink);
g_object_notify (G_OBJECT (device), NM_DEVICE_ETHERNET_PERMANENT_HW_ADDRESS);
}
@@ -1682,7 +1682,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass)
object_class->set_property = set_property;
parent_class->get_generic_capabilities = get_generic_capabilities;
- parent_class->setup = setup;
+ parent_class->setup_start = setup_start;
parent_class->check_connection_compatible = check_connection_compatible;
parent_class->complete_connection = complete_connection;
parent_class->new_default_connection = new_default_connection;
diff --git a/src/devices/nm-device-generic.c b/src/devices/nm-device-generic.c
index f80f781dd1..c43cee3280 100644
--- a/src/devices/nm-device-generic.c
+++ b/src/devices/nm-device-generic.c
@@ -55,13 +55,13 @@ get_generic_capabilities (NMDevice *dev)
}
static void
-setup (NMDevice *device, NMPlatformLink *plink)
+setup_start (NMDevice *device, NMPlatformLink *plink)
{
NMDeviceGeneric *self = NM_DEVICE_GENERIC (device);
NMDeviceGenericPrivate *priv = NM_DEVICE_GENERIC_GET_PRIVATE (self);
int ifindex;
- NM_DEVICE_CLASS (nm_device_generic_parent_class)->setup (device, plink);
+ NM_DEVICE_CLASS (nm_device_generic_parent_class)->setup_start (device, plink);
g_clear_pointer (&priv->type_description, g_free);
ifindex = nm_device_get_ip_ifindex (NM_DEVICE (self));
@@ -183,7 +183,7 @@ nm_device_generic_class_init (NMDeviceGenericClass *klass)
object_class->get_property = get_property;
object_class->set_property = set_property;
- parent_class->setup = setup;
+ parent_class->setup_start = setup_start;
parent_class->get_generic_capabilities = get_generic_capabilities;
parent_class->check_connection_compatible = check_connection_compatible;
parent_class->update_connection = update_connection;
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index 8212b1d6d2..62de8d9f2c 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -143,6 +143,7 @@ static gboolean
check_connection_compatible (NMDevice *device, NMConnection *connection)
{
NMSettingInfiniband *s_infiniband;
+ const char *mac;
if (!NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->check_connection_compatible (device, connection))
return FALSE;
@@ -154,9 +155,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!s_infiniband)
return FALSE;
- if (s_infiniband) {
- const char *mac;
-
+ if (nm_device_is_real (device)) {
mac = nm_setting_infiniband_get_mac_address (s_infiniband);
if (mac && !nm_utils_hwaddr_matches (mac, -1, nm_device_get_hw_address (device), -1))
return FALSE;
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index a88241a8df..10f6e40ec8 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -96,12 +96,12 @@ link_changed (NMDevice *device, NMPlatformLink *info)
}
static void
-setup (NMDevice *device, NMPlatformLink *plink)
+setup_start (NMDevice *device, NMPlatformLink *plink)
{
NMDeviceTun *self = NM_DEVICE_TUN (device);
NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self);
- NM_DEVICE_CLASS (nm_device_tun_parent_class)->setup (device, plink);
+ NM_DEVICE_CLASS (nm_device_tun_parent_class)->setup_start (device, plink);
priv->mode = NULL;
if (plink->type == NM_LINK_TYPE_TUN)
@@ -193,7 +193,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass)
object_class->set_property = set_property;
device_class->link_changed = link_changed;
- device_class->setup = setup;
+ device_class->setup_start = setup_start;
/* properties */
g_object_class_install_property
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index 8570db5b43..5aa1ee3e2e 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -120,12 +120,12 @@ nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent)
}
static void
-setup (NMDevice *device, NMPlatformLink *plink)
+setup_start (NMDevice *device, NMPlatformLink *plink)
{
NMDeviceVlan *self = NM_DEVICE_VLAN (device);
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
- NM_DEVICE_CLASS (nm_device_vlan_parent_class)->setup (device, plink);
+ NM_DEVICE_CLASS (nm_device_vlan_parent_class)->setup_start (device, plink);
_LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s",
priv->vlan_id, nm_device_get_iface (priv->parent));
@@ -370,18 +370,21 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
if (!s_vlan)
return FALSE;
- if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id)
- return FALSE;
-
- /* Check parent interface; could be an interface name or a UUID */
- parent = nm_setting_vlan_get_parent (s_vlan);
- if (parent) {
- if (!match_parent (NM_DEVICE_VLAN (device), parent))
- return FALSE;
- } else {
- /* Parent could be a MAC address in an NMSettingWired */
- if (!match_hwaddr (device, connection, TRUE))
+ /* Before the device is realized some properties will not be set */
+ if (nm_device_is_real (device)) {
+ if (nm_setting_vlan_get_id (s_vlan) != priv->vlan_id)
return FALSE;
+
+ /* Check parent interface; could be an interface name or a UUID */
+ parent = nm_setting_vlan_get_parent (s_vlan);
+ if (parent) {
+ if (!match_parent (NM_DEVICE_VLAN (device), parent))
+ return FALSE;
+ } else {
+ /* Parent could be a MAC address in an NMSettingWired */
+ if (!match_hwaddr (device, connection, TRUE))
+ return FALSE;
+ }
}
/* Ensure the interface name matches. If not specified we assume a match
@@ -626,7 +629,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass)
parent_class->create_and_realize = create_and_realize;
parent_class->realize = realize;
- parent_class->setup = setup;
+ parent_class->setup_start = setup_start;
parent_class->unrealize = unrealize;
parent_class->get_generic_capabilities = get_generic_capabilities;
parent_class->bring_up = bring_up;
diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c
index 6de6fb0d6c..65fb8bec88 100644
--- a/src/devices/nm-device-vxlan.c
+++ b/src/devices/nm-device-vxlan.c
@@ -133,11 +133,11 @@ link_changed (NMDevice *device, NMPlatformLink *info)
}
static void
-setup (NMDevice *device, NMPlatformLink *plink)
+setup_start (NMDevice *device, NMPlatformLink *plink)
{
g_assert (plink->type == NM_LINK_TYPE_VXLAN);
- NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->setup (device, plink);
+ NM_DEVICE_CLASS (nm_device_vxlan_parent_class)->setup_start (device, plink);
update_properties (device);
}
@@ -230,7 +230,7 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass)
object_class->get_property = get_property;
device_class->link_changed = link_changed;
- device_class->setup = setup;
+ device_class->setup_start = setup_start;
/* properties */
g_object_class_install_property
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 196806559e..85b769c0bb 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -1265,23 +1265,31 @@ update_for_ip_ifname_change (NMDevice *self)
}
static void
-device_set_master (NMDevice *self, int ifindex)
+device_recheck_slave_status (NMDevice *self, NMPlatformLink *plink)
{
- NMDevice *master;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- master = nm_manager_get_device_by_ifindex (nm_manager_get (), ifindex);
- if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) {
- g_clear_object (&priv->master);
- priv->master = g_object_ref (master);
- nm_device_master_add_slave (master, self, FALSE);
- } else if (master) {
- _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring",
- nm_device_get_iface (master));
- } else {
- _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s",
- ifindex,
- nm_platform_link_get_name (NM_PLATFORM_GET, ifindex));
+ g_return_if_fail (plink != NULL);
+
+ if (priv->enslaved && plink->master != nm_device_get_ifindex (priv->master))
+ nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE);
+
+ if (plink->master && !priv->enslaved) {
+ NMDevice *master;
+
+ master = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->master);
+ if (master && NM_DEVICE_GET_CLASS (master)->enslave_slave) {
+ g_clear_object (&priv->master);
+ priv->master = g_object_ref (master);
+ nm_device_master_add_slave (master, self, FALSE);
+ } else if (master) {
+ _LOGI (LOGD_DEVICE, "enslaved to non-master-type device %s; ignoring",
+ nm_device_get_iface (master));
+ } else {
+ _LOGW (LOGD_DEVICE, "enslaved to unknown device %d %s",
+ plink->master,
+ nm_platform_link_get_name (NM_PLATFORM_GET, plink->master));
+ }
}
}
@@ -1314,6 +1322,12 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
}
+ if (info->driver && g_strcmp0 (priv->driver, info->driver) != 0) {
+ g_free (priv->driver);
+ priv->driver = g_strdup (info->driver);
+ g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
+ }
+
if (info->name[0] && strcmp (priv->iface, info->name) != 0) {
_LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'",
priv->ifindex, priv->iface, info->name);
@@ -1336,15 +1350,6 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
nm_device_emit_recheck_auto_activate (self);
}
- /* Update slave status for external changes */
- if (priv->enslaved && info->master != nm_device_get_ifindex (priv->master))
- nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE);
- if (info->master && !priv->enslaved) {
- device_set_master (self, info->master);
- if (priv->master)
- nm_device_enslave_slave (priv->master, self, NULL);
- }
-
if (priv->rdisc && nm_platform_link_get_ipv6_token (NM_PLATFORM_GET, priv->ifindex, &token_iid)) {
_LOGD (LOGD_DEVICE, "IPv6 tokenized identifier present on device %s", priv->iface);
if (nm_rdisc_set_iid (priv->rdisc, token_iid))
@@ -1452,9 +1457,10 @@ link_changed_cb (NMPlatform *platform,
* and it results in also setting IFF_LOWER_UP.
*/
- if (ifindex == nm_device_get_ifindex (self))
+ if (ifindex == nm_device_get_ifindex (self)) {
device_link_changed (self, info);
- else if (ifindex == nm_device_get_ip_ifindex (self))
+ device_recheck_slave_status (self, info);
+ } else if (ifindex == nm_device_get_ip_ifindex (self))
device_ip_link_changed (self, info);
}
@@ -1473,7 +1479,8 @@ link_changed (NMDevice *self, NMPlatformLink *info)
* @plink: an existing platform link or %NULL
* @error: location to store error, or %NULL
*
- * Initializes and sets up the device using existing backing resources.
+ * Initializes and sets up the device using existing backing resources. Before
+ * the device is ready for use nm_device_setup_finish() must be called.
*
* Returns: %TRUE on success, %FALSE on error
*/
@@ -1486,7 +1493,7 @@ nm_device_realize (NMDevice *self, NMPlatformLink *plink, GError **error)
return FALSE;
}
- NM_DEVICE_GET_CLASS (self)->setup (self, plink);
+ NM_DEVICE_GET_CLASS (self)->setup_start (self, plink);
return TRUE;
}
@@ -1517,7 +1524,8 @@ nm_device_create_and_realize (NMDevice *self,
return FALSE;
}
- NM_DEVICE_GET_CLASS (self)->setup (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL);
+ NM_DEVICE_GET_CLASS (self)->setup_start (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL);
+ NM_DEVICE_GET_CLASS (self)->setup_finish (self, (plink.type != NM_LINK_TYPE_UNKNOWN) ? &plink : NULL);
g_warn_if_fail (nm_device_check_connection_compatible (self, connection));
return TRUE;
@@ -1539,6 +1547,7 @@ update_device_from_platform_link (NMDevice *self, NMPlatformLink *plink)
if (plink->driver && g_strcmp0 (plink->driver, priv->driver) != 0) {
g_free (priv->driver);
priv->driver = g_strdup (plink->driver);
+ g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
}
priv->platform_link_initialized = plink->initialized;
}
@@ -1567,7 +1576,7 @@ check_carrier (NMDevice *self)
}
static void
-setup (NMDevice *self, NMPlatformLink *plink)
+setup_start (NMDevice *self, NMPlatformLink *plink)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
static guint32 id = 0;
@@ -1584,7 +1593,7 @@ setup (NMDevice *self, NMPlatformLink *plink)
}
if (priv->ifindex > 0) {
- _LOGD (LOGD_DEVICE, "setup(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex);
+ _LOGD (LOGD_DEVICE, "setup_start(): %s, kernel ifindex %d", G_OBJECT_TYPE_NAME (self), priv->ifindex);
priv->physical_port_id = nm_platform_link_get_physical_port_id (NM_PLATFORM_GET, priv->ifindex);
priv->dev_id = nm_platform_link_get_dev_id (NM_PLATFORM_GET, priv->ifindex);
if (nm_platform_link_is_software (NM_PLATFORM_GET, priv->ifindex))
@@ -1667,15 +1676,26 @@ setup (NMDevice *self, NMPlatformLink *plink)
g_object_notify (G_OBJECT (self), NM_DEVICE_CAPABILITIES);
- /* Enslave ourselves */
- if (priv->ifindex > 0) {
- int master = nm_platform_link_get_master (NM_PLATFORM_GET, priv->ifindex);
+ priv->real = TRUE;
+}
- if (master > 0)
- device_set_master (self, master);
+static void
+setup_finish (NMDevice *self, NMPlatformLink *plink)
+{
+ if (plink) {
+ update_device_from_platform_link (self, plink);
+ device_recheck_slave_status (self, plink);
}
+}
- priv->real = TRUE;
+void
+nm_device_setup_finish (NMDevice *self, NMPlatformLink *plink)
+{
+ NM_DEVICE_GET_CLASS (self)->setup_finish (self, plink);
+
+ nm_device_recheck_available_connections (self);
+
+ NM_DEVICE_GET_PRIVATE (self)->real = TRUE;
g_object_notify (G_OBJECT (self), NM_DEVICE_REAL);
g_object_thaw_notify (G_OBJECT (self));
@@ -7534,6 +7554,7 @@ nm_device_check_connection_available (NMDevice *self,
&& nm_device_get_unmanaged_flag (self, NM_UNMANAGED_ALL & ~NM_UNMANAGED_DEFAULT))
return FALSE;
if ( state < NM_DEVICE_STATE_DISCONNECTED
+ && !nm_device_is_software (self)
&& ( ( !NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
&& !nm_device_is_available (self, NM_DEVICE_CHECK_DEV_AVAILABLE_NONE))
|| ( NM_FLAGS_HAS (flags, _NM_DEVICE_CHECK_CON_AVAILABLE_FOR_USER_REQUEST_WAITING_CARRIER)
@@ -9208,7 +9229,8 @@ nm_device_class_init (NMDeviceClass *klass)
klass->check_connection_compatible = check_connection_compatible;
klass->check_connection_available = check_connection_available;
klass->can_unmanaged_external_down = can_unmanaged_external_down;
- klass->setup = setup;
+ klass->setup_start = setup_start;
+ klass->setup_finish = setup_finish;
klass->unrealize = unrealize;
klass->is_up = is_up;
klass->bring_up = bring_up;
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 5f87e0da07..47529e1fcb 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -174,14 +174,28 @@ typedef struct {
GError **error);
/**
- * setup():
+ * setup_start():
* @self: the #NMDevice
* @plink: the #NMPlatformLink if backed by a kernel netdevice
*
* Update the device from backing resource properties (like hardware
- * addresses, carrier states, driver/firmware info, etc).
+ * addresses, carrier states, driver/firmware info, etc). This function
+ * should only change properties for this device, and should not perform
+ * any tasks that affect other interfaces (like master/slave or parent/child
+ * stuff).
*/
- void (*setup) (NMDevice *self, NMPlatformLink *plink);
+ void (*setup_start) (NMDevice *self, NMPlatformLink *plink);
+
+ /**
+ * setup_finish():
+ * @self: the #NMDevice
+ * @plink: the #NMPlatformLink if backed by a kernel netdevice
+ *
+ * Update the device's master/slave or parent/child relationships from
+ * backing resource properties. After this function finishes, the device
+ * is ready for network connectivity.
+ */
+ void (*setup_finish) (NMDevice *self, NMPlatformLink *plink);
/**
* unrealize():
@@ -465,6 +479,8 @@ gboolean nm_device_create_and_realize (NMDevice *self,
NMConnection *connection,
NMDevice *parent,
GError **error);
+void nm_device_setup_finish (NMDevice *self,
+ NMPlatformLink *plink);
gboolean nm_device_unrealize (NMDevice *device,
gboolean remove_resources,
GError **error);
diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c
index 40f1f2a4ec..52c9f05865 100644
--- a/src/devices/wifi/nm-device-wifi.c
+++ b/src/devices/wifi/nm-device-wifi.c
@@ -449,9 +449,9 @@ periodic_update_cb (gpointer user_data)
}
static void
-setup (NMDevice *device, NMPlatformLink *plink)
+setup_start (NMDevice *device, NMPlatformLink *plink)
{
- NM_DEVICE_CLASS (nm_device_wifi_parent_class)->setup (device, plink);
+ NM_DEVICE_CLASS (nm_device_wifi_parent_class)->setup_start (device, plink);
g_object_notify (G_OBJECT (device), NM_DEVICE_WIFI_PERMANENT_HW_ADDRESS);
}
@@ -2970,7 +2970,7 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass)
object_class->dispose = dispose;
object_class->finalize = finalize;
- parent_class->setup = setup;
+ parent_class->setup_start = setup_start;
parent_class->bring_up = bring_up;
parent_class->can_auto_connect = can_auto_connect;
parent_class->is_available = is_available;
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index d0b5b8753f..2a8f53ace1 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -516,6 +516,7 @@ master_state_cb (NMActiveConnection *master,
{
NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
NMActiveConnectionState master_state = nm_active_connection_get_state (master);
+ NMDevice *master_device = nm_active_connection_get_device (master);
check_master_ready (self);
@@ -523,8 +524,8 @@ master_state_cb (NMActiveConnection *master,
self, master, state_to_string (master_state), master_state);
if (master_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATING &&
- nm_active_connection_get_device (master) == NULL) {
- /* Master failed without ever creating its device */
+ (!master_device || !nm_device_is_real (master_device))) {
+ /* Master failed without ever creating or realizing its device */
if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
}
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 158164d583..8c489b0133 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -113,7 +113,7 @@ static void impl_manager_check_connectivity (NMManager *manager,
#include "nm-manager-glue.h"
-static void add_device (NMManager *self, NMDevice *device, gboolean try_assume);
+static void add_device (NMManager *self, NMDevice *device);
static NMActiveConnection *_new_active_connection (NMManager *self,
NMConnection *connection,
@@ -163,8 +163,6 @@ typedef struct {
NMConfig *config;
NMConnectivity *connectivity;
- int ignore_link_added_cb;
-
NMPolicy *policy;
NMDBusManager *dbus_mgr;
@@ -521,8 +519,11 @@ find_device_by_ip_iface (NMManager *self, const gchar *iface)
g_return_val_if_fail (iface != NULL, NULL);
for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = g_slist_next (iter)) {
- if (g_strcmp0 (nm_device_get_ip_iface (NM_DEVICE (iter->data)), iface) == 0)
- return NM_DEVICE (iter->data);
+ NMDevice *candidate = iter->data;
+
+ if ( nm_device_is_real (candidate)
+ && g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0)
+ return candidate;
}
return NULL;
}
@@ -849,7 +850,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection)
return NULL;
/* Try as an interface name */
- parent = find_device_by_ip_iface (self, parent_name);
+ parent = find_device_by_iface (self, parent_name);
if (parent)
return parent;
@@ -964,10 +965,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDeviceFactory *factory;
- GSList *iter;
- char *iface = NULL;
+ GSList *connections, *iter;
+ gs_free char *iface = NULL;
NMDevice *device = NULL, *parent = NULL;
- gboolean nm_owned = FALSE;
g_return_val_if_fail (NM_IS_MANAGER (self), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
@@ -989,7 +989,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_FAILED,
"interface name '%s' already created", iface);
- goto out;
+ return NULL;
}
}
@@ -1003,80 +1003,59 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError
NM_MANAGER_ERROR_FAILED,
"NetworkManager plugin for '%s' unavailable",
nm_connection_get_connection_type (connection));
- goto out;
+ return NULL;
}
- /* Block notification of link added since we're creating the device
- * explicitly here, otherwise adding the platform/kernel device would
- * create it before this function can do the rest of the setup.
- */
- priv->ignore_link_added_cb++;
-
- nm_owned = !nm_platform_link_exists (NM_PLATFORM_GET, iface);
-
device = nm_device_factory_create_device (factory, iface, NULL, connection, NULL, error);
- if (device) {
- if (nm_device_create_and_realize (device, connection, parent, error)) {
- if (nm_owned)
- nm_device_set_nm_owned (device);
-
- /* If it was created by NM there's no connection to assume, but if it
- * previously existed there might be one.
- */
- add_device (self, device, !nm_owned);
- }
- g_clear_object (&device);
- }
-
- priv->ignore_link_added_cb--;
-
-out:
- g_free (iface);
- return device;
-}
-
-static void
-system_create_virtual_devices (NMManager *self)
-{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- GSList *iter, *connections;
+ if (!device)
+ return NULL;
- nm_log_dbg (LOGD_CORE, "creating virtual devices...");
+ if (!nm_platform_link_exists (NM_PLATFORM_GET, iface))
+ nm_device_set_nm_owned (device);
+ add_device (self, device);
+ g_object_unref (device);
+ /* Create backing resources if the device has any autoconnect connections */
connections = nm_settings_get_connections (priv->settings);
for (iter = connections; iter; iter = g_slist_next (iter)) {
- NMConnection *connection = iter->data;
+ NMConnection *candidate = iter->data;
+ NMSettingConnection *s_con;
+
+ if (!nm_device_check_connection_compatible (device, candidate))
+ continue;
+
+ s_con = nm_connection_get_setting_connection (candidate);
+ g_assert (s_con);
+ if (!nm_setting_connection_get_autoconnect (s_con))
+ continue;
- /* We only create a virtual interface if the connection can autoconnect */
- if ( nm_connection_is_virtual (connection)
- && nm_settings_connection_can_autoconnect (NM_SETTINGS_CONNECTION (connection)))
- system_create_virtual_device (self, connection, NULL);
+ /* Create any backing resources the device needs */
+ if (!nm_device_create_and_realize (device, connection, parent, error)) {
+ remove_device (self, device, FALSE, TRUE);
+ device = NULL;
+ }
+ break;
}
- g_slist_free (connections);
+
+ return device;
}
static void
connection_added (NMSettings *settings,
- NMSettingsConnection *settings_connection,
+ NMConnection *connection,
NMManager *manager)
{
- NMConnection *connection = NM_CONNECTION (settings_connection);
-
- if (nm_connection_is_virtual (connection)) {
- NMSettingConnection *s_con = nm_connection_get_setting_connection (connection);
-
- g_assert (s_con);
- if (nm_setting_connection_get_autoconnect (s_con))
- system_create_virtual_device (manager, connection, NULL);
- }
+ if (nm_connection_is_virtual (connection))
+ system_create_virtual_device (manager, connection, NULL);
}
static void
connection_changed (NMSettings *settings,
- NMSettingsConnection *connection,
+ NMConnection *connection,
NMManager *manager)
{
- /* FIXME: Some virtual devices may need to be updated in the future. */
+ if (nm_connection_is_virtual (connection))
+ system_create_virtual_device (manager, connection, NULL);
}
static void
@@ -1588,19 +1567,25 @@ assume_connection (NMManager *self, NMDevice *device, NMConnection *connection)
}
static gboolean
+can_start_device (NMManager *self, NMDevice *device)
+{
+ return nm_device_is_real (device)
+ && !manager_sleeping (self)
+ && !nm_device_get_unmanaged_flag (device, NM_UNMANAGED_USER)
+ && !nm_device_get_unmanaged_flag (device, NM_UNMANAGED_INTERNAL)
+ && !nm_device_get_unmanaged_flag (device, NM_UNMANAGED_EXTERNAL_DOWN)
+ && !nm_device_get_unmanaged_flag (device, NM_UNMANAGED_PARENT);
+}
+
+static gboolean
recheck_assume_connection (NMDevice *device, gpointer user_data)
{
NMManager *self = NM_MANAGER (user_data);
NMConnection *connection;
- gboolean was_unmanaged = FALSE, success, generated;
+ gboolean was_unmanaged = FALSE, success, generated = FALSE;
NMDeviceState state;
- if (manager_sleeping (self))
- return FALSE;
- if (nm_device_get_unmanaged_flag (device, NM_UNMANAGED_USER) ||
- nm_device_get_unmanaged_flag (device, NM_UNMANAGED_INTERNAL) ||
- nm_device_get_unmanaged_flag (device, NM_UNMANAGED_EXTERNAL_DOWN) ||
- nm_device_get_unmanaged_flag (device, NM_UNMANAGED_PARENT))
+ if (nm_device_get_is_nm_owned (device) || !can_start_device (self, device))
return FALSE;
state = nm_device_get_state (device);
@@ -1683,26 +1668,51 @@ notify_component_added (NMManager *self, GObject *component)
return FALSE;
}
+static void
+device_realized (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ int ifindex;
+ gboolean assumed;
+
+ /* Loopback device never gets managed */
+ ifindex = nm_device_get_ifindex (device);
+ if (ifindex > 0 && nm_platform_link_get_type (NM_PLATFORM_GET, ifindex) == NM_LINK_TYPE_LOOPBACK)
+ return;
+
+ if (!can_start_device (self, device))
+ return;
+
+ assumed = recheck_assume_connection (device, self);
+ if (!assumed && nm_device_get_managed (device)) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_UNAVAILABLE,
+ NM_DEVICE_STATE_REASON_NOW_MANAGED);
+ }
+
+ if (!nm_device_get_is_nm_owned (device)) {
+ g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME,
+ G_CALLBACK (recheck_assume_connection), self);
+ }
+}
+
/**
* add_device:
* @self: the #NMManager
* @device: the #NMDevice to add
- * @try_assume: %TRUE if existing connection (if any) should be assumed
*
* If successful, this function will increase the references count of @device.
* Callers should decrease the reference count.
*/
static void
-add_device (NMManager *self, NMDevice *device, gboolean try_assume)
+add_device (NMManager *self, NMDevice *device)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- const char *iface, *driver, *type_desc;
+ const char *iface, *type_desc;
const GSList *unmanaged_specs;
- gboolean user_unmanaged, sleeping;
- gboolean enabled = FALSE;
RfKillType rtype;
GSList *iter, *remove = NULL;
- gboolean connection_assumed = FALSE;
int ifindex;
/* No duplicates */
@@ -1745,6 +1755,9 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
g_signal_connect (device, "notify::" NM_DEVICE_IP_IFACE,
G_CALLBACK (device_ip_iface_changed),
self);
+ g_signal_connect (device, "notify::" NM_DEVICE_REAL,
+ G_CALLBACK (device_realized),
+ self);
if (priv->startup) {
g_signal_connect (device, "notify::" NM_DEVICE_HAS_PENDING_ACTION,
@@ -1759,57 +1772,32 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume)
rtype = nm_device_get_rfkill_type (device);
if (rtype != RFKILL_TYPE_UNKNOWN) {
nm_manager_rfkill_update (self, rtype);
- enabled = radio_enabled_for_type (self, rtype, TRUE);
- nm_device_set_enabled (device, enabled);
+ nm_device_set_enabled (device, radio_enabled_for_type (self, rtype, TRUE));
}
iface = nm_device_get_iface (device);
g_assert (iface);
-
type_desc = nm_device_get_type_desc (device);
g_assert (type_desc);
- driver = nm_device_get_driver (device);
- if (!driver)
- driver = "unknown";
- nm_log_info (LOGD_HW, "(%s): new %s device (carrier: %s, driver: '%s', ifindex: %d)",
- iface, type_desc,
- nm_device_has_capability (device, NM_DEVICE_CAP_CARRIER_DETECT)
- ? (nm_device_has_carrier (device) ? "ON" : "OFF")
- : "UNKNOWN",
- driver, nm_device_get_ifindex (device));
- unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
- user_unmanaged = nm_device_spec_match_list (device, unmanaged_specs);
- nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_USER, user_unmanaged);
+ nm_log_info (LOGD_HW, "(%s): new %s device", iface, type_desc);
- sleeping = manager_sleeping (self);
- nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_INTERNAL, sleeping);
+ unmanaged_specs = nm_settings_get_unmanaged_specs (priv->settings);
+ nm_device_set_initial_unmanaged_flag (device,
+ NM_UNMANAGED_USER,
+ nm_device_spec_match_list (device, unmanaged_specs));
+ nm_device_set_initial_unmanaged_flag (device,
+ NM_UNMANAGED_INTERNAL,
+ manager_sleeping (self));
nm_device_dbus_export (device);
nm_device_finish_init (device);
- if (try_assume) {
- connection_assumed = recheck_assume_connection (device, self);
- g_signal_connect (device, NM_DEVICE_RECHECK_ASSUME,
- G_CALLBACK (recheck_assume_connection), self);
- }
-
- if (!connection_assumed && nm_device_get_managed (device)) {
- nm_device_state_changed (device,
- NM_DEVICE_STATE_UNAVAILABLE,
- NM_DEVICE_STATE_REASON_NOW_MANAGED);
- }
-
nm_settings_device_added (priv->settings, device);
g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
g_object_notify (G_OBJECT (self), NM_MANAGER_DEVICES);
notify_component_added (self, G_OBJECT (device));
-
- /* New devices might be master interfaces for virtual interfaces; so we may
- * need to create new virtual interfaces now.
- */
- system_create_virtual_devices (self);
}
/*******************************************************************/
@@ -1821,9 +1809,10 @@ factory_device_added_cb (NMDeviceFactory *factory,
{
GError *error = NULL;
- if (nm_device_realize (device, NULL, &error))
- add_device (NM_MANAGER (user_data), device, TRUE);
- else {
+ if (nm_device_realize (device, NULL, &error)) {
+ add_device (NM_MANAGER (user_data), device);
+ nm_device_setup_finish (device, NULL);
+ } else {
nm_log_warn (LOGD_DEVICE, "(%s): %s", nm_device_get_iface (device), error->message);
g_error_free (error);
}
@@ -1860,7 +1849,6 @@ platform_link_added (NMManager *self,
NMPlatformLink *plink,
NMPlatformReason reason)
{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDeviceFactory *factory;
NMDevice *device = NULL;
GError *error = NULL;
@@ -1868,11 +1856,28 @@ platform_link_added (NMManager *self,
g_return_if_fail (ifindex > 0);
- if (priv->ignore_link_added_cb > 0)
+ if (nm_manager_get_device_by_ifindex (self, ifindex))
return;
- if (nm_manager_get_device_by_ifindex (self, ifindex))
+ device = find_device_by_iface (self, plink->name);
+ if (device) {
+ if (!nm_device_is_real (device)) {
+ if (nm_device_realize (device, plink, &error))
+ nm_device_setup_finish (device, plink);
+ else {
+ nm_log_warn (LOGD_DEVICE, "(%s): %s", plink->name, error->message);
+ g_clear_error (&error);
+ remove_device (self, device, FALSE, FALSE);
+ }
+ return;
+ } else if (!nm_device_realize (device, plink, &error)) {
+ nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s",
+ plink->name, error->message);
+ g_clear_error (&error);
+ return;
+ }
return;
+ }
/* Try registered device factories */
factory = nm_device_factory_manager_find_factory_for_link_type (plink->type);
@@ -1881,21 +1886,15 @@ platform_link_added (NMManager *self,
device = nm_device_factory_create_device (factory, plink->name, plink, NULL, &ignore, &error);
if (!device) {
- if (!ignore) {
- nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s",
- plink->name, error->message);
- g_clear_error (&error);
- }
- return;
- } else if (!nm_device_realize (device, plink, &error)) {
+ if (ignore)
+ return;
nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s",
plink->name, error->message);
g_clear_error (&error);
- return;
}
}
- if (device == NULL) {
+ if (!device) {
switch (plink->type) {
case NM_LINK_TYPE_WWAN_ETHERNET:
case NM_LINK_TYPE_BNEP:
@@ -1908,14 +1907,20 @@ platform_link_added (NMManager *self,
/* fall through */
default:
device = nm_device_generic_new (plink);
+ if (nm_plugin_missing)
+ nm_device_set_nm_plugin_missing (device, TRUE);
break;
}
}
if (device) {
- if (nm_plugin_missing)
- nm_device_set_nm_plugin_missing (device, TRUE);
- add_device (self, device, plink->type != NM_LINK_TYPE_LOOPBACK);
+ if (nm_device_realize (device, plink, &error)) {
+ add_device (self, device);
+ nm_device_setup_finish (device, plink);
+ } else {
+ nm_log_warn (LOGD_DEVICE, "(%s): %s", plink->name, error->message);
+ g_clear_error (&error);
+ }
g_object_unref (device);
}
}
@@ -1940,14 +1945,20 @@ platform_link_cb (NMPlatform *platform,
device = nm_manager_get_device_by_ifindex (self, ifindex);
if (!device)
break;
+
+ /* Software devices stick around until their connection is removed */
if (nm_device_is_software (device)) {
if (!nm_device_unrealize (device, FALSE, &error)) {
nm_log_warn (LOGD_DEVICE, "(%s): failed to unrealize: %s",
nm_device_get_iface (device),
error->message);
g_clear_error (&error);
+ remove_device (self, device, FALSE, TRUE);
}
+ break;
}
+
+ /* Hardware devices always get removed when their kernel link is gone */
remove_device (self, device, FALSE, TRUE);
break;
default:
@@ -2014,8 +2025,10 @@ impl_manager_get_devices (NMManager *manager, GPtrArray **devices, GError **err)
*devices = g_ptr_array_sized_new (g_slist_length (priv->devices));
- for (iter = priv->devices; iter; iter = iter->next)
- g_ptr_array_add (*devices, g_strdup (nm_device_get_path (NM_DEVICE (iter->data))));
+ for (iter = priv->devices; iter; iter = iter->next) {
+ if (nm_device_is_real (NM_DEVICE (iter->data)))
+ g_ptr_array_add (*devices, g_strdup (nm_device_get_path (NM_DEVICE (iter->data))));
+ }
return TRUE;
}
@@ -2116,7 +2129,7 @@ find_master (NMManager *self,
const char *master;
NMDevice *master_device = NULL;
NMConnection *master_connection = NULL;
- GSList *iter, *connections = NULL;
+ GSList *iter;
s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
@@ -2126,7 +2139,7 @@ find_master (NMManager *self,
return TRUE; /* success, but no master */
/* Try as an interface name first */
- master_device = find_device_by_ip_iface (self, master);
+ master_device = find_device_by_iface (self, master);
if (master_device) {
if (master_device == device) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
@@ -2158,23 +2171,6 @@ find_master (NMManager *self,
break;
}
}
- } else {
- /* Might be a virtual interface that hasn't been created yet, so
- * look through the interface names of connections that require
- * virtual interfaces and see if one of their virtual interface
- * names matches the master.
- */
- connections = nm_manager_get_activatable_connections (self);
- for (iter = connections; iter && !master_connection; iter = g_slist_next (iter)) {
- NMConnection *candidate = iter->data;
- char *vname;
-
- vname = get_virtual_iface_name (self, connection, NULL, NULL);
- if (g_strcmp0 (master, vname) == 0 && is_compatible_with_slave (candidate, connection))
- master_connection = candidate;
- g_free (vname);
- }
- g_slist_free (connections);
}
}
@@ -2268,7 +2264,7 @@ ensure_master_active_connection (NMManager *self,
/* If the device is disconnected, find a compatible connection and
* activate it on the device.
*/
- if (master_state == NM_DEVICE_STATE_DISCONNECTED) {
+ if (master_state == NM_DEVICE_STATE_DISCONNECTED || !nm_device_is_real (master_device)) {
GSList *connections;
g_assert (master_connection == NULL);
@@ -2329,9 +2325,11 @@ ensure_master_active_connection (NMManager *self,
continue;
found_device = TRUE;
- master_state = nm_device_get_state (candidate);
- if (master_state != NM_DEVICE_STATE_DISCONNECTED)
- continue;
+ if (!nm_device_is_software (candidate)) {
+ master_state = nm_device_get_state (candidate);
+ if (nm_device_is_real (candidate) && master_state != NM_DEVICE_STATE_DISCONNECTED)
+ continue;
+ }
master_ac = nm_manager_activate_connection (self,
master_connection,
@@ -2493,6 +2491,17 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
return FALSE;
}
+ /* Create any backing resources the device needs */
+ if (!nm_device_is_real (device)) {
+ NMDevice *parent;
+
+ parent = find_parent_device_for_connection (self, connection);
+ if (!nm_device_create_and_realize (device, connection, parent, error)) {
+ g_prefix_error (error, "%s failed to create resources: ", nm_device_get_iface (device));
+ return FALSE;
+ }
+ }
+
/* Try to find the master connection/device if the connection has a dependency */
if (!find_master (self, connection, device,
&master_connection, &master_device, &master_ac,
@@ -2861,7 +2870,7 @@ validate_activation_request (NMManager *self,
if (!iface)
goto error;
- device = find_device_by_ip_iface (self, iface);
+ device = find_device_by_iface (self, iface);
g_free (iface);
}
}
@@ -3932,6 +3941,7 @@ void
nm_manager_start (NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ GSList *iter, *connections;
guint i;
/* Set initial radio enabled/disabled state */
@@ -3967,11 +3977,14 @@ nm_manager_start (NMManager *self)
nm_platform_query_devices (NM_PLATFORM_GET);
- /*
- * Connections added before the manager is started do not emit
+ /* Connections added before the manager is started do not emit
* connection-added signals thus devices have to be created manually.
*/
- system_create_virtual_devices (self);
+ nm_log_dbg (LOGD_CORE, "creating virtual devices...");
+ connections = nm_settings_get_connections (priv->settings);
+ for (iter = connections; iter; iter = iter->next)
+ connection_added (priv->settings, NM_CONNECTION (iter->data), self);
+ g_slist_free (connections);
check_if_startup_complete (self);
}
@@ -4732,7 +4745,7 @@ get_property (GObject *object, guint prop_id,
array = g_ptr_array_sized_new (5);
for (iter = priv->devices; iter; iter = g_slist_next (iter)) {
path = nm_device_get_path (NM_DEVICE (iter->data));
- if (path)
+ if (path && nm_device_is_real (NM_DEVICE (iter->data)))
g_ptr_array_add (array, g_strdup (path));
}
g_value_take_boxed (value, array);
@@ -4827,6 +4840,7 @@ dispose (GObject *object)
g_clear_object (&priv->policy);
}
+ g_signal_handlers_disconnect_by_data (priv->settings, manager);
g_clear_object (&priv->settings);
g_free (priv->state_file);
g_clear_object (&priv->vpn_manager);