#include "zclient.h"
#include "bfd.h"
#include "ldp_sync.h"
+#include "plist.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_bfd.h"
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 */
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();
{
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);
!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;
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");
+ }
+ }
}
}
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",
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));
/* "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);
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")
"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",
"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"
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]
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(
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(
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()