return rv == 0;
}
+static char *ecommunity_str_get(struct ecommunity *ecom, int i)
+{
+ return ecommunity_ecom2str_one(ecom, ECOMMUNITY_FORMAT_DISPLAY, i);
+}
+
static char *lcommunity_str_get(struct lcommunity *lcom, int i)
{
struct lcommunity_val lcomval;
return false;
}
+/* Internal function to perform regular expression match for a single ecommunity. */
+static bool ecommunity_regexp_include(regex_t *reg, struct ecommunity *ecom, int i)
+{
+ char *str;
+
+ /* When there is no communities attribute it is treated as empty string.
+ */
+ if (ecom == NULL || ecom->size == 0)
+ str = XSTRDUP(MTYPE_ECOMMUNITY_STR, "");
+ else
+ str = ecommunity_str_get(ecom, i);
+
+ /* Regular expression match. */
+ if (regexec(reg, str, 0, NULL, 0) == 0) {
+ XFREE(MTYPE_ECOMMUNITY_STR, str);
+ return true;
+ }
+
+ XFREE(MTYPE_ECOMMUNITY_STR, str);
+ /* No match. */
+ return false;
+}
+
static bool lcommunity_regexp_match(struct lcommunity *com, regex_t *reg)
{
const char *str;
return false;
}
+/* Perform exact matching. In case of expanded extended-community-list, do
+ * same thing as ecommunity_list_match().
+ */
+bool ecommunity_list_exact_match(struct ecommunity *ecom, struct community_list *list)
+{
+ struct community_entry *entry;
+
+ for (entry = list->head; entry; entry = entry->next) {
+ if (entry->style == EXTCOMMUNITY_LIST_STANDARD) {
+ if (ecommunity_cmp(ecom, entry->u.lcom))
+ return entry->direct == COMMUNITY_PERMIT;
+ } else if (entry->style == EXTCOMMUNITY_LIST_EXPANDED) {
+ if (ecommunity_regexp_match(ecom, entry->reg))
+ return entry->direct == COMMUNITY_PERMIT;
+ }
+ }
+ return false;
+}
/* Perform exact matching. In case of expanded large-community-list, do
* same thing as lcommunity_list_match().
return false;
}
+bool ecommunity_list_any_match(struct ecommunity *ecom, struct community_list *list)
+{
+ struct community_entry *entry;
+ uint8_t *ptr;
+ uint32_t i;
+
+ for (i = 0; i < ecom->size; i++) {
+ ptr = ecom->val + (i * ecom->unit_size);
+
+ for (entry = list->head; entry; entry = entry->next) {
+ if ((entry->style == EXTCOMMUNITY_LIST_STANDARD) &&
+ ecommunity_include_one(entry->u.ecom, ptr))
+ return entry->direct == COMMUNITY_PERMIT;
+ if ((entry->style == EXTCOMMUNITY_LIST_EXPANDED) &&
+ ecommunity_regexp_include(entry->reg, ecom, i))
+ return entry->direct == COMMUNITY_PERMIT;
+ }
+ }
+ return false;
+}
+
/* Delete all permitted large communities in the list from com. */
struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
struct community_list *list)
struct community_list *list);
extern bool community_list_exact_match(struct community *com,
struct community_list *list);
+extern bool ecommunity_list_exact_match(struct ecommunity *com, struct community_list *list);
extern bool lcommunity_list_exact_match(struct lcommunity *lcom,
struct community_list *list);
extern bool community_list_any_match(struct community *com,
community_list_match_delete(struct community *com, struct community_list *list);
extern bool lcommunity_list_any_match(struct lcommunity *lcom,
struct community_list *list);
+extern bool ecommunity_list_any_match(struct ecommunity *ecom, struct community_list *list);
extern struct lcommunity *
lcommunity_list_match_delete(struct lcommunity *lcom,
struct community_list *list);
*
* Filter is added to display only ECOMMUNITY_ROUTE_TARGET in some cases.
* 0 value displays all.
+ * Index is a unsigned integer value, and stands for the extended community list entry
+ * to display when value is not -1.
*/
-char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
+static char *_ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter, int index)
{
uint32_t i;
uint8_t *pnt;
bool unk_ecom = false;
memset(encbuf, 0x00, sizeof(encbuf));
+ if (index != -1 && (uint32_t)index != i)
+ continue;
/* Space between each value. */
- if (i > 0)
+ if (index == -1 && i > 0)
strlcat(str_buf, " ", str_size);
/* Retrieve value field */
return str_buf;
}
+char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
+{
+ return _ecommunity_ecom2str(ecom, format, filter, -1);
+}
+
+char *ecommunity_ecom2str_one(struct ecommunity *ecom, int format, int number)
+{
+ return _ecommunity_ecom2str(ecom, format, 0, number);
+}
+
+bool ecommunity_include_one(struct ecommunity *ecom, uint8_t *ptr)
+{
+ uint32_t i;
+ uint8_t *ecom_ptr;
+
+ for (i = 0; i < ecom->size; i++) {
+ ecom_ptr = ecom->val + (i * ecom->unit_size);
+ if (memcmp(ptr, ecom_ptr, ecom->unit_size) == 0)
+ return true;
+ }
+ return false;
+}
+
bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2)
{
uint32_t i, j;
extern struct ecommunity *ecommunity_str2com(const char *, int, int);
extern struct ecommunity *ecommunity_str2com_ipv6(const char *str, int type,
int keyword_included);
-extern char *ecommunity_ecom2str(struct ecommunity *, int, int);
+extern char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter);
+extern char *ecommunity_ecom2str_one(struct ecommunity *ecom, int format, int number);
extern bool ecommunity_has_route_target(struct ecommunity *ecom);
extern void ecommunity_strfree(char **s);
+extern bool ecommunity_include_one(struct ecommunity *ecom, uint8_t *ptr);
extern bool ecommunity_include(struct ecommunity *e1, struct ecommunity *e2);
extern bool ecommunity_match(const struct ecommunity *,
const struct ecommunity *);
if (!list)
return RMAP_NOMATCH;
- if (ecommunity_list_match(bgp_attr_get_ecommunity(path->attr), list))
- return RMAP_MATCH;
+ if (rcom->exact) {
+ if (ecommunity_list_exact_match(bgp_attr_get_ecommunity(path->attr), list))
+ return RMAP_MATCH;
+ } else if (rcom->any) {
+ if (!bgp_attr_get_ecommunity(path->attr))
+ return RMAP_OKAY;
+ if (ecommunity_list_any_match(bgp_attr_get_ecommunity(path->attr), list))
+ return RMAP_MATCH;
+ } else {
+ if (ecommunity_list_match(bgp_attr_get_ecommunity(path->attr), list))
+ return RMAP_MATCH;
+ }
return RMAP_NOMATCH;
}
static void *route_match_ecommunity_compile(const char *arg)
{
struct rmap_community *rcom;
+ int len;
+ char *p;
rcom = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_community));
- rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
- rcom->name_hash = bgp_clist_hash_key(rcom->name);
+ p = strchr(arg, ' ');
+ if (p) {
+ len = p - arg;
+ rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
+ memcpy(rcom->name, arg, len);
+ p++;
+ if (*p == 'e')
+ rcom->exact = true;
+ else
+ rcom->any = true;
+ } else {
+ rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+ rcom->exact = false;
+ rcom->any = false;
+ }
+
+ rcom->name_hash = bgp_clist_hash_key(rcom->name);
return rcom;
}
DEFPY_YANG (match_ecommunity,
match_ecommunity_cmd,
- "match extcommunity <(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME>",
+ "match extcommunity <(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]",
MATCH_STR
"Match BGP/VPN extended community list\n"
"Extended community-list number (standard)\n"
"Extended community-list number (expanded)\n"
- "Extended community-list name\n")
+ "Extended community-list name\n"
+ "Do exact matching of communities\n"
+ "Do matching of any community\n")
{
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:match-extcommunity']";
char xpath_value[XPATH_MAXLEN];
+ char xpath_match[XPATH_MAXLEN];
int idx_comm_list = 2;
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_comm_list]->arg);
+ snprintf(xpath_match, sizeof(xpath_match),
+ "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match",
+ xpath);
+ if (exact)
+ nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true");
+ else
+ nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false");
+
+ snprintf(xpath_match, sizeof(xpath_match),
+ "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", xpath);
+ if (any)
+ nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "true");
+ else
+ nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY, "false");
+
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>]",
+ "no match extcommunity [<(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]]",
NO_STR
MATCH_STR
"Match BGP/VPN extended community list\n"
"Extended community-list number (standard)\n"
"Extended community-list number (expanded)\n"
- "Extended community-list name\n")
+ "Extended community-list name\n"
+ "Do exact matching of communities\n"
+ "Do matching of any community\n")
{
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:match-extcommunity']";
BGP Extended Communities in Route Map
"""""""""""""""""""""""""""""""""""""
-.. clicmd:: match extcommunity WORD
+.. clicmd:: match extcommunity WORD [exact-match|any]
-.. clicmd:: match extcommunity-limit (0-65535)
+ This command perform match to BGP updates using extended community list WORD.
+ When the one of BGP extended communities value match to the one of the extended
+ communities value in community list, it is match. When ``exact-match`` keyword
+ is specified, match happens only when BGP updates have completely same extended
+ communities value specified in the extended community list. When ``any`` keyword
+ is set, match happens when any of the extended communities of the BGP updates
+ matches an extended community of the specified list.
+
+ .. 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
vty_out(vty, " any");
vty_out(vty, "\n");
} else if (IS_MATCH_EXTCOMMUNITY(condition)) {
- vty_out(vty, " match extcommunity %s\n",
+ vty_out(vty, " match extcommunity %s",
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name"));
+ if (yang_dnode_get_bool(
+ dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match"))
+ vty_out(vty, " exact-match");
+ if (yang_dnode_get_bool(dnode,
+ "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any"))
+ vty_out(vty, " any");
+ vty_out(vty, "\n");
} else if (IS_MATCH_IPV4_NH(condition)) {
vty_out(vty, " match ip next-hop address %s\n",
yang_dnode_get_string(