1.实验目的

熟悉Mininet自定义拓扑脚本的编写;

熟悉编写POX脚本动态改变转发规则。

2.实验原理

在SDN环境中,控制器可以通过对交换机下发流表操作来控制交换机的转发行为。在本实验中,基于Mininet脚本,编写POX脚本,动态改变交换机的转发规则。

3.实验任务

本次实验的拓扑图:

在该环境下,假设H1 ping H4,初始的路由规则是S1-S2-S5,一秒后,路由转发规则变为S1-S3-S5,再过一秒,规则变为S1-S4-S5,然后再回到最初的转发规则S1-S2-S5。通过这个循环调度的例子动态地改变交换机的转发规则。

4.实验步骤

4.1 搭建环境

本实验需要两台虚拟机,分别安装POX(4G)和支持OpenFlow1.3协议的Mininet。

4.2 实验操作

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()

4.3 运行脚本

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,如此循环调度。

5.实验结论

基于Mininet,通过编写POX的脚本内容,可以实现动态改变交换机的转发规则的功能。