Add support for switches in GUI and configuration file
refs: #2583
Change-Id: I051dfe7c9e5fae292a7ca97f26f41dfc403241b8
diff --git a/bin/minindn b/bin/minindn
index bf5a525..836beed 100755
--- a/bin/minindn
+++ b/bin/minindn
@@ -68,7 +68,7 @@
from ndn import ExperimentManager
from ndn.ndn_host import NdnHost, CpuLimitedNdnHost
-from ndn.conf_parser import parse_hosts, parse_links
+from ndn.conf_parser import parse_hosts, parse_switches, parse_links
import os.path, time
import optparse
@@ -175,6 +175,7 @@
global hosts_conf
global links_conf
hosts_conf = parse_hosts(conf_arq)
+ switches_conf = parse_switches(conf_arq)
links_conf = parse_links(conf_arq)
self.isTCLink = False
@@ -185,6 +186,9 @@
self.isLimited = True
self.addHost(host.name, app=host.app, params=host.uri_tuples, cpu=host.cpu,cores=host.cores,cache=host.cache, workdir=workDir)
+ for switch in switches_conf:
+ self.addSwitch(switch.name)
+
for link in links_conf:
if len(link.linkDict) == 0:
self.addLink(link.h1, link.h2)
@@ -245,6 +249,11 @@
for intf in host.intfList():
link = intf.link
node1, node2 = link.intf1.node, link.intf2.node
+
+ if node1 in net.switches or node2 in net.switches:
+ print "%s or %s is a switch" % (node1.name, node2.name)
+ continue
+
if link.intf1 not in interfaces and link.intf2 not in interfaces:
interfaces.append(link.intf1)
interfaces.append(link.intf2)
diff --git a/bin/minindnedit b/bin/minindnedit
index 13627e8..fa5d071 100755
--- a/bin/minindnedit
+++ b/bin/minindnedit
@@ -514,7 +514,7 @@
self.images = miniEditImages()
self.buttons = {}
self.active = None
- self.tools = ( 'Select', 'Host', 'NetLink' )
+ self.tools = ( 'Select', 'Host', 'Switch', 'NetLink' )
#self.customColors = { 'LegacyRouter': 'darkGreen', 'Host': 'blue' }
self.toolbar = self.createToolbar()
@@ -530,7 +530,7 @@
# Initialize node data
self.nodeBindings = self.createNodeBindings()
- self.nodePrefixes = { 'LegacyRouter': 'r', 'Host': 'h'}
+ self.nodePrefixes = { 'LegacyRouter': 'r', 'Host': 'h', 'Switch': 's'}
self.widgetToItem = {}
self.itemToWidget = {}
@@ -572,6 +572,7 @@
self.switchOpts = {}
self.routerOpts = {}
self.hostCount = 0
+ self.switchCount = 0
self.routerCount = 0
self.net = None
@@ -768,9 +769,11 @@
for widget in self.widgetToItem:
name = widget[ 'text' ]
tags = self.canvas.gettags( self.widgetToItem[ widget ] )
- print self.hostOpts[name]
+
if 'Host' in tags:
hOpts=self.hostOpts[name]
+ print hOpts
+
template.write(name + ': ')
if 'startCommand' in hOpts:
cmds = hOpts['startCommand'].replace("\"", "\\\"")
@@ -840,6 +843,15 @@
template.write('\n')
+ # Write switches
+ template.write('[switches]\n')
+
+ for switch in self.switchOpts.values():
+ print "Switch%s" % switch
+
+ name = switch['hostname']
+ template.write(name + ': _\n')
+
# Make links
template.write('[links]\n')
for link in self.links.values():
@@ -868,6 +880,8 @@
self.routerCount += 1
if 'Host' == node:
self.hostCount += 1
+ if 'Switch' == node:
+ self.switchCount += 1
if name is None:
name = self.nodePrefixes[ node ] + nodeNum
self.addNamedNode(node, name, x, y)
@@ -959,6 +973,29 @@
icon.bind('<Button-3>', self.do_legacyRouterPopup )
self.routerOpts[hostname] = router['opts']
+ # Load switches
+ switches = loadedTopology['switches']
+
+ for switch in switches:
+ nodeNum = switch['number']
+ hostname = 's' + nodeNum
+
+ if 'hostname' in switch['opts']:
+ hostname = switch['opts']['hostname']
+ else:
+ switch['opts']['hostname'] = hostname
+
+ if 'nodeNum' not in switch['opts']:
+ switch['opts']['nodeNum'] = int(nodeNum)
+
+ x = switch['x']
+ y = switch['y']
+
+ self.addNode('Switch', nodeNum, float(x), float(y), name=hostname)
+ icon = self.findWidgetByName(hostname)
+
+ self.switchOpts[hostname] = switch['opts']
+
# Load links
links = loadedTopology['links']
for link in links:
@@ -990,6 +1027,7 @@
self.deleteItem( self.widgetToItem[ widget ] )
self.hostCount = 0
self.routerCount = 0
+ self.switchCount = 0
self.links = {}
self.hostOpts = {}
self.routerOpts = {}
@@ -1010,6 +1048,7 @@
# Save routers and Hosts
hostsToSave = []
routersToSave = []
+ switchesToSave = []
for widget in self.widgetToItem:
name = widget[ 'text' ]
@@ -1029,10 +1068,18 @@
'y':str(y1),
'opts':self.hostOpts[name] }
hostsToSave.append(nodeToSave)
+ elif 'Switch' in tags:
+ nodeNum = self.switchOpts[name]['nodeNum']
+ nodeToSave = {'number':str(nodeNum),
+ 'x':str(x1),
+ 'y':str(y1),
+ 'opts':self.switchOpts[name] }
+ switchesToSave.append(nodeToSave)
else:
raise Exception( "Cannot create mystery node: " + name )
savingDictionary['hosts'] = hostsToSave
savingDictionary['routers'] = routersToSave
+ savingDictionary['switches'] = switchesToSave
# Save Links
linksToSave = []
@@ -1164,6 +1211,13 @@
self.hostOpts[name]['nodeNum']=self.hostCount
self.hostOpts[name]['hostname']=name
+ if 'Switch' == 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
+
icon = self.nodeIcon( node, name )
item = self.canvas.create_window( x, y, anchor='c', window=icon,
tags=node )
@@ -1180,6 +1234,10 @@
"Add a new host to our canvas."
self.newNode( 'Host', event )
+ def clickSwitch( self, event ):
+ "Add a new switch to the canvas."
+ self.newNode( 'Switch', event )
+
def clickLegacyRouter( self, event ):
"Add a new router to our canvas."
self.newNode( 'LegacyRouter', event )
@@ -1805,6 +1863,41 @@
C8cSBBAQADs=
""" ),
+ 'Switch': PhotoImage( data=r"""
+ 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
+ 4BE2eIRYeHAEIBwBP0Y4Qn41YWRSCQgAOw==
+ """ ),
+
'NetLink': PhotoImage( data=r"""
R0lGODlhFgAWAPcAMf//////zP//mf//Zv//M///AP/M///MzP/M
mf/MZv/MM//MAP+Z//+ZzP+Zmf+ZZv+ZM/+ZAP9m//9mzP9mmf9m
diff --git a/docs/GUI.md b/docs/GUI.md
index c4d61c7..a465269 100644
--- a/docs/GUI.md
+++ b/docs/GUI.md
@@ -43,8 +43,14 @@
### Host tool
![host-tool](img/gui/host-tool.png)
-The *host tool* is used to add a node to the topology. Click on the canvas to create a new node at
-the mouse cursor's position.
+The *host tool* is used to add a host node to the topology. Click on the canvas to create a new host
+node at the mouse cursor's position.
+
+### Switch tool
+![switch-tool](img/gui/switch-tool.png)
+
+The *switch tool* is used to add a switch to the topology. Click on the canvas to create a new
+switch at the mouse cursor's position.
### Link tool
![link-tool](img/gui/link-tool.png)
diff --git a/docs/img/gui/minindnedit.png b/docs/img/gui/minindnedit.png
index 70dcec4..0fe6879 100644
--- a/docs/img/gui/minindnedit.png
+++ b/docs/img/gui/minindnedit.png
Binary files differ
diff --git a/docs/img/gui/switch-tool.png b/docs/img/gui/switch-tool.png
new file mode 100644
index 0000000..919b11d
--- /dev/null
+++ b/docs/img/gui/switch-tool.png
Binary files differ
diff --git a/ndn/conf_parser.py b/ndn/conf_parser.py
index 84add19..a351a68 100644
--- a/ndn/conf_parser.py
+++ b/ndn/conf_parser.py
@@ -86,6 +86,10 @@
' Angle: ' + str(self.angle) + \
' NLSR Parameters: ' + self.nlsrParameters
+class confNdnSwitch:
+ def __init__(self, name):
+ self.name = name
+
class confNDNLink():
def __init__(self,h1,h2,linkDict=None):
@@ -147,6 +151,24 @@
return hosts
+def parse_switches(conf_arq):
+ 'Parse switches section from the conf file.'
+ config = ConfigParser.RawConfigParser()
+ config.read(conf_arq)
+
+ switches = []
+
+ try:
+ items = config.items('switches')
+ except ConfigParser.NoSectionError:
+ return switches
+
+ for item in items:
+ name = item[0]
+ switches.append(confNdnSwitch(name))
+
+ return switches
+
def parse_links(conf_arq):
'Parse links section from the conf file.'
arq = open(conf_arq,'r')