1 // SPDX-License-Identifier: GPL-2.0
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>
18 #include "../kselftest_harness.h"
20 static int tun_attach(int fd
, char *dev
)
24 memset(&ifr
, 0, sizeof(ifr
));
25 strcpy(ifr
.ifr_name
, dev
);
26 ifr
.ifr_flags
= IFF_ATTACH_QUEUE
;
28 return ioctl(fd
, TUNSETQUEUE
, (void *) &ifr
);
31 static int tun_detach(int fd
, char *dev
)
35 memset(&ifr
, 0, sizeof(ifr
));
36 strcpy(ifr
.ifr_name
, dev
);
37 ifr
.ifr_flags
= IFF_DETACH_QUEUE
;
39 return ioctl(fd
, TUNSETQUEUE
, (void *) &ifr
);
42 static int tun_alloc(char *dev
)
47 fd
= open("/dev/net/tun", O_RDWR
);
49 fprintf(stderr
, "can't open tun: %s\n", strerror(errno
));
53 memset(&ifr
, 0, sizeof(ifr
));
54 strcpy(ifr
.ifr_name
, dev
);
55 ifr
.ifr_flags
= IFF_TAP
| IFF_NAPI
| IFF_MULTI_QUEUE
;
57 err
= ioctl(fd
, TUNSETIFF
, (void *) &ifr
);
59 fprintf(stderr
, "can't TUNSETIFF: %s\n", strerror(errno
));
63 strcpy(dev
, ifr
.ifr_name
);
67 static int tun_delete(char *dev
)
72 unsigned char data
[64];
77 rtnl
= socket(AF_NETLINK
, SOCK_DGRAM
, NETLINK_ROUTE
);
79 fprintf(stderr
, "can't open rtnl: %s\n", strerror(errno
));
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
;
88 req
.ifm
.ifi_family
= AF_UNSPEC
;
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
);
96 ret
= send(rtnl
, &req
, req
.nh
.nlmsg_len
, 0);
98 fprintf(stderr
, "can't send: %s\n", strerror(errno
));
99 ret
= (unsigned int)ret
!= req
.nh
.nlmsg_len
;
107 char ifname
[IFNAMSIZ
];
113 memset(self
->ifname
, 0, sizeof(self
->ifname
));
115 self
->fd
= tun_alloc(self
->ifname
);
116 ASSERT_GE(self
->fd
, 0);
118 self
->fd2
= tun_alloc(self
->ifname
);
119 ASSERT_GE(self
->fd2
, 0);
122 FIXTURE_TEARDOWN(tun
)
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);
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);
141 TEST_F(tun
, detach_close_delete
) {
142 EXPECT_EQ(tun_detach(self
->fd
, self
->ifname
), 0);
145 EXPECT_EQ(tun_delete(self
->ifname
), 0);
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);
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);
159 EXPECT_EQ(tun_delete(self
->ifname
), 0);