summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilippe Guibert <philippe.guibert@6wind.com>2025-02-14 09:24:20 +0100
committerPhilippe Guibert <philippe.guibert@6wind.com>2025-02-27 22:25:52 +0100
commitc3084cacf4816cd0bba5ad8695bbf3365500563f (patch)
tree340705e796e9794324e8132024ee33006504b90c
parente27631e10ae0f45ccada53e556c6c1331dbadd19 (diff)
bgpd: add 'match extcommunity-count' command to restrict comm count
Add a mechanism in route-map to filter out route-map which have a list of extended communities greater than the given number. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
-rw-r--r--bgpd/bgp_routemap.c82
-rw-r--r--bgpd/bgp_routemap_nb.c7
-rw-r--r--bgpd/bgp_routemap_nb.h4
-rw-r--r--bgpd/bgp_routemap_nb_config.c51
-rw-r--r--doc/user/bgp.rst7
-rw-r--r--lib/routemap.h1
-rw-r--r--lib/routemap_cli.c4
-rw-r--r--yang/frr-bgp-route-map.yang17
8 files changed, 173 insertions, 0 deletions
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index fa8701dc50..17b1ba730d 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -1358,6 +1358,65 @@ static const struct route_map_rule_cmd route_match_community_limit_cmd = {
route_match_community_limit_compile, route_match_community_limit_free
};
+/* `match extcommunity-limit' */
+
+/* Match function should return :
+ * - RMAP_MATCH if the bgp update extcommunity list count
+ * is less or equal to the configured limit.
+ * - RMAP_NOMATCH if the extcommunity list count is greater than the
+ * configured limit.
+ */
+static enum route_map_cmd_result_t
+route_match_extcommunity_limit(void *rule, const struct prefix *prefix, void *object)
+{
+ struct bgp_path_info *path = NULL;
+ struct ecommunity *piextcomm = NULL, *pi6extcomm = NULL;
+ uint16_t count = 0;
+ uint16_t *limit_rule = rule;
+
+ path = (struct bgp_path_info *)object;
+
+ piextcomm = bgp_attr_get_ecommunity(path->attr);
+ if (piextcomm)
+ count = piextcomm->size;
+
+ pi6extcomm = bgp_attr_get_ipv6_ecommunity(path->attr);
+ if (pi6extcomm)
+ count += pi6extcomm->size;
+
+ if (count <= *limit_rule)
+ return RMAP_MATCH;
+
+ return RMAP_NOMATCH;
+}
+
+/* Route map `extcommunity-limit' match statement. */
+static void *route_match_extcommunity_limit_compile(const char *arg)
+{
+ uint16_t *limit = NULL;
+ char *end = NULL;
+
+ limit = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint16_t));
+ *limit = strtoul(arg, &end, 10);
+ if (*end != '\0') {
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, limit);
+ return NULL;
+ }
+ return limit;
+}
+
+/* Free route map's compiled `community-limit' value. */
+static void route_match_extcommunity_limit_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Route map commands for community limit matching. */
+static const struct route_map_rule_cmd route_match_extcommunity_limit_cmd = {
+ "extcommunity-limit", route_match_extcommunity_limit,
+ route_match_extcommunity_limit_compile, route_match_extcommunity_limit_free
+};
+
static enum route_map_cmd_result_t
route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
{
@@ -5885,6 +5944,27 @@ DEFPY_YANG (match_ecommunity,
}
+DEFPY_YANG(
+ match_extcommunity_limit, match_extcommunity_limit_cmd,
+ "[no$no] match extcommunity-limit ![(0-65535)$limit]",
+ NO_STR
+ MATCH_STR
+ "Match BGP extended community limit\n"
+ "Extended community limit number\n")
+{
+ const char *xpath =
+ "./match-condition[condition='frr-bgp-route-map:match-extcommunity-limit']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, no ? NB_OP_DESTROY : NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-match-condition/frr-bgp-route-map:extcommunity-limit", xpath);
+
+ nb_cli_enqueue_change(vty, xpath_value, no ? NB_OP_DESTROY : NB_OP_MODIFY, limit_str);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+
DEFUN_YANG (no_match_ecommunity,
no_match_ecommunity_cmd,
"no match extcommunity [<(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME>]",
@@ -7980,6 +8060,7 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_evpn_route_type_cmd);
route_map_install_match(&route_match_evpn_rd_cmd);
route_map_install_match(&route_match_community_limit_cmd);
+ route_map_install_match(&route_match_extcommunity_limit_cmd);
route_map_install_match(&route_match_evpn_default_route_cmd);
route_map_install_match(&route_match_vrl_source_vrf_cmd);
@@ -8053,6 +8134,7 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &match_community_cmd);
install_element(RMAP_NODE, &no_match_community_cmd);
install_element(RMAP_NODE, &match_community_limit_cmd);
+ install_element(RMAP_NODE, &match_extcommunity_limit_cmd);
install_element(RMAP_NODE, &match_lcommunity_cmd);
install_element(RMAP_NODE, &no_match_lcommunity_cmd);
install_element(RMAP_NODE, &match_ecommunity_cmd);
diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c
index 4645593441..9372647f3d 100644
--- a/bgpd/bgp_routemap_nb.c
+++ b/bgpd/bgp_routemap_nb.c
@@ -222,6 +222,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
}
},
{
+ .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:extcommunity-limit",
+ .cbs = {
+ .modify = lib_route_map_entry_match_condition_rmap_match_condition_extcommunity_limit_modify,
+ .destroy = lib_route_map_entry_match_condition_rmap_match_condition_extcommunity_limit_destroy,
+ }
+ },
+ {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-rt",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_rt_modify,
diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h
index 45689242a0..f04429078f 100644
--- a/bgpd/bgp_routemap_nb.h
+++ b/bgpd/bgp_routemap_nb.h
@@ -76,6 +76,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_community_limit_mod
struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_community_limit_destroy(
struct nb_cb_destroy_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_extcommunity_limit_modify(
+ struct nb_cb_modify_args *args);
+int lib_route_map_entry_match_condition_rmap_match_condition_extcommunity_limit_destroy(
+ struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(
struct nb_cb_create_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index 223c416dc5..5f5274c5e1 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -1667,6 +1667,57 @@ int lib_route_map_entry_set_action_rmap_set_action_distance_destroy(
}
/*
+ * XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:extcommunity-limit
+ */
+int lib_route_map_entry_match_condition_rmap_match_condition_extcommunity_limit_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct routemap_hook_context *rhc;
+ const char *limit;
+ enum rmap_compile_rets ret;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ /* Add configuration. */
+ rhc = nb_running_get_entry(args->dnode, NULL, true);
+ limit = yang_dnode_get_string(args->dnode, NULL);
+
+ rhc->rhc_mhook = bgp_route_match_delete;
+ rhc->rhc_rule = "extcommunity-limit";
+ rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
+
+ ret = bgp_route_match_add(rhc->rhc_rmi, "extcommunity-limit", limit,
+ RMAP_EVENT_MATCH_ADDED, args->errmsg, args->errmsg_len);
+
+ if (ret != RMAP_COMPILE_SUCCESS) {
+ rhc->rhc_mhook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_match_condition_rmap_match_condition_extcommunity_limit_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_match_destroy(args);
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-rt
*/
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index cba539708a..5286acd792 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -2920,6 +2920,13 @@ BGP Extended Communities in Route Map
.. clicmd:: match extcommunity WORD
+.. clicmd:: match extcommunity-limit (0-65535)
+
+ This command matches BGP updates that use extended community list and IPv6
+ extended community list, and with an extended community list count less or
+ equal than the defined limit. Setting extended community-limit to 0 will
+ only match BGP updates with no extended community.
+
.. clicmd:: set extcommunity none
This command resets the extended community value in BGP updates. If the attribute is
diff --git a/lib/routemap.h b/lib/routemap.h
index 1c02348313..0e41a7a856 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -317,6 +317,7 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(C, "frr-bgp-route-map:match-large-community"))
#define IS_MATCH_EXTCOMMUNITY(C) \
(strmatch(C, "frr-bgp-route-map:match-extcommunity"))
+#define IS_MATCH_EXTCOMMUNITY_LIMIT(C) (strmatch(C, "frr-bgp-route-map:match-extcommunity-limit"))
#define IS_MATCH_IPV4_NH(C) \
(strmatch(C, "frr-bgp-route-map:ipv4-nexthop"))
#define IS_MATCH_IPV6_NH(C) \
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index eb01709707..a59d504287 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -715,6 +715,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-bgp-route-map:rpki"));
+ } else if (IS_MATCH_EXTCOMMUNITY_LIMIT(condition)) {
+ vty_out(vty, " match extcommunity-limit %s\n",
+ yang_dnode_get_string(dnode,
+ "./rmap-match-condition/frr-bgp-route-map:extcommunity-limit"));
} else if (IS_MATCH_RPKI_EXTCOMMUNITY(condition)) {
vty_out(vty, " match rpki-extcommunity %s\n",
yang_dnode_get_string(
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index efb0b2fa08..f1fa93664c 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -166,6 +166,12 @@ module frr-bgp-route-map {
"Match BGP extcommunity list";
}
+ identity match-extcommunity-limit {
+ base frr-route-map:rmap-match-type;
+ description
+ "Match BGP extcommunity limit count";
+ }
+
identity as-path-list {
base frr-route-map:rmap-match-type;
description
@@ -819,6 +825,17 @@ identity set-extcommunity-color {
}
}
+ case extcommunity-limit {
+ when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-extcommunity-limit')";
+ description
+ "Match BGP updates when the list of extended communities count is less than the configured limit.";
+ leaf extcommunity-limit {
+ type uint16 {
+ range "0..1024";
+ }
+ }
+ }
+
case comm-list-name {
when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-community') or "
+ "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-large-community') or "