bgpd: add set extended-comm-list <> delete command

Signed-off-by: Farid Mihoub <farid.mihoub@6wind.com>
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
Farid Mihoub 2023-06-14 16:16:55 +02:00
parent 1aa34e5fb7
commit 902a8d1fd3
9 changed files with 197 additions and 1 deletions

View File

@ -986,6 +986,44 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
return lcom;
}
/* Delete all permitted extended communities in the list from ecom.*/
struct ecommunity *ecommunity_list_match_delete(struct ecommunity *ecom,
struct community_list *list)
{
struct community_entry *entry;
uint32_t com_index_to_delete[ecom->size];
uint8_t *ptr;
uint32_t delete_index = 0;
uint32_t i;
struct ecommunity local_ecom = {.size = 1};
struct ecommunity_val local_eval = {0};
for (i = 0; i < ecom->size; i++) {
local_ecom.val = ecom->val + (i * ECOMMUNITY_SIZE);
for (entry = list->head; entry; entry = entry->next) {
if (((entry->style == EXTCOMMUNITY_LIST_STANDARD) &&
ecommunity_include(entry->u.ecom, &local_ecom)) ||
((entry->style == EXTCOMMUNITY_LIST_EXPANDED) &&
ecommunity_regexp_match(ecom, entry->reg))) {
if (entry->direct == COMMUNITY_PERMIT) {
com_index_to_delete[delete_index] = i;
delete_index++;
}
break;
}
}
}
/* Delete all of the extended communities we flagged for deletion */
for (i = delete_index; i > 0; i--) {
ptr = ecom->val + (com_index_to_delete[i-1] * ECOMMUNITY_SIZE);
memcpy(&local_eval.val, ptr, sizeof(local_eval.val));
ecommunity_del_val(ecom, &local_eval);
}
return ecom;
}
/* Helper to check if every octet do not exceed UINT_MAX */
bool lcommunity_list_valid(const char *community, int style)
{

View File

@ -163,6 +163,9 @@ community_list_match_delete(struct community *com, struct community_list *list);
extern struct lcommunity *
lcommunity_list_match_delete(struct lcommunity *lcom,
struct community_list *list);
extern struct ecommunity *
ecommunity_list_match_delete(struct ecommunity *ecom,
struct community_list *list);
static inline uint32_t bgp_clist_hash_key(char *name)
{

View File

@ -2852,6 +2852,83 @@ static const struct route_map_rule_cmd route_set_community_delete_cmd = {
route_set_community_delete_free,
};
/* `set extcomm-list (<1-99>|<100-500>|WORD) delete' */
static enum route_map_cmd_result_t
route_set_ecommunity_delete(void *rule, const struct prefix *prefix,
void *object)
{
struct community_list *list;
struct ecommunity *merge;
struct ecommunity *new;
struct ecommunity *old;
struct bgp_path_info *path;
struct rmap_community *rcom = rule;
if (!rcom)
return RMAP_OKAY;
path = object;
list = community_list_lookup(bgp_clist, rcom->name, rcom->name_hash,
EXTCOMMUNITY_LIST_MASTER);
old = bgp_attr_get_ecommunity(path->attr);
if (list && old) {
merge = ecommunity_list_match_delete(ecommunity_dup(old), list);
new = ecommunity_uniq_sort(merge);
ecommunity_free(&merge);
/* HACK: if the old community is not intern'd,
* we should free it here, or all reference to it may be
* lost.
* Really need to cleanup attribute caching sometime.
*/
if (old->refcnt == 0)
ecommunity_free(&old);
if (new->size == 0) {
bgp_attr_set_ecommunity(path->attr, NULL);
ecommunity_free(&new);
} else {
bgp_attr_set_ecommunity(path->attr, new);
}
}
return RMAP_OKAY;
}
static void *route_set_ecommunity_delete_compile(const char *arg)
{
struct rmap_community *rcom;
char **splits;
int num;
frrstr_split(arg, " ", &splits, &num);
rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, splits[0]);
rcom->name_hash = bgp_clist_hash_key(rcom->name);
for (int i = 0; i < num; i++)
XFREE(MTYPE_TMP, splits[i]);
XFREE(MTYPE_TMP, splits);
return rcom;
}
static void route_set_ecommunity_delete_free(void *rule)
{
struct rmap_community *rcom = rule;
XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom->name);
XFREE(MTYPE_ROUTE_MAP_COMPILED, rcom);
}
static const struct route_map_rule_cmd route_set_ecommunity_delete_cmd = {
"extended-comm-list",
route_set_ecommunity_delete,
route_set_ecommunity_delete_compile,
route_set_ecommunity_delete_free,
};
/* `set extcommunity rt COMMUNITY' */
struct rmap_ecom_set {
@ -5522,6 +5599,51 @@ DEFUN_YANG (no_match_ecommunity,
}
DEFPY_YANG (set_ecommunity_delete,
set_ecommunity_delete_cmd,
"set extended-comm-list " EXTCOMM_LIST_CMD_STR " delete",
SET_STR
"set BGP extended community list (for deletion)\n"
EXTCOMM_STD_LIST_NUM_STR
EXTCOMM_EXP_LIST_NUM_STR
EXTCOMM_LIST_NAME_STR
"Delete matching extended communities\n")
{
const char *xpath =
"./set-action[action='frr-bgp-route-map:extended-comm-list-delete']";
char xpath_value[XPATH_MAXLEN];
int idx_comm_list = 2;
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-set-action/frr-bgp-route-map:comm-list-name",
xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY,
argv[idx_comm_list]->arg);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY_YANG (no_set_ecommunity_delete,
no_set_ecommunity_delete_cmd,
"no set extended-comm-list [" EXTCOMM_LIST_CMD_STR "] delete",
NO_STR
SET_STR
"set BGP extended community list (for deletion)\n"
EXTCOMM_STD_LIST_NUM_STR
EXTCOMM_EXP_LIST_NUM_STR
EXTCOMM_LIST_NAME_STR
"Delete matching extended communities\n")
{
const char *xpath =
"./set-action[action='frr-bgp-route-map:extended-comm-list-delete']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
DEFUN_YANG (match_aspath,
match_aspath_cmd,
"match as-path AS_PATH_FILTER_NAME",
@ -7605,6 +7727,7 @@ void bgp_route_map_init(void)
route_map_install_set(&route_set_aggregator_as_cmd);
route_map_install_set(&route_set_community_cmd);
route_map_install_set(&route_set_community_delete_cmd);
route_map_install_set(&route_set_ecommunity_delete_cmd);
route_map_install_set(&route_set_lcommunity_cmd);
route_map_install_set(&route_set_lcommunity_delete_cmd);
route_map_install_set(&route_set_vpnv4_nexthop_cmd);
@ -7724,6 +7847,8 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &set_ecommunity_color_cmd);
install_element(RMAP_NODE, &no_set_ecommunity_color_cmd);
install_element(RMAP_NODE, &no_set_ecommunity_color_all_cmd);
install_element(RMAP_NODE, &set_ecommunity_delete_cmd);
install_element(RMAP_NODE, &no_set_ecommunity_delete_cmd);
#ifdef KEEP_OLD_VPN_COMMANDS
install_element(RMAP_NODE, &set_vpn_nexthop_cmd);
install_element(RMAP_NODE, &no_set_vpn_nexthop_cmd);

View File

@ -2835,6 +2835,8 @@ int lib_route_map_entry_set_action_rmap_set_action_comm_list_name_modify(
"../../frr-route-map:action");
if (IS_SET_COMM_LIST_DEL(action))
rhc->rhc_rule = "comm-list";
else if (IS_SET_EXTCOMM_LIST_DEL(action))
rhc->rhc_rule = "extended-comm-list";
else
rhc->rhc_rule = "large-comm-list";

View File

@ -335,6 +335,10 @@ Route Map Set Command
Set the BGP community attribute.
.. clicmd:: set extended-comm-list <EXTCOMMUNITY_LIST_NAME> delete
Set BGP extended community list for deletion.
.. clicmd:: set ipv6 next-hop local IPV6_ADDRESS
Set the BGP-4+ link local IPv6 nexthop address.

View File

@ -416,6 +416,10 @@ struct cmd_node {
#define COMMUNITY_AANN_STR "Community number where AA and NN are (0-65535)\n"
#define COMMUNITY_VAL_STR \
"Community number in AA:NN format (where AA and NN are (0-65535)) or local-AS|no-advertise|no-export|internet|graceful-shutdown|accept-own-nexthop|accept-own|route-filter-translated-v4|route-filter-v4|route-filter-translated-v6|route-filter-v6|llgr-stale|no-llgr|blackhole|no-peer or additive\n"
#define EXTCOMM_LIST_CMD_STR "<(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME>"
#define EXTCOMM_STD_LIST_NUM_STR "Extended community-list number (standard)\n"
#define EXTCOMM_EXP_LIST_NUM_STR "Extended community-list number (expanded)\n"
#define EXTCOMM_LIST_NAME_STR "Extended community-list name\n"
#define MPLS_TE_STR "MPLS-TE specific commands\n"
#define LINK_PARAMS_STR "Configure interface link parameters\n"
#define OSPF_RI_STR "OSPF Router Information specific commands\n"

View File

@ -348,6 +348,8 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(A, "frr-bgp-route-map:comm-list-delete"))
#define IS_SET_LCOMM_LIST_DEL(A) \
(strmatch(A, "frr-bgp-route-map:large-comm-list-delete"))
#define IS_SET_EXTCOMM_LIST_DEL(A) \
(strmatch(A, "frr-bgp-route-map:extended-comm-list-delete"))
#define IS_SET_LCOMMUNITY(A) \
(strmatch(A, "frr-bgp-route-map:set-large-community"))
#define IS_SET_COMMUNITY(A) \

View File

@ -1186,6 +1186,16 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
assert(acl);
vty_out(vty, " set large-comm-list %s delete\n", acl);
} else if (IS_SET_EXTCOMM_LIST_DEL(action)) {
acl = NULL;
ln = yang_dnode_get(dnode, "./rmap-set-action/frr-bgp-route-map:comm-list-name");
if (ln)
acl = yang_dnode_get_string(ln, NULL);
assert(acl);
vty_out(vty, " set extended-comm-list %s delete\n", acl);
} else if (IS_SET_LCOMMUNITY(action)) {
if (yang_dnode_exists(
dnode,

View File

@ -352,6 +352,12 @@ identity set-extcommunity-color {
"Set BGP large community list (for deletion)";
}
identity extended-comm-list-delete {
base frr-route-map:rmap-set-type;
description
"Set BGP extended community list (for deletion)";
}
identity set-evpn-gateway-ip-ipv4 {
base frr-route-map:rmap-set-type;
description
@ -1109,7 +1115,9 @@ identity set-extcommunity-color {
case comm-list-name {
when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:comm-list-delete') or "
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:large-comm-list-delete')";
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:large-comm-list-delete') or "
+ "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action,
'frr-bgp-route-map:extended-comm-list-delete')";
leaf comm-list-name {
type bgp-filter:bgp-list-name;
}