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