blob: 1738cf738585ee898edd9c1e472aef17bb2e5154 [file] [log] [blame]
Thomas Vachuska9ee49792016-03-01 16:51:14 -08001#!/usr/bin/python
2
3import sys
Brian O'Connord6c73fb2016-03-04 15:24:52 -08004import itertools
Brian O'Connore9b4dd72016-03-05 01:07:18 -08005import signal
Brian O'Connord6c73fb2016-03-04 15:24:52 -08006from time import sleep
Brian O'Connore9b4dd72016-03-05 01:07:18 -08007from threading import Thread
Thomas Vachuska9ee49792016-03-01 16:51:14 -08008
9from mininet.net import Mininet
10from mininet.log import setLogLevel
Brian O'Connore9b4dd72016-03-05 01:07:18 -080011from mininet.node import RemoteController, Node
12from mininet.log import info, debug, output, error
Thomas Vachuska9ee49792016-03-01 16:51:14 -080013from mininet.link import TCLink
14from mininet.cli import CLI
15
Brian O'Connore9b4dd72016-03-05 01:07:18 -080016# This is the program that each host will call
17import gratuitousArp
18ARP_PATH = gratuitousArp.__file__.replace('.pyc', '.py')
Thomas Vachuska9ee49792016-03-01 16:51:14 -080019
Brian O'Connore9b4dd72016-03-05 01:07:18 -080020class ONOSMininet( Mininet ):
Thomas Vachuska9ee49792016-03-01 16:51:14 -080021
22 def __init__( self, controllers=[], gratuitousArp=True, build=True, *args, **kwargs ):
23 """Create Mininet object for ONOS.
24 controllers: List of controller IP addresses
25 gratuitousArp: Send an ARP from each host to aid controller's host discovery"""
26 # discarding provided controller (if any),
27 # using list of remote controller IPs instead
28 kwargs[ 'controller' ] = None
29
30 # delay building for a second
31 kwargs[ 'build' ] = False
32
33 Mininet.__init__(self, *args, **kwargs )
34
35 self.gratArp = gratuitousArp
Thomas Vachuska9ee49792016-03-01 16:51:14 -080036
37 info ( '*** Adding controllers\n' )
38 ctrl_count = 0
39 for controllerIP in controllers:
40 self.addController( 'c%d' % ctrl_count, RemoteController, ip=controllerIP )
41 info( ' c%d (%s)\n' % ( ctrl_count, controllerIP ) )
42 ctrl_count = ctrl_count + 1
43
44 if self.topo and build:
45 self.build()
46
47 def start( self ):
48 Mininet.start( self )
49 if self.gratArp:
Brian O'Connore9b4dd72016-03-05 01:07:18 -080050 self.waitConnected( timeout=5 )
Thomas Vachuska9ee49792016-03-01 16:51:14 -080051 info ( '*** Sending a gratuitious ARP from each host\n' )
52 self.gratuitousArp()
53
Brian O'Connore9b4dd72016-03-05 01:07:18 -080054 def verifyHosts( self, hosts ):
55 for i in range( len( hosts ) ):
56 if isinstance( hosts[i], str):
57 if hosts[i] in self:
58 hosts[i] = self[ hosts[i] ]
Brian O'Connord6c73fb2016-03-04 15:24:52 -080059 else:
Brian O'Connore9b4dd72016-03-05 01:07:18 -080060 info( '*** ERROR: %s is not a host\n' % hosts[i] )
61 del hosts[i]
62 elif not isinstance( hosts[i], Node):
63 del hosts[i]
64
65 def gratuitousArp( self, hosts=[] ):
66 "Send an ARP from each host to aid controller's host discovery; fallback to ping if necessary"
67 if not hosts:
68 hosts = self.hosts
69 self.verifyHosts( hosts )
70
71 for host in hosts:
72 info( '%s ' % host.name )
73 info( host.cmd( ARP_PATH ) )
Brian O'Connord6c73fb2016-03-04 15:24:52 -080074 info ( '\n' )
Thomas Vachuska9ee49792016-03-01 16:51:14 -080075
76 def pingloop( self ):
77 "Loop forever pinging the full mesh of hosts"
78 setLogLevel( 'error' )
79 try:
80 while True:
81 self.ping()
82 finally:
83 setLogLevel( 'info' )
84
Brian O'Connord6c73fb2016-03-04 15:24:52 -080085 def bgIperf( self, hosts=[], seconds=10 ):
Brian O'Connore9b4dd72016-03-05 01:07:18 -080086 self.verifyHosts( hosts )
Brian O'Connord6c73fb2016-03-04 15:24:52 -080087 servers = [ host.popen("iperf -s") for host in hosts ]
88
89 clients = []
Brian O'Connore9b4dd72016-03-05 01:07:18 -080090 for s, d in itertools.combinations(hosts, 2):
91 info ( '%s <--> %s\n' % ( s.name, d.name ))
92 cmd = 'iperf -c %s -t %s -y csv' % (d.IP(), seconds)
93 p = s.popen(cmd)
94 p.s = s.name
95 p.d = d.name
96 clients.append(p)
Brian O'Connord6c73fb2016-03-04 15:24:52 -080097
Brian O'Connore9b4dd72016-03-05 01:07:18 -080098 def handler (_signum, _frame):
99 raise BackgroundException()
100 oldSignal = signal.getsignal(signal.SIGTSTP)
101 signal.signal(signal.SIGTSTP, handler)
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800102
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800103 def finish( verbose=True ):
104 for c in clients:
105 out, err = c.communicate()
106 if verbose:
107 if err:
108 info( err )
109 else:
110 bw = out.split( ',' )[8]
111 info( '%s <--> %s: %s\n' % ( c.s, c.d, formatBw(bw) ) )
112 for s in servers:
113 s.terminate()
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800114
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800115 try:
116 info ( 'Press ^Z to continue in background or ^C to abort\n')
117 progress( seconds )
118 finish()
119 except KeyboardInterrupt:
120 for c in clients:
121 c.terminate()
122 for s in servers:
123 s.terminate()
124 except BackgroundException:
125 info( '\n*** Continuing in background...\n' )
126 t = Thread( target=finish, args=[ False ] )
127 t.start()
128 finally:
129 #Disable custom background signal
130 signal.signal(signal.SIGTSTP, oldSignal)
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800131
132def progress(t):
133 while t > 0:
134 sys.stdout.write( '.' )
135 t -= 1
136 sys.stdout.flush()
137 sleep(1)
138 print
139
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800140def formatBw( bw ):
141 bw = float(bw)
142 if bw > 1000:
143 bw /= 1000
144 if bw > 1000:
145 bw /= 1000
146 if bw > 1000:
147 bw /= 1000
148 return '%.2f Gbps' % bw
149 return '%.2f Mbps' % bw
150 return '%.2f Kbps' % bw
151 return '%.2f bps' % bw
Thomas Vachuska9ee49792016-03-01 16:51:14 -0800152
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800153class BackgroundException( Exception ):
154 pass
155
156def do_bgIperf( self, line ):
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800157 args = line.split()
158 if not args:
159 output( 'Provide a list of hosts.\n' )
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800160
161 #Try to parse the '-t' argument as the number of seconds
162 seconds = 10
163 for i, arg in enumerate(args):
164 if arg == '-t':
165 if i + 1 < len(args):
166 try:
167 seconds = int(args[i + 1])
168 except ValueError:
169 error( 'Could not parse number of seconds: %s', args[i+1] )
170 del(args[i+1])
171 del args[i]
172
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800173 hosts = []
174 err = False
175 for arg in args:
176 if arg not in self.mn:
177 err = True
178 error( "node '%s' not in network\n" % arg )
179 else:
180 hosts.append( self.mn[ arg ] )
181 if "bgIperf" in dir(self.mn) and not err:
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800182 self.mn.bgIperf( hosts, seconds=seconds )
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800183
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800184def do_gratuitousArp( self, line ):
185 args = line.split()
186 if "gratuitousArp" in dir( self.mn ):
187 self.mn.gratuitousArp( args )
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800188 else:
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800189 output( 'Gratuitous ARP is not supported.\n' )
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800190
Brian O'Connore9b4dd72016-03-05 01:07:18 -0800191CLI.do_bgIperf = do_bgIperf
Brian O'Connord6c73fb2016-03-04 15:24:52 -0800192CLI.do_gratuitousArp = do_gratuitousArp
193
Thomas Vachuska9ee49792016-03-01 16:51:14 -0800194def run( topo, controllers=None, link=TCLink, autoSetMacs=True ):
195 if not controllers and len( sys.argv ) > 1:
196 controllers = sys.argv[ 1: ]
197 else:
198 print 'Need to provide a topology and list of controllers'
199 exit( 1 )
200
201 setLogLevel( 'info' )
202
203 net = ONOSMininet( topo=topo, controllers=controllers, link=link, autoSetMacs=autoSetMacs )
204 net.start()
205 CLI( net )
206 net.stop()