def test_path_length_2(self): f = Flow(0, "X") fwg = FwGraph(5, 0, "X") fwg.add_fw_rule(0, 1) fwg.add_fw_rule(1, 3) fwg.add_fw_rule(3, -1) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(2, -1) p = PathLengthProperty(f, 2) self.assertTrue(p.check({f: fwg}))
def test_isolation_4(self): f1 = Flow(3, "2") f2 = Flow(5, "4") fwg1 = FwGraph(6, 3, "2") fwg1.add_fw_rule(3, 1) fwg1.add_fw_rule(1, 0) fwg1.add_fw_rule(0, 3) fwg2 = FwGraph(6, 5, "4") fwg2.add_fw_rule(5, 4) fwgs = {f1: fwg1, f2: fwg2} p = IsolationProperty([f1, f2]) self.assertTrue(p.check(fwgs))
def test_reachable_2(self): f = Flow(0, "X") fwg = FwGraph(5, 0, "X") fwg.add_fw_rule(0, 1) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(1, 3) fwg.add_fw_rule(3, -1) p = ReachableProperty(f) self.assertFalse(p.check({f: fwg}))
def test_egress_2(self): f = Flow(0, "X") fwg = FwGraph(4, 0, "X") fwg.add_fw_rule(0, 1) fwg.add_fw_rule(1, 3) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(2, -1) fwg.add_fw_rule(3, -1) p = EgressProperty(f, 2) self.assertFalse(p.check({f: fwg}))
def test_loop(self): f = Flow(0, "X") fwg = FwGraph(5, 0, "X") fwg.add_fw_rule(0, 1) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(2, 3) fwg.add_fw_rule(3, 4) fwg.add_fw_rule(3, 1) p = LoopProperty(f) self.assertTrue(p.check({f: fwg}))
def test_balanced(self): f = Flow(0, "6") fwg = FwGraph(7, 0, "6") fwg.add_fw_rule(0, 1) fwg.add_fw_rule(1, 3) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(3, 4) fwg.add_fw_rule(3, 5) fwg.add_fw_rule(2, 5) fwg.add_fw_rule(4, 6) fwg.add_fw_rule(5, 6) fwgs = {f: fwg} self.assertFalse( BalancedProperty([f], [1.0], [(4, 6), (1, 2)], 0.2).check(fwgs)) self.assertTrue( BalancedProperty([f], [1.0], [(4, 6), (1, 5)], 0.25).check(fwgs)) self.assertTrue( BalancedProperty([f], [1.0], [(1, 3), (2, 5)], 0.0).check(fwgs))
def test_congestion(self): f = Flow(0, "6") fwg = FwGraph(7, 0, "6") fwg.add_fw_rule(0, 1) fwg.add_fw_rule(1, 3) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(3, 4) fwg.add_fw_rule(3, 5) fwg.add_fw_rule(2, 5) fwg.add_fw_rule(4, 6) fwg.add_fw_rule(5, 6) fwgs = {f: fwg} p = CongestionProperty([f], [1.0], (4, 6), 0.25) link_load = p._get_load_for_links(fwgs) self.assertEqual(link_load[(1, 3)], 0.5) self.assertEqual(link_load[(3, 4)], 0.25) self.assertEqual(link_load[(5, 6)], 0.75) self.assertTrue(p.check(fwgs))
def test_waypoint_4(self): f = Flow(3, "2") fwg = FwGraph(6, 3, "2") fwg.add_fw_rule(3, 1) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(2, 5) fwg.add_fw_rule(5, 4) fwg.add_fw_rule(4, 1) fwgs = {f: fwg} p = WaypointProperty(f, 2) self.assertTrue(p.check(fwgs))
def _construct_fw_graph_decision_points(self, flow: Flow) -> tuple: """ :return: (FwGraph, list[int]). The first entry is the forwarding graph, the second entry are the decision points """ fwg = FwGraph(self.problem.nof_nodes, flow.src, flow.dst) decision_points = [] visited = [False] * self.problem.nof_nodes # putting None as next hop makes sure that the source of the flow becomes a decision point self._visit_construct_fw_graph(fwg, decision_points, visited, flow.src, None) return fwg, decision_points
def _check_rec(self, fwg: FwGraph, visited: list, cur: int) -> bool: if visited[cur]: return True # we are in a loop if fwg.exits_at(cur): return False visited[cur] = True for n in fwg.next[cur]: if self._check_rec(fwg, visited, n): return True return False
def _visit_construct_fw_graph(self, fwg: FwGraph, decision_points: list, visited: list, cur: int, prev_next_hop): if visited[cur]: return visited[cur] = True sr_next = self._igp_provider.get_static_route_at(cur, fwg.dst) if sr_next is None: bgp_next_hop = self._igp_provider.get_bgp_next_hop(cur, fwg.dst) if bgp_next_hop != prev_next_hop: decision_points.append(cur) if bgp_next_hop is not None: if bgp_next_hop.is_external(): # traffic exits the network here fwg.add_fw_rule(cur, -1) else: next_routers = self._igp_provider.get_next_routers_shortest_paths( cur, bgp_next_hop.assigned_node) for next in next_routers: fwg.add_fw_rule(cur, next) self._visit_construct_fw_graph(fwg, decision_points, visited, next, bgp_next_hop) else: if self.problem.G.has_edge(cur, sr_next): fwg.add_fw_rule(cur, sr_next) # putting None as next hop makes sure that the target of the static route becomes a decision point self._visit_construct_fw_graph(fwg, decision_points, visited, sr_next, None)
def test_waypoint_2(self): f = Flow(3, "2") fwg = FwGraph(6, 3, "2") fwg.add_fw_rule(3, 1) fwg.add_fw_rule(1, 2) fwg.add_fw_rule(2, 5) fwgs = {f: fwg} p = WaypointProperty(f, 0) self.assertFalse(p.check(fwgs))
def _check_rec(self, fwg: FwGraph, visited: list, cur: int) -> bool: if visited[cur]: return False # we are in a loop if fwg.exits_at(cur): return True # traffic reaches its destination if len(fwg.next[cur]) == 0: return False # we have a black hole visited[cur] = True for n in fwg.next[cur]: if not self._check_rec(fwg, visited, n): return False return True
def _check_rec(self, fwg: FwGraph, visited: list, cur: int, n_traversed: int) -> bool: if visited[cur]: return False # we are in a loop if fwg.exits_at(cur): return n_traversed == self.len if len(fwg.next[cur]) == 0: return n_traversed == self.len # black hole (whether to ever return true here is arguable) visited[cur] = True for n in fwg.next[cur]: if not self._check_rec(fwg, visited, n, n_traversed + 1): return False return True
def _check_all_traverse_waypoint(self, fwg: FwGraph, visited: list, on_current_path: list, cur: int) -> bool: if cur == self.waypoint: return True elif fwg.exits_at(cur): return False if visited[cur]: if on_current_path[cur]: return False # we have a loop return True if len(fwg.next[cur]) == 0: return False # we have a black hole visited[cur] = True on_current_path[cur] = True for n in fwg.next[cur]: if not self._check_all_traverse_waypoint(fwg, visited, on_current_path, n): return False on_current_path[cur] = False return True