diff options
author | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2021-05-03 15:25:52 +0200 |
---|---|---|
committer | Rafael Zalamena <rzalamena@opensourcerouting.org> | 2024-07-27 16:32:30 +0200 |
commit | be3bfe5daa721acc0182d6c3f003a9d9d80e6612 (patch) | |
tree | 036568b0964c5ca419c5c22b6a74442c008eb094 /pimd | |
parent | yang: MSDP SA filtering support (diff) | |
download | frr-be3bfe5daa721acc0182d6c3f003a9d9d80e6612.tar.xz frr-be3bfe5daa721acc0182d6c3f003a9d9d80e6612.zip |
pimd: MSDP SA filtering
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
router pim
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
router pim
msdp peer 192.168.0.1 sa-filter filter-management-group in
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
Diffstat (limited to 'pimd')
-rw-r--r-- | pimd/pim_cmd.c | 65 | ||||
-rw-r--r-- | pimd/pim_msdp.c | 9 | ||||
-rw-r--r-- | pimd/pim_msdp.h | 5 | ||||
-rw-r--r-- | pimd/pim_msdp_packet.c | 164 | ||||
-rw-r--r-- | pimd/pim_msdp_packet.h | 2 | ||||
-rw-r--r-- | pimd/pim_nb.c | 14 | ||||
-rw-r--r-- | pimd/pim_nb.h | 4 | ||||
-rw-r--r-- | pimd/pim_nb_config.c | 88 |
8 files changed, 327 insertions, 24 deletions
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 92214eced..1e3e09086 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -6486,6 +6486,69 @@ DEFPY_ATTR(no_ip_pim_msdp_peer, return ret; } +DEFPY(msdp_peer_sa_filter, msdp_peer_sa_filter_cmd, + "msdp peer A.B.C.D$peer sa-filter ACL_NAME$acl_name <in|out>$dir", + 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; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, 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_msdp_peer_sa_filter, no_ip_msdp_peer_sa_filter_cmd, + "no msdp peer A.B.C.D$peer sa-filter ACL_NAME <in|out>$dir", + NO_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; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, 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(pim_msdp_mesh_group_member, pim_msdp_mesh_group_member_cmd, "msdp mesh-group WORD$gname member A.B.C.D$maddr", @@ -8259,6 +8322,8 @@ void pim_cmd_init(void) install_element(PIM_NODE, &no_pim_msdp_peer_cmd); install_element(PIM_NODE, &pim_msdp_timers_cmd); install_element(PIM_NODE, &no_pim_msdp_timers_cmd); + install_element(PIM_NODE, &msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &no_ip_msdp_peer_sa_filter_cmd); install_element(PIM_NODE, &pim_msdp_mesh_group_member_cmd); install_element(PIM_NODE, &no_pim_msdp_mesh_group_member_cmd); install_element(PIM_NODE, &pim_msdp_mesh_group_source_cmd); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index 3393cebdd..0bb2d93a3 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1317,6 +1317,15 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, &mp->local); + + if (mp->acl_in) + vty_out(vty, " msdp peer %pI4 sa-filter %s in\n", + &mp->peer, mp->acl_in); + + if (mp->acl_out) + vty_out(vty, " msdp peer %pI4 sa-filter %s out\n", + &mp->peer, mp->acl_out); + written = true; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index 80ca003dc..a45726cb8 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -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 { diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index 4324a96be..27f4966a1 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -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> @@ -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; @@ -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) { @@ -384,6 +367,90 @@ 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) { @@ -393,7 +460,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) { @@ -418,6 +485,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; @@ -457,15 +533,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); } @@ -487,6 +580,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. */ @@ -511,6 +613,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; @@ -534,6 +637,19 @@ 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 diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index 1584a2453..3af8d9368 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -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 diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 339935f81..6f4e32522 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -164,6 +164,20 @@ const struct frr_yang_module_info frr_pim_info = { } }, { + .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 = { .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create, diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 2d854d73d..56153bafb 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -65,6 +65,10 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify( struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index be0be8588..49bd9a5ce 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1287,6 +1287,94 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms #endif /* PIM_IPV != 6 */ /* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in + */ +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + mp->acl_in = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out + */ +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + mp->acl_out = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + break; + } + + return NB_OK; +} + +/* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag */ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( |