tun.c 3.4 KB

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