mirror of
https://github.com/checkpoint-restore/criu.git
synced 2026-08-05 00:03:33 +00:00
Acked-by: Mike Rapoport <rppt@linux.ibm.com> Signed-off-by: Adrian Reber <areber@redhat.com>
240 lines
4.7 KiB
C
240 lines
4.7 KiB
C
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/socket.h>
|
|
#include <linux/if.h>
|
|
#include <linux/if_tun.h>
|
|
#include <sched.h>
|
|
|
|
#include "zdtmtst.h"
|
|
|
|
const char *test_doc = "Test TUN/TAP devices\n";
|
|
const char *test_author = "Pavel Emelianov <xemul@parallels.com>";
|
|
|
|
#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)
|
|
pr_perror("Can't open tun file %s", TUN_DEVICE);
|
|
|
|
return fd;
|
|
}
|
|
|
|
static int set_tun_queue(int fd, const char *name, unsigned flags)
|
|
{
|
|
struct ifreq ifr = {
|
|
.ifr_flags = flags,
|
|
};
|
|
|
|
if (ioctl(fd, TUNSETQUEUE, &ifr) < 0) {
|
|
pr_perror("Can't set queue on %s", name);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int __attach_tun(int fd, const char *name, unsigned flags)
|
|
{
|
|
struct ifreq ifr = {
|
|
.ifr_flags = flags,
|
|
};
|
|
|
|
strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name) - 1);
|
|
|
|
if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
|
|
if (!(flags & IFF_TUN_EXCL))
|
|
pr_perror("Can't attach iff %s", name);
|
|
return -1;
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
static int open_tun(const 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, const 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);
|
|
}
|
|
}
|
|
|
|
static int dev_get_hwaddr(int fd, const char *name, char *a)
|
|
{
|
|
struct ifreq ifr = {};
|
|
|
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
|
pr_perror("Can't get hwaddr on %s", name);
|
|
return -1;
|
|
}
|
|
|
|
memcpy(a, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int fds[5], ret;
|
|
char addr[ETH_ALEN], a2[ETH_ALEN];
|
|
|
|
test_init(argc, argv);
|
|
#ifdef TUN_NS
|
|
if (unshare(CLONE_NEWNET)) {
|
|
pr_perror("unshare");
|
|
return 1;
|
|
}
|
|
system("ip link set up dev lo");
|
|
#endif
|
|
/* fd[0] -- opened file */
|
|
fds[0] = __open_tun();
|
|
if (fds[0] < 0) {
|
|
pr_perror("No file 0");
|
|
return 1;
|
|
}
|
|
|
|
/* fd[1] -- opened file with tun device */
|
|
fds[1] = open_tun("tunx0", IFF_TUN);
|
|
if (fds[1] < 0) {
|
|
pr_perror("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) {
|
|
pr_perror("No file 2");
|
|
return 1;
|
|
}
|
|
|
|
fds[3] = open_tun("tunx1", IFF_TUN | IFF_MULTI_QUEUE);
|
|
if (fds[3] < 0) {
|
|
pr_perror("No file 3");
|
|
return 1;
|
|
}
|
|
|
|
ret = set_tun_queue(fds[3], "tunx1", IFF_DETACH_QUEUE);
|
|
if (ret < 0)
|
|
return 1;
|
|
|
|
/* special case -- persistent device */
|
|
ret = open_tun("tunx2", IFF_TUN);
|
|
if (ret < 0) {
|
|
pr_perror("No persistent device");
|
|
return 1;
|
|
}
|
|
|
|
if (ioctl(ret, TUNSETPERSIST, 1) < 0) {
|
|
pr_perror("Can't make persistent");
|
|
return 1;
|
|
}
|
|
|
|
/* and one tap in fd[4] */
|
|
fds[4] = open_tun("tapx0", IFF_TAP);
|
|
if (fds[4] < 0) {
|
|
pr_perror("No tap");
|
|
return 1;
|
|
}
|
|
|
|
if (dev_get_hwaddr(fds[4], "tapx0", addr) < 0) {
|
|
pr_perror("No hwaddr for 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], "tunx1", IFF_DETACH_QUEUE);
|
|
if (ret < 0) {
|
|
any_fail = 1;
|
|
fail("Queue not attached");
|
|
}
|
|
|
|
ret = set_tun_queue(fds[3], "tunx1", 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)
|
|
pr_perror("Can't attach tun2");
|
|
else
|
|
ioctl(ret, TUNSETPERSIST, 0);
|
|
}
|
|
|
|
check_tun(fds[4], "tapx0", IFF_TAP);
|
|
if (dev_get_hwaddr(fds[4], "tapx0", a2) < 0) {
|
|
pr_perror("No hwaddr for tap? (2)");
|
|
any_fail = 1;
|
|
} else if (memcmp(addr, a2, sizeof(addr))) {
|
|
fail("Address mismatch on tap %x:%x -> %x:%x", (int)addr[0], (int)addr[1], (int)a2[0], (int)a2[1]);
|
|
any_fail = 1;
|
|
}
|
|
|
|
if (!any_fail)
|
|
pass();
|
|
|
|
return 0;
|
|
}
|