引言:为什么需要虚拟网络设备------TUN/TAP?
在Linux网络虚拟化领域,TUN/TAP设备扮演着至关重要的角色。无论是容器网络、VPN技术还是虚拟机网络,背后都有它们的身影。理解TUN/TAP不仅是掌握Linux网络的基础,更是深入理解Kubernetes网络插件(如flannel)的关键。
1.概述
1.1 什么是TUN/TAP设备?
TUN/TAP 设备是操作系统内核中的虚拟网络设备,是用软件模拟的网络设备,提供与硬件网络设备完全相同的功能。主要用于用户空间和内核空间传递报文。
1.1.1 双重身份的理解
从不同视角看,TUN/TAP设备有着不同的身份:
- 从Linux文件系统视角 :TUN/TAP是用户可以用文件句柄操作的字符设备。这种设计使得用户态程序可以像操作普通文件一样操作网络数据包。
- 从网络虚拟化视角:它是虚拟网卡,一端连接着内核网络协议栈,另一端连接着用户态程序。这种特殊的"桥梁"设计,为网络数据包的处理提供了极大的灵活性。
1.1.2 tun与tap:表兄弟而非亲兄弟
虽然经常被并列提及,但tun和tap有着明显的区别:
- tun设备:虚拟的是点对点设备,工作在网络层(第三层),处理的是IP数据包。它没有 MAC 地址,因此不能处理 ARP 请求或以太网广播。
- tap设备:虚拟的是以太网设备,工作在数据链路层(第二层),处理的是完整的以太网帧。拥有 MAC 地址,可以参与桥接网络,就像一块虚拟的以太网卡。
1.2 TUN/TAP设备有什么作用呢?(重要)
TUN/TAP设备可以将TCP/IP协议栈处理好的网络包发送给任何一个使用TUN/TAP驱动的进程,由进程重新处理后发到物理链路中。TUN/TAP设备就像是埋在用户程序空间的一个钩子,我们可以很方便地将对网络包的处理程序挂在这个钩子上,OpenVPN、Vtun、flannel都是基于它实现隧道包封装的。
2.核心工作原理:连接用户空间与内核空间
2.1 TUN/TAP 设备与物理网卡的区别
- 物理网卡:一端连接的是物理网络,一端连接的是网络协议栈。
- **TUN/TAP 设备:**在操作系统内部连接了内核网络协议栈和用户空间的应用程序。一端连接的是应用程序,一端连接的是网络协议栈。
2.2 TUN/TAP设备的工作原理
2.2.1 Socket的数据交互原理
在讲解TUN/TAP设备的前,先简单介绍物理设备上的数据是如何通过Linux网络协议栈送达用户态程序的(对应2.2.2章节tun设备的工作模式图中应用进程B、应用进程C)。物理网卡从网络接收数据后,会将其送入内核的网络协议栈进行处理,用户态程序则通过创建的Socket套接字,从协议栈中读取数据;反之,发送数据时也通过Socket将数据交由协议栈,最终由网卡发出。
2.2.2 TUN/TAP设备的工作原理
从网络协议栈的角度看,TUN/TAP设备这类虚拟网卡与物理网卡并无区别。只是对TUN/TAP设备而言,它与物理网卡的不同表现在它的数据源不是物理链路,而是来自用户态!这也是TUN/TAP设备的最大价值所在。
TUN/TAP设备其实就是利用Linux的设备文件实现内核态和用户态的数据交互,而访问设备文件则会调用设备驱动相应的例程,要知道设备驱动也是内核态和用户态的一个接口。tun设备的工作模式如下图所示。
普通的物理网卡通过网线收发数据包,而tun设备通过一个设备文件(/dev/net/tun)收发数据包。应用的数据收发过程:
- 数据发送:应用进程 A open/dev/net/tun 字符设备,通过 ioctl 调用创建虚拟接口 tunx 或者 tapx, ioctl 调用返回表示对应 tunx 或者 tapx 设备的文件描述符 fd ,应用 A 通过这个文件描述符 fd 写入格式化的数据,数据通过虚拟网卡驱动到达协议栈,对于协议栈来说,这个数据就像从真实网卡接收的一样。
- 数据接收:当网络协议栈发送数据到虚拟接口 tunx 或者 tapx 时,应用进程 A 通过上述创建的设备文件描述符 fd,从中读取接口发送的数据,然后进行处理。
tap设备与tun设备的工作原理完全相同,区别在于:
- tun设备的 /dev/net/tun 文件收发的是IP包,因此只能工作在L3,无法与物理网卡做桥接,但可以通过三层交换(例如ip_forward)与物理网卡连通;
- tap设备的 /dev/net/tun 文件收发的是链路层数据包。从这点来看,Tap 虚拟设备和真实的物理网卡的能力更接近,可以与物理网卡做 bridge。
注意事项:
- 无论是 tun 还是 tap 设备,都是通过open /dev/net/tun 这个字符设备文件,通过 ioctl 系统调用在内核创建新的 tun、tap 设备,创建的设备并不会以文件的形式出现在 /dev/ 下,可以在 sys/class/net/ 下看到对应的网络接口 tunx 或者 tapx。
- 设备 /dev/net/tun 必须以 read/write 的方式打开。该设备也被称为克隆设备,它是创建任何 TUN/TAP 虚拟接口的起点。
- open 系统调用执行的时候,VFS 会为这次 open 分配一个独立的内核态 file 结构,也就是说,每次打开执行时,内核为此次打开分配的 file 结构实例不同,代表不同的字符设备。
2.2.3 TUN/TAP 驱动
TUN/TAP 驱动程序中包含两个部分,一部分是字符设备驱动,还有一部分是网卡驱动。
- 利用网卡驱动部分接收来自 TCP/IP 协议栈的网络分包并发送或者反过来将接收到的网络分包传给协议栈处理。
- 字符驱动部分则将网络分包在内核与用户态之间传送,模拟物理链路的数据接收和发送。用户态程序通过 ioctl read write 系统调用 与字符设备 /dev/net/tun 进行数据交互。
3.TUN/TAP设备的应用场景
TUN/TAP设备强大的能力使其成为许多现代网络技术的基石,以下是几个最典型的应用场景。
3.1 虚拟专用网络(VPN)
这是TUN设备最经典的应用。VPN客户端程序会创建一个TUN设备(如tun0)。当你的操作系统要访问远程公司内网时,产生的目标地址为内网的IP数据包会被路由到tun0设备。随后,VPN程序从tun0的文件描述符中读取到这个原始IP数据包,对其进行加密、封装(例如封装成UDP包),再通过真实的物理网卡发送给VPN服务器。服务器解密后,将原始IP包注入其网络栈,最终送达目标内网。这个过程为你创建了一条安全的"网络隧道"。
3.2 虚拟机与容器网络
在虚拟化环境中,TAP设备发挥着关键作用。当QEMU等虚拟机管理器启动一台虚拟机时,通常会在宿主机上创建一个TAP设备(如tap0)作为虚拟机的"网卡接口"。这个tap0设备会被加入到宿主机的Linux网桥(如br0)中,同时物理网卡也可能加入此网桥。这样,虚拟机发出的以太网数据帧通过TAP设备被宿主机上的网络程序(如QEMU)读取,再转发到网桥,最终可以像宿主机上的真实设备一样与外部网络或其他虚拟机通信。这种机制也是许多容器网络方案的基础。
3.3 其他应用方向
网络协议实验:开发者可以利用TUN/TAP在用户空间实现自定义的网络协议栈,用于学习或研究,而无需修改内核。
流量监控与过滤:通过读取TUN/TAP设备的数据,可以对特定流量进行监控、分析或实现灵活的防火墙策略。
4.TUN/TAP的局限性与替代方案
尽管TUN/TAP设备非常灵活,但它们也存在一定的局限性,最主要问题在于性能开销。由于数据包必须在内核协议栈和用户态应用程序之间频繁传递,每次传输都涉及上下文切换和数据拷贝,这在高速网络(如25Gbps及以上)或小包高并发场景下容易成为性能瓶颈。虽然通过多队列(Multiqueue)等技术可以提升性能,但其吞吐量和延迟通常仍不及一些更先进的内核直通方案。
因此,在需要更高性能或特定功能的场景下,可以考虑其他虚拟网络方案作为替代或补充。例如,veth pair常用于连接不同的网络命名空间,是容器网络的基础组件;MACVTAP 则旨在简化虚拟化环境下的桥接网络,能减少数据拷贝开销,提升性能;而功能更丰富的 Open vSwitch (OVS) 及其 MACTAP 接口则提供了强大的虚拟交换能力和更优的内核级数据通路,特别适用于云数据中心等复杂网络环境。选择哪种方案需根据具体的性能要求、功能复杂度和部署环境进行权衡。
5.总结
TUN/TAP设备巧妙地利用Linux"一切皆文件"的哲学,通过一个字符设备文件/dev/net/tun,在内核网络协议栈和用户态程序之间架起了一座桥梁。它们虽然纯粹由软件实现,但在内核看来,其行为与物理网卡无异。
其核心价值在于将网络数据包的处理能力开放给了用户空间。这种设计带来了极大的灵活性,催生了从VPN、虚拟化网络到云原生基础设施等诸多强大应用。理解TUN/TAP,不仅是掌握Linux网络虚拟化的关键,更能让我们看清许多上层网络技术(如Kubernetes网络插件)的底层实现逻辑。