Chinaunix

标题: 如何在linux程序中创建多个tun/tap虚拟网卡? [打印本页]

作者: 享耳亲斤    时间: 2009-06-04 09:30
标题: 如何在linux程序中创建多个tun/tap虚拟网卡?
我想在redhat enterprise 5的程序中创建多个tun/tap虚拟网卡。最初先创建一个tap设备,写了收包和发包函数,能正常工作,可是当创建两个tap设备时,出现了问题。我把创建的函数帖出来:
int tun_create(char *dev, int flags)
{
     struct ifreq ifr;
     int fd, err;
     assert(dev != NULL);
     if ((fd = open("/dev/net/tun", O_RDWR)) < 0)
         return fd;
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags |= flags;
     if (*dev != '\0')
         strncpy(ifr.ifr_name, dev, IFNAMSIZ);     
     if ((err=ioctl(fd,TUNSETIFF,(void *)&ifr))<0){
   close(fd);
      return err;
  }
    // set_nonblock (fd);
     strcpy(dev,ifr.ifr_name);
     return fd;
}

int main(int argc, char *argv[])
{
        char tun_name[IFNAMSIZ]="tap0";
        char tun_name1[IFNAMSIZ]="tap1";   
        Tap=tun_create(tun_name, IFF_TAP | IFF_NO_PI);
        if (Tap< 0) {
                perror("tun_create");
                return 1;
                            }
        printf("TAP name is %s\n", tun_name);
        printf("Tap=%d\n",Tap);
        system("ifconfig tap0 10.0.0.185 netmask 255.255.0.0 up");
   
        Tap1=tun_create(tun_name1, IFF_TAP | IFF_NO_PI);
        if (Tap1< 0) {
                perror("tun_create");
                return 1;
                            }
        printf("TAP1 name is %s\n", tun_name1);
        printf("Tap1=%d\n",Tap1);
        system("ifconfig tap1 10.0.0.186 netmask 255.255.0.0 up");
}
这样就创建了tap0(IP地址:10.0.0.185)和tap1(IP地址:10.0.0.186)。但ping tap0时,发出ping 回应的却是tap1,感觉它们两个好像是一个设备。
请问应该怎样创建两个或多个tap设备?希望用过tun/tap虚拟网卡的高手帮忙,谢谢!
我的Email:simba226@163.com
作者: fly6    时间: 2009-06-04 10:01
...........

[ 本帖最后由 fly6 于 2009-6-4 10:58 编辑 ]
作者: 享耳亲斤    时间: 2009-06-04 15:57
多谢2位的回复。
我试了modprobe tun
mknod /dev/net/tun0 c 10 200
mknod /dev/net/tun1 c 10 201
然后在程序里
int tun0_create(char *dev, int flags)
{
     struct ifreq ifr;
     int fd, err;
     assert(dev != NULL);
     if ((fd = open("/dev/net/tun0", O_RDWR)) < 0)
         return fd;
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags |= flags;
     if (*dev != '\0')
         strncpy(ifr.ifr_name, dev, IFNAMSIZ);     
     if ((err=ioctl(fd,TUNSETIFF,(void *)&ifr))<0){
   close(fd);
      return err;
  }
   
     strcpy(dev,ifr.ifr_name);
     return fd;
}
int tun1_create(char *dev, int flags)
{
     struct ifreq ifr;
     int fd, err;
     assert(dev != NULL);
     if ((fd = open("/dev/net/tun1", O_RDWR)) < 0)
         return fd;
     memset(&ifr, 0, sizeof(ifr));
     ifr.ifr_flags |= flags;
     if (*dev != '\0')
         strncpy(ifr.ifr_name, dev, IFNAMSIZ);     
     if ((err=ioctl(fd,TUNSETIFF,(void *)&ifr))<0){
   close(fd);
      return err;
  }
   
     strcpy(dev,ifr.ifr_name);
     return fd;
}
int main(int argc, char *argv[])
{
        char tun_name[IFNAMSIZ]="tap0";
        char tun_name1[IFNAMSIZ]="tap1";   
        Tap=tun0_create(tun_name, IFF_TAP | IFF_NO_PI);
        if (Tap< 0) {
                perror("tun_create");
                return 1;
                            }
        printf("TAP name is %s\n", tun_name);
        printf("Tap=%d\n",Tap);
        system("ifconfig tap0 10.0.0.185 netmask 255.255.0.0 up");
   
        Tap1=tun1_create(tun_name1, IFF_TAP | IFF_NO_PI);
        if (Tap1< 0) {
                perror("tun_create");
                return 1;
                            }
        printf("TAP1 name is %s\n", tun_name1);
        printf("Tap1=%d\n",Tap1);
        system("ifconfig tap1 10.0.0.186 netmask 255.255.0.0 up");
}
可是运行时发现tun1_create函数里,fd = open("/dev/net/tun1", O_RDWR),fd返回-1,然后程序结束。请问怎么办?谢谢
作者: Cyberman.Wu    时间: 2009-06-04 18:59
你确信你给的代码就是你测试用的代码?我用的环境是CentOS5.3,标准的发布内核(实际上是升级了又降回去了),测试并没有问题,是正常的:
[Cyberman@Cyberspace Network]$ ping -c 4 10.0.0.185
PING 10.0.0.185 (10.0.0.185) 56(84) bytes of data.
64 bytes from 10.0.0.185: icmp_seq=1 ttl=64 time=0.049 ms
64 bytes from 10.0.0.185: icmp_seq=2 ttl=64 time=0.049 ms
64 bytes from 10.0.0.185: icmp_seq=3 ttl=64 time=0.049 ms
64 bytes from 10.0.0.185: icmp_seq=4 ttl=64 time=0.048 ms

--- 10.0.0.185 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3000ms
rtt min/avg/max/mdev = 0.048/0.048/0.049/0.008 ms
[Cyberman@Cyberspace Network]$ ping -c 4 10.0.0.186
PING 10.0.0.186 (10.0.0.186) 56(84) bytes of data.
64 bytes from 10.0.0.186: icmp_seq=1 ttl=64 time=0.055 ms
64 bytes from 10.0.0.186: icmp_seq=2 ttl=64 time=0.050 ms
64 bytes from 10.0.0.186: icmp_seq=3 ttl=64 time=0.050 ms
64 bytes from 10.0.0.186: icmp_seq=4 ttl=64 time=0.052 ms

--- 10.0.0.186 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.050/0.051/0.055/0.009 ms
[Cyberman@Cyberspace Network]$



TUNSETIFF时输入结构的名称应该是没有意义的吧?反正内核中具体处理的代码还没看,测试出来是相同的。

[ 本帖最后由 Cyberman.Wu 于 2009-6-4 19:00 编辑 ]

tap_test.tar.bz2

927 Bytes, 下载次数: 56


作者: 享耳亲斤    时间: 2009-06-05 08:11
标题: 回复 #5 Cyberman.Wu 的帖子
谢谢回复!
你是在本机ping这两个虚拟网卡的吧?
我是从另外一个机子上的虚拟网卡来ping其中的一个虚拟网卡,而且它们都运行了olsr路由协议,结果发现ping某一个虚拟网卡时,回复的包却不一定来自它。而且一个ping 请求包它会回复多个相应包,相同的响应包后面加有(DUP!)。不知道怎么回事
作者: Cyberman.Wu    时间: 2009-06-05 09:57
标题: 回复 #6 享耳亲斤 的帖子
我是从本机ping的。

不知道你的路由协议具体是怎么配置的,用的是哪个版本的内核?我在一块板子上测试时遇到过和你类似的问题,上面几个网口直接从二层收包,然后针对每个网口创建一个TAP,中间插错网口好像出现过类似的问题,当时用的内核版本是2.6.18.8,现在用的2.6.26.7好像不会出现同样的问题。
作者: 享耳亲斤    时间: 2009-06-08 09:04
高手帮帮忙,谢谢
作者: 享耳亲斤    时间: 2009-06-09 10:31
标题: 回复 #7 Cyberman.Wu 的帖子
我用的是redhat enterprise 5,内核是2.6.18。你也出现过类似的问题,比如ping主机上的tap0,回复ping的却是tap1这种情况吗?用2.6.26.7就没这样的问题吗?
作者: 享耳亲斤    时间: 2009-06-11 11:41
在两个主机上分别创建了两个tap虚拟网卡,每个虚拟网卡运行olsr路由协议,从其中一个ping另外一个虚拟网卡,得到如图所示结果:

作者: Cyberman.Wu    时间: 2009-06-11 18:47
原帖由 享耳亲斤 于 2009-6-9 10:31 发表
我用的是redhat enterprise 5,内核是2.6.18。你也出现过类似的问题,比如ping主机上的tap0,回复ping的却是tap1这种情况吗?用2.6.26.7就没这样的问题吗?


现在我还不是很清楚是否和内核版本有关,那天测试时的结果比较奇怪,出现过类似的情况,不过后来没时间也就没再去测试;后来我在2.6.26.7版本上测试的确没再测出来。但那个现象好像也不是必然的,当时六个网口就我的本子现象比较奇怪。
作者: Cyberman.Wu    时间: 2009-06-11 18:57
标题: 回复 #11 享耳亲斤 的帖子
DUP的话是连续几个包都是回复同一个的ICMP Request导致的吧,为啥这样是不是和你用的那个路由协议有一定关系?

我那次遇到的现象和你的不太一样,没有重复的包,就是IP成另一个了。

能不能把你如何把包注入到TAP中描述一下?如果是用PF_PACKET的话有时候会出现一个包从物理端口往上走到协议栈,同时又从TAP进入一份,从而导致一些比较奇怪的现象。

我知道Linux协议栈在发ARP请求时只要本地有这个IP就回应,但物理地址又是收到包的那个端口,例如你的eth0是192.168.0.10,eth1是192.168.1.10,如果在eth0上收到请求192.168.1.10的ARP Request它会回应,MAC地址则填写eth0的。我原来遇到一个怪问题就是用PF_PACKET抓包注入TAP时Linux协议栈先回了一个ARP,然后才走到TAP,再回一个。对于Windows一般后面一个ARP响应覆盖前面的,所以后面的ICMP Request中的目标MAC是TAP的,但对于Linux则有些奇怪,如果是正常的IP是OK的,但对于ifconfig增加的eth0:0之类的,则只有前面的ARP生效。
作者: 享耳亲斤    时间: 2009-06-12 10:35
标题: 回复 #13 Cyberman.Wu 的帖子
谢谢回复!
可能和olsr路由协议无关,因为我试了另一个路由协议aodv,也是同样的问题。
我是这样把包注入到TAP中的:在物理网卡ath0用libpcap抓包,抓到包以后调用write函数把抓到的包写入到TAP中。
还有我在TAP发包时,进行了mac地址替换,用目的TAP所在主机的物理网卡的mac地址替换目的mac地址,用源TAP所在主机的物理网卡的mac地址替换源mac地址,把替换下来的mac地址放到数据包最后,在接收端在替换回去。然后write到目的TAP中。

我用抓包工具在TAP抓包发现,它总是先回应一个icmp reply,然后才收到icmp request,再回应一个icmp reply。每个icmp包都是这样。
作者: Mr__key    时间: 2017-03-07 15:29
在你最开始程序的基础上,无论ping tap1还是ping tap0,是不是总是tap1 reply ?

我感觉你用一个字符设备/dev/net/tun0 绑定了两个tap,而linux tun驱动中一个tun_sturct只能关联一个net_device。后TUNSETIFF的tap1覆盖了tap0.




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2