From fb1d04099f445eda974cbf0dfb334b3718031cc7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 16 Oct 2014 15:01:16 -0500 Subject: [PATCH 01/14] core: don't activate failed queued activation requests If the queued activation request failed before the device is finished deactiving the old request, don't start activating the failed queued request. --- src/devices/nm-device.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f0ef6572e3..9e6d6d00e9 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5891,14 +5891,20 @@ impl_device_delete (NMDevice *self, DBusGMethodInvocation *context) NULL); } -static void +static gboolean _device_activate (NMDevice *self, NMActRequest *req) { NMDevicePrivate *priv; NMConnection *connection; - g_return_if_fail (NM_IS_DEVICE (self)); - g_return_if_fail (NM_IS_ACT_REQUEST (req)); + g_return_val_if_fail (NM_IS_DEVICE (self), FALSE); + g_return_val_if_fail (NM_IS_ACT_REQUEST (req), FALSE); + + /* Ensure the activation request is still valid; the master may have + * already failed in which case activation of this device should not proceed. + */ + if (nm_active_connection_get_state (NM_ACTIVE_CONNECTION (req)) >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) + return FALSE; priv = NM_DEVICE_GET_PRIVATE (self); @@ -5924,6 +5930,7 @@ _device_activate (NMDevice *self, NMActRequest *req) priv->act_request = g_object_ref (req); nm_device_activate_schedule_stage1_device_prepare (self); + return TRUE; } static void @@ -6019,7 +6026,8 @@ nm_device_queue_activation (NMDevice *self, NMActRequest *req) if (!priv->act_request && !must_queue) { /* Just activate immediately */ - _device_activate (self, req); + if (!_device_activate (self, req)) + g_assert_not_reached (); return; } @@ -8110,13 +8118,18 @@ _set_state_full (NMDevice *self, if ( priv->queued_act_request && !priv->queued_act_request_is_waiting_for_carrier) { NMActRequest *queued_req; + gboolean success; queued_req = priv->queued_act_request; priv->queued_act_request = NULL; - _device_activate (self, queued_req); + success = _device_activate (self, queued_req); g_object_unref (queued_req); - } else if ( old_state > NM_DEVICE_STATE_DISCONNECTED - && nm_device_get_default_unmanaged (self)) + if (success) + break; + /* fall through */ + } + if ( old_state > NM_DEVICE_STATE_DISCONNECTED + && nm_device_get_default_unmanaged (self)) nm_device_queue_state (self, NM_DEVICE_STATE_UNMANAGED, NM_DEVICE_STATE_REASON_NONE); break; case NM_DEVICE_STATE_ACTIVATED: From 77d01c909470058695c16ae0e22ccfd6e604df34 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 24 Sep 2014 14:42:51 -0500 Subject: [PATCH 02/14] settings: ignore incompatible connections when looking for existing ones beb18050 made this code run for all devices instead of just ethernet devices, which means any kind of connection gets compared to any device. But only compatible connections should be considered. --- src/settings/nm-settings.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 6100681502..2c0f8e3337 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -1590,6 +1590,9 @@ have_connection_for_device (NMSettings *self, NMDevice *device) NMConnection *connection = NM_CONNECTION (data); const char *ctype, *iface; + if (!nm_device_check_connection_compatible (device, connection)) + continue; + s_con = nm_connection_get_setting_connection (connection); iface = nm_setting_connection_get_interface_name (s_con); From baee9080b790830183fa74fd83f5bf9757f4ac78 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 May 2015 09:20:55 -0500 Subject: [PATCH 03/14] platform: recognize Bluetooth BNEP devices via DEVTYPE Instead of strcmp()-ing the device name, recognize these devices from their driver's DEVTYPE. --- src/nm-manager.c | 2 +- src/nm-types.h | 1 + src/platform/nm-linux-platform.c | 12 ++++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 0bb3b0efdd..fe80156712 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2187,7 +2187,7 @@ platform_link_added (NMManager *self, /* Ignore Bluetooth PAN interfaces; they are handled by their NMDeviceBt * parent and don't get a separate interface. */ - if (!strncmp (plink->name, "bnep", STRLEN ("bnep"))) + if (plink->type == NM_LINK_TYPE_BNEP) return; if (device == NULL) { diff --git a/src/nm-types.h b/src/nm-types.h index f22272d91f..1c0ba9b46a 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -101,6 +101,7 @@ typedef enum { NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, NM_LINK_TYPE_VXLAN, + NM_LINK_TYPE_BNEP, /* Bluetooth Ethernet emulation */ /* Software types with slaves */ NM_LINK_TYPE_BRIDGE = 0x10000 | 0x20000, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 0ef684d971..532fa4de4e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -881,6 +881,7 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, + { NM_LINK_TYPE_BNEP, "bluetooth", NULL, "bluetooth" }, { NM_LINK_TYPE_BRIDGE, "bridge", "bridge", "bridge" }, { NM_LINK_TYPE_BOND, "bond", "bond", "bond" }, @@ -980,7 +981,6 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) else if (arptype == ARPHRD_INFINIBAND) return NM_LINK_TYPE_INFINIBAND; - ifname = rtnl_link_get_name (rtnllink); if (ifname) { const char *driver = ethtool_get_driver (ifname); @@ -1007,8 +1007,16 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) devtype = read_devtype (sysfs_path); for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) { - if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) + if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) { + if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) { + /* Both BNEP and 6lowpan use DEVTYPE=bluetooth, so we must + * use arptype to distinguish between them. + */ + if (arptype != ARPHRD_ETHER) + continue; + } return linktypes[i].nm_type; + } } /* Fallback for drivers that don't call SET_NETDEV_DEVTYPE() */ From 477cbc848af27f0eccf59092873d75e5a50552c1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 29 Apr 2015 10:06:51 +0200 Subject: [PATCH 04/14] trivial: move code --- src/devices/nm-device-vlan.c | 83 +++++++++++++++++------------------- 1 file changed, 39 insertions(+), 44 deletions(-) diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 34fa585488..b2a2fbf5f4 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -107,6 +107,45 @@ bring_up (NMDevice *dev, gboolean *no_firmware) /******************************************************************/ +static void +parent_state_changed (NMDevice *parent, + NMDeviceState new_state, + NMDeviceState old_state, + NMDeviceStateReason reason, + gpointer user_data) +{ + NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); + + /* We'll react to our own carrier state notifications. Ignore the parent's. */ + if (reason == NM_DEVICE_STATE_REASON_CARRIER) + return; + + nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); +} + +static void +nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent) +{ + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); + + if (priv->parent_state_id) { + g_signal_handler_disconnect (priv->parent, priv->parent_state_id); + priv->parent_state_id = 0; + } + g_clear_object (&priv->parent); + + if (parent) { + priv->parent = g_object_ref (parent); + priv->parent_state_id = g_signal_connect (priv->parent, + "state-changed", + G_CALLBACK (parent_state_changed), + device); + } + g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); +} + +/******************************************************************/ + static gboolean match_parent (NMDeviceVlan *self, const char *parent) { @@ -239,32 +278,6 @@ complete_connection (NMDevice *device, return TRUE; } -static void parent_state_changed (NMDevice *parent, NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data); - -static void -nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); - - if (priv->parent_state_id) { - g_signal_handler_disconnect (priv->parent, priv->parent_state_id); - priv->parent_state_id = 0; - } - g_clear_object (&priv->parent); - - if (parent) { - priv->parent = g_object_ref (parent); - priv->parent_state_id = g_signal_connect (priv->parent, - "state-changed", - G_CALLBACK (parent_state_changed), - device); - } - g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); -} - static void update_connection (NMDevice *device, NMConnection *connection) { @@ -396,24 +409,6 @@ deactivate (NMDevice *device) /******************************************************************/ -static void -parent_state_changed (NMDevice *parent, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason, - gpointer user_data) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); - - /* We'll react to our own carrier state notifications. Ignore the parent's. */ - if (reason == NM_DEVICE_STATE_REASON_CARRIER) - return; - - nm_device_set_unmanaged (NM_DEVICE (self), NM_UNMANAGED_PARENT, !nm_device_get_managed (parent), reason); -} - -/******************************************************************/ - static void nm_device_vlan_init (NMDeviceVlan * self) { From cd3df12c8f8ed6c868c12bc4e7fe6ba162dafc5b Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 13 Apr 2015 11:43:12 -0500 Subject: [PATCH 05/14] vlan: don't fail if parent isn't found at construct time for existing devices For existing devices, depending on the order that netlink sends interfaces to us, the parent may be found after the VLAN interface and not be available when the VLAN interface is constructed. Instead of failing construction, when a NMDeviceVlan has no parent keep it unavailable for activation. Then have the Manager notify existing devices when a new device is found, and let NMDeviceVlan find the parent later and become available via that mechanism. This doesn't apply to VLANs created by NM itself, because the kernel requires a parent ifindex when creating a VLAN device. Thus this fix only applies to VLANs created outside NetworkManager, or existing when NM starts up. --- introspection/nm-device.xml | 10 +++ libnm-core/nm-dbus-interface.h | 4 ++ libnm-util/NetworkManager.h | 4 ++ src/devices/nm-device-vlan.c | 108 +++++++++++++++++++++++++-------- src/devices/nm-device.h | 15 +++++ src/nm-manager.c | 23 ++++--- 6 files changed, 131 insertions(+), 33 deletions(-) diff --git a/introspection/nm-device.xml b/introspection/nm-device.xml index 7aef2f35b1..71b830f108 100644 --- a/introspection/nm-device.xml +++ b/introspection/nm-device.xml @@ -648,6 +648,16 @@ A new connection activation was enqueued. + + + The device's parent changed. + + + + + The device parent's management changed. + + diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 9bab80f354..ccc3b3a9e9 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -467,6 +467,8 @@ typedef enum { * @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available * @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect * @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued + * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed + * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed * * Device state change reason codes * @@ -534,6 +536,8 @@ typedef enum { NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58, NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59, NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60, + NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61, + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62, } NMDeviceStateReason; diff --git a/libnm-util/NetworkManager.h b/libnm-util/NetworkManager.h index 5a98b8e496..4fa861e88f 100644 --- a/libnm-util/NetworkManager.h +++ b/libnm-util/NetworkManager.h @@ -472,6 +472,8 @@ typedef enum { * @NM_DEVICE_STATE_REASON_MODEM_AVAILABLE: Modem now ready and available * @NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT: SIM PIN was incorrect * @NM_DEVICE_STATE_REASON_NEW_ACTIVATION: New connection activation was enqueued + * @NM_DEVICE_STATE_REASON_PARENT_CHANGED: the device's parent changed + * @NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED: the device parent's management changed * * Device state change reason codes * @@ -539,6 +541,8 @@ typedef enum { NM_DEVICE_STATE_REASON_MODEM_AVAILABLE = 58, NM_DEVICE_STATE_REASON_SIM_PIN_INCORRECT = 59, NM_DEVICE_STATE_REASON_NEW_ACTIVATION = 60, + NM_DEVICE_STATE_REASON_PARENT_CHANGED = 61, + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED = 62, NM_DEVICE_STATE_REASON_LAST = 0xFFFF } NMDeviceStateReason; diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index b2a2fbf5f4..5513d73abb 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -107,6 +107,15 @@ bring_up (NMDevice *dev, gboolean *no_firmware) /******************************************************************/ +static gboolean +is_available (NMDevice *device, NMDeviceCheckDevAvailableFlags flags) +{ + if (!NM_DEVICE_VLAN_GET_PRIVATE (device)->parent) + return FALSE; + + return NM_DEVICE_CLASS (nm_device_vlan_parent_class)->is_available (device, flags); +} + static void parent_state_changed (NMDevice *parent, NMDeviceState new_state, @@ -124,9 +133,13 @@ parent_state_changed (NMDevice *parent, } static void -nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent) +nm_device_vlan_set_parent (NMDeviceVlan *self, NMDevice *parent, gboolean construct) { - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); + NMDevice *device = NM_DEVICE (self); + + if (parent == priv->parent) + return; if (priv->parent_state_id) { g_signal_handler_disconnect (priv->parent, priv->parent_state_id); @@ -140,10 +153,56 @@ nm_device_vlan_set_parent (NMDeviceVlan *device, NMDevice *parent) "state-changed", G_CALLBACK (parent_state_changed), device); + + /* Set parent-dependent unmanaged flag */ + if (construct) { + nm_device_set_initial_unmanaged_flag (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent)); + } else { + nm_device_set_unmanaged (device, + NM_UNMANAGED_PARENT, + !nm_device_get_managed (parent), + NM_DEVICE_STATE_REASON_PARENT_MANAGED_CHANGED); + } } + + /* Recheck availability now that the parent has changed */ + nm_device_queue_recheck_available (self, + NM_DEVICE_STATE_REASON_PARENT_CHANGED, + NM_DEVICE_STATE_REASON_PARENT_CHANGED); g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_PARENT); } +static gboolean +component_added (NMDevice *device, GObject *component) +{ + NMDeviceVlan *self = NM_DEVICE_VLAN (device); + NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); + NMDevice *added_device; + int parent_ifindex = -1; + + if (priv->parent) + return FALSE; + + if (!NM_IS_DEVICE (component)) + return FALSE; + added_device = NM_DEVICE (component); + + if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) { + _LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component."); + return FALSE; + } + + if (nm_device_get_ifindex (added_device) != parent_ifindex) + return FALSE; + + nm_device_vlan_set_parent (self, added_device, FALSE); + + /* Don't claim parent exclusively */ + return FALSE; +} + /******************************************************************/ static gboolean @@ -153,6 +212,9 @@ match_parent (NMDeviceVlan *self, const char *parent) g_return_val_if_fail (parent != NULL, FALSE); + if (!priv->parent) + return FALSE; + if (nm_utils_is_uuid (parent)) { NMActRequest *parent_req; NMConnection *parent_connection; @@ -309,8 +371,7 @@ update_connection (NMDevice *device, NMConnection *connection) parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); g_assert (parent); - if (priv->parent != parent) - nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE); /* Update parent in the connection; default to parent's interface name */ new_parent = nm_device_get_iface (parent); @@ -426,12 +487,6 @@ constructed (GObject *object) if (G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed) G_OBJECT_CLASS (nm_device_vlan_parent_class)->constructed (object); - if (!priv->parent) { - _LOGE (LOGD_VLAN, "no parent specified."); - priv->invalid = TRUE; - return; - } - itype = nm_platform_link_get_type (NM_PLATFORM_GET, ifindex); if (itype != NM_LINK_TYPE_VLAN) { _LOGE (LOGD_VLAN, "failed to get VLAN interface type."); @@ -445,18 +500,27 @@ constructed (GObject *object) return; } - if ( parent_ifindex < 0 - || parent_ifindex != nm_device_get_ip_ifindex (priv->parent) - || vlan_id < 0) { + if (parent_ifindex < 0 || vlan_id < 0) { _LOGW (LOGD_VLAN, "VLAN parent ifindex (%d) or VLAN ID (%d) invalid.", parent_ifindex, priv->vlan_id); priv->invalid = TRUE; return; } + if (priv->parent && parent_ifindex != nm_device_get_ip_ifindex (priv->parent)) { + _LOGW (LOGD_VLAN, "VLAN parent %s (%d) and parent ifindex %d don't match.", + nm_device_get_iface (priv->parent), + nm_device_get_ifindex (priv->parent), + parent_ifindex); + priv->invalid = TRUE; + return; + } + priv->vlan_id = vlan_id; - _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s", - priv->vlan_id, nm_device_get_iface (priv->parent)); + _LOGI (LOGD_HW | LOGD_VLAN, "VLAN ID %d with parent %s (%d)", + priv->vlan_id, + priv->parent ? nm_device_get_iface (priv->parent) : "unknown", + parent_ifindex); } static void @@ -489,7 +553,7 @@ set_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_INT_PARENT_DEVICE: - nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value)); + nm_device_vlan_set_parent (NM_DEVICE_VLAN (object), g_value_get_object (value), TRUE); break; case PROP_VLAN_ID: priv->vlan_id = g_value_get_uint (value); @@ -512,7 +576,7 @@ dispose (GObject *object) } priv->disposed = TRUE; - nm_device_vlan_set_parent (self, NULL); + nm_device_vlan_set_parent (self, NULL, FALSE); G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object); } @@ -551,6 +615,8 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) parent_class->act_stage1_prepare = act_stage1_prepare; parent_class->ip4_config_pre_commit = ip4_config_pre_commit; parent_class->deactivate = deactivate; + parent_class->is_available = is_available; + parent_class->component_added = component_added; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; @@ -626,10 +692,6 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) device = NULL; } - /* Set initial parent-dependent unmanaged flag */ - if (device) - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent)); - return device; } @@ -682,10 +744,6 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, device = NULL; } - /* Set initial parent-dependent unmanaged flag */ - if (device) - nm_device_set_initial_unmanaged_flag (device, NM_UNMANAGED_PARENT, !nm_device_get_managed (parent)); - return device; } diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index f7ba2a5296..e3daa9b615 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -237,6 +237,21 @@ typedef struct { gboolean (* have_any_ready_slaves) (NMDevice *self, const GSList *slaves); + /** + * component_added: + * @self: the #NMDevice + * @component: the component (device, modem, etc) which was added + * + * Notifies @self that a new component was added to the Manager. This + * may include any kind of %GObject subclass, and the device is expected + * to match only specific components they care about, like %NMModem objects + * or %NMDevice objects. + * + * Returns: %TRUE if the component was claimed exclusively and no further + * devices should be notified of the new component. %FALSE to indicate + * that the component was not exclusively claimed and other devices should + * be notified. + */ gboolean (* component_added) (NMDevice *self, GObject *component); gboolean (* owns_iface) (NMDevice *self, const char *iface); diff --git a/src/nm-manager.c b/src/nm-manager.c index fe80156712..755b1f1916 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1776,6 +1776,18 @@ device_ip_iface_changed (NMDevice *device, } } +static gboolean +notify_component_added (NMManager *self, GObject *component) +{ + GSList *iter; + + for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { + if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) + return TRUE; + } + return FALSE; +} + /** * add_device: * @self: the #NMManager @@ -1893,6 +1905,8 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) 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. */ @@ -1929,14 +1943,7 @@ factory_component_added_cb (NMDeviceFactory *factory, GObject *component, gpointer user_data) { - NMManager *self = NM_MANAGER (user_data); - GSList *iter; - - for (iter = NM_MANAGER_GET_PRIVATE (self)->devices; iter; iter = iter->next) { - if (nm_device_notify_component_added (NM_DEVICE (iter->data), component)) - return TRUE; - } - return FALSE; + return notify_component_added (NM_MANAGER (user_data), component); } #define PLUGIN_PREFIX "libnm-device-plugin-" From 71bde20c302ba321688f203a8c5cd1e2d296f0d1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 17 Sep 2014 14:17:30 -0500 Subject: [PATCH 06/14] core: let device plugins advertise supported link and setting types Instead of looping over all plugins and asking each plugin whether it can handle a link or a connection, have them advertise the link and connection types they support, and use that when creating new devices. --- src/devices/adsl/nm-atm-manager.c | 11 +- src/devices/bluetooth/nm-bluez-manager.c | 11 +- src/devices/nm-device-bond.c | 39 +-- src/devices/nm-device-bridge.c | 39 +-- src/devices/nm-device-ethernet.c | 19 +- src/devices/nm-device-factory.c | 402 +++++++++++++++++++++-- src/devices/nm-device-factory.h | 83 +++-- src/devices/nm-device-gre.c | 18 +- src/devices/nm-device-infiniband.c | 35 +- src/devices/nm-device-macvlan.c | 18 +- src/devices/nm-device-tun.c | 11 +- src/devices/nm-device-veth.c | 18 +- src/devices/nm-device-vlan.c | 50 ++- src/devices/nm-device-vxlan.c | 18 +- src/devices/team/nm-device-team.c | 18 +- src/devices/team/nm-team-factory.c | 19 +- src/devices/wifi/nm-wifi-factory.c | 15 +- src/devices/wwan/nm-wwan-factory.c | 13 +- src/nm-manager.c | 311 +++--------------- 19 files changed, 653 insertions(+), 495 deletions(-) diff --git a/src/devices/adsl/nm-atm-manager.c b/src/devices/adsl/nm-atm-manager.c index 6f34c02bbd..0830f85d15 100644 --- a/src/devices/adsl/nm-atm-manager.c +++ b/src/devices/adsl/nm-atm-manager.c @@ -25,6 +25,7 @@ #include #include "nm-atm-manager.h" +#include "nm-setting-adsl.h" #include "nm-device-adsl.h" #include "nm-device-factory.h" #include "nm-logging.h" @@ -203,11 +204,9 @@ handle_uevent (GUdevClient *client, adsl_remove (self, device); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_ADSL; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_ADSL_SETTING_NAME) +) /*********************************************************************/ @@ -224,7 +223,7 @@ nm_atm_manager_init (NMAtmManager *self) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; factory_iface->start = start; } diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index 6b0de9949a..d325f44c8c 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -29,6 +29,7 @@ #include "nm-logging.h" #include "nm-bluez-manager.h" #include "nm-device-factory.h" +#include "nm-setting-bluetooth.h" #include "nm-bluez4-manager.h" #include "nm-bluez5-manager.h" #include "nm-bluez-device.h" @@ -367,11 +368,9 @@ start (NMDeviceFactory *factory) check_bluez_and_try_setup (NM_BLUEZ_MANAGER (factory)); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_BT; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BLUETOOTH_SETTING_NAME) +) /*********************************************************************/ @@ -407,7 +406,7 @@ nm_bluez_manager_init (NMBluezManager *self) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; factory_iface->start = start; } diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index b41bd14eee..3356125b7c 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -555,16 +555,13 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_BOND) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bonding", - NM_DEVICE_TYPE_DESC, "Bond", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, - NM_DEVICE_IS_MASTER, TRUE, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_DRIVER, "bonding", + NM_DEVICE_TYPE_DESC, "Bond", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, + NM_DEVICE_IS_MASTER, TRUE, + NULL); } static NMDevice * @@ -573,19 +570,17 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - const char *iface; + const char *iface = nm_connection_get_interface_name (connection); - if (!nm_connection_is_type (connection, NM_SETTING_BOND_SETTING_NAME)) - return NULL; - - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface) - && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_BOND, "(%s): failed to create bonding master interface for '%s': %s", - iface, nm_connection_get_id (connection), - nm_platform_get_error_msg (NM_PLATFORM_GET)); + && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bond interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -598,7 +593,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(BOND, Bond, bond, +NM_DEVICE_FACTORY_DEFINE_INTERNAL (BOND, Bond, bond, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BOND) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BOND_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index 0d9a76c466..f5219b02dd 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -479,16 +479,13 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_BRIDGE) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_DRIVER, "bridge", - NM_DEVICE_TYPE_DESC, "Bridge", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, - NM_DEVICE_IS_MASTER, TRUE, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_DRIVER, "bridge", + NM_DEVICE_TYPE_DESC, "Bridge", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE, + NM_DEVICE_IS_MASTER, TRUE, + NULL); } static NMDevice * @@ -497,21 +494,15 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - const char *iface; + const char *iface = nm_connection_get_interface_name (connection); NMSettingBridge *s_bridge; const char *mac_address_str; guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; - if (!nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME)) - return NULL; - - g_return_val_if_fail (connection != NULL, NULL); - - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); s_bridge = nm_connection_get_setting_bridge (connection); - g_return_val_if_fail (s_bridge, NULL); + g_assert (s_bridge); mac_address_str = nm_setting_bridge_get_mac_address (s_bridge); if (mac_address_str) { @@ -524,8 +515,10 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, mac_address_str ? mac_address : NULL, mac_address_str ? ETH_ALEN : 0) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_BRIDGE, "(%s): failed to create bridge master interface for '%s': %s", - iface, nm_connection_get_id (connection), + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create bridge interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -539,7 +532,9 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(BRIDGE, Bridge, bridge, +NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index bce1cef7f0..a728bf2394 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1757,17 +1757,16 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_ETHERNET) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Ethernet", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Ethernet", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(ETHERNET, Ethernet, ethernet, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (ETHERNET, Ethernet, ethernet, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_ETHERNET) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_PPPOE_SETTING_NAME), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index abfb8d4a67..9957efdc33 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -19,8 +19,19 @@ */ #include "config.h" +#include +#include +#include +#include + +#include #include "nm-device-factory.h" +#include "nm-logging.h" +#include "nm-platform.h" + +const NMLinkType _nm_device_factory_no_default_links[] = { NM_LINK_TYPE_NONE }; +const char *_nm_device_factory_no_default_settings[] = { NULL }; enum { DEVICE_ADDED, @@ -29,21 +40,6 @@ enum { }; static guint signals[LAST_SIGNAL] = { 0 }; -static GSList *internal_types = NULL; - -void -_nm_device_factory_internal_register_type (GType factory_type) -{ - g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL); - internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type)); -} - -const GSList * -nm_device_factory_get_internal_factory_types (void) -{ - return internal_types; -} - gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component) { @@ -108,12 +104,24 @@ nm_device_factory_get_type (void) return device_factory_type; } -NMDeviceType -nm_device_factory_get_device_type (NMDeviceFactory *factory) +void +nm_device_factory_get_supported_types (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types) { - g_return_val_if_fail (factory != NULL, NM_DEVICE_TYPE_UNKNOWN); + const NMLinkType *link_types_fallback; + const char **setting_types_fallback; - return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_device_type (factory); + g_return_if_fail (factory != NULL); + + if (!out_link_types) + out_link_types = &link_types_fallback; + if (!out_setting_types) + out_setting_types = &setting_types_fallback; + + NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_supported_types (factory, + out_link_types, + out_setting_types); } void @@ -130,12 +138,38 @@ nm_device_factory_new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { + NMDeviceFactory *interface; + const NMLinkType *link_types = NULL; + const char **setting_types = NULL; + int i; + g_return_val_if_fail (factory != NULL, NULL); g_return_val_if_fail (plink != NULL, NULL); - if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link) - return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->new_link (factory, plink, error); - return NULL; + /* Ensure the factory can create interfaces for this connection */ + nm_device_factory_get_supported_types (factory, &link_types, &setting_types); + for (i = 0; link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + if (plink->type == link_types[i]) + break; + } + + if (link_types[i] == NM_LINK_TYPE_UNKNOWN) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Device factory %s does not support link type %s (%d)", + G_OBJECT_TYPE_NAME (factory), + plink->kind, plink->type); + return NULL; + } + + interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); + if (!interface->new_link) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "Device factory %s cannot manage new devices", + G_OBJECT_TYPE_NAME (factory)); + return NULL; + } + + return interface->new_link (factory, plink, error); } NMDevice * @@ -145,14 +179,334 @@ nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory GError **error) { NMDeviceFactory *interface; + const char **setting_types = NULL; + gboolean found = FALSE; + int i; g_return_val_if_fail (factory, NULL); g_return_val_if_fail (connection, NULL); g_return_val_if_fail (!error || !*error, NULL); + /* Ensure the factory can create interfaces for this connection */ + nm_device_factory_get_supported_types (factory, NULL, &setting_types); + for (i = 0; setting_types && setting_types[i]; i++) { + if (nm_connection_is_type (connection, setting_types[i])) { + found = TRUE; + break; + } + } + + if (!found) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION, + "Device factory %s does not support connection type %s", + G_OBJECT_TYPE_NAME (factory), + nm_connection_get_connection_type (connection)); + return NULL; + } + interface = NM_DEVICE_FACTORY_GET_INTERFACE (factory); - if (interface->create_virtual_device_for_connection) - return interface->create_virtual_device_for_connection (factory, connection, parent, error); + if (!interface->create_virtual_device_for_connection) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "Device factory %s cannot create virtual devices", + G_OBJECT_TYPE_NAME (factory)); + return NULL; + } + + return interface->create_virtual_device_for_connection (factory, connection, parent, error); +} + +/*******************************************************************/ + +static GSList *internal_types = NULL; +static GHashTable *factories_by_link = NULL; +static GHashTable *factories_by_setting = NULL; + +void +_nm_device_factory_internal_register_type (GType factory_type) +{ + g_return_if_fail (g_slist_find (internal_types, GUINT_TO_POINTER (factory_type)) == NULL); + internal_types = g_slist_prepend (internal_types, GUINT_TO_POINTER (factory_type)); +} + +static void __attribute__((destructor)) +_cleanup (void) +{ + g_clear_pointer (&internal_types, g_slist_free); + g_clear_pointer (&factories_by_link, g_hash_table_unref); + g_clear_pointer (&factories_by_setting, g_hash_table_unref); +} + +static NMDeviceFactory * +find_factory (const NMLinkType *needle_link_types, + const char **needle_setting_types) +{ + NMDeviceFactory *found; + guint i; + + g_return_val_if_fail (factories_by_link, NULL); + g_return_val_if_fail (factories_by_setting, NULL); + + /* NMLinkType search */ + for (i = 0; needle_link_types && needle_link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) { + found = g_hash_table_lookup (factories_by_link, GUINT_TO_POINTER (needle_link_types[i])); + if (found) + return found; + } + + /* NMSetting name search */ + for (i = 0; needle_setting_types && needle_setting_types[i]; i++) { + found = g_hash_table_lookup (factories_by_setting, needle_setting_types[i]); + if (found) + return found; + } + return NULL; } +NMDeviceFactory * +nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type) +{ + const NMLinkType ltypes[2] = { link_type, NM_LINK_TYPE_NONE }; + + g_assert (ltypes[0] > NM_LINK_TYPE_UNKNOWN); + return find_factory (ltypes, NULL); +} + +NMDeviceFactory * +nm_device_factory_manager_find_factory_for_connection (NMConnection *connection) +{ + const char *stypes[2] = { nm_connection_get_connection_type (connection), NULL }; + + g_assert (stypes[0]); + return find_factory (NULL, stypes); +} + +void +nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + GHashTableIter iter; + NMDeviceFactory *factory; + GSList *list_iter, *list = NULL; + + g_return_if_fail (factories_by_link); + g_return_if_fail (factories_by_setting); + + g_hash_table_iter_init (&iter, factories_by_link); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } + + g_hash_table_iter_init (&iter, factories_by_setting); + while (g_hash_table_iter_next (&iter, NULL, (gpointer) &factory)) { + if (!g_slist_find (list, factory)) + list = g_slist_prepend (list, factory); + } + + for (list_iter = list; list_iter; list_iter = list_iter->next) + callback (list_iter->data, user_data); + + g_slist_free (list); +} + +#define PLUGIN_PREFIX "libnm-device-plugin-" +#define PLUGIN_PATH_TAG "NMManager-plugin-path" + +struct read_device_factory_paths_data { + char *path; + struct stat st; +}; + +static gint +read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b) +{ + const struct read_device_factory_paths_data *da = a; + const struct read_device_factory_paths_data *db = b; + time_t ta, tb; + + ta = MAX (da->st.st_mtime, da->st.st_ctime); + tb = MAX (db->st.st_mtime, db->st.st_ctime); + + if (ta < tb) + return 1; + if (ta > tb) + return -1; + return 0; +} + +static char** +read_device_factory_paths (void) +{ + GDir *dir; + GError *error = NULL; + const char *item; + GArray *paths; + char **result; + guint i; + + dir = g_dir_open (NMPLUGINDIR, 0, &error); + if (!dir) { + nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s", + NMPLUGINDIR, + (error && error->message) ? error->message : "(unknown)"); + g_clear_error (&error); + return NULL; + } + + paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data)); + + while ((item = g_dir_read_name (dir))) { + int errsv; + struct read_device_factory_paths_data data; + + if (!g_str_has_prefix (item, PLUGIN_PREFIX)) + continue; + if (g_str_has_suffix (item, ".la")) + continue; + + data.path = g_build_filename (NMPLUGINDIR, item, NULL); + + if (stat (data.path, &data.st) != 0) { + errsv = errno; + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv)); + goto NEXT; + } + if (!S_ISREG (data.st.st_mode)) + goto NEXT; + if (data.st.st_uid != 0) { + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path); + goto NEXT; + } + if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { + nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path); + goto NEXT; + } + + g_array_append_val (paths, data); + continue; +NEXT: + g_free (data.path); + } + g_dir_close (dir); + + /* sort filenames by modification time. */ + g_array_sort (paths, read_device_factory_paths_sort_fcn); + + result = g_new (char *, paths->len + 1); + for (i = 0; i < paths->len; i++) + result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path; + result[i] = NULL; + + g_array_free (paths, TRUE); + return result; +} + +static gboolean +_add_factory (NMDeviceFactory *factory, + gboolean check_duplicates, + const char *path, + NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + NMDeviceFactory *found = NULL; + const NMLinkType *link_types = NULL; + const char **setting_types = NULL; + int i; + + g_return_val_if_fail (factories_by_link, FALSE); + g_return_val_if_fail (factories_by_setting, FALSE); + + nm_device_factory_get_supported_types (factory, &link_types, &setting_types); + if (check_duplicates) { + found = find_factory (link_types, setting_types); + if (found) { + nm_log_warn (LOGD_HW, "Loading device plugin failed: multiple plugins " + "for same type (using '%s' instead of '%s')", + (char *) g_object_get_data (G_OBJECT (found), PLUGIN_PATH_TAG), + path); + return FALSE; + } + } + + g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, g_strdup (path), g_free); + for (i = 0; link_types && link_types[i] > NM_LINK_TYPE_UNKNOWN; i++) + g_hash_table_insert (factories_by_link, GUINT_TO_POINTER (link_types[i]), g_object_ref (factory)); + for (i = 0; setting_types && setting_types[i]; i++) + g_hash_table_insert (factories_by_setting, (char *) setting_types[i], g_object_ref (factory)); + + callback (factory, user_data); + + nm_log_info (LOGD_HW, "Loaded device plugin: %s (%s)", G_OBJECT_TYPE_NAME (factory), path); + return TRUE; +} + +void +nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data) +{ + NMDeviceFactory *factory; + const GSList *iter; + GError *error = NULL; + char **path, **paths; + + g_return_if_fail (factories_by_link == NULL); + g_return_if_fail (factories_by_setting == NULL); + + factories_by_link = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); + factories_by_setting = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref); + + /* Register internal factories first */ + for (iter = internal_types; iter; iter = iter->next) { + GType ftype = (GType) GPOINTER_TO_SIZE (iter->data); + + factory = (NMDeviceFactory *) g_object_new (ftype, NULL); + g_assert (factory); + _add_factory (factory, FALSE, "internal", callback, user_data); + } + + paths = read_device_factory_paths (); + if (!paths) + return; + + for (path = paths; *path; path++) { + GModule *plugin; + NMDeviceFactoryCreateFunc create_func; + const char *item; + + item = strrchr (*path, '/'); + g_assert (item); + + plugin = g_module_open (*path, G_MODULE_BIND_LOCAL); + + if (!plugin) { + nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ()); + continue; + } + + if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { + nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); + g_module_close (plugin); + continue; + } + + factory = create_func (&error); + if (!factory) { + nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", + item, error ? error->message : "unknown"); + g_clear_error (&error); + g_module_close (plugin); + continue; + } + g_clear_error (&error); + + if (_add_factory (factory, TRUE, g_module_name (plugin), callback, user_data)) + g_module_make_resident (plugin); + else + g_module_close (plugin); + + g_object_unref (factory); + } + g_strfreev (paths); +} + diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index ce672b8bfb..c6e4fa6914 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -66,14 +66,19 @@ struct _NMDeviceFactory { GTypeInterface g_iface; /** - * get_device_type: + * get_supported_types: * @factory: the #NMDeviceFactory + * @out_link_types: on return, a %NM_LINK_TYPE_NONE terminated + * list of #NMLinkType that the plugin supports + * @out_setting_types: on return, a %NULL terminated list of + * base-type #NMSetting names that the plugin can create devices for * - * This function MUST be implemented. - * - * Returns: the #NMDeviceType that this plugin creates + * Returns the #NMLinkType and #NMSetting names that this plugin + * supports. This function MUST be implemented. */ - NMDeviceType (*get_device_type) (NMDeviceFactory *factory); + void (*get_supported_types) (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types); /** * start: @@ -87,15 +92,17 @@ struct _NMDeviceFactory { /** * new_link: * @factory: the #NMDeviceFactory - * @link: the new link + * @plink: the new link * @error: error if the link could be claimed but an error occurred * * The NetworkManager core was notified of a new link which the plugin * may want to claim and create a #NMDevice subclass for. If the link - * represents a device the factory is capable of claiming, but the device - * could not be created, %NULL should be returned and @error should be set. - * %NULL should always be returned and @error should never be set if the - * factory cannot create devices for the type which @link represents. + * represents a device which the factory does not support, or the link + * is supported but the device could not be created, %NULL should be + * returned and @error should be set. + * + * @plink is guaranteed to be one of the types the factory returns in + * get_supported_types(). * * Returns: the #NMDevice if the link was claimed and created, %NULL if not */ @@ -151,7 +158,9 @@ struct _NMDeviceFactory { GType nm_device_factory_get_type (void); -NMDeviceType nm_device_factory_get_device_type (NMDeviceFactory *factory); +void nm_device_factory_get_supported_types (NMDeviceFactory *factory, + const NMLinkType **out_link_types, + const char ***out_setting_types); void nm_device_factory_start (NMDeviceFactory *factory); @@ -168,15 +177,33 @@ NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFacto gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *component); +#define NM_DEVICE_FACTORY_DECLARE_LINK_TYPES(...) \ + { static const NMLinkType _df_links[] = { __VA_ARGS__, NM_LINK_TYPE_NONE }; *out_link_types = _df_links; } +#define NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES(...) \ + { static const char *_df_settings[] = { __VA_ARGS__, NULL }; *out_setting_types = _df_settings; } + +extern const NMLinkType _nm_device_factory_no_default_links[]; +extern const char *_nm_device_factory_no_default_settings[]; + +#define NM_DEVICE_FACTORY_DECLARE_TYPES(...) \ + static void \ + get_supported_types (NMDeviceFactory *factory, \ + const NMLinkType **out_link_types, \ + const char ***out_setting_types) \ + { \ + *out_link_types = _nm_device_factory_no_default_links; \ + *out_setting_types = _nm_device_factory_no_default_settings; \ + \ + { __VA_ARGS__; } \ + } \ + \ + /************************************************************************** * INTERNAL DEVICE FACTORY FUNCTIONS - devices provided by plugins should * not use these functions. **************************************************************************/ -#define DEFINE_DEVICE_FACTORY_INTERNAL(upper, mixed, lower, dfi_code) \ - DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, upper, dfi_code) - -#define DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(upper, mixed, lower, devtype, dfi_code) \ +#define NM_DEVICE_FACTORY_DEFINE_INTERNAL(upper, mixed, lower, st_code, dfi_code) \ typedef GObject NM##mixed##Factory; \ typedef GObjectClass NM##mixed##FactoryClass; \ \ @@ -198,16 +225,12 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, g_type_ensure (NM_TYPE_##upper##_FACTORY); \ } \ \ - static NMDeviceType \ - get_device_type (NMDeviceFactory *factory) \ - { \ - return NM_DEVICE_TYPE_##devtype; \ - } \ + NM_DEVICE_FACTORY_DECLARE_TYPES(st_code) \ \ static void \ device_factory_interface_init (NMDeviceFactory *factory_iface) \ { \ - factory_iface->get_device_type = get_device_type; \ + factory_iface->get_supported_types = get_supported_types; \ dfi_code \ } \ \ @@ -222,6 +245,22 @@ gboolean nm_device_factory_emit_component_added (NMDeviceFactory *factory, } void _nm_device_factory_internal_register_type (GType factory_type); -const GSList *nm_device_factory_get_internal_factory_types (void); + +/************************************************************************** + * PRIVATE FACTORY FUNCTIONS - for factory consumers (eg, NMManager). + **************************************************************************/ + +typedef void (*NMDeviceFactoryManagerFactoryFunc) (NMDeviceFactory *factory, + gpointer user_data); + +void nm_device_factory_manager_load_factories (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data); + +NMDeviceFactory * nm_device_factory_manager_find_factory_for_link_type (NMLinkType link_type); + +NMDeviceFactory * nm_device_factory_manager_find_factory_for_connection (NMConnection *connection); + +void nm_device_factory_manager_for_each_factory (NMDeviceFactoryManagerFactoryFunc callback, + gpointer user_data); #endif /* __NETWORKMANAGER_DEVICE_FACTORY_H__ */ diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c index 6313bfd714..9e592b51f9 100644 --- a/src/devices/nm-device-gre.c +++ b/src/devices/nm-device-gre.c @@ -269,17 +269,15 @@ nm_device_gre_class_init (NMDeviceGreClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_GRE || plink->type == NM_LINK_TYPE_GRETAP) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Gre", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Gre", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(GRE, Gre, gre, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (GRE, Gre, gre, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_GRE, NM_LINK_TYPE_GRETAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 0a3b17c708..9f2119abac 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -295,14 +295,11 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_INFINIBAND) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "InfiniBand", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "InfiniBand", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, + NULL); } static NMDevice * @@ -315,23 +312,27 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, int p_key, parent_ifindex; const char *iface; - if (!nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) + if (!NM_IS_DEVICE_INFINIBAND (parent)) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Parent interface %s must be an InfiniBand interface", + nm_device_get_iface (parent)); return NULL; - - g_return_val_if_fail (NM_IS_DEVICE_INFINIBAND (parent), NULL); + } s_infiniband = nm_connection_get_setting_infiniband (connection); iface = nm_setting_infiniband_get_virtual_interface_name (s_infiniband); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); parent_ifindex = nm_device_get_ifindex (parent); p_key = nm_setting_infiniband_get_p_key (s_infiniband); if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_INFINIBAND, "(%s): failed to add InfiniBand P_Key interface for '%s': %s", - iface, nm_connection_get_id (connection), + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -344,8 +345,10 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL(INFINIBAND, Infiniband, infiniband, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME), + factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 608e541db0..4235b62783 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -177,17 +177,15 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_MACVLAN || plink->type == NM_LINK_TYPE_MACVTAP) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Macvlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Macvlan", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(MACVLAN, Macvlan, macvlan, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (MACVLAN, Macvlan, macvlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_MACVLAN, NM_LINK_TYPE_MACVTAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 4f4ed69b25..54cbbf82f3 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -278,8 +278,10 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) mode = "tun"; else if (plink->type == NM_LINK_TYPE_TAP) mode = "tap"; - else - return NULL; + else { + g_warn_if_reached (); + mode = "unknown"; + } return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN, NM_DEVICE_PLATFORM_DEVICE, plink, @@ -289,7 +291,8 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(TUN, Tun, tun, GENERIC, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index 7650502c2d..bb3d4af941 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -179,17 +179,15 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_VETH) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Veth", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Veth", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_ETHERNET, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VETH, Veth, veth, ETHERNET, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VETH, Veth, veth, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VETH), + factory_iface->new_link = new_link; ) diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 5513d73abb..55292173af 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -40,6 +40,7 @@ #include "nm-device-factory.h" #include "nm-manager.h" #include "nm-core-internal.h" +#include "gsystem-local-alloc.h" #include "nm-device-vlan-glue.h" @@ -660,25 +661,13 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) int parent_ifindex = -1; NMDevice *parent, *device; - if (plink->type != NM_LINK_TYPE_VLAN) - return NULL; - - /* Have to find the parent device */ + /* Find the parent device */ if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, plink->ifindex, &parent_ifindex, NULL)) { - nm_log_err (LOGD_HW, "(%s): failed to get VLAN parent ifindex", plink->name); + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN parent ifindex unknown"); return NULL; } - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); - if (!parent) { - /* If udev signaled the VLAN interface before it signaled - * the VLAN's parent at startup we may not know about the - * parent device yet. But we'll find it on the second pass - * from nm_manager_start(). - */ - nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", plink->name); - return NULL; - } device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, NM_DEVICE_PLATFORM_DEVICE, plink, @@ -688,6 +677,8 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, NULL); if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN initialization failed"); g_object_unref (device); device = NULL; } @@ -703,15 +694,16 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, { NMDevice *device; NMSettingVlan *s_vlan; - char *iface; + gs_free char *iface = NULL; - if (!nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) + if (!NM_IS_DEVICE (parent)) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "VLAN interfaces must have parents"); return NULL; - - g_return_val_if_fail (NM_IS_DEVICE (parent), NULL); + } s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); + g_assert (s_vlan); iface = g_strdup (nm_connection_get_interface_name (connection)); if (!iface) { @@ -725,9 +717,11 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, nm_setting_vlan_get_id (s_vlan), nm_setting_vlan_get_flags (s_vlan)) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - nm_log_warn (LOGD_DEVICE | LOGD_VLAN, "(%s) failed to add VLAN interface for '%s'", - iface, nm_connection_get_id (connection)); - g_free (iface); + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VLAN interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } @@ -738,8 +732,10 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NM_DEVICE_TYPE_DESC, "VLAN", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_VLAN, NULL); - g_free (iface); if (NM_DEVICE_VLAN_GET_PRIVATE (device)->invalid) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create VLAN interface '%s' for '%s': initialization failed", + iface, nm_connection_get_id (connection)); g_object_unref (device); device = NULL; } @@ -747,8 +743,10 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, return device; } -DEFINE_DEVICE_FACTORY_INTERNAL(VLAN, Vlan, vlan, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VLAN) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME), + factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; ) diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index 25ee804dfa..c0492aee34 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -355,17 +355,15 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_VXLAN) { - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, - NM_DEVICE_PLATFORM_DEVICE, plink, - NM_DEVICE_TYPE_DESC, "Vxlan", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, - NULL); - } - return NULL; + return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, + NM_DEVICE_PLATFORM_DEVICE, plink, + NM_DEVICE_TYPE_DESC, "Vxlan", + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NULL); } -DEFINE_DEVICE_FACTORY_INTERNAL_WITH_DEVTYPE(VXLAN, Vxlan, vxlan, GENERIC, \ - factory_iface->new_link = new_link; \ +NM_DEVICE_FACTORY_DEFINE_INTERNAL (VXLAN, Vxlan, vxlan, + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VXLAN), + factory_iface->new_link = new_link; ) diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 6b58014393..5cefde770c 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -676,8 +676,6 @@ release_slave (NMDevice *device, NMDevice * nm_device_team_new (NMPlatformLink *platform_device) { - g_return_val_if_fail (platform_device != NULL, NULL); - return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TEAM, NM_DEVICE_PLATFORM_DEVICE, platform_device, NM_DEVICE_DRIVER, "team", @@ -690,20 +688,16 @@ nm_device_team_new (NMPlatformLink *platform_device) NMDevice * nm_device_team_new_for_connection (NMConnection *connection, GError **error) { - const char *iface; + const char *iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (connection != NULL, NULL); - - iface = nm_connection_get_interface_name (connection); - g_return_val_if_fail (iface != NULL, NULL); + g_assert (iface); if ( !nm_platform_team_add (NM_PLATFORM_GET, iface) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { - g_set_error (error, - NM_DEVICE_ERROR, - NM_DEVICE_ERROR_CREATION_FAILED, - "failed to create team master interface '%s' for connection '%s': %s", - iface, nm_connection_get_id (connection), + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create team master interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), nm_platform_get_error_msg (NM_PLATFORM_GET)); return NULL; } diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c index cb887cac24..f21f07502c 100644 --- a/src/devices/team/nm-team-factory.c +++ b/src/devices/team/nm-team-factory.c @@ -50,9 +50,7 @@ nm_device_factory_create (GError **error) static NMDevice * new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) { - if (plink->type == NM_LINK_TYPE_TEAM) - return nm_device_team_new (plink); - return NULL; + return nm_device_team_new (plink); } static NMDevice * @@ -61,16 +59,13 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NMDevice *parent, GError **error) { - if (nm_connection_is_type (connection, NM_SETTING_TEAM_SETTING_NAME)) - return nm_device_team_new_for_connection (connection, error); - return NULL; + return nm_device_team_new_for_connection (connection, error); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_TEAM; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TEAM) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TEAM_SETTING_NAME) +) /************************************************************************/ @@ -84,7 +79,7 @@ device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; } static void diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 4093c61239..19578b3d58 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -23,6 +23,8 @@ #include #include "nm-device-factory.h" +#include "nm-setting-wireless.h" +#include "nm-setting-olpc-mesh.h" #include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" #include "nm-settings-connection.h" @@ -63,20 +65,19 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) return nm_device_wifi_new (plink); else if (plink->type == NM_LINK_TYPE_OLPC_MESH) return nm_device_olpc_mesh_new (plink); - return NULL; + g_assert_not_reached (); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_WIFI; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIFI, NM_LINK_TYPE_OLPC_MESH) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_OLPC_MESH_SETTING_NAME) +) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->new_link = new_link; - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; } static void diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index 2b9c3d4dd0..b6870d0dde 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -25,6 +25,8 @@ #include "nm-device-factory.h" #include "nm-wwan-factory.h" +#include "nm-setting-gsm.h" +#include "nm-setting-cdma.h" #include "nm-modem-manager.h" #include "nm-device-modem.h" #include "nm-logging.h" @@ -87,11 +89,10 @@ modem_added_cb (NMModemManager *manager, } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_MODEM; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WWAN_ETHERNET) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_GSM_SETTING_NAME, NM_SETTING_CDMA_SETTING_NAME) +) static void start (NMDeviceFactory *factory) @@ -115,7 +116,7 @@ nm_wwan_factory_init (NMWwanFactory *self) static void device_factory_interface_init (NMDeviceFactory *factory_iface) { - factory_iface->get_device_type = get_device_type; + factory_iface->get_supported_types = get_supported_types; factory_iface->start = start; } diff --git a/src/nm-manager.c b/src/nm-manager.c index 755b1f1916..84529ed758 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include #include @@ -178,9 +176,6 @@ typedef struct { gboolean prop_filter_added; NMRfkillManager *rfkill_mgr; - /* List of NMDeviceFactoryFunc pointers sorted in priority order */ - GSList *factories; - NMSettings *settings; char *hostname; @@ -1048,7 +1043,7 @@ static NMDevice * system_create_virtual_device (NMManager *self, NMConnection *connection, GError **error) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GError *local_err = NULL; + NMDeviceFactory *factory; GSList *iter; char *iface = NULL; NMDevice *device = NULL, *parent = NULL; @@ -1085,6 +1080,19 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError } } + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) { + nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", + nm_connection_get_id (connection), iface, + nm_connection_get_connection_type (connection)); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); + goto out; + } + /* 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. @@ -1093,24 +1101,10 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError nm_owned = !nm_platform_link_exists (NM_PLATFORM_GET, iface); - for (iter = priv->factories; iter; iter = iter->next) { - device = nm_device_factory_create_virtual_device_for_connection (NM_DEVICE_FACTORY (iter->data), - connection, - parent, - &local_err); - if (device || local_err) { - if (device) - g_assert_no_error (local_err); - else { - nm_log_err (LOGD_DEVICE, "(%s) failed to create virtual device: %s", - nm_connection_get_id (connection), - local_err ? local_err->message : "(unknown error)"); - g_propagate_error (error, local_err); - } - break; - } - } - + device = nm_device_factory_create_virtual_device_for_connection (factory, + connection, + parent, + error); if (device) { if (nm_owned) nm_device_set_nm_owned (device); @@ -1121,16 +1115,6 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError add_device (self, device, !nm_owned); g_object_unref (device); - } else { - if (error && !*error) - nm_log_err (LOGD_DEVICE, "(%s:%s) NetworkManager plugin for '%s' unavailable", - nm_connection_get_id (connection), iface, - nm_connection_get_connection_type (connection)); - g_set_error (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "NetworkManager plugin for '%s' unavailable", - nm_connection_get_connection_type (connection)); } priv->ignore_link_added_cb--; @@ -1946,124 +1930,10 @@ factory_component_added_cb (NMDeviceFactory *factory, return notify_component_added (NM_MANAGER (user_data), component); } -#define PLUGIN_PREFIX "libnm-device-plugin-" -#define PLUGIN_PATH_TAG "NMManager-plugin-path" - -struct read_device_factory_paths_data { - char *path; - struct stat st; -}; - -static gint -read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b) +static void +_register_device_factory (NMDeviceFactory *factory, gpointer user_data) { - const struct read_device_factory_paths_data *da = a; - const struct read_device_factory_paths_data *db = b; - time_t ta, tb; - - ta = MAX (da->st.st_mtime, da->st.st_ctime); - tb = MAX (db->st.st_mtime, db->st.st_ctime); - - if (ta < tb) - return 1; - if (ta > tb) - return -1; - return 0; -} - -static char** -read_device_factory_paths (void) -{ - GDir *dir; - GError *error = NULL; - const char *item; - GArray *paths; - char **result; - guint i; - - dir = g_dir_open (NMPLUGINDIR, 0, &error); - if (!dir) { - nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s", - NMPLUGINDIR, - (error && error->message) ? error->message : "(unknown)"); - g_clear_error (&error); - return NULL; - } - - paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data)); - - while ((item = g_dir_read_name (dir))) { - int errsv; - struct read_device_factory_paths_data data; - - if (!g_str_has_prefix (item, PLUGIN_PREFIX)) - continue; - if (g_str_has_suffix (item, ".la")) - continue; - - data.path = g_build_filename (NMPLUGINDIR, item, NULL); - - if (stat (data.path, &data.st) != 0) { - errsv = errno; - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (error during stat: %s)", data.path, strerror (errsv)); - goto NEXT; - } - if (!S_ISREG (data.st.st_mode)) - goto NEXT; - if (data.st.st_uid != 0) { - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (file must be owned by root)", data.path); - goto NEXT; - } - if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID)) { - nm_log_warn (LOGD_HW, "device plugin: skip invalid file %s (invalid file permissions)", data.path); - goto NEXT; - } - - g_array_append_val (paths, data); - continue; -NEXT: - g_free (data.path); - } - g_dir_close (dir); - - /* sort filenames by modification time. */ - g_array_sort (paths, read_device_factory_paths_sort_fcn); - - result = g_new (char *, paths->len + 1); - for (i = 0; i < paths->len; i++) - result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path; - result[i] = NULL; - - g_array_free (paths, TRUE); - return result; -} - -static gboolean -_register_device_factory (NMManager *self, - NMDeviceFactory *factory, - gboolean duplicate_check, - const char *path, - GError **error) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMDeviceType ftype; - GSList *iter; - - if (duplicate_check) { - /* Make sure we don't double-register factories */ - ftype = nm_device_factory_get_device_type (factory); - for (iter = priv->factories; iter; iter = iter->next) { - if (ftype == nm_device_factory_get_device_type (iter->data)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, - "multiple plugins for same type (using '%s' instead of '%s')", - (char *) g_object_get_data (G_OBJECT (iter->data), PLUGIN_PATH_TAG), - path); - return FALSE; - } - } - } - - priv->factories = g_slist_append (priv->factories, factory); + NMManager *self = NM_MANAGER (user_data); g_signal_connect (factory, NM_DEVICE_FACTORY_DEVICE_ADDED, @@ -2073,80 +1943,6 @@ _register_device_factory (NMManager *self, NM_DEVICE_FACTORY_COMPONENT_ADDED, G_CALLBACK (factory_component_added_cb), self); - g_object_set_data_full (G_OBJECT (factory), PLUGIN_PATH_TAG, - g_strdup (path), g_free); - return TRUE; -} - -static void -load_device_factories (NMManager *self) -{ - NMDeviceFactory *factory; - const GSList *iter; - GError *error = NULL; - char **path, **paths; - - /* Register internal factories first */ - for (iter = nm_device_factory_get_internal_factory_types (); iter; iter = iter->next) { - GType ftype = (GType) GPOINTER_TO_SIZE (iter->data); - - factory = (NMDeviceFactory *) g_object_new (ftype, NULL); - g_assert (factory); - if (_register_device_factory (self, factory, FALSE, "internal", &error)) { - nm_log_dbg (LOGD_HW, "Loaded device plugin: %s", g_type_name (ftype)); - } else { - nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message); - g_object_unref (factory); - g_clear_error (&error); - } - } - - paths = read_device_factory_paths (); - if (!paths) - return; - - for (path = paths; *path; path++) { - GModule *plugin; - NMDeviceFactoryCreateFunc create_func; - const char *item; - - item = strrchr (*path, '/'); - g_assert (item); - - plugin = g_module_open (*path, G_MODULE_BIND_LOCAL); - - if (!plugin) { - nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ()); - continue; - } - - if (!g_module_symbol (plugin, "nm_device_factory_create", (gpointer) &create_func)) { - nm_log_warn (LOGD_HW, "(%s): failed to find device factory creator: %s", item, g_module_error ()); - g_module_close (plugin); - continue; - } - - factory = create_func (&error); - if (!factory) { - nm_log_warn (LOGD_HW, "(%s): failed to initialize device factory: %s", - item, error ? error->message : "unknown"); - g_clear_error (&error); - g_module_close (plugin); - continue; - } - g_clear_error (&error); - - if (_register_device_factory (self, factory, TRUE, g_module_name (plugin), &error)) { - nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin)); - g_module_make_resident (plugin); - } else { - nm_log_warn (LOGD_HW, "Loading device plugin failed: %s", error->message); - g_object_unref (factory); - g_module_close (plugin); - g_clear_error (&error); - } - } - g_strfreev (paths); } /*******************************************************************/ @@ -2158,8 +1954,8 @@ platform_link_added (NMManager *self, NMPlatformReason reason) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + NMDeviceFactory *factory; NMDevice *device = NULL; - GSList *iter; GError *error = NULL; gboolean nm_plugin_missing = FALSE; @@ -2171,41 +1967,31 @@ platform_link_added (NMManager *self, if (nm_manager_get_device_by_ifindex (self, ifindex)) return; - /* Try registered device factories */ - for (iter = priv->factories; iter; iter = iter->next) { - NMDeviceFactory *factory = NM_DEVICE_FACTORY (iter->data); - - device = nm_device_factory_new_link (factory, plink, &error); - if (device && NM_IS_DEVICE (device)) { - g_assert_no_error (error); - break; /* success! */ - } - - if (error) { - nm_log_warn (LOGD_HW, "%s: factory failed to create device: (%d) %s", - plink->udi, - error ? error->code : -1, - error ? error->message : "(unknown)"); - g_clear_error (&error); - return; - } - } - /* Ignore Bluetooth PAN interfaces; they are handled by their NMDeviceBt * parent and don't get a separate interface. */ if (plink->type == NM_LINK_TYPE_BNEP) return; + /* Try registered device factories */ + factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); + if (factory) { + device = nm_device_factory_new_link (factory, plink, &error); + if (!device) { + nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", + plink->name, error->message); + g_clear_error (&error); + return; + } + } + if (device == NULL) { switch (plink->type) { - case NM_LINK_TYPE_WWAN_ETHERNET: /* WWAN pseudo-ethernet interfaces are handled automatically by * their NMDeviceModem and don't get a separate NMDevice object. */ break; - case NM_LINK_TYPE_OLPC_MESH: case NM_LINK_TYPE_TEAM: case NM_LINK_TYPE_WIFI: @@ -4226,11 +4012,16 @@ impl_manager_check_connectivity (NMManager *manager, nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE); } +static void +start_factory (NMDeviceFactory *factory, gpointer user_data) +{ + nm_device_factory_start (factory); +} + void nm_manager_start (NMManager *self) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; guint i; /* Set initial radio enabled/disabled state */ @@ -4262,8 +4053,7 @@ nm_manager_start (NMManager *self) system_hostname_changed_cb (priv->settings, NULL, self); /* Start device factories */ - for (iter = priv->factories; iter; iter = iter->next) - nm_device_factory_start (iter->data); + nm_device_factory_manager_for_each_factory (start_factory, NULL); nm_platform_query_devices (NM_PLATFORM_GET); @@ -4868,7 +4658,7 @@ nm_manager_new (NMSettings *settings, rfkill_change (priv->radio_states[RFKILL_TYPE_WLAN].desc, RFKILL_TYPE_WLAN, initial_wifi_enabled); rfkill_change (priv->radio_states[RFKILL_TYPE_WWAN].desc, RFKILL_TYPE_WWAN, initial_wwan_enabled); - load_device_factories (singleton); + nm_device_factory_manager_load_factories (_register_device_factory, singleton); return singleton; } @@ -5094,6 +4884,12 @@ set_property (GObject *object, guint prop_id, } } +static void +_deinit_device_factory (NMDeviceFactory *factory, gpointer user_data) +{ + g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, NM_MANAGER (user_data)); +} + static void dispose (GObject *object) { @@ -5101,7 +4897,6 @@ dispose (GObject *object) NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager); DBusGConnection *bus; DBusConnection *dbus_connection; - GSList *iter; g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; @@ -5177,14 +4972,8 @@ dispose (GObject *object) g_clear_object (&priv->fw_monitor); } - for (iter = priv->factories; iter; iter = iter->next) { - NMDeviceFactory *factory = iter->data; - - g_signal_handlers_disconnect_matched (factory, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, manager); - g_object_unref (factory); - } - g_clear_pointer (&priv->factories, g_slist_free); - + nm_device_factory_manager_for_each_factory (_deinit_device_factory, manager); + if (priv->timestamp_update_id) { g_source_remove (priv->timestamp_update_id); priv->timestamp_update_id = 0; From 42b272b604d8a40d699e1e08beb6135ad1f0caba Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 29 Apr 2015 10:56:36 +0200 Subject: [PATCH 07/14] trivial: move code --- src/devices/nm-device-factory.c | 112 ++++++++++++++++---------------- src/nm-manager.c | 76 +++++++++++----------- 2 files changed, 94 insertions(+), 94 deletions(-) diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 9957efdc33..1038f75191 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -49,61 +49,6 @@ nm_device_factory_emit_component_added (NMDeviceFactory *factory, GObject *compo return consumed; } -static void -interface_init (gpointer g_iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (G_LIKELY (initialized)) - return; - - /* Signals */ - signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDeviceFactory, device_added), - NULL, NULL, NULL, - G_TYPE_NONE, 1, NM_TYPE_DEVICE); - - signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, - iface_type, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (NMDeviceFactory, component_added), - g_signal_accumulator_true_handled, NULL, NULL, - G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); - - initialized = TRUE; -} - -GType -nm_device_factory_get_type (void) -{ - static GType device_factory_type = 0; - - if (!device_factory_type) { - const GTypeInfo device_factory_info = { - sizeof (NMDeviceFactory), /* class_size */ - interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - device_factory_type = g_type_register_static (G_TYPE_INTERFACE, - "NMDeviceFactory", - &device_factory_info, - 0); - g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT); - } - - return device_factory_type; -} - void nm_device_factory_get_supported_types (NMDeviceFactory *factory, const NMLinkType **out_link_types, @@ -217,6 +162,63 @@ nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory /*******************************************************************/ +static void +interface_init (gpointer g_iface) +{ + GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); + static gboolean initialized = FALSE; + + if (G_LIKELY (initialized)) + return; + + /* Signals */ + signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDeviceFactory, device_added), + NULL, NULL, NULL, + G_TYPE_NONE, 1, NM_TYPE_DEVICE); + + signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, + iface_type, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (NMDeviceFactory, component_added), + g_signal_accumulator_true_handled, NULL, NULL, + G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); + + initialized = TRUE; +} + +GType +nm_device_factory_get_type (void) +{ + static GType device_factory_type = 0; + + if (!device_factory_type) { + const GTypeInfo device_factory_info = { + sizeof (NMDeviceFactory), /* class_size */ + interface_init, /* base_init */ + NULL, /* base_finalize */ + NULL, + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, + 0, /* n_preallocs */ + NULL + }; + + device_factory_type = g_type_register_static (G_TYPE_INTERFACE, + "NMDeviceFactory", + &device_factory_info, + 0); + g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT); + } + + return device_factory_type; +} + +/*******************************************************************/ + static GSList *internal_types = NULL; static GHashTable *factories_by_link = NULL; static GHashTable *factories_by_setting = NULL; diff --git a/src/nm-manager.c b/src/nm-manager.c index 84529ed758..edfd3513c2 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -127,8 +127,6 @@ static NMActiveConnection *_new_active_connection (NMManager *self, static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data); -static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface); - static void rfkill_change (const char *desc, RfKillType rtype, gboolean enabled); static gboolean find_master (NMManager *self, @@ -515,6 +513,43 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex) return NULL; } +static NMDevice * +get_device_from_hwaddr (NMManager *self, const char *setting_mac) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + const char *device_mac; + GSList *iter; + + if (!setting_mac) + return NULL; + + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + NMDevice *device = iter->data; + + device_mac = nm_device_get_hw_address (iter->data); + if (!device_mac) + continue; + if (nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1)) + return device; + } + return NULL; +} + +static NMDevice * +find_device_by_ip_iface (NMManager *self, const gchar *iface) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + GSList *iter; + + for (iter = priv->devices; iter; iter = g_slist_next (iter)) { + NMDevice *candidate = iter->data; + + if (g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) + return candidate; + } + return NULL; +} + static gboolean manager_sleeping (NMManager *self) { @@ -842,28 +877,6 @@ nm_manager_get_state (NMManager *manager) /* Settings stuff via NMSettings */ /*******************************************************************/ -static NMDevice * -get_device_from_hwaddr (NMManager *self, const char *setting_mac) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - const char *device_mac; - GSList *iter; - - if (!setting_mac) - return NULL; - - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *device = iter->data; - - device_mac = nm_device_get_hw_address (iter->data); - if (!device_mac) - continue; - if (nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1)) - return device; - } - return NULL; -} - static NMDevice * find_vlan_parent (NMManager *self, NMConnection *connection) @@ -1897,21 +1910,6 @@ add_device (NMManager *self, NMDevice *device, gboolean try_assume) system_create_virtual_devices (self); } -static NMDevice * -find_device_by_ip_iface (NMManager *self, const gchar *iface) -{ - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - GSList *iter; - - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *candidate = iter->data; - - if (g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) - return candidate; - } - return NULL; -} - /*******************************************************************/ static void From 179d56c73c35e83368589b40a8a2d429b41a4dbf Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 18 Sep 2014 17:50:47 -0500 Subject: [PATCH 08/14] core: move virtual interface name handling into device plugins Instead of having a bunch of logic in the Manager for determining the VLAN and Infiniband virtual interface names, move the type-specific logic into the plugins themselves. --- src/devices/nm-device-factory.c | 95 ++++++---- src/devices/nm-device-factory.h | 35 ++++ src/devices/nm-device-infiniband.c | 32 ++++ src/devices/nm-device-vlan.c | 53 ++++++ src/nm-manager.c | 272 +++++++++++------------------ 5 files changed, 285 insertions(+), 202 deletions(-) diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 1038f75191..0357845c12 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -160,61 +160,92 @@ nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory return interface->create_virtual_device_for_connection (factory, connection, parent, error); } +const char * +nm_device_factory_get_connection_parent (NMDeviceFactory *factory, + NMConnection *connection) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + if (!nm_connection_is_virtual (connection)) + return NULL; + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_connection_parent (factory, connection); + return NULL; +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *iface; + + /* For any other virtual connection, NMSettingConnection:interface-name is + * the virtual device name. + */ + iface = nm_connection_get_interface_name (connection); + g_return_val_if_fail (iface != NULL, NULL); + return g_strdup (iface); +} + +char * +nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + g_return_val_if_fail (factory != NULL, NULL); + g_return_val_if_fail (connection != NULL, NULL); + + if (!nm_connection_is_virtual (connection)) + return NULL; + + if (NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name) + return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_virtual_iface_name (factory, connection, parent_iface); + return NULL; +} + /*******************************************************************/ static void -interface_init (gpointer g_iface) +default_init (NMDeviceFactory *factory_iface) { - GType iface_type = G_TYPE_FROM_INTERFACE (g_iface); - static gboolean initialized = FALSE; - - if (G_LIKELY (initialized)) - return; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; /* Signals */ signals[DEVICE_ADDED] = g_signal_new (NM_DEVICE_FACTORY_DEVICE_ADDED, - iface_type, + NM_TYPE_DEVICE_FACTORY, G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (NMDeviceFactory, device_added), NULL, NULL, NULL, G_TYPE_NONE, 1, NM_TYPE_DEVICE); signals[COMPONENT_ADDED] = g_signal_new (NM_DEVICE_FACTORY_COMPONENT_ADDED, - iface_type, + NM_TYPE_DEVICE_FACTORY, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (NMDeviceFactory, component_added), g_signal_accumulator_true_handled, NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_OBJECT); - - initialized = TRUE; } GType nm_device_factory_get_type (void) { - static GType device_factory_type = 0; - - if (!device_factory_type) { - const GTypeInfo device_factory_info = { - sizeof (NMDeviceFactory), /* class_size */ - interface_init, /* base_init */ - NULL, /* base_finalize */ - NULL, - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, - 0, /* n_preallocs */ - NULL - }; - - device_factory_type = g_type_register_static (G_TYPE_INTERFACE, - "NMDeviceFactory", - &device_factory_info, - 0); - g_type_interface_add_prerequisite (device_factory_type, G_TYPE_OBJECT); + static volatile gsize g_define_type_id__volatile = 0; + if (g_once_init_enter (&g_define_type_id__volatile)) { + GType g_define_type_id = + g_type_register_static_simple (G_TYPE_INTERFACE, + g_intern_static_string ("NMDeviceFactory"), + sizeof (NMDeviceFactory), + (GClassInitFunc) default_init, + 0, + (GInstanceInitFunc) NULL, + (GTypeFlags) 0); + g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT); + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); } - - return device_factory_type; + return g_define_type_id__volatile; } /*******************************************************************/ diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index c6e4fa6914..40050d4dd3 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -128,6 +128,34 @@ struct _NMDeviceFactory { NMDevice *parent, GError **error); + /** + * get_connection_parent: + * @factory: the #NMDeviceFactory + * @connection: the #NMConnection to return the parent name for, if supported + * + * Given a connection, returns the a parent interface name, parent connection + * UUID, or parent device hardware address for @connection. + * + * Returns: the parent interface name, parent connection UUID, parent + * device hardware address, or %NULL + */ + const char * (*get_connection_parent) (NMDeviceFactory *factory, + NMConnection *connection); + + /** + * get_virtual_iface_name: + * @factory: the #NMDeviceFactory + * @connection: the #NMConnection to return the virtual interface name for + * @parent_iface: parent interface name + * + * Given a connection, returns the interface name that a device activating + * that connection would have. + * + * Returns: the interface name, or %NULL + */ + char * (*get_virtual_iface_name) (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface); /* Signals */ @@ -162,6 +190,13 @@ void nm_device_factory_get_supported_types (NMDeviceFactory *factory, const NMLinkType **out_link_types, const char ***out_setting_types); +const char *nm_device_factory_get_connection_parent (NMDeviceFactory *factory, + NMConnection *connection); + +char * nm_device_factory_get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface); + void nm_device_factory_start (NMDeviceFactory *factory); NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 9f2119abac..c7b8787c45 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -345,10 +345,42 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, NULL); } +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingInfiniband *s_infiniband; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL); + + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_assert (s_infiniband); + + return nm_setting_infiniband_get_parent (s_infiniband); +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + NMSettingInfiniband *s_infiniband; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME), NULL); + + s_infiniband = nm_connection_get_setting_infiniband (connection); + g_assert (s_infiniband); + + g_return_val_if_fail (g_strcmp0 (parent_iface, nm_setting_infiniband_get_parent (s_infiniband)) == 0, NULL); + + return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband)); +} + NM_DEVICE_FACTORY_DEFINE_INTERNAL (INFINIBAND, Infiniband, infiniband, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_INFINIBAND) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_INFINIBAND_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 55292173af..ba79a6ccb1 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -743,10 +743,63 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, return device; } +static const char * +get_connection_parent (NMDeviceFactory *factory, NMConnection *connection) +{ + NMSettingVlan *s_vlan; + NMSettingWired *s_wired; + const char *parent = NULL; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + parent = nm_setting_vlan_get_parent (s_vlan); + if (parent) + return parent; + + /* Try the hardware address from the VLAN connection's hardware setting */ + s_wired = nm_connection_get_setting_wired (connection); + if (s_wired) + return nm_setting_wired_get_mac_address (s_wired); + + return NULL; +} + +static char * +get_virtual_iface_name (NMDeviceFactory *factory, + NMConnection *connection, + const char *parent_iface) +{ + const char *ifname; + NMSettingVlan *s_vlan; + + g_return_val_if_fail (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME), NULL); + + s_vlan = nm_connection_get_setting_vlan (connection); + g_assert (s_vlan); + + if (!parent_iface) + return NULL; + + ifname = nm_connection_get_interface_name (connection); + if (ifname) + return g_strdup (ifname); + + /* If the connection doesn't specify the interface name for the VLAN + * device, we create one for it using the VLAN ID and the parent + * interface's name. + */ + return nm_utils_new_vlan_name (parent_iface, nm_setting_vlan_get_id (s_vlan)); +} + NM_DEVICE_FACTORY_DEFINE_INTERNAL (VLAN, Vlan, vlan, NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_VLAN) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_VLAN_SETTING_NAME), factory_iface->new_link = new_link; factory_iface->create_virtual_device_for_connection = create_virtual_device_for_connection; + factory_iface->get_connection_parent = get_connection_parent; + factory_iface->get_virtual_iface_name = get_virtual_iface_name; ) diff --git a/src/nm-manager.c b/src/nm-manager.c index edfd3513c2..6bb867ca71 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -514,23 +514,19 @@ nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex) } static NMDevice * -get_device_from_hwaddr (NMManager *self, const char *setting_mac) +find_device_by_hw_addr (NMManager *manager, const char *hwaddr) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - const char *device_mac; GSList *iter; + const char *device_addr; - if (!setting_mac) - return NULL; + g_return_val_if_fail (hwaddr != NULL, NULL); - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *device = iter->data; - - device_mac = nm_device_get_hw_address (iter->data); - if (!device_mac) - continue; - if (nm_utils_hwaddr_matches (setting_mac, -1, device_mac, -1)) - return device; + if (nm_utils_hwaddr_valid (hwaddr, -1)) { + for (iter = NM_MANAGER_GET_PRIVATE (manager)->devices; iter; iter = iter->next) { + device_addr = nm_device_get_hw_address (NM_DEVICE (iter->data)); + if (device_addr && nm_utils_hwaddr_matches (hwaddr, -1, device_addr, -1)) + return NM_DEVICE (iter->data); + } } return NULL; } @@ -538,14 +534,13 @@ get_device_from_hwaddr (NMManager *self, const char *setting_mac) static NMDevice * find_device_by_ip_iface (NMManager *self, const gchar *iface) { - NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); GSList *iter; - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMDevice *candidate = iter->data; + g_return_val_if_fail (iface != NULL, NULL); - if (g_strcmp0 (nm_device_get_ip_iface (candidate), iface) == 0) - return candidate; + 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); } return NULL; } @@ -873,87 +868,56 @@ nm_manager_get_state (NMManager *manager) return NM_MANAGER_GET_PRIVATE (manager)->state; } -/*******************************************************************/ -/* Settings stuff via NMSettings */ -/*******************************************************************/ +/***************************/ static NMDevice * -find_vlan_parent (NMManager *self, - NMConnection *connection) +find_parent_device_for_connection (NMManager *self, NMConnection *connection) { NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); - NMSettingVlan *s_vlan; - NMSettingWired *s_wired; + NMDeviceFactory *factory; + const char *parent_name = NULL; NMConnection *parent_connection; - const char *parent_iface; - NMDevice *parent = NULL; - const char *setting_mac; + NMDevice *parent, *first_compatible = NULL; GSList *iter; - /* The 'parent' property could be given by an interface name, a - * connection UUID, or the MAC address of an NMSettingWired. + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) + return NULL; + + parent_name = nm_device_factory_get_connection_parent (factory, connection); + if (!parent_name) + return NULL; + + /* Try as an interface name */ + parent = find_device_by_ip_iface (self, parent_name); + if (parent) + return parent; + + /* Maybe a hardware address */ + parent = find_device_by_hw_addr (self, parent_name); + if (parent) + return parent; + + /* Maybe a connection UUID */ + parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_name); + if (!parent_connection) + return NULL; + + /* Check if the parent connection is currently activated or is comaptible + * with some known device. */ - s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); + for (iter = priv->devices; iter; iter = iter->next) { + NMDevice *candidate = iter->data; - s_wired = nm_connection_get_setting_wired (connection); - setting_mac = s_wired ? nm_setting_wired_get_mac_address (s_wired) : NULL; + if (nm_device_get_connection (candidate) == parent_connection) + return candidate; - parent_iface = nm_setting_vlan_get_parent (s_vlan); - if (parent_iface) { - parent = find_device_by_ip_iface (self, parent_iface); - if (parent) - return parent; - - if (nm_utils_is_uuid (parent_iface)) { - /* Try as a connection UUID */ - parent_connection = (NMConnection *) nm_settings_get_connection_by_uuid (priv->settings, parent_iface); - if (parent_connection) { - /* Check if the parent connection is activated on some device already */ - for (iter = priv->devices; iter; iter = g_slist_next (iter)) { - NMActRequest *req; - NMConnection *candidate; - - req = nm_device_get_act_request (NM_DEVICE (iter->data)); - if (req) { - candidate = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req)); - if (candidate == parent_connection) - return NM_DEVICE (iter->data); - } - } - - /* Check the hardware address of the parent connection */ - return get_device_from_hwaddr (self, setting_mac); - } - return NULL; - } + if ( !first_compatible + && nm_device_check_connection_compatible (candidate, parent_connection)) + first_compatible = candidate; } - /* Try the hardware address from the VLAN connection's hardware setting */ - return get_device_from_hwaddr (self, setting_mac); -} - -static NMDevice * -find_infiniband_parent (NMManager *self, - NMConnection *connection) -{ - NMSettingInfiniband *s_infiniband; - const char *parent_iface; - NMDevice *parent = NULL; - const char *setting_mac; - - s_infiniband = nm_connection_get_setting_infiniband (connection); - g_return_val_if_fail (s_infiniband != NULL, NULL); - - parent_iface = nm_setting_infiniband_get_parent (s_infiniband); - if (parent_iface) { - parent = find_device_by_ip_iface (self, parent_iface); - if (parent) - return parent; - } - - setting_mac = nm_setting_infiniband_get_mac_address (s_infiniband); - return get_device_from_hwaddr (self, setting_mac); + return first_compatible; } /** @@ -961,86 +925,69 @@ find_infiniband_parent (NMManager *self, * @self: the #NMManager * @connection: the #NMConnection representing a virtual interface * @out_parent: on success, the parent device if any + * @error: an error if determining the virtual interface name failed * * Given @connection, returns the interface name that the connection - * would represent. If the interface name is not given by the connection, - * this may require constructing it based on information in the connection - * and existing network interfaces. + * would represent if it is a virtual connection. %NULL is returned and + * @error is set if the connection is not virtual, or if the name could + * not be determined. * * Returns: the expected interface name (caller takes ownership), or %NULL */ static char * get_virtual_iface_name (NMManager *self, NMConnection *connection, - NMDevice **out_parent) + NMDevice **out_parent, + GError **error) { + NMDeviceFactory *factory; + char *iface = NULL; NMDevice *parent = NULL; - const char *ifname; if (out_parent) *out_parent = NULL; - if (!nm_connection_is_virtual (connection)) + if (!nm_connection_is_virtual (connection)) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); return NULL; - - ifname = nm_connection_get_interface_name (connection); - - if (nm_connection_is_type (connection, NM_SETTING_VLAN_SETTING_NAME)) { - NMSettingVlan *s_vlan; - char *vname; - - s_vlan = nm_connection_get_setting_vlan (connection); - g_return_val_if_fail (s_vlan != NULL, NULL); - - parent = find_vlan_parent (self, connection); - if (!parent) - return NULL; - - if (!nm_device_supports_vlans (parent)) { - nm_log_warn (LOGD_DEVICE, "(%s): No support for VLANs on interface %s of type %s", - ifname ? ifname : nm_connection_get_id (connection), - nm_device_get_ip_iface (parent), - nm_device_get_type_desc (parent)); - return NULL; - } - - /* If the connection doesn't specify the interface name for the VLAN - * device, we create one for it using the VLAN ID and the parent - * interface's name. - */ - if (ifname) - vname = g_strdup (ifname); - else { - vname = nm_utils_new_vlan_name (nm_device_get_ip_iface (parent), - nm_setting_vlan_get_id (s_vlan)); - } - if (out_parent) - *out_parent = parent; - return vname; } - if (nm_connection_is_type (connection, NM_SETTING_INFINIBAND_SETTING_NAME)) { - NMSettingInfiniband *s_infiniband; - - parent = find_infiniband_parent (self, connection); - if (!parent) - return NULL; - - s_infiniband = nm_connection_get_setting_infiniband (connection); - if (out_parent) - *out_parent = parent; - return g_strdup (nm_setting_infiniband_get_virtual_interface_name (s_infiniband)); + factory = nm_device_factory_manager_find_factory_for_connection (connection); + if (!factory) { + nm_log_warn (LOGD_DEVICE, "(%s) NetworkManager plugin for '%s' unavailable", + nm_connection_get_id (connection), + nm_connection_get_connection_type (connection)); + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_FAILED, + "NetworkManager plugin for '%s' unavailable", + nm_connection_get_connection_type (connection)); + return NULL; } - /* For any other virtual connection, NMSettingConnection:interface-name is - * the virtual device name. - */ - g_return_val_if_fail (ifname != NULL, NULL); - return g_strdup (ifname); + parent = find_parent_device_for_connection (self, connection); + iface = nm_device_factory_get_virtual_iface_name (factory, + connection, + parent ? nm_device_get_ip_iface (parent) : NULL); + if (!iface) { + nm_log_warn (LOGD_DEVICE, "(%s) failed to determine virtual interface name", + nm_connection_get_id (connection)); + g_set_error_literal (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "failed to determine virtual interface name"); + return NULL; + } + + if (out_parent) + *out_parent = parent; + return iface; } -/***************************/ - /** * system_create_virtual_device: * @self: the #NMManager @@ -1066,16 +1013,9 @@ system_create_virtual_device (NMManager *self, NMConnection *connection, GError g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - iface = get_virtual_iface_name (self, connection, &parent); - if (!iface) { - nm_log_dbg (LOGD_DEVICE, "(%s) failed to determine virtual interface name", - nm_connection_get_id (connection)); - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_FAILED, - "failed to determine virtual interface name"); + iface = get_virtual_iface_name (self, connection, &parent, error); + if (!iface) return NULL; - } /* Make sure we didn't create a device for this connection already */ for (iter = priv->devices; iter; iter = g_slist_next (iter)) { @@ -2251,13 +2191,10 @@ find_master (NMManager *self, NMConnection *candidate = iter->data; char *vname; - if (nm_connection_is_virtual (candidate)) { - vname = get_virtual_iface_name (self, candidate, NULL); - if ( g_strcmp0 (master, vname) == 0 - && is_compatible_with_slave (candidate, connection)) - master_connection = candidate; - g_free (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); } @@ -2939,17 +2876,12 @@ validate_activation_request (NMManager *self, } if (is_software) { - /* Look for an existing device with the connection's interface name */ char *iface; - iface = get_virtual_iface_name (self, connection, NULL); - if (!iface) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "Failed to determine connection's virtual interface name"); + /* Look for an existing device with the connection's interface name */ + iface = get_virtual_iface_name (self, connection, NULL, error); + if (!iface) goto error; - } device = find_device_by_ip_iface (self, iface); g_free (iface); From 2abda4bfa59bfd6de8da69741f2c5f3304e46617 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 18 Sep 2014 12:53:19 -0500 Subject: [PATCH 09/14] platform: return link objects from add functions --- src/devices/nm-device-bond.c | 2 +- src/devices/nm-device-bridge.c | 3 +- src/devices/nm-device-infiniband.c | 2 +- src/devices/nm-device-vlan.c | 3 +- src/devices/team/nm-device-team.c | 2 +- src/platform/nm-fake-platform.c | 31 ++++++++----- src/platform/nm-linux-platform.c | 45 ++++++++++++++++--- src/platform/nm-platform.c | 70 +++++++++++++++++++++--------- src/platform/nm-platform.h | 23 ++++++---- src/platform/tests/platform.c | 10 ++--- src/platform/tests/test-address.c | 2 +- src/platform/tests/test-cleanup.c | 2 +- src/platform/tests/test-link.c | 16 +++---- src/platform/tests/test-route.c | 2 +- src/tests/test-route-manager.c | 4 +- 15 files changed, 148 insertions(+), 69 deletions(-) diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 3356125b7c..951954ba6e 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -574,7 +574,7 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, g_assert (iface); - if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface) + if ( !nm_platform_bond_add (NM_PLATFORM_GET, iface, NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create bond interface '%s' for '%s': %s", diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index f5219b02dd..ffec9764dd 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -513,7 +513,8 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, if ( !nm_platform_bridge_add (NM_PLATFORM_GET, iface, mac_address_str ? mac_address : NULL, - mac_address_str ? ETH_ALEN : 0) + mac_address_str ? ETH_ALEN : 0, + NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create bridge interface '%s' for '%s': %s", diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index c7b8787c45..f9cd946d44 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -327,7 +327,7 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, parent_ifindex = nm_device_get_ifindex (parent); p_key = nm_setting_infiniband_get_p_key (s_infiniband); - if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key) + if ( !nm_platform_infiniband_partition_add (NM_PLATFORM_GET, parent_ifindex, p_key, NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create InfiniBand P_Key interface '%s' for '%s': %s", diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index ba79a6ccb1..7d374348e7 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -715,7 +715,8 @@ create_virtual_device_for_connection (NMDeviceFactory *factory, iface, nm_device_get_ifindex (parent), nm_setting_vlan_get_id (s_vlan), - nm_setting_vlan_get_flags (s_vlan)) + nm_setting_vlan_get_flags (s_vlan), + NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create VLAN interface '%s' for '%s': %s", diff --git a/src/devices/team/nm-device-team.c b/src/devices/team/nm-device-team.c index 5cefde770c..1f80d543c4 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -692,7 +692,7 @@ nm_device_team_new_for_connection (NMConnection *connection, GError **error) g_assert (iface); - if ( !nm_platform_team_add (NM_PLATFORM_GET, iface) + if ( !nm_platform_team_add (NM_PLATFORM_GET, iface, NULL) && nm_platform_get_error (NM_PLATFORM_GET) != NM_PLATFORM_ERROR_EXISTS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create team master interface '%s' for '%s': %s", diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 0da6590ffb..2969e37b6b 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -162,13 +162,18 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l) { NMFakePlatformLink *device = link_get (platform, ifindex); - if (device) + if (device && l) *l = device->link; return !!device; } static gboolean -link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len) +link_add (NMPlatform *platform, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); NMFakePlatformLink device; @@ -180,6 +185,8 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a if (device.link.ifindex) g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, device.link.ifindex, &device, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_INTERNAL); + if (out_link) + *out_link = device.link; return TRUE; } @@ -584,11 +591,11 @@ slave_get_option (NMPlatform *platform, int slave, const char *option) } static gboolean -vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, NMPlatformLink *out_link) { NMFakePlatformLink *device; - if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0)) + if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, 0, NULL)) return FALSE; device = link_get (platform, link_get_ifindex (platform, name)); @@ -598,6 +605,8 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint device->vlan_id = vlan_id; device->link.parent = parent; + if (out_link) + *out_link = device->link; return TRUE; } @@ -629,7 +638,7 @@ vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to) } static gboolean -infiniband_partition_add (NMPlatform *platform, int parent, int p_key) +infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatformLink *out_link) { NMFakePlatformLink *parent_device; char *name; @@ -639,7 +648,7 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key) g_return_val_if_fail (parent_device != NULL, FALSE); name = g_strdup_printf ("%s.%04x", parent_device->link.name, p_key); - success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0); + success = link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, 0, out_link); g_free (name); return success; @@ -1313,15 +1322,15 @@ nm_fake_platform_setup (void) nm_platform_setup (platform); /* skip zero element */ - link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0); + link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, 0, NULL); /* add loopback interface */ - link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0); + link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, 0, NULL); /* add some ethernets */ - link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0); - link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0); - link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0); + link_add (platform, "eth0", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL); + link_add (platform, "eth1", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL); + link_add (platform, "eth2", NM_LINK_TYPE_ETHERNET, NULL, 0, NULL); } static void diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 532fa4de4e..68688280d9 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2304,9 +2304,10 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); auto_nl_object struct rtnl_link *rtnllink = NULL; + NMPlatformLink tmp = { 0 }; rtnllink = rtnl_link_get (priv->link_cache, ifindex); - return (rtnllink && init_link (platform, l, rtnllink)); + return (rtnllink && init_link (platform, l ? l : &tmp, rtnllink)); } static struct nl_object * @@ -2324,7 +2325,25 @@ build_rtnl_link (int ifindex, const char *name, NMLinkType type) } static gboolean -link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *address, size_t address_len) +link_get_by_name (NMPlatform *platform, const char *name, NMPlatformLink *out_link) +{ + int ifindex; + + if (out_link) { + ifindex = nm_platform_link_get_ifindex (platform, name); + g_return_val_if_fail (ifindex > 0, FALSE); + return _nm_platform_link_get (platform, ifindex, out_link); + } + return TRUE; +} + +static gboolean +link_add (NMPlatform *platform, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { struct nl_object *l; @@ -2351,7 +2370,11 @@ link_add (NMPlatform *platform, const char *name, NMLinkType type, const void *a rtnl_link_set_addr ((struct rtnl_link *) l, nladdr); } - return add_object (platform, l); + + if (!add_object (platform, l)) + return FALSE; + + return link_get_by_name (platform, name, out_link); } static struct rtnl_link * @@ -2842,7 +2865,12 @@ link_get_dev_id (NMPlatform *platform, int ifindex) } static int -vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags) +vlan_add (NMPlatform *platform, + const char *name, + int parent, + int vlan_id, + guint32 vlan_flags, + NMPlatformLink *out_link) { struct nl_object *object = build_rtnl_link (0, name, NM_LINK_TYPE_VLAN); struct rtnl_link *rtnllink = (struct rtnl_link *) object; @@ -2863,7 +2891,10 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint debug ("link: add vlan '%s', parent %d, vlan id %d, flags %X (native: %X)", name, parent, vlan_id, (unsigned int) vlan_flags, kernel_flags); - return add_object (platform, object); + if (!add_object (platform, object)) + return FALSE; + + return link_get_by_name (platform, name, out_link); } static gboolean @@ -3024,7 +3055,7 @@ slave_get_option (NMPlatform *platform, int slave, const char *option) } static gboolean -infiniband_partition_add (NMPlatform *platform, int parent, int p_key) +infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatformLink *out_link) { const char *parent_name; char *path, *id; @@ -3044,6 +3075,8 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key) auto_nl_object struct rtnl_link *rtnllink = _nm_rtnl_link_alloc (0, ifname); success = refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_INTERNAL); + if (success) + success = link_get_by_name (platform, ifname, out_link); } return success; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 844ad32cda..0b51614e2f 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -536,7 +536,6 @@ nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link) _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (link, FALSE); g_return_val_if_fail (klass->link_get, FALSE); return !!klass->link_get (self, ifindex, link); @@ -549,14 +548,24 @@ nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link) * @type: Interface type * @address: (allow-none): set the mac address of the link * @address_len: the length of the @address + * @out_link: on success, the link object * - * Add a software interface. Sets self->error to NM_PLATFORM_ERROR_EXISTS - * if interface is already already exists. Any link-changed ADDED signal will be - * emitted directly, before this function finishes. + * Add a software interface. If the interface already exists and is of type + * @type, sets platform->error to NM_PLATFORM_ERROR_EXISTS and returns the link + * in @out_link. If the interface already exists and is not of type @type, + * sets platform->error to NM_PLATFORM_ERROR_WRONG_TYPE. Any link-changed ADDED + * signal will be emitted directly, before this function finishes. */ static gboolean -nm_platform_link_add (NMPlatform *self, const char *name, NMLinkType type, const void *address, size_t address_len) +nm_platform_link_add (NMPlatform *self, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { + int ifindex; + _CHECK_SELF (self, klass, FALSE); reset_error (self); @@ -564,29 +573,37 @@ nm_platform_link_add (NMPlatform *self, const char *name, NMLinkType type, const g_return_val_if_fail (klass->link_add, FALSE); g_return_val_if_fail ( (address != NULL) ^ (address_len == 0) , FALSE); - if (nm_platform_link_exists (self, name)) { + ifindex = nm_platform_link_get_ifindex (self, name); + if (ifindex > 0) { debug ("link: already exists"); - self->error = NM_PLATFORM_ERROR_EXISTS; + if (nm_platform_link_get_type (self, ifindex) != type) + self->error = NM_PLATFORM_ERROR_WRONG_TYPE; + else { + self->error = NM_PLATFORM_ERROR_EXISTS; + (void) nm_platform_link_get (self, ifindex, out_link); + } return FALSE; } - return klass->link_add (self, name, type, address, address_len); + reset_error(self); + return klass->link_add (self, name, type, address, address_len, out_link); } /** * nm_platform_dummy_add: * @self: platform instance * @name: New interface name + * @out_link: on success, the link object * * Create a software ethernet-like interface */ gboolean -nm_platform_dummy_add (NMPlatform *self, const char *name) +nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { g_return_val_if_fail (name, FALSE); debug ("link: adding dummy '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0); + return nm_platform_link_add (self, name, NM_LINK_TYPE_DUMMY, NULL, 0, out_link); } /** @@ -1277,42 +1294,49 @@ nm_platform_link_get_master (NMPlatform *self, int slave) * @name: New interface name * @address: (allow-none): set the mac address of the new bridge * @address_len: the length of the @address + * @out_link: on success, the link object * * Create a software bridge. */ gboolean -nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len) +nm_platform_bridge_add (NMPlatform *self, + const char *name, + const void *address, + size_t address_len, + NMPlatformLink *out_link) { debug ("link: adding bridge '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len); + return nm_platform_link_add (self, name, NM_LINK_TYPE_BRIDGE, address, address_len, out_link); } /** * nm_platform_bond_add: * @self: platform instance * @name: New interface name + * @out_link: on success, the link object * * Create a software bonding device. */ gboolean -nm_platform_bond_add (NMPlatform *self, const char *name) +nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { debug ("link: adding bond '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0); + return nm_platform_link_add (self, name, NM_LINK_TYPE_BOND, NULL, 0, out_link); } /** * nm_platform_team_add: * @self: platform instance * @name: New interface name + * @out_link: on success, the link object * * Create a software teaming device. */ gboolean -nm_platform_team_add (NMPlatform *self, const char *name) +nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link) { debug ("link: adding team '%s'", name); - return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0); + return nm_platform_link_add (self, name, NM_LINK_TYPE_TEAM, NULL, 0, out_link); } /** @@ -1321,11 +1345,17 @@ nm_platform_team_add (NMPlatform *self, const char *name) * @name: New interface name * @vlanid: VLAN identifier * @vlanflags: VLAN flags from libnm + * @out_link: on success, the link object * * Create a software VLAN device. */ gboolean -nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags) +nm_platform_vlan_add (NMPlatform *self, + const char *name, + int parent, + int vlanid, + guint32 vlanflags, + NMPlatformLink *out_link) { _CHECK_SELF (self, klass, FALSE); reset_error (self); @@ -1343,7 +1373,7 @@ nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid debug ("link: adding vlan '%s' parent %d vlanid %d vlanflags %x", name, parent, vlanid, vlanflags); - return klass->vlan_add (self, name, parent, vlanid, vlanflags); + return klass->vlan_add (self, name, parent, vlanid, vlanflags, out_link); } gboolean @@ -1444,7 +1474,7 @@ nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to } gboolean -nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key) +nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link) { const char *parent_name; char *name; @@ -1471,7 +1501,7 @@ nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key) } g_free (name); - return klass->infiniband_partition_add (self, parent, p_key); + return klass->infiniband_partition_add (self, parent, p_key, out_link); } gboolean diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 1de8747a59..ea8d82994f 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -375,7 +375,12 @@ typedef struct { gboolean (*link_get) (NMPlatform *platform, int ifindex, NMPlatformLink *link); GArray *(*link_get_all) (NMPlatform *); - gboolean (*link_add) (NMPlatform *, const char *name, NMLinkType type, const void *address, size_t address_len); + gboolean (*link_add) (NMPlatform *, + const char *name, + NMLinkType type, + const void *address, + size_t address_len, + NMPlatformLink *out_link); gboolean (*link_delete) (NMPlatform *, int ifindex); int (*link_get_ifindex) (NMPlatform *, const char *name); const char *(*link_get_name) (NMPlatform *, int ifindex); @@ -418,12 +423,12 @@ typedef struct { gboolean (*slave_set_option) (NMPlatform *, int ifindex, const char *option, const char *value); char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option); - gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags); + gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link); gboolean (*vlan_get_info) (NMPlatform *, int ifindex, int *parent, int *vlan_id); gboolean (*vlan_set_ingress_map) (NMPlatform *, int ifindex, int from, int to); gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to); - gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key); + gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link); gboolean (*veth_get_properties) (NMPlatform *, int ifindex, NMPlatformVethProperties *properties); gboolean (*tun_get_properties) (NMPlatform *, int ifindex, NMPlatformTunProperties *properties); @@ -526,10 +531,10 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char gboolean nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link); GArray *nm_platform_link_get_all (NMPlatform *self); -gboolean nm_platform_dummy_add (NMPlatform *self, const char *name); -gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len); -gboolean nm_platform_bond_add (NMPlatform *self, const char *name); -gboolean nm_platform_team_add (NMPlatform *self, const char *name); +gboolean nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); +gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, NMPlatformLink *out_link); +gboolean nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); +gboolean nm_platform_team_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); gboolean nm_platform_link_exists (NMPlatform *self, const char *name); gboolean nm_platform_link_delete (NMPlatform *self, int ifindex); int nm_platform_link_get_ifindex (NMPlatform *self, const char *name); @@ -575,12 +580,12 @@ char *nm_platform_master_get_option (NMPlatform *self, int ifindex, const char * gboolean nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value); char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option); -gboolean nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags); +gboolean nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link); gboolean nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid); gboolean nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to); gboolean nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to); -gboolean nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key); +gboolean nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link); gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *properties); gboolean nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties); diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c index 07ca8f9108..d46d140abd 100644 --- a/src/platform/tests/platform.c +++ b/src/platform/tests/platform.c @@ -93,25 +93,25 @@ do_link_get_all (char **argv) static gboolean do_dummy_add (char **argv) { - return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0]); + return nm_platform_dummy_add (NM_PLATFORM_GET, argv[0], NULL); } static gboolean do_bridge_add (char **argv) { - return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0); + return nm_platform_bridge_add (NM_PLATFORM_GET, argv[0], NULL, 0, NULL); } static gboolean do_bond_add (char **argv) { - return nm_platform_bond_add (NM_PLATFORM_GET, argv[0]); + return nm_platform_bond_add (NM_PLATFORM_GET, argv[0], NULL); } static gboolean do_team_add (char **argv) { - return nm_platform_team_add (NM_PLATFORM_GET, argv[0]); + return nm_platform_team_add (NM_PLATFORM_GET, argv[0], NULL); } static gboolean @@ -122,7 +122,7 @@ do_vlan_add (char **argv) int vlanid = strtol (*argv++, NULL, 10); guint32 vlan_flags = strtol (*argv++, NULL, 10); - return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags); + return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent, vlanid, vlan_flags, NULL); } static gboolean diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index 0547261551..e7b0a47388 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -259,7 +259,7 @@ setup_tests (void) nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); accept_signal (link_added); free_signal (link_added); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 473489da81..962730463f 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -35,7 +35,7 @@ test_cleanup_internal (void) inet_pton (AF_INET6, "2001:db8:e:f:1:2:3:4", &gateway6); /* Create and set up device */ - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); accept_signal (link_added); free_signal (link_added); g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME))); diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index d82d0165e6..bbd42946af 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -90,13 +90,13 @@ software_add (NMLinkType link_type, const char *name) { switch (link_type) { case NM_LINK_TYPE_DUMMY: - return nm_platform_dummy_add (NM_PLATFORM_GET, name); + return nm_platform_dummy_add (NM_PLATFORM_GET, name, NULL); case NM_LINK_TYPE_BRIDGE: - return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0); + return nm_platform_bridge_add (NM_PLATFORM_GET, name, NULL, 0, NULL); case NM_LINK_TYPE_BOND: { gboolean bond0_exists = nm_platform_link_exists (NM_PLATFORM_GET, "bond0"); - gboolean result = nm_platform_bond_add (NM_PLATFORM_GET, name); + gboolean result = nm_platform_bond_add (NM_PLATFORM_GET, name, NULL); NMPlatformError error = nm_platform_get_error (NM_PLATFORM_GET); /* Check that bond0 is *not* automatically created. */ @@ -107,14 +107,14 @@ software_add (NMLinkType link_type, const char *name) return result; } case NM_LINK_TYPE_TEAM: - return nm_platform_team_add (NM_PLATFORM_GET, name); + return nm_platform_team_add (NM_PLATFORM_GET, name, NULL); case NM_LINK_TYPE_VLAN: { SignalData *parent_added; SignalData *parent_changed; /* Don't call link_callback for the bridge interface */ parent_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, PARENT_NAME); - if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0)) + if (nm_platform_bridge_add (NM_PLATFORM_GET, PARENT_NAME, NULL, 0, NULL)) accept_signal (parent_added); free_signal (parent_added); @@ -126,7 +126,7 @@ software_add (NMLinkType link_type, const char *name) accept_signal (parent_changed); free_signal (parent_changed); - return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0); + return nm_platform_vlan_add (NM_PLATFORM_GET, name, parent_ifindex, VLAN_ID, 0, NULL); } } default: @@ -403,12 +403,12 @@ test_internal (void) error (NM_PLATFORM_ERROR_NOT_FOUND); /* Add device */ - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); no_error (); accept_signal (link_added); /* Try to add again */ - g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (!nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); error (NM_PLATFORM_ERROR_EXISTS); /* Check device index, name and type */ diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index c22ce51571..dcc74d9621 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -324,7 +324,7 @@ setup_tests (void) nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME)); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, DEVICE_NAME)); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME)); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, DEVICE_NAME, NULL)); accept_signal (link_added); free_signal (link_added); diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 17bcb454c1..f7b37a3b4a 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -639,7 +639,7 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data) "nm-test-device0"); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0")); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device0")); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0")); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL)); accept_signal (link_added); free_signal (link_added); fixture->ifindex0 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0"); @@ -651,7 +651,7 @@ fixture_setup (test_fixture *fixture, gconstpointer user_data) "nm-test-device1"); nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1")); g_assert (!nm_platform_link_exists (NM_PLATFORM_GET, "nm-test-device1")); - g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1")); + g_assert (nm_platform_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL)); accept_signal (link_added); free_signal (link_added); fixture->ifindex1 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1"); From 29ccb8851ce09855d227cdc5e58ebc31e25cb4c5 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 16 Oct 2014 09:23:10 -0500 Subject: [PATCH 10/14] platform: ensure created interface matches requested type If the caller requested that a bond be created, don't return success if there was an existing bridge with the same name. --- src/platform/nm-linux-platform.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 68688280d9..bd8fb185db 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -1776,12 +1776,14 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed announce_object (platform, kernel_object, cached_object ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, reason); - /* Refresh the master device (even on enslave/release) */ if (type == OBJECT_TYPE_LINK) { int kernel_master = rtnl_link_get_master ((struct rtnl_link *) kernel_object); int cached_master = cached_object ? rtnl_link_get_master ((struct rtnl_link *) cached_object) : 0; + const char *orig_link_type = rtnl_link_get_type ((struct rtnl_link *) object); + const char *kernel_link_type = rtnl_link_get_type ((struct rtnl_link *) kernel_object); struct nl_object *master_object; + /* Refresh the master device (even on enslave/release) */ if (kernel_master) { master_object = build_rtnl_link (kernel_master, NULL, NM_LINK_TYPE_NONE); refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL); @@ -1792,6 +1794,12 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed refresh_object (platform, master_object, FALSE, NM_PLATFORM_REASON_INTERNAL); nl_object_put (master_object); } + + /* Ensure the existing link type matches the refreshed link type */ + if (orig_link_type && kernel_link_type && strcmp (orig_link_type, kernel_link_type)) { + platform->error = NM_PLATFORM_ERROR_WRONG_TYPE; + return FALSE; + } } } @@ -2329,6 +2337,8 @@ link_get_by_name (NMPlatform *platform, const char *name, NMPlatformLink *out_li { int ifindex; + g_return_val_if_fail (name != NULL, FALSE); + if (out_link) { ifindex = nm_platform_link_get_ifindex (platform, name); g_return_val_if_fail (ifindex > 0, FALSE); @@ -3072,8 +3082,9 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatfor if (success) { gs_free char *ifname = g_strdup_printf ("%s.%04x", parent_name, p_key); - auto_nl_object struct rtnl_link *rtnllink = _nm_rtnl_link_alloc (0, ifname); + auto_nl_object struct rtnl_link *rtnllink; + rtnllink = (struct rtnl_link *) build_rtnl_link (0, ifname, NM_LINK_TYPE_INFINIBAND); success = refresh_object (platform, (struct nl_object *) rtnllink, FALSE, NM_PLATFORM_REASON_INTERNAL); if (success) success = link_get_by_name (platform, ifname, out_link); From fa74ed7ca1bf014b774d1e537e12df80a9c22af4 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 18 Sep 2014 12:16:11 -0500 Subject: [PATCH 11/14] platform: add nm_platform_link_get_by_address() --- src/platform/nm-fake-platform.c | 23 +++++++++++++++++++++++ src/platform/nm-linux-platform.c | 25 +++++++++++++++++++++++++ src/platform/nm-platform.c | 29 +++++++++++++++++++++++++++++ src/platform/nm-platform.h | 2 ++ 4 files changed, 79 insertions(+) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 2969e37b6b..1d74a3c5e7 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -167,6 +167,28 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l) return !!device; } +static gboolean +_nm_platform_link_get_by_address (NMPlatform *platform, + gconstpointer address, + size_t length, + NMPlatformLink *l) +{ + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform); + guint i; + + for (i = 0; i < priv->links->len; i++) { + NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); + + if ( device->address + && g_bytes_get_size (device->address) == length + && memcmp (g_bytes_get_data (device->address, NULL), address, length) == 0) { + *l = device->link; + return TRUE; + } + } + return FALSE; +} + static gboolean link_add (NMPlatform *platform, const char *name, @@ -1370,6 +1392,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->sysctl_get = sysctl_get; platform_class->link_get = _nm_platform_link_get; + platform_class->link_get_by_address = _nm_platform_link_get_by_address; platform_class->link_get_all = link_get_all; platform_class->link_add = link_add; platform_class->link_delete = link_delete; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index bd8fb185db..fecbdf001c 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2318,6 +2318,30 @@ _nm_platform_link_get (NMPlatform *platform, int ifindex, NMPlatformLink *l) return (rtnllink && init_link (platform, l ? l : &tmp, rtnllink)); } +static gboolean +_nm_platform_link_get_by_address (NMPlatform *platform, + gconstpointer address, + size_t length, + NMPlatformLink *l) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + struct nl_object *object; + + for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) { + struct rtnl_link *rtnl_link = (struct rtnl_link *) object; + struct nl_addr *nladdr; + gconstpointer hwaddr; + + nladdr = rtnl_link_get_addr (rtnl_link); + if (nladdr && (nl_addr_get_len (nladdr) == length)) { + hwaddr = nl_addr_get_binary_addr (nladdr); + if (hwaddr && memcmp (hwaddr, address, length) == 0) + return init_link (platform, l, rtnl_link); + } + } + return FALSE; +} + static struct nl_object * build_rtnl_link (int ifindex, const char *name, NMLinkType type) { @@ -4705,6 +4729,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->sysctl_get = sysctl_get; platform_class->link_get = _nm_platform_link_get; + platform_class->link_get_by_address = _nm_platform_link_get_by_address; platform_class->link_get_all = link_get_all; platform_class->link_add = link_add; platform_class->link_delete = link_delete; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 0b51614e2f..ff81ec01cc 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -541,6 +541,35 @@ nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link) return !!klass->link_get (self, ifindex, link); } +/** + * nm_platform_link_get_by_address: + * @self: platform instance + * @address: a pointer to the binary hardware address + * @length: the size of @address in bytes + * @link: (out): output NMPlatformLink structure. + * + * If a link with given @address exists, fill the given NMPlatformLink + * structure. + * + * Returns: %TRUE, if such a link exists, %FALSE otherwise. + * If the link does not exist, the content of @link is undefined. + **/ +gboolean +nm_platform_link_get_by_address (NMPlatform *self, + gconstpointer address, + size_t length, + NMPlatformLink *link) +{ + _CHECK_SELF (self, klass, FALSE); + + g_return_val_if_fail (address != NULL, FALSE); + g_return_val_if_fail (length > 0, FALSE); + g_return_val_if_fail (link, FALSE); + + g_return_val_if_fail (klass->link_get_by_address, FALSE); + return !!klass->link_get_by_address (self, address, length, link); +} + /** * nm_platform_link_add: * @self: platform instance diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index ea8d82994f..df03f80c5b 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -374,6 +374,7 @@ typedef struct { char * (*sysctl_get) (NMPlatform *, const char *path); gboolean (*link_get) (NMPlatform *platform, int ifindex, NMPlatformLink *link); + gboolean (*link_get_by_address) (NMPlatform *platform, gconstpointer address, size_t length, NMPlatformLink *link); GArray *(*link_get_all) (NMPlatform *); gboolean (*link_add) (NMPlatform *, const char *name, @@ -531,6 +532,7 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char gboolean nm_platform_link_get (NMPlatform *self, int ifindex, NMPlatformLink *link); GArray *nm_platform_link_get_all (NMPlatform *self); +gboolean nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length, NMPlatformLink *link); gboolean nm_platform_dummy_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); gboolean nm_platform_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, NMPlatformLink *out_link); gboolean nm_platform_bond_add (NMPlatform *self, const char *name, NMPlatformLink *out_link); From ddaea22332907c05222cbec1e1b4365689fbda9f Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 3 Oct 2014 13:41:49 -0500 Subject: [PATCH 12/14] platform: move driver & firmware version reading into the platform --- src/devices/nm-device.c | 53 ++++-------------------------- src/platform/nm-fake-platform.c | 21 ++++++++++++ src/platform/nm-linux-platform.c | 56 +++++++++++++++++++++++++------- src/platform/nm-platform.c | 32 ++++++++++++++++++ src/platform/nm-platform.h | 10 ++++++ 5 files changed, 114 insertions(+), 58 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 9e6d6d00e9..0874327264 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include #include @@ -8504,46 +8502,6 @@ nm_device_init (NMDevice *self) priv->default_route.v6_is_assumed = TRUE; } -/* - * Get driver info from SIOCETHTOOL ioctl() for 'iface' - * Returns driver and firmware versions to 'driver_version and' 'firmware_version' - */ -static gboolean -device_get_driver_info (NMDevice *self, const char *iface, char **driver_version, char **firmware_version) -{ - struct ethtool_drvinfo drvinfo; - struct ifreq req; - int fd; - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW, "couldn't open control socket."); - return FALSE; - } - - /* Get driver and firmware version info */ - memset (&drvinfo, 0, sizeof (drvinfo)); - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, iface, IFNAMSIZ); - drvinfo.cmd = ETHTOOL_GDRVINFO; - req.ifr_data = &drvinfo; - - errno = 0; - if (ioctl (fd, SIOCETHTOOL, &req) < 0) { - _LOGD (LOGD_HW, "SIOCETHTOOL ioctl() failed: cmd=ETHTOOL_GDRVINFO, iface=%s, errno=%d", - iface, errno); - close (fd); - return FALSE; - } - if (driver_version) - *driver_version = g_strdup (drvinfo.version); - if (firmware_version) - *firmware_version = g_strdup (drvinfo.fw_version); - - close (fd); - return TRUE; -} - static GObject* constructor (GType type, guint n_construct_params, @@ -8579,10 +8537,13 @@ constructor (GType type, if (NM_DEVICE_GET_CLASS (self)->get_generic_capabilities) priv->capabilities |= NM_DEVICE_GET_CLASS (self)->get_generic_capabilities (self); - if (priv->ifindex <= 0 && !nm_device_has_capability (self, NM_DEVICE_CAP_IS_NON_KERNEL)) - _LOGW (LOGD_HW, "failed to look up interface index"); - - device_get_driver_info (self, priv->iface, &priv->driver_version, &priv->firmware_version); + if (priv->ifindex > 0) { + nm_platform_link_get_driver_info (NM_PLATFORM_GET, + priv->ifindex, + NULL, + &priv->driver_version, + &priv->firmware_version); + } /* Watch for external IP config changes */ platform = nm_platform_get (); diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 1d74a3c5e7..4cf2e46452 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -502,6 +502,26 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) return FALSE; } +static gboolean +link_get_driver_info (NMPlatform *platform, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) +{ + if (out_driver_name) + *out_driver_name = NULL; + if (out_driver_version) + *out_driver_version = NULL; + if (out_fw_version) + *out_fw_version = NULL; + + /* We call link_get just to cause an error to be set if @ifindex is bad. */ + link_get (platform, ifindex); + + return TRUE; +} + static gboolean link_supports_carrier_detect (NMPlatform *platform, int ifindex) { @@ -1418,6 +1438,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; platform_class->link_get_wake_on_lan = link_get_wake_on_lan; + platform_class->link_get_driver_info = link_get_driver_info; platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index fecbdf001c..ab20af57d7 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -372,6 +372,9 @@ ethtool_get (const char *name, gpointer edata) struct ifreq ifr; int fd; + if (!name || !*name) + return FALSE; + memset (&ifr, 0, sizeof (ifr)); strncpy (ifr.ifr_name, name, IFNAMSIZ); ifr.ifr_data = edata; @@ -426,21 +429,29 @@ ethtool_get_stringset_index (const char *ifname, int stringset_id, const char *s return -1; } -static const char * -ethtool_get_driver (const char *ifname) +static gboolean +ethtool_get_driver_info (const char *ifname, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) { struct ethtool_drvinfo drvinfo = { 0 }; - g_return_val_if_fail (ifname != NULL, NULL); + if (!ifname) + return FALSE; drvinfo.cmd = ETHTOOL_GDRVINFO; if (!ethtool_get (ifname, &drvinfo)) - return NULL; + return FALSE; - if (!*drvinfo.driver) - return NULL; + if (out_driver_name) + *out_driver_name = g_strdup (drvinfo.driver); + if (out_driver_version) + *out_driver_version = g_strdup (drvinfo.version); + if (out_fw_version) + *out_fw_version = g_strdup (drvinfo.fw_version); - return g_intern_string (drvinfo.driver); + return TRUE; } /****************************************************************** @@ -983,7 +994,7 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) ifname = rtnl_link_get_name (rtnllink); if (ifname) { - const char *driver = ethtool_get_driver (ifname); + gs_free char *driver = NULL; gs_free char *sysfs_path = NULL; gs_free char *anycast_mask = NULL; gs_free char *devtype = NULL; @@ -997,8 +1008,10 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink) } /* Fallback OVS detection for kernel <= 3.16 */ - if (!g_strcmp0 (driver, "openvswitch")) - return NM_LINK_TYPE_OPENVSWITCH; + if (ethtool_get_driver_info (ifname, &driver, NULL, NULL)) { + if (!g_strcmp0 (driver, "openvswitch")) + return NM_LINK_TYPE_OPENVSWITCH; + } sysfs_path = g_strdup_printf ("/sys/class/net/%s", ifname); anycast_mask = g_strdup_printf ("%s/anycast_mask", sysfs_path); @@ -1041,6 +1054,7 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); GUdevDevice *udev_device; const char *name; + char *tmp; g_return_val_if_fail (rtnllink, FALSE); @@ -1070,8 +1084,12 @@ init_link (NMPlatform *platform, NMPlatformLink *info, struct rtnl_link *rtnllin if (!info->driver) info->driver = info->kind; - if (!info->driver) - info->driver = ethtool_get_driver (info->name); + if (!info->driver) { + if (ethtool_get_driver_info (name, &tmp, NULL, NULL)) { + info->driver = g_intern_string (tmp); + g_free (tmp); + } + } if (!info->driver) info->driver = "unknown"; @@ -3658,6 +3676,19 @@ link_get_wake_on_lan (NMPlatform *platform, int ifindex) return FALSE; } +static gboolean +link_get_driver_info (NMPlatform *platform, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) +{ + return ethtool_get_driver_info (nm_platform_link_get_name (platform, ifindex), + out_driver_name, + out_driver_version, + out_fw_version); +} + /******************************************************************/ static gboolean @@ -4762,6 +4793,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_get_physical_port_id = link_get_physical_port_id; platform_class->link_get_dev_id = link_get_dev_id; platform_class->link_get_wake_on_lan = link_get_wake_on_lan; + platform_class->link_get_driver_info = link_get_driver_info; platform_class->link_supports_carrier_detect = link_supports_carrier_detect; platform_class->link_supports_vlans = link_supports_vlans; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index ff81ec01cc..24baa38ff9 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1241,6 +1241,38 @@ nm_platform_link_get_wake_on_lan (NMPlatform *self, int ifindex) return klass->link_get_wake_on_lan (self, ifindex); } +/** + * nm_platform_link_get_driver_info: + * @self: platform instance + * @ifindex: Interface index + * @out_driver_name: (transfer full): on success, the driver name if available + * @out_driver_version: (transfer full): on success, the driver version if available + * @out_fw_version: (transfer full): on success, the firmware version if available + * + * Returns: %TRUE on success (though @out_driver_name, @out_driver_version and + * @out_fw_version can be %NULL if no information was available), %FALSE on + * failure. + */ +gboolean +nm_platform_link_get_driver_info (NMPlatform *self, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version) +{ + _CHECK_SELF (self, klass, FALSE); + reset_error (self); + + g_return_val_if_fail (ifindex >= 0, FALSE); + g_return_val_if_fail (klass->link_get_driver_info, FALSE); + + return klass->link_get_driver_info (self, + ifindex, + out_driver_name, + out_driver_version, + out_fw_version); +} + /** * nm_platform_link_enslave: * @self: platform instance diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index df03f80c5b..f09e617d38 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -412,6 +412,11 @@ typedef struct { char * (*link_get_physical_port_id) (NMPlatform *, int ifindex); guint (*link_get_dev_id) (NMPlatform *, int ifindex); gboolean (*link_get_wake_on_lan) (NMPlatform *, int ifindex); + gboolean (*link_get_driver_info) (NMPlatform *, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version); gboolean (*link_supports_carrier_detect) (NMPlatform *, int ifindex); gboolean (*link_supports_vlans) (NMPlatform *, int ifindex); @@ -570,6 +575,11 @@ gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); char *nm_platform_link_get_physical_port_id (NMPlatform *self, int ifindex); guint nm_platform_link_get_dev_id (NMPlatform *self, int ifindex); gboolean nm_platform_link_get_wake_on_lan (NMPlatform *self, int ifindex); +gboolean nm_platform_link_get_driver_info (NMPlatform *self, + int ifindex, + char **out_driver_name, + char **out_driver_version, + char **out_fw_version); gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex); gboolean nm_platform_link_supports_vlans (NMPlatform *self, int ifindex); From aba250a7d4e72a7a98e6d43b1fb36689671b4855 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 3 Oct 2014 17:37:26 -0500 Subject: [PATCH 13/14] core: move permanent and initial MAC address reading to NMDevice and NMPlatform Ethernet, WiFi, and VLAN used the same implementation for initial address. Ethernet and WiFi used the same implementation (and duplicated code) for permanent MAC address, plus they both used ethtool in what should be generic code, which is better done in the platform. --- src/devices/nm-device-ethernet.c | 142 ++++++++------------------- src/devices/nm-device-vlan.c | 32 +----- src/devices/nm-device.c | 46 ++++++++- src/devices/nm-device.h | 7 +- src/devices/wifi/nm-device-wifi.c | 157 +++++++++--------------------- src/platform/nm-fake-platform.c | 7 ++ src/platform/nm-linux-platform.c | 35 +++++++ src/platform/nm-platform.c | 31 +++++- src/platform/nm-platform.h | 5 + 9 files changed, 209 insertions(+), 253 deletions(-) diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index a728bf2394..114b2c9eb3 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -99,9 +99,6 @@ typedef enum { } DcbWait; typedef struct { - char * perm_hw_addr; /* Permanent MAC address */ - char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */ - guint32 speed; Supplicant supplicant; @@ -310,66 +307,6 @@ nm_device_ethernet_init (NMDeviceEthernet *self) priv->s390_options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } -static void -update_permanent_hw_address (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - struct ifreq req; - struct ethtool_perm_addr *epaddr = NULL; - int fd, ret, errsv; - const char *mac; - - g_return_if_fail (priv->perm_hw_addr == NULL); - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGW (LOGD_HW, "couldn't open control socket."); - return; - } - - /* Get permanent MAC address */ - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); - - epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN); - epaddr->cmd = ETHTOOL_GPERMADDR; - epaddr->size = ETH_ALEN; - req.ifr_data = (void *) epaddr; - - errno = 0; - ret = ioctl (fd, SIOCETHTOOL, &req); - errsv = errno; - if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) { - _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", errsv); - /* Fall back to current address */ - mac = nm_device_get_hw_address (dev); - if (mac) - nm_utils_hwaddr_aton (mac, epaddr->data, ETH_ALEN); - else - memset (epaddr->data, 0, ETH_ALEN); - } - - priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN); - - g_free (epaddr); - close (fd); -} - -static void -update_initial_hw_address (NMDevice *dev) -{ - NMDeviceEthernet *self = NM_DEVICE_ETHERNET (dev); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - - /* This sets initial MAC address from current MAC address. It should only - * be called from NMDevice constructor() to really get the initial address. - */ - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev)); - - _LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr); -} - static NMDeviceCapabilities get_generic_capabilities (NMDevice *device) { @@ -421,7 +358,6 @@ static gboolean check_connection_compatible (NMDevice *device, NMConnection *connection) { NMDeviceEthernet *self = NM_DEVICE_ETHERNET (device); - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); NMSettingWired *s_wired; if (!NM_DEVICE_CLASS (nm_device_ethernet_parent_class)->check_connection_compatible (device, connection)) @@ -438,7 +374,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; if (s_wired) { - const char *mac; + const char *mac, *perm_hw_addr; gboolean try_mac = TRUE; const char * const *mac_blacklist; int i; @@ -446,21 +382,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!match_subchans (self, s_wired, &try_mac)) return FALSE; + perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wired_get_mac_address (s_wired); - if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1)) - return FALSE; - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); - for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); + if (perm_hw_addr) { + if (try_mac && mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) return FALSE; + + /* Check for MAC address blacklist */ + mac_blacklist = nm_setting_wired_get_mac_address_blacklist (s_wired); + for (i = 0; mac_blacklist[i]; i++) { + if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { + g_warn_if_reached (); + return FALSE; + } + + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + return FALSE; } - - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1)) - return FALSE; - } + } else if (mac) + return FALSE; } return TRUE; @@ -1391,8 +1331,8 @@ deactivate (NMDevice *device) NM_DEVICE_ETHERNET_GET_PRIVATE (device)->last_pppoe_time = nm_utils_get_monotonic_timestamp_s (); /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_ETHER); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_ETHER); } static gboolean @@ -1402,10 +1342,10 @@ complete_connection (NMDevice *device, const GSList *existing_connections, GError **error) { - NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMSettingWired *s_wired; NMSettingPppoe *s_pppoe; const char *setting_mac; + const char *perm_hw_addr; s_pppoe = nm_connection_get_setting_pppoe (connection); @@ -1432,21 +1372,22 @@ complete_connection (NMDevice *device, nm_connection_add_setting (connection, NM_SETTING (s_wired)); } - setting_mac = nm_setting_wired_get_mac_address (s_wired); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); - return FALSE; - } - } else { - if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) { + perm_hw_addr = nm_device_get_permanent_hw_address (device); + if (perm_hw_addr) { + setting_mac = nm_setting_wired_get_mac_address (s_wired); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("connection does not match device")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_WIRED_MAC_ADDRESS); + return FALSE; + } + } else { g_object_set (G_OBJECT (s_wired), - NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr, + NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); } } @@ -1515,6 +1456,7 @@ update_connection (NMDevice *device, NMConnection *connection) { NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (device); NMSettingWired *s_wired = nm_connection_get_setting_wired (connection); + const char *perm_hw_addr = nm_device_get_permanent_hw_address (device); const char *mac = nm_device_get_hw_address (device); const char *mac_prop = NM_SETTING_WIRED_MAC_ADDRESS; GHashTableIter iter; @@ -1528,11 +1470,11 @@ update_connection (NMDevice *device, NMConnection *connection) /* If the device reports a permanent address, use that for the MAC address * and the current MAC, if different, is the cloned MAC. */ - if (!nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, NULL, ETH_ALEN)) { - g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, priv->perm_hw_addr, NULL); + if (perm_hw_addr) { + g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS, perm_hw_addr, NULL); mac_prop = NULL; - if (mac && !nm_utils_hwaddr_matches (priv->perm_hw_addr, -1, mac, -1)) + if (mac && !nm_utils_hwaddr_matches (perm_hw_addr, -1, mac, -1)) mac_prop = NM_SETTING_WIRED_CLONED_MAC_ADDRESS; } @@ -1649,8 +1591,6 @@ finalize (GObject *object) NMDeviceEthernet *self = NM_DEVICE_ETHERNET (object); NMDeviceEthernetPrivate *priv = NM_DEVICE_ETHERNET_GET_PRIVATE (self); - g_free (priv->perm_hw_addr); - g_free (priv->initial_hw_addr); g_clear_object (&priv->supplicant.mgr); g_free (priv->subchan1); g_free (priv->subchan2); @@ -1671,7 +1611,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, priv->perm_hw_addr); + g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (object))); break; case PROP_SPEED: g_value_set_uint (value, priv->speed); @@ -1711,8 +1651,6 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) object_class->set_property = set_property; parent_class->get_generic_capabilities = get_generic_capabilities; - parent_class->update_permanent_hw_address = update_permanent_hw_address; - parent_class->update_initial_hw_address = update_initial_hw_address; 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-vlan.c b/src/devices/nm-device-vlan.c index 7d374348e7..ce2005a8ad 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -52,8 +52,6 @@ G_DEFINE_TYPE (NMDeviceVlan, nm_device_vlan, NM_TYPE_DEVICE) #define NM_DEVICE_VLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VLAN, NMDeviceVlanPrivate)) typedef struct { - char *initial_hw_addr; - gboolean disposed; gboolean invalid; @@ -75,16 +73,6 @@ enum { /******************************************************************/ -static void -update_initial_hw_address (NMDevice *dev) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (dev); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (dev)); - _LOGD (LOGD_DEVICE | LOGD_VLAN, "read initial MAC address %s", priv->initial_hw_addr); -} - static NMDeviceCapabilities get_generic_capabilities (NMDevice *dev) { @@ -461,12 +449,9 @@ ip4_config_pre_commit (NMDevice *device, NMIP4Config *config) static void deactivate (NMDevice *device) { - NMDeviceVlan *self = NM_DEVICE_VLAN (device); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_VLAN); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_VLAN); } /******************************************************************/ @@ -582,17 +567,6 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_device_vlan_parent_class)->dispose (object); } -static void -finalize (GObject *object) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (object); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - g_free (priv->initial_hw_addr); - - G_OBJECT_CLASS (nm_device_vlan_parent_class)->finalize (object); -} - static void nm_device_vlan_class_init (NMDeviceVlanClass *klass) { @@ -608,9 +582,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; object_class->dispose = dispose; - object_class->finalize = finalize; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->bring_up = bring_up; parent_class->act_stage1_prepare = act_stage1_prepare; diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 0874327264..9bfd5b3a0b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -201,6 +201,8 @@ typedef struct { GHashTable * available_connections; char * hw_addr; guint hw_addr_len; + char * perm_hw_addr; + char * initial_hw_addr; char * physical_port_id; guint dev_id; @@ -8408,6 +8410,22 @@ nm_device_set_hw_addr (NMDevice *self, const char *addr, return success; } +const char * +nm_device_get_permanent_hw_address (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + return NM_DEVICE_GET_PRIVATE (self)->perm_hw_addr; +} + +const char * +nm_device_get_initial_hw_address (NMDevice *self) +{ + g_return_val_if_fail (NM_IS_DEVICE (self), NULL); + + return NM_DEVICE_GET_PRIVATE (self)->initial_hw_addr; +} + /** * nm_device_spec_match_list: * @self: an #NMDevice @@ -8579,13 +8597,29 @@ constructed (GObject *object) nm_device_update_hw_address (self); - if (NM_DEVICE_GET_CLASS (self)->update_permanent_hw_address) - NM_DEVICE_GET_CLASS (self)->update_permanent_hw_address (self); + if (priv->hw_addr_len) { + priv->initial_hw_addr = g_strdup (priv->hw_addr); + _LOGD (LOGD_DEVICE | LOGD_HW, "read initial MAC address %s", priv->initial_hw_addr); - if (NM_DEVICE_GET_CLASS (self)->update_initial_hw_address) - NM_DEVICE_GET_CLASS (self)->update_initial_hw_address (self); + if (priv->ifindex > 0) { + guint8 buf[NM_UTILS_HWADDR_LEN_MAX]; + size_t len = 0; - /* Have to call update_initial_hw_address() before calling get_ignore_carrier() */ + if (nm_platform_link_get_permanent_address (NM_PLATFORM_GET, priv->ifindex, buf, &len)) { + g_warn_if_fail (len == priv->hw_addr_len); + priv->perm_hw_addr = nm_utils_hwaddr_ntoa (buf, priv->hw_addr_len); + _LOGD (LOGD_DEVICE | LOGD_HW, "read permanent MAC address %s", + priv->perm_hw_addr); + } else { + /* Fall back to current address */ + _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", + nm_platform_get_error (NM_PLATFORM_GET)); + priv->perm_hw_addr = g_strdup (priv->hw_addr); + } + } + } + + /* Note: initial hardware address must be read before calling get_ignore_carrier() */ if (nm_device_has_capability (self, NM_DEVICE_CAP_CARRIER_DETECT)) { NMConfig *config = nm_config_get (); @@ -8718,6 +8752,8 @@ finalize (GObject *object) _LOGD (LOGD_DEVICE, "finalize(): %s", G_OBJECT_TYPE_NAME (self)); g_free (priv->hw_addr); + g_free (priv->perm_hw_addr); + g_free (priv->initial_hw_addr); g_slist_free_full (priv->pending_actions, g_free); g_clear_pointer (&priv->physical_port_id, g_free); g_free (priv->udi); diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h index e3daa9b615..218faa4fa1 100644 --- a/src/devices/nm-device.h +++ b/src/devices/nm-device.h @@ -139,9 +139,6 @@ typedef struct { /* Carrier state (IFF_LOWER_UP) */ void (*carrier_changed) (NMDevice *, gboolean carrier); - void (* update_permanent_hw_address) (NMDevice *self); - void (* update_initial_hw_address) (NMDevice *self); - gboolean (* get_ip_iface_identifier) (NMDevice *self, NMUtilsIPv6IfaceId *out_iid); NMDeviceCapabilities (* get_generic_capabilities) (NMDevice *self); @@ -287,7 +284,9 @@ int nm_device_get_priority (NMDevice *dev); guint32 nm_device_get_ip4_route_metric (NMDevice *dev); guint32 nm_device_get_ip6_route_metric (NMDevice *dev); -const char * nm_device_get_hw_address (NMDevice *dev); +const char * nm_device_get_hw_address (NMDevice *dev); +const char * nm_device_get_permanent_hw_address (NMDevice *dev); +const char * nm_device_get_initial_hw_address (NMDevice *dev); NMDhcp4Config * nm_device_get_dhcp4_config (NMDevice *dev); NMDhcp6Config * nm_device_get_dhcp6_config (NMDevice *dev); diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index cc4db66628..500fa3aade 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -26,13 +26,7 @@ #include #include #include -#include -#include -#include #include -#include -#include -#include #include #include "nm-glib-compat.h" @@ -117,9 +111,6 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; struct _NMDeviceWifiPrivate { - char * perm_hw_addr; /* Permanent MAC address */ - char * initial_hw_addr; /* Initial MAC address (as seen when NM starts) */ - gint8 invalid_strength_counter; GHashTable * aps; @@ -533,8 +524,8 @@ deactivate (NMDevice *device) nm_platform_wifi_indicate_addressing_running (NM_PLATFORM_GET, ifindex, FALSE); /* Reset MAC address back to initial address */ - if (priv->initial_hw_addr) - nm_device_set_hw_addr (device, priv->initial_hw_addr, "reset", LOGD_WIFI); + if (nm_device_get_initial_hw_address (device)) + nm_device_set_hw_addr (device, nm_device_get_initial_hw_address (device), "reset", LOGD_WIFI); nm_platform_wifi_set_powersave (NM_PLATFORM_GET, ifindex, 0); @@ -600,6 +591,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) const char * const *mac_blacklist; int i; const char *mode; + const char *perm_hw_addr; if (!NM_DEVICE_CLASS (nm_device_wifi_parent_class)->check_connection_compatible (device, connection)) return FALSE; @@ -614,21 +606,25 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) if (!s_wireless) return FALSE; + perm_hw_addr = nm_device_get_permanent_hw_address (device); mac = nm_setting_wireless_get_mac_address (s_wireless); - if (mac && !nm_utils_hwaddr_matches (mac, -1, priv->perm_hw_addr, -1)) - return FALSE; - - /* Check for MAC address blacklist */ - mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); - for (i = 0; mac_blacklist[i]; i++) { - if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { - g_warn_if_reached (); + if (perm_hw_addr) { + if (mac && !nm_utils_hwaddr_matches (mac, -1, perm_hw_addr, -1)) return FALSE; + + /* Check for MAC address blacklist */ + mac_blacklist = nm_setting_wireless_get_mac_address_blacklist (s_wireless); + for (i = 0; mac_blacklist[i]; i++) { + if (!nm_utils_hwaddr_valid (mac_blacklist[i], ETH_ALEN)) { + g_warn_if_reached (); + return FALSE; + } + + if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, perm_hw_addr, -1)) + return FALSE; } - - if (nm_utils_hwaddr_matches (mac_blacklist[i], -1, priv->perm_hw_addr, -1)) - return FALSE; - } + } else if (mac) + return FALSE; if (is_adhoc_wpa (connection)) return FALSE; @@ -767,7 +763,6 @@ complete_connection (NMDevice *device, GError **error) { NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); NMSettingWireless *s_wifi; NMSettingWirelessSecurity *s_wsec; NMSetting8021x *s_8021x; @@ -778,6 +773,7 @@ complete_connection (NMDevice *device, GByteArray *tmp_ssid = NULL; GBytes *setting_ssid = NULL; gboolean hidden = FALSE; + const char *perm_hw_addr; s_wifi = nm_connection_get_setting_wireless (connection); s_wsec = nm_connection_get_setting_wireless_security (connection); @@ -908,29 +904,31 @@ complete_connection (NMDevice *device, if (hidden) g_object_set (s_wifi, NM_SETTING_WIRELESS_HIDDEN, TRUE, NULL); - setting_mac = nm_setting_wireless_get_mac_address (s_wifi); - if (setting_mac) { - /* Make sure the setting MAC (if any) matches the device's permanent MAC */ - if (!nm_utils_hwaddr_matches (setting_mac, -1, priv->perm_hw_addr, -1)) { - g_set_error_literal (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("connection does not match device")); - g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); - return FALSE; - } - } else { - guint8 perm_hw_addr[ETH_ALEN]; + perm_hw_addr = nm_device_get_permanent_hw_address (device); + if (perm_hw_addr) { + setting_mac = nm_setting_wireless_get_mac_address (s_wifi); + if (setting_mac) { + /* Make sure the setting MAC (if any) matches the device's permanent MAC */ + if (!nm_utils_hwaddr_matches (setting_mac, -1, perm_hw_addr, -1)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("connection does not match device")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_WIRELESS_SETTING_NAME, NM_SETTING_WIRELESS_MAC_ADDRESS); + return FALSE; + } + } else { + guint8 tmp[ETH_ALEN]; - /* Lock the connection to this device by default if it uses a - * permanent MAC address (ie not a 'locally administered' one) - */ - nm_utils_hwaddr_aton (priv->perm_hw_addr, perm_hw_addr, ETH_ALEN); - if ( !(perm_hw_addr[0] & 0x02) - && !nm_utils_hwaddr_matches (perm_hw_addr, ETH_ALEN, NULL, ETH_ALEN)) { - g_object_set (G_OBJECT (s_wifi), - NM_SETTING_WIRELESS_MAC_ADDRESS, priv->perm_hw_addr, - NULL); + /* Lock the connection to this device by default if it uses a + * permanent MAC address (ie not a 'locally administered' one) + */ + nm_utils_hwaddr_aton (perm_hw_addr, tmp, ETH_ALEN); + if (!(tmp[0] & 0x02)) { + g_object_set (G_OBJECT (s_wifi), + NM_SETTING_WIRELESS_MAC_ADDRESS, perm_hw_addr, + NULL); + } } } @@ -2241,62 +2239,6 @@ error: /****************************************************************************/ -static void -update_permanent_hw_address (NMDevice *device) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - struct ifreq req; - struct ethtool_perm_addr *epaddr = NULL; - int fd, ret, errsv; - - g_return_if_fail (priv->perm_hw_addr == NULL); - - fd = socket (PF_INET, SOCK_DGRAM, 0); - if (fd < 0) { - _LOGE (LOGD_HW, "could not open control socket."); - return; - } - - /* Get permanent MAC address */ - memset (&req, 0, sizeof (struct ifreq)); - strncpy (req.ifr_name, nm_device_get_iface (device), IFNAMSIZ); - - epaddr = g_malloc0 (sizeof (struct ethtool_perm_addr) + ETH_ALEN); - epaddr->cmd = ETHTOOL_GPERMADDR; - epaddr->size = ETH_ALEN; - req.ifr_data = (void *) epaddr; - - errno = 0; - ret = ioctl (fd, SIOCETHTOOL, &req); - errsv = errno; - if ((ret < 0) || !nm_ethernet_address_is_valid (epaddr->data, ETH_ALEN)) { - _LOGD (LOGD_HW | LOGD_ETHER, "unable to read permanent MAC address (error %d)", - errsv); - /* Fall back to current address */ - nm_utils_hwaddr_aton (nm_device_get_hw_address (device), epaddr->data, ETH_ALEN); - } - - priv->perm_hw_addr = nm_utils_hwaddr_ntoa (epaddr->data, ETH_ALEN); - - g_free (epaddr); - close (fd); -} - -static void -update_initial_hw_address (NMDevice *device) -{ - NMDeviceWifi *self = NM_DEVICE_WIFI (device); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - /* This sets initial MAC address from current MAC address. It should only - * be called from NMDevice constructor() to really get the initial address. - */ - priv->initial_hw_addr = g_strdup (nm_device_get_hw_address (device)); - - _LOGD (LOGD_DEVICE | LOGD_ETHER, "read initial MAC address %s", priv->initial_hw_addr); -} - static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { @@ -2950,12 +2892,7 @@ dispose (GObject *object) static void finalize (GObject *object) { - NMDeviceWifi *self = NM_DEVICE_WIFI (object); - NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self); - - g_free (priv->perm_hw_addr); - g_free (priv->initial_hw_addr); - g_clear_pointer (&priv->aps, g_hash_table_unref); + g_clear_pointer (&NM_DEVICE_WIFI_GET_PRIVATE (object)->aps, g_hash_table_unref); G_OBJECT_CLASS (nm_device_wifi_parent_class)->finalize (object); } @@ -2972,7 +2909,7 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PERM_HW_ADDRESS: - g_value_set_string (value, priv->perm_hw_addr); + g_value_set_string (value, nm_device_get_permanent_hw_address (NM_DEVICE (device))); break; case PROP_MODE: g_value_set_uint (value, priv->mode); @@ -3028,8 +2965,6 @@ nm_device_wifi_class_init (NMDeviceWifiClass *klass) object_class->finalize = finalize; parent_class->bring_up = bring_up; - parent_class->update_permanent_hw_address = update_permanent_hw_address; - parent_class->update_initial_hw_address = update_initial_hw_address; parent_class->can_auto_connect = can_auto_connect; parent_class->is_available = is_available; parent_class->check_connection_compatible = check_connection_compatible; diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 4cf2e46452..1ac61d41d4 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -454,6 +454,12 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length) return g_bytes_get_data (device->address, length); } +static gboolean +link_get_permanent_address (NMPlatform *platform, int ifindex, guint8 *buf, size_t *length) +{ + return FALSE; +} + static gboolean link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) { @@ -1432,6 +1438,7 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->link_set_address = link_set_address; platform_class->link_get_address = link_get_address; + platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_get_mtu = link_get_mtu; platform_class->link_set_mtu = link_set_mtu; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index ab20af57d7..68da68625d 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -454,6 +454,31 @@ ethtool_get_driver_info (const char *ifname, return TRUE; } +static gboolean +ethtool_get_permanent_address (const char *ifname, + guint8 *buf, + size_t *length) +{ + gs_free struct ethtool_perm_addr *epaddr = NULL; + + if (!ifname) + return FALSE; + + epaddr = g_malloc0 (sizeof (*epaddr) + NM_UTILS_HWADDR_LEN_MAX); + epaddr->cmd = ETHTOOL_GPERMADDR; + epaddr->size = NM_UTILS_HWADDR_LEN_MAX; + + if (!ethtool_get (ifname, epaddr)) + return FALSE; + if (!nm_ethernet_address_is_valid (epaddr->data, epaddr->size)) + return FALSE; + + g_assert (epaddr->size <= NM_UTILS_HWADDR_LEN_MAX); + memcpy (buf, epaddr->data, epaddr->size); + *length = epaddr->size; + return TRUE; +} + /****************************************************************** * udev ******************************************************************/ @@ -2854,6 +2879,15 @@ link_get_address (NMPlatform *platform, int ifindex, size_t *length) return a; } +static gboolean +link_get_permanent_address (NMPlatform *platform, + int ifindex, + guint8 *buf, + size_t *length) +{ + return ethtool_get_permanent_address (nm_platform_link_get_name (platform, ifindex), buf, length); +} + static gboolean link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu) { @@ -4787,6 +4821,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_get_address = link_get_address; platform_class->link_set_address = link_set_address; + platform_class->link_get_permanent_address = link_get_permanent_address; platform_class->link_get_mtu = link_get_mtu; platform_class->link_set_mtu = link_set_mtu; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 24baa38ff9..a02423ddeb 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1012,7 +1012,8 @@ nm_platform_link_set_address (NMPlatform *self, int ifindex, gconstpointer addre * @ifindex: Interface index * @length: Pointer to a variable to store address length * - * Saves interface hardware address to @address. + * Returns: the interface hardware address as an array of bytes of + * length @length. */ gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length) @@ -1029,6 +1030,34 @@ nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length) return klass->link_get_address (self, ifindex, length); } +/** + * nm_platform_link_get_permanent_address: + * @self: platform instance + * @ifindex: Interface index + * @buf: buffer of at least %NM_UTILS_HWADDR_LEN_MAX bytes, on success + * the permanent hardware address + * @length: Pointer to a variable to store address length + * + * Returns: %TRUE on success, %FALSE on failure to read the permanent hardware + * address. + */ +gboolean +nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length) +{ + _CHECK_SELF (self, klass, FALSE); + reset_error (self); + + if (length) + *length = 0; + + g_return_val_if_fail (ifindex > 0, FALSE); + g_return_val_if_fail (klass->link_get_permanent_address, FALSE); + g_return_val_if_fail (buf, FALSE); + g_return_val_if_fail (length, FALSE); + + return klass->link_get_permanent_address (self, ifindex, buf, length); +} + gboolean nm_platform_link_supports_carrier_detect (NMPlatform *self, int ifindex) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index f09e617d38..5341958586 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -405,6 +405,10 @@ typedef struct { gboolean (*link_set_user_ipv6ll_enabled) (NMPlatform *, int ifindex, gboolean enabled); gconstpointer (*link_get_address) (NMPlatform *, int ifindex, size_t *length); + gboolean (*link_get_permanent_address) (NMPlatform *, + int ifindex, + guint8 *buf, + size_t *length); gboolean (*link_set_address) (NMPlatform *, int ifindex, gconstpointer address, size_t length); guint32 (*link_get_mtu) (NMPlatform *, int ifindex); gboolean (*link_set_mtu) (NMPlatform *, int ifindex, guint32 mtu); @@ -568,6 +572,7 @@ gboolean nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex gboolean nm_platform_link_set_user_ipv6ll_enabled (NMPlatform *self, int ifindex, gboolean enabled); gconstpointer nm_platform_link_get_address (NMPlatform *self, int ifindex, size_t *length); +gboolean nm_platform_link_get_permanent_address (NMPlatform *self, int ifindex, guint8 *buf, size_t *length); gboolean nm_platform_link_set_address (NMPlatform *self, int ifindex, const void *address, size_t length); guint32 nm_platform_link_get_mtu (NMPlatform *self, int ifindex); gboolean nm_platform_link_set_mtu (NMPlatform *self, int ifindex, guint32 mtu); From 8fa0f4690f6f97b046399e33de1d1d6d81235636 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 6 May 2015 09:53:44 -0500 Subject: [PATCH 14/14] core: let plugins indicate links which should be ignored Instead of hacky stuff in the Manager, let plugins themselves indicate which links should be ignored (because they are really child links that are controlled by a different device that the plugin handles). --- src/devices/bluetooth/nm-bluez-manager.c | 11 +++++++++++ src/devices/nm-device-bond.c | 2 +- src/devices/nm-device-bridge.c | 2 +- src/devices/nm-device-ethernet.c | 2 +- src/devices/nm-device-factory.c | 3 ++- src/devices/nm-device-factory.h | 6 ++++++ src/devices/nm-device-gre.c | 2 +- src/devices/nm-device-infiniband.c | 2 +- src/devices/nm-device-macvlan.c | 2 +- src/devices/nm-device-tun.c | 2 +- src/devices/nm-device-veth.c | 2 +- src/devices/nm-device-vlan.c | 2 +- src/devices/nm-device-vxlan.c | 2 +- src/devices/team/nm-team-factory.c | 2 +- src/devices/wifi/nm-wifi-factory.c | 2 +- src/devices/wwan/nm-wwan-factory.c | 10 ++++++++++ src/nm-manager.c | 23 +++++++++-------------- 17 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/devices/bluetooth/nm-bluez-manager.c b/src/devices/bluetooth/nm-bluez-manager.c index d325f44c8c..2e1c46b13c 100644 --- a/src/devices/bluetooth/nm-bluez-manager.c +++ b/src/devices/bluetooth/nm-bluez-manager.c @@ -37,6 +37,7 @@ #include "nm-connection-provider.h" #include "nm-device-bt.h" #include "nm-core-internal.h" +#include "nm-platform.h" typedef struct { int bluez_version; @@ -369,6 +370,7 @@ start (NMDeviceFactory *factory) } NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BNEP) NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BLUETOOTH_SETTING_NAME) ) @@ -403,10 +405,19 @@ nm_bluez_manager_init (NMBluezManager *self) g_assert (priv->provider); } +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +{ + g_warn_if_fail (plink->type == NM_LINK_TYPE_BNEP); + *out_ignore = TRUE; + return NULL; +} + static void device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->get_supported_types = get_supported_types; + factory_iface->new_link = new_link; factory_iface->start = start; } diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c index 951954ba6e..17fb12c919 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -553,7 +553,7 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) #define NM_BOND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BOND_FACTORY, NMBondFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BOND, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index ffec9764dd..221bed97bb 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -477,7 +477,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) #define NM_BRIDGE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BRIDGE_FACTORY, NMBridgeFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c index 114b2c9eb3..3337a106d4 100644 --- a/src/devices/nm-device-ethernet.c +++ b/src/devices/nm-device-ethernet.c @@ -1693,7 +1693,7 @@ nm_device_ethernet_class_init (NMDeviceEthernetClass *klass) #define NM_ETHERNET_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ETHERNET_FACTORY, NMEthernetFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_ETHERNET, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device-factory.c b/src/devices/nm-device-factory.c index 0357845c12..de7e9d7312 100644 --- a/src/devices/nm-device-factory.c +++ b/src/devices/nm-device-factory.c @@ -81,6 +81,7 @@ nm_device_factory_start (NMDeviceFactory *factory) NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error) { NMDeviceFactory *interface; @@ -114,7 +115,7 @@ nm_device_factory_new_link (NMDeviceFactory *factory, return NULL; } - return interface->new_link (factory, plink, error); + return interface->new_link (factory, plink, out_ignore, error); } NMDevice * diff --git a/src/devices/nm-device-factory.h b/src/devices/nm-device-factory.h index 40050d4dd3..34c056d20f 100644 --- a/src/devices/nm-device-factory.h +++ b/src/devices/nm-device-factory.h @@ -93,6 +93,7 @@ struct _NMDeviceFactory { * new_link: * @factory: the #NMDeviceFactory * @plink: the new link + * @out_ignore: on return, %TRUE if the link should be ignored * @error: error if the link could be claimed but an error occurred * * The NetworkManager core was notified of a new link which the plugin @@ -101,6 +102,9 @@ struct _NMDeviceFactory { * is supported but the device could not be created, %NULL should be * returned and @error should be set. * + * If the plugin cannot create a #NMDevice for the link and wants the + * core to ignore it, set @out_ignore to %TRUE and return no error. + * * @plink is guaranteed to be one of the types the factory returns in * get_supported_types(). * @@ -108,6 +112,7 @@ struct _NMDeviceFactory { */ NMDevice * (*new_link) (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error); /** @@ -201,6 +206,7 @@ void nm_device_factory_start (NMDeviceFactory *factory); NMDevice * nm_device_factory_new_link (NMDeviceFactory *factory, NMPlatformLink *plink, + gboolean *out_ignore, GError **error); NMDevice * nm_device_factory_create_virtual_device_for_connection (NMDeviceFactory *factory, diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c index 9e592b51f9..b3510d2e25 100644 --- a/src/devices/nm-device-gre.c +++ b/src/devices/nm-device-gre.c @@ -267,7 +267,7 @@ nm_device_gre_class_init (NMDeviceGreClass *klass) #define NM_GRE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_GRE_FACTORY, NMGreFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_GRE, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index f9cd946d44..5e89660e7d 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -293,7 +293,7 @@ nm_device_infiniband_class_init (NMDeviceInfinibandClass *klass) #define NM_INFINIBAND_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_INFINIBAND_FACTORY, NMInfinibandFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_INFINIBAND, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 4235b62783..0bfe3fe9fc 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -175,7 +175,7 @@ nm_device_macvlan_class_init (NMDeviceMacvlanClass *klass) #define NM_MACVLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MACVLAN_FACTORY, NMMacvlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_MACVLAN, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 54cbbf82f3..5aaff8b1a0 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -270,7 +270,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) #define NM_TUN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_TUN_FACTORY, NMTunFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { const char *mode = NULL; diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c index bb3d4af941..04f03fbbe5 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -177,7 +177,7 @@ nm_device_veth_class_init (NMDeviceVethClass *klass) #define NM_VETH_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VETH_FACTORY, NMVethFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VETH, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index ce2005a8ad..fcbe402aba 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -628,7 +628,7 @@ nm_device_vlan_class_init (NMDeviceVlanClass *klass) #define NM_VLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VLAN_FACTORY, NMVlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { int parent_ifindex = -1; NMDevice *parent, *device; diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c index c0492aee34..7811934d2a 100644 --- a/src/devices/nm-device-vxlan.c +++ b/src/devices/nm-device-vxlan.c @@ -353,7 +353,7 @@ nm_device_vxlan_class_init (NMDeviceVxlanClass *klass) #define NM_VXLAN_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VXLAN_FACTORY, NMVxlanFactory)) static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return (NMDevice *) g_object_new (NM_TYPE_DEVICE_VXLAN, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/devices/team/nm-team-factory.c b/src/devices/team/nm-team-factory.c index f21f07502c..d87919b6b7 100644 --- a/src/devices/team/nm-team-factory.c +++ b/src/devices/team/nm-team-factory.c @@ -48,7 +48,7 @@ nm_device_factory_create (GError **error) /************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { return nm_device_team_new (plink); } diff --git a/src/devices/wifi/nm-wifi-factory.c b/src/devices/wifi/nm-wifi-factory.c index 19578b3d58..c4b4042e70 100644 --- a/src/devices/wifi/nm-wifi-factory.c +++ b/src/devices/wifi/nm-wifi-factory.c @@ -59,7 +59,7 @@ nm_device_factory_create (GError **error) /**************************************************************************/ static NMDevice * -new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) { if (plink->type == NM_LINK_TYPE_WIFI) return nm_device_wifi_new (plink); diff --git a/src/devices/wwan/nm-wwan-factory.c b/src/devices/wwan/nm-wwan-factory.c index b6870d0dde..49b0b0af53 100644 --- a/src/devices/wwan/nm-wwan-factory.c +++ b/src/devices/wwan/nm-wwan-factory.c @@ -30,6 +30,7 @@ #include "nm-modem-manager.h" #include "nm-device-modem.h" #include "nm-logging.h" +#include "nm-platform.h" static GType nm_wwan_factory_get_type (void); @@ -94,6 +95,14 @@ NM_DEVICE_FACTORY_DECLARE_TYPES ( NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_GSM_SETTING_NAME, NM_SETTING_CDMA_SETTING_NAME) ) +static NMDevice * +new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, GError **error) +{ + g_warn_if_fail (plink->type == NM_LINK_TYPE_WWAN_ETHERNET); + *out_ignore = TRUE; + return NULL; +} + static void start (NMDeviceFactory *factory) { @@ -117,6 +126,7 @@ static void device_factory_interface_init (NMDeviceFactory *factory_iface) { factory_iface->get_supported_types = get_supported_types; + factory_iface->new_link = new_link; factory_iface->start = start; } diff --git a/src/nm-manager.c b/src/nm-manager.c index 6bb867ca71..848ccd26bf 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -1905,20 +1905,18 @@ platform_link_added (NMManager *self, if (nm_manager_get_device_by_ifindex (self, ifindex)) return; - /* Ignore Bluetooth PAN interfaces; they are handled by their NMDeviceBt - * parent and don't get a separate interface. - */ - if (plink->type == NM_LINK_TYPE_BNEP) - return; - /* Try registered device factories */ factory = nm_device_factory_manager_find_factory_for_link_type (plink->type); if (factory) { - device = nm_device_factory_new_link (factory, plink, &error); + gboolean ignore = FALSE; + + device = nm_device_factory_new_link (factory, plink, &ignore, &error); if (!device) { - nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", - plink->name, error->message); - g_clear_error (&error); + if (!ignore) { + nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", + plink->name, error->message); + g_clear_error (&error); + } return; } } @@ -1926,10 +1924,7 @@ platform_link_added (NMManager *self, if (device == NULL) { switch (plink->type) { case NM_LINK_TYPE_WWAN_ETHERNET: - /* WWAN pseudo-ethernet interfaces are handled automatically by - * their NMDeviceModem and don't get a separate NMDevice object. - */ - break; + case NM_LINK_TYPE_BNEP: case NM_LINK_TYPE_OLPC_MESH: case NM_LINK_TYPE_TEAM: case NM_LINK_TYPE_WIFI: