diff --git a/test/zdtm.sh b/test/zdtm.sh index 7f34c8d9c..77b723bd4 100755 --- a/test/zdtm.sh +++ b/test/zdtm.sh @@ -116,6 +116,7 @@ static/shm static/msgque static/sem transition/ipc +ns/static/tun " TEST_CR_KERNEL=" @@ -136,6 +137,7 @@ cmdlinenv00 packet_sock fanotify00 sk-netlink +tun " source $(readlink -f `dirname $0`/env.sh) || exit 1 diff --git a/test/zdtm/lib/ns.c b/test/zdtm/lib/ns.c index 70efa8b20..cd082d85b 100644 --- a/test/zdtm/lib/ns.c +++ b/test/zdtm/lib/ns.c @@ -90,6 +90,9 @@ static int prepare_mntns() mkdir("/dev", 0777); mknod("/dev/null", 0777 | S_IFCHR, makedev(1, 3)); chmod("/dev/null", 0777); + mkdir("/dev/net", 0777); + mknod("/dev/net/tun", 0777 | S_IFCHR, makedev(10, 200)); + chmod("/dev/net/tun", 0777); return 0; } diff --git a/test/zdtm/live/static/Makefile b/test/zdtm/live/static/Makefile index 44d016f6e..f76e61b25 100644 --- a/test/zdtm/live/static/Makefile +++ b/test/zdtm/live/static/Makefile @@ -100,6 +100,7 @@ TST_NOFILE = \ sk-netlink \ mem-touch \ grow_map \ + tun \ # jobctl00 \ TST_FILE = \ diff --git a/test/zdtm/live/static/tun.c b/test/zdtm/live/static/tun.c new file mode 100644 index 000000000..5f544013d --- /dev/null +++ b/test/zdtm/live/static/tun.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "zdtmtst.h" + +const char *test_doc = "Test TUN/TAP devices\n"; +const char *test_author = "Pavel Emelianov "; + +#define TUN_DEVICE "/dev/net/tun" +#ifndef IFF_MULTI_QUEUE +#define IFF_MULTI_QUEUE 0x0100 +#define IFF_ATTACH_QUEUE 0x0200 +#define IFF_DETACH_QUEUE 0x0400 +#define IFF_PERSIST 0x0800 +#endif + +#ifndef TUNSETQUEUE +#define TUNSETQUEUE _IOW('T', 217, int) +#endif + +static int any_fail = 0; + +static int __open_tun(void) +{ + int fd; + + fd = open(TUN_DEVICE, O_RDWR); + if (fd < 0) + err("Can't open tun file"); + + return fd; +} + +static int set_tun_queue(int fd, unsigned flags) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = flags; + + if (ioctl(fd, TUNSETQUEUE, &ifr) < 0) { + err("Can't set queue"); + return -1; + } + + return 0; +} + +static int __attach_tun(int fd, char *name, unsigned flags) +{ + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, name); + ifr.ifr_flags = flags; + + if (ioctl(fd, TUNSETIFF, &ifr) < 0) { + if (!(flags & IFF_TUN_EXCL)) + err("Can't attach iff %s", name); + return -1; + } + + return fd; +} + +static int open_tun(char *name, unsigned flags) +{ + int fd; + + fd = __open_tun(); + if (fd < 0) + return -1; + + return __attach_tun(fd, name, flags); +} + +static void check_tun(int fd, char *name, unsigned flags) +{ + struct ifreq ifr; + + if (ioctl(fd, TUNGETIFF, &ifr) > 0) { + any_fail = 1; + fail("Attached tun %s file lost device", name); + } + + if (strcmp(ifr.ifr_name, name)) { + any_fail = 1; + fail("Attached tun %s wrong device", name); + } + + if ((ifr.ifr_flags & flags) != flags) { + any_fail = 1; + fail("Attached tun %s wrong device type", name); + } +} + +int main(int argc, char **argv) +{ + int fds[5], ret; + + test_init(argc, argv); + + /* fd[0] -- opened file */ + fds[0] = __open_tun(); + if (fds[0] < 0) { + err("No file 0"); + return -1; + } + + /* fd[1] -- opened file with tun device */ + fds[1] = open_tun("tunx0", IFF_TUN); + if (fds[1] < 0) { + err("No file 1"); + return -1; + } + + /* fd[2] and [3] -- two-queued device, with 3 detached */ + fds[2] = open_tun("tunx1", IFF_TUN | IFF_MULTI_QUEUE); + if (fds[2] < 0) { + err("No file 2"); + return -1; + } + + fds[3] = open_tun("tunx1", IFF_TUN | IFF_MULTI_QUEUE); + if (fds[3] < 0) { + err("No file 3"); + return -1; + } + + ret = set_tun_queue(fds[3], IFF_DETACH_QUEUE); + if (ret < 0) + return -1; + + /* special case -- persistent device */ + ret = open_tun("tunx2", IFF_TUN); + if (ret < 0) { + err("No persistent device"); + return -1; + } + + if (ioctl(ret, TUNSETPERSIST, 1) < 0) { + err("Can't make persistent"); + return -1; + } + + /* and one tap in fd[4] */ + fds[4] = open_tun("tapx0", IFF_TAP); + if (fds[4] < 0) { + err("No tap"); + return -1; + } + + close(ret); + + test_daemon(); + test_waitsig(); + + /* check fds[0] is not attached to device */ + ret = __attach_tun(fds[0], "tunx3", IFF_TUN); + if (ret < 0) { + any_fail = 1; + fail("Opened tun file broken"); + } + + /* check that fds[1] has device */ + check_tun(fds[1], "tunx0", IFF_TUN); + + /* check that fds[2] and [3] are at MQ device with */ + check_tun(fds[2], "tunx1", IFF_TUN | IFF_MULTI_QUEUE); + check_tun(fds[3], "tunx1", IFF_TUN | IFF_MULTI_QUEUE); + + ret = set_tun_queue(fds[2], IFF_DETACH_QUEUE); + if (ret < 0) { + any_fail = 1; + fail("Queue not attached"); + } + + ret = set_tun_queue(fds[3], IFF_ATTACH_QUEUE); + if (ret < 0) { + any_fail = 1; + fail("Queue not detached"); + } + + /* check persistent device */ + ret = open_tun("tunx2", IFF_TUN | IFF_TUN_EXCL); + if (ret >= 0) { + any_fail = 1; + fail("Persistent device lost"); + } else { + ret = open_tun("tunx2", IFF_TUN); + if (ret < 0) + err("Can't attach tun2"); + else + ioctl(ret, TUNSETPERSIST, 0); + } + + check_tun(fds[4], "tapx0", IFF_TAP); + + if (!any_fail) + pass(); + + return 0; +}