diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index f3c308afb9e3..4c47728fe078 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -748,6 +748,30 @@ bool community_list_exact_match(struct community *com, 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, + COMMUNITY_INTERNET) || + 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) @@ -938,6 +962,28 @@ int community_list_unset(struct community_list_handler *ch, const char *name, 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 == COMMUNITY_LIST_STANDARD) && + lcommunity_include(entry->u.lcom, ptr)) + return entry->direct == COMMUNITY_PERMIT; + if ((entry->style == 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) diff --git a/bgpd/bgp_clist.h b/bgpd/bgp_clist.h index 8e5d637babee..5cae201d6d47 100644 --- a/bgpd/bgp_clist.h +++ b/bgpd/bgp_clist.h @@ -158,8 +158,12 @@ extern bool community_list_exact_match(struct community *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, + struct community_list *list); extern struct community * 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 struct lcommunity * lcommunity_list_match_delete(struct lcommunity *lcom, struct community_list *list); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 7db110be9339..0d112c2b24ed 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -1527,7 +1527,8 @@ static const struct route_map_rule_cmd route_match_aspath_cmd = { struct rmap_community { char *name; uint32_t name_hash; - int exact; + bool exact; + bool any; }; /* Match function for community match. */ @@ -1550,6 +1551,10 @@ route_match_community(void *rule, const struct prefix *prefix, void *object) if (community_list_exact_match( bgp_attr_get_community(path->attr), list)) return RMAP_MATCH; + } else if (rcom->any) { + 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)) @@ -1573,10 +1578,15 @@ static void *route_match_community_compile(const char *arg) 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); @@ -1636,6 +1646,10 @@ route_match_lcommunity(void *rule, const struct prefix *prefix, void *object) if (lcommunity_list_exact_match( bgp_attr_get_lcommunity(path->attr), list)) return RMAP_MATCH; + } else if (rcom->any) { + 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)) @@ -1659,10 +1673,14 @@ static void *route_match_lcommunity_compile(const char *arg) len = p - arg; rcom->name = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, len + 1); memcpy(rcom->name, arg, len); - rcom->exact = 1; + 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); @@ -5241,21 +5259,22 @@ DEFUN_YANG(no_match_alias, no_match_alias_cmd, "no match alias [ALIAS_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> []", + 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']"; char xpath_value[XPATH_MAXLEN]; char xpath_match[XPATH_MAXLEN]; - int idx_comm_list = 2; + int idx_comm_list = 2, idx; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); @@ -5265,21 +5284,24 @@ DEFPY_YANG (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 (argv_find(argv, argc, "exact-match", &idx)) 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 (argv_find(argv, argc, "any", &idx)) + 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); } @@ -5302,21 +5324,22 @@ DEFUN_YANG (no_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> []", + 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']"; char xpath_value[XPATH_MAXLEN]; char xpath_match[XPATH_MAXLEN]; - int idx_lcomm_list = 2; + int idx_lcomm_list = 2, idx; nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); @@ -5326,21 +5349,24 @@ DEFPY_YANG (match_lcommunity, 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 (argv_find(argv, argc, "exact-match", &idx)) 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 (argv_find(argv, argc, "any", &idx)) + 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); } diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index 282ebe9116a6..9ef781a3be55 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -164,6 +164,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy, } }, + { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy, + } + }, { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:ipv4-address", .cbs = { diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index 7066fdb4195c..6be61b59ee0d 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -65,6 +65,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_exact_match_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( + struct nb_cb_modify_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_destroy( + struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv4_address_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_modify(struct nb_cb_modify_args *args); diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 02564b000410..c00d63cbc108 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -1127,6 +1127,7 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( struct routemap_hook_context *rhc; const char *value; bool exact_match = false; + bool any = false; char *argstr; const char *condition; route_map_event_t event; @@ -1140,12 +1141,21 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_finish( exact_match = yang_dnode_get_bool( args->dnode, "./comm-list-name-exact-match"); + if (yang_dnode_exists(args->dnode, "./comm-list-name-any")) + any = yang_dnode_get_bool(args->dnode, "./comm-list-name-any"); + if (exact_match) { argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, strlen(value) + strlen("exact-match") + 2); snprintf(argstr, (strlen(value) + strlen("exact-match") + 2), - "%s exact-match", value); + "%s any", value); + } else if (any) { + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, + strlen(value) + strlen("any") + 2); + + snprintf(argstr, (strlen(value) + strlen("any") + 2), "%s any", + value); } else argstr = (char *)value; @@ -1217,6 +1227,39 @@ lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_nam } +/* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-any + */ +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_route_map_entry_match_condition_rmap_match_condition_comm_list_comm_list_name_any_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/comm-list-name-exact-match */ diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index b557cabb22ae..ed0dcc814e00 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -749,6 +749,12 @@ module frr-bgp-route-map { description "Do exact matching of communities"; } + leaf comm-list-name-any { + type boolean; + description + "Do matching of any community"; + } + } }