工具:Mininet
拓扑:
一开始设想的拓扑是这样的
实验目的:
实现将fowarding路线从h1-s1-s2-h2(default)改成h1-s1-s3-h2,反过来也一样
使用mininet提供的接口写的python脚本来建立这个拓扑,这一步很简单
from mininet.topo import Topo
class MyTopo(Topo):
def build(self):
#Add hosts and switches
leftHost = self.addHost('h1')
rightHost = self.addHost('h2')
leftSwitch = self.addSwitch('s1')
rightSwitch1 = self.addSwitch('s2')
rightSwitch2 = self.addSwitch('s3')
#Add links
self.addLink(leftHost, leftSwitch)
self.addLink(leftSwitch, rightSwitch1)
self.addLink(leftSwitch, rightSwitch2)
self.addLink(rightSwitch1, rightHost)
self.addLink(rightSwitch2, rightHost)
topos = {'mytopo':(lambda:MyTopo() ) }
sudo mn --custom FILE_PATH --topo mytopo --mac
创建topo时可选的几个实用选项,这些在mininet walkthrough里都可以找到:
--custom: 按后面FILE_PATH对应的文件里给的脚本自定义拓扑
--topo mytopo:指定使用脚本文件中的哪个topo
--mac:这个对于简化实验来说很关键,在这个实验里它把H1的eth0和H2的eth0的mac地址分别设置为了00:00:00:00:00:01和00:00:00:00:00:02(注意,h2的eth1并没有被设置为00:00:00:00:00:02或00:00:00:00:00:03)
--test pingall:可以让所有host节点互ping,看网络是不是通的
此时,h1 ping h2,是可以ping通的,但是走的path是h1-s1-s2-h2,
下面我打算把
建立完成之后使用open flow提供的ovs-vsctl手动写command line
###icmp
s1:
1.
#把h1的request消息发给h2:
sudo ovs-ofctl add-flow s1 priority=65535,icmp,in_port="s1-eth1",vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,nw_src=10.0.0.1,nw_dst=10.0.0.2,nw_tos=0,icmp_type=8,icmp_code=0,actions=output:"s1-eth3"
2.
#把h2的reply消息发给h1:
sudo ovs-ofctl add-flow s1 priority=65535,icmp,in_port="s1-eth3",vlan_tci=0x0000,dl_src=00:00:00:00:00:02,dl_dst=00:00:00:00:00:01,nw_src=10.0.0.2,nw_dst=10.0.0.1,nw_tos=0,icmp_type=0,icmp_code=0,actions=output:"s1-eth1"
###arp
3.
#把h1的arp request 发给h2
sudo ovs-ofctl add-flow s1 priority=65535,arp,in_port="s1-eth1",vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=1,action=output:"s1-eth3"
4.
#把h1的arp reply 发给h2
sudo ovs-ofctl add-flow s1 priority=65535,arp,in_port="s1-eth1",vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=2,actions=output:"s1-eth3"
5.
#把h2的arp request发给h1
sudo ovs-ofctl add-flow s1 priority=65535,arp,in_port="s1-eth3",vlan_tci=0x0000,dl_src=00:00:00:00:00:02,dl_dst=00:00:00:00:00:01,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=1,actions=output:"s1-eth1"
6.
#把h2的arp reply发给h1
sudo ovs-ofctl add-flow s1 priority=65535,arp,in_port="s1-eth3",vlan_tci=0x0000,dl_src=00:00:00:00:00:02,dl_dst=00:00:00:00:00:01,arp_spa=10.0.0.2,arp_tpa=10.0.0.1,arp_op=2,actions=output:"s1-eth1"
s2:让它不接受广播
sudo ovs-ofctl add-flow s2 priority=65535,arp,in_port="s2-eth1",vlan_tci=0x0000,dl_src=00:00:00:00:00:01,dl_dst=00:00:00:00:00:02,arp_spa=10.0.0.1,arp_tpa=10.0.0.2,arp_op=1,actions=DROP
在这一步里我做了很多花里胡哨的设置,然而h1 ping h2不通了
感觉自己的逻辑没有问题,使用wireshark抓包之后发现出现了一个让人费解的问题:
h1发request确实是按照规定的h1-s1-s3-h2路线走的,可是h2收到包之后从来不发reply
h2(10.0.0.2)表现得像不认识这个包
问题的特点是:
(1)
沿h1-s1-s2-h2转发,既有request又有reply
(2)
沿h1-s1-s3-h2转发,request正常,h2不进行reply,h2不报错,只是“不认识”这个icmp reques
那么问题出在哪里呢?
(1)
h1-s1-s3-h2的路线上switch的转发是正常、open flow 在链路层的转发中不涉及改变包的目的mac地址和源mac地址(在转发过程中一直是h1的mac地址、h2的mac地址),只是重复从一个port送到另一个port的简单动作-->暂且认为不是switch上出现的问题
(2)
mininet很多人都在用、没有搜到mininet在这方面有重大bug、这是一个很简单的forwarding path实验-->暂且认为不是虚拟机的问题。
(3)
学了一下icmp协议,没有发现什么和这个问题看起来有联系的问题 -->坑应该不在icmp上
(4)
看了一下网上的类似问题,那个是checksum有问题,这边看wireshark好像并没有这方面的问题-->request一直传到h2都是正常被转发的
(5)
怀疑了一下可能是spanning Tree的问题,(或许根据spanning Tree, request包只能发给h2的eth0端口)--->师兄告诉我因为这个h2有两个网卡接入网络,所以不存在spanning Tree冲突问题
看到这里我明白了,icmp没有reply的原因是目的mac地址是00:00:00:00:00:02,这个是h2-eth0的mac,所以当包被发到h2-eth1的时候,h2不对这个icmp request做响应
到这里,我想到了两个方法解决这个问题
(1)
在s1转发流表中的action中加入mod_dl_dst="h2-eth1的mac地址",这个还没尝试,后面更新
(2)
改拓扑,在s2-h2和s3-h2中加一个s4,拓扑被改成这样:
这时候出了一个问题,h1 ping h2不通了,我马上去检查了topo文件是不是有错,盯着这短短的几行代码,看不出任何问题,我重启了网络加入了参数--test pingall,发现真的ping不通,
不写--test pingall,仅仅是建立mininet网络,打开wireshark发现h1和h2一直在互相广播icmpv6和mdns消息,同时所有设备的所有端口都充满了一样的icmpv6和mdns消息,而在正常情况下,如果不进行任何操作,仅仅打开网络,所有设备的所有端口应该是几乎收不到任何消息的。现在的情况看起来,所有的节点一直在保持商讨某种东西,而没有能达成一个一致的结果。
为什么会这样呢,为什么不加s4的时候(上面的topo),就是正常的,加入s4之后就会发生这样的问题呢?
解释是,新的拓扑里有环路,在没写flow table时,mininet如果存在环路,则无法确定一个各个节点之间转发的路径。
而上面的3switch网络看似是有环路的,其实因为使用了h2的两个端口,是一个树形结构,因此不存在成环的问题。
所以接下来我们对switches的流表进行设置:
#topo:
s2
/ \
h1 - s1 s4 - h2
\ /
s3
#开启wireshark方法:xterm h1/xterm s1 打开host的shell或 switch的shell
#运行wireshark -n
#(1)所有消息都从s3转发:
sudo ovs-ofctl add-flow s1 in_port='s1-eth1',actions=output:'s1-eth3'
sudo ovs-ofctl add-flow s3 in_port='s3-eth1',actions=output:'s3-eth2'
sudo ovs-ofctl add-flow s4 in_port='s4-eth2',actions=output:'s4-eth3'
sudo ovs-ofctl add-flow s2 in_port='s2-eth1',actions=DROP
sudo ovs-ofctl add-flow s1 in_port='s1-eth2',actions=output:'s1-eth1'
sudo ovs-ofctl add-flow s3 in_port='s3-eth2',actions=output:'s3-eth1'
sudo ovs-ofctl add-flow s4 in_port='s4-eth3',actions=output:'s4-eth1'
sudo ovs-ofctl add-flow s2 in_port='s2-eth2',actions=DROP
#打开wireshark可以看到icmp request和icmp reply都是从s3转发的
#(2)h1-h2的消息从s3转发,h2-h1的消息从s2转发:
sudo ovs-ofctl add-flow s1 in_port='s1-eth1',actions=output:'s1-eth3'
sudo ovs-ofctl add-flow s3 in_port='s3-eth1',actions=output:'s3-eth2'
sudo ovs-ofctl add-flow s4 in_port='s4-eth2',actions=output:'s4-eth3'
sudo ovs-ofctl add-flow s2 in_port='s2-eth1',actions=DROP
sudo ovs-ofctl add-flow s1 in_port='s1-eth2',actions=output:'s1-eth1'
sudo ovs-ofctl add-flow s2 in_port='s2-eth2',actions=output:'s2-eth1'
sudo ovs-ofctl add-flow s4 in_port='s4-eth3',actions=output:'s4-eth1'
sudo ovs-ofctl add-flow s3 in_port='s3-eth2',actions=DROP
#打开wireshark可以看到:request的路线是h1-s1-s3-s4-h2,reply的路线是h2-s4-s2-s1-h1
到此,一个简单的通过ofctl命令添加流表的方式控制转发的实验就已经完成了,后面做完再更新通过ryu controller文件下发流表控制转发的实验。