Skip to content

Commit

Permalink
tests: multiple OSPF routers connected to a single switch
Browse files Browse the repository at this point in the history
A large set of routers are connected to the same switch. Each router
shares a single network. All shared networks must be reachable from all
routers.

Signed-off-by: "Adriano Marto Reis" <[email protected]>
  • Loading branch information
adrianomarto committed Jan 26, 2024
1 parent 8e3a96e commit 3b12cf8
Show file tree
Hide file tree
Showing 9 changed files with 333 additions and 0 deletions.
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r1_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r1
ip forwarding
!
interface r1-eth0
ip address 203.0.113.1/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r1-eth1
ip address 10.0.1.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.1
!
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r2_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r2
ip forwarding
!
interface r2-eth0
ip address 203.0.113.2/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r2-eth1
ip address 10.0.2.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.2
!
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r3_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r3
ip forwarding
!
interface r3-eth0
ip address 203.0.113.3/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r3-eth1
ip address 10.0.3.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.3
!
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r4_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r4
ip forwarding
!
interface r4-eth0
ip address 203.0.113.4/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r4-eth1
ip address 10.0.4.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.4
!
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r5_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r5
ip forwarding
!
interface r5-eth0
ip address 203.0.113.5/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r5-eth1
ip address 10.0.5.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.5
!
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r6_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r6
ip forwarding
!
interface r6-eth0
ip address 203.0.113.6/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r6-eth1
ip address 10.0.6.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.6
!
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r7_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r7
ip forwarding
!
interface r7-eth0
ip address 203.0.113.7/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r7-eth1
ip address 10.0.7.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.7
!
18 changes: 18 additions & 0 deletions tests/topotests/ospf_single_switch/r8_frr.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
!
hostname r8
ip forwarding
!
interface r8-eth0
ip address 203.0.113.8/24
ip ospf network point-to-multipoint
ip ospf area 0.0.0.0
!ip ospf prefix-suppression
!
interface r8-eth1
ip address 10.0.8.1/24
ip ospf passive
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.0.8
!
189 changes: 189 additions & 0 deletions tests/topotests/ospf_single_switch/test_ospf_single_switch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC

#
# Copyright (c) 2023 by
# Adriano Marto Reis <[email protected]>
#

import os
import sys
import json
import subprocess
from functools import partial
import pytest

from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger

from lib.common_config import verify_rib
from lib.ospf import verify_ospf_rib
from _ast import Try

pytestmark = pytest.mark.ospfd

"""
A large set of routers are connected to the same switch. Each router shares a
single network. All shared networks must be reachable from all routers.
"""

TOPOLOGY = """
net1 net2 netN
--- --- ---
| | OSPF-passive |
| | |
+---+---+ +---+---+ +---+---+
| | | | | |
| r1 | | r2 | (...) | rN |
| | | | | |
+---+---+ +---+---+ +---+---+
| | OSPF-active |
| | |
+----------------+--------------------------------+
switch
"""

N_ROUTERS = 8

# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))


def build_topo(tgen):
"Build the topology"

# Create a single switch to connect all the routers
switch = tgen.add_switch("switch")

# Create routers
for router_id in range(1, N_ROUTERS + 1):
router = tgen.add_router(f"r{router_id}")
switch.add_link(router)

# The shared network needs to be connected to something
dummy = tgen.add_switch(f"s{router_id}")
dummy.add_link(router)


def setup_module(mod):
logger.info("OSPF single switch:\n {}".format(TOPOLOGY))

tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()

# Starting Routers
router_list = tgen.routers()

for rname, router in router_list.items():
logger.info("Loading router %s" % rname)
router.load_frr_config(os.path.join(CWD, "{}_frr.conf".format(rname)))

# Initialize all routers.
tgen.start_router()


def teardown_module(mod):
"Tear-down the test environment"
tgen = get_topogen()
tgen.stop_topology()


def is_iproute2_json_supported():
"""
Checks if the command 'ip -j route' is supported.
"""
try:
output = subprocess.run(['ip', '-j', 'route'], stdout=subprocess.PIPE).stdout.decode()
json.loads(output)
return True
except json.JSONDecodeError:
return False


@pytest.mark.skipif(not is_iproute2_json_supported(), reason="'ip -j route' not supported")
def test_all_routes_advertised():
tgen = get_topogen()

if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")

# networks advertised by each router and the expected next hops
networks = {
"r1": ("10.0.1.0/24", "203.0.113.1"),
"r2": ("10.0.2.0/24", "203.0.113.2"),
"r3": ("10.0.3.0/24", "203.0.113.3"),
"r4": ("10.0.4.0/24", "203.0.113.4"),
"r5": ("10.0.5.0/24", "203.0.113.5"),
"r6": ("10.0.6.0/24", "203.0.113.6"),
"r7": ("10.0.7.0/24", "203.0.113.7"),
"r8": ("10.0.8.0/24", "203.0.113.8"),
}

for router_orig in tgen.routers().keys():
for router_dest, network in networks.items():
if router_orig != router_dest:
input_dict = {
router_orig: {
"static_routes": [
{
"network": network[0],
}
]
}
}
result = verify_ospf_rib(tgen, router_orig, input_dict, next_hop=network[1])
assert result is True, "Error: {}".format(result)
result = verify_rib(tgen, "ipv4", router_orig, input_dict, next_hop=network[1])
assert result is True, "Error: {}".format(result)

check_route(router_orig, network[0], network[1])


def check_route(router_name, network, expected_nexthop):
"""
Checks if the given network is present on the given router and has the
expected next hop.
"""
tgen = get_topogen()
router = tgen.gears[router_name]

expected_response = {
network: [
{
"prefix": network,
"protocol": "ospf",
"nexthops": [
{
"ip": expected_nexthop,
"active": True,
},
],
},
],
}

test_func = partial(
topotest.router_json_cmp,
router,
f"show ip route {network} json",
expected_response,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assert (
result is None
), f"{router_name} (ospfd): no route {network} via {expected_nexthop}"

address = network.split("/")[0]
output = router.cmd(f"ip -j route get {address}")
logger.info(output)
routes = json.loads(output)
assert routes[0]["gateway"] == expected_nexthop, f"{router_name} (kernel): no route {address} via {expected_nexthop}"


if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

0 comments on commit 3b12cf8

Please sign in to comment.