Allow bmv2-demo mininet topology with arbitrary size
+ made imbalanced striping optional
+ improved generated netcfg
+ various improvements to bmv2.py
Change-Id: Ic297a9d4571bc1987a9cf8fe7bec7c648fb86686
diff --git a/tools/dev/mininet/bmv2.py b/tools/dev/mininet/bmv2.py
index c4e27d5..5a4de21 100644
--- a/tools/dev/mininet/bmv2.py
+++ b/tools/dev/mininet/bmv2.py
@@ -5,7 +5,7 @@
import urllib2
from mininet.log import info, warn, error
-from mininet.node import Switch
+from mininet.node import Switch, Host
if 'ONOS_ROOT' not in os.environ:
error("ERROR: environment var $ONOS_ROOT not set")
@@ -14,6 +14,23 @@
BMV2_TARGET = 'simple_switch_grpc'
ONOS_ROOT = os.environ["ONOS_ROOT"]
CPU_PORT = 255
+PKT_BYTES_TO_DUMP = 80
+
+
+class ONOSHost(Host):
+ def __init__(self, name, inNamespace=True, **params):
+ Host.__init__(self, name, inNamespace=inNamespace, **params)
+
+ def config(self, **params):
+ r = super(Host, self).config(**params)
+ for off in ["rx", "tx", "sg"]:
+ cmd = "/sbin/ethtool --offload %s %s off" % (self.defaultIntf(), off)
+ self.cmd(cmd)
+ # disable IPv6
+ self.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1")
+ self.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1")
+ self.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1")
+ return r
class ONOSBmv2Switch(Switch):
@@ -24,7 +41,7 @@
def __init__(self, name, json=None, debugger=False, loglevel="warn", elogger=False,
persistent=False, grpcPort=None, thriftPort=None, netcfg=True,
- pipeconfId="", **kwargs):
+ pipeconfId="", pktdump=False, **kwargs):
Switch.__init__(self, name, **kwargs)
self.grpcPort = ONOSBmv2Switch.pickUnusedPort() if not grpcPort else grpcPort
self.thriftPort = ONOSBmv2Switch.pickUnusedPort() if not thriftPort else thriftPort
@@ -38,6 +55,7 @@
self.loglevel = loglevel
self.logfile = '/tmp/bmv2-%d.log' % self.deviceId
self.elogger = elogger
+ self.pktdump = pktdump
self.persistent = persistent
self.netcfg = netcfg
self.netcfgfile = '/tmp/bmv2-%d-netcfg.json' % self.deviceId
@@ -102,19 +120,19 @@
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
+ "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
@@ -161,6 +179,8 @@
if self.debugger:
args.append('--debugger')
args.append('--log-console')
+ if self.pktdump:
+ args.append('--pcap --dump-packet-data %d' % PKT_BYTES_TO_DUMP)
args.append('-L%s' % self.loglevel)
args.append('--thrift-port %d' % self.thriftPort)
if not self.json:
@@ -206,3 +226,4 @@
# Exports for bin/mn
switches = {'onosbmv2': ONOSBmv2Switch}
+hosts = {'onoshost': ONOSHost}
diff --git a/tools/test/topos/bmv2-demo.py b/tools/test/topos/bmv2-demo.py
index 4aa7eb5..171cc6f 100755
--- a/tools/test/topos/bmv2-demo.py
+++ b/tools/test/topos/bmv2-demo.py
@@ -4,6 +4,7 @@
import sys
import json
import argparse
+from collections import OrderedDict
TEMP_NETCFG_FILE = '/tmp/bmv2-demo-cfg.json'
BASE_LONGITUDE = -115
@@ -27,7 +28,7 @@
RUN_PACK_PATH = os.environ["RUN_PACK_PATH"]
from onos import ONOSCluster, ONOSCLI
-from bmv2 import ONOSBmv2Switch
+from bmv2 import ONOSBmv2Switch, ONOSHost
from itertools import combinations
from time import sleep
@@ -44,11 +45,15 @@
class ClosTopo(Topo):
"2 stage Clos topology"
- def __init__(self, pipeconfId="", **opts):
+ def __init__(self, args, **opts):
# Initialize topology and default options
Topo.__init__(self, **opts)
- bmv2SwitchIds = ["s11", "s12", "s13", "s21", "s22", "s23"]
+ bmv2SwitchIds = []
+ for row in (1, 2):
+ for col in range(1, args.size + 1):
+ bmv2SwitchIds.append("s%d%d" % (row, col))
+
bmv2Switches = {}
for switchId in bmv2SwitchIds:
@@ -65,21 +70,22 @@
netcfg=False,
longitude=longitude,
latitude=latitude,
- pipeconfId=pipeconfId)
+ pipeconfId=args.pipeconf_id)
- for i in (1, 2, 3):
- for j in (1, 2, 3):
+ for i in range(1, args.size + 1):
+ for j in range(1, args.size + 1):
if i == j:
# 2 links
self.addLink(bmv2Switches["s1%d" % i], bmv2Switches["s2%d" % j],
cls=TCLink, bw=DEFAULT_SW_BW)
- self.addLink(bmv2Switches["s1%d" % i], bmv2Switches["s2%d" % j],
- cls=TCLink, bw=DEFAULT_SW_BW)
+ if args.with_imbalanced_striping:
+ self.addLink(bmv2Switches["s1%d" % i], bmv2Switches["s2%d" % j],
+ cls=TCLink, bw=DEFAULT_SW_BW)
else:
self.addLink(bmv2Switches["s1%d" % i], bmv2Switches["s2%d" % j],
cls=TCLink, bw=DEFAULT_SW_BW)
- for hostId in (1, 2, 3):
+ for hostId in range(1, args.size + 1):
host = self.addHost("h%d" % hostId,
cls=DemoHost,
ip="10.0.0.%d/24" % hostId,
@@ -87,28 +93,14 @@
self.addLink(host, bmv2Switches["s1%d" % hostId], cls=TCLink, bw=DEFAULT_HOST_BW)
-class DemoHost(Host):
+class DemoHost(ONOSHost):
"Demo host"
- def __init__(self, name, inNamespace=True, **params):
- Host.__init__(self, name, inNamespace=inNamespace, **params)
+ def __init__(self, name, **params):
+ ONOSHost.__init__(self, name, **params)
self.exectoken = "/tmp/mn-exec-token-host-%s" % name
self.cmd("touch %s" % self.exectoken)
- def config(self, **params):
- r = super(Host, self).config(**params)
-
- for off in ["rx", "tx", "sg"]:
- cmd = "/sbin/ethtool --offload %s %s off" % (self.defaultIntf(), off)
- self.cmd(cmd)
-
- # disable IPv6
- self.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1")
- self.cmd("sysctl -w net.ipv6.conf.default.disable_ipv6=1")
- self.cmd("sysctl -w net.ipv6.conf.lo.disable_ipv6=1")
-
- return r
-
def startPingBg(self, h):
self.cmd(self.getInfiniteCmdBg("ping -i0.5 %s" % h.IP()))
self.cmd(self.getInfiniteCmdBg("arping -w5000000 %s" % h.IP()))
@@ -146,7 +138,10 @@
def generateNetcfg(onosIp, net, args):
- netcfg = {'devices': {}, 'links': {}, 'hosts': {}}
+ netcfg = OrderedDict()
+ netcfg['devices'] = {}
+ netcfg['links'] = {}
+ netcfg['hosts'] = {}
# Device configs
for sw in net.switches:
srcIp = sw.getSourceIp(onosIp)
@@ -177,13 +172,14 @@
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
+ for linkId in ('%s/%s-%s/%s' % (sw1.onosDeviceId, port1, sw2.onosDeviceId, port2),
+ '%s/%s-%s/%s' % (sw2.onosDeviceId, port2, sw1.onosDeviceId, port1)):
+ netcfg['links'][linkId] = {
+ 'basic': {
+ 'type': 'DIRECT',
+ 'bandwidth': DEFAULT_SW_BW
+ }
}
- }
# Host configs
longitude = BASE_LONGITUDE
@@ -207,6 +203,14 @@
}
netcfg['hosts'][hostId] = hostConfig
+ netcfg["apps"] = {
+ "org.onosproject.core": {
+ "core": {
+ "linkDiscoveryMode": "STRICT"
+ }
+ }
+ }
+
print "Writing network config to %s" % TEMP_NETCFG_FILE
with open(TEMP_NETCFG_FILE, 'w') as tempFile:
json.dump(netcfg, tempFile, indent=4)
@@ -220,7 +224,7 @@
controller = RemoteController('c0', ip=args.onos_ip)
onosIp = args.onos_ip
- topo = ClosTopo(pipeconfId=args.pipeconf_id)
+ topo = ClosTopo(args)
net = Mininet(topo=topo, build=False, controller=[controller])
@@ -265,6 +269,10 @@
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('--size', help='Number of leaf/spine switches',
+ type=int, action="store", required=False, default=2)
+ parser.add_argument('--with-imbalanced-striping', help='Topology with imbalanced striping',
+ type=bool, action="store", required=False, default=False)
parser.add_argument('--pipeconf-id', help='Pipeconf ID for switches',
type=str, action="store", required=False, default='')
args = parser.parse_args()