SDN(软件定义网络)初体验----Mininet
弈心:从事计算机网络工作十年(新加坡7年,沙特3年),2013年考取CCIE,在新加坡先后任职于AT&T,新加坡交通部,苹果,Equinix,苏格兰皇家银行等大型企业、银行和政府部门。 目前供职于“世界第一土豪大学“沙特阿卜杜拉国王科技大学(KAUST),担任Senior Network Engineer,为KAUST校史上第一位也是唯一一位华人IT部门高级职员。2019年6月在知乎发布了华语圈第一本专门为编程零基础的网络工程师量身打造的Python教程《网络工程师的Python之路》。
还记得我2013年考下CCIE RS后,在国外一个技术论坛偶然读到了一篇介绍SDN的文章,作者把SDN写得神乎其神,中心思想就是:完全靠网络工程师手动配置和手动排错,效率低下的传统网络迟早有”寿终正寝“的一天,而取而代之的就是能够带来”革命性改变“的SDN。的确,IT技术日新月异,当年CCIE RS v1 v2考试大纲里的那些古董级别的Apple Talk, FDDI, Token Ring, X.25, ATM等等,现在还有几个人有兴趣去花时间理解它们?由此自己开始关注Software Defined Network (软件定义网络)。
本篇文章是我2014年自学Mininet时的一些心得和笔记,温故知新,如今回味起来依然能学到不少东西:
1. SDN和传统网络最大的区别在于:SDN具有灵活的软件编程能力,让网络的自动化管理和控制能力获得空前的提升,能够有效地解决当前网络系统所面临的资源规模扩展受限、组网灵活性差的问题。
2. 传统网络设备的Control Plane和Data Plane在SDN中被完全拆开,互不干涉。
3. SDN的转发机制不再是Destination-based,而是Flow-based。
4. SDN的Control logic由SDN Controller(类似于现在的IOS之类的命令行操作系统,但运行方式不同)掌控。
5. Openflow, Opendaylight, OpenContrail等都是SDN的一部分。
6. 。。。。。。。。。。。
理论太多,不想赘述,因为学再多理论也比不过亲自动手尝试,还好最近找到了一款叫做Mininet的东西,这对所有SDN的初学者是一个福音。作为一个轻量级网络研究平台,Mininet已经出现很多年了,有志于研究SDN(openflow)的都知道它的来历和用途,关于Mininet的背景就不多做介绍了。下面是自己使用Mininet时做的一些笔记:
安装Mininet的步骤:
1. 下载Mininet(版本2.1.0)的镜像文件 (https://github.com/mininet/mininet/wiki/Mininet-VM-Images),这是一个基于Ubuntu的虚拟机文件。
2. 用VMware或者Virtual Box打开
Mininet使用笔记:
1. 学习Mininet之前,最好将Mininet官方的Walkthrough过一遍(http://mininet.org/walkthrough/)
2. sudo mn命令将创建一个最简单的拓扑,包括一个SDN Controller (c0),一个交换机 (s1),两台主机 (h1和h2)
3. Mininet几个比较重要的选项和参数总结如下:
--topo= 这个是Mininet创建的虚拟网络的拓扑,有4种类型:
minimal – 即上面提到的sudo mn命令,包括一个SDN Controller (c0),一个交换机 (s1),两台主机 (h1和h2)
single,X – 一个交换机,下面直连X个主机(自已定义)
linear,X – 创建X个环状链路的交换机,每个交换机下面直连一个主机
tree,X – 树状型拓扑,有X个fanout
--switch= 创建不同类型的交换机
ovsk – Mininet默认自带的Open vSwitch,已经预装在VM里面
user – 比ovsk慢很多,不推荐使用
--controller= 即SDN Controller,三个参数
ovsc – Mininet默认自带的OVS Controller,已经预装在VM里面
nox – 顾名思义,NOX controller
remote – 不创建Controller,尝试连接外部Controller
--mac 创建自定义的MAC地址
来做个实验具体说明,首先创建一个交换机,3个主机,无Controller的拓扑。
命令: Sudo mn –topo=single,3 –mac –controller=remote
在SDN中,交换机是没有Control Plane的,也就是说它仅是一个纯粹的转发设备, 并且这种”无脑型“的Openflow交换机只有在收到SDN controller的指示后,才能做出转发决定。遇到未知traffic时,Openflow交换机只会做一件事:就是把它们转发给SDN controller,自己什么也不管。这大大降低了习惯在传统网络的交换机中做各种2层排错的网工们的工作量。
既然Controller是SDN网络的大脑,那么创建一个没有controller的SDN拓扑还能玩吗?当然可以,这里要用到dptcl这个工具,dptcl的作用是可以跳过controller,直接通过TCP 6634这个端口来控制和查看openflow交换机的flow table(记住SDN网络的转发机制是flow-based,不是destination-based),不过dptcl和SDN controller是完全不同的两种东西,不能划等号,这点切记。
DPTCL的命令格式:
dptcl [show/dump-flows/add-flow] tcp:127.0.0.1:6634
最终实验拓扑如下:
具体配置和验证命令:
1. 开启Wireshark,让它在后台运行
mininet@mininet-vm:~$ sudo wireshark
2. 创建一个交换机(ovsk类型),3个主机,无Controller的SDN网络
mininet@mininet-vm:~$ sudo mn --topo=single,3 --mac --switch=ovsk --controller=remote*** Creating network*** Adding controllerUnable to contact the remote controller at 127.0.0.1:6633 //无controller的拓扑*** Adding hosts:h1 h2 h3*** Adding switches:s1*** Adding links:(h1, s1) (h2, s1) (h3, s1)*** Configuring hostsh1 h2 h3*** Starting controller*** Starting 1 switchess1*** Starting CLI:mininet>
3. 查看网络节点
mininet> nodesavailable nodes are:c0 h1 h2 h3 s1mininet>
4. 查看物理拓扑
mininet> neth1 h1-eth0:s1-eth1h2 h2-eth0:s1-eth2h3 h3-eth0:s1-eth3s1 lo: s1-eth1:h1-eth0 s1-eth2:h2-eth0 s1-eth3:h3-eth0c0mininet>
5. 查看各个节点的信息
mininet> dump<Host h1: h1-eth0:10.0.0.1 pid=9730><Host h2: h2-eth0:10.0.0.2 pid=9731><Host h3: h3-eth0:10.0.0.3 pid=9732><OVSSwitch s1: lo:127.0.0.1,s1-eth1:None,s1-eth2:None,s1-eth3:None pid=9735><RemoteController c0: 127.0.0.1:6633 pid=9723>mininet>
验证SDN交换机工作原理
Scenario #1 (SDN交换机flow table为空)
1. 首先在三个主机(h1,h2,h3)上开启Xterm (Windows用户需要安装Xming,并在putty里开启X-forwarding)
mininet> xterm h1 h2 h3
2. 用dpctl查看交换机当前的flow table信息 (由于还没有手动添加flow entry,该flow table为空)
mininet> dpctl dump-flows*** s1 --------------------------------------------NXST_FLOW reply (xid=0x4):
3. 在h1上ping h2,在h2上用tcpdump抓包,查看结果
结论: Ping失败,h2上没有收到任何ICMP echo request packet.
原因: 拓扑里没有SDN controller,我们也没有用dptcl给openflow交换机添加任何flow entry, 所以交换机不会做转发决定,并直接丢弃h1到h2的ping包。
Scenario #2 (为SDN交换机添加flow entry)
1. 用dpctl给SDN交换机添加双向的flow entry, 因为ping包除了echo request还有echo reply
mininet@mininet-vm:~$ dpctl add-flow tcp:127.0.0.1:6634 in_port=1,actions=output:2mininet@mininet-vm:~$ dpctl add-flow tcp:127.0.0.1:6634 in_port=2,actions=output:1
2. 查看SDN交换机的flow table,两条flow entry添加成功。
mininet> dpctl dump-flows*** s1 --------------------------------------------NXST_FLOW reply (xid=0x4):cookie=0x0, duration=27,213s, table=0, n_packets=5, n_bytes=378, idle_timeout=60, idle_age=7, in_port=1 actions=output:2cookie=0x0, duration=27,213s, table=0, n_packets=5, n_bytes=378, idle_timeout=60, idle_age=7, in_port=2 actions=output:1
3. 在h1上ping h2,在h2和h3上用tcpdump抓包,查看结果
结论:h1成功ping到h2,并且h3没收到任何ping包。
其他一些常用dpctl命令及功能 (拓扑同上)
1. 关闭或开启openflow交换机的端口(等于对一个端口shutdown / no shutdown)
dpctl mod-port [port num] up/down
2. 关闭交换机的端口1(下接h1),
mininet> dpctl mod-port 1 down
关闭端口1后再来h1 ping h2,结果当然fail
*** s1 ------------------------------------------------------------------------mininet> h1 ping h2PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.--- 10.0.0.2 ping statistics ---3 packets transmitted, 0 received, 100% packet loss, time 2000ms
3. 开启交换机的端口1
mininet> dpctl mod-port 1 up
ping成功
*** s1 ------------------------------------------------------------------------mininet> h1 ping -c 2 h2PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=8.37 ms64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=1.02 ms--- 10.0.0.2 ping statistics ---2 packets transmitted, 2 received, 0% packet loss, time 1002msrtt min/avg/max/mdev = 1.026/4.698/8.370/3.672 ms
4. 查看端口的统计信息,包括Tx,Rx counters, bytes以及Error counters等等
mininet> dpctl dump-ports*** s1 ------------------------------------------------------------------------OFPST_PORT reply (xid=0x2): 4 portsport 3: rx pkts=7, bytes=558, drop=0, errs=0, frame=0, over=0, crc=0 tx pkts=0, bytes=0, drop=0, errs=0, coll=0port 1: rx pkts=32, bytes=2076, drop=0, errs=0, frame=0, over=0, crc=0 tx pkts=14, bytes=1092, drop=0, errs=0, coll=0port 2: rx pkts=33, bytes=2154, drop=0, errs=0, frame=0, over=0, crc=0 tx pkts=26, bytes=1596, drop=0, errs=0, coll=0port LOCAL: rx pkts=0, bytes=0, drop=0, errs=0, frame=0, over=0, crc=0 tx pkts=0, bytes=0, drop=0, errs=0, coll=0
5. 查看端口的一层和二层信息
mininet> dpctl show*** s1 ------------------------------------------------------------------------OFPT_FEATURES_REPLY (xid=0x2): dpid:0000000000000001n_tables:254, n_buffers:256capabilities: FLOW_STATS TABLE_STATS PORT_STATS QUEUE_STATS ARP_MATCH_IPactions: OUTPUT SET_VLAN_VID SET_VLAN_PCP STRIP_VLAN SET_DL_SRC SET_DL_DST SET_NW_SRC SET_NW_DST SET_NW_TOS SET_TP_SRC SET_TP_DST ENQUEUE1(s1-eth1): addr:66:9a:a3:e0:64:8fconfig: 0state: 0current: 10GB-FD COPPERspeed: 10000 Mbps now, 0 Mbps max2(s1-eth2): addr:26:bb:36:e0:99:4econfig: 0state: 0current: 10GB-FD COPPERspeed: 10000 Mbps now, 0 Mbps max3(s1-eth3): addr:76:c9:ca:0e:92:4bconfig: 0state: 0current: 10GB-FD COPPERspeed: 10000 Mbps now, 0 Mbps maxLOCAL(s1): addr:fe:3f:bf:f6:26:42config: 0state: 0speed: 0 Mbps now, 0 Mbps maxOFPT_GET_CONFIG_REPLY (xid=0x4): frags=normal miss_send_len=0
开篇时曾提到:默认情况下,SDN交换机的flow table为空,在没有controller的情况下,可以使用dpctl来查询和管理交换机的flow table,之前的实验里我用dpctl给交换机加了两个flow,让h1可以ping通h2。两条命令如下:
dpctl add-flow in_port=1,actions=output:2dpctl add-flow in_port=2,actions=output:1
第一条命令的意思是:用dpctl对交换机添加flow,让交换机从s1-eth1这个端口接收到的所有traffic都从s1-eth2这个端口发出去。
第二条命令的意思是:用dpctl对交换机添加flow,让交换机从s1-eth2这个端口接收到的所有traffic都从s1-eth1这个端口发出去。(这里重点强调“所有traffic",原因后面解释)
添加这两条flow后,h1能够ping通h2.
mininet> h1 ping h2PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=3.80 ms64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.915 ms64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=1.50 ms^C--- 10.0.0.2 ping statistics ---3 packets transmitted, 3 received, 0% packet loss, time 2005msrtt min/avg/max/mdev = 0.915/2.073/3.805/1.248 ms
除了这种匹配所有traffic的方法外,dpctl还允许自定义更详细的traffic类型,比如ARP,IPv4, IPv6, MPLS等等,用dpctl的命令来匹配这些traffic不难,关键是要弄懂交换机是怎样识别它收到的traffci是属于哪种类型的,从而参照自己的flowtable然后对该traffic进行转发。要弄懂这点,就必须了解EtherType(以太网类型字段)这个东西,首先来回顾一下二层帧(frame)的结构:
如图,我已经把EtherType标记出来了,它就在Source MAC字段的后面。
根据IEEE 802.3定义,EtherType字段长度为2Byte,它的作用是用来指明应用于Payload这个字段里的是什么协议,它的起始值是0x0800,指代的是IPv4这个协议,常见的EtherType数值和所对应的协议如下:
0x0800 = IPv4
0x0806 = ARP
0x86DD = IPv6
0x8847 = MPLS (unicast)
0x8848 = MPLS (multicast)
在dpctl里面,我们使用dl_type来指代EtherType,下面来做个试验,具体说明一下怎么在dpctl里面根据EtherType来自定义traffic的协议类型。
首先把之前添加的两条匹配所有traffic的flow拿掉,这里用dpctl del-flows这个命令,删除后用dpctl dump-flows验证,确保交换机flow table为空。
mininet> dpctl del-flows*** s1 ------------------------------------------------------------------------mininet> dpctl dump-flows*** s1 ------------------------------------------------------------------------NXST_FLOW reply (xid=0x4):
然后用dpctl给交换机添加两条traffic类型为IPv4的flow,命令如下:
dpctl add-flow dl_type=0x0800,nw_dst=10.0.0.2,actions=output:2dpctl add-flow dl_type=0x0800,nw_dst=10.0.0.1,actions=output:1
第一条命令的意思是:用dpctl对交换机添加flow,让交换机把所有EtherType为0x0800(IPv4)并且destiation IP为10.0.0.2的traffic从s1-eth2这个端口发出去。
第二条命令的意思是:用dpctl对交换机添加flow,让交换机把所有EtherType为0x0800(IPv4)并且destiation IP为10.0.0.1的traffic从s1-eth1这个端口发出去。
添加完后验证一下交换机的flow table:
mininet> dpctl dump-flows*** s1 ------------------------------------------------------------------------NXST_FLOW reply (xid=0x4):cookie=0x0, duration=477.255s, table=0, n_packets=0, n_bytes=0, idle_age=477, ip,nw_dst=10.0.0.2 actions=output:2cookie=0x0, duration=469.45s, table=0, n_packets=0, n_bytes=0, idle_age=469, ip,nw_dst=10.0.0.1 actions=output:1
然后再次尝试h1是否能ping通h2
mininet> h1 ping -c 3 h2PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.--- 10.0.0.2 ping statistics ---3 packets transmitted, 0 received, 100% packet loss, time 2013ms
结论:Ping失败!
原因:众所周知,处在同一网段下的host,它们之间的交流是L2 forwarding,是要靠ARP来解析MAC地址的,之前我们只匹配了0x0800 (IPv4) 这个协议,并没有匹配到0x0806(ARP),这样当交换机收到h1的ARP包后,因为没有controller,flow table里面也没有相应的flow告诉它如何转发这个ARP包,交换机只能将它丢弃,从而导致h1 ping h2失败。
添加ARP的dpctl命令如下:
dpctl add-flow dl_type=0x0806,actions=NORMAL
这条命令的意思是:用dpctl对交换机添加flow,让交换机以NORMAL形式(即广播)将所有ARP包从各个端口广播出去。
老规矩,添加完flow后,马上验证flow table
mininet> dpctl dump-flows
*** s1 ------------------------------------------------------------------------NXST_FLOW reply (xid=0x4):cookie=0x0, duration=1288.291s, table=0, n_packets=22, n_bytes=2156, idle_age=703, ip,nw_dst=10.0.0.2 actions=output:2cookie=0x0, duration=1280.486s, table=0, n_packets=8, n_bytes=784, idle_age=727, ip,nw_dst=10.0.0.1 actions=output:1cookie=0x0, duration=8.772s, table=0, n_packets=0, n_bytes=0, idle_age=8, arp actions=NORMAL
再次尝试h1是否能ping通h2
mininet> h1 ping -c 3 h2PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=6.34 ms64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=0.991 ms64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=1.08 ms--- 10.0.0.2 ping statistics ---3 packets transmitted, 3 received, 0% packet loss, time 2006msrtt min/avg/max/mdev = 0.991/2.807/6.345/2.502 ms
结论:IP和ARP的flow都添加完毕后,h1 ping h2成功!
用WIRESHARK抓包,靠实战理解openflow交换机和Controller之间的工作原理。
1. 首先创建一个最简单的拓扑,1个Controller, 1个交换机,2台HOST
mininet@mininet-vm:~$ sudo mn*** Creating network*** Adding controller*** Adding hosts:h1 h2*** Adding switches:s1*** Adding links:(h1, s1) (h2, s1)*** Configuring hostsh1 h2*** Starting controller*** Starting 1 switchess1*** Starting CLI:mininet>
2. 重开一个putty窗口(记住enable X forwarding),ssh进入VM后开启wireshark
mininet@mininet-vm:~$ sudo wireshark &
3. Wireshark启动后,Interface List选lo0 (127.0.0.1),然后点Start,如下图
4.回到第一个putty窗口 (mininet>)下,用pingall命令来让h1(10.0.0.1)和h2(10.0.0.2)互相ping对方,因为这次的实验拓扑已经有了一台controller,所以无需再用dpctl来手动对交换机添加flow,h1已经可以直接ping通h2了。
mininet> pingall*** Ping: testing ping reachabilityh1 -> h2h2 -> h1*** Results: 0% dropped (2/2 received)
5. 回到Wireshark,这个时候应该capture到了很多TCP包,先不管它们,在Filter里输入of进行过滤,目的是为了抓到OFP (即Openflow Protocol)的包,如下图:
6. 点开第一个包,即Echo Request (SM)(8B)这个包,如下图:
从这个包里可以看出的信息是:
a.这个Echo Request是openflow交换机(127.0.0.1:60497) 发给Controller (127.0.0.1:6633)的,之间已经提到过,dpctl是靠TCP 6634这个端口来控制交换机的,而Controller则是用TCP 6633这个端口来控制交换机,而为了监控交换机和Controller之间的connectivity,交换机会不间断地向Controller发出Echo Request (注意这个不是ICMP的Echo Request),Controller收到Echo Request包后会向交换机返回一个Echo Reply包。
b. 点开最下面的Openflow Protocol(就不截图了),可以看到OFP的一些基本信息,比如version为0x01,Type为Echo Request (SM) (2),Length为8等等等。
7. 看完交换机和Echo Request和Echo Reply包后,接下来来看刚才用pingall命令,让h1 (10.0.0.1)和(10.0.0.2)互ping后出现的包。
如上图,在我抓的包里面:
a. 把序号为436,437,439,440的包分为一组,这一组是10.0.0.1 ping 10.0.0.2的Ping Echo Request以及Ping Echo Reply的包。
b. 把序号为441,442,443,444的包分为一组,这一组是10.0.0.2 ping 10.0.0.1的Ping Echo Request以及Ping Echo Reply的包。
8. 点开436这个包,如下图:
这里你会感到奇怪,为什么刚才在第7步里看到的该包,Source为10.0.0.1,Destination为10.0.0.2,为什么点开该包后,里面的内容却是Source127.0.0.1:60497(交换机), Destination 127.0.0.1:6633(Controller)?要回答这个问题,就需要回到第7步去看436这个包的Protocol,你会发现它已不再是我们在传统网络里理解的那个单独的ICMP包了,在SDN里,它已经变成了OFP+ICMP包。对这个OFP+ICMP包应该这样理解:当10.0.0.1 ping 10.0.0.2的时候,“无脑”的交换机(127.0.0.1:60497) 因为不知道怎么转发这个ICMP包,它唯一能做的就是用OFP包将这个ICMP包封装,将它转发给Controller (127.0.0.1:6633) 做决定,而这个由交换机重新封装后的ICMP包就叫做OFP+ICMP包。
9. 点开437这个包, 如下图:
这个包是接436这个包的,它是由Controller收到交换机发给它的OFP+ICMP后,Controller再返回给一个OFP包给交换机,所以它的Source127.0.0.1:6634,Destination127.0.0.1:60497。这里需要重点关注的是该包OpenFlow Protocol里面的内容。如图,依次点开OpenFlow Protocol>Output Actions(s)>Action,这里可以看到Output port:2 ,顾名思义,它的意思就是说:Controller现在告诉交换机,“关于这个10.0.0.1 ping 10.0.0.2的ICMP包,你把它从s1-eth2这个端口发出去”,这样h1 (10.0.0.1)的Ping echo request包就能到达h2 (10.0.0.2)了,因为h2就是直连在s1-eth2这个端口下的。
10. 后面的438-444就无需多解释了,有网络基础的都懂,它们和436还有437这两个包其实都是一个原理,只是source和destination不同。
要把SDN学精,学会写代码是必不可少的。整个Mininet的架构基本是用Python 2.0写出来的(注意不是3.0,前后两者差别很大),而自己的Python水平大概还停留在入门阶段。任重道远,下面是自己总结的Mininet中常见的一些Class, Methods, Functions还有Variables:
Topo: 用来创建拓扑,Mininet API中最基本的Class
addSwitch(): 在拓扑中创建一个switch,并返回switch name。
addHost(): 在拓扑中创建一个host,并返回host name。
addLink(): 在拓扑中创建一个双向的link,并返回link key,默认情况下link都是双向的(bidirectional)。
Mininet: 用来创建和管理一个拓扑的Main Class。
start(): 启动网络
pingAll():所有host相互ping对方,用来测试网络连接性
stop(): 关闭网络
net.hosts: 表示拓扑内所有的host
dumpNodeConnections(): 显示指定节点(Node)的connection
setLogLevel( 'info' | 'debug' | 'output' ): 设定Mininet默认的ouput level,一般用info。
举个简单的例子,用python写一个单交换机,下接N个host的拓扑的代码:
#!/usr/bin/pythonfrom mininet.topo import Topofrom mininet.net import Mininetfrom mininet.util import dumpNodeConnectionsfrom mininet.log import setLogLevel
# 用from import导入python的模块
class SingleSwitchTopo(Topo):def __init__(self, n=2, **opts)Topo.__init__(self, **opts) # 初始化拓扑以及默认的optionswitch = self.addSwitch('s1') # 添加一个名为s1的交换机for h in range(n):host = self.addHost('h%s' % (h + 1)) #添加主机self.addLink(host, switch) #添加双向连接def simpleTest():topo = SingleSwitchTopo(n=4)net = Mininet(topo) #用Main Class来创建拓扑net.start() #启动网络print "Dumping host connections"dumpNodeConnections(net.hosts) #显示拓扑内所有节点(host)的connection信息print "Testing network connectivity"net.pingAll() #所有host相互ping对方,用来测试网络连接性net.stop()if __name__ == '__main__':setLogLevel('info') # 设置 Mininet 默认输出级别为infosimpleTest()
验证:
# python test-single.py*** Creating network*** Adding controller*** Adding hosts:h1 h2 h3 h4*** Adding switches:s1*** Adding links:(h1, s1) (h2, s1) (h3, s1) (h4, s1)*** Configuring hostsh1 h2 h3 h4*** Starting controller*** Starting 1 switchess1Dumping host connectionsh1 h1-eth0:s1-eth1h2 h2-eth0:s1-eth2h3 h3-eth0:s1-eth3h4 h4-eth0:s1-eth4Testing network connectivity*** Ping: testing ping reachabilityh1 -> h2 h3 h4h2 -> h1 h3 h4h3 -> h1 h2 h4h4 -> h1 h2 h3*** Results: 0% dropped (12/12 received)
评论