Beispiel #1
0
    def get_waypoint_policies(self,
                              policies,
                              forwarding_graphs,
                              dominator_graphs,
                              node_local_reachability=False):

        start_time = time.time()
        for subnet, graph in dominator_graphs.items():

            all_destinations, destinations, dst_routers = self.get_destination_interfaces_for_subnet(
                subnet, forwarding_graphs[subnet])

            # TODO how to deal with Loadbalancing to same prefix, but last hop is different router?!
            # only use router specific subnets (e.g., subnets that are connected at a single interface, such as loopback
            # and host subnets). This removes all subnet that just exist between two routers (usually /31)
            if len(all_destinations) > 1:
                continue

            for waypoint in self.waypoints:
                if waypoint in graph:
                    candidates = [waypoint]
                    sources = [PolicySource(waypoint)]

                    while candidates:
                        current_node = candidates.pop()
                        if current_node not in graph:
                            self.logger.error(
                                "Node {node} is not in the dominator graph for subnet {subnet}."
                                .format(node=current_node, subnet=subnet))
                            break
                        predecessors = list(graph.predecessors(current_node))

                        candidates.extend(predecessors)
                        for predecessor in predecessors:

                            # prevent policies within a single router (e.g., r1 can reach r1:loopback0)
                            if not (not node_local_reachability
                                    and predecessor in dst_routers):
                                sources.append(PolicySource(predecessor))

                    for source in sources:
                        if source.router not in dst_routers:
                            for policy_destination in destinations[
                                    source.router]:
                                policies.append(
                                    (PolicyType.Waypoint, policy_destination,
                                     waypoint, source))

        self.logger.debug(
            "Getting the waypoint policies from dominator and forwarding graph took {time:.4f}s."
            .format(time=time.time() - start_time, ))

        return policies
Beispiel #2
0
    def get_reachability_policies(self,
                                  policies,
                                  forwarding_graphs,
                                  dominator_graphs,
                                  node_local_reachability=False):

        all_nodes = set(self.network.nodes())

        # iterate over every forwarding graph and check if it is connected
        start_time = time.time()
        for subnet, graph in dominator_graphs.items():

            all_destinations, destinations, dst_routers = self.get_destination_interfaces_for_subnet(
                subnet, forwarding_graphs[subnet])

            # only use router specific subnets (e.g., subnets that are connected at a single interface, such as loopback
            # and host subnets). This removes all subnet that just exist between two routers (usually /31)
            if len(all_destinations) > 1 or len(all_destinations) == 0:
                continue

            # get all routers that can reach the destination and all routers that are isolated from it
            reachable_sources = set(graph.nodes())
            isolated_sources = all_nodes.difference(reachable_sources)

            if 'sink' in reachable_sources:
                reachable_sources.remove("sink")

            # prevent policies within a single router (e.g., r1 can reach r1:loopback0)
            if not node_local_reachability:
                for dst_router in dst_routers:
                    reachable_sources.remove(dst_router)

            # add all reachability policies
            for source in reachable_sources:
                policy_source = PolicySource(source)
                policy_destinations = destinations[source]
                for policy_destination in policy_destinations:
                    policies.append((PolicyType.Reachability,
                                     policy_destination, 0, policy_source))

            # add all isolation policies
            for source in isolated_sources:
                policy_source = PolicySource(source)
                for policy_destination in all_destinations:
                    policies.append((PolicyType.Isolation, policy_destination,
                                     0, policy_source))

        self.logger.debug(
            "Getting the reachability policies from the forwarding graphs took {time:.4f}s."
            .format(time=time.time() - start_time))

        return policies
Beispiel #3
0
    def get_two_interfaces_network(self, local=False):
        subnet = IPv4Network("10.0.0.0/24")

        # normal forwarding graph
        fwd_graph = nx.DiGraph()
        fwd_graph.add_edge("r1", "sink")
        fwd_graph.add_edge("r2", "sink")
        fwd_graph.add_edge("r3", "r1")
        fwd_graph.add_edge("r4", "r1")
        fwd_graph.add_edge("r4", "r2")
        fwd_graph.add_edge("r5", "r2")
        fwd_graph.add_edge("r6", "r2")
        fwd_graph.add_edge("r6", "r5")

        # according to the definition in https://en.wikipedia.org/wiki/Dominator_(graph_theory)
        dom_graph = nx.DiGraph()
        dom_graph.add_edge("r1", "sink")
        dom_graph.add_edge("r2", "sink")
        dom_graph.add_edge("r3", "r1")
        dom_graph.add_edge("r4", "sink")
        dom_graph.add_edge("r5", "r2")
        dom_graph.add_edge("r6", "r2")

        fwd_graphs = {subnet: fwd_graph}
        dom_graphs = {subnet: dom_graph}

        # dummy network
        nodes = ["r1", "r2", "r3", "r4", "r5", "r6", ]
        dst_router1 = "r1"
        dst_router2 = "r2"
        dst_interface = Interface("FastEthernet0/0")
        dst_interface.set_ip_address(next(subnet.hosts()), subnet)
        interfaces = {subnet: [(dst_router1, dst_interface), (dst_router2, dst_interface), ]}
        network = DummyNetwork(nodes, interfaces)

        policy_destination1 = PolicyDestination(dst_router1, dst_interface, subnet)
        policy_destination2 = PolicyDestination(dst_router2, dst_interface, subnet)

        reachability_policies = [
            (PolicyType.Reachability, policy_destination1, 0, PolicySource("r3")),
            (PolicyType.Reachability, policy_destination1, 0, PolicySource("r4")),
            (PolicyType.Reachability, policy_destination2, 0, PolicySource("r4")),
            (PolicyType.Reachability, policy_destination2, 0, PolicySource("r5")),
            (PolicyType.Reachability, policy_destination2, 0, PolicySource("r6")),
        ]

        if local:
            reachability_policies.append((PolicyType.Reachability, policy_destination1, 0, PolicySource("r1")))
            reachability_policies.append((PolicyType.Reachability, policy_destination2, 0, PolicySource("r2")))

        return network, fwd_graphs, dom_graphs, reachability_policies
Beispiel #4
0
    def test_get_waypoint_policies(self):

        network, fwd_graphs, dom_graphs, policy_destination, reachability_policies = self.get_disconnected_network()

        correct_policies = [
            (PolicyType.Waypoint, policy_destination, "r2", PolicySource("r2")),
            (PolicyType.Waypoint, policy_destination, "r2", PolicySource("r3")),
        ]

        test_policies = list()
        pg = PolicyGuesser(network, waypoints=["r2", "r6"])
        pg.get_waypoint_policies(test_policies, fwd_graphs, dom_graphs, node_local_reachability=False)

        self.assertCountEqual(test_policies, correct_policies)
Beispiel #5
0
    def test_get_waypoint_policies_simple(self):
        network, fwd_graphs, dom_graphs, policy_destination, _ = self.get_simple_network()

        correct_policies = [
            (PolicyType.Reachability, policy_destination, 0, PolicySource("r2")),
            (PolicyType.Reachability, policy_destination, 0, PolicySource("r3")),
            (PolicyType.Reachability, policy_destination, 0, PolicySource("r4")),
            (PolicyType.Reachability, policy_destination, 0, PolicySource("r5")),
            (PolicyType.Reachability, policy_destination, 0, PolicySource("r6")),
        ]

        test_policies = list()
        pg = PolicyGuesser(network)
        pg.get_reachability_policies(test_policies, fwd_graphs, dom_graphs, node_local_reachability=False)

        self.assertCountEqual(test_policies, correct_policies)
Beispiel #6
0
    def get_query(sources):
        sources = [PolicySource(src_router) for src_router in sources]
        destinations = PolicyDestination("r12", "FastEthernet1/1", "11.0.12.0/24")
        num_paths = 3
        links = [Link("l{id}".format(id=i), edge, LinkState.UP) for i, edge in enumerate(ResponseTest.get_all_edges())]
        netenv = NetworkEnvironment(links)

        return Query(PolicyType.LoadBalancingSimple, sources, destinations, num_paths, netenv, negate=False)
Beispiel #7
0
    def test_get_loadbalancing_policies_disconnected(self):
        network, fwd_graphs, dom_graphs, policy_destination, _ = self.get_disconnected_network()

        correct_policies = [
            (PolicyType.LoadBalancingSimple, policy_destination, 2, PolicySource("r4")),
        ]

        test_policies = list()
        pg = PolicyGuesser(network)
        pg.get_loadbalancing_policies(test_policies, fwd_graphs, dom_graphs, simple=True, node_local_reachability=False)

        self.assertCountEqual(test_policies, correct_policies)
            # restart backend
            ms_manager.restart(force=True)

            policy_db = get_policy_db(network, waypoints=waypoints, debug=debug)

            # add all the policies
            start_time = time.time()
            destinations = list()
            for subnet, interfaces in network.subnets.items():
                if len(interfaces) == 1:
                    dst_router, dst_interface = interfaces[0]
                    destinations.append(PolicyDestination(dst_router, dst_interface, subnet))

            sources = list()
            for router in network.nodes():
                sources.append(PolicySource(router))

            policies = list()
            for source in sources:
                for destination in destinations:
                    policies.append((PolicyType.Reachability, destination, 0, source))
                    policies.append((PolicyType.Isolation, destination, 0, source))

                    for waypoint in waypoints:
                        policies.append((PolicyType.Waypoint, destination, waypoint, source))

                    policies.append((PolicyType.LoadBalancingSimple, destination, 2, source))
            policy_db.update_policies2(policies, 99)
            policy_time = time.time() - start_time

            verifier_baseline = VerificationOnly(policy_db, netenv, ms_manager)
Beispiel #9
0
    def get_loadbalancing_policies(self,
                                   policies,
                                   forwarding_graphs,
                                   dominator_graphs,
                                   node_local_reachability=False,
                                   simple=True,
                                   edge_disjoint=False,
                                   node_disjoint=False):

        start_time = time.time()
        for subnet, graph in dominator_graphs.items():
            all_destinations, destinations, dst_routers = self.get_destination_interfaces_for_subnet(
                subnet, forwarding_graphs[subnet])

            # TODO how to deal with Loadbalancing to same prefix, but last hop is different router?!
            # only use router specific subnets (e.g., subnets that are connected at a single interface, such as loopback
            # and host subnets). This removes all subnet that just exist between two routers (usually /31)
            if len(all_destinations) > 1:
                continue

            for node in graph.nodes():
                # prevent policies within the same router
                if node == "sink" or (not node_local_reachability
                                      and node in dst_routers):
                    continue

                if len(destinations[node]) == 1:
                    policy_destination = destinations[node][0]
                    dst_router = policy_destination.router
                else:
                    self.logger.error(
                        "There should only be a single destination for {node} this subnet: {subnet}."
                        .format(node=node, subnet=subnet))
                    continue

                policy_source = PolicySource(node)

                all_paths = list(
                    nx.all_simple_paths(forwarding_graphs[subnet], node,
                                        "sink"))

                # only continue if there is more than one path available
                if len(all_paths) > 1:
                    # simple loadbalancing, more than a single path
                    if simple:
                        policies.append((PolicyType.LoadBalancingSimple,
                                         policy_destination, len(all_paths),
                                         policy_source))

                    # edge disjoint loadbalancing
                    if edge_disjoint:
                        edge_disjoint_paths = list()
                        edge_union = set()
                        for path in all_paths:
                            edges = set([
                                Link.get_name(path[i], path[i + 1])
                                for i in range(len(path) - 1)
                            ])

                            if not edge_union.intersection(edges):
                                edge_union.union(edges)
                                edge_disjoint_paths.append(path)

                        if len(edge_disjoint_paths) > 1:
                            self.logger.debug(
                                "There are {num_paths} edge-disjoint paths from {src} to {dst}."
                                .format(num_paths=len(edge_disjoint_paths),
                                        src=node,
                                        dst=dst_router))

                            # TODO add policies

                    # node disjoint loadbalancing
                    if node_disjoint:
                        node_disjoint_paths = list()
                        node_union = set()
                        for path in all_paths:
                            # need to remove the source and destination as all the paths will have them in common
                            nodes = set(path[1:-1])

                            if not node_union.intersection(nodes):
                                node_union.union(nodes)
                                node_disjoint_paths.append(path)

                        if len(node_disjoint_paths) > 1:
                            self.logger.debug(
                                "There are {num_paths} node-disjoint paths from {src} to {dst}."
                                .format(num_paths=len(node_disjoint_paths),
                                        src=node,
                                        dst=dst_router))

                            # TODO add policies

        self.logger.debug(
            "Getting the loadbalancing policies from the forwarding graphs took {time:.4f}s."
            .format(time=time.time() - start_time, ))

        return policies