Linux tun/tap驱动

tun/tap是纯软件实现的一套虚拟网络设备。tap表示虚拟以太网设备,工作在二层网络上,具有直接处理以太帧的能力。tun表示虚拟点对点设备,工作在三层网络上,具有处理IP包的能力。

其实现原理相对简单。它在内核空间添加一个杂项设备(msicdevice)/dev/net/tun,实质上就是一个主设备号为10的字符设备,作为用户空间与内核空间信息交互的接口。tun/tap驱动程序包括两个部分,一部分是字符设备驱动,另一部分是虚拟网卡驱动。利用网卡驱动部分,接收来自内核协议栈的网络数据包并发送出去,或者反过来将接收到的数据包转交给内核协议栈处理。而字符设备驱动部分则负责数据包在内核空间与用户空间之间传递。

这里以2.6.18内核为例。内核为tun/tap驱动定义的结构体描述如下:/include/linux/if_tun.h

struct tun_struct {
	struct list_head list; //tun/tap网络设备链表
	unsigned long flags; //区分tun或tap设备
	...
	wait_queue_head_t read_wait; //等待队列
	struct sk_buff_head readq; //接收数据包缓存链表
	
	struct net_device *dev; //对应的网络设备结构
	...
}
模块源码(/drivers/net/tun.c)中,模块初始化函数tun_init调用杂项设备注册函数misc_register注册一个名为tun的字符设备,并提供包括open、close、read、write等在内的一系列标准接口。

注册虚拟网络设备:

用户空间程序调用open函数打开tun字符设备,返回一个文件描述符fd,调用ioctl(fd, TUNSETIFF, ...)申请创建一个新的虚拟网络设备,内核接口函数tun_chr_ioctl解析cmd,触发执行tun_set_iff函数。在该函数中,分配一个net_device结构体,这是linux提供的一个统一的网络设备结构,调用tun_setup函数,该函数为虚拟网络设备注册网络驱动程序处理例程,包括open、stop、hard_start_xmit、get_stats等,并完成接收网络数据包缓存链表readq和等待队列read_wait的初始化。最终调用register_netdevice向内核空间注册该网络设备。至此,网络设备的注册工作完成。

数据包发送流程:

驱动程序调用之前注册好的hard_start_xmit函数,这里是tun_net_xmit,该函数将skb加入到readq链表,并唤醒阻塞在read_wait上的读数据包进程。接着,调用tun_chr_read从readq链表中获取skb,然后调用tun_put_user函数将数据包内容发送到用户空间。

数据包接收流程:

当用户空间应用程序调用函数write向tun/tap字符设备写数据时,tun_chr_write将被调用,进而调用tun_get_user函数从用户空间缓冲区接收数据,并为数据内容分配相应的sk_buff进行管理,最终调用netif_rx_ni函数将数据包转交给内核协议栈处理。



参考资料:

1、TUN/TAP维基百科:这里

2、虚拟网卡TUN/TAP驱动程序设计原理:这里



你可能感兴趣的:(其它,linux)