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