Loading...
墨滴

一介刁民

2021/11/10  阅读:24  主题:自定义主题1

【云原生虚拟化】一文读懂网络虚拟化之 tun/tap 网络设备

【云原生虚拟化】一文读懂网络虚拟化之 tun/tap 网络设备

了解云原生的同学应该都了解过 flannel 的 overlay 网络模型吧,overlay 模型中有一种是 UDP 模式,虽然因为性能差被弃用了,但也是最典型的容器跨主机网络方案。

这个图大家都不陌生吧,这个是张磊的《深入剖析 Kubernetes》中的网络解析,可以看到 Flannel 进行 UDP 的封包与解包都是在用户态通过 tun 设备(flannel0)来实现的,这个 flannel0 就是今天咱们要讲的主角之一,tun 设备。

tun/tap 设备是操作系统内核中的虚拟网络设备,是用软件模拟的网络设备,提供与硬件网络设备完全相同的功能。主要用于用户空间和内核空间传递报文。

如上图所示:

  • 对于硬件网络设备而言,一端连接的是物理网络,一端连接的是网络协议栈。
  • 对于 tun/tap 设备而言,一端连接的是应用程序(通过 文件 /net/dev/tun),一端连接的是网络协议栈

工作原理

工作原理

从上图可以更直观的看出 tun/tap 设备和物理设备的区别:虽然它们的一端都是连着网络协议栈,但是物理网卡另一端连接的是物理网络,而 tun/tap 设备另一端连接的是一个 应用层程序,这样协议栈发送给 tun/tap 的数据包就可以被这个应用程序读取到,此时这个应用程序可以对数据包进行一些自定义的修改(比如封装成 UDP),然后又通过网络协议栈发送出去——其实这就是目前大多数 代理 的工作原理。

Tun/tap 设备提供的虚拟网卡驱动,从tcp/ip协议栈的角度而言,它与真实网卡驱动并没有区别。

工作模式

tun/tap 有两种模式,**tun 模式 **与 tap 模式。tun 设备与 tap 设备工作方式完全相同,区别在于:

  1. Tun 设备是一个三层设备,从/dev/net/tun字符设备上读取的是IP数据包,写入的也只能是IP数据包,因此不能进行二层操作,如发送ARP请求和以太网广播
  2. Tap设备是二层设备,处理的是二层 MAC 层数据帧,从/dev/net/tun字符设备上读取的是MAC 层数据帧,写入的也只能是 MAC 层数据帧。从这点来看,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结构实例不同,代表不同的字符设备。

应用的数据收发过程:

  1. 数据发送:应用进程 A open/dev/net/tun 字符设备,通过 ioctl 调用创建虚拟接口 tunx 或者 tapx, ioctl 调用返回表示对应 tunx 或者 tapx 设备的文件描述符 fd ,应用 A 通过这个文件描述符 fd 写入格式化的数据,数据通过虚拟网卡驱动到达协议栈,对于协议栈来说,这个数据就像从真实网卡接收的一样
  2. 数据接收:当网络协议栈发送数据到虚拟接口 tunx 或者 tapx时,应用进程 A 通过上述创建的设备文件描述符 fd,从中读取接口发送的数据,然后进行处理

设备创建

除了在应用中通过克隆设备 /dev/net/tun 和 ioctl 系统调用创建虚拟设备,还可以通过 ip tuntap 命令创建。

# 创建 tun/tap 设备
ip tuntap add dev tap0 mod tap # 创建 tap
ip tuntap add dev tun0 mod tun # 创建 tun


# 删除tun/tap设备
ip tuntap del dev tap0 mod tap # 删除 tap
ip tuntap del dev tun0 mod tun # 删除 tun

# 设置 ip 地址,up 设备
ip address add dev tap0 10.0.1.5/24
ip link set dev tap0 up

tun/tap 驱动

Tun/tap驱动程序中包含两个部分,一部分是字符设备驱动,还有一部分是网卡驱动。

  • 利用网卡驱动部分接收来自TCP/IP协议栈的网络分包并发送或者反过来将接收到的网络分包传给协议栈处理。
  • 字符驱动部分则将网络分包在内核与用户态之间传送,模拟物理链路的数据接收和发送。用户态程序通过 ioctl read write 系统调用 与字符设备/dev/net/tun 进行数据交互。

通过 modinfo tunmodinfo tap 查看 tun/tap 设备驱动

root@~:~# modinfo tun
filename:       /lib/modules/4.14.81.bm.15-amd64/kernel/drivers/net/tun.ko
alias:          devname:net/tun
alias:          char-major-10-200
license:        GPL
author:         (C) 1999-2004 Max Krasnyansky <maxk@qualcomm.com>
description:    Universal TUN/TAP device driver
depends:
intree:         Y
name:           tun
vermagic:       4.14.81.bm.15-amd64 SMP mod_unload modversions

root@~:~# modinfo tap
filename:       /lib/modules/4.14.81.bm.15-amd64/kernel/drivers/net/tap.ko
license:        GPL
author:         Sainath Grandhi <sainath.grandhi@intel.com>
author:         Arnd Bergmann <arnd@arndb.de>
depends:
intree:         Y
name:           tap
vermagic:       4.14.81.bm.15-amd64 SMP mod_unload modversions

应用场景

vpn

接收数据流程

接收机制如上图所示,黑线是公网IP,红线是解密后的内网IP包。vpn 进程监听的是公网 ip + 端口,数据包经过网卡到达协议栈,到达 vpn 进程,vpn 进程解密解包后,将数据通过 字符设备文件发送给虚拟设备,再次经过协议栈的路由,最终将数据发到用户程序。

发送数据流程

发送机制如上图所示,红线是内网IP,黑色线是加密过后的公网IP包。应用程序发送目的 ip 为 内网 ip 的数据包,到达虚拟网卡,转到字符设备文件,被 vpn进程读取到。经过封包加密后,通过协议栈路由到网卡,最终通过公网 网卡发送出去。

虚拟机VM

以 qemu 为例,qemu 启动时通过 qemu -netdev tap 指定 tap 设备

如图中所示,红色箭头表示数据报文的入方向,步骤:

  1. 网络数据从 Host 上的物理网卡接收,到达网桥;
  2. 由于 eth0 与 tap1 均加入网桥中,根据二层转发原则,br0 将数据从 tap1 口转发出去,即数据由 Tap设备接收;
  3. Tap 设备通知对应的 fd 数据可读;
  4. fd 的读动作通过 tap 设备的字符设备驱动将数据拷贝到用户空间,完成数据报文的前端接收。

参考

一介刁民

2021/11/10  阅读:24  主题:自定义主题1

作者介绍

一介刁民