Pyretic+Mininet: Find a path width maximum capacity with Dijkstra's Algorithm

[Topology]

 

 

[Mininet: mytopo2.py]

#!/usr/bin/python

 

from mininet.net import Mininet

from mininet.node import Controller, RemoteController, OVSKernelSwitch, OVSLegacyKernelSwitch, UserSwitch

from mininet.cli import CLI

from mininet.log import setLogLevel

from mininet.link import Link, TCLink, Intf

 

def topology():

    "Create a network."

    net = Mininet( controller=RemoteController, link=TCLink, switch=OVSKernelSwitch )

    print "*** Creating nodes"

    h1 = net.addHost( 'h1')

    h2 = net.addHost( 'h2')

    h3 = net.addHost( 'h3')

    s1 = net.addSwitch('s1')

    s2 = net.addSwitch('s2')

    s3 = net.addSwitch('s3' )

    c7 = net.addController( 'c7', controller=RemoteController, ip='127.0.0.1', port=6633 )

 

    print "*** Creating links"

    linkBW = {'bw':1}

    net.addLink(s1, h1, cls=TCLink, **linkBW)

    net.addLink(s1, s2, cls=TCLink, **linkBW)

    net.addLink(s1, s3, cls=TCLink, **linkBW)

    net.addLink(s3, s2, cls=TCLink, **linkBW)

    net.addLink(s2, h2, cls=TCLink, **linkBW)

    net.addLink(s2, h3, cls=TCLink, **linkBW)

 

    print "*** Starting network"

    net.build()

    c7.start()

    s1.start( [c7] )

    s2.start( [c7] )

    s3.start( [c7] )

 

    print "*** Running CLI"

    CLI( net )

 

    print "*** Stopping network"

    net.stop()

 

if __name__ == '__main__':

    setLogLevel( 'info' )

    topology()

 

 

[Pyretic Controller: pri_route.py]

from pyretic.lib.corelib import*

from pyretic.lib.std import *

from multiprocessing import Lock

from pyretic.lib.query import *

from collections import defaultdict

 

from datetime import datetime

import time

import threading

 

#switches

switches = []

 

#myhost[srcmac]->(switch, port)

myhost={}

 

#adjacency map [sw1][sw2]->port from sw1 to sw2

adjacency=defaultdict(lambda:defaultdict(lambda:None))

 

#link bandwidth consumption [sw1][sw2]->bandwidth consumed

link_bw=defaultdict(lambda:defaultdict(lambda:None))

byte=defaultdict(lambda:defaultdict(lambda:None))

clock=defaultdict(lambda:defaultdict(lambda:None))

 

ip1 = IPAddr('10.0.0.1')

ip2 = IPAddr('10.0.0.2')

 

def max_abw(abw, Q):

  max = float('-Inf')

  node = 0

  for v in Q:

    if abw[v] > max:

      max = abw[v]

      node = v

  return node

 

def get_path2 (src,dst,first_port,final_port):

  print "Dijkstra's widest path algorithm"

  print "src=",src," dst=",dst, " first_port=", first_port, " final_port=", final_port

  #available bandwidth

  abw = {}

  previous = {}

 

  for dpid in switches:

    abw[dpid] = float('-Inf')

    previous[dpid] = None

 

  abw[src]=float('Inf')

  Q=set(switches)

 

  print time.time()

  while len(Q)>0:

    u = max_abw(abw, Q)

    #print "Q=",Q , "u=", u

    Q.remove(u)

 

    for p in switches:

      if adjacency[u][p]!=None:

        #available bandwidth between u and p, assume that the bandwidth of each link is 1Mbps

        link_abw = 1024000.0 - link_bw[u][p]

        #alt=max(abw[p], min(width[u], abw_between(u,p)))

        if abw[u] < link_abw:

          tmp = abw[u]

        else:

          tmp = link_abw

        if abw[p] > tmp:

          alt = abw[p]

        else:

          alt = tmp

 

        if alt > abw[p]:

          abw[p] = alt

          previous[p] = u

 

  r=[]

  p=dst

  r.append(p)

  q=previous[p]

  while q is not None:

    if q == src:

      r.append(q)

      break

    p=q

    r.append(p)

    q=previous[p]

 

  r.reverse()

  if src==dst:

    path=[src]

  else:

    path=r

  print "Selected Width Path:", path

 

  # Now add the ports

  r = []

  in_port = first_port

  for s1,s2 in zip(path[:-1],path[1:]):

    out_port = adjacency[s1][s2]

    r.append((s1,in_port,out_port))

    in_port = adjacency[s2][s1]

  r.append((dst,in_port,final_port))

  return r 

 

def minimum_distance(distance, Q):

  min = float('Inf')

  node = 0

  for v in Q:

    if distance[v] < min:

      min = distance[v]

      node = v

  return node

 

def get_path (src,dst,first_port,final_port):

  #Dijkstra's algorithm

  print "src=",src," dst=",dst, " first_port=", first_port, " final_port=", final_port

  distance = {}

  previous = {}

 

  for dpid in switches:

    distance[dpid] = 9999

    previous[dpid] = None

 

  distance[src]=0

  Q=set(switches)

   

  while len(Q)>0:

    u = minimum_distance(distance, Q)

    Q.remove(u)

   

    for p in switches:

      if adjacency[u][p]!=None:

        w = 1

        if distance[u] + w < distance[p]:

          distance[p] = distance[u] + w

          previous[p] = u

 

  r=[]

  p=dst

  r.append(p)

  q=previous[p]

  while q is not None:

    if q == src:

      r.append(q)

      break

    p=q

    r.append(p)

    q=previous[p]

 

  r.reverse()

  if src==dst:

    path=[src]

  else:

    path=r

  print "Selected Shortest Path:", path

 

  # Now add the ports

  r = []

  in_port = first_port

  for s1,s2 in zip(path[:-1],path[1:]):

    out_port = adjacency[s1][s2]

    r.append((s1,in_port,out_port))

    in_port = adjacency[s2][s1]

  r.append((dst,in_port,final_port))

  return r 

 

class find_route(DynamicPolicy):

  def __init__(self):

    super(find_route,self).__init__()

    self.flood = flood()

    self.set_initial_state()

 

  def set_initial_state(self):

    self.query = packets(1,['srcmac','dstmac', 'srcip', 'dstip'])

    self.query.register_callback(self.myroute)

    self.forward = self.flood

    self.update_policy()

 

  def set_network(self,network):

    self.set_initial_state()

 

  def update_policy(self):

    self.policy = self.forward + self.query

 

  def myroute(self,pkt):

    #print pkt['srcmac'], pkt['dstmac'], pkt['srcip'], pkt['dstip']

    if (pkt['srcmac'] not in myhost.keys()) or (pkt['dstmac'] not in myhost.keys()):

      return

    #print myhost[pkt['srcmac']][0], myhost[pkt['dstmac']][0]

    #if match(ethtype=IP_TYPE):

    #  print "ipv4 packet"

    if pkt['srcip']==ip1 and pkt['dstip']==ip2:

      p = get_path2(myhost[pkt['srcmac']][0], myhost[pkt['dstmac']][0],myhost[pkt['srcmac']][1], myhost[pkt['dstmac']][1])

    else:

      p = get_path(myhost[pkt['srcmac']][0], myhost[pkt['dstmac']][0],myhost[pkt['srcmac']][1], myhost[pkt['dstmac']][1])

    print p

 

    r = parallel([(match(switch=a,srcip=pkt['srcip'],dstip=pkt['dstip']) >> fwd(c)) for a,b,c in p])

    #print r

   

    self.forward = if_(match(srcip=pkt['srcip'],dstip=pkt['dstip']),r,self.forward)

    self.update_policy()

 

 

def find_host():

   q = packets(1,['srcmac','switch'])

   q.register_callback(mymac_learner)

   return q

 

def mymac_learner(pkt):

   print pkt['srcmac'], pkt['dstmac'], pkt['switch'], pkt['inport']

   #if match(ethtype=ARP_TYPE):

   # print "arp packet"

  

   if pkt['srcmac'] not in myhost.keys():

      myhost[pkt['srcmac']]=( pkt['switch'], pkt['inport'])

  

class find_switch(DynamicPolicy):

    def __init__(self):

        self.last_topology = None

        self.lock = Lock()

        super(find_switch,self).__init__()

 

    def set_network(self, network):

        with self.lock:

            for x in network.switch_list():

              switches.append(x)

            for (s1,s2,data) in network.topology.edges(data=True):

              adjacency[s1][s2]=data[s1]

              adjacency[s2][s1]=data[s2]

              link_bw[s1][s2]=0

              link_bw[s2][s1]=0

            self.last_topology = network.topology

          

def arp_and_ip():

  return if_(match(ethtype=ARP_TYPE), flood(), find_route())

 

def byte_count_printer(n):

  if len(n)!=0:

    #print time.time()

    for i, j in n.items():

      #print "switch:", str(i).split(" ")[2][0], "inport:", str(i).split(" ")[4][0], "bytes:", j

      for p in switches:

        for q in switches:

          if adjacency[p][q]!=None and str(q)==str(i).split(" ")[2][0] and str(adjacency[q][p])==str(i).split(" ")[4][0]:

            if byte[p][q]>0:  

              link_bw[p][q]=(j - byte[p][q]) * 8.0 / (time.time()-clock[p][q])

              #print "link[",p,"][",q,"]=",link_bw[p][q], "bps"

            byte[p][q]=j

            clock[p][q]=time.time()

     

def byte_counts():

  q = count_bytes(1,['switch','inport'])

  q.register_callback(byte_count_printer)

  return q

         

def main():

  return ( find_switch() + find_host() + arp_and_ip() + byte_counts())

 

 

[Execution]

 

Initial flow from h1 to h3 first. (From the following figure, we can see the path for flow h1-h3 is via switch 1 and switch 2.

 

Then start the flow from h1 to h2. (From the following figure, we can see the path for flow for h1-h2 is via switch 1, 3, and 2. But the flow from h2-h1 is via switch 2 and 1.)

 

[Reference]

1. http://stackoverflow.com/questions/18552964/finding-path-with-maximum-minimum-capacity-in-graph

 

Dr. Chih-Heng Ke (smallko@gmail.com)

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.