Skip to content

Commit 839b92f

Browse files
committed
selftest: tun: add test for NAPI dismantle
Being lazy does not pay, add the test for various ordering of tun queue close / detach / destroy. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent ff1fa20 commit 839b92f

File tree

2 files changed

+163
-1
lines changed

2 files changed

+163
-1
lines changed

tools/testing/selftests/net/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ TEST_GEN_FILES += ipsec
5454
TEST_GEN_FILES += ioam6_parser
5555
TEST_GEN_FILES += gro
5656
TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa
57-
TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls
57+
TEST_GEN_PROGS += reuseport_dualstack reuseaddr_conflict tls tun
5858
TEST_GEN_FILES += toeplitz
5959
TEST_GEN_FILES += cmsg_sender
6060
TEST_GEN_FILES += stress_reuseport_listen

tools/testing/selftests/net/tun.c

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#define _GNU_SOURCE
4+
5+
#include <errno.h>
6+
#include <fcntl.h>
7+
#include <stdio.h>
8+
#include <stdlib.h>
9+
#include <string.h>
10+
#include <unistd.h>
11+
#include <linux/if.h>
12+
#include <linux/if_tun.h>
13+
#include <linux/netlink.h>
14+
#include <linux/rtnetlink.h>
15+
#include <sys/ioctl.h>
16+
#include <sys/socket.h>
17+
18+
#include "../kselftest_harness.h"
19+
20+
static int tun_attach(int fd, char *dev)
21+
{
22+
struct ifreq ifr;
23+
24+
memset(&ifr, 0, sizeof(ifr));
25+
strcpy(ifr.ifr_name, dev);
26+
ifr.ifr_flags = IFF_ATTACH_QUEUE;
27+
28+
return ioctl(fd, TUNSETQUEUE, (void *) &ifr);
29+
}
30+
31+
static int tun_detach(int fd, char *dev)
32+
{
33+
struct ifreq ifr;
34+
35+
memset(&ifr, 0, sizeof(ifr));
36+
strcpy(ifr.ifr_name, dev);
37+
ifr.ifr_flags = IFF_DETACH_QUEUE;
38+
39+
return ioctl(fd, TUNSETQUEUE, (void *) &ifr);
40+
}
41+
42+
static int tun_alloc(char *dev)
43+
{
44+
struct ifreq ifr;
45+
int fd, err;
46+
47+
fd = open("/dev/net/tun", O_RDWR);
48+
if (fd < 0) {
49+
fprintf(stderr, "can't open tun: %s\n", strerror(errno));
50+
return fd;
51+
}
52+
53+
memset(&ifr, 0, sizeof(ifr));
54+
strcpy(ifr.ifr_name, dev);
55+
ifr.ifr_flags = IFF_TAP | IFF_NAPI | IFF_MULTI_QUEUE;
56+
57+
err = ioctl(fd, TUNSETIFF, (void *) &ifr);
58+
if (err < 0) {
59+
fprintf(stderr, "can't TUNSETIFF: %s\n", strerror(errno));
60+
close(fd);
61+
return err;
62+
}
63+
strcpy(dev, ifr.ifr_name);
64+
return fd;
65+
}
66+
67+
static int tun_delete(char *dev)
68+
{
69+
struct {
70+
struct nlmsghdr nh;
71+
struct ifinfomsg ifm;
72+
unsigned char data[64];
73+
} req;
74+
struct rtattr *rta;
75+
int ret, rtnl;
76+
77+
rtnl = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE);
78+
if (rtnl < 0) {
79+
fprintf(stderr, "can't open rtnl: %s\n", strerror(errno));
80+
return 1;
81+
}
82+
83+
memset(&req, 0, sizeof(req));
84+
req.nh.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(req.ifm)));
85+
req.nh.nlmsg_flags = NLM_F_REQUEST;
86+
req.nh.nlmsg_type = RTM_DELLINK;
87+
88+
req.ifm.ifi_family = AF_UNSPEC;
89+
90+
rta = (struct rtattr *)(((char *)&req) + NLMSG_ALIGN(req.nh.nlmsg_len));
91+
rta->rta_type = IFLA_IFNAME;
92+
rta->rta_len = RTA_LENGTH(IFNAMSIZ);
93+
req.nh.nlmsg_len += rta->rta_len;
94+
memcpy(RTA_DATA(rta), dev, IFNAMSIZ);
95+
96+
ret = send(rtnl, &req, req.nh.nlmsg_len, 0);
97+
if (ret < 0)
98+
fprintf(stderr, "can't send: %s\n", strerror(errno));
99+
ret = (unsigned int)ret != req.nh.nlmsg_len;
100+
101+
close(rtnl);
102+
return ret;
103+
}
104+
105+
FIXTURE(tun)
106+
{
107+
char ifname[IFNAMSIZ];
108+
int fd, fd2;
109+
};
110+
111+
FIXTURE_SETUP(tun)
112+
{
113+
memset(self->ifname, 0, sizeof(self->ifname));
114+
115+
self->fd = tun_alloc(self->ifname);
116+
ASSERT_GE(self->fd, 0);
117+
118+
self->fd2 = tun_alloc(self->ifname);
119+
ASSERT_GE(self->fd2, 0);
120+
}
121+
122+
FIXTURE_TEARDOWN(tun)
123+
{
124+
if (self->fd >= 0)
125+
close(self->fd);
126+
if (self->fd2 >= 0)
127+
close(self->fd2);
128+
}
129+
130+
TEST_F(tun, delete_detach_close) {
131+
EXPECT_EQ(tun_delete(self->ifname), 0);
132+
EXPECT_EQ(tun_detach(self->fd, self->ifname), -1);
133+
EXPECT_EQ(errno, 22);
134+
}
135+
136+
TEST_F(tun, detach_delete_close) {
137+
EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
138+
EXPECT_EQ(tun_delete(self->ifname), 0);
139+
}
140+
141+
TEST_F(tun, detach_close_delete) {
142+
EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
143+
close(self->fd);
144+
self->fd = -1;
145+
EXPECT_EQ(tun_delete(self->ifname), 0);
146+
}
147+
148+
TEST_F(tun, reattach_delete_close) {
149+
EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
150+
EXPECT_EQ(tun_attach(self->fd, self->ifname), 0);
151+
EXPECT_EQ(tun_delete(self->ifname), 0);
152+
}
153+
154+
TEST_F(tun, reattach_close_delete) {
155+
EXPECT_EQ(tun_detach(self->fd, self->ifname), 0);
156+
EXPECT_EQ(tun_attach(self->fd, self->ifname), 0);
157+
close(self->fd);
158+
self->fd = -1;
159+
EXPECT_EQ(tun_delete(self->ifname), 0);
160+
}
161+
162+
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)