1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Prefix list functions.
3 * Copyright (C) 1999 Kunihiro Ishiguro
12 #include "sockunion.h"
20 #include "plist_int.h"
22 DEFINE_MTYPE_STATIC(LIB
, PREFIX_LIST
, "Prefix List");
23 DEFINE_MTYPE_STATIC(LIB
, MPREFIX_LIST_STR
, "Prefix List Str");
24 DEFINE_MTYPE_STATIC(LIB
, PREFIX_LIST_ENTRY
, "Prefix List Entry");
25 DEFINE_MTYPE_STATIC(LIB
, PREFIX_LIST_TRIE
, "Prefix List Trie Table");
27 /* not currently changeable, code assumes bytes further down */
29 #define PLC_LEN (1 << PLC_BITS)
30 #define PLC_MAXLEVELV4 2 /* /24 for IPv4 */
31 #define PLC_MAXLEVELV6 4 /* /48 for IPv6 */
32 #define PLC_MAXLEVEL 4 /* max(v4,v6) */
36 struct pltrie_table
*next_table
;
37 struct prefix_list_entry
*final_chain
;
40 struct prefix_list_entry
*up_chain
;
44 struct pltrie_entry entries
[PLC_LEN
];
47 /* Master structure of prefix_list. */
48 struct prefix_master
{
49 /* The latest update. */
50 struct prefix_list
*recent
;
52 /* Hook function which is executed when new prefix_list is added. */
53 void (*add_hook
)(struct prefix_list
*);
55 /* Hook function which is executed when prefix_list is deleted. */
56 void (*delete_hook
)(struct prefix_list
*);
58 /* number of bytes that have a trie level */
61 struct plist_head str
;
63 static int prefix_list_compare_func(const struct prefix_list
*a
,
64 const struct prefix_list
*b
);
65 DECLARE_RBTREE_UNIQ(plist
, struct prefix_list
, plist_item
,
66 prefix_list_compare_func
);
68 /* Static structure of IPv4 prefix_list's master. */
69 static struct prefix_master prefix_master_ipv4
= {
70 NULL
, NULL
, NULL
, PLC_MAXLEVELV4
,
73 /* Static structure of IPv6 prefix-list's master. */
74 static struct prefix_master prefix_master_ipv6
= {
75 NULL
, NULL
, NULL
, PLC_MAXLEVELV6
,
78 /* Static structure of BGP ORF prefix_list's master. */
79 static struct prefix_master prefix_master_orf_v4
= {
80 NULL
, NULL
, NULL
, PLC_MAXLEVELV4
,
83 /* Static structure of BGP ORF prefix_list's master. */
84 static struct prefix_master prefix_master_orf_v6
= {
85 NULL
, NULL
, NULL
, PLC_MAXLEVELV6
,
88 static struct prefix_master
*prefix_master_get(afi_t afi
, int orf
)
91 return orf
? &prefix_master_orf_v4
: &prefix_master_ipv4
;
93 return orf
? &prefix_master_orf_v6
: &prefix_master_ipv6
;
97 const char *prefix_list_name(struct prefix_list
*plist
)
102 afi_t
prefix_list_afi(struct prefix_list
*plist
)
104 if (plist
->master
== &prefix_master_ipv4
105 || plist
->master
== &prefix_master_orf_v4
)
110 static int prefix_list_compare_func(const struct prefix_list
*a
,
111 const struct prefix_list
*b
)
113 return strcmp(a
->name
, b
->name
);
116 /* Lookup prefix_list from list of prefix_list by name. */
117 static struct prefix_list
*prefix_list_lookup_do(afi_t afi
, int orf
,
120 struct prefix_list
*plist
, lookup
;
121 struct prefix_master
*master
;
126 master
= prefix_master_get(afi
, orf
);
130 lookup
.name
= XSTRDUP(MTYPE_TMP
, name
);
131 plist
= plist_find(&master
->str
, &lookup
);
132 XFREE(MTYPE_TMP
, lookup
.name
);
136 struct prefix_list
*prefix_list_lookup(afi_t afi
, const char *name
)
138 return prefix_list_lookup_do(afi
, 0, name
);
141 struct prefix_list
*prefix_bgp_orf_lookup(afi_t afi
, const char *name
)
143 return prefix_list_lookup_do(afi
, 1, name
);
146 static struct prefix_list
*prefix_list_new(void)
148 struct prefix_list
*new;
150 new = XCALLOC(MTYPE_PREFIX_LIST
, sizeof(struct prefix_list
));
154 static void prefix_list_free(struct prefix_list
*plist
)
156 XFREE(MTYPE_PREFIX_LIST
, plist
);
159 struct prefix_list_entry
*prefix_list_entry_new(void)
161 struct prefix_list_entry
*new;
163 new = XCALLOC(MTYPE_PREFIX_LIST_ENTRY
,
164 sizeof(struct prefix_list_entry
));
168 void prefix_list_entry_free(struct prefix_list_entry
*pentry
)
170 XFREE(MTYPE_PREFIX_LIST_ENTRY
, pentry
);
173 /* Insert new prefix list to list of prefix_list. Each prefix_list
174 is sorted by the name. */
175 static struct prefix_list
*prefix_list_insert(afi_t afi
, int orf
,
178 struct prefix_list
*plist
;
179 struct prefix_master
*master
;
181 master
= prefix_master_get(afi
, orf
);
185 /* Allocate new prefix_list and copy given name. */
186 plist
= prefix_list_new();
187 plist
->name
= XSTRDUP(MTYPE_MPREFIX_LIST_STR
, name
);
188 plist
->master
= master
;
190 XCALLOC(MTYPE_PREFIX_LIST_TRIE
, sizeof(struct pltrie_table
));
192 plist_add(&master
->str
, plist
);
197 struct prefix_list
*prefix_list_get(afi_t afi
, int orf
, const char *name
)
199 struct prefix_list
*plist
;
201 plist
= prefix_list_lookup_do(afi
, orf
, name
);
204 plist
= prefix_list_insert(afi
, orf
, name
);
208 static void prefix_list_trie_del(struct prefix_list
*plist
,
209 struct prefix_list_entry
*pentry
);
211 /* Delete prefix-list from prefix_list_master and free it. */
212 void prefix_list_delete(struct prefix_list
*plist
)
214 struct prefix_master
*master
;
215 struct prefix_list_entry
*pentry
;
216 struct prefix_list_entry
*next
;
218 /* If prefix-list contain prefix_list_entry free all of it. */
219 for (pentry
= plist
->head
; pentry
; pentry
= next
) {
220 route_map_notify_pentry_dependencies(plist
->name
, pentry
,
221 RMAP_EVENT_PLIST_DELETED
);
223 prefix_list_trie_del(plist
, pentry
);
224 prefix_list_entry_free(pentry
);
228 master
= plist
->master
;
230 plist_del(&master
->str
, plist
);
232 XFREE(MTYPE_TMP
, plist
->desc
);
234 /* Make sure master's recent changed prefix-list information is
236 master
->recent
= NULL
;
238 route_map_notify_dependencies(plist
->name
, RMAP_EVENT_PLIST_DELETED
);
240 if (master
->delete_hook
)
241 (*master
->delete_hook
)(plist
);
243 XFREE(MTYPE_MPREFIX_LIST_STR
, plist
->name
);
245 XFREE(MTYPE_PREFIX_LIST_TRIE
, plist
->trie
);
247 prefix_list_free(plist
);
250 static struct prefix_list_entry
*
251 prefix_list_entry_make(struct prefix
*prefix
, enum prefix_list_type type
,
252 int64_t seq
, int le
, int ge
, bool any
)
254 struct prefix_list_entry
*pentry
;
256 pentry
= prefix_list_entry_new();
261 prefix_copy(&pentry
->prefix
, prefix
);
270 /* Add hook function. */
271 void prefix_list_add_hook(void (*func
)(struct prefix_list
*plist
))
273 prefix_master_ipv4
.add_hook
= func
;
274 prefix_master_ipv6
.add_hook
= func
;
277 /* Delete hook function. */
278 void prefix_list_delete_hook(void (*func
)(struct prefix_list
*plist
))
280 prefix_master_ipv4
.delete_hook
= func
;
281 prefix_master_ipv6
.delete_hook
= func
;
284 /* Calculate new sequential number. */
285 int64_t prefix_new_seq_get(struct prefix_list
*plist
)
289 struct prefix_list_entry
*pentry
;
293 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
294 if (maxseq
< pentry
->seq
)
295 maxseq
= pentry
->seq
;
298 newseq
= ((maxseq
/ 5) * 5) + 5;
300 return (newseq
> UINT_MAX
) ? UINT_MAX
: newseq
;
303 /* Return prefix list entry which has same seq number. */
304 static struct prefix_list_entry
*prefix_seq_check(struct prefix_list
*plist
,
307 struct prefix_list_entry
*pentry
;
309 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
)
310 if (pentry
->seq
== seq
)
315 struct prefix_list_entry
*
316 prefix_list_entry_lookup(struct prefix_list
*plist
, struct prefix
*prefix
,
317 enum prefix_list_type type
, int64_t seq
,
320 struct prefix_list_entry
*pentry
;
322 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
)
323 if (prefix_same(&pentry
->prefix
, prefix
)
324 && pentry
->type
== type
) {
325 if (seq
>= 0 && pentry
->seq
!= seq
)
328 if (pentry
->le
!= le
)
330 if (pentry
->ge
!= ge
)
340 prefix_list_entry_lookup_prefix(struct prefix_list
*plist
,
341 struct prefix_list_entry
*plist_entry
)
343 struct prefix_list_entry
*pentry
= NULL
;
345 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
346 if (pentry
== plist_entry
)
348 if (prefix_same(&pentry
->prefix
, &plist_entry
->prefix
))
355 static void trie_walk_affected(size_t validbits
, struct pltrie_table
*table
,
356 uint8_t byte
, struct prefix_list_entry
*object
,
357 void (*fn
)(struct prefix_list_entry
*object
,
358 struct prefix_list_entry
**updptr
))
363 if (validbits
> PLC_BITS
) {
364 fn(object
, &table
->entries
[byte
].final_chain
);
368 mask
= (1 << (8 - validbits
)) - 1;
369 for (bwalk
= byte
& ~mask
; bwalk
<= byte
+ mask
; bwalk
++) {
370 fn(object
, &table
->entries
[bwalk
].up_chain
);
374 static void trie_uninstall_fn(struct prefix_list_entry
*object
,
375 struct prefix_list_entry
**updptr
)
377 for (; *updptr
; updptr
= &(*updptr
)->next_best
)
378 if (*updptr
== object
) {
379 *updptr
= object
->next_best
;
384 static int trie_table_empty(struct pltrie_table
*table
)
387 for (i
= 0; i
< PLC_LEN
; i
++)
388 if (table
->entries
[i
].next_table
|| table
->entries
[i
].up_chain
)
393 static void prefix_list_trie_del(struct prefix_list
*plist
,
394 struct prefix_list_entry
*pentry
)
396 size_t depth
, maxdepth
= plist
->master
->trie_depth
;
397 uint8_t *bytes
= pentry
->prefix
.u
.val
;
398 size_t validbits
= pentry
->prefix
.prefixlen
;
399 struct pltrie_table
*table
, **tables
[PLC_MAXLEVEL
];
402 for (depth
= 0; validbits
> PLC_BITS
&& depth
< maxdepth
- 1; depth
++) {
403 uint8_t byte
= bytes
[depth
];
404 assert(table
->entries
[byte
].next_table
);
406 tables
[depth
+ 1] = &table
->entries
[byte
].next_table
;
407 table
= table
->entries
[byte
].next_table
;
409 validbits
-= PLC_BITS
;
412 trie_walk_affected(validbits
, table
, bytes
[depth
], pentry
,
415 for (; depth
> 0; depth
--)
416 if (trie_table_empty(*tables
[depth
])) {
417 XFREE(MTYPE_PREFIX_LIST_TRIE
, *tables
[depth
]);
422 void prefix_list_entry_delete(struct prefix_list
*plist
,
423 struct prefix_list_entry
*pentry
, int update_list
)
425 bool duplicate
= false;
427 if (plist
== NULL
|| pentry
== NULL
)
430 if (prefix_list_entry_lookup_prefix(plist
, pentry
))
433 prefix_list_trie_del(plist
, pentry
);
436 pentry
->prev
->next
= pentry
->next
;
438 plist
->head
= pentry
->next
;
440 pentry
->next
->prev
= pentry
->prev
;
442 plist
->tail
= pentry
->prev
;
445 route_map_notify_pentry_dependencies(plist
->name
, pentry
,
446 RMAP_EVENT_PLIST_DELETED
);
448 prefix_list_entry_free(pentry
);
453 route_map_notify_dependencies(plist
->name
,
454 RMAP_EVENT_PLIST_DELETED
);
455 if (plist
->master
->delete_hook
)
456 (*plist
->master
->delete_hook
)(plist
);
458 if (plist
->head
== NULL
&& plist
->tail
== NULL
459 && plist
->desc
== NULL
)
460 prefix_list_delete(plist
);
462 plist
->master
->recent
= plist
;
466 static void trie_install_fn(struct prefix_list_entry
*object
,
467 struct prefix_list_entry
**updptr
)
470 if (*updptr
== object
)
472 if ((*updptr
)->prefix
.prefixlen
< object
->prefix
.prefixlen
)
474 if ((*updptr
)->prefix
.prefixlen
== object
->prefix
.prefixlen
475 && (*updptr
)->seq
> object
->seq
)
477 updptr
= &(*updptr
)->next_best
;
480 if (!object
->next_best
)
481 object
->next_best
= *updptr
;
483 assert(object
->next_best
== *updptr
|| !*updptr
);
488 static void prefix_list_trie_add(struct prefix_list
*plist
,
489 struct prefix_list_entry
*pentry
)
491 size_t depth
= plist
->master
->trie_depth
;
492 uint8_t *bytes
= pentry
->prefix
.u
.val
;
493 size_t validbits
= pentry
->prefix
.prefixlen
;
494 struct pltrie_table
*table
;
497 while (validbits
> PLC_BITS
&& depth
> 1) {
498 if (!table
->entries
[*bytes
].next_table
)
499 table
->entries
[*bytes
].next_table
=
500 XCALLOC(MTYPE_PREFIX_LIST_TRIE
,
501 sizeof(struct pltrie_table
));
502 table
= table
->entries
[*bytes
].next_table
;
505 validbits
-= PLC_BITS
;
508 trie_walk_affected(validbits
, table
, *bytes
, pentry
, trie_install_fn
);
511 static void prefix_list_entry_add(struct prefix_list
*plist
,
512 struct prefix_list_entry
*pentry
)
514 struct prefix_list_entry
*replace
;
515 struct prefix_list_entry
*point
;
517 /* Automatic asignment of seq no. */
518 if (pentry
->seq
== -1)
519 pentry
->seq
= prefix_new_seq_get(plist
);
521 if (plist
->tail
&& pentry
->seq
> plist
->tail
->seq
)
524 /* Is there any same seq prefix list entry? */
525 replace
= prefix_seq_check(plist
, pentry
->seq
);
527 prefix_list_entry_delete(plist
, replace
, 0);
529 /* Check insert point. */
530 for (point
= plist
->head
; point
; point
= point
->next
)
531 if (point
->seq
>= pentry
->seq
)
535 /* In case of this is the first element of the list. */
536 pentry
->next
= point
;
540 point
->prev
->next
= pentry
;
542 plist
->head
= pentry
;
544 pentry
->prev
= point
->prev
;
545 point
->prev
= pentry
;
548 plist
->tail
->next
= pentry
;
550 plist
->head
= pentry
;
552 pentry
->prev
= plist
->tail
;
553 plist
->tail
= pentry
;
556 prefix_list_trie_add(plist
, pentry
);
558 /* Increment count. */
561 route_map_notify_pentry_dependencies(plist
->name
, pentry
,
562 RMAP_EVENT_PLIST_ADDED
);
564 /* Run hook function. */
565 if (plist
->master
->add_hook
)
566 (*plist
->master
->add_hook
)(plist
);
568 route_map_notify_dependencies(plist
->name
, RMAP_EVENT_PLIST_ADDED
);
569 plist
->master
->recent
= plist
;
573 * Prefix list entry update start procedure:
574 * Remove entry from previosly installed master list, tries and notify
577 * \param[in] ple prefix list entry.
579 void prefix_list_entry_update_start(struct prefix_list_entry
*ple
)
581 struct prefix_list
*pl
= ple
->pl
;
582 bool duplicate
= false;
584 /* Not installed, nothing to do. */
588 if (prefix_list_entry_lookup_prefix(pl
, ple
))
591 prefix_list_trie_del(pl
, ple
);
593 /* List manipulation: shameless copy from `prefix_list_entry_delete`. */
595 ple
->prev
->next
= ple
->next
;
597 pl
->head
= ple
->next
;
599 ple
->next
->prev
= ple
->prev
;
601 pl
->tail
= ple
->prev
;
604 route_map_notify_pentry_dependencies(pl
->name
, ple
,
605 RMAP_EVENT_PLIST_DELETED
);
608 route_map_notify_dependencies(pl
->name
, RMAP_EVENT_PLIST_DELETED
);
609 if (pl
->master
->delete_hook
)
610 (*pl
->master
->delete_hook
)(pl
);
612 if (pl
->head
|| pl
->tail
|| pl
->desc
)
613 pl
->master
->recent
= pl
;
615 ple
->next_best
= NULL
;
616 ple
->installed
= false;
620 * Prefix list entry update finish procedure:
621 * Add entry back master list, to the trie, notify observers and call master
624 * \param[in] ple prefix list entry.
626 void prefix_list_entry_update_finish(struct prefix_list_entry
*ple
)
628 struct prefix_list
*pl
= ple
->pl
;
629 struct prefix_list_entry
*point
;
631 /* Already installed, nothing to do. */
636 * Check if the entry is installable:
637 * We can only install entry if at least the prefix is provided (IPv4
640 if (ple
->prefix
.family
!= AF_INET
&& ple
->prefix
.family
!= AF_INET6
)
643 /* List manipulation: shameless copy from `prefix_list_entry_add`. */
644 if (pl
->tail
&& ple
->seq
> pl
->tail
->seq
)
647 /* Check insert point. */
648 for (point
= pl
->head
; point
; point
= point
->next
)
649 if (point
->seq
>= ple
->seq
)
653 /* In case of this is the first element of the list. */
658 point
->prev
->next
= ple
;
662 ple
->prev
= point
->prev
;
666 pl
->tail
->next
= ple
;
670 ple
->prev
= pl
->tail
;
674 prefix_list_trie_add(pl
, ple
);
677 route_map_notify_pentry_dependencies(pl
->name
, ple
,
678 RMAP_EVENT_PLIST_ADDED
);
680 /* Run hook function. */
681 if (pl
->master
->add_hook
)
682 (*pl
->master
->add_hook
)(pl
);
684 route_map_notify_dependencies(pl
->name
, RMAP_EVENT_PLIST_ADDED
);
685 pl
->master
->recent
= pl
;
687 ple
->installed
= true;
691 * Same as `prefix_list_entry_delete` but without `free()`ing the list if its
694 * \param[in] ple prefix list entry.
696 void prefix_list_entry_delete2(struct prefix_list_entry
*ple
)
698 /* Does the boiler plate list removal and entry removal notification. */
699 prefix_list_entry_update_start(ple
);
701 /* Effective `free()` memory. */
702 prefix_list_entry_free(ple
);
705 /* Return string of prefix_list_type. */
706 static const char *prefix_list_type_str(struct prefix_list_entry
*pentry
)
708 switch (pentry
->type
) {
718 static int prefix_list_entry_match(struct prefix_list_entry
*pentry
,
719 const struct prefix
*p
, bool address_mode
)
723 if (pentry
->prefix
.family
!= p
->family
)
726 ret
= prefix_match(&pentry
->prefix
, p
);
733 /* In case of le nor ge is specified, exact match is performed. */
734 if (!pentry
->le
&& !pentry
->ge
) {
735 if (pentry
->prefix
.prefixlen
!= p
->prefixlen
)
739 if (p
->prefixlen
> pentry
->le
)
743 if (p
->prefixlen
< pentry
->ge
)
749 enum prefix_list_type
prefix_list_apply_ext(
750 struct prefix_list
*plist
,
751 const struct prefix_list_entry
**which
,
752 union prefixconstptr object
,
755 struct prefix_list_entry
*pentry
, *pbest
= NULL
;
757 const struct prefix
*p
= object
.p
;
758 const uint8_t *byte
= p
->u
.val
;
760 size_t validbits
= p
->prefixlen
;
761 struct pltrie_table
*table
;
769 if (plist
->count
== 0) {
772 return PREFIX_PERMIT
;
775 depth
= plist
->master
->trie_depth
;
778 for (pentry
= table
->entries
[*byte
].up_chain
; pentry
;
779 pentry
= pentry
->next_best
) {
780 if (pbest
&& pbest
->seq
< pentry
->seq
)
782 if (prefix_list_entry_match(pentry
, p
, address_mode
))
786 if (validbits
<= PLC_BITS
)
788 validbits
-= PLC_BITS
;
791 if (!table
->entries
[*byte
].next_table
)
794 table
= table
->entries
[*byte
].next_table
;
799 for (pentry
= table
->entries
[*byte
].final_chain
; pentry
;
800 pentry
= pentry
->next_best
) {
801 if (pbest
&& pbest
->seq
< pentry
->seq
)
803 if (prefix_list_entry_match(pentry
, p
, address_mode
))
823 static void __attribute__((unused
)) prefix_list_print(struct prefix_list
*plist
)
825 struct prefix_list_entry
*pentry
;
830 printf("ip prefix-list %s: %d entries\n", plist
->name
, plist
->count
);
832 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
834 printf("any %s\n", prefix_list_type_str(pentry
));
840 printf(" seq %lld %s %pFX", (long long)pentry
->seq
,
841 prefix_list_type_str(pentry
), p
);
843 printf(" ge %d", pentry
->ge
);
845 printf(" le %d", pentry
->le
);
851 /* Return 1 when plist already include pentry policy. */
852 static struct prefix_list_entry
*
853 prefix_entry_dup_check(struct prefix_list
*plist
, struct prefix_list_entry
*new)
855 size_t depth
, maxdepth
= plist
->master
->trie_depth
;
856 uint8_t byte
, *bytes
= new->prefix
.u
.val
;
857 size_t validbits
= new->prefix
.prefixlen
;
858 struct pltrie_table
*table
;
859 struct prefix_list_entry
*pentry
;
863 seq
= prefix_new_seq_get(plist
);
868 for (depth
= 0; validbits
> PLC_BITS
&& depth
< maxdepth
- 1; depth
++) {
870 if (!table
->entries
[byte
].next_table
)
873 table
= table
->entries
[byte
].next_table
;
874 validbits
-= PLC_BITS
;
878 if (validbits
> PLC_BITS
)
879 pentry
= table
->entries
[byte
].final_chain
;
881 pentry
= table
->entries
[byte
].up_chain
;
883 for (; pentry
; pentry
= pentry
->next_best
) {
884 if (prefix_same(&pentry
->prefix
, &new->prefix
)
885 && pentry
->type
== new->type
&& pentry
->le
== new->le
886 && pentry
->ge
== new->ge
&& pentry
->seq
!= seq
)
901 static void vty_show_prefix_entry(struct vty
*vty
, json_object
*json
, afi_t afi
,
902 struct prefix_list
*plist
,
903 struct prefix_master
*master
,
904 enum display_type dtype
, int seqnum
)
906 struct prefix_list_entry
*pentry
;
907 json_object
*json_pl
= NULL
;
909 /* Print the name of the protocol */
911 json_pl
= json_object_new_object();
912 json_object_object_add(json
, plist
->name
, json_pl
);
914 vty_out(vty
, "%s: ", frr_protoname
);
916 if (dtype
== normal_display
) {
918 json_object_string_add(json_pl
, "addressFamily",
920 json_object_int_add(json_pl
, "entries", plist
->count
);
922 json_object_string_add(json_pl
, "description",
925 vty_out(vty
, "ip%s prefix-list %s: %d entries\n",
926 afi
== AFI_IP
? "" : "v6", plist
->name
,
929 vty_out(vty
, " Description: %s\n",
932 } else if (dtype
== summary_display
|| dtype
== detail_display
) {
934 json_object_string_add(json_pl
, "addressFamily",
937 json_object_string_add(json_pl
, "description",
939 json_object_int_add(json_pl
, "count", plist
->count
);
940 json_object_int_add(json_pl
, "rangeEntries",
942 json_object_int_add(json_pl
, "sequenceStart",
943 plist
->head
? plist
->head
->seq
: 0);
944 json_object_int_add(json_pl
, "sequenceEnd",
945 plist
->tail
? plist
->tail
->seq
: 0);
947 vty_out(vty
, "ip%s prefix-list %s:\n",
948 afi
== AFI_IP
? "" : "v6", plist
->name
);
951 vty_out(vty
, " Description: %s\n",
955 " count: %d, range entries: %d, sequences: %" PRId64
957 plist
->count
, plist
->rangecount
,
958 plist
->head
? plist
->head
->seq
: 0,
959 plist
->tail
? plist
->tail
->seq
: 0);
963 if (dtype
!= summary_display
) {
964 json_object
*json_entries
= NULL
;
967 json_entries
= json_object_new_array();
968 json_object_object_add(json_pl
, "entries",
972 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
973 if (dtype
== sequential_display
974 && pentry
->seq
!= seqnum
)
978 json_object
*json_entry
;
980 json_entry
= json_object_new_object();
981 json_object_array_add(json_entries
, json_entry
);
983 json_object_int_add(json_entry
,
986 json_object_string_add(
988 prefix_list_type_str(pentry
));
989 json_object_string_addf(json_entry
, "prefix",
996 "minimumPrefixLength",
1001 "maximumPrefixLength",
1004 if (dtype
== detail_display
1005 || dtype
== sequential_display
) {
1006 json_object_int_add(json_entry
,
1009 json_object_int_add(json_entry
,
1016 vty_out(vty
, "seq %" PRId64
" ", pentry
->seq
);
1019 prefix_list_type_str(pentry
));
1022 vty_out(vty
, "any");
1024 struct prefix
*p
= &pentry
->prefix
;
1026 vty_out(vty
, "%pFX", p
);
1029 vty_out(vty
, " ge %d",
1032 vty_out(vty
, " le %d",
1036 if (dtype
== detail_display
1037 || dtype
== sequential_display
)
1039 " (hit count: %ld, refcount: %ld)",
1040 pentry
->hitcnt
, pentry
->refcnt
);
1048 static int vty_show_prefix_list(struct vty
*vty
, afi_t afi
, const char *name
,
1049 const char *seq
, enum display_type dtype
,
1052 struct prefix_list
*plist
;
1053 struct prefix_master
*master
;
1055 json_object
*json
= NULL
;
1056 json_object
*json_proto
= NULL
;
1058 master
= prefix_master_get(afi
, 0);
1063 json
= json_object_new_object();
1064 json_proto
= json_object_new_object();
1065 json_object_object_add(json
, frr_protoname
, json_proto
);
1069 seqnum
= (int64_t)atol(seq
);
1072 plist
= prefix_list_lookup(afi
, name
);
1076 "%% Can't find specified prefix-list\n");
1079 vty_show_prefix_entry(vty
, json_proto
, afi
, plist
, master
,
1082 if (dtype
== detail_display
|| dtype
== summary_display
) {
1083 if (master
->recent
&& !uj
)
1085 "Prefix-list with the last deletion/insertion: %s\n",
1086 master
->recent
->name
);
1089 frr_each (plist
, &master
->str
, plist
)
1090 vty_show_prefix_entry(vty
, json_proto
, afi
, plist
,
1091 master
, dtype
, seqnum
);
1094 return vty_json(vty
, json
);
1097 static int vty_show_prefix_list_prefix(struct vty
*vty
, afi_t afi
,
1098 const char *name
, const char *prefix
,
1099 enum display_type type
)
1101 struct prefix_list
*plist
;
1102 struct prefix_list_entry
*pentry
;
1107 plist
= prefix_list_lookup(afi
, name
);
1109 vty_out(vty
, "%% Can't find specified prefix-list\n");
1113 ret
= str2prefix(prefix
, &p
);
1115 vty_out(vty
, "%% prefix is malformed\n");
1119 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1122 if (type
== normal_display
|| type
== first_match_display
)
1123 if (prefix_same(&p
, &pentry
->prefix
))
1126 if (type
== longer_display
) {
1127 if ((p
.family
== pentry
->prefix
.family
)
1128 && (prefix_match(&p
, &pentry
->prefix
)))
1133 vty_out(vty
, " seq %" PRId64
" %s ", pentry
->seq
,
1134 prefix_list_type_str(pentry
));
1137 vty_out(vty
, "any");
1139 struct prefix
*pf
= &pentry
->prefix
;
1141 vty_out(vty
, "%pFX", pf
);
1144 vty_out(vty
, " ge %d", pentry
->ge
);
1146 vty_out(vty
, " le %d", pentry
->le
);
1149 if (type
== normal_display
1150 || type
== first_match_display
)
1151 vty_out(vty
, " (hit count: %ld, refcount: %ld)",
1152 pentry
->hitcnt
, pentry
->refcnt
);
1156 if (type
== first_match_display
)
1163 static int vty_clear_prefix_list(struct vty
*vty
, afi_t afi
, const char *name
,
1166 struct prefix_master
*master
;
1167 struct prefix_list
*plist
;
1168 struct prefix_list_entry
*pentry
;
1172 master
= prefix_master_get(afi
, 0);
1176 if (name
== NULL
&& prefix
== NULL
) {
1177 frr_each (plist
, &master
->str
, plist
)
1178 for (pentry
= plist
->head
; pentry
;
1179 pentry
= pentry
->next
)
1182 plist
= prefix_list_lookup(afi
, name
);
1184 vty_out(vty
, "%% Can't find specified prefix-list\n");
1189 ret
= str2prefix(prefix
, &p
);
1191 vty_out(vty
, "%% prefix is malformed\n");
1196 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1198 if (pentry
->prefix
.family
== p
.family
1199 && prefix_match(&pentry
->prefix
, &p
))
1208 #include "lib/plist_clippy.c"
1210 DEFPY (show_ip_prefix_list
,
1211 show_ip_prefix_list_cmd
,
1212 "show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
1216 "Name of a prefix list\n"
1217 "sequence number of an entry\n"
1221 enum display_type dtype
= normal_display
;
1223 dtype
= sequential_display
;
1225 return vty_show_prefix_list(vty
, AFI_IP
, prefix_list
, arg_str
, dtype
,
1229 DEFPY (show_ip_prefix_list_prefix
,
1230 show_ip_prefix_list_prefix_cmd
,
1231 "show ip prefix-list WORD A.B.C.D/M$prefix [longer$dl|first-match$dfm]",
1235 "Name of a prefix list\n"
1236 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1237 "Lookup longer prefix\n"
1238 "First matched prefix\n")
1240 enum display_type dtype
= normal_display
;
1242 dtype
= longer_display
;
1244 dtype
= first_match_display
;
1246 return vty_show_prefix_list_prefix(vty
, AFI_IP
, prefix_list
, prefix_str
,
1250 DEFPY (show_ip_prefix_list_summary
,
1251 show_ip_prefix_list_summary_cmd
,
1252 "show ip prefix-list summary [WORD$prefix_list] [json$uj]",
1256 "Summary of prefix lists\n"
1257 "Name of a prefix list\n"
1260 return vty_show_prefix_list(vty
, AFI_IP
, prefix_list
, NULL
,
1261 summary_display
, !!uj
);
1264 DEFPY (show_ip_prefix_list_detail
,
1265 show_ip_prefix_list_detail_cmd
,
1266 "show ip prefix-list detail [WORD$prefix_list] [json$uj]",
1270 "Detail of prefix lists\n"
1271 "Name of a prefix list\n"
1274 return vty_show_prefix_list(vty
, AFI_IP
, prefix_list
, NULL
,
1275 detail_display
, !!uj
);
1278 DEFPY (clear_ip_prefix_list
,
1279 clear_ip_prefix_list_cmd
,
1280 "clear ip prefix-list [WORD [A.B.C.D/M$prefix]]",
1284 "Name of a prefix list\n"
1285 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
1287 return vty_clear_prefix_list(vty
, AFI_IP
, prefix_list
, prefix_str
);
1290 DEFPY (show_ipv6_prefix_list
,
1291 show_ipv6_prefix_list_cmd
,
1292 "show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
1296 "Name of a prefix list\n"
1297 "sequence number of an entry\n"
1301 enum display_type dtype
= normal_display
;
1303 dtype
= sequential_display
;
1305 return vty_show_prefix_list(vty
, AFI_IP6
, prefix_list
, arg_str
, dtype
,
1309 DEFPY (show_ipv6_prefix_list_prefix
,
1310 show_ipv6_prefix_list_prefix_cmd
,
1311 "show ipv6 prefix-list WORD X:X::X:X/M$prefix [longer$dl|first-match$dfm]",
1315 "Name of a prefix list\n"
1316 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1317 "Lookup longer prefix\n"
1318 "First matched prefix\n")
1320 enum display_type dtype
= normal_display
;
1322 dtype
= longer_display
;
1324 dtype
= first_match_display
;
1326 return vty_show_prefix_list_prefix(vty
, AFI_IP6
, prefix_list
,
1330 DEFPY (show_ipv6_prefix_list_summary
,
1331 show_ipv6_prefix_list_summary_cmd
,
1332 "show ipv6 prefix-list summary [WORD$prefix-list] [json$uj]",
1336 "Summary of prefix lists\n"
1337 "Name of a prefix list\n"
1340 return vty_show_prefix_list(vty
, AFI_IP6
, prefix_list
, NULL
,
1341 summary_display
, !!uj
);
1344 DEFPY (show_ipv6_prefix_list_detail
,
1345 show_ipv6_prefix_list_detail_cmd
,
1346 "show ipv6 prefix-list detail [WORD$prefix-list] [json$uj]",
1350 "Detail of prefix lists\n"
1351 "Name of a prefix list\n"
1354 return vty_show_prefix_list(vty
, AFI_IP6
, prefix_list
, NULL
,
1355 detail_display
, !!uj
);
1358 DEFPY (clear_ipv6_prefix_list
,
1359 clear_ipv6_prefix_list_cmd
,
1360 "clear ipv6 prefix-list [WORD [X:X::X:X/M$prefix]]",
1364 "Name of a prefix list\n"
1365 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
1367 return vty_clear_prefix_list(vty
, AFI_IP6
, prefix_list
, prefix_str
);
1370 DEFPY (debug_prefix_list_match
,
1371 debug_prefix_list_match_cmd
,
1372 "debug prefix-list WORD$prefix-list match <A.B.C.D/M|X:X::X:X/M>"
1373 " [address-mode$addr_mode]",
1375 "Prefix-list test access\n"
1376 "Name of a prefix list\n"
1377 "Test prefix for prefix list result\n"
1378 "Prefix to test in ip prefix-list\n"
1379 "Prefix to test in ipv6 prefix-list\n"
1380 "Use address matching mode (PIM RP)\n")
1382 struct prefix_list
*plist
;
1383 const struct prefix_list_entry
*entry
= NULL
;
1384 enum prefix_list_type ret
;
1386 plist
= prefix_list_lookup(family2afi(match
->family
), prefix_list
);
1388 vty_out(vty
, "%% no prefix list named %s for AFI %s\n",
1389 prefix_list
, afi2str(family2afi(match
->family
)));
1393 ret
= prefix_list_apply_ext(plist
, &entry
, match
, !!addr_mode
);
1395 vty_out(vty
, "%s prefix list %s yields %s for %pFX, ",
1396 afi2str(family2afi(match
->family
)), prefix_list
,
1397 ret
== PREFIX_DENY
? "DENY" : "PERMIT", match
);
1400 vty_out(vty
, "no match found\n");
1402 vty_out(vty
, "matching entry #%"PRId64
": %pFX", entry
->seq
,
1405 vty_out(vty
, " ge %d", entry
->ge
);
1407 vty_out(vty
, " le %d", entry
->le
);
1411 /* allow using this in scripts for quick prefix-list member tests */
1412 return (ret
== PREFIX_PERMIT
) ? CMD_SUCCESS
: CMD_WARNING
;
1415 struct stream
*prefix_bgp_orf_entry(struct stream
*s
, struct prefix_list
*plist
,
1416 uint8_t init_flag
, uint8_t permit_flag
,
1419 struct prefix_list_entry
*pentry
;
1424 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1425 uint8_t flag
= init_flag
;
1426 struct prefix
*p
= &pentry
->prefix
;
1428 flag
|= (pentry
->type
== PREFIX_PERMIT
? permit_flag
1430 stream_putc(s
, flag
);
1431 stream_putl(s
, (uint32_t)pentry
->seq
);
1432 stream_putc(s
, (uint8_t)pentry
->ge
);
1433 stream_putc(s
, (uint8_t)pentry
->le
);
1434 stream_put_prefix(s
, p
);
1440 int prefix_bgp_orf_set(char *name
, afi_t afi
, struct orf_prefix
*orfp
,
1441 int permit
, int set
)
1443 struct prefix_list
*plist
;
1444 struct prefix_list_entry
*pentry
;
1446 /* ge and le value check */
1447 if (orfp
->ge
&& orfp
->ge
< orfp
->p
.prefixlen
)
1448 return CMD_WARNING_CONFIG_FAILED
;
1449 if (orfp
->le
&& orfp
->le
< orfp
->p
.prefixlen
)
1450 return CMD_WARNING_CONFIG_FAILED
;
1451 if (orfp
->le
&& orfp
->ge
> orfp
->le
)
1452 return CMD_WARNING_CONFIG_FAILED
;
1454 if (orfp
->ge
&& orfp
->le
== (afi
== AFI_IP
? 32 : 128))
1457 plist
= prefix_list_get(afi
, 1, name
);
1459 return CMD_WARNING_CONFIG_FAILED
;
1461 apply_mask(&orfp
->p
);
1464 pentry
= prefix_list_entry_make(
1465 &orfp
->p
, (permit
? PREFIX_PERMIT
: PREFIX_DENY
),
1466 orfp
->seq
, orfp
->le
, orfp
->ge
, false);
1468 if (prefix_entry_dup_check(plist
, pentry
)) {
1469 prefix_list_entry_free(pentry
);
1470 return CMD_WARNING_CONFIG_FAILED
;
1473 prefix_list_entry_add(plist
, pentry
);
1475 pentry
= prefix_list_entry_lookup(
1476 plist
, &orfp
->p
, (permit
? PREFIX_PERMIT
: PREFIX_DENY
),
1477 orfp
->seq
, orfp
->le
, orfp
->ge
);
1480 return CMD_WARNING_CONFIG_FAILED
;
1482 prefix_list_entry_delete(plist
, pentry
, 1);
1488 void prefix_bgp_orf_remove_all(afi_t afi
, char *name
)
1490 struct prefix_list
*plist
;
1492 plist
= prefix_bgp_orf_lookup(afi
, name
);
1494 prefix_list_delete(plist
);
1497 /* return prefix count */
1498 int prefix_bgp_show_prefix_list(struct vty
*vty
, afi_t afi
, char *name
,
1501 struct prefix_list
*plist
;
1502 struct prefix_list_entry
*pentry
;
1503 json_object
*json
= NULL
;
1504 json_object
*json_prefix
= NULL
;
1505 json_object
*json_list
= NULL
;
1507 plist
= prefix_bgp_orf_lookup(afi
, name
);
1512 return plist
->count
;
1515 json
= json_object_new_object();
1516 json_prefix
= json_object_new_object();
1517 json_list
= json_object_new_object();
1519 json_object_int_add(json_prefix
, "prefixListCounter",
1521 json_object_string_add(json_prefix
, "prefixListName",
1524 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1525 struct prefix
*p
= &pentry
->prefix
;
1528 snprintf(buf_a
, sizeof(buf_a
), "%pFX", p
);
1530 json_object_int_add(json_list
, "seq", pentry
->seq
);
1531 json_object_string_add(json_list
, "seqPrefixListType",
1532 prefix_list_type_str(pentry
));
1535 json_object_int_add(json_list
, "ge",
1538 json_object_int_add(json_list
, "le",
1541 json_object_object_add(json_prefix
, buf_a
, json_list
);
1544 json_object_object_add(json
, "ipPrefixList",
1547 json_object_object_add(json
, "ipv6PrefixList",
1550 vty_json(vty
, json
);
1552 vty_out(vty
, "ip%s prefix-list %s: %d entries\n",
1553 afi
== AFI_IP
? "" : "v6", plist
->name
, plist
->count
);
1555 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1556 struct prefix
*p
= &pentry
->prefix
;
1558 vty_out(vty
, " seq %" PRId64
" %s %pFX", pentry
->seq
,
1559 prefix_list_type_str(pentry
), p
);
1562 vty_out(vty
, " ge %d", pentry
->ge
);
1564 vty_out(vty
, " le %d", pentry
->le
);
1569 return plist
->count
;
1572 static void prefix_list_reset_afi(afi_t afi
, int orf
)
1574 struct prefix_list
*plist
;
1575 struct prefix_master
*master
;
1577 master
= prefix_master_get(afi
, orf
);
1581 while ((plist
= plist_first(&master
->str
))) {
1582 prefix_list_delete(plist
);
1585 master
->recent
= NULL
;
1588 /* Prefix-list node. */
1589 static struct cmd_node prefix_node
= {
1590 .name
= "ipv4 prefix list",
1591 .node
= PREFIX_NODE
,
1595 static void plist_autocomplete_afi(afi_t afi
, vector comps
,
1596 struct cmd_token
*token
)
1598 struct prefix_list
*plist
;
1599 struct prefix_master
*master
;
1601 master
= prefix_master_get(afi
, 0);
1605 frr_each (plist
, &master
->str
, plist
)
1606 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, plist
->name
));
1609 static void plist_autocomplete(vector comps
, struct cmd_token
*token
)
1611 plist_autocomplete_afi(AFI_IP
, comps
, token
);
1612 plist_autocomplete_afi(AFI_IP6
, comps
, token
);
1615 static const struct cmd_variable_handler plist_var_handlers
[] = {
1616 {/* "prefix-list WORD" */
1617 .varname
= "prefix_list",
1618 .completions
= plist_autocomplete
},
1619 {.tokenname
= "PREFIXLIST_NAME",
1620 .completions
= plist_autocomplete
},
1621 {.completions
= NULL
}};
1624 static void prefix_list_init_ipv4(void)
1626 install_node(&prefix_node
);
1628 install_element(VIEW_NODE
, &show_ip_prefix_list_cmd
);
1629 install_element(VIEW_NODE
, &show_ip_prefix_list_prefix_cmd
);
1630 install_element(VIEW_NODE
, &show_ip_prefix_list_summary_cmd
);
1631 install_element(VIEW_NODE
, &show_ip_prefix_list_detail_cmd
);
1633 install_element(ENABLE_NODE
, &clear_ip_prefix_list_cmd
);
1636 /* Prefix-list node. */
1637 static struct cmd_node prefix_ipv6_node
= {
1638 .name
= "ipv6 prefix list",
1639 .node
= PREFIX_IPV6_NODE
,
1643 static void prefix_list_init_ipv6(void)
1645 install_node(&prefix_ipv6_node
);
1647 install_element(VIEW_NODE
, &show_ipv6_prefix_list_cmd
);
1648 install_element(VIEW_NODE
, &show_ipv6_prefix_list_prefix_cmd
);
1649 install_element(VIEW_NODE
, &show_ipv6_prefix_list_summary_cmd
);
1650 install_element(VIEW_NODE
, &show_ipv6_prefix_list_detail_cmd
);
1651 install_element(VIEW_NODE
, &debug_prefix_list_match_cmd
);
1653 install_element(ENABLE_NODE
, &clear_ipv6_prefix_list_cmd
);
1656 void prefix_list_init(void)
1658 plist_init(&prefix_master_ipv4
.str
);
1659 plist_init(&prefix_master_orf_v4
.str
);
1660 plist_init(&prefix_master_ipv6
.str
);
1661 plist_init(&prefix_master_orf_v6
.str
);
1663 cmd_variable_handler_register(plist_var_handlers
);
1665 prefix_list_init_ipv4();
1666 prefix_list_init_ipv6();
1669 void prefix_list_reset(void)
1671 prefix_list_reset_afi(AFI_IP
, 0);
1672 prefix_list_reset_afi(AFI_IP6
, 0);
1673 prefix_list_reset_afi(AFI_IP
, 1);
1674 prefix_list_reset_afi(AFI_IP6
, 1);