163 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#define _GNU_SOURCE4 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_MAIN163