ospfd: Implement OSPF prefix-suppression as specified in RFC 6860

Signed-off-by: Acee <aceelindem@gmail.com>
This commit is contained in:
Acee 2023-07-17 13:47:16 -04:00
parent ff10abcc89
commit e2eea4fe8e
11 changed files with 1236 additions and 22 deletions

View File

@ -699,6 +699,15 @@ Interfaces
OSPF (:ref:`redistribute-routes-to-ospf`). This is the only way to OSPF (:ref:`redistribute-routes-to-ospf`). This is the only way to
advertise non-OSPF links into stub areas. advertise non-OSPF links into stub areas.
.. clicmd:: ip ospf prefix-suppression [A.B.C.D]
Configure OSPF to not advertise the IPv4 prefix associated with the
OSPF interface. The associated IPv4 prefix will be omitted from an OSPF
router-LSA or advertised with a host mask in an OSPF network-LSA as
specified in RFC 6860, "Hiding Transit-Only Networks in OSPF". If an
optional IPv4 address is specified, the prefix suppression will apply
to the OSPF interface associated with the specified interface address.
.. clicmd:: ip ospf area (A.B.C.D|(0-4294967295)) .. clicmd:: ip ospf area (A.B.C.D|(0-4294967295))

View File

@ -70,7 +70,7 @@ extern "C" {
#define OSPF_FAST_HELLO_DEFAULT 0 #define OSPF_FAST_HELLO_DEFAULT 0
#define OSPF_P2MP_DELAY_REFLOOD_DEFAULT false #define OSPF_P2MP_DELAY_REFLOOD_DEFAULT false
#define OSPF_OPAQUE_CAPABLE_DEFAULT true #define OSPF_OPAQUE_CAPABLE_DEFAULT true
#define OSPF_PREFIX_SUPPRESSION_DEFAULT false
#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */ #define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */
#define OSPF_AREA_RANGE_COST_UNSPEC -1U #define OSPF_AREA_RANGE_COST_UNSPEC -1U

View File

@ -600,6 +600,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr)
!OSPF_IF_PARAM_CONFIGURED(oip, auth_type) && !OSPF_IF_PARAM_CONFIGURED(oip, auth_type) &&
!OSPF_IF_PARAM_CONFIGURED(oip, if_area) && !OSPF_IF_PARAM_CONFIGURED(oip, if_area) &&
!OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) && !OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) &&
!OSPF_IF_PARAM_CONFIGURED(oip, prefix_suppression) &&
listcount(oip->auth_crypt) == 0) { listcount(oip->auth_crypt) == 0) {
ospf_del_if_params(ifp, oip); ospf_del_if_params(ifp, oip);
rn->info = NULL; rn->info = NULL;
@ -709,6 +710,8 @@ int ospf_if_new_hook(struct interface *ifp)
SET_IF_PARAM(IF_DEF_PARAMS(ifp), opaque_capable); SET_IF_PARAM(IF_DEF_PARAMS(ifp), opaque_capable);
IF_DEF_PARAMS(ifp)->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT; IF_DEF_PARAMS(ifp)->opaque_capable = OSPF_OPAQUE_CAPABLE_DEFAULT;
IF_DEF_PARAMS(ifp)->prefix_suppression = OSPF_PREFIX_SUPPRESSION_DEFAULT;
rc = ospf_opaque_new_if(ifp); rc = ospf_opaque_new_if(ifp);
return rc; return rc;
} }

View File

@ -81,6 +81,9 @@ struct ospf_if_params {
/* Fast-Hellos */ /* Fast-Hellos */
DECLARE_IF_PARAM(uint8_t, fast_hello); DECLARE_IF_PARAM(uint8_t, fast_hello);
/* Prefix-Suppression */
DECLARE_IF_PARAM(bool, prefix_suppression);
/* Authentication data. */ /* Authentication data. */
uint8_t auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1]; /* Simple password. */ uint8_t auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1]; /* Simple password. */
uint8_t auth_simple__config : 1; uint8_t auth_simple__config : 1;

View File

@ -539,16 +539,23 @@ static int lsa_link_ptop_set(struct stream **s, struct ospf_interface *oi)
} }
/* no need for a stub link for unnumbered interfaces */ /* no need for a stub link for unnumbered interfaces */
if (oi->ptp_dmvpn if (OSPF_IF_PARAM(oi, prefix_suppression)) {
|| !CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug("LSA[Type1]: Interface %s stub link omitted due prefix-suppression",
oi->ifp->name);
} else {
if (oi->ptp_dmvpn ||
!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) {
/* Regardless of the state of the neighboring router, we must /* Regardless of the state of the neighboring router, we must
add a Type 3 link (stub network). add a Type 3 link (stub network).
N.B. Options 1 & 2 share basically the same logic. */ N.B. Options 1 & 2 share basically the same logic. */
masklen2ip(oi->address->prefixlen, &mask); masklen2ip(oi->address->prefixlen, &mask);
id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr id.s_addr =
& mask.s_addr; CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr &
links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, mask.s_addr;
oi->output_cost); links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB,
0, oi->output_cost);
}
} }
return links; return links;
@ -563,9 +570,14 @@ static int lsa_link_broadcast_set(struct stream **s, struct ospf_interface *oi)
/* Describe Type 3 Link. */ /* Describe Type 3 Link. */
if (oi->state == ISM_Waiting) { if (oi->state == ISM_Waiting) {
if (OSPF_IF_PARAM(oi, prefix_suppression)) {
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug( zlog_debug("LSA[Type1]: Interface %s stub link omitted due prefix-suppression",
"LSA[Type1]: Interface %s is in state Waiting. Adding stub interface", oi->ifp->name);
return 0;
}
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug("LSA[Type1]: Interface %s is in state Waiting. Adding stub interface",
oi->ifp->name); oi->ifp->name);
masklen2ip(oi->address->prefixlen, &mask); masklen2ip(oi->address->prefixlen, &mask);
id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
@ -587,9 +599,14 @@ static int lsa_link_broadcast_set(struct stream **s, struct ospf_interface *oi)
} }
/* Describe type 3 link. */ /* Describe type 3 link. */
else { else {
if (OSPF_IF_PARAM(oi, prefix_suppression)) {
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug( zlog_debug("LSA[Type1]: Interface %s stub link omitted due prefix-suppression",
"LSA[Type1]: Interface %s has no DR. Adding stub interface", oi->ifp->name);
return 0;
}
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug("LSA[Type1]: Interface %s has no DR. Adding stub interface",
oi->ifp->name); oi->ifp->name);
masklen2ip(oi->address->prefixlen, &mask); masklen2ip(oi->address->prefixlen, &mask);
id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
@ -603,7 +620,7 @@ static int lsa_link_loopback_set(struct stream **s, struct ospf_interface *oi)
struct in_addr id, mask; struct in_addr id, mask;
/* Describe Type 3 Link. */ /* Describe Type 3 Link. */
if (oi->state != ISM_Loopback) if ((oi->state != ISM_Loopback) || OSPF_IF_PARAM(oi, prefix_suppression))
return 0; return 0;
mask.s_addr = 0xffffffff; mask.s_addr = 0xffffffff;
@ -645,9 +662,15 @@ static int lsa_link_ptomp_set(struct stream **s, struct ospf_interface *oi)
struct in_addr id, mask; struct in_addr id, mask;
uint16_t cost = ospf_link_cost(oi); uint16_t cost = ospf_link_cost(oi);
if (OSPF_IF_PARAM(oi, prefix_suppression)) {
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug("LSA[Type1]: Interface %s stub link omitted due prefix-suppression",
oi->ifp->name);
} else {
mask.s_addr = 0xffffffff; mask.s_addr = 0xffffffff;
id.s_addr = oi->address->u.prefix4.s_addr; id.s_addr = oi->address->u.prefix4.s_addr;
links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, 0); links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, 0);
}
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE)) if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug("PointToMultipoint: running ptomultip_set"); zlog_debug("PointToMultipoint: running ptomultip_set");
@ -1006,7 +1029,14 @@ static void ospf_network_lsa_body_set(struct stream *s,
struct route_node *rn; struct route_node *rn;
struct ospf_neighbor *nbr; struct ospf_neighbor *nbr;
if (OSPF_IF_PARAM(oi, prefix_suppression)) {
mask.s_addr = 0xffffffff;
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug("LSA[Type2]: Interface %s network mask set to host mask due prefix-suppression",
oi->ifp->name);
} else {
masklen2ip(oi->address->prefixlen, &mask); masklen2ip(oi->address->prefixlen, &mask);
}
stream_put_ipv4(s, mask.s_addr); stream_put_ipv4(s, mask.s_addr);
/* The network-LSA lists those routers that are fully adjacent to /* The network-LSA lists those routers that are fully adjacent to

View File

@ -462,6 +462,12 @@ void ospf_intra_add_transit(struct route_table *rt, struct vertex *v,
the IP network number, which can be obtained by masking the the IP network number, which can be obtained by masking the
Vertex ID (Link State ID) with its associated subnet mask (found Vertex ID (Link State ID) with its associated subnet mask (found
in the body of the associated network-LSA). */ in the body of the associated network-LSA). */
if (lsa->mask.s_addr == 0xffffffff) {
if (IS_DEBUG_OSPF_EVENT)
zlog_debug("Suppress installing LSA[Type2,%pI4] route due to host mask",
&(lsa->header.id));
return;
}
p.family = AF_INET; p.family = AF_INET;
p.prefix = v->id; p.prefix = v->id;
p.prefixlen = ip_masklen(lsa->mask); p.prefixlen = ip_masklen(lsa->mask);

View File

@ -4076,6 +4076,20 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
ospf_interface_bfd_show(vty, ifp, json_interface_sub); ospf_interface_bfd_show(vty, ifp, json_interface_sub);
if (use_json) {
json_object_boolean_add(json_interface_sub,
"prefixSuppression",
OSPF_IF_PARAM(oi,
prefix_suppression));
json_object_boolean_add(json_oi, "prefixSuppression",
OSPF_IF_PARAM(oi,
prefix_suppression));
} else {
if (OSPF_IF_PARAM(oi, prefix_suppression))
vty_out(vty,
" Suppress advertisement of interface IP prefix\n");
}
/* OSPF Authentication information */ /* OSPF Authentication information */
ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); ospf_interface_auth_show(vty, oi, json_interface_sub, use_json);
@ -9865,6 +9879,56 @@ DEFPY(ip_ospf_capability_opaque, ip_ospf_capability_opaque_addr_cmd,
} }
DEFPY(ip_ospf_prefix_suppression, ip_ospf_prefix_suppression_addr_cmd,
"[no] ip ospf prefix-suppression [A.B.C.D]$ip_addr", NO_STR
"IP Information\n"
"OSPF interface commands\n"
"Supress OSPF prefix advertisement on this interface\n"
"Address of interface\n")
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct route_node *rn;
bool prefix_suppression_change;
struct ospf_if_params *params;
params = IF_DEF_PARAMS(ifp);
if (ip_addr.s_addr != INADDR_ANY) {
params = ospf_get_if_params(ifp, ip_addr);
ospf_if_update_params(ifp, ip_addr);
}
prefix_suppression_change = (params->prefix_suppression == (bool)no);
params->prefix_suppression = (no) ? false : true;
if (params->prefix_suppression != OSPF_PREFIX_SUPPRESSION_DEFAULT)
SET_IF_PARAM(params, prefix_suppression);
else {
UNSET_IF_PARAM(params, prefix_suppression);
if (params != IF_DEF_PARAMS(ifp)) {
ospf_free_if_params(ifp, ip_addr);
ospf_if_update_params(ifp, ip_addr);
}
}
/*
* If there is a change to the prefix suppression, update the Router-LSA.
*/
if (prefix_suppression_change) {
for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
struct ospf_interface *oi = rn->info;
if (oi && (oi->state > ISM_Down) &&
(ip_addr.s_addr == INADDR_ANY ||
IPV4_ADDR_SAME(&oi->address->u.prefix4, &ip_addr))) {
(void)ospf_router_lsa_update_area(oi->area);
if (oi->state == ISM_DR)
ospf_network_lsa_update(oi);
}
}
}
return CMD_SUCCESS;
}
DEFUN (ospf_max_metric_router_lsa_admin, DEFUN (ospf_max_metric_router_lsa_admin,
ospf_max_metric_router_lsa_admin_cmd, ospf_max_metric_router_lsa_admin_cmd,
"max-metric router-lsa administrative", "max-metric router-lsa administrative",
@ -12243,6 +12307,22 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
/* prefix-suppression print. */
if (OSPF_IF_PARAM_CONFIGURED(params,
prefix_suppression) &&
params->prefix_suppression !=
OSPF_PREFIX_SUPPRESSION_DEFAULT) {
if (params->prefix_suppression == false)
vty_out(vty,
" no ip ospf prefix-suppression");
else
vty_out(vty,
" ip ospf prefix-suppression");
if (params != IF_DEF_PARAMS(ifp) && rn)
vty_out(vty, " %pI4", &rn->p.u.prefix4);
vty_out(vty, "\n");
}
while (1) { while (1) {
if (rn == NULL) if (rn == NULL)
rn = route_top(IF_OIFS_PARAMS(ifp)); rn = route_top(IF_OIFS_PARAMS(ifp));
@ -13055,6 +13135,9 @@ static void ospf_vty_if_init(void)
/* "ip ospf capability opaque" commands. */ /* "ip ospf capability opaque" commands. */
install_element(INTERFACE_NODE, &ip_ospf_capability_opaque_addr_cmd); install_element(INTERFACE_NODE, &ip_ospf_capability_opaque_addr_cmd);
/* "ip ospf prefix-suppression" commands. */
install_element(INTERFACE_NODE, &ip_ospf_prefix_suppression_addr_cmd);
/* These commands are compatibitliy for previous version. */ /* These commands are compatibitliy for previous version. */
install_element(INTERFACE_NODE, &ospf_authentication_key_cmd); install_element(INTERFACE_NODE, &ospf_authentication_key_cmd);
install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd); install_element(INTERFACE_NODE, &ospf_message_digest_key_cmd);

View File

@ -0,0 +1,47 @@
!
hostname r1
password zebra
log file /tmp/r1-frr.log
ip forwarding
!
interface r1-eth0
ip address 10.1.1.1/24
ip ospf network broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
interface r1-eth1
ip address 10.1.2.1/24
ip ospf network non-broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
interface r1-eth2
ip address 10.1.3.1/24
ip ospf network point-to-point
ip ospf hello-interval 1
ip ospf dead-interval 30
!
interface r1-eth3
ip address 10.1.4.1/24
ip ospf network point-to-multipoint
ip ospf hello-interval 1
ip ospf dead-interval 30
!
interface r1-eth4
ip address 10.1.7.1/24
ip ospf network broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
router ospf
ospf router-id 1.1.1.1
distance 20
network 10.1.1.0/24 area 0
network 10.1.2.0/24 area 0
network 10.1.3.0/24 area 0
network 10.1.4.0/24 area 0
network 10.1.7.0/24 area 0
!

View File

@ -0,0 +1,57 @@
!
hostname r2
password zebra
log file /tmp/r1-frr.log
ip forwarding
!
interface r2-eth0
ip address 10.1.1.2/24
ip ospf network broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
interface r2-eth1
ip address 10.1.2.2/24
ip ospf network non-broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
interface r2-eth2
ip address 10.1.3.2/24
ip ospf network point-to-point
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
interface r2-eth3
ip address 10.1.4.2/24
ip ospf network point-to-multipoint
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
interface r2-eth4
ip address 10.1.5.2/24
ip ospf network broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
interface r2-eth5
ip address 10.1.6.2/24
ip ospf network broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
router ospf
ospf router-id 2.2.2.2
distance 20
network 10.1.1.0/24 area 0
network 10.1.2.0/24 area 0
network 10.1.3.0/24 area 0
network 10.1.4.0/24 area 0
network 10.1.5.0/24 area 0
network 10.1.6.0/24 area 1
!

View File

@ -0,0 +1,25 @@
!
hostname r3
password zebra
log file /tmp/r1-frr.log
ip forwarding
!
interface r3-eth0
ip address 10.1.5.3/24
ip ospf network broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
interface r3-eth1
ip address 10.1.6.3/24
ip ospf network broadcast
ip ospf hello-interval 1
ip ospf dead-interval 30
!
!
router ospf
ospf router-id 3.3.3.3
distance 20
network 10.1.5.0/24 area 0
network 10.1.6.0/24 area 1

View File

@ -0,0 +1,951 @@
#!/usr/bin/env python
# SPDX-License-Identifier: ISC
#
# test_ospf_prefix_suppression.py
#
# Copyright (c) 2023 LabN Consulting
# Acee Lindem
#
import os
import sys
import json
from time import sleep
from functools import partial
import pytest
# 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
from lib.common_config import (
run_frr_cmd,
shutdown_bringup_interface,
start_router_daemons,
step,
)
"""
test_ospf_metric_propagation.py: Test OSPF/BGP metric propagation
"""
TOPOLOGY = """
+-----+ +-----+ +-----+
eth4 | | eth0 | | eth4 eth0 | |
------+ +-------------+ +--------------+ |
10.1.7.0/24 | | 10.1.1.0/24 | | 10.1.5.0/24 | |
| | | |.2 .3| |
| | eth1 | | | |
| +-------------+ | | |
| R1 | 10.1.2.0/24 | R2 | | R3 |
| | | | | |
| | eth2 | | | |
| +-------------+ | | |
| | 10.1.3.0/24 | | | |
| | | | | |
| | eth3 | | eth5 eth1 | |
| +-------------+ +--------------+ |
| | 10.1.4.0/24 | | 10.1.6.0/24 | |
.1 +-----+.1 .2+-----+.2 .3+-----+
"""
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# Required to instantiate the topology builder class.
pytestmark = [pytest.mark.ospfd, pytest.mark.bgpd]
def build_topo(tgen):
"Build function"
# Create 3 routers
tgen.add_router("r1")
tgen.add_router("r2")
tgen.add_router("r3")
# Interconect router 1, 2 (0)
switch = tgen.add_switch("s1-1-2")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
# Interconect router 1, 2 (1)
switch = tgen.add_switch("s2-1-2")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
# Interconect router 1, 2 (2)
switch = tgen.add_switch("s3-1-2")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
# Interconect router 1, 2 (3)
switch = tgen.add_switch("s4-1-2")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
# Interconect router 2, 3 (0)
switch = tgen.add_switch("s5-2-3")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
# Interconect router 2, 3 (1)
switch = tgen.add_switch("s6-2-3")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
# Add standalone network to router 1
switch = tgen.add_switch("s7-1")
switch.add_link(tgen.gears["r1"])
def setup_module(mod):
logger.info("OSPF Prefix Suppression:\n {}".format(TOPOLOGY))
tgen = Topogen(build_topo, mod.__name__)
tgen.start_topology()
# Starting Routers
router_list = tgen.routers()
for rname, router in router_list.items():
logger.info("Loading router %s" % rname)
router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
# Initialize all routers.
tgen.start_router()
def teardown_module(mod):
"Teardown the pytest environment"
tgen = get_topogen()
tgen.stop_topology()
def test_all_routes_advertised():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")
# Verify OSPF routes are installed
r3 = tgen.gears["r3"]
input_dict = {
"10.1.1.0/24": [
{
"prefix": "10.1.1.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.1.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.1.0/24 not installed on router r3"
assert result is None, assertmsg
input_dict = {
"10.1.2.0/24": [
{
"prefix": "10.1.2.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.2.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.2.0/24 not installed on router r3"
assert result is None, assertmsg
input_dict = {
"10.1.3.0/24": [
{
"prefix": "10.1.3.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.3.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.3.0/24 not installed on router r3"
assert result is None, assertmsg
input_dict = {
"10.1.4.1/32": [
{
"prefix": "10.1.4.1/32",
"prefixLen": 32,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.4.1/32 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.4.1/32 not installed on router r3"
assert result is None, assertmsg
input_dict = {
"10.1.4.2/32": [
{
"prefix": "10.1.4.2/32",
"prefixLen": 32,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.4.2/32 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.4.2/32 not installed on router r3"
assert result is None, assertmsg
input_dict = {
"10.1.7.0/24": [
{
"prefix": "10.1.7.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.7.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.7.0/24 not installed on router r3"
assert result is None, assertmsg
input_dict = {}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.8.0/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.8.0/24 installed on router r3"
assert result is None, assertmsg
def test_broadcast_stub_suppression():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")
step("Configure R1 interface r1-eth4 with prefix suppression")
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth4\nip ospf prefix-suppression")
step("Verify the R1 configuration of 'ip ospf prefix-suppression'")
prefix_suppression_cfg = (
tgen.net["r1"]
.cmd('vtysh -c "show running ospfd" | grep "^ ip ospf prefix-suppression"')
.rstrip()
)
assertmsg = "'ip ospf prefix-suppression' applied, but not present in configuration"
assert prefix_suppression_cfg == " ip ospf prefix-suppression", assertmsg
step("Verify that ospf-prefix suppression is applied to the R1 interface")
r1_eth4_with_prefix_suppression = {
"interfaces": {
"r1-eth4": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.7.1",
"ospfIfType": "Broadcast",
"prefixSuppression": True,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth4 json",
r1_eth4_with_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "R1 OSPF interface r1-eth4 doesn't have prefix-suppression enabled"
assert result is None, assertmsg
step(
"Verify that ospf-prefix suppression is applied to the R1 interface (non-JSON)"
)
prefix_suppression_show = (
tgen.net["r1"]
.cmd(
'vtysh -c "show ip ospf interface r1-eth4" | grep "^ Suppress advertisement of interface IP prefix"'
)
.rstrip()
)
assertmsg = (
"'ip ospf prefix-suppression' applied, but not present in interface show"
)
assert (
prefix_suppression_show == " Suppress advertisement of interface IP prefix"
), assertmsg
step("Verify the ospf prefix is not advertised and not present on r3")
r3 = tgen.gears["r3"]
input_dict = {}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.7.0/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.7.0/24 installed on router r3"
assert result is None, assertmsg
step("Remove R1 interface r1-eth4 prefix-suppression configuration")
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth4\nno ip ospf prefix-suppression")
step("Verify no R1 configuration of 'ip ospf prefix-suppression")
rc, _, _ = tgen.net["r1"].cmd_status(
"show running ospfd | grep -q 'ip ospf prefix-suppression'", warn=False
)
assertmsg = (
"'ip ospf prefix-suppression' not applied, but present in R1 configuration"
)
assert rc, assertmsg
step("Verify that ospf-prefix suppression is not applied to the R1 interface")
r1_eth4_without_prefix_suppression = {
"interfaces": {
"r1-eth4": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.7.1",
"ospfIfType": "Broadcast",
"prefixSuppression": False,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth4 json",
r1_eth4_without_prefix_suppression,
)
step("Verify that 10.1.7.0/24 route is now installed on R3")
input_dict = {
"10.1.7.0/24": [
{
"prefix": "10.1.7.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.7.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.7.0/24 not installed on router r3"
assert result is None, assertmsg
def test_broadcast_transit_suppression():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")
step(
"Configure R1 interface r1-eth0 with prefix suppression using interface address"
)
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf prefix-suppression 10.1.1.1")
step("Verify the R1 configuration of 'ip ospf prefix-suppression 10.1.1.1'")
prefix_suppression_cfg = (
tgen.net["r1"]
.cmd(
'vtysh -c "show running ospfd" | grep "^ ip ospf prefix-suppression 10.1.1.1"'
)
.rstrip()
)
assertmsg = "'ip ospf prefix-suppression 10.1.1.1' applied, but not present in configuration"
assert prefix_suppression_cfg == " ip ospf prefix-suppression 10.1.1.1", assertmsg
step(
"Configure R2 interface r2-eth0 with prefix suppression using interface address"
)
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth0\nip ospf prefix-suppression 10.1.1.2")
step("Verify that ospf-prefix suppression is applied to the R1 interface")
r1_eth0_with_prefix_suppression = {
"interfaces": {
"r1-eth0": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.1.1",
"ospfIfType": "Broadcast",
"networkType": "BROADCAST",
"prefixSuppression": True,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth0 json",
r1_eth0_with_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "R1 OSPF interface r1-eth0 doesn't have prefix-suppression enabled"
assert result is None, assertmsg
step("Verify the OSPF prefix is not advertised and not present on r3")
r3 = tgen.gears["r3"]
input_dict = {}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.1.0/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.1.0/24 installed on router r3"
assert result is None, assertmsg
step("Verify the OSPF Network-LSA prefixes are also not present on R3 ")
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.1.1/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.1.1/24 installed on router r3"
assert result is None, assertmsg
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.1.2/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.1.2/24 installed on router r3"
assert result is None, assertmsg
step(
"Remove R1 interface r1-eth0 prefix-suppression configuration using interface address"
)
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth0\nno ip ospf prefix-suppression 10.1.1.1")
step(
"Remove R2 interface r2-eth0 prefix-suppression configuration using interface address"
)
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth0\nno ip ospf prefix-suppression 10.1.1.2")
step("Verify no R1 configuration of 'ip ospf prefix-suppression")
rc, _, _ = tgen.net["r1"].cmd_status(
"show running ospfd | grep -q 'ip ospf prefix-suppression 10.1.1.1'", warn=False
)
assertmsg = "'ip ospf prefix-suppression 10.1.1.1' not applied, but present in R1 configuration"
assert rc, assertmsg
step("Verify that ospf-prefix suppression is not applied to the R1 interface")
r1_eth0_without_prefix_suppression = {
"interfaces": {
"r1-eth0": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.1.1",
"ospfIfType": "Broadcast",
"networkType": "BROADCAST",
"prefixSuppression": False,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth0 json",
r1_eth0_without_prefix_suppression,
)
step("Verify that 10.1.1.0/24 route is now installed on R3")
input_dict = {
"10.1.1.0/24": [
{
"prefix": "10.1.1.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.1.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.1.0/24 not installed on router r3"
assert result is None, assertmsg
def test_nbma_transit_suppression():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")
step("Configure R1 interface r1-eth1 with prefix suppression")
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth1\nip ospf prefix-suppression")
step("Configure R2 interface r2-eth1 with prefix suppression")
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth1\nip ospf prefix-suppression")
step("Verify that ospf-prefix suppression is applied to the R1 interface")
r1_eth1_with_prefix_suppression = {
"interfaces": {
"r1-eth1": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.2.1",
"ospfIfType": "Broadcast",
"networkType": "NBMA",
"prefixSuppression": True,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth1 json",
r1_eth1_with_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "R1 OSPF interface r1-eth1 doesn't have prefix-suppression enabled"
assert result is None, assertmsg
step("Verify the OSPF prefix is not advertised and not present on r3")
r3 = tgen.gears["r3"]
input_dict = {}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.2.0/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.2.0/24 installed on router r3"
assert result is None, assertmsg
step("Verify the OSPF Network-LSA prefixes are also not present on R3 ")
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.2.1/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.2.1/24 installed on router r3"
assert result is None, assertmsg
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.2.2/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.2.2/24 installed on router r3"
assert result is None, assertmsg
step("Remove R1 interface r1-eth1 prefix-suppression configuration")
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth1\nno ip ospf prefix-suppression")
step("Remove R2 interface eth1 prefix-suppression configuration")
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth1\nno ip ospf prefix-suppression")
step("Verify no R1 configuration of 'ip ospf prefix-suppression")
rc, _, _ = tgen.net["r1"].cmd_status(
"show running ospfd | grep -q 'ip ospf prefix-suppression'", warn=False
)
assertmsg = (
"'ip ospf prefix-suppression' not applied, but present in R1 configuration"
)
assert rc, assertmsg
step("Verify that ospf-prefix suppression is not applied to the R1 interface")
r1_eth1_without_prefix_suppression = {
"interfaces": {
"r1-eth1": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.2.1",
"ospfIfType": "Broadcast",
"networkType": "NBMA",
"prefixSuppression": False,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth1 json",
r1_eth1_without_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "Prefix suppression on interface r1-eth1"
assert result is None, assertmsg
step("Verify that 10.1.2.0/24 route is now installed on R3")
input_dict = {
"10.1.2.0/24": [
{
"prefix": "10.1.2.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.2.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.2.0/24 not installed on router r3"
assert result is None, assertmsg
def test_p2p_suppression():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")
step(
"Configure R1 interface r1-eth2 with prefix suppression with interface address"
)
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth2\nip ospf prefix-suppression 10.1.3.1")
step(
"Configure R2 interface r2-eth1 with prefix suppression with interface address"
)
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth2\nip ospf prefix-suppression 10.1.3.2")
step("Verify the R1 configuration of 'ip ospf prefix-suppression 10.1.3.1'")
prefix_suppression_cfg = (
tgen.net["r1"]
.cmd(
'vtysh -c "show running ospfd" | grep "^ ip ospf prefix-suppression 10.1.3.1"'
)
.rstrip()
)
assertmsg = "'ip ospf prefix-suppression 10.1.3.1' applied, but not present in configuration"
assert prefix_suppression_cfg == " ip ospf prefix-suppression 10.1.3.1", assertmsg
step("Verify that ospf-prefix suppression is applied to the R1 interface")
r1_eth2_with_prefix_suppression = {
"interfaces": {
"r1-eth2": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.3.1",
"ospfIfType": "Broadcast",
"networkType": "POINTOPOINT",
"prefixSuppression": True,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth2 json",
r1_eth2_with_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "R1 OSPF interface r1-eth2 doesn't have prefix-suppression enabled"
assert result is None, assertmsg
step("Verify the OSPF prefix is not advertised and not present on r3")
r3 = tgen.gears["r3"]
input_dict = {}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.3.0/24 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.3.0/24 installed on router r3"
assert result is None, assertmsg
step(
"Remove R1 interface r1-eth2 prefix-suppression configuration using interface address"
)
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth2\nno ip ospf prefix-suppression 10.1.3.1")
step(
"Remove R2 interface r2-eth2 prefix-suppression configuration using interface address"
)
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth2\nno ip ospf prefix-suppression 10.1.3.2")
step("Verify no R1 configuration of 'ip ospf prefix-suppression")
rc, _, _ = tgen.net["r1"].cmd_status(
"show running ospfd | grep -q 'ip ospf prefix-suppression 10.1.3.1'", warn=False
)
assertmsg = "'ip ospf prefix-suppressio 10.1.3.1' not applied, but present in R1 configuration"
assert rc, assertmsg
step("Verify that ospf-prefix suppression is not applied to the R1 interface")
r1_eth2_without_prefix_suppression = {
"interfaces": {
"r1-eth2": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.3.1",
"ospfIfType": "Broadcast",
"networkType": "POINTOPOINT",
"prefixSuppression": False,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth2 json",
r1_eth2_without_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "Prefix suppression on interface r1-eth2"
assert result is None, assertmsg
step("Verify that 10.1.3.0/24 route is now installed on R3")
input_dict = {
"10.1.3.0/24": [
{
"prefix": "10.1.3.0/24",
"prefixLen": 24,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.3.0/24 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.3.0/24 not installed on router r3"
assert result is None, assertmsg
def test_p2mp_suppression():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip("Skipped because of router(s) failure")
step("Configure R1 interface r1-eth3 with prefix suppression")
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth3\nip ospf prefix-suppression")
step("Configure R2 interface r2-eth3 with prefix suppression")
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth3\nip ospf prefix-suppression")
step("Verify that ospf-prefix suppression is applied to the R1 interface")
r1_eth3_with_prefix_suppression = {
"interfaces": {
"r1-eth3": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.4.1",
"ospfIfType": "Broadcast",
"networkType": "POINTOMULTIPOINT",
"prefixSuppression": True,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth3 json",
r1_eth3_with_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "R1 OSPF interface r1-eth3 doesn't have prefix-suppression enabled"
assert result is None, assertmsg
step("Verify the OSPF P2MP prefixes are not advertised and not present on r3")
r3 = tgen.gears["r3"]
input_dict = {}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.4.1/32 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.4.1/32 installed on router r3"
assert result is None, assertmsg
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.4.2/32 json", input_dict, True
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.4.2/32 installed on router r3"
assert result is None, assertmsg
step("Remove R1 interface r1-eth3 prefix-suppression configuration")
r1 = tgen.gears["r1"]
r1.vtysh_cmd("conf t\ninterface r1-eth3\nno ip ospf prefix-suppression")
step("Remove R2 interface r2-eth3 prefix-suppression configuration")
r2 = tgen.gears["r2"]
r2.vtysh_cmd("conf t\ninterface r2-eth3\nno ip ospf prefix-suppression")
step("Verify no R1 configuration of 'ip ospf prefix-suppression")
rc, _, _ = tgen.net["r1"].cmd_status(
"show running ospfd | grep -q 'ip ospf prefix-suppression'", warn=False
)
assertmsg = (
"'ip ospf prefix-suppression' not applied, but present in R1 configuration"
)
assert rc, assertmsg
step("Verify that ospf-prefix suppression is not applied to the R1 interface")
r1_eth3_without_prefix_suppression = {
"interfaces": {
"r1-eth3": {
"ifUp": True,
"ospfEnabled": True,
"ipAddress": "10.1.4.1",
"ospfIfType": "Broadcast",
"networkType": "POINTOMULTIPOINT",
"prefixSuppression": False,
}
}
}
test_func = partial(
topotest.router_json_cmp,
r1,
"show ip ospf interface r1-eth3 json",
r1_eth3_without_prefix_suppression,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "Prefix suppression on interface r1-eth3"
assert result is None, assertmsg
step("Verify that 10.1.4.1/32 route is now installed on R3")
input_dict = {
"10.1.4.1/32": [
{
"prefix": "10.1.4.1/32",
"prefixLen": 32,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.4.1/32 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.4.1/32 not installed on router r3"
assert result is None, assertmsg
step("Verify that 10.1.4.2/32 route is now installed on R3")
input_dict = {
"10.1.4.2/32": [
{
"prefix": "10.1.4.2/32",
"prefixLen": 32,
"protocol": "ospf",
"nexthops": [
{
"ip": "10.1.5.2",
"interfaceName": "r3-eth0",
}
],
}
]
}
test_func = partial(
topotest.router_json_cmp, r3, "show ip route 10.1.4.2/32 json", input_dict
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "10.1.4.2/32 not installed on router r3"
assert result is None, assertmsg
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))