Skip to content

Commit

Permalink
bgpd: add 'match community-count' command to restrict comm count
Browse files Browse the repository at this point in the history
Add a mechanism in route-map to filter out route-map which have a list
of communities greater than the given number.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
  • Loading branch information
pguibert6WIND committed Jan 14, 2025
1 parent ba4122d commit f19b866
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 0 deletions.
76 changes: 76 additions & 0 deletions bgpd/bgp_routemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,61 @@ static const struct route_map_rule_cmd route_match_evpn_rd_cmd = {
route_match_rd_free
};

/* `match community-limit' */

/* Match function should return :
* - RMAP_MATCH if the bgp update community list count
* is less or equal to the configured limit.
* - RMAP_NOMATCH if the community list count is greater than the
* configured limit.
*/
static enum route_map_cmd_result_t
route_match_community_limit(void *rule, const struct prefix *prefix, void *object)
{
struct bgp_path_info *path = NULL;
struct community *picomm = NULL;
uint16_t count = 0;
uint16_t *limit_rule = rule;

path = (struct bgp_path_info *)object;

picomm = bgp_attr_get_community(path->attr);
if (picomm)
count = picomm->size;

if (count <= *limit_rule)
return RMAP_MATCH;

return RMAP_NOMATCH;
}

/* Route map `community-limit' match statement. */
static void *route_match_community_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_community_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_community_limit_cmd = {
"community-limit", route_match_community_limit,
route_match_community_limit_compile, route_match_community_limit_free
};

static enum route_map_cmd_result_t
route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
{
Expand Down Expand Up @@ -5708,6 +5763,25 @@ DEFPY_YANG(
return nb_cli_apply_changes(vty, NULL);
}

DEFPY_YANG(
match_community_limit, match_community_limit_cmd,
"[no$no] match community-limit ![(0-65535)$limit]",
NO_STR
MATCH_STR
"Match BGP community limit\n"
"Community limit number\n")
{
const char *xpath = "./match-condition[condition='frr-bgp-route-map:match-community-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:community-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_community, no_match_community_cmd,
"no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]]",
Expand Down Expand Up @@ -7906,6 +7980,7 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_evpn_vni_cmd);
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_evpn_default_route_cmd);
route_map_install_match(&route_match_vrl_source_vrf_cmd);

Expand Down Expand Up @@ -7978,6 +8053,7 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_match_alias_cmd);
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_lcommunity_cmd);
install_element(RMAP_NODE, &no_match_lcommunity_cmd);
install_element(RMAP_NODE, &match_ecommunity_cmd);
Expand Down
7 changes: 7 additions & 0 deletions bgpd/bgp_routemap_nb.c
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.destroy = lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:community-limit",
.cbs = {
.modify = lib_route_map_entry_match_condition_rmap_match_condition_community_limit_modify,
.destroy = lib_route_map_entry_match_condition_rmap_match_condition_community_limit_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list",
.cbs = {
Expand Down
4 changes: 4 additions & 0 deletions bgpd/bgp_routemap_nb.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_mod
int lib_route_map_entry_match_condition_rmap_match_condition_evpn_route_type_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_community_limit_modify(
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_comm_list_create(
struct nb_cb_create_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
Expand Down
51 changes: 51 additions & 0 deletions bgpd/bgp_routemap_nb_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,57 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des
return NB_OK;
}

/*
* XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:community-limit
*/
int lib_route_map_entry_match_condition_rmap_match_condition_community_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 = "community-limit";
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;

ret = bgp_route_match_add(rhc->rhc_rmi, "community-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_community_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/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list
*/
Expand Down
6 changes: 6 additions & 0 deletions doc/user/bgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2693,6 +2693,12 @@ The following commands can be used in route maps:
happen only when BGP updates have completely same communities value
specified in the community list.

.. clicmd:: match community-limit (0-65535)

This command matches BGP updates that use community list, and with a community
list count less or equal than the defined limit. Setting community-limit to 0
will only match BGP updates with no community.

.. clicmd:: set community <none|COMMUNITY> additive

This command sets the community value in BGP updates. If the attribute is
Expand Down
1 change: 1 addition & 0 deletions lib/routemap.h
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(C, "frr-bgp-route-map:ip-route-source"))
#define IS_MATCH_ROUTE_SRC_PL(C) \
(strmatch(C, "frr-bgp-route-map:ip-route-source-prefix-list"))
#define IS_MATCH_COMMUNITY_LIMIT(C) (strmatch(C, "frr-bgp-route-map:match-community-limit"))
#define IS_MATCH_COMMUNITY(C) \
(strmatch(C, "frr-bgp-route-map:match-community"))
#define IS_MATCH_LCOMMUNITY(C) \
Expand Down
4 changes: 4 additions & 0 deletions lib/routemap_cli.c
Original file line number Diff line number Diff line change
Expand Up @@ -810,6 +810,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:list-name"));
} else if (IS_MATCH_COMMUNITY_LIMIT(condition)) {
vty_out(vty, " match community-limit %s\n",
yang_dnode_get_string(dnode,
"./rmap-match-condition/frr-bgp-route-map:community-limit"));
} else if (IS_MATCH_COMMUNITY(condition)) {
vty_out(vty, " match community %s",
yang_dnode_get_string(
Expand Down
11 changes: 11 additions & 0 deletions yang/frr-bgp-route-map.yang
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,17 @@ identity set-extcommunity-color {
}
}

case community-limit {
when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-community-limit')";
description
"Match BGP updates when the list of communities count is less than the configured limit.";
leaf community-limit {
type uint16 {
range "1..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 "
Expand Down

0 comments on commit f19b866

Please sign in to comment.