]>
Commit | Line | Data |
---|---|---|
0534e94c KS |
1 | #!/usr/bin/env python |
2 | ||
3 | # | |
4 | # test_ldp_isis_topo1.py | |
5 | # Part of NetDEF Topology Tests | |
6 | # | |
7 | # Copyright (c) 2020 by Volta Networks | |
8 | # | |
9 | # Permission to use, copy, modify, and/or distribute this software | |
10 | # for any purpose with or without fee is hereby granted, provided | |
11 | # that the above copyright notice and this permission notice appear | |
12 | # in all copies. | |
13 | # | |
14 | # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES | |
15 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
16 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR | |
17 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY | |
18 | # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
19 | # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
20 | # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE | |
21 | # OF THIS SOFTWARE. | |
22 | # | |
23 | ||
24 | """ | |
25 | test_ldp_vpls_topo1.py: | |
26 | ||
27 | +---------+ +---------+ | |
28 | | | | | | |
29 | | CE1 | | CE2 | | |
30 | | | | | | |
31 | +---------+ +---------+ | |
32 | ce1-eth0 (172.16.1.1/24)| |ce2-eth0 (172.16.1.2/24) | |
33 | | | | |
34 | | | | |
35 | rt1-eth0| |rt2-eth0 | |
36 | +---------+ 10.0.1.0/24 +---------+ | |
37 | | |rt1-eth1 | | | |
38 | | RT1 +----------------+ RT2 | | |
39 | | 1.1.1.1 | rt2-eth1| 2.2.2.2 | | |
40 | | | | | | |
41 | +---------+ +---------+ | |
42 | rt1-eth2| |rt2-eth2 | |
43 | | | | |
44 | | | | |
45 | 10.0.2.0/24| +---------+ |10.0.3.0/24 | |
46 | | | | | | |
47 | | | RT3 | | | |
48 | +--------+ 3.3.3.3 +-------+ | |
49 | rt3-eth2| |rt3-eth1 | |
50 | +---------+ | |
51 | |rt3-eth0 | |
52 | | | |
53 | | | |
54 | ce3-eth0 (172.16.1.3/24)| | |
55 | +---------+ | |
56 | | | | |
57 | | CE3 | | |
58 | | | | |
59 | +---------+ | |
60 | """ | |
61 | ||
62 | import os | |
63 | import re | |
64 | import sys | |
65 | import pytest | |
66 | import json | |
67 | from time import sleep | |
68 | from functools import partial | |
69 | ||
70 | # Save the Current Working Directory to find configuration files. | |
71 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
72 | sys.path.append(os.path.join(CWD, "../")) | |
73 | ||
74 | # pylint: disable=C0413 | |
75 | # Import topogen and topotest helpers | |
76 | from lib import topotest | |
77 | from lib.topogen import Topogen, TopoRouter, get_topogen | |
78 | from lib.topolog import logger | |
79 | from lib.snmptest import SnmpTester | |
80 | ||
81 | # Required to instantiate the topology builder class. | |
82 | from mininet.topo import Topo | |
83 | ||
84 | ||
85 | class TemplateTopo(Topo): | |
86 | "Test topology builder" | |
87 | ||
88 | def build(self, *_args, **_opts): | |
89 | "Build function" | |
90 | tgen = get_topogen(self) | |
91 | ||
92 | # | |
93 | # Define FRR Routers | |
94 | # | |
95 | for router in ["ce1", "ce2", "ce3", "r1", "r2", "r3"]: | |
96 | tgen.add_router(router) | |
97 | ||
98 | # | |
99 | # Define connections | |
100 | # | |
101 | switch = tgen.add_switch("s1") | |
102 | switch.add_link(tgen.gears["ce1"]) | |
103 | switch.add_link(tgen.gears["r1"]) | |
104 | ||
105 | switch = tgen.add_switch("s2") | |
106 | switch.add_link(tgen.gears["ce2"]) | |
107 | switch.add_link(tgen.gears["r2"]) | |
108 | ||
109 | switch = tgen.add_switch("s3") | |
110 | switch.add_link(tgen.gears["ce3"]) | |
111 | switch.add_link(tgen.gears["r3"]) | |
112 | ||
113 | switch = tgen.add_switch("s4") | |
114 | switch.add_link(tgen.gears["r1"]) | |
115 | switch.add_link(tgen.gears["r2"]) | |
116 | ||
117 | switch = tgen.add_switch("s5") | |
118 | switch.add_link(tgen.gears["r1"]) | |
119 | switch.add_link(tgen.gears["r3"]) | |
120 | ||
121 | switch = tgen.add_switch("s6") | |
122 | switch.add_link(tgen.gears["r2"]) | |
123 | switch.add_link(tgen.gears["r3"]) | |
124 | ||
125 | ||
126 | def setup_module(mod): | |
127 | "Sets up the pytest environment" | |
128 | tgen = Topogen(TemplateTopo, mod.__name__) | |
129 | tgen.start_topology() | |
130 | ||
131 | router_list = tgen.routers() | |
132 | ||
133 | # For all registered routers, load the zebra configuration file | |
134 | for rname, router in router_list.items(): | |
135 | router.load_config( | |
136 | TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) | |
137 | ) | |
138 | # Don't start isisd and ldpd in the CE nodes | |
139 | if router.name[0] == "r": | |
140 | router.load_config( | |
141 | TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) | |
142 | ) | |
143 | router.load_config( | |
144 | TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname)), | |
145 | "-M snmp" | |
146 | ) | |
147 | router.load_config( | |
148 | TopoRouter.RD_SNMP, os.path.join(CWD, "{}/snmpd.conf".format(rname)), | |
149 | "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX,trap" | |
150 | ) | |
151 | ||
152 | ||
153 | tgen.start_router() | |
154 | ||
155 | ||
156 | def teardown_module(mod): | |
157 | "Teardown the pytest environment" | |
158 | tgen = get_topogen() | |
159 | ||
160 | # This function tears down the whole topology. | |
161 | tgen.stop_topology() | |
162 | ||
163 | ||
164 | def router_compare_json_output(rname, command, reference): | |
165 | "Compare router JSON output" | |
166 | ||
167 | logger.info('Comparing router "%s" "%s" output', rname, command) | |
168 | ||
169 | tgen = get_topogen() | |
170 | filename = "{}/{}/{}".format(CWD, rname, reference) | |
171 | expected = json.loads(open(filename).read()) | |
172 | ||
173 | # Run test function until we get an result. | |
174 | test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected) | |
175 | _, diff = topotest.run_and_expect(test_func, None, count=320, wait=0.5) | |
176 | assertmsg = '"{}" JSON output mismatches the expected result'.format(rname) | |
177 | assert diff is None, assertmsg | |
178 | ||
179 | ||
180 | def test_isis_convergence(): | |
181 | logger.info("Test: check ISIS adjacencies") | |
182 | tgen = get_topogen() | |
183 | ||
184 | # Skip if previous fatal error condition is raised | |
185 | if tgen.routers_have_failure(): | |
186 | pytest.skip(tgen.errors) | |
187 | ||
188 | for rname in ["r1", "r2", "r3"]: | |
189 | router_compare_json_output( | |
190 | rname, | |
191 | "show yang operational-data /frr-interface:lib isisd", | |
192 | "show_yang_interface_isis_adjacencies.ref", | |
193 | ) | |
194 | ||
195 | ||
196 | def test_rib(): | |
197 | logger.info("Test: verify RIB") | |
198 | tgen = get_topogen() | |
199 | ||
200 | # Skip if previous fatal error condition is raised | |
201 | # TODO: disabling this check to avoid 'snmpd not running' errors | |
202 | #if tgen.routers_have_failure(): | |
203 | # pytest.skip(tgen.errors) | |
204 | ||
205 | for rname in ["r1", "r2", "r3"]: | |
206 | router_compare_json_output(rname, "show ip route json", "show_ip_route.ref") | |
207 | ||
208 | ||
209 | def test_ldp_adjacencies(): | |
210 | logger.info("Test: verify LDP adjacencies") | |
211 | tgen = get_topogen() | |
212 | ||
213 | # Skip if previous fatal error condition is raised | |
214 | # TODO: disabling this check to avoid 'snmpd not running' errors | |
215 | #if tgen.routers_have_failure(): | |
216 | # pytest.skip(tgen.errors) | |
217 | ||
218 | for rname in ["r1", "r2", "r3"]: | |
219 | router_compare_json_output( | |
220 | rname, "show mpls ldp discovery json", "show_ldp_discovery.ref" | |
221 | ) | |
222 | ||
223 | ||
224 | def test_ldp_neighbors(): | |
225 | logger.info("Test: verify LDP neighbors") | |
226 | tgen = get_topogen() | |
227 | ||
228 | # Skip if previous fatal error condition is raised | |
229 | #if tgen.routers_have_failure(): | |
230 | # pytest.skip(tgen.errors) | |
231 | ||
232 | for rname in ["r1", "r2", "r3"]: | |
233 | router_compare_json_output( | |
234 | rname, "show mpls ldp neighbor json", "show_ldp_neighbor.ref" | |
235 | ) | |
236 | ||
237 | ||
238 | def test_r1_ldp_lsr_objects(): | |
239 | "Test mplsLdpLsrObjects objects" | |
240 | tgen = get_topogen() | |
241 | ||
242 | r1 = tgen.net.get("r1") | |
243 | r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") | |
244 | ||
245 | assert r1_snmp.test_oid('mplsLdpLsrId', "01 01 01 01") | |
246 | assert r1_snmp.test_oid('mplsLdpLsrLoopDetectionCapable', 'none(1)') | |
247 | ||
248 | ||
249 | def test_r1_ldp_entity_table(): | |
250 | "Test mplsLdpEntityTable" | |
251 | tgen = get_topogen() | |
252 | ||
253 | r1 = tgen.net.get("r1") | |
254 | r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") | |
255 | ||
256 | assert r1_snmp.test_oid_walk( | |
257 | 'mplsLdpEntityLdpId', ['1.1.1.1:0']) | |
258 | assert r1_snmp.test_oid_walk( | |
259 | 'mplsLdpEntityIndex', ['1']) | |
260 | assert r1_snmp.test_oid_walk( | |
261 | 'mplsLdpEntityProtocolVersion', ['1']) | |
262 | assert r1_snmp.test_oid_walk( | |
263 | 'mplsLdpEntityAdminStatus', ['enable(1)']) | |
264 | assert r1_snmp.test_oid_walk( | |
265 | 'mplsLdpEntityOperStatus', ['enabled(2)']) | |
266 | assert r1_snmp.test_oid_walk( | |
267 | 'mplsLdpEntityTcpPort', ['646']) | |
268 | assert r1_snmp.test_oid_walk( | |
269 | 'mplsLdpEntityUdpDscPort', ['646']) | |
270 | assert r1_snmp.test_oid_walk( | |
271 | 'mplsLdpEntityMaxPduLength', ['4096 octets']) | |
272 | assert r1_snmp.test_oid_walk( | |
273 | 'mplsLdpEntityKeepAliveHoldTimer', ['180 seconds']) | |
274 | assert r1_snmp.test_oid_walk( | |
275 | 'mplsLdpEntityHelloHoldTimer', ['0 seconds']) | |
276 | assert r1_snmp.test_oid_walk( | |
277 | 'mplsLdpEntityInitSessionThreshold', ['0']) | |
278 | assert r1_snmp.test_oid_walk( | |
279 | 'mplsLdpEntityLabelDistMethod', ['downstreamUnsolicited(2)']) | |
280 | assert r1_snmp.test_oid_walk( | |
281 | 'mplsLdpEntityLabelRetentionMode', ['liberal(2)']) | |
282 | assert r1_snmp.test_oid_walk( | |
283 | 'mplsLdpEntityPathVectorLimit', ['0']) | |
284 | assert r1_snmp.test_oid_walk( | |
285 | 'mplsLdpEntityHopCountLimit', ['0']) | |
286 | assert r1_snmp.test_oid_walk( | |
287 | 'mplsLdpEntityTransportAddrKind', ['loopback(2)']) | |
288 | assert r1_snmp.test_oid_walk( | |
289 | 'mplsLdpEntityTargetPeer', ['true(1)']) | |
290 | assert r1_snmp.test_oid_walk( | |
291 | 'mplsLdpEntityTargetPeerAddrType', ['ipv4(1)']) | |
292 | assert r1_snmp.test_oid_walk( | |
293 | 'mplsLdpEntityTargetPeerAddr', ['01 01 01 01']) | |
294 | assert r1_snmp.test_oid_walk( | |
295 | 'mplsLdpEntityLabelType', ['generic(1)']) | |
296 | assert r1_snmp.test_oid_walk( | |
297 | 'mplsLdpEntityDiscontinuityTime', ['(0) 0:00:00.00']) | |
298 | assert r1_snmp.test_oid_walk( | |
299 | 'mplsLdpEntityStorageType', ['nonVolatile(3)']) | |
300 | assert r1_snmp.test_oid_walk( | |
301 | 'mplsLdpEntityRowStatus', ['createAndGo(4)']) | |
302 | ||
303 | ||
304 | def test_r1_ldp_peer_table(): | |
305 | "Test mplsLdpPeerTable" | |
306 | tgen = get_topogen() | |
307 | ||
308 | r1 = tgen.net.get("r1") | |
309 | r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") | |
310 | ||
311 | assert r1_snmp.test_oid_walk( | |
312 | 'mplsLdpPeerLdpId', ['2.2.2.2:0', '3.3.3.3:0']) | |
313 | assert r1_snmp.test_oid_walk( | |
314 | 'mplsLdpPeerLabelDistMethod', | |
315 | ['downstreamUnsolicited(2)', 'downstreamUnsolicited(2)']) | |
316 | assert r1_snmp.test_oid_walk( | |
317 | 'mplsLdpPeerPathVectorLimit', ['0', '0']) | |
318 | assert r1_snmp.test_oid_walk( | |
319 | 'mplsLdpPeerTransportAddrType', ['ipv4(1)', 'ipv4(1)']) | |
320 | assert r1_snmp.test_oid_walk( | |
321 | 'mplsLdpPeerTransportAddr', ['02 02 02 02', '03 03 03 03']) | |
322 | ||
323 | ||
324 | def test_r1_ldp_session_table(): | |
325 | "Test mplsLdpSessionTable" | |
326 | tgen = get_topogen() | |
327 | ||
328 | r1 = tgen.net.get("r1") | |
329 | r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") | |
330 | ||
331 | assert r1_snmp.test_oid_walk('mplsLdpSessionState', | |
332 | ['operational(5)', 'operational(5)']) | |
333 | assert r1_snmp.test_oid_walk('mplsLdpSessionRole', | |
334 | ['passive(3)', 'passive(3)']) | |
335 | assert r1_snmp.test_oid_walk('mplsLdpSessionProtocolVersion', | |
336 | ['1', '1']) | |
337 | assert r1_snmp.test_oid_walk('mplsLdpSessionKeepAliveTime', | |
338 | ['180 seconds', '180 seconds']) | |
339 | assert r1_snmp.test_oid_walk('mplsLdpSessionMaxPduLength', | |
340 | ['4096 octets', '4096 octets']) | |
341 | assert r1_snmp.test_oid_walk('mplsLdpSessionDiscontinuityTime', | |
342 | ['(0) 0:00:00.00', '(0) 0:00:00.00']) | |
343 | ||
344 | ||
345 | def test_r1_ldp_hello_adjacency_table(): | |
346 | "Test mplsLdpHelloAdjacencyTable" | |
347 | tgen = get_topogen() | |
348 | ||
349 | r1 = tgen.net.get("r1") | |
350 | r1_snmp = SnmpTester(r1, "1.1.1.1", "public", "2c") | |
351 | ||
352 | assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyIndex', | |
353 | ['1', '2', '1']) | |
354 | assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyHoldTime', | |
355 | ['15', '45', '15']) | |
356 | assert r1_snmp.test_oid_walk('mplsLdpHelloAdjacencyType', | |
357 | ['link(1)', 'targeted(2)', 'link(1)']) | |
358 | ||
359 | ||
360 | # Memory leak test template | |
361 | # disabling memory leak | |
362 | def test_memory_leak(): | |
363 | "Run the memory leak test and report results." | |
364 | tgen = get_topogen() | |
365 | if not tgen.is_memleak_enabled(): | |
366 | pytest.skip("Memory leak test/report is disabled") | |
367 | ||
368 | tgen.report_memory_leaks() | |
369 | ||
370 | ||
371 | if __name__ == "__main__": | |
372 | args = ["-s"] + sys.argv[1:] | |
373 | sys.exit(pytest.main(args)) |