summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_route.c4
-rw-r--r--bgpd/bgp_snmp_bgp4.c4
-rw-r--r--doc/user/ospfd.rst26
-rw-r--r--nhrpd/nhrp_nhs.c12
-rw-r--r--ospfd/ospf_interface.c34
-rw-r--r--ospfd/ospf_interface.h7
-rw-r--r--ospfd/ospf_packet.c15
-rw-r--r--ospfd/ospf_snmp.c26
-rw-r--r--ospfd/ospf_vty.c89
-rw-r--r--ospfd/ospf_zebra.c14
-rw-r--r--tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py152
11 files changed, 351 insertions, 32 deletions
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 848e8ffd8d..3feb2717d1 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -7138,6 +7138,10 @@ int bgp_static_set(struct vty *vty, bool negate, const char *ip_str,
bgp_static->label = label;
bgp_static->prd = prd;
+ if (rd_str)
+ bgp_static->prd_pretty = XSTRDUP(MTYPE_BGP,
+ rd_str);
+
if (rmap) {
XFREE(MTYPE_ROUTE_MAP_NAME,
bgp_static->rmap.name);
diff --git a/bgpd/bgp_snmp_bgp4.c b/bgpd/bgp_snmp_bgp4.c
index 3d04dc2ece..755777c167 100644
--- a/bgpd/bgp_snmp_bgp4.c
+++ b/bgpd/bgp_snmp_bgp4.c
@@ -401,7 +401,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
/* Set OID offset for prefix. */
offset = name + v->namelen;
oid2in_addr(offset, IN_ADDR_SIZE, &addr->prefix);
- offset++;
+ offset += IN_ADDR_SIZE;
/* Prefix length. */
addr->prefixlen = *offset;
@@ -497,7 +497,7 @@ static struct bgp_path_info *bgp4PathAttrLookup(struct variable *v, oid name[],
offset = name + v->namelen;
oid_copy_in_addr(offset, &rn_p->u.prefix4);
- offset++;
+ offset += IN_ADDR_SIZE;
*offset = rn_p->prefixlen;
offset++;
oid_copy_in_addr(offset,
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 47f8fad17b..5652e34a43 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -757,6 +757,32 @@ Interfaces
optional IPv4 address is specified, the prefix suppression will apply
to the OSPF interface associated with the specified interface address.
+.. clicmd:: ip ospf neighbor-filter NAME [A.B.C.D]
+
+ Configure an IP prefix-list to use to filter packets received from
+ OSPF neighbors on the OSPF interface. The prefix-list should include rules
+ to permit or deny OSPF neighbors by IP source address. This is useful for
+ multi-access interfaces where adjacencies with only a subset of the
+ reachable neighbors are desired. Applications include testing partially
+ meshed topologies, OSPF Denial of Sevice (DoS) mitigation, and avoidance
+ of adjacencies with OSPF neighbors not meeting traffic engineering criteria.
+
+ Example:
+
+.. code-block:: frr
+
+ !
+ ! Prefix-list to block neighbor with source address 10.1.0.2
+ !
+ ip prefix-list nbr-filter seq 10 deny 10.1.0.2/32
+ ip prefix-list nbr-filter seq 200 permit any
+ !
+ ! Configure the neighbor filter prefix-list on interface eth0
+ !
+ interface eth0
+ ip ospf neighbor-filter nbr-filter
+ !
+
.. clicmd:: ip ospf area (A.B.C.D|(0-4294967295))
diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c
index acd3b7df97..f779f93486 100644
--- a/nhrpd/nhrp_nhs.c
+++ b/nhrpd/nhrp_nhs.c
@@ -169,9 +169,15 @@ static void nhrp_reg_send_req(struct event *t)
struct nhrp_cie_header *cie;
if (!nhrp_peer_check(r->peer, 2)) {
- debugf(NHRP_DEBUG_COMMON, "NHS: Waiting link for %pSU",
- &r->peer->vc->remote.nbma);
- event_add_timer(master, nhrp_reg_send_req, r, 120,
+ int renewtime = if_ad->holdtime / 4;
+ /* RFC 2332 5.2.0.1 says "a retry is sent after an appropriate
+ * interval." Using holdtime/4, to be shorter than
+ * recommended renew time (holdtime/3), see RFC2332 Sec 5.2.3
+ */
+ debugf(NHRP_DEBUG_COMMON,
+ "NHS: Waiting link for %pSU, retrying in %d seconds",
+ &r->peer->vc->remote.nbma, renewtime);
+ event_add_timer(master, nhrp_reg_send_req, r, renewtime,
&r->t_register);
return;
}
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 319db1efe2..0b27501019 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -19,6 +19,7 @@
#include "zclient.h"
#include "bfd.h"
#include "ldp_sync.h"
+#include "plist.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_bfd.h"
@@ -67,6 +68,34 @@ int ospf_interface_neighbor_count(struct ospf_interface *oi)
return count;
}
+
+void ospf_intf_neighbor_filter_apply(struct ospf_interface *oi)
+{
+ struct route_node *rn;
+ struct ospf_neighbor *nbr = NULL;
+ struct prefix nbr_src_prefix = { AF_INET, IPV4_MAX_BITLEN, { 0 } };
+
+ if (!oi->nbr_filter)
+ return;
+
+ /*
+ * Kill neighbors that don't match the neighbor filter prefix-list
+ * excluding the neighbor for the router itself and any neighbors
+ * that are already down.
+ */
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+ if (nbr && nbr != oi->nbr_self && nbr->state != NSM_Down) {
+ nbr_src_prefix.u.prefix4 = nbr->src;
+ if (prefix_list_apply(oi->nbr_filter,
+ (struct prefix *)&(
+ nbr_src_prefix)) !=
+ PREFIX_PERMIT)
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+ }
+ }
+}
+
int ospf_if_get_output_cost(struct ospf_interface *oi)
{
/* If all else fails, use default OSPF cost */
@@ -526,6 +555,7 @@ static struct ospf_if_params *ospf_new_if_params(void)
UNSET_IF_PARAM(oip, if_area);
UNSET_IF_PARAM(oip, opaque_capable);
UNSET_IF_PARAM(oip, keychain_name);
+ UNSET_IF_PARAM(oip, nbr_filter_name);
oip->auth_crypt = list_new();
@@ -544,6 +574,7 @@ static void ospf_del_if_params(struct interface *ifp,
{
list_delete(&oip->auth_crypt);
XFREE(MTYPE_OSPF_IF_PARAMS, oip->keychain_name);
+ XFREE(MTYPE_OSPF_IF_PARAMS, oip->nbr_filter_name);
ospf_interface_disable_bfd(ifp, oip);
ldp_sync_info_free(&(oip->ldp_sync_info));
XFREE(MTYPE_OSPF_IF_PARAMS, oip);
@@ -579,7 +610,8 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr)
!OSPF_IF_PARAM_CONFIGURED(oip, if_area) &&
!OSPF_IF_PARAM_CONFIGURED(oip, opaque_capable) &&
!OSPF_IF_PARAM_CONFIGURED(oip, prefix_suppression) &&
- !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) &&
+ !OSPF_IF_PARAM_CONFIGURED(oip, keychain_name) &&
+ !OSPF_IF_PARAM_CONFIGURED(oip, nbr_filter_name) &&
listcount(oip->auth_crypt) == 0) {
ospf_del_if_params(ifp, oip);
rn->info = NULL;
diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h
index 721ab1a9d7..2e53fbfbfa 100644
--- a/ospfd/ospf_interface.h
+++ b/ospfd/ospf_interface.h
@@ -124,6 +124,9 @@ struct ospf_if_params {
/* Opaque LSA capability at interface level (see RFC5250) */
DECLARE_IF_PARAM(bool, opaque_capable);
+
+ /* Name of prefix-list name for packet source address filtering. */
+ DECLARE_IF_PARAM(char *, nbr_filter_name);
};
enum { MEMBER_ALLROUTERS = 0,
@@ -242,6 +245,9 @@ struct ospf_interface {
/* List of configured NBMA neighbor. */
struct list *nbr_nbma;
+ /* Configured prefix-list for filtering neighbors. */
+ struct prefix_list *nbr_filter;
+
/* Graceful-Restart data. */
struct {
struct {
@@ -367,6 +373,7 @@ extern void ospf_crypt_key_add(struct list *list, struct crypt_key *key);
extern int ospf_crypt_key_delete(struct list *list, uint8_t key_id);
extern uint8_t ospf_default_iftype(struct interface *ifp);
extern int ospf_interface_neighbor_count(struct ospf_interface *oi);
+extern void ospf_intf_neighbor_filter_apply(struct ospf_interface *oi);
/* Set all multicast memberships appropriately based on the type and
state of the interface. */
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 60479ddcd1..87aaccad92 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -23,6 +23,7 @@
#endif
#include "vrf.h"
#include "lib_errors.h"
+#include "plist.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@@ -2747,6 +2748,20 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
oi = ospf_if_lookup_recv_if(ospf, iph->ip_src, ifp);
/*
+ * If a neighbor filter prefix-list is configured, apply it to the IP
+ * source address and ignore the packet if it doesn't match.
+ */
+ if (oi && oi->nbr_filter) {
+ struct prefix ip_src_prefix = { AF_INET, IPV4_MAX_BITLEN, { 0 } };
+
+ ip_src_prefix.u.prefix4 = iph->ip_src;
+ if (prefix_list_apply(oi->nbr_filter,
+ (struct prefix *)&(ip_src_prefix)) !=
+ PREFIX_PERMIT)
+ return OSPF_READ_CONTINUE;
+ }
+
+ /*
* ospf_verify_header() relies on a valid "oi" and thus can be called
* only after the passive/backbone/other checks below are passed.
* These checks in turn access the fields of unverified "ospfh"
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
index fc0c143c28..4e1f15361e 100644
--- a/ospfd/ospf_snmp.c
+++ b/ospfd/ospf_snmp.c
@@ -906,7 +906,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name,
area = ospf_area_lookup_by_area_id(ospf, *area_id);
if (!area)
return NULL;
- offset++;
+ offset += IN_ADDR_SIZE;
/* Type. */
*type = *offset;
@@ -914,7 +914,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name,
/* LS ID. */
oid2in_addr(offset, IN_ADDR_SIZE, ls_id);
- offset++;
+ offset += IN_ADDR_SIZE;
/* Router ID. */
oid2in_addr(offset, IN_ADDR_SIZE, router_id);
@@ -971,7 +971,7 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name,
}
/* Router ID. */
- offset++;
+ offset += IN_ADDR_SIZE;
offsetlen -= IN_ADDR_SIZE;
len = offsetlen;
@@ -996,11 +996,11 @@ static struct ospf_lsa *ospfLsdbLookup(struct variable *v, oid *name,
/* Fill in value. */
offset = name + v->namelen;
oid_copy_in_addr(offset, area_id);
- offset++;
+ offset += IN_ADDR_SIZE;
*offset = lsa->data->type;
offset++;
oid_copy_in_addr(offset, &lsa->data->id);
- offset++;
+ offset += IN_ADDR_SIZE;
oid_copy_in_addr(offset,
&lsa->data->adv_router);
@@ -1106,7 +1106,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v,
if (!area)
return NULL;
- offset++;
+ offset += IN_ADDR_SIZE;
/* Lookup area range. */
oid2in_addr(offset, IN_ADDR_SIZE, range_net);
@@ -1135,7 +1135,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v,
return NULL;
do {
- offset++;
+ offset += IN_ADDR_SIZE;
offsetlen -= IN_ADDR_SIZE;
len = offsetlen;
@@ -1157,7 +1157,7 @@ static struct ospf_area_range *ospfAreaRangeLookup(struct variable *v,
/* Fill in value. */
offset = name + v->namelen;
oid_copy_in_addr(offset, area_id);
- offset++;
+ offset += IN_ADDR_SIZE;
oid_copy_in_addr(offset, range_net);
return range;
@@ -1559,7 +1559,7 @@ static struct ospf_interface *ospfIfLookup(struct variable *v, oid *name,
*length = v->namelen + IN_ADDR_SIZE + 1;
offset = name + v->namelen;
oid_copy_in_addr(offset, ifaddr);
- offset++;
+ offset += IN_ADDR_SIZE;
*offset = *ifindex;
return oi;
}
@@ -1703,7 +1703,7 @@ static struct ospf_interface *ospfIfMetricLookup(struct variable *v, oid *name,
*length = v->namelen + IN_ADDR_SIZE + 1 + 1;
offset = name + v->namelen;
oid_copy_in_addr(offset, ifaddr);
- offset++;
+ offset += IN_ADDR_SIZE;
*offset = *ifindex;
offset++;
*offset = OSPF_SNMP_METRIC_VALUE;
@@ -2241,7 +2241,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name,
/* LS ID. */
oid2in_addr(offset, IN_ADDR_SIZE, ls_id);
- offset++;
+ offset += IN_ADDR_SIZE;
/* Router ID. */
oid2in_addr(offset, IN_ADDR_SIZE, router_id);
@@ -2269,7 +2269,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name,
oid2in_addr(offset, len, ls_id);
- offset++;
+ offset += IN_ADDR_SIZE;
offsetlen -= IN_ADDR_SIZE;
/* Router ID. */
@@ -2292,7 +2292,7 @@ static struct ospf_lsa *ospfExtLsdbLookup(struct variable *v, oid *name,
*offset = OSPF_AS_EXTERNAL_LSA;
offset++;
oid_copy_in_addr(offset, &lsa->data->id);
- offset++;
+ offset += IN_ADDR_SIZE;
oid_copy_in_addr(offset, &lsa->data->adv_router);
return lsa;
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 4980cd3eca..e2f4f64d81 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -4085,6 +4085,31 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf,
if (use_json)
json_object_object_addf(json_ois, json_oi, "%pI4",
&oi->address->u.prefix4);
+
+ if (oi->nbr_filter) {
+ if (use_json) {
+ json_object_string_add(json_interface_sub,
+ "nbrFilterPrefixList",
+ prefix_list_name(
+ oi->nbr_filter));
+ json_object_string_add(json_oi,
+ "nbrFilterPrefixList",
+ prefix_list_name(
+ oi->nbr_filter));
+ } else
+ vty_out(vty,
+ " Neighbor filter prefix-list: %s\n",
+ prefix_list_name(oi->nbr_filter));
+ } else {
+ if (use_json) {
+ json_object_string_add(json_interface_sub,
+ "nbrFilterPrefixList",
+ "N/A");
+ json_object_string_add(json_oi,
+ "nbrFilterPrefixList",
+ "N/A");
+ }
+ }
}
}
@@ -9937,6 +9962,58 @@ DEFPY(ip_ospf_prefix_suppression, ip_ospf_prefix_suppression_addr_cmd,
return CMD_SUCCESS;
}
+DEFPY(ip_ospf_neighbor_filter, ip_ospf_neighbor_filter_addr_cmd,
+ "[no] ip ospf neighbor-filter ![PREFIXLIST4_NAME]$prefix_list [A.B.C.D]$ip_addr", NO_STR
+ "IP Information\n"
+ "OSPF interface commands\n"
+ "Filter OSPF neighbor packets\n"
+ "Prefix-List used for filtering\n"
+ "Address of interface\n")
+{
+ VTY_DECLVAR_CONTEXT(interface, ifp);
+ struct ospf_if_params *params;
+ struct prefix_list *nbr_filter = NULL;
+ struct route_node *rn;
+
+ 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);
+ }
+
+ if (params->nbr_filter_name)
+ XFREE(MTYPE_OSPF_IF_PARAMS, params->nbr_filter_name);
+
+ if (no) {
+ UNSET_IF_PARAM(params, nbr_filter_name);
+ params->nbr_filter_name = NULL;
+ } else {
+ SET_IF_PARAM(params, nbr_filter_name);
+ params->nbr_filter_name = XSTRDUP(MTYPE_OSPF_IF_PARAMS,
+ prefix_list);
+ nbr_filter = prefix_list_lookup(AFI_IP, params->nbr_filter_name);
+ }
+
+ /*
+ * Determine if there is a change in neighbor filter prefix-list for the
+ * interface.
+ */
+ for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
+ struct ospf_interface *oi = rn->info;
+
+ if (oi &&
+ (ip_addr.s_addr == INADDR_ANY ||
+ IPV4_ADDR_SAME(&oi->address->u.prefix4, &ip_addr)) &&
+ oi->nbr_filter != nbr_filter) {
+ oi->nbr_filter = nbr_filter;
+ if (oi->nbr_filter)
+ ospf_intf_neighbor_filter_apply(oi);
+ }
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (ospf_max_metric_router_lsa_admin,
ospf_max_metric_router_lsa_admin_cmd,
"max-metric router-lsa administrative",
@@ -12360,6 +12437,15 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf)
vty_out(vty, "\n");
}
+ /* neighbor-filter print. */
+ if (OSPF_IF_PARAM_CONFIGURED(params, nbr_filter_name)) {
+ vty_out(vty, " ip ospf neighbor-filter %s",
+ params->nbr_filter_name);
+ 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));
@@ -13176,6 +13262,9 @@ static void ospf_vty_if_init(void)
/* "ip ospf prefix-suppression" commands. */
install_element(INTERFACE_NODE, &ip_ospf_prefix_suppression_addr_cmd);
+ /* "ip ospf neighbor-filter" commands. */
+ install_element(INTERFACE_NODE, &ip_ospf_neighbor_filter_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);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index bb6cc3a89c..2c518f2c9e 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -1769,6 +1769,7 @@ static void ospf_prefix_list_update(struct prefix_list *plist)
int type;
int abr_inv = 0;
struct ospf_area *area;
+ struct ospf_interface *oi;
struct listnode *node, *n1;
/* If OSPF instatnce does not exist, return right now. */
@@ -1824,6 +1825,19 @@ static void ospf_prefix_list_update(struct prefix_list *plist)
}
}
+ /* Update interface neighbor-filter lists. */
+ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+ if (OSPF_IF_PARAM(oi, nbr_filter_name) &&
+ strcmp(OSPF_IF_PARAM(oi, nbr_filter_name),
+ prefix_list_name(plist)) == 0) {
+ oi->nbr_filter = prefix_list_lookup(
+ AFI_IP,
+ OSPF_IF_PARAM(oi, nbr_filter_name));
+ if (oi->nbr_filter)
+ ospf_intf_neighbor_filter_apply(oi);
+ }
+ }
+
/* Schedule ABR task. */
if (IS_OSPF_ABR(ospf) && abr_inv)
ospf_schedule_abr_task(ospf);
diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
index 352180b7ce..1f0f87959a 100644
--- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
+++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py
@@ -118,17 +118,21 @@ def teardown_module(mod):
tgen.stop_topology()
-def verify_p2mp_interface(tgen):
+def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter):
"Verify the P2MP Configuration and interface settings"
- r1 = tgen.gears["r1"]
+ topo_router = tgen.gears[router]
step("Test running configuration for P2MP configuration")
rc = 0
- rc, _, _ = tgen.net["r1"].cmd_status(
+ rc, _, _ = tgen.net[router].cmd_status(
"show running ospfd | grep 'ip ospf network point-to-multipoint'", warn=False
)
- assertmsg = "'ip ospf network point-to-multipoint' applied, but not present in r1 configuration"
+ assertmsg = (
+ "'ip ospf network point-to-multipoint' applied, but not present in "
+ + router
+ + "configuration"
+ )
assert rc, assertmsg
step("Test OSPF interface for P2MP settings")
@@ -145,11 +149,11 @@ def verify_p2mp_interface(tgen):
"networkType": "POINTOMULTIPOINT",
"cost": 10,
"state": "Point-To-Point",
- "nbrCount": 3,
- "nbrAdjacentCount": 3,
+ "nbrCount": nbr_cnt,
+ "nbrAdjacentCount": nbr_adj_cnt,
"prefixSuppression": False,
"p2mpDelayReflood": False,
- "p2mpNonBroadcast": False,
+ "nbrFilterPrefixList": nbr_filter,
}
},
"ipAddress": "10.1.0.1",
@@ -161,16 +165,19 @@ def verify_p2mp_interface(tgen):
"cost": 10,
"state": "Point-To-Point",
"opaqueCapable": True,
- "nbrCount": 3,
- "nbrAdjacentCount": 3,
+ "nbrCount": nbr_cnt,
+ "nbrAdjacentCount": nbr_adj_cnt,
"prefixSuppression": False,
"p2mpDelayReflood": False,
- "p2mpNonBroadcast": False,
+ "nbrFilterPrefixList": nbr_filter,
}
}
}
test_func = partial(
- topotest.router_json_cmp, r1, "show ip ospf interface r1-eth0 json", input_dict
+ topotest.router_json_cmp,
+ topo_router,
+ "show ip ospf interface r1-eth0 json",
+ input_dict,
)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
assertmsg = "P2MP Interface Mismatch on router r1"
@@ -251,6 +258,23 @@ def verify_p2mp_neighbor(tgen, router, neighbor, state, intf_addr, interface):
assert result is None, assertmsg
+def verify_p2mp_neighbor_missing(tgen, router, neighbor):
+ topo_router = tgen.gears[router]
+
+ step("Verify neighbor " + neighbor + " missing")
+ input_dict = {"default": {}}
+ test_func = partial(
+ topotest.router_json_cmp,
+ topo_router,
+ "show ip ospf neighbor " + neighbor + " json",
+ input_dict,
+ True, # Require exact match for missing neighbor
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assertmsg = "P2MP Neighbor " + neighbor + " not missing"
+ assert result is None, assertmsg
+
+
def verify_p2mp_route(tgen, router, prefix, prefix_len, nexthop, interface):
topo_router = tgen.gears[router]
@@ -288,7 +312,7 @@ def test_p2mp_broadcast_interface():
pytest.skip("Skipped because of router(s) failure")
step("Verify router r1 interface r1-eth0 p2mp configuration")
- verify_p2mp_interface(tgen)
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
step("Verify router r1 p2mp interface r1-eth0 neighbors")
verify_p2mp_neighbor(
@@ -313,7 +337,7 @@ def test_p2mp_broadcast_interface():
step("Verify router r1 interface r1-eth0 p2mp configuration application")
r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint")
- verify_p2mp_interface(tgen)
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
step("Verify restablishment of r1-eth0 p2mp neighbors")
verify_p2mp_neighbor(
@@ -332,6 +356,108 @@ def test_p2mp_broadcast_interface():
verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0")
+def test_p2mp_broadcast_neighbor_filter():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip("Skipped because of router(s) failure")
+
+ step("Verify router r1 interface r1-eth0 p2mp configuration")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+ step("Verify router r1 p2mp interface r1-eth0 neighbors")
+ verify_p2mp_neighbor(
+ tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1"
+ )
+ verify_p2mp_neighbor(
+ tgen, "r1", "3.3.3.3", "Full/DROther", "10.1.0.3", "r1-eth0:10.1.0.1"
+ )
+ verify_p2mp_neighbor(
+ tgen, "r1", "4.4.4.4", "Full/DROther", "10.1.0.4", "r1-eth0:10.1.0.1"
+ )
+
+ step("Add OSPF interface neighbor-filter to r1")
+ r1 = tgen.gears["r1"]
+ r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter")
+
+ step("Verify the R1 configuration of 'ip ospf neighbor-filter nbr-filter'")
+ neighbor_filter_cfg = (
+ tgen.net["r1"]
+ .cmd(
+ 'vtysh -c "show running ospfd" | grep "^ ip ospf neighbor-filter nbr-filter"'
+ )
+ .rstrip()
+ )
+ assertmsg = (
+ "'ip ospf neighbor-filter nbr-filter' applied, but not present in configuration"
+ )
+ assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg
+
+ step("Verify non-existent neighbor-filter is not applied to r1 interfaces")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+ step("Add nbr-filter prefix-list configuration to r1")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any")
+
+ step(
+ "Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent"
+ )
+ verify_p2mp_interface(tgen, "r1", 3, 3, "nbr-filter")
+
+ step("Add nbr-filter prefix-list configuration to block r4")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32")
+
+ step(
+ "Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent"
+ )
+ verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter")
+ verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4")
+
+ step("Verify route to r4 subnet is now through r2")
+ verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.2", "r1-eth0")
+
+ step("Add nbr-filter prefix-list configuration to block r2")
+ r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32")
+
+ step(
+ "Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent"
+ )
+ verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter")
+ verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2")
+
+ step("Verify route to r4 and r2 subnet are now through r3")
+ verify_p2mp_route(tgen, "r1", "10.1.2.0/24", 24, "10.1.0.3", "r1-eth0")
+ verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.3", "r1-eth0")
+
+ step("Remove neighbor filter configuration and verify")
+ r1.vtysh_cmd("conf t\ninterface r1-eth0\nno ip ospf neighbor-filter")
+ rc, _, _ = tgen.net["r1"].cmd_status(
+ "show running ospfd | grep -q 'ip ospf neighbor-filter'", warn=False
+ )
+ assertmsg = "'ip ospf neighbor' not applied, but present in R1 configuration"
+ assert rc, assertmsg
+
+ step("Verify interface neighbor-filter is removed and neighbors present")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+ step("Add neighbor filter configuration and verify neighbors are filtered")
+ r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter")
+ verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2")
+ verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4")
+
+ step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor")
+ r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20")
+ verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter")
+ verify_p2mp_neighbor(
+ tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1"
+ )
+
+ step("Delete nbr-filter prefix-list and verify neighbors are present")
+ r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter")
+ verify_p2mp_interface(tgen, "r1", 3, 3, "N/A")
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()