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
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
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
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
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()
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
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
def __init__(self): self.pox_nom_decoder = NOMDecoder()
def __init__(self): SnapshotService.__init__(self) self.port = 7790 self.myNOMDecoder = NOMDecoder()
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))