forked from Mirror/frr
bgpd: add 'match community-count' command to restrict comm count
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>
This commit is contained in:
parent
ba4122d6db
commit
f19b8668b3
|
@ -1303,6 +1303,61 @@ static const struct route_map_rule_cmd route_match_evpn_rd_cmd = {
|
||||||
route_match_rd_free
|
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
|
static enum route_map_cmd_result_t
|
||||||
route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
|
route_set_evpn_gateway_ip(void *rule, const struct prefix *prefix, void *object)
|
||||||
{
|
{
|
||||||
|
@ -5708,6 +5763,25 @@ DEFPY_YANG(
|
||||||
return nb_cli_apply_changes(vty, NULL);
|
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(
|
DEFUN_YANG(
|
||||||
no_match_community, no_match_community_cmd,
|
no_match_community, no_match_community_cmd,
|
||||||
"no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]]",
|
"no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]]",
|
||||||
|
@ -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_vni_cmd);
|
||||||
route_map_install_match(&route_match_evpn_route_type_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_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_evpn_default_route_cmd);
|
||||||
route_map_install_match(&route_match_vrl_source_vrf_cmd);
|
route_map_install_match(&route_match_vrl_source_vrf_cmd);
|
||||||
|
|
||||||
|
@ -7978,6 +8053,7 @@ void bgp_route_map_init(void)
|
||||||
install_element(RMAP_NODE, &no_match_alias_cmd);
|
install_element(RMAP_NODE, &no_match_alias_cmd);
|
||||||
install_element(RMAP_NODE, &match_community_cmd);
|
install_element(RMAP_NODE, &match_community_cmd);
|
||||||
install_element(RMAP_NODE, &no_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, &match_lcommunity_cmd);
|
||||||
install_element(RMAP_NODE, &no_match_lcommunity_cmd);
|
install_element(RMAP_NODE, &no_match_lcommunity_cmd);
|
||||||
install_element(RMAP_NODE, &match_ecommunity_cmd);
|
install_element(RMAP_NODE, &match_ecommunity_cmd);
|
||||||
|
|
|
@ -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,
|
.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",
|
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list",
|
||||||
.cbs = {
|
.cbs = {
|
||||||
|
|
|
@ -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_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_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_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(
|
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_create(
|
||||||
struct nb_cb_create_args *args);
|
struct nb_cb_create_args *args);
|
||||||
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
|
int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_destroy(
|
||||||
|
|
|
@ -1274,6 +1274,57 @@ lib_route_map_entry_match_condition_rmap_match_condition_route_distinguisher_des
|
||||||
return NB_OK;
|
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
|
* XPath = /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2693,6 +2693,12 @@ The following commands can be used in route maps:
|
||||||
happen only when BGP updates have completely same communities value
|
happen only when BGP updates have completely same communities value
|
||||||
specified in the community list.
|
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
|
.. clicmd:: set community <none|COMMUNITY> additive
|
||||||
|
|
||||||
This command sets the community value in BGP updates. If the attribute is
|
This command sets the community value in BGP updates. If the attribute is
|
||||||
|
|
|
@ -310,6 +310,7 @@ DECLARE_QOBJ_TYPE(route_map);
|
||||||
(strmatch(C, "frr-bgp-route-map:ip-route-source"))
|
(strmatch(C, "frr-bgp-route-map:ip-route-source"))
|
||||||
#define IS_MATCH_ROUTE_SRC_PL(C) \
|
#define IS_MATCH_ROUTE_SRC_PL(C) \
|
||||||
(strmatch(C, "frr-bgp-route-map:ip-route-source-prefix-list"))
|
(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) \
|
#define IS_MATCH_COMMUNITY(C) \
|
||||||
(strmatch(C, "frr-bgp-route-map:match-community"))
|
(strmatch(C, "frr-bgp-route-map:match-community"))
|
||||||
#define IS_MATCH_LCOMMUNITY(C) \
|
#define IS_MATCH_LCOMMUNITY(C) \
|
||||||
|
|
|
@ -810,6 +810,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
|
||||||
yang_dnode_get_string(
|
yang_dnode_get_string(
|
||||||
dnode,
|
dnode,
|
||||||
"./rmap-match-condition/frr-bgp-route-map:list-name"));
|
"./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)) {
|
} else if (IS_MATCH_COMMUNITY(condition)) {
|
||||||
vty_out(vty, " match community %s",
|
vty_out(vty, " match community %s",
|
||||||
yang_dnode_get_string(
|
yang_dnode_get_string(
|
||||||
|
|
|
@ -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 {
|
case comm-list-name {
|
||||||
when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-community') or "
|
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 "
|
+ "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:match-large-community') or "
|
||||||
|
|
Loading…
Reference in a new issue