Update to 2.1.0.8
This commit is contained in:
+367
-37
@@ -10,9 +10,10 @@ Bob Lantz, April 2010
|
|||||||
Gregory Gee, July 2013
|
Gregory Gee, July 2013
|
||||||
|
|
||||||
Controller icon from http://semlabs.co.uk/
|
Controller icon from http://semlabs.co.uk/
|
||||||
|
OpenFlow icon from https://www.opennetworking.org/
|
||||||
"""
|
"""
|
||||||
|
|
||||||
MINIEDIT_VERSION = '2.1.0.7.1'
|
MINIEDIT_VERSION = '2.1.0.8'
|
||||||
|
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
from Tkinter import *
|
from Tkinter import *
|
||||||
@@ -39,9 +40,9 @@ from mininet.util import ipStr, netParse, ipAdd, quietRun
|
|||||||
from mininet.util import buildTopo
|
from mininet.util import buildTopo
|
||||||
from mininet.term import makeTerm, cleanUpScreens
|
from mininet.term import makeTerm, cleanUpScreens
|
||||||
from mininet.node import Controller, RemoteController, NOX, OVSController
|
from mininet.node import Controller, RemoteController, NOX, OVSController
|
||||||
from mininet.node import CPULimitedHost, Host
|
from mininet.node import CPULimitedHost, Host, Node
|
||||||
from mininet.node import OVSKernelSwitch, OVSSwitch
|
from mininet.node import OVSKernelSwitch, OVSSwitch, UserSwitch
|
||||||
from mininet.link import TCLink, Intf
|
from mininet.link import TCLink, Intf, Link
|
||||||
from mininet.cli import CLI
|
from mininet.cli import CLI
|
||||||
from mininet.moduledeps import moduleDeps, pathCheck
|
from mininet.moduledeps import moduleDeps, pathCheck
|
||||||
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
from mininet.topo import SingleSwitchTopo, LinearTopo, SingleSwitchReversedTopo
|
||||||
@@ -71,10 +72,49 @@ class InbandController( RemoteController ):
|
|||||||
"Overridden to do nothing."
|
"Overridden to do nothing."
|
||||||
return
|
return
|
||||||
|
|
||||||
|
class CustomUserSwitch(UserSwitch):
|
||||||
|
def __init__( self, name, dpopts='--no-slicing', **kwargs ):
|
||||||
|
UserSwitch.__init__( self, name, **kwargs )
|
||||||
|
self.switchIP = None
|
||||||
|
|
||||||
|
def getSwitchIP(self):
|
||||||
|
return self.switchIP
|
||||||
|
|
||||||
|
def setSwitchIP(self, ip):
|
||||||
|
self.switchIP = ip
|
||||||
|
|
||||||
|
def start( self, controllers ):
|
||||||
|
# Call superclass constructor
|
||||||
|
UserSwitch.start( self, controllers )
|
||||||
|
# Set Switch IP address
|
||||||
|
if (self.switchIP is not None):
|
||||||
|
if not self.inNamespace:
|
||||||
|
self.cmd( 'ifconfig', self, self.switchIP )
|
||||||
|
else:
|
||||||
|
self.cmd( 'ifconfig lo', self.switchIP )
|
||||||
|
|
||||||
|
class LegacyRouter( Node ):
|
||||||
|
|
||||||
|
def __init__( self, name, inNamespace=True, **params ):
|
||||||
|
Node.__init__( self, name, inNamespace, **params )
|
||||||
|
|
||||||
|
def config( self, **_params ):
|
||||||
|
if self.intfs:
|
||||||
|
self.setParam( _params, 'setIP', ip='0.0.0.0' )
|
||||||
|
r = Node.config( self, **_params )
|
||||||
|
self.cmd('sysctl -w net.ipv4.ip_forward=1')
|
||||||
|
return r
|
||||||
|
|
||||||
|
class LegacySwitch(OVSSwitch):
|
||||||
|
|
||||||
|
def __init__( self, name, **params ):
|
||||||
|
OVSSwitch.__init__( self, name, failMode='standalone', **params )
|
||||||
|
self.switchIP = None
|
||||||
|
|
||||||
class customOvs(OVSSwitch):
|
class customOvs(OVSSwitch):
|
||||||
|
|
||||||
def __init__( self, name, failMode='secure', datapath='kernel', **params ):
|
def __init__( self, name, failMode='secure', datapath='kernel', **params ):
|
||||||
OVSSwitch.__init__( self, name, **params )
|
OVSSwitch.__init__( self, name, failMode=failMode, datapath=datapath, **params )
|
||||||
self.switchIP = None
|
self.switchIP = None
|
||||||
|
|
||||||
def getSwitchIP(self):
|
def getSwitchIP(self):
|
||||||
@@ -160,11 +200,15 @@ class PrefsDialog(tkSimpleDialog.Dialog):
|
|||||||
# Selection of switch type
|
# Selection of switch type
|
||||||
Label(self.leftfieldFrame, text="Default Switch:").grid(row=3, sticky=E)
|
Label(self.leftfieldFrame, text="Default Switch:").grid(row=3, sticky=E)
|
||||||
self.switchType = StringVar(self.leftfieldFrame)
|
self.switchType = StringVar(self.leftfieldFrame)
|
||||||
self.switchTypeMenu = OptionMenu(self.leftfieldFrame, self.switchType, "Open vSwitch", "Indigo Virtual Switch")
|
self.switchTypeMenu = OptionMenu(self.leftfieldFrame, self.switchType, "Open vSwitch", "Indigo Virtual Switch", "Userspace Switch", "Userspace Switch inNamespace")
|
||||||
self.switchTypeMenu.grid(row=3, column=1, sticky=W)
|
self.switchTypeMenu.grid(row=3, column=1, sticky=W)
|
||||||
switchTypePref = self.prefValues['switchType']
|
switchTypePref = self.prefValues['switchType']
|
||||||
if switchTypePref == 'ivs':
|
if switchTypePref == 'ivs':
|
||||||
self.switchType.set("Indigo Virtual Switch")
|
self.switchType.set("Indigo Virtual Switch")
|
||||||
|
elif switchTypePref == 'userns':
|
||||||
|
self.switchType.set("Userspace Switch inNamespace")
|
||||||
|
elif switchTypePref == 'user':
|
||||||
|
self.switchType.set("Userspace Switch")
|
||||||
else:
|
else:
|
||||||
self.switchType.set("Open vSwitch")
|
self.switchType.set("Open vSwitch")
|
||||||
|
|
||||||
@@ -299,6 +343,10 @@ class PrefsDialog(tkSimpleDialog.Dialog):
|
|||||||
self.ovsOk = False
|
self.ovsOk = False
|
||||||
showerror(title="Error",
|
showerror(title="Error",
|
||||||
message='MiniNet version 2.1+ required. You have '+VERSION+'.')
|
message='MiniNet version 2.1+ required. You have '+VERSION+'.')
|
||||||
|
elif sw == 'Userspace Switch':
|
||||||
|
self.result['switchType'] = 'user'
|
||||||
|
elif sw == 'Userspace Switch inNamespace':
|
||||||
|
self.result['switchType'] = 'userns'
|
||||||
else:
|
else:
|
||||||
self.result['switchType'] = 'ovs'
|
self.result['switchType'] = 'ovs'
|
||||||
|
|
||||||
@@ -561,12 +609,16 @@ class SwitchDialog(CustomDialog):
|
|||||||
# Selection of switch type
|
# Selection of switch type
|
||||||
Label(self.fieldFrame, text="Switch Type:").grid(row=rowCount, sticky=E)
|
Label(self.fieldFrame, text="Switch Type:").grid(row=rowCount, sticky=E)
|
||||||
self.switchType = StringVar(self.fieldFrame)
|
self.switchType = StringVar(self.fieldFrame)
|
||||||
self.switchTypeMenu = OptionMenu(self.fieldFrame, self.switchType, "Default", "Open vSwitch", "Indigo Virtual Switch")
|
self.switchTypeMenu = OptionMenu(self.fieldFrame, self.switchType, "Default", "Open vSwitch", "Indigo Virtual Switch", "Userspace Switch", "Userspace Switch inNamespace")
|
||||||
self.switchTypeMenu.grid(row=rowCount, column=1, sticky=W)
|
self.switchTypeMenu.grid(row=rowCount, column=1, sticky=W)
|
||||||
if 'switchType' in self.prefValues:
|
if 'switchType' in self.prefValues:
|
||||||
switchTypePref = self.prefValues['switchType']
|
switchTypePref = self.prefValues['switchType']
|
||||||
if switchTypePref == 'ivs':
|
if switchTypePref == 'ivs':
|
||||||
self.switchType.set("Indigo Virtual Switch")
|
self.switchType.set("Indigo Virtual Switch")
|
||||||
|
elif switchTypePref == 'userns':
|
||||||
|
self.switchType.set("Userspace Switch inNamespace")
|
||||||
|
elif switchTypePref == 'user':
|
||||||
|
self.switchType.set("Userspace Switch")
|
||||||
elif switchTypePref == 'ovs':
|
elif switchTypePref == 'ovs':
|
||||||
self.switchType.set("Open vSwitch")
|
self.switchType.set("Open vSwitch")
|
||||||
else:
|
else:
|
||||||
@@ -650,6 +702,10 @@ class SwitchDialog(CustomDialog):
|
|||||||
self.ovsOk = False
|
self.ovsOk = False
|
||||||
showerror(title="Error",
|
showerror(title="Error",
|
||||||
message='MiniNet version 2.1+ required. You have '+VERSION+'.')
|
message='MiniNet version 2.1+ required. You have '+VERSION+'.')
|
||||||
|
elif sw == 'Userspace Switch inNamespace':
|
||||||
|
results['switchType'] = 'userns'
|
||||||
|
elif sw == 'Userspace Switch':
|
||||||
|
results['switchType'] = 'user'
|
||||||
elif sw == 'Open vSwitch':
|
elif sw == 'Open vSwitch':
|
||||||
results['switchType'] = 'ovs'
|
results['switchType'] = 'ovs'
|
||||||
else:
|
else:
|
||||||
@@ -881,11 +937,48 @@ class ControllerDialog(tkSimpleDialog.Dialog):
|
|||||||
else:
|
else:
|
||||||
self.result['controllerType'] = 'ovsc'
|
self.result['controllerType'] = 'ovsc'
|
||||||
|
|
||||||
|
class ToolTip(object):
|
||||||
|
|
||||||
|
def __init__(self, widget):
|
||||||
|
self.widget = widget
|
||||||
|
self.tipwindow = None
|
||||||
|
self.id = None
|
||||||
|
self.x = self.y = 0
|
||||||
|
|
||||||
|
def showtip(self, text):
|
||||||
|
"Display text in tooltip window"
|
||||||
|
self.text = text
|
||||||
|
if self.tipwindow or not self.text:
|
||||||
|
return
|
||||||
|
x, y, cx, cy = self.widget.bbox("insert")
|
||||||
|
x = x + self.widget.winfo_rootx() + 27
|
||||||
|
y = y + cy + self.widget.winfo_rooty() +27
|
||||||
|
self.tipwindow = tw = Toplevel(self.widget)
|
||||||
|
tw.wm_overrideredirect(1)
|
||||||
|
tw.wm_geometry("+%d+%d" % (x, y))
|
||||||
|
try:
|
||||||
|
# For Mac OS
|
||||||
|
tw.tk.call("::tk::unsupported::MacWindowStyle",
|
||||||
|
"style", tw._w,
|
||||||
|
"help", "noActivates")
|
||||||
|
except TclError:
|
||||||
|
pass
|
||||||
|
label = Label(tw, text=self.text, justify=LEFT,
|
||||||
|
background="#ffffe0", relief=SOLID, borderwidth=1,
|
||||||
|
font=("tahoma", "8", "normal"))
|
||||||
|
label.pack(ipadx=1)
|
||||||
|
|
||||||
|
def hidetip(self):
|
||||||
|
tw = self.tipwindow
|
||||||
|
self.tipwindow = None
|
||||||
|
if tw:
|
||||||
|
tw.destroy()
|
||||||
|
|
||||||
class MiniEdit( Frame ):
|
class MiniEdit( Frame ):
|
||||||
|
|
||||||
"A simple network editor for Mininet."
|
"A simple network editor for Mininet."
|
||||||
|
|
||||||
def __init__( self, parent=None, cheight=400, cwidth=800 ):
|
def __init__( self, parent=None, cheight=600, cwidth=1000 ):
|
||||||
|
|
||||||
self.defaultIpBase='10.0.0.0/8'
|
self.defaultIpBase='10.0.0.0/8'
|
||||||
|
|
||||||
@@ -941,7 +1034,7 @@ class MiniEdit( Frame ):
|
|||||||
self.images = miniEditImages()
|
self.images = miniEditImages()
|
||||||
self.buttons = {}
|
self.buttons = {}
|
||||||
self.active = None
|
self.active = None
|
||||||
self.tools = ( 'Select', 'Host', 'Switch', 'Link', 'Controller' )
|
self.tools = ( 'Select', 'Host', 'Switch', 'LegacySwitch', 'LegacyRouter', 'NetLink', 'Controller' )
|
||||||
self.customColors = { 'Switch': 'darkGreen', 'Host': 'blue' }
|
self.customColors = { 'Switch': 'darkGreen', 'Host': 'blue' }
|
||||||
self.toolbar = self.createToolbar()
|
self.toolbar = self.createToolbar()
|
||||||
|
|
||||||
@@ -957,7 +1050,7 @@ class MiniEdit( Frame ):
|
|||||||
|
|
||||||
# Initialize node data
|
# Initialize node data
|
||||||
self.nodeBindings = self.createNodeBindings()
|
self.nodeBindings = self.createNodeBindings()
|
||||||
self.nodePrefixes = { 'Switch': 's', 'Host': 'h' , 'Controller': 'c'}
|
self.nodePrefixes = { 'LegacyRouter': 'r', 'LegacySwitch': 's', 'Switch': 's', 'Host': 'h' , 'Controller': 'c'}
|
||||||
self.widgetToItem = {}
|
self.widgetToItem = {}
|
||||||
self.itemToWidget = {}
|
self.itemToWidget = {}
|
||||||
|
|
||||||
@@ -983,13 +1076,18 @@ class MiniEdit( Frame ):
|
|||||||
self.hostRunPopup.add_separator()
|
self.hostRunPopup.add_separator()
|
||||||
self.hostRunPopup.add_command(label='Terminal', font=self.font, command=self.xterm )
|
self.hostRunPopup.add_command(label='Terminal', font=self.font, command=self.xterm )
|
||||||
|
|
||||||
|
self.legacyRouterRunPopup = Menu(self.top, tearoff=0)
|
||||||
|
self.legacyRouterRunPopup.add_command(label='Router Options', font=self.font)
|
||||||
|
self.legacyRouterRunPopup.add_separator()
|
||||||
|
self.legacyRouterRunPopup.add_command(label='Terminal', font=self.font, command=self.xterm )
|
||||||
|
|
||||||
self.switchPopup = Menu(self.top, tearoff=0)
|
self.switchPopup = Menu(self.top, tearoff=0)
|
||||||
self.switchPopup.add_command(label='Swtich Options', font=self.font)
|
self.switchPopup.add_command(label='Switch Options', font=self.font)
|
||||||
self.switchPopup.add_separator()
|
self.switchPopup.add_separator()
|
||||||
self.switchPopup.add_command(label='Properties', font=self.font, command=self.switchDetails )
|
self.switchPopup.add_command(label='Properties', font=self.font, command=self.switchDetails )
|
||||||
|
|
||||||
self.switchRunPopup = Menu(self.top, tearoff=0)
|
self.switchRunPopup = Menu(self.top, tearoff=0)
|
||||||
self.switchRunPopup.add_command(label='Swtich Options', font=self.font)
|
self.switchRunPopup.add_command(label='Switch Options', font=self.font)
|
||||||
self.switchRunPopup.add_separator()
|
self.switchRunPopup.add_separator()
|
||||||
self.switchRunPopup.add_command(label='List bridge details', font=self.font, command=self.listBridge )
|
self.switchRunPopup.add_command(label='List bridge details', font=self.font, command=self.listBridge )
|
||||||
|
|
||||||
@@ -1132,6 +1230,16 @@ class MiniEdit( Frame ):
|
|||||||
# Activate dynamic bindings
|
# Activate dynamic bindings
|
||||||
self.active = toolName
|
self.active = toolName
|
||||||
|
|
||||||
|
|
||||||
|
def createToolTip(self, widget, text):
|
||||||
|
toolTip = ToolTip(widget)
|
||||||
|
def enter(event):
|
||||||
|
toolTip.showtip(text)
|
||||||
|
def leave(event):
|
||||||
|
toolTip.hidetip()
|
||||||
|
widget.bind('<Enter>', enter)
|
||||||
|
widget.bind('<Leave>', leave)
|
||||||
|
|
||||||
def createToolbar( self ):
|
def createToolbar( self ):
|
||||||
"Create and return our toolbar frame."
|
"Create and return our toolbar frame."
|
||||||
|
|
||||||
@@ -1143,6 +1251,7 @@ class MiniEdit( Frame ):
|
|||||||
b = Button( toolbar, text=tool, font=self.smallFont, command=cmd)
|
b = Button( toolbar, text=tool, font=self.smallFont, command=cmd)
|
||||||
if tool in self.images:
|
if tool in self.images:
|
||||||
b.config( height=35, image=self.images[ tool ] )
|
b.config( height=35, image=self.images[ tool ] )
|
||||||
|
self.createToolTip(b, str(tool))
|
||||||
# b.config( compound='top' )
|
# b.config( compound='top' )
|
||||||
b.pack( fill='x' )
|
b.pack( fill='x' )
|
||||||
self.buttons[ tool ] = b
|
self.buttons[ tool ] = b
|
||||||
@@ -1283,10 +1392,19 @@ class MiniEdit( Frame ):
|
|||||||
switch['opts']['nodeNum'] = int(nodeNum)
|
switch['opts']['nodeNum'] = int(nodeNum)
|
||||||
x = switch['x']
|
x = switch['x']
|
||||||
y = switch['y']
|
y = switch['y']
|
||||||
|
if switch['opts']['switchType'] == "legacyRouter":
|
||||||
|
self.addNode('LegacyRouter', nodeNum, float(x), float(y), name=hostname)
|
||||||
|
icon = self.findWidgetByName(hostname)
|
||||||
|
icon.bind('<Button-3>', self.do_legacyRouterPopup )
|
||||||
|
elif switch['opts']['switchType'] == "legacySwitch":
|
||||||
|
self.addNode('LegacySwitch', nodeNum, float(x), float(y), name=hostname)
|
||||||
|
icon = self.findWidgetByName(hostname)
|
||||||
|
icon.bind('<Button-3>', self.do_legacySwitchPopup )
|
||||||
|
else:
|
||||||
self.addNode('Switch', nodeNum, float(x), float(y), name=hostname)
|
self.addNode('Switch', nodeNum, float(x), float(y), name=hostname)
|
||||||
self.switchOpts[hostname] = switch['opts']
|
|
||||||
icon = self.findWidgetByName(hostname)
|
icon = self.findWidgetByName(hostname)
|
||||||
icon.bind('<Button-3>', self.do_switchPopup )
|
icon.bind('<Button-3>', self.do_switchPopup )
|
||||||
|
self.switchOpts[hostname] = switch['opts']
|
||||||
|
|
||||||
# create links to controllers
|
# create links to controllers
|
||||||
if (int(loadedTopology['version']) > 1):
|
if (int(loadedTopology['version']) > 1):
|
||||||
@@ -1381,7 +1499,7 @@ class MiniEdit( Frame ):
|
|||||||
name = widget[ 'text' ]
|
name = widget[ 'text' ]
|
||||||
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
||||||
x1, y1 = self.canvas.coords( self.widgetToItem[ widget ] )
|
x1, y1 = self.canvas.coords( self.widgetToItem[ widget ] )
|
||||||
if 'Switch' in tags:
|
if 'Switch' in tags or 'LegacySwitch' in tags or 'LegacyRouter' in tags:
|
||||||
nodeNum = self.switchOpts[name]['nodeNum']
|
nodeNum = self.switchOpts[name]['nodeNum']
|
||||||
nodeToSave = {'number':str(nodeNum),
|
nodeToSave = {'number':str(nodeNum),
|
||||||
'x':str(x1),
|
'x':str(x1),
|
||||||
@@ -1449,8 +1567,8 @@ class MiniEdit( Frame ):
|
|||||||
f.write("\n")
|
f.write("\n")
|
||||||
f.write("from mininet.net import Mininet\n")
|
f.write("from mininet.net import Mininet\n")
|
||||||
f.write("from mininet.node import Controller, RemoteController, OVSController\n")
|
f.write("from mininet.node import Controller, RemoteController, OVSController\n")
|
||||||
f.write("from mininet.node import CPULimitedHost, Host\n")
|
f.write("from mininet.node import CPULimitedHost, Host, Node\n")
|
||||||
f.write("from mininet.node import OVSKernelSwitch\n")
|
f.write("from mininet.node import OVSKernelSwitch, UserSwitch\n")
|
||||||
if StrictVersion(VERSION) > StrictVersion('2.0'):
|
if StrictVersion(VERSION) > StrictVersion('2.0'):
|
||||||
f.write("from mininet.node import IVSSwitch\n")
|
f.write("from mininet.node import IVSSwitch\n")
|
||||||
f.write("from mininet.cli import CLI\n")
|
f.write("from mininet.cli import CLI\n")
|
||||||
@@ -1458,6 +1576,7 @@ class MiniEdit( Frame ):
|
|||||||
f.write("from mininet.link import TCLink, Intf\n")
|
f.write("from mininet.link import TCLink, Intf\n")
|
||||||
|
|
||||||
inBandCtrl = False
|
inBandCtrl = False
|
||||||
|
hasLegacySwitch = False
|
||||||
for widget in self.widgetToItem:
|
for widget in self.widgetToItem:
|
||||||
name = widget[ 'text' ]
|
name = widget[ 'text' ]
|
||||||
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
||||||
@@ -1483,8 +1602,7 @@ class MiniEdit( Frame ):
|
|||||||
if len(self.appPrefs['dpctl']) > 0:
|
if len(self.appPrefs['dpctl']) > 0:
|
||||||
f.write(" listenPort="+self.appPrefs['dpctl']+",\n")
|
f.write(" listenPort="+self.appPrefs['dpctl']+",\n")
|
||||||
f.write(" build=False,\n")
|
f.write(" build=False,\n")
|
||||||
f.write(" ipBase='"+self.appPrefs['ipBase']+"',\n")
|
f.write(" ipBase='"+self.appPrefs['ipBase']+"')\n")
|
||||||
f.write(" link=TCLink)\n")
|
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
f.write(" info( '*** Adding controller\\n' )\n")
|
f.write(" info( '*** Adding controller\\n' )\n")
|
||||||
for widget in self.widgetToItem:
|
for widget in self.widgetToItem:
|
||||||
@@ -1519,6 +1637,11 @@ class MiniEdit( Frame ):
|
|||||||
for widget in self.widgetToItem:
|
for widget in self.widgetToItem:
|
||||||
name = widget[ 'text' ]
|
name = widget[ 'text' ]
|
||||||
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
||||||
|
if 'LegacyRouter' in tags:
|
||||||
|
f.write(" "+name+" = net.addHost('"+name+"', cls=Node, ip='0.0.0.0')\n")
|
||||||
|
f.write(" "+name+".cmd('sysctl -w net.ipv4.ip_forward=1')\n")
|
||||||
|
if 'LegacySwitch' in tags:
|
||||||
|
f.write(" "+name+" = net.addSwitch('"+name+"', cls=OVSKernelSwitch, failMode='standalone')\n")
|
||||||
if 'Switch' in tags:
|
if 'Switch' in tags:
|
||||||
opts = self.switchOpts[name]
|
opts = self.switchOpts[name]
|
||||||
nodeNum = opts['nodeNum']
|
nodeNum = opts['nodeNum']
|
||||||
@@ -1526,10 +1649,18 @@ class MiniEdit( Frame ):
|
|||||||
if opts['switchType'] == 'default':
|
if opts['switchType'] == 'default':
|
||||||
if self.appPrefs['switchType'] == 'ivs':
|
if self.appPrefs['switchType'] == 'ivs':
|
||||||
f.write(", cls=IVSSwitch")
|
f.write(", cls=IVSSwitch")
|
||||||
|
elif self.appPrefs['switchType'] == 'user':
|
||||||
|
f.write(", cls=UserSwitch")
|
||||||
|
elif self.appPrefs['switchType'] == 'userns':
|
||||||
|
f.write(", cls=UserSwitch, inNamespace=True")
|
||||||
else:
|
else:
|
||||||
f.write(", cls=OVSKernelSwitch")
|
f.write(", cls=OVSKernelSwitch")
|
||||||
elif opts['switchType'] == 'ivs':
|
elif opts['switchType'] == 'ivs':
|
||||||
f.write(", cls=IVSSwitch")
|
f.write(", cls=IVSSwitch")
|
||||||
|
elif opts['switchType'] == 'user':
|
||||||
|
f.write(", cls=UserSwitch")
|
||||||
|
elif opts['switchType'] == 'userns':
|
||||||
|
f.write(", cls=UserSwitch, inNamespace=True")
|
||||||
else:
|
else:
|
||||||
f.write(", cls=OVSKernelSwitch")
|
f.write(", cls=OVSKernelSwitch")
|
||||||
if 'dpctl' in opts:
|
if 'dpctl' in opts:
|
||||||
@@ -1625,7 +1756,7 @@ class MiniEdit( Frame ):
|
|||||||
f.write(" "+srcName+dstName+" = "+linkOpts+"\n")
|
f.write(" "+srcName+dstName+" = "+linkOpts+"\n")
|
||||||
f.write(" net.addLink("+srcName+", "+dstName)
|
f.write(" net.addLink("+srcName+", "+dstName)
|
||||||
if optsExist:
|
if optsExist:
|
||||||
f.write(", **"+srcName+dstName)
|
f.write(", link=TCLink , **"+srcName+dstName)
|
||||||
f.write(")\n")
|
f.write(")\n")
|
||||||
|
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
@@ -1641,7 +1772,7 @@ class MiniEdit( Frame ):
|
|||||||
for widget in self.widgetToItem:
|
for widget in self.widgetToItem:
|
||||||
name = widget[ 'text' ]
|
name = widget[ 'text' ]
|
||||||
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
||||||
if 'Switch' in tags:
|
if 'Switch' in tags or 'LegacySwitch' in tags:
|
||||||
opts = self.switchOpts[name]
|
opts = self.switchOpts[name]
|
||||||
ctrlList = ",".join(opts['controllers'])
|
ctrlList = ",".join(opts['controllers'])
|
||||||
f.write(" net.get('"+name+"').start(["+ctrlList+"])\n")
|
f.write(" net.get('"+name+"').start(["+ctrlList+"])\n")
|
||||||
@@ -1654,6 +1785,28 @@ class MiniEdit( Frame ):
|
|||||||
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
||||||
if 'Switch' in tags:
|
if 'Switch' in tags:
|
||||||
opts = self.switchOpts[name]
|
opts = self.switchOpts[name]
|
||||||
|
if opts['switchType'] == 'default':
|
||||||
|
if self.appPrefs['switchType'] == 'user':
|
||||||
|
if ('switchIP' in opts):
|
||||||
|
if (len(opts['switchIP'])>0):
|
||||||
|
f.write(" "+name+".cmd('ifconfig "+name+" "+opts['switchIP']+"')\n")
|
||||||
|
elif self.appPrefs['switchType'] == 'userns':
|
||||||
|
if ('switchIP' in opts):
|
||||||
|
if (len(opts['switchIP'])>0):
|
||||||
|
f.write(" "+name+".cmd('ifconfig lo "+opts['switchIP']+"')\n")
|
||||||
|
elif self.appPrefs['switchType'] == 'ovs':
|
||||||
|
if ('switchIP' in opts):
|
||||||
|
if (len(opts['switchIP'])>0):
|
||||||
|
f.write(" "+name+".cmd('ifconfig "+name+" "+opts['switchIP']+"')\n")
|
||||||
|
elif opts['switchType'] == 'user':
|
||||||
|
if ('switchIP' in opts):
|
||||||
|
if (len(opts['switchIP'])>0):
|
||||||
|
f.write(" "+name+".cmd('ifconfig "+name+" "+opts['switchIP']+"')\n")
|
||||||
|
elif opts['switchType'] == 'userns':
|
||||||
|
if ('switchIP' in opts):
|
||||||
|
if (len(opts['switchIP'])>0):
|
||||||
|
f.write(" "+name+".cmd('ifconfig lo "+opts['switchIP']+"')\n")
|
||||||
|
elif opts['switchType'] == 'ovs':
|
||||||
if ('switchIP' in opts):
|
if ('switchIP' in opts):
|
||||||
if (len(opts['switchIP'])>0):
|
if (len(opts['switchIP'])>0):
|
||||||
f.write(" "+name+".cmd('ifconfig "+name+" "+opts['switchIP']+"')\n")
|
f.write(" "+name+".cmd('ifconfig "+name+" "+opts['switchIP']+"')\n")
|
||||||
@@ -1769,6 +1922,21 @@ class MiniEdit( Frame ):
|
|||||||
self.switchOpts[name]['hostname']=name
|
self.switchOpts[name]['hostname']=name
|
||||||
self.switchOpts[name]['switchType']='default'
|
self.switchOpts[name]['switchType']='default'
|
||||||
self.switchOpts[name]['controllers']=[]
|
self.switchOpts[name]['controllers']=[]
|
||||||
|
if 'LegacyRouter' == node:
|
||||||
|
self.switchCount += 1
|
||||||
|
name = self.nodePrefixes[ node ] + str( self.switchCount )
|
||||||
|
self.switchOpts[name] = {}
|
||||||
|
self.switchOpts[name]['nodeNum']=self.switchCount
|
||||||
|
self.switchOpts[name]['hostname']=name
|
||||||
|
self.switchOpts[name]['switchType']='legacyRouter'
|
||||||
|
if 'LegacySwitch' == node:
|
||||||
|
self.switchCount += 1
|
||||||
|
name = self.nodePrefixes[ node ] + str( self.switchCount )
|
||||||
|
self.switchOpts[name] = {}
|
||||||
|
self.switchOpts[name]['nodeNum']=self.switchCount
|
||||||
|
self.switchOpts[name]['hostname']=name
|
||||||
|
self.switchOpts[name]['switchType']='legacySwitch'
|
||||||
|
self.switchOpts[name]['controllers']=[]
|
||||||
if 'Host' == node:
|
if 'Host' == node:
|
||||||
self.hostCount += 1
|
self.hostCount += 1
|
||||||
name = self.nodePrefixes[ node ] + str( self.hostCount )
|
name = self.nodePrefixes[ node ] + str( self.hostCount )
|
||||||
@@ -1794,6 +1962,10 @@ class MiniEdit( Frame ):
|
|||||||
icon.links = {}
|
icon.links = {}
|
||||||
if 'Switch' == node:
|
if 'Switch' == node:
|
||||||
icon.bind('<Button-3>', self.do_switchPopup )
|
icon.bind('<Button-3>', self.do_switchPopup )
|
||||||
|
if 'LegacyRouter' == node:
|
||||||
|
icon.bind('<Button-3>', self.do_legacyRouterPopup )
|
||||||
|
if 'LegacySwitch' == node:
|
||||||
|
icon.bind('<Button-3>', self.do_legacySwitchPopup )
|
||||||
if 'Host' == node:
|
if 'Host' == node:
|
||||||
icon.bind('<Button-3>', self.do_hostPopup )
|
icon.bind('<Button-3>', self.do_hostPopup )
|
||||||
if 'Controller' == node:
|
if 'Controller' == node:
|
||||||
@@ -1807,11 +1979,19 @@ class MiniEdit( Frame ):
|
|||||||
"Add a new host to our canvas."
|
"Add a new host to our canvas."
|
||||||
self.newNode( 'Host', event )
|
self.newNode( 'Host', event )
|
||||||
|
|
||||||
|
def clickLegacyRouter( self, event ):
|
||||||
|
"Add a new switch to our canvas."
|
||||||
|
self.newNode( 'LegacyRouter', event )
|
||||||
|
|
||||||
|
def clickLegacySwitch( self, event ):
|
||||||
|
"Add a new switch to our canvas."
|
||||||
|
self.newNode( 'LegacySwitch', event )
|
||||||
|
|
||||||
def clickSwitch( self, event ):
|
def clickSwitch( self, event ):
|
||||||
"Add a new switch to our canvas."
|
"Add a new switch to our canvas."
|
||||||
self.newNode( 'Switch', event )
|
self.newNode( 'Switch', event )
|
||||||
|
|
||||||
def dragLink( self, event ):
|
def dragNetLink( self, event ):
|
||||||
"Drag a link's endpoint to another node."
|
"Drag a link's endpoint to another node."
|
||||||
if self.link is None:
|
if self.link is None:
|
||||||
return
|
return
|
||||||
@@ -1821,7 +2001,7 @@ class MiniEdit( Frame ):
|
|||||||
c = self.canvas
|
c = self.canvas
|
||||||
c.coords( self.link, self.linkx, self.linky, x, y )
|
c.coords( self.link, self.linkx, self.linky, x, y )
|
||||||
|
|
||||||
def releaseLink( self, _event ):
|
def releaseNetLink( self, _event ):
|
||||||
"Give up on the current link."
|
"Give up on the current link."
|
||||||
if self.link is not None:
|
if self.link is not None:
|
||||||
self.canvas.delete( self.link )
|
self.canvas.delete( self.link )
|
||||||
@@ -1858,7 +2038,7 @@ class MiniEdit( Frame ):
|
|||||||
|
|
||||||
def clickNode( self, event ):
|
def clickNode( self, event ):
|
||||||
"Node click handler."
|
"Node click handler."
|
||||||
if self.active is 'Link':
|
if self.active is 'NetLink':
|
||||||
self.startLink( event )
|
self.startLink( event )
|
||||||
else:
|
else:
|
||||||
self.selectNode( event )
|
self.selectNode( event )
|
||||||
@@ -1866,14 +2046,14 @@ class MiniEdit( Frame ):
|
|||||||
|
|
||||||
def dragNode( self, event ):
|
def dragNode( self, event ):
|
||||||
"Node drag handler."
|
"Node drag handler."
|
||||||
if self.active is 'Link':
|
if self.active is 'NetLink':
|
||||||
self.dragLink( event )
|
self.dragNetLink( event )
|
||||||
else:
|
else:
|
||||||
self.dragNodeAround( event )
|
self.dragNodeAround( event )
|
||||||
|
|
||||||
def releaseNode( self, event ):
|
def releaseNode( self, event ):
|
||||||
"Node release handler."
|
"Node release handler."
|
||||||
if self.active is 'Link':
|
if self.active is 'NetLink':
|
||||||
self.finishLink( event )
|
self.finishLink( event )
|
||||||
|
|
||||||
# Specific node handlers
|
# Specific node handlers
|
||||||
@@ -1980,16 +2160,20 @@ class MiniEdit( Frame ):
|
|||||||
dest = self.itemToWidget.get( target, None )
|
dest = self.itemToWidget.get( target, None )
|
||||||
if ( source is None or dest is None or source == dest
|
if ( source is None or dest is None or source == dest
|
||||||
or dest in source.links or source in dest.links ):
|
or dest in source.links or source in dest.links ):
|
||||||
self.releaseLink( event )
|
self.releaseNetLink( event )
|
||||||
return
|
return
|
||||||
# For now, don't allow hosts to be directly linked
|
# For now, don't allow hosts to be directly linked
|
||||||
stags = self.canvas.gettags( self.widgetToItem[ source ] )
|
stags = self.canvas.gettags( self.widgetToItem[ source ] )
|
||||||
dtags = self.canvas.gettags( target )
|
dtags = self.canvas.gettags( target )
|
||||||
if (('Host' in stags and 'Host' in dtags) or
|
if (('Host' in stags and 'Host' in dtags) or
|
||||||
('Controller' in stags and 'Host' in dtags) or
|
('Controller' in dtags and 'LegacyRouter' in stags) or
|
||||||
|
('Controller' in stags and 'LegacyRouter' in dtags) or
|
||||||
|
('Controller' in dtags and 'LegacySwitch' in stags) or
|
||||||
|
('Controller' in stags and 'LegacySwitch' in dtags) or
|
||||||
('Controller' in dtags and 'Host' in stags) or
|
('Controller' in dtags and 'Host' in stags) or
|
||||||
|
('Controller' in stags and 'Host' in dtags) or
|
||||||
('Controller' in stags and 'Controller' in dtags)):
|
('Controller' in stags and 'Controller' in dtags)):
|
||||||
self.releaseLink( event )
|
self.releaseNetLink( event )
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set link type
|
# Set link type
|
||||||
@@ -2175,7 +2359,7 @@ class MiniEdit( Frame ):
|
|||||||
dest = linkDetail['dest']
|
dest = linkDetail['dest']
|
||||||
linkopts = linkDetail['linkOpts']
|
linkopts = linkDetail['linkOpts']
|
||||||
linkBox = LinkDialog(self, title='Link Details', linkDefaults=linkopts)
|
linkBox = LinkDialog(self, title='Link Details', linkDefaults=linkopts)
|
||||||
if linkBox.result:
|
if linkBox.result is not None:
|
||||||
linkDetail['linkOpts'] = linkBox.result
|
linkDetail['linkOpts'] = linkBox.result
|
||||||
print 'New link details = ' + str(linkBox.result)
|
print 'New link details = ' + str(linkBox.result)
|
||||||
|
|
||||||
@@ -2231,7 +2415,7 @@ class MiniEdit( Frame ):
|
|||||||
|
|
||||||
if name not in self.net.nameToNode:
|
if name not in self.net.nameToNode:
|
||||||
return
|
return
|
||||||
if 'Switch' in tags:
|
if 'Switch' in tags or 'LegacySwitch' in tags:
|
||||||
call(["xterm -T 'Bridge Details' -sb -sl 2000 -e 'ovs-vsctl list bridge " + name + "; read -p \"Press Enter to close\"' &"], shell=True)
|
call(["xterm -T 'Bridge Details' -sb -sl 2000 -e 'ovs-vsctl list bridge " + name + "; read -p \"Press Enter to close\"' &"], shell=True)
|
||||||
|
|
||||||
def ovsShow( self, _ignore=None ):
|
def ovsShow( self, _ignore=None ):
|
||||||
@@ -2309,6 +2493,7 @@ class MiniEdit( Frame ):
|
|||||||
for widget in self.widgetToItem:
|
for widget in self.widgetToItem:
|
||||||
name = widget[ 'text' ]
|
name = widget[ 'text' ]
|
||||||
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
|
||||||
|
#print name+' has '+str(tags)
|
||||||
|
|
||||||
if 'Switch' in tags:
|
if 'Switch' in tags:
|
||||||
opts = self.switchOpts[name]
|
opts = self.switchOpts[name]
|
||||||
@@ -2323,14 +2508,27 @@ class MiniEdit( Frame ):
|
|||||||
if opts['switchType'] == 'default':
|
if opts['switchType'] == 'default':
|
||||||
if self.appPrefs['switchType'] == 'ivs':
|
if self.appPrefs['switchType'] == 'ivs':
|
||||||
switchClass = IVSSwitch
|
switchClass = IVSSwitch
|
||||||
|
elif self.appPrefs['switchType'] == 'user':
|
||||||
|
switchClass = CustomUserSwitch
|
||||||
|
elif self.appPrefs['switchType'] == 'userns':
|
||||||
|
switchParms['inNamespace'] = True
|
||||||
|
switchClass = CustomUserSwitch
|
||||||
else:
|
else:
|
||||||
switchClass = customOvs
|
switchClass = customOvs
|
||||||
|
elif opts['switchType'] == 'user':
|
||||||
|
switchClass = CustomUserSwitch
|
||||||
|
elif opts['switchType'] == 'userns':
|
||||||
|
switchClass = CustomUserSwitch
|
||||||
|
switchParms['inNamespace'] = True
|
||||||
elif opts['switchType'] == 'ivs':
|
elif opts['switchType'] == 'ivs':
|
||||||
switchClass = IVSSwitch
|
switchClass = IVSSwitch
|
||||||
else:
|
else:
|
||||||
switchClass = customOvs
|
switchClass = customOvs
|
||||||
newSwitch = net.addSwitch( name , cls=switchClass, **switchParms)
|
newSwitch = net.addSwitch( name , cls=switchClass, **switchParms)
|
||||||
#if self.appPrefs['switchType'] == 'ovs':
|
if switchClass == CustomUserSwitch:
|
||||||
|
if ('switchIP' in opts):
|
||||||
|
if (len(opts['switchIP']) > 0):
|
||||||
|
newSwitch.setSwitchIP(opts['switchIP'])
|
||||||
if switchClass == customOvs:
|
if switchClass == customOvs:
|
||||||
newSwitch.setOpenFlowVersion(self.appPrefs['openFlowVersions'])
|
newSwitch.setOpenFlowVersion(self.appPrefs['openFlowVersions'])
|
||||||
if ('switchIP' in opts):
|
if ('switchIP' in opts):
|
||||||
@@ -2343,6 +2541,10 @@ class MiniEdit( Frame ):
|
|||||||
if self.checkIntf(extInterface):
|
if self.checkIntf(extInterface):
|
||||||
Intf( extInterface, node=newSwitch )
|
Intf( extInterface, node=newSwitch )
|
||||||
|
|
||||||
|
elif 'LegacySwitch' in tags:
|
||||||
|
newSwitch = net.addSwitch( name , cls=LegacySwitch)
|
||||||
|
elif 'LegacyRouter' in tags:
|
||||||
|
newSwitch = net.addHost( name , cls=LegacyRouter)
|
||||||
elif 'Host' in tags:
|
elif 'Host' in tags:
|
||||||
opts = self.hostOpts[name]
|
opts = self.hostOpts[name]
|
||||||
ip = None
|
ip = None
|
||||||
@@ -2357,8 +2559,11 @@ class MiniEdit( Frame ):
|
|||||||
ip = ipAdd(i=nodeNum, prefixLen=prefixLen, ipBaseNum=ipBaseNum)
|
ip = ipAdd(i=nodeNum, prefixLen=prefixLen, ipBaseNum=ipBaseNum)
|
||||||
|
|
||||||
# Create the correct host class
|
# Create the correct host class
|
||||||
|
hostCls = Host
|
||||||
|
if 'cores' in opts or 'cpu' in opts:
|
||||||
|
hostCls=CPULimitedHost
|
||||||
newHost = net.addHost( name,
|
newHost = net.addHost( name,
|
||||||
cls=CPULimitedHost,
|
cls=hostCls,
|
||||||
ip=ip,
|
ip=ip,
|
||||||
defaultRoute=defaultRoute
|
defaultRoute=defaultRoute
|
||||||
)
|
)
|
||||||
@@ -2432,7 +2637,10 @@ class MiniEdit( Frame ):
|
|||||||
linkopts=link['linkOpts']
|
linkopts=link['linkOpts']
|
||||||
srcName, dstName = src[ 'text' ], dst[ 'text' ]
|
srcName, dstName = src[ 'text' ], dst[ 'text' ]
|
||||||
src, dst = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
|
src, dst = net.nameToNode[ srcName ], net.nameToNode[ dstName ]
|
||||||
net.addLink(src, dst, **linkopts)
|
if linkopts:
|
||||||
|
net.addLink(src, dst, cls=TCLink, **linkopts)
|
||||||
|
else:
|
||||||
|
net.addLink(src, dst)
|
||||||
self.canvas.itemconfig(key, dash=())
|
self.canvas.itemconfig(key, dash=())
|
||||||
|
|
||||||
|
|
||||||
@@ -2445,7 +2653,6 @@ class MiniEdit( Frame ):
|
|||||||
net = Mininet( topo=None,
|
net = Mininet( topo=None,
|
||||||
listenPort=dpctl,
|
listenPort=dpctl,
|
||||||
build=False,
|
build=False,
|
||||||
link=TCLink,
|
|
||||||
ipBase=self.appPrefs['ipBase'] )
|
ipBase=self.appPrefs['ipBase'] )
|
||||||
|
|
||||||
self.buildNodes(net)
|
self.buildNodes(net)
|
||||||
@@ -2564,6 +2771,9 @@ class MiniEdit( Frame ):
|
|||||||
info( name + ' ')
|
info( name + ' ')
|
||||||
# Figure out what controllers will manage this switch
|
# Figure out what controllers will manage this switch
|
||||||
self.net.get(name).start( switchControllers )
|
self.net.get(name).start( switchControllers )
|
||||||
|
if 'LegacySwitch' in tags:
|
||||||
|
self.net.get(name).start( [] )
|
||||||
|
info( name + ' ')
|
||||||
info('\n')
|
info('\n')
|
||||||
|
|
||||||
self.postStartSetup()
|
self.postStartSetup()
|
||||||
@@ -2599,6 +2809,15 @@ class MiniEdit( Frame ):
|
|||||||
# make sure to release the grab (Tk 8.0a1 only)
|
# make sure to release the grab (Tk 8.0a1 only)
|
||||||
self.controllerPopup.grab_release()
|
self.controllerPopup.grab_release()
|
||||||
|
|
||||||
|
def do_legacyRouterPopup(self, event):
|
||||||
|
# display the popup menu
|
||||||
|
if ( self.net is not None ):
|
||||||
|
try:
|
||||||
|
self.legacyRouterRunPopup.tk_popup(event.x_root, event.y_root, 0)
|
||||||
|
finally:
|
||||||
|
# make sure to release the grab (Tk 8.0a1 only)
|
||||||
|
self.legacyRouterRunPopup.grab_release()
|
||||||
|
|
||||||
def do_hostPopup(self, event):
|
def do_hostPopup(self, event):
|
||||||
# display the popup menu
|
# display the popup menu
|
||||||
if ( self.net is None ):
|
if ( self.net is None ):
|
||||||
@@ -2614,6 +2833,15 @@ class MiniEdit( Frame ):
|
|||||||
# make sure to release the grab (Tk 8.0a1 only)
|
# make sure to release the grab (Tk 8.0a1 only)
|
||||||
self.hostRunPopup.grab_release()
|
self.hostRunPopup.grab_release()
|
||||||
|
|
||||||
|
def do_legacySwitchPopup(self, event):
|
||||||
|
# display the popup menu
|
||||||
|
if ( self.net is not None ):
|
||||||
|
try:
|
||||||
|
self.switchRunPopup.tk_popup(event.x_root, event.y_root, 0)
|
||||||
|
finally:
|
||||||
|
# make sure to release the grab (Tk 8.0a1 only)
|
||||||
|
self.switchRunPopup.grab_release()
|
||||||
|
|
||||||
def do_switchPopup(self, event):
|
def do_switchPopup(self, event):
|
||||||
# display the popup menu
|
# display the popup menu
|
||||||
if ( self.net is None ):
|
if ( self.net is None ):
|
||||||
@@ -2837,6 +3065,108 @@ def miniEditImages():
|
|||||||
'Select': BitmapImage(
|
'Select': BitmapImage(
|
||||||
file='/usr/include/X11/bitmaps/left_ptr' ),
|
file='/usr/include/X11/bitmaps/left_ptr' ),
|
||||||
|
|
||||||
|
'Switch': PhotoImage( data=r"""
|
||||||
|
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
|
||||||
|
"""),
|
||||||
|
|
||||||
|
'LegacySwitch': PhotoImage( data=r"""
|
||||||
|
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
|
||||||
|
4BE2eIRYeHAEIBwBP0Y4Qn41YWRSCQgAOw==
|
||||||
|
"""),
|
||||||
|
|
||||||
|
'LegacyRouter': PhotoImage( data=r"""
|
||||||
|
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
|
||||||
|
gGPLHwLwcMIo12Qxu0ABAQA7
|
||||||
|
"""),
|
||||||
|
|
||||||
'Controller': PhotoImage( data=r"""
|
'Controller': PhotoImage( data=r"""
|
||||||
R0lGODlhMAAwAPcAAAEBAWfNAYWFhcfHx+3t6/f390lJUaWlpfPz8/Hx72lpaZGRke/v77m5uc0B
|
R0lGODlhMAAwAPcAAAEBAWfNAYWFhcfHx+3t6/f390lJUaWlpfPz8/Hx72lpaZGRke/v77m5uc0B
|
||||||
AeHh4e/v7WNjY3t7e5eXlyMjI4mJidPT0+3t7f///09PT7Ozs/X19fHx8ZWTk8HBwX9/fwAAAAAA
|
AeHh4e/v7WNjY3t7e5eXlyMjI4mJidPT0+3t7f///09PT7Ozs/X19fHx8ZWTk8HBwX9/fwAAAAAA
|
||||||
@@ -2890,7 +3220,7 @@ def miniEditImages():
|
|||||||
C8cSBBAQADs=
|
C8cSBBAQADs=
|
||||||
""" ),
|
""" ),
|
||||||
|
|
||||||
'Switch': PhotoImage( data=r"""
|
'OldSwitch': PhotoImage( data=r"""
|
||||||
R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
|
R0lGODlhIAAYAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
|
||||||
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
|
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
|
||||||
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
|
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
|
||||||
@@ -2917,7 +3247,7 @@ def miniEditImages():
|
|||||||
6saLWLNq3cq1q9evYB0GBAA7
|
6saLWLNq3cq1q9evYB0GBAA7
|
||||||
""" ),
|
""" ),
|
||||||
|
|
||||||
'Link': PhotoImage( data=r"""
|
'NetLink': PhotoImage( data=r"""
|
||||||
R0lGODlhFgAWAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
|
R0lGODlhFgAWAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
|
||||||
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
|
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
|
||||||
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
|
Zv9mM/9mAP8z//8zzP8zmf8zZv8zM/8zAP8A//8AzP8Amf8AZv8A
|
||||||
|
|||||||
Reference in New Issue
Block a user