Minor refactoring of BMv2 mininet scripts

With options to delay pushing the netcfg for each device and generating
the full netcfg JSON for bmv2-demo.

Change-Id: I046a93a8c639f4bb4cf76cbd61b826473760bfb1
This commit is contained in:
Carmelo Cascone 2017-11-22 14:27:06 -08:00
parent 6168994ad6
commit 6ec8f8ff93
2 changed files with 90 additions and 55 deletions

View File

@ -35,7 +35,8 @@ class ONOSHost(Host):
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)
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")
@ -52,7 +53,8 @@ class ONOSBmv2Switch(Switch):
def __init__(self, name, json=None, debugger=False, loglevel="warn", elogger=False,
persistent=False, grpcPort=None, thriftPort=None, netcfg=True, dryrun=False,
pipeconfId="", pktdump=False, valgrind=False, **kwargs):
pipeconfId="", pktdump=False, valgrind=False, netcfgDelay=0,
**kwargs):
Switch.__init__(self, name, **kwargs)
self.grpcPort = ONOSBmv2Switch.pickUnusedPort() if not grpcPort else grpcPort
self.thriftPort = ONOSBmv2Switch.pickUnusedPort() if not thriftPort else thriftPort
@ -71,6 +73,7 @@ class ONOSBmv2Switch(Switch):
self.netcfg = parseBoolean(netcfg)
self.dryrun = parseBoolean(dryrun)
self.valgrind = parseBoolean(valgrind)
self.netcfgDelay = netcfgDelay
self.netcfgfile = '/tmp/bmv2-%d-netcfg.json' % self.deviceId
self.pipeconfId = pipeconfId
if persistent:
@ -229,11 +232,13 @@ class ONOSBmv2Switch(Switch):
out = self.cmd(cmdStr)
if out:
print out
if self.netcfg and self.valgrind:
# With valgrind, it takes some time before the gRPC server is available.
# Wait before pushing the netcfg.
info("\n*** Waiting %d seconds before pushing the config to ONOS...\n" % VALGRIND_SLEEP)
time.sleep(VALGRIND_SLEEP)
if self.netcfg:
if self.valgrind:
# With valgrind, it takes some time before the gRPC server is available.
# Wait before pushing the netcfg.
info("\n*** Waiting %d seconds before pushing the config to ONOS...\n" % VALGRIND_SLEEP)
time.sleep(VALGRIND_SLEEP)
time.sleep(self.netcfgDelay)
try: # onos.py
clist = controllers[0].nodes()

View File

@ -42,8 +42,12 @@ from mininet.node import RemoteController, Host
from mininet.topo import Topo
def getCmdBg(cmd, logfile="/dev/null"):
return "{} > {} 2>&1 &".format(cmd, logfile)
class ClosTopo(Topo):
"2 stage Clos topology"
"""2 stage Clos topology"""
def __init__(self, args, **opts):
# Initialize topology and default options
@ -58,16 +62,17 @@ class ClosTopo(Topo):
for switchId in bmv2SwitchIds:
deviceId = int(switchId[1:])
# Use first number in device id to calculate latitude (row number)
# Use first number in device id to calculate latitude (row number),
# use second to calculate longitude (column 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",
loglevel=args.log_level,
deviceId=deviceId,
netcfg=False,
netcfg=True,
netcfgDelay=0.5,
longitude=longitude,
latitude=latitude,
pipeconfId=args.pipeconf_id)
@ -75,14 +80,17 @@ class ClosTopo(Topo):
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],
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],
# 2 links
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],
self.addLink(bmv2Switches["s1%d" % i],
bmv2Switches["s2%d" % j],
cls=TCLink, bw=DEFAULT_SW_BW)
for hostId in range(1, args.size + 1):
@ -90,11 +98,12 @@ class ClosTopo(Topo):
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=DEFAULT_HOST_BW)
self.addLink(host, bmv2Switches["s1%d" % hostId],
cls=TCLink, bw=DEFAULT_HOST_BW)
class DemoHost(ONOSHost):
"Demo host"
"""Demo host"""
def __init__(self, name, **params):
ONOSHost.__init__(self, name, **params)
@ -109,10 +118,11 @@ class DemoHost(ONOSHost):
self.cmd(self.getInfiniteCmdBg("iperf -s -u"))
def startIperfClient(self, h, flowBw="512k", numFlows=5, duration=5):
iperfCmd = "iperf -c{} -u -b{} -P{} -t{}".format(h.IP(), flowBw, numFlows, duration)
self.cmd(self.getInfiniteCmdBg(iperfCmd, sleep=0))
iperfCmd = "iperf -c{} -u -b{} -P{} -t{}".format(
h.IP(), flowBw, numFlows, duration)
self.cmd(self.getInfiniteCmdBg(iperfCmd, delay=0))
def stop(self):
def stop(self, **kwargs):
self.cmd("killall iperf")
self.cmd("killall ping")
self.cmd("killall arping")
@ -127,28 +137,27 @@ class DemoHost(ONOSHost):
)
print "**********"
def getInfiniteCmdBg(self, cmd, logfile="/dev/null", sleep=1):
def getInfiniteCmdBg(self, cmd, logfile="/dev/null", delay=1):
return "(while [ -e {} ]; " \
"do {}; " \
"sleep {}; " \
"done;) > {} 2>&1 &".format(self.exectoken, cmd, sleep, logfile)
def getCmdBg(self, cmd, logfile="/dev/null"):
return "{} > {} 2>&1 &".format(cmd, logfile)
"done;) > {} 2>&1 &".format(self.exectoken, cmd, delay, logfile)
def generateNetcfg(onosIp, net, args):
netcfg = OrderedDict()
netcfg['hosts'] = {}
netcfg['devices'] = {}
netcfg['links'] = {}
netcfg['hosts'] = {}
# Device configs
for sw in net.switches:
srcIp = sw.getSourceIp(onosIp)
netcfg['devices'][sw.onosDeviceId] = sw.getDeviceConfig(srcIp)
if args.full_netcfg:
# 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
@ -172,14 +181,18 @@ def generateNetcfg(onosIp, net, args):
hostLocations[sw2.name] = '%s/%s' % (sw1.onosDeviceId, port1)
continue
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
if args.full_netcfg:
# Link configs
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
@ -203,13 +216,14 @@ def generateNetcfg(onosIp, net, args):
}
netcfg['hosts'][hostId] = hostConfig
netcfg["apps"] = {
"org.onosproject.core": {
"core": {
"linkDiscoveryMode": "STRICT"
if args.full_netcfg:
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:
@ -233,7 +247,7 @@ def main(args):
print "Network started"
# Generate background traffic.
# Always generate background pings.
sleep(3)
for (h1, h2) in combinations(net.hosts, 2):
h1.startPingBg(h2)
@ -246,14 +260,17 @@ def main(args):
print "Iperf servers started"
# sleep(4)
# print "Starting traffic from h1 to h3..."
# net.hosts[0].startIperfClient(net.hosts[-1], flowBw="200k", numFlows=100, duration=10)
if args.bg_traffic:
sleep(4)
print "Starting iperf clients..."
net.hosts[0].startIperfClient(net.hosts[-1], flowBw="400k",
numFlows=50, duration=10)
generateNetcfg(onosIp, net, args)
if args.netcfg_sleep > 0:
print "Waiting %d seconds before pushing config to ONOS..." % args.netcfg_sleep
print "Waiting %d seconds before pushing config to ONOS..." \
% args.netcfg_sleep
sleep(args.netcfg_sleep)
print "Pushing config to ONOS..."
@ -275,12 +292,25 @@ if __name__ == '__main__':
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('--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='')
parser.add_argument('--netcfg-sleep', help='Seconds to wait before pushing config to ONOS',
parser.add_argument('--netcfg-sleep',
help='Seconds to wait before pushing config to ONOS',
type=int, action="store", required=False, default=5)
args = parser.parse_args()
parser.add_argument('--log-level', help='BMv2 log level',
type=str, action="store", required=False,
default='warn')
parser.add_argument('--full-netcfg',
help='Generate full netcfg JSON with links and devices',
type=bool, action="store", required=False,
default=False)
parser.add_argument('--bg-traffic',
help='Starts background traffic',
type=bool, action="store", required=False,
default=False)
setLogLevel('info')
main(args)
main(parser.parse_args())