熟悉Mininet自定义拓扑脚本的编写;
熟悉编写POX脚本动态改变转发规则。
在SDN环境中,控制器可以通过对交换机下发流表操作来控制交换机的转发行为。在本实验中,基于Mininet脚本,编写POX脚本,动态改变交换机的转发规则。
本次实验的拓扑图:
在该环境下,假设H1 ping H4,初始的路由规则是S1-S2-S5,一秒后,路由转发规则变为S1-S3-S5,再过一秒,规则变为S1-S4-S5,然后再回到最初的转发规则S1-S2-S5。通过这个循环调度的例子动态地改变交换机的转发规则。
本实验需要两台虚拟机,分别安装POX(4G)和支持OpenFlow1.3协议的Mininet。
1在装有POX的虚拟机里,/root/pox目录下新建文件lab_controller.py。
2编辑文件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)
3在Mininet中创建文件mymininet.py。
4编辑文件mymininet.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)) 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()
5在POX中,/root/pox目录下运行脚本lab_controller.py。
#./pox.py lab_controller
6在Mininet下运行脚本mymininet.py。
#chmod +x mymininet.py #./mymininet.py
7查看POX界面,打印出以下内容,及在web中显示的topo图:
8在Mininet中执行h1 ping -i 0.1 h4,每秒从h1传送10个包到h4。
9查看虚POX打印出来的结果显示先从s1_p4 (switch 1, port 4)发出10个包,然后是从s1_p5,接着从s1_p6,如此循环调度。
基于Mininet,通过编写POX的脚本内容,可以实现动态改变交换机的转发规则的功能。