]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: add 'match community-list any' function
authorPhilippe Guibert <philippe.guibert@6wind.com>
Tue, 27 Jun 2023 19:36:01 +0000 (21:36 +0200)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Mon, 2 Oct 2023 13:24:18 +0000 (15:24 +0200)
There is no match mechanism to match one community from the
incoming community-list. Add the 'any' keyword to the 'match
route-map' command of communit-list and large-community-list.

> match community-list AAA any
> match large-community-list AAA any

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
15 files changed:
bgpd/bgp_clist.c
bgpd/bgp_clist.h
bgpd/bgp_routemap.c
bgpd/bgp_routemap_nb.c
bgpd/bgp_routemap_nb.h
bgpd/bgp_routemap_nb_config.c
lib/routemap_cli.c
tests/topotests/bgp_comm_list_match/r1/bgpd.conf
tests/topotests/bgp_comm_list_match/r1/zebra.conf
tests/topotests/bgp_comm_list_match/r2/bgpd.conf
tests/topotests/bgp_comm_list_match/r2/zebra.conf
tests/topotests/bgp_comm_list_match/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_comm_list_match/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py
yang/frr-bgp-route-map.yang

index 3fd246397fd897a3da404f5ff9c9fd1cf923d69d..e52230713420493563e6126e5c3143577df4a5fd 100644 (file)
@@ -735,6 +735,27 @@ 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, 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)
@@ -922,6 +943,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 == 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)
index 251169876da6695af408da419b083ff8c00bd027..a435b92ce1832c5f6139582508dbe843658865af 100644 (file)
@@ -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);
index 274df5197e2c65cc794b56c9b3de55daac61f84c..e0db43f676ad9836d9abadd78d86cd25d0e01276 100644 (file)
@@ -1528,7 +1528,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. */
@@ -1551,6 +1552,12 @@ 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 (!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))
@@ -1574,10 +1581,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);
@@ -1637,6 +1649,12 @@ 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 (!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))
@@ -1660,10 +1678,15 @@ 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;
+               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);
@@ -5493,15 +5516,15 @@ 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> [<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']";
@@ -5517,35 +5540,35 @@ 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 (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']";
@@ -5554,15 +5577,15 @@ 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> [<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']";
@@ -5578,35 +5601,35 @@ 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 (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']";
index ae695a6f80a158197d44e42f9405757ad0490c01..abebfe5155c1f7ff12cb5d214f93e3c09109bbc3 100644 (file)
@@ -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 = {
index 3ff58f71a73305a3aeb70c3017d9a1f7dd44fb18..28e4188026c4b091dc705cf050446cc4a233b638 100644 (file)
@@ -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);
index 9ef9031e54a53fa9b22bd7c1e173c5fb6cdfbb17..370295b6c31ea3683b25e98d79f07c75bc4a4a0f 100644 (file)
@@ -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);
+       } 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
  */
index a5e66880a75cffe7a193733429b018af54511cee..20a157e95539d9f6d6275286016424cfa320632e 100644 (file)
@@ -729,6 +729,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
                            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_LCOMMUNITY(condition)) {
                vty_out(vty, " match large-community %s",
@@ -739,6 +743,10 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
                            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_EXTCOMMUNITY(condition)) {
                vty_out(vty, " match extcommunity %s\n",
index 89c9f7728e609a98f4a96601d501e867ade56be8..bac84120881892c927e2b7c72a8b4f5c21128709 100644 (file)
@@ -11,6 +11,7 @@ router bgp 65001
 !
 ip prefix-list p1 seq 5 permit 172.16.255.1/32
 ip prefix-list p3 seq 5 permit 172.16.255.3/32
+ip prefix-list p4 seq 5 permit 172.16.255.4/32
 !
 route-map r2 permit 10
  match ip address prefix-list p1
@@ -19,5 +20,9 @@ route-map r2 permit 20
  match ip address prefix-list p3
  set community 65001:3
 route-map r2 permit 30
+ match ip address prefix-list p4
+ set community 65001:10 65001:12 65001:13
+exit
+route-map r2 permit 40
 exit
 !
index 17d0ecceaf0d415d3da85c8afe723416221f8adb..4219a7ca3a4e4f4e7464fce9be3d84c35a72aec4 100644 (file)
@@ -3,6 +3,7 @@ interface lo
  ip address 172.16.255.1/32
  ip address 172.16.255.2/32
  ip address 172.16.255.3/32
+ ip address 172.16.255.4/32
 !
 interface r1-eth0
  ip address 192.168.0.1/24
index 98a9780688883e524b20e5e58493e6789c5934e8..cb2f89e5c5ad2a42f44d4572c848534f7a244041 100644 (file)
@@ -6,6 +6,9 @@ router bgp 65002
  neighbor 192.168.0.1 remote-as external
  neighbor 192.168.0.1 timers 1 3
  neighbor 192.168.0.1 timers connect 1
+ neighbor 192.168.1.3 remote-as external
+ neighbor 192.168.1.3 timers 1 3
+ neighbor 192.168.1.3 timers connect 1
  address-family ipv4
   neighbor 192.168.0.1 route-map r1 in
   neighbor 192.168.0.1 soft-reconfiguration inbound
index a69c622352b854e6ad00ebe2faa6ef35c00e41d3..7fe82bac8ff77a4f6bfb460a498f4f7a747326fb 100644 (file)
@@ -2,5 +2,8 @@
 interface r2-eth0
  ip address 192.168.0.2/24
 !
+interface r2-eth1
+ ip address 192.168.1.2/24
+!
 ip forwarding
 !
diff --git a/tests/topotests/bgp_comm_list_match/r3/bgpd.conf b/tests/topotests/bgp_comm_list_match/r3/bgpd.conf
new file mode 100644 (file)
index 0000000..e68a3e4
--- /dev/null
@@ -0,0 +1,21 @@
+!
+!debug bgp updates
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ address-family ipv4
+  neighbor 192.168.1.2 route-map r1 in
+  neighbor 192.168.1.2 soft-reconfiguration inbound
+ exit-address-family
+!
+bgp community-list 2 seq 10 permit 65001:12
+!
+route-map r1 deny 10
+ match community 2 any
+exit
+route-map r1 permit 20
+exit
+!
diff --git a/tests/topotests/bgp_comm_list_match/r3/zebra.conf b/tests/topotests/bgp_comm_list_match/r3/zebra.conf
new file mode 100644 (file)
index 0000000..755dd18
--- /dev/null
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.1.3/24
+!
+ip forwarding
+!
index 03fa8da9d4bc12a5c30125b2bb0298de709558a2..de69ea9387eddc4577b4eab21d15961f1f97f961 100644 (file)
@@ -39,12 +39,15 @@ pytestmark = [pytest.mark.bgpd]
 
 
 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):
@@ -95,12 +98,41 @@ def test_bgp_comm_list_match():
         }
         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))
index 05fe57c7d7cc5ef4d105ffe33b786bbe445b97fe..c50c51389eca2427b062543b567015ad90d46bac 100644 (file)
@@ -777,6 +777,13 @@ identity set-extcommunity-color {
           description
             "Do exact matching of communities";
         }
+
+        leaf comm-list-name-any {
+          type boolean;
+          description
+            "Do matching of any community";
+        }
+
       }
     }