blob: 44f66c2c14a77eea96112b9c29045dde15ddd814 [file] [log] [blame]
Carmelo Cascone977ae3f2016-06-23 19:28:28 -07001import socket
2
Carmelo Cascone785fada2016-06-16 18:34:16 -07003from mininet.log import error, info
4from mininet.node import Switch
5from os import environ
6from os.path import isfile
7
8
9class ONOSBmv2Switch(Switch):
10 """BMv2 software switch """
11
Carmelo Cascone785fada2016-06-16 18:34:16 -070012 deviceId = 0
Carmelo Cascone977ae3f2016-06-23 19:28:28 -070013 instanceCount = 0
Carmelo Cascone785fada2016-06-16 18:34:16 -070014
15 def __init__(self, name, thriftPort=None, deviceId=None, debugger=False,
16 loglevel="warn", elogger=False, persistent=True, **kwargs):
17 Switch.__init__(self, name, **kwargs)
18 self.swPath = environ['BMV2_EXE']
19 self.jsonPath = environ['BMV2_JSON']
Carmelo Cascone977ae3f2016-06-23 19:28:28 -070020 if thriftPort:
Carmelo Cascone785fada2016-06-16 18:34:16 -070021 self.thriftPort = thriftPort
Carmelo Cascone977ae3f2016-06-23 19:28:28 -070022 else:
23 self.thriftPort = ONOSBmv2Switch.pickUnusedPort()
Carmelo Cascone785fada2016-06-16 18:34:16 -070024 if not deviceId:
25 if self.dpid:
26 self.deviceId = int(self.dpid, 0 if 'x' in self.dpid else 16)
27 else:
28 self.deviceId = ONOSBmv2Switch.deviceId
29 ONOSBmv2Switch.deviceId += 1
30 else:
31 self.deviceId = deviceId
32 ONOSBmv2Switch.deviceId = max(deviceId, ONOSBmv2Switch.deviceId)
33 self.debugger = debugger
34 self.loglevel = loglevel
35 self.logfile = '/tmp/bmv2-%d.log' % self.deviceId
36 self.output = open(self.logfile, 'w')
37 self.elogger = elogger
38 self.persistent = persistent
39 if persistent:
40 self.exectoken = "/tmp/bmv2-%d-exec-token" % self.deviceId
41 self.cmd("touch %s" % self.exectoken)
Carmelo Cascone977ae3f2016-06-23 19:28:28 -070042 # Store thrift port for future uses.
43 self.cmd("echo %d > /tmp/bmv2-%d-thrift-port" % (self.thriftPort, self.deviceId))
44
45 @classmethod
46 def pickUnusedPort(cls):
47 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
48 s.bind(('localhost', 0))
49 addr, port = s.getsockname()
50 s.close()
51 return port
Carmelo Cascone785fada2016-06-16 18:34:16 -070052
53 @classmethod
54 def setup(cls):
55 err = False
Carmelo Cascone785fada2016-06-16 18:34:16 -070056 if 'BMV2_EXE' not in environ:
57 error("ERROR! environment var $BMV2_EXE not set\n")
58 err = True
59 elif not isfile(environ['BMV2_EXE']):
60 error("ERROR! BMV2_EXE=%s: no such file\n" % environ['BMV2_EXE'])
61 err = True
Carmelo Cascone785fada2016-06-16 18:34:16 -070062 if 'BMV2_JSON' not in environ:
63 error("ERROR! environment var $BMV2_JSON not set\n")
64 err = True
65 elif not isfile(environ['BMV2_JSON']):
66 error("ERROR! BMV2_JSON=%s: no such file\n" % environ['BMV2_JSON'])
67 err = True
Carmelo Cascone785fada2016-06-16 18:34:16 -070068 if err:
69 exit(1)
70
71 def start(self, controllers):
72 args = [self.swPath, '--device-id %s' % str(self.deviceId)]
73 for port, intf in self.intfs.items():
74 if not intf.IP():
75 args.append('-i %d@%s' % (port, intf.name))
76 if self.thriftPort:
77 args.append('--thrift-port %d' % self.thriftPort)
78 if self.elogger:
79 nanomsg = 'ipc:///tmp/bmv2-%d-log.ipc' % self.deviceId
80 args.append('--nanolog %s' % nanomsg)
81 if self.debugger:
82 args.append('--debugger')
83 args.append('--log-console -L%s' % self.loglevel)
84 args.append(self.jsonPath)
Carmelo Cascone977ae3f2016-06-23 19:28:28 -070085 try: # onos.py
86 clist = controllers[0].nodes()
87 except AttributeError:
88 clist = controllers
89 assert len(clist) > 0
90 # BMv2 can't connect to multiple controllers.
91 # Uniformly balance connections among available ones.
92 cip = clist[ONOSBmv2Switch.instanceCount % len(clist)].IP()
93 ONOSBmv2Switch.instanceCount += 1
94 # BMv2 controler port is hardcoded here as it is hardcoded also in ONOS.
95 cport = 40123
Carmelo Cascone785fada2016-06-16 18:34:16 -070096 args.append('--')
Carmelo Cascone977ae3f2016-06-23 19:28:28 -070097 args.append('--controller-ip %s' % cip)
98 args.append('--controller-port %d' % cport)
Carmelo Cascone785fada2016-06-16 18:34:16 -070099
100 bmv2cmd = " ".join(args)
Carmelo Cascone785fada2016-06-16 18:34:16 -0700101 info("\nStarting BMv2 target: %s\n" % bmv2cmd)
Carmelo Cascone785fada2016-06-16 18:34:16 -0700102 if self.persistent:
103 # Re-exec the switch if it crashes.
104 cmdStr = "(while [ -e {} ]; " \
105 "do {} ; " \
106 "sleep 1; " \
107 "done;) > {} 2>&1 &".format(self.exectoken, bmv2cmd, self.logfile)
108 else:
109 cmdStr = "{} > {} 2>&1 &".format(bmv2cmd, self.logfile)
Carmelo Cascone785fada2016-06-16 18:34:16 -0700110 self.cmd(cmdStr)
111
112 def stop(self):
113 "Terminate switch."
114 self.output.flush()
Carmelo Cascone977ae3f2016-06-23 19:28:28 -0700115 self.cmd("rm -f /tmp/bmv2-%d-*" % self.deviceId)
116 self.cmd("rm -f /tmp/bmv2-%d.log" % self.deviceId)
Carmelo Cascone785fada2016-06-16 18:34:16 -0700117 self.cmd('kill %' + self.swPath)
118 self.deleteIntfs()
119
120
121### Exports for bin/mn
Carmelo Cascone785fada2016-06-16 18:34:16 -0700122switches = {'onosbmv2': ONOSBmv2Switch}