虚拟网卡TUN/TAP 驱动程序设计原理

昨天韦哥写了《Linux下Tun/Tap设备通信原理》一文,只提到了两个使用Tun的用户进程之间的通信路径,并没有说明Tun虚拟网卡驱动是如何实现的,而正好看到了这里的一篇讲解这方面的文章,果断转载了,感谢作者,原文在这里:虚拟网卡TUN/TAP 驱动程序设计原理

简介

虚拟网卡Tun/tap驱动是一个开源项目,支持很多的类UNIX平台,OpenVPN和Vtun都是基于它实现隧道包封装。本文将介绍tun/tap驱动的使用并分析虚拟网卡tun/tap驱动程序在linux环境下的设计思路。

tun/tap
驱动程序实现了虚拟网卡的功能,tun表示虚拟的是点对点设备,tap表示虚拟的是以太网设备,这两种设备针对网络包实施不同的封装。利用tun/tap
驱动,可以将tcp/ip协议栈处理好的网络分包传给任何一个使用tun/tap驱动的进程,由进程重新处理后再发到物理链路中。开源项目
openvpn( http://openvpn.sourceforge.net)和Vtun( http://vtun.sourceforge.net)都是利用tun/tap驱动实现的隧道封装。

使用tun/tap驱动

在linux 2.4内核版本及以后版本中,tun/tap驱动是作为系统默认预先编译进内核中的。在使用之前,确保已经装载了tun/tap模块并建立设备文件:

#modprobe tun
#mknod /dev/net/tun c 10 200

参数c表示是字符设备, 10和200分别是主设备号和次设备号。

这样,我们就可以在程序中使用该驱动了。

使用tun/tap设备的示例程序(摘自openvpn开源项目 http://openvpn.sourceforge.net,tun.c文件)

int open_tun (const char *dev, char *actual, int size)
{
  struct ifreq ifr;
  int fd;
  char *device = "/dev/net/tun";
  if ((fd = open (device, O_RDWR)) < 0) //创建描述符
    msg (M_ERR, "Cannot open TUN/TAP dev %s", device);
  memset (&ifr, 0, sizeof (ifr));
  ifr.ifr_flags = IFF_NO_PI;
  if (!strncmp (dev, "tun", 3)) {
      ifr.ifr_flags |= IFF_TUN;
   }
  else if (!strncmp (dev, "tap", 3)) {
      ifr.ifr_flags |= IFF_TAP;
    }
  else {
    msg (M_FATAL, "I don‘t recognize device %s as a TUN or TAP device",dev);
    }
  if (strlen (dev) > 3)		/* unit number specified? */
    strncpy (ifr.ifr_name, dev, IFNAMSIZ);
  if (ioctl (fd, TUNSETIFF, (void *) &ifr) < 0) //打开虚拟网卡
    msg (M_ERR, "Cannot ioctl TUNSETIFF %s", dev);
  set_nonblock (fd);
  msg (M_INFO, "TUN/TAP device %s opened", ifr.ifr_name);
  strncpynt (actual, ifr.ifr_name, size);
  return fd;
}

调用上述函数后,就可以在shell命令行下使用ifconfig 命令配置虚拟网卡了,通过生成的字符设备描述符,在程序中使用read和write函数就可以读取或者发送给虚拟的网卡数据了。

Tun/tap驱动程序工作原理

做 为虚拟网卡驱动,Tun/tap驱动程序的数据接收和发送并不直接和真实网卡打交道,而是通过用户态来转交。在linux下,要实现核心态和用户态数据的 交互,有多种方式:可以通用socket创建特殊套接字,利用套接字实现数据交互;通过proc文件系统创建文件来进行数据交互;还可以使用设备文件的方 式,访问设备文件会调用设备驱动相应的例程,设备驱动本身就是核心态和用户态的一个接口,Tun/tap驱动就是利用设备文件实现用户态和核心态的数据交 互。

从结构上来说,Tun/tap驱动并不单纯是实现网卡驱动,同时它还实现了字符设备驱动部分。以字符设备的方式连接用户态和核心态。下面是示意图:

Tun/tap 驱动程序中包含两个部分,一部分是字符设备驱动,还有一部分是网卡驱动部分。利用网卡驱动部分接收来自TCP/IP协议栈的网络分包并发送或者反过来将接 收到的网络分包传给协议栈处理,而字符驱动部分则将网络分包在内核与用户态之间传送,模拟物理链路的数据接收和发送。Tun/tap驱动很好的实现了两种 驱动的结合。

下面是定义的tun/tap设备结构:

struct tun_struct {
	char 			name[8]; //设备名
	unsigned long 		flags; //区分tun和tap设备
	struct fasync_struct    *fasync; //文件异步通知结构
	wait_queue_head_t 	read_wait; //等待队列
	struct net_device	dev;  //linux 抽象网络设备结构
	struct sk_buff_head 	txq; //网络缓冲区队列
    struct net_device_stats	stats; //网卡状态信息结构
};

struct net_device结构是linux内核提供的统一网络设备结构,定义了系统统一的访问接口。

Tun/tap驱动中实现的网卡驱动的处理例程:

static int tun_net_open(struct net_device *dev);
static int tun_net_close(struct net_device *dev);
static int tun_net_xmit(struct sk_buff *skb, struct net_device *dev);//数据包发送例程
static void tun_net_mclist(struct net_device *dev);//设置多点传输的地址链表
static
struct net_device_stats *tun_net_stats(struct net_device
*dev);//当一个应用程序需要知道网络接口的一些统计数据时,可调用该函数,如ifconfig、netstat等。
int tun_net_init(struct net_device *dev);//网络设备初始例程

字符设备部分:

在Linux中,字符设备和块设备统一以文件的方式访问,访问它们的接口是统一的,都是使用open()函数打开设备文件或普通文件,用read()和write()函数实现读写文件等等。Tun/tap驱动定义的字符设备的访问接口如下:

static struct file_operations tun_fops = {
owner: THIS_MODULE,
llseek: tun_chr_lseek,
read tun_chr_read,
write: tun_chr_write,
poll: tun_chr_poll,
ioctl: tun_chr_ioctl,
open: tun_chr_open,
release: tun_chr_close,
fasync: tun_chr_fasync
};

在内核中利用misc_register() 函数将该驱动注册为非标准字符设备驱动,提供字符设备具有的各种程序接口。代码摘自linux-2.4.20\linux-2.4.20\drivers\net\tun.c

static struct miscdevice tun_miscdev=
{
        TUN_MINOR,
        "net/tun",
        &tun_fops
};
int __init tun_init(void)
{
	…
	if (misc_register(&tun_miscdev)) {
		printk(KERN_ERR "tun: Can‘t register misc device %d\n", TUN_MINOR);
		return -EIO;
	}
	return 0;
}

当打开一个tun/tap设备时,open 函数将调用tun_chr_open()函数,其中将完成一些重要的初始化过程,包括设置网卡驱动部分的初始化函数以及网络缓冲区链表的初始化和等待队列 的初始化。Tun/tap驱动中网卡的注册被嵌入了字符驱动的ioctl例程中,它是通过对字符设备文件描述符利用自定义的ioctl设置标志 TUNSETIFF完成网卡的注册的。下面是函数调用关系示意图:

使 用ioctl()函数操作字符设备文件描述符,将调用字符设备中tun_chr_ioctl 来设置已经open好的tun/tap设备,如果设置标志为TUNSETIFF,则调用tun_set_iff() 函数,此函数将完成很重要的一步操作,就是对网卡驱动进行注册register_netdev(&tun->dev),网卡驱动的各个处理 例程的挂接在open操作时由tun_chr_open()函数初始化好了。

Tun/tap设备的工作过程:

Tun/tap 设备提供的虚拟网卡驱动,从tcp/ip协议栈的角度而言,它与真实网卡驱动并没有区别。从驱动程序的角度来说,它与真实网卡的不同表现在tun/tap 设备获取的数据不是来自物理链路,而是来自用户区,Tun/tap设备驱动通过字符设备文件来实现数据从用户区的获取。发送数据时tun/tap设备也不 是发送到物理链路,而是通过字符设备发送至用户区,再由用户区程序通过其他渠道发送。

发送过程:

使 用tun/tap网卡的程序经过协议栈把数据传送给驱动程序,驱动程序调用注册好的hard_start_xmit函数发 送,hard_start_xmit函数又会调用tun_net_xmit函数,其中skb将会被加入skb链表,然后唤醒被阻塞的使用tun/tap设 备字符驱动读数据的进程,接着tun/tap设备的字符驱动部分调用其tun_chr_read()过程读取skb链表,并将每一个读到的skb发往用户 区,完成虚拟网卡的数据发送。

接收数据的过程:

当 我们使用write()系统调用向tun/tap设备的字符设备文件写入数据时,tun_chr_write函数将被调用,它使用 tun_get_user从用户区接受数据,其中将数据存入skb中,然后调用关键的函数netif_rx(skb) 将skb送给tcp/ip协议栈处理,完成虚拟网卡的数据接收。

小结

tun/tap驱动很巧妙的将字符驱动和网卡驱动糅合在一起,本文重点分析两种驱动之间的衔接,具体的驱动处理细节没有一一列出,请读者参考相关文档。

参考资料

时间: 2024-10-12 18:51:25

虚拟网卡TUN/TAP 驱动程序设计原理的相关文章

Linux下虚拟网卡tun/tap

#include <stdio.h>#include <string.h>#include <linux/if_tun.h>#include <sys/types.h>#include <net/if.h>#include <sys/stat.h>#include <fcntl.h>#include <sys/ioctl.h> int tun_create(char *dev, int flags) { str

Linux的虚拟网卡TUN和TAP

TUN/TAP 提供了给用户空间程序的包的接收和传输,它可以看成是简单的点对点设备或是以太网设备.它不是从物理设备接收包,而是从用户空间程序接收包.它发送包不是通过物理设备来发送包,而是将这些包写入用户空间程序来发送.为了应用这个驱动,应用程序需要打开/dev/net/tun 设备(字符设备),然后发出一个控制(ioctl)来注册一个网卡设备,一个网络设备将命名为tunXX 或tapXX.依赖于你所设定的标志位.当应用程序关闭文件描述符的时候,网络设备和其他相关的路由将会消失.依赖于所选择的设备

Linux下Tun/Tap设备通信原理

Tun/Tap都是虚拟网卡,没有直接映射到物理网卡,是一种纯软件的实现.Tun是三层虚拟设备,能够处理三层即IP包,Tap是二层设备,能处理链路层网络包如以太网包.使用虚拟网络设备,可以实现隧道,如OpenVPN的实现.这篇文章我主要根据自己画的一个图来简单说明在隧道实现中两个虚拟网络设备数据包的流程. 上面的图中,左右两边分别为两台机器.一台有一块物理网卡配置了IP:172.16.1.11,这台机器的系统里有一个Tun(以Tun为例,不讲Tap了)设备,配置了IP:192.168.1.11;

CentOS下使用TUN/TAP虚拟网卡的基本教程

在计算机网络中,TUN与TAP是操作系统内核中的虚拟网络设备.不同于普通靠硬件网路板卡实现的设备,这些虚拟的网络设备全部用软件实现,并向运行于操作系统上的软件提供与硬件的网络设备完全相同的功能.TAP 等同于一个以太网设备,它操作第二层数据包如以太网数据帧.TUN模拟了网络层设备,操作第三层数据包比如IP数据封包.操作系统通过TUN/TAP设备向绑定该设备的用户空间的程序发送数据,反之,用户空间的程序也可以像操作硬件网络设备那样,通过TUN/TAP设备发送数据.在后种情况下,TUN/TAP设备向

[原]openstack-networking-neutron(二)---tun/tap

简介 虚拟网卡Tun/tap驱动是一个开源项目,支持很多的类UNIX平台,OpenVPN和Vtun都是基于它实现隧道包封装.本文将介绍tun/tap驱动的使用并分析虚拟网卡tun/tap驱动程序在linux环境下的设计思路. tun/tap驱动程序实现了虚拟网卡的功能,tun表示虚拟的是点对点设备,tap表示虚拟的是以太网设备,这两种设备针对网络包实施不同的封装.利用tun/tap驱动,可以将tcp/ip协议栈处理好的网络分包传给任何一个使用tun/tap驱动的进程,由进程重新处理后再发到物理链

TUN/TAP设备浅析

https://www.jianshu.com/p/660e69326e65 在 linux 2.4 及之后的内核版本中,tun/tap 驱动是默认编译进内核中的. (tun编译到内核中, tap作为内核模块编译) TUN/TAP设备浅析(一) -- 原理浅析 https://www.jianshu.com/p/09f9375b7fa7 TUN/TAP设备浅析(二) -- TUN/TAP的编程 https://www.jianshu.com/p/ab91f7cd98cd TUN/TAP设备浅析(

[转载]windows过滤驱动程序设计入门(驱动程序基本结构,设备栈,IRP栈和工作原理)

本文转载自: http://blog.csdn.net/arvon2012/article/details/7789724 最近在学习windows驱动设计,认真看了些教材后总结了我认为驱动中都会涉及到,也最重要的概念,和大家分享.如果有说的不对的请大家留言指出.谢谢! 这里主要是写概念,代码涉及的不多也不详细,但是我会说出涉及到的API,详细的使用细节大家可以自己动手搜搜.掌握下面的概念之后,看驱动开发的教材里的代码,或者理解教材里说的内容应该就顺利很多! 过滤驱动程序概括: 对于window

解决vmware安装 win7 后 没有虚拟网卡驱动 不能上网的问题

项目需要用到win7 32位系统,于是装个虚拟机,换了好几个系统资源,都是没有网卡驱动, XP 2003 都能上网唯独WIN7 不行,安装vmware tools也不管用,终于找到了这个东西.vmware win7 虚拟网卡驱动 链接:http://pan.baidu.com/s/1skNnMln 密码:1tui 下载后拖拽到虚拟机里,然后设备管理器更新上就OK了.

基于嵌入式Linux的千兆以太网卡驱动程序设计及测试

一. 引言 千兆以太网是一种具有高带宽和高响应的新网络技术,相关协议遵循IEEE 802.3规范标准.采用和10M以太网相似的帧格式.网络协议和布线系统,基于光纤和短距离同轴电缆的物理层介质,更适用于交换机.服务器等数据吞吐率大的设备.本文设计实现一种基于嵌入式Linux千兆以太网卡的驱动程序,并完成后续的测试工作和代码移植. 千兆以太网网卡工作在OSI网络架构的物理层和数据链路层,其中物理层由PHY芯片管理,数据链路层由千兆以太网控制器(GMAC)管理.硬件构架上,GMAC控制器由核心层.MT