tun.c (3440B)
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 20static 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 31static 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 42static 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 67static 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 105FIXTURE(tun) 106{ 107 char ifname[IFNAMSIZ]; 108 int fd, fd2; 109}; 110 111FIXTURE_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 122FIXTURE_TEARDOWN(tun) 123{ 124 if (self->fd >= 0) 125 close(self->fd); 126 if (self->fd2 >= 0) 127 close(self->fd2); 128} 129 130TEST_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 136TEST_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 141TEST_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 148TEST_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 154TEST_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 162TEST_HARNESS_MAIN