diff options
Diffstat (limited to 'src/devices/nm-device-tun.c')
| -rw-r--r-- | src/devices/nm-device-tun.c | 355 |
1 files changed, 176 insertions, 179 deletions
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index c3ce4b73..a7d7c0bf 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -25,7 +25,6 @@ #include <stdlib.h> #include <string.h> #include <sys/types.h> -#include <linux/if_tun.h> #include "nm-act-request.h" #include "nm-device-private.h" @@ -35,6 +34,8 @@ #include "nm-setting-tun.h" #include "nm-core-internal.h" +#include "introspection/org.freedesktop.NetworkManager.Device.Tun.h" + #include "nm-device-logging.h" _LOG_DECLARE_SELF(NMDeviceTun); @@ -50,7 +51,8 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceTun, ); typedef struct { - NMPlatformLnkTun props; + NMPlatformTunProperties props; + const char *mode; } NMDeviceTunPrivate; struct _NMDeviceTun { @@ -69,62 +71,48 @@ G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE) /*****************************************************************************/ static void -update_properties_from_struct (NMDeviceTun *self, - const NMPlatformLnkTun *props) -{ - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - const NMPlatformLnkTun props0 = { }; - - if (!props) { - /* allow passing %NULL to reset all properties. */ - props = &props0; - } - - g_object_freeze_notify (G_OBJECT (self)); - -#define CHECK_PROPERTY_CHANGED_VALID(field, prop) \ - G_STMT_START { \ - if ( priv->props.field != props->field \ - || priv->props.field##_valid != props->field##_valid) { \ - priv->props.field##_valid = props->field##_valid; \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END - -#define CHECK_PROPERTY_CHANGED(field, prop) \ - G_STMT_START { \ - if (priv->props.field != props->field) { \ - priv->props.field = props->field; \ - _notify (self, prop); \ - } \ - } G_STMT_END - - CHECK_PROPERTY_CHANGED_VALID (owner, PROP_OWNER); - CHECK_PROPERTY_CHANGED_VALID (group, PROP_GROUP); - CHECK_PROPERTY_CHANGED (type, PROP_MODE); - CHECK_PROPERTY_CHANGED (pi, PROP_NO_PI); - CHECK_PROPERTY_CHANGED (vnet_hdr, PROP_VNET_HDR); - CHECK_PROPERTY_CHANGED (multi_queue, PROP_MULTI_QUEUE); - - g_object_thaw_notify (G_OBJECT (self)); -} - -static void update_properties (NMDeviceTun *self) { - NMPlatformLnkTun props_storage; - const NMPlatformLnkTun *props = NULL; + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + GObject *object = G_OBJECT (self); + NMPlatformTunProperties props; int ifindex; ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - if ( ifindex > 0 - && nm_platform_link_tun_get_properties (nm_device_get_platform (NM_DEVICE (self)), - ifindex, - &props_storage)) - props = &props_storage; - - update_properties_from_struct (self, props); + if (ifindex > 0) { + if (!nm_platform_link_tun_get_properties (nm_device_get_platform (NM_DEVICE (self)), ifindex, &props)) { + _LOGD (LOGD_DEVICE, "tun-properties: cannot loading tun properties from platform for ifindex %d", ifindex); + ifindex = 0; + } else if (g_strcmp0 (priv->mode, props.mode) != 0) { + /* if the mode differs, we ignore what we loaded. A NMDeviceTun cannot + * change the mode after construction. */ + _LOGD (LOGD_DEVICE, "tun-properties: loading tun properties yielded tun-mode %s%s%s, but %s%s%s expected (ifindex %d)", + NM_PRINT_FMT_QUOTE_STRING (props.mode), + NM_PRINT_FMT_QUOTE_STRING (priv->mode), + ifindex); + ifindex = 0; + } + } else + _LOGD (LOGD_DEVICE, "tun-properties: ignore loading properties due to missing ifindex"); + if (ifindex <= 0) + memset (&props, 0, sizeof (props)); + + g_object_freeze_notify (object); + + if (priv->props.owner != props.owner) + _notify (self, PROP_OWNER); + if (priv->props.group != props.group) + _notify (self, PROP_GROUP); + if (priv->props.no_pi != props.no_pi) + _notify (self, PROP_NO_PI); + if (priv->props.vnet_hdr != props.vnet_hdr) + _notify (self, PROP_VNET_HDR); + if (priv->props.multi_queue != props.multi_queue) + _notify (self, PROP_MULTI_QUEUE); + + memcpy (&priv->props, &props, sizeof (NMPlatformTunProperties)); + + g_object_thaw_notify (object); } static NMDeviceCapabilities @@ -145,7 +133,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - NMConnection *const*existing_connections, + const GSList *existing_connections, GError **error) { NMSettingTun *s_tun; @@ -169,57 +157,61 @@ complete_connection (NMDevice *device, 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 update_connection (NMDevice *device, NMConnection *connection) { NMDeviceTun *self = NM_DEVICE_TUN (device); - NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - NMSettingTun *s_tun; + NMSettingTun *s_tun = nm_connection_get_setting_tun (connection); + NMPlatformTunProperties props; NMSettingTunMode mode; - char s_buf[100]; - const char *str; - - /* Note: since we read tun properties from sysctl for older kernels, - * we don't get proper change notifications. Make sure that all our - * tun properties are up to date at this point. We should not do this, - * if we would entirely rely on netlink events. */ - update_properties (NM_DEVICE_TUN (device)); + gint64 user, group; + char *str; - switch (priv->props.type) { - case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break; - case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break; - default: - /* Huh? */ - return; - } - - s_tun = nm_connection_get_setting_tun (connection); if (!s_tun) { s_tun = (NMSettingTun *) nm_setting_tun_new (); nm_connection_add_setting (connection, (NMSetting *) s_tun); } + if (!nm_platform_link_tun_get_properties (nm_device_get_platform (device), nm_device_get_ifindex (device), &props)) { + _LOGW (LOGD_PLATFORM, "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, (guint) mode, NULL); + 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); - str = priv->props.owner_valid - ? nm_sprintf_buf (s_buf, "%" G_GINT32_FORMAT, priv->props.owner) - : NULL; - if (!nm_streq0 (str, nm_setting_tun_get_owner (s_tun))) + 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); + } - str = priv->props.group_valid - ? nm_sprintf_buf (s_buf, "%" G_GINT32_FORMAT, priv->props.group) - : NULL; - if (!nm_streq0 (str, nm_setting_tun_get_group (s_tun))) + 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 (priv->props.pi != nm_setting_tun_get_pi (s_tun)) - g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_PI, (gboolean) priv->props.pi, NULL); - if (priv->props.vnet_hdr != nm_setting_tun_get_vnet_hdr (s_tun)) - g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_VNET_HDR, (gboolean) priv->props.vnet_hdr, NULL); - if (priv->props.multi_queue != nm_setting_tun_get_multi_queue (s_tun)) - g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MULTI_QUEUE, (gboolean) priv->props.multi_queue, NULL); + 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 @@ -230,42 +222,23 @@ create_and_realize (NMDevice *device, GError **error) { const char *iface = nm_device_get_iface (device); - NMPlatformLnkTun props = { }; NMPlatformError plerr; NMSettingTun *s_tun; - gint64 owner, group; + gint64 user, group; s_tun = nm_connection_get_setting_tun (connection); - g_return_val_if_fail (s_tun, FALSE); - - switch (nm_setting_tun_get_mode (s_tun)) { - case NM_SETTING_TUN_MODE_TAP: props.type = IFF_TAP; break; - case NM_SETTING_TUN_MODE_TUN: props.type = IFF_TUN; break; - default: - g_return_val_if_reached (FALSE); - } + g_assert (s_tun); - owner = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); - if (owner != -1) { - props.owner_valid = TRUE; - props.owner = owner; - } + 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 (group != -1) { - props.group_valid = TRUE; - props.group = group; - } - props.pi = nm_setting_tun_get_pi (s_tun); - props.vnet_hdr = nm_setting_tun_get_vnet_hdr (s_tun); - props.multi_queue = nm_setting_tun_get_multi_queue (s_tun); - props.persist = TRUE; - - plerr = nm_platform_link_tun_add (nm_device_get_platform (device), - iface, - &props, - out_plink, - NULL); + plerr = nm_platform_link_tun_add (nm_device_get_platform (device), 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) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, "Failed to create TUN/TAP interface '%s' for '%s': %s", @@ -279,22 +252,13 @@ create_and_realize (NMDevice *device, } static gboolean -_same_og (const char *str, gboolean og_valid, guint32 og_num) -{ - gint64 v; - - v = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXINT32, -1); - return (!og_valid && ( v == (gint64) -1)) - || ( og_valid && (((guint32) v) == og_num )); -} - -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; if (!NM_DEVICE_CLASS (nm_device_tun_parent_class)->check_connection_compatible (device, connection)) return FALSE; @@ -304,21 +268,18 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; if (nm_device_is_real (device)) { - switch (priv->props.type) { - case IFF_TUN: mode = NM_SETTING_TUN_MODE_TUN; break; - case IFF_TAP: mode = NM_SETTING_TUN_MODE_TAP; break; - default: - /* Huh? */ - return FALSE; - } - + mode = tun_mode_from_string (priv->mode); if (mode != nm_setting_tun_get_mode (s_tun)) return FALSE; - if (!_same_og (nm_setting_tun_get_owner (s_tun), priv->props.owner_valid, priv->props.owner)) + + 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 (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group)) + if (group != priv->props.group) return FALSE; - if (nm_setting_tun_get_pi (s_tun) != priv->props.pi) + 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; @@ -341,7 +302,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) return ret; /* Nothing to do for TUN devices */ - if (priv->props.type == IFF_TUN) + if (g_strcmp0 (priv->mode, "tap")) return NM_ACT_STAGE_RETURN_SUCCESS; if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE)) @@ -353,8 +314,16 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) static void unrealize_notify (NMDevice *device) { + NMDeviceTun *self = NM_DEVICE_TUN (device); + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + guint i; + NM_DEVICE_CLASS (nm_device_tun_parent_class)->unrealize_notify (device); - update_properties_from_struct (NM_DEVICE_TUN (device), NULL); + + memset (&priv->props, 0, sizeof (NMPlatformTunProperties)); + + for (i = 1; i < _PROPERTY_ENUMS_LAST; i++) + g_object_notify_by_pspec ((GObject *) self, obj_properties[i]); } /*****************************************************************************/ @@ -365,25 +334,19 @@ get_property (GObject *object, guint prop_id, { NMDeviceTun *self = NM_DEVICE_TUN (object); NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - const char *s; switch (prop_id) { case PROP_OWNER: - g_value_set_int64 (value, priv->props.owner_valid ? (gint64) priv->props.owner : (gint64) -1); + g_value_set_int64 (value, priv->props.owner); break; case PROP_GROUP: - g_value_set_int64 (value, priv->props.group_valid ? (gint64) priv->props.group : (gint64) -1); + g_value_set_int64 (value, priv->props.group); break; case PROP_MODE: - switch (priv->props.type) { - case IFF_TUN: s = "tun"; break; - case IFF_TAP: s = "tap"; break; - default: s = NULL; break; - } - g_value_set_static_string (value, s); + g_value_set_string (value, priv->mode); break; case PROP_NO_PI: - g_value_set_boolean (value, !priv->props.pi); + g_value_set_boolean (value, priv->props.no_pi); break; case PROP_VNET_HDR: g_value_set_boolean (value, priv->props.vnet_hdr); @@ -397,6 +360,33 @@ get_property (GObject *object, guint prop_id, } } +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMDeviceTun *self = NM_DEVICE_TUN (object); + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + const char *str; + + switch (prop_id) { + case PROP_MODE: + /* construct-only */ + str = g_value_get_string (value); + + /* mode is G_PARAM_STATIC_STRINGS */ + if (g_strcmp0 (str, "tun") == 0) + priv->mode = "tun"; + else if (g_strcmp0 (str, "tap") == 0) + priv->mode = "tap"; + else + g_return_if_fail (FALSE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + /*****************************************************************************/ static void @@ -404,37 +394,16 @@ nm_device_tun_init (NMDeviceTun *self) { } -static const NMDBusInterfaceInfoExtended interface_info_device_tun = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - NM_DBUS_INTERFACE_DEVICE_TUN, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &nm_signal_info_property_changed_legacy, - ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS ( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Owner", "x", NM_DEVICE_TUN_OWNER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Group", "x", NM_DEVICE_TUN_GROUP), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("Mode", "s", NM_DEVICE_TUN_MODE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("NoPi", "b", NM_DEVICE_TUN_NO_PI), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("VnetHdr", "b", NM_DEVICE_TUN_VNET_HDR), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("MultiQueue", "b", NM_DEVICE_TUN_MULTI_QUEUE), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L ("HwAddress", "s", NM_DEVICE_HW_ADDRESS), - ), - ), - .legacy_property_changed = TRUE, -}; - static void nm_device_tun_class_init (NMDeviceTunClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS (klass); NMDeviceClass *device_class = NM_DEVICE_CLASS (klass); - NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN) + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN, NM_LINK_TYPE_TAP) object_class->get_property = get_property; - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_tun); + object_class->set_property = set_property; device_class->connection_type = NM_SETTING_TUN_SETTING_NAME; device_class->link_changed = link_changed; @@ -459,8 +428,9 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) obj_properties[PROP_MODE] = g_param_spec_string (NM_DEVICE_TUN_MODE, "", "", - NULL, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + "tun", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); obj_properties[PROP_NO_PI] = g_param_spec_boolean (NM_DEVICE_TUN_NO_PI, "", "", @@ -478,6 +448,10 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass), + NMDBUS_TYPE_DEVICE_TUN_SKELETON, + NULL); } @@ -493,19 +467,42 @@ create_device (NMDeviceFactory *factory, NMConnection *connection, gboolean *out_ignore) { - g_return_val_if_fail (!plink || plink->type == NM_LINK_TYPE_TUN, NULL); - g_return_val_if_fail (!connection || nm_streq0 (nm_connection_get_connection_type (connection), NM_SETTING_TUN_SETTING_NAME), NULL); + NMSettingTun *s_tun; + NMLinkType link_type = NM_LINK_TYPE_UNKNOWN; + const char *mode; + + if (plink) { + link_type = plink->type; + } else if (connection) { + s_tun = nm_connection_get_setting_tun (connection); + if (!s_tun) + return NULL; + switch (nm_setting_tun_get_mode (s_tun)) { + case NM_SETTING_TUN_MODE_TUN: + link_type = NM_LINK_TYPE_TUN; + break; + case NM_SETTING_TUN_MODE_TAP: + link_type = NM_LINK_TYPE_TAP; + break; + case NM_SETTING_TUN_MODE_UNKNOWN: + g_return_val_if_reached (NULL); + } + } + + g_return_val_if_fail (link_type != NM_LINK_TYPE_UNKNOWN, NULL); + mode = link_type == NM_LINK_TYPE_TUN ? "tun" : "tap"; 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_TUN, - NM_DEVICE_LINK_TYPE, (guint) NM_LINK_TYPE_TUN, + NM_DEVICE_LINK_TYPE, link_type, + NM_DEVICE_TUN_MODE, mode, NULL); } NM_DEVICE_FACTORY_DEFINE_INTERNAL (TUN, Tun, tun, - NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_TUN) + 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_class->create_device = create_device; ); |