summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;