当前位置: 首页 >> 程序设计 >> 虚拟网卡 TUN/TAP 驱动程序设计原理
 

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

作者:bekars 的 Blog      来源:     发表时间:2006-03-22     浏览次数:      字号:    

内容摘要 简介 虚拟网卡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);//网络设备初始例程

[1] [2]

编辑 webmaster

 
 
 
评论更多>>
 
 
发表
 
姓名: QQ:
性别: MSN:
E-mail: 主页:
评分: 1 2 3 4 5
评论内容:
验证码:
  
  • 请遵守《互联网电子公告服务管理规定》及中华人民共和国其他各项有关法律法规。
  • 严禁发表危害国家安全、损害国家利益、破坏民族团结、破坏国家宗教政策、破坏社会稳定、侮辱、诽谤、教唆、淫秽等内容的评论 。
  • 用户需对自己在使用本站服务过程中的行为承担法律责任(直接或间接导致的)。
  • 本站管理员有权保留或删除评论内容。
  • 评论内容只代表网友个人观点,与本网站立场无关。
  •