随着虚拟化技术的出现,网络也随之被虚拟化,相较于单一的物理网络,虚拟网络变得非常复杂,在一个主机系统里面,需要实现诸如交换、路由、隧道、隔离、聚合等多种网络功能。
而实现这些功能的基本元素就是虚拟的网络设备,比如 tap、tun 和 veth-pair。

tap/tun

tap/tun 提供了一台主机内用户空间的数据传输机制。它虚拟了一套网络接口,这套接口和物理的接口无任何区别,可以配置 IP,可以路由流量,不同的是,它的流量只在主机内流通。

tap/tun 有些许的不同,tun 是一个点对点的三层设备,只操作三层的 IP 包,而 tap 是一个二层设备操作二层的以太网帧。

cloud_dev_tap_tun.png

现网虚拟化平台扩容 虚拟化网络设备_现网虚拟化平台扩容


作为网络设备,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 接口读到数据,反之,内核可以通过相反的方式向用户程序发送数据。

cloud_dev_tap_tun_tx.png

现网虚拟化平台扩容 虚拟化网络设备_用户空间_02

tap/tun 和网络协议栈的数据传输

tap/tun 通过实现相应的网卡驱动程序来和网络协议栈通信。一般的流程和物理网卡和协议栈的交互流程是一样的,不同的是物理网卡一端是连接物理网络,而 tap/tun 虚拟网卡一般连接到用户空间。

cloud_dev_tap_tun_txstack.png

现网虚拟化平台扩容 虚拟化网络设备_驱动程序_03


应用程序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 tap0ip tuntap:
命令行输入 ip help 查看 ip 命令是否支持 tuntap 工具,支持的话就会显示 tuntap 选项.
ip tuntap help查看详细使用命令.
常见用法:
创建 tap/tun 设备:

ip tuntap add dev tap0 mod tap # 创建 tapip tuntap add dev tun0 mod tun # 创建 tun 删除 tap/tun 设备:
ip tuntap del dev tap0 mod tap # 删除 tapip 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.png

现网虚拟化平台扩容 虚拟化网络设备_用户空间_04


它都是成对出现的。一端连着协议栈,一端彼此相连着。如下图所示:

cloud_dev_veth_pair_struct.jpg

现网虚拟化平台扩容 虚拟化网络设备_现网虚拟化平台扩容_05


正因为有这个特性,它常常充当着一个桥梁,连接着各种虚拟网络设备,典型的例子像“两个 namespace 之间的连接”,“Bridge、OVS 之间的连接”,“Docker 容器之间的连接” 等等。