随着虚拟化技术的出现,网络也随之被虚拟化,相较于单一的物理网络,虚拟网络变得非常复杂,在一个主机系统里面,需要实现诸如交换、路由、隧道、隔离、聚合等多种网络功能。
而实现这些功能的基本元素就是虚拟的网络设备,比如 tap、tun 和 veth-pair。
tap/tun
tap/tun 提供了一台主机内用户空间的数据传输机制。它虚拟了一套网络接口,这套接口和物理的接口无任何区别,可以配置 IP,可以路由流量,不同的是,它的流量只在主机内流通。
tap/tun 有些许的不同,tun 是一个点对点的三层设备,只操作三层的 IP 包,而 tap 是一个二层设备操作二层的以太网帧。
作为网络设备,tap/tun 也需要配套相应的驱动程序才能工作。tap/tun 驱动程序包括两个部分,一个是字符设备驱动,一个是网卡驱动。这两部分驱动程序分工不太一样,字符驱动负责数据包在内核空间和用户空间的传送,网卡驱动负责数据包在 TCP/IP 网络协议栈上的传输和处理。
用户空间与内核空间的数据传输
tap/tun 通过驱动程序和一个与之关联的字符设备,来实现用户空间和内核空间的通信接口。
在 Linux 内核 2.6.x 之后的版本中,tap/tun 对应的字符设备文件分别为:
tap:/dev/tap0
tun:/dev/net/tun
设备文件即充当了用户空间和内核空间通信的接口。当应用程序打开设备文件时,驱动程序就会创建并注册相应的虚拟设备接口,一般以 tunX 或 tapX 命名。当应用程序关闭文件时,驱动也会自动删除 tunX 和 tapX 设备,还会删除已经建立起来的路由等信息。
tap/tun 设备文件就像一个管道,一端连接着用户空间,一端连接着内核空间。当用户程序向文件 /dev/net/tun 或 /dev/tap0 写数据时,内核就可以从对应的 tunX 或 tapX 接口读到数据,反之,内核可以通过相反的方式向用户程序发送数据。
tap/tun 和网络协议栈的数据传输
tap/tun 通过实现相应的网卡驱动程序来和网络协议栈通信。一般的流程和物理网卡和协议栈的交互流程是一样的,不同的是物理网卡一端是连接物理网络,而 tap/tun 虚拟网卡一般连接到用户空间。
应用程序A构造包发往192.168.1.0/24网段的主机102.168.1.1流程:
- A–socket A–>dst:192.168.1.1
- NPS查dst,出接口为tun0
- tun0发现另一端被B打开,将数据发送给应用程序B
- B进行一些处理之后,构造包,sip为10.1.1.11,dst是10.1.1.10/24的网关10.1.1.1,封装原来的数据包,发给NSP
- NSP查路由,将包从eth0发出。、
后续步骤,当 10.1.1.1 收到数据包后,会进行解封装,读取里面的原始数据包,继而转发给本地的主机 192.168.1.1。当接收回包时,也遵循同样的流程。
在这个流程中,应用程序 B 的作用其实是利用 tun0 对数据包做了一层隧道封装。其实 tun 设备的最大用途就是用于隧道通信的。
tap/tun 的应用
从上面的数据流程中可以看到,tun 设备充当了一层隧道,所以,tap/tun 最常见的应用也就是用于隧道通信,比如 VPN,包括 tunnel 和应用层的 IPsec 等,其中比较有名的两个开源项目是 openvpn 和 VTun。
创建 tap/tun 设备
tunctl:
apt-get install uml-utilities
tunctl [ OPTIONS ] [ -u owner ] [-g group] [ -t device-name ]
-u 参数指定用户名,表明这个接口只受该用户控制,这个接口发生的事不会影响到系统的接口。
-g 指定一组用户
-t 指定要创建的 tap/tun 设备名。
[OPTIONS] 部分:
-b 简单打印创建的接口名字
-n 创建 tun 设备
-p 创建 tap 设备,默认创建该设备
-f tun-clone-device 指定 tun 设备对应的文件名,默认是 /dev/net/tun,有些系统是 /dev/misc/net/tun。
-d interfacename 删除指定接口
常见用法:
默认创建 tap 接口:
tunctl等价于 tunctl -p
为用户 user 创建一个 tap 接口:tunctl -u user
创建 tun 接口:tunctl -n
为接口配置 IP 并启用:ifconfig tap0 192.168.0.254 up
为接口添加路由:route add -host 192.168.0.1 dev tap0
删除接口:tunctl -d tap0
ip tuntap:
命令行输入 ip help 查看 ip 命令是否支持 tuntap 工具,支持的话就会显示 tuntap 选项.
ip tuntap help查看详细使用命令.
常见用法:
创建 tap/tun 设备:
ip tuntap add dev tap0 mod tap # 创建 tap
ip tuntap add dev tun0 mod tun # 创建 tun
删除 tap/tun 设备:ip tuntap del dev tap0 mod tap # 删除 tap
ip tuntap del dev tun0 mod tun # 删除 tun
PS: user 和 group 参数和 tunctl 的 -u、 -g 参数是一样的。
以上两个工具,我们更推荐使用 ip tuntap,一个是因为 iproute2 更全更新,已经逐步在替代老旧的一些工具,另一个是因为 tunctl 在某些 Debian 类的系统上支持不全。
veth-pair
veth-pair 是成对出现的一种虚拟网络设备,一端连接着协议栈,一端连接着彼此,数据从一端出,从另一端进。
它的这个特性常常用来连接不同的虚拟网络组件,构建大规模的虚拟网络拓扑,比如连接 Linux Bridge、OVS、LXC 容器等。
一个很常见的案例就是它被用于 OpenStack Neutron,构建非常复杂的网络形态。
它都是成对出现的。一端连着协议栈,一端彼此相连着。如下图所示:
cloud_dev_veth_pair_struct.jpg
正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备,典型的例子像“两个 namespace 之间的连接”,“Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等。