]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: don't announce prefix delete for duplicates 14526/head
authorRafael Zalamena <rzalamena@opensourcerouting.org>
Fri, 22 Sep 2023 15:28:38 +0000 (12:28 -0300)
committerMergify <37929162+mergify[bot]@users.noreply.github.com>
Tue, 3 Oct 2023 14:29:40 +0000 (14:29 +0000)
When deleting a duplicated prefix list entry don't announce the change
to route map listeners, otherwise they will be removing rules that
shouldn't be removed causing the prefix that still exist in the
prefix-list to be not evaluated anymore.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
(cherry picked from commit aed94c80967213124236ae0dfc8eebfbe9f465d5)

lib/plist.c

index e286a32f9212ba1b699fba7a5a9eaf4df8f0ac0b..2f5827cf4354543e22de20997d42888d3db7fe56 100644 (file)
@@ -402,14 +402,55 @@ static void prefix_list_trie_del(struct prefix_list *plist,
                }
 }
 
+/**
+ * Find duplicated prefix entry (same prefix but different entry) in prefix
+ * list.
+ */
+static bool prefix_list_entry_is_duplicated(struct prefix_list *list,
+                                           struct prefix_list_entry *entry)
+{
+       size_t depth, maxdepth = list->master->trie_depth;
+       uint8_t byte, *bytes = entry->prefix.u.val;
+       size_t validbits = entry->prefix.prefixlen;
+       struct pltrie_table *table = list->trie;
+       struct prefix_list_entry *pentry;
+
+       for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) {
+               byte = bytes[depth];
+               if (!table->entries[byte].next_table)
+                       return NULL;
+
+               table = table->entries[byte].next_table;
+               validbits -= PLC_BITS;
+       }
+
+       byte = bytes[depth];
+       if (validbits > PLC_BITS)
+               pentry = table->entries[byte].final_chain;
+       else
+               pentry = table->entries[byte].up_chain;
+
+       for (; pentry; pentry = pentry->next_best) {
+               if (pentry == entry)
+                       continue;
+               if (prefix_same(&pentry->prefix, &entry->prefix))
+                       return true;
+       }
+
+       return false;
+}
 
 void prefix_list_entry_delete(struct prefix_list *plist,
                              struct prefix_list_entry *pentry,
                              int update_list)
 {
+       bool duplicate;
+
        if (plist == NULL || pentry == NULL)
                return;
 
+       duplicate = prefix_list_entry_is_duplicated(plist, pentry);
+
        prefix_list_trie_del(plist, pentry);
 
        if (pentry->prev)
@@ -421,8 +462,10 @@ void prefix_list_entry_delete(struct prefix_list *plist,
        else
                plist->tail = pentry->prev;
 
-       route_map_notify_pentry_dependencies(plist->name, pentry,
-                                            RMAP_EVENT_PLIST_DELETED);
+       if (!duplicate)
+               route_map_notify_pentry_dependencies(plist->name, pentry,
+                                                    RMAP_EVENT_PLIST_DELETED);
+
        prefix_list_entry_free(pentry);
 
        plist->count--;
@@ -557,11 +600,14 @@ static void prefix_list_entry_add(struct prefix_list *plist,
 void prefix_list_entry_update_start(struct prefix_list_entry *ple)
 {
        struct prefix_list *pl = ple->pl;
+       bool duplicate;
 
        /* Not installed, nothing to do. */
        if (!ple->installed)
                return;
 
+       duplicate = prefix_list_entry_is_duplicated(pl, ple);
+
        prefix_list_trie_del(pl, ple);
 
        /* List manipulation: shameless copy from `prefix_list_entry_delete`. */
@@ -574,8 +620,9 @@ void prefix_list_entry_update_start(struct prefix_list_entry *ple)
        else
                pl->tail = ple->prev;
 
-       route_map_notify_pentry_dependencies(pl->name, ple,
-                                            RMAP_EVENT_PLIST_DELETED);
+       if (!duplicate)
+               route_map_notify_pentry_dependencies(pl->name, ple,
+                                                    RMAP_EVENT_PLIST_DELETED);
        pl->count--;
 
        route_map_notify_dependencies(pl->name, RMAP_EVENT_PLIST_DELETED);