back to topotato report
topotato coverage report
Current view: top level - lib - plist.c (source / functions) Hit Total Coverage
Test: test_ospf6_vlink.py::VirtualLinkBasic Lines: 57 731 7.8 %
Date: 2023-02-16 02:06:43 Functions: 15 57 26.3 %

          Line data    Source code
       1             : /* Prefix list functions.
       2             :  * Copyright (C) 1999 Kunihiro Ishiguro
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published
       8             :  * by the Free Software Foundation; either version 2, or (at your
       9             :  * option) any later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include "prefix.h"
      24             : #include "command.h"
      25             : #include "memory.h"
      26             : #include "plist.h"
      27             : #include "sockunion.h"
      28             : #include "buffer.h"
      29             : #include "log.h"
      30             : #include "routemap.h"
      31             : #include "lib/json.h"
      32             : #include "libfrr.h"
      33             : 
      34             : #include <typesafe.h>
      35             : #include "plist_int.h"
      36             : 
      37          48 : DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST, "Prefix List");
      38          48 : DEFINE_MTYPE_STATIC(LIB, MPREFIX_LIST_STR, "Prefix List Str");
      39          48 : DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_ENTRY, "Prefix List Entry");
      40          48 : DEFINE_MTYPE_STATIC(LIB, PREFIX_LIST_TRIE, "Prefix List Trie Table");
      41             : 
      42             : /* not currently changeable, code assumes bytes further down */
      43             : #define PLC_BITS        8
      44             : #define PLC_LEN         (1 << PLC_BITS)
      45             : #define PLC_MAXLEVELV4  2       /* /24 for IPv4 */
      46             : #define PLC_MAXLEVELV6  4       /* /48 for IPv6 */
      47             : #define PLC_MAXLEVEL    4       /* max(v4,v6) */
      48             : 
      49             : struct pltrie_entry {
      50             :         union {
      51             :                 struct pltrie_table *next_table;
      52             :                 struct prefix_list_entry *final_chain;
      53             :         };
      54             : 
      55             :         struct prefix_list_entry *up_chain;
      56             : };
      57             : 
      58             : struct pltrie_table {
      59             :         struct pltrie_entry entries[PLC_LEN];
      60             : };
      61             : 
      62             : /* Master structure of prefix_list. */
      63             : struct prefix_master {
      64             :         /* The latest update. */
      65             :         struct prefix_list *recent;
      66             : 
      67             :         /* Hook function which is executed when new prefix_list is added. */
      68             :         void (*add_hook)(struct prefix_list *);
      69             : 
      70             :         /* Hook function which is executed when prefix_list is deleted. */
      71             :         void (*delete_hook)(struct prefix_list *);
      72             : 
      73             :         /* number of bytes that have a trie level */
      74             :         size_t trie_depth;
      75             : 
      76             :         struct plist_head str;
      77             : };
      78             : static int prefix_list_compare_func(const struct prefix_list *a,
      79             :                                     const struct prefix_list *b);
      80          64 : DECLARE_RBTREE_UNIQ(plist, struct prefix_list, plist_item,
      81             :                     prefix_list_compare_func);
      82             : 
      83             : /* Static structure of IPv4 prefix_list's master. */
      84             : static struct prefix_master prefix_master_ipv4 = {
      85             :         NULL, NULL, NULL, PLC_MAXLEVELV4,
      86             : };
      87             : 
      88             : /* Static structure of IPv6 prefix-list's master. */
      89             : static struct prefix_master prefix_master_ipv6 = {
      90             :         NULL, NULL, NULL, PLC_MAXLEVELV6,
      91             : };
      92             : 
      93             : /* Static structure of BGP ORF prefix_list's master. */
      94             : static struct prefix_master prefix_master_orf_v4 = {
      95             :         NULL, NULL, NULL, PLC_MAXLEVELV4,
      96             : };
      97             : 
      98             : /* Static structure of BGP ORF prefix_list's master. */
      99             : static struct prefix_master prefix_master_orf_v6 = {
     100             :         NULL, NULL, NULL, PLC_MAXLEVELV6,
     101             : };
     102             : 
     103          64 : static struct prefix_master *prefix_master_get(afi_t afi, int orf)
     104             : {
     105          64 :         if (afi == AFI_IP)
     106          32 :                 return orf ? &prefix_master_orf_v4 : &prefix_master_ipv4;
     107          32 :         if (afi == AFI_IP6)
     108          32 :                 return orf ? &prefix_master_orf_v6 : &prefix_master_ipv6;
     109             :         return NULL;
     110             : }
     111             : 
     112           0 : const char *prefix_list_name(struct prefix_list *plist)
     113             : {
     114           0 :         return plist->name;
     115             : }
     116             : 
     117           0 : afi_t prefix_list_afi(struct prefix_list *plist)
     118             : {
     119           0 :         if (plist->master == &prefix_master_ipv4
     120           0 :             || plist->master == &prefix_master_orf_v4)
     121           0 :                 return AFI_IP;
     122             :         return AFI_IP6;
     123             : }
     124             : 
     125           0 : static int prefix_list_compare_func(const struct prefix_list *a,
     126             :                                     const struct prefix_list *b)
     127             : {
     128           0 :         return strcmp(a->name, b->name);
     129             : }
     130             : 
     131             : /* Lookup prefix_list from list of prefix_list by name. */
     132           0 : static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf,
     133             :                                                  const char *name)
     134             : {
     135           0 :         struct prefix_list *plist, lookup;
     136           0 :         struct prefix_master *master;
     137             : 
     138           0 :         if (name == NULL)
     139             :                 return NULL;
     140             : 
     141           0 :         master = prefix_master_get(afi, orf);
     142             :         if (master == NULL)
     143             :                 return NULL;
     144             : 
     145           0 :         lookup.name = XSTRDUP(MTYPE_TMP, name);
     146           0 :         plist = plist_find(&master->str, &lookup);
     147           0 :         XFREE(MTYPE_TMP, lookup.name);
     148           0 :         return plist;
     149             : }
     150             : 
     151           0 : struct prefix_list *prefix_list_lookup(afi_t afi, const char *name)
     152             : {
     153           0 :         return prefix_list_lookup_do(afi, 0, name);
     154             : }
     155             : 
     156           0 : struct prefix_list *prefix_bgp_orf_lookup(afi_t afi, const char *name)
     157             : {
     158           0 :         return prefix_list_lookup_do(afi, 1, name);
     159             : }
     160             : 
     161           0 : static struct prefix_list *prefix_list_new(void)
     162             : {
     163           0 :         struct prefix_list *new;
     164             : 
     165           0 :         new = XCALLOC(MTYPE_PREFIX_LIST, sizeof(struct prefix_list));
     166           0 :         return new;
     167             : }
     168             : 
     169           0 : static void prefix_list_free(struct prefix_list *plist)
     170             : {
     171           0 :         XFREE(MTYPE_PREFIX_LIST, plist);
     172             : }
     173             : 
     174           0 : struct prefix_list_entry *prefix_list_entry_new(void)
     175             : {
     176           0 :         struct prefix_list_entry *new;
     177             : 
     178           0 :         new = XCALLOC(MTYPE_PREFIX_LIST_ENTRY,
     179             :                       sizeof(struct prefix_list_entry));
     180           0 :         return new;
     181             : }
     182             : 
     183           0 : void prefix_list_entry_free(struct prefix_list_entry *pentry)
     184             : {
     185           0 :         XFREE(MTYPE_PREFIX_LIST_ENTRY, pentry);
     186           0 : }
     187             : 
     188             : /* Insert new prefix list to list of prefix_list.  Each prefix_list
     189             :    is sorted by the name. */
     190           0 : static struct prefix_list *prefix_list_insert(afi_t afi, int orf,
     191             :                                               const char *name)
     192             : {
     193           0 :         struct prefix_list *plist;
     194           0 :         struct prefix_master *master;
     195             : 
     196           0 :         master = prefix_master_get(afi, orf);
     197             :         if (master == NULL)
     198             :                 return NULL;
     199             : 
     200             :         /* Allocate new prefix_list and copy given name. */
     201           0 :         plist = prefix_list_new();
     202           0 :         plist->name = XSTRDUP(MTYPE_MPREFIX_LIST_STR, name);
     203           0 :         plist->master = master;
     204           0 :         plist->trie =
     205           0 :                 XCALLOC(MTYPE_PREFIX_LIST_TRIE, sizeof(struct pltrie_table));
     206             : 
     207           0 :         plist_add(&master->str, plist);
     208             : 
     209           0 :         return plist;
     210             : }
     211             : 
     212           0 : struct prefix_list *prefix_list_get(afi_t afi, int orf, const char *name)
     213             : {
     214           0 :         struct prefix_list *plist;
     215             : 
     216           0 :         plist = prefix_list_lookup_do(afi, orf, name);
     217             : 
     218           0 :         if (plist == NULL)
     219           0 :                 plist = prefix_list_insert(afi, orf, name);
     220           0 :         return plist;
     221             : }
     222             : 
     223             : static void prefix_list_trie_del(struct prefix_list *plist,
     224             :                                  struct prefix_list_entry *pentry);
     225             : 
     226             : /* Delete prefix-list from prefix_list_master and free it. */
     227           0 : void prefix_list_delete(struct prefix_list *plist)
     228             : {
     229           0 :         struct prefix_master *master;
     230           0 :         struct prefix_list_entry *pentry;
     231           0 :         struct prefix_list_entry *next;
     232             : 
     233             :         /* If prefix-list contain prefix_list_entry free all of it. */
     234           0 :         for (pentry = plist->head; pentry; pentry = next) {
     235           0 :                 route_map_notify_pentry_dependencies(plist->name, pentry,
     236             :                                                      RMAP_EVENT_PLIST_DELETED);
     237           0 :                 next = pentry->next;
     238           0 :                 prefix_list_trie_del(plist, pentry);
     239           0 :                 prefix_list_entry_free(pentry);
     240           0 :                 plist->count--;
     241             :         }
     242             : 
     243           0 :         master = plist->master;
     244             : 
     245           0 :         plist_del(&master->str, plist);
     246             : 
     247           0 :         XFREE(MTYPE_TMP, plist->desc);
     248             : 
     249             :         /* Make sure master's recent changed prefix-list information is
     250             :            cleared. */
     251           0 :         master->recent = NULL;
     252             : 
     253           0 :         route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
     254             : 
     255           0 :         if (master->delete_hook)
     256           0 :                 (*master->delete_hook)(plist);
     257             : 
     258           0 :         XFREE(MTYPE_MPREFIX_LIST_STR, plist->name);
     259             : 
     260           0 :         XFREE(MTYPE_PREFIX_LIST_TRIE, plist->trie);
     261             : 
     262           0 :         prefix_list_free(plist);
     263           0 : }
     264             : 
     265             : static struct prefix_list_entry *
     266           0 : prefix_list_entry_make(struct prefix *prefix, enum prefix_list_type type,
     267             :                        int64_t seq, int le, int ge, bool any)
     268             : {
     269           0 :         struct prefix_list_entry *pentry;
     270             : 
     271           0 :         pentry = prefix_list_entry_new();
     272             : 
     273           0 :         if (any)
     274           0 :                 pentry->any = true;
     275             : 
     276           0 :         prefix_copy(&pentry->prefix, prefix);
     277           0 :         pentry->type = type;
     278           0 :         pentry->seq = seq;
     279           0 :         pentry->le = le;
     280           0 :         pentry->ge = ge;
     281             : 
     282           0 :         return pentry;
     283             : }
     284             : 
     285             : /* Add hook function. */
     286          16 : void prefix_list_add_hook(void (*func)(struct prefix_list *plist))
     287             : {
     288          16 :         prefix_master_ipv4.add_hook = func;
     289          16 :         prefix_master_ipv6.add_hook = func;
     290          16 : }
     291             : 
     292             : /* Delete hook function. */
     293          16 : void prefix_list_delete_hook(void (*func)(struct prefix_list *plist))
     294             : {
     295          16 :         prefix_master_ipv4.delete_hook = func;
     296          16 :         prefix_master_ipv6.delete_hook = func;
     297          16 : }
     298             : 
     299             : /* Calculate new sequential number. */
     300           0 : int64_t prefix_new_seq_get(struct prefix_list *plist)
     301             : {
     302           0 :         int64_t maxseq;
     303           0 :         int64_t newseq;
     304           0 :         struct prefix_list_entry *pentry;
     305             : 
     306           0 :         maxseq = 0;
     307             : 
     308           0 :         for (pentry = plist->head; pentry; pentry = pentry->next) {
     309           0 :                 if (maxseq < pentry->seq)
     310             :                         maxseq = pentry->seq;
     311             :         }
     312             : 
     313           0 :         newseq = ((maxseq / 5) * 5) + 5;
     314             : 
     315           0 :         return (newseq > UINT_MAX) ? UINT_MAX : newseq;
     316             : }
     317             : 
     318             : /* Return prefix list entry which has same seq number. */
     319           0 : static struct prefix_list_entry *prefix_seq_check(struct prefix_list *plist,
     320             :                                                   int64_t seq)
     321             : {
     322           0 :         struct prefix_list_entry *pentry;
     323             : 
     324           0 :         for (pentry = plist->head; pentry; pentry = pentry->next)
     325           0 :                 if (pentry->seq == seq)
     326             :                         return pentry;
     327             :         return NULL;
     328             : }
     329             : 
     330             : struct prefix_list_entry *
     331           0 : prefix_list_entry_lookup(struct prefix_list *plist, struct prefix *prefix,
     332             :                          enum prefix_list_type type, int64_t seq,
     333             :                          int le, int ge)
     334             : {
     335           0 :         struct prefix_list_entry *pentry;
     336             : 
     337           0 :         for (pentry = plist->head; pentry; pentry = pentry->next)
     338           0 :                 if (prefix_same(&pentry->prefix, prefix)
     339           0 :                     && pentry->type == type) {
     340           0 :                         if (seq >= 0 && pentry->seq != seq)
     341           0 :                                 continue;
     342             : 
     343           0 :                         if (pentry->le != le)
     344           0 :                                 continue;
     345           0 :                         if (pentry->ge != ge)
     346           0 :                                 continue;
     347             : 
     348           0 :                         return pentry;
     349             :                 }
     350             : 
     351             :         return NULL;
     352             : }
     353             : 
     354           0 : static void trie_walk_affected(size_t validbits, struct pltrie_table *table,
     355             :                                uint8_t byte, struct prefix_list_entry *object,
     356             :                                void (*fn)(struct prefix_list_entry *object,
     357             :                                           struct prefix_list_entry **updptr))
     358             : {
     359           0 :         uint8_t mask;
     360           0 :         uint16_t bwalk;
     361             : 
     362           0 :         if (validbits > PLC_BITS) {
     363           0 :                 fn(object, &table->entries[byte].final_chain);
     364           0 :                 return;
     365             :         }
     366             : 
     367           0 :         mask = (1 << (8 - validbits)) - 1;
     368           0 :         for (bwalk = byte & ~mask; bwalk <= byte + mask; bwalk++) {
     369           0 :                 fn(object, &table->entries[bwalk].up_chain);
     370             :         }
     371             : }
     372             : 
     373           0 : static void trie_uninstall_fn(struct prefix_list_entry *object,
     374             :                               struct prefix_list_entry **updptr)
     375             : {
     376           0 :         for (; *updptr; updptr = &(*updptr)->next_best)
     377           0 :                 if (*updptr == object) {
     378           0 :                         *updptr = object->next_best;
     379           0 :                         break;
     380             :                 }
     381           0 : }
     382             : 
     383           0 : static int trie_table_empty(struct pltrie_table *table)
     384             : {
     385           0 :         size_t i;
     386           0 :         for (i = 0; i < PLC_LEN; i++)
     387           0 :                 if (table->entries[i].next_table || table->entries[i].up_chain)
     388             :                         return 0;
     389             :         return 1;
     390             : }
     391             : 
     392           0 : static void prefix_list_trie_del(struct prefix_list *plist,
     393             :                                  struct prefix_list_entry *pentry)
     394             : {
     395           0 :         size_t depth, maxdepth = plist->master->trie_depth;
     396           0 :         uint8_t *bytes = pentry->prefix.u.val;
     397           0 :         size_t validbits = pentry->prefix.prefixlen;
     398           0 :         struct pltrie_table *table, **tables[PLC_MAXLEVEL];
     399             : 
     400           0 :         table = plist->trie;
     401           0 :         for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) {
     402           0 :                 uint8_t byte = bytes[depth];
     403           0 :                 assert(table->entries[byte].next_table);
     404             : 
     405           0 :                 tables[depth + 1] = &table->entries[byte].next_table;
     406           0 :                 table = table->entries[byte].next_table;
     407             : 
     408           0 :                 validbits -= PLC_BITS;
     409             :         }
     410             : 
     411           0 :         trie_walk_affected(validbits, table, bytes[depth], pentry,
     412             :                            trie_uninstall_fn);
     413             : 
     414           0 :         for (; depth > 0; depth--)
     415           0 :                 if (trie_table_empty(*tables[depth])) {
     416           0 :                         XFREE(MTYPE_PREFIX_LIST_TRIE, *tables[depth]);
     417             :                 }
     418           0 : }
     419             : 
     420             : 
     421           0 : void prefix_list_entry_delete(struct prefix_list *plist,
     422             :                               struct prefix_list_entry *pentry,
     423             :                               int update_list)
     424             : {
     425           0 :         if (plist == NULL || pentry == NULL)
     426             :                 return;
     427             : 
     428           0 :         prefix_list_trie_del(plist, pentry);
     429             : 
     430           0 :         if (pentry->prev)
     431           0 :                 pentry->prev->next = pentry->next;
     432             :         else
     433           0 :                 plist->head = pentry->next;
     434           0 :         if (pentry->next)
     435           0 :                 pentry->next->prev = pentry->prev;
     436             :         else
     437           0 :                 plist->tail = pentry->prev;
     438             : 
     439           0 :         route_map_notify_pentry_dependencies(plist->name, pentry,
     440             :                                              RMAP_EVENT_PLIST_DELETED);
     441           0 :         prefix_list_entry_free(pentry);
     442             : 
     443           0 :         plist->count--;
     444             : 
     445           0 :         if (update_list) {
     446           0 :                 route_map_notify_dependencies(plist->name,
     447             :                                               RMAP_EVENT_PLIST_DELETED);
     448           0 :                 if (plist->master->delete_hook)
     449           0 :                         (*plist->master->delete_hook)(plist);
     450             : 
     451           0 :                 if (plist->head == NULL && plist->tail == NULL
     452           0 :                     && plist->desc == NULL)
     453           0 :                         prefix_list_delete(plist);
     454             :                 else
     455           0 :                         plist->master->recent = plist;
     456             :         }
     457             : }
     458             : 
     459           0 : static void trie_install_fn(struct prefix_list_entry *object,
     460             :                             struct prefix_list_entry **updptr)
     461             : {
     462           0 :         while (*updptr) {
     463           0 :                 if (*updptr == object)
     464             :                         return;
     465           0 :                 if ((*updptr)->prefix.prefixlen < object->prefix.prefixlen)
     466             :                         break;
     467           0 :                 if ((*updptr)->prefix.prefixlen == object->prefix.prefixlen
     468           0 :                     && (*updptr)->seq > object->seq)
     469             :                         break;
     470           0 :                 updptr = &(*updptr)->next_best;
     471             :         }
     472             : 
     473           0 :         if (!object->next_best)
     474           0 :                 object->next_best = *updptr;
     475             :         else
     476           0 :                 assert(object->next_best == *updptr || !*updptr);
     477             : 
     478           0 :         *updptr = object;
     479             : }
     480             : 
     481           0 : static void prefix_list_trie_add(struct prefix_list *plist,
     482             :                                  struct prefix_list_entry *pentry)
     483             : {
     484           0 :         size_t depth = plist->master->trie_depth;
     485           0 :         uint8_t *bytes = pentry->prefix.u.val;
     486           0 :         size_t validbits = pentry->prefix.prefixlen;
     487           0 :         struct pltrie_table *table;
     488             : 
     489           0 :         table = plist->trie;
     490           0 :         while (validbits > PLC_BITS && depth > 1) {
     491           0 :                 if (!table->entries[*bytes].next_table)
     492           0 :                         table->entries[*bytes].next_table =
     493           0 :                                 XCALLOC(MTYPE_PREFIX_LIST_TRIE,
     494             :                                         sizeof(struct pltrie_table));
     495           0 :                 table = table->entries[*bytes].next_table;
     496           0 :                 bytes++;
     497           0 :                 depth--;
     498           0 :                 validbits -= PLC_BITS;
     499             :         }
     500             : 
     501           0 :         trie_walk_affected(validbits, table, *bytes, pentry, trie_install_fn);
     502           0 : }
     503             : 
     504           0 : static void prefix_list_entry_add(struct prefix_list *plist,
     505             :                                   struct prefix_list_entry *pentry)
     506             : {
     507           0 :         struct prefix_list_entry *replace;
     508           0 :         struct prefix_list_entry *point;
     509             : 
     510             :         /* Automatic asignment of seq no. */
     511           0 :         if (pentry->seq == -1)
     512           0 :                 pentry->seq = prefix_new_seq_get(plist);
     513             : 
     514           0 :         if (plist->tail && pentry->seq > plist->tail->seq)
     515             :                 point = NULL;
     516             :         else {
     517             :                 /* Is there any same seq prefix list entry? */
     518           0 :                 replace = prefix_seq_check(plist, pentry->seq);
     519           0 :                 if (replace)
     520           0 :                         prefix_list_entry_delete(plist, replace, 0);
     521             : 
     522             :                 /* Check insert point. */
     523           0 :                 for (point = plist->head; point; point = point->next)
     524           0 :                         if (point->seq >= pentry->seq)
     525             :                                 break;
     526             :         }
     527             : 
     528             :         /* In case of this is the first element of the list. */
     529           0 :         pentry->next = point;
     530             : 
     531           0 :         if (point) {
     532           0 :                 if (point->prev)
     533           0 :                         point->prev->next = pentry;
     534             :                 else
     535           0 :                         plist->head = pentry;
     536             : 
     537           0 :                 pentry->prev = point->prev;
     538           0 :                 point->prev = pentry;
     539             :         } else {
     540           0 :                 if (plist->tail)
     541           0 :                         plist->tail->next = pentry;
     542             :                 else
     543           0 :                         plist->head = pentry;
     544             : 
     545           0 :                 pentry->prev = plist->tail;
     546           0 :                 plist->tail = pentry;
     547             :         }
     548             : 
     549           0 :         prefix_list_trie_add(plist, pentry);
     550             : 
     551             :         /* Increment count. */
     552           0 :         plist->count++;
     553             : 
     554           0 :         route_map_notify_pentry_dependencies(plist->name, pentry,
     555             :                                              RMAP_EVENT_PLIST_ADDED);
     556             : 
     557             :         /* Run hook function. */
     558           0 :         if (plist->master->add_hook)
     559           0 :                 (*plist->master->add_hook)(plist);
     560             : 
     561           0 :         route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_ADDED);
     562           0 :         plist->master->recent = plist;
     563           0 : }
     564             : 
     565             : /**
     566             :  * Prefix list entry update start procedure:
     567             :  * Remove entry from previosly installed master list, tries and notify
     568             :  * observers.
     569             :  *
     570             :  * \param[in] ple prefix list entry.
     571             :  */
     572           0 : void prefix_list_entry_update_start(struct prefix_list_entry *ple)
     573             : {
     574           0 :         struct prefix_list *pl = ple->pl;
     575             : 
     576             :         /* Not installed, nothing to do. */
     577           0 :         if (!ple->installed)
     578             :                 return;
     579             : 
     580           0 :         prefix_list_trie_del(pl, ple);
     581             : 
     582             :         /* List manipulation: shameless copy from `prefix_list_entry_delete`. */
     583           0 :         if (ple->prev)
     584           0 :                 ple->prev->next = ple->next;
     585             :         else
     586           0 :                 pl->head = ple->next;
     587           0 :         if (ple->next)
     588           0 :                 ple->next->prev = ple->prev;
     589             :         else
     590           0 :                 pl->tail = ple->prev;
     591             : 
     592           0 :         route_map_notify_pentry_dependencies(pl->name, ple,
     593             :                                              RMAP_EVENT_PLIST_DELETED);
     594           0 :         pl->count--;
     595             : 
     596           0 :         route_map_notify_dependencies(pl->name, RMAP_EVENT_PLIST_DELETED);
     597           0 :         if (pl->master->delete_hook)
     598           0 :                 (*pl->master->delete_hook)(pl);
     599             : 
     600           0 :         if (pl->head || pl->tail || pl->desc)
     601           0 :                 pl->master->recent = pl;
     602             : 
     603           0 :         ple->next_best = NULL;
     604           0 :         ple->installed = false;
     605             : }
     606             : 
     607             : /**
     608             :  * Prefix list entry update finish procedure:
     609             :  * Add entry back master list, to the trie, notify observers and call master
     610             :  * hook.
     611             :  *
     612             :  * \param[in] ple prefix list entry.
     613             :  */
     614           0 : void prefix_list_entry_update_finish(struct prefix_list_entry *ple)
     615             : {
     616           0 :         struct prefix_list *pl = ple->pl;
     617           0 :         struct prefix_list_entry *point;
     618             : 
     619             :         /* Already installed, nothing to do. */
     620           0 :         if (ple->installed)
     621             :                 return;
     622             : 
     623             :         /*
     624             :          * Check if the entry is installable:
     625             :          * We can only install entry if at least the prefix is provided (IPv4
     626             :          * or IPv6).
     627             :          */
     628           0 :         if (ple->prefix.family != AF_INET && ple->prefix.family != AF_INET6)
     629             :                 return;
     630             : 
     631             :         /* List manipulation: shameless copy from `prefix_list_entry_add`. */
     632           0 :         if (pl->tail && ple->seq > pl->tail->seq)
     633             :                 point = NULL;
     634             :         else {
     635             :                 /* Check insert point. */
     636           0 :                 for (point = pl->head; point; point = point->next)
     637           0 :                         if (point->seq >= ple->seq)
     638             :                                 break;
     639             :         }
     640             : 
     641             :         /* In case of this is the first element of the list. */
     642           0 :         ple->next = point;
     643             : 
     644           0 :         if (point) {
     645           0 :                 if (point->prev)
     646           0 :                         point->prev->next = ple;
     647             :                 else
     648           0 :                         pl->head = ple;
     649             : 
     650           0 :                 ple->prev = point->prev;
     651           0 :                 point->prev = ple;
     652             :         } else {
     653           0 :                 if (pl->tail)
     654           0 :                         pl->tail->next = ple;
     655             :                 else
     656           0 :                         pl->head = ple;
     657             : 
     658           0 :                 ple->prev = pl->tail;
     659           0 :                 pl->tail = ple;
     660             :         }
     661             : 
     662           0 :         prefix_list_trie_add(pl, ple);
     663           0 :         pl->count++;
     664             : 
     665           0 :         route_map_notify_pentry_dependencies(pl->name, ple,
     666             :                                              RMAP_EVENT_PLIST_ADDED);
     667             : 
     668             :         /* Run hook function. */
     669           0 :         if (pl->master->add_hook)
     670           0 :                 (*pl->master->add_hook)(pl);
     671             : 
     672           0 :         route_map_notify_dependencies(pl->name, RMAP_EVENT_PLIST_ADDED);
     673           0 :         pl->master->recent = pl;
     674             : 
     675           0 :         ple->installed = true;
     676             : }
     677             : 
     678             : /**
     679             :  * Same as `prefix_list_entry_delete` but without `free()`ing the list if its
     680             :  * empty.
     681             :  *
     682             :  * \param[in] ple prefix list entry.
     683             :  */
     684           0 : void prefix_list_entry_delete2(struct prefix_list_entry *ple)
     685             : {
     686             :         /* Does the boiler plate list removal and entry removal notification. */
     687           0 :         prefix_list_entry_update_start(ple);
     688             : 
     689             :         /* Effective `free()` memory. */
     690           0 :         prefix_list_entry_free(ple);
     691           0 : }
     692             : 
     693             : /* Return string of prefix_list_type. */
     694           0 : static const char *prefix_list_type_str(struct prefix_list_entry *pentry)
     695             : {
     696           0 :         switch (pentry->type) {
     697             :         case PREFIX_PERMIT:
     698             :                 return "permit";
     699           0 :         case PREFIX_DENY:
     700           0 :                 return "deny";
     701           0 :         default:
     702           0 :                 return "";
     703             :         }
     704             : }
     705             : 
     706           0 : static int prefix_list_entry_match(struct prefix_list_entry *pentry,
     707             :                                    const struct prefix *p, bool address_mode)
     708             : {
     709           0 :         int ret;
     710             : 
     711           0 :         if (pentry->prefix.family != p->family)
     712             :                 return 0;
     713             : 
     714           0 :         ret = prefix_match(&pentry->prefix, p);
     715           0 :         if (!ret)
     716             :                 return 0;
     717             : 
     718           0 :         if (address_mode)
     719             :                 return 1;
     720             : 
     721             :         /* In case of le nor ge is specified, exact match is performed. */
     722           0 :         if (!pentry->le && !pentry->ge) {
     723           0 :                 if (pentry->prefix.prefixlen != p->prefixlen)
     724             :                         return 0;
     725             :         } else {
     726           0 :                 if (pentry->le)
     727           0 :                         if (p->prefixlen > pentry->le)
     728             :                                 return 0;
     729             : 
     730           0 :                 if (pentry->ge)
     731           0 :                         if (p->prefixlen < pentry->ge)
     732             :                                 return 0;
     733             :         }
     734             :         return 1;
     735             : }
     736             : 
     737           0 : enum prefix_list_type prefix_list_apply_ext(
     738             :         struct prefix_list *plist,
     739             :         const struct prefix_list_entry **which,
     740             :         union prefixconstptr object,
     741             :         bool address_mode)
     742             : {
     743           0 :         struct prefix_list_entry *pentry, *pbest = NULL;
     744             : 
     745           0 :         const struct prefix *p = object.p;
     746           0 :         const uint8_t *byte = p->u.val;
     747           0 :         size_t depth;
     748           0 :         size_t validbits = p->prefixlen;
     749           0 :         struct pltrie_table *table;
     750             : 
     751           0 :         if (plist == NULL) {
     752           0 :                 if (which)
     753           0 :                         *which = NULL;
     754           0 :                 return PREFIX_DENY;
     755             :         }
     756             : 
     757           0 :         if (plist->count == 0) {
     758           0 :                 if (which)
     759           0 :                         *which = NULL;
     760           0 :                 return PREFIX_PERMIT;
     761             :         }
     762             : 
     763           0 :         depth = plist->master->trie_depth;
     764           0 :         table = plist->trie;
     765           0 :         while (1) {
     766           0 :                 for (pentry = table->entries[*byte].up_chain; pentry;
     767           0 :                      pentry = pentry->next_best) {
     768           0 :                         if (pbest && pbest->seq < pentry->seq)
     769           0 :                                 continue;
     770           0 :                         if (prefix_list_entry_match(pentry, p, address_mode))
     771           0 :                                 pbest = pentry;
     772             :                 }
     773             : 
     774           0 :                 if (validbits <= PLC_BITS)
     775             :                         break;
     776           0 :                 validbits -= PLC_BITS;
     777             : 
     778           0 :                 if (--depth) {
     779           0 :                         if (!table->entries[*byte].next_table)
     780             :                                 break;
     781             : 
     782           0 :                         table = table->entries[*byte].next_table;
     783           0 :                         byte++;
     784           0 :                         continue;
     785             :                 }
     786             : 
     787           0 :                 for (pentry = table->entries[*byte].final_chain; pentry;
     788           0 :                      pentry = pentry->next_best) {
     789           0 :                         if (pbest && pbest->seq < pentry->seq)
     790           0 :                                 continue;
     791           0 :                         if (prefix_list_entry_match(pentry, p, address_mode))
     792           0 :                                 pbest = pentry;
     793             :                 }
     794             :                 break;
     795             :         }
     796             : 
     797           0 :         if (which) {
     798           0 :                 if (pbest)
     799           0 :                         *which = pbest;
     800             :                 else
     801           0 :                         *which = NULL;
     802             :         }
     803             : 
     804           0 :         if (pbest == NULL)
     805           0 :                 return PREFIX_DENY;
     806             : 
     807           0 :         pbest->hitcnt++;
     808           0 :         return pbest->type;
     809             : }
     810             : 
     811             : static void __attribute__((unused)) prefix_list_print(struct prefix_list *plist)
     812             : {
     813             :         struct prefix_list_entry *pentry;
     814             : 
     815             :         if (plist == NULL)
     816             :                 return;
     817             : 
     818             :         printf("ip prefix-list %s: %d entries\n", plist->name, plist->count);
     819             : 
     820             :         for (pentry = plist->head; pentry; pentry = pentry->next) {
     821             :                 if (pentry->any)
     822             :                         printf("any %s\n", prefix_list_type_str(pentry));
     823             :                 else {
     824             :                         struct prefix *p;
     825             : 
     826             :                         p = &pentry->prefix;
     827             : 
     828             :                         printf("  seq %lld %s %pFX", (long long)pentry->seq,
     829             :                                prefix_list_type_str(pentry), p);
     830             :                         if (pentry->ge)
     831             :                                 printf(" ge %d", pentry->ge);
     832             :                         if (pentry->le)
     833             :                                 printf(" le %d", pentry->le);
     834             :                         printf("\n");
     835             :                 }
     836             :         }
     837             : }
     838             : 
     839             : /* Return 1 when plist already include pentry policy. */
     840             : static struct prefix_list_entry *
     841           0 : prefix_entry_dup_check(struct prefix_list *plist, struct prefix_list_entry *new)
     842             : {
     843           0 :         size_t depth, maxdepth = plist->master->trie_depth;
     844           0 :         uint8_t byte, *bytes = new->prefix.u.val;
     845           0 :         size_t validbits = new->prefix.prefixlen;
     846           0 :         struct pltrie_table *table;
     847           0 :         struct prefix_list_entry *pentry;
     848           0 :         int64_t seq = 0;
     849             : 
     850           0 :         if (new->seq == -1)
     851           0 :                 seq = prefix_new_seq_get(plist);
     852             :         else
     853             :                 seq = new->seq;
     854             : 
     855           0 :         table = plist->trie;
     856           0 :         for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) {
     857           0 :                 byte = bytes[depth];
     858           0 :                 if (!table->entries[byte].next_table)
     859             :                         return NULL;
     860             : 
     861           0 :                 table = table->entries[byte].next_table;
     862           0 :                 validbits -= PLC_BITS;
     863             :         }
     864             : 
     865           0 :         byte = bytes[depth];
     866           0 :         if (validbits > PLC_BITS)
     867           0 :                 pentry = table->entries[byte].final_chain;
     868             :         else
     869           0 :                 pentry = table->entries[byte].up_chain;
     870             : 
     871           0 :         for (; pentry; pentry = pentry->next_best) {
     872           0 :                 if (prefix_same(&pentry->prefix, &new->prefix)
     873           0 :                     && pentry->type == new->type && pentry->le == new->le
     874           0 :                     && pentry->ge == new->ge && pentry->seq != seq)
     875           0 :                         return pentry;
     876             :         }
     877             :         return NULL;
     878             : }
     879             : 
     880             : enum display_type {
     881             :         normal_display,
     882             :         summary_display,
     883             :         detail_display,
     884             :         sequential_display,
     885             :         longer_display,
     886             :         first_match_display
     887             : };
     888             : 
     889           0 : static void vty_show_prefix_entry(struct vty *vty, json_object *json, afi_t afi,
     890             :                                   struct prefix_list *plist,
     891             :                                   struct prefix_master *master,
     892             :                                   enum display_type dtype, int seqnum)
     893             : {
     894           0 :         struct prefix_list_entry *pentry;
     895           0 :         json_object *json_pl = NULL;
     896             : 
     897             :         /* Print the name of the protocol */
     898           0 :         if (json) {
     899           0 :                 json_pl = json_object_new_object();
     900           0 :                 json_object_object_add(json, plist->name, json_pl);
     901             :         } else
     902           0 :                 vty_out(vty, "%s: ", frr_protoname);
     903             : 
     904           0 :         if (dtype == normal_display) {
     905           0 :                 if (json) {
     906           0 :                         json_object_string_add(json_pl, "addressFamily",
     907             :                                                afi2str(afi));
     908           0 :                         json_object_int_add(json_pl, "entries", plist->count);
     909           0 :                         if (plist->desc)
     910           0 :                                 json_object_string_add(json_pl, "description",
     911             :                                                        plist->desc);
     912             :                 } else {
     913           0 :                         vty_out(vty, "ip%s prefix-list %s: %d entries\n",
     914             :                                 afi == AFI_IP ? "" : "v6", plist->name,
     915             :                                 plist->count);
     916           0 :                         if (plist->desc)
     917           0 :                                 vty_out(vty, "   Description: %s\n",
     918             :                                         plist->desc);
     919             :                 }
     920           0 :         } else if (dtype == summary_display || dtype == detail_display) {
     921           0 :                 if (json) {
     922           0 :                         json_object_string_add(json_pl, "addressFamily",
     923             :                                                afi2str(afi));
     924           0 :                         if (plist->desc)
     925           0 :                                 json_object_string_add(json_pl, "description",
     926             :                                                        plist->desc);
     927           0 :                         json_object_int_add(json_pl, "count", plist->count);
     928           0 :                         json_object_int_add(json_pl, "rangeEntries",
     929           0 :                                             plist->rangecount);
     930           0 :                         json_object_int_add(json_pl, "sequenceStart",
     931           0 :                                             plist->head ? plist->head->seq : 0);
     932           0 :                         json_object_int_add(json_pl, "sequenceEnd",
     933           0 :                                             plist->tail ? plist->tail->seq : 0);
     934             :                 } else {
     935           0 :                         vty_out(vty, "ip%s prefix-list %s:\n",
     936             :                                 afi == AFI_IP ? "" : "v6", plist->name);
     937             : 
     938           0 :                         if (plist->desc)
     939           0 :                                 vty_out(vty, "   Description: %s\n",
     940             :                                         plist->desc);
     941             : 
     942           0 :                         vty_out(vty,
     943             :                                 "   count: %d, range entries: %d, sequences: %" PRId64
     944             :                                 " - %" PRId64 "\n",
     945             :                                 plist->count, plist->rangecount,
     946           0 :                                 plist->head ? plist->head->seq : 0,
     947           0 :                                 plist->tail ? plist->tail->seq : 0);
     948             :                 }
     949             :         }
     950             : 
     951           0 :         if (dtype != summary_display) {
     952           0 :                 json_object *json_entries = NULL;
     953             : 
     954           0 :                 if (json) {
     955           0 :                         json_entries = json_object_new_array();
     956           0 :                         json_object_object_add(json_pl, "entries",
     957             :                                                json_entries);
     958             :                 }
     959             : 
     960           0 :                 for (pentry = plist->head; pentry; pentry = pentry->next) {
     961           0 :                         if (dtype == sequential_display
     962           0 :                             && pentry->seq != seqnum)
     963           0 :                                 continue;
     964             : 
     965           0 :                         if (json) {
     966           0 :                                 json_object *json_entry;
     967             : 
     968           0 :                                 json_entry = json_object_new_object();
     969           0 :                                 json_object_array_add(json_entries, json_entry);
     970             : 
     971           0 :                                 json_object_int_add(json_entry,
     972             :                                                     "sequenceNumber",
     973             :                                                     pentry->seq);
     974           0 :                                 json_object_string_add(
     975             :                                         json_entry, "type",
     976             :                                         prefix_list_type_str(pentry));
     977           0 :                                 json_object_string_addf(json_entry, "prefix",
     978             :                                                         "%pFX",
     979             :                                                         &pentry->prefix);
     980             : 
     981           0 :                                 if (pentry->ge)
     982           0 :                                         json_object_int_add(
     983             :                                                 json_entry,
     984             :                                                 "minimumPrefixLength",
     985             :                                                 pentry->ge);
     986           0 :                                 if (pentry->le)
     987           0 :                                         json_object_int_add(
     988             :                                                 json_entry,
     989             :                                                 "maximumPrefixLength",
     990             :                                                 pentry->le);
     991             : 
     992           0 :                                 if (dtype == detail_display
     993           0 :                                     || dtype == sequential_display) {
     994           0 :                                         json_object_int_add(json_entry,
     995             :                                                             "hitCount",
     996           0 :                                                             pentry->hitcnt);
     997           0 :                                         json_object_int_add(json_entry,
     998             :                                                             "referenceCount",
     999           0 :                                                             pentry->refcnt);
    1000             :                                 }
    1001             :                         } else {
    1002           0 :                                 vty_out(vty, "   ");
    1003             : 
    1004           0 :                                 vty_out(vty, "seq %" PRId64 " ", pentry->seq);
    1005             : 
    1006           0 :                                 vty_out(vty, "%s ",
    1007             :                                         prefix_list_type_str(pentry));
    1008             : 
    1009           0 :                                 if (pentry->any)
    1010           0 :                                         vty_out(vty, "any");
    1011             :                                 else {
    1012           0 :                                         struct prefix *p = &pentry->prefix;
    1013             : 
    1014           0 :                                         vty_out(vty, "%pFX", p);
    1015             : 
    1016           0 :                                         if (pentry->ge)
    1017           0 :                                                 vty_out(vty, " ge %d",
    1018             :                                                         pentry->ge);
    1019           0 :                                         if (pentry->le)
    1020           0 :                                                 vty_out(vty, " le %d",
    1021             :                                                         pentry->le);
    1022             :                                 }
    1023             : 
    1024           0 :                                 if (dtype == detail_display
    1025           0 :                                     || dtype == sequential_display)
    1026           0 :                                         vty_out(vty,
    1027             :                                                 " (hit count: %ld, refcount: %ld)",
    1028             :                                                 pentry->hitcnt, pentry->refcnt);
    1029             : 
    1030           0 :                                 vty_out(vty, "\n");
    1031             :                         }
    1032             :                 }
    1033             :         }
    1034           0 : }
    1035             : 
    1036           0 : static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name,
    1037             :                                 const char *seq, enum display_type dtype,
    1038             :                                 bool uj)
    1039             : {
    1040           0 :         struct prefix_list *plist;
    1041           0 :         struct prefix_master *master;
    1042           0 :         int64_t seqnum = 0;
    1043           0 :         json_object *json = NULL;
    1044           0 :         json_object *json_proto = NULL;
    1045             : 
    1046           0 :         master = prefix_master_get(afi, 0);
    1047             :         if (master == NULL)
    1048             :                 return CMD_WARNING;
    1049             : 
    1050           0 :         if (uj) {
    1051           0 :                 json = json_object_new_object();
    1052           0 :                 json_proto = json_object_new_object();
    1053           0 :                 json_object_object_add(json, frr_protoname, json_proto);
    1054             :         }
    1055             : 
    1056           0 :         if (seq)
    1057           0 :                 seqnum = (int64_t)atol(seq);
    1058             : 
    1059           0 :         if (name) {
    1060           0 :                 plist = prefix_list_lookup(afi, name);
    1061           0 :                 if (!plist) {
    1062           0 :                         if (!uj)
    1063           0 :                                 vty_out(vty,
    1064             :                                         "%% Can't find specified prefix-list\n");
    1065           0 :                         return CMD_WARNING;
    1066             :                 }
    1067           0 :                 vty_show_prefix_entry(vty, json_proto, afi, plist, master,
    1068             :                                       dtype, seqnum);
    1069             :         } else {
    1070           0 :                 if (dtype == detail_display || dtype == summary_display) {
    1071           0 :                         if (master->recent && !uj)
    1072           0 :                                 vty_out(vty,
    1073             :                                         "Prefix-list with the last deletion/insertion: %s\n",
    1074             :                                         master->recent->name);
    1075             :                 }
    1076             : 
    1077           0 :                 frr_each (plist, &master->str, plist)
    1078           0 :                         vty_show_prefix_entry(vty, json_proto, afi, plist,
    1079             :                                               master, dtype, seqnum);
    1080             :         }
    1081             : 
    1082           0 :         return vty_json(vty, json);
    1083             : }
    1084             : 
    1085           0 : static int vty_show_prefix_list_prefix(struct vty *vty, afi_t afi,
    1086             :                                        const char *name, const char *prefix,
    1087             :                                        enum display_type type)
    1088             : {
    1089           0 :         struct prefix_list *plist;
    1090           0 :         struct prefix_list_entry *pentry;
    1091           0 :         struct prefix p;
    1092           0 :         int ret;
    1093           0 :         int match;
    1094             : 
    1095           0 :         plist = prefix_list_lookup(afi, name);
    1096           0 :         if (!plist) {
    1097           0 :                 vty_out(vty, "%% Can't find specified prefix-list\n");
    1098           0 :                 return CMD_WARNING;
    1099             :         }
    1100             : 
    1101           0 :         ret = str2prefix(prefix, &p);
    1102           0 :         if (ret <= 0) {
    1103           0 :                 vty_out(vty, "%% prefix is malformed\n");
    1104           0 :                 return CMD_WARNING;
    1105             :         }
    1106             : 
    1107           0 :         for (pentry = plist->head; pentry; pentry = pentry->next) {
    1108           0 :                 match = 0;
    1109             : 
    1110           0 :                 if (type == normal_display || type == first_match_display)
    1111           0 :                         if (prefix_same(&p, &pentry->prefix))
    1112           0 :                                 match = 1;
    1113             : 
    1114           0 :                 if (type == longer_display) {
    1115           0 :                         if ((p.family == pentry->prefix.family)
    1116           0 :                             && (prefix_match(&p, &pentry->prefix)))
    1117             :                                 match = 1;
    1118             :                 }
    1119             : 
    1120           0 :                 if (match) {
    1121           0 :                         vty_out(vty, "   seq %" PRId64 " %s ", pentry->seq,
    1122             :                                 prefix_list_type_str(pentry));
    1123             : 
    1124           0 :                         if (pentry->any)
    1125           0 :                                 vty_out(vty, "any");
    1126             :                         else {
    1127           0 :                                 struct prefix *pf = &pentry->prefix;
    1128             : 
    1129           0 :                                 vty_out(vty, "%pFX", pf);
    1130             : 
    1131           0 :                                 if (pentry->ge)
    1132           0 :                                         vty_out(vty, " ge %d", pentry->ge);
    1133           0 :                                 if (pentry->le)
    1134           0 :                                         vty_out(vty, " le %d", pentry->le);
    1135             :                         }
    1136             : 
    1137           0 :                         if (type == normal_display
    1138             :                             || type == first_match_display)
    1139           0 :                                 vty_out(vty, " (hit count: %ld, refcount: %ld)",
    1140             :                                         pentry->hitcnt, pentry->refcnt);
    1141             : 
    1142           0 :                         vty_out(vty, "\n");
    1143             : 
    1144           0 :                         if (type == first_match_display)
    1145             :                                 return CMD_SUCCESS;
    1146             :                 }
    1147             :         }
    1148             :         return CMD_SUCCESS;
    1149             : }
    1150             : 
    1151           0 : static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name,
    1152             :                                  const char *prefix)
    1153             : {
    1154           0 :         struct prefix_master *master;
    1155           0 :         struct prefix_list *plist;
    1156           0 :         struct prefix_list_entry *pentry;
    1157           0 :         int ret;
    1158           0 :         struct prefix p;
    1159             : 
    1160           0 :         master = prefix_master_get(afi, 0);
    1161             :         if (master == NULL)
    1162             :                 return CMD_WARNING;
    1163             : 
    1164           0 :         if (name == NULL && prefix == NULL) {
    1165           0 :                 frr_each (plist, &master->str, plist)
    1166           0 :                         for (pentry = plist->head; pentry;
    1167           0 :                              pentry = pentry->next)
    1168           0 :                                 pentry->hitcnt = 0;
    1169             :         } else {
    1170           0 :                 plist = prefix_list_lookup(afi, name);
    1171           0 :                 if (!plist) {
    1172           0 :                         vty_out(vty, "%% Can't find specified prefix-list\n");
    1173           0 :                         return CMD_WARNING;
    1174             :                 }
    1175             : 
    1176           0 :                 if (prefix) {
    1177           0 :                         ret = str2prefix(prefix, &p);
    1178           0 :                         if (ret <= 0) {
    1179           0 :                                 vty_out(vty, "%% prefix is malformed\n");
    1180           0 :                                 return CMD_WARNING;
    1181             :                         }
    1182             :                 }
    1183             : 
    1184           0 :                 for (pentry = plist->head; pentry; pentry = pentry->next) {
    1185           0 :                         if (prefix) {
    1186           0 :                                 if (pentry->prefix.family == p.family
    1187           0 :                                     && prefix_match(&pentry->prefix, &p))
    1188           0 :                                         pentry->hitcnt = 0;
    1189             :                         } else
    1190           0 :                                 pentry->hitcnt = 0;
    1191             :                 }
    1192             :         }
    1193             :         return CMD_SUCCESS;
    1194             : }
    1195             : 
    1196             : #include "lib/plist_clippy.c"
    1197             : 
    1198           0 : DEFPY (show_ip_prefix_list,
    1199             :        show_ip_prefix_list_cmd,
    1200             :        "show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
    1201             :        SHOW_STR
    1202             :        IP_STR
    1203             :        PREFIX_LIST_STR
    1204             :        "Name of a prefix list\n"
    1205             :        "sequence number of an entry\n"
    1206             :        "Sequence number\n"
    1207             :        JSON_STR)
    1208             : {
    1209           0 :         enum display_type dtype = normal_display;
    1210           0 :         if (dseq)
    1211           0 :                 dtype = sequential_display;
    1212             : 
    1213           0 :         return vty_show_prefix_list(vty, AFI_IP, prefix_list, arg_str, dtype,
    1214             :                                     !!uj);
    1215             : }
    1216             : 
    1217           0 : DEFPY (show_ip_prefix_list_prefix,
    1218             :        show_ip_prefix_list_prefix_cmd,
    1219             :        "show ip prefix-list WORD A.B.C.D/M$prefix [longer$dl|first-match$dfm]",
    1220             :        SHOW_STR
    1221             :        IP_STR
    1222             :        PREFIX_LIST_STR
    1223             :        "Name of a prefix list\n"
    1224             :        "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
    1225             :        "Lookup longer prefix\n"
    1226             :        "First matched prefix\n")
    1227             : {
    1228           0 :         enum display_type dtype = normal_display;
    1229           0 :         if (dl)
    1230             :                 dtype = longer_display;
    1231           0 :         else if (dfm)
    1232           0 :                 dtype = first_match_display;
    1233             : 
    1234           0 :         return vty_show_prefix_list_prefix(vty, AFI_IP, prefix_list, prefix_str,
    1235             :                                            dtype);
    1236             : }
    1237             : 
    1238           0 : DEFPY (show_ip_prefix_list_summary,
    1239             :        show_ip_prefix_list_summary_cmd,
    1240             :        "show ip prefix-list summary [WORD$prefix_list] [json$uj]",
    1241             :        SHOW_STR
    1242             :        IP_STR
    1243             :        PREFIX_LIST_STR
    1244             :        "Summary of prefix lists\n"
    1245             :        "Name of a prefix list\n"
    1246             :        JSON_STR)
    1247             : {
    1248           0 :         return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
    1249             :                                     summary_display, !!uj);
    1250             : }
    1251             : 
    1252           0 : DEFPY (show_ip_prefix_list_detail,
    1253             :        show_ip_prefix_list_detail_cmd,
    1254             :        "show ip prefix-list detail [WORD$prefix_list] [json$uj]",
    1255             :        SHOW_STR
    1256             :        IP_STR
    1257             :        PREFIX_LIST_STR
    1258             :        "Detail of prefix lists\n"
    1259             :        "Name of a prefix list\n"
    1260             :        JSON_STR)
    1261             : {
    1262           0 :         return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
    1263             :                                     detail_display, !!uj);
    1264             : }
    1265             : 
    1266           0 : DEFPY (clear_ip_prefix_list,
    1267             :        clear_ip_prefix_list_cmd,
    1268             :        "clear ip prefix-list [WORD [A.B.C.D/M$prefix]]",
    1269             :        CLEAR_STR
    1270             :        IP_STR
    1271             :        PREFIX_LIST_STR
    1272             :        "Name of a prefix list\n"
    1273             :        "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
    1274             : {
    1275           0 :         return vty_clear_prefix_list(vty, AFI_IP, prefix_list, prefix_str);
    1276             : }
    1277             : 
    1278           0 : DEFPY (show_ipv6_prefix_list,
    1279             :        show_ipv6_prefix_list_cmd,
    1280             :        "show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
    1281             :        SHOW_STR
    1282             :        IPV6_STR
    1283             :        PREFIX_LIST_STR
    1284             :        "Name of a prefix list\n"
    1285             :        "sequence number of an entry\n"
    1286             :        "Sequence number\n"
    1287             :        JSON_STR)
    1288             : {
    1289           0 :         enum display_type dtype = normal_display;
    1290           0 :         if (dseq)
    1291           0 :                 dtype = sequential_display;
    1292             : 
    1293           0 :         return vty_show_prefix_list(vty, AFI_IP6, prefix_list, arg_str, dtype,
    1294             :                                     !!uj);
    1295             : }
    1296             : 
    1297           0 : DEFPY (show_ipv6_prefix_list_prefix,
    1298             :        show_ipv6_prefix_list_prefix_cmd,
    1299             :        "show ipv6 prefix-list WORD X:X::X:X/M$prefix [longer$dl|first-match$dfm]",
    1300             :        SHOW_STR
    1301             :        IPV6_STR
    1302             :        PREFIX_LIST_STR
    1303             :        "Name of a prefix list\n"
    1304             :        "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
    1305             :        "Lookup longer prefix\n"
    1306             :        "First matched prefix\n")
    1307             : {
    1308           0 :         enum display_type dtype = normal_display;
    1309           0 :         if (dl)
    1310             :                 dtype = longer_display;
    1311           0 :         else if (dfm)
    1312           0 :                 dtype = first_match_display;
    1313             : 
    1314           0 :         return vty_show_prefix_list_prefix(vty, AFI_IP6, prefix_list,
    1315             :                                            prefix_str, dtype);
    1316             : }
    1317             : 
    1318           0 : DEFPY (show_ipv6_prefix_list_summary,
    1319             :        show_ipv6_prefix_list_summary_cmd,
    1320             :        "show ipv6 prefix-list summary [WORD$prefix-list] [json$uj]",
    1321             :        SHOW_STR
    1322             :        IPV6_STR
    1323             :        PREFIX_LIST_STR
    1324             :        "Summary of prefix lists\n"
    1325             :        "Name of a prefix list\n"
    1326             :        JSON_STR)
    1327             : {
    1328           0 :         return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
    1329             :                                     summary_display, !!uj);
    1330             : }
    1331             : 
    1332           0 : DEFPY (show_ipv6_prefix_list_detail,
    1333             :        show_ipv6_prefix_list_detail_cmd,
    1334             :        "show ipv6 prefix-list detail [WORD$prefix-list] [json$uj]",
    1335             :        SHOW_STR
    1336             :        IPV6_STR
    1337             :        PREFIX_LIST_STR
    1338             :        "Detail of prefix lists\n"
    1339             :        "Name of a prefix list\n"
    1340             :        JSON_STR)
    1341             : {
    1342           0 :         return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
    1343             :                                     detail_display, !!uj);
    1344             : }
    1345             : 
    1346           0 : DEFPY (clear_ipv6_prefix_list,
    1347             :        clear_ipv6_prefix_list_cmd,
    1348             :        "clear ipv6 prefix-list [WORD [X:X::X:X/M$prefix]]",
    1349             :        CLEAR_STR
    1350             :        IPV6_STR
    1351             :        PREFIX_LIST_STR
    1352             :        "Name of a prefix list\n"
    1353             :        "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
    1354             : {
    1355           0 :         return vty_clear_prefix_list(vty, AFI_IP6, prefix_list, prefix_str);
    1356             : }
    1357             : 
    1358           0 : DEFPY (debug_prefix_list_match,
    1359             :        debug_prefix_list_match_cmd,
    1360             :        "debug prefix-list WORD$prefix-list match <A.B.C.D/M|X:X::X:X/M>"
    1361             :        " [address-mode$addr_mode]",
    1362             :        DEBUG_STR
    1363             :        "Prefix-list test access\n"
    1364             :        "Name of a prefix list\n"
    1365             :        "Test prefix for prefix list result\n"
    1366             :        "Prefix to test in ip prefix-list\n"
    1367             :        "Prefix to test in ipv6 prefix-list\n"
    1368             :        "Use address matching mode (PIM RP)\n")
    1369             : {
    1370           0 :         struct prefix_list *plist;
    1371           0 :         const struct prefix_list_entry *entry = NULL;
    1372           0 :         enum prefix_list_type ret;
    1373             : 
    1374           0 :         plist = prefix_list_lookup(family2afi(match->family), prefix_list);
    1375           0 :         if (!plist) {
    1376           0 :                 vty_out(vty, "%% no prefix list named %s for AFI %s\n",
    1377           0 :                         prefix_list, afi2str(family2afi(match->family)));
    1378           0 :                 return CMD_WARNING;
    1379             :         }
    1380             : 
    1381           0 :         ret = prefix_list_apply_ext(plist, &entry, match, !!addr_mode);
    1382             : 
    1383           0 :         vty_out(vty, "%s prefix list %s yields %s for %pFX, ",
    1384           0 :                 afi2str(family2afi(match->family)), prefix_list,
    1385             :                 ret == PREFIX_DENY ? "DENY" : "PERMIT", match);
    1386             : 
    1387           0 :         if (!entry)
    1388           0 :                 vty_out(vty, "no match found\n");
    1389             :         else {
    1390           0 :                 vty_out(vty, "matching entry #%"PRId64": %pFX", entry->seq,
    1391             :                         &entry->prefix);
    1392           0 :                 if (entry->ge)
    1393           0 :                         vty_out(vty, " ge %d", entry->ge);
    1394           0 :                 if (entry->le)
    1395           0 :                         vty_out(vty, " le %d", entry->le);
    1396           0 :                 vty_out(vty, "\n");
    1397             :         }
    1398             : 
    1399             :         /* allow using this in scripts for quick prefix-list member tests */
    1400           0 :         return (ret == PREFIX_PERMIT) ? CMD_SUCCESS : CMD_WARNING;
    1401             : }
    1402             : 
    1403           0 : struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist,
    1404             :                                     uint8_t init_flag, uint8_t permit_flag,
    1405             :                                     uint8_t deny_flag)
    1406             : {
    1407           0 :         struct prefix_list_entry *pentry;
    1408             : 
    1409           0 :         if (!plist)
    1410             :                 return s;
    1411             : 
    1412           0 :         for (pentry = plist->head; pentry; pentry = pentry->next) {
    1413           0 :                 uint8_t flag = init_flag;
    1414           0 :                 struct prefix *p = &pentry->prefix;
    1415             : 
    1416           0 :                 flag |= (pentry->type == PREFIX_PERMIT ? permit_flag
    1417             :                                                        : deny_flag);
    1418           0 :                 stream_putc(s, flag);
    1419           0 :                 stream_putl(s, (uint32_t)pentry->seq);
    1420           0 :                 stream_putc(s, (uint8_t)pentry->ge);
    1421           0 :                 stream_putc(s, (uint8_t)pentry->le);
    1422           0 :                 stream_put_prefix(s, p);
    1423             :         }
    1424             : 
    1425             :         return s;
    1426             : }
    1427             : 
    1428           0 : int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp,
    1429             :                        int permit, int set)
    1430             : {
    1431           0 :         struct prefix_list *plist;
    1432           0 :         struct prefix_list_entry *pentry;
    1433             : 
    1434             :         /* ge and le value check */
    1435           0 :         if (orfp->ge && orfp->ge < orfp->p.prefixlen)
    1436             :                 return CMD_WARNING_CONFIG_FAILED;
    1437           0 :         if (orfp->le && orfp->le < orfp->p.prefixlen)
    1438             :                 return CMD_WARNING_CONFIG_FAILED;
    1439           0 :         if (orfp->le && orfp->ge > orfp->le)
    1440             :                 return CMD_WARNING_CONFIG_FAILED;
    1441             : 
    1442           0 :         if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128))
    1443           0 :                 orfp->le = 0;
    1444             : 
    1445           0 :         plist = prefix_list_get(afi, 1, name);
    1446           0 :         if (!plist)
    1447             :                 return CMD_WARNING_CONFIG_FAILED;
    1448             : 
    1449           0 :         apply_mask(&orfp->p);
    1450             : 
    1451           0 :         if (set) {
    1452           0 :                 pentry = prefix_list_entry_make(
    1453             :                         &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY),
    1454           0 :                         orfp->seq, orfp->le, orfp->ge, false);
    1455             : 
    1456           0 :                 if (prefix_entry_dup_check(plist, pentry)) {
    1457           0 :                         prefix_list_entry_free(pentry);
    1458           0 :                         return CMD_WARNING_CONFIG_FAILED;
    1459             :                 }
    1460             : 
    1461           0 :                 prefix_list_entry_add(plist, pentry);
    1462             :         } else {
    1463           0 :                 pentry = prefix_list_entry_lookup(
    1464             :                         plist, &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY),
    1465           0 :                         orfp->seq, orfp->le, orfp->ge);
    1466             : 
    1467           0 :                 if (!pentry)
    1468             :                         return CMD_WARNING_CONFIG_FAILED;
    1469             : 
    1470           0 :                 prefix_list_entry_delete(plist, pentry, 1);
    1471             :         }
    1472             : 
    1473             :         return CMD_SUCCESS;
    1474             : }
    1475             : 
    1476           0 : void prefix_bgp_orf_remove_all(afi_t afi, char *name)
    1477             : {
    1478           0 :         struct prefix_list *plist;
    1479             : 
    1480           0 :         plist = prefix_bgp_orf_lookup(afi, name);
    1481           0 :         if (plist)
    1482           0 :                 prefix_list_delete(plist);
    1483           0 : }
    1484             : 
    1485             : /* return prefix count */
    1486           0 : int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name,
    1487             :                                 bool use_json)
    1488             : {
    1489           0 :         struct prefix_list *plist;
    1490           0 :         struct prefix_list_entry *pentry;
    1491           0 :         json_object *json = NULL;
    1492           0 :         json_object *json_prefix = NULL;
    1493           0 :         json_object *json_list = NULL;
    1494             : 
    1495           0 :         plist = prefix_bgp_orf_lookup(afi, name);
    1496           0 :         if (!plist)
    1497             :                 return 0;
    1498             : 
    1499           0 :         if (!vty)
    1500           0 :                 return plist->count;
    1501             : 
    1502           0 :         if (use_json) {
    1503           0 :                 json = json_object_new_object();
    1504           0 :                 json_prefix = json_object_new_object();
    1505           0 :                 json_list = json_object_new_object();
    1506             : 
    1507           0 :                 json_object_int_add(json_prefix, "prefixListCounter",
    1508           0 :                                     plist->count);
    1509           0 :                 json_object_string_add(json_prefix, "prefixListName",
    1510           0 :                                        plist->name);
    1511             : 
    1512           0 :                 for (pentry = plist->head; pentry; pentry = pentry->next) {
    1513           0 :                         struct prefix *p = &pentry->prefix;
    1514           0 :                         char buf_a[BUFSIZ];
    1515             : 
    1516           0 :                         snprintf(buf_a, sizeof(buf_a), "%pFX", p);
    1517             : 
    1518           0 :                         json_object_int_add(json_list, "seq", pentry->seq);
    1519           0 :                         json_object_string_add(json_list, "seqPrefixListType",
    1520             :                                                prefix_list_type_str(pentry));
    1521             : 
    1522           0 :                         if (pentry->ge)
    1523           0 :                                 json_object_int_add(json_list, "ge",
    1524             :                                                     pentry->ge);
    1525           0 :                         if (pentry->le)
    1526           0 :                                 json_object_int_add(json_list, "le",
    1527             :                                                     pentry->le);
    1528             : 
    1529           0 :                         json_object_object_add(json_prefix, buf_a, json_list);
    1530             :                 }
    1531           0 :                 if (afi == AFI_IP)
    1532           0 :                         json_object_object_add(json, "ipPrefixList",
    1533             :                                                json_prefix);
    1534             :                 else
    1535           0 :                         json_object_object_add(json, "ipv6PrefixList",
    1536             :                                                json_prefix);
    1537             : 
    1538           0 :                 vty_json(vty, json);
    1539             :         } else {
    1540           0 :                 vty_out(vty, "ip%s prefix-list %s: %d entries\n",
    1541             :                         afi == AFI_IP ? "" : "v6", plist->name, plist->count);
    1542             : 
    1543           0 :                 for (pentry = plist->head; pentry; pentry = pentry->next) {
    1544           0 :                         struct prefix *p = &pentry->prefix;
    1545             : 
    1546           0 :                         vty_out(vty, "   seq %" PRId64 " %s %pFX", pentry->seq,
    1547             :                                 prefix_list_type_str(pentry), p);
    1548             : 
    1549           0 :                         if (pentry->ge)
    1550           0 :                                 vty_out(vty, " ge %d", pentry->ge);
    1551           0 :                         if (pentry->le)
    1552           0 :                                 vty_out(vty, " le %d", pentry->le);
    1553             : 
    1554           0 :                         vty_out(vty, "\n");
    1555             :                 }
    1556             :         }
    1557           0 :         return plist->count;
    1558             : }
    1559             : 
    1560          64 : static void prefix_list_reset_afi(afi_t afi, int orf)
    1561             : {
    1562          64 :         struct prefix_list *plist;
    1563          64 :         struct prefix_master *master;
    1564             : 
    1565          64 :         master = prefix_master_get(afi, orf);
    1566          64 :         if (master == NULL)
    1567             :                 return;
    1568             : 
    1569          64 :         while ((plist = plist_first(&master->str))) {
    1570           0 :                 prefix_list_delete(plist);
    1571             :         }
    1572             : 
    1573          64 :         master->recent = NULL;
    1574             : }
    1575             : 
    1576             : /* Prefix-list node. */
    1577             : static struct cmd_node prefix_node = {
    1578             :         .name = "ipv4 prefix list",
    1579             :         .node = PREFIX_NODE,
    1580             :         .prompt = "",
    1581             : };
    1582             : 
    1583           0 : static void plist_autocomplete_afi(afi_t afi, vector comps,
    1584             :                                    struct cmd_token *token)
    1585             : {
    1586           0 :         struct prefix_list *plist;
    1587           0 :         struct prefix_master *master;
    1588             : 
    1589           0 :         master = prefix_master_get(afi, 0);
    1590             :         if (master == NULL)
    1591             :                 return;
    1592             : 
    1593           0 :         frr_each (plist, &master->str, plist)
    1594           0 :                 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, plist->name));
    1595             : }
    1596             : 
    1597           0 : static void plist_autocomplete(vector comps, struct cmd_token *token)
    1598             : {
    1599           0 :         plist_autocomplete_afi(AFI_IP, comps, token);
    1600           0 :         plist_autocomplete_afi(AFI_IP6, comps, token);
    1601           0 : }
    1602             : 
    1603             : static const struct cmd_variable_handler plist_var_handlers[] = {
    1604             :         {/* "prefix-list WORD" */
    1605             :          .varname = "prefix_list",
    1606             :          .completions = plist_autocomplete},
    1607             :         {.tokenname = "PREFIXLIST_NAME",
    1608             :          .completions = plist_autocomplete},
    1609             :         {.completions = NULL}};
    1610             : 
    1611             : 
    1612          16 : static void prefix_list_init_ipv4(void)
    1613             : {
    1614          16 :         install_node(&prefix_node);
    1615             : 
    1616          16 :         install_element(VIEW_NODE, &show_ip_prefix_list_cmd);
    1617          16 :         install_element(VIEW_NODE, &show_ip_prefix_list_prefix_cmd);
    1618          16 :         install_element(VIEW_NODE, &show_ip_prefix_list_summary_cmd);
    1619          16 :         install_element(VIEW_NODE, &show_ip_prefix_list_detail_cmd);
    1620             : 
    1621          16 :         install_element(ENABLE_NODE, &clear_ip_prefix_list_cmd);
    1622          16 : }
    1623             : 
    1624             : /* Prefix-list node. */
    1625             : static struct cmd_node prefix_ipv6_node = {
    1626             :         .name = "ipv6 prefix list",
    1627             :         .node = PREFIX_IPV6_NODE,
    1628             :         .prompt = "",
    1629             : };
    1630             : 
    1631          16 : static void prefix_list_init_ipv6(void)
    1632             : {
    1633          16 :         install_node(&prefix_ipv6_node);
    1634             : 
    1635          16 :         install_element(VIEW_NODE, &show_ipv6_prefix_list_cmd);
    1636          16 :         install_element(VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd);
    1637          16 :         install_element(VIEW_NODE, &show_ipv6_prefix_list_summary_cmd);
    1638          16 :         install_element(VIEW_NODE, &show_ipv6_prefix_list_detail_cmd);
    1639          16 :         install_element(VIEW_NODE, &debug_prefix_list_match_cmd);
    1640             : 
    1641          16 :         install_element(ENABLE_NODE, &clear_ipv6_prefix_list_cmd);
    1642          16 : }
    1643             : 
    1644          16 : void prefix_list_init(void)
    1645             : {
    1646          16 :         plist_init(&prefix_master_ipv4.str);
    1647          16 :         plist_init(&prefix_master_orf_v4.str);
    1648          16 :         plist_init(&prefix_master_ipv6.str);
    1649          16 :         plist_init(&prefix_master_orf_v6.str);
    1650             : 
    1651          16 :         cmd_variable_handler_register(plist_var_handlers);
    1652             : 
    1653          16 :         prefix_list_init_ipv4();
    1654          16 :         prefix_list_init_ipv6();
    1655          16 : }
    1656             : 
    1657          16 : void prefix_list_reset(void)
    1658             : {
    1659          16 :         prefix_list_reset_afi(AFI_IP, 0);
    1660          16 :         prefix_list_reset_afi(AFI_IP6, 0);
    1661          16 :         prefix_list_reset_afi(AFI_IP, 1);
    1662          16 :         prefix_list_reset_afi(AFI_IP6, 1);
    1663          16 : }

Generated by: LCOV version v1.16-topotato