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