def __init__(self, *args, **kwargs): super(SouthboundListener, self).__init__(*args, **kwargs) self.igp_graph = IGPGraph() self.dirty = False self.json_proxy = SJMPClient(hostname=CFG.get(DEFAULTSECT, 'json_hostname'), port=CFG.getint(DEFAULTSECT, 'json_port'), target=self) self.quagga_manager = ProxyCloner(FakeNodeProxy, self.json_proxy)
def __init__(self, fwd_dags, optimizer, additional_routes=None): self.igp_graph = nx.DiGraph() self.dirty = False self.additional_routes = additional_routes self.optimizer = optimizer self.fwd_dags = fwd_dags self.current_lsas = set([]) self.json_proxy = SJMPClient(hostname=CFG.get(DEFAULTSECT, 'json_hostname'), port=CFG.getint(DEFAULTSECT, 'json_port'), target=self) self.quagga_manager = ProxyCloner(FakeNodeProxy, self.json_proxy)
def __init__(self, client, *args, **kwargs): Cmd.__init__(self, *args, **kwargs) self.client = client def do_add(self, line=''): self.client.add(('192.168.14.1', '192.168.23.2', 1, '3.3.3.0/24')) self.client.add((None, '192.168.23.2', 1, '4.4.4.0/24')) self.client.add([(None, '192.168.23.2', 1, '5.5.5.0/24'), (None, '192.168.14.1', 1, '5.5.5.0/24')]) def do_remove(self, line=''): self.client.remove(('192.168.14.1', '192.168.23.2', '3.3.3.0/24')) self.client.remove((None, '192.168.23.2', '4.4.4.0/24')) self.client.remove([(None, '192.168.23.2', '5.5.5.0/24'), (None, '192.168.14.1', '5.5.5.0/24')]) def do_exit(self, line): return True if __name__ == '__main__': log.setLevel(logging.DEBUG) shapeshifter = ShapeshifterProxyTest() c = SJMPClient("localhost", CFG.getint(DEFAULTSECT, "json_port"), target=shapeshifter) fakenode = ProxyCloner(FakeNodeProxy, c) Thread(target=c.communicate, name='client').start() TestCLI(fakenode).cmdloop() c.stop()
class SouthboundListener(ShapeshifterProxy): """This basic controller maintains a structure describing the IGP topology and listens for changes.""" def __init__(self, *args, **kwargs): super(SouthboundListener, self).__init__(*args, **kwargs) self.igp_graph = IGPGraph() self.dirty = False self.json_proxy = SJMPClient(hostname=CFG.get(DEFAULTSECT, 'json_hostname'), port=CFG.getint(DEFAULTSECT, 'json_port'), target=self) self.quagga_manager = ProxyCloner(FakeNodeProxy, self.json_proxy) def run(self): """Connect the the southbound controller. This call will not return unless the connection is halted.""" log.info('Connecting to server ...') self.json_proxy.communicate() def stop(self): """Stop the connection to the southbound controller""" self.json_proxy.stop() def bootstrap_graph(self, graph, node_properties): self.igp_graph.clear() self.igp_graph.add_edges_from(graph) for _, _, d in self.igp_graph.edges_iter(data=True): sanitize_edge_data(d) self.update_node_properties(**node_properties) log.debug('Bootstrapped graph with edges: %s and properties: %s', self.igp_graph.edges(data=True), node_properties) self.received_initial_graph() self.graph_changed() def received_initial_graph(self): """Called when the initial graph has been bootstrapped, before calling graph_changed""" pass def add_edge(self, source, destination, properties={'metric': 1}): properties = sanitize_edge_data(properties) # metric is added twice to support backward-compat. self.igp_graph.add_edge(source, destination, properties) log.debug('Added edge: %s-%s@%s', source, destination, properties) # Only trigger an update if the link is bidirectional self.dirty = self.igp_graph.has_edge(destination, source) def commit(self): log.debug('End of graph update') if self.dirty: self.dirty = False self.graph_changed() @abc.abstractmethod def graph_changed(self): """Called when the IGP graph has changed.""" def remove_edge(self, source, destination): # TODO: pay attention to re-add the symmetric edge if only one way # crashed try: self.igp_graph.remove_edge(source, destination) log.debug('Removed edge %s-%s', source, destination) self.igp_graph.remove_edge(destination, source) log.debug('Removed edge %s-%s', destination, source) except nx.NetworkXError: # This means that we had already removed both side of the edge # earlier or that the adjacency was not fully established before # going down pass else: self.dirty = True def update_node_properties(self, **properties): log.debug('Updating node propeties: %s', properties) for node, data in properties.iteritems(): self.igp_graph.node[node].update(data) self.dirty = self.dirty or properties
class SouthboundManager(ShapeshifterProxy): def __init__(self, fwd_dags, optimizer, additional_routes=None): self.igp_graph = nx.DiGraph() self.dirty = False self.additional_routes = additional_routes self.optimizer = optimizer self.fwd_dags = fwd_dags self.current_lsas = set([]) self.json_proxy = SJMPClient(hostname=CFG.get(DEFAULTSECT, 'json_hostname'), port=CFG.getint(DEFAULTSECT, 'json_port'), target=self) self.quagga_manager = ProxyCloner(FakeNodeProxy, self.json_proxy) def run(self): log.info('Connecting to server ...') self.json_proxy.communicate() def stop(self): self.quagga_manager.remove(list(self.current_lsas)) self.json_proxy.stop() # Helper functions def _refresh_augmented_topo(self): log.info('Solving topologies') self.optimizer.solve(self.igp_graph, self.fwd_dags) def _get_diff_lsas(self): self._refresh_augmented_topo() new_lsas = set(self.optimizer.get_fake_lsas()) log.info('New LSA set: %s', new_lsas) to_add = new_lsas.difference(self.current_lsas) to_rem = self.current_lsas.difference(new_lsas) log.info('Removing LSA set: %s', to_rem) self.current_lsas = new_lsas return to_add, to_rem def _refresh_lsas(self): (to_add, to_rem) = self._get_diff_lsas() if to_rem: self.quagga_manager.remove(list(to_rem)) if to_add: self.quagga_manager.add(list(to_add)) # Interface functions def boostrap_graph(self, graph): self.igp_graph.clear() for u, v, metric in graph: self.igp_graph.add_edge(u, v, weight=int(metric)) log.debug('Bootstrapped graph with edges: %s', self.igp_graph.edges()) log.debug('Sending initial lsa''s') if self.additional_routes: self.quagga_manager.add_static(self.additional_routes) self._refresh_lsas() def add_edge(self, source, destination, metric): self.igp_graph.add_edge(source, destination, weight=int(metric)) log.debug('Added edge: %s-%s@%s', source, destination, metric) try: self.igp_graph[destination][source] except KeyError: # Only trigger an update if the link is bidirectional pass else: self.dirty = True def commit(self): if self.dirty: self._refresh_lsas() self.dirty = False def remove_edge(self, source, destination): # TODO: pay attention to re-add the symmetric edge if only one way # crashed try: self.igp_graph.remove_edge(source, destination) log.debug('Removed edge %s-%s', source, destination) self.igp_graph.remove_edge(destination, source) log.debug('Removed edge %s-%s', destination, source) except nx.NetworkXError: # This means that we had already removed both side of the edge # earlier pass else: self.dirty = True
class TestCLI(Cmd): Cmd.prompt = "> " def __init__(self, client, *args, **kwargs): Cmd.__init__(self, *args, **kwargs) self.client = client def do_add(self, line=""): self.client.add(("192.168.14.1", "192.168.23.2", 1, "3.3.3.0/24")) self.client.add((None, "192.168.23.2", 1, "4.4.4.0/24")) self.client.add([(None, "192.168.23.2", 1, "5.5.5.0/24"), (None, "192.168.14.1", 1, "5.5.5.0/24")]) def do_remove(self, line=""): self.client.remove(("192.168.14.1", "192.168.23.2", "3.3.3.0/24")) self.client.remove((None, "192.168.23.2", "4.4.4.0/24")) self.client.remove([(None, "192.168.23.2", "5.5.5.0/24"), (None, "192.168.14.1", "5.5.5.0/24")]) def do_exit(self, line): return True if __name__ == "__main__": log.setLevel(logging.DEBUG) shapeshifter = ShapeshifterProxyTest() c = SJMPClient("localhost", CFG.getint(DEFAULTSECT, "json_port"), target=shapeshifter) fakenode = ProxyCloner(FakeNodeProxy, c) Thread(target=c.communicate, name="client").start() TestCLI(fakenode).cmdloop() c.stop()
def do_exit(self, line): return True def do_info(self, line): # Query the remopte end for the supported methods/docs/args self.client.ask_info() def default(self, line): items = line.split(' ') self.client.execute(items[0], *items[1:]) if __name__ == '__main__': log.setLevel(logging.DEBUG) s = SJMPServer(H, P, target=EchoProxy()) c = SJMPClient(H, P) a = ProxyCloner(EchoProxy, c) log.debug(dir(a)) st = Thread(target=s.communicate, name='server') st.daemon = True st.start() log.debug('Started server') ct = Thread(target=c.communicate, name='client') ct.daemon = True ct.start() log.debug('Started client') a.echo('hello world') a.sum(1, 2) TestCLI(c).cmdloop() c.stop() s.stop()