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
)
339 static void trie_walk_affected(size_t validbits
, struct pltrie_table
*table
,
340 uint8_t byte
, struct prefix_list_entry
*object
,
341 void (*fn
)(struct prefix_list_entry
*object
,
342 struct prefix_list_entry
**updptr
))
347 if (validbits
> PLC_BITS
) {
348 fn(object
, &table
->entries
[byte
].final_chain
);
352 mask
= (1 << (8 - validbits
)) - 1;
353 for (bwalk
= byte
& ~mask
; bwalk
<= byte
+ mask
; bwalk
++) {
354 fn(object
, &table
->entries
[bwalk
].up_chain
);
358 static void trie_uninstall_fn(struct prefix_list_entry
*object
,
359 struct prefix_list_entry
**updptr
)
361 for (; *updptr
; updptr
= &(*updptr
)->next_best
)
362 if (*updptr
== object
) {
363 *updptr
= object
->next_best
;
368 static int trie_table_empty(struct pltrie_table
*table
)
371 for (i
= 0; i
< PLC_LEN
; i
++)
372 if (table
->entries
[i
].next_table
|| table
->entries
[i
].up_chain
)
377 static void prefix_list_trie_del(struct prefix_list
*plist
,
378 struct prefix_list_entry
*pentry
)
380 size_t depth
, maxdepth
= plist
->master
->trie_depth
;
381 uint8_t *bytes
= pentry
->prefix
.u
.val
;
382 size_t validbits
= pentry
->prefix
.prefixlen
;
383 struct pltrie_table
*table
, **tables
[PLC_MAXLEVEL
];
386 for (depth
= 0; validbits
> PLC_BITS
&& depth
< maxdepth
- 1; depth
++) {
387 uint8_t byte
= bytes
[depth
];
388 assert(table
->entries
[byte
].next_table
);
390 tables
[depth
+ 1] = &table
->entries
[byte
].next_table
;
391 table
= table
->entries
[byte
].next_table
;
393 validbits
-= PLC_BITS
;
396 trie_walk_affected(validbits
, table
, bytes
[depth
], pentry
,
399 for (; depth
> 0; depth
--)
400 if (trie_table_empty(*tables
[depth
])) {
401 XFREE(MTYPE_PREFIX_LIST_TRIE
, *tables
[depth
]);
406 void prefix_list_entry_delete(struct prefix_list
*plist
,
407 struct prefix_list_entry
*pentry
,
410 if (plist
== NULL
|| pentry
== NULL
)
413 prefix_list_trie_del(plist
, pentry
);
416 pentry
->prev
->next
= pentry
->next
;
418 plist
->head
= pentry
->next
;
420 pentry
->next
->prev
= pentry
->prev
;
422 plist
->tail
= pentry
->prev
;
424 route_map_notify_pentry_dependencies(plist
->name
, pentry
,
425 RMAP_EVENT_PLIST_DELETED
);
426 prefix_list_entry_free(pentry
);
431 route_map_notify_dependencies(plist
->name
,
432 RMAP_EVENT_PLIST_DELETED
);
433 if (plist
->master
->delete_hook
)
434 (*plist
->master
->delete_hook
)(plist
);
436 if (plist
->head
== NULL
&& plist
->tail
== NULL
437 && plist
->desc
== NULL
)
438 prefix_list_delete(plist
);
440 plist
->master
->recent
= plist
;
444 static void trie_install_fn(struct prefix_list_entry
*object
,
445 struct prefix_list_entry
**updptr
)
448 if (*updptr
== object
)
450 if ((*updptr
)->prefix
.prefixlen
< object
->prefix
.prefixlen
)
452 if ((*updptr
)->prefix
.prefixlen
== object
->prefix
.prefixlen
453 && (*updptr
)->seq
> object
->seq
)
455 updptr
= &(*updptr
)->next_best
;
458 if (!object
->next_best
)
459 object
->next_best
= *updptr
;
461 assert(object
->next_best
== *updptr
|| !*updptr
);
466 static void prefix_list_trie_add(struct prefix_list
*plist
,
467 struct prefix_list_entry
*pentry
)
469 size_t depth
= plist
->master
->trie_depth
;
470 uint8_t *bytes
= pentry
->prefix
.u
.val
;
471 size_t validbits
= pentry
->prefix
.prefixlen
;
472 struct pltrie_table
*table
;
475 while (validbits
> PLC_BITS
&& depth
> 1) {
476 if (!table
->entries
[*bytes
].next_table
)
477 table
->entries
[*bytes
].next_table
=
478 XCALLOC(MTYPE_PREFIX_LIST_TRIE
,
479 sizeof(struct pltrie_table
));
480 table
= table
->entries
[*bytes
].next_table
;
483 validbits
-= PLC_BITS
;
486 trie_walk_affected(validbits
, table
, *bytes
, pentry
, trie_install_fn
);
489 static void prefix_list_entry_add(struct prefix_list
*plist
,
490 struct prefix_list_entry
*pentry
)
492 struct prefix_list_entry
*replace
;
493 struct prefix_list_entry
*point
;
495 /* Automatic asignment of seq no. */
496 if (pentry
->seq
== -1)
497 pentry
->seq
= prefix_new_seq_get(plist
);
499 if (plist
->tail
&& pentry
->seq
> plist
->tail
->seq
)
502 /* Is there any same seq prefix list entry? */
503 replace
= prefix_seq_check(plist
, pentry
->seq
);
505 prefix_list_entry_delete(plist
, replace
, 0);
507 /* Check insert point. */
508 for (point
= plist
->head
; point
; point
= point
->next
)
509 if (point
->seq
>= pentry
->seq
)
513 /* In case of this is the first element of the list. */
514 pentry
->next
= point
;
518 point
->prev
->next
= pentry
;
520 plist
->head
= pentry
;
522 pentry
->prev
= point
->prev
;
523 point
->prev
= pentry
;
526 plist
->tail
->next
= pentry
;
528 plist
->head
= pentry
;
530 pentry
->prev
= plist
->tail
;
531 plist
->tail
= pentry
;
534 prefix_list_trie_add(plist
, pentry
);
536 /* Increment count. */
539 route_map_notify_pentry_dependencies(plist
->name
, pentry
,
540 RMAP_EVENT_PLIST_ADDED
);
542 /* Run hook function. */
543 if (plist
->master
->add_hook
)
544 (*plist
->master
->add_hook
)(plist
);
546 route_map_notify_dependencies(plist
->name
, RMAP_EVENT_PLIST_ADDED
);
547 plist
->master
->recent
= plist
;
551 * Prefix list entry update start procedure:
552 * Remove entry from previosly installed master list, tries and notify
555 * \param[in] ple prefix list entry.
557 void prefix_list_entry_update_start(struct prefix_list_entry
*ple
)
559 struct prefix_list
*pl
= ple
->pl
;
561 /* Not installed, nothing to do. */
565 prefix_list_trie_del(pl
, ple
);
567 /* List manipulation: shameless copy from `prefix_list_entry_delete`. */
569 ple
->prev
->next
= ple
->next
;
571 pl
->head
= ple
->next
;
573 ple
->next
->prev
= ple
->prev
;
575 pl
->tail
= ple
->prev
;
577 route_map_notify_pentry_dependencies(pl
->name
, ple
,
578 RMAP_EVENT_PLIST_DELETED
);
581 route_map_notify_dependencies(pl
->name
, RMAP_EVENT_PLIST_DELETED
);
582 if (pl
->master
->delete_hook
)
583 (*pl
->master
->delete_hook
)(pl
);
585 if (pl
->head
|| pl
->tail
|| pl
->desc
)
586 pl
->master
->recent
= pl
;
588 ple
->next_best
= NULL
;
589 ple
->installed
= false;
593 * Prefix list entry update finish procedure:
594 * Add entry back master list, to the trie, notify observers and call master
597 * \param[in] ple prefix list entry.
599 void prefix_list_entry_update_finish(struct prefix_list_entry
*ple
)
601 struct prefix_list
*pl
= ple
->pl
;
602 struct prefix_list_entry
*point
;
604 /* Already installed, nothing to do. */
609 * Check if the entry is installable:
610 * We can only install entry if at least the prefix is provided (IPv4
613 if (ple
->prefix
.family
!= AF_INET
&& ple
->prefix
.family
!= AF_INET6
)
616 /* List manipulation: shameless copy from `prefix_list_entry_add`. */
617 if (pl
->tail
&& ple
->seq
> pl
->tail
->seq
)
620 /* Check insert point. */
621 for (point
= pl
->head
; point
; point
= point
->next
)
622 if (point
->seq
>= ple
->seq
)
626 /* In case of this is the first element of the list. */
631 point
->prev
->next
= ple
;
635 ple
->prev
= point
->prev
;
639 pl
->tail
->next
= ple
;
643 ple
->prev
= pl
->tail
;
647 prefix_list_trie_add(pl
, ple
);
650 route_map_notify_pentry_dependencies(pl
->name
, ple
,
651 RMAP_EVENT_PLIST_ADDED
);
653 /* Run hook function. */
654 if (pl
->master
->add_hook
)
655 (*pl
->master
->add_hook
)(pl
);
657 route_map_notify_dependencies(pl
->name
, RMAP_EVENT_PLIST_ADDED
);
658 pl
->master
->recent
= pl
;
660 ple
->installed
= true;
664 * Same as `prefix_list_entry_delete` but without `free()`ing the list if its
667 * \param[in] ple prefix list entry.
669 void prefix_list_entry_delete2(struct prefix_list_entry
*ple
)
671 /* Does the boiler plate list removal and entry removal notification. */
672 prefix_list_entry_update_start(ple
);
674 /* Effective `free()` memory. */
675 prefix_list_entry_free(ple
);
678 /* Return string of prefix_list_type. */
679 static const char *prefix_list_type_str(struct prefix_list_entry
*pentry
)
681 switch (pentry
->type
) {
691 static int prefix_list_entry_match(struct prefix_list_entry
*pentry
,
692 const struct prefix
*p
, bool address_mode
)
696 if (pentry
->prefix
.family
!= p
->family
)
699 ret
= prefix_match(&pentry
->prefix
, p
);
706 /* In case of le nor ge is specified, exact match is performed. */
707 if (!pentry
->le
&& !pentry
->ge
) {
708 if (pentry
->prefix
.prefixlen
!= p
->prefixlen
)
712 if (p
->prefixlen
> pentry
->le
)
716 if (p
->prefixlen
< pentry
->ge
)
722 enum prefix_list_type
prefix_list_apply_ext(
723 struct prefix_list
*plist
,
724 const struct prefix_list_entry
**which
,
725 union prefixconstptr object
,
728 struct prefix_list_entry
*pentry
, *pbest
= NULL
;
730 const struct prefix
*p
= object
.p
;
731 const uint8_t *byte
= p
->u
.val
;
733 size_t validbits
= p
->prefixlen
;
734 struct pltrie_table
*table
;
742 if (plist
->count
== 0) {
745 return PREFIX_PERMIT
;
748 depth
= plist
->master
->trie_depth
;
751 for (pentry
= table
->entries
[*byte
].up_chain
; pentry
;
752 pentry
= pentry
->next_best
) {
753 if (pbest
&& pbest
->seq
< pentry
->seq
)
755 if (prefix_list_entry_match(pentry
, p
, address_mode
))
759 if (validbits
<= PLC_BITS
)
761 validbits
-= PLC_BITS
;
764 if (!table
->entries
[*byte
].next_table
)
767 table
= table
->entries
[*byte
].next_table
;
772 for (pentry
= table
->entries
[*byte
].final_chain
; pentry
;
773 pentry
= pentry
->next_best
) {
774 if (pbest
&& pbest
->seq
< pentry
->seq
)
776 if (prefix_list_entry_match(pentry
, p
, address_mode
))
796 static void __attribute__((unused
)) prefix_list_print(struct prefix_list
*plist
)
798 struct prefix_list_entry
*pentry
;
803 printf("ip prefix-list %s: %d entries\n", plist
->name
, plist
->count
);
805 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
807 printf("any %s\n", prefix_list_type_str(pentry
));
813 printf(" seq %lld %s %pFX", (long long)pentry
->seq
,
814 prefix_list_type_str(pentry
), p
);
816 printf(" ge %d", pentry
->ge
);
818 printf(" le %d", pentry
->le
);
824 /* Return 1 when plist already include pentry policy. */
825 static struct prefix_list_entry
*
826 prefix_entry_dup_check(struct prefix_list
*plist
, struct prefix_list_entry
*new)
828 size_t depth
, maxdepth
= plist
->master
->trie_depth
;
829 uint8_t byte
, *bytes
= new->prefix
.u
.val
;
830 size_t validbits
= new->prefix
.prefixlen
;
831 struct pltrie_table
*table
;
832 struct prefix_list_entry
*pentry
;
836 seq
= prefix_new_seq_get(plist
);
841 for (depth
= 0; validbits
> PLC_BITS
&& depth
< maxdepth
- 1; depth
++) {
843 if (!table
->entries
[byte
].next_table
)
846 table
= table
->entries
[byte
].next_table
;
847 validbits
-= PLC_BITS
;
851 if (validbits
> PLC_BITS
)
852 pentry
= table
->entries
[byte
].final_chain
;
854 pentry
= table
->entries
[byte
].up_chain
;
856 for (; pentry
; pentry
= pentry
->next_best
) {
857 if (prefix_same(&pentry
->prefix
, &new->prefix
)
858 && pentry
->type
== new->type
&& pentry
->le
== new->le
859 && pentry
->ge
== new->ge
&& pentry
->seq
!= seq
)
874 static void vty_show_prefix_entry(struct vty
*vty
, json_object
*json
, afi_t afi
,
875 struct prefix_list
*plist
,
876 struct prefix_master
*master
,
877 enum display_type dtype
, int seqnum
)
879 struct prefix_list_entry
*pentry
;
880 json_object
*json_pl
= NULL
;
882 /* Print the name of the protocol */
884 json_pl
= json_object_new_object();
885 json_object_object_add(json
, plist
->name
, json_pl
);
887 vty_out(vty
, "%s: ", frr_protoname
);
889 if (dtype
== normal_display
) {
891 json_object_string_add(json_pl
, "addressFamily",
893 json_object_int_add(json_pl
, "entries", plist
->count
);
895 json_object_string_add(json_pl
, "description",
898 vty_out(vty
, "ip%s prefix-list %s: %d entries\n",
899 afi
== AFI_IP
? "" : "v6", plist
->name
,
902 vty_out(vty
, " Description: %s\n",
905 } else if (dtype
== summary_display
|| dtype
== detail_display
) {
907 json_object_string_add(json_pl
, "addressFamily",
910 json_object_string_add(json_pl
, "description",
912 json_object_int_add(json_pl
, "count", plist
->count
);
913 json_object_int_add(json_pl
, "rangeEntries",
915 json_object_int_add(json_pl
, "sequenceStart",
916 plist
->head
? plist
->head
->seq
: 0);
917 json_object_int_add(json_pl
, "sequenceEnd",
918 plist
->tail
? plist
->tail
->seq
: 0);
920 vty_out(vty
, "ip%s prefix-list %s:\n",
921 afi
== AFI_IP
? "" : "v6", plist
->name
);
924 vty_out(vty
, " Description: %s\n",
928 " count: %d, range entries: %d, sequences: %" PRId64
930 plist
->count
, plist
->rangecount
,
931 plist
->head
? plist
->head
->seq
: 0,
932 plist
->tail
? plist
->tail
->seq
: 0);
936 if (dtype
!= summary_display
) {
937 json_object
*json_entries
= NULL
;
940 json_entries
= json_object_new_array();
941 json_object_object_add(json_pl
, "entries",
945 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
946 if (dtype
== sequential_display
947 && pentry
->seq
!= seqnum
)
951 json_object
*json_entry
;
953 json_entry
= json_object_new_object();
954 json_object_array_add(json_entries
, json_entry
);
956 json_object_int_add(json_entry
,
959 json_object_string_add(
961 prefix_list_type_str(pentry
));
962 json_object_string_addf(json_entry
, "prefix",
969 "minimumPrefixLength",
974 "maximumPrefixLength",
977 if (dtype
== detail_display
978 || dtype
== sequential_display
) {
979 json_object_int_add(json_entry
,
982 json_object_int_add(json_entry
,
989 vty_out(vty
, "seq %" PRId64
" ", pentry
->seq
);
992 prefix_list_type_str(pentry
));
997 struct prefix
*p
= &pentry
->prefix
;
999 vty_out(vty
, "%pFX", p
);
1002 vty_out(vty
, " ge %d",
1005 vty_out(vty
, " le %d",
1009 if (dtype
== detail_display
1010 || dtype
== sequential_display
)
1012 " (hit count: %ld, refcount: %ld)",
1013 pentry
->hitcnt
, pentry
->refcnt
);
1021 static int vty_show_prefix_list(struct vty
*vty
, afi_t afi
, const char *name
,
1022 const char *seq
, enum display_type dtype
,
1025 struct prefix_list
*plist
;
1026 struct prefix_master
*master
;
1028 json_object
*json
= NULL
;
1029 json_object
*json_proto
= NULL
;
1031 master
= prefix_master_get(afi
, 0);
1036 json
= json_object_new_object();
1037 json_proto
= json_object_new_object();
1038 json_object_object_add(json
, frr_protoname
, json_proto
);
1042 seqnum
= (int64_t)atol(seq
);
1045 plist
= prefix_list_lookup(afi
, name
);
1049 "%% Can't find specified prefix-list\n");
1052 vty_show_prefix_entry(vty
, json_proto
, afi
, plist
, master
,
1055 if (dtype
== detail_display
|| dtype
== summary_display
) {
1056 if (master
->recent
&& !uj
)
1058 "Prefix-list with the last deletion/insertion: %s\n",
1059 master
->recent
->name
);
1062 frr_each (plist
, &master
->str
, plist
)
1063 vty_show_prefix_entry(vty
, json_proto
, afi
, plist
,
1064 master
, dtype
, seqnum
);
1067 return vty_json(vty
, json
);
1070 static int vty_show_prefix_list_prefix(struct vty
*vty
, afi_t afi
,
1071 const char *name
, const char *prefix
,
1072 enum display_type type
)
1074 struct prefix_list
*plist
;
1075 struct prefix_list_entry
*pentry
;
1080 plist
= prefix_list_lookup(afi
, name
);
1082 vty_out(vty
, "%% Can't find specified prefix-list\n");
1086 ret
= str2prefix(prefix
, &p
);
1088 vty_out(vty
, "%% prefix is malformed\n");
1092 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1095 if (type
== normal_display
|| type
== first_match_display
)
1096 if (prefix_same(&p
, &pentry
->prefix
))
1099 if (type
== longer_display
) {
1100 if ((p
.family
== pentry
->prefix
.family
)
1101 && (prefix_match(&p
, &pentry
->prefix
)))
1106 vty_out(vty
, " seq %" PRId64
" %s ", pentry
->seq
,
1107 prefix_list_type_str(pentry
));
1110 vty_out(vty
, "any");
1112 struct prefix
*pf
= &pentry
->prefix
;
1114 vty_out(vty
, "%pFX", pf
);
1117 vty_out(vty
, " ge %d", pentry
->ge
);
1119 vty_out(vty
, " le %d", pentry
->le
);
1122 if (type
== normal_display
1123 || type
== first_match_display
)
1124 vty_out(vty
, " (hit count: %ld, refcount: %ld)",
1125 pentry
->hitcnt
, pentry
->refcnt
);
1129 if (type
== first_match_display
)
1136 static int vty_clear_prefix_list(struct vty
*vty
, afi_t afi
, const char *name
,
1139 struct prefix_master
*master
;
1140 struct prefix_list
*plist
;
1141 struct prefix_list_entry
*pentry
;
1145 master
= prefix_master_get(afi
, 0);
1149 if (name
== NULL
&& prefix
== NULL
) {
1150 frr_each (plist
, &master
->str
, plist
)
1151 for (pentry
= plist
->head
; pentry
;
1152 pentry
= pentry
->next
)
1155 plist
= prefix_list_lookup(afi
, name
);
1157 vty_out(vty
, "%% Can't find specified prefix-list\n");
1162 ret
= str2prefix(prefix
, &p
);
1164 vty_out(vty
, "%% prefix is malformed\n");
1169 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1171 if (pentry
->prefix
.family
== p
.family
1172 && prefix_match(&pentry
->prefix
, &p
))
1181 #include "lib/plist_clippy.c"
1183 DEFPY (show_ip_prefix_list
,
1184 show_ip_prefix_list_cmd
,
1185 "show ip prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
1189 "Name of a prefix list\n"
1190 "sequence number of an entry\n"
1194 enum display_type dtype
= normal_display
;
1196 dtype
= sequential_display
;
1198 return vty_show_prefix_list(vty
, AFI_IP
, prefix_list
, arg_str
, dtype
,
1202 DEFPY (show_ip_prefix_list_prefix
,
1203 show_ip_prefix_list_prefix_cmd
,
1204 "show ip prefix-list WORD A.B.C.D/M$prefix [longer$dl|first-match$dfm]",
1208 "Name of a prefix list\n"
1209 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1210 "Lookup longer prefix\n"
1211 "First matched prefix\n")
1213 enum display_type dtype
= normal_display
;
1215 dtype
= longer_display
;
1217 dtype
= first_match_display
;
1219 return vty_show_prefix_list_prefix(vty
, AFI_IP
, prefix_list
, prefix_str
,
1223 DEFPY (show_ip_prefix_list_summary
,
1224 show_ip_prefix_list_summary_cmd
,
1225 "show ip prefix-list summary [WORD$prefix_list] [json$uj]",
1229 "Summary of prefix lists\n"
1230 "Name of a prefix list\n"
1233 return vty_show_prefix_list(vty
, AFI_IP
, prefix_list
, NULL
,
1234 summary_display
, !!uj
);
1237 DEFPY (show_ip_prefix_list_detail
,
1238 show_ip_prefix_list_detail_cmd
,
1239 "show ip prefix-list detail [WORD$prefix_list] [json$uj]",
1243 "Detail of prefix lists\n"
1244 "Name of a prefix list\n"
1247 return vty_show_prefix_list(vty
, AFI_IP
, prefix_list
, NULL
,
1248 detail_display
, !!uj
);
1251 DEFPY (clear_ip_prefix_list
,
1252 clear_ip_prefix_list_cmd
,
1253 "clear ip prefix-list [WORD [A.B.C.D/M$prefix]]",
1257 "Name of a prefix list\n"
1258 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n")
1260 return vty_clear_prefix_list(vty
, AFI_IP
, prefix_list
, prefix_str
);
1263 DEFPY (show_ipv6_prefix_list
,
1264 show_ipv6_prefix_list_cmd
,
1265 "show ipv6 prefix-list [WORD [seq$dseq (1-4294967295)$arg]] [json$uj]",
1269 "Name of a prefix list\n"
1270 "sequence number of an entry\n"
1274 enum display_type dtype
= normal_display
;
1276 dtype
= sequential_display
;
1278 return vty_show_prefix_list(vty
, AFI_IP6
, prefix_list
, arg_str
, dtype
,
1282 DEFPY (show_ipv6_prefix_list_prefix
,
1283 show_ipv6_prefix_list_prefix_cmd
,
1284 "show ipv6 prefix-list WORD X:X::X:X/M$prefix [longer$dl|first-match$dfm]",
1288 "Name of a prefix list\n"
1289 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1290 "Lookup longer prefix\n"
1291 "First matched prefix\n")
1293 enum display_type dtype
= normal_display
;
1295 dtype
= longer_display
;
1297 dtype
= first_match_display
;
1299 return vty_show_prefix_list_prefix(vty
, AFI_IP6
, prefix_list
,
1303 DEFPY (show_ipv6_prefix_list_summary
,
1304 show_ipv6_prefix_list_summary_cmd
,
1305 "show ipv6 prefix-list summary [WORD$prefix-list] [json$uj]",
1309 "Summary of prefix lists\n"
1310 "Name of a prefix list\n"
1313 return vty_show_prefix_list(vty
, AFI_IP6
, prefix_list
, NULL
,
1314 summary_display
, !!uj
);
1317 DEFPY (show_ipv6_prefix_list_detail
,
1318 show_ipv6_prefix_list_detail_cmd
,
1319 "show ipv6 prefix-list detail [WORD$prefix-list] [json$uj]",
1323 "Detail of prefix lists\n"
1324 "Name of a prefix list\n"
1327 return vty_show_prefix_list(vty
, AFI_IP6
, prefix_list
, NULL
,
1328 detail_display
, !!uj
);
1331 DEFPY (clear_ipv6_prefix_list
,
1332 clear_ipv6_prefix_list_cmd
,
1333 "clear ipv6 prefix-list [WORD [X:X::X:X/M$prefix]]",
1337 "Name of a prefix list\n"
1338 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n")
1340 return vty_clear_prefix_list(vty
, AFI_IP6
, prefix_list
, prefix_str
);
1343 DEFPY (debug_prefix_list_match
,
1344 debug_prefix_list_match_cmd
,
1345 "debug prefix-list WORD$prefix-list match <A.B.C.D/M|X:X::X:X/M>"
1346 " [address-mode$addr_mode]",
1348 "Prefix-list test access\n"
1349 "Name of a prefix list\n"
1350 "Test prefix for prefix list result\n"
1351 "Prefix to test in ip prefix-list\n"
1352 "Prefix to test in ipv6 prefix-list\n"
1353 "Use address matching mode (PIM RP)\n")
1355 struct prefix_list
*plist
;
1356 const struct prefix_list_entry
*entry
= NULL
;
1357 enum prefix_list_type ret
;
1359 plist
= prefix_list_lookup(family2afi(match
->family
), prefix_list
);
1361 vty_out(vty
, "%% no prefix list named %s for AFI %s\n",
1362 prefix_list
, afi2str(family2afi(match
->family
)));
1366 ret
= prefix_list_apply_ext(plist
, &entry
, match
, !!addr_mode
);
1368 vty_out(vty
, "%s prefix list %s yields %s for %pFX, ",
1369 afi2str(family2afi(match
->family
)), prefix_list
,
1370 ret
== PREFIX_DENY
? "DENY" : "PERMIT", match
);
1373 vty_out(vty
, "no match found\n");
1375 vty_out(vty
, "matching entry #%"PRId64
": %pFX", entry
->seq
,
1378 vty_out(vty
, " ge %d", entry
->ge
);
1380 vty_out(vty
, " le %d", entry
->le
);
1384 /* allow using this in scripts for quick prefix-list member tests */
1385 return (ret
== PREFIX_PERMIT
) ? CMD_SUCCESS
: CMD_WARNING
;
1388 struct stream
*prefix_bgp_orf_entry(struct stream
*s
, struct prefix_list
*plist
,
1389 uint8_t init_flag
, uint8_t permit_flag
,
1392 struct prefix_list_entry
*pentry
;
1397 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1398 uint8_t flag
= init_flag
;
1399 struct prefix
*p
= &pentry
->prefix
;
1401 flag
|= (pentry
->type
== PREFIX_PERMIT
? permit_flag
1403 stream_putc(s
, flag
);
1404 stream_putl(s
, (uint32_t)pentry
->seq
);
1405 stream_putc(s
, (uint8_t)pentry
->ge
);
1406 stream_putc(s
, (uint8_t)pentry
->le
);
1407 stream_put_prefix(s
, p
);
1413 int prefix_bgp_orf_set(char *name
, afi_t afi
, struct orf_prefix
*orfp
,
1414 int permit
, int set
)
1416 struct prefix_list
*plist
;
1417 struct prefix_list_entry
*pentry
;
1419 /* ge and le value check */
1420 if (orfp
->ge
&& orfp
->ge
< orfp
->p
.prefixlen
)
1421 return CMD_WARNING_CONFIG_FAILED
;
1422 if (orfp
->le
&& orfp
->le
< orfp
->p
.prefixlen
)
1423 return CMD_WARNING_CONFIG_FAILED
;
1424 if (orfp
->le
&& orfp
->ge
> orfp
->le
)
1425 return CMD_WARNING_CONFIG_FAILED
;
1427 if (orfp
->ge
&& orfp
->le
== (afi
== AFI_IP
? 32 : 128))
1430 plist
= prefix_list_get(afi
, 1, name
);
1432 return CMD_WARNING_CONFIG_FAILED
;
1434 apply_mask(&orfp
->p
);
1437 pentry
= prefix_list_entry_make(
1438 &orfp
->p
, (permit
? PREFIX_PERMIT
: PREFIX_DENY
),
1439 orfp
->seq
, orfp
->le
, orfp
->ge
, false);
1441 if (prefix_entry_dup_check(plist
, pentry
)) {
1442 prefix_list_entry_free(pentry
);
1443 return CMD_WARNING_CONFIG_FAILED
;
1446 prefix_list_entry_add(plist
, pentry
);
1448 pentry
= prefix_list_entry_lookup(
1449 plist
, &orfp
->p
, (permit
? PREFIX_PERMIT
: PREFIX_DENY
),
1450 orfp
->seq
, orfp
->le
, orfp
->ge
);
1453 return CMD_WARNING_CONFIG_FAILED
;
1455 prefix_list_entry_delete(plist
, pentry
, 1);
1461 void prefix_bgp_orf_remove_all(afi_t afi
, char *name
)
1463 struct prefix_list
*plist
;
1465 plist
= prefix_bgp_orf_lookup(afi
, name
);
1467 prefix_list_delete(plist
);
1470 /* return prefix count */
1471 int prefix_bgp_show_prefix_list(struct vty
*vty
, afi_t afi
, char *name
,
1474 struct prefix_list
*plist
;
1475 struct prefix_list_entry
*pentry
;
1476 json_object
*json
= NULL
;
1477 json_object
*json_prefix
= NULL
;
1478 json_object
*json_list
= NULL
;
1480 plist
= prefix_bgp_orf_lookup(afi
, name
);
1485 return plist
->count
;
1488 json
= json_object_new_object();
1489 json_prefix
= json_object_new_object();
1490 json_list
= json_object_new_object();
1492 json_object_int_add(json_prefix
, "prefixListCounter",
1494 json_object_string_add(json_prefix
, "prefixListName",
1497 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1498 struct prefix
*p
= &pentry
->prefix
;
1501 snprintf(buf_a
, sizeof(buf_a
), "%pFX", p
);
1503 json_object_int_add(json_list
, "seq", pentry
->seq
);
1504 json_object_string_add(json_list
, "seqPrefixListType",
1505 prefix_list_type_str(pentry
));
1508 json_object_int_add(json_list
, "ge",
1511 json_object_int_add(json_list
, "le",
1514 json_object_object_add(json_prefix
, buf_a
, json_list
);
1517 json_object_object_add(json
, "ipPrefixList",
1520 json_object_object_add(json
, "ipv6PrefixList",
1523 vty_json(vty
, json
);
1525 vty_out(vty
, "ip%s prefix-list %s: %d entries\n",
1526 afi
== AFI_IP
? "" : "v6", plist
->name
, plist
->count
);
1528 for (pentry
= plist
->head
; pentry
; pentry
= pentry
->next
) {
1529 struct prefix
*p
= &pentry
->prefix
;
1531 vty_out(vty
, " seq %" PRId64
" %s %pFX", pentry
->seq
,
1532 prefix_list_type_str(pentry
), p
);
1535 vty_out(vty
, " ge %d", pentry
->ge
);
1537 vty_out(vty
, " le %d", pentry
->le
);
1542 return plist
->count
;
1545 static void prefix_list_reset_afi(afi_t afi
, int orf
)
1547 struct prefix_list
*plist
;
1548 struct prefix_master
*master
;
1550 master
= prefix_master_get(afi
, orf
);
1554 while ((plist
= plist_first(&master
->str
))) {
1555 prefix_list_delete(plist
);
1558 master
->recent
= NULL
;
1561 /* Prefix-list node. */
1562 static struct cmd_node prefix_node
= {
1563 .name
= "ipv4 prefix list",
1564 .node
= PREFIX_NODE
,
1568 static void plist_autocomplete_afi(afi_t afi
, vector comps
,
1569 struct cmd_token
*token
)
1571 struct prefix_list
*plist
;
1572 struct prefix_master
*master
;
1574 master
= prefix_master_get(afi
, 0);
1578 frr_each (plist
, &master
->str
, plist
)
1579 vector_set(comps
, XSTRDUP(MTYPE_COMPLETION
, plist
->name
));
1582 static void plist_autocomplete(vector comps
, struct cmd_token
*token
)
1584 plist_autocomplete_afi(AFI_IP
, comps
, token
);
1585 plist_autocomplete_afi(AFI_IP6
, comps
, token
);
1588 static const struct cmd_variable_handler plist_var_handlers
[] = {
1589 {/* "prefix-list WORD" */
1590 .varname
= "prefix_list",
1591 .completions
= plist_autocomplete
},
1592 {.tokenname
= "PREFIXLIST_NAME",
1593 .completions
= plist_autocomplete
},
1594 {.completions
= NULL
}};
1597 static void prefix_list_init_ipv4(void)
1599 install_node(&prefix_node
);
1601 install_element(VIEW_NODE
, &show_ip_prefix_list_cmd
);
1602 install_element(VIEW_NODE
, &show_ip_prefix_list_prefix_cmd
);
1603 install_element(VIEW_NODE
, &show_ip_prefix_list_summary_cmd
);
1604 install_element(VIEW_NODE
, &show_ip_prefix_list_detail_cmd
);
1606 install_element(ENABLE_NODE
, &clear_ip_prefix_list_cmd
);
1609 /* Prefix-list node. */
1610 static struct cmd_node prefix_ipv6_node
= {
1611 .name
= "ipv6 prefix list",
1612 .node
= PREFIX_IPV6_NODE
,
1616 static void prefix_list_init_ipv6(void)
1618 install_node(&prefix_ipv6_node
);
1620 install_element(VIEW_NODE
, &show_ipv6_prefix_list_cmd
);
1621 install_element(VIEW_NODE
, &show_ipv6_prefix_list_prefix_cmd
);
1622 install_element(VIEW_NODE
, &show_ipv6_prefix_list_summary_cmd
);
1623 install_element(VIEW_NODE
, &show_ipv6_prefix_list_detail_cmd
);
1624 install_element(VIEW_NODE
, &debug_prefix_list_match_cmd
);
1626 install_element(ENABLE_NODE
, &clear_ipv6_prefix_list_cmd
);
1629 void prefix_list_init(void)
1631 plist_init(&prefix_master_ipv4
.str
);
1632 plist_init(&prefix_master_orf_v4
.str
);
1633 plist_init(&prefix_master_ipv6
.str
);
1634 plist_init(&prefix_master_orf_v6
.str
);
1636 cmd_variable_handler_register(plist_var_handlers
);
1638 prefix_list_init_ipv4();
1639 prefix_list_init_ipv6();
1642 void prefix_list_reset(void)
1644 prefix_list_reset_afi(AFI_IP
, 0);
1645 prefix_list_reset_afi(AFI_IP6
, 0);
1646 prefix_list_reset_afi(AFI_IP
, 1);
1647 prefix_list_reset_afi(AFI_IP6
, 1);