diff options
| author | Acee Lindem <acee@lindem.com> | 2024-04-17 20:14:56 +0000 | 
|---|---|---|
| committer | Acee Lindem <acee@lindem.com> | 2024-04-18 15:32:58 +0000 | 
| commit | 0ccad8a2b0b744d7ed64f53ab6e70a8d6aba69e6 (patch) | |
| tree | fce17b663806106750689e00ba161c42dd53b6fd /ospfd | |
| parent | 84d1fb19e22a5f0d13d3bbb7c74e9948773e66f3 (diff) | |
ospfd: Add prefix-list filtering of OSPF neighbors on OSPF interface
This commit adds the capabiity to filter OSPF neighbors using a
prefix-list with rules matching the neighbor's IP source address.
Configuration, filtering, immediate neighbor pruning, topo-tests,
and documentation are included. The command is:
     ip ospf neighbor-filter <prefix-list> [A.B.C.D]
Signed-off-by: Acee Lindem <acee@lindem.com>
Diffstat (limited to 'ospfd')
| -rw-r--r-- | ospfd/ospf_interface.c | 34 | ||||
| -rw-r--r-- | ospfd/ospf_interface.h | 7 | ||||
| -rw-r--r-- | ospfd/ospf_packet.c | 15 | ||||
| -rw-r--r-- | ospfd/ospf_vty.c | 89 | ||||
| -rw-r--r-- | ospfd/ospf_zebra.c | 14 | 
5 files changed, 158 insertions, 1 deletions
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_vty.c b/ospfd/ospf_vty.c index b366b3ca30..ea483f72f5 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -4084,6 +4084,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"); +			} +		}  	}  } @@ -9936,6 +9961,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", @@ -12359,6 +12436,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)); @@ -13175,6 +13261,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);  | 
