summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-04-09 20:29:13 +0200
committerThomas Haller <thaller@redhat.com>2018-04-09 20:29:13 +0200
commit69e80d6c51d9447445c8ef2696c8f3ef8c4d1dc9 (patch)
tree833709ce514cc580e216d9ddf2cbcb1fb07263b0
parent7a063a91c7f8db8f78cab124bf9ba80a242be233 (diff)
parentef93f6caad0552b8bd73057caed52147dac5eda0 (diff)
downloadNetworkManager-69e80d6c51d9447445c8ef2696c8f3ef8c4d1dc9.tar.gz
platform: merge branch 'th/platform-tun'
https://github.com/NetworkManager/NetworkManager/pull/87
-rw-r--r--shared/nm-utils/nm-test-utils.h14
-rw-r--r--src/devices/nm-device-tun.c3
-rw-r--r--src/devices/tests/test-lldp.c52
-rw-r--r--src/platform/nm-linux-platform.c87
-rw-r--r--src/platform/nm-platform.c29
-rw-r--r--src/platform/nm-platform.h6
-rw-r--r--src/platform/tests/test-common.c103
-rw-r--r--src/platform/tests/test-common.h12
-rw-r--r--src/platform/tests/test-link.c65
-rwxr-xr-xtools/run-nm-test.sh8
10 files changed, 296 insertions, 83 deletions
diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h
index d7233de20f..f44f49d835 100644
--- a/shared/nm-utils/nm-test-utils.h
+++ b/shared/nm-utils/nm-test-utils.h
@@ -162,6 +162,14 @@
g_assert_not_reached (); \
} G_STMT_END
+#define nmtst_assert_nonnull(command) \
+ ({ \
+ typeof (*(command)) *_ptr = (command); \
+ \
+ g_assert (_ptr && (TRUE || (command))); \
+ _ptr; \
+ })
+
#define nmtst_assert_success(success, error) \
G_STMT_START { \
g_assert_no_error (error); \
@@ -808,6 +816,12 @@ nmtst_get_rand_int (void)
return g_rand_int (nmtst_get_rand ());
}
+static inline gboolean
+nmtst_get_rand_bool (void)
+{
+ return nmtst_get_rand_int () % 2;
+}
+
static inline gpointer
nmtst_rand_buf (GRand *rand, gpointer buffer, gsize buffer_length)
{
diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c
index 123455f16d..c3ce4b7357 100644
--- a/src/devices/nm-device-tun.c
+++ b/src/devices/nm-device-tun.c
@@ -264,7 +264,8 @@ create_and_realize (NMDevice *device,
plerr = nm_platform_link_tun_add (nm_device_get_platform (device),
iface,
&props,
- out_plink);
+ out_plink,
+ NULL);
if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create TUN/TAP interface '%s' for '%s': %s",
diff --git a/src/devices/tests/test-lldp.c b/src/devices/tests/test-lldp.c
index 655f26ecad..5d0625f80a 100644
--- a/src/devices/tests/test-lldp.c
+++ b/src/devices/tests/test-lldp.c
@@ -347,8 +347,7 @@ static void
_test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data)
{
const NMPlatformLink *link;
- struct ifreq ifr = { };
- int fd, s;
+ nm_auto_close int fd = -1;
fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd == -1) {
@@ -357,20 +356,45 @@ _test_recv_fixture_setup (TestRecvFixture *fixture, gconstpointer user_data)
return;
}
- ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
- nm_utils_ifname_cpy (ifr.ifr_name, TEST_IFNAME);
- g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0);
-
- /* Bring the interface up */
- s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
- g_assert (s >= 0);
- ifr.ifr_flags |= IFF_UP;
- g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0);
- nm_close (s);
+ if (nmtst_get_rand_bool ()) {
+ const NMPlatformLnkTun lnk = {
+ .type = IFF_TAP,
+ .pi = FALSE,
+ .vnet_hdr = FALSE,
+ .multi_queue = FALSE,
+ .persist = FALSE,
+ };
+
+ nm_close (nm_steal_fd (&fd));
+
+ link = nmtstp_link_tun_add (NM_PLATFORM_GET,
+ FALSE,
+ TEST_IFNAME,
+ &lnk,
+ &fd);
+ g_assert (link);
+ nmtstp_link_set_updown (NM_PLATFORM_GET, -1, link->ifindex, TRUE);
+ link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 0);
+ } else {
+ int s;
+ struct ifreq ifr = { };
+
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ nm_utils_ifname_cpy (ifr.ifr_name, TEST_IFNAME);
+ g_assert (ioctl (fd, TUNSETIFF, &ifr) >= 0);
+
+ /* Bring the interface up */
+ s = socket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ g_assert (s >= 0);
+ ifr.ifr_flags |= IFF_UP;
+ g_assert (ioctl (s, SIOCSIFFLAGS, &ifr) >= 0);
+ nm_close (s);
+
+ link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 100);
+ }
- link = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, TEST_IFNAME, NM_LINK_TYPE_TUN, 100);
fixture->ifindex = link->ifindex;
- fixture->fd = fd;
+ fixture->fd = nm_steal_fd (&fd);
memcpy (fixture->mac, link->addr.data, ETH_ALEN);
}
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index b8d252070e..0ed8fa06fb 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -1396,10 +1396,6 @@ _parse_lnk_tun (const char *kind, struct nlattr *info_data)
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;
@@ -3934,40 +3930,46 @@ cache_on_change (NMPlatform *platform,
&& (obj_new && obj_new->_link.netlink.is_in_netlink)
&& (!obj_old || !obj_old->_link.netlink.is_in_netlink))
{
- if (!obj_new->_link.netlink.lnk) {
+ gboolean re_request_link = FALSE;
+ const NMPlatformLnkTun *lnk_tun;
+
+ if ( !obj_new->_link.netlink.lnk
+ && NM_IN_SET (obj_new->link.type, NM_LINK_TYPE_GRE,
+ NM_LINK_TYPE_IP6TNL,
+ NM_LINK_TYPE_INFINIBAND,
+ NM_LINK_TYPE_MACVLAN,
+ NM_LINK_TYPE_MACVLAN,
+ NM_LINK_TYPE_SIT,
+ NM_LINK_TYPE_TUN,
+ NM_LINK_TYPE_VLAN,
+ NM_LINK_TYPE_VXLAN)) {
/* certain link-types also come with a IFLA_INFO_DATA/lnk_data. It may happen that
* kernel didn't send this notification, thus when we first learn about a link
* that lacks an lnk_data we re-request it again.
*
* For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */
- switch (obj_new->link.type) {
- case NM_LINK_TYPE_GRE:
- case NM_LINK_TYPE_IP6TNL:
- case NM_LINK_TYPE_INFINIBAND:
- case NM_LINK_TYPE_MACVLAN:
- case NM_LINK_TYPE_MACVTAP:
- case NM_LINK_TYPE_SIT:
- case NM_LINK_TYPE_VLAN:
- case NM_LINK_TYPE_VXLAN:
- delayed_action_schedule (platform,
- DELAYED_ACTION_TYPE_REFRESH_LINK,
- GINT_TO_POINTER (obj_new->link.ifindex));
- break;
- default:
- break;
- }
- }
- if ( obj_new->link.type == NM_LINK_TYPE_VETH
- && obj_new->link.parent == 0) {
+ re_request_link = TRUE;
+ } else if ( obj_new->link.type == NM_LINK_TYPE_TUN
+ && obj_new->_link.netlink.lnk
+ && (lnk_tun = &(obj_new->_link.netlink.lnk)->lnk_tun)
+ && !lnk_tun->persist
+ && lnk_tun->pi
+ && !lnk_tun->vnet_hdr
+ && !lnk_tun->multi_queue
+ && !lnk_tun->owner_valid
+ && !lnk_tun->group_valid) {
+ /* kernel has/had a know issue that the first notification for TUN device would
+ * be sent with invalid parameters. The message looks like that kind, so refetch
+ * it. */
+ re_request_link = TRUE;
+ } else if ( obj_new->link.type == NM_LINK_TYPE_VETH
+ && obj_new->link.parent == 0) {
/* the initial notification when adding a veth pair can lack the parent/IFLA_LINK
* (https://bugzilla.redhat.com/show_bug.cgi?id=1285827).
* Request it again. */
- delayed_action_schedule (platform,
- DELAYED_ACTION_TYPE_REFRESH_LINK,
- GINT_TO_POINTER (obj_new->link.ifindex));
- }
- if ( obj_new->link.type == NM_LINK_TYPE_ETHERNET
- && obj_new->link.addr.len == 0) {
+ re_request_link = TRUE;
+ } else if ( obj_new->link.type == NM_LINK_TYPE_ETHERNET
+ && obj_new->link.addr.len == 0) {
/* Due to a kernel bug, we sometimes receive spurious NEWLINK
* messages after a wifi interface has disappeared. Since the
* link is not present anymore we can't determine its type and
@@ -3975,6 +3977,9 @@ cache_on_change (NMPlatform *platform,
* specified. Request the link again to check if it really
* exists. https://bugzilla.redhat.com/show_bug.cgi?id=1302037
*/
+ re_request_link = TRUE;
+ }
+ if (re_request_link) {
delayed_action_schedule (platform,
DELAYED_ACTION_TYPE_REFRESH_LINK,
GINT_TO_POINTER (obj_new->link.ifindex));
@@ -5591,14 +5596,15 @@ static gboolean
link_tun_add (NMPlatform *platform,
const char *name,
const NMPlatformLnkTun *props,
- const NMPlatformLink **out_link)
+ const NMPlatformLink **out_link,
+ int *out_fd)
{
const NMPObject *obj;
struct ifreq ifr = { };
nm_auto_close int fd = -1;
- if (!NM_IN_SET (props->type, IFF_TAP, IFF_TUN))
- return FALSE;
+ nm_assert (NM_IN_SET (props->type, IFF_TAP, IFF_TUN));
+ nm_assert (props->persist || out_fd);
fd = open ("/dev/net/tun", O_RDWR | O_CLOEXEC);
if (fd < 0)
@@ -5623,18 +5629,23 @@ link_tun_add (NMPlatform *platform,
return FALSE;
}
- if (ioctl (fd, TUNSETPERSIST, (int) !!props->persist))
- return FALSE;
+ if (props->persist) {
+ if (ioctl (fd, TUNSETPERSIST, 1))
+ 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;
+ if (!obj)
+ return FALSE;
+
+ NM_SET_OUT (out_link, &obj->link);
+ NM_SET_OUT (out_fd, nm_steal_fd (&fd));
+ return TRUE;
}
static gboolean
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index a645da2ee6..976039def4 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -2046,6 +2046,11 @@ nm_platform_link_vxlan_add (NMPlatform *self,
* @vnet_hdr: whether to set the IFF_VNET_HDR flag
* @multi_queue: whether to set the IFF_MULTI_QUEUE flag
* @out_link: on success, the link object
+ * @out_fd: (allow-none): if give, return the file descriptor for the
+ * created device. Note that when creating a non-persistent device,
+ * this argument is mandatory, otherwise it makes no sense
+ * to create such an interface.
+ * The caller is responsible for closing this file descriptor.
*
* Create a TUN or TAP interface.
*/
@@ -2053,7 +2058,8 @@ NMPlatformError
nm_platform_link_tun_add (NMPlatform *self,
const char *name,
const NMPlatformLnkTun *props,
- const NMPlatformLink **out_link)
+ const NMPlatformLink **out_link,
+ int *out_fd)
{
char b[255];
NMPlatformError plerr;
@@ -2062,6 +2068,13 @@ nm_platform_link_tun_add (NMPlatform *self,
g_return_val_if_fail (name, NM_PLATFORM_ERROR_BUG);
g_return_val_if_fail (props, NM_PLATFORM_ERROR_BUG);
+ g_return_val_if_fail (NM_IN_SET (props->type, IFF_TUN, IFF_TAP), NM_PLATFORM_ERROR_BUG);
+
+ /* creating a non-persistant device requires that the caller handles
+ * the file descriptor. */
+ g_return_val_if_fail (props->persist || out_fd, NM_PLATFORM_ERROR_BUG);
+
+ NM_SET_OUT (out_fd, -1);
plerr = _link_add_check_existing (self, name, NM_LINK_TYPE_TUN, out_link);
if (plerr != NM_PLATFORM_ERROR_SUCCESS)
@@ -2069,7 +2082,7 @@ nm_platform_link_tun_add (NMPlatform *self,
_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))
+ if (!klass->link_tun_add (self, name, props, out_link, out_fd))
return NM_PLATFORM_ERROR_UNSPECIFIED;
return NM_PLATFORM_ERROR_SUCCESS;
}
@@ -5120,17 +5133,19 @@ nm_platform_lnk_tun_to_string (const NMPlatformLnkTun *lnk, char *buf, gsize len
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" /* type */
+ "%s" /* pi */
+ "%s" /* vnet_hdr */
"%s" /* multi_queue */
+ "%s" /* persist */
"%s" /* owner */
"%s" /* group */
"",
type,
- lnk->pi ? "on" : "off",
- lnk->vnet_hdr ? "on" : "off",
+ lnk->pi ? " pi" : "",
+ lnk->vnet_hdr ? " vnet_hdr" : "",
lnk->multi_queue ? " multi_queue" : "",
+ lnk->persist ? " persist" : "",
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;
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 824735083a..e6cef63bae 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -853,7 +853,8 @@ typedef struct {
gboolean (*link_tun_add) (NMPlatform *platform,
const char *name,
const NMPlatformLnkTun *props,
- const NMPlatformLink **out_link);
+ const NMPlatformLink **out_link,
+ int *out_fd);
gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, const NMPlatformLink **out_link);
gboolean (*infiniband_partition_delete) (NMPlatform *, int parent, int p_key);
@@ -1286,7 +1287,8 @@ NMPlatformError nm_platform_link_sit_add (NMPlatform *self,
NMPlatformError nm_platform_link_tun_add (NMPlatform *self,
const char *name,
const NMPlatformLnkTun *props,
- const NMPlatformLink **out_link);
+ const NMPlatformLink **out_link,
+ int *out_fd);
const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address);
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index 67e74c13f2..8724fedc86 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -23,6 +23,7 @@
#include <sched.h>
#include <sys/wait.h>
#include <fcntl.h>
+#include <linux/if_tun.h>
#include "test-common.h"
@@ -627,7 +628,10 @@ nmtstp_wait_for_signal_until (NMPlatform *platform, gint64 until_ms)
const NMPlatformLink *
nmtstp_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 timeout_ms)
{
- return nmtstp_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms);
+ return nmtstp_wait_for_link_until (platform, ifname, expected_link_type,
+ timeout_ms
+ ? nm_utils_get_monotonic_timestamp_ms () + timeout_ms
+ : 0);
}
const NMPlatformLink *
@@ -635,6 +639,7 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType
{
const NMPlatformLink *plink;
gint64 now;
+ gboolean waited_once = FALSE;
_init_platform (&platform, FALSE);
@@ -646,29 +651,24 @@ nmtstp_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType
&& (expected_link_type == NM_LINK_TYPE_NONE || plink->type == expected_link_type))
return plink;
- if (until_ms < now)
+ if (until_ms == 0) {
+ /* don't wait, don't even poll the socket. */
+ return NULL;
+ }
+
+ if ( waited_once
+ && until_ms < now) {
+ /* timeout reached (+ we already waited for a signal at least once). */
return NULL;
+ }
+ waited_once = TRUE;
+ /* regardless of whether timeout is already reached, we poll the netlink
+ * socket a bit. */
nmtstp_wait_for_signal (platform, until_ms - now);
}
}
-const NMPlatformLink *
-nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms)
-{
- return nmtstp_assert_wait_for_link_until (platform, ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms);
-}
-
-const NMPlatformLink *
-nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms)
-{
- const NMPlatformLink *plink;
-
- plink = nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms);
- g_assert (plink);
- return plink;
-}
-
/*****************************************************************************/
int
@@ -1469,6 +1469,73 @@ nmtstp_link_sit_add (NMPlatform *platform,
}
const NMPlatformLink *
+nmtstp_link_tun_add (NMPlatform *platform,
+ gboolean external_command,
+ const char *name,
+ const NMPlatformLnkTun *lnk,
+ int *out_fd)
+{
+ const NMPlatformLink *pllink = NULL;
+ NMPlatformError plerr;
+ int err;
+
+ g_assert (nm_utils_is_valid_iface_name (name, NULL));
+ g_assert (lnk);
+ g_assert (NM_IN_SET (lnk->type, IFF_TUN, IFF_TAP));
+ g_assert (!out_fd || *out_fd == -1);
+
+ if (!lnk->persist) {
+ /* ip tuntap does not support non-persistent devices.
+ *
+ * Add this device only via NMPlatform. */
+ if (external_command == -1)
+ external_command = FALSE;
+ }
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ _init_platform (&platform, external_command);
+
+ if (external_command) {
+ gs_free char *dev = NULL;
+ gs_free char *local = NULL, *remote = NULL;
+
+ g_assert (lnk->persist);
+
+ err = nmtstp_run_command ("ip tuntap add"
+ " mode %s"
+ "%s" /* user */
+ "%s" /* group */
+ "%s" /* pi */
+ "%s" /* vnet_hdr */
+ "%s" /* multi_queue */
+ " name %s",
+ lnk->type == IFF_TUN ? "tun" : "tap",
+ lnk->owner_valid ? nm_sprintf_bufa (100, " user %u", (guint) lnk->owner) : "",
+ lnk->group_valid ? nm_sprintf_bufa (100, " group %u", (guint) lnk->group) : "",
+ lnk->pi ? " pi" : "",
+ lnk->vnet_hdr ? " vnet_hdr" : "",
+ lnk->multi_queue ? " multi_queue" : "",
+ name);
+ /* Older versions of iproute2 don't support adding devices.
+ * On failure, fallback to using platform code. */
+ if (err == 0)
+ pllink = nmtstp_assert_wait_for_link (platform, name, NM_LINK_TYPE_TUN, 100);
+ else
+ g_error ("failure to add tun/tap device via ip-route");
+ } else {
+ g_assert (lnk->persist || out_fd);
+ plerr = nm_platform_link_tun_add (platform, name, lnk, &pllink, out_fd);
+ g_assert_cmpint (plerr, ==, NM_PLATFORM_ERROR_SUCCESS);
+ }
+
+ g_assert (pllink);
+ g_assert_cmpint (pllink->type, ==, NM_LINK_TYPE_TUN);
+ g_assert_cmpstr (pllink->name, ==, name);
+ return pllink;
+}
+
+const NMPlatformLink *
nmtstp_link_vxlan_add (NMPlatform *platform,
gboolean external_command,
const char *name,
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index 2b830cf196..bd02b0d7d3 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -129,8 +129,11 @@ const NMPlatformLink *nmtstp_wait_for_link_until (NMPlatform *platform, const ch
g_assert_not_reached (); \
} G_STMT_END
-const NMPlatformLink *nmtstp_assert_wait_for_link (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, guint timeout_ms);
-const NMPlatformLink *nmtstp_assert_wait_for_link_until (NMPlatform *platform, const char *ifname, NMLinkType expected_link_type, gint64 until_ms);
+#define nmtstp_assert_wait_for_link(platform, ifname, expected_link_type, timeout_ms) \
+ nmtst_assert_nonnull (nmtstp_wait_for_link (platform, ifname, expected_link_type, timeout_ms))
+
+#define nmtstp_assert_wait_for_link_until(platform, ifname, expected_link_type, until_ms) \
+ nmtst_assert_nonnull (nmtstp_wait_for_link_until (platform, ifname, expected_link_type, until_ms))
/*****************************************************************************/
@@ -307,6 +310,11 @@ const NMPlatformLink *nmtstp_link_sit_add (NMPlatform *platform,
gboolean external_command,
const char *name,
const NMPlatformLnkSit *lnk);
+const NMPlatformLink *nmtstp_link_tun_add (NMPlatform *platform,
+ gboolean external_command,
+ const char *name,
+ const NMPlatformLnkTun *lnk,
+ int *out_fd);
const NMPlatformLink *nmtstp_link_vxlan_add (NMPlatform *platform,
gboolean external_command,
const char *name,
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index 90bb823ddb..dcd600ee64 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -23,6 +23,7 @@
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <linux/if_tun.h>
#include "platform/nmp-object.h"
#include "platform/nmp-netns.h"
@@ -697,6 +698,8 @@ test_software_detect (gconstpointer user_data)
const NMPObject *lnk;
guint i_step;
const gboolean ext = test_data->external_command;
+ NMPlatformLnkTun lnk_tun;
+ nm_auto_close int tun_fd = -1;
nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME);
ifindex_parent = nmtstp_assert_wait_for_link (NM_PLATFORM_GET, PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
@@ -892,6 +895,38 @@ test_software_detect (gconstpointer user_data)
g_assert (nmtstp_link_vxlan_add (NULL, ext, DEVICE_NAME, &lnk_vxlan));
break;
}
+ case NM_LINK_TYPE_TUN: {
+ gboolean owner_valid = nmtst_get_rand_bool ();
+ gboolean group_valid = nmtst_get_rand_bool ();
+
+ switch (test_data->test_mode) {
+ case 0:
+ lnk_tun = (NMPlatformLnkTun) {
+ .type = nmtst_get_rand_bool () ? IFF_TUN : IFF_TAP,
+ .owner = owner_valid ? getuid () : 0,
+ .owner_valid = owner_valid,
+ .group = group_valid ? getgid () : 0,
+ .group_valid = group_valid,
+ .pi = nmtst_get_rand_bool (),
+ .vnet_hdr = nmtst_get_rand_bool (),
+ .multi_queue = nmtst_get_rand_bool (),
+
+ /* if we add the device via iproute2 (external), we can only
+ * create persistent devices. */
+ .persist = (ext == 1) ? TRUE : nmtst_get_rand_bool (),
+ };
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ g_assert (nmtstp_link_tun_add (NULL, ext, DEVICE_NAME, &lnk_tun,
+ (!lnk_tun.persist || nmtst_get_rand_bool ())
+ ? &tun_fd
+ : NULL));
+ break;
+ }
default:
g_assert_not_reached ();
}
@@ -922,7 +957,13 @@ test_software_detect (gconstpointer user_data)
lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, test_data->link_type, &plink);
g_assert (plink);
g_assert_cmpint (plink->ifindex, ==, ifindex);
- g_assert (lnk);
+
+ if ( !lnk
+ && test_data->link_type == NM_LINK_TYPE_TUN) {
+ /* this is ok. Kernel apparently does not support tun properties via netlink. We
+ * fetch them from sysfs below. */
+ } else
+ g_assert (lnk);
switch (test_data->link_type) {
case NM_LINK_TYPE_GRE: {
@@ -1011,6 +1052,27 @@ test_software_detect (gconstpointer user_data)
g_assert_cmpint (plnk->path_mtu_discovery, ==, FALSE);
break;
}
+ case NM_LINK_TYPE_TUN: {
+ const NMPlatformLnkTun *plnk;
+ NMPlatformLnkTun lnk_tun2;
+
+ g_assert ((lnk ? &lnk->lnk_tun : NULL) == nm_platform_link_get_lnk_tun (NM_PLATFORM_GET, ifindex, NULL));
+
+ /* kernel might not expose tun options via netlink. Either way, try
+ * to read them (either from platform cache, or fallback to sysfs).
+ * See also: rh#1547213. */
+ if (!nm_platform_link_tun_get_properties (NM_PLATFORM_GET,
+ ifindex,
+ &lnk_tun2))
+ g_assert_not_reached ();
+
+ plnk = lnk ? &lnk->lnk_tun : &lnk_tun2;
+ if (lnk)
+ g_assert (memcmp (plnk, &lnk_tun2, sizeof (NMPlatformLnkTun)) == 0);
+
+ g_assert (nm_platform_lnk_tun_cmp (plnk, &lnk_tun) == 0);
+ break;
+ }
case NM_LINK_TYPE_VLAN: {
const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan;
@@ -2581,6 +2643,7 @@ _nmtstp_setup_tests (void)
test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0);
test_software_detect_add ("/link/software/detect/macvtap", NM_LINK_TYPE_MACVTAP, 0);
test_software_detect_add ("/link/software/detect/sit", NM_LINK_TYPE_SIT, 0);
+ test_software_detect_add ("/link/software/detect/tun", NM_LINK_TYPE_TUN, 0);
test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);
test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1);
diff --git a/tools/run-nm-test.sh b/tools/run-nm-test.sh
index 5848d0a061..2c23e7175f 100755
--- a/tools/run-nm-test.sh
+++ b/tools/run-nm-test.sh
@@ -121,6 +121,10 @@ else
NMTST_USE_VALGRIND=0
shift;
;;
+ "-d")
+ NMTST_SET_DEBUG=1
+ shift;
+ ;;
"--test"|-t)
shift
TEST="$1"
@@ -146,6 +150,10 @@ else
fi
+if [ "$NMTST_SET_DEBUG" == 1 -a -z "${NMTST_DEBUG+x}" ]; then
+ export NMTST_DEBUG=d
+fi
+
if _is_true "$NMTST_MAKE_FIRST" 0; then
git_dir="$(readlink -f "$(git rev-parse --show-toplevel)")"
rel_path="$(realpath --relative-to="$git_dir" -m "$TEST" 2>/dev/null)" || die "cannot resolve test-name \"$TEST\". Did you call the script properly?"