summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-03-13 15:29:03 +0100
committerThomas Haller <thaller@redhat.com>2018-03-18 21:09:26 +0100
commite036c81a40c9aba3bcf6e09b1acf7f37ba0bb3a2 (patch)
treeef629e694a4cdc7f02cce87ea482b505aeff2ed4
parent4b24f42e5e35f060ae6d711fc9e93f13e7634c2b (diff)
downloadNetworkManager-th/platform-tun-netlink-rh1547213.tar.gz
core/platform: add support for TUN/TAP netlink support and various cleanupth/platform-tun-netlink-rh1547213
Kernel recently got support for exposing TUN/TAP information on netlink [1], [2], [3]. Add support for that in the platform cache. The advantage of using netlink is that querying sysctl bypasses the order of events of the netlink socket. It is out of sync and racy. For example, platform cache might still think that a tun device exists, but a subsequent lookup at sysfs might fail because the device was deleted in the meantime. Another point is, that we don't get change notifications via sysctl and that it requires various extra syscalls to read the device information. If the tun information is present on netlink, put it into the cache. This bypasses checking sysctl while we keep looking at sysctl for backward compatibility until we require support from kernel. Notes: - we had two link types NM_LINK_TYPE_TAP and NM_LINK_TYPE_TUN. This deviates from the model of how kernel treats TUN/TAP devices, which makes it more complicated. The link type of a NMPlatformLink instance should match what kernel thinks about the device. Point in case, when parsing RTM_NETLINK messages, we very early need to determine the link type (_linktype_get_type()). However, to determine the type of a TUN/TAP at that point, we need to look into nested netlink attributes which in turn depend on the type (IFLA_INFO_KIND and IFLA_INFO_DATA), or even worse, we would need to look into sysctl for older kernel vesions. Now, the TUN/TAP type is a property of the link type NM_LINK_TYPE_TUN, instead of determining two different link types. - various parts of the API (both kernel's sysctl vs. netlink) and NMDeviceTun vs. NMSettingTun disagree whether the PI is positive (NM_SETTING_TUN_PI, IFLA_TUN_PI, NMPlatformLnkTun.pi) or inverted (NM_DEVICE_TUN_NO_PI, IFF_NO_PI). There is no consistent way, but prefer the positive form for internal API at NMPlatformLnkTun.pi. - previously NMDeviceTun.mode could not change after initializing the object. Allow for that to happen, because forcing some properties that are reported by kernel to not change is wrong, in case they might change. Of course, in practice kernel doesn't allow the device to ever change its type, but type type of the NMDeviceTun should not make that assumption, because, if it actually changes, what would it mean? - note that as of now, new netlink API is not yet merged to mainline Linus tree. Shortcut _parse_lnk_tun() to not accidentally use unstable API for now. [1] https://bugzilla.redhat.com/show_bug.cgi?id=1277457 [2] https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git/commit/?id=1ec010e705934c8acbe7dbf31afc81e60e3d828b [3] https://git.kernel.org/pub/scm/network/iproute2/iproute2-next.git/commit/?id=118eda77d6602616bc523a17ee45171e879d1818 https://bugzilla.redhat.com/show_bug.cgi?id=1547213
-rw-r--r--libnm-core/nm-setting-tun.c4
-rw-r--r--src/devices/nm-device-tun.c305
-rw-r--r--src/devices/tests/test-lldp.c2
-rw-r--r--src/nm-types.h2
-rw-r--r--src/platform/nm-linux-platform.c212
-rw-r--r--src/platform/nm-netlink.h9
-rw-r--r--src/platform/nm-platform.c196
-rw-r--r--src/platform/nm-platform.h54
-rw-r--r--src/platform/nmp-object.c11
-rw-r--r--src/platform/nmp-object.h7
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;