Esempio n. 1
0
class PoxSnapshotService(SnapshotService):
  def __init__(self):
    SnapshotService.__init__(self)
    self.port = 7790
    self.myNOMDecoder = NOMDecoder()

  def fetchSnapshot(self, controller):
    from pox.lib.util import connect_socket_with_backoff
    import socket
    snapshotSocket = connect_socket_with_backoff('127.0.0.1', self.port)
    log.debug("Sending Request")
    snapshotSocket.send("{\"hello\":\"nommessenger\"}")
    snapshotSocket.send("{\"getnom\":0}", socket.MSG_WAITALL)
    log.debug("Receiving Results")
    jsonstr = ""
    while True:
      data = snapshotSocket.recv(1024)
      log.debug("%d byte packet received" % len(data))
      if not data: break
      jsonstr += data
      if len(data) != 1024: break
    snapshotSocket.close()

    jsonNOM = json.loads(jsonstr) # (json string with the NOM)

    # Update local Snapshot object
    self.snapshot.switches = [self.myNOMDecoder.decode(s) for s in jsonNOM["switches"]]
    self.snapshot.hosts = [self.myNOMDecoder.decode(h) for h in jsonNOM["hosts"]]
    self.snapshot.links = [self.myNOMDecoder.decode(l) for l in jsonNOM["links"]]
    self.snapshot.time = time.time()

    return self.snapshot
Esempio n. 2
0
class SyncProtoSnapshotService(SnapshotService):
  def __init__(self):
    SnapshotService.__init__(self)
    self.myNOMDecoder = NOMDecoder()

  def fetchSnapshot(self, controller):
    jsonNOM = controller.sync_connection.get_nom_snapshot()

    # Update local Snapshot object
    self.snapshot.switches = [self.myNOMDecoder.decode(s) for s in jsonNOM["switches"]]
    self.snapshot.hosts = [self.myNOMDecoder.decode(h) for h in jsonNOM["hosts"]]
    self.snapshot.links = [self.myNOMDecoder.decode(l) for l in jsonNOM["links"]]
    self.snapshot.time = time.time()

    return self.snapshot
Esempio n. 3
0
class SyncProtoSnapshotService(SnapshotService):
    def __init__(self):
        SnapshotService.__init__(self)
        self.myNOMDecoder = NOMDecoder()

    def fetchSnapshot(self, controller):
        jsonNOM = controller.sync_connection.get_nom_snapshot()

        # Update local Snapshot object
        self.snapshot.switches = [
            self.myNOMDecoder.decode(s) for s in jsonNOM["switches"]
        ]
        self.snapshot.hosts = [
            self.myNOMDecoder.decode(h) for h in jsonNOM["hosts"]
        ]
        self.snapshot.links = [
            self.myNOMDecoder.decode(l) for l in jsonNOM["links"]
        ]
        self.snapshot.time = time.time()

        return self.snapshot
Esempio n. 4
0
class PoxSnapshotService(SnapshotService):
    def __init__(self):
        SnapshotService.__init__(self)
        self.port = 7790
        self.myNOMDecoder = NOMDecoder()

    def fetchSnapshot(self, controller):
        from pox.lib.util import connect_socket_with_backoff
        import socket
        snapshotSocket = connect_socket_with_backoff('127.0.0.1', self.port)
        log.debug("Sending Request")
        snapshotSocket.send("{\"hello\":\"nommessenger\"}")
        snapshotSocket.send("{\"getnom\":0}", socket.MSG_WAITALL)
        log.debug("Receiving Results")
        jsonstr = ""
        while True:
            data = snapshotSocket.recv(1024)
            log.debug("%d byte packet received" % len(data))
            if not data: break
            jsonstr += data
            if len(data) != 1024: break
        snapshotSocket.close()

        jsonNOM = json.loads(jsonstr)  # (json string with the NOM)

        # Update local Snapshot object
        self.snapshot.switches = [
            self.myNOMDecoder.decode(s) for s in jsonNOM["switches"]
        ]
        self.snapshot.hosts = [
            self.myNOMDecoder.decode(h) for h in jsonNOM["hosts"]
        ]
        self.snapshot.links = [
            self.myNOMDecoder.decode(l) for l in jsonNOM["links"]
        ]
        self.snapshot.time = time.time()

        return self.snapshot
Esempio n. 5
0
    def __init__(self, parent=None):
        QtGui.QGraphicsView.__init__(self, parent)
        self.parent = parent
        # topologyInterface exchanges json messages with monitoring server
        
        #self.topologyInterface = TopologyInterface(self)
        self.topologyInterface = self.parent.parent.communication
        #self.topologyInterface.start()
        self.mininet = jsonrpc.ServerProxy(jsonrpc.JsonRpc20(),
            jsonrpc.TransportTcpIp(addr=(self.parent.parent.mininet_address, 31415)))

    
        self.setStyleSheet("background: black")
    
        self.topoScene = QtGui.QGraphicsScene(self)
        self.topoScene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex)
        self.topoScene.setSceneRect(-300, -300, 600, 600)
        self.setScene(self.topoScene)
        self.setCacheMode(QtGui.QGraphicsView.CacheBackground)
        self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
        
        self.drawAccess = 'Default'  #(utilization/te/et/etc)

        self.scale(0.9, 0.9)
        self.setMinimumSize(400, 400)
        
        # Pan
        self.setDragMode(self.ScrollHandDrag)
        self.setCursor(QtCore.Qt.ArrowCursor)        
        
        # Connect signals to slots
        self.topologyInterface.topology_received_signal[object].connect \
                (self.got_topo_msg)
        self.updateAllSignal.connect(self.updateAll)
        
        self.myDecoder = NOMDecoder()
        
        # Dictionaries holding node and link QGraphicsItems
        self.nodes = {}
        self.links = {}
                
        self.helloMessenger()        
        
        # Get an initial current snapshot of the topology        
        self.get_topology()
Esempio n. 6
0
class FlexibleNOMDecoder:
    def __init__(self):
        self.pox_nom_decoder = NOMDecoder()

    def decode(self, json):
        if isinstance(json,
                      (str, unicode)) and string.find(json, "__module__") >= 0:
            return self.pox_nom_decoder.decode(json)
        else:
            return self.decode_switch(json)

    def decode_switch(self, json):
        flow_table = self.decode_flow_table(
            json["flow_table"] if "flow_table" in json else json["flowTable"])
        switch = OpenFlowSwitch(json["dpid"], flow_table=flow_table)
        return switch

    def decode_flow_table(self, json):
        ft = FlowTable()
        for e in json["entries"]:
            ft.add_entry(self.decode_entry(e))
        return ft

    def decode_entry(self, json):
        e = TableEntry()
        for (k, v) in json.iteritems():
            if k == "match":
                e.match = self.decode_match(v)
            elif k == "actions":
                e.actions = [self.decode_action(a) for a in v]
            else:
                setattr(e, k, v)
        return e

    def decode_match(self, json):
        return ofp_match(**json)

    def decode_action(self, json):
        a = ofp_action_output(port=json['port'])
        return a
Esempio n. 7
0
class FlexibleNOMDecoder:
  def __init__(self):
    self.pox_nom_decoder = NOMDecoder()

  def decode(self, json):
    if isinstance(json, (str, unicode)) and string.find(json, "__module__")>=0:
      return self.pox_nom_decoder.decode(json)
    else:
      return self.decode_switch(json)

  def decode_switch(self, json):
    flow_table = self.decode_flow_table(json["flow_table"] if "flow_table" in json else json["flowTable"])
    switch = OpenFlowSwitch(json["dpid"], flow_table=flow_table)
    return switch

  def decode_flow_table(self, json):
    ft = FlowTable()
    for e in json["entries"]:
      ft.add_entry(self.decode_entry(e))
    return ft

  def decode_entry(self, json):
    e = TableEntry()
    for (k, v) in json.iteritems():
      if k == "match":
        e.match = self.decode_match(v)
      elif k == "actions":
        e.actions = [ self.decode_action(a) for a in v ]
      else:
        setattr(e, k, v)
    return e

  def decode_match(self, json):
    return ofp_match(**json)

  def decode_action(self, json):
    a = ofp_action_output(port = json['port'])
    return a
Esempio n. 8
0
 def __init__(self):
   self.pox_nom_decoder = NOMDecoder()
Esempio n. 9
0
 def __init__(self):
   SnapshotService.__init__(self)
   self.port = 7790
   self.myNOMDecoder = NOMDecoder()
Esempio n. 10
0
 def __init__(self):
     self.pox_nom_decoder = NOMDecoder()
Esempio n. 11
0
 def __init__(self):
     SnapshotService.__init__(self)
     self.port = 7790
     self.myNOMDecoder = NOMDecoder()
Esempio n. 12
0
class TopologyView(QtGui.QGraphicsView):

    updateAllSignal = QtCore.pyqtSignal() 
    
    def __init__(self, parent=None):
        QtGui.QGraphicsView.__init__(self, parent)
        self.parent = parent
        # topologyInterface exchanges json messages with monitoring server
        
        #self.topologyInterface = TopologyInterface(self)
        self.topologyInterface = self.parent.parent.communication
        #self.topologyInterface.start()
        self.mininet = jsonrpc.ServerProxy(jsonrpc.JsonRpc20(),
            jsonrpc.TransportTcpIp(addr=(self.parent.parent.mininet_address, 31415)))

    
        self.setStyleSheet("background: black")
    
        self.topoScene = QtGui.QGraphicsScene(self)
        self.topoScene.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex)
        self.topoScene.setSceneRect(-300, -300, 600, 600)
        self.setScene(self.topoScene)
        self.setCacheMode(QtGui.QGraphicsView.CacheBackground)
        self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QtGui.QGraphicsView.AnchorViewCenter)
        
        self.drawAccess = 'Default'  #(utilization/te/et/etc)

        self.scale(0.9, 0.9)
        self.setMinimumSize(400, 400)
        
        # Pan
        self.setDragMode(self.ScrollHandDrag)
        self.setCursor(QtCore.Qt.ArrowCursor)        
        
        # Connect signals to slots
        self.topologyInterface.topology_received_signal[object].connect \
                (self.got_topo_msg)
        self.updateAllSignal.connect(self.updateAll)
        
        self.myDecoder = NOMDecoder()
        
        # Dictionaries holding node and link QGraphicsItems
        self.nodes = {}
        self.links = {}
                
        self.helloMessenger()        
        
        # Get an initial current snapshot of the topology        
        self.get_topology()
        
    def helloMessenger(self):
        '''
        Initialize communication with backend messenger
        '''
        msg = {"hello":"mux"}
        self.topologyInterface.send(msg)
        msg = {"_mux":"gui", "hello":"gui"}
        self.topologyInterface.send(msg)
        
    def get_topology(self):
        '''
        Ask topology for updated nodes and links sets
        '''
        msg = {"_mux":"gui", "type":"topology", "command":"requestall"}
        self.topologyInterface.send(msg)
    
    def got_topo_msg(self, msg):
        '''
        Handle received links/nodes message 
        '''
        if msg["command"] == "add":
            if not "jsonobject" in msg:
                raise RuntimeError("Got ADD command without jsonobject")
            jsonobj = msg["jsonobject"]
            obj = self.myDecoder.decode(jsonobj)
            if isinstance(obj, NOMHost):
                nodeID = obj.macstr
                if nodeID not in self.nodes.keys():
                    nodeItem = Node(self, nodeID, "host")
                    self.nodes[nodeID] = nodeItem
                    self.addNode(nodeItem)
                    self.positionNodes([nodeItem])
            elif isinstance(obj, NOMSwitch):
                nodeID = obj.dpid
                if nodeID not in self.nodes.keys():
                    nodeItem = Node(self, nodeID, "switch")
                    self.nodes[nodeID] = nodeItem
                    self.addNode(nodeItem)
                    self.positionNodes([nodeItem])
            elif isinstance(obj, NOMLink):
                # If it is an AccessLink
                if isinstance(obj, NOMAccessLink):
                    srcid = obj.node1
                    dstid = obj.hostmac
                    key = str(srcid)+'-'+str(dstid)
                    
                    # Create new linkItem
                    linkid = len(self.links)
                    linkItem = Link(self, self.nodes[srcid], self.nodes[dstid],\
                        obj.port1, 1, linkid) 
                # If it is a switch-switch link
                else:
                    '''
                    The backend advertises 1 link for each direction
                    We'll add a single object for a biderectional link
                    We'll always use 'minend-maxend' as the key
                    '''
                    srcid = obj.node1
                    dstid = obj.node2
                    minend = str(min(srcid,dstid))
                    maxend = str(max(srcid,dstid))
                    key = minend+'-'+maxend
                    
                    if key in self.links:
                        return
                    
                    # Create new linkItem
                    linkid = len(self.links)
                    linkItem = Link(self, self.nodes[srcid], self.nodes[dstid],\
                        obj.port1, obj.port2, linkid) 
                    self.links[key]=linkItem
                
                # Add it to the Scene
                self.addLink(linkItem)
        
        """
        if "node_id" in msg:
            if msg["command"] == "add":
                nodes = msg["node_id"]
                new_nodes = []
                # Populate nodes
                for nodeID in nodes:
                    # If nodeItem doesn't already exist
                    if nodeID not in self.nodes.keys():
                        nodeItem = Node(self, nodeID, msg["node_type"])
                        self.nodes[nodeID] = nodeItem
                        new_nodes.append(nodeItem)  
                self.addNodes(new_nodes)
                self.positionNodes(new_nodes)
                
            elif msg["command"] == "delete":
                nodes = msg["node_id"]
                for nodeID in nodes:
                    if not msg["node_type"] == "host":
                        pass
                    if nodeID in self.nodes.keys():
                        #un-draw node
                        n = self.nodes[nodeID]
                        self.topoScene.removeItem(n)
                        n.update()
                        '''Should I delete nodes or store in 'down' state?'''
                        del self.nodes[nodeID]
                        
        elif "links" in msg:
            if msg["command"] == "add":
                links = msg["links"]
                new_links = []
                # Populate Links
                linkid = len(self.links)
                for link in links:
                    '''
                    Lavi advertises 1 link for each direction
                    We'll add a single object for a biderectional link
                    We'll always use 'minend-maxend' as the key
                    '''
                    srcid = link["src id"]
                    dstid = link["dst id"]
                    minend = str(min(srcid,dstid))
                    maxend = str(max(srcid,dstid))
                    key = minend+'-'+maxend
                    
                    if key in self.links:
                        continue
                       
                    # If src_port is missing, default to 1
                    if not "src port" in link:
                        link["src port"] = 1
                    linkid = linkid+1
                    
                    # Create new linkItem
                    linkItem = Link(self, self.nodes[srcid], self.nodes[dstid],\
                        link["src port"], link["dst port"], linkid) 
                    self.links[key]=linkItem                    
                    new_links.append(linkItem)
                    
                self.addLinks(new_links)
                
            elif msg["command"] == "delete":
                links = msg["links"]
                for link in links:
                    # Only do this once (for both directions)
                    if link["src id"] > link["dst id"]:
                        continue
                    # First, check if link exists
                    key = str(link["src id"])+"-"+str(link["dst id"])
                    if key in self.links:
                        #un-draw link
                        l = self.links[key]
                        self.topoScene.removeItem(l)
                        l.update()
                        '''Should I delete links or store in 'down' state?'''
                        del self.links[key]
                        
                    else:    
                        print "Attempted to removed inexistent link:", key
            """
        self.updateAll()
    
    def addNode(self, newNode):
        '''
        Add new node to topology Scene
        '''
        self.topoScene.addItem(newNode)
    
    def addNodes(self, new_nodes):
        '''
        Add list of nodes to topology Scene
        '''
        for nodeItem in new_nodes:
            self.addNode(nodeItem)
            
    def addLink(self, newLink):
        '''
        Add new link to topology Scene
        '''
        self.topoScene.addItem(newLink)
            
    def addLinks(self, new_links):
        '''
        Add links to topology Scene
        '''
        for linkItem in new_links:
            self.topoScene.addItem(linkItem)
            
    def positionNodes(self, new_nodes):
        '''
        Position nodes according to current loaded layout (or random if none)
        '''
        
        minX, maxX = -300, 300
        minY, maxY = -200, 200
        
        layout = self.parent.parent.settings.current_topo_layout 
        
        if layout == "random":
            for node in new_nodes:
                node.setPos(randint(minX,maxX), randint(minY,maxY))
        
        else:
            '''
            If node position is described in current layout file, choose that,
            otherwise place randomly
            '''        
            # Optimize: scan file into a dictionary. same for load.
            f = QtCore.QFile("gui/layouts/"+layout)
            f.open(QtCore.QIODevice.ReadOnly)
            for node in new_nodes:
                line = f.readLine()
                found = False
                while not line.isNull():
                    nodeid,x,y = str(line).split()
                    line = f.readLine()
                    if str(node.id) == nodeid:
                        node.setPos(float(x), float(y))
                        found = True
                if not found:
                    node.setPos(randint(minX,maxX), randint(minY,maxY))
            f.close()
        
    def itemMoved(self):
        pass
    
    def disableAllLinks(self):
        for e in self.links.values():
            e.setLinkDown()
            e.update()

    def enableAllLinks(self):
        for e in self.links.values():
            e.setLinkUp()
            e.update()

    def disableAllNodes(self):
        for n in self.nodes.values():
            n.bringSwitchDown()
            n.update()

    def enableAllNodes(self):
        for n in self.nodes.values():
            n.bringSwitchUp()
            n.update()

    def updateAllNodes(self):
        '''
        Refresh all Nodes
        '''
        for n in self.nodes.values():
            n.update()
            
    def updateAllLinks(self):
        '''
        Refresh all Links
        '''
        for e in self.links.values():
            e.update()
            e.adjust()
            
    def updateAll(self):
        '''
        Refresh all Items
        '''
        self.updateAllNodes()
        self.updateAllLinks()
            
    def keyPressEvent(self, event):
        '''
        Topology View hotkeys
        '''
        key = event.key()
        if key == QtCore.Qt.Key_Plus:
            self.scaleView(1.2)
        elif key == QtCore.Qt.Key_Minus:
            self.scaleView(1 / 1.2)
        elif key == QtCore.Qt.Key_N:
            self.toggleNodes()
        elif key == QtCore.Qt.Key_I:
            self.toggleNodeIDs()
        elif key == QtCore.Qt.Key_K:
            self.toggleLinks()
        elif key == QtCore.Qt.Key_L:
            # Backend counts a biderctional link as 2 links, so IDs overlap
            self.toggleLinkIDs()
            self.updateAllLinks()
        elif key == QtCore.Qt.Key_P:
            self.togglePorts()
            self.updateAllLinks()
        elif key == QtCore.Qt.Key_H:
            self.toggleHosts()
            self.updateAllNodes()
        elif key == QtCore.Qt.Key_Space or key == QtCore.Qt.Key_Enter:
            # Redraw topology
            self.positionNodes(self.nodes.values())
            self.updateAll()
        else:
            QtGui.QGraphicsView.keyPressEvent(self, event)
    '''
    Toggle display of drawn items
    '''
    def toggleNodes(self):
        for node in self.nodes.values():
            node.showNode = not node.showNode
            node.update()
            
    def toggleNodeIDs(self):
        for node in self.nodes.values():
            node.showID = not node.showID
            node.update()            

    def toggleLinks(self):
        for link in self.links.values():
            link.showLink = not link.showLink
            link.update()
            
    def toggleLinkIDs(self):
        for link in self.links.values():
            link.showID = not link.showID
            link.update()
            
    def togglePorts(self):
        for link in self.links.values():
            link.showPorts = not link.showPorts
            link.update()
            
    def toggleHosts(self):        
        for node in self.nodes.values():
            if node.layer == 3:
                for l in node.linkList:
                    l.showLink = not l.showLink
                    l.update()
                node.showID = not node.showID
                node.showNode = not node.showNode
                node.update()

    def drawBackground(self, painter, rect):
        '''
        Draw background. For now just some text
        '''
        sceneRect = self.sceneRect()
        textRect = QtCore.QRectF(sceneRect.left() -5, sceneRect.top() + 60,
                                 sceneRect.width() - 4, sceneRect.height() - 4)
        
        message = self.tr("Topology")
        
        font = painter.font()
        font.setPointSize(12)
        painter.setFont(font)
        painter.setPen(QtCore.Qt.darkGray)
        painter.drawText(textRect.translated(20.8, 5.8), message)
        painter.setPen(QtCore.Qt.white)
        painter.setPen(QtGui.QColor(QtCore.Qt.gray).light(130))
        painter.drawText(textRect.translated(20, 5), message)
                
    def wheelEvent(self, event):
        '''
        Zoom
        '''
        self.scaleView(math.pow(2.0, event.delta() / 300.0))
        
    def scaleView(self, scaleFactor):
        factor = self.matrix().scale(scaleFactor, scaleFactor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width()

        if factor < 0.07 or factor > 100:
            return

        self.scale(scaleFactor, scaleFactor)
    
    def mouseReleaseEvent(self, event):
        '''
        Show context menu when right-clicking on empty space on the scene.
        '''
        if not self.itemAt(event.pos()):
            if event.button() == QtCore.Qt.RightButton:
                popup = QtGui.QMenu()
                popup.addAction("Load Layout", self.loadLayout)
                popup.addAction("Save Layout", self.saveLayout)
                m = popup.addMenu("Mininet")
                m.addAction("Add Switch", self.addSwitch)
                m.addAction("Add Host", self.addHost)
                popup.exec_(event.globalPos())
        QtGui.QGraphicsView.mouseReleaseEvent(self, event)
    
    def saveLayout(self):
        '''
        Saves the current node positioning
        '''
        title = "Specify file to store topology layout"
        filename = QtGui.QFileDialog.getSaveFileName(self,title,"gui/layouts")
        f = QtCore.QFile(filename)
        f.open(QtCore.QIODevice.WriteOnly)
        for node in self.nodes.values():
            line = QtCore.QByteArray(str(node.id)+" "+\
                                    str(round(int(node.x()),-1))+" "+\
                                    str(round(int(node.y()),-1))+" \n")
            f.write(line)
        f.close()
        
        layout = str(filename).split("/")
        layout = layout[len(layout)-1]
        self.parent.parent.settings.set_current_topo_layout(layout)
        
    def loadLayout(self):
        '''
        Loads a custom node positioning for this topology
        '''
        title = "Load topology layout from file"
        filename = QtGui.QFileDialog.getOpenFileName(self,title,"gui/layouts")
        f = QtCore.QFile(filename)
        f.open(QtCore.QIODevice.ReadOnly)
        line = f.readLine()
        while not line.isNull():
            nodeid,x,y = str(line).split()
            line = f.readLine()
            if not ":" in nodeid:
                nodeid = int(nodeid)
            if not nodeid in self.nodes:
                print "Layout mismatch (node", nodeid, "exists in conf file but has not been discovered on the network)"
            else:
                self.nodes[nodeid].setX(float(x))
                self.nodes[nodeid].setY(float(y))
        f.close()
        
        layout = str(filename).split("/")
        layout = layout[len(layout)-1]
        self.parent.parent.settings.set_current_topo_layout(layout)
        
        self.updateAll()
        
    def addSwitch(self):
        self.mininet.addNextSwitch()
        
    def addHost(self):
        self.mininet.addNextHost()
        
    def mininetLinkFrom(self, id):
        self.linkfrom = id
        self.linkto = getattr(self, "linkto", None)
        if not self.linkto:
            self.parent.setStatusTip("Adding link from %s" % id)
        else:
            self.parent.setStatusTip("Adding link %s <-> %s"
                                     %(self.linkto, self.linkfrom))
            self.mininet.addLink(self.linkfrom, self.linkto )
            self.linkfrom = None
            self.linkto = None
        
    def mininetLinkTo(self, id):
        self.linkto = id
        self.linkfrom = getattr(self, "linkfrom", None)
        if not self.linkfrom:
            self.parent.setStatusTip("Adding link to %s" % id)
        else:
            self.parent.setStatusTip("Adding link %s <-> %s"
                                     %(self.linkto, self.linkfrom))
            self.mininet.addLink(self.linkfrom, self.linkto )
            self.linkfrom = None
            self.linkto = None
                
    def mininetLinkUp(self, src, dst):
        self.mininet.linkUp(src, dst)
        self.parent.setStatusTip("Brought up link %s <-> %s" %(src, dst))
    
    def mininetLinkDown(self, src, dst):
        self.mininet.linkDown(src, dst)
        self.parent.setStatusTip("Brought down link %s <-> %s" %(src, dst))