Merge pull request #348 from ggee/miniedit2109

Update to MiniEdit 2.2.0.1
This commit is contained in:
lantz
2014-08-20 22:03:21 -05:00
+386 -110
View File
@@ -13,10 +13,11 @@ Controller icon from http://semlabs.co.uk/
OpenFlow icon from https://www.opennetworking.org/
"""
MINIEDIT_VERSION = '2.1.0.8.1'
MINIEDIT_VERSION = '2.2.0.1'
from optparse import OptionParser
from Tkinter import *
from ttk import Notebook
from tkMessageBox import showinfo, showerror, showwarning
from subprocess import call
import tkFont
@@ -28,6 +29,7 @@ import json
from distutils.version import StrictVersion
import os
import sys
from functools import partial
if 'PYTHONPATH' in os.environ:
sys.path = os.environ[ 'PYTHONPATH' ].split( ':' ) + sys.path
@@ -38,9 +40,10 @@ from mininet.log import info, error, debug, output, setLogLevel
from mininet.net import Mininet, VERSION
from mininet.util import ipStr, netParse, ipAdd, quietRun
from mininet.util import buildTopo
from mininet.util import custom, customConstructor
from mininet.term import makeTerm, cleanUpScreens
from mininet.node import Controller, RemoteController, NOX, OVSController
from mininet.node import CPULimitedHost, Host, Node
from mininet.node import CPULimitedHost, Host, Node, HostWithPrivateDirs
from mininet.node import OVSKernelSwitch, OVSSwitch, UserSwitch
from mininet.link import TCLink, Intf, Link
from mininet.cli import CLI
@@ -66,6 +69,40 @@ CONTROLLERS = { 'ref': Controller,
'nox': NOX,
'remote': RemoteController,
'none': lambda name: None }
LINKDEF = 'default'
LINKS = { 'default': Link,
'tc': TCLink }
HOSTDEF = 'proc'
HOSTS = { 'proc': Host,
'rt': custom( CPULimitedHost, sched='rt' ),
'cfs': custom( CPULimitedHost, sched='cfs' ) }
class CPULimitedHostWithPrivateDirs( CPULimitedHost ):
"Host with private directories"
def __init__( self, name, sched='cfs', **kwargs ):
"privateDirs: list of private directory strings or tuples"
self.name = name
self.privateDirs = kwargs.pop( 'privateDirs', [] )
CPULimitedHost.__init__( self, name, sched, **kwargs )
self.mountPrivateDirs()
def mountPrivateDirs( self ):
"mount private directories"
for directory in self.privateDirs:
if isinstance( directory, tuple ):
# mount given private directory
privateDir = directory[ 1 ] % self.__dict__
mountPoint = directory[ 0 ]
self.cmd( 'mkdir -p %s' % privateDir )
self.cmd( 'mkdir -p %s' % mountPoint )
self.cmd( 'mount --bind %s %s' %
( privateDir, mountPoint ) )
else:
# mount temporary filesystem on directory
self.cmd( 'mkdir -p %s' % directory )
self.cmd( 'mount -n -t tmpfs tmpfs %s' % directory )
class InbandController( RemoteController ):
@@ -124,35 +161,9 @@ class customOvs(OVSSwitch):
def setSwitchIP(self, ip):
self.switchIP = ip
def getOpenFlowVersion(self):
return self.openFlowVersions
def setOpenFlowVersion(self, versions):
self.openFlowVersions = []
if versions['ovsOf10'] == '1':
self.openFlowVersions.append('OpenFlow10')
if versions['ovsOf11'] == '1':
self.openFlowVersions.append('OpenFlow11')
if versions['ovsOf12'] == '1':
self.openFlowVersions.append('OpenFlow12')
if versions['ovsOf13'] == '1':
self.openFlowVersions.append('OpenFlow13')
def configureOpenFlowVersion(self):
if not ( 'OpenFlow11' in self.openFlowVersions or
'OpenFlow12' in self.openFlowVersions or
'OpenFlow13' in self.openFlowVersions ):
return
protoList = ",".join(self.openFlowVersions)
print 'Configuring OpenFlow to '+protoList
self.cmd( 'ovs-vsctl -- set bridge', self, 'protocols='+protoList)
def start( self, controllers ):
# Call superclass constructor
OVSSwitch.start( self, controllers )
# Set OpenFlow Versions
self.configureOpenFlowVersion()
# Set Switch IP address
if (self.switchIP is not None):
self.cmd( 'ifconfig', self, self.switchIP )
@@ -201,7 +212,7 @@ class PrefsDialog(tkSimpleDialog.Dialog):
# Selection of switch type
Label(self.leftfieldFrame, text="Default Switch:").grid(row=3, sticky=E)
self.switchType = StringVar(self.leftfieldFrame)
self.switchTypeMenu = OptionMenu(self.leftfieldFrame, self.switchType, "Open vSwitch", "Indigo Virtual Switch", "Userspace Switch", "Userspace Switch inNamespace")
self.switchTypeMenu = OptionMenu(self.leftfieldFrame, self.switchType, "Open vSwitch Kernel Mode", "Indigo Virtual Switch", "Userspace Switch", "Userspace Switch inNamespace")
self.switchTypeMenu.grid(row=3, column=1, sticky=W)
switchTypePref = self.prefValues['switchType']
if switchTypePref == 'ivs':
@@ -211,7 +222,7 @@ class PrefsDialog(tkSimpleDialog.Dialog):
elif switchTypePref == 'user':
self.switchType.set("Userspace Switch")
else:
self.switchType.set("Open vSwitch")
self.switchType.set("Open vSwitch Kernel Mode")
# Fields for OVS OpenFlow version
@@ -431,36 +442,43 @@ class HostDialog(CustomDialog):
def body(self, master):
self.rootFrame = master
self.leftfieldFrame = Frame(self.rootFrame)
self.leftfieldFrame.grid(row=0, column=0, sticky='nswe', columnspan=2)
self.rightfieldFrame = Frame(self.rootFrame)
self.rightfieldFrame.grid(row=0, column=2, sticky='nswe', columnspan=2)
n = Notebook(self.rootFrame)
self.propFrame = Frame(n)
self.vlanFrame = Frame(n)
self.interfaceFrame = Frame(n)
self.mountFrame = Frame(n)
n.add(self.propFrame, text='Properties')
n.add(self.vlanFrame, text='VLAN Interfaces')
n.add(self.interfaceFrame, text='External Interfaces')
n.add(self.mountFrame, text='Private Directories')
n.pack()
### TAB 1
# Field for Hostname
Label(self.leftfieldFrame, text="Hostname:").grid(row=0, sticky=E)
self.hostnameEntry = Entry(self.leftfieldFrame)
Label(self.propFrame, text="Hostname:").grid(row=0, sticky=E)
self.hostnameEntry = Entry(self.propFrame)
self.hostnameEntry.grid(row=0, column=1)
if 'hostname' in self.prefValues:
self.hostnameEntry.insert(0, self.prefValues['hostname'])
# Field for Switch IP
Label(self.leftfieldFrame, text="IP Address:").grid(row=1, sticky=E)
self.ipEntry = Entry(self.leftfieldFrame)
Label(self.propFrame, text="IP Address:").grid(row=1, sticky=E)
self.ipEntry = Entry(self.propFrame)
self.ipEntry.grid(row=1, column=1)
if 'ip' in self.prefValues:
self.ipEntry.insert(0, self.prefValues['ip'])
# Field for default route
Label(self.leftfieldFrame, text="Default Route:").grid(row=2, sticky=E)
self.routeEntry = Entry(self.leftfieldFrame)
Label(self.propFrame, text="Default Route:").grid(row=2, sticky=E)
self.routeEntry = Entry(self.propFrame)
self.routeEntry.grid(row=2, column=1)
if 'defaultRoute' in self.prefValues:
self.routeEntry.insert(0, self.prefValues['defaultRoute'])
# Field for CPU
Label(self.rightfieldFrame, text="Amount CPU:").grid(row=0, sticky=E)
self.cpuEntry = Entry(self.rightfieldFrame)
self.cpuEntry.grid(row=0, column=1)
Label(self.propFrame, text="Amount CPU:").grid(row=3, sticky=E)
self.cpuEntry = Entry(self.propFrame)
self.cpuEntry.grid(row=3, column=1)
if 'cpu' in self.prefValues:
self.cpuEntry.insert(0, str(self.prefValues['cpu']))
# Selection of Scheduler
@@ -468,26 +486,40 @@ class HostDialog(CustomDialog):
sched = self.prefValues['sched']
else:
sched = 'host'
self.schedVar = StringVar(self.rightfieldFrame)
self.schedOption = OptionMenu(self.rightfieldFrame, self.schedVar, "host", "cfs", "rt")
self.schedOption.grid(row=0, column=2, sticky=W)
self.schedVar = StringVar(self.propFrame)
self.schedOption = OptionMenu(self.propFrame, self.schedVar, "host", "cfs", "rt")
self.schedOption.grid(row=3, column=2, sticky=W)
self.schedVar.set(sched)
# Selection of Cores
Label(self.rightfieldFrame, text="Cores:").grid(row=1, sticky=E)
self.coreEntry = Entry(self.rightfieldFrame)
self.coreEntry.grid(row=1, column=1)
Label(self.propFrame, text="Cores:").grid(row=4, sticky=E)
self.coreEntry = Entry(self.propFrame)
self.coreEntry.grid(row=4, column=1)
if 'cores' in self.prefValues:
self.coreEntry.insert(1, self.prefValues['cores'])
# Start command
Label(self.propFrame, text="Start Command:").grid(row=5, sticky=E)
self.startEntry = Entry(self.propFrame)
self.startEntry.grid(row=5, column=1, sticky='nswe', columnspan=3)
if 'startCommand' in self.prefValues:
self.startEntry.insert(0, str(self.prefValues['startCommand']))
# Stop command
Label(self.propFrame, text="Stop Command:").grid(row=6, sticky=E)
self.stopEntry = Entry(self.propFrame)
self.stopEntry.grid(row=6, column=1, sticky='nswe', columnspan=3)
if 'stopCommand' in self.prefValues:
self.stopEntry.insert(0, str(self.prefValues['stopCommand']))
### TAB 2
# External Interfaces
self.externalInterfaces = 0
Label(self.rootFrame, text="External Interface:").grid(row=1, column=0, sticky=E)
self.b = Button( self.rootFrame, text='Add', command=self.addInterface)
self.b.grid(row=1, column=1)
Label(self.interfaceFrame, text="External Interface:").grid(row=0, column=0, sticky=E)
self.b = Button( self.interfaceFrame, text='Add', command=self.addInterface)
self.b.grid(row=0, column=1)
self.interfaceFrame = VerticalScrolledTable(self.rootFrame, rows=0, columns=1, title='External Interfaces')
self.interfaceFrame.grid(row=2, column=0, sticky='nswe', columnspan=2)
self.interfaceFrame = VerticalScrolledTable(self.interfaceFrame, rows=0, columns=1, title='External Interfaces')
self.interfaceFrame.grid(row=1, column=0, sticky='nswe', columnspan=2)
self.tableFrame = self.interfaceFrame.interior
self.tableFrame.addRow(value=['Interface Name'], readonly=True)
@@ -499,14 +531,15 @@ class HostDialog(CustomDialog):
for externalInterface in externalInterfaces:
self.tableFrame.addRow(value=[externalInterface])
### TAB 3
# VLAN Interfaces
self.vlanInterfaces = 0
Label(self.rootFrame, text="VLAN Interface:").grid(row=1, column=2, sticky=E)
self.vlanButton = Button( self.rootFrame, text='Add', command=self.addVlanInterface)
self.vlanButton.grid(row=1, column=3)
Label(self.vlanFrame, text="VLAN Interface:").grid(row=0, column=0, sticky=E)
self.vlanButton = Button( self.vlanFrame, text='Add', command=self.addVlanInterface)
self.vlanButton.grid(row=0, column=1)
self.vlanFrame = VerticalScrolledTable(self.rootFrame, rows=0, columns=2, title='VLAN Interfaces')
self.vlanFrame.grid(row=2, column=2, sticky='nswe', columnspan=2)
self.vlanFrame = VerticalScrolledTable(self.vlanFrame, rows=0, columns=2, title='VLAN Interfaces')
self.vlanFrame.grid(row=1, column=0, sticky='nswe', columnspan=2)
self.vlanTableFrame = self.vlanFrame.interior
self.vlanTableFrame.addRow(value=['IP Address','VLAN ID'], readonly=True)
@@ -516,6 +549,31 @@ class HostDialog(CustomDialog):
for vlanInterface in vlanInterfaces:
self.vlanTableFrame.addRow(value=vlanInterface)
### TAB 4
# Private Directories
self.privateDirectories = 0
Label(self.mountFrame, text="Private Directory:").grid(row=0, column=0, sticky=E)
self.mountButton = Button( self.mountFrame, text='Add', command=self.addDirectory)
self.mountButton.grid(row=0, column=1)
self.mountFrame = VerticalScrolledTable(self.mountFrame, rows=0, columns=2, title='Directories')
self.mountFrame.grid(row=1, column=0, sticky='nswe', columnspan=2)
self.mountTableFrame = self.mountFrame.interior
self.mountTableFrame.addRow(value=['Mount','Persistent Directory'], readonly=True)
directoryList = []
if 'privateDirectory' in self.prefValues:
directoryList = self.prefValues['privateDirectory']
for privateDir in directoryList:
if isinstance( privateDir, tuple ):
self.mountTableFrame.addRow(value=privateDir)
else:
self.mountTableFrame.addRow(value=[privateDir,''])
def addDirectory( self ):
self.mountTableFrame.addRow()
def addVlanInterface( self ):
self.vlanTableFrame.addRow()
@@ -534,6 +592,13 @@ class HostDialog(CustomDialog):
len(self.vlanTableFrame.get(row, 1)) > 0 and
row > 0):
vlanInterfaces.append([self.vlanTableFrame.get(row, 0), self.vlanTableFrame.get(row, 1)])
privateDirectories = []
for row in range(self.mountTableFrame.rows):
if (len(self.mountTableFrame.get(row, 0)) > 0 and row > 0):
if(len(self.mountTableFrame.get(row, 1)) > 0):
privateDirectories.append((self.mountTableFrame.get(row, 0), self.mountTableFrame.get(row, 1)))
else:
privateDirectories.append(self.mountTableFrame.get(row, 0))
results = {'cpu': self.cpuEntry.get(),
'cores':self.coreEntry.get(),
@@ -541,6 +606,9 @@ class HostDialog(CustomDialog):
'hostname':self.hostnameEntry.get(),
'ip':self.ipEntry.get(),
'defaultRoute':self.routeEntry.get(),
'startCommand':self.startEntry.get(),
'stopCommand':self.stopEntry.get(),
'privateDirectory':privateDirectories,
'externalInterfaces':externalInterfaces,
'vlanInterfaces':vlanInterfaces}
self.result = results
@@ -555,34 +623,35 @@ class SwitchDialog(CustomDialog):
def body(self, master):
self.rootFrame = master
self.leftfieldFrame = Frame(self.rootFrame)
self.rightfieldFrame = Frame(self.rootFrame)
self.leftfieldFrame.grid(row=0, column=0, sticky='nswe')
self.rightfieldFrame.grid(row=0, column=1, sticky='nswe')
rowCount = 0
externalInterfaces = []
if 'externalInterfaces' in self.prefValues:
externalInterfaces = self.prefValues['externalInterfaces']
self.fieldFrame = Frame(self.rootFrame)
self.fieldFrame.grid(row=0, column=0, sticky='nswe')
# Field for Hostname
Label(self.fieldFrame, text="Hostname:").grid(row=rowCount, sticky=E)
self.hostnameEntry = Entry(self.fieldFrame)
Label(self.leftfieldFrame, text="Hostname:").grid(row=rowCount, sticky=E)
self.hostnameEntry = Entry(self.leftfieldFrame)
self.hostnameEntry.grid(row=rowCount, column=1)
self.hostnameEntry.insert(0, self.prefValues['hostname'])
rowCount+=1
# Field for DPID
Label(self.fieldFrame, text="DPID:").grid(row=rowCount, sticky=E)
self.dpidEntry = Entry(self.fieldFrame)
Label(self.leftfieldFrame, text="DPID:").grid(row=rowCount, sticky=E)
self.dpidEntry = Entry(self.leftfieldFrame)
self.dpidEntry.grid(row=rowCount, column=1)
if 'dpid' in self.prefValues:
self.dpidEntry.insert(0, self.prefValues['dpid'])
rowCount+=1
# Field for Netflow
Label(self.fieldFrame, text="Enable NetFlow:").grid(row=rowCount, sticky=E)
Label(self.leftfieldFrame, text="Enable NetFlow:").grid(row=rowCount, sticky=E)
self.nflow = IntVar()
self.nflowButton = Checkbutton(self.fieldFrame, variable=self.nflow)
self.nflowButton = Checkbutton(self.leftfieldFrame, variable=self.nflow)
self.nflowButton.grid(row=rowCount, column=1, sticky=W)
if 'netflow' in self.prefValues:
if self.prefValues['netflow'] == '0':
@@ -594,9 +663,9 @@ class SwitchDialog(CustomDialog):
rowCount+=1
# Field for sflow
Label(self.fieldFrame, text="Enable sFlow:").grid(row=rowCount, sticky=E)
Label(self.leftfieldFrame, text="Enable sFlow:").grid(row=rowCount, sticky=E)
self.sflow = IntVar()
self.sflowButton = Checkbutton(self.fieldFrame, variable=self.sflow)
self.sflowButton = Checkbutton(self.leftfieldFrame, variable=self.sflow)
self.sflowButton.grid(row=rowCount, column=1, sticky=W)
if 'sflow' in self.prefValues:
if self.prefValues['sflow'] == '0':
@@ -608,9 +677,9 @@ class SwitchDialog(CustomDialog):
rowCount+=1
# Selection of switch type
Label(self.fieldFrame, text="Switch Type:").grid(row=rowCount, sticky=E)
self.switchType = StringVar(self.fieldFrame)
self.switchTypeMenu = OptionMenu(self.fieldFrame, self.switchType, "Default", "Open vSwitch", "Indigo Virtual Switch", "Userspace Switch", "Userspace Switch inNamespace")
Label(self.leftfieldFrame, text="Switch Type:").grid(row=rowCount, sticky=E)
self.switchType = StringVar(self.leftfieldFrame)
self.switchTypeMenu = OptionMenu(self.leftfieldFrame, self.switchType, "Default", "Open vSwitch Kernel Mode", "Indigo Virtual Switch", "Userspace Switch", "Userspace Switch inNamespace")
self.switchTypeMenu.grid(row=rowCount, column=1, sticky=W)
if 'switchType' in self.prefValues:
switchTypePref = self.prefValues['switchType']
@@ -621,7 +690,7 @@ class SwitchDialog(CustomDialog):
elif switchTypePref == 'user':
self.switchType.set("Userspace Switch")
elif switchTypePref == 'ovs':
self.switchType.set("Open vSwitch")
self.switchType.set("Open vSwitch Kernel Mode")
else:
self.switchType.set("Default")
else:
@@ -629,34 +698,49 @@ class SwitchDialog(CustomDialog):
rowCount+=1
# Field for Switch IP
Label(self.fieldFrame, text="IP Address:").grid(row=rowCount, sticky=E)
self.ipEntry = Entry(self.fieldFrame)
Label(self.leftfieldFrame, text="IP Address:").grid(row=rowCount, sticky=E)
self.ipEntry = Entry(self.leftfieldFrame)
self.ipEntry.grid(row=rowCount, column=1)
if 'switchIP' in self.prefValues:
self.ipEntry.insert(0, self.prefValues['switchIP'])
rowCount+=1
# Field for DPCTL port
Label(self.fieldFrame, text="DPCTL port:").grid(row=rowCount, sticky=E)
self.dpctlEntry = Entry(self.fieldFrame)
Label(self.leftfieldFrame, text="DPCTL port:").grid(row=rowCount, sticky=E)
self.dpctlEntry = Entry(self.leftfieldFrame)
self.dpctlEntry.grid(row=rowCount, column=1)
if 'dpctl' in self.prefValues:
self.dpctlEntry.insert(0, self.prefValues['dpctl'])
rowCount+=1
# External Interfaces
Label(self.fieldFrame, text="External Interface:").grid(row=rowCount, sticky=E)
self.b = Button( self.fieldFrame, text='Add', command=self.addInterface)
self.b.grid(row=rowCount, column=1)
Label(self.rightfieldFrame, text="External Interface:").grid(row=0, sticky=E)
self.b = Button( self.rightfieldFrame, text='Add', command=self.addInterface)
self.b.grid(row=0, column=1)
self.interfaceFrame = VerticalScrolledTable(self.rootFrame, rows=0, columns=1, title='External Interfaces')
self.interfaceFrame.grid(row=2, column=0, sticky='nswe')
self.interfaceFrame = VerticalScrolledTable(self.rightfieldFrame, rows=0, columns=1, title='External Interfaces')
self.interfaceFrame.grid(row=1, column=0, sticky='nswe', columnspan=2)
self.tableFrame = self.interfaceFrame.interior
# Add defined interfaces
for externalInterface in externalInterfaces:
self.tableFrame.addRow(value=[externalInterface])
rowCount+=1
self.commandFrame = Frame(self.rootFrame)
self.commandFrame.grid(row=1, column=0, sticky='nswe', columnspan=2)
self.commandFrame.columnconfigure(1, weight=1)
# Start command
Label(self.commandFrame, text="Start Command:").grid(row=0, column=0, sticky=W)
self.startEntry = Entry(self.commandFrame)
self.startEntry.grid(row=0, column=1, sticky='nsew')
if 'startCommand' in self.prefValues:
self.startEntry.insert(0, str(self.prefValues['startCommand']))
# Stop command
Label(self.commandFrame, text="Stop Command:").grid(row=1, column=0, sticky=W)
self.stopEntry = Entry(self.commandFrame)
self.stopEntry.grid(row=1, column=1, sticky='nsew')
if 'stopCommand' in self.prefValues:
self.stopEntry.insert(0, str(self.prefValues['stopCommand']))
def addInterface( self ):
self.tableFrame.addRow()
@@ -692,6 +776,8 @@ class SwitchDialog(CustomDialog):
results = {'externalInterfaces':externalInterfaces,
'hostname':self.hostnameEntry.get(),
'dpid':dpid,
'startCommand':self.startEntry.get(),
'stopCommand':self.stopEntry.get(),
'sflow':str(self.sflow.get()),
'netflow':str(self.nflow.get()),
'dpctl':self.dpctlEntry.get(),
@@ -707,7 +793,7 @@ class SwitchDialog(CustomDialog):
results['switchType'] = 'userns'
elif sw == 'Userspace Switch':
results['switchType'] = 'user'
elif sw == 'Open vSwitch':
elif sw == 'Open vSwitch Kernel Mode':
results['switchType'] = 'ovs'
else:
results['switchType'] = 'default'
@@ -877,6 +963,7 @@ class ControllerDialog(tkSimpleDialog.Dialog):
def body(self, master):
self.var = StringVar(master)
self.protcolvar = StringVar(master)
rowCount=0
# Field for Hostname
@@ -908,6 +995,20 @@ class ControllerDialog(tkSimpleDialog.Dialog):
self.var.set("OVS Controller")
rowCount+=1
# Field for Controller Protcol
Label(master, text="Protocol:").grid(row=rowCount, sticky=E)
if 'controllerProtocol' in self.ctrlrValues:
controllerProtocol = self.ctrlrValues['controllerProtocol']
else:
controllerProtocol = 'tcp'
self.protcol = OptionMenu(master, self.protcolvar, "TCP", "SSL")
self.protcol.grid(row=rowCount, column=1, sticky=W)
if controllerProtocol == 'ssl':
self.protcolvar.set("SSL")
else:
self.protcolvar.set("TCP")
rowCount+=1
# Field for Remove Controller IP
remoteFrame= LabelFrame(master, text='Remote/In-Band Controller', padx=5, pady=5)
remoteFrame.grid(row=rowCount, column=0, columnspan=2, sticky=W)
@@ -921,14 +1022,11 @@ class ControllerDialog(tkSimpleDialog.Dialog):
return self.hostnameEntry # initial focus
def apply(self):
hostname = self.hostnameEntry.get()
controllerType = self.var.get()
remoteIP = self.e1.get()
controllerPort = int(self.e2.get())
self.result = { 'hostname': hostname,
'remoteIP': remoteIP,
'remotePort': controllerPort}
self.result = { 'hostname': self.hostnameEntry.get(),
'remoteIP': self.e1.get(),
'remotePort': int(self.e2.get())}
controllerType = self.var.get()
if controllerType == 'Remote Controller':
self.result['controllerType'] = 'remote'
elif controllerType == 'In-Band Controller':
@@ -937,6 +1035,11 @@ class ControllerDialog(tkSimpleDialog.Dialog):
self.result['controllerType'] = 'ref'
else:
self.result['controllerType'] = 'ovsc'
controllerProtocol = self.protcolvar.get()
if controllerProtocol == 'SSL':
self.result['controllerProtocol'] = 'ssl'
else:
self.result['controllerProtocol'] = 'tcp'
class ToolTip(object):
@@ -1144,7 +1247,7 @@ class MiniEdit( Frame ):
fileMenu.add_command( label="New", font=font, command=self.newTopology )
fileMenu.add_command( label="Open", font=font, command=self.loadTopology )
fileMenu.add_command( label="Save", font=font, command=self.saveTopology )
fileMenu.add_command( label="Export", font=font, command=self.exportTopology )
fileMenu.add_command( label="Export Level 2 Script", font=font, command=self.exportScript )
fileMenu.add_separator()
fileMenu.add_command( label='Quit', command=self.quit, font=font )
@@ -1305,6 +1408,17 @@ class MiniEdit( Frame ):
self.itemToWidget[ item ] = icon
icon.links = {}
def convertJsonUnicode(self, input):
"Some part of Mininet don't like Unicode"
if isinstance(input, dict):
return {self.convertJsonUnicode(key): self.convertJsonUnicode(value) for key, value in input.iteritems()}
elif isinstance(input, list):
return [self.convertJsonUnicode(element) for element in input]
elif isinstance(input, unicode):
return input.encode('utf-8')
else:
return input
def loadTopology( self ):
"Load command."
c = self.canvas
@@ -1317,7 +1431,7 @@ class MiniEdit( Frame ):
if f == None:
return
self.newTopology()
loadedTopology = eval(f.read())
loadedTopology = self.convertJsonUnicode(json.load(f))
# Load application preferences
if 'application' in loadedTopology:
@@ -1372,6 +1486,16 @@ class MiniEdit( Frame ):
x = host['x']
y = host['y']
self.addNode('Host', nodeNum, float(x), float(y), name=hostname)
# Fix JSON converting tuple to list when saving
if 'privateDirectory' in host['opts']:
newDirList = []
for privateDir in host['opts']['privateDirectory']:
if isinstance( privateDir, list ):
newDirList.append((privateDir[0],privateDir[1]))
else:
newDirList.append(privateDir)
host['opts']['privateDirectory'] = newDirList
self.hostOpts[hostname] = host['opts']
icon = self.findWidgetByName(hostname)
icon.bind('<Button-3>', self.do_hostPopup )
@@ -1545,14 +1669,13 @@ class MiniEdit( Frame ):
try:
f = open(fileName, 'wb')
#f.write(str(savingDictionary))
f.write(json.dumps(savingDictionary, sort_keys=True, indent=4, separators=(',', ': ')))
except Exception as er:
print er
finally:
f.close()
def exportTopology( self ):
def exportScript( self ):
"Export command."
myFormats = [
('Mininet Custom Topology','*.py'),
@@ -1575,6 +1698,7 @@ class MiniEdit( Frame ):
f.write("from mininet.cli import CLI\n")
f.write("from mininet.log import setLogLevel, info\n")
f.write("from mininet.link import TCLink, Intf\n")
f.write("from subprocess import call\n")
inBandCtrl = False
hasLegacySwitch = False
@@ -1613,6 +1737,10 @@ class MiniEdit( Frame ):
if 'Controller' in tags:
opts = self.controllers[name]
controllerType = opts['controllerType']
if 'controllerProtocol' in opts:
controllerProtocol = opts['controllerProtocol']
else:
controllerProtocol = 'tcp'
controllerIP = opts['remoteIP']
controllerPort = opts['remotePort']
@@ -1630,6 +1758,7 @@ class MiniEdit( Frame ):
else:
f.write(" controller=Controller,\n")
f.write(" protocol='"+controllerProtocol+"',\n")
f.write(" port="+str(controllerPort)+")\n")
f.write("\n")
@@ -1757,7 +1886,7 @@ class MiniEdit( Frame ):
f.write(" "+srcName+dstName+" = "+linkOpts+"\n")
f.write(" net.addLink("+srcName+", "+dstName)
if optsExist:
f.write(", link=TCLink , **"+srcName+dstName)
f.write(", cls=TCLink , **"+srcName+dstName)
f.write(")\n")
f.write("\n")
@@ -1780,7 +1909,7 @@ class MiniEdit( Frame ):
f.write("\n")
f.write(" info( '*** Configuring switches\\n')\n")
f.write(" info( '*** Post configure switches and hosts\\n')\n")
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
@@ -1821,10 +1950,75 @@ class MiniEdit( Frame ):
for vlanInterface in opts['vlanInterfaces']:
f.write(" "+name+".cmd('vconfig add "+name+"-eth0 "+vlanInterface[1]+"')\n")
f.write(" "+name+".cmd('ifconfig "+name+"-eth0."+vlanInterface[1]+" "+vlanInterface[0]+"')\n")
# Run User Defined Start Command
if ('startCommand' in opts):
f.write(" "+name+".cmdPrint('"+opts['startCommand']+"')\n")
if 'Switch' in tags:
opts = self.switchOpts[name]
# Run User Defined Start Command
if ('startCommand' in opts):
f.write(" "+name+".cmdPrint('"+opts['startCommand']+"')\n")
# Configure NetFlow
nflowValues = self.appPrefs['netflow']
if len(nflowValues['nflowTarget']) > 0:
nflowEnabled = False
nflowSwitches = ''
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
if 'Switch' in tags:
opts = self.switchOpts[name]
if 'netflow' in opts:
if opts['netflow'] == '1':
nflowSwitches = nflowSwitches+' -- set Bridge '+name+' netflow=@MiniEditNF'
nflowEnabled=True
if nflowEnabled:
nflowCmd = 'ovs-vsctl -- --id=@MiniEditNF create NetFlow '+ 'target=\\\"'+nflowValues['nflowTarget']+'\\\" '+ 'active-timeout='+nflowValues['nflowTimeout']
if nflowValues['nflowAddId'] == '1':
nflowCmd = nflowCmd + ' add_id_to_interface=true'
else:
nflowCmd = nflowCmd + ' add_id_to_interface=false'
f.write(" \n")
f.write(" call('"+nflowCmd+nflowSwitches+"', shell=True)\n")
# Configure sFlow
sflowValues = self.appPrefs['sflow']
if len(sflowValues['sflowTarget']) > 0:
sflowEnabled = False
sflowSwitches = ''
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
if 'Switch' in tags:
opts = self.switchOpts[name]
if 'sflow' in opts:
if opts['sflow'] == '1':
sflowSwitches = sflowSwitches+' -- set Bridge '+name+' sflow=@MiniEditSF'
sflowEnabled=True
if sflowEnabled:
sflowCmd = 'ovs-vsctl -- --id=@MiniEditSF create sFlow '+ 'target=\\\"'+sflowValues['sflowTarget']+'\\\" '+ 'header='+sflowValues['sflowHeader']+' '+ 'sampling='+sflowValues['sflowSampling']+' '+ 'polling='+sflowValues['sflowPolling']
f.write(" \n")
f.write(" call('"+sflowCmd+sflowSwitches+"', shell=True)\n")
f.write("\n")
f.write(" CLI(net)\n")
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
if 'Host' in tags:
opts = self.hostOpts[name]
# Run User Defined Stop Command
if ('stopCommand' in opts):
f.write(" "+name+".cmdPrint('"+opts['stopCommand']+"')\n")
if 'Switch' in tags:
opts = self.switchOpts[name]
# Run User Defined Stop Command
if ('stopCommand' in opts):
f.write(" "+name+".cmdPrint('"+opts['stopCommand']+"')\n")
f.write(" net.stop()\n")
f.write("\n")
f.write("if __name__ == '__main__':\n")
@@ -1948,6 +2142,7 @@ class MiniEdit( Frame ):
name = self.nodePrefixes[ node ] + str( self.controllerCount )
ctrlr = { 'controllerType': 'ref',
'hostname': name,
'controllerProtocol': 'tcp',
'remoteIP': '127.0.0.1',
'remotePort': 6633}
self.controllers[name] = ctrlr
@@ -2272,6 +2467,10 @@ class MiniEdit( Frame ):
if hostBox.result:
newHostOpts = {'nodeNum':self.hostOpts[name]['nodeNum']}
newHostOpts['sched'] = hostBox.result['sched']
if len(hostBox.result['startCommand']) > 0:
newHostOpts['startCommand'] = hostBox.result['startCommand']
if len(hostBox.result['stopCommand']) > 0:
newHostOpts['stopCommand'] = hostBox.result['stopCommand']
if len(hostBox.result['cpu']) > 0:
newHostOpts['cpu'] = float(hostBox.result['cpu'])
if len(hostBox.result['cores']) > 0:
@@ -2288,6 +2487,8 @@ class MiniEdit( Frame ):
newHostOpts['externalInterfaces'] = hostBox.result['externalInterfaces']
if len(hostBox.result['vlanInterfaces']) > 0:
newHostOpts['vlanInterfaces'] = hostBox.result['vlanInterfaces']
if len(hostBox.result['privateDirectory']) > 0:
newHostOpts['privateDirectory'] = hostBox.result['privateDirectory']
self.hostOpts[name] = newHostOpts
print 'New host details for ' + name + ' = ' + str(newHostOpts)
@@ -2309,6 +2510,10 @@ class MiniEdit( Frame ):
newSwitchOpts = {'nodeNum':self.switchOpts[name]['nodeNum']}
newSwitchOpts['switchType'] = switchBox.result['switchType']
newSwitchOpts['controllers'] = self.switchOpts[name]['controllers']
if len(switchBox.result['startCommand']) > 0:
newSwitchOpts['startCommand'] = switchBox.result['startCommand']
if len(switchBox.result['stopCommand']) > 0:
newSwitchOpts['stopCommand'] = switchBox.result['stopCommand']
if len(switchBox.result['dpctl']) > 0:
newSwitchOpts['dpctl'] = switchBox.result['dpctl']
if len(switchBox.result['dpid']) > 0:
@@ -2498,6 +2703,7 @@ class MiniEdit( Frame ):
if 'Switch' in tags:
opts = self.switchOpts[name]
#print str(opts)
# Create the correct switch class
switchClass = customOvs
@@ -2525,13 +2731,28 @@ class MiniEdit( Frame ):
switchClass = IVSSwitch
else:
switchClass = customOvs
if switchClass == customOvs:
# Set OpenFlow versions
self.openFlowVersions = []
if self.appPrefs['openFlowVersions']['ovsOf10'] == '1':
self.openFlowVersions.append('OpenFlow10')
if self.appPrefs['openFlowVersions']['ovsOf11'] == '1':
self.openFlowVersions.append('OpenFlow11')
if self.appPrefs['openFlowVersions']['ovsOf12'] == '1':
self.openFlowVersions.append('OpenFlow12')
if self.appPrefs['openFlowVersions']['ovsOf13'] == '1':
self.openFlowVersions.append('OpenFlow13')
protoList = ",".join(self.openFlowVersions)
switchParms['protocols'] = protoList
newSwitch = net.addSwitch( name , cls=switchClass, **switchParms)
# Some post startup config
if switchClass == CustomUserSwitch:
if ('switchIP' in opts):
if (len(opts['switchIP']) > 0):
newSwitch.setSwitchIP(opts['switchIP'])
if switchClass == customOvs:
newSwitch.setOpenFlowVersion(self.appPrefs['openFlowVersions'])
if ('switchIP' in opts):
if (len(opts['switchIP']) > 0):
newSwitch.setSwitchIP(opts['switchIP'])
@@ -2548,6 +2769,7 @@ class MiniEdit( Frame ):
newSwitch = net.addHost( name , cls=LegacyRouter)
elif 'Host' in tags:
opts = self.hostOpts[name]
#print str(opts)
ip = None
defaultRoute = None
if 'defaultRoute' in opts and len(opts['defaultRoute']) > 0:
@@ -2560,9 +2782,18 @@ class MiniEdit( Frame ):
ip = ipAdd(i=nodeNum, prefixLen=prefixLen, ipBaseNum=ipBaseNum)
# Create the correct host class
hostCls = Host
if 'cores' in opts or 'cpu' in opts:
if ('privateDirectory' in opts):
hostCls = partial( CPULimitedHostWithPrivateDirs,
privateDirs=opts['privateDirectory'] )
else:
hostCls=CPULimitedHost
else:
if ('privateDirectory' in opts):
hostCls = partial( HostWithPrivateDirs,
privateDirs=opts['privateDirectory'] )
else:
hostCls=Host
newHost = net.addHost( name,
cls=hostCls,
ip=ip,
@@ -2590,28 +2821,37 @@ class MiniEdit( Frame ):
# Get controller info from panel
controllerType = opts['controllerType']
if 'controllerProtocol' in opts:
controllerProtocol = opts['controllerProtocol']
else:
controllerProtocol = 'tcp'
opts['controllerProtocol'] = 'tcp'
controllerIP = opts['remoteIP']
controllerPort = opts['remotePort']
# Make controller
print 'Getting controller selection:'+controllerType
controllerIP = opts['remoteIP']
controllerPort = opts['remotePort']
if controllerType == 'remote':
net.addController(name=name,
controller=RemoteController,
ip=controllerIP,
protocol=controllerProtocol,
port=controllerPort)
elif controllerType == 'inband':
net.addController(name=name,
controller=InbandController,
ip=controllerIP,
protocol=controllerProtocol,
port=controllerPort)
elif controllerType == 'ovsc':
net.addController(name=name,
controller=OVSController,
protocol=controllerProtocol,
port=controllerPort)
else:
net.addController(name=name,
controller=Controller,
protocol=controllerProtocol,
port=controllerPort)
else:
@@ -2637,11 +2877,13 @@ class MiniEdit( Frame ):
dst=link['dest']
linkopts=link['linkOpts']
srcName, dstName = src[ 'text' ], dst[ 'text' ]
src, dst = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
srcNode, dstNode = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
if linkopts:
net.addLink(src, dst, cls=TCLink, **linkopts)
net.addLink(srcNode, dstNode, cls=TCLink, **linkopts)
else:
net.addLink(src, dst)
#print str(srcNode)
#print str(dstNode)
net.addLink(srcNode, dstNode)
self.canvas.itemconfig(key, dash=())
@@ -2667,19 +2909,28 @@ class MiniEdit( Frame ):
def postStartSetup( self ):
# Setup host VLAN subinterfaces
# Setup host details
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
if 'Host' in tags:
newHost = self.net.get(name)
opts = self.hostOpts[name]
# Attach vlan interfaces
if ('vlanInterfaces' in opts):
for vlanInterface in opts['vlanInterfaces']:
print 'adding vlan interface '+vlanInterface[1]
newHost = self.net.get(name)
newHost.cmdPrint('vconfig add '+name+'-eth0 '+vlanInterface[1])
newHost.cmdPrint('ifconfig '+name+'-eth0.'+vlanInterface[1]+' '+vlanInterface[0])
# Run User Defined Start Command
if ('startCommand' in opts):
newHost.cmdPrint(opts['startCommand'])
if 'Switch' in tags:
newNode = self.net.get(name)
opts = self.switchOpts[name]
# Run User Defined Start Command
if ('startCommand' in opts):
newNode.cmdPrint(opts['startCommand'])
# Configure NetFlow
nflowValues = self.appPrefs['netflow']
@@ -2782,6 +3033,23 @@ class MiniEdit( Frame ):
def stop( self ):
"Stop network."
if self.net is not None:
# Stop host details
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
if 'Host' in tags:
newHost = self.net.get(name)
opts = self.hostOpts[name]
# Run User Defined Stop Command
if ('stopCommand' in opts):
newHost.cmdPrint(opts['stopCommand'])
if 'Switch' in tags:
newNode = self.net.get(name)
opts = self.switchOpts[name]
# Run User Defined Stop Command
if ('stopCommand' in opts):
newNode.cmdPrint(opts['stopCommand'])
self.net.stop()
cleanUpScreens()
self.net = None
@@ -2908,6 +3176,8 @@ class MiniEdit( Frame ):
opts = OptionParser( description=desc, usage=usage )
addDictOption( opts, TOPOS, TOPODEF, 'topo' )
addDictOption( opts, LINKS, LINKDEF, 'link' )
opts.add_option( '--custom', type='string', default=None,
help='read custom topo and node params from .py' +
'file' )
@@ -2947,7 +3217,8 @@ class MiniEdit( Frame ):
return
self.newTopology()
topo = buildTopo( TOPOS, self.options.topo )
importNet = Mininet(topo=topo, build=False)
link = customConstructor( LINKS, self.options.link )
importNet = Mininet(topo=topo, build=False, link=link)
importNet.build()
c = self.canvas
@@ -2965,6 +3236,7 @@ class MiniEdit( Frame ):
icon.bind('<Button-3>', self.do_controllerPopup )
ctrlr = { 'controllerType': 'ref',
'hostname': name,
'controllerProtocol': controller.protocol,
'remoteIP': controller.ip,
'remotePort': controller.port}
self.controllers[name] = ctrlr
@@ -3038,6 +3310,7 @@ class MiniEdit( Frame ):
print 'links:'+str(len(topo.links()))
#[('h1', 's3'), ('h2', 's4'), ('s3', 's4')]
for link in topo.links():
print str(link)
srcNode = link[0]
src = self.findWidgetByName(srcNode)
sx, sy = self.canvas.coords( self.widgetToItem[ src ] )
@@ -3046,10 +3319,13 @@ class MiniEdit( Frame ):
dest = self.findWidgetByName(destNode)
dx, dy = self.canvas.coords( self.widgetToItem[ dest] )
params = topo.linkInfo( srcNode, destNode )
print 'Link Parameters='+str(params)
self.link = self.canvas.create_line( sx, sy, dx, dy, width=4,
fill='blue', tag='link' )
c.itemconfig(self.link, tags=c.gettags(self.link)+('data',))
self.addLink( src, dest )
self.addLink( src, dest, linkopts=params )
self.createDataLinkBindings()
self.link = self.linkWidget = None