Merge pull request #14034 from LabNConsulting/aceelindem/ospf_prefix_suppression

ospfd: Implement OSPF prefix-suppression as specified in RFC 6860
This commit is contained in:
Donatas Abraitis 2023-07-21 10:14:22 +03:00 committed by GitHub
commit 3a58764e3a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
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
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))

View file

@ -70,7 +70,7 @@ extern "C" {
#define OSPF_FAST_HELLO_DEFAULT 0
#define OSPF_P2MP_DELAY_REFLOOD_DEFAULT false
#define OSPF_OPAQUE_CAPABLE_DEFAULT true
#define OSPF_PREFIX_SUPPRESSION_DEFAULT false
#define OSPF_AREA_BACKBONE 0x00000000 /* 0.0.0.0 */
#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, if_area) &&
!OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) &&
!OSPF_IF_PARAM_CONFIGURED(oip, prefix_suppression) &&
listcount(oip->auth_crypt) == 0) {
ospf_del_if_params(ifp, oip);
rn->info = NULL;
@ -709,6 +710,8 @@ int ospf_if_new_hook(struct interface *ifp)
SET_IF_PARAM(IF_DEF_PARAMS(ifp), opaque_capable);
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);
return rc;
}

View file

@ -81,6 +81,9 @@ struct ospf_if_params {
/* Fast-Hellos */
DECLARE_IF_PARAM(uint8_t, fast_hello);
/* Prefix-Suppression */
DECLARE_IF_PARAM(bool, prefix_suppression);
/* Authentication data. */
uint8_t auth_simple[OSPF_AUTH_SIMPLE_SIZE + 1]; /* Simple password. */
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 */
if (oi->ptp_dmvpn
|| !CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) {
/* Regardless of the state of the neighboring router, we must
add a Type 3 link (stub network).
N.B. Options 1 & 2 share basically the same logic. */
masklen2ip(oi->address->prefixlen, &mask);
id.s_addr = CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr
& mask.s_addr;
links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0,
oi->output_cost);
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 {
if (oi->ptp_dmvpn ||
!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) {
/* Regardless of the state of the neighboring router, we must
add a Type 3 link (stub network).
N.B. Options 1 & 2 share basically the same logic. */
masklen2ip(oi->address->prefixlen, &mask);
id.s_addr =
CONNECTED_PREFIX(oi->connected)->u.prefix4.s_addr &
mask.s_addr;
links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB,
0, oi->output_cost);
}
}
return links;
@ -563,10 +570,15 @@ static int lsa_link_broadcast_set(struct stream **s, struct ospf_interface *oi)
/* Describe Type 3 Link. */
if (oi->state == ISM_Waiting) {
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);
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);
zlog_debug("LSA[Type1]: Interface %s is in state Waiting. Adding stub interface",
oi->ifp->name);
masklen2ip(oi->address->prefixlen, &mask);
id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
return link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0,
@ -587,10 +599,15 @@ static int lsa_link_broadcast_set(struct stream **s, struct ospf_interface *oi)
}
/* Describe type 3 link. */
else {
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);
return 0;
}
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
zlog_debug(
"LSA[Type1]: Interface %s has no DR. Adding stub interface",
oi->ifp->name);
zlog_debug("LSA[Type1]: Interface %s has no DR. Adding stub interface",
oi->ifp->name);
masklen2ip(oi->address->prefixlen, &mask);
id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
return link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0,
@ -603,7 +620,7 @@ static int lsa_link_loopback_set(struct stream **s, struct ospf_interface *oi)
struct in_addr id, mask;
/* Describe Type 3 Link. */
if (oi->state != ISM_Loopback)
if ((oi->state != ISM_Loopback) || OSPF_IF_PARAM(oi, prefix_suppression))
return 0;
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;
uint16_t cost = ospf_link_cost(oi);
mask.s_addr = 0xffffffff;
id.s_addr = oi->address->u.prefix4.s_addr;
links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, 0);
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;
id.s_addr = oi->address->u.prefix4.s_addr;
links += link_info_set(s, id, mask, LSA_LINK_TYPE_STUB, 0, 0);
}
if (IS_DEBUG_OSPF(lsa, LSA_GENERATE))
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 ospf_neighbor *nbr;
masklen2ip(oi->address->prefixlen, &mask);
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);
}
stream_put_ipv4(s, mask.s_addr);
/* The network-LSA lists those routers that are fully adjacent to

View file

@ -463,6 +463,12 @@ void ospf_intra_add_transit(struct route_table *rt, struct vertex *v,
the IP network number, which can be obtained by masking the
Vertex ID (Link State ID) with its associated subnet mask (found
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.prefix = v->id;
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);
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_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,
ospf_max_metric_router_lsa_admin_cmd,
"max-metric router-lsa administrative",
@ -12285,6 +12349,22 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
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) {
if (rn == NULL)
rn = route_top(IF_OIFS_PARAMS(ifp));
@ -13097,6 +13177,9 @@ static void ospf_vty_if_init(void)
/* "ip ospf capability opaque" commands. */
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. */
install_element(INTERFACE_NODE, &ospf_authentication_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))