return false;
}
+bool community_list_any_match(struct community *com, struct community_list *list)
+{
+ struct community_entry *entry;
+ uint32_t val;
+ int i;
+
+ for (i = 0; i < com->size; i++) {
+ val = community_val_get(com, i);
+
+ for (entry = list->head; entry; entry = entry->next) {
+ if (entry->style == COMMUNITY_LIST_STANDARD &&
+ community_include(entry->u.com, val))
+ return entry->direct == COMMUNITY_PERMIT;
+ if ((entry->style == COMMUNITY_LIST_EXPANDED) &&
+ community_regexp_include(entry->reg, com, i))
+ return entry->direct == COMMUNITY_PERMIT;
+ }
+ }
+ return false;
+}
+
/* Delete all permitted communities in the list from com. */
struct community *community_list_match_delete(struct community *com,
struct community_list *list)
return 0;
}
+bool lcommunity_list_any_match(struct lcommunity *lcom,
+ struct community_list *list)
+{
+ struct community_entry *entry;
+ uint8_t *ptr;
+ int i;
+
+ for (i = 0; i < lcom->size; i++) {
+ ptr = lcom->val + (i * LCOMMUNITY_SIZE);
+
+ for (entry = list->head; entry; entry = entry->next) {
+ if ((entry->style == LARGE_COMMUNITY_LIST_STANDARD) &&
+ lcommunity_include(entry->u.lcom, ptr))
+ return entry->direct == COMMUNITY_PERMIT;
+ if ((entry->style == LARGE_COMMUNITY_LIST_EXPANDED) &&
+ lcommunity_regexp_include(entry->reg, lcom, 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 rmap_community {
char *name;
uint32_t name_hash;
- int exact;
+ bool exact;
+ bool any;
};
/* Match function for community match. */
if (community_list_exact_match(
bgp_attr_get_community(path->attr), list))
return RMAP_MATCH;
+ } else if (rcom->any) {
+ if (!bgp_attr_get_community(path->attr))
+ return RMAP_OKAY;
+ if (community_list_any_match(bgp_attr_get_community(path->attr),
+ list))
+ return RMAP_MATCH;
} else {
if (community_list_match(bgp_attr_get_community(path->attr),
list))
len = p - arg;
rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
memcpy(rcom->name, arg, len);
- rcom->exact = 1;
+ p++;
+ if (*p == 'e')
+ rcom->exact = true;
+ else
+ rcom->any = true;
} else {
rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
- rcom->exact = 0;
+ rcom->exact = false;
+ rcom->any = false;
}
rcom->name_hash = bgp_clist_hash_key(rcom->name);
if (lcommunity_list_exact_match(
bgp_attr_get_lcommunity(path->attr), list))
return RMAP_MATCH;
+ } else if (rcom->any) {
+ if (!bgp_attr_get_lcommunity(path->attr))
+ return RMAP_OKAY;
+ if (lcommunity_list_any_match(bgp_attr_get_lcommunity(path->attr),
+ list))
+ return RMAP_MATCH;
} else {
if (lcommunity_list_match(bgp_attr_get_lcommunity(path->attr),
list))
len = p - arg;
rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1);
memcpy(rcom->name, arg, len);
- rcom->exact = 1;
+ p++;
+ if (*p == 'e')
+ rcom->exact = true;
+ else
+ rcom->any = true;
} else {
rcom->name = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
- rcom->exact = 0;
+ rcom->exact = false;
+ rcom->any = false;
}
rcom->name_hash = bgp_clist_hash_key(rcom->name);
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY_YANG (match_community,
- match_community_cmd,
- "match community <(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]",
- MATCH_STR
- "Match BGP community list\n"
- "Community-list number (standard)\n"
- "Community-list number (expanded)\n"
- "Community-list name\n"
- "Do exact matching of communities\n")
+DEFPY_YANG(
+ match_community, match_community_cmd,
+ "match community <(1-99)|(100-500)|COMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]",
+ MATCH_STR "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "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-community']";
xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_comm_list]->arg);
- if (argc == 4) {
- snprintf(
- xpath_match, sizeof(xpath_match),
- "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match",
- xpath);
+ 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 {
- snprintf(
- xpath_match, sizeof(xpath_match),
- "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match",
- xpath);
- nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY,
- "false");
- }
+ 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_community,
- no_match_community_cmd,
- "no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]]",
- NO_STR
- MATCH_STR
- "Match BGP community list\n"
- "Community-list number (standard)\n"
- "Community-list number (expanded)\n"
- "Community-list name\n"
- "Do exact matching of communities\n")
+DEFUN_YANG(
+ no_match_community, no_match_community_cmd,
+ "no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]]",
+ NO_STR MATCH_STR "Match BGP community list\n"
+ "Community-list number (standard)\n"
+ "Community-list number (expanded)\n"
+ "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-community']";
return nb_cli_apply_changes(vty, NULL);
}
-DEFPY_YANG (match_lcommunity,
- match_lcommunity_cmd,
- "match large-community <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]",
- MATCH_STR
- "Match BGP large community list\n"
- "Large Community-list number (standard)\n"
- "Large Community-list number (expanded)\n"
- "Large Community-list name\n"
- "Do exact matching of communities\n")
+DEFPY_YANG(
+ match_lcommunity, match_lcommunity_cmd,
+ "match large-community <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [<exact-match$exact|any$any>]",
+ MATCH_STR "Match BGP large community list\n"
+ "Large Community-list number (standard)\n"
+ "Large Community-list number (expanded)\n"
+ "Large 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-large-community']";
xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[idx_lcomm_list]->arg);
- if (argc == 4) {
- snprintf(
- xpath_match, sizeof(xpath_match),
- "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match",
- xpath);
+ 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 {
- snprintf(
- xpath_match, sizeof(xpath_match),
- "%s/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match",
- xpath);
- nb_cli_enqueue_change(vty, xpath_match, NB_OP_MODIFY,
- "false");
- }
+ 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_lcommunity,
- no_match_lcommunity_cmd,
- "no match large-community [<(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]]",
- NO_STR
- MATCH_STR
- "Match BGP large community list\n"
- "Large Community-list number (standard)\n"
- "Large Community-list number (expanded)\n"
- "Large Community-list name\n"
- "Do exact matching of communities\n")
+DEFUN_YANG(
+ no_match_lcommunity, no_match_lcommunity_cmd,
+ "no match large-community [<(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [<exact-match|any>]]",
+ NO_STR MATCH_STR "Match BGP large community list\n"
+ "Large Community-list number (standard)\n"
+ "Large Community-list number (expanded)\n"
+ "Large 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-large-community']";
def build_topo(tgen):
- for routern in range(1, 3):
+ for routern in range(1, 4):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r2"])
def setup_module(mod):
}
return topotest.json_cmp(output, expected)
- step("Initial BGP converge")
+ step("Initial BGP converge between R1 and R2")
test_func = functools.partial(_bgp_converge)
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, "Failed to filter BGP UPDATES with community-list on R2"
+def test_bgp_comm_list_match_any():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r3"]
+
+ def _bgp_converge():
+ output = json.loads(
+ router.vtysh_cmd(
+ "show bgp ipv4 unicast neighbors 192.168.1.2 filtered-routes json"
+ )
+ )
+ expected = {
+ "receivedRoutes": {
+ "172.16.255.4/32": {
+ "path": "65002 65001",
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ step("Initial BGP converge between R3 and R2")
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to filter BGP UPDATES with community-list on R3"
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))