diff options
author | Dan Williams <dcbw@redhat.com> | 2014-09-17 14:17:30 -0500 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-06-17 16:19:19 +0200 |
commit | c174da8e1391f54396c01a7c20f3fe46d67533bb (patch) | |
tree | 2c2aa8e3135fa7e13583783682563541dfc594f7 | |
parent | 998f1cf7324cd3d0b169bae480b6ea4c5cafab27 (diff) |
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.
(cherry picked from commit 71bde20c302ba321688f203a8c5cd1e2d296f0d1)
-rw-r--r-- | src/devices/adsl/nm-atm-manager.c | 11 | ||||
-rw-r--r-- | src/devices/bluetooth/nm-bluez-manager.c | 11 | ||||
-rw-r--r-- | src/devices/nm-device-bond.c | 39 | ||||
-rw-r--r-- | src/devices/nm-device-bridge.c | 39 | ||||
-rw-r--r-- | src/devices/nm-device-ethernet.c | 19 | ||||
-rw-r--r-- | src/devices/nm-device-factory.c | 402 | ||||
-rw-r--r-- | src/devices/nm-device-factory.h | 83 | ||||
-rw-r--r-- | src/devices/nm-device-gre.c | 18 | ||||
-rw-r--r-- | src/devices/nm-device-infiniband.c | 35 | ||||
-rw-r--r-- | src/devices/nm-device-macvlan.c | 18 | ||||
-rw-r--r-- | src/devices/nm-device-tun.c | 11 | ||||
-rw-r--r-- | src/devices/nm-device-veth.c | 18 | ||||
-rw-r--r-- | src/devices/nm-device-vlan.c | 50 | ||||
-rw-r--r-- | src/devices/nm-device-vxlan.c | 18 | ||||
-rw-r--r-- | src/devices/team/nm-device-team.c | 18 | ||||
-rw-r--r-- | src/devices/team/nm-team-factory.c | 19 | ||||
-rw-r--r-- | src/devices/wifi/nm-wifi-factory.c | 15 | ||||
-rw-r--r-- | src/devices/wimax/nm-wimax-factory.c | 12 | ||||
-rw-r--r-- | src/devices/wwan/nm-wwan-factory.c | 13 | ||||
-rw-r--r-- | src/nm-manager.c | 309 |
20 files changed, 658 insertions, 500 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 <gmodule.h> #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 e176a4b462..d2e5e96e08 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" @@ -368,11 +369,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) +) /*********************************************************************/ @@ -408,7 +407,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 0821fe4253..14ccedfb78 100644 --- a/src/devices/nm-device-bond.c +++ b/src/devices/nm-device-bond.c @@ -557,16 +557,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 * @@ -575,19 +572,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; } @@ -600,7 +595,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 30081e1e23..f3c3eea5e0 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -480,16 +480,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 * @@ -498,21 +495,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) { @@ -525,8 +516,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; } @@ -540,7 +533,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 041eb278e7..dd8de2e590 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 <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> + +#include <gmodule.h> #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; + + 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; - return NM_DEVICE_FACTORY_GET_INTERFACE (factory)->get_device_type (factory); + 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 5eba1b3c39..ba0b304b0b 100644 --- a/src/devices/nm-device-veth.c +++ b/src/devices/nm-device-veth.c @@ -167,17 +167,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 3f31244ec2..b52b00253b 100644 --- a/src/devices/team/nm-device-team.c +++ b/src/devices/team/nm-device-team.c @@ -696,8 +696,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", @@ -710,20 +708,16 @@ nm_device_team_new (NMPlatformLink *platform_device) NMDevice * nm_device_team_new_for_connection (NMConnection *connection, GError **error) { - const char *iface; - - g_return_val_if_fail (connection != NULL, NULL); + const char *iface = nm_connection_get_interface_name (connection); - 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 <gmodule.h> #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/wimax/nm-wimax-factory.c b/src/devices/wimax/nm-wimax-factory.c index 39e9a28738..ffda4674e5 100644 --- a/src/devices/wimax/nm-wimax-factory.c +++ b/src/devices/wimax/nm-wimax-factory.c @@ -25,6 +25,7 @@ #include "nm-device-factory.h" #include "nm-device-wimax.h" #include "nm-platform.h" +#include "nm-setting-wimax.h" #define NM_TYPE_WIMAX_FACTORY (nm_wimax_factory_get_type ()) #define NM_WIMAX_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_WIMAX_FACTORY, NMWimaxFactory)) @@ -66,17 +67,16 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, GError **error) return (NMDevice *) nm_device_wimax_new (plink); } -static NMDeviceType -get_device_type (NMDeviceFactory *factory) -{ - return NM_DEVICE_TYPE_WIMAX; -} +NM_DEVICE_FACTORY_DECLARE_TYPES ( + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_WIMAX) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_WIMAX_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 2705efd4ea..172b4d194b 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -26,8 +26,6 @@ #include <errno.h> #include <string.h> #include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> #include <dbus/dbus-glib-lowlevel.h> #include <dbus/dbus-glib.h> #include <gio/gio.h> @@ -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; @@ -1053,7 +1048,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; @@ -1090,6 +1085,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. @@ -1098,24 +1106,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); @@ -1126,16 +1120,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--; @@ -1952,124 +1936,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) -{ - 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) +static void +_register_device_factory (NMDeviceFactory *factory, gpointer user_data) { - 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, @@ -2079,80 +1949,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); } /*******************************************************************/ @@ -2164,8 +1960,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; g_return_if_fail (ifindex > 0); @@ -2176,41 +1972,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); + /* 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_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)"); + if (!device) { + nm_log_warn (LOGD_HW, "%s: factory failed to create device: %s", + plink->name, error->message); 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; - 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: @@ -4233,11 +4019,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 */ @@ -4269,8 +4060,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); @@ -4875,7 +4665,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; } @@ -5110,13 +4900,18 @@ 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) { NMManager *manager = NM_MANAGER (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; @@ -5188,14 +4983,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; |