Exemplo n.º 1
0
def test_prop_parent_pos_child_pos():

    # Add a parent aggregate rioute and a child more specific route, each with only positive
    # next-hops.

    fib = Fib()
    rib = Rib(fib)

    # Install two routes into the RIB:
    rib.put_route("1.2.0.0/16", ["nh1", "nh2"])     # Parent aggregate route, positive nexthops
    rib.put_route("1.2.3.0/24", ["nh3", "nh4"])     # Child more specific route, positive nexthops

    # The RIB must contain the following routes:
    assert str(rib) == ("1.2.0.0/16 -> nh1, nh2\n"
                        "1.2.3.0/24 -> nh3, nh4\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("1.2.0.0/16 -> nh1, nh2\n"
                        "1.2.3.0/24 -> nh3, nh4\n")

    # Delete the parent route from the RIB.
    rib.del_route("1.2.0.0/16")
    assert str(rib) == "1.2.3.0/24 -> nh3, nh4\n"

    # The corresponding route should be deleted from the FIB.
    assert str(fib) == "1.2.3.0/24 -> nh3, nh4\n"

    # Delete the child route from the RIB.
    rib.del_route("1.2.3.0/24")

    # The RIB must be empty.
    assert str(rib) == ""

    # The FIB must be empty.
    assert str(fib) == ""
def test_add_two_route_same_destination_with_subnet_and_remove_one():
    rib = Rib()
    default_route = RibRoute(default_prefix, N_SPF, default_next_hops)
    rib.put_route(default_route)
    best_default_route = RibRoute(default_prefix, S_SPF, ["S1", "S2", "S3"])
    rib.put_route(best_default_route)
    first_disagg_route = RibRoute(first_negative_disagg_prefix, S_SPF, [], first_negative_disagg_next_hops)
    rib.put_route(first_disagg_route)
    subnet_disagg_route = RibRoute(subnet_disagg_prefix, S_SPF, [], subnet_negative_disagg_next_hops)
    rib.put_route(subnet_disagg_route)
    rib.del_route(default_prefix, S_SPF)
    # Test for default
    assert rib.destinations.get(default_prefix).best_route == default_route
    assert rib.destinations.get(default_prefix).best_route.positive_next_hops == {'S1', 'S2', 'S3', 'S4'}
    assert rib.destinations.get(default_prefix).best_route.negative_next_hops == set()
    assert rib.destinations.get(default_prefix).best_route.next_hops == {'S1', 'S2', 'S3', 'S4'}
    assert rib.fib.routes[default_prefix].next_hops == default_route.next_hops
    assert rib.fib.kernel.routes[default_prefix] == default_route.next_hops
    # Test for 10.0.0.0/16
    assert rib.destinations.get(first_negative_disagg_prefix).best_route == first_disagg_route
    assert rib.destinations.get(first_negative_disagg_prefix).best_route.positive_next_hops == set()
    assert rib.destinations.get(first_negative_disagg_prefix).best_route.negative_next_hops == {'S1'}
    assert rib.destinations.get(first_negative_disagg_prefix).best_route.next_hops == {'S2', 'S3', 'S4'}
    assert rib.fib.routes[first_negative_disagg_prefix].next_hops == first_disagg_route.next_hops
    assert rib.fib.kernel.routes[first_negative_disagg_prefix] == first_disagg_route.next_hops
    # Test for 10.0.10.0/24
    assert rib.destinations.get(subnet_disagg_prefix).best_route == subnet_disagg_route
    assert rib.destinations.get(subnet_disagg_prefix).best_route.positive_next_hops == set()
    assert rib.destinations.get(subnet_disagg_prefix).best_route.negative_next_hops == {'S2'}
    assert rib.destinations.get(subnet_disagg_prefix).best_route.next_hops == {'S3', 'S4'}
    assert rib.fib.routes[subnet_disagg_prefix].next_hops == subnet_disagg_route.next_hops
    assert rib.fib.kernel.routes[subnet_disagg_prefix] == subnet_disagg_route.next_hops
def test_remove_default_route():
    rib = Rib()
    default_route = RibRoute(default_prefix, S_SPF, default_next_hops)
    rib.put_route(default_route)
    first_disagg_route = RibRoute(first_negative_disagg_prefix, S_SPF, [], first_negative_disagg_next_hops)
    rib.put_route(first_disagg_route)
    subnet_disagg_route = RibRoute(subnet_disagg_prefix, S_SPF, [], subnet_negative_disagg_next_hops)
    rib.put_route(subnet_disagg_route)
    rib.del_route(default_prefix, S_SPF)
    # Test for default
    assert not rib.destinations.has_key(default_prefix)
    assert default_prefix not in rib.fib.routes
    assert default_prefix not in rib.fib.kernel.routes
    # Test for 10.0.0.0/16
    assert rib.destinations.get(first_negative_disagg_prefix).parent_prefix_dest is None
    assert rib.destinations.get(first_negative_disagg_prefix).best_route.positive_next_hops == set()
    assert rib.destinations.get(first_negative_disagg_prefix).best_route.negative_next_hops == {'S1'}
    assert rib.destinations.get(first_negative_disagg_prefix).best_route.next_hops == set()
    assert rib.fib.routes[first_negative_disagg_prefix].next_hops == set()
    assert rib.fib.kernel.routes[first_negative_disagg_prefix] == "unreachable"
    # Test for 10.0.10.0/24
    assert rib.destinations.get(subnet_disagg_prefix).best_route.positive_next_hops == set()
    assert rib.destinations.get(subnet_disagg_prefix).best_route.negative_next_hops == {'S2'}
    assert rib.destinations.get(subnet_disagg_prefix).best_route.next_hops == set()
    assert rib.fib.routes[subnet_disagg_prefix].next_hops == set()
    assert rib.fib.kernel.routes[subnet_disagg_prefix] == "unreachable"
Exemplo n.º 4
0
def test_del_route():
    fib = Fib()
    rib = Rib(fib)
    rib.put_route("4.0.0.0/8", ["nh1", "nh2"])
    rib.put_route("5.5.0.0/16", ["nh3", "nh4"])
    rib.del_route("4.0.0.0/8")
    rib.del_route("3.0.0.0/8")
    assert str(rib) == ("5.5.0.0/16 -> nh3, nh4\n")
def test_remove_superfluous_subnet():
    rib = Rib()
    default_route = RibRoute(default_prefix, S_SPF, default_next_hops)
    rib.put_route(default_route)
    first_disagg_route = RibRoute(first_negative_disagg_prefix, S_SPF, [], first_negative_disagg_next_hops)
    rib.put_route(first_disagg_route)
    subnet_disagg_route = RibRoute(subnet_disagg_prefix, S_SPF, [], subnet_negative_disagg_next_hops)
    rib.put_route(subnet_disagg_route)
    rib.del_route(subnet_disagg_prefix, S_SPF)
    assert not rib.destinations.has_key(subnet_disagg_prefix)
    assert subnet_disagg_prefix not in rib.fib.routes
    assert subnet_disagg_prefix not in rib.fib.kernel.routes
def test_remove_best_route():
    rib = Rib()
    default_route = RibRoute(default_prefix, N_SPF, default_next_hops)
    rib.put_route(default_route)
    best_default_route = RibRoute(default_prefix, S_SPF, ['S1'])
    rib.put_route(best_default_route)
    rib.del_route(default_prefix, S_SPF)
    assert rib.destinations.get(default_prefix).best_route == default_route
    assert rib.destinations.get(default_prefix).best_route.positive_next_hops == {'S1', 'S2', 'S3', 'S4'}
    assert rib.destinations.get(default_prefix).best_route.negative_next_hops == set()
    assert rib.destinations.get(default_prefix).best_route.next_hops == {'S1', 'S2', 'S3', 'S4'}
    assert rib.fib.routes[default_prefix].next_hops == default_route.next_hops
    assert rib.fib.kernel.routes[default_prefix] == default_route.next_hops
Exemplo n.º 7
0
def test_prop_delete_nexthop_one_level():

    # Test slide 58 in Pascal's "negative disaggregation" presentation.
    # Delete a nexthop from a parent route, and check that the computed complementary nexthops in
    # the child routes are properly updated.

    fib = Fib()
    rib = Rib(fib)

    # Install the following three routes into the RIB:
    rib.put_route("0.0.0.0/0", ["nh1", "nh2", "nh3", "nh4"])    # Parent default route
    rib.put_route("10.0.0.0/16", [], ["nh1"])                   # First child, negative nexthop
    rib.put_route("10.1.0.0/16", [], ["nh4"])                   # Second child, negative nexthop

    # The RIB must contain the following routes:
    assert str(rib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4\n"
                        "10.0.0.0/16 -> ~nh1\n"
                        "10.1.0.0/16 -> ~nh4\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4\n"
                        "10.0.0.0/16 -> nh2, nh3, nh4\n"
                        "10.1.0.0/16 -> nh1, nh2, nh3\n")

    # Delete nexthop nh2 from the parent route 0.0.0.0/0 (by replacing the route with a new one
    # that has the reduced set of nexthops).
    rib.put_route("0.0.0.0/0", ["nh1", "nh3", "nh4"])

    # The RIB must contain the following routes:
    assert str(rib) == ("0.0.0.0/0 -> nh1, nh3, nh4\n"      # nh2 is gone
                        "10.0.0.0/16 -> ~nh1\n"
                        "10.1.0.0/16 -> ~nh4\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("0.0.0.0/0 -> nh1, nh3, nh4\n"      # nh2 is gone
                        "10.0.0.0/16 -> nh3, nh4\n"         # computed nh2 is gone
                        "10.1.0.0/16 -> nh1, nh3\n")        # computed nh2 is gone

    # Delete all routes from the RIB.
    rib.del_route("0.0.0.0/0")
    rib.del_route("10.0.0.0/16")
    rib.del_route("10.1.0.0/16")

    # The RIB must be empty.
    assert str(rib) == ""

    # The FIB must be empty.
    assert str(fib) == ""
Exemplo n.º 8
0
def test_prop_mix_positive_negative():

    # Child routes have mixture of positive and negative nexthops

    fib = Fib()
    rib = Rib(fib)

    # Install the following three routes into the RIB:
    rib.put_route("1.0.0.0/8", ["nh1", "nh2", "nh3"])    # Parent aggregate route
    rib.put_route("1.1.0.0/16", ["nh4"], ["nh1"])        # Child, positive and negative nexthop
    rib.put_route("1.1.1.0/24", ["nh5"], ["nh2"])        # Grandchild, positive and negative nexthop

    # The RIB must contain the following routes:
    assert str(rib) == ("1.0.0.0/8 -> nh1, nh2, nh3\n"
                        "1.1.0.0/16 -> ~nh1, nh4\n"
                        "1.1.1.0/24 -> ~nh2, nh5\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("1.0.0.0/8 -> nh1, nh2, nh3\n"
                        "1.1.0.0/16 -> nh2, nh3, nh4\n"
                        "1.1.1.0/24 -> nh3, nh4, nh5\n")

    # Delete nexthop nh3 from the parent route 1.0.0.0/8 (by replacing the route with a new one
    # that has the reduced set of nexthops).
    rib.put_route("1.0.0.0/8", ["nh1", "nh2"])

    # The RIB must contain the following routes:
    assert str(rib) == ("1.0.0.0/8 -> nh1, nh2\n"           # nh3 is gone
                        "1.1.0.0/16 -> ~nh1, nh4\n"
                        "1.1.1.0/24 -> ~nh2, nh5\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("1.0.0.0/8 -> nh1, nh2\n"           # nh3 is gone
                        "1.1.0.0/16 -> nh2, nh4\n"          # computed nh3 is gone
                        "1.1.1.0/24 -> nh4, nh5\n")         # computed nh3 is gone

    # Delete all routes from the RIB.
    rib.del_route("1.0.0.0/8")
    rib.del_route("1.1.0.0/16")
    rib.del_route("1.1.1.0/24")

    # The RIB must be empty.
    assert str(rib) == ""

    # The FIB must be empty.
    assert str(fib) == ""
def test_remove_superfluous_subnet_recursive():
    rib = Rib()
    default_route = RibRoute(default_prefix, S_SPF, default_next_hops)
    rib.put_route(default_route)
    first_disagg_route = RibRoute(first_negative_disagg_prefix, S_SPF, [], first_negative_disagg_next_hops)
    rib.put_route(first_disagg_route)
    subnet_disagg_route = RibRoute(subnet_disagg_prefix, S_SPF, [], subnet_negative_disagg_next_hops)
    rib.put_route(subnet_disagg_route)
    rib.del_route(first_negative_disagg_prefix, S_SPF)
    assert not rib.destinations.has_key(first_negative_disagg_prefix)
    assert first_negative_disagg_prefix not in rib.fib.routes
    assert first_negative_disagg_prefix not in rib.fib.kernel.routes
    assert rib.destinations.get(subnet_disagg_prefix).best_route.positive_next_hops == set()
    assert rib.destinations.get(subnet_disagg_prefix).best_route.negative_next_hops == {'S2'}
    assert rib.destinations.get(subnet_disagg_prefix).best_route.next_hops == {'S1', 'S3', 'S4'}
    assert rib.fib.routes[subnet_disagg_prefix].next_hops == subnet_disagg_route.next_hops
    assert rib.fib.kernel.routes[subnet_disagg_prefix] == subnet_disagg_route.next_hops
    assert rib.destinations.get(subnet_disagg_prefix).parent_prefix_dest == rib.destinations.get(default_prefix)
Exemplo n.º 10
0
def test_prop_two_children():

    # Test slide 57 in Pascal's "negative disaggregation" presentation:
    # Add a parent aggregate with positive nexthops and two children with negative nexthops.

    fib = Fib()
    rib = Rib(fib)

    # Install the following routes into the RIB:
    rib.put_route("0.0.0.0/0", ["nh1", "nh2", "nh3", "nh4"])    # Parent default route
    rib.put_route("10.0.0.0/16", [], ["nh1"])                   # First child route, negative nh
    rib.put_route("10.1.0.0/16", [], ["nh4"])                   # Second child route, negative nh

    # The RIB must contain the following routes:
    assert str(rib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4\n"
                        "10.0.0.0/16 -> ~nh1\n"
                        "10.1.0.0/16 -> ~nh4\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4\n"
                        "10.0.0.0/16 -> nh2, nh3, nh4\n"
                        "10.1.0.0/16 -> nh1, nh2, nh3\n")

    # Delete the parent route from the RIB.
    rib.del_route("0.0.0.0/0")

    # The RIB must contain the following routes:
    assert str(rib) == ("10.0.0.0/16 -> ~nh1\n"
                        "10.1.0.0/16 -> ~nh4\n")

    # The FIB must contain the following routes (note: no nexthops, so discard routes):
    assert str(fib) == ("10.0.0.0/16 -> \n"
                        "10.1.0.0/16 -> \n")

    # Delete both remaining child routes from the RIB.
    rib.del_route("10.0.0.0/16")
    rib.del_route("10.1.0.0/16")

    # The RIB must be empty.
    assert str(rib) == ""

    # The FIB must be empty.
    assert str(fib) == ""
Exemplo n.º 11
0
def test_prop_one_child():

    # Test slide 56 in Pascal's "negative disaggregation" presentation:
    # Add a parent aggregate with positive nexthops and one child with a negative nexthop.

    fib = Fib()
    rib = Rib(fib)

    # Install two routes into the RIB: one parent aggregate with four ECMP positive nexthops, and
    # one child more specific with one negative nexthop.
    rib.put_route("0.0.0.0/0", ["nh1", "nh2", "nh3", "nh4"])    # Parent default route
    rib.put_route("10.0.0.0/16", [], ["nh1"])                   # Child route with negative nexthop

    # The RIB must contain the following routes:
    assert str(rib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4\n"
                        "10.0.0.0/16 -> ~nh1\n")

    # The RIB must contain the following routes:
    assert str(fib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4\n"     # Parent route, same as RIB
                        "10.0.0.0/16 -> nh2, nh3, nh4\n")       # Child route, complementary nhs

    # Delete the parent route from the RIB.
    rib.del_route("0.0.0.0/0")

    # The RIB must contain the following routes:
    assert str(rib) == "10.0.0.0/16 -> ~nh1\n"

    # The FIB must contain the following routes:
    assert str(fib) == "10.0.0.0/16 -> \n"

    # Delete the child route from the RIB.
    rib.del_route("10.0.0.0/16")

    # The RIB must be empty.
    assert str(rib) == ""

    # The FIB must be empty.
    assert str(fib) == ""
Exemplo n.º 12
0
def test_prop_one_route_pos():

    # Add a single route with only positive next-hops

    fib = Fib()
    rib = Rib(fib)

    # Install one route into the RIB:
    rib.put_route("1.2.3.0/24", ["nh1", "nh2"])     # A single route, positive nexthops

    # The RIB must contain the following route:
    assert str(rib) == ("1.2.3.0/24 -> nh1, nh2\n")

    # The FIB must contain the following route:
    assert str(fib) == ("1.2.3.0/24 -> nh1, nh2\n")

    # Delete the route from the RIB.
    rib.del_route("1.2.3.0/24")

    # The RIB must be empty.
    assert str(rib) == ("")

    # The FIB must be empty.
    assert str(fib) == ("")
Exemplo n.º 13
0
def test_prop_nesting_with_siblings():

    # Deep nesting of more specific routes using the following tree:
    #
    #   1.0.0.0/8 -> nh1, nh2, nh3, nh4, nh5, nh6, nh7
    #    |
    #    +--- 1.1.0.0/16 -> ~nh1
    #    |     |
    #    |     +--- 1.1.1.0/24 -> ~nh2
    #    |     |
    #    |     +--- 1.1.2.0/24 -> ~nh3
    #    |
    #    +--- 1.2.0.0/16 -> ~nh4
    #          |
    #          +--- 1.2.1.0/24 -> ~nh5
    #          |
    #          +--- 1.2.2.0/24 -> ~nh6
    #
    # Note: we add the routes in a random order

    fib = Fib()
    rib = Rib(fib)

    # Install the following three routes into the RIB:
    rib.put_route("1.2.1.0/24", [], ["nh5"])
    rib.put_route("1.1.2.0/24", [], ["nh3"])
    rib.put_route("1.1.0.0/16", [], ["nh1"])
    rib.put_route("1.1.1.0/24", [], ["nh2"])
    rib.put_route("1.2.0.0/16", [], ["nh4"])
    rib.put_route("1.0.0.0/8", ["nh1", "nh2", "nh3", "nh4", "nh5", "nh6", "nh7"])
    rib.put_route("1.2.2.0/24", [], ["nh6"])

    # The RIB must contain the following routes:
    assert str(rib) == ("1.0.0.0/8 -> nh1, nh2, nh3, nh4, nh5, nh6, nh7\n"
                        "1.1.0.0/16 -> ~nh1\n"
                        "1.1.1.0/24 -> ~nh2\n"
                        "1.1.2.0/24 -> ~nh3\n"
                        "1.2.0.0/16 -> ~nh4\n"
                        "1.2.1.0/24 -> ~nh5\n"
                        "1.2.2.0/24 -> ~nh6\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("1.0.0.0/8 -> nh1, nh2, nh3, nh4, nh5, nh6, nh7\n"
                        "1.1.0.0/16 -> nh2, nh3, nh4, nh5, nh6, nh7\n"
                        "1.1.1.0/24 -> nh3, nh4, nh5, nh6, nh7\n"
                        "1.1.2.0/24 -> nh2, nh4, nh5, nh6, nh7\n"
                        "1.2.0.0/16 -> nh1, nh2, nh3, nh5, nh6, nh7\n"
                        "1.2.1.0/24 -> nh1, nh2, nh3, nh6, nh7\n"
                        "1.2.2.0/24 -> nh1, nh2, nh3, nh5, nh7\n")

    # Delete nexthop nh3 from the parent route 0.0.0.0/0.
    rib.put_route("1.0.0.0/8", ["nh1", "nh2", "nh4", "nh5", "nh6", "nh7"])

    # The RIB must contain the following routes:
    assert str(rib) == ("1.0.0.0/8 -> nh1, nh2, nh4, nh5, nh6, nh7\n"
                        "1.1.0.0/16 -> ~nh1\n"
                        "1.1.1.0/24 -> ~nh2\n"
                        "1.1.2.0/24 -> ~nh3\n"
                        "1.2.0.0/16 -> ~nh4\n"
                        "1.2.1.0/24 -> ~nh5\n"
                        "1.2.2.0/24 -> ~nh6\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("1.0.0.0/8 -> nh1, nh2, nh4, nh5, nh6, nh7\n"
                        "1.1.0.0/16 -> nh2, nh4, nh5, nh6, nh7\n"
                        "1.1.1.0/24 -> nh4, nh5, nh6, nh7\n"
                        "1.1.2.0/24 -> nh2, nh4, nh5, nh6, nh7\n"
                        "1.2.0.0/16 -> nh1, nh2, nh5, nh6, nh7\n"
                        "1.2.1.0/24 -> nh1, nh2, nh6, nh7\n"
                        "1.2.2.0/24 -> nh1, nh2, nh5, nh7\n")

    # Delete all routes from the RIB.
    rib.del_route("1.0.0.0/8")
    rib.del_route("1.1.0.0/16")
    rib.del_route("1.1.1.0/24")
    rib.del_route("1.1.2.0/24")
    rib.del_route("1.2.0.0/16")
    rib.del_route("1.2.1.0/24")
    rib.del_route("1.2.2.0/24")

    # The RIB must be empty.
    assert str(rib) == ""

    # The FIB must be empty.
    assert str(fib) == ""
Exemplo n.º 14
0
def test_prop_deep_nesting():

    # Deep nesting of more specific routes: parent, child, grand child, grand-grand child, ...

    fib = Fib()
    rib = Rib(fib)

    # Install the following three routes into the RIB:
    rib.put_route("0.0.0.0/0", ["nh1", "nh2", "nh3", "nh4", "nh5"]) # Parent
    rib.put_route("1.0.0.0/8", [], ["nh1"])                         # Child
    rib.put_route("1.128.0.0/9", [], ["nh2"])                       # Grand child
    rib.put_route("1.192.0.0/10", [], ["nh3"])                      # Grand-grand child
    rib.put_route("1.224.0.0/11", [], ["nh4"])                      # Grand-grand-grand child
    rib.put_route("1.240.0.0/12", [], ["nh5"])                      # Grand-grand-grand-grand child

    # The RIB must contain the following routes:
    assert str(rib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4, nh5\n"
                        "1.0.0.0/8 -> ~nh1\n"
                        "1.128.0.0/9 -> ~nh2\n"
                        "1.192.0.0/10 -> ~nh3\n"
                        "1.224.0.0/11 -> ~nh4\n"
                        "1.240.0.0/12 -> ~nh5\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("0.0.0.0/0 -> nh1, nh2, nh3, nh4, nh5\n"
                        "1.0.0.0/8 -> nh2, nh3, nh4, nh5\n"
                        "1.128.0.0/9 -> nh3, nh4, nh5\n"
                        "1.192.0.0/10 -> nh4, nh5\n"
                        "1.224.0.0/11 -> nh5\n"
                        "1.240.0.0/12 -> \n")

    # Delete nexthop nh3 from the parent route 0.0.0.0/0.
    rib.put_route("0.0.0.0/0", ["nh1", "nh2", "nh4", "nh5"])

    # The RIB must contain the following routes:
    assert str(rib) == ("0.0.0.0/0 -> nh1, nh2, nh4, nh5\n"
                        "1.0.0.0/8 -> ~nh1\n"
                        "1.128.0.0/9 -> ~nh2\n"
                        "1.192.0.0/10 -> ~nh3\n"
                        "1.224.0.0/11 -> ~nh4\n"
                        "1.240.0.0/12 -> ~nh5\n")

    # The FIB must contain the following routes:
    assert str(fib) == ("0.0.0.0/0 -> nh1, nh2, nh4, nh5\n"
                        "1.0.0.0/8 -> nh2, nh4, nh5\n"
                        "1.128.0.0/9 -> nh4, nh5\n"
                        "1.192.0.0/10 -> nh4, nh5\n"
                        "1.224.0.0/11 -> nh5\n"
                        "1.240.0.0/12 -> \n")

    # Delete all routes from the RIB.
    rib.del_route("0.0.0.0/0")
    rib.del_route("1.0.0.0/8")
    rib.del_route("1.128.0.0/9")
    rib.del_route("1.192.0.0/10")
    rib.del_route("1.224.0.0/11")
    rib.del_route("1.240.0.0/12")

    # The RIB must be empty.
    assert str(rib) == ""

    # The FIB must be empty.
    assert str(fib) == ""
def test_prop_nesting_with_siblings():

    # Deep nesting of more specific routes using the following tree:
    #
    #   1.0.0.0/8 -> S1, S2, S3, S4, S5, S6, S7
    #    |
    #    +--- 1.1.0.0/16 -> ~S1
    #    |     |
    #    |     +--- 1.1.1.0/24 -> ~S2
    #    |     |
    #    |     +--- 1.1.2.0/24 -> ~S3
    #    |
    #    +--- 1.2.0.0/16 -> ~S4
    #          |
    #          +--- 1.2.1.0/24 -> ~S5
    #          |
    #          +--- 1.2.2.0/24 -> ~S6
    #
    # Note: we add the routes in a random order

    rib = Rib()

    rib.put_route(RibRoute("1.2.1.0/24", S_SPF, [], ["S5"]))
    rib.put_route(RibRoute("1.1.2.0/24", S_SPF, [], ["S3"]))
    rib.put_route(RibRoute("1.1.0.0/16", S_SPF, [], ['S1']))
    rib.put_route(RibRoute("1.1.1.0/24", S_SPF, [], ['S2']))
    rib.put_route(RibRoute("1.2.0.0/16", S_SPF, [], ['S4']))
    rib.put_route(RibRoute("1.0.0.0/8", S_SPF, ['S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7']))
    rib.put_route(RibRoute("1.2.2.0/24", S_SPF, [], ['S6']))

    # Testing only rib, fib and kernel next hops
    assert rib.destinations.get('1.0.0.0/8').best_route.next_hops == {'S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.0.0.0/8'].next_hops == {'S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.0.0.0/8'] == {'S1', 'S2', 'S3', 'S4', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.1.0.0/16').best_route.negative_next_hops == {'S1'}
    assert rib.destinations.get('1.1.0.0/16').best_route.next_hops == {'S2', 'S3', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.1.0.0/16'].next_hops == {'S2', 'S3', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.1.0.0/16'] == {'S2', 'S3', 'S4', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.1.1.0/24').best_route.negative_next_hops == {'S2'}
    assert rib.destinations.get('1.1.1.0/24').best_route.next_hops == {'S3', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.1.1.0/24'].next_hops == {'S3', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.1.1.0/24'] == {'S3', 'S4', 'S5', 'S6', 'S7'}


    assert rib.destinations.get('1.1.2.0/24').best_route.negative_next_hops == {'S3'}
    assert rib.destinations.get('1.1.2.0/24').best_route.next_hops == {'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.1.2.0/24'].next_hops == {'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.1.2.0/24'] == {'S2', 'S4', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.2.0.0/16').best_route.negative_next_hops == {'S4'}
    assert rib.destinations.get('1.2.0.0/16').best_route.next_hops == {'S1', 'S2', 'S3', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.2.0.0/16'].next_hops == {'S1', 'S2', 'S3', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.2.0.0/16'] == {'S1', 'S2', 'S3', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.2.1.0/24').best_route.negative_next_hops == {'S5'}
    assert rib.destinations.get('1.2.1.0/24').best_route.next_hops == {'S1', 'S2', 'S3', 'S6', 'S7'}
    assert rib.fib.routes['1.2.1.0/24'].next_hops == {'S1', 'S2', 'S3', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.2.1.0/24'] == {'S1', 'S2', 'S3', 'S6', 'S7'}

    assert rib.destinations.get('1.2.2.0/24').best_route.negative_next_hops == {'S6'}
    assert rib.destinations.get('1.2.2.0/24').best_route.next_hops == {'S1', 'S2', 'S3', 'S5', 'S7'}
    assert rib.fib.routes['1.2.2.0/24'].next_hops == {'S1', 'S2', 'S3', 'S5', 'S7'}
    assert rib.fib.kernel.routes['1.2.2.0/24'] == {'S1', 'S2', 'S3', 'S5', 'S7'}

    # Delete nexthop S3 from the parent route 0.0.0.0/0.
    rib.put_route(RibRoute('1.0.0.0/8', S_SPF, ['S1', 'S2', 'S4', 'S5', 'S6', 'S7']))

    # Testing only rib, fib and kernel next hops
    assert rib.destinations.get('1.0.0.0/8').best_route.next_hops == {'S1', 'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.0.0.0/8'].next_hops == {'S1', 'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.0.0.0/8'] == {'S1', 'S2', 'S4', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.1.0.0/16').best_route.negative_next_hops == {'S1'}
    assert rib.destinations.get('1.1.0.0/16').best_route.next_hops == {'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.1.0.0/16'].next_hops == {'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.1.0.0/16'] == {'S2', 'S4', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.1.1.0/24').best_route.negative_next_hops == {'S2'}
    assert rib.destinations.get('1.1.1.0/24').best_route.next_hops == {'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.1.1.0/24'].next_hops == {'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.1.1.0/24'] == {'S4', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.1.2.0/24').best_route.negative_next_hops == {'S3'}
    assert rib.destinations.get('1.1.2.0/24').best_route.next_hops == {'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.1.2.0/24'].next_hops == {'S2', 'S4', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.1.2.0/24'] == {'S2', 'S4', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.2.0.0/16').best_route.negative_next_hops == {'S4'}
    assert rib.destinations.get('1.2.0.0/16').best_route.next_hops == {'S1', 'S2', 'S5', 'S6', 'S7'}
    assert rib.fib.routes['1.2.0.0/16'].next_hops == {'S1', 'S2', 'S5', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.2.0.0/16'] == {'S1', 'S2', 'S5', 'S6', 'S7'}

    assert rib.destinations.get('1.2.1.0/24').best_route.negative_next_hops == {'S5'}
    assert rib.destinations.get('1.2.1.0/24').best_route.next_hops == {'S1', 'S2', 'S6', 'S7'}
    assert rib.fib.routes['1.2.1.0/24'].next_hops == {'S1', 'S2', 'S6', 'S7'}
    assert rib.fib.kernel.routes['1.2.1.0/24'] == {'S1', 'S2', 'S6', 'S7'}

    assert rib.destinations.get('1.2.2.0/24').best_route.negative_next_hops == {'S6'}
    assert rib.destinations.get('1.2.2.0/24').best_route.next_hops == {'S1', 'S2', 'S5', 'S7'}
    assert rib.fib.routes['1.2.2.0/24'].next_hops == {'S1', 'S2', 'S5', 'S7'}
    assert rib.fib.kernel.routes['1.2.2.0/24'] == {'S1', 'S2', 'S5', 'S7'}

    # Delete all routes from the RIB.
    rib.del_route("1.0.0.0/8", S_SPF)
    rib.del_route("1.1.0.0/16", S_SPF)
    rib.del_route("1.1.1.0/24", S_SPF)
    rib.del_route("1.1.2.0/24", S_SPF)
    rib.del_route("1.2.0.0/16", S_SPF)
    rib.del_route("1.2.1.0/24", S_SPF)
    rib.del_route("1.2.2.0/24", S_SPF)

    assert not rib.destinations.keys()
    assert not rib.fib.routes.keys()
    assert not rib.fib.kernel.routes.keys()
def test_prop_deep_nesting():
    # Deep nesting of more specific routes: parent, child, grand child, grand-grand child, ...
    rib = Rib()
    # Default route
    new_default_next_hops = ['S1', 'S2', 'S3', 'S4', 'S5']
    new_default_route = RibRoute(default_prefix, S_SPF, new_default_next_hops)
    rib.put_route(new_default_route)
    # Child route
    child_prefix = '1.0.0.0/8'
    child_route = RibRoute(child_prefix, S_SPF, [], ['S1'])
    rib.put_route(child_route)
    # Grand child route
    g_child_prefix = '1.128.0.0/9'
    g_child_route = RibRoute(g_child_prefix, S_SPF, [], ['S2'])
    rib.put_route(g_child_route)
    # Grand-grand child route
    gg_child_prefix = '1.192.0.0/10'
    gg_child_route = RibRoute(gg_child_prefix, S_SPF, [], ['S3'])
    rib.put_route(gg_child_route)
    # Grand-grand-grand child route
    ggg_child_prefix = '1.224.0.0/11'
    ggg_child_route = RibRoute(ggg_child_prefix, S_SPF, [], ['S4'])
    rib.put_route(ggg_child_route)
    # Grand-grand-grand-grand child route
    gggg_child_prefix = '1.240.0.0/12'
    gggg_child_route = RibRoute(gggg_child_prefix, S_SPF, [], ['S5'])
    rib.put_route(gggg_child_route)

    # Default route asserts
    assert rib.destinations.get(default_prefix).best_route == new_default_route
    assert rib.destinations.get(default_prefix).best_route.next_hops == {'S1', 'S2', 'S3', 'S4', 'S5'}
    assert rib.fib.routes[default_prefix].next_hops == new_default_route.next_hops
    assert rib.fib.kernel.routes[default_prefix] == new_default_route.next_hops
    # Child route asserts
    assert rib.destinations.get(child_prefix).best_route == child_route
    assert rib.destinations.get(child_prefix).best_route.next_hops == {'S2', 'S3', 'S4', 'S5'}
    assert rib.fib.routes[child_prefix].next_hops == child_route.next_hops
    assert rib.fib.kernel.routes[child_prefix] == child_route.next_hops
    # Grand-child route asserts
    assert rib.destinations.get(g_child_prefix).best_route == g_child_route
    assert rib.destinations.get(g_child_prefix).best_route.next_hops == {'S3', 'S4', 'S5'}
    assert rib.fib.routes[g_child_prefix].next_hops == g_child_route.next_hops
    assert rib.fib.kernel.routes[g_child_prefix] == g_child_route.next_hops
    # Grand-grand child route asserts
    assert rib.destinations.get(gg_child_prefix).best_route == gg_child_route
    assert rib.destinations.get(gg_child_prefix).best_route.next_hops == {'S4', 'S5'}
    assert rib.fib.routes[gg_child_prefix].next_hops == gg_child_route.next_hops
    assert rib.fib.kernel.routes[gg_child_prefix] == gg_child_route.next_hops
    # Grand-grand-grand child route asserts
    assert rib.destinations.get(ggg_child_prefix).best_route == ggg_child_route
    assert rib.destinations.get(ggg_child_prefix).best_route.next_hops == {'S5'}
    assert rib.fib.routes[ggg_child_prefix].next_hops == ggg_child_route.next_hops
    assert rib.fib.kernel.routes[ggg_child_prefix] == ggg_child_route.next_hops
    # Grand-grand-grand-grand child route asserts
    assert rib.destinations.get(gggg_child_prefix).best_route == gggg_child_route
    assert rib.destinations.get(gggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gggg_child_prefix].next_hops == gggg_child_route.next_hops
    assert rib.fib.kernel.routes[gggg_child_prefix] == 'unreachable'

    # Delete S3 from default route
    new_default_route = RibRoute(default_prefix, S_SPF, ['S1', 'S2', 'S4', 'S5'])
    rib.put_route(new_default_route)

    # Default route asserts
    assert rib.destinations.get(default_prefix).best_route == new_default_route
    assert rib.destinations.get(default_prefix).best_route.next_hops == {'S1', 'S2', 'S4', 'S5'}
    assert rib.fib.routes[default_prefix].next_hops == new_default_route.next_hops
    assert rib.fib.kernel.routes[default_prefix] == new_default_route.next_hops
    # Child route asserts
    assert rib.destinations.get(child_prefix).best_route == child_route
    assert rib.destinations.get(child_prefix).best_route.next_hops == {'S2', 'S4', 'S5'}
    assert rib.fib.routes[child_prefix].next_hops == child_route.next_hops
    assert rib.fib.kernel.routes[child_prefix] == child_route.next_hops
    # Grand-child route asserts
    assert rib.destinations.get(g_child_prefix).best_route == g_child_route
    assert rib.destinations.get(g_child_prefix).best_route.next_hops == {'S4', 'S5'}
    assert rib.fib.routes[g_child_prefix].next_hops == g_child_route.next_hops
    assert rib.fib.kernel.routes[g_child_prefix] == g_child_route.next_hops
    # Grand-grand child route asserts
    assert rib.destinations.get(gg_child_prefix).best_route == gg_child_route
    assert rib.destinations.get(gg_child_prefix).best_route.next_hops == {'S4', 'S5'}
    assert rib.fib.routes[gg_child_prefix].next_hops == gg_child_route.next_hops
    assert rib.fib.kernel.routes[gg_child_prefix] == gg_child_route.next_hops
    # Grand-grand-grand child route asserts
    assert rib.destinations.get(ggg_child_prefix).best_route == ggg_child_route
    assert rib.destinations.get(ggg_child_prefix).best_route.next_hops == {'S5'}
    assert rib.fib.routes[ggg_child_prefix].next_hops == ggg_child_route.next_hops
    assert rib.fib.kernel.routes[ggg_child_prefix] == ggg_child_route.next_hops
    # Grand-grand-grand-grand child route asserts
    assert rib.destinations.get(gggg_child_prefix).best_route == gggg_child_route
    assert rib.destinations.get(gggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gggg_child_prefix].next_hops == gggg_child_route.next_hops
    assert rib.fib.kernel.routes[gggg_child_prefix] == 'unreachable'

    rib.del_route(default_prefix, S_SPF)
    # Default route asserts
    assert not rib.destinations.has_key(default_prefix)
    # Child route asserts
    assert rib.destinations.get(child_prefix).best_route == child_route
    assert rib.destinations.get(child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[child_prefix] == 'unreachable'
    # Grand-child route asserts
    assert rib.destinations.get(g_child_prefix).best_route == g_child_route
    assert rib.destinations.get(g_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[g_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[g_child_prefix] == 'unreachable'
    # Grand-grand child route asserts
    assert rib.destinations.get(gg_child_prefix).best_route == gg_child_route
    assert rib.destinations.get(gg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gg_child_prefix].next_hops ==  set()
    assert rib.fib.kernel.routes[gg_child_prefix] == 'unreachable'
    # Grand-grand-grand child route asserts
    assert rib.destinations.get(ggg_child_prefix).best_route == ggg_child_route
    assert rib.destinations.get(ggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[ggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[ggg_child_prefix] == 'unreachable'
    # Grand-grand-grand-grand child route asserts
    assert rib.destinations.get(gggg_child_prefix).best_route == gggg_child_route
    assert rib.destinations.get(gggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[gggg_child_prefix] == 'unreachable'

    rib.del_route(child_prefix, S_SPF)
    # Child route asserts
    assert not rib.destinations.has_key(child_prefix)
    # Grand-child route asserts
    assert rib.destinations.get(g_child_prefix).best_route == g_child_route
    assert rib.destinations.get(g_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[g_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[g_child_prefix] == 'unreachable'
    # Grand-grand child route asserts
    assert rib.destinations.get(gg_child_prefix).best_route == gg_child_route
    assert rib.destinations.get(gg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gg_child_prefix].next_hops ==  set()
    assert rib.fib.kernel.routes[gg_child_prefix] == 'unreachable'
    # Grand-grand-grand child route asserts
    assert rib.destinations.get(ggg_child_prefix).best_route == ggg_child_route
    assert rib.destinations.get(ggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[ggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[ggg_child_prefix] == 'unreachable'
    # Grand-grand-grand-grand child route asserts
    assert rib.destinations.get(gggg_child_prefix).best_route == gggg_child_route
    assert rib.destinations.get(gggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[gggg_child_prefix] == 'unreachable'

    rib.del_route(g_child_prefix, S_SPF)
    # Grand-child route asserts
    assert not rib.destinations.has_key(g_child_prefix)
    # Grand-grand child route asserts
    assert rib.destinations.get(gg_child_prefix).best_route == gg_child_route
    assert rib.destinations.get(gg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gg_child_prefix].next_hops ==  set()
    assert rib.fib.kernel.routes[gg_child_prefix] == 'unreachable'
    # Grand-grand-grand child route asserts
    assert rib.destinations.get(ggg_child_prefix).best_route == ggg_child_route
    assert rib.destinations.get(ggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[ggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[ggg_child_prefix] == 'unreachable'
    # Grand-grand-grand-grand child route asserts
    assert rib.destinations.get(gggg_child_prefix).best_route == gggg_child_route
    assert rib.destinations.get(gggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[gggg_child_prefix] == 'unreachable'

    rib.del_route(gg_child_prefix, S_SPF)
    # Grand-child route asserts
    assert not rib.destinations.has_key(gg_child_prefix)
    # Grand-grand-grand child route asserts
    assert rib.destinations.get(ggg_child_prefix).best_route == ggg_child_route
    assert rib.destinations.get(ggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[ggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[ggg_child_prefix] == 'unreachable'
    # Grand-grand-grand-grand child route asserts
    assert rib.destinations.get(gggg_child_prefix).best_route == gggg_child_route
    assert rib.destinations.get(gggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[gggg_child_prefix] == 'unreachable'

    rib.del_route(ggg_child_prefix, S_SPF)
    # Grand-child route asserts
    assert not rib.destinations.has_key(ggg_child_prefix)
    # Grand-grand-grand-grand child route asserts
    assert rib.destinations.get(gggg_child_prefix).best_route == gggg_child_route
    assert rib.destinations.get(gggg_child_prefix).best_route.next_hops == set()
    assert rib.fib.routes[gggg_child_prefix].next_hops == set()
    assert rib.fib.kernel.routes[gggg_child_prefix] == 'unreachable'

    rib.del_route(gggg_child_prefix, S_SPF)
    # Grand-grand-grand-grand child route asserts
    assert not rib.destinations.has_key(gggg_child_prefix)

    assert not rib.destinations.keys()
    assert not rib.fib.routes.keys()
    assert not rib.fib.kernel.routes.keys()