]>
Commit | Line | Data |
---|---|---|
ad9c18f3 CH |
1 | #!/usr/bin/env python |
2 | # -*- coding: utf-8 eval: (blacken-mode 1) -*- | |
acddc0ed | 3 | # SPDX-License-Identifier: GPL-2.0-or-later |
ad9c18f3 | 4 | # |
9495c405 | 5 | # Copyright (c) 2021-2022, LabN Consulting, L.L.C. |
ad9c18f3 | 6 | # |
ad9c18f3 CH |
7 | |
8 | """ | |
9 | test_ospf_clientapi.py: Test the OSPF client API. | |
10 | """ | |
11 | ||
12 | import logging | |
13 | import os | |
14 | import re | |
15 | import signal | |
16 | import subprocess | |
17 | import sys | |
18 | import time | |
19 | from datetime import datetime, timedelta | |
20 | ||
21 | import pytest | |
4e7eb1e6 | 22 | from lib.common_config import ( |
39e1f084 | 23 | kill_router_daemons, |
4e7eb1e6 A |
24 | retry, |
25 | run_frr_cmd, | |
4e7eb1e6 | 26 | shutdown_bringup_interface, |
39e1f084 CH |
27 | start_router_daemons, |
28 | step, | |
4e7eb1e6 | 29 | ) |
663a0c96 | 30 | from lib.micronet import Timeout, comm_error |
ad9c18f3 CH |
31 | from lib.topogen import Topogen, TopoRouter |
32 | from lib.topotest import interface_set_status, json_cmp | |
33 | ||
34 | pytestmark = [pytest.mark.ospfd] | |
35 | ||
36 | CWD = os.path.dirname(os.path.realpath(__file__)) | |
37 | TESTDIR = os.path.abspath(CWD) | |
38 | ||
39 | CLIENTDIR = os.path.abspath(os.path.join(CWD, "../../../ospfclient")) | |
40 | if not os.path.exists(CLIENTDIR): | |
41 | CLIENTDIR = os.path.join(CWD, "/usr/lib/frr") | |
42 | ||
43 | assert os.path.exists( | |
44 | os.path.join(CLIENTDIR, "ospfclient.py") | |
45 | ), "can't locate ospfclient.py" | |
46 | ||
47 | ||
48 | # ---------- | |
49 | # Test Setup | |
50 | # ---------- | |
51 | ||
663a0c96 CH |
52 | # |
53 | # r1 - r2 | |
54 | # | | | |
55 | # r4 - r3 | |
56 | # | |
57 | ||
ad9c18f3 CH |
58 | |
59 | @pytest.fixture(scope="function", name="tgen") | |
60 | def _tgen(request): | |
61 | "Setup/Teardown the environment and provide tgen argument to tests" | |
62 | nrouters = request.param | |
663a0c96 CH |
63 | topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)} |
64 | if nrouters == 4: | |
65 | topodef["sw4"] = ("r4", "r1") | |
ad9c18f3 CH |
66 | |
67 | tgen = Topogen(topodef, request.module.__name__) | |
68 | tgen.start_topology() | |
69 | ||
70 | router_list = tgen.routers() | |
71 | for _, router in router_list.items(): | |
72 | router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") | |
73 | router.load_config(TopoRouter.RD_OSPF, "ospfd.conf") | |
74 | router.net.daemons_options["ospfd"] = "--apiserver" | |
75 | ||
76 | tgen.start_router() | |
77 | ||
78 | yield tgen | |
79 | ||
80 | tgen.stop_topology() | |
81 | ||
82 | ||
83 | # Fixture that executes before each test | |
84 | @pytest.fixture(autouse=True) | |
85 | def skip_on_failure(tgen): | |
86 | if tgen.routers_have_failure(): | |
87 | pytest.skip("skipped because of previous test failure") | |
88 | ||
89 | ||
90 | # ------------ | |
91 | # Test Utility | |
92 | # ------------ | |
93 | ||
94 | ||
95 | @retry(retry_timeout=45) | |
96 | def verify_ospf_database(tgen, dut, input_dict, cmd="show ip ospf database json"): | |
97 | del tgen | |
98 | show_ospf_json = run_frr_cmd(dut, cmd, isjson=True) | |
99 | if not bool(show_ospf_json): | |
100 | return "ospf is not running" | |
101 | result = json_cmp(show_ospf_json, input_dict) | |
102 | return str(result) if result else None | |
103 | ||
104 | ||
105 | def myreadline(f): | |
106 | buf = b"" | |
107 | while True: | |
663a0c96 | 108 | # logging.debug("READING 1 CHAR") |
ad9c18f3 CH |
109 | c = f.read(1) |
110 | if not c: | |
111 | return buf if buf else None | |
112 | buf += c | |
663a0c96 | 113 | # logging.debug("READ CHAR: '%s'", c) |
ad9c18f3 CH |
114 | if c == b"\n": |
115 | return buf | |
116 | ||
117 | ||
663a0c96 CH |
118 | def _wait_output(p, regex, maxwait=120): |
119 | timeout = Timeout(maxwait) | |
120 | while not timeout.is_expired(): | |
ad9c18f3 CH |
121 | # line = p.stdout.readline() |
122 | line = myreadline(p.stdout) | |
123 | if not line: | |
663a0c96 | 124 | assert None, "EOF waiting for '{}'".format(regex) |
ad9c18f3 CH |
125 | line = line.decode("utf-8") |
126 | line = line.rstrip() | |
127 | if line: | |
128 | logging.debug("GOT LINE: '%s'", line) | |
129 | m = re.search(regex, line) | |
130 | if m: | |
131 | return m | |
663a0c96 CH |
132 | assert None, "Failed to get output matching '{}' withint {} actual {}s".format( |
133 | regex, maxwait, timeout.elapsed() | |
134 | ) | |
ad9c18f3 CH |
135 | |
136 | ||
137 | # ----- | |
138 | # Tests | |
139 | # ----- | |
140 | ||
141 | ||
142 | def _test_reachability(tgen, testbin): | |
143 | waitlist = [ | |
663a0c96 CH |
144 | "1.0.0.0,2.0.0.0,4.0.0.0", |
145 | "2.0.0.0,4.0.0.0", | |
146 | "1.0.0.0,2.0.0.0,4.0.0.0", | |
ad9c18f3 CH |
147 | ] |
148 | r2 = tgen.gears["r2"] | |
149 | r3 = tgen.gears["r3"] | |
663a0c96 | 150 | r4 = tgen.gears["r4"] |
ad9c18f3 CH |
151 | |
152 | wait_args = [f"--wait={x}" for x in waitlist] | |
153 | ||
154 | p = None | |
155 | try: | |
156 | step("reachable: check for initial reachability") | |
157 | p = r3.popen( | |
158 | ["/usr/bin/timeout", "120", testbin, "-v", *wait_args], | |
159 | encoding=None, # don't buffer | |
160 | stdin=subprocess.DEVNULL, | |
161 | stdout=subprocess.PIPE, | |
162 | stderr=subprocess.STDOUT, | |
163 | ) | |
164 | _wait_output(p, "SUCCESS: {}".format(waitlist[0])) | |
165 | ||
166 | step("reachable: check for modified reachability") | |
167 | interface_set_status(r2, "r2-eth0", False) | |
663a0c96 | 168 | interface_set_status(r4, "r4-eth1", False) |
ad9c18f3 CH |
169 | _wait_output(p, "SUCCESS: {}".format(waitlist[1])) |
170 | ||
171 | step("reachable: check for restored reachability") | |
172 | interface_set_status(r2, "r2-eth0", True) | |
663a0c96 | 173 | interface_set_status(r4, "r4-eth1", True) |
ad9c18f3 CH |
174 | _wait_output(p, "SUCCESS: {}".format(waitlist[2])) |
175 | except Exception as error: | |
176 | logging.error("ERROR: %s", error) | |
177 | raise | |
178 | finally: | |
179 | if p: | |
180 | p.terminate() | |
181 | p.wait() | |
182 | ||
183 | ||
184 | @pytest.mark.parametrize("tgen", [4], indirect=True) | |
185 | def test_ospf_reachability(tgen): | |
186 | testbin = os.path.join(TESTDIR, "ctester.py") | |
187 | rc, o, e = tgen.gears["r2"].net.cmd_status([testbin, "--help"]) | |
663a0c96 | 188 | logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e) |
ad9c18f3 CH |
189 | _test_reachability(tgen, testbin) |
190 | ||
191 | ||
9495c405 CH |
192 | def _test_router_id(tgen, testbin): |
193 | r1 = tgen.gears["r1"] | |
194 | waitlist = [ | |
663a0c96 | 195 | "1.0.0.0", |
9495c405 | 196 | "1.1.1.1", |
663a0c96 | 197 | "1.0.0.0", |
9495c405 CH |
198 | ] |
199 | ||
200 | mon_args = [f"--monitor={x}" for x in waitlist] | |
201 | ||
202 | p = None | |
203 | try: | |
204 | step("router id: check for initial router id") | |
205 | p = r1.popen( | |
206 | ["/usr/bin/timeout", "120", testbin, "-v", *mon_args], | |
207 | encoding=None, # don't buffer | |
208 | stdin=subprocess.DEVNULL, | |
209 | stdout=subprocess.PIPE, | |
210 | stderr=subprocess.STDOUT, | |
211 | ) | |
212 | _wait_output(p, "SUCCESS: {}".format(waitlist[0])) | |
213 | ||
214 | step("router id: check for modified router id") | |
215 | r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 1.1.1.1") | |
216 | _wait_output(p, "SUCCESS: {}".format(waitlist[1])) | |
217 | ||
218 | step("router id: check for restored router id") | |
663a0c96 | 219 | r1.vtysh_multicmd("conf t\nrouter ospf\nospf router-id 1.0.0.0") |
9495c405 CH |
220 | _wait_output(p, "SUCCESS: {}".format(waitlist[2])) |
221 | except Exception as error: | |
222 | logging.error("ERROR: %s", error) | |
223 | raise | |
224 | finally: | |
225 | if p: | |
226 | p.terminate() | |
227 | p.wait() | |
228 | ||
229 | ||
230 | @pytest.mark.parametrize("tgen", [2], indirect=True) | |
231 | def test_ospf_router_id(tgen): | |
232 | testbin = os.path.join(TESTDIR, "ctester.py") | |
233 | rc, o, e = tgen.gears["r1"].net.cmd_status([testbin, "--help"]) | |
663a0c96 | 234 | logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e) |
9495c405 CH |
235 | _test_router_id(tgen, testbin) |
236 | ||
237 | ||
ad9c18f3 CH |
238 | def _test_add_data(tgen, apibin): |
239 | "Test adding opaque data to domain" | |
240 | ||
241 | r1 = tgen.gears["r1"] | |
242 | ||
243 | step("add opaque: add opaque link local") | |
244 | ||
245 | p = None | |
246 | try: | |
247 | p = r1.popen([apibin, "-v", "add,9,10.0.1.1,230,2,00000202"]) | |
248 | input_dict = { | |
663a0c96 | 249 | "routerId": "1.0.0.0", |
ad9c18f3 CH |
250 | "areas": { |
251 | "1.2.3.4": { | |
252 | "linkLocalOpaqueLsa": [ | |
253 | { | |
254 | "lsId": "230.0.0.2", | |
663a0c96 | 255 | "advertisedRouter": "1.0.0.0", |
ad9c18f3 CH |
256 | "sequenceNumber": "80000001", |
257 | } | |
258 | ], | |
259 | } | |
260 | }, | |
261 | } | |
262 | # Wait for it to show up | |
263 | assert verify_ospf_database(tgen, r1, input_dict) is None | |
264 | ||
265 | input_dict = { | |
266 | "linkLocalOpaqueLsa": { | |
267 | "areas": { | |
268 | "1.2.3.4": [ | |
269 | { | |
270 | "linkStateId": "230.0.0.2", | |
663a0c96 | 271 | "advertisingRouter": "1.0.0.0", |
ad9c18f3 CH |
272 | "lsaSeqNumber": "80000001", |
273 | "opaqueData": "00000202", | |
274 | }, | |
275 | ], | |
276 | } | |
277 | }, | |
278 | } | |
279 | # verify content | |
280 | json_cmd = "show ip ospf da opaque-link json" | |
281 | assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None | |
282 | ||
283 | step("reset client, add opaque area, verify link local flushing") | |
284 | ||
285 | p.send_signal(signal.SIGINT) | |
286 | time.sleep(2) | |
287 | p.wait() | |
288 | p = None | |
289 | p = r1.popen([apibin, "-v", "add,10,1.2.3.4,231,1,00010101"]) | |
290 | input_dict = { | |
663a0c96 | 291 | "routerId": "1.0.0.0", |
ad9c18f3 CH |
292 | "areas": { |
293 | "1.2.3.4": { | |
294 | "linkLocalOpaqueLsa": [ | |
295 | { | |
296 | "lsId": "230.0.0.2", | |
663a0c96 | 297 | "advertisedRouter": "1.0.0.0", |
ad9c18f3 CH |
298 | "sequenceNumber": "80000001", |
299 | "lsaAge": 3600, | |
300 | } | |
301 | ], | |
302 | "areaLocalOpaqueLsa": [ | |
303 | { | |
304 | "lsId": "231.0.0.1", | |
663a0c96 | 305 | "advertisedRouter": "1.0.0.0", |
ad9c18f3 CH |
306 | "sequenceNumber": "80000001", |
307 | }, | |
308 | ], | |
309 | } | |
310 | }, | |
311 | } | |
312 | # Wait for it to show up | |
313 | assert verify_ospf_database(tgen, r1, input_dict) is None | |
314 | ||
315 | input_dict = { | |
316 | "areaLocalOpaqueLsa": { | |
317 | "areas": { | |
318 | "1.2.3.4": [ | |
319 | { | |
320 | "linkStateId": "231.0.0.1", | |
663a0c96 | 321 | "advertisingRouter": "1.0.0.0", |
ad9c18f3 CH |
322 | "lsaSeqNumber": "80000001", |
323 | "opaqueData": "00010101", | |
324 | }, | |
325 | ], | |
326 | } | |
327 | }, | |
328 | } | |
329 | # verify content | |
330 | json_cmd = "show ip ospf da opaque-area json" | |
331 | assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None | |
332 | ||
333 | step("reset client, add opaque AS, verify area flushing") | |
334 | ||
335 | p.send_signal(signal.SIGINT) | |
336 | time.sleep(2) | |
337 | p.wait() | |
338 | p = None | |
339 | ||
340 | p = r1.popen([apibin, "-v", "add,11,232,3,deadbeaf01234567"]) | |
341 | input_dict = { | |
663a0c96 | 342 | "routerId": "1.0.0.0", |
ad9c18f3 CH |
343 | "areas": { |
344 | "1.2.3.4": { | |
345 | "areaLocalOpaqueLsa": [ | |
346 | { | |
347 | "lsId": "231.0.0.1", | |
663a0c96 | 348 | "advertisedRouter": "1.0.0.0", |
ad9c18f3 CH |
349 | "sequenceNumber": "80000001", |
350 | "lsaAge": 3600, | |
351 | }, | |
352 | ], | |
353 | } | |
354 | }, | |
355 | "asExternalOpaqueLsa": [ | |
356 | { | |
357 | "lsId": "232.0.0.3", | |
663a0c96 | 358 | "advertisedRouter": "1.0.0.0", |
ad9c18f3 CH |
359 | "sequenceNumber": "80000001", |
360 | }, | |
361 | ], | |
362 | } | |
363 | # Wait for it to show up | |
364 | assert verify_ospf_database(tgen, r1, input_dict) is None | |
365 | ||
366 | input_dict = { | |
367 | "asExternalOpaqueLsa": [ | |
368 | { | |
369 | "linkStateId": "232.0.0.3", | |
663a0c96 | 370 | "advertisingRouter": "1.0.0.0", |
ad9c18f3 CH |
371 | "lsaSeqNumber": "80000001", |
372 | "opaqueData": "deadbeaf01234567", | |
373 | }, | |
374 | ] | |
375 | } | |
376 | # verify content | |
377 | json_cmd = "show ip ospf da opaque-as json" | |
378 | assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None | |
379 | ||
380 | step("stop client, verify AS flushing") | |
381 | ||
382 | p.send_signal(signal.SIGINT) | |
383 | time.sleep(2) | |
384 | p.wait() | |
385 | p = None | |
386 | ||
387 | input_dict = { | |
663a0c96 | 388 | "routerId": "1.0.0.0", |
ad9c18f3 CH |
389 | "asExternalOpaqueLsa": [ |
390 | { | |
391 | "lsId": "232.0.0.3", | |
663a0c96 | 392 | "advertisedRouter": "1.0.0.0", |
ad9c18f3 CH |
393 | "sequenceNumber": "80000001", |
394 | "lsaAge": 3600, | |
395 | }, | |
396 | ], | |
397 | } | |
398 | # Wait for it to be flushed | |
399 | assert verify_ospf_database(tgen, r1, input_dict) is None | |
400 | ||
401 | step("start client adding opaque domain, verify new sequence number and data") | |
402 | ||
403 | # Originate it again | |
404 | p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"]) | |
405 | input_dict = { | |
663a0c96 | 406 | "routerId": "1.0.0.0", |
ad9c18f3 CH |
407 | "asExternalOpaqueLsa": [ |
408 | { | |
409 | "lsId": "232.0.0.3", | |
663a0c96 | 410 | "advertisedRouter": "1.0.0.0", |
ad9c18f3 CH |
411 | "sequenceNumber": "80000002", |
412 | }, | |
413 | ], | |
414 | } | |
415 | assert verify_ospf_database(tgen, r1, input_dict) is None | |
416 | ||
417 | input_dict = { | |
418 | "asExternalOpaqueLsa": [ | |
419 | { | |
420 | "linkStateId": "232.0.0.3", | |
663a0c96 | 421 | "advertisingRouter": "1.0.0.0", |
ad9c18f3 CH |
422 | "lsaSeqNumber": "80000002", |
423 | "opaqueData": "ebadf00d", | |
424 | }, | |
425 | ] | |
426 | } | |
427 | # verify content | |
428 | json_cmd = "show ip ospf da opaque-as json" | |
429 | assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None | |
430 | ||
663a0c96 | 431 | logging.debug("sending interrupt to writer api client") |
ad9c18f3 CH |
432 | p.send_signal(signal.SIGINT) |
433 | time.sleep(2) | |
434 | p.wait() | |
435 | p = None | |
436 | ||
437 | except Exception: | |
438 | if p: | |
439 | p.terminate() | |
440 | if p.wait(): | |
441 | comm_error(p) | |
442 | p = None | |
443 | raise | |
444 | finally: | |
445 | if p: | |
663a0c96 | 446 | logging.debug("cleanup: sending interrupt to writer api client") |
ad9c18f3 CH |
447 | p.terminate() |
448 | p.wait() | |
449 | ||
450 | ||
451 | @pytest.mark.parametrize("tgen", [2], indirect=True) | |
452 | def test_ospf_opaque_add_data3(tgen): | |
453 | apibin = os.path.join(CLIENTDIR, "ospfclient.py") | |
454 | rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) | |
663a0c96 | 455 | logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) |
ad9c18f3 CH |
456 | _test_add_data(tgen, apibin) |
457 | ||
458 | ||
459 | def _test_opaque_add_del(tgen, apibin): | |
460 | "Test adding opaque data to domain" | |
461 | ||
462 | r1 = tgen.gears["r1"] | |
463 | r2 = tgen.gears["r2"] | |
464 | ||
465 | p = None | |
466 | pread = None | |
663a0c96 CH |
467 | # Log to our stdin, stderr |
468 | pout = open(os.path.join(r1.net.logdir, "r1/add-del.log"), "a+") | |
ad9c18f3 CH |
469 | try: |
470 | step("reachable: check for add notification") | |
471 | pread = r2.popen( | |
663a0c96 | 472 | ["/usr/bin/timeout", "120", apibin, "-v", "--logtag=READER", "wait,120"], |
ad9c18f3 CH |
473 | encoding=None, # don't buffer |
474 | stdin=subprocess.DEVNULL, | |
475 | stdout=subprocess.PIPE, | |
476 | stderr=subprocess.STDOUT, | |
477 | ) | |
0b242b11 LB |
478 | p = r1.popen( |
479 | [ | |
480 | apibin, | |
481 | "-v", | |
c4fff21b | 482 | "add,9,10.0.1.1,230,1", |
0b242b11 | 483 | "add,9,10.0.1.1,230,2,00000202", |
0b242b11 | 484 | "wait,1", |
c4fff21b LB |
485 | "add,10,1.2.3.4,231,1", |
486 | "add,10,1.2.3.4,231,2,0102030405060708", | |
487 | "wait,1", | |
488 | "add,11,232,1", | |
489 | "add,11,232,2,ebadf00d", | |
0b242b11 | 490 | "wait,20", |
c4fff21b LB |
491 | "del,9,10.0.1.1,230,2,0", |
492 | "del,10,1.2.3.4,231,2,1", | |
493 | "del,11,232,1,1", | |
0b242b11 LB |
494 | ] |
495 | ) | |
0b242b11 LB |
496 | add_input_dict = { |
497 | "areas": { | |
498 | "1.2.3.4": { | |
499 | "linkLocalOpaqueLsa": [ | |
c4fff21b LB |
500 | { |
501 | "lsId": "230.0.0.1", | |
663a0c96 | 502 | "advertisedRouter": "1.0.0.0", |
c4fff21b | 503 | "sequenceNumber": "80000001", |
663a0c96 | 504 | "checksum": "76bf", |
c4fff21b | 505 | }, |
0b242b11 LB |
506 | { |
507 | "lsId": "230.0.0.2", | |
663a0c96 | 508 | "advertisedRouter": "1.0.0.0", |
0b242b11 | 509 | "sequenceNumber": "80000001", |
663a0c96 | 510 | "checksum": "8aa2", |
c4fff21b | 511 | }, |
0b242b11 | 512 | ], |
c4fff21b | 513 | "linkLocalOpaqueLsaCount": 2, |
0b242b11 LB |
514 | "areaLocalOpaqueLsa": [ |
515 | { | |
516 | "lsId": "231.0.0.1", | |
663a0c96 | 517 | "advertisedRouter": "1.0.0.0", |
0b242b11 | 518 | "sequenceNumber": "80000001", |
663a0c96 | 519 | "checksum": "5bd8", |
0b242b11 LB |
520 | }, |
521 | { | |
522 | "lsId": "231.0.0.2", | |
663a0c96 | 523 | "advertisedRouter": "1.0.0.0", |
0b242b11 | 524 | "sequenceNumber": "80000001", |
663a0c96 | 525 | "checksum": "7690", |
0b242b11 LB |
526 | }, |
527 | ], | |
c4fff21b LB |
528 | "areaLocalOpaqueLsaCount": 2, |
529 | }, | |
0b242b11 LB |
530 | }, |
531 | "asExternalOpaqueLsa": [ | |
532 | { | |
c4fff21b | 533 | "lsId": "232.0.0.1", |
663a0c96 | 534 | "advertisedRouter": "1.0.0.0", |
0b242b11 | 535 | "sequenceNumber": "80000001", |
663a0c96 | 536 | "checksum": "5ed5", |
c4fff21b LB |
537 | }, |
538 | { | |
539 | "lsId": "232.0.0.2", | |
663a0c96 | 540 | "advertisedRouter": "1.0.0.0", |
c4fff21b | 541 | "sequenceNumber": "80000001", |
663a0c96 | 542 | "checksum": "d9bd", |
c4fff21b | 543 | }, |
0b242b11 | 544 | ], |
c4fff21b | 545 | "asExternalOpaqueLsaCount": 2, |
0b242b11 LB |
546 | } |
547 | ||
548 | step("reachable: check for add LSAs") | |
549 | json_cmd = "show ip ospf da json" | |
550 | assert verify_ospf_database(tgen, r1, add_input_dict, json_cmd) is None | |
551 | assert verify_ospf_database(tgen, r2, add_input_dict, json_cmd) is None | |
552 | ||
553 | numcs = 3 | |
554 | json_cmds = [ | |
555 | "show ip ospf da opaque-link json", | |
556 | "show ip ospf da opaque-area json", | |
557 | "show ip ospf da opaque-as json", | |
558 | ] | |
559 | add_detail_input_dict = [ | |
560 | { | |
561 | "linkLocalOpaqueLsa": { | |
562 | "areas": { | |
563 | "1.2.3.4": [ | |
c4fff21b LB |
564 | { |
565 | "linkStateId": "230.0.0.1", | |
663a0c96 | 566 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 567 | "lsaSeqNumber": "80000001", |
663a0c96 | 568 | "checksum": "76bf", |
c4fff21b LB |
569 | "length": 20, |
570 | "opaqueDataLength": 0, | |
571 | }, | |
0b242b11 LB |
572 | { |
573 | "linkStateId": "230.0.0.2", | |
663a0c96 | 574 | "advertisingRouter": "1.0.0.0", |
0b242b11 | 575 | "lsaSeqNumber": "80000001", |
663a0c96 | 576 | "checksum": "8aa2", |
0b242b11 LB |
577 | "length": 24, |
578 | "opaqueId": 2, | |
579 | "opaqueDataLength": 4, | |
c4fff21b | 580 | }, |
0b242b11 LB |
581 | ] |
582 | } | |
583 | } | |
584 | }, | |
585 | { | |
586 | "areaLocalOpaqueLsa": { | |
587 | "areas": { | |
588 | "1.2.3.4": [ | |
589 | { | |
590 | "linkStateId": "231.0.0.1", | |
663a0c96 | 591 | "advertisingRouter": "1.0.0.0", |
0b242b11 | 592 | "lsaSeqNumber": "80000001", |
663a0c96 | 593 | "checksum": "5bd8", |
c4fff21b LB |
594 | "length": 20, |
595 | "opaqueDataLength": 0, | |
0b242b11 LB |
596 | }, |
597 | { | |
598 | "linkStateId": "231.0.0.2", | |
663a0c96 | 599 | "advertisingRouter": "1.0.0.0", |
0b242b11 | 600 | "lsaSeqNumber": "80000001", |
663a0c96 | 601 | "checksum": "7690", |
c4fff21b LB |
602 | "length": 28, |
603 | "opaqueDataLength": 8, | |
0b242b11 | 604 | }, |
c4fff21b LB |
605 | ], |
606 | }, | |
607 | }, | |
0b242b11 LB |
608 | }, |
609 | { | |
610 | "asExternalOpaqueLsa": [ | |
611 | { | |
c4fff21b | 612 | "linkStateId": "232.0.0.1", |
663a0c96 | 613 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 614 | "lsaSeqNumber": "80000001", |
663a0c96 | 615 | "checksum": "5ed5", |
c4fff21b LB |
616 | "length": 20, |
617 | "opaqueDataLength": 0, | |
618 | }, | |
619 | { | |
620 | "linkStateId": "232.0.0.2", | |
663a0c96 | 621 | "advertisingRouter": "1.0.0.0", |
0b242b11 | 622 | "lsaSeqNumber": "80000001", |
663a0c96 | 623 | "checksum": "d9bd", |
0b242b11 LB |
624 | "length": 24, |
625 | "opaqueDataLength": 4, | |
c4fff21b LB |
626 | }, |
627 | ], | |
0b242b11 LB |
628 | }, |
629 | ] | |
630 | i = 0 | |
631 | while i < numcs: | |
632 | step("reachable: check for add LSA details: %s" % json_cmds[i]) | |
633 | assert ( | |
634 | verify_ospf_database(tgen, r1, add_detail_input_dict[i], json_cmds[i]) | |
635 | is None | |
636 | ) | |
637 | assert ( | |
638 | verify_ospf_database(tgen, r2, add_detail_input_dict[i], json_cmds[i]) | |
639 | is None | |
640 | ) | |
641 | i += 1 | |
ad9c18f3 CH |
642 | |
643 | # Wait for add notification | |
644 | # RECV: LSA update msg for LSA 232.0.0.3 in area 0.0.0.0 seq 0x80000001 len 24 age 9 | |
645 | ||
c4fff21b LB |
646 | ls_ids = [ |
647 | "230.0.0.1", | |
648 | "230.0.0.2", | |
649 | "231.0.0.1", | |
650 | "231.0.0.2", | |
651 | "232.0.0.1", | |
652 | "232.0.0.2", | |
653 | ] | |
0b242b11 | 654 | for ls_id in ls_ids: |
c4fff21b | 655 | step("reachable: check for API add notification: %s" % ls_id) |
0b242b11 LB |
656 | waitfor = "RECV:.*update msg.*LSA {}.*age ([0-9]+)".format(ls_id) |
657 | _ = _wait_output(pread, waitfor) | |
658 | ||
659 | del_input_dict = { | |
660 | "areas": { | |
661 | "1.2.3.4": { | |
662 | "linkLocalOpaqueLsa": [ | |
c4fff21b LB |
663 | { |
664 | "lsId": "230.0.0.1", | |
663a0c96 | 665 | "advertisedRouter": "1.0.0.0", |
c4fff21b | 666 | "sequenceNumber": "80000001", |
663a0c96 | 667 | "checksum": "76bf", |
c4fff21b | 668 | }, |
0b242b11 LB |
669 | { |
670 | "lsId": "230.0.0.2", | |
663a0c96 | 671 | "advertisedRouter": "1.0.0.0", |
c4fff21b | 672 | "lsaAge": 3600, |
0b242b11 | 673 | "sequenceNumber": "80000001", |
663a0c96 | 674 | "checksum": "8aa2", |
c4fff21b | 675 | }, |
0b242b11 | 676 | ], |
c4fff21b | 677 | "linkLocalOpaqueLsaCount": 2, |
0b242b11 LB |
678 | "areaLocalOpaqueLsa": [ |
679 | { | |
0b242b11 | 680 | "lsId": "231.0.0.1", |
663a0c96 | 681 | "advertisedRouter": "1.0.0.0", |
0b242b11 | 682 | "sequenceNumber": "80000001", |
663a0c96 | 683 | "checksum": "5bd8", |
0b242b11 LB |
684 | }, |
685 | { | |
0b242b11 | 686 | "lsId": "231.0.0.2", |
663a0c96 | 687 | "advertisedRouter": "1.0.0.0", |
c4fff21b LB |
688 | "lsaAge": 3600, |
689 | "sequenceNumber": "80000002", | |
663a0c96 | 690 | "checksum": "4fe2", |
0b242b11 LB |
691 | }, |
692 | ], | |
c4fff21b LB |
693 | "areaLocalOpaqueLsaCount": 2, |
694 | }, | |
0b242b11 LB |
695 | }, |
696 | "asExternalOpaqueLsa": [ | |
697 | { | |
c4fff21b | 698 | "lsId": "232.0.0.1", |
663a0c96 | 699 | "advertisedRouter": "1.0.0.0", |
c4fff21b | 700 | "lsaAge": 3600, |
0b242b11 | 701 | "sequenceNumber": "80000001", |
663a0c96 | 702 | "checksum": "5ed5", |
c4fff21b LB |
703 | }, |
704 | { | |
705 | "lsId": "232.0.0.2", | |
663a0c96 | 706 | "advertisedRouter": "1.0.0.0", |
c4fff21b | 707 | "sequenceNumber": "80000001", |
663a0c96 | 708 | "checksum": "d9bd", |
c4fff21b | 709 | }, |
0b242b11 | 710 | ], |
c4fff21b | 711 | "asExternalOpaqueLsaCount": 2, |
0b242b11 LB |
712 | } |
713 | ||
714 | step("reachable: check for explicit withdrawal LSAs") | |
715 | json_cmd = "show ip ospf da json" | |
716 | assert verify_ospf_database(tgen, r1, del_input_dict, json_cmd) is None | |
717 | assert verify_ospf_database(tgen, r2, del_input_dict, json_cmd) is None | |
ad9c18f3 | 718 | |
c4fff21b LB |
719 | del_detail_input_dict = [ |
720 | { | |
721 | "linkLocalOpaqueLsa": { | |
722 | "areas": { | |
723 | "1.2.3.4": [ | |
724 | { | |
725 | "linkStateId": "230.0.0.1", | |
663a0c96 | 726 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 727 | "lsaSeqNumber": "80000001", |
663a0c96 | 728 | "checksum": "76bf", |
c4fff21b LB |
729 | "length": 20, |
730 | "opaqueDataLength": 0, | |
731 | }, | |
732 | { | |
733 | "linkStateId": "230.0.0.2", | |
663a0c96 | 734 | "advertisingRouter": "1.0.0.0", |
c4fff21b LB |
735 | "lsaAge": 3600, |
736 | "lsaSeqNumber": "80000001", | |
663a0c96 | 737 | "checksum": "8aa2", |
c4fff21b LB |
738 | "length": 24, |
739 | "opaqueId": 2, | |
740 | "opaqueDataLength": 4, | |
741 | }, | |
742 | ] | |
743 | } | |
744 | } | |
745 | }, | |
746 | { | |
747 | "areaLocalOpaqueLsa": { | |
748 | "areas": { | |
749 | "1.2.3.4": [ | |
750 | { | |
751 | "linkStateId": "231.0.0.1", | |
663a0c96 | 752 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 753 | "lsaSeqNumber": "80000001", |
663a0c96 | 754 | "checksum": "5bd8", |
c4fff21b LB |
755 | "length": 20, |
756 | "opaqueDataLength": 0, | |
757 | }, | |
758 | { | |
759 | "lsaAge": 3600, | |
760 | "linkStateId": "231.0.0.2", | |
663a0c96 | 761 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 762 | "lsaSeqNumber": "80000002", |
663a0c96 | 763 | "checksum": "4fe2", |
c4fff21b LB |
764 | # data removed |
765 | "length": 20, | |
766 | "opaqueDataLength": 0, | |
767 | }, | |
768 | ], | |
769 | }, | |
770 | }, | |
771 | }, | |
772 | { | |
773 | "asExternalOpaqueLsa": [ | |
774 | { | |
775 | "linkStateId": "232.0.0.1", | |
663a0c96 | 776 | "advertisingRouter": "1.0.0.0", |
c4fff21b LB |
777 | "lsaAge": 3600, |
778 | "lsaSeqNumber": "80000001", | |
663a0c96 | 779 | "checksum": "5ed5", |
c4fff21b LB |
780 | "length": 20, |
781 | "opaqueDataLength": 0, | |
782 | }, | |
783 | { | |
784 | "linkStateId": "232.0.0.2", | |
663a0c96 | 785 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 786 | "lsaSeqNumber": "80000001", |
663a0c96 | 787 | "checksum": "d9bd", |
c4fff21b LB |
788 | "length": 24, |
789 | "opaqueDataLength": 4, | |
790 | }, | |
791 | ], | |
792 | }, | |
793 | ] | |
794 | i = 0 | |
795 | while i < numcs: | |
796 | step("reachable: check for delete LSA details: %s" % json_cmds[i]) | |
797 | assert ( | |
798 | verify_ospf_database(tgen, r1, del_detail_input_dict[i], json_cmds[i]) | |
799 | is None | |
800 | ) | |
801 | assert ( | |
802 | verify_ospf_database(tgen, r2, del_detail_input_dict[i], json_cmds[i]) | |
803 | is None | |
804 | ) | |
805 | i += 1 | |
806 | ||
ad9c18f3 CH |
807 | p.terminate() |
808 | if p.wait(): | |
809 | comm_error(p) | |
c4fff21b LB |
810 | |
811 | del_detail_input_dict = [ | |
812 | { | |
813 | "linkLocalOpaqueLsa": { | |
814 | "areas": { | |
815 | "1.2.3.4": [ | |
816 | { | |
817 | "linkStateId": "230.0.0.1", | |
663a0c96 | 818 | "advertisingRouter": "1.0.0.0", |
c4fff21b LB |
819 | "lsaAge": 3600, |
820 | "lsaSeqNumber": "80000001", | |
663a0c96 | 821 | "checksum": "76bf", |
c4fff21b LB |
822 | "length": 20, |
823 | "opaqueDataLength": 0, | |
824 | }, | |
825 | { | |
826 | "linkStateId": "230.0.0.2", | |
663a0c96 | 827 | "advertisingRouter": "1.0.0.0", |
c4fff21b LB |
828 | "lsaAge": 3600, |
829 | "lsaSeqNumber": "80000001", | |
663a0c96 | 830 | "checksum": "8aa2", |
c4fff21b LB |
831 | "length": 24, |
832 | "opaqueId": 2, | |
833 | "opaqueDataLength": 4, | |
834 | }, | |
835 | ] | |
836 | } | |
0b242b11 LB |
837 | } |
838 | }, | |
c4fff21b LB |
839 | { |
840 | "areaLocalOpaqueLsa": { | |
841 | "areas": { | |
842 | "1.2.3.4": [ | |
843 | { | |
844 | "lsaAge": 3600, | |
845 | "linkStateId": "231.0.0.1", | |
663a0c96 | 846 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 847 | "lsaSeqNumber": "80000001", |
663a0c96 | 848 | "checksum": "5bd8", |
c4fff21b LB |
849 | "length": 20, |
850 | "opaqueDataLength": 0, | |
851 | }, | |
852 | { | |
853 | "lsaAge": 3600, | |
854 | "linkStateId": "231.0.0.2", | |
663a0c96 | 855 | "advertisingRouter": "1.0.0.0", |
c4fff21b | 856 | "lsaSeqNumber": "80000002", |
663a0c96 | 857 | "checksum": "4fe2", |
c4fff21b LB |
858 | # data removed |
859 | "length": 20, | |
860 | "opaqueDataLength": 0, | |
861 | }, | |
862 | ], | |
863 | }, | |
864 | }, | |
865 | }, | |
866 | { | |
867 | "asExternalOpaqueLsa": [ | |
868 | { | |
869 | "linkStateId": "232.0.0.1", | |
663a0c96 | 870 | "advertisingRouter": "1.0.0.0", |
c4fff21b LB |
871 | "lsaAge": 3600, |
872 | "lsaSeqNumber": "80000001", | |
663a0c96 | 873 | "checksum": "5ed5", |
c4fff21b LB |
874 | "length": 20, |
875 | "opaqueDataLength": 0, | |
876 | }, | |
877 | { | |
878 | "linkStateId": "232.0.0.2", | |
663a0c96 | 879 | "advertisingRouter": "1.0.0.0", |
c4fff21b LB |
880 | "lsaAge": 3600, |
881 | "lsaSeqNumber": "80000001", | |
663a0c96 | 882 | "checksum": "d9bd", |
c4fff21b LB |
883 | "length": 24, |
884 | "opaqueDataLength": 4, | |
885 | }, | |
886 | ], | |
887 | }, | |
888 | ] | |
889 | i = 0 | |
890 | while i < numcs: | |
891 | step( | |
892 | "reachable: check for post API shutdown delete LSA details: %s" | |
893 | % json_cmds[i] | |
894 | ) | |
895 | assert ( | |
896 | verify_ospf_database(tgen, r1, del_detail_input_dict[i], json_cmds[i]) | |
897 | is None | |
898 | ) | |
899 | assert ( | |
900 | verify_ospf_database(tgen, r2, del_detail_input_dict[i], json_cmds[i]) | |
901 | is None | |
902 | ) | |
903 | i += 1 | |
ad9c18f3 CH |
904 | |
905 | # step("reachable: check for flush/age out") | |
906 | # # Wait for max age notification | |
907 | # waitfor = "RECV:.*update msg.*LSA {}.*age 3600".format(ls_id) | |
908 | # _wait_output(pread, waitfor) | |
c4fff21b LB |
909 | ls_ids = [ |
910 | "230.0.0.2", | |
911 | "231.0.0.2", | |
912 | "232.0.0.1", | |
913 | "230.0.0.1", | |
914 | "231.0.0.1", | |
915 | "232.0.0.2", | |
916 | ] | |
0b242b11 | 917 | for ls_id in ls_ids: |
c4fff21b LB |
918 | step("reachable: check for API delete notification: %s" % ls_id) |
919 | waitfor = "RECV:.*delete msg.*LSA {}.*age".format(ls_id) | |
0b242b11 | 920 | _ = _wait_output(pread, waitfor) |
ad9c18f3 CH |
921 | except Exception: |
922 | if p: | |
923 | p.terminate() | |
924 | if p.wait(): | |
925 | comm_error(p) | |
926 | p = None | |
927 | raise | |
928 | finally: | |
929 | if pread: | |
930 | pread.terminate() | |
931 | pread.wait() | |
932 | if p: | |
933 | p.terminate() | |
934 | p.wait() | |
935 | ||
936 | ||
937 | @pytest.mark.parametrize("tgen", [2], indirect=True) | |
938 | def test_ospf_opaque_delete_data3(tgen): | |
939 | apibin = os.path.join(CLIENTDIR, "ospfclient.py") | |
940 | rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) | |
663a0c96 | 941 | logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) |
ad9c18f3 CH |
942 | _test_opaque_add_del(tgen, apibin) |
943 | ||
944 | ||
4e7eb1e6 A |
945 | def _test_opaque_add_restart_add(tgen, apibin): |
946 | "Test adding an opaque LSA and then restarting ospfd" | |
947 | ||
948 | r1 = tgen.gears["r1"] | |
949 | r2 = tgen.gears["r2"] | |
950 | ||
951 | p = None | |
952 | pread = None | |
953 | # Log to our stdin, stderr | |
954 | pout = open(os.path.join(r1.net.logdir, "r1/add-del.log"), "a+") | |
955 | try: | |
956 | step("reachable: check for add notification") | |
957 | pread = r2.popen( | |
958 | ["/usr/bin/timeout", "120", apibin, "-v", "--logtag=READER", "wait,120"], | |
959 | encoding=None, # don't buffer | |
960 | stdin=subprocess.DEVNULL, | |
961 | stdout=subprocess.PIPE, | |
962 | stderr=subprocess.STDOUT, | |
963 | ) | |
964 | p = r1.popen( | |
965 | [ | |
966 | apibin, | |
967 | "-v", | |
39e1f084 | 968 | "add,10,1.2.3.4,231,1", # seq = 80000001 |
4e7eb1e6 | 969 | "wait, 5", |
39e1f084 | 970 | "add,10,1.2.3.4,231,1,feedaceebeef", # seq = 80000002 |
4e7eb1e6 A |
971 | "wait, 5", |
972 | ] | |
973 | ) | |
974 | add_input_dict = { | |
975 | "areas": { | |
976 | "1.2.3.4": { | |
977 | "areaLocalOpaqueLsa": [ | |
978 | { | |
979 | "lsId": "231.0.0.1", | |
980 | "advertisedRouter": "1.0.0.0", | |
39e1f084 CH |
981 | "sequenceNumber": "80000002", |
982 | "checksum": "cd26", | |
4e7eb1e6 A |
983 | }, |
984 | ], | |
985 | "areaLocalOpaqueLsaCount": 1, | |
986 | }, | |
987 | }, | |
988 | } | |
39e1f084 | 989 | step("Wait for the Opaque LSA to be distributed") |
4e7eb1e6 A |
990 | json_cmd = "show ip ospf da json" |
991 | assert verify_ospf_database(tgen, r1, add_input_dict, json_cmd) is None | |
992 | assert verify_ospf_database(tgen, r2, add_input_dict, json_cmd) is None | |
993 | ||
994 | step("Shutdown the interface on r1 to isolate it for r2") | |
995 | shutdown_bringup_interface(tgen, "r1", "r1-eth0", False) | |
996 | ||
997 | time.sleep(2) | |
998 | step("Reset the client") | |
999 | p.send_signal(signal.SIGINT) | |
1000 | time.sleep(2) | |
1001 | p.wait() | |
1002 | p = None | |
1003 | ||
39e1f084 CH |
1004 | # Verify the OLD LSA is still there unchanged on R2 |
1005 | assert verify_ospf_database(tgen, r2, add_input_dict, json_cmd) is None | |
1006 | ||
4e7eb1e6 A |
1007 | step("Kill ospfd on R1") |
1008 | kill_router_daemons(tgen, "r1", ["ospfd"]) | |
1009 | time.sleep(2) | |
1010 | ||
1011 | step("Bring ospfd on R1 back up") | |
1012 | start_router_daemons(tgen, "r1", ["ospfd"]) | |
1013 | ||
39e1f084 CH |
1014 | # This will start off with sequence num 80000001 |
1015 | # But should advance to 80000003 when we reestablish with r2 | |
4e7eb1e6 A |
1016 | p = r1.popen( |
1017 | [ | |
1018 | apibin, | |
1019 | "-v", | |
39e1f084 | 1020 | "add,10,1.2.3.4,231,1,feedaceecafebeef", # seq=80000001 |
4e7eb1e6 A |
1021 | "wait, 5", |
1022 | ] | |
1023 | ) | |
1024 | ||
39e1f084 CH |
1025 | # verify the old value on r2 doesn't change yet |
1026 | time.sleep(2) | |
1027 | assert verify_ospf_database(tgen, r2, add_input_dict, json_cmd) is None | |
4e7eb1e6 | 1028 | |
4e7eb1e6 | 1029 | json_cmd = "show ip ospf da opaque-area json" |
39e1f084 | 1030 | new_add_input_dict = { |
4e7eb1e6 A |
1031 | "areaLocalOpaqueLsa": { |
1032 | "areas": { | |
1033 | "1.2.3.4": [ | |
1034 | { | |
1035 | "linkStateId": "231.0.0.1", | |
1036 | "advertisingRouter": "1.0.0.0", | |
39e1f084 CH |
1037 | "lsaSeqNumber": "80000001", |
1038 | "checksum": "b07a", | |
4e7eb1e6 A |
1039 | "length": 28, |
1040 | "opaqueDataLength": 8, | |
1041 | }, | |
1042 | ], | |
1043 | }, | |
1044 | }, | |
1045 | } | |
39e1f084 CH |
1046 | # verify new value with initial seq number on r1 |
1047 | assert verify_ospf_database(tgen, r1, new_add_input_dict, json_cmd) is None | |
1048 | ||
1049 | step("Bring the interface on r1 back up for connection to r2") | |
1050 | shutdown_bringup_interface(tgen, "r1", "r1-eth0", True) | |
1051 | ||
1052 | step("Verify area opaque LSA refresh") | |
1053 | ||
1054 | # Update the expected value to sequence number rev and new checksum | |
1055 | update_dict = new_add_input_dict["areaLocalOpaqueLsa"]["areas"]["1.2.3.4"][0] | |
1056 | update_dict["lsaSeqNumber"] = "80000003" | |
1057 | update_dict["checksum"] = "cb27" | |
1058 | ||
1059 | # should settle on the same value now. | |
1060 | assert verify_ospf_database(tgen, r1, new_add_input_dict, json_cmd) is None | |
1061 | assert verify_ospf_database(tgen, r2, new_add_input_dict, json_cmd) is None | |
4e7eb1e6 A |
1062 | |
1063 | step("Shutdown the interface on r1 to isolate it for r2") | |
1064 | shutdown_bringup_interface(tgen, "r1", "r1-eth0", False) | |
1065 | ||
1066 | time.sleep(2) | |
1067 | step("Reset the client") | |
1068 | p.send_signal(signal.SIGINT) | |
1069 | time.sleep(2) | |
1070 | p.wait() | |
1071 | p = None | |
1072 | ||
1073 | step("Kill ospfd on R1") | |
1074 | kill_router_daemons(tgen, "r1", ["ospfd"]) | |
1075 | time.sleep(2) | |
1076 | ||
1077 | step("Bring ospfd on R1 back up") | |
1078 | start_router_daemons(tgen, "r1", ["ospfd"]) | |
1079 | ||
1080 | step("Bring the interface on r1 back up for connection to r2") | |
1081 | shutdown_bringup_interface(tgen, "r1", "r1-eth0", True) | |
1082 | ||
1083 | step("Verify area opaque LSA Purging") | |
1084 | json_cmd = "show ip ospf da opaque-area json" | |
1085 | add_detail_input_dict = { | |
1086 | "areaLocalOpaqueLsa": { | |
1087 | "areas": { | |
1088 | "1.2.3.4": [ | |
1089 | { | |
1090 | "lsaAge": 3600, | |
1091 | "linkStateId": "231.0.0.1", | |
1092 | "advertisingRouter": "1.0.0.0", | |
39e1f084 CH |
1093 | "lsaSeqNumber": "80000003", |
1094 | "checksum": "cb27", | |
4e7eb1e6 A |
1095 | "length": 28, |
1096 | "opaqueDataLength": 8, | |
1097 | }, | |
1098 | ], | |
1099 | }, | |
1100 | }, | |
1101 | } | |
1102 | assert verify_ospf_database(tgen, r1, add_detail_input_dict, json_cmd) is None | |
1103 | assert verify_ospf_database(tgen, r2, add_detail_input_dict, json_cmd) is None | |
1104 | step("Verify Area Opaque LSA removal after timeout (60 seconds)") | |
1105 | time.sleep(60) | |
1106 | json_cmd = "show ip ospf da opaque-area json" | |
1107 | timeout_detail_input_dict = { | |
1108 | "areaLocalOpaqueLsa": { | |
1109 | "areas": { | |
1110 | "1.2.3.4": [], | |
1111 | }, | |
1112 | }, | |
1113 | } | |
1114 | assert ( | |
1115 | verify_ospf_database(tgen, r1, timeout_detail_input_dict, json_cmd) is None | |
1116 | ) | |
1117 | assert ( | |
1118 | verify_ospf_database(tgen, r2, timeout_detail_input_dict, json_cmd) is None | |
1119 | ) | |
1120 | ||
1121 | except Exception: | |
1122 | if p: | |
1123 | p.terminate() | |
1124 | if p.wait(): | |
1125 | comm_error(p) | |
1126 | p = None | |
1127 | raise | |
1128 | finally: | |
1129 | if pread: | |
1130 | pread.terminate() | |
1131 | pread.wait() | |
1132 | if p: | |
1133 | p.terminate() | |
1134 | p.wait() | |
1135 | ||
1136 | ||
1137 | @pytest.mark.parametrize("tgen", [2], indirect=True) | |
1138 | def test_ospf_opaque_restart(tgen): | |
1139 | apibin = os.path.join(CLIENTDIR, "ospfclient.py") | |
1140 | rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"]) | |
1141 | logging.debug("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e) | |
1142 | _test_opaque_add_restart_add(tgen, apibin) | |
1143 | ||
1144 | ||
ad9c18f3 CH |
1145 | if __name__ == "__main__": |
1146 | args = ["-s"] + sys.argv[1:] | |
1147 | sys.exit(pytest.main(args)) |