[ONOS-6854] refactor bmv2-demo.py
Change-Id: I9b7460b15f6664363f2ff0b16110e2b3bc4dedeb
diff --git a/tools/dev/mininet/bmv2.py b/tools/dev/mininet/bmv2.py
index 5071c88..c4e27d5 100644
--- a/tools/dev/mininet/bmv2.py
+++ b/tools/dev/mininet/bmv2.py
@@ -23,7 +23,8 @@
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 @@
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 @@
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 @@
}
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:
diff --git a/tools/test/topos/bmv2-demo-cfg.json b/tools/test/topos/bmv2-demo-cfg.json
deleted file mode 100644
index 6c745b5..0000000
--- a/tools/test/topos/bmv2-demo-cfg.json
+++ /dev/null
@@ -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
- }
- }
- }
-}
diff --git a/tools/test/topos/bmv2-demo.py b/tools/test/topos/bmv2-demo.py
old mode 100644
new mode 100755
index 646c7353..a2aeaa6
--- a/tools/test/topos/bmv2-demo.py
+++ b/tools/test/topos/bmv2-demo.py
@@ -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.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 @@
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 @@
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 @@
# 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 @@
CLI(net)
net.stop()
+ call(("rm", "-f", TEMP_NETCFG_FILE))
if __name__ == '__main__':
@@ -182,8 +263,8 @@
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)