Skip to content

Commit

Permalink
Merge pull request #15783 from LabNConsulting/aceelindem/ospf-neighbo…
Browse files Browse the repository at this point in the history
…r-filter

ospfd: Add prefix-list filtering of OSPF neighbors on OSPF interface
  • Loading branch information
ton31337 authored Apr 24, 2024
2 parents ebe31e1 + 0ccad8a commit 0d0350a
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 14 deletions.
26 changes: 26 additions & 0 deletions doc/user/ospfd.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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))


Expand Down
34 changes: 33 additions & 1 deletion ospfd/ospf_interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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();

Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions ospfd/ospf_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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. */
Expand Down
15 changes: 15 additions & 0 deletions ospfd/ospf_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#endif
#include "vrf.h"
#include "lib_errors.h"
#include "plist.h"

#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
Expand Down Expand Up @@ -2746,6 +2747,20 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf)
/* associate packet with ospf interface */
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.
Expand Down
89 changes: 89 additions & 0 deletions ospfd/ospf_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
}
}

Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
Expand Down
14 changes: 14 additions & 0 deletions ospfd/ospf_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit 0d0350a

Please sign in to comment.