diff options
| author | Michael Biebl <biebl@debian.org> | 2018-04-23 18:00:21 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2018-04-23 18:00:21 +0200 |
| commit | f60117b41d5433be1b4a96d82cd11d0c3dce9b63 (patch) | |
| tree | 2dd55c4ab0fdcbe9cddb26adb4a554b1a45c73c8 /src/devices/nm-device-tun.c | |
| parent | 7e9ff09fcb2366b383b7ebbec80d2f6fff117290 (diff) | |
New upstream version 1.11.3 upstream/1.11.3
Diffstat (limited to 'src/devices/nm-device-tun.c')
| -rw-r--r-- | src/devices/nm-device-tun.c | 355 |
1 files changed, 179 insertions, 176 deletions
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index a7d7c0bf..c3ce4b73 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -25,6 +25,7 @@ #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" @@ -34,8 +35,6 @@ #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); @@ -51,8 +50,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceTun, ); typedef struct { - NMPlatformTunProperties props; - const char *mode; + NMPlatformLnkTun props; } NMDeviceTunPrivate; struct _NMDeviceTun { @@ -71,48 +69,62 @@ G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE) /*****************************************************************************/ static void -update_properties (NMDeviceTun *self) +update_properties_from_struct (NMDeviceTun *self, + const NMPlatformLnkTun *props) { NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); - GObject *object = G_OBJECT (self); - NMPlatformTunProperties props; + 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; int ifindex; ifindex = nm_device_get_ifindex (NM_DEVICE (self)); - 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); + 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); } static NMDeviceCapabilities @@ -133,7 +145,7 @@ static gboolean complete_connection (NMDevice *device, NMConnection *connection, const char *specific_object, - const GSList *existing_connections, + NMConnection *const*existing_connections, GError **error) { NMSettingTun *s_tun; @@ -157,61 +169,57 @@ 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); - NMSettingTun *s_tun = nm_connection_get_setting_tun (connection); - NMPlatformTunProperties props; + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + NMSettingTun *s_tun; NMSettingTunMode mode; - gint64 user, group; - char *str; + char s_buf[100]; + const char *str; - if (!s_tun) { - s_tun = (NMSettingTun *) nm_setting_tun_new (); - nm_connection_add_setting (connection, (NMSetting *) s_tun); - } + /* 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)); - 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."); + 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; } - mode = tun_mode_from_string (props.mode); + 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 (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); + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, (guint) mode, NULL); - if (props.owner != user) { - str = props.owner >= 0 ? g_strdup_printf ("%" G_GINT32_FORMAT, (gint32) props.owner) : NULL; + 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))) 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; + 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))) 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); + 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); } static gboolean @@ -222,23 +230,42 @@ create_and_realize (NMDevice *device, GError **error) { const char *iface = nm_device_get_iface (device); + NMPlatformLnkTun props = { }; NMPlatformError plerr; NMSettingTun *s_tun; - gint64 user, group; + gint64 owner, group; s_tun = nm_connection_get_setting_tun (connection); - g_assert (s_tun); + 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); + } - user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + 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; + } 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; + } - 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); + 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); 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", @@ -252,13 +279,22 @@ 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; @@ -268,18 +304,21 @@ check_connection_compatible (NMDevice *device, NMConnection *connection) return FALSE; if (nm_device_is_real (device)) { - mode = tun_mode_from_string (priv->mode); - if (mode != nm_setting_tun_get_mode (s_tun)) + 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; + } - 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) + 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)) return FALSE; - if (group != priv->props.group) + if (!_same_og (nm_setting_tun_get_group (s_tun), priv->props.group_valid, priv->props.group)) return FALSE; - if (nm_setting_tun_get_pi (s_tun) == priv->props.no_pi) + if (nm_setting_tun_get_pi (s_tun) != priv->props.pi) return FALSE; if (nm_setting_tun_get_vnet_hdr (s_tun) != priv->props.vnet_hdr) return FALSE; @@ -302,7 +341,7 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason) return ret; /* Nothing to do for TUN devices */ - if (g_strcmp0 (priv->mode, "tap")) + if (priv->props.type == IFF_TUN) return NM_ACT_STAGE_RETURN_SUCCESS; if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE)) @@ -314,16 +353,8 @@ 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); - - memset (&priv->props, 0, sizeof (NMPlatformTunProperties)); - - for (i = 1; i < _PROPERTY_ENUMS_LAST; i++) - g_object_notify_by_pspec ((GObject *) self, obj_properties[i]); + update_properties_from_struct (NM_DEVICE_TUN (device), NULL); } /*****************************************************************************/ @@ -334,19 +365,25 @@ 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); + g_value_set_int64 (value, priv->props.owner_valid ? (gint64) priv->props.owner : (gint64) -1); break; case PROP_GROUP: - g_value_set_int64 (value, priv->props.group); + g_value_set_int64 (value, priv->props.group_valid ? (gint64) priv->props.group : (gint64) -1); break; case PROP_MODE: - g_value_set_string (value, priv->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); break; case PROP_NO_PI: - g_value_set_boolean (value, priv->props.no_pi); + g_value_set_boolean (value, !priv->props.pi); break; case PROP_VNET_HDR: g_value_set_boolean (value, priv->props.vnet_hdr); @@ -360,33 +397,6 @@ 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 @@ -394,16 +404,37 @@ 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_LINK_TYPE_TAP) + NM_DEVICE_CLASS_DECLARE_TYPES (klass, NULL, NM_LINK_TYPE_TUN) object_class->get_property = get_property; - object_class->set_property = set_property; + + dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS (&interface_info_device_tun); device_class->connection_type = NM_SETTING_TUN_SETTING_NAME; device_class->link_changed = link_changed; @@ -428,9 +459,8 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) obj_properties[PROP_MODE] = g_param_spec_string (NM_DEVICE_TUN_MODE, "", "", - "tun", - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); obj_properties[PROP_NO_PI] = g_param_spec_boolean (NM_DEVICE_TUN_NO_PI, "", "", @@ -448,10 +478,6 @@ 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); } @@ -467,42 +493,19 @@ create_device (NMDeviceFactory *factory, NMConnection *connection, gboolean *out_ignore) { - 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"; + 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); 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, link_type, - NM_DEVICE_TUN_MODE, mode, + NM_DEVICE_LINK_TYPE, (guint) NM_LINK_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_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_TUN_SETTING_NAME), factory_class->create_device = create_device; ); |