最佳的測试方式当然是不依赖不论什么外部设备了。显而易见的方法就是做自环。
RJ45口的双绞线能够做物理层自环。1/3。2/6短接就可以。这样一台机器的一块网卡自己就能够既发又收了,可是你能对照头发略粗的光纤做什么呢?真实的做法当然是用软件攻克了,在Linux上能够使用netns来解决。即net namespace。 netns是一个非常好玩的东西,它能够让你在一台机器上模拟多个网络设备。这样做的意义是非同一般的:1.使用netns能够充分利用闲置的处理器资源,特别是你的多块网卡性能压不满CPU的时候;2.使用netns能够将不同类型的网络应用隔离,针对每一类实施不同的策略。3.使用netns有点玩虚拟化的意思。只是比虚拟机更灵活。一个net namespace有自己独立的路由表。iptables策略。设备管理机构,和其他的netns全然隔离。比方你将eth0增加了netns1,那么netns2中的应用程序就看不到eth0。网卡设备管理仅仅是netns中的一个元素,还有非常多,比方你在netns1中配置的iptables策略对netns2中的数据包没有不论什么影响。总之,假设你懂Linux内核源代码,那么仅仅要附着有net结构体字段的那些结构。比方skb,net_device,都和netns有关。 那么我应该怎么做自环呢?我的设备有4个网卡。我希望1和4之间通信,通过2和3转发。它的逻辑拓扑例如以下:PC1/eth0----PC2/eth1(forward)PC2/eth2----PC3/eth3非常easy,将eth0和eth3设置在两个不同的netns。然后用线缆连接eth0和eth1。相同连接eth2和eth3,最后将eth0和eth1的IP地址设置在一个网段,将eth2和eth3的IP地址设置在还有一个不同的网段就可以。光说不练假把式,详细应该怎么做呢?相同非常easy:1.增加两个netnsip netns add t1ip netns add t22.将eth0增加t1,而且设置IP地址ip link set eth0 netns t1此时再ifconfig就看不到eth0了,你甚至运行ls /sys/class/net也看不到eth0了,仅仅有运行ip netns exec t1 ls /sys/class/net才干看到。ip netns exec t1 ifconfig eth0 192.168.1.200/243.将eth3增加t2。而且设置IP地址ip link set eth3 netns t2此时ifconfig就看不到eth3了。你甚至运行ls /sys/class/net也看不到eth3了,仅仅有运行ip netns exec t2 ls /sys/class/net才干看到。ip netns exec t1 ifconfig eth3 172.16.1.200/244.设置eth1和eth2的地址ifconfig eth1 192.168.1.1/24ifconfig eth2 172.16.1.1/245.设置两个netns的默认路由ip netns exec t1 route add default gw 192.168.1.1ip netns exec t2 route add default gw 172.16.1.16.測试在netns t1中ping netns t2中的eth3地址ip netns exec t1 ping 172.16.1.200上述配置之后,从eth0发出的包会通过网线到达eth1(而不是走local路由表的loopback),然后经过eth1的forward从eth2发出。经由网线到达目的地eth3杯接收。整个过程中就一台机器。展示出的效果好像三台机器的样子。有了这个机制,是不是再也不用为搭建測试环境而发愁了呢? 除了自环測试之外,netns还能够用于设置策略路由。这样的策略路由不须要ip rule。试想一种场景,你同一时候运行了P1和P2两个程序。本机所在的局域网有两个出口到达外网。你希望P1通过gw1和外界通信。P2通过gw2和外界通信,约束条件是你的机器仅仅有一张网卡eth0,怎么办呢?通过iptables为P1和P2的数据包打上不同的mark,然后通过ip rule设置策略路由无疑能够解决,另外直接在P1和P2应用程序中用setsockopt也是能够设置ipmark的,这就不须要iptables了。然而这一切都过时了,2014年我须要一种不同的方式。
我不知道怎么表达我思考的过程,可是给出一个操作序列是简单的事情,由于照着这么做确实能够满足需求,然后看到这篇文章的人照着操作步骤倒推回去,就能够得到一个思考过程。首先你要明确的是Linux内核支持一种虚拟网卡类型。即veth,一般而言veth是成对的,从一个veth发出的数据包能够直接到达它的peer veth,感兴趣的能够看Linux内核的drivers/net/veth.c。和drivers/net/tun.c没什么不同,更简单些罢了。第一步要做的就是建立一对veth:ip link add veth1 type veth peer name veth2此时系统中除了eth0之外又多了两块网卡,全部的网卡为lo。eth0,veth1。veth2。中间隐含着一个事实。即veth1和veth2之间有一条虚拟的链路将两块网卡连接起来,就好像一条双绞线连接的两块物理网卡一样。我如今希望P1的数据包通过veth1发出。然后自然而然地就能发到veth2,可是随后怎么通过eth0发到物理线路呢?太简单。太简单。使用bridge吧:brctl addbr br0brctl addif br0 eth0 veth2
同一时候,veth1和br0所在的局域网设置在一个IP网段中,这下子就全通了。该二层网络的逻辑拓扑为:veth1----veth2(bridge)eth0----gw(1,2)怎么设置netns我本来不想说了,可是由于小小临时不跟我玩了,我还是写完吧。首先将veth1设置到netns1(详细怎么创建netns,不再赘述)并设置路由:
ip link set veth1 netns netns1ip netns exec netns1 route add default gw $gw1route add default gw $gw2这就完了?是的,完事了。其实,保留br0的默认netns就可以,没有必要创建netns2了。接下来须要做的就是启动P1和P2了:
ip netns exec netns1 P1P2好了,一切结束。 我始终都认为。在Linux上一般都是不用改动源代码就能解决这个问题,可是我还是喜欢改动代码,原因何在?非常easy,源代码非常容易获得,而且源代码非常容易改动,我走火入魔般地写了大量的Netfilter扩展以及做了大量的nf_conntrack改动。甚至还增加了一些该死的socket filter...尽管这些行为都是自娱自乐型的。并没有被应用在工作中,可是这些行为说明我不是网络管理员,而是一名程序猿。哈哈,自封的资深软件project师(我还是认为这些成果能被应用)。然而,做一名技术精湛的网络管理人员的难度却远远超过做程序猿的难度。这不,重新遇到了OpenVPN的多实例问题。我认为,单纯的程序猿搞不定它。单纯的网管也不行。 TAP模式的多实例已经被我用Linux Bridge完美蹂躏了。可是TUN模式的多实例问题仍然没有完美的方案。尽管改动tun驱动。使用broadcast mode bonding+tun filter能够解决。可是我还是认为那是一种走火入魔的方式。因此就算在公司我也没能将整个调试測试进行下去,结果落了个不了了之,其实,是我太不喜欢那种方式。tun的IP filter是我改出来的方案。并非标准的。能不能使用标准的方式进行寻址呢?使用netns,答案就是肯定的。
假设在GW上启动了2个OpenVPN实例ovpn1和ovpn2,虚拟网卡分别为tun1和tun2。在client-connect脚本中得知ovpn2负责N1,ovpn2负责N2。如今问题的关键是。GW后方出发的数据包如何知道是将数据包发送到tun1还是tun2。这个推断能不能自己主动进行?假设使用netns,那就是能够的,我能够将2个tun分别设置在不同的netns,然后每个netns相应一个同处一个netns的veth虚拟网卡,这些veth的peer们处在另外一个netns中。这样就能够实现IP层TUN模式虚拟网卡到以太网的TAP模式虚拟网卡的适配。最后将这些peer们Bridge成一个br0,那么TUN模式的OpenVPN就能和TAP模式的OpenVPN採用同一种方式处理了。
无论如何,当你玩弄netns的时候,你要知道你并非在玩弄冷酷无情的虚拟化操作系统,也不是真的模拟了两台物理上相互隔离的机器,由于尽管两个程序的网络是隔离的,可是文件系统却是共享的。你要时刻准备着,使用网络隔离和使用内存,文件系统共享相结合。
将一台机器既能够作为多台机器使用,又能够作为一台机器共享资源!
无论如何。当你玩弄netns的时候,你要知道你并非在玩弄冷酷无情的虚拟化操作系统,也不是真的模拟了两台物理上相互隔离的机器。由于尽管两个程序的网络是隔离的,可是文件系统却是共享的。你要时刻准备着,使用网络隔离和使用内存,文件系统共享相结合。将一台机器既能够作为多台机器使用。又能够作为一台机器共享资源!
理解了上述的样例和最后的总结,那么我来发问,单网卡或者没有网卡怎么玩自环?这个需求可能就是为了測试一下协议栈而已。略去思考的过程,非常easy,多加一个层次。比方你有一台机器一块网卡也没有,那么你仅仅须要以下的命令就能够在你的机器上实现IP转发或者bridge转发了:
ip link add v1 type veth peer name vp1ip link add v2 type veth peer name vp2brctl addbr br0brctl addif vp1 vp2ifconfig vp1 upifconfig vp2 upsysctl -w net.ipv4.ip_forward=1ip netns add t1ip netns add t2ip link set v1 netns t1ip link set v2 netns t2ip netns exec t1 ifconfig v1 1.1.1.1/24ip netns exec t2 ifconfig v2 1.1.1.2/24ip netns exec t1 ping 1.1.1.2...