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