写在前面
这次实验遇到了非常多问题,非常非常多,花了很多时间去解决,还是有一些小问题没有解决,但是基本上能完成实验。建议先看完全文再开始做实验。实验内容
先看一下本次实验的拓扑图:
在该环境下,假设H1 ping H4,初始的路由规则是S1-S2-S5,一秒后,路由转发规则变为S1-S3-S5,再过一秒,规则变为S1-S4-S5,然后再回到最初的转发规则S1-S2-S5。通过这个循环调度的例子动态地改变交换机的转发规则。参考
Mininet动态改变转发规则实验实验环境
虚拟机: Oracle VM VirtualBox Ubuntu16.04LTS
PS:原文中说「本实验需要两台虚拟机,分别安装POX(4G)和支持OpenFlow1.3协议的Mininet。」而我只在自己的一台机子上进行实验,也许这就是出现如此多问题的根源?实验步骤
1. ~/pox目录下新建文件lab_controller.py
# cd pox # vim lab_controller.py
脚本内容如下:
from pox.core import core import pox.openflow.libopenflow_01 as of from pox.lib.util import dpidToStr from pox.lib.addresses import IPAddr, EthAddr from pox.lib.packet.arp import arp from pox.lib.packet.ethernet import ethernet, ETHER_BROADCAST from pox.lib.packet.packet_base import packet_base from pox.lib.packet.packet_utils import * import pox.lib.packet as pkt from pox.lib.recoco import Timer import time log = core.getLogger() s1_dpid=0 s2_dpid=0 s3_dpid=0 s4_dpid=0 s5_dpid=0 s1_p1=0 s1_p4=0 s1_p5=0 s1_p6=0 s2_p1=0 s3_p1=0 s4_p1=0 pre_s1_p1=0 pre_s1_p4=0 pre_s1_p5=0 pre_s1_p6=0 pre_s2_p1=0 pre_s3_p1=0 pre_s4_p1=0 turn=0 def getTheTime(): #fuction to create a timestamp flock = time.localtime() then = "[%s-%s-%s" %(str(flock.tm_year),str(flock.tm_mon),str(flock.tm_mday)) if int(flock.tm_hour)<10: hrs = "0%s" % (str(flock.tm_hour)) else: hrs = str(flock.tm_hour) if int(flock.tm_min)<10: mins = str(flock.tm_min) secs = "0%s" % (str(flock.tm_sec)) else: secs = str(flock.tm_sec) then +="]%s.%s.%s" % (hrs,mins,secs) return then def _timer_func (): global s1_dpid, s2_dpid, s3_dpid, s4_dpid, s5_dpid,turn #print getTheTime(), "sent the port stats request to s1_dpid" if turn==0: msg = of.ofp_flow_mod() msg.command=of.OFPFC_MODIFY_STRICT msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.4" msg.actions.append(of.ofp_action_output(port = 5)) core.openflow.getConnection(s1_dpid).send(msg) turn=1 return if turn==1: msg = of.ofp_flow_mod() msg.command=of.OFPFC_MODIFY_STRICT msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.4" msg.actions.append(of.ofp_action_output(port = 6)) core.openflow.getConnection(s1_dpid).send(msg) turn=2 return if turn==2: msg = of.ofp_flow_mod() msg.command=of.OFPFC_MODIFY_STRICT msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.4" msg.actions.append(of.ofp_action_output(port = 4)) turn=0 return def _handle_portstats_received (event): global s1_p1,s1_p4, s1_p5, s1_p6, s2_p1, s3_p1, s4_p1 global pre_s1_p1,pre_s1_p4, pre_s1_p5, pre_s1_p6, pre_s2_p1, pre_s3_p1, pre_s4_p1 if event.connection.dpid==s1_dpid: for f in event.stats: if int(f.port_no)<65534: if f.port_no==1: pre_s1_p1=s1_p1 s1_p1=f.rx_packets if f.port_no==4: pre_s1_p4=s1_p4 s1_p4=f.tx_packets #s1_p4=f.tx_bytes if f.port_no==5: pre_s1_p5=s1_p5 s1_p5=f.tx_packets if f.port_no==6: pre_s1_p6=s1_p6 s1_p6=f.tx_packets for f in event.stats: //非常非常非常坑,原文这一行行首多了一个空格,这里已经是修改好的 if int(f.port_no)<65534: if f.port_no==1: pre_s2_p1=s2_p1 s2_p1=f.rx_packets #s2_p1=f.rx_bytes if event.connection.dpid==s3_dpid: for f in event.stats: if int(f.port_no)<65534: if f.port_no==1: pre_s3_p1=s3_p1 s3_p1=f.rx_packets if event.connection.dpid==s4_dpid: for f in event.stats: if int(f.port_no)<65534: if f.port_no==1: pre_s4_p1=s4_p1 s4_p1=f.rx_packets def _handle_ConnectionUp (event): global s1_dpid, s2_dpid, s3_dpid, s4_dpid, s5_dpid print "ConnectionUp: ",dpidToStr(event.connection.dpid) #remember the connection dpid for switch for m in event.connection.features.ports: if m.name == "s1-eth1": s1_dpid = event.connection.dpid print "s1_dpid=", s1_dpid elif m.name == "s2-eth1": s2_dpid = event.connection.dpid print "s2_dpid=", s2_dpid elif m.name == "s3-eth1": s3_dpid = event.connection.dpid elif m.name == "s4-eth1": s4_dpid = event.connection.dpid print "s4_dpid=", s4_dpid elif m.name == "s5-eth1": s5_dpid = event.connection.dpid print "s5_dpid=", s5_dpid if s1_dpid<>0 and s2_dpid<>0 and s3_dpid<>0 and s4_dpid<>0: Timer(1, _timer_func, recurring=True) def _handle_PacketIn(event): global s1_dpid, s2_dpid, s3_dpid, s4_dpid, s5_dpid packet=event.parsed if event.connection.dpid==s1_dpid: a=packet.find('arp') if a and a.protodst=="10.0.0.4": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=4)) event.connection.send(msg) if a and a.protodst=="10.0.0.5": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=5)) event.connection.send(msg) if a and a.protodst=="10.0.0.6": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=6)) event.connection.send(msg) if a and a.protodst=="10.0.0.1": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=1)) event.connection.send(msg) if a and a.protodst=="10.0.0.2": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=2)) event.connection.send(msg) if a and a.protodst=="10.0.0.3": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=3)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.1" msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.2" msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.3" msg.actions.append(of.ofp_action_output(port = 3)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 1 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.4" msg.actions.append(of.ofp_action_output(port = 4)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.5" msg.actions.append(of.ofp_action_output(port = 5)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.6" msg.actions.append(of.ofp_action_output(port = 6)) event.connection.send(msg) elif event.connection.dpid==s2_dpid: msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 1 msg.match.dl_type=0x0806 msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 1 msg.match.dl_type=0x0800 msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 2 msg.match.dl_type=0x0806 msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 2 msg.match.dl_type=0x0800 msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) elif event.connection.dpid==s3_dpid: msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 1 msg.match.dl_type=0x0806 msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 1 msg.match.dl_type=0x0800 msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 2 msg.match.dl_type=0x0806 msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 2 msg.match.dl_type=0x0800 msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) elif event.connection.dpid==s4_dpid: msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 1 msg.match.dl_type=0x0806 msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 1 msg.match.dl_type=0x0800 msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 2 msg.match.dl_type=0x0806 msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =10 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.in_port = 2 msg.match.dl_type=0x0800 msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) elif event.connection.dpid==s5_dpid: a=packet.find('arp') if a and a.protodst=="10.0.0.4": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=4)) event.connection.send(msg) if a and a.protodst=="10.0.0.5": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=5)) event.connection.send(msg) if a and a.protodst=="10.0.0.6": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=6)) event.connection.send(msg) if a and a.protodst=="10.0.0.1": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=1)) event.connection.send(msg) if a and a.protodst=="10.0.0.2": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=2)) event.connection.send(msg) if a and a.protodst=="10.0.0.3": msg = of.ofp_packet_out(data=event.ofp) msg.actions.append(of.ofp_action_output(port=3)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.1" msg.actions.append(of.ofp_action_output(port = 1)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.2" msg.actions.append(of.ofp_action_output(port = 2)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.3" msg.actions.append(of.ofp_action_output(port = 3)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.4" msg.actions.append(of.ofp_action_output(port = 4)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.5" msg.actions.append(of.ofp_action_output(port = 5)) event.connection.send(msg) msg = of.ofp_flow_mod() msg.priority =100 msg.idle_timeout = 0 msg.hard_timeout = 0 msg.match.dl_type = 0x0800 msg.match.nw_dst = "10.0.0.6" msg.actions.append(of.ofp_action_output(port = 6)) event.connection.send(msg) def launch (): global start_time core.openflow.addListenerByName("PortStatsReceived",_handle_portstats_received) core.openflow.addListenerByName("ConnectionUp", _handle_ConnectionUp) core.openflow.addListenerByName("PacketIn",_handle_PacketIn)
这段代码原文中是有问题的,如果执行会出现下面的错误:
2. 在~/mininet中创建文件mym.py
# cd mininet # vim mym.py
脚本内容如下:
#!/usr/bin/python from mininet.topo import Topo from mininet.net import Mininet from mininet.node import CPULimitedHost from mininet.link import TCLink from mininet.util import dumpNodeConnections from mininet.log import setLogLevel from mininet.node import Controller from mininet.cli import CLI from functools import partial from mininet.node import RemoteController import os class MyTopo(Topo): "Single switch connected to n hosts." def __init__(self): Topo.__init__(self) s1=self.addSwitch('s1') s2=self.addSwitch('s2') s3=self.addSwitch('s3') s4=self.addSwitch('s4') s5=self.addSwitch('s5') h1=self.addHost('h1') h2=self.addHost('h2') h3=self.addHost('h3') h4=self.addHost('h4') h5=self.addHost('h5') h6=self.addHost('h6') self.addLink(h1, s1, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(h2, s1, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(h3, s1, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s1, s2, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s1, s3, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s1, s4, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s2, s5, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s3, s5, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s4, s5, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s5, h4, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s5, h5, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) self.addLink(s5, h6, bw=1, delay='10ms', loss=0, max_queue_size=1000, use_htb=True) def perfTest(): "Create network and run simple performance test" topo = MyTopo() net = Mininet(topo=topo, host=CPULimitedHost, link=TCLink, controller=partial(RemoteController, ip='10.0.0.13', port=6633)) //这里的 ip 改为本地 IP 地址,例如我的是 10.0.2.15 否则会连接不上控制器 net.start() print "Dumping host connections" dumpNodeConnections(net.hosts) h1,h2,h3=net.get('h1','h2','h3') h4,h5,h6=net.get('h4','h5','h6') h1.setMAC("0:0:0:0:0:1") h2.setMAC("0:0:0:0:0:2") h3.setMAC("0:0:0:0:0:3") h4.setMAC("0:0:0:0:0:4") h5.setMAC("0:0:0:0:0:5") h6.setMAC("0:0:0:0:0:6") CLI(net) net.stop() if __name__ == '__main__': setLogLevel('info') perfTest()
这里又是一个坑,参照原文执行会得到以下错误:
因为做实验的时候是在同一台机子上进行,POX 控制器也是部署在本机上,因此在创建拓扑结构时要把控制器的 IP 地址改为本地的 IP 地址
查看 IP 地址:
ifconfig
3. 运行脚本
首先运行 lab_controller.py
# cd pox # ./pox.py lab_controller
然后运行 mym.py
# cd mininet # python mym.py
这时观察 pox 控制台,发现出现了一堆 warning 先不理...
在 mininet 中执行 h1 ping -i 0.1 h4,即每秒从 h1 传送 10 个包到 h4
原文中提到「查看虚POX打印出来的结果显示先从 s1_p4 (switch 1, port 4) 发出 10 个包,然后是从 s1_p5 ,接着从 s1_p6 ,
如此循环调度」但是实际过程中在 POX 控制台并没有看到这些信息,重复尝试几次之后,依然看不见。后来在网上看到 POX 是有图形化界面的,也就是 poxdesk,之后利用 pox 的 Web 界面再次进行实验。
poxdesk 安装:
# cd ./pox/ext # git clone https://github.com/MurphyMc/poxdesk # cd poxdesk # wget http://downloads.sourceforge.net/qooxdoo/qooxdoo-2.0.2-sdk.zip # unzip qooxdoo-2.0.2-sdk.zip # mv qooxdoo-2.0.2-sdk qx # cd poxdesk # ./generate.py # cd ../../..
参考:SDN常用控制器安装部署之POX篇
到这里 poxdesk 就安装好了。重做实验的流程都不变,只是在执行 pox 脚本时代码改为
./pox.py lab_controller web messenger messenger.log_service messenger.ajax_transport openflow.of_service poxdesk //通用的命令为:./pox.py 脚本名 web messenger messenger.log_service messenger.ajax_transport openflow.of_service poxdesk
之后再运行 mininet 脚本
然后在浏览器中打开 http://pox-ip:8000/poxdesk 来访问界面,其中pox-ip是本机 IP 地址,例如我的是10.0.2.15
依次点击左下角pox->TableViewer->左上角Switch->第一个交换机00_00_00_00_00_01 观察目的主机 h4 对应的那一行(也就是 nw_dst 为 10.0.0.4/32 的那一行)可以发现 OUTPUT一直在5、6两个端口之间变动
这里还是有一个问题,实验开头说路由规则会在三种情况之间变化,但是这样看来只有两种情况,不知道是什么原因,个人推测应该问题应该出在 POX 脚本上
总结
1. 实验过程中遇到的问题
- 因为之前的实验在关闭 mininet 之后就可以了,开始实验前我都没有执行
「sudo mn -c」
然而这次实验在运行 mininet 脚本之后,想要再次进行实验必须先输入 「sudo mn -c」,否则会报错 - 在运行 pox 时会出现这样的错误 「error: [Errno 98] Address already in ues」这是因为在上一次实验结束的时候没有关闭 pox 控制器。解决方法:重启...
- 在 h1 ping h4 一段时间后会出现错误,具体是为什么还没有弄清
其他的问题在实验步骤中都有提到了
2. 收获
- 熟悉Mininet自定义拓扑脚本的编写
- 熟悉编写POX脚本动态改变转发规则
这是 Mininet 系列实验做到现在遇到最多问题的一次,主要是原文中代码的错误本身就比较多。解决问题的过程远比实验本身重要的多,收获也更多。
来源:https://www.cnblogs.com/multhree/p/9389430.html