网卡
网卡分为很多类型,虚拟网卡,物理网卡等。
- 物理网卡
物理网卡需要通过网卡驱动在内核中注册后才能工作,它在内核网络协议栈和外界网络之间传递数据,用户可以为物理网卡配置网卡接口属性,比如IP地址,这些属性都配置在内核的网络协议栈中。内核也可以直接创建虚拟的网卡,只要为虚拟网卡提供网卡驱动程序,使其在内核中可以注册成为网卡设备,它就可以工作。
从Linux内核3.x版本开始,物理网卡和虚拟网卡是平等的设备,它们都会在注册时创建net_device数据结构来保存(物理或虚拟)设备信息。相比于物理网卡负责内核网络协议栈和外界网络之间的数据传输,虚拟网卡的两端则是内核网络协议栈和用户空间,它负责在内核网络协议栈和用户空间的程序之间传递数据:发送到虚拟网卡的数据来自于用户空间,然后被内核读取到网络协议栈中。内核写入虚拟网卡准备通过该网卡发送的数据,目的地是用户空间。
- 虚拟网卡
物理网卡是硬件网卡,它位于硬件层,虚拟网卡则可以看作是用户空间的网卡,就像用户空间的文件系统(fuse)一样。物理网卡和虚拟网卡唯一的不同点在于物理网卡本身的硬件功能:物理网卡以比特流的方式传输数据。也就是说,内核会公平对待物理网卡和虚拟网卡,物理网卡能做的配置,虚拟网卡也能做。比如可以为虚拟网卡接口配置IP地址、设置子网掩码,可以将虚拟网卡接入网桥等等。只有在数据流经物理网卡和虚拟网卡的那一刻,才会体现出它们的不同,即传输数据的方式不同:物理网卡以比特流的方式传输数据,虚拟网卡则直接在内存中拷贝数据(即,在内核之间和读写虚拟网卡的程序之间传输)。正因为虚拟网卡不具备物理网卡以比特流方式传输数据的硬件功能,所以,绝不可能通过虚拟网卡向外界发送数据,外界数据也不可能直接发送到虚拟网卡上。能够直接收发外界数据的,只能是物理设备。虽然虚拟网卡无法将数据传输到外界网络,但却可以将数据传输到本机的另一个网卡(虚拟网卡或物理网卡)或其它虚拟设备(如虚拟交换机)上。可以在用户空间运行一个可读写虚拟网卡的程序,该程序可将流经虚拟网卡的数据包进行处理,这个用户程序就像是物理网卡的硬件功能一样,可以收发数据(可将物理网卡的硬件功能看作是嵌入在网卡上的程序),比如OpenVPN和VTun就是这样的工具。
Note:很多人会误解这样的用户空间程序,认为它们可以对数据进行封装。比如认为OpenVPN可以在数据包的基础上再封装一层隧道IP首部,但这种理解是错的。
用户空间的程序是无法对数据包做任何封装和解封操作的,所有的封装和解封都只能由内核的网络协议栈来完成。使用OpenVPN之所以可对数据再封装一层隧道IP层,是因为OpenVPN可以读取已经封装过一次IP首部的数据,并将包含ip首部的数据作为普通数据通过虚拟网卡再次传输给内核。因为内核接收到的是来自虚拟网卡的数据,所以内核会将其当作普通数据从头开始封装(从四层封装到二层封装)。当数据从网络协议栈流出时,就有了两层IP首部的封装。
- 物理网卡
一般来说,数据的起点和终点是用户程序,所以多数时候的数据需要在用户空间和内核空间(TCP/IP网络协议栈)再传输一次。
- 当用户进程的数据要发送出去时,数据从用户空间写入内核的网络协议栈,再从网络协议栈传输到网卡,最后发送出去。
- 当用户进程等待外界响应数据时,数据从网卡流入,传输至内核的网络协议栈,最后数据写入用户空间被用户进程读取。在次过程中内核和用户空间的数据传输由内核占用CPU来完成,内核和网卡之间的数据传输由网卡的DMA来完成。
用户空间和内核空间与标准TCP/IP协议栈对应关系:用户空间的程序是无法对数据包做任何封装和解封操作的,所有的封装和解封都只能由内核的网络协议栈来完成。
表示(7)层,应用(6)层,会话(5)层只是i编码,并没有内核参数进行封装,大致的封装如下
TCP/TUN
tap/tun 提供了一台主机内用户空间的数据传输机制。它虚拟了一套网络接口,这套接口和物理的接口无任何区别,可以配置 IP,可以路由流量,不同的是,它的流量只在主机内流通。作为网络设备,tap/tun 也需要配套相应的驱动程序才能工作。tap/tun 驱动程序包括两个部分,一个是字符设备驱动,一个是网卡驱动。这两部分驱动程序分工不太一样,字符驱动负责数据包在内核空间和用户空间的传送,网卡驱动负责数据包在 TCP/IP 网络协议栈上的传输和处理。tap/tun 有些许的不同,tun 只操作三层的 IP 包,而 tap 操作二层的以太网帧。在 Linux 中,用户空间和内核空间的数据传输有多种方式,字符设备就是其中的一种。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 是 Linux 内核 2.4.x 版本之后实现的虚拟网络设备,不同于物理网卡靠硬件板卡实现,tap/tun 虚拟网卡完全由软件实现,功能和硬件实现完全没差别,它们都属于网络设备,都可配置 IP,都归 Linux 网络设备管理模块统一管理。
tun和tap都是虚拟网卡设备:
- tun是三层设备,其封装的外层是IP头。
- tap是二层设备,其封装的外层是以太网帧(frame)头。
- tun是PPP点对点设备,没有MAC地址。
tap是以太网设备,有MAC地址tap比tun更接近于物理网卡,可以认为,tap设备等价于去掉了硬件功能的物理网卡这意味着,如果提供了用户空间的程序去收发tun/tap虚拟网卡的数据,所收发的内容是不同的。
- 收发tun设备的用户程序,只能间接提供封装和解封数据包的IP头的功能
- 收发tap设备的用户程序,只能间接提供封装和解封数据包的帧头的功能
注意,此处用词是【收发数据】而非【处理数据】,是【间接提供】而非【直接提供】,因为在不绕过内核网络协议栈的情况下,读写虚拟网卡的用户程序是不能封装和解封数据的,只有内核的网络协议栈才能封装和解封数据。虚拟网卡的两个主要功能是:
- 连接其它设备(虚拟网卡或物理网卡)和虚拟交换机(bridge)。
- 提供用户空间程序去收发虚拟网卡上的数据
基于这两个功能,tap设备通常用来连接其它网络设备(它更像网卡),tun设备通常用来结合用户空间程序实现再次封装。换句话说,tap设备通常接入到虚拟交换机(bridge)上作为局域网的一个节点,tun设备通常用来实现三层的ip隧道。但tun/tap的用法是灵活的,只不过上面两种使用场景更为广泛。例如,除了可以使用tun设备来实现ip层隧道,使用tap设备实现二层隧道的场景也颇为常见。tun、tap作为虚拟网卡,除了不具备物理网卡的硬件功能外,它们和物理网卡的功能是一样的,此外tun、tap负责在内核网络协议栈和用户空间之间传输数据。
tun
程序 A 希望构造数据包发往 192.168.1.0/24 网段的主机 192.168.1.1。
数据包要转发,是比要从用户空间转发到内核空间,到了内核空间后,如果是普通报文就直接送往网络设备上了(1,6,7)。
但是有了tun设备的介入,数据在传递的时候查看了路由表,数据不应该被送往到物理网卡,而是要传送到tun进程打开的设备上。tun设备本身就可以把内核的报文送回给用户空间,用户空间收到后仍然想正常的报文一样处理,但是不同的是,会将报文做一些修改,因为用户空间本身不能做封装,这些修改的内容最终发送到内核空间,内核空间就照单全收,根据数据包信息进行发送。(1-3-4-5-6-7)
这个方式和openvpn是一样的。