diff options
author | Dan Williams <dcbw@redhat.com> | 2014-09-24 16:58:07 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2015-05-15 09:46:38 -0500 |
commit | 4e20195e5769a76f628bf43c75c80c4ec884209f (patch) | |
tree | 021e92a77589fe77ddd75728606882de53175830 | |
parent | 2ac0e142300dbc81e04fc49199ad22a30ad640a9 (diff) | |
download | NetworkManager-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.c | 2 | ||||
-rw-r--r-- | src/devices/nm-device-ethernet.c | 6 | ||||
-rw-r--r-- | src/devices/nm-device-generic.c | 6 | ||||
-rw-r--r-- | src/devices/nm-device-infiniband.c | 5 | ||||
-rw-r--r-- | src/devices/nm-device-tun.c | 6 | ||||
-rw-r--r-- | src/devices/nm-device-vlan.c | 31 | ||||
-rw-r--r-- | src/devices/nm-device-vxlan.c | 6 | ||||
-rw-r--r-- | src/devices/nm-device.c | 96 | ||||
-rw-r--r-- | src/devices/nm-device.h | 22 | ||||
-rw-r--r-- | src/devices/wifi/nm-device-wifi.c | 6 | ||||
-rw-r--r-- | src/nm-active-connection.c | 5 | ||||
-rw-r--r-- | src/nm-manager.c | 330 |
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); |