Pyretic + Mininet: Finding all shortest paths

 

[Topology]

 

[Mininet Script: multiple_path.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')

    s1 = net.addSwitch('s1')

    s2 = net.addSwitch('s2')

    s3 = net.addSwitch('s3' )

    s4 = net.addSwitch('s4' )

    s5 = net.addSwitch('s5' )

    s6 = net.addSwitch('s6' )

    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(s2, s3, cls=TCLink, **linkBW)

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

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

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

    net.addLink(s5, s6, cls=TCLink, **linkBW)

    net.addLink(s6, s4, cls=TCLink, **linkBW)

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

 

    print "*** Starting network"

    net.build()

    c7.start()

    s1.start( [c7] )

    s2.start( [c7] )

    s3.start( [c7] )

    s4.start( [c7] )

    s5.start( [c7] )

    s6.start( [c7] )

 

    print "*** Running CLI"

    CLI( net )

 

    print "*** Stopping network"

    net.stop()

 

if __name__ == '__main__':

    setLogLevel( 'info' )

    topology()

 

 

[pyretic: asp.py]

from pyretic.lib.corelib import*

from pyretic.lib.std import *

from multiprocessing import Lock

from pyretic.lib.query import *

from collections import defaultdict

 

import random

 

#switches

switches = []

 

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

myhost={}

 

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

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

 

ip1 = IPAddr('10.0.0.1')

ip2 = IPAddr('10.0.0.2')

tmp_asp=set()

#list: save all the shortest paths for the path from ip1 to ip2

list_asp=[]

 

def get_dist(src):

  distance = {}

  previous = {}

 

  for dpid in switches:

    distance[dpid] = float('Inf')

    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

  return distance

 

def find_one_shortest_path(new_adjacency, now, dst, path_info):

  if now == dst:

    #print path_info

    tmp_asp.add(tuple(path_info))

    return

  for p in switches:

    if new_adjacency[now][p]!=None:

      path_info.append(p)

      find_one_shortest_path(new_adjacency, p, dst, path_info)

      path_info.pop(-1) 

 

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

  print "all_shortest_paths() is called"

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

  disS={} #shortest path from src

  disT={}

  disS = get_dist(src)

  disT = get_dist(dst)

  #print "disS=", disS

  #print "disT=", disT

 

  new_adjacency=defaultdict(lambda:defaultdict(lambda:None))

  for p in switches:

    for q in switches:

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

        if (disS[p] + 1 + disT[q]) == disS[dst]:

          new_adjacency[p][q] = adjacency[p][q]

 

  #print new_adjacency

  find_one_shortest_path(new_adjacency, src, dst, [])

  tuple_asp=tuple(tmp_asp)

  #print "tuple_asp=", tuple_asp

 

  for i in range(len(tuple_asp)):

    tmp = [src] + list(tuple_asp[i])

    print tmp

    # Now add the ports

    r = []

    in_port = first_port

    for s1,s2 in zip(tmp[:-1],tmp[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))

    #print r

    list_asp.append(r)

  #print "list_asp=", list_asp

  

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

  print "Dijkstra's algorithm"

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

  distance = {}

  previous = {}

 

  for dpid in switches:

    distance[dpid] = float('Inf')

    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

 

  # 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:

      all_shortest_paths(myhost[pkt['srcmac']][0], myhost[pkt['dstmac']][0],myhost[pkt['srcmac']][1], myhost[pkt['dstmac']][1])

      p1=random.choice(list_asp)

    else:

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

   

    print p1

   

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

  

    self.forward = if_(match(dstip=pkt['dstip'],srcip=pkt['srcip']),r1,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]

            self.last_topology = network.topology

          

def arp_and_ip():

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

        

def main():

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


[Execution]

 

H1 ping H2 (From the right hand of following figure. We can see that there will be three paths for packets from h1 to h2, i.e. 1-2-3-4, 1-5-6-4, and 1-2-6-4.

The Selected path is 1-2-6-4.)

 

[Reference]

1.      http://www.widecodes.com/0izqkPgPPe/python-dijkstra-k-shortest-paths.html

 

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

Department of Computer Science and Information Engineering,

National Quemoy University, Kinmen, Taiwan.