diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2015-09-15 15:08:06 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2015-11-25 11:39:57 +0100 |
commit | 9110ad39c55bee0b338350d645374fb99fb6e47d (patch) | |
tree | 5c93af5a31b25f232a38fd7076c759de68b27508 | |
parent | 5b2271190809dd5b8bbf4aadd8114c38cc7eb00f (diff) | |
download | NetworkManager-9110ad39c55bee0b338350d645374fb99fb6e47d.tar.gz |
device/tun: support device creation
Allow the creation of a new TUN/TAP interface when a tun connection is
activated.
-rw-r--r-- | libnm-core/nm-connection.c | 3 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | src/devices/nm-device-tun.c | 191 | ||||
-rw-r--r-- | src/devices/nm-device-tun.h | 4 | ||||
-rw-r--r-- | src/devices/nm-device.c | 2 |
5 files changed, 182 insertions, 19 deletions
diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 278282b552..94a897539a 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1594,7 +1594,8 @@ nm_connection_is_virtual (NMConnection *connection) if ( !strcmp (type, NM_SETTING_BOND_SETTING_NAME) || !strcmp (type, NM_SETTING_TEAM_SETTING_NAME) || !strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME) - || !strcmp (type, NM_SETTING_VLAN_SETTING_NAME)) + || !strcmp (type, NM_SETTING_VLAN_SETTING_NAME) + || !strcmp (type, NM_SETTING_TUN_SETTING_NAME)) return TRUE; if (!strcmp (type, NM_SETTING_INFINIBAND_SETTING_NAME)) { diff --git a/po/POTFILES.in b/po/POTFILES.in index be11d0ca55..af5ccb28ac 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -147,6 +147,7 @@ src/devices/nm-device-bridge.c src/devices/nm-device-ethernet.c src/devices/nm-device-ethernet-utils.c src/devices/nm-device-infiniband.c +src/devices/nm-device-tun.c src/devices/nm-device-vlan.c src/devices/team/nm-device-team.c src/devices/wifi/nm-device-olpc-mesh.c diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index e103363361..4002ef0cf5 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -15,26 +15,29 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2013 Red Hat, Inc. + * Copyright 2013 - 2015 Red Hat, Inc. */ #include "config.h" #include <stdlib.h> #include <string.h> +#include <sys/types.h> #include "nm-device-tun.h" #include "nm-device-private.h" #include "nm-default.h" #include "nm-platform.h" #include "nm-device-factory.h" +#include "nm-setting-tun.h" +#include "nm-core-internal.h" #include "nmdbus-device-tun.h" #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceTun); -G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE_GENERIC) +G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE) #define NM_DEVICE_TUN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_TUN, NMDeviceTunPrivate)) @@ -81,6 +84,7 @@ reload_tun_properties (NMDeviceTun *self) if (priv->props.multi_queue != props.multi_queue) g_object_notify (object, NM_DEVICE_TUN_MULTI_QUEUE); + priv->mode = props.mode; memcpy (&priv->props, &props, sizeof (NMPlatformTunProperties)); g_object_thaw_notify (object); @@ -94,24 +98,172 @@ link_changed (NMDevice *device, NMPlatformLink *info) reload_tun_properties (NM_DEVICE_TUN (device)); } +static gboolean +complete_connection (NMDevice *device, + NMConnection *connection, + const char *specific_object, + const GSList *existing_connections, + GError **error) +{ + NMSettingTun *s_tun; + + nm_utils_complete_generic (connection, + NM_SETTING_TUN_SETTING_NAME, + existing_connections, + NULL, + _("TUN connection"), + NULL, + TRUE); + + s_tun = nm_connection_get_setting_tun (connection); + if (!s_tun) { + g_set_error_literal (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_INVALID_CONNECTION, + "A 'tun' setting is required."); + return FALSE; + } + + return TRUE; +} + +static int +tun_mode_from_string (const char *string) +{ + if (!g_strcmp0 (string, "tap")) + return NM_SETTING_TUN_MODE_TAP; + else + return NM_SETTING_TUN_MODE_TUN; +} + static void -setup (NMDevice *device, NMPlatformLink *plink) +update_connection (NMDevice *device, NMConnection *connection) { NMDeviceTun *self = NM_DEVICE_TUN (device); - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + NMSettingTun *s_tun = nm_connection_get_setting_tun (connection); + NMPlatformTunProperties props; + NMSettingTunMode mode; + gint64 user, group; + char *str; - NM_DEVICE_CLASS (nm_device_tun_parent_class)->setup (device, plink); + if (!s_tun) { + s_tun = (NMSettingTun *) nm_setting_tun_new (); + nm_connection_add_setting (connection, (NMSetting *) s_tun); + } - priv->mode = NULL; - if (plink->type == NM_LINK_TYPE_TUN) - priv->mode = "tun"; - else if (plink->type == NM_LINK_TYPE_TAP) - priv->mode = "tap"; - else - g_assert_not_reached (); - g_object_notify (G_OBJECT (device), NM_DEVICE_TUN_MODE); + if (!nm_platform_tun_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) { + _LOGW (LOGD_HW, "failed to get TUN interface info while updating connection."); + return; + } + + mode = tun_mode_from_string (props.mode); + + if (mode != nm_setting_tun_get_mode (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, mode, NULL); + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + if (props.owner != user) { + str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL; + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_OWNER, str, NULL); + g_free (str); + } + + if (props.group != group) { + str = props.group >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.group) : NULL; + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_GROUP, str, NULL); + g_free (str); + } + + if ((!props.no_pi) != nm_setting_tun_get_pi (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, !props.no_pi, NULL); + if (props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, props.vnet_hdr, NULL); + if (props.multi_queue != nm_setting_tun_get_multi_queue (s_tun)) + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, props.multi_queue, NULL); +} + +static gboolean +create_and_realize (NMDevice *device, + NMConnection *connection, + NMDevice *parent, + NMPlatformLink *out_plink, + GError **error) +{ + const char *iface = nm_device_get_iface (device); + NMPlatformError plerr; + NMSettingTun *s_tun; + gint64 user, group; + + s_tun = nm_connection_get_setting_tun (connection); + g_assert (s_tun); + g_assert (out_plink); + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + + plerr = nm_platform_tun_add (NM_PLATFORM_GET, iface, + nm_setting_tun_get_mode (s_tun) == NM_SETTING_TUN_MODE_TAP, + user, group, + nm_setting_tun_get_pi (s_tun), + nm_setting_tun_get_vnet_hdr (s_tun), + nm_setting_tun_get_multi_queue (s_tun), + out_plink); + if (plerr != NM_PLATFORM_ERROR_SUCCESS && plerr != NM_PLATFORM_ERROR_EXISTS) { + g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, + "Failed to create TUN/TAP interface '%s' for '%s': %s", + iface, + nm_connection_get_id (connection), + nm_platform_error_to_string (plerr)); + return FALSE; + } + + return TRUE; +} + +static gboolean +realize (NMDevice *device, NMPlatformLink *plink, GError **error) +{ reload_tun_properties (NM_DEVICE_TUN (device)); + return TRUE; +} + +static gboolean +check_connection_compatible (NMDevice *device, NMConnection *connection) +{ + NMDeviceTun *self = NM_DEVICE_TUN (device); + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + NMSettingTunMode mode; + NMSettingTun *s_tun; + gint64 user, group; + + reload_tun_properties (self); + + if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) + return FALSE; + + s_tun = nm_connection_get_setting_tun (connection); + if (!s_tun) + return FALSE; + + mode = tun_mode_from_string (priv->mode); + if (mode != nm_setting_tun_get_mode (s_tun)) + return FALSE; + + user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + group = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_group (s_tun), 10, 0, G_MAXINT32, -1); + + if (user != priv->props.owner) + return FALSE; + if (group != priv->props.group) + return FALSE; + if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi) + return FALSE; + if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) + return FALSE; + if (nm_setting_tun_get_multi_queue (s_tun) != priv->props.multi_queue) + return FALSE; + + return TRUE; } /**************************************************************/ @@ -191,8 +343,14 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) object_class->get_property = get_property; object_class->set_property = set_property; + device_class->connection_type = NM_SETTING_TUN_SETTING_NAME; + device_class->link_changed = link_changed; - device_class->setup = setup; + device_class->complete_connection = complete_connection; + device_class->check_connection_compatible = check_connection_compatible; + device_class->create_and_realize = create_and_realize; + device_class->realize = realize; + device_class->update_connection = update_connection; /* properties */ g_object_class_install_property @@ -252,12 +410,13 @@ create_device (NMDeviceFactory *factory, return (NMDevice *) g_object_new (NM_TYPE_DEVICE_TUN, NM_DEVICE_IFACE, iface, NM_DEVICE_TYPE_DESC, "Tun", - NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_GENERIC, + NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_TUN, NULL); } NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP), + NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP) + NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TUN_SETTING_NAME), factory_iface->create_device = create_device; ) diff --git a/src/devices/nm-device-tun.h b/src/devices/nm-device-tun.h index b253d68e45..32dcfd47b5 100644 --- a/src/devices/nm-device-tun.h +++ b/src/devices/nm-device-tun.h @@ -39,8 +39,8 @@ G_BEGIN_DECLS #define NM_DEVICE_TUN_VNET_HDR "vnet-hdr" #define NM_DEVICE_TUN_MULTI_QUEUE "multi-queue" -typedef NMDeviceGeneric NMDeviceTun; -typedef NMDeviceGenericClass NMDeviceTunClass; +typedef NMDevice NMDeviceTun; +typedef NMDeviceClass NMDeviceTunClass; GType nm_device_tun_get_type (void); diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f9e0475c2f..07b7b072bf 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -754,6 +754,8 @@ nm_device_get_priority (NMDevice *self) return 400; case NM_DEVICE_TYPE_BRIDGE: return 425; + case NM_DEVICE_TYPE_TUN: + return 450; case NM_DEVICE_TYPE_WIFI: return 600; case NM_DEVICE_TYPE_OLPC_MESH: |