tests: Add ip6_route_zebra lib function

Add a common function to retrieve and canonicalize
'show ipv6 route' output for use in topotests. Use that in
the test_ospf6_topo1 test; update the corresponding 'expected'
results files to match the lib function.

Replace some 'print' with 'logger' statements in that test also.

Signed-off-by: Mark Stapp <mjs@voltanet.io>
This commit is contained in:
Mark Stapp 2019-06-06 11:49:15 -04:00
parent 92a9c7bd28
commit e394d9aa5f
10 changed files with 90 additions and 188 deletions

View File

@ -429,6 +429,33 @@ def ip4_route_zebra(node, vrf_name=None):
lines = lines[1:] lines = lines[1:]
return '\n'.join(lines) return '\n'.join(lines)
def ip6_route_zebra(node, vrf_name=None):
"""
Retrieves the output of 'show ipv6 route [vrf vrf_name]', then
canonicalizes it by eliding link-locals.
"""
if vrf_name == None:
tmp = node.vtysh_cmd('show ipv6 route')
else:
tmp = node.vtysh_cmd('show ipv6 route vrf {0}'.format(vrf_name))
# Mask out timestamp
output = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", tmp)
# Mask out the link-local addresses
output = re.sub(r'fe80::[^ ]+,', 'fe80::XXXX:XXXX:XXXX:XXXX,', output)
lines = output.splitlines()
header_found = False
while lines and (not lines[0].strip() or not header_found):
if '> - selected route' in lines[0]:
header_found = True
lines = lines[1:]
return '\n'.join(lines)
def proto_name_to_number(protocol): def proto_name_to_number(protocol):
return { return {
'bgp': '186', 'bgp': '186',

View File

@ -1,27 +0,0 @@
hostname r1
log file ospf6d.log
!
debug ospf6 message all
debug ospf6 lsa unknown
debug ospf6 zebra
debug ospf6 interface
debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
interface r1-stubnet
ipv6 ospf6 network broadcast
!
interface r1-sw5
ipv6 ospf6 network broadcast
!
router ospf6
router-id 10.0.0.1
log-adjacency-changes detail
redistribute static
interface r1-stubnet area 0.0.0.0
interface r1-sw5 area 0.0.0.0
!
line vty
exec-timeout 0 0
!

View File

@ -1,9 +1,9 @@
O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet, XX:XX:XX
O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5 O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, XX:XX:XX
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5 O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX

View File

@ -1,27 +0,0 @@
hostname r2
log file ospf6d.log
!
debug ospf6 message all
debug ospf6 lsa unknown
debug ospf6 zebra
debug ospf6 interface
debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
interface r2-stubnet
ipv6 ospf6 network broadcast
!
interface r2-sw5
ipv6 ospf6 network broadcast
!
router ospf6
router-id 10.0.0.2
log-adjacency-changes detail
redistribute static
interface r2-stubnet area 0.0.0.0
interface r2-sw5 area 0.0.0.0
!
line vty
exec-timeout 0 0
!

View File

@ -1,10 +1,10 @@
O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet, XX:XX:XX
O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5 O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, XX:XX:XX
O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5 O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX

View File

@ -1,31 +0,0 @@
hostname r3
log file ospf6d.log
!
debug ospf6 message all
debug ospf6 lsa unknown
debug ospf6 zebra
debug ospf6 interface
debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
interface r3-stubnet
ipv6 ospf6 network broadcast
!
interface r3-sw5
ipv6 ospf6 network broadcast
!
interface r3-sw6
ipv6 ospf6 network broadcast
!
router ospf6
router-id 10.0.0.3
log-adjacency-changes detail
redistribute static
interface r3-stubnet area 0.0.0.0
interface r3-sw5 area 0.0.0.0
interface r3-sw6 area 0.0.0.1
!
line vty
exec-timeout 0 0
!

View File

@ -1,10 +1,10 @@
O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, XX:XX:XX
O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6 O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, XX:XX:XX
O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5 O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, XX:XX:XX
O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6 O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, XX:XX:XX
O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5 O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6 O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, XX:XX:XX

View File

@ -1,27 +0,0 @@
hostname r4
log file ospf6d.log
!
debug ospf6 message all
debug ospf6 lsa unknown
debug ospf6 zebra
debug ospf6 interface
debug ospf6 neighbor
debug ospf6 route table
debug ospf6 flooding
!
interface r4-stubnet
ipv6 ospf6 network broadcast
!
interface r4-sw6
ipv6 ospf6 network broadcast
!
router ospf6
router-id 10.0.0.4
log-adjacency-changes detail
redistribute static
interface r4-stubnet area 0.0.0.1
interface r4-sw6 area 0.0.0.1
!
line vty
exec-timeout 0 0
!

View File

@ -1,9 +1,9 @@
O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet, XX:XX:XX
O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6 O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, XX:XX:XX
O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6 O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX

View File

@ -154,17 +154,13 @@ def setup_module(mod):
tgen = Topogen(NetworkTopo, mod.__name__) tgen = Topogen(NetworkTopo, mod.__name__)
tgen.start_topology() tgen.start_topology()
print("\n\n** %s: Setup Topology" % mod.__name__) logger.info("** %s: Setup Topology" % mod.__name__)
print("******************************************\n") logger.info("******************************************")
# For debugging after starting net, but before starting FRR, # For debugging after starting net, but before starting FRR,
# uncomment the next line # uncomment the next line
# tgen.mininet_cli() # tgen.mininet_cli()
ospf_config = 'ospf6d.conf'
if tgen.gears['r1'].has_version('<', '4.0'):
ospf_config = 'ospf6d.conf-pre-v4'
router_list = tgen.routers() router_list = tgen.routers()
for rname, router in router_list.iteritems(): for rname, router in router_list.iteritems():
router.load_config( router.load_config(
@ -173,7 +169,7 @@ def setup_module(mod):
) )
router.load_config( router.load_config(
TopoRouter.RD_OSPF6, TopoRouter.RD_OSPF6,
os.path.join(CWD, '{}/{}'.format(rname, ospf_config)) os.path.join(CWD, '{}/ospf6d.conf'.format(rname))
) )
# Initialize all routers. # Initialize all routers.
@ -201,8 +197,7 @@ def test_ospf6_converged():
#tgen.mininet_cli() #tgen.mininet_cli()
# Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State) # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
print("\n\n** Verify OSPF6 daemons' convergence") logger.info("Waiting for OSPF6 convergence")
print("******************************************\n")
# Set up for regex # Set up for regex
pat1 = re.compile('^[0-9]') pat1 = re.compile('^[0-9]')
@ -210,7 +205,7 @@ def test_ospf6_converged():
timeout = 60 timeout = 60
while timeout > 0: while timeout > 0:
print("Timeout in %s: " % timeout), logger.info("Timeout in %s: " % timeout),
sys.stdout.flush() sys.stdout.flush()
# Look for any node not yet converged # Look for any node not yet converged
@ -230,12 +225,12 @@ def test_ospf6_converged():
break break
if isConverged == False: if isConverged == False:
print('Waiting for {}'.format(router)) logger.info('Waiting for {}'.format(router))
sys.stdout.flush() sys.stdout.flush()
break break
if isConverged: if isConverged:
print('Done\n') logger.info('Done')
break break
else: else:
sleep(5) sleep(5)
@ -246,12 +241,7 @@ def test_ospf6_converged():
ospfStatus = rnode.vtysh_cmd('show ipv6 ospf neigh') ospfStatus = rnode.vtysh_cmd('show ipv6 ospf neigh')
assert False, "OSPFv6 did not converge:\n{}".format(ospfStatus) assert False, "OSPFv6 did not converge:\n{}".format(ospfStatus)
print("OSPFv3 converged.") logger.info("OSPFv3 converged.")
if timeout < 60:
# Only wait if we actually went through a convergence
print("\nwaiting 15s for routes to populate")
sleep(15)
# For debugging, uncomment the next line # For debugging, uncomment the next line
# tgen.mininet_cli() # tgen.mininet_cli()
@ -266,7 +256,9 @@ def compare_show_ipv6(rname, expected):
result with the expected output. result with the expected output.
""" """
tgen = get_topogen() tgen = get_topogen()
current = tgen.gears[rname].vtysh_cmd('show ipv6 route')
# Use the vtysh output, with some masking to make comparison easy
current = topotest.ip6_route_zebra(tgen.gears[rname])
# Use just the 'O'spf lines of the output # Use just the 'O'spf lines of the output
linearr = [] linearr = []
@ -276,14 +268,6 @@ def compare_show_ipv6(rname, expected):
current = '\n'.join(linearr) current = '\n'.join(linearr)
# Remove the link addresses
current = re.sub(r'fe80::[^ ]+', 'fe80::xxxx:xxxx:xxxx:xxxx', current)
expected = re.sub(r'fe80::[^ ]+', 'fe80::xxxx:xxxx:xxxx:xxxx', expected)
# Remove the time
current = re.sub(r', \d+:\d{2}:\d{2}', '', current)
expected = re.sub(r'\d+:\d{2}:\d{2}', '', expected)
return topotest.difflines(topotest.normalize_text(current), return topotest.difflines(topotest.normalize_text(current),
topotest.normalize_text(expected), topotest.normalize_text(expected),
title1="Current output", title1="Current output",
@ -322,8 +306,8 @@ def test_linux_ipv6_kernel_routingTable():
pytest.skip('skipped because of router(s) failure') pytest.skip('skipped because of router(s) failure')
# Verify Linux Kernel Routing Table # Verify Linux Kernel Routing Table
print("\n\n** Verifying Linux IPv6 Kernel Routing Table") logger.info("Verifying Linux IPv6 Kernel Routing Table")
print("******************************************\n")
failures = 0 failures = 0
# Get a list of all current link-local addresses first as they change for # Get a list of all current link-local addresses first as they change for
@ -332,7 +316,8 @@ def test_linux_ipv6_kernel_routingTable():
for i in range(1, 5): for i in range(1, 5):
linklocals += tgen.net['r{}'.format(i)].get_ipv6_linklocal() linklocals += tgen.net['r{}'.format(i)].get_ipv6_linklocal()
# Now compare the routing tables (after substituting link-local addresses) # Now compare the routing tables (after substituting link-local addresses)
for i in range(1, 5): for i in range(1, 5):
refTableFile = os.path.join(CWD, 'r{}/ip_6_address.ref'.format(i)) refTableFile = os.path.join(CWD, 'r{}/ip_6_address.ref'.format(i))
if os.path.isfile(refTableFile): if os.path.isfile(refTableFile):
@ -365,9 +350,9 @@ def test_linux_ipv6_kernel_routingTable():
actual = '\n'.join(filtered_lines).splitlines(1) actual = '\n'.join(filtered_lines).splitlines(1)
# Print Actual table # Print Actual table
# print("Router r%s table" % i) # logger.info("Router r%s table" % i)
# for line in actual: # for line in actual:
# print(line.rstrip()) # logger.info(line.rstrip())
# Generate Diff # Generate Diff
diff = topotest.get_textdiff(actual, expected, diff = topotest.get_textdiff(actual, expected,
@ -379,7 +364,7 @@ def test_linux_ipv6_kernel_routingTable():
sys.stderr.write('r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n' % (i, diff)) sys.stderr.write('r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n' % (i, diff))
failures += 1 failures += 1
else: else:
print("r%s ok" % i) logger.info("r%s ok" % i)
assert failures == 0, "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff) assert failures == 0, "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff)
@ -392,29 +377,29 @@ def test_shutdown_check_stderr():
pytest.skip('skipped because of router(s) failure') pytest.skip('skipped because of router(s) failure')
if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n") logger.info("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
pytest.skip('Skipping test for Stderr output') pytest.skip('Skipping test for Stderr output')
net = tgen.net net = tgen.net
print("\n\n** Verifying unexpected STDERR output from daemons") logger.info("\n\n** Verifying unexpected STDERR output from daemons")
print("******************************************\n") logger.info("******************************************")
for i in range(1, 5): for i in range(1, 5):
net['r%s' % i].stopRouter() net['r%s' % i].stopRouter()
log = net['r%s' % i].getStdErr('ospf6d') log = net['r%s' % i].getStdErr('ospf6d')
if log: if log:
print("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log)) logger.info("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log))
log = net['r%s' % i].getStdErr('zebra') log = net['r%s' % i].getStdErr('zebra')
if log: if log:
print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log)) logger.info("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
def test_shutdown_check_memleak(): def test_shutdown_check_memleak():
"Run the memory leak test and report results." "Run the memory leak test and report results."
if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None: if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None:
print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n") logger.info("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)")
pytest.skip('Skipping test for memory leaks') pytest.skip('Skipping test for memory leaks')
tgen = get_topogen() tgen = get_topogen()
@ -430,7 +415,9 @@ def test_shutdown_check_memleak():
if __name__ == '__main__': if __name__ == '__main__':
# To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli # To suppress tracebacks, either use the following pytest call or
# add "--tb=no" to cli
# retval = pytest.main(["-s", "--tb=no"]) # retval = pytest.main(["-s", "--tb=no"])
retval = pytest.main(["-s"]) retval = pytest.main(["-s"])
sys.exit(retval) sys.exit(retval)