TUN/TAP/VETH

本文详细介绍了TUN/TAP虚拟网络设备及其工作原理,包括TUN/TAP设备的区别及应用场景,并对比了VETH设备的特点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 TUN/TAP虚拟网络设备为用户空间程序提供了网络数据包的发送和接收能力。他既可以当做点对点设备(TUN),也可以当做以太网设备(TAP)。

TUN/TAP虚拟网络设备的原理:

在Linux内核中添加了一个TUN/TAP虚拟网络设备的驱动程序和一个与之相关连的字符设备/dev/net/tun,字符设备tun作为用户空间和内核空间交换数据的接口。当内核将数据包发送到虚拟网络设备时,数据包被保存在设备相关的一个队列中,直到用户空间程序通过打开的字符设备tun的描述符读取时,它才会被拷贝到用户空间的缓冲区中,其效果就相当于,数据包直接发送到了用户空间。通过系统调用write发送数据包时其原理与此类似。

1、tun设备

TUN 设备是一种虚拟网络设备,通过此设备,程序可以方便地模拟网络行为。

TUN 模拟的是一个三层设备,也就是说,通过它可以处理来自网络层的数据,更通俗一点的说,通过它,我们可以处理 IP 数据包。

先来看看物理设备是如何工作的:

图中的 eth0 是主机已有的真实的网卡接口 (interface)。

网卡接口 eth0 所代表的真实网卡通过网线(wire)和外部网络相连,该物理网卡收到的数据包会经由接口 eth0 传递给内核的网络协议栈(Network Stack)。然后协议栈对这些数据包进行进一步的处理。

对于一些错误的数据包,协议栈可以选择丢弃;

对于不属于本机的数据包,协议栈可以选择转发;

而对于确实是传递给本机的数据包,而且该数据包确实被上层的应用所需要,协议栈会通过 Socket API 告知上层正在等待的应用程序。

 

下面看看 TUN 的工作方式:

我们知道,普通的网卡是通过网线来收发数据包的话,而 TUN 设备比较特殊,它通过一个设备文件(/dev/tunX)收发数据包。

如上图所示,tunX 和上面的 eth0 在逻辑上面是等价的, tunX 也代表了一个网络接口,虽然这个接口是系统通过软件所模拟出来的。

网卡接口 tunX 所代表的虚拟网卡通过文件 /dev/tunX 与我们的应用程序(App) 相连,应用程序每次使用 write 之类的系统调用将数据写入该文件,这些数据会以网络层数据包的形式,通过该虚拟网卡,经由网络接口 tunX 传递给网络协议栈。

同时该应用程序也可以通过 read 之类的系统调用,经由文件 /dev/tunX 读取到协议栈向 tunX 传递的所有数据包。

 

协议栈可以像操纵普通网卡一样来操纵 tunX 所代表的虚拟网卡:

比如,给 tunX 设定 IP 地址,设置路由,总之,在协议栈看来,tunX 所代表的网卡和其他普通的网卡区别不大,当然,硬要说区别,那还是有的,那就是 tunX 设备不存在 MAC 地址,这个很好理解,tunX 只模拟到了网络层,要 MAC地址没有任何意义。

如果是 tapX 的话,在协议栈的眼中,tapX 和真是网卡没有任何区别!!!!

 

示例:

Tun/Tap都是虚拟网卡,没有直接映射到物理网卡,是一种纯软件的实现。Tun是三层虚拟设备,能够处理三层即IP包,Tap是二层设备,能处理链路层网络包如以太网包。使用虚拟网络设备,可以实现隧道,如OpenVPN的实现。

上面的图中,左右两边分别为两台机器。一台有一块物理网卡配置了IP:172.16.1.11,这台机器的系统里有一个Tun(以Tun为例,不讲Tap了)设备,配置了IP:192.168.1.11; 另一台的一块物理网卡配置了IP:172.16.1.12,系统里有一个Tun设备并配置了IP:192.168.1.12。

 左边Linux系统里有一个Application,绑定到端口地址为: 192.168.1.11:5000,右边Linux也有一个Application,绑定到端口地址为:192.168.1.12:5000,显然它们绑定的都是Tun设备的IP,接着它们就通过这两个地址通信了。

 假设左边的Application要给右边的Application发送一个数据包,流程是这样的:

 左边的Application并不知道什么虚拟网络设备,它只知道往"192.168.1.12:5000"这个地址发送,左边主机系统首先按正常的发包过程处理,比如判断目的主机是不是位于同一网段等等,然后数据包就在Linux的网络协议栈中穿行。Tun设备并不是真实的物理网卡,它不知道把数据包往哪里送,但是这些经过了Linux网络协议栈的数据可以从Tun设备的文件描述符中读取到,图中的“User Program”就是监听这个描述符等待读取数据的。这个“User Program”程序绑定的端口地址是:172.16.1.11:6000,每当它从Tun设备读到数据的时候,就把这些数据从物理网卡发送出去,目标地址是右边的:172.168.1.12:6000。

 数据到达右边的系统,经过网络协议栈之后到达“User Program”应用进程,“User Program”将接收到的数据往Tun设备对应的文件描述符写入。对于Tun设备来说,“写入”就像是物理网卡接受到数据包一样,因此这些接收到的数据又进入了Linux的网络协议栈,最终到达右边的Application。

 

这里的Application是指各种各样的用户程序,如ping工具。“User Program”是用来辅助Tun设备来实现隧道功能的,可以想象成是OpenVPN进程,没有它隧道就废了!!!!

  

2、TAP设备

如图所示,当备一个 TAP 设被创建时,在 Linux 设备文件目录下将会生成一个对应 char 设备,用户程序可以像打开普通文件一样打开这个文件进行读写。

当执行write()操作时,数据进入 TAP 设备,此时对于 Linux 网络层来说,相当于 TAP 设备收到了一包数据,请求内核接受它,如同普通的物理网卡从外界收到一包数据一样,不同的是其实数据来自 Linux 上的一个用户程序。Linux 收到此数据后将根据网络配置进行后续处理,从而完成了用户程序向 Linux 内核网络层注入数据的功能。

当用户程序执行read()请求时,相当于向内核查询 TAP 设备上是否有需要被发送出去的数据,有的话取出到用户程序里,完成 TAP 设备的发送数据功能。

 

针对 TAP 设备的一个形象的比喻是:

使用 TAP 设备的应用程序相当于另外一台计算机,TAP 设备是本机的一个网卡,他们之间相互连接。应用程序通过 read()/write()操作,和本机网络核心进行通讯。

 

TAP 设备与 TUN 设备工作方式完全相同,区别在于:

1)TUN 设备是点对点的三层设备,处理IP分组,它只模拟到了 IP 层,即网络层 我们可以通过 /dev/tunX 文件收发 IP 层数据包,它无法与物理网卡做 bridge,但是可以通过三层交换(如 ip_forward)与物理网卡连通。可以使用ifconfig等命令给该设备设定 IP 地址。

2)TAP 设备是一个二层虚拟以太网设备,处理以太网帧,它比 TUN 更加深入,通过 /dev/tapX 文件可以收发 MAC 层数据包,即数据链路层,拥有 MAC 层功能,可以与物理网卡做 bridge,支持 MAC 层广播。同样的,我们也可以通过ifconfig等命令给该设备设定 IP 地址,还可以给它设定 MAC 地址。

 3)

  TAP:子网掩码是/24,255.255.255.0,对应以太网设备

  TUN:子网掩码是/30,255.255.255.252,点对点设备。

4)设备节点号不同:

  2.4的核:TUN 设备号是36 16+,文件节点:/dev/tun0
  2.6的核:TUN 设备号是10 200,文件节点:/dev/net/tun

 

 

 

OSI模型中的七层:

第一层是物理层

第二层是数据链路层(tap设备)

第三层是网络层(tun设备)

第四层是传输层

第五层是会话层

第六层是表示层

第七层是应用层

 

 

 3、VETH

 VETH 设备出现较早,它的作用是反转通讯数据的方向,需要发送的数据会被转换成需要收到的数据,重新送入内核网络层进行处理,从而间接的完成数据的注入。

 VETH 设备总是成对出现,送到一端请求发送的数据总是从另一端以请求接受的形式出现。

该设备不能被用户程序直接操作,但使用起来比较简单。创建并配置正确后,向其一端输入数据,VETH 会改变数据的方向并将其送入内核网络核心,完成数据的注入。在另一端能读到此数据

  

veth、tun、tap比对

 

转载于:https://www.cnblogs.com/wyzhou/p/9286864.html

<think>好的,我需要回答用户关于如何编译veth源码以及分析其实现的问题。首先,我要确认用户的需求。用户可能是在进行Linux网络虚拟化相关的开发或学习,需要深入了解veth的源码结构和编译方法。 首先,我需要回忆一下veth在Linux内核中的位置。veth是虚拟以太网设备,属于网络子系统的一部分。源码通常在内核的drivers/net/目录下,特别是veth.c文件。所以编译veth源码实际上涉及到整个Linux内核的编译过程,因为veth是内核模块的一部分。 接下来,用户可能不知道如何获取内核源码并进行配置。我应该分步骤说明,从获取源码开始,比如通过git克隆官方仓库,或者下载特定版本的源码包。然后配置内核选项,确保veth驱动被启用。这里需要解释make menuconfig或类似工具的使用,找到Network device support中的Virtual ethernet pair device选项。 然后,编译内核或单独编译模块。如果用户只是想编译veth模块,可以指导他们使用make M=drivers/net/veth命令。但需要提醒用户编译内核模块需要安装必要的依赖,比如gcc、make、内核头文件等,否则会遇到错误。 另外,用户提到源码分析,可能需要解释veth的关键结构体和函数。比如veth的结构体veth_priv,以及初始化函数veth_setup。这部分需要准确,不能出错,可能需要参考内核源码或文档。 同时,用户的问题可能涉及到veth pair的工作原理,比如如何实现数据包的传输。根据引用[3],veth pair像双向管道,一端发送另一端接收。在源码中,这涉及到网络设备操作结构体中的xmit函数,比如veth_xmit函数负责发送数据包到对端。 还要注意引用相关的资料,比如引用[1]到[4],特别是引用[3]和[4]直接提到了veth pair的特性,可能需要在回答中引用这些内容,说明其实现原理。 另外,用户可能需要调试或修改veth模块,所以建议使用动态加载模块的方式,这样不需要重新编译整个内核。比如使用insmod和rmmod命令,但需要提醒用户注意内核版本兼容性。 最后,生成相关问题需要考虑用户可能的后续问题,比如如何调试veth模块,如何扩展其功能,或者与其他虚拟网络设备如bridge、tun/tap的配合使用。需要确保问题与当前主题相关,并且对深入学习有帮助。 总结一下,回答的结构应该是:编译步骤(获取源码、配置、编译)、关键源码分析(结构体、函数)、动态加载方法,以及相关的问题。同时,引用正确的资料,确保信息的准确性。</think>### 关于veth源码编译与分析的指导 #### 一、veth源码编译步骤 1. **获取Linux内核源码** veth是Linux内核原生组件,需从[官方仓库](https://git.kernel.org/)克隆或下载对应版本源码(如`git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git`)[^3]。 2. **配置内核编译选项** 通过`make menuconfig`进入配置界面,启用以下选项: ``` Device Drivers → Network device support → Virtual ethernet pair device (CONFIG_VETH) ``` 保存配置后生成`.config`文件[^2]。 3. **编译内核或单独编译模块** - **全内核编译**:执行`make -j$(nproc)`编译整个内核。 - **仅编译veth模块**:使用`make M=drivers/net/veth`生成`veth.ko`内核模块[^4]。 4. **安装与加载模块** 编译完成后,通过以下命令加载模块: ```bash sudo insmod drivers/net/veth.ko ``` 验证加载状态:`lsmod | grep veth`。 --- #### 二、veth关键源码分析 veth实现位于内核源码的`drivers/net/veth.c`,核心逻辑如下: 1. **数据结构** - `struct veth_priv`:存储veth设备对端指针(`peer`)和统计信息。 - `struct net_device_ops`:定义设备操作函数(如数据包发送`veth_xmit`)。 2. **关键函数** - **veth_xmit**:数据包发送函数,通过`netif_rx()`将对端设备加入接收队列。 - **veth_setup**:初始化网络设备属性(如MTU、MAC地址生成)。 3. **工作原理** veth pair通过内核的虚拟网络栈连接,发送到一端的数据直接传递到另一端,类似双向管道。例如: ```c // veth_xmit函数核心逻辑(简化) static netdev_tx_t veth_xmit(struct sk_buff *skb, struct net_device *dev) { struct veth_priv *priv = netdev_priv(dev); skb->dev = priv->peer; // 将数据包目标设为对端设备 netif_rx(skb); // 触发对端接收 return NETDEV_TX_OK; } ``` --- #### 三、动态调试与扩展 1. **动态加载与卸载** 修改代码后重新编译模块,通过`insmod/rmmod`快速测试,无需重启系统。 2. **调试技巧** 使用`dmesg`查看内核日志,或在代码中添加`printk`输出调试信息。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值