]>
Commit | Line | Data |
---|---|---|
83c78d54 DA |
1 | #!/usr/bin/env python |
2 | # SPDX-License-Identifier: ISC | |
3 | ||
4 | # Copyright (c) 2023 by | |
5 | # Donatas Abraitis <donatas@opensourcerouting.org> | |
6 | # | |
7 | ||
8 | """ | |
9 | Test if RIP `allow-ecmp` command works correctly. | |
10 | """ | |
11 | ||
12 | import os | |
13 | import sys | |
14 | import json | |
15 | import pytest | |
16 | import functools | |
17 | ||
18 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
19 | sys.path.append(os.path.join(CWD, "../")) | |
20 | ||
21 | # pylint: disable=C0413 | |
22 | from lib import topotest | |
23 | from lib.topogen import Topogen, TopoRouter, get_topogen | |
4972a6ee | 24 | from lib.common_config import step |
83c78d54 DA |
25 | |
26 | pytestmark = [pytest.mark.ripd] | |
27 | ||
28 | ||
29 | def setup_module(mod): | |
4972a6ee | 30 | topodef = {"s1": ("r1", "r2", "r3", "r4", "r5")} |
83c78d54 DA |
31 | tgen = Topogen(topodef, mod.__name__) |
32 | tgen.start_topology() | |
33 | ||
34 | router_list = tgen.routers() | |
35 | ||
36 | for _, (rname, router) in enumerate(router_list.items(), 1): | |
37 | router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) | |
38 | ||
39 | tgen.start_router() | |
40 | ||
41 | ||
42 | def teardown_module(mod): | |
43 | tgen = get_topogen() | |
44 | tgen.stop_topology() | |
45 | ||
46 | ||
47 | def test_rip_allow_ecmp(): | |
48 | tgen = get_topogen() | |
49 | ||
50 | if tgen.routers_have_failure(): | |
51 | pytest.skip(tgen.errors) | |
52 | ||
53 | r1 = tgen.gears["r1"] | |
54 | ||
55 | def _show_rip_routes(): | |
9b3fd1ef CH |
56 | xpath = ( |
57 | "/frr-ripd:ripd/instance[vrf='default']" | |
58 | "/state/routes/route[prefix='10.10.10.1/32']" | |
8d6765aa | 59 | ) |
9b3fd1ef CH |
60 | try: |
61 | output = json.loads( | |
62 | r1.vtysh_cmd(f"show yang operational-data {xpath} ripd") | |
63 | ) | |
64 | except Exception: | |
65 | return False | |
66 | ||
83c78d54 DA |
67 | try: |
68 | output = output["frr-ripd:ripd"]["instance"][0]["state"]["routes"] | |
69 | except KeyError: | |
70 | return False | |
71 | ||
72 | expected = { | |
73 | "route": [ | |
74 | { | |
75 | "prefix": "10.10.10.1/32", | |
76 | "nexthops": { | |
77 | "nexthop": [ | |
78 | { | |
79 | "nh-type": "ip4", | |
80 | "protocol": "rip", | |
81 | "rip-type": "normal", | |
82 | "gateway": "192.168.1.2", | |
83 | "from": "192.168.1.2", | |
84 | "tag": 0, | |
85 | }, | |
86 | { | |
87 | "nh-type": "ip4", | |
88 | "protocol": "rip", | |
89 | "rip-type": "normal", | |
90 | "gateway": "192.168.1.3", | |
91 | "from": "192.168.1.3", | |
92 | "tag": 0, | |
93 | }, | |
94 | ] | |
95 | }, | |
96 | "metric": 2, | |
83c78d54 DA |
97 | }, |
98 | ] | |
99 | } | |
100 | return topotest.json_cmp(output, expected) | |
101 | ||
102 | test_func = functools.partial(_show_rip_routes) | |
103 | _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) | |
104 | assert result is None, "Can't see 10.10.10.1/32 as multipath in `show ip rip`" | |
105 | ||
66e0f6c4 | 106 | def _show_routes(nh_num): |
83c78d54 DA |
107 | output = json.loads(r1.vtysh_cmd("show ip route json")) |
108 | expected = { | |
109 | "10.10.10.1/32": [ | |
110 | { | |
66e0f6c4 DA |
111 | "internalNextHopNum": nh_num, |
112 | "internalNextHopActiveNum": nh_num, | |
83c78d54 DA |
113 | "nexthops": [ |
114 | { | |
115 | "ip": "192.168.1.2", | |
116 | "active": True, | |
117 | }, | |
118 | { | |
119 | "ip": "192.168.1.3", | |
120 | "active": True, | |
121 | }, | |
66e0f6c4 | 122 | ], |
83c78d54 DA |
123 | } |
124 | ] | |
125 | } | |
126 | return topotest.json_cmp(output, expected) | |
127 | ||
66e0f6c4 | 128 | test_func = functools.partial(_show_routes, 4) |
83c78d54 | 129 | _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) |
66e0f6c4 | 130 | assert result is None, "Can't see 10.10.10.1/32 as multipath (4) in `show ip route`" |
83c78d54 | 131 | |
4972a6ee DA |
132 | step( |
133 | "Configure allow-ecmp 2, ECMP group routes SHOULD have next-hops with the lowest IPs" | |
134 | ) | |
135 | r1.vtysh_cmd( | |
136 | """ | |
137 | configure terminal | |
138 | router rip | |
139 | allow-ecmp 2 | |
140 | """ | |
141 | ) | |
142 | ||
143 | test_func = functools.partial(_show_rip_routes) | |
144 | _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) | |
145 | assert ( | |
146 | result is None | |
147 | ), "Can't see 10.10.10.1/32 as ECMP with the lowest next-hop IPs" | |
148 | ||
66e0f6c4 DA |
149 | test_func = functools.partial(_show_routes, 2) |
150 | _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) | |
151 | assert result is None, "Can't see 10.10.10.1/32 as multipath (2) in `show ip route`" | |
152 | ||
83c78d54 DA |
153 | |
154 | if __name__ == "__main__": | |
155 | args = ["-s"] + sys.argv[1:] | |
156 | sys.exit(pytest.main(args)) |