]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/eigrp_topo1/test_eigrp_topo1.py
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / tests / topotests / eigrp_topo1 / test_eigrp_topo1.py
1 #!/usr/bin/env python
2 # SPDX-License-Identifier: ISC
3
4 #
5 # test_eigrp_topo1.py
6 #
7 # Copyright (c) 2017 by
8 # Cumulus Networks, Inc.
9 # Donald Sharp
10 #
11
12 """
13 test_eigrp_topo1.py: Testing EIGRP
14
15 """
16
17 import os
18 import re
19 import sys
20 import pytest
21 import json
22
23 pytestmark = [pytest.mark.eigrpd]
24
25 # Save the Current Working Directory to find configuration files.
26 CWD = os.path.dirname(os.path.realpath(__file__))
27 sys.path.append(os.path.join(CWD, "../"))
28
29 # pylint: disable=C0413
30 # Import topogen and topotest helpers
31 from lib import topotest
32 from lib.topogen import Topogen, TopoRouter, get_topogen
33 from lib.topolog import logger
34
35 # Required to instantiate the topology builder class.
36
37 #####################################################
38 ##
39 ## Network Topology Definition
40 ##
41 #####################################################
42
43
44 def build_topo(tgen):
45 for routern in range(1, 4):
46 tgen.add_router("r{}".format(routern))
47
48 # On main router
49 # First switch is for a dummy interface (for local network)
50 switch = tgen.add_switch("sw1")
51 switch.add_link(tgen.gears["r1"])
52
53 # Switches for EIGRP
54 # switch 2 switch is for connection to EIGRP router
55 switch = tgen.add_switch("sw2")
56 switch.add_link(tgen.gears["r1"])
57 switch.add_link(tgen.gears["r2"])
58
59 # switch 4 is stub on remote EIGRP router
60 switch = tgen.add_switch("sw4")
61 switch.add_link(tgen.gears["r3"])
62
63 # switch 3 is between EIGRP routers
64 switch = tgen.add_switch("sw3")
65 switch.add_link(tgen.gears["r2"])
66 switch.add_link(tgen.gears["r3"])
67
68
69 #####################################################
70 ##
71 ## Tests starting
72 ##
73 #####################################################
74
75
76 def setup_module(module):
77 "Setup topology"
78 tgen = Topogen(build_topo, module.__name__)
79 tgen.start_topology()
80
81 # This is a sample of configuration loading.
82 router_list = tgen.routers()
83 for rname, router in router_list.items():
84 router.load_config(
85 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
86 )
87 router.load_config(
88 TopoRouter.RD_EIGRP, os.path.join(CWD, "{}/eigrpd.conf".format(rname))
89 )
90
91 tgen.start_router()
92
93
94 def teardown_module(_mod):
95 "Teardown the pytest environment"
96 tgen = get_topogen()
97
98 # This function tears down the whole topology.
99 tgen.stop_topology()
100
101
102 def test_converge_protocols():
103 "Wait for protocol convergence"
104
105 tgen = get_topogen()
106 # Don't run this test if we have any failure.
107 if tgen.routers_have_failure():
108 pytest.skip(tgen.errors)
109
110 topotest.sleep(5, "Waiting for EIGRP convergence")
111
112
113 def test_eigrp_routes():
114 "Test EIGRP 'show ip eigrp'"
115
116 tgen = get_topogen()
117 # Don't run this test if we have any failure.
118 if tgen.routers_have_failure():
119 pytest.skip(tgen.errors)
120
121 # Verify EIGRP Status
122 logger.info("Verifying EIGRP routes")
123
124 router_list = tgen.routers().values()
125 for router in router_list:
126 refTableFile = "{}/{}/show_ip_eigrp.json".format(CWD, router.name)
127
128 # Read expected result from file
129 expected = json.loads(open(refTableFile).read())
130
131 # Actual output from router
132 actual = ip_eigrp_topo(router)
133
134 assertmsg = '"show ip eigrp topo" mismatches on {}'.format(router.name)
135 assert topotest.json_cmp(actual, expected) is None, assertmsg
136
137
138 def test_zebra_ipv4_routingTable():
139 "Test 'show ip route'"
140
141 tgen = get_topogen()
142 # Don't run this test if we have any failure.
143 if tgen.routers_have_failure():
144 pytest.skip(tgen.errors)
145
146 failures = 0
147 router_list = tgen.routers().values()
148 for router in router_list:
149 output = router.vtysh_cmd("show ip route json", isjson=True)
150 refTableFile = "{}/{}/show_ip_route.json_ref".format(CWD, router.name)
151 expected = json.loads(open(refTableFile).read())
152
153 assertmsg = "Zebra IPv4 Routing Table verification failed for router {}".format(
154 router.name
155 )
156 assert topotest.json_cmp(output, expected) is None, assertmsg
157
158
159 def test_shut_interface_and_recover():
160 "Test shutdown of an interface and recovery of the interface"
161
162 tgen = get_topogen()
163 router = tgen.gears["r1"]
164 router.run("ip link set r1-eth1 down")
165 topotest.sleep(5, "Waiting for EIGRP convergence")
166 router.run("ip link set r1-eth1 up")
167
168
169 def test_shutdown_check_stderr():
170 if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
171 pytest.skip("Skipping test for Stderr output and memory leaks")
172
173 tgen = get_topogen()
174 # Don't run this test if we have any failure.
175 if tgen.routers_have_failure():
176 pytest.skip(tgen.errors)
177
178 logger.info("Verifying unexpected STDERR output from daemons")
179
180 router_list = tgen.routers().values()
181 for router in router_list:
182 router.stop()
183
184 log = tgen.net[router.name].getStdErr("eigrpd")
185 if log:
186 logger.error("EIGRPd StdErr Log:" + log)
187 log = tgen.net[router.name].getStdErr("zebra")
188 if log:
189 logger.error("Zebra StdErr Log:" + log)
190
191
192 if __name__ == "__main__":
193 args = ["-s"] + sys.argv[1:]
194 sys.exit(pytest.main(args))
195
196 #
197 # Auxiliary Functions
198 #
199 def ip_eigrp_topo(node):
200 """
201 Parse 'show ip eigrp topo' from `node` and returns a dict with the
202 result.
203
204 Example:
205 {
206 'P': {
207 '192.168.1.0/24': {
208 'sucessors': 1,
209 'fd': 112233,
210 'serno': 0,
211 'via': 'Connected',
212 'interface': 'eth0',
213 },
214 '192.168.2.0/24': {
215 'sucessors': 1,
216 'fd': 112234,
217 'serno': 0,
218 'via': 'Connected',
219 'interface': 'eth1',
220 }
221 }
222 }
223 """
224 output = topotest.normalize_text(node.vtysh_cmd("show ip eigrp topo")).splitlines()
225 result = {}
226 for idx, line in enumerate(output):
227 columns = line.split(" ", 1)
228
229 # Parse the following format into python dicts
230 # code A.B.C.D/E, X successors, FD is Y, serno: Z
231 # via FOO, interface-name
232 code = columns[0]
233 if code not in ["P", "A", "U", "Q", "R", "r", "s"]:
234 continue
235
236 if code not in result:
237 result[code] = {}
238
239 # Split network from the rest
240 columns = columns[1].split(",")
241
242 # Parse first line data
243 network = columns[0]
244 result[code][network] = {}
245 for column in columns:
246 # Skip the network column
247 if column == columns[0]:
248 continue
249
250 match = re.search(r"(\d+) successors", column)
251 if match is not None:
252 result[code][network]["successors"] = match.group(1)
253 continue
254
255 match = re.search(r"FD is (\d+)", column)
256 if match is not None:
257 result[code][network]["fd"] = match.group(1)
258 continue
259
260 match = re.search(r"serno: (\d+)", column)
261 if match is not None:
262 result[code][network]["serno"] = match.group(1)
263 continue
264
265 # Parse second line data
266 nextline = output[idx + 1]
267 columns = topotest.normalize_text(nextline).split(",")
268 for column in columns:
269 match = re.search(r"via (.+)", column)
270 if match is not None:
271 result[code][network]["via"] = match.group(1)
272 continue
273
274 match = re.search(r"(.+)", column)
275 if match is not None:
276 result[code][network]["interface"] = match.group(1)
277 continue
278
279 return result