[ONOS-6854] refactor bmv2-demo.py

Change-Id: I9b7460b15f6664363f2ff0b16110e2b3bc4dedeb
This commit is contained in:
Yi Tseng 2017-08-08 10:15:58 -07:00 committed by Carmelo Cascone
parent e3e21ae133
commit 7875cb78bb
3 changed files with 156 additions and 212 deletions

View File

@ -23,7 +23,8 @@ class ONOSBmv2Switch(Switch):
instanceCount = 0
def __init__(self, name, json=None, debugger=False, loglevel="warn", elogger=False,
persistent=False, grpcPort=None, thriftPort=None, netcfg=True, **kwargs):
persistent=False, grpcPort=None, thriftPort=None, netcfg=True,
pipeconfId="", **kwargs):
Switch.__init__(self, name, **kwargs)
self.grpcPort = ONOSBmv2Switch.pickUnusedPort() if not grpcPort else grpcPort
self.thriftPort = ONOSBmv2Switch.pickUnusedPort() if not thriftPort else thriftPort
@ -40,12 +41,25 @@ class ONOSBmv2Switch(Switch):
self.persistent = persistent
self.netcfg = netcfg
self.netcfgfile = '/tmp/bmv2-%d-netcfg.json' % self.deviceId
self.pipeconfId = pipeconfId
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-grpc-port" % (self.grpcPort, self.deviceId))
if 'longitude' in kwargs:
self.longitude = kwargs['longitude']
else:
self.longitude = None
if 'latitude' in kwargs:
self.latitude = kwargs['latitude']
else:
self.latitude = None
self.onosDeviceId = "device:bmv2:%d" % self.deviceId
@classmethod
def pickUnusedPort(cls):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -63,15 +77,7 @@ class ONOSBmv2Switch(Switch):
r = re.search(r"src (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", ipRouteOut)
return r.group(1) if r else None
def doOnosNetcfg(self, controllerIP):
"""
Notifies ONOS about the new device via Netcfg.
"""
srcIP = self.getSourceIp(controllerIP)
if not srcIP:
warn("WARN: unable to get device IP address, won't do onos-netcfg")
return
onosDeviceId = "bmv2:%s" % self.deviceId
def getDeviceConfig(self, srcIP):
portData = {}
portId = 1
for intfName in self.intfNames():
@ -87,25 +93,44 @@ class ONOSBmv2Switch(Switch):
}
portId += 1
basicCfg = {
"driver": "bmv2"
}
if self.longitude and self.latitude:
basicCfg["longitude"] = self.longitude
basicCfg["latitude"] = self.latitude
cfgData = {
"generalprovider": {
"p4runtime": {
"ip": srcIP,
"port": self.grpcPort,
"deviceId": self.deviceId,
"deviceKeyId": "p4runtime:%s" % self.onosDeviceId
}
},
"piPipeconf": {
"piPipeconfId": self.pipeconfId
},
"basic": basicCfg,
"ports": portData
}
return cfgData
def doOnosNetcfg(self, controllerIP):
"""
Notifies ONOS about the new device via Netcfg.
"""
srcIP = self.getSourceIp(controllerIP)
if not srcIP:
warn("WARN: unable to get device IP address, won't do onos-netcfg")
return
cfgData = {
"devices": {
"device:%s" % onosDeviceId: {
"generalprovider": {
"p4runtime": {
"ip": srcIP,
"port": self.grpcPort,
"deviceId": self.deviceId,
"deviceKeyId": "p4runtime:%s" % onosDeviceId
}
},
"piPipeconf": {
"piPipeconfId": ""
},
"basic": {
"driver": "bmv2"
},
"ports": portData
}
self.onosDeviceId: self.getDeviceConfig(srcIP)
}
}
with open(self.netcfgfile, 'w') as fp:

View File

@ -1,162 +0,0 @@
{
"apps": {
"org.onosproject.core": {
"core": {
"linkDiscoveryMode": "STRICT"
}
}
},
"devices": {
"bmv2:192.168.123.4:9090#11": {
"basic": {
"name": "bmv2:11",
"latitude": 40,
"longitude": -107
}
},
"bmv2:192.168.123.4:9091#12": {
"basic": {
"name": "bmv2:12",
"latitude": 40,
"longitude": -99
}
},
"bmv2:192.168.123.4:9092#13": {
"basic": {
"name": "bmv2:13",
"latitude": 40,
"longitude": -91
}
},
"bmv2:192.168.123.4:9093#21": {
"basic": {
"name": "bmv2:21",
"latitude": 46,
"longitude": -107
}
},
"bmv2:192.168.123.4:9094#22": {
"basic": {
"name": "bmv2:22",
"latitude": 46,
"longitude": -99
}
},
"bmv2:192.168.123.4:9095#23": {
"basic": {
"name": "bmv2:23",
"latitude": 46,
"longitude": -91
}
}
},
"links": {
"bmv2:192.168.123.4:9090#11/1-bmv2:192.168.123.4:9093#21/1": {
"basic": {}
},
"bmv2:192.168.123.4:9093#21/1-bmv2:192.168.123.4:9090#11/1": {
"basic": {}
},
"bmv2:192.168.123.4:9090#11/2-bmv2:192.168.123.4:9093#21/2": {
"basic": {}
},
"bmv2:192.168.123.4:9093#21/2-bmv2:192.168.123.4:9090#11/2": {
"basic": {}
},
"bmv2:192.168.123.4:9090#11/3-bmv2:192.168.123.4:9094#22/1": {
"basic": {}
},
"bmv2:192.168.123.4:9094#22/1-bmv2:192.168.123.4:9090#11/3": {
"basic": {}
},
"bmv2:192.168.123.4:9090#11/4-bmv2:192.168.123.4:9095#23/1": {
"basic": {}
},
"bmv2:192.168.123.4:9095#23/1-bmv2:192.168.123.4:9090#11/4": {
"basic": {}
},
"bmv2:192.168.123.4:9091#12/1-bmv2:192.168.123.4:9093#21/3": {
"basic": {}
},
"bmv2:192.168.123.4:9093#21/3-bmv2:192.168.123.4:9091#12/1": {
"basic": {}
},
"bmv2:192.168.123.4:9091#12/2-bmv2:192.168.123.4:9094#22/2": {
"basic": {}
},
"bmv2:192.168.123.4:9094#22/2-bmv2:192.168.123.4:9091#12/2": {
"basic": {}
},
"bmv2:192.168.123.4:9091#12/3-bmv2:192.168.123.4:9094#22/3": {
"basic": {}
},
"bmv2:192.168.123.4:9094#22/3-bmv2:192.168.123.4:9091#12/3": {
"basic": {}
},
"bmv2:192.168.123.4:9091#12/4-bmv2:192.168.123.4:9095#23/2": {
"basic": {}
},
"bmv2:192.168.123.4:9095#23/2-bmv2:192.168.123.4:9091#12/4": {
"basic": {}
},
"bmv2:192.168.123.4:9092#13/1-bmv2:192.168.123.4:9093#21/4": {
"basic": {}
},
"bmv2:192.168.123.4:9093#21/4-bmv2:192.168.123.4:9092#13/1": {
"basic": {}
},
"bmv2:192.168.123.4:9092#13/2-bmv2:192.168.123.4:9094#22/4": {
"basic": {}
},
"bmv2:192.168.123.4:9094#22/4-bmv2:192.168.123.4:9092#13/2": {
"basic": {}
},
"bmv2:192.168.123.4:9092#13/3-bmv2:192.168.123.4:9095#23/3": {
"basic": {}
},
"bmv2:192.168.123.4:9095#23/3-bmv2:192.168.123.4:9092#13/3": {
"basic": {}
},
"bmv2:192.168.123.4:9092#13/4-bmv2:192.168.123.4:9095#23/4": {
"basic": {}
},
"bmv2:192.168.123.4:9095#23/4-bmv2:192.168.123.4:9092#13/4": {
"basic": {}
}
},
"hosts": {
"00:00:00:00:00:01/-1": {
"basic": {
"locations": ["bmv2:192.168.123.4:9090#11/5"],
"ips": [
"10.0.0.1"
],
"name": "h1",
"latitude": 36,
"longitude": -107
}
},
"00:00:00:00:00:02/-1": {
"basic": {
"locations": ["bmv2:192.168.123.4:9091#12/5"],
"ips": [
"10.0.0.2"
],
"name": "h2",
"latitude": 36,
"longitude": -99
}
},
"00:00:00:00:00:03/-1": {
"basic": {
"locations": ["bmv2:192.168.123.4:9092#13/5"],
"ips": [
"10.0.0.3"
],
"name": "h3",
"latitude": 36,
"longitude": -91
}
}
}
}

127
tools/test/topos/bmv2-demo.py Normal file → Executable file
View File

@ -2,8 +2,18 @@
import os
import sys
import json
import argparse
TEMP_NETCFG_FILE = '/tmp/bmv2-demo-cfg.json'
BASE_LONGITUDE = -115
SWITCH_BASE_LATITUDE = 25
HOST_BASE_LATITUDE = 28
BASE_SHIFT = 8
VLAN_NONE = -1
DEFAULT_SW_BW = 50
DEFAULT_HOST_BW = 25
if 'ONOS_ROOT' not in os.environ:
print "Environment var $ONOS_ROOT not set"
exit()
@ -28,47 +38,52 @@ from mininet.link import TCLink
from mininet.log import setLogLevel
from mininet.net import Mininet
from mininet.node import RemoteController, Host
from mininet.topo import Topo, SingleSwitchTopo
from mininet.topo import Topo
class ClosTopo(Topo):
"2 stage Clos topology"
def __init__(self, **opts):
def __init__(self, pipeconfId="", **opts):
# Initialize topology and default options
Topo.__init__(self, **opts)
bmv2SwitchIds = ["s11", "s12", "s13", "s21", "s22", "s23"]
bmv2Switches = {}
tport = 9090
for switchId in bmv2SwitchIds:
deviceId=int(switchId[1:])
# Use first number in device id to calculate latitude (row number)
latitude = SWITCH_BASE_LATITUDE + (deviceId // 10) * BASE_SHIFT
# Use second number in device id to calculate longitude (column number)
longitude = BASE_LONGITUDE + (deviceId % 10) * BASE_SHIFT
bmv2Switches[switchId] = self.addSwitch(switchId,
cls=ONOSBmv2Switch,
loglevel="warn",
deviceId=int(switchId[1:]),
thriftPort=tport)
tport += 1
deviceId=deviceId,
netcfg=False,
longitude=longitude,
latitude=latitude,
pipeconfId=pipeconfId)
for i in (1, 2, 3):
for j in (1, 2, 3):
if i == j:
# 2 links
self.addLink(bmv2Switches["s1%d" % i], bmv2Switches["s2%d" % j],
cls=TCLink, bw=50)
cls=TCLink, bw=DEFAULT_SW_BW)
self.addLink(bmv2Switches["s1%d" % i], bmv2Switches["s2%d" % j],
cls=TCLink, bw=50)
cls=TCLink, bw=DEFAULT_SW_BW)
else:
self.addLink(bmv2Switches["s1%d" % i], bmv2Switches["s2%d" % j],
cls=TCLink, bw=50)
cls=TCLink, bw=DEFAULT_SW_BW)
for hostId in (1, 2, 3):
host = self.addHost("h%d" % hostId,
cls=DemoHost,
ip="10.0.0.%d/24" % hostId,
mac='00:00:00:00:00:%02x' % hostId)
self.addLink(host, bmv2Switches["s1%d" % hostId], cls=TCLink, bw=22)
self.addLink(host, bmv2Switches["s1%d" % hostId], cls=TCLink, bw=DEFAULT_HOST_BW)
class DemoHost(Host):
@ -82,10 +97,8 @@ class DemoHost(Host):
def config(self, **params):
r = super(Host, self).config(**params)
self.defaultIntf().rename("eth0")
for off in ["rx", "tx", "sg"]:
cmd = "/sbin/ethtool --offload eth0 %s off" % off
cmd = "/sbin/ethtool --offload %s %s off" % (self.defaultIntf(), off)
self.cmd(cmd)
# disable IPv6
@ -130,17 +143,83 @@ class DemoHost(Host):
def getCmdBg(self, cmd, logfile="/dev/null"):
return "{} > {} 2>&1 &".format(cmd, logfile)
def generateNetcfg(onosIp, net):
netcfg = { 'devices': {}, 'links': {}, 'hosts': {}}
# Device configs
for sw in net.switches:
srcIp = sw.getSourceIp(onosIp)
netcfg['devices'][sw.onosDeviceId] = sw.getDeviceConfig(srcIp)
hostLocations = {}
# Link configs
for link in net.links:
switchPort = link.intf1.name.split('-')
sw1Name = switchPort[0] # s11
port1Name = switchPort[1] # eth0
port1 = port1Name[3:]
switchPort = link.intf2.name.split('-')
sw2Name = switchPort[0]
port2Name = switchPort[1]
port2 = port2Name[3:]
sw1 = net[sw1Name]
sw2 = net[sw2Name]
if isinstance(sw1, Host):
# record host location and ignore it
# e.g. {'h1': 'device:bmv2:11'}
hostLocations[sw1.name] = '%s/%s' % (sw2.onosDeviceId, port2)
continue
if isinstance(sw2, Host):
# record host location and ignore it
# e.g. {'h1': 'device:bmv2:11'}
hostLocations[sw2.name] = '%s/%s' % (sw1.onosDeviceId, port1)
continue
linkId = '%s/%s-%s/%s' % (sw1.onosDeviceId, port1, sw2.onosDeviceId, port2)
netcfg['links'][linkId] = {
'basic': {
'type': 'DIRECT',
'bandwidth': 50
}
}
# Host configs
longitude = BASE_LONGITUDE
for host in net.hosts:
longitude = longitude + BASE_SHIFT
hostDefaultIntf = host.defaultIntf()
hostMac = host.MAC(hostDefaultIntf)
hostIp = host.IP(hostDefaultIntf)
hostId = '%s/%d' % (hostMac, VLAN_NONE)
location = hostLocations[host.name]
# use host Id to generate host location
hostConfig = {
'basic': {
'locations': [location],
'ips': [hostIp],
'name': host.name,
'latitude': HOST_BASE_LATITUDE,
'longitude': longitude
}
}
netcfg['hosts'][hostId] = hostConfig
print "Writing network config to %s" % TEMP_NETCFG_FILE
with open(TEMP_NETCFG_FILE, 'w') as tempFile:
json.dump(netcfg, tempFile)
def main(args):
topo = ClosTopo()
setLogLevel('debug')
if not args.onos_ip:
controller = ONOSCluster('c0', 3)
onosIp = controller.nodes()[0].IP()
else:
controller = RemoteController('c0', ip=args.onos_ip, port=args.onos_port)
controller = RemoteController('c0', ip=args.onos_ip)
onosIp = args.onos_ip
topo = ClosTopo(pipeconfId=args.pipeconf_id)
net = Mininet(topo=topo, build=False, controller=[controller])
net.build()
@ -165,9 +244,10 @@ def main(args):
# print "Starting traffic from h1 to h3..."
# net.hosts[0].startIperfClient(net.hosts[-1], flowBw="200k", numFlows=100, duration=10)
print "Setting netcfg..."
call(("%s/onos-netcfg" % RUN_PACK_PATH, onosIp,
"%s/tools/test/topos/bmv2-demo-cfg.json" % ONOS_ROOT))
generateNetcfg(onosIp, net)
print "Uploading netcfg..."
call(("%s/onos-netcfg" % RUN_PACK_PATH, onosIp, TEMP_NETCFG_FILE))
if not args.onos_ip:
ONOSCLI(net)
@ -175,6 +255,7 @@ def main(args):
CLI(net)
net.stop()
call(("rm", "-f", TEMP_NETCFG_FILE))
if __name__ == '__main__':
@ -182,8 +263,8 @@ if __name__ == '__main__':
description='BMv2 mininet demo script (2-stage Clos topology)')
parser.add_argument('--onos-ip', help='ONOS-BMv2 controller IP address',
type=str, action="store", required=False)
parser.add_argument('--onos-port', help='ONOS-BMv2 controller port',
type=int, action="store", default=40123)
parser.add_argument('--pipeconf-id', help='Pipeconf ID for switches',
type=str, action="store", required=False, default='')
args = parser.parse_args()
setLogLevel('info')
main(args)