mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-06 04:36:17 +02:00
[ONOS-6854] refactor bmv2-demo.py
Change-Id: I9b7460b15f6664363f2ff0b16110e2b3bc4dedeb
This commit is contained in:
parent
e3e21ae133
commit
7875cb78bb
@ -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:
|
||||
|
||||
@ -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
127
tools/test/topos/bmv2-demo.py
Normal file → Executable 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)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user