core: add device factory infrastructure and make WiMAX a plugin

This allows us to package WiMAX separately so you can choose
to install WiMAX or not.  For package-based distros you can now
install libnm-device-plugin-wimax.so in a separate package that
links to/requires the Intel WiMAX service instead of having the
main NM package require it and pull it in by default.  This
plugin infrastructure will be extended to other device types
as well.
This commit is contained in:
Dan Williams 2011-11-18 15:52:42 -06:00
parent 21fab21ec0
commit 2099459794
5 changed files with 316 additions and 40 deletions

View file

@ -36,10 +36,6 @@ INCLUDES = -I${top_srcdir} \
-I${top_srcdir}/libnm-util \
-I${top_srcdir}/callouts
if WITH_WIMAX
INCLUDES += -I$(top_srcdir)/src/wimax
endif
###########################################
# Test libraries
###########################################
@ -146,6 +142,7 @@ NetworkManager_SOURCES = \
nm-dbus-manager.c \
nm-udev-manager.c \
nm-udev-manager.h \
nm-device-factory.h \
nm-hostname-provider.c \
nm-hostname-provider.h \
nm-ip4-config.c \
@ -265,14 +262,9 @@ NetworkManager_CPPFLAGS = \
-DLOCALSTATEDIR=\"$(localstatedir)\" \
-DNM_RUN_DIR=\"$(rundir)\" \
-DNMLOCALEDIR=\"$(datadir)/locale\" \
-DNMPLUGINDIR=\"$(pkglibdir)\"
-DARP_DEBUG
WIMAX_LIBS=
if WITH_WIMAX
WIMAX_LIBS += ./wimax/libwimax.la
endif
NetworkManager_LDADD = \
$(top_builddir)/marshallers/libmarshallers.la \
./logging/libnm-logging.la \
@ -287,7 +279,6 @@ NetworkManager_LDADD = \
./bluez-manager/libbluez-manager.la \
./firewall-manager/libfirewall-manager.la \
./settings/libsettings.la \
$(WIMAX_LIBS) \
./backends/libnmbackend.la \
$(top_builddir)/libnm-util/libnm-util.la \
$(DBUS_LIBS) \

91
src/nm-device-factory.h Normal file
View file

@ -0,0 +1,91 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2007 - 2011 Red Hat, Inc.
*/
#ifndef NM_DEVICE_FACTORY_H
#define NM_DEVICE_FACTORY_H
#include <glib.h>
#include <glib-object.h>
#include <gudev/gudev.h>
#include "NetworkManager.h"
/* WARNING: this file is private API between NetworkManager and its internal
* device plugins. Its API can change at any time and is not guaranteed to be
* stable. NM and device plugins are distributed together and this API is
* not meant to enable third-party plugins.
*/
/**
* nm_device_factory_create_device:
* @device: GUdev device object representing the device
* @devpath: sysfs path of the device
* @ifname: interface name of the device
* @driver: driver of the device
* @error: error for failure information
*
* Creates a #NMDevice subclass if the given information represents a device
* the factory is capable of creating. If the information does represent a
* device the factory is capable of creating, but the device could not be
* created, %NULL should be returned and @error should be set. If the
* factory is not capable of creating a device with the given information
* (ie, the factory creates Ethernet devices but the information represents
* a WiFi device) it should return %NULL and leave @error untouched.
*
* Returns: the device object (a subclass of #NMDevice) or %NULL
*/
GObject *nm_device_factory_create_device (GUdevDevice *device,
const char *devpath,
const char *ifname,
const char *driver,
GError **error);
/* Should match nm_device_factory() */
typedef GObject * (*NMDeviceFactoryCreateFunc) (GUdevDevice *device,
const char *devpath,
const char *ifname,
const char *driver,
GError **error);
/**
* nm_device_factory_get_priority:
*
* Returns the priority of this plugin. Higher numbers mean a higher priority.
*
* Returns: plugin priority
*/
guint32 nm_device_factory_get_priority (void);
typedef guint32 (*NMDeviceFactoryPriorityFunc) (void);
/**
* nm_device_factory_get_type:
*
* Returns the type of device this factory can create. Only one factory for
* each type of device is allowed.
*
* Returns: the %NMDeviceType
*/
NMDeviceType nm_device_factory_get_type (void);
typedef NMDeviceType (*NMDeviceFactoryTypeFunc) (void);
#endif /* NM_DEVICE_FACTORY_H */

View file

@ -28,6 +28,7 @@
#include <unistd.h>
#include <net/if_arp.h>
#include <gmodule.h>
#include <gudev/gudev.h>
#include "nm-udev-manager.h"
@ -38,15 +39,16 @@
#include "nm-device-olpc-mesh.h"
#include "nm-device-infiniband.h"
#include "nm-device-ethernet.h"
#include "nm-device-factory.h"
#include "wifi-utils.h"
#if WITH_WIMAX
#include "nm-device-wimax.h"
#endif
#include "nm-system.h"
typedef struct {
GUdevClient *client;
/* List of NMDeviceFactoryFunc pointers sorted in priority order */
GSList *factories;
/* Authoritative rfkill state (RFKILL_* enum) */
RfKillState rfkill_states[RFKILL_TYPE_MAX];
GSList *killswitches;
@ -374,15 +376,6 @@ is_olpc_mesh (GUdevDevice *device)
return (prop != NULL);
}
static gboolean
is_wimax (const char *driver)
{
/* FIXME: check 'DEVTYPE' instead; but since we only support Intel
* WiMAX devices for now this is appropriate.
*/
return g_strcmp0 (driver, "i2400m_usb") == 0;
}
static gboolean
is_infiniband (GUdevDevice *device)
{
@ -395,10 +388,13 @@ device_creator (NMUdevManager *manager,
GUdevDevice *udev_device,
gboolean sleeping)
{
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (manager);
GObject *device = NULL;
const char *ifname, *driver, *path, *subsys;
GUdevDevice *parent = NULL, *grandparent = NULL;
gint ifindex;
GError *error = NULL;
GSList *iter;
ifname = g_udev_device_get_name (udev_device);
g_assert (ifname);
@ -455,18 +451,35 @@ device_creator (NMUdevManager *manager,
goto out;
}
if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver);
else if (is_wireless (udev_device))
device = (GObject *) nm_device_wifi_new (path, ifname, driver);
else if (is_wimax (driver)) {
#if WITH_WIMAX
device = (GObject *) nm_device_wimax_new (path, ifname, driver);
#endif
} else if (is_infiniband (udev_device))
device = (GObject *) nm_device_infiniband_new (path, ifname, driver);
else
device = (GObject *) nm_device_ethernet_new (path, ifname, driver);
/* Try registered device factories */
for (iter = priv->factories; iter; iter = g_slist_next (iter)) {
NMDeviceFactoryCreateFunc create_func = iter->data;
g_clear_error (&error);
device = create_func (udev_device, path, ifname, driver, &error);
if (device) {
g_assert_no_error (error);
break; /* success! */
}
if (error) {
nm_log_warn (LOGD_HW, "%s: factory failed to create device: (%d) %s",
path, error->code, error->message);
g_clear_error (&error);
goto out;
}
}
if (device == NULL) {
if (is_olpc_mesh (udev_device)) /* must be before is_wireless */
device = (GObject *) nm_device_olpc_mesh_new (path, ifname, driver);
else if (is_wireless (udev_device))
device = (GObject *) nm_device_wifi_new (path, ifname, driver);
else if (is_infiniband (udev_device))
device = (GObject *) nm_device_infiniband_new (path, ifname, driver);
else
device = (GObject *) nm_device_ethernet_new (path, ifname, driver);
}
out:
if (grandparent)
@ -555,6 +568,121 @@ nm_udev_manager_query_devices (NMUdevManager *self)
g_list_free (devices);
}
#define PLUGIN_PREFIX "libnm-device-plugin-"
typedef struct {
NMDeviceType t;
guint priority;
NMDeviceFactoryCreateFunc create_func;
} PluginInfo;
static gint
plugin_sort (PluginInfo *a, PluginInfo *b)
{
/* Higher priority means sort earlier in the list (ie, return -1) */
if (a->priority > b->priority)
return -1;
else if (a->priority < b->priority)
return 1;
return 0;
}
static void
load_device_factories (NMUdevManager *self)
{
NMUdevManagerPrivate *priv = NM_UDEV_MANAGER_GET_PRIVATE (self);
GDir *dir;
GError *error = NULL;
const char *item;
char *path;
GSList *list = NULL, *iter;
dir = g_dir_open (NMPLUGINDIR, 0, &error);
if (!dir) {
nm_log_warn (LOGD_HW, "Failed to open plugin directory %s: %s",
NMPLUGINDIR,
(error && error->message) ? error->message : "(unknown)");
g_clear_error (&error);
return;
}
while ((item = g_dir_read_name (dir))) {
GModule *plugin;
NMDeviceFactoryCreateFunc create_func;
NMDeviceFactoryPriorityFunc priority_func;
NMDeviceFactoryTypeFunc type_func;
PluginInfo *info = NULL;
NMDeviceType plugin_type;
if (!g_str_has_prefix (item, PLUGIN_PREFIX))
continue;
path = g_module_build_path (NMPLUGINDIR, item);
g_assert (path);
plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
g_free (path);
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_get_type", (gpointer) (&type_func))) {
nm_log_warn (LOGD_HW, "(%s): failed to find device factory: %s", item, g_module_error ());
g_module_close (plugin);
continue;
}
/* Make sure we don't double-load plugins */
plugin_type = type_func ();
for (iter = list; iter; iter = g_slist_next (iter)) {
PluginInfo *candidate = iter->data;
if (plugin_type == candidate->t) {
info = candidate;
break;
}
}
if (info) {
g_module_close (plugin);
continue;
}
if (!g_module_symbol (plugin, "nm_device_factory_create_device", (gpointer) (&create_func))) {
nm_log_warn (LOGD_HW, "(%s): failed to find device creator: %s", item, g_module_error ());
g_module_close (plugin);
continue;
}
info = g_malloc0 (sizeof (*info));
info->create_func = create_func;
info->t = plugin_type;
/* Grab priority; higher number equals higher priority */
if (g_module_symbol (plugin, "nm_device_factory_get_priority", (gpointer) (&priority_func)))
info->priority = priority_func ();
else {
nm_log_dbg (LOGD_HW, "(%s): failed to find device factory priority func: %s",
item, g_module_error ());
}
g_module_make_resident (plugin);
list = g_slist_insert_sorted (list, info, (GCompareFunc) plugin_sort);
nm_log_info (LOGD_HW, "Loaded device factory: %s", g_module_name (plugin));
};
g_dir_close (dir);
/* Ditch the priority info and copy the factory functions to our private data */
for (iter = list; iter; iter = g_slist_next (iter)) {
PluginInfo *info = iter->data;
priv->factories = g_slist_append (priv->factories, info->create_func);
g_free (info);
}
g_slist_free (list);
}
static void
handle_uevent (GUdevClient *client,
const char *action,
@ -612,6 +740,8 @@ nm_udev_manager_init (NMUdevManager *self)
g_list_free (switches);
recheck_killswitches (self);
load_device_factories (self);
}
static void
@ -631,6 +761,8 @@ dispose (GObject *object)
g_slist_foreach (priv->killswitches, (GFunc) killswitch_destroy, NULL);
g_slist_free (priv->killswitches);
g_slist_free (priv->factories);
G_OBJECT_CLASS (nm_udev_manager_parent_class)->dispose (object);
}

View file

@ -5,9 +5,10 @@ INCLUDES = \
-I${top_srcdir}/libnm-util \
-I${top_builddir}/marshallers
noinst_LTLIBRARIES = libwimax.la
pkglib_LTLIBRARIES = libnm-device-plugin-wimax.la
libwimax_la_SOURCES = \
libnm_device_plugin_wimax_la_SOURCES = \
nm-wimax-factory.c \
nm-device-wimax.c \
nm-device-wimax.h \
nm-wimax-nsp.c \
@ -18,14 +19,17 @@ libwimax_la_SOURCES = \
iwmxsdk.c \
iwmxsdk.h
libwimax_la_CPPFLAGS = \
libnm_device_plugin_wimax_la_CPPFLAGS = \
$(DBUS_CFLAGS) \
$(IWMX_SDK_CFLAGS) \
$(LIBNL_CFLAGS)
$(LIBNL_CFLAGS) \
$(GUDEV_CFLAGS)
libwimax_la_LIBADD = \
libnm_device_plugin_wimax_la_LDFLAGS = -module -avoid-version
libnm_device_plugin_wimax_la_LIBADD = \
$(DBUS_LIBS) \
$(IWMX_SDK_LIBS) \
$(GUDEV_LIBS) \
$(top_builddir)/marshallers/libmarshallers.la
nm-wimax-nsp-glue.h: $(top_srcdir)/introspection/nm-wimax-nsp.xml

View file

@ -0,0 +1,58 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2011 Red Hat, Inc.
*/
#include <gmodule.h>
#include "nm-device-factory.h"
#include "nm-device-wimax.h"
G_MODULE_EXPORT GObject *
nm_device_factory_create_device (GUdevDevice *device,
const char *devpath,
const char *ifname,
const char *driver,
GError **error)
{
GObject *dev;
/* FIXME: check 'DEVTYPE' instead; but since we only support Intel
* WiMAX devices for now this is appropriate.
*/
if (g_strcmp0 (driver, "i2400m_usb") != 0)
return NULL; /* unsupported */
dev = (GObject *) nm_device_wimax_new (devpath, ifname, driver);
if (dev == NULL)
g_set_error_literal (error, 0, 0, "Failed to create WiMAX device.");
return dev;
}
G_MODULE_EXPORT guint32
nm_device_factory_get_priority (void)
{
return 0;
}
G_MODULE_EXPORT NMDeviceType
nm_device_factory_get_type (void)
{
return NM_DEVICE_TYPE_WIMAX;
}