From 0fbcb8c9aecd652926c58553f401de2e5be1e785 Mon Sep 17 00:00:00 2001 From: boul Date: Sun, 12 Oct 2014 23:56:03 +0200 Subject: [PATCH 1/1] Added ifvirt plugin --- configure.ac | 5 + src/settings/plugins/Makefile.am | 4 + src/settings/plugins/ifvirt/Makefile.am | 41 +++++ src/settings/plugins/ifvirt/plugin.c | 271 ++++++++++++++++++++++++++++++++ src/settings/plugins/ifvirt/plugin.h | 50 ++++++ 5 files changed, 371 insertions(+) create mode 100644 src/settings/plugins/ifvirt/Makefile.am create mode 100644 src/settings/plugins/ifvirt/plugin.c create mode 100644 src/settings/plugins/ifvirt/plugin.h diff --git a/configure.ac b/configure.ac index 94b0758..0e1caf7 100644 --- a/configure.ac +++ b/configure.ac @@ -95,6 +95,7 @@ AC_ARG_ENABLE(ifcfg-rh, AS_HELP_STRING([--enable-ifcfg-rh], [enable ifcfg-rh con AC_ARG_ENABLE(ifcfg-suse, AS_HELP_STRING([--enable-ifcfg-suse], [enable ifcfg-suse configuration plugin (SUSE)])) AC_ARG_ENABLE(ifupdown, AS_HELP_STRING([--enable-ifupdown], [enable ifupdown configuration plugin (Debian/Ubuntu)])) AC_ARG_ENABLE(ifnet, AS_HELP_STRING([--enable-ifnet], [enable ifnet configuration plugin (Gentoo)])) +AC_ARG_ENABLE(ifnet, AS_HELP_STRING([--enable-ifvirt], [enable ifvirt configuration plugin])) # Default alternative plugins by distribution AS_IF([test -z "$enable_ifcfg_rh"], AC_CHECK_FILE(/etc/redhat-release, enable_ifcfg_rh=yes)) AS_IF([test -z "$enable_ifcfg_rh"], AC_CHECK_FILE(/etc/fedora-release, enable_ifcfg_rh=yes)) @@ -107,11 +108,13 @@ AS_IF([test -z "$enable_ifcfg_rh"], enable_ifcfg_rh=no) AS_IF([test -z "$enable_ifcfg_suse"], enable_ifcfg_suse=no) AS_IF([test -z "$enable_ifupdown"], enable_ifupdown=no) AS_IF([test -z "$enable_ifnet"], enable_ifnet=no) +AS_IF([test -z "$enable_ifvirt"], enable_ifvirt=no) # Create automake conditionals AM_CONDITIONAL(CONFIG_PLUGIN_IFCFG_RH, test "$enable_ifcfg_rh" = "yes") AM_CONDITIONAL(CONFIG_PLUGIN_IFCFG_SUSE, test "$enable_ifcfg_suse" = "yes") AM_CONDITIONAL(CONFIG_PLUGIN_IFUPDOWN, test "$enable_ifupdown" = "yes") AM_CONDITIONAL(CONFIG_PLUGIN_IFNET, test "$enable_ifnet" = "yes") +AM_CONDITIONAL(CONFIG_PLUGIN_IFVIRT, test "$enable_ifvirt" = "yes") if test "$enable_ifcfg_rh" = "yes"; then DISTRO_NETWORK_SERVICE=network.service @@ -794,6 +797,7 @@ src/settings/plugins/ifcfg-suse/Makefile src/settings/plugins/keyfile/Makefile src/settings/plugins/keyfile/tests/Makefile src/settings/plugins/keyfile/tests/keyfiles/Makefile +src/settings/plugins/ifvirt/Makefile src/settings/plugins/example/Makefile src/settings/tests/Makefile src/platform/Makefile @@ -906,6 +910,7 @@ echo " ifcfg-rh: ${enable_ifcfg_rh}" echo " ifcfg-suse: ${enable_ifcfg_suse}" echo " ifupdown: ${enable_ifupdown}" echo " ifnet: ${enable_ifnet}" +echo " ifvirt: ${enable_ifvirt}" echo echo "Handlers for /etc/resolv.conf:" diff --git a/src/settings/plugins/Makefile.am b/src/settings/plugins/Makefile.am index 41694e7..2ae7444 100644 --- a/src/settings/plugins/Makefile.am +++ b/src/settings/plugins/Makefile.am @@ -17,3 +17,7 @@ endif if CONFIG_PLUGIN_IFNET SUBDIRS+=ifnet endif + +if CONFIG_PLUGIN_IFVIRT +SUBDIRS+=ifvirt +endif diff --git a/src/settings/plugins/ifvirt/Makefile.am b/src/settings/plugins/ifvirt/Makefile.am new file mode 100644 index 0000000..ab15e55 --- /dev/null +++ b/src/settings/plugins/ifvirt/Makefile.am @@ -0,0 +1,41 @@ +SUBDIRS = . + + GNOME_CODE_COVERAGE_RULES@ + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src \ + -I$(top_srcdir)/src/config \ + -I$(top_srcdir)/src/logging \ + -I$(top_srcdir)/src/settings \ + -I$(top_srcdir)/include \ + -I$(top_builddir)/include \ + -I$(top_srcdir)/libnm-util \ + -I$(top_builddir)/libnm-util \ + -DG_LOG_DOMAIN=\""NetworkManager-ifvirt"\" \ + -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ + $(GLIB_CFLAGS) \ + $(DBUS_CFLAGS) \ + $(POLKIT_CFLAGS) \ + $(GUDEV_CFLAGS) \ + -DNMCONFDIR=\"$(nmconfdir)\" + +pkglib_LTLIBRARIES = libnm-settings-plugin-ifvirt.la + +##################################### + +libnm_settings_plugin_ifvirt_la_SOURCES = \ + plugin.c \ + plugin.h + +libnm_settings_plugin_ifvirt_la_LIBADD = \ + $(top_builddir)/libnm-util/libnm-util.la \ + $(GLIB_LIBS) \ + $(GUDEV_LIBS) + +libnm_settings_plugin_ifvirt_la_LDFLAGS = -rdynamic + +ifvirtdir=$(sysconfdir)/NetworkManager/system-connections + +install-data-hook: + $(mkinstalldirs) -m 0755 $(DESTDIR)$(ifvirtdir) + diff --git a/src/settings/plugins/ifvirt/plugin.c b/src/settings/plugins/ifvirt/plugin.c new file mode 100644 index 0000000..cac1443 --- /dev/null +++ b/src/settings/plugins/ifvirt/plugin.c @@ -0,0 +1,271 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service - keyfile plugin + * + * 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) 2014 Nicolas Boulicault + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "plugin.h" +#include "nm-system-config-interface.h" +//#include "utils.h" + +static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class); + +G_DEFINE_TYPE_EXTENDED (SCPluginIfVirt, sc_plugin_ifvirt, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, + system_config_interface_init)) + +#define SC_PLUGIN_IFVIRT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SC_TYPE_PLUGIN_IFVIRT, SCPluginIfVirtPrivate)) + +typedef struct { + GUdevClient *client; + GHashTable *virtual_ifaces; +} SCPluginIfVirtPrivate; + +/* + * Return a list of device specifications which NetworkManager should not + * manage. Returned list will be freed by the system settings service, and + * each element must be allocated using g_malloc() or its variants. + */ +static GSList* +sc_plugin_ifvirt_get_unmanaged_specs (NMSystemConfigInterface *config) +{ + SCPluginIfVirtPrivate *priv = SC_PLUGIN_IFVIRT_GET_PRIVATE(config); + GSList *specs = NULL; + GHashTableIter iter; + GUdevDevice *device; + const char *iface; + + g_hash_table_iter_init (&iter, priv->virtual_ifaces); + while (g_hash_table_iter_next (&iter, (gpointer) &iface, (gpointer) &device)) { + specs = g_slist_append (specs, g_strdup_printf ("interface-name:%s", iface)); + } + + return specs; +} + +gboolean is_iface_virtual(const char *iface, const char *sysfs_path) +{ + const char *virt_path = "/sys/devices/virtual/net"; + + // loopback is already handled by network-manager + if (g_ascii_strncasecmp(iface, "lo", strlen(iface)) == 0) + return FALSE; + + if (g_ascii_strncasecmp (sysfs_path, virt_path, strlen (virt_path)) == 0) { + return TRUE; + } + + return FALSE; +} + +static void +udev_device_added (SCPluginIfVirt *self, GUdevDevice *device) +{ + SCPluginIfVirtPrivate *priv = SC_PLUGIN_IFVIRT_GET_PRIVATE (self); + const char *iface, *path; + + iface = g_udev_device_get_name (device); + path = g_udev_device_get_sysfs_path (device); + if (!iface || !path) + return; + + if (is_iface_virtual(iface, path)) { + nm_log_info(LOGD_SETTINGS, "ifvirt: iface %s is virtual, adding to unmanaged ifaces", iface); + g_hash_table_insert (priv->virtual_ifaces, g_strdup (iface), g_object_ref (device)); + } + + g_signal_emit_by_name (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); +} + +static void +udev_device_removed(SCPluginIfVirt *self, GUdevDevice *device) +{ + SCPluginIfVirtPrivate *priv = SC_PLUGIN_IFVIRT_GET_PRIVATE (self); + const char *iface, *path; + + iface = g_udev_device_get_name (device); + path = g_udev_device_get_sysfs_path (device); + if (!iface || !path) + return; + + // iface is not in virtual ifaces list, do nothing + if (!g_hash_table_contains(priv->virtual_ifaces, iface)) { + return; + } + + g_hash_table_remove(priv->virtual_ifaces, iface); + g_signal_emit_by_name (G_OBJECT (self), NM_SYSTEM_CONFIG_INTERFACE_UNMANAGED_SPECS_CHANGED); +} + +static void +handle_uevent (GUdevClient *client, + const char *action, + GUdevDevice *device, + gpointer user_data) +{ + SCPluginIfVirt *self = SC_PLUGIN_IFVIRT(user_data); + const char *subsys; + + g_return_if_fail (action != NULL); + + subsys = g_udev_device_get_subsystem (device); + g_return_if_fail (subsys != NULL); + g_return_if_fail (strcmp (subsys, "net") == 0); + + if (!strcmp (action, "add")) + udev_device_added (self, device); + else if (!strcmp (action, "remove")) + udev_device_removed (self, device); +} + +static void +SCPluginIfVirt_init (NMSystemConfigInterface *plugin) +{ + const gchar *subsys[2] = { "net", NULL }; + GList *all_interfaces, *iter; + + SCPluginIfVirt *self = SC_PLUGIN_IFVIRT (plugin); + SCPluginIfVirtPrivate *priv = SC_PLUGIN_IFVIRT_GET_PRIVATE (self); + + priv->virtual_ifaces = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); + + priv->client = g_udev_client_new (subsys); + if (!priv->client) { + nm_log_warn (LOGD_SETTINGS, "ifvirt: error initializing libgudev !"); + } else + g_signal_connect (priv->client, "uevent", G_CALLBACK (handle_uevent), self); + + // Get list of network devices, and simulate addition to check virtual interfaces + all_interfaces = g_udev_client_query_by_subsystem(priv->client, subsys[0]); + for (iter = all_interfaces; iter; iter = g_list_next (iter)) { + udev_device_added (self, G_UDEV_DEVICE (iter->data)); + g_object_unref (G_UDEV_DEVICE (iter->data)); + } + + g_list_free (all_interfaces); +} + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + case NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME: + g_value_set_string (value, IFVIRT_PLUGIN_NAME); + break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO: + g_value_set_string (value, IFVIRT_PLUGIN_INFO); + break; + case NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES: + g_value_set_uint (value, 0); + break; + default: + nm_log_warn(LOGD_SETTINGS, "ifvirt: get_property %d not implemented !", prop_id); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + switch (prop_id) { + default: + nm_log_warn(LOGD_SETTINGS, "ifvirt: set_property %d not implemented !", prop_id); + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +system_config_interface_init (NMSystemConfigInterface *system_config_interface_class) +{ + system_config_interface_class->get_unmanaged_specs = sc_plugin_ifvirt_get_unmanaged_specs; + system_config_interface_class->init = SCPluginIfVirt_init; +} + +static void +dispose (GObject *object) +{ + SCPluginIfVirt *self = SC_PLUGIN_IFVIRT (object); + SCPluginIfVirtPrivate *priv = SC_PLUGIN_IFVIRT_GET_PRIVATE (self); + + if (priv->virtual_ifaces) + g_hash_table_destroy(priv->virtual_ifaces); + + if (priv->client) + g_object_unref (priv->client); + + G_OBJECT_CLASS (sc_plugin_ifvirt_parent_class)->dispose (object); +} + +static void sc_plugin_ifvirt_init(SCPluginIfVirt *plugin) +{ +} + +static void +sc_plugin_ifvirt_class_init (SCPluginIfVirtClass *req_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (req_class); + + g_type_class_add_private (req_class, sizeof (SCPluginIfVirtPrivate)); + + object_class->dispose = dispose; + object_class->get_property = get_property; + object_class->set_property = set_property; + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_NAME, + NM_SYSTEM_CONFIG_INTERFACE_NAME); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_INFO, + NM_SYSTEM_CONFIG_INTERFACE_INFO); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_CAPABILITIES, + NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES); + + g_object_class_override_property (object_class, + NM_SYSTEM_CONFIG_INTERFACE_PROP_HOSTNAME, + NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME); +} + +G_MODULE_EXPORT GObject * +nm_system_config_factory (void) +{ + static SCPluginIfVirt *singleton = NULL; + + if (!singleton) { + singleton = SC_PLUGIN_IFVIRT (g_object_new (SC_TYPE_PLUGIN_IFVIRT, NULL)); + } else + g_object_ref (singleton); + + return G_OBJECT (singleton); +} diff --git a/src/settings/plugins/ifvirt/plugin.h b/src/settings/plugins/ifvirt/plugin.h new file mode 100644 index 0000000..1d834da --- /dev/null +++ b/src/settings/plugins/ifvirt/plugin.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager system settings service - ifvirt plugin + * + * 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) 2014 Nicolas Boulicault + */ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +#define IFVIRT_PLUGIN_NAME "ifvirt" +#define IFVIRT_PLUGIN_INFO "(c) 2014 Nicolas Boulicault (boul51 gmail com)" + +#include + +#define SC_TYPE_PLUGIN_IFVIRT (sc_plugin_ifvirt_get_type ()) +#define SC_PLUGIN_IFVIRT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SC_TYPE_PLUGIN_IFVIRT, SCPluginIfVirt)) +#define SC_PLUGIN_IFVIRT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SC_TYPE_PLUGIN_IFVIRT, SCPluginIfVirtClass)) +#define SC_IS_PLUGIN_IFVIRT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SC_TYPE_PLUGIN_IFVIRT)) +#define SC_IS_PLUGIN_IFVIRT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SC_TYPE_PLUGIN_IFVIRT)) +#define SC_PLUGIN_IFVIRT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SC_TYPE_PLUGIN_IFVIRT, SCPluginIfVirtClass)) + +typedef struct { + GObject parent; +} SCPluginIfVirt; + +typedef struct { + GObjectClass parent; +} SCPluginIfVirtClass; + +GType sc_plugin_ifvirt_get_type (void); + +//GQuark ifvirt_plugin_error_quark (void); + +GObject *nm_settings_ifvirt_plugin_new (void); + +#endif /* _PLUGIN_H_ */ -- 2.1.1