codeblock

2016年4月12日 星期二

Mininet - FatTree Topology

- Fat tree topology: https://en.wikipedia.org/wiki/Fat_tree

- If there is a loop in the topology, the hosts cannot ping the others because https://github.com/mininet/mininet/wiki/FAQ#ethernet-loops

- Every time when I need to start mininet which supports a loop network, I have to add "--switch ovs,failMode=standalone,stp=1", it's so annoying.
- Every time when I try to start mininet  with a custom topology, I have to add "--custum urfilename.py --topo urtopologyname", it's also annoying.
- Every time when I start mininet with spanning tree protocol enabled, I need to wait for a while to let STP converge. The only chance I could know whether it is converge is keep trying to pingall hosts.
- Although in https://github.com/mininet/mininet/wiki/FAQ#ethernet-loops a net.waitConnected() method is suggested, but this function seems doesn't work for me, and it doesn't work for a remote controller.

- I would like to write a python function to simplify these sh*ts, and construct a k=4 fat tree topology.
- To hard code a fat tree is exhausted, so the assignment also infer that "use 2-level for loops to construct it"


- SmallTreeTopo
class SmallTreeTopo(Topo):
    host_list = []
    switch_list = []

    def __init__( self ):
 
 # Initialize topology
        Topo.__init__( self )
 
 # Add hosts and switches---------------    
 host_P1_1 = self.addHost('10_0_0_2', ip='10.0.0.2')
        host_P1_2 = self.addHost('10_0_0_3', ip='10.0.0.3')
        host_P1_3 = self.addHost('10_0_1_2', ip='10.0.1.2')
        host_P1_4 = self.addHost('10_0_1_3', ip='10.0.1.3')
     
 self.host_list = ['10_0_0_2', '10_0_0_3', '10_0_1_2', '10_0_1_3']
 
 # Switches
 switch_E1_1 = self.addSwitch('10_0_0_1')
 switch_E1_2 = self.addSwitch('10_0_1_1')
 switch_A1_1 = self.addSwitch('10_0_2_1')
 switch_A1_2 = self.addSwitch('10_0_3_1')
     
 self.switch_list = ['10_0_0_1', '10_0_1_1', '10_0_2_1', '10_0_3_1']
 
 # Add links ------------------------------
 # POD 1: EDGE-HOSTS 
 self.addLink(switch_E1_1, host_P1_1)
 self.addLink(switch_E1_1, host_P1_2)
 self.addLink(switch_E1_2, host_P1_3)
 self.addLink(switch_E1_2, host_P1_4)

 # POD 1: AGGR-EDGE
 self.addLink(switch_A1_1, switch_E1_1)
 self.addLink(switch_A1_1, switch_E1_2)
 self.addLink(switch_A1_2, switch_E1_1)
 self.addLink(switch_A1_2, switch_E1_2)
- SmallTreeTopo is only "a pod" of a k=4 Fat Tree topology, so if someone try to add switches/hosts/links one by one, the file will be at least 4 times larger than this.

- FatTreeTopo

class FatTreeTopo(Topo):
    k = 4
    host_list = []
    switch_list = []
    
    core_switch_object = []
    aggr_switch_object = []
    edge_switch_object = []
    host_object = []
    
    def __init__( self ):
        "Create custom topo."
        # Initialize topology
        Topo.__init__( self )
 # add switches and hosts
 for i in range(self.k):
     # add core switches
     self.core_switch_object.append(self.addSwitch(
   '10_%d_%d_%d' % (self.k, i/2+1, i%2+1)))
     for j in range(self.k):
  #add hosts
  self.host_object.append(self.addHost(
   '10_%d_%d_%d' % (i, j/2, j%2+2), 
   ip='10.%d.%d.%d' % (i, j/2, j%2+2)))
  #add edge switches
  if j < self.k:
      self.edge_switch_object.append(self.addSwitch(
   '10_%d_%d_1' % (i, j)))
  #add aggr switches
  else:
      self.aggr_switch_object.append(self.addSwitch(
   '10_%d_%d_1' % (i, j)))
 
 self.host_list.extend(self.host_object)
 self.switch_list.extend(self.core_switch_object)  
 self.switch_list.extend(self.aggr_switch_object)  
 self.switch_list.extend(self.edge_switch_object)  
 
 #add links 
 for switch in self.switch_list:
     a, b, c, d = switch.split("_")
     # core switches: connect to aggr switches
     if int(b) == 4:
  if int(c) == 1:
      for i in range(4):      
   self.addLink(switch, "10_%d_2_1" % i)
  elif int(c) == 2:
      for i in range(4):      
   self.addLink(switch, "10_%d_3_1" % i)
     # aggr switches: connect to edge switches
     elif int(c) in (2, 3):
  self.addLink(switch, "10_%d_0_1" % int(b))
  self.addLink(switch, "10_%d_1_1" % int(b))
     # edge switches: connect to hosts
     elif int(d) == 1:
  self.addLink(switch, "10_%d_%d_2" % (int(b), int(c)))
      self.addLink(switch, "10_%d_%d_3" % (int(b), int(c)))
- Start mininet with this topology, and will see the following in the console.
mininet@mininet-vm:~/cloudhw2$ sudo python mymininet.py -t fattree --stp
*** Creating network
*** Adding controller
*** Adding hosts:
10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
*** Adding switches:
10_0_0_1 10_0_1_1 10_0_2_1 10_0_3_1 10_1_0_1 10_1_1_1 10_1_2_1 10_1_3_1 10_2_0_1 10_2_1_1 10_2_2_1 10_2_3_1 10_3_0_1 10_3_1_1 10_3_2_1 10_3_3_1 10_4_1_1 10_4_1_2 10_4_2_1 10_4_2_2 
*** Adding links:
(10_0_0_1, 10_0_0_2) (10_0_0_1, 10_0_0_3) (10_0_1_1, 10_0_1_2) (10_0_1_1, 10_0_1_3) (10_0_2_1, 10_0_0_1) (10_0_2_1, 10_0_1_1) (10_0_3_1, 10_0_0_1) (10_0_3_1, 10_0_1_1) (10_1_0_1, 10_1_0_2) (10_1_0_1, 10_1_0_3) (10_1_1_1, 10_1_1_2) (10_1_1_1, 10_1_1_3) (10_1_2_1, 10_1_0_1) (10_1_2_1, 10_1_1_1) (10_1_3_1, 10_1_0_1) (10_1_3_1, 10_1_1_1) (10_2_0_1, 10_2_0_2) (10_2_0_1, 10_2_0_3) (10_2_1_1, 10_2_1_2) (10_2_1_1, 10_2_1_3) (10_2_2_1, 10_2_0_1) (10_2_2_1, 10_2_1_1) (10_2_3_1, 10_2_0_1) (10_2_3_1, 10_2_1_1) (10_3_0_1, 10_3_0_2) (10_3_0_1, 10_3_0_3) (10_3_1_1, 10_3_1_2) (10_3_1_1, 10_3_1_3) (10_3_2_1, 10_3_0_1) (10_3_2_1, 10_3_1_1) (10_3_3_1, 10_3_0_1) (10_3_3_1, 10_3_1_1) (10_4_1_1, 10_0_2_1) (10_4_1_1, 10_1_2_1) (10_4_1_1, 10_2_2_1) (10_4_1_1, 10_3_2_1) (10_4_1_2, 10_0_2_1) (10_4_1_2, 10_1_2_1) (10_4_1_2, 10_2_2_1) (10_4_1_2, 10_3_2_1) (10_4_2_1, 10_0_3_1) (10_4_2_1, 10_1_3_1) (10_4_2_1, 10_2_3_1) (10_4_2_1, 10_3_3_1) (10_4_2_2, 10_0_3_1) (10_4_2_2, 10_1_3_1) (10_4_2_2, 10_2_3_1) (10_4_2_2, 10_3_3_1) 
*** Configuring hosts
10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
*** Starting controller
c0 
*** Starting 20 switches
10_0_0_1 10_0_1_1 10_0_2_1 10_0_3_1 10_1_0_1 10_1_1_1 10_1_2_1 10_1_3_1 10_2_0_1 10_2_1_1 10_2_2_1 10_2_3_1 10_3_0_1 10_3_1_1 10_3_2_1 10_3_3_1 10_4_1_1 10_4_1_2 10_4_2_1 10_4_2_2 ...
*** Enabling STP
10_4_1_1 ...  done
10_4_1_2 ...  done
10_4_2_1 ...  done
10_4_2_2 ...  done
10_0_0_1 ...  done
10_0_1_1 ...  done
10_0_2_1 ...  done
10_0_3_1 ...  done
10_1_0_1 ...  done
10_1_1_1 ...  done
10_1_2_1 ...  done
10_1_3_1 ...  done
10_2_0_1 ...  done
10_2_1_1 ...  done
10_2_2_1 ...  done
10_2_3_1 ...  done
10_3_0_1 ...  done
10_3_1_1 ...  done
10_3_2_1 ...  done
10_3_3_1 ...  done
Wait for STP converge ... Done!
*** Starting CLI:
mininet> pingall
*** Ping: testing ping reachability
10_0_0_2 -> 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_0_0_3 -> 10_0_0_2 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_0_1_2 -> 10_0_0_2 10_0_0_3 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_0_1_3 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_1_0_2 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_1_0_3 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_1_1_2 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_1_1_3 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_2_0_2 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_2_0_3 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_2_1_2 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_2_1_3 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_3_0_2 10_3_0_3 10_3_1_2 10_3_1_3 
10_3_0_2 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_3 10_3_1_2 10_3_1_3 
10_3_0_3 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_1_2 10_3_1_3 
10_3_1_2 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_3 
10_3_1_3 -> 10_0_0_2 10_0_0_3 10_0_1_2 10_0_1_3 10_1_0_2 10_1_0_3 10_1_1_2 10_1_1_3 10_2_0_2 10_2_0_3 10_2_1_2 10_2_1_3 10_3_0_2 10_3_0_3 10_3_1_2 
*** Results: 0% dropped (240/240 received)
mininet> iperf
*** Iperf: testing TCP bandwidth between 10_0_0_2 and 10_3_1_3 
*** Results: ['14.9 Gbits/sec', '15.0 Gbits/sec']
mininet> 

- I have enabled stp in the main function and tried to write a small procedure to check the convergence of stp. As long as stp converges, pingall function works.
- The name of hosts and switches are assigned by their IP address(simply replace dots with "_"). The addressing method refers to http://ccr.sigcomm.org/online/files/p63-alfares.pdf
- Next step: Install RYU as controller! 

1 則留言: