def _setUpPaperGadget(self): # H1 -- 19 -- A1 ---------+ # | | # +-- 10 ----+ 2 # | | # H2 -- 2 -- X -- 100 -- Y # | / \ | # 6 H3 -- 2 \ | # | | 8 | # | 6----+ / 17 # | | / | # +--------A2------------+ # self.paper_gadget = g = IGPGraph() self._add_edge(g, 'H1', 'A1', 19) self._add_edge(g, 'H1', 'X', 10) self._add_edge(g, 'A1', 'Y', 2) self._add_edge(g, 'X', 'Y', 100) self._add_edge(g, 'X', 'H2', 2) self._add_edge(g, 'X', 'H3', 2) self._add_edge(g, 'X', 'A2', 8) self._add_edge(g, 'H3', 'A2', 6) self._add_edge(g, 'H2', 'A2', 6) self._add_edge(g, 'Y', 'A2', 17) for _, data in g.nodes_iter(data=True): data['router'] = True
def _setUpDoubleDiamond(self): # + --------19--------- + # | | # H1 ---10--- Y1 | # \ | | # 15 5 | # \ | | # Y2 -10- X --100-- D --1000-- 1/8 # | | # H2---2---+ | # / | # 6 | # / | # A -------- 17 --------+ self.ddiamond = g = IGPGraph() self._add_edge(g, 'H1', 'D', metric=19) self._add_edge(g, 'H1', 'Y1', metric=10) self._add_edge(g, 'Y1', 'X', metric=5) self._add_edge(g, 'H1', 'Y2', metric=15) self._add_edge(g, 'Y2', 'X', metric=10) self._add_edge(g, 'A', 'H2', metric=6) self._add_edge(g, 'H2', 'X', metric=2) self._add_edge(g, 'A', 'D', metric=17) self._add_edge(g, 'X', 'D', metric=100) for _, data in g.nodes_iter(data=True): data['router'] = True
def testDoubleDiamond(self, expected_lsa_count=3): self.log_test_name() self._test( self.gadgets.ddiamond, { '1_8': IGPGraph([('H1', 'Y1'), ('H1', 'Y2'), ('Y1', 'X'), ('Y2', 'X'), ('H2', 'X'), ('X', 'D')]) }, expected_lsa_count)
def testPaperGadget(self): log.warning('Testing PaperGadget') self._test( self.gadgets.paper_gadget, { '3_8': IGPGraph([('H1', 'X'), ('H2', 'X'), ('H3', 'X'), ('X', 'Y'), ('A1', 'Y'), ('A2', 'Y')]) }, 1)
def testSquareWithThreeConsecutiveChanges(self): log.warning('Testing SquareWithThreeConsecutiveChanges') self._test( self.gadgets.square, { '3_8': IGPGraph([('D2', 'B1'), ('B1', 'T1'), ('T1', 'T2'), ('T2', 'B2'), ('B2', 'D1')]) }, 3)
def testDoubleDiamond(self): log.warning('Testing DoubleDiamond') self._test( self.gadgets.ddiamond, { '1_8': IGPGraph([('H1', 'Y1'), ('H1', 'Y2'), ('Y1', 'X'), ('Y2', 'X'), ('H2', 'X'), ('X', 'D')]) }, 3)
def testSquareWithThreeConsecutiveChanges(self, expected_lsa_count=3): self.log_test_name() self._test( self.gadgets.square, { '3_8': IGPGraph([('D2', 'B1'), ('B1', 'T1'), ('T1', 'T2'), ('T2', 'B2'), ('B2', 'D1')]) }, expected_lsa_count)
def testPaperGadget(self, expected_lsa_count=1): self.log_test_name() self._test( self.gadgets.paper_gadget, { '3_8': IGPGraph([('H1', 'X'), ('H2', 'X'), ('H3', 'X'), ('X', 'Y'), ('A1', 'Y'), ('A2', 'Y')]) }, expected_lsa_count)
def testDiamond(self, expected_lsa_count=2): self.log_test_name() self._test( self.gadgets.diamond, { '3_8': IGPGraph([('A', 'Y1'), ('A', 'Y2'), ('Y2', 'X'), ('Y1', 'X'), ('X', 'D'), ('O', 'D')]) }, expected_lsa_count)
def testDiamond(self): log.warning('Testing Diamond') self._test( self.gadgets.diamond, { '3_8': IGPGraph([('A', 'Y1'), ('A', 'Y2'), ('Y2', 'X'), ('Y1', 'X'), ('X', 'D'), ('O', 'D')]) }, 2)
def simple_path_requirement(self, prefix, path): """Add a path requirement for the given prefix. :param path: The ordered list of routerid composing the path. E.g. for path = [A, B, C], the following edges will be used as requirements: [](A, B), (B, C), (C, D)]""" self.fwd_dags[prefix] = IGPGraph( [(s, d) for s, d in zip(path[:-1], path[1:])]) self.refresh_lsas()
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 testParallel(self): log.warning('Testing Parallel') self._test( self.gadgets.parallel, { '3_8': IGPGraph([('A2', 'B2'), ('B2', 'C2'), ('C2', 'D2'), ('D2', 'D1'), ('D1', 'C1'), ('C1', 'B1'), ('B1', 'A1'), ('A1', 'D')]) }, 4)
def testParallel(self, expected_lsa_count=4): self.log_test_name() self._test( self.gadgets.parallel, { '3_8': IGPGraph([('A2', 'B2'), ('B2', 'C2'), ('C2', 'D2'), ('D2', 'D1'), ('D1', 'C1'), ('C1', 'B1'), ('B1', 'A1'), ('A1', 'D')]) }, expected_lsa_count)
def testSquareWithThreeConsecutiveChangesAndMultipleRequirements( self, expected_lsa_count=5): self.log_test_name() dag = IGPGraph([('D2', 'B1'), ('B1', 'T1'), ('T1', 'T2'), ('T2', 'B2'), ('B2', 'D1')]) self._test(self.gadgets.square, { '3_8': dag, '8_3': dag.reverse(copy=True) }, expected_lsa_count)
def testSquareWithThreeConsecutiveChangesAndMultipleRequirements(self): log.warning('Testing SquareWithThreeConsecutiveChanges' 'AndMultipleRequirements') dag = IGPGraph([('D2', 'B1'), ('B1', 'T1'), ('T1', 'T2'), ('T2', 'B2'), ('B2', 'D1')]) self._test(self.gadgets.square, { '3_8': dag, '8_3': dag.reverse(copy=True) }, 5)
def _setUpWeird(self): # +-----D-----+ # / | \ # 2 2 2 # / | \ # A -- 4 -- B -- 2 -- C self.weird = g = IGPGraph() self._add_edge(g, 'A', 'B', 4) self._add_edge(g, 'B', 'C', 2) self._add_edge(g, 'D', 'C', 2) self._add_edge(g, 'D', 'B', 2) self._add_edge(g, 'D', 'A', 2)
def _setUpTrapezoid(self): # R1 -- 100 -- E1 -- 10 -+ # | | # 100 D # | | # R2 -- 10 -- E2 -- 10 -+ self.trap = g = IGPGraph() self._add_edge(g, 'R1', 'E1', metric=100) self._add_edge(g, 'R1', 'R2', metric=100) self._add_edge(g, 'R2', 'E2', metric=10) self._add_edge(g, 'E1', 'D', metric=10) self._add_edge(g, 'E2', 'D', metric=10)
def _setUpWeird(self): # +-----D-----+ # / | \ # 2 2 2 # / | \ # A -- 4 -- B -- 2 -- C self.weird = g = IGPGraph() self._add_edge(g, 'A', 'B', 4) self._add_edge(g, 'B', 'C', 2) self._add_edge(g, 'D', 'C', 2) self._add_edge(g, 'D', 'B', 2) self._add_edge(g, 'D', 'A', 2) for _, data in g.nodes_iter(data=True): data['router'] = True
def _setUpTrapezoid(self): # R1 -- 100 -- E1 -- 10 -+ # | | # 100 D # | | # R2 -- 10 -- E2 -- 10 -+ self.trap = g = IGPGraph() self._add_edge(g, 'R1', 'E1', metric=100) self._add_edge(g, 'R1', 'R2', metric=100) self._add_edge(g, 'R2', 'E2', metric=10) self._add_edge(g, 'E1', 'D', metric=10) self._add_edge(g, 'E2', 'D', metric=10) for _, data in g.nodes_iter(data=True): data['router'] = True
def testTrapezoidWithEcmp(self, expected_lsa_count=3): self.log_test_name() self._test( self.gadgets.trap, { '2_8': IGPGraph([ ('R1', 'R2'), ('R2', 'E2'), ('E2', 'D'), # ECMP on E1 ('E1', 'D'), ('E1', 'R1') ]) }, expected_lsa_count)
def testTrapezoidWithEcmp(self): log.warning('Testing TrapezoidWithEcmp') self._test( self.gadgets.trap, { '2_8': IGPGraph([ ('R1', 'R2'), ('R2', 'E2'), ('E2', 'D'), # ECMP on E1 ('E1', 'D'), ('E1', 'R1') ]) }, 3)
def _setUpParallelTracks(self): # A2--B2--C2--D2 # /| | | | # D-A1--B1--C1--D1 self.parallel = g = IGPGraph() self._add_edge(g, 'D', 'A1', 2) self._add_edge(g, 'D', 'A2', 2) self._add_edge(g, 'B2', 'A2', 2) self._add_edge(g, 'B1', 'A1', 2) self._add_edge(g, 'B1', 'C1', 2) self._add_edge(g, 'B2', 'C2', 2) self._add_edge(g, 'C2', 'D2', 2) self._add_edge(g, 'C1', 'D1', 2) self._add_edge(g, 'D2', 'D1', 2) self._add_edge(g, 'C2', 'C1', 2) self._add_edge(g, 'B2', 'B1', 2) self._add_edge(g, 'A2', 'A1', 2)
def _setUpSquare(self): self.square = g = IGPGraph() # T1 --10-- T2 # | \ | # 10 5 100 # | \ | # B1 --3-- B2 --100--D1 # | # 100 # | # D2 self._add_edge(g, 'B1', 'B2', metric=3) self._add_edge(g, 'T1', 'B1', metric=10) self._add_edge(g, 'T2', 'T1', metric=10) self._add_edge(g, 'B2', 'T1', metric=5) self._add_edge(g, 'T2', 'B2', metric=100) self._add_edge(g, 'D1', 'B2', metric=100) self._add_edge(g, 'D2', 'B1', metric=100)
def __init__(self): self.BASE_NET = ip_network(CFG.get(DEFAULTSECT, 'base_net')) self.private_addresses = PrivateAddressStore(CFG.get(DEFAULTSECT, 'private_ips')) self.last_line = '' self.leader_watchdog = None self.transaction = False self.uncommitted_changes = 0 self.graph = IGPGraph() self._lsdb = {NetworkLSA.TYPE: {}, RouterLSA.TYPE: {}, ASExtLSA.TYPE: {}} self.controllers = defaultdict(list) # controller nr : ip_list self.listener = {} self.keep_running = True self.queue = Queue() self.processing_thread = start_daemon_thread( target=self.process_lsa, name='lsa processing thread')
def __init__(self): self.BASE_NET = ip_network(CFG.get(DEFAULTSECT, 'base_net')) self.private_addresses = PrivateAddressStore( CFG.get(DEFAULTSECT, 'private_ips')) self.last_line = '' self.leader_watchdog = None self.transaction = None self.graph = IGPGraph() self.routers = {} # router-id : lsa self.networks = {} # DR IP : lsa self.ext_networks = {} # (router-id, dest) : lsa self.controllers = defaultdict(list) # controller nr : ip_list self.listener = {} self.keep_running = True self.queue = Queue() self.processing_thread = Thread(target=self.process_lsa, name="lsa_processing_thread") self.processing_thread.setDaemon(True) self.processing_thread.start()
def build_graph(self): self.controllers.clear() new_graph = IGPGraph() # Rebuild the graph from the LSDB for lsa in chain(self.routers.itervalues(), self.networks.itervalues(), self.ext_networks.itervalues()): if is_expired_lsa(lsa): log.debug("LSA %s is too old (%d) ignoring it!", lsa, lsa.age) else: lsa.apply(new_graph, self) # Contract all IPs to their respective router-id for rlsa in self.routers.itervalues(): rlsa.contract_graph(new_graph, self.private_addresses .addresses_of(rlsa.routerid)) # Figure out the controllers layout controller_prefix = CFG.getint(DEFAULTSECT, 'controller_prefixlen') # Group by controller and log them for ip in new_graph.nodes_iter(): try: addr = ip_address(ip) except ValueError: continue # Have a prefix if addr in self.BASE_NET: """1. Compute address diff to remove base_net 2. Right shift to remove host bits 3. Mask with controller mask""" cid = (((int(addr) - int(self.BASE_NET.network_address)) >> self.BASE_NET.max_prefixlen - controller_prefix) & ((1 << controller_prefix) - 1)) self.controllers[cid].append(ip) # Contract them on the graph for id, ips in self.controllers.iteritems(): cname = 'C_%s' % id new_graph.add_controller(cname) new_graph.contract(cname, ips) # Remove generated self loops new_graph.remove_edges_from(new_graph.selfloop_edges()) self.apply_secondary_addresses(new_graph) return new_graph
def _setUpParallelTracks(self): # A2--B2--C2--D2 # /| | | | # D-A1--B1--C1--D1 self.parallel = g = IGPGraph() self._add_edge(g, 'D', 'A1', 2) self._add_edge(g, 'D', 'A2', 2) self._add_edge(g, 'B2', 'A2', 2) self._add_edge(g, 'B1', 'A1', 2) self._add_edge(g, 'B1', 'C1', 2) self._add_edge(g, 'B2', 'C2', 2) self._add_edge(g, 'C2', 'D2', 2) self._add_edge(g, 'C1', 'D1', 2) self._add_edge(g, 'D2', 'D1', 2) self._add_edge(g, 'C2', 'C1', 2) self._add_edge(g, 'B2', 'B1', 2) self._add_edge(g, 'A2', 'A1', 2) for _, data in g.nodes_iter(data=True): data['router'] = True
def commit_change(self): """ @API commit the changes, and applied the requirements entered for the current session """ for prefix in self.change_pfx: tmp = [] if not self.simple_req[prefix]: self.remove_dag_requirement(prefix) else: for item in self.simple_req[prefix]: for s, d in zip(item.path[:-1], item.path[1:]): if (s, d) not in tmp: tmp.append((s, d)) LOG.debug('add_dag_requirement') self.add_dag_requirement(prefix, IGPGraph(tmp)) del self.change_pfx[:] self.refresh_augmented_topo()
def _setUpDiamond(self): # A ---5--- Y1 # | \ | # | 10 10 # | \ | # | Y2 -15-- X ---50--- D # | | | # 25 +--30----+ | # | / | # O -------- 10 ---------+ self.diamond = g = IGPGraph() self._add_edge(g, 'A', 'Y1', metric=5) self._add_edge(g, 'Y1', 'X', metric=10) self._add_edge(g, 'A', 'Y2', metric=10) self._add_edge(g, 'Y2', 'X', metric=15) self._add_edge(g, 'X', 'D', metric=50) self._add_edge(g, 'A', 'O', metric=25) self._add_edge(g, 'X', 'O', metric=30) self._add_edge(g, 'D', 'O', metric=10)