Add OSPF Segment Routing tests

- Build a topology made of 4 routers: 3 PE connected to a P
 - Segment Routing is activated on all 4 routers with various setting
for the MSD, Global Block and Prefix (with or without NO-PHP flag)
 - 2 tests have been elaborated: the first one check the consistency of the
Segment Routing database on each router compared to a reference and the second
one check that the MPLS FIB has been correctly configured on each router,
again compared to a reference

Signed-off-by: Olivier Dugeon <olivier.dugeon@orange.com>
This commit is contained in:
Olivier Dugeon 2018-02-15 16:06:01 +01:00 committed by Donald Sharp
parent d01e89f168
commit a60948db9c
20 changed files with 1119 additions and 0 deletions

View File

View File

@ -0,0 +1,106 @@
{
"srdbID":"10.0.255.1",
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"algorithms":[
{
"0":"SPF"
}
],
"extendedPrefix":[
{
"prefix":"10.0.255.2\/32",
"sid":200,
"inputLabel":20200,
"outputLabel":"pop",
"interface":"r1-eth0",
"nexthop":"10.0.1.2"
}
]
},
{
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":12,
"extendedPrefix":[
{
"prefix":"10.0.255.4\/32",
"sid":400,
"inputLabel":20400,
"outputLabel":"8400",
"interface":"r1-eth0",
"nexthop":"10.0.1.2"
}
]
},
{
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
"sid":300,
"inputLabel":20300,
"outputLabel":"8300",
"interface":"r1-eth0",
"nexthop":"10.0.1.2"
}
]
},
{
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
"sid":100,
"inputLabel":20100,
"outputLabel":"pop",
"interface":"lo",
"nexthop":"10.0.255.1"
}
],
"extendedLink":[
{
"prefix":"10.0.1.1\/32",
"sid":50001,
"inputLabel":50001,
"outputLabel":"pop",
"interface":"r1-eth0",
"nexthop":"10.0.1.2"
},
{
"prefix":"10.0.1.1\/32",
"sid":50000,
"inputLabel":50000,
"outputLabel":"pop",
"interface":"r1-eth0",
"nexthop":"10.0.1.2"
}
]
}
]
}

View File

@ -0,0 +1,17 @@
!
interface lo
ip ospf area 0.0.0.0
!
interface r1-eth0
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.255.1
capability opaque
router-info area 0.0.0.0
segment-routing on
segment-routing node-msd 16
segment-routing global-block 20000 29999
segment-routing prefix 10.0.255.1/32 index 100 no-php-flag
!

View File

@ -0,0 +1,9 @@
!
interface lo
ip address 10.0.255.1/32
!
interface r1-eth0
ip address 10.0.1.1/24
!
ip forwarding
!

View File

@ -0,0 +1,68 @@
{
"20100":{
"inLabel":20100,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.255.1"
}
]
},
"20200":{
"inLabel":20200,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.1.2"
}
]
},
"20300":{
"inLabel":20300,
"nexthops":[
{
"type":"SR",
"outLabel":8300,
"distance":150,
"nexthop":"10.0.1.2"
}
]
},
"20400":{
"inLabel":20400,
"nexthops":[
{
"type":"SR",
"outLabel":8400,
"distance":150,
"nexthop":"10.0.1.2"
}
]
},
"50000":{
"inLabel":50000,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.1.2"
}
]
},
"50001":{
"inLabel":50001,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.1.2"
}
]
}
}

View File

@ -0,0 +1,138 @@
{
"srdbID":"10.0.255.2",
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"algorithms":[
{
"0":"SPF"
}
],
"extendedPrefix":[
{
"prefix":"10.0.255.2\/32",
"sid":200,
"inputLabel":0,
"outputLabel":"0",
"interface":"lo",
"nexthop":"10.0.255.2"
}
],
"extendedLink":[
{
"prefix":"10.0.4.2\/32",
"sid":50001,
"inputLabel":50001,
"outputLabel":"pop",
"interface":"r2-eth2",
"nexthop":"10.0.4.1"
},
{
"prefix":"10.0.4.2\/32",
"sid":50000,
"inputLabel":50000,
"outputLabel":"pop",
"interface":"r2-eth2",
"nexthop":"10.0.4.1"
},
{
"prefix":"10.0.3.2\/32",
"sid":50003,
"inputLabel":50003,
"outputLabel":"pop",
"interface":"r2-eth1",
"nexthop":"10.0.3.1"
},
{
"prefix":"10.0.3.2\/32",
"sid":50002,
"inputLabel":50002,
"outputLabel":"pop",
"interface":"r2-eth1",
"nexthop":"10.0.3.1"
},
{
"prefix":"10.0.1.2\/32",
"sid":50005,
"inputLabel":50005,
"outputLabel":"pop",
"interface":"r2-eth0",
"nexthop":"10.0.1.1"
},
{
"prefix":"10.0.1.2\/32",
"sid":50004,
"inputLabel":50004,
"outputLabel":"pop",
"interface":"r2-eth0",
"nexthop":"10.0.1.1"
}
]
},
{
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":12,
"extendedPrefix":[
{
"prefix":"10.0.255.4\/32",
"sid":400,
"inputLabel":8400,
"outputLabel":"10400",
"interface":"r2-eth2",
"nexthop":"10.0.4.1"
}
]
},
{
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
"sid":300,
"inputLabel":8300,
"outputLabel":"pop",
"interface":"r2-eth1",
"nexthop":"10.0.3.1"
}
]
},
{
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
"sid":100,
"inputLabel":8100,
"outputLabel":"20100",
"interface":"r2-eth0",
"nexthop":"10.0.1.1"
}
]
}
]
}

View File

@ -0,0 +1,22 @@
!
interface lo
ip ospf area 0.0.0.0
!
interface r2-eth0
ip ospf area 0.0.0.0
!
interface r2-eth1
ip ospf network point-to-point
ip ospf area 0.0.0.0
!
interface r2-eth2
ip ospf network point-to-point
ip ospf area 0.0.0.0
!
router ospf
ospf router-id 10.0.255.2
capability opaque
router-info area 0.0.0.0
segment-routing on
segment-routing prefix 10.0.255.2/32 index 200
!

View File

@ -0,0 +1,15 @@
!
interface lo
ip address 10.0.255.2/32
!
interface r2-eth0
ip address 10.0.1.2/24
!
interface r2-eth1
ip address 10.0.3.2/24
!
interface r2-eth2
ip address 10.0.4.2/24
!
ip forwarding
!

View File

@ -0,0 +1,101 @@
{
"8100":{
"inLabel":8100,
"nexthops":[
{
"type":"SR",
"outLabel":20100,
"distance":150,
"nexthop":"10.0.1.1"
}
]
},
"8300":{
"inLabel":8300,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.3.1"
}
]
},
"8400":{
"inLabel":8400,
"nexthops":[
{
"type":"SR",
"outLabel":10400,
"distance":150,
"nexthop":"10.0.4.1"
}
]
},
"50000":{
"inLabel":50000,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.4.1"
}
]
},
"50001":{
"inLabel":50001,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.4.1"
}
]
},
"50002":{
"inLabel":50002,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.3.1"
}
]
},
"50003":{
"inLabel":50003,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.3.1"
}
]
},
"50004":{
"inLabel":50004,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.1.1"
}
]
},
"50005":{
"inLabel":50005,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.1.1"
}
]
}
}

View File

@ -0,0 +1,106 @@
{
"srdbID":"10.0.255.3",
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"algorithms":[
{
"0":"SPF"
}
],
"extendedPrefix":[
{
"prefix":"10.0.255.2\/32",
"sid":200,
"inputLabel":10200,
"outputLabel":"pop",
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}
]
},
{
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":12,
"extendedPrefix":[
{
"prefix":"10.0.255.4\/32",
"sid":400,
"inputLabel":10400,
"outputLabel":"8400",
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}
]
},
{
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
"sid":300,
"inputLabel":0,
"outputLabel":"0",
"interface":"lo",
"nexthop":"10.0.255.3"
}
],
"extendedLink":[
{
"prefix":"10.0.3.1\/32",
"sid":50001,
"inputLabel":50001,
"outputLabel":"pop",
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
},
{
"prefix":"10.0.3.1\/32",
"sid":50000,
"inputLabel":50000,
"outputLabel":"pop",
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}
]
},
{
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
"sid":100,
"inputLabel":10100,
"outputLabel":"8100",
"interface":"r3-eth0",
"nexthop":"10.0.3.2"
}
]
}
]
}

View File

@ -0,0 +1,18 @@
!
interface lo
ip ospf area 0.0.0.0
!
interface r3-eth0
ip ospf network point-to-point
ip ospf area 0.0.0.0
!
!
router ospf
ospf router-id 10.0.255.3
capability opaque
router-info area 0.0.0.0
segment-routing on
segment-routing global-block 10000 19999
segment-routing node-msd 8
segment-routing prefix 10.0.255.3/32 index 300
!

View File

@ -0,0 +1,9 @@
!
interface lo
ip address 10.0.255.3/32
!
interface r3-eth0
ip address 10.0.3.1/24
!
ip forwarding
!

View File

@ -0,0 +1,57 @@
{
"10100":{
"inLabel":10100,
"nexthops":[
{
"type":"SR",
"outLabel":8100,
"distance":150,
"nexthop":"10.0.3.2"
}
]
},
"10200":{
"inLabel":10200,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.3.2"
}
]
},
"10400":{
"inLabel":10400,
"nexthops":[
{
"type":"SR",
"outLabel":8400,
"distance":150,
"nexthop":"10.0.3.2"
}
]
},
"50000":{
"inLabel":50000,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.3.2"
}
]
},
"50001":{
"inLabel":50001,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.3.2"
}
]
}
}

View File

@ -0,0 +1,106 @@
{
"srdbID":"10.0.255.4",
"srNodes":[
{
"routerID":"10.0.255.2",
"srgbSize":20000,
"srgbLabel":8000,
"algorithms":[
{
"0":"SPF"
}
],
"extendedPrefix":[
{
"prefix":"10.0.255.2\/32",
"sid":200,
"inputLabel":10200,
"outputLabel":"pop",
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}
]
},
{
"routerID":"10.0.255.4",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":12,
"extendedPrefix":[
{
"prefix":"10.0.255.4\/32",
"sid":400,
"inputLabel":10400,
"outputLabel":"pop",
"interface":"lo",
"nexthop":"10.0.255.4"
}
],
"extendedLink":[
{
"prefix":"10.0.4.1\/32",
"sid":50001,
"inputLabel":50001,
"outputLabel":"pop",
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
},
{
"prefix":"10.0.4.1\/32",
"sid":50000,
"inputLabel":50000,
"outputLabel":"pop",
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}
]
},
{
"routerID":"10.0.255.3",
"srgbSize":10000,
"srgbLabel":10000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":8,
"extendedPrefix":[
{
"prefix":"10.0.255.3\/32",
"sid":300,
"inputLabel":10300,
"outputLabel":"8300",
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}
]
},
{
"routerID":"10.0.255.1",
"srgbSize":10000,
"srgbLabel":20000,
"algorithms":[
{
"0":"SPF"
}
],
"nodeMsd":16,
"extendedPrefix":[
{
"prefix":"10.0.255.1\/32",
"sid":100,
"inputLabel":10100,
"outputLabel":"8100",
"interface":"r4-eth0",
"nexthop":"10.0.4.2"
}
]
}
]
}

View File

@ -0,0 +1,18 @@
!
interface lo
ip ospf area 0.0.0.0
!
interface r4-eth0
ip ospf network point-to-point
ip ospf area 0.0.0.0
!
!
router ospf
ospf router-id 10.0.255.4
capability opaque
router-info area 0.0.0.0
segment-routing on
segment-routing global-block 10000 19999
segment-routing node-msd 12
segment-routing prefix 10.0.255.4/32 index 400 no-php-flag
!

View File

@ -0,0 +1,9 @@
!
interface lo
ip address 10.0.255.4/32
!
interface r4-eth0
ip address 10.0.4.1/24
!
ip forwarding
!

View File

@ -0,0 +1,68 @@
{
"10100":{
"inLabel":10100,
"nexthops":[
{
"type":"SR",
"outLabel":8100,
"distance":150,
"nexthop":"10.0.4.2"
}
]
},
"10200":{
"inLabel":10200,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.4.2"
}
]
},
"10300":{
"inLabel":10300,
"nexthops":[
{
"type":"SR",
"outLabel":8300,
"distance":150,
"nexthop":"10.0.4.2"
}
]
},
"10400":{
"inLabel":10400,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.255.4"
}
]
},
"50000":{
"inLabel":50000,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.4.2"
}
]
},
"50001":{
"inLabel":50001,
"nexthops":[
{
"type":"SR",
"outLabel":3,
"distance":150,
"nexthop":"10.0.4.2"
}
]
}
}

View File

@ -0,0 +1,78 @@
## Color coding:
#########################
## Main FRR: #f08080 red
## Switches: #d0e0d0 gray
## RIP: #19e3d9 Cyan
## RIPng: #fcb314 dark yellow
## OSPFv2: #32b835 Green
## OSPFv3: #19e3d9 Cyan
## ISIS IPv4 #fcb314 dark yellow
## ISIS IPv6 #9a81ec purple
## BGP IPv4 #eee3d3 beige
## BGP IPv6 #fdff00 yellow
##### Colors (see http://www.color-hex.com/)
graph ospf_topo1 {
label="ospf SR topo1";
# Routers
r1 [
label="r1\nrtr-id 10.0.255.1/32",
shape=doubleoctagon,
fillcolor="#f08080",
style=filled,
];
r2 [
label="r2\nrtr-id 10.0.255.2/32",
shape=doubleoctagon,
fillcolor="#f08080",
style=filled,
];
r3 [
label="r3\nrtr-id 10.0.255.3/32",
shape=doubleoctagon,
fillcolor="#f08080",
style=filled,
];
r4 [
label="r4\nrtr-id 10.0.255.4/32",
shape=doubleoctagon,
fillcolor="#f08080",
style=filled,
];
# Switches
s1 [
label="s2\n10.0.1.0/24",
shape=oval,
fillcolor="#d0e0d0",
style=filled,
];
s2 [
label="s1\n10.0.3.0/24",
shape=oval,
fillcolor="#d0e0d0",
style=filled,
];
s3 [
label="s2\n10.0.4.0/24",
shape=oval,
fillcolor="#d0e0d0",
style=filled,
];
# Connections
subgraph cluster0 {
label="area 0"
r1 -- s1 [label="eth0\n.1"];
r2 -- s1 [label="eth0\n.2"];
r2 -- s2 [label="eth1\n.2"];
r2 -- s3 [label="eth2\n.2"];
r3 -- s2 [label="eth0\n.1"];
r4 -- s3 [label="eth0\n.1"];
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,174 @@
#!/usr/bin/env python
#
# test_ospf_sr_topo1.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2017 by
# Network Device Education Foundation, Inc. ("NetDEF")
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
test_ospf_sr_topo1.py: Test the FRR/Quagga OSPF routing daemon
with Segment Routing.
"""
import os
import re
import sys
from functools import partial
import pytest
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, '../'))
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
# Required to instantiate the topology builder class.
from mininet.topo import Topo
class OSPFTopo(Topo):
"Test topology builder"
def build(self, *_args, **_opts):
"Build function"
tgen = get_topogen(self)
# Create 4 routers
for routern in range(1, 5):
tgen.add_router('r{}'.format(routern))
# Interconect router 1 and 2
switch = tgen.add_switch('s1')
switch.add_link(tgen.gears['r1'])
switch.add_link(tgen.gears['r2'])
# Interconect router 3 and 2
switch = tgen.add_switch('s2')
switch.add_link(tgen.gears['r3'])
switch.add_link(tgen.gears['r2'])
# Interconect router 4 and 2
switch = tgen.add_switch('s3')
switch.add_link(tgen.gears['r4'])
switch.add_link(tgen.gears['r2'])
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(OSPFTopo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
for rname, router in router_list.iteritems():
router.load_config(
TopoRouter.RD_ZEBRA,
os.path.join(CWD, '{}/zebra.conf'.format(rname))
)
router.load_config(
TopoRouter.RD_OSPF,
os.path.join(CWD, '{}/ospfd.conf'.format(rname))
)
# Initialize all routers.
tgen.start_router()
def teardown_module(mod):
"Teardown the pytest environment"
tgen = get_topogen()
tgen.stop_topology()
# Shared test function to validate expected output.
def compare_ospf_srdb(rname, expected):
"""
Calls 'show ip ospf database segment-routing json' for router `rname`
and compare the obtained result with the expected output.
"""
tgen = get_topogen()
current = tgen.gears[rname].vtysh_cmd('show ip ospf database segment-routing json')
return topotest.difflines(current, expected,
title1="Current output",
title2="Expected output")
def compare_mpls_table(rname, expected):
"""
Calls 'show mpls table json' for router `rname` and compare the obtained
result with the expected output.
"""
tgen = get_topogen()
current = tgen.gears[rname].vtysh_cmd('show mpls table json')
return topotest.difflines(current, expected,
title1="Current output",
title2="Expected output")
def test_ospf_sr():
"Test OSPF daemon Segment Routing"
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip('skipped because of router(s) failure')
for rnum in range(1, 5):
router = 'r{}'.format(rnum)
logger.info('Checking OSPF Segment Routing database on router "%s"',
router)
# Load expected results from the command
reffile = os.path.join(CWD, '{}/ospf_srdb.json'.format(router))
expected = open(reffile).read()
# Run test function until we get an result. Wait at most 60 seconds.
test_func = partial(compare_ospf_srdb, router, expected)
result, diff = topotest.run_and_expect(test_func, '',
count=25, wait=3)
assert result, 'OSPF did not start Segment Routing on {}:\n{}'.format(router, diff)
def test_ospf_kernel_route():
"Test OSPF Segment Routing MPLS route installation"
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip('skipped because of router(s) failure')
for rnum in range(1, 5):
router = 'r{}'.format(rnum)
logger.info('Checking OSPF SR MPLS table in "%s"', router)
# Load expected results from the command
reffile = os.path.join(CWD, '{}/zebra_mpls.json'.format(router))
expected = open(reffile).read()
# Run test function until we get an result. Wait at most 60 seconds.
test_func = partial(compare_mpls_table, router, expected)
result, diff = topotest.run_and_expect(test_func, '',
count=25, wait=3)
assert result, 'OSPF did not properly instal MPLS table on {}:\n{}'.format(router, diff)
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
if not tgen.is_memleak_enabled():
pytest.skip('Memory leak test/report is disabled')
tgen.report_memory_leaks()
if __name__ == '__main__':
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))