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