]> git.proxmox.com Git - mirror_frr.git/blob - lib/plist.c
Merge pull request #5778 from ton31337/fix/add_doc_for_ebgp_connected_route_check
[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 static 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 static 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 static 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 next = pentry->next;
307 prefix_list_trie_del(plist, pentry);
308 prefix_list_entry_free(pentry);
309 plist->count--;
310 }
311
312 master = plist->master;
313
314 if (plist->type == PREFIX_TYPE_NUMBER)
315 list = &master->num;
316 else
317 list = &master->str;
318
319 if (plist->next)
320 plist->next->prev = plist->prev;
321 else
322 list->tail = plist->prev;
323
324 if (plist->prev)
325 plist->prev->next = plist->next;
326 else
327 list->head = plist->next;
328
329 XFREE(MTYPE_TMP, plist->desc);
330
331 /* Make sure master's recent changed prefix-list information is
332 cleared. */
333 master->recent = NULL;
334
335 route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_DELETED);
336
337 if (master->delete_hook)
338 (*master->delete_hook)(plist);
339
340 XFREE(MTYPE_MPREFIX_LIST_STR, plist->name);
341
342 XFREE(MTYPE_PREFIX_LIST_TRIE, plist->trie);
343
344 prefix_list_free(plist);
345 }
346
347 static struct prefix_list_entry *
348 prefix_list_entry_make(struct prefix *prefix, enum prefix_list_type type,
349 int64_t seq, int le, int ge, int any)
350 {
351 struct prefix_list_entry *pentry;
352
353 pentry = prefix_list_entry_new();
354
355 if (any)
356 pentry->any = 1;
357
358 prefix_copy(&pentry->prefix, prefix);
359 pentry->type = type;
360 pentry->seq = seq;
361 pentry->le = le;
362 pentry->ge = ge;
363
364 return pentry;
365 }
366
367 /* Add hook function. */
368 void prefix_list_add_hook(void (*func)(struct prefix_list *plist))
369 {
370 prefix_master_ipv4.add_hook = func;
371 prefix_master_ipv6.add_hook = func;
372 }
373
374 /* Delete hook function. */
375 void prefix_list_delete_hook(void (*func)(struct prefix_list *plist))
376 {
377 prefix_master_ipv4.delete_hook = func;
378 prefix_master_ipv6.delete_hook = func;
379 }
380
381 /* Calculate new sequential number. */
382 static int64_t prefix_new_seq_get(struct prefix_list *plist)
383 {
384 int64_t maxseq;
385 int64_t newseq;
386 struct prefix_list_entry *pentry;
387
388 maxseq = newseq = 0;
389
390 for (pentry = plist->head; pentry; pentry = pentry->next) {
391 if (maxseq < pentry->seq)
392 maxseq = pentry->seq;
393 }
394
395 newseq = ((maxseq / 5) * 5) + 5;
396
397 return (newseq > UINT_MAX) ? UINT_MAX : newseq;
398 }
399
400 /* Return prefix list entry which has same seq number. */
401 static struct prefix_list_entry *prefix_seq_check(struct prefix_list *plist,
402 int64_t seq)
403 {
404 struct prefix_list_entry *pentry;
405
406 for (pentry = plist->head; pentry; pentry = pentry->next)
407 if (pentry->seq == seq)
408 return pentry;
409 return NULL;
410 }
411
412 static struct prefix_list_entry *
413 prefix_list_entry_lookup(struct prefix_list *plist, struct prefix *prefix,
414 enum prefix_list_type type, int64_t seq,
415 int le, int ge)
416 {
417 struct prefix_list_entry *pentry;
418
419 for (pentry = plist->head; pentry; pentry = pentry->next)
420 if (prefix_same(&pentry->prefix, prefix)
421 && pentry->type == type) {
422 if (seq >= 0 && pentry->seq != seq)
423 continue;
424
425 if (pentry->le != le)
426 continue;
427 if (pentry->ge != ge)
428 continue;
429
430 return pentry;
431 }
432
433 return NULL;
434 }
435
436 static void trie_walk_affected(size_t validbits, struct pltrie_table *table,
437 uint8_t byte, struct prefix_list_entry *object,
438 void (*fn)(struct prefix_list_entry *object,
439 struct prefix_list_entry **updptr))
440 {
441 uint8_t mask;
442 uint16_t bwalk;
443
444 if (validbits > PLC_BITS) {
445 fn(object, &table->entries[byte].final_chain);
446 return;
447 }
448
449 mask = (1 << (8 - validbits)) - 1;
450 for (bwalk = byte & ~mask; bwalk <= byte + mask; bwalk++) {
451 fn(object, &table->entries[bwalk].up_chain);
452 }
453 }
454
455 static void trie_uninstall_fn(struct prefix_list_entry *object,
456 struct prefix_list_entry **updptr)
457 {
458 for (; *updptr; updptr = &(*updptr)->next_best)
459 if (*updptr == object) {
460 *updptr = object->next_best;
461 break;
462 }
463 }
464
465 static int trie_table_empty(struct pltrie_table *table)
466 {
467 size_t i;
468 for (i = 0; i < PLC_LEN; i++)
469 if (table->entries[i].next_table || table->entries[i].up_chain)
470 return 0;
471 return 1;
472 }
473
474 static void prefix_list_trie_del(struct prefix_list *plist,
475 struct prefix_list_entry *pentry)
476 {
477 size_t depth, maxdepth = plist->master->trie_depth;
478 uint8_t *bytes = pentry->prefix.u.val;
479 size_t validbits = pentry->prefix.prefixlen;
480 struct pltrie_table *table, **tables[PLC_MAXLEVEL];
481
482 table = plist->trie;
483 for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) {
484 uint8_t byte = bytes[depth];
485 assert(table->entries[byte].next_table);
486
487 tables[depth + 1] = &table->entries[byte].next_table;
488 table = table->entries[byte].next_table;
489
490 validbits -= PLC_BITS;
491 }
492
493 trie_walk_affected(validbits, table, bytes[depth], pentry,
494 trie_uninstall_fn);
495
496 for (; depth > 0; depth--)
497 if (trie_table_empty(*tables[depth])) {
498 XFREE(MTYPE_PREFIX_LIST_TRIE, *tables[depth]);
499 }
500 }
501
502
503 static void prefix_list_entry_delete(struct prefix_list *plist,
504 struct prefix_list_entry *pentry,
505 int update_list)
506 {
507 if (plist == NULL || pentry == NULL)
508 return;
509
510 prefix_list_trie_del(plist, pentry);
511
512 if (pentry->prev)
513 pentry->prev->next = pentry->next;
514 else
515 plist->head = pentry->next;
516 if (pentry->next)
517 pentry->next->prev = pentry->prev;
518 else
519 plist->tail = pentry->prev;
520
521 prefix_list_entry_free(pentry);
522
523 plist->count--;
524
525 if (update_list) {
526 route_map_notify_dependencies(plist->name,
527 RMAP_EVENT_PLIST_DELETED);
528 if (plist->master->delete_hook)
529 (*plist->master->delete_hook)(plist);
530
531 if (plist->head == NULL && plist->tail == NULL
532 && plist->desc == NULL)
533 prefix_list_delete(plist);
534 else
535 plist->master->recent = plist;
536 }
537 }
538
539 static void trie_install_fn(struct prefix_list_entry *object,
540 struct prefix_list_entry **updptr)
541 {
542 while (*updptr) {
543 if (*updptr == object)
544 return;
545 if ((*updptr)->prefix.prefixlen < object->prefix.prefixlen)
546 break;
547 if ((*updptr)->prefix.prefixlen == object->prefix.prefixlen
548 && (*updptr)->seq > object->seq)
549 break;
550 updptr = &(*updptr)->next_best;
551 }
552
553 if (!object->next_best)
554 object->next_best = *updptr;
555 else
556 assert(object->next_best == *updptr || !*updptr);
557
558 *updptr = object;
559 }
560
561 static void prefix_list_trie_add(struct prefix_list *plist,
562 struct prefix_list_entry *pentry)
563 {
564 size_t depth = plist->master->trie_depth;
565 uint8_t *bytes = pentry->prefix.u.val;
566 size_t validbits = pentry->prefix.prefixlen;
567 struct pltrie_table *table;
568
569 table = plist->trie;
570 while (validbits > PLC_BITS && depth > 1) {
571 if (!table->entries[*bytes].next_table)
572 table->entries[*bytes].next_table =
573 XCALLOC(MTYPE_PREFIX_LIST_TRIE,
574 sizeof(struct pltrie_table));
575 table = table->entries[*bytes].next_table;
576 bytes++;
577 depth--;
578 validbits -= PLC_BITS;
579 }
580
581 trie_walk_affected(validbits, table, *bytes, pentry, trie_install_fn);
582 }
583
584 static void prefix_list_entry_add(struct prefix_list *plist,
585 struct prefix_list_entry *pentry)
586 {
587 struct prefix_list_entry *replace;
588 struct prefix_list_entry *point;
589
590 /* Automatic asignment of seq no. */
591 if (pentry->seq == -1)
592 pentry->seq = prefix_new_seq_get(plist);
593
594 if (plist->tail && pentry->seq > plist->tail->seq)
595 point = NULL;
596 else {
597 /* Is there any same seq prefix list entry? */
598 replace = prefix_seq_check(plist, pentry->seq);
599 if (replace)
600 prefix_list_entry_delete(plist, replace, 0);
601
602 /* Check insert point. */
603 for (point = plist->head; point; point = point->next)
604 if (point->seq >= pentry->seq)
605 break;
606 }
607
608 /* In case of this is the first element of the list. */
609 pentry->next = point;
610
611 if (point) {
612 if (point->prev)
613 point->prev->next = pentry;
614 else
615 plist->head = pentry;
616
617 pentry->prev = point->prev;
618 point->prev = pentry;
619 } else {
620 if (plist->tail)
621 plist->tail->next = pentry;
622 else
623 plist->head = pentry;
624
625 pentry->prev = plist->tail;
626 plist->tail = pentry;
627 }
628
629 prefix_list_trie_add(plist, pentry);
630
631 /* Increment count. */
632 plist->count++;
633
634 /* Run hook function. */
635 if (plist->master->add_hook)
636 (*plist->master->add_hook)(plist);
637
638 route_map_notify_dependencies(plist->name, RMAP_EVENT_PLIST_ADDED);
639 plist->master->recent = plist;
640 }
641
642 /* Return string of prefix_list_type. */
643 static const char *prefix_list_type_str(struct prefix_list_entry *pentry)
644 {
645 switch (pentry->type) {
646 case PREFIX_PERMIT:
647 return "permit";
648 case PREFIX_DENY:
649 return "deny";
650 default:
651 return "";
652 }
653 }
654
655 static int prefix_list_entry_match(struct prefix_list_entry *pentry,
656 const struct prefix *p)
657 {
658 int ret;
659
660 if (pentry->prefix.family != p->family)
661 return 0;
662
663 ret = prefix_match(&pentry->prefix, p);
664 if (!ret)
665 return 0;
666
667 /* In case of le nor ge is specified, exact match is performed. */
668 if (!pentry->le && !pentry->ge) {
669 if (pentry->prefix.prefixlen != p->prefixlen)
670 return 0;
671 } else {
672 if (pentry->le)
673 if (p->prefixlen > pentry->le)
674 return 0;
675
676 if (pentry->ge)
677 if (p->prefixlen < pentry->ge)
678 return 0;
679 }
680 return 1;
681 }
682
683 enum prefix_list_type prefix_list_apply_which_prefix(
684 struct prefix_list *plist,
685 const struct prefix **which,
686 const void *object)
687 {
688 struct prefix_list_entry *pentry, *pbest = NULL;
689
690 const struct prefix *p = (const struct prefix *)object;
691 const uint8_t *byte = p->u.val;
692 size_t depth;
693 size_t validbits = p->prefixlen;
694 struct pltrie_table *table;
695
696 if (plist == NULL) {
697 if (which)
698 *which = NULL;
699 return PREFIX_DENY;
700 }
701
702 if (plist->count == 0) {
703 if (which)
704 *which = NULL;
705 return PREFIX_PERMIT;
706 }
707
708 depth = plist->master->trie_depth;
709 table = plist->trie;
710 while (1) {
711 for (pentry = table->entries[*byte].up_chain; pentry;
712 pentry = pentry->next_best) {
713 if (pbest && pbest->seq < pentry->seq)
714 continue;
715 if (prefix_list_entry_match(pentry, p))
716 pbest = pentry;
717 }
718
719 if (validbits <= PLC_BITS)
720 break;
721 validbits -= PLC_BITS;
722
723 if (--depth) {
724 if (!table->entries[*byte].next_table)
725 break;
726
727 table = table->entries[*byte].next_table;
728 byte++;
729 continue;
730 }
731
732 for (pentry = table->entries[*byte].final_chain; pentry;
733 pentry = pentry->next_best) {
734 if (pbest && pbest->seq < pentry->seq)
735 continue;
736 if (prefix_list_entry_match(pentry, p))
737 pbest = pentry;
738 }
739 break;
740 }
741
742 if (which) {
743 if (pbest)
744 *which = &pbest->prefix;
745 else
746 *which = NULL;
747 }
748
749 if (pbest == NULL)
750 return PREFIX_DENY;
751
752 pbest->hitcnt++;
753 return pbest->type;
754 }
755
756 static void __attribute__((unused)) prefix_list_print(struct prefix_list *plist)
757 {
758 struct prefix_list_entry *pentry;
759
760 if (plist == NULL)
761 return;
762
763 printf("ip prefix-list %s: %d entries\n", plist->name, plist->count);
764
765 for (pentry = plist->head; pentry; pentry = pentry->next) {
766 if (pentry->any)
767 printf("any %s\n", prefix_list_type_str(pentry));
768 else {
769 struct prefix *p;
770 char buf[BUFSIZ];
771
772 p = &pentry->prefix;
773
774 printf(" seq %" PRId64 " %s %s/%d", pentry->seq,
775 prefix_list_type_str(pentry),
776 inet_ntop(p->family, p->u.val, buf, BUFSIZ),
777 p->prefixlen);
778 if (pentry->ge)
779 printf(" ge %d", pentry->ge);
780 if (pentry->le)
781 printf(" le %d", pentry->le);
782 printf("\n");
783 }
784 }
785 }
786
787 /* Retrun 1 when plist already include pentry policy. */
788 static struct prefix_list_entry *
789 prefix_entry_dup_check(struct prefix_list *plist, struct prefix_list_entry *new)
790 {
791 size_t depth, maxdepth = plist->master->trie_depth;
792 uint8_t byte, *bytes = new->prefix.u.val;
793 size_t validbits = new->prefix.prefixlen;
794 struct pltrie_table *table;
795 struct prefix_list_entry *pentry;
796 int64_t seq = 0;
797
798 if (new->seq == -1)
799 seq = prefix_new_seq_get(plist);
800 else
801 seq = new->seq;
802
803 table = plist->trie;
804 for (depth = 0; validbits > PLC_BITS && depth < maxdepth - 1; depth++) {
805 byte = bytes[depth];
806 if (!table->entries[byte].next_table)
807 return NULL;
808
809 table = table->entries[byte].next_table;
810 validbits -= PLC_BITS;
811 }
812
813 byte = bytes[depth];
814 if (validbits > PLC_BITS)
815 pentry = table->entries[byte].final_chain;
816 else
817 pentry = table->entries[byte].up_chain;
818
819 for (; pentry; pentry = pentry->next_best) {
820 if (prefix_same(&pentry->prefix, &new->prefix)
821 && pentry->type == new->type && pentry->le == new->le
822 && pentry->ge == new->ge && pentry->seq != seq)
823 return pentry;
824 }
825 return NULL;
826 }
827
828 static int vty_invalid_prefix_range(struct vty *vty, const char *prefix)
829 {
830 vty_out(vty,
831 "%% Invalid prefix range for %s, make sure: len < ge-value <= le-value\n",
832 prefix);
833 return CMD_WARNING_CONFIG_FAILED;
834 }
835
836 static int vty_prefix_list_install(struct vty *vty, afi_t afi, const char *name,
837 const char *seq, const char *typestr,
838 const char *prefix, const char *ge,
839 const char *le)
840 {
841 int ret;
842 enum prefix_list_type type;
843 struct prefix_list *plist;
844 struct prefix_list_entry *pentry;
845 struct prefix_list_entry *dup;
846 struct prefix p, p_tmp;
847 int any = 0;
848 int64_t seqnum = -1;
849 int lenum = 0;
850 int genum = 0;
851
852 if (name == NULL || prefix == NULL || typestr == NULL) {
853 vty_out(vty, "%% Missing prefix or type\n");
854 return CMD_WARNING_CONFIG_FAILED;
855 }
856
857 /* Sequential number. */
858 if (seq)
859 seqnum = (int64_t)atol(seq);
860
861 /* ge and le number */
862 if (ge)
863 genum = atoi(ge);
864 if (le)
865 lenum = atoi(le);
866
867 /* Check filter type. */
868 if (strncmp("permit", typestr, 1) == 0)
869 type = PREFIX_PERMIT;
870 else if (strncmp("deny", typestr, 1) == 0)
871 type = PREFIX_DENY;
872 else {
873 vty_out(vty, "%% prefix type must be permit or deny\n");
874 return CMD_WARNING_CONFIG_FAILED;
875 }
876
877 /* "any" is special token for matching any IPv4 addresses. */
878 switch (afi) {
879 case AFI_IP:
880 if (strncmp("any", prefix, strlen(prefix)) == 0) {
881 ret = str2prefix_ipv4("0.0.0.0/0",
882 (struct prefix_ipv4 *)&p);
883 genum = 0;
884 lenum = IPV4_MAX_BITLEN;
885 any = 1;
886 } else
887 ret = str2prefix_ipv4(prefix, (struct prefix_ipv4 *)&p);
888
889 if (ret <= 0) {
890 vty_out(vty, "%% Malformed IPv4 prefix\n");
891 return CMD_WARNING_CONFIG_FAILED;
892 }
893
894 /* make a copy to verify prefix matches mask length */
895 prefix_copy(&p_tmp, &p);
896 apply_mask_ipv4((struct prefix_ipv4 *)&p_tmp);
897
898 break;
899 case AFI_IP6:
900 if (strncmp("any", prefix, strlen(prefix)) == 0) {
901 ret = str2prefix_ipv6("::/0", (struct prefix_ipv6 *)&p);
902 genum = 0;
903 lenum = IPV6_MAX_BITLEN;
904 any = 1;
905 } else
906 ret = str2prefix_ipv6(prefix, (struct prefix_ipv6 *)&p);
907
908 if (ret <= 0) {
909 vty_out(vty, "%% Malformed IPv6 prefix\n");
910 return CMD_WARNING_CONFIG_FAILED;
911 }
912
913 /* make a copy to verify prefix matches mask length */
914 prefix_copy(&p_tmp, &p);
915 apply_mask_ipv6((struct prefix_ipv6 *)&p_tmp);
916
917 break;
918 case AFI_L2VPN:
919 default:
920 vty_out(vty, "%% Unrecognized AFI (%d)\n", afi);
921 return CMD_WARNING_CONFIG_FAILED;
922 break;
923 }
924
925 /* If prefix has bits not under the mask, adjust it to fit */
926 if (!prefix_same(&p_tmp, &p)) {
927 char buf[PREFIX2STR_BUFFER];
928 char buf_tmp[PREFIX2STR_BUFFER];
929 prefix2str(&p, buf, sizeof(buf));
930 prefix2str(&p_tmp, buf_tmp, sizeof(buf_tmp));
931 vty_out(vty,
932 "%% Prefix-list %s prefix changed from %s to %s to match length\n",
933 name, buf, buf_tmp);
934 zlog_info(
935 "Prefix-list %s prefix changed from %s to %s to match length",
936 name, buf, buf_tmp);
937 p = p_tmp;
938 }
939
940 /* ge and le check. */
941 if (genum && (genum <= p.prefixlen))
942 return vty_invalid_prefix_range(vty, prefix);
943
944 if (lenum && (lenum < p.prefixlen))
945 return vty_invalid_prefix_range(vty, prefix);
946
947 if (lenum && (genum > lenum))
948 return vty_invalid_prefix_range(vty, prefix);
949
950 if (genum && (lenum == (afi == AFI_IP ? 32 : 128)))
951 lenum = 0;
952
953 /* Get prefix_list with name. */
954 plist = prefix_list_get(afi, 0, name);
955
956 /* Make prefix entry. */
957 pentry = prefix_list_entry_make(&p, type, seqnum, lenum, genum, any);
958
959 /* Check same policy. */
960 dup = prefix_entry_dup_check(plist, pentry);
961
962 if (dup) {
963 prefix_list_entry_free(pentry);
964 return CMD_SUCCESS;
965 }
966
967 /* Install new filter to the access_list. */
968 prefix_list_entry_add(plist, pentry);
969
970 return CMD_SUCCESS;
971 }
972
973 static int vty_prefix_list_uninstall(struct vty *vty, afi_t afi,
974 const char *name, const char *seq,
975 const char *typestr, const char *prefix,
976 const char *ge, const char *le)
977 {
978 int ret;
979 enum prefix_list_type type;
980 struct prefix_list *plist;
981 struct prefix_list_entry *pentry;
982 struct prefix p;
983 int64_t seqnum = -1;
984 int lenum = 0;
985 int genum = 0;
986
987 /* Check prefix list name. */
988 plist = prefix_list_lookup(afi, name);
989 if (!plist) {
990 vty_out(vty, "%% Can't find specified prefix-list\n");
991 return CMD_WARNING_CONFIG_FAILED;
992 }
993
994 /* Only prefix-list name specified, delete the entire prefix-list. */
995 if (seq == NULL && typestr == NULL && prefix == NULL && ge == NULL
996 && le == NULL) {
997 prefix_list_delete(plist);
998 return CMD_SUCCESS;
999 }
1000
1001 /* Check sequence number. */
1002 if (seq)
1003 seqnum = (int64_t)atol(seq);
1004
1005 /* Sequence number specified, but nothing else. */
1006 if (seq && typestr == NULL && prefix == NULL && ge == NULL
1007 && le == NULL) {
1008 pentry = prefix_seq_check(plist, seqnum);
1009
1010 if (pentry == NULL) {
1011 vty_out(vty,
1012 "%% Can't find prefix-list %s with sequence number %" PRIu64 "\n",
1013 name, seqnum);
1014 return CMD_WARNING_CONFIG_FAILED;
1015 }
1016
1017 prefix_list_entry_delete(plist, pentry, 1);
1018 return CMD_SUCCESS;
1019 }
1020
1021 /* ge and le number */
1022 if (ge)
1023 genum = atoi(ge);
1024 if (le)
1025 lenum = atoi(le);
1026
1027 /* We must have, at a minimum, both the type and prefix here */
1028 if ((typestr == NULL) || (prefix == NULL))
1029 return CMD_WARNING_CONFIG_FAILED;
1030
1031 /* Check of filter type. */
1032 if (strncmp("permit", typestr, 1) == 0)
1033 type = PREFIX_PERMIT;
1034 else if (strncmp("deny", typestr, 1) == 0)
1035 type = PREFIX_DENY;
1036 else {
1037 vty_out(vty, "%% prefix type must be permit or deny\n");
1038 return CMD_WARNING_CONFIG_FAILED;
1039 }
1040
1041 /* "any" is special token for matching any IPv4 addresses. */
1042 if (afi == AFI_IP) {
1043 if (strncmp("any", prefix, strlen(prefix)) == 0) {
1044 ret = str2prefix_ipv4("0.0.0.0/0",
1045 (struct prefix_ipv4 *)&p);
1046 genum = 0;
1047 lenum = IPV4_MAX_BITLEN;
1048 } else
1049 ret = str2prefix_ipv4(prefix, (struct prefix_ipv4 *)&p);
1050
1051 if (ret <= 0) {
1052 vty_out(vty, "%% Malformed IPv4 prefix\n");
1053 return CMD_WARNING_CONFIG_FAILED;
1054 }
1055 } else if (afi == AFI_IP6) {
1056 if (strncmp("any", prefix, strlen(prefix)) == 0) {
1057 ret = str2prefix_ipv6("::/0", (struct prefix_ipv6 *)&p);
1058 genum = 0;
1059 lenum = IPV6_MAX_BITLEN;
1060 } else
1061 ret = str2prefix_ipv6(prefix, (struct prefix_ipv6 *)&p);
1062
1063 if (ret <= 0) {
1064 vty_out(vty, "%% Malformed IPv6 prefix\n");
1065 return CMD_WARNING_CONFIG_FAILED;
1066 }
1067 }
1068
1069 /* Lookup prefix entry. */
1070 pentry =
1071 prefix_list_entry_lookup(plist, &p, type, seqnum, lenum, genum);
1072
1073 if (pentry == NULL) {
1074 vty_out(vty, "%% Can't find specified prefix-list\n");
1075 return CMD_WARNING_CONFIG_FAILED;
1076 }
1077
1078 /* Install new filter to the access_list. */
1079 prefix_list_entry_delete(plist, pentry, 1);
1080
1081 return CMD_SUCCESS;
1082 }
1083
1084 static int vty_prefix_list_desc_unset(struct vty *vty, afi_t afi,
1085 const char *name)
1086 {
1087 struct prefix_list *plist;
1088
1089 plist = prefix_list_lookup(afi, name);
1090 if (!plist) {
1091 vty_out(vty, "%% Can't find specified prefix-list\n");
1092 return CMD_WARNING_CONFIG_FAILED;
1093 }
1094
1095 XFREE(MTYPE_TMP, plist->desc);
1096
1097 if (plist->head == NULL && plist->tail == NULL && plist->desc == NULL)
1098 prefix_list_delete(plist);
1099
1100 return CMD_SUCCESS;
1101 }
1102
1103 enum display_type {
1104 normal_display,
1105 summary_display,
1106 detail_display,
1107 sequential_display,
1108 longer_display,
1109 first_match_display
1110 };
1111
1112 static void vty_show_prefix_entry(struct vty *vty, afi_t afi,
1113 struct prefix_list *plist,
1114 struct prefix_master *master,
1115 enum display_type dtype, int seqnum)
1116 {
1117 struct prefix_list_entry *pentry;
1118
1119 /* Print the name of the protocol */
1120 vty_out(vty, "%s: ", frr_protoname);
1121
1122 if (dtype == normal_display) {
1123 vty_out(vty, "ip%s prefix-list %s: %d entries\n",
1124 afi == AFI_IP ? "" : "v6", plist->name, plist->count);
1125 if (plist->desc)
1126 vty_out(vty, " Description: %s\n", plist->desc);
1127 } else if (dtype == summary_display || dtype == detail_display) {
1128 vty_out(vty, "ip%s prefix-list %s:\n",
1129 afi == AFI_IP ? "" : "v6", plist->name);
1130
1131 if (plist->desc)
1132 vty_out(vty, " Description: %s\n", plist->desc);
1133
1134 vty_out(vty,
1135 " count: %d, range entries: %d, sequences: %" PRId64 " - %" PRId64 "\n",
1136 plist->count, plist->rangecount,
1137 plist->head ? plist->head->seq : 0,
1138 plist->tail ? plist->tail->seq : 0);
1139 }
1140
1141 if (dtype != summary_display) {
1142 for (pentry = plist->head; pentry; pentry = pentry->next) {
1143 if (dtype == sequential_display
1144 && pentry->seq != seqnum)
1145 continue;
1146
1147 vty_out(vty, " ");
1148
1149 if (master->seqnum)
1150 vty_out(vty, "seq %" PRId64 " ", pentry->seq);
1151
1152 vty_out(vty, "%s ", prefix_list_type_str(pentry));
1153
1154 if (pentry->any)
1155 vty_out(vty, "any");
1156 else {
1157 struct prefix *p = &pentry->prefix;
1158 char buf[BUFSIZ];
1159
1160 vty_out(vty, "%s/%d",
1161 inet_ntop(p->family, p->u.val, buf,
1162 BUFSIZ),
1163 p->prefixlen);
1164
1165 if (pentry->ge)
1166 vty_out(vty, " ge %d", pentry->ge);
1167 if (pentry->le)
1168 vty_out(vty, " le %d", pentry->le);
1169 }
1170
1171 if (dtype == detail_display
1172 || dtype == sequential_display)
1173 vty_out(vty, " (hit count: %ld, refcount: %ld)",
1174 pentry->hitcnt, pentry->refcnt);
1175
1176 vty_out(vty, "\n");
1177 }
1178 }
1179 }
1180
1181 static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name,
1182 const char *seq, enum display_type dtype)
1183 {
1184 struct prefix_list *plist;
1185 struct prefix_master *master;
1186 int64_t seqnum = 0;
1187
1188 master = prefix_master_get(afi, 0);
1189 if (master == NULL)
1190 return CMD_WARNING;
1191
1192 if (seq)
1193 seqnum = (int64_t)atol(seq);
1194
1195 if (name) {
1196 plist = prefix_list_lookup(afi, name);
1197 if (!plist) {
1198 vty_out(vty, "%% Can't find specified prefix-list\n");
1199 return CMD_WARNING;
1200 }
1201 vty_show_prefix_entry(vty, afi, plist, master, dtype, seqnum);
1202 } else {
1203 if (dtype == detail_display || dtype == summary_display) {
1204 if (master->recent)
1205 vty_out(vty,
1206 "Prefix-list with the last deletion/insertion: %s\n",
1207 master->recent->name);
1208 }
1209
1210 for (plist = master->num.head; plist; plist = plist->next)
1211 vty_show_prefix_entry(vty, afi, plist, master, dtype,
1212 seqnum);
1213
1214 for (plist = master->str.head; plist; plist = plist->next)
1215 vty_show_prefix_entry(vty, afi, plist, master, dtype,
1216 seqnum);
1217 }
1218
1219 return CMD_SUCCESS;
1220 }
1221
1222 static int vty_show_prefix_list_prefix(struct vty *vty, afi_t afi,
1223 const char *name, const char *prefix,
1224 enum display_type type)
1225 {
1226 struct prefix_list *plist;
1227 struct prefix_list_entry *pentry;
1228 struct prefix p;
1229 int ret;
1230 int match;
1231
1232 plist = prefix_list_lookup(afi, name);
1233 if (!plist) {
1234 vty_out(vty, "%% Can't find specified prefix-list\n");
1235 return CMD_WARNING;
1236 }
1237
1238 ret = str2prefix(prefix, &p);
1239 if (ret <= 0) {
1240 vty_out(vty, "%% prefix is malformed\n");
1241 return CMD_WARNING;
1242 }
1243
1244 for (pentry = plist->head; pentry; pentry = pentry->next) {
1245 match = 0;
1246
1247 if (type == normal_display || type == first_match_display)
1248 if (prefix_same(&p, &pentry->prefix))
1249 match = 1;
1250
1251 if (type == longer_display) {
1252 if ((p.family == pentry->prefix.family)
1253 && (prefix_match(&p, &pentry->prefix)))
1254 match = 1;
1255 }
1256
1257 if (match) {
1258 vty_out(vty, " seq %" PRId64 " %s ", pentry->seq,
1259 prefix_list_type_str(pentry));
1260
1261 if (pentry->any)
1262 vty_out(vty, "any");
1263 else {
1264 struct prefix *pf = &pentry->prefix;
1265 char buf[BUFSIZ];
1266
1267 vty_out(vty, "%s/%d",
1268 inet_ntop(pf->family, pf->u.val, buf,
1269 BUFSIZ),
1270 pf->prefixlen);
1271
1272 if (pentry->ge)
1273 vty_out(vty, " ge %d", pentry->ge);
1274 if (pentry->le)
1275 vty_out(vty, " le %d", pentry->le);
1276 }
1277
1278 if (type == normal_display
1279 || type == first_match_display)
1280 vty_out(vty, " (hit count: %ld, refcount: %ld)",
1281 pentry->hitcnt, pentry->refcnt);
1282
1283 vty_out(vty, "\n");
1284
1285 if (type == first_match_display)
1286 return CMD_SUCCESS;
1287 }
1288 }
1289 return CMD_SUCCESS;
1290 }
1291
1292 static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name,
1293 const char *prefix)
1294 {
1295 struct prefix_master *master;
1296 struct prefix_list *plist;
1297 struct prefix_list_entry *pentry;
1298 int ret;
1299 struct prefix p;
1300
1301 master = prefix_master_get(afi, 0);
1302 if (master == NULL)
1303 return CMD_WARNING;
1304
1305 if (name == NULL && prefix == NULL) {
1306 for (plist = master->num.head; plist; plist = plist->next)
1307 for (pentry = plist->head; pentry;
1308 pentry = pentry->next)
1309 pentry->hitcnt = 0;
1310
1311 for (plist = master->str.head; plist; plist = plist->next)
1312 for (pentry = plist->head; pentry;
1313 pentry = pentry->next)
1314 pentry->hitcnt = 0;
1315 } else {
1316 plist = prefix_list_lookup(afi, name);
1317 if (!plist) {
1318 vty_out(vty, "%% Can't find specified prefix-list\n");
1319 return CMD_WARNING;
1320 }
1321
1322 if (prefix) {
1323 ret = str2prefix(prefix, &p);
1324 if (ret <= 0) {
1325 vty_out(vty, "%% prefix is malformed\n");
1326 return CMD_WARNING;
1327 }
1328 }
1329
1330 for (pentry = plist->head; pentry; pentry = pentry->next) {
1331 if (prefix) {
1332 if (pentry->prefix.family == p.family
1333 && prefix_match(&pentry->prefix, &p))
1334 pentry->hitcnt = 0;
1335 } else
1336 pentry->hitcnt = 0;
1337 }
1338 }
1339 return CMD_SUCCESS;
1340 }
1341
1342 #ifndef VTYSH_EXTRACT_PL
1343 #include "lib/plist_clippy.c"
1344 #endif
1345
1346 DEFPY (ip_prefix_list,
1347 ip_prefix_list_cmd,
1348 "ip prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|A.B.C.D/M$dest [{ge (0-32)|le (0-32)}]>",
1349 IP_STR
1350 PREFIX_LIST_STR
1351 "Name of a prefix list\n"
1352 "sequence number of an entry\n"
1353 "Sequence number\n"
1354 "Specify packets to reject\n"
1355 "Specify packets to forward\n"
1356 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1357 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1358 "Minimum prefix length to be matched\n"
1359 "Minimum prefix length\n"
1360 "Maximum prefix length to be matched\n"
1361 "Maximum prefix length\n")
1362 {
1363 return vty_prefix_list_install(vty, AFI_IP, prefix_list, seq_str,
1364 action, dest, ge_str, le_str);
1365 }
1366
1367 DEFPY (no_ip_prefix_list,
1368 no_ip_prefix_list_cmd,
1369 "no ip prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|A.B.C.D/M$dest [{ge (0-32)|le (0-32)}]>",
1370 NO_STR
1371 IP_STR
1372 PREFIX_LIST_STR
1373 "Name of a prefix list\n"
1374 "sequence number of an entry\n"
1375 "Sequence number\n"
1376 "Specify packets to reject\n"
1377 "Specify packets to forward\n"
1378 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1379 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1380 "Minimum prefix length to be matched\n"
1381 "Minimum prefix length\n"
1382 "Maximum prefix length to be matched\n"
1383 "Maximum prefix length\n")
1384 {
1385 return vty_prefix_list_uninstall(vty, AFI_IP, prefix_list, seq_str,
1386 action, dest, ge_str, le_str);
1387 }
1388
1389 DEFPY(no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd,
1390 "no ip prefix-list WORD seq (1-4294967295)",
1391 NO_STR IP_STR PREFIX_LIST_STR
1392 "Name of a prefix list\n"
1393 "sequence number of an entry\n"
1394 "Sequence number\n")
1395 {
1396 return vty_prefix_list_uninstall(vty, AFI_IP, prefix_list, seq_str,
1397 NULL, NULL, NULL, NULL);
1398 }
1399
1400 DEFPY (no_ip_prefix_list_all,
1401 no_ip_prefix_list_all_cmd,
1402 "no ip prefix-list WORD",
1403 NO_STR
1404 IP_STR
1405 PREFIX_LIST_STR
1406 "Name of a prefix list\n")
1407 {
1408 return vty_prefix_list_uninstall(vty, AFI_IP, prefix_list, NULL, NULL,
1409 NULL, NULL, NULL);
1410 }
1411
1412 DEFPY (ip_prefix_list_sequence_number,
1413 ip_prefix_list_sequence_number_cmd,
1414 "[no] ip prefix-list sequence-number",
1415 NO_STR
1416 IP_STR
1417 PREFIX_LIST_STR
1418 "Include/exclude sequence numbers in NVGEN\n")
1419 {
1420 prefix_master_ipv4.seqnum = no ? false : true;
1421 return CMD_SUCCESS;
1422 }
1423
1424 DEFUN (ip_prefix_list_description,
1425 ip_prefix_list_description_cmd,
1426 "ip prefix-list WORD description LINE...",
1427 IP_STR
1428 PREFIX_LIST_STR
1429 "Name of a prefix list\n"
1430 "Prefix-list specific description\n"
1431 "Up to 80 characters describing this prefix-list\n")
1432 {
1433 int idx_word = 2;
1434 int idx_line = 4;
1435 struct prefix_list *plist;
1436
1437 plist = prefix_list_get(AFI_IP, 0, argv[idx_word]->arg);
1438
1439 if (plist->desc) {
1440 XFREE(MTYPE_TMP, plist->desc);
1441 plist->desc = NULL;
1442 }
1443 plist->desc = argv_concat(argv, argc, idx_line);
1444
1445 return CMD_SUCCESS;
1446 }
1447
1448 DEFUN (no_ip_prefix_list_description,
1449 no_ip_prefix_list_description_cmd,
1450 "no ip prefix-list WORD description",
1451 NO_STR
1452 IP_STR
1453 PREFIX_LIST_STR
1454 "Name of a prefix list\n"
1455 "Prefix-list specific description\n")
1456 {
1457 int idx_word = 3;
1458 return vty_prefix_list_desc_unset(vty, AFI_IP, argv[idx_word]->arg);
1459 }
1460
1461 /* ALIAS_FIXME */
1462 DEFUN (no_ip_prefix_list_description_comment,
1463 no_ip_prefix_list_description_comment_cmd,
1464 "no ip prefix-list WORD description LINE...",
1465 NO_STR
1466 IP_STR
1467 PREFIX_LIST_STR
1468 "Name of a prefix list\n"
1469 "Prefix-list specific description\n"
1470 "Up to 80 characters describing this prefix-list\n")
1471 {
1472 return no_ip_prefix_list_description(self, vty, argc, argv);
1473 }
1474
1475 DEFPY (show_ip_prefix_list,
1476 show_ip_prefix_list_cmd,
1477 "show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]]",
1478 SHOW_STR
1479 IP_STR
1480 PREFIX_LIST_STR
1481 "Name of a prefix list\n"
1482 "sequence number of an entry\n"
1483 "Sequence number\n")
1484 {
1485 enum display_type dtype = normal_display;
1486 if (dseq)
1487 dtype = sequential_display;
1488
1489 return vty_show_prefix_list(vty, AFI_IP, prefix_list, arg_str, dtype);
1490 }
1491
1492 DEFPY (show_ip_prefix_list_prefix,
1493 show_ip_prefix_list_prefix_cmd,
1494 "show ip prefix-list WORD A.B.C.D/M$prefix [longer$dl|first-match$dfm]",
1495 SHOW_STR
1496 IP_STR
1497 PREFIX_LIST_STR
1498 "Name of a prefix list\n"
1499 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1500 "Lookup longer prefix\n"
1501 "First matched prefix\n")
1502 {
1503 enum display_type dtype = normal_display;
1504 if (dl)
1505 dtype = longer_display;
1506 else if (dfm)
1507 dtype = first_match_display;
1508
1509 return vty_show_prefix_list_prefix(vty, AFI_IP, prefix_list, prefix_str,
1510 dtype);
1511 }
1512
1513 DEFPY (show_ip_prefix_list_summary,
1514 show_ip_prefix_list_summary_cmd,
1515 "show ip prefix-list summary [WORD$prefix_list]",
1516 SHOW_STR
1517 IP_STR
1518 PREFIX_LIST_STR
1519 "Summary of prefix lists\n"
1520 "Name of a prefix list\n")
1521 {
1522 return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
1523 summary_display);
1524 }
1525
1526 DEFPY (show_ip_prefix_list_detail,
1527 show_ip_prefix_list_detail_cmd,
1528 "show ip prefix-list detail [WORD$prefix_list]",
1529 SHOW_STR
1530 IP_STR
1531 PREFIX_LIST_STR
1532 "Detail of prefix lists\n"
1533 "Name of a prefix list\n")
1534 {
1535 return vty_show_prefix_list(vty, AFI_IP, prefix_list, NULL,
1536 detail_display);
1537 }
1538
1539 DEFPY (clear_ip_prefix_list,
1540 clear_ip_prefix_list_cmd,
1541 "clear ip prefix-list [WORD [A.B.C.D/M$prefix]]",
1542 CLEAR_STR
1543 IP_STR
1544 PREFIX_LIST_STR
1545 "Name of a prefix list\n"
1546 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
1547 {
1548 return vty_clear_prefix_list(vty, AFI_IP, prefix_list, prefix_str);
1549 }
1550
1551 DEFPY (ipv6_prefix_list,
1552 ipv6_prefix_list_cmd,
1553 "ipv6 prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|X:X::X:X/M$dest [{ge (0-128)|le (0-128)}]>",
1554 IPV6_STR
1555 PREFIX_LIST_STR
1556 "Name of a prefix list\n"
1557 "sequence number of an entry\n"
1558 "Sequence number\n"
1559 "Specify packets to reject\n"
1560 "Specify packets to forward\n"
1561 "Any prefix match. Same as \"::0/0 le 128\"\n"
1562 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1563 "Maximum prefix length to be matched\n"
1564 "Maximum prefix length\n"
1565 "Minimum prefix length to be matched\n"
1566 "Minimum prefix length\n")
1567 {
1568 return vty_prefix_list_install(vty, AFI_IP6, prefix_list, seq_str,
1569 action, dest, ge_str, le_str);
1570 }
1571
1572 DEFPY (no_ipv6_prefix_list,
1573 no_ipv6_prefix_list_cmd,
1574 "no ipv6 prefix-list WORD [seq (1-4294967295)] <deny|permit>$action <any$dest|X:X::X:X/M$dest [{ge (0-128)|le (0-128)}]>",
1575 NO_STR
1576 IPV6_STR
1577 PREFIX_LIST_STR
1578 "Name of a prefix list\n"
1579 "sequence number of an entry\n"
1580 "Sequence number\n"
1581 "Specify packets to reject\n"
1582 "Specify packets to forward\n"
1583 "Any prefix match. Same as \"::0/0 le 128\"\n"
1584 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1585 "Maximum prefix length to be matched\n"
1586 "Maximum prefix length\n"
1587 "Minimum prefix length to be matched\n"
1588 "Minimum prefix length\n")
1589 {
1590 return vty_prefix_list_uninstall(vty, AFI_IP6, prefix_list, seq_str,
1591 action, dest, ge_str, le_str);
1592 }
1593
1594 DEFPY (no_ipv6_prefix_list_all,
1595 no_ipv6_prefix_list_all_cmd,
1596 "no ipv6 prefix-list WORD",
1597 NO_STR
1598 IPV6_STR
1599 PREFIX_LIST_STR
1600 "Name of a prefix list\n")
1601 {
1602 return vty_prefix_list_uninstall(vty, AFI_IP6, prefix_list, NULL, NULL,
1603 NULL, NULL, NULL);
1604 }
1605
1606 DEFPY (ipv6_prefix_list_sequence_number,
1607 ipv6_prefix_list_sequence_number_cmd,
1608 "[no] ipv6 prefix-list sequence-number",
1609 NO_STR
1610 IPV6_STR
1611 PREFIX_LIST_STR
1612 "Include/exclude sequence numbers in NVGEN\n")
1613 {
1614 prefix_master_ipv6.seqnum = no ? false : true;
1615 return CMD_SUCCESS;
1616 }
1617
1618 DEFUN (ipv6_prefix_list_description,
1619 ipv6_prefix_list_description_cmd,
1620 "ipv6 prefix-list WORD description LINE...",
1621 IPV6_STR
1622 PREFIX_LIST_STR
1623 "Name of a prefix list\n"
1624 "Prefix-list specific description\n"
1625 "Up to 80 characters describing this prefix-list\n")
1626 {
1627 int idx_word = 2;
1628 int iddx_line = 4;
1629 struct prefix_list *plist;
1630
1631 plist = prefix_list_get(AFI_IP6, 0, argv[idx_word]->arg);
1632
1633 if (plist->desc) {
1634 XFREE(MTYPE_TMP, plist->desc);
1635 plist->desc = NULL;
1636 }
1637 plist->desc = argv_concat(argv, argc, iddx_line);
1638
1639 return CMD_SUCCESS;
1640 }
1641
1642 DEFUN (no_ipv6_prefix_list_description,
1643 no_ipv6_prefix_list_description_cmd,
1644 "no ipv6 prefix-list WORD description",
1645 NO_STR
1646 IPV6_STR
1647 PREFIX_LIST_STR
1648 "Name of a prefix list\n"
1649 "Prefix-list specific description\n")
1650 {
1651 int idx_word = 3;
1652 return vty_prefix_list_desc_unset(vty, AFI_IP6, argv[idx_word]->arg);
1653 }
1654
1655 /* ALIAS_FIXME */
1656 DEFUN (no_ipv6_prefix_list_description_comment,
1657 no_ipv6_prefix_list_description_comment_cmd,
1658 "no ipv6 prefix-list WORD description LINE...",
1659 NO_STR
1660 IPV6_STR
1661 PREFIX_LIST_STR
1662 "Name of a prefix list\n"
1663 "Prefix-list specific description\n"
1664 "Up to 80 characters describing this prefix-list\n")
1665 {
1666 return no_ipv6_prefix_list_description(self, vty, argc, argv);
1667 }
1668
1669
1670 DEFPY (show_ipv6_prefix_list,
1671 show_ipv6_prefix_list_cmd,
1672 "show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]]",
1673 SHOW_STR
1674 IPV6_STR
1675 PREFIX_LIST_STR
1676 "Name of a prefix list\n"
1677 "sequence number of an entry\n"
1678 "Sequence number\n")
1679 {
1680 enum display_type dtype = normal_display;
1681 if (dseq)
1682 dtype = sequential_display;
1683
1684 return vty_show_prefix_list(vty, AFI_IP6, prefix_list, arg_str, dtype);
1685 }
1686
1687 DEFPY (show_ipv6_prefix_list_prefix,
1688 show_ipv6_prefix_list_prefix_cmd,
1689 "show ipv6 prefix-list WORD X:X::X:X/M$prefix [longer$dl|first-match$dfm]",
1690 SHOW_STR
1691 IPV6_STR
1692 PREFIX_LIST_STR
1693 "Name of a prefix list\n"
1694 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1695 "Lookup longer prefix\n"
1696 "First matched prefix\n")
1697 {
1698 enum display_type dtype = normal_display;
1699 if (dl)
1700 dtype = longer_display;
1701 else if (dfm)
1702 dtype = first_match_display;
1703
1704 return vty_show_prefix_list_prefix(vty, AFI_IP6, prefix_list,
1705 prefix_str, dtype);
1706 }
1707
1708 DEFPY (show_ipv6_prefix_list_summary,
1709 show_ipv6_prefix_list_summary_cmd,
1710 "show ipv6 prefix-list summary [WORD$prefix-list]",
1711 SHOW_STR
1712 IPV6_STR
1713 PREFIX_LIST_STR
1714 "Summary of prefix lists\n"
1715 "Name of a prefix list\n")
1716 {
1717 return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
1718 summary_display);
1719 }
1720
1721 DEFPY (show_ipv6_prefix_list_detail,
1722 show_ipv6_prefix_list_detail_cmd,
1723 "show ipv6 prefix-list detail [WORD$prefix-list]",
1724 SHOW_STR
1725 IPV6_STR
1726 PREFIX_LIST_STR
1727 "Detail of prefix lists\n"
1728 "Name of a prefix list\n")
1729 {
1730 return vty_show_prefix_list(vty, AFI_IP6, prefix_list, NULL,
1731 detail_display);
1732 }
1733
1734 DEFPY (clear_ipv6_prefix_list,
1735 clear_ipv6_prefix_list_cmd,
1736 "clear ipv6 prefix-list [WORD [X:X::X:X/M$prefix]]",
1737 CLEAR_STR
1738 IPV6_STR
1739 PREFIX_LIST_STR
1740 "Name of a prefix list\n"
1741 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
1742 {
1743 return vty_clear_prefix_list(vty, AFI_IP6, prefix_list, prefix_str);
1744 }
1745
1746 /* Configuration write function. */
1747 static int config_write_prefix_afi(afi_t afi, struct vty *vty)
1748 {
1749 struct prefix_list *plist;
1750 struct prefix_list_entry *pentry;
1751 struct prefix_master *master;
1752 int write = 0;
1753
1754 master = prefix_master_get(afi, 0);
1755 if (master == NULL)
1756 return 0;
1757
1758 if (!master->seqnum) {
1759 vty_out(vty, "no ip%s prefix-list sequence-number\n",
1760 afi == AFI_IP ? "" : "v6");
1761 vty_out(vty, "!\n");
1762 }
1763
1764 for (plist = master->num.head; plist; plist = plist->next) {
1765 if (plist->desc) {
1766 vty_out(vty, "ip%s prefix-list %s description %s\n",
1767 afi == AFI_IP ? "" : "v6", plist->name,
1768 plist->desc);
1769 write++;
1770 }
1771
1772 for (pentry = plist->head; pentry; pentry = pentry->next) {
1773 vty_out(vty, "ip%s prefix-list %s ",
1774 afi == AFI_IP ? "" : "v6", plist->name);
1775
1776 if (master->seqnum)
1777 vty_out(vty, "seq %" PRId64 " ", pentry->seq);
1778
1779 vty_out(vty, "%s ", prefix_list_type_str(pentry));
1780
1781 if (pentry->any)
1782 vty_out(vty, "any");
1783 else {
1784 struct prefix *p = &pentry->prefix;
1785 char buf[BUFSIZ];
1786
1787 vty_out(vty, "%s/%d",
1788 inet_ntop(p->family, p->u.val, buf,
1789 BUFSIZ),
1790 p->prefixlen);
1791
1792 if (pentry->ge)
1793 vty_out(vty, " ge %d", pentry->ge);
1794 if (pentry->le)
1795 vty_out(vty, " le %d", pentry->le);
1796 }
1797 vty_out(vty, "\n");
1798 write++;
1799 }
1800 /* vty_out (vty, "!\n"); */
1801 }
1802
1803 for (plist = master->str.head; plist; plist = plist->next) {
1804 if (plist->desc) {
1805 vty_out(vty, "ip%s prefix-list %s description %s\n",
1806 afi == AFI_IP ? "" : "v6", plist->name,
1807 plist->desc);
1808 write++;
1809 }
1810
1811 for (pentry = plist->head; pentry; pentry = pentry->next) {
1812 vty_out(vty, "ip%s prefix-list %s ",
1813 afi == AFI_IP ? "" : "v6", plist->name);
1814
1815 if (master->seqnum)
1816 vty_out(vty, "seq %" PRId64 " ", pentry->seq);
1817
1818 vty_out(vty, "%s", prefix_list_type_str(pentry));
1819
1820 if (pentry->any)
1821 vty_out(vty, " any");
1822 else {
1823 struct prefix *p = &pentry->prefix;
1824 char buf[BUFSIZ];
1825
1826 vty_out(vty, " %s/%d",
1827 inet_ntop(p->family, p->u.val, buf,
1828 BUFSIZ),
1829 p->prefixlen);
1830
1831 if (pentry->ge)
1832 vty_out(vty, " ge %d", pentry->ge);
1833 if (pentry->le)
1834 vty_out(vty, " le %d", pentry->le);
1835 }
1836 vty_out(vty, "\n");
1837 write++;
1838 }
1839 }
1840
1841 return write;
1842 }
1843
1844 struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist,
1845 uint8_t init_flag, uint8_t permit_flag,
1846 uint8_t deny_flag)
1847 {
1848 struct prefix_list_entry *pentry;
1849
1850 if (!plist)
1851 return s;
1852
1853 for (pentry = plist->head; pentry; pentry = pentry->next) {
1854 uint8_t flag = init_flag;
1855 struct prefix *p = &pentry->prefix;
1856
1857 flag |= (pentry->type == PREFIX_PERMIT ? permit_flag
1858 : deny_flag);
1859 stream_putc(s, flag);
1860 stream_putl(s, (uint32_t)pentry->seq);
1861 stream_putc(s, (uint8_t)pentry->ge);
1862 stream_putc(s, (uint8_t)pentry->le);
1863 stream_put_prefix(s, p);
1864 }
1865
1866 return s;
1867 }
1868
1869 int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp,
1870 int permit, int set)
1871 {
1872 struct prefix_list *plist;
1873 struct prefix_list_entry *pentry;
1874
1875 /* ge and le value check */
1876 if (orfp->ge && orfp->ge <= orfp->p.prefixlen)
1877 return CMD_WARNING_CONFIG_FAILED;
1878 if (orfp->le && orfp->le <= orfp->p.prefixlen)
1879 return CMD_WARNING_CONFIG_FAILED;
1880 if (orfp->le && orfp->ge > orfp->le)
1881 return CMD_WARNING_CONFIG_FAILED;
1882
1883 if (orfp->ge && orfp->le == (afi == AFI_IP ? 32 : 128))
1884 orfp->le = 0;
1885
1886 plist = prefix_list_get(afi, 1, name);
1887 if (!plist)
1888 return CMD_WARNING_CONFIG_FAILED;
1889
1890 apply_mask(&orfp->p);
1891
1892 if (set) {
1893 pentry = prefix_list_entry_make(
1894 &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY),
1895 orfp->seq, orfp->le, orfp->ge, 0);
1896
1897 if (prefix_entry_dup_check(plist, pentry)) {
1898 prefix_list_entry_free(pentry);
1899 return CMD_WARNING_CONFIG_FAILED;
1900 }
1901
1902 prefix_list_entry_add(plist, pentry);
1903 } else {
1904 pentry = prefix_list_entry_lookup(
1905 plist, &orfp->p, (permit ? PREFIX_PERMIT : PREFIX_DENY),
1906 orfp->seq, orfp->le, orfp->ge);
1907
1908 if (!pentry)
1909 return CMD_WARNING_CONFIG_FAILED;
1910
1911 prefix_list_entry_delete(plist, pentry, 1);
1912 }
1913
1914 return CMD_SUCCESS;
1915 }
1916
1917 void prefix_bgp_orf_remove_all(afi_t afi, char *name)
1918 {
1919 struct prefix_list *plist;
1920
1921 plist = prefix_bgp_orf_lookup(afi, name);
1922 if (plist)
1923 prefix_list_delete(plist);
1924 }
1925
1926 /* return prefix count */
1927 int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name,
1928 bool use_json)
1929 {
1930 struct prefix_list *plist;
1931 struct prefix_list_entry *pentry;
1932 json_object *json = NULL;
1933 json_object *json_prefix = NULL;
1934 json_object *json_list = NULL;
1935
1936 plist = prefix_bgp_orf_lookup(afi, name);
1937 if (!plist)
1938 return 0;
1939
1940 if (!vty)
1941 return plist->count;
1942
1943 if (use_json) {
1944 json = json_object_new_object();
1945 json_prefix = json_object_new_object();
1946 json_list = json_object_new_object();
1947
1948 json_object_int_add(json_prefix, "prefixListCounter",
1949 plist->count);
1950 json_object_string_add(json_prefix, "prefixListName",
1951 plist->name);
1952
1953 for (pentry = plist->head; pentry; pentry = pentry->next) {
1954 struct prefix *p = &pentry->prefix;
1955 char buf_a[BUFSIZ];
1956 char buf_b[BUFSIZ];
1957
1958 sprintf(buf_a, "%s/%d",
1959 inet_ntop(p->family, p->u.val, buf_b,
1960 BUFSIZ),
1961 p->prefixlen);
1962
1963 json_object_int_add(json_list, "seq", pentry->seq);
1964 json_object_string_add(json_list, "seqPrefixListType",
1965 prefix_list_type_str(pentry));
1966
1967 if (pentry->ge)
1968 json_object_int_add(json_list, "ge",
1969 pentry->ge);
1970 if (pentry->le)
1971 json_object_int_add(json_list, "le",
1972 pentry->le);
1973
1974 json_object_object_add(json_prefix, buf_a, json_list);
1975 }
1976 if (afi == AFI_IP)
1977 json_object_object_add(json, "ipPrefixList",
1978 json_prefix);
1979 else
1980 json_object_object_add(json, "ipv6PrefixList",
1981 json_prefix);
1982
1983 vty_out(vty, "%s\n", json_object_to_json_string_ext(
1984 json, JSON_C_TO_STRING_PRETTY));
1985 json_object_free(json);
1986 } else {
1987 vty_out(vty, "ip%s prefix-list %s: %d entries\n",
1988 afi == AFI_IP ? "" : "v6", plist->name, plist->count);
1989
1990 for (pentry = plist->head; pentry; pentry = pentry->next) {
1991 struct prefix *p = &pentry->prefix;
1992 char buf[BUFSIZ];
1993
1994 vty_out(vty, " seq %" PRId64 " %s %s/%d",
1995 pentry->seq,
1996 prefix_list_type_str(pentry),
1997 inet_ntop(p->family, p->u.val, buf, BUFSIZ),
1998 p->prefixlen);
1999
2000 if (pentry->ge)
2001 vty_out(vty, " ge %d", pentry->ge);
2002 if (pentry->le)
2003 vty_out(vty, " le %d", pentry->le);
2004
2005 vty_out(vty, "\n");
2006 }
2007 }
2008 return plist->count;
2009 }
2010
2011 static void prefix_list_reset_afi(afi_t afi, int orf)
2012 {
2013 struct prefix_list *plist;
2014 struct prefix_list *next;
2015 struct prefix_master *master;
2016
2017 master = prefix_master_get(afi, orf);
2018 if (master == NULL)
2019 return;
2020
2021 for (plist = master->num.head; plist; plist = next) {
2022 next = plist->next;
2023 prefix_list_delete(plist);
2024 }
2025 for (plist = master->str.head; plist; plist = next) {
2026 next = plist->next;
2027 prefix_list_delete(plist);
2028 }
2029
2030 assert(master->num.head == NULL);
2031 assert(master->num.tail == NULL);
2032
2033 assert(master->str.head == NULL);
2034 assert(master->str.tail == NULL);
2035
2036 master->seqnum = 1;
2037 master->recent = NULL;
2038 }
2039
2040
2041 /* Prefix-list node. */
2042 static struct cmd_node prefix_node = {PREFIX_NODE,
2043 "", /* Prefix list has no interface. */
2044 1};
2045
2046 static int config_write_prefix_ipv4(struct vty *vty)
2047 {
2048 return config_write_prefix_afi(AFI_IP, vty);
2049 }
2050
2051 static void plist_autocomplete_afi(afi_t afi, vector comps,
2052 struct cmd_token *token)
2053 {
2054 struct prefix_list *plist;
2055 struct prefix_master *master;
2056
2057 master = prefix_master_get(afi, 0);
2058 if (master == NULL)
2059 return;
2060
2061 for (plist = master->str.head; plist; plist = plist->next)
2062 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, plist->name));
2063 for (plist = master->num.head; plist; plist = plist->next)
2064 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, plist->name));
2065 }
2066
2067 static void plist_autocomplete(vector comps, struct cmd_token *token)
2068 {
2069 plist_autocomplete_afi(AFI_IP, comps, token);
2070 plist_autocomplete_afi(AFI_IP6, comps, token);
2071 }
2072
2073 static const struct cmd_variable_handler plist_var_handlers[] = {
2074 {/* "prefix-list WORD" */
2075 .varname = "prefix_list",
2076 .completions = plist_autocomplete},
2077 {.completions = NULL}};
2078
2079
2080 static void prefix_list_init_ipv4(void)
2081 {
2082 install_node(&prefix_node, config_write_prefix_ipv4);
2083
2084 install_element(CONFIG_NODE, &ip_prefix_list_cmd);
2085 install_element(CONFIG_NODE, &no_ip_prefix_list_cmd);
2086 install_element(CONFIG_NODE, &no_ip_prefix_list_seq_cmd);
2087 install_element(CONFIG_NODE, &no_ip_prefix_list_all_cmd);
2088
2089 install_element(CONFIG_NODE, &ip_prefix_list_description_cmd);
2090 install_element(CONFIG_NODE, &no_ip_prefix_list_description_cmd);
2091 install_element(CONFIG_NODE,
2092 &no_ip_prefix_list_description_comment_cmd);
2093
2094 install_element(CONFIG_NODE, &ip_prefix_list_sequence_number_cmd);
2095
2096 install_element(VIEW_NODE, &show_ip_prefix_list_cmd);
2097 install_element(VIEW_NODE, &show_ip_prefix_list_prefix_cmd);
2098 install_element(VIEW_NODE, &show_ip_prefix_list_summary_cmd);
2099 install_element(VIEW_NODE, &show_ip_prefix_list_detail_cmd);
2100
2101 install_element(ENABLE_NODE, &clear_ip_prefix_list_cmd);
2102 }
2103
2104 /* Prefix-list node. */
2105 static struct cmd_node prefix_ipv6_node = {
2106 PREFIX_IPV6_NODE, "", /* Prefix list has no interface. */
2107 1};
2108
2109 static int config_write_prefix_ipv6(struct vty *vty)
2110 {
2111 return config_write_prefix_afi(AFI_IP6, vty);
2112 }
2113
2114 static void prefix_list_init_ipv6(void)
2115 {
2116 install_node(&prefix_ipv6_node, config_write_prefix_ipv6);
2117
2118 install_element(CONFIG_NODE, &ipv6_prefix_list_cmd);
2119 install_element(CONFIG_NODE, &no_ipv6_prefix_list_cmd);
2120 install_element(CONFIG_NODE, &no_ipv6_prefix_list_all_cmd);
2121
2122 install_element(CONFIG_NODE, &ipv6_prefix_list_description_cmd);
2123 install_element(CONFIG_NODE, &no_ipv6_prefix_list_description_cmd);
2124 install_element(CONFIG_NODE,
2125 &no_ipv6_prefix_list_description_comment_cmd);
2126
2127 install_element(CONFIG_NODE, &ipv6_prefix_list_sequence_number_cmd);
2128
2129 install_element(VIEW_NODE, &show_ipv6_prefix_list_cmd);
2130 install_element(VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd);
2131 install_element(VIEW_NODE, &show_ipv6_prefix_list_summary_cmd);
2132 install_element(VIEW_NODE, &show_ipv6_prefix_list_detail_cmd);
2133
2134 install_element(ENABLE_NODE, &clear_ipv6_prefix_list_cmd);
2135 }
2136
2137 void prefix_list_init(void)
2138 {
2139 cmd_variable_handler_register(plist_var_handlers);
2140
2141 prefix_list_init_ipv4();
2142 prefix_list_init_ipv6();
2143 }
2144
2145 void prefix_list_reset(void)
2146 {
2147 prefix_list_reset_afi(AFI_IP, 0);
2148 prefix_list_reset_afi(AFI_IP6, 0);
2149 prefix_list_reset_afi(AFI_IP, 1);
2150 prefix_list_reset_afi(AFI_IP6, 1);
2151 }