blob: c6b96dd1f2813fd9cde3d2086401c79a8deb36f1 [file] [log] [blame]
Bob Lantzc7c05402013-12-16 21:22:12 -08001#!/usr/bin/env python
2
3"""
4onos.py: A simple ONOS Controller() subclass for Mininet
5
6We implement the following classes:
7
8ONOSController: a custom Controller() subclass to start ONOS
9OVSSwitchONOS: a custom OVSSwitch() switch that connects to multiple controllers.
10
11We use single Zookeeper and Cassandra instances for now.
12
13As a custom file, exports:
14
15--controller onos
16--switch ovso
17
18Usage:
19
20$ sudo ./onos.py
21
22This will start up a simple 2-host, 2 ONOS network
23
24$ sudo mn --custom onos.py --controller onos,2 --switch ovso
25"""
26
27from mininet.node import Controller, OVSSwitch
28from mininet.net import Mininet
29from mininet.cli import CLI
30from mininet.topo import SingleSwitchTopo
31from mininet.log import setLogLevel, info
32from mininet.util import quietRun
33
34from shutil import copyfile
35from os import environ
36from functools import partial
37
38
39class ONOS( Controller ):
40 "Custom controller class for ONOS"
41
42 # Directories and configuration templates
43 home = environ[ 'HOME' ]
44 onosDir = home + "/ONOS"
45 zookeeperDir = home + "/zookeeper-3.4.5"
46 dirBase = '/tmp'
47 logDir = dirBase + '/onos-%s.logs'
48 cassDir = dirBase + '/onos-%s.cassandra'
49 configFile = dirBase + '/onos-%s.properties'
50 logbackFile = dirBase + '/onos-%s.logback'
51 jmxbase = 7189
52 restbase = 8080
53 ofbase = 6633
54
55 # Per-instance property template
56 fc = 'net.floodlightcontroller.'
57 proctag = 'mn-onos-id'
58 jvmopts = (
59 # We match on this to shut down our instances
60 ( proctag, 0 ),
61 ( fc + 'restserver.RestApiServer.port', restbase ),
62 ( fc + 'core.FloodlightProvider.openflowport', ofbase ),
63 ( fc + 'core.FloodlightProvider.controllerid', 0 ) )
64
65
Bob Lantz7a4d6102013-12-17 00:34:55 -080066 # For maven debugging
67 # mvn = 'mvn -o -e -X'
Bob Lantzc7c05402013-12-16 21:22:12 -080068
69 def __init__( self, name, n=1, drop=True, **params):
70 """n: number of ONOS instances to run (1)
71 drop: drop root privileges (True)"""
72 self.check()
73 self.drop = drop
74 self.count = n
75 self.ids = range( 0, self.count )
76 Controller.__init__( self, name, **params )
77 # We don't need to run as root, and it can interfere
78 # with starting Zookeeper manually
79 if self.drop:
80 self.user = quietRun( 'who am i' ).split()[ 0 ]
81 self.sendCmd( 'su', self.user )
82 self.waiting = False
83 # Need to run commands from ONOS dir
84 self.cmd( 'cd', self.onosDir )
85 self.cmd( 'export PATH=$PATH:%s' % self.onosDir )
Bob Lantz7a4d6102013-12-17 00:34:55 -080086 if hasattr( self, 'mvn' ):
87 self.cmd( 'export MVN="%s"' % self.mvn )
Bob Lantzc7c05402013-12-16 21:22:12 -080088
89 def check( self ):
90 "Check for prerequisites"
91 if not quietRun( 'which java' ):
92 raise Exception( 'java not found -'
93 ' make sure it is installed and in $PATH' )
94 if not quietRun( 'which mvn' ):
95 raise Exception( 'Maven (mvn) not found -'
96 ' make sure it is installed and in $PATH' )
97
98 def startCassandra( self ):
99 "Start Cassandra"
100 self.cmd( 'start-cassandra.sh start' )
101 status = self.cmd( 'start-cassandra.sh status' )
102 if 'Error' in status:
103 raise Exception( 'Cassandra startup failed: ' + status )
104
105 def stopCassandra( self ):
106 "Stop Cassandra"
107 self.cmd( 'start-cassandra.sh stop' )
108
109 def startZookeeper( self, initcfg=True ):
110 "Start Zookeeper"
111 # Reinitialize configuration file
112 if initcfg:
113 cfg = self.zookeeperDir + '/conf/zoo.cfg'
114 template = self.zookeeperDir + '/conf/zoo_sample.cfg'
115 copyfile( template, cfg )
116 self.cmd( 'start-zk.sh restart' )
117 status = self.cmd( 'start-zk.sh status' )
118 if 'Error' in status:
119 raise Exception( 'Zookeeper startup failed: ' + status )
120
121 def stopZookeeper( self ):
122 "Stop Zookeeper"
123 self.cmd( 'start-zk.sh stop' )
124
125 def setVars( self, id ):
126 "Set and return environment vars"
127 # ONOS directories and files
128 logdir = self.logDir % id
129 cassdir = self.cassDir % id
130 logback = self.logbackFile % id
131 jmxport = self.jmxbase + id
132 self.cmd( 'mkdir -p', logdir, cassdir )
133 self.cmd( 'export ONOS_LOGDIR="%s"' % logdir )
134 self.cmd( 'export ZOO_LOG_DIR="%s"' % logdir )
135 self.cmd( 'export CASS_DIR="%s"' % cassdir )
136 self.cmd( 'export ONOS_LOGBACK="%s"' % logback )
137 self.cmd( 'export JMX_PORT=%s' % jmxport )
138 jvmopts = ('-agentlib:jdwp=transport=dt_socket,address=%s,server=y,suspend=n '
139 % ( 8000 + id ) )
140 jvmopts += ' '.join( '-D%s=%s '% ( opt, val + id )
141 for opt, val in self.jvmopts )
142 self.cmd( 'export JVM_OPTS="%s"' % jvmopts )
143
144 def startONOS( self, id ):
145 """Start ONOS
146 id: identifier for new instance"""
147 # self.stopONOS( id )
148 self.setVars( id )
149 self.cmdPrint( 'start-onos.sh startnokill' )
150
151 def stopONOS( self, id ):
152 """Shut down ONOS
153 id: identifier for instance"""
154 pid = self.cmd( "jps -v | grep %s=%s | awk '{print $1}'" %
155 ( self.proctag, id ) ).strip()
156 if pid:
157 self.cmdPrint( 'kill', pid )
158
159 def start( self, *args ):
160 "Start ONOS instances"
161 info( '* Starting Cassandra\n' )
162 self.startCassandra()
163 info( '* Starting Zookeeper\n' )
164 self.startZookeeper()
165 for id in self.ids:
166 info( '* Starting ONOS %s\n' % id )
167 self.startONOS( id )
168
169 def stop( self, *args ):
170 "Stop ONOS instances"
171 for id in self.ids:
172 info( '* Stopping ONOS %s\n' % id )
173 self.stopONOS( id )
174 info( '* Stopping zookeeper\n' )
175 self.stopZookeeper()
176 info( '* Stopping Cassandra\n' )
177 self.stopCassandra()
178
179 def clist( self ):
180 "Return list of controller specifiers (proto:ip:port)"
181 return [ 'tcp:127.0.0.1:%s' % ( self.ofbase + id )
182 for id in range( 0, self.count ) ]
183
184
185class OVSSwitchONOS( OVSSwitch ):
186 "OVS switch which connects to multiple controllers"
187 def start( self, controllers ):
188 OVSSwitch.start( self, controllers )
189 assert len( controllers ) == 1
190 c0 = controllers[ 0 ]
191 assert type( c0 ) == ONOS
192 clist = ','.join( c0.clist() )
193 self.cmd( 'ovs-vsctl set-controller', self, clist)
194 # Reconnect quickly to controllers (1s vs. 15s max_backoff)
195 for uuid in self.controllerUUIDs():
196 if uuid.count( '-' ) != 4:
197 # Doesn't look like a UUID
198 continue
199 uuid = uuid.strip()
200 self.cmd( 'ovs-vsctl set Controller', uuid,
201 'max_backoff=1000' )
202
203
204controllers = { 'onos': ONOS }
205switches = { 'ovso': OVSSwitchONOS }
206
207
208if __name__ == '__main__':
209 "Simple test of ONOSController"
210 setLogLevel( 'info' )
211 net = Mininet( topo=SingleSwitchTopo( 2 ),
212 controller=partial( ONOS, n=2 ),
213 switch=OVSSwitchONOS )
214 net.start()
215 CLI( net )
216 net.stop()