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