Skip to content

Commit

Permalink
pimd: MSDP SA filtering
Browse files Browse the repository at this point in the history
Implement MSDP peer incoming/outgoing SA filter.

Note
----

  Cisco extended access list has a special meaning: the first address is
  the source address to filter.

Example:

  ! The rules below filter some LAN prefix to be leaked out
  access-list filter-lan-source deny ip 192.168.0.0 0.0.255.255 224.0.0.0 0.255.255.255
  access-list filter-lan-source permit any
  ip msdp peer 192.168.0.1 sa-filter filter-lan-source out

  ! The rules below filter some special management group from being
  ! learned
  access-list filter-management-group deny 230.0.0.0 0.255.255.255
  access-list filter-management-group permit any
  ip msdp peer 192.168.0.1 sa-filter filter-management-group in

Signed-off-by: Rafael Zalamena <[email protected]>
  • Loading branch information
rzalamena committed Jun 6, 2024
1 parent 2db4136 commit 0c015af
Show file tree
Hide file tree
Showing 8 changed files with 345 additions and 24 deletions.
81 changes: 81 additions & 0 deletions pimd/pim_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -5134,6 +5134,83 @@ DEFUN (no_ip_msdp_peer,
return nb_cli_apply_changes(vty, NULL);
}

DEFPY(ip_msdp_peer_sa_filter, ip_msdp_peer_sa_filter_cmd,
"ip msdp peer A.B.C.D$peer sa-filter ACL_NAME$acl_name <in|out>$dir",
IP_STR
CFG_MSDP_STR
"Configure MSDP peer\n"
"MSDP Peer address\n"
"SA access-list filter\n"
"SA access-list name\n"
"Filter incoming SAs\n"
"Filter outgoing SAs\n")
{
const struct lyd_node *peer_node;
const char *vrfname;
char xpath[XPATH_MAXLEN];

vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;

snprintf(xpath, sizeof(xpath),
FRR_PIM_VRF_XPATH "/msdp-peer[peer-ip='%s']", "frr-pim:pimd",
"pim", vrfname, "frr-routing:ipv4", peer_str);
peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath);
if (peer_node == NULL) {
vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str);
return CMD_SUCCESS;
}

if (strcmp(dir, "in") == 0)
nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_MODIFY,
acl_name);
else
nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_MODIFY,
acl_name);

return nb_cli_apply_changes(vty, "%s", xpath);
}

DEFPY(no_ip_msdp_peer_sa_filter, no_ip_msdp_peer_sa_filter_cmd,
"no ip msdp peer A.B.C.D$peer sa-filter ACL_NAME <in|out>$dir",
NO_STR
IP_STR
CFG_MSDP_STR
"Configure MSDP peer\n"
"MSDP Peer address\n"
"SA access-list filter\n"
"SA access-list name\n"
"Filter incoming SAs\n"
"Filter outgoing SAs\n")
{
const struct lyd_node *peer_node;
const char *vrfname;
char xpath[XPATH_MAXLEN];

vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;

snprintf(xpath, sizeof(xpath),
FRR_PIM_VRF_XPATH "/msdp-peer[peer-ip='%s']", "frr-pim:pimd",
"pim", vrfname, "frr-routing:ipv4", peer_str);
peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath);
if (peer_node == NULL) {
vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str);
return CMD_SUCCESS;
}

if (strcmp(dir, "in") == 0)
nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_DESTROY,
NULL);
else
nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_DESTROY,
NULL);

return nb_cli_apply_changes(vty, "%s", xpath);
}

DEFPY(ip_msdp_mesh_group_member,
ip_msdp_mesh_group_member_cmd,
"ip msdp mesh-group WORD$gname member A.B.C.D$maddr",
Expand Down Expand Up @@ -6475,6 +6552,10 @@ void pim_cmd_init(void)
install_element(VRF_NODE, &ip_msdp_peer_cmd);
install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd);
install_element(VRF_NODE, &no_ip_msdp_peer_cmd);
install_element(CONFIG_NODE, &ip_msdp_peer_sa_filter_cmd);
install_element(VRF_NODE, &ip_msdp_peer_sa_filter_cmd);
install_element(CONFIG_NODE, &no_ip_msdp_peer_sa_filter_cmd);
install_element(VRF_NODE, &no_ip_msdp_peer_sa_filter_cmd);
install_element(CONFIG_NODE, &ip_pim_ecmp_cmd);
install_element(VRF_NODE, &ip_pim_ecmp_cmd);
install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd);
Expand Down
9 changes: 9 additions & 0 deletions pimd/pim_msdp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1321,6 +1321,15 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim,

vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces,
&mp->peer, &mp->local);

if (mp->acl_in)
vty_out(vty, "%sip msdp peer %pI4 sa-filter %s in\n",
spaces, &mp->peer, mp->acl_in);

if (mp->acl_out)
vty_out(vty, "%sip msdp peer %pI4 sa-filter %s out\n",
spaces, &mp->peer, mp->acl_out);

written = true;
}

Expand Down
5 changes: 5 additions & 0 deletions pimd/pim_msdp.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ struct pim_msdp_peer {

/* timestamps */
int64_t uptime;

/** SA input access list name. */
char *acl_in;
/** SA output access list name. */
char *acl_out;
};

struct pim_msdp_mg_mbr {
Expand Down
166 changes: 142 additions & 24 deletions pimd/pim_msdp_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
#include <zebra.h>

#include <lib/log.h>
#include <lib/filter.h>
#include <lib/network.h>
#include <lib/prefix.h>
#include <lib/stream.h>
#include "frrevent.h"
#include <lib/vty.h>
Expand Down Expand Up @@ -322,8 +324,8 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
pim_msdp_pkt_send(mp, s);
}

static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
struct pim_msdp_peer *mp)
static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
struct pim_msdp_peer *mp)
{
struct stream *s;

Expand All @@ -338,25 +340,6 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
}
}

/* push the stream into the obuf fifo of all the peers */
static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
struct pim_msdp_peer *mp)
{
struct listnode *mpnode;

if (mp) {
pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
} else {
for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
mp->key_str);
}
pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
}
}
}

static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
struct in_addr rp)
{
Expand Down Expand Up @@ -384,6 +367,91 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
}

static bool msdp_cisco_match(const struct filter *filter,
const struct in_addr *source,
const struct in_addr *group)
{
const struct filter_cisco *cfilter = &filter->u.cfilter;
uint32_t source_addr;
uint32_t group_addr;

group_addr = group->s_addr & ~cfilter->mask_mask.s_addr;

if (cfilter->extended) {
source_addr = source->s_addr & ~cfilter->addr_mask.s_addr;
if (group_addr == cfilter->mask.s_addr &&
source_addr == cfilter->addr.s_addr)
return true;
} else if (group_addr == cfilter->addr.s_addr)
return true;

return false;
}

static enum filter_type msdp_access_list_apply(struct access_list *access,
const struct in_addr *source,
const struct in_addr *group)
{
struct filter *filter;
struct prefix group_prefix;

if (access == NULL)
return FILTER_DENY;

for (filter = access->head; filter; filter = filter->next) {
if (filter->cisco) {
if (msdp_cisco_match(filter, source, group))
return filter->type;
} else {
group_prefix.family = AF_INET;
group_prefix.prefixlen = IPV4_MAX_BITLEN;
group_prefix.u.prefix4.s_addr = group->s_addr;
if (access_list_apply(access, &group_prefix))
return filter->type;
}
}

return FILTER_DENY;
}

bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp,
const struct pim_msdp_sa *sa)
{
struct access_list *acl;

/* No output filter configured, just quit. */
if (mp->acl_out == NULL)
return false;

/* Find access list and test it. */
acl = access_list_lookup(AFI_IP, mp->acl_out);
if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) ==
FILTER_DENY)
return true;

return false;
}

/** Count the number of SAs to be sent for a specific peer. */
static size_t pim_msdp_peer_sa_count(const struct pim_instance *pim,
const struct pim_msdp_peer *peer)
{
const struct pim_msdp_sa *sa;
const struct listnode *node;
size_t sa_count = 0;

for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, node, sa)) {
if (!CHECK_FLAG(sa->flags, PIM_MSDP_SAF_LOCAL))
continue;
if (msdp_peer_sa_filter(peer, sa))
continue;

sa_count++;
}

return sa_count;
}

static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
struct pim_msdp_peer *mp)
{
Expand All @@ -393,7 +461,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
struct prefix group_all;
struct in_addr rp;
int sa_count;
int local_cnt = pim->msdp.local_cnt;
int local_cnt = pim_msdp_peer_sa_count(pim, mp);

sa_count = 0;
if (PIM_DEBUG_MSDP_INTERNAL) {
Expand All @@ -418,6 +486,15 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
* peers */
continue;
}

if (msdp_peer_sa_filter(mp, sa)) {
if (PIM_DEBUG_MSDP_EVENTS)
zlog_debug("MSDP peer %pI4 filter SA out %s",
&mp->peer, sa->sg_str);

continue;
}

/* add sa into scratch pad */
pim_msdp_pkt_sa_fill_one(sa);
++sa_count;
Expand Down Expand Up @@ -457,15 +534,32 @@ static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)

void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
{
pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
struct pim_msdp_peer *mp;
struct listnode *node;

for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp))
pim_msdp_pkt_sa_gen(pim, mp);

pim_msdp_pkt_sa_tx_done(pim);
}

void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
{
struct pim_msdp_peer *mp;
struct listnode *node;

pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
pim_msdp_pkt_sa_fill_one(sa);
pim_msdp_pkt_sa_push(sa->pim, NULL);
for (ALL_LIST_ELEMENTS_RO(sa->pim->msdp.peer_list, node, mp)) {
if (msdp_peer_sa_filter(mp, sa)) {
if (PIM_DEBUG_MSDP_EVENTS)
zlog_debug("MSDP peer %pI4 filter SA out %s",
&mp->peer, sa->sg_str);
continue;
}

pim_msdp_pkt_sa_push(sa->pim, mp);
}
pim_msdp_pkt_sa_tx_done(sa->pim);
}

Expand All @@ -487,6 +581,15 @@ void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
/* Fills the message contents. */
sa.pim = mp->pim;
sa.sg = sg;

/* Don't push it if filtered. */
if (msdp_peer_sa_filter(mp, &sa)) {
if (PIM_DEBUG_MSDP_EVENTS)
zlog_debug("MSDP peer %pI4 filter SA out (%pI4, %pI4)",
&mp->peer, &sa.sg.src, &sa.sg.grp);
return;
}

pim_msdp_pkt_sa_fill_one(&sa);

/* Pushes the message. */
Expand All @@ -511,6 +614,7 @@ static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)

static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
{
struct access_list *acl;
int prefix_len;
pim_sgaddr sg;
struct listnode *peer_node;
Expand All @@ -534,6 +638,20 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
if (PIM_DEBUG_MSDP_PACKETS) {
zlog_debug(" sg %pSG", &sg);
}

/* Filter incoming SA with configured access list. */
if (mp->acl_in) {
acl = access_list_lookup(AFI_IP, mp->acl_in);
if (msdp_access_list_apply(acl, &sg.src, &sg.grp) ==
FILTER_DENY) {
if (PIM_DEBUG_MSDP_EVENTS)
zlog_debug(
"MSDP peer %pI4 filter SA in (%pI4, %pI4)",
&mp->peer, &sg.src, &sg.grp);
return;
}
}

pim_msdp_sa_ref(mp->pim, mp, &sg, rp);

/* Forwards the SA to the peers that are not in the RPF to the RP nor in
Expand Down
2 changes: 2 additions & 0 deletions pimd/pim_msdp_packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,5 +57,7 @@ void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa);
void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp);
void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
struct in_addr rp, pim_sgaddr sg);
bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp,
const struct pim_msdp_sa *sa);

#endif
14 changes: 14 additions & 0 deletions pimd/pim_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,20 @@ const struct frr_yang_module_info frr_pim_info = {
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in",
.cbs = {
.modify = pim_msdp_peer_sa_filter_in_modify,
.destroy = pim_msdp_peer_sa_filter_in_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out",
.cbs = {
.modify = pim_msdp_peer_sa_filter_out_modify,
.destroy = pim_msdp_peer_sa_filter_out_destroy,
}
},
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag",
.cbs = {
Expand Down
Loading

0 comments on commit 0c015af

Please sign in to comment.