使用ioctl创建TAP设备异常:程序执行成功但无设备生成求助
TAP设备创建成功但无法找到的问题排查与修复
问题描述
提供的C代码执行后提示创建成功,但系统中找不到对应的TAP设备tap99。代码如下:
#include <fcntl.h> #include <net/if.h> #include <linux/if_tun.h> #include <sys/ioctl.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <errno.h> int main() { struct ifreq ifr; int fd = open("/dev/net/tun", O_RDWR); if(fd < 0) { perror("open tun fail"); return -1; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_UP; // set tap device name strncpy(ifr.ifr_name, "tap99", IFNAMSIZ); if(ioctl(fd, TUNSETIFF, (void*)(&ifr)) < 0) { perror("ioctl fail"); close(fd); return -1; } printf("TAP device %s created successfully\n", ifr.ifr_name); close(fd); return 0; }
已完成的排查步骤:
- 内核对TUN/TAP支持正常:
[root@Qwons c_test]# lsmod | grep tun tun 49152 2 [root@Qwons c_test]# lsmod | grep tap tap 28672 0 [root@Qwons c_test]# ll /dev/net/tun total 0 crw-rw-rw- 1 root root 10, 200 Dec 23 23:38 tun - 执行程序后,
ip和ifconfig均无法找到tap99:[root@Qwons c_test]# ./modify TAP device tap99 created successfully [qwons@Qwons c_test]$ ip link set tap99 up Cannot find device "tap99" [qwons@Qwons c_test]$ ifconfig | grep tap99 [qwons@Qwons c_test]$
原因分析
核心问题是程序创建TAP设备后立刻关闭了文件描述符。Linux的TUN/TAP设备与文件描述符强绑定,当对应的fd被关闭时,内核会自动销毁该TAP设备,因此程序退出后设备直接消失,自然无法通过系统命令查到。
另外,代码中的IFF_UP标志无实际作用——设备创建后未完成激活流程,且fd关闭后设备直接销毁,该标志不会生效。
修复方法
有两种常用的修复思路:
方法1:保持文件描述符打开,维持程序运行
修改代码,在设备创建成功后不立即关闭fd,通过让程序持续运行(如等待信号、死循环或业务逻辑)来保留TAP设备:
#include <fcntl.h> #include <net/if.h> #include <linux/if_tun.h> #include <sys/ioctl.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <errno.h> int main() { struct ifreq ifr; int fd = open("/dev/net/tun", O_RDWR); if(fd < 0) { perror("open tun fail"); return -1; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; // 移除IFF_UP,后续用ip命令手动激活 strncpy(ifr.ifr_name, "tap99", IFNAMSIZ); if(ioctl(fd, TUNSETIFF, (void*)(&ifr)) < 0) { perror("ioctl fail"); close(fd); return -1; } printf("TAP device %s created successfully. Keep running to maintain device...\n", ifr.ifr_name); // 保持程序运行,等待任意信号终止(如Ctrl+C) pause(); close(fd); return 0; }
编译运行后,打开新终端即可用ip link show tap99看到设备,还能执行ip link set tap99 up激活设备。
方法2:创建持久化TAP设备
如果需要设备在程序退出后依然存在,可通过TUNSETPERSIST ioctl命令设置持久化属性,这样即使关闭fd,设备也不会被销毁:
#include <fcntl.h> #include <net/if.h> #include <linux/if_tun.h> #include <sys/ioctl.h> #include <unistd.h> #include <string.h> #include <stdio.h> #include <errno.h> int main() { struct ifreq ifr; int fd = open("/dev/net/tun", O_RDWR); if(fd < 0) { perror("open tun fail"); return -1; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, "tap99", IFNAMSIZ); if(ioctl(fd, TUNSETIFF, (void*)(&ifr)) < 0) { perror("ioctl fail"); close(fd); return -1; } // 设置持久化,需root权限执行 int persist = 1; if(ioctl(fd, TUNSETPERSIST, &persist) < 0) { perror("set persist fail"); close(fd); return -1; } printf("Persistent TAP device %s created successfully\n", ifr.ifr_name); close(fd); return 0; }
注意:TUNSETPERSIST需要以root权限执行,设置后设备会一直存在,直到手动执行ip link delete tap99删除。
内容的提问来源于stack exchange,提问作者Qwons
相关产品推荐
相关产品推荐

