]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_clist.c
bgpd: Adding BGP GR Global & Per Neighbour FSM changes
[mirror_frr.git] / bgpd / bgp_clist.c
index 84a00488c19565383dd81fc6c2fe646389a37897..29e668d179b34cf01f3445c9004c9d2999fd562f 100644 (file)
@@ -27,6 +27,7 @@
 #include "filter.h"
 #include "stream.h"
 #include "jhash.h"
+#include "frrstr.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_community.h"
@@ -36,9 +37,9 @@
 #include "bgpd/bgp_regex.h"
 #include "bgpd/bgp_clist.h"
 
-static uint32_t bgp_clist_hash_key_community_list(void *data)
+static uint32_t bgp_clist_hash_key_community_list(const void *data)
 {
-       struct community_list *cl = data;
+       struct community_list *cl = (struct community_list *) data;
 
        if (cl->name_hash)
                return cl->name_hash;
@@ -100,16 +101,14 @@ static void community_entry_free(struct community_entry *entry)
        case EXTCOMMUNITY_LIST_STANDARD:
                /* In case of standard extcommunity-list, configuration string
                   is made by ecommunity_ecom2str().  */
-               if (entry->config)
-                       XFREE(MTYPE_ECOMMUNITY_STR, entry->config);
+               XFREE(MTYPE_ECOMMUNITY_STR, entry->config);
                if (entry->u.ecom)
                        ecommunity_free(&entry->u.ecom);
                break;
        case COMMUNITY_LIST_EXPANDED:
        case EXTCOMMUNITY_LIST_EXPANDED:
        case LARGE_COMMUNITY_LIST_EXPANDED:
-               if (entry->config)
-                       XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
+               XFREE(MTYPE_COMMUNITY_LIST_CONFIG, entry->config);
                if (entry->reg)
                        bgp_regex_free(entry->reg);
        default:
@@ -127,8 +126,7 @@ static struct community_list *community_list_new(void)
 /* Free community-list.  */
 static void community_list_free(struct community_list *list)
 {
-       if (list->name)
-               XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name);
+       XFREE(MTYPE_COMMUNITY_LIST_NAME, list->name);
        XFREE(MTYPE_COMMUNITY_LIST, list);
 }
 
@@ -159,7 +157,7 @@ community_list_insert(struct community_list_handler *ch, const char *name,
        /* If name is made by all digit character.  We treat it as
           number. */
        for (number = 0, i = 0; i < strlen(name); i++) {
-               if (isdigit((int)name[i]))
+               if (isdigit((unsigned char)name[i]))
                        number = (number * 10) + (name[i] - '0');
                else
                        break;
@@ -698,6 +696,32 @@ int lcommunity_list_match(struct lcommunity *lcom, struct community_list *list)
        return 0;
 }
 
+
+/* Perform exact matching.  In case of expanded large-community-list, do
+ * same thing as lcommunity_list_match().
+ */
+int lcommunity_list_exact_match(struct lcommunity *lcom,
+                              struct community_list *list)
+{
+       struct community_entry *entry;
+
+       for (entry = list->head; entry; entry = entry->next) {
+               if (entry->any)
+                       return entry->direct == COMMUNITY_PERMIT ? 1 : 0;
+
+               if (entry->style == LARGE_COMMUNITY_LIST_STANDARD) {
+                       if (lcommunity_cmp(lcom, entry->u.com))
+                               return entry->direct == COMMUNITY_PERMIT ? 1
+                                                                        : 0;
+               } else if (entry->style == LARGE_COMMUNITY_LIST_EXPANDED) {
+                       if (lcommunity_regexp_match(lcom, entry->reg))
+                               return entry->direct == COMMUNITY_PERMIT ? 1
+                                                                        : 0;
+               }
+       }
+       return 0;
+}
+
 int ecommunity_list_match(struct ecommunity *ecom, struct community_list *list)
 {
        struct community_entry *entry;
@@ -799,6 +823,7 @@ struct community *community_list_match_delete(struct community *com,
        /* Delete all of the communities we flagged for deletion */
        for (i = delete_index - 1; i >= 0; i--) {
                val = community_val_get(com, com_index_to_delete[i]);
+               val = htonl(val);
                community_del_val(com, &val);
        }
 
@@ -1003,6 +1028,33 @@ struct lcommunity *lcommunity_list_match_delete(struct lcommunity *lcom,
        return lcom;
 }
 
+/* Helper to check if every octet do not exceed UINT_MAX */
+static int lcommunity_list_valid(const char *community)
+{
+       int octets = 0;
+       char **splits;
+       int num;
+
+       frrstr_split(community, ":", &splits, &num);
+
+       for (int i = 0; i < num; i++) {
+               if (strtoul(splits[i], NULL, 10) > UINT_MAX)
+                       return 0;
+
+               if (strlen(splits[i]) == 0)
+                       return 0;
+
+               octets++;
+               XFREE(MTYPE_TMP, splits[i]);
+       }
+       XFREE(MTYPE_TMP, splits);
+
+       if (octets < 3)
+               return 0;
+
+       return 1;
+}
+
 /* Set lcommunity-list.  */
 int lcommunity_list_set(struct community_list_handler *ch, const char *name,
                        const char *str, int direct, int style)
@@ -1031,6 +1083,9 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
        }
 
        if (str) {
+               if (!lcommunity_list_valid(str))
+                       return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
                if (style == LARGE_COMMUNITY_LIST_STANDARD)
                        lcom = lcommunity_str2com(str);
                else
@@ -1052,8 +1107,10 @@ int lcommunity_list_set(struct community_list_handler *ch, const char *name,
        /* Do not put duplicated community entry.  */
        if (community_list_dup_check(list, entry))
                community_entry_free(entry);
-       else
+       else {
                community_list_entry_add(list, entry);
+               route_map_notify_dependencies(name, RMAP_EVENT_LLIST_ADDED);
+       }
 
        return 0;
 }
@@ -1078,6 +1135,7 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
        /* Delete all of entry belongs to this community-list.  */
        if (!str) {
                community_list_delete(cm, list);
+               route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
                return 0;
        }
 
@@ -1103,6 +1161,7 @@ int lcommunity_list_unset(struct community_list_handler *ch, const char *name,
                return COMMUNITY_LIST_ERR_CANT_FIND_LIST;
 
        community_list_entry_delete(cm, list, entry);
+       route_map_notify_dependencies(name, RMAP_EVENT_LLIST_DELETED);
 
        return 0;
 }