一、tun/tap概述
tun/tap是一种虚拟网络设备,它可以将数据包从用户空间传输到内核空间,或者反过来,通过用户空间的程序来协议地访问网络设备。
tun/tap模块的出现,主要是为了满足虚拟网络设备的需求。尤其是虚拟机技术的普及,使得网络设备需要能够高效地和虚拟机进行通信和交互,tun/tap成为了这方面的最佳选择。
// 用户空间程序创建并使用一个tun设备 #include #include #include #include #include #include int tun_alloc(char *dev) { struct ifreq ifr; int fd, err; if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { return fd; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN; if (*dev) { strncpy(ifr.ifr_name, dev, IFNAMSIZ); } if ((err = ioctl(fd, TUNSETIFF, (void *)&ifr)) 0) { printf("Received %lu bytes\n", strlen(buffer)); } close(tun_fd); return 0; }
二、tun/tap的工作原理
tun/tap依赖于内核的TUN/TAP驱动模块,它通过创建一个虚拟网络设备,来实现一个虚拟的网络接口,作为网络数据包的收发通道。整个过程可以分为以下几个步骤:
- 用户程序申请创建tun/tap设备
- 内核向用户程序返回tun/tap设备信息
- 用户程序配置tun/tap设备
- tun/tap设备准备就绪,可以开始数据包的收发
- 用户程序通过read/write等系统调用,向tun/tap设备中写入/读取数据包
在数据包的收发过程中,用户程序和TUN/TAP驱动模块之间通过ioctl系统调用交互,完成接口状态、MAC和IP地址等的设置、读取和修改等。同时,内核还会调度进程,执行网络协议栈,完成数据包的处理和转发等操作。
三、tun/tap的使用场景
tun/tap最常见的使用场景是虚拟机和容器技术,因为它可以实现网络设备的隔离、共享和管理。在虚拟机中,将tun/tap设备挂载到虚拟机中,就可以实现虚拟机网络设备和宿主机网络设备之间的通信,也可以方便地实现虚拟机之间的网络互通。
tun/tap还可以用于VPN和隧道网络等场景,可以实现在公共网络中建立私有网络的功能。此外,tun/tap还可以用于网络监控和测试等需求,方便收集和分析数据包。
四、tun/tap的高级特性
1. 多队列支持
在网络设备高负载的情况下,多队列支持可以提高网络设备的转发性能。tun/tap对于多队列的支持,可以通过参数设置和ioctl系统调用相结合的方式实现。通过设置多个队列,不同流量可以被映射到不同队列中,在每个队列上进行处理,从而提高并发性和负载均衡性。
// 多队列的创建与设置 int tun_queue[tun_queues]; for (int i = 0; i < tun_queues; i++) { // 创建tun设备 tun_queue[i] = tun_create(tun_queue_name[i], IFF_TAP | IFF_NO_PI); // 为tun设备设置队列数量 ioctl(tun_queue[i], TUNSETQUEUE, i); } // 读取队列数据包操作 char buf[BUFLEN]; for (;;) { int ret = select(maxfd + 1, &rfds, NULL, NULL, NULL); if (ret < 0) { perror("select"); break; } for (int i = 0; i < tun_queues; i++) { // 测试该文件描述符是否就绪 if (FD_ISSET(tun_queue[i], &rfds)) { // 读取数据 int len = read(tun_queue[i], buf, BUFLEN); if (len < 0) { perror("read()"); break; } // 处理数据包 // ... } } }
2. 用户空间和内核空间之间的零拷贝技术
在tun/tap的数据收发过程中,往往会涉及到数据的拷贝,因为数据需要在用户程序和内核之间进行传递。为了避免频繁的数据拷贝对系统性能带来的负面影响,tun/tap可以使用零拷贝技术,即在发送数据包时,将数据包的内存映射到内核空间,这样就可以直接从内存中访问数据包,避免了数据的复制操作。
int tun_fd; char buffer[2048]; tun_fd = open("/dev/net/tun", O_RDWR); if (tun_fd < 0) { perror("open"); return EXIT_FAILURE; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; if (dev && *dev) { strncpy(ifr.ifr_name, dev, IFNAMSIZ); } if (ioctl(tun_fd, TUNSETIFF, (void *)&ifr) cmsg_level = IPPROTO_IP; cmsg->cmsg_type = IP_TOS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); *(int *)CMSG_DATA(cmsg) = IPTOS_LOWDELAY; // 零拷贝技术的实现 int bytes_sent = sendmsg(tun_fd, &msg, MSG_DONTWAIT);
3. tun/tap虚拟设备的扩展
在tun/tap虚拟设备的使用中,还可以根据需要来自定义设备的协议和实现方式。比如,可以通过对TUN/TAP驱动模块的修改,增加虚拟设备的类型和功能,也可以通过对用户程序的修改,增加自定义的数据包处理逻辑。
原创文章,作者:TTANJ,如若转载,请注明出处:https://www.506064.com/n/333793.html