tun/tap 设备

来源:互联网 发布:python监控系统性能 编辑:程序博客网 时间:2024/06/06 18:17
什么是tun/tap?
     TUN/TAP虚拟网络设备为用户空间程序提供了网络数据包的发送和接收能力。他既可以当做点对点设备(TUN),也可以当做以太网设备(TAP)。实际上,不仅Linux支持TUN/TAP虚拟网络设备,其他UNIX也是支持的,他们之间只有少许差别。
     TUN/TAP虚拟网络设备的原理比较简单,他在Linux内核中添加了一个TUN/TAP虚拟网络设备的驱动程序和一个与之相关连的字符设备/dev/net/tun,字符设备tun作为用户空间和内核空间交换数据的接口。当内核将数据包发送到虚拟网络设备时,数据包被保存在设备相关的一个队列中,直到用户空间程序通过打开的字符设备tun的描述符读取时,它才会被拷贝到用户空间的缓冲区中,其效果就相当于,数据包直接发送到了用户空间。通过系统调用write发送数据包时其原理与此类似。
     值得注意的是:一次read系统调用,有且只有一个数据包被传送到用户空间,并且当用户空间的缓冲区比较小时,数据包将被截断,剩余部分将永久地消失,write系统调用与read类似,每次只发送一个数据包。所以在编写此类程序的时候,请用足够大的缓冲区,直接调用系统调用read/write,避免采用C语言的带缓存的IO函数。
     是一类虚拟网卡的驱动。网卡驱动很好理解,就是netdev+driver,最后将数据包通过这些驱动发送出去,netdev可以参考内核或者OVS代码,基本使用的就是几个钩子函数。
     虚拟网卡就是没有物理设备的网卡,那么他的驱动就是需要开发人员自己编写。一般虚拟网卡用于实现物理网卡不愿意做的事情,例如tunnel封装(用于vpn,openvpn( http://openvpn.sourceforge.net)和Vtun( http://vtun.sourceforge.net)),多个物理网卡的聚合等。一般使用虚拟网卡的方式与使用物理网卡一样,在协议栈中通过回调函数call到虚拟网卡的API,经过虚拟网卡处理之后的数据包再由协议栈发送出去。


tun/tap驱动?
     linux2.4内核之后代码默认编译tun、tap驱动,使用的时候只需要将模块加载即可(modprobe tun,mknod /dev/net/tun c 10 200)。运行tun、tap设备之后,会在内核空间添加一个杂项设备(miscdevice,类比字符设备、块设备等)/dev/net/tun,实质上是主设备号10的字符设备。从功能上看,tun设备驱动主要应该包括两个部分,一是虚拟网卡驱动,其实就是虚拟网卡中对skb进行封装解封装等操作;二是字符设备驱动,用于内核空间与用户空间的交互。
     源代码在/drivers/net/tun.c中,与其他netdev类似,tun这个netdev也提供open、close、read、write等API。使用tun的过程也类似,首先在tun_init中初始化,tun_destroy中销毁。初始化与配置的过程如上图。
     驱动从协议栈接受数据包发送给用户空间的时候,驱动调用之前注册hard_start_xmit(这是协议栈收包专用函数,是从L2的位置收取上来的。类比tap设备从L3位置收取,发送也是一样,这是tun与tap的区别,就是走不走路由) 好的钩子函数tun_net_xmit,这个函数分配一个skb加入到读包链表,并唤醒真正从收包队列中读取包的线程来填充这个skb。然后tun_net_xmit调用tun_chr_read从readq中获取skb,最后调用tun_put_user发送给用户空间。
     驱动从用户空间接受数据包发送给协议栈的时候,用户进程首先调用字符设备的write函数向tun/tap设备写数据,最终驱动通过netif_rx_ni将数据包发送给协议栈。发送与接收的过程如下图。


如何进行tun/tap编程?
     首先准备linux内核,编译内核时候选择(Device Drivers => Network device support => Universal TUN/TAP device driver support),运行时候加载内核模块。
     demo见https://github.com/batmancn/MyLife/blob/master/Demos/linux-kernel-demo/tun-tap-demo.c 。


OVS中vxlan vport与gre port?
     OVS中并没有使用tun/tap设备,因为如果想要使用的话需要按照上面的步骤操作。因为OVS2.3.0中只是用了vxlan和gre封装,所以使用udp的socket即可。
     datapath中定义了vxlan vport,如果想要使用这个vport需要加载vxlan的kernel module。上层用户添加vxlan vport的时候,通过netlink调用ovs_vxlan_vport_ops.vxlan_tnl_create,具体过程见(https://github.com/batmancn/ovs.git)中的注释。
     gre是L3 over L3,(http://www.netadmin.com.tw/article_content.aspx?sn=1405120002),使用ipgre_newlink这个API创建。见注释。
0 0