diff options
-rw-r--r-- | libnm-core/nm-setting-tun.c | 4 | ||||
-rw-r--r-- | src/devices/nm-device-tun.c | 305 | ||||
-rw-r--r-- | src/devices/tests/test-lldp.c | 2 | ||||
-rw-r--r-- | src/nm-types.h | 2 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 212 | ||||
-rw-r--r-- | src/platform/nm-netlink.h | 9 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 196 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 54 | ||||
-rw-r--r-- | src/platform/nmp-object.c | 11 | ||||
-rw-r--r-- | src/platform/nmp-object.h | 7 |
10 files changed, 500 insertions, 302 deletions
diff --git a/libnm-core/nm-setting-tun.c b/libnm-core/nm-setting-tun.c index dab407bdd6..edcb3ffdc9 100644 --- a/libnm-core/nm-setting-tun.c +++ b/libnm-core/nm-setting-tun.c @@ -179,8 +179,8 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingTunPrivate *priv = NM_SETTING_TUN_GET_PRIVATE (setting); - if ( priv->mode != NM_SETTING_TUN_MODE_TUN - && priv->mode != NM_SETTING_TUN_MODE_TAP) { + if (!NM_IN_SET (priv->mode, NM_SETTING_TUN_MODE_TUN, + NM_SETTING_TUN_MODE_TAP)) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 5dd53054d0..3573334b3d 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" @@ -49,8 +50,7 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMDeviceTun, ); typedef struct { - NMPlatformTunProperties props; - const char *mode; + NMPlatformLnkTun props; } NMDeviceTunPrivate; struct _NMDeviceTun { @@ -69,49 +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; - int ifindex; + const NMPlatformLnkTun props0 = { }; - 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)); + if (!props) { + /* allow passing %NULL to reset all properties. */ + props = &props0; + } - g_object_freeze_notify (object); + 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; \ + if (priv->props.field != props->field) { \ + priv->props.field = props->field; \ _notify (self, prop); \ } \ } G_STMT_END - CHECK_PROPERTY_CHANGED (owner, PROP_OWNER); - CHECK_PROPERTY_CHANGED (group, PROP_GROUP); - CHECK_PROPERTY_CHANGED (no_pi, PROP_NO_PI); + 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 (object); + 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 + && 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 @@ -156,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); + g_object_set (G_OBJECT (s_tun), NM_SETTING_TUN_MODE, (guint) 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; + 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 @@ -221,22 +230,40 @@ 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); - user = _nm_utils_ascii_str_to_int64 (nm_setting_tun_get_owner (s_tun), 10, 0, G_MAXINT32, -1); + 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); + } + + 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; + } + + 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, - 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), + plerr = nm_platform_link_tun_add (nm_device_get_platform (device), + iface, + &props, out_plink); if (plerr != NM_PLATFORM_ERROR_SUCCESS) { g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED, @@ -251,13 +278,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; @@ -267,18 +303,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; @@ -301,7 +340,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)) @@ -313,16 +352,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); } /*****************************************************************************/ @@ -333,19 +364,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); @@ -359,33 +396,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 @@ -419,10 +429,9 @@ nm_device_tun_class_init (NMDeviceTunClass *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); @@ -449,9 +458,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, "", "", @@ -484,42 +492,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; ); diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c index c3c4f0d2c5..655f26ecad 100644 --- a/src/devices/tests/test-lldp.c +++ b/src/devices/tests/test-lldp.c @@ -368,7 +368,7 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data) g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0); nm_close (s); - link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TAP, 100); + link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 100); fixture->ifindex = link->ifindex; fixture->fd = fd; memcpy (fixture->mac, link->addr.data, ETH_ALEN); diff --git a/src/nm-types.h b/src/nm-types.h index 4434c8cce5..487b001ec6 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -158,7 +158,6 @@ typedef enum { NM_LINK_TYPE_OPENVSWITCH, NM_LINK_TYPE_PPP, NM_LINK_TYPE_SIT, - NM_LINK_TYPE_TAP, NM_LINK_TYPE_TUN, NM_LINK_TYPE_VETH, NM_LINK_TYPE_VLAN, @@ -192,6 +191,7 @@ typedef enum { NMP_OBJECT_TYPE_LNK_MACVLAN, NMP_OBJECT_TYPE_LNK_MACVTAP, NMP_OBJECT_TYPE_LNK_SIT, + NMP_OBJECT_TYPE_LNK_TUN, NMP_OBJECT_TYPE_LNK_VLAN, NMP_OBJECT_TYPE_LNK_VXLAN, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index f29ee03e6a..8454ea52c8 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -124,6 +124,18 @@ enum { #define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) #endif +#define IFLA_TUN_UNSPEC 0 +#define IFLA_TUN_OWNER 1 +#define IFLA_TUN_GROUP 2 +#define IFLA_TUN_TYPE 3 +#define IFLA_TUN_PI 4 +#define IFLA_TUN_VNET_HDR 5 +#define IFLA_TUN_PERSIST 6 +#define IFLA_TUN_MULTI_QUEUE 7 +#define IFLA_TUN_NUM_QUEUES 8 +#define IFLA_TUN_NUM_DISABLED_QUEUES 9 +#define __IFLA_TUN_MAX 10 +#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) static const gboolean RTA_PREF_SUPPORTED_AT_COMPILETIME = (RTA_MAX >= 20 /* RTA_PREF */); @@ -538,8 +550,7 @@ static const LinkDesc linktypes[] = { { NM_LINK_TYPE_OPENVSWITCH, "openvswitch", "openvswitch", NULL }, { NM_LINK_TYPE_PPP, "ppp", NULL, "ppp" }, { NM_LINK_TYPE_SIT, "sit", "sit", NULL }, - { NM_LINK_TYPE_TAP, "tap", NULL, NULL }, - { NM_LINK_TYPE_TUN, "tun", NULL, NULL }, + { NM_LINK_TYPE_TUN, "tun", "tun", NULL }, { NM_LINK_TYPE_VETH, "veth", "veth", NULL }, { NM_LINK_TYPE_VLAN, "vlan", "vlan", "vlan" }, { NM_LINK_TYPE_VXLAN, "vxlan", "vxlan", "vxlan" }, @@ -800,36 +811,25 @@ _linktype_get_type (NMPlatform *platform, && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE) && nm_streq (ifname, obj->link.name) && ( !kind - || !g_strcmp0 (kind, obj->link.kind))) { + || nm_streq0 (kind, obj->link.kind))) { nm_assert (obj->link.kind == g_intern_string (obj->link.kind)); *out_kind = obj->link.kind; return obj->link.type; } } + /* we intern kind to not require us to keep the pointer alive. Essentially + * leaking it in a global cache. That should be safe enough, because the + * kind comes only from kernel messages, which depend on the number of + * available drivers. So, there is not the danger that we leak uncontrolled + * many kinds. */ *out_kind = g_intern_string (kind); if (kind) { for (i = 0; i < G_N_ELEMENTS (linktypes); i++) { - if (g_strcmp0 (kind, linktypes[i].rtnl_type) == 0) + if (nm_streq0 (kind, linktypes[i].rtnl_type)) { return linktypes[i].nm_type; - } - - if (!strcmp (kind, "tun")) { - NMPlatformTunProperties props; - - if ( platform - && nm_platform_link_tun_get_properties (platform, ifindex, &props)) { - if (!g_strcmp0 (props.mode, "tap")) - return NM_LINK_TYPE_TAP; - if (!g_strcmp0 (props.mode, "tun")) - return NM_LINK_TYPE_TUN; } - - /* try guessing the type using the link flags instead... */ - if (flags & IFF_POINTOPOINT) - return NM_LINK_TYPE_TUN; - return NM_LINK_TYPE_TAP; } } @@ -1377,6 +1377,64 @@ _parse_lnk_sit (const char *kind, struct nlattr *info_data) /*****************************************************************************/ +static NMPObject * +_parse_lnk_tun (const char *kind, struct nlattr *info_data) +{ + static const struct nla_policy policy[IFLA_TUN_MAX + 1] = { + [IFLA_TUN_OWNER] = { .type = NLA_U32 }, + [IFLA_TUN_GROUP] = { .type = NLA_U32 }, + [IFLA_TUN_TYPE] = { .type = NLA_U8 }, + [IFLA_TUN_PI] = { .type = NLA_U8 }, + [IFLA_TUN_VNET_HDR] = { .type = NLA_U8 }, + [IFLA_TUN_PERSIST] = { .type = NLA_U8 }, + [IFLA_TUN_MULTI_QUEUE] = { .type = NLA_U8 }, + [IFLA_TUN_NUM_QUEUES] = { .type = NLA_U32 }, + [IFLA_TUN_NUM_DISABLED_QUEUES] = { .type = NLA_U32 }, + }; + struct nlattr *tb[IFLA_TUN_MAX + 1]; + int err; + NMPObject *obj; + NMPlatformLnkTun *props; + + // FIXME: the netlink API is not yet part of a released kernel version + // Disable it for now, until we are sure it is stable. + return NULL; + + if (!info_data || !nm_streq0 (kind, "tun")) + return NULL; + + err = nla_parse_nested (tb, IFLA_TUN_MAX, info_data, policy); + if (err < 0) + return NULL; + + if (!tb[IFLA_TUN_TYPE]) { + /* we require at least a type. */ + return NULL; + } + + obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_TUN, NULL); + props = &obj->lnk_tun; + + props->type = nla_get_u8 (tb[IFLA_TUN_TYPE]); + + props->pi = !!nla_get_u8_cond (tb, IFLA_TUN_PI, FALSE); + props->vnet_hdr = !!nla_get_u8_cond (tb, IFLA_TUN_VNET_HDR, FALSE); + props->multi_queue = !!nla_get_u8_cond (tb, IFLA_TUN_MULTI_QUEUE, FALSE); + props->persist = !!nla_get_u8_cond (tb, IFLA_TUN_PERSIST, FALSE); + + if (tb[IFLA_TUN_OWNER]) { + props->owner_valid = TRUE; + props->owner = nla_get_u32 (tb[IFLA_TUN_OWNER]); + } + if (tb[IFLA_TUN_GROUP]) { + props->group_valid = TRUE; + props->group = nla_get_u32 (tb[IFLA_TUN_GROUP]); + } + return obj; +} + +/*****************************************************************************/ + static gboolean _vlan_qos_mapping_from_nla (struct nlattr *nlattr, const NMVlanQosMapping **out_map, @@ -1808,6 +1866,9 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr case NM_LINK_TYPE_SIT: lnk_data = _parse_lnk_sit (nl_info_kind, nl_info_data); break; + case NM_LINK_TYPE_TUN: + lnk_data = _parse_lnk_tun (nl_info_kind, nl_info_data); + break; case NM_LINK_TYPE_VLAN: lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data); break; @@ -5527,6 +5588,56 @@ nla_put_failure: } static gboolean +link_tun_add (NMPlatform *platform, + const char *name, + const NMPlatformLnkTun *props, + const NMPlatformLink **out_link) +{ + const NMPObject *obj; + struct ifreq ifr = { }; + nm_auto_close int fd = -1; + + if (!NM_IN_SET (props->type, IFF_TAP, IFF_TUN)) + return FALSE; + + fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); + if (fd < 0) + return FALSE; + + nm_utils_ifname_cpy (ifr.ifr_name, name); + ifr.ifr_flags = ((short) props->type) + | ((short) IFF_TUN_EXCL) + | (!props->pi ? (short) IFF_NO_PI : (short) 0) + | ( props->vnet_hdr ? (short) IFF_VNET_HDR : (short) 0) + | ( props->multi_queue ? (short) NM_IFF_MULTI_QUEUE : (short) 0); + if (ioctl (fd, TUNSETIFF, &ifr)) + return FALSE; + + if (props->owner_valid) { + if (ioctl (fd, TUNSETOWNER, (uid_t) props->owner)) + return FALSE; + } + + if (props->group_valid) { + if (ioctl (fd, TUNSETGROUP, (gid_t) props->group)) + return FALSE; + } + + if (ioctl (fd, TUNSETPERSIST, (int) !!props->persist)) + return FALSE; + + do_request_link (platform, 0, name); + obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), + 0, name, FALSE, + NM_LINK_TYPE_TUN, + NULL, NULL); + if (out_link) + *out_link = obj ? &obj->link : NULL; + + return !!obj; +} + +static gboolean link_vxlan_add (NMPlatform *platform, const char *name, const NMPlatformLnkVxlan *props, @@ -5766,64 +5877,6 @@ link_vlan_change (NMPlatform *platform, return do_change_link (platform, CHANGE_LINK_TYPE_UNSPEC, ifindex, nlmsg, NULL) == NM_PLATFORM_ERROR_SUCCESS; } -static int -tun_add (NMPlatform *platform, const char *name, gboolean tap, - gint64 owner, gint64 group, gboolean pi, gboolean vnet_hdr, - gboolean multi_queue, const NMPlatformLink **out_link) -{ - const NMPObject *obj; - struct ifreq ifr = { }; - int fd; - - fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC); - if (fd < 0) - return FALSE; - - nm_utils_ifname_cpy (ifr.ifr_name, name); - ifr.ifr_flags = tap ? IFF_TAP : IFF_TUN; - - if (!pi) - ifr.ifr_flags |= IFF_NO_PI; - if (vnet_hdr) - ifr.ifr_flags |= IFF_VNET_HDR; - if (multi_queue) - ifr.ifr_flags |= NM_IFF_MULTI_QUEUE; - - if (ioctl (fd, TUNSETIFF, &ifr)) { - nm_close (fd); - return FALSE; - } - - if (owner >= 0 && owner < G_MAXINT32) { - if (ioctl (fd, TUNSETOWNER, (uid_t) owner)) { - nm_close (fd); - return FALSE; - } - } - - if (group >= 0 && group < G_MAXINT32) { - if (ioctl (fd, TUNSETGROUP, (gid_t) group)) { - nm_close (fd); - return FALSE; - } - } - - if (ioctl (fd, TUNSETPERSIST, 1)) { - nm_close (fd); - return FALSE; - } - do_request_link (platform, 0, name); - obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), - 0, name, FALSE, - tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, - NULL, NULL); - if (out_link) - *out_link = obj ? &obj->link : NULL; - - nm_close (fd); - return !!obj; -} - static gboolean link_enslave (NMPlatform *platform, int master, int slave) { @@ -7156,8 +7209,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_vlan_change = link_vlan_change; platform_class->link_vxlan_add = link_vxlan_add; - platform_class->tun_add = tun_add; - platform_class->infiniband_partition_add = infiniband_partition_add; platform_class->infiniband_partition_delete = infiniband_partition_delete; @@ -7182,6 +7233,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->link_macvlan_add = link_macvlan_add; platform_class->link_ipip_add = link_ipip_add; platform_class->link_sit_add = link_sit_add; + platform_class->link_tun_add = link_tun_add; platform_class->object_delete = object_delete; platform_class->ip4_address_add = ip4_address_add; diff --git a/src/platform/nm-netlink.h b/src/platform/nm-netlink.h index bd8a9cfaf0..1c89c18808 100644 --- a/src/platform/nm-netlink.h +++ b/src/platform/nm-netlink.h @@ -176,6 +176,15 @@ nla_get_u8 (const struct nlattr *nla) return *(const uint8_t *) nla_data (nla); } +static inline uint8_t +nla_get_u8_cond (/*const*/ struct nlattr *const*tb, int attr, uint8_t default_val) +{ + nm_assert (tb); + nm_assert (attr >= 0); + + return tb[attr] ? nla_get_u8 (tb[attr]) : default_val; +} + static inline uint16_t nla_get_u16 (const struct nlattr *nla) { diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 7e2f27ced0..9ee8f5cdfe 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -1894,6 +1894,12 @@ nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLin return _link_get_lnk (self, ifindex, NM_LINK_TYPE_SIT, out_link); } +const NMPlatformLnkTun * +nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) +{ + return _link_get_lnk (self, ifindex, NM_LINK_TYPE_TUN, out_link); +} + const NMPlatformLnkVlan * nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link) { @@ -2046,27 +2052,24 @@ nm_platform_link_vxlan_add (NMPlatform *self, NMPlatformError nm_platform_link_tun_add (NMPlatform *self, const char *name, - gboolean tap, - gint64 owner, - gint64 group, - gboolean pi, - gboolean vnet_hdr, - gboolean multi_queue, + const NMPlatformLnkTun *props, const NMPlatformLink **out_link) { + char b[255]; NMPlatformError plerr; _CHECK_SELF (self, klass, NM_PLATFORM_ERROR_BUG); g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG); + g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG); - plerr = _link_add_check_existing (self, name, tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN, out_link); + plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_TUN, out_link); if (plerr != NM_PLATFORM_ERROR_SUCCESS) return plerr; - _LOGD ("link: adding %s '%s' owner %" G_GINT64_FORMAT " group %" G_GINT64_FORMAT, - tap ? "tap" : "tun", name, owner, group); - if (!klass->tun_add (self, name, tap, owner, group, pi, vnet_hdr, multi_queue, out_link)) + _LOGD ("link: adding tun '%s' %s", + name, nm_platform_lnk_tun_to_string (props, b, sizeof (b))); + if (!klass->link_tun_add (self, name, props, out_link)) return NM_PLATFORM_ERROR_UNSPECIFIED; return NM_PLATFORM_ERROR_SUCCESS; } @@ -2670,44 +2673,100 @@ nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_pe return TRUE; } +/** + * nm_platform_link_tun_get_properties: + * @self: the #NMPlatform instance + * @ifindex: the ifindex to look up + * @out_properties: (out): (allow-none): return the read properties + * + * Only recent versions of kernel export tun properties via netlink. + * So, if that's the case, then we have the NMPlatformLnkTun instance + * in the platform cache ready to return. Otherwise, this function + * falls back reading sysctl to obtain the tun properties. That + * is racy, because querying sysctl means that the object might + * be already removed from cache (while NM didn't yet process the + * netlink message). + * + * Hence, to lookup the tun properties, you always need to use this + * function, and use it with care knowing that it might obtain it's + * data by reading sysctl. Note that we don't want to add this workaround + * to the platform cache itself, because the cache should (mainly) + * contain data from netlink. To access the sysctl side channel, the + * user needs to do explicitly. + * + * Returns: #TRUE, if the properties could be read. */ gboolean -nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props) +nm_platform_link_tun_get_properties (NMPlatform *self, + int ifindex, + NMPlatformLnkTun *out_properties) { - nm_auto_close int dirfd = -1; + const NMPObject *plobj; + const NMPObject *pllnk; char ifname[IFNAMSIZ]; + gint64 owner; + gint64 group; gint64 flags; - gboolean success = TRUE; + _CHECK_SELF (self, klass, FALSE); g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (props, FALSE); - memset (props, 0, sizeof (*props)); - props->owner = -1; - props->group = -1; - - dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname); - if (dirfd < 0) + /* we consider also invisible links (those that are not yet in udev). */ + plobj = nm_platform_link_get_obj (self, ifindex, FALSE); + if (!plobj) + return FALSE; + if (NMP_OBJECT_CAST_LINK (plobj)->type != NM_LINK_TYPE_TUN) return FALSE; - props->owner = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "owner"), 10, -1, G_MAXINT64, -1); - if (errno) - success = FALSE; + pllnk = plobj->_link.netlink.lnk; + if (pllnk) { + nm_assert (NMP_OBJECT_GET_TYPE (pllnk) == NMP_OBJECT_TYPE_LNK_TUN); + nm_assert (NMP_OBJECT_GET_CLASS (pllnk)->lnk_link_type == NM_LINK_TYPE_TUN); - props->group = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "group"), 10, -1, G_MAXINT64, -1); - if (errno) - success = FALSE; + /* recent kernels expose tun properties via netlink and thus we have them + * in the platform cache. */ + NM_SET_OUT (out_properties, pllnk->lnk_tun); + return TRUE; + } - flags = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "tun_flags"), 16, 0, G_MAXINT64, -1); - if (flags >= 0) { - props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap"; - props->no_pi = !!(flags & IFF_NO_PI); - props->vnet_hdr = !!(flags & IFF_VNET_HDR); - props->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); - } else - success = FALSE; + /* fallback to reading sysctl. */ + { + nm_auto_close int dirfd = -1; - return success; + dirfd = nm_platform_sysctl_open_netdir (self, ifindex, ifname); + if (dirfd < 0) + return FALSE; + + owner = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "owner"), 10, -1, G_MAXUINT32, -2); + if (owner == -2) + return FALSE; + + group = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "group"), 10, -1, G_MAXUINT32, -2); + if (group == -2) + return FALSE; + + flags = nm_platform_sysctl_get_int_checked (self, NMP_SYSCTL_PATHID_NETDIR (dirfd, ifname, "tun_flags"), 16, 0, G_MAXINT64, -1); + if (flags == -1) + return FALSE; + } + + if (out_properties) { + memset (out_properties, 0, sizeof (*out_properties)); + if (owner != -1) { + out_properties->owner_valid = TRUE; + out_properties->owner = owner; + } + if (group != -1) { + out_properties->group_valid = TRUE; + out_properties->group = group; + } + out_properties->type = (flags & TUN_TYPE_MASK); + out_properties->pi = !(flags & IFF_NO_PI); + out_properties->vnet_hdr = !!(flags & IFF_VNET_HDR); + out_properties->multi_queue = !!(flags & NM_IFF_MULTI_QUEUE); + out_properties->persist = !!(flags & IFF_PERSIST); + } + return TRUE; } gboolean @@ -4995,6 +5054,41 @@ nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len } const char * +nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len) +{ + char str_owner[50]; + char str_group[50]; + char str_type[50]; + const char *type; + + if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len)) + return buf; + + if (lnk->type == IFF_TUN) + type = "tun"; + else if (lnk->type == IFF_TAP) + type = "tap"; + else + type = nm_sprintf_buf (str_type, "tun type %u", (guint) lnk->type); + + g_snprintf (buf, len, + "%s " /* type */ + " pi %s" /* pi */ + " vnet_hdr %s" /* vnet_hdr */ + "%s" /* multi_queue */ + "%s" /* owner */ + "%s" /* group */ + "", + type, + lnk->pi ? "on" : "off", + lnk->vnet_hdr ? "on" : "off", + lnk->multi_queue ? " multi_queue" : "", + lnk->owner_valid ? nm_sprintf_buf (str_owner, " owner %u", (guint) lnk->owner) : "", + lnk->group_valid ? nm_sprintf_buf (str_group, " group %u", (guint) lnk->group) : ""); + return buf; +} + +const char * nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len) { char *b; @@ -5825,6 +5919,38 @@ nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b) } void +nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h) +{ + nm_hash_update_vals (h, + obj->type, + obj->owner, + obj->group, + NM_HASH_COMBINE_BOOLS (guint8, + obj->owner_valid, + obj->group_valid, + obj->pi, + obj->vnet_hdr, + obj->multi_queue, + obj->persist)); +} + +int +nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b) +{ + NM_CMP_SELF (a, b); + NM_CMP_FIELD (a, b, type); + NM_CMP_FIELD (a, b, owner); + NM_CMP_FIELD (a, b, group); + NM_CMP_FIELD_BOOL (a, b, owner_valid); + NM_CMP_FIELD_BOOL (a, b, group_valid); + NM_CMP_FIELD_BOOL (a, b, pi); + NM_CMP_FIELD_BOOL (a, b, vnet_hdr); + NM_CMP_FIELD_BOOL (a, b, multi_queue); + NM_CMP_FIELD_BOOL (a, b, persist); + return 0; +} + +void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h) { nm_hash_update_vals (h, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 53b2975bf5..0afdb3b060 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -656,6 +656,21 @@ typedef struct { } NMPlatformLnkSit; typedef struct { + guint32 owner; + guint32 group; + + guint8 type; + + bool owner_valid:1; + bool group_valid:1; + + bool pi:1; + bool vnet_hdr:1; + bool multi_queue:1; + bool persist:1; +} NMPlatformLnkTun; + +typedef struct { /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */ guint16 id; NMVlanFlags flags; @@ -682,15 +697,6 @@ typedef struct { bool l3miss:1; } NMPlatformLnkVxlan; -typedef struct { - gint64 owner; - gint64 group; - const char *mode; - bool no_pi:1; - bool vnet_hdr:1; - bool multi_queue:1; -} NMPlatformTunProperties; - typedef enum { NM_PLATFORM_LINK_DUPLEX_UNKNOWN, NM_PLATFORM_LINK_DUPLEX_HALF, @@ -816,12 +822,14 @@ typedef struct { const NMPlatformLnkSit *props, const NMPlatformLink **out_link); + gboolean (*link_tun_add) (NMPlatform *platform, + const char *name, + const NMPlatformLnkTun *props, + const NMPlatformLink **out_link); + gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link); gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key); - gboolean (*tun_add) (NMPlatform *platform, const char *name, gboolean tap, gint64 owner, gint64 group, gboolean pi, - gboolean vnet_hdr, gboolean multi_queue, const NMPlatformLink **out_link); - gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps); gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid); GByteArray *(*wifi_get_ssid) (NMPlatform *, int ifindex); @@ -1159,6 +1167,7 @@ const NMPlatformLnkMacsec *nm_platform_link_get_lnk_macsec (NMPlatform *self, in const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkMacvtap *nm_platform_link_get_lnk_macvtap (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkSit *nm_platform_link_get_lnk_sit (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); +const NMPlatformLnkTun *nm_platform_link_get_lnk_tun (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link); @@ -1186,16 +1195,6 @@ NMPlatformError nm_platform_link_vxlan_add (NMPlatform *self, const NMPlatformLnkVxlan *props, const NMPlatformLink **out_link); -NMPlatformError nm_platform_link_tun_add (NMPlatform *self, - const char *name, - gboolean tap, - gint64 owner, - gint64 group, - gboolean pi, - gboolean vnet_hdr, - gboolean multi_queue, - const NMPlatformLink **out_link); - NMPlatformError nm_platform_link_infiniband_add (NMPlatform *self, int parent, int p_key, @@ -1206,7 +1205,9 @@ NMPlatformError nm_platform_link_infiniband_delete (NMPlatform *self, gboolean nm_platform_link_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode); gboolean nm_platform_link_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex); -gboolean nm_platform_link_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties); +gboolean nm_platform_link_tun_get_properties (NMPlatform *self, + int ifindex, + NMPlatformLnkTun *out_properties); gboolean nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps); gboolean nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid); @@ -1254,6 +1255,10 @@ NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const char *name, const NMPlatformLnkSit *props, const NMPlatformLink **out_link); +NMPlatformError nm_platform_link_tun_add (NMPlatform *self, + const char *name, + const NMPlatformLnkTun *props, + const NMPlatformLink **out_link); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); @@ -1337,6 +1342,7 @@ const char *nm_platform_lnk_ipip_to_string (const NMPlatformLnkIpIp *lnk, char * const char *nm_platform_lnk_macsec_to_string (const NMPlatformLnkMacsec *lnk, char *buf, gsize len); const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_sit_to_string (const NMPlatformLnkSit *lnk, char *buf, gsize len); +const char *nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len); const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len); const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len); const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len); @@ -1360,6 +1366,7 @@ int nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpI int nm_platform_lnk_macsec_cmp (const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b); int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b); int nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b); +int nm_platform_lnk_tun_cmp (const NMPlatformLnkTun *a, const NMPlatformLnkTun *b); int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b); int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b); int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b); @@ -1395,6 +1402,7 @@ void nm_platform_lnk_ipip_hash_update (const NMPlatformLnkIpIp *obj, NMHashState void nm_platform_lnk_macsec_hash_update (const NMPlatformLnkMacsec *obj, NMHashState *h); void nm_platform_lnk_macvlan_hash_update (const NMPlatformLnkMacvlan *obj, NMHashState *h); void nm_platform_lnk_sit_hash_update (const NMPlatformLnkSit *obj, NMHashState *h); +void nm_platform_lnk_tun_hash_update (const NMPlatformLnkTun *obj, NMHashState *h); void nm_platform_lnk_vlan_hash_update (const NMPlatformLnkVlan *obj, NMHashState *h); void nm_platform_lnk_vxlan_hash_update (const NMPlatformLnkVxlan *obj, NMHashState *h); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 4df64e608c..23f4b9c1d0 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -2780,6 +2780,17 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_sit_hash_update, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp, }, + [NMP_OBJECT_TYPE_LNK_TUN - 1] = { + .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), + .obj_type = NMP_OBJECT_TYPE_LNK_TUN, + .sizeof_data = sizeof (NMPObjectLnkTun), + .sizeof_public = sizeof (NMPlatformLnkTun), + .obj_type_name = "tun", + .lnk_link_type = NM_LINK_TYPE_TUN, + .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_tun_to_string, + .cmd_plobj_hash_update = (void (*) (const NMPlatformObject *obj, NMHashState *h)) nm_platform_lnk_tun_hash_update, + .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_tun_cmp, + }, [NMP_OBJECT_TYPE_LNK_VLAN - 1] = { .parent = DEDUP_MULTI_OBJ_CLASS_INIT(), .obj_type = NMP_OBJECT_TYPE_LNK_VLAN, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 8c36e2e3d4..91eb2f5106 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -197,6 +197,10 @@ typedef struct { } NMPObjectLnkSit; typedef struct { + NMPlatformLnkTun _public; +} NMPObjectLnkTun; + +typedef struct { NMPlatformLnkVlan _public; guint n_ingress_qos_map; @@ -265,6 +269,9 @@ struct _NMPObject { NMPlatformLnkSit lnk_sit; NMPObjectLnkSit _lnk_sit; + NMPlatformLnkTun lnk_tun; + NMPObjectLnkTun _lnk_tun; + NMPlatformLnkVlan lnk_vlan; NMPObjectLnkVlan _lnk_vlan; |