2 * FRR filter CLI implementation.
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 #include "northbound.h"
27 #include "lib/command.h"
28 #include "lib/filter.h"
29 #include "lib/northbound_cli.h"
30 #include "lib/plist.h"
31 #include "lib/plist_int.h"
32 #include "lib/printfrr.h"
34 #ifndef VTYSH_EXTRACT_PL
35 #include "lib/filter_cli_clippy.c"
36 #endif /* VTYSH_EXTRACT_PL */
38 #define ACCESS_LIST_STR "Access list entry\n"
39 #define ACCESS_LIST_ZEBRA_STR "Access list name\n"
40 #define ACCESS_LIST_SEQ_STR \
41 "Sequence number of an entry\n" \
43 #define ACCESS_LIST_ACTION_STR \
44 "Specify packets to reject\n" \
45 "Specify packets to forward\n"
46 #define ACCESS_LIST_REMARK_STR "Access list entry comment\n"
47 #define ACCESS_LIST_REMARK_LINE_STR "Comment up to 100 characters\n"
49 #define PREFIX_LIST_NAME_STR "Prefix list entry name\n"
52 * Helper function to generate a sequence number for legacy commands.
54 static int acl_get_seq_cb(const struct lyd_node
*dnode
, void *arg
)
57 int64_t cur_seq
= yang_dnode_get_uint32(dnode
, "sequence");
62 return YANG_ITER_CONTINUE
;
66 * Helper function that iterates over the XPath `xpath` on the candidate
67 * configuration in `vty->candidate_config`.
69 * \param[in] vty shell context with the candidate configuration.
70 * \param[in] xpath the XPath to look for the sequence leaf.
71 * \returns next unused sequence number.
73 static long acl_get_seq(struct vty
*vty
, const char *xpath
)
77 yang_dnode_iterate(acl_get_seq_cb
, &seq
, vty
->candidate_config
->dnode
,
83 static int acl_remove_if_empty(struct vty
*vty
, const char *iptype
,
86 char xpath
[XPATH_MAXLEN
];
88 snprintf(xpath
, sizeof(xpath
),
89 "/frr-filter:lib/access-list[type='%s'][name='%s']/remark",
91 /* List is not empty if there is a remark, check that: */
92 if (yang_dnode_exists(vty
->candidate_config
->dnode
, xpath
))
95 /* Check if we have any entries: */
96 snprintf(xpath
, sizeof(xpath
),
97 "/frr-filter:lib/access-list[type='%s'][name='%s']", iptype
,
100 * NOTE: if the list is empty it will return the first sequence
103 if (acl_get_seq(vty
, xpath
) != 5)
106 /* Nobody is using this list, lets remove it. */
107 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
108 return nb_cli_apply_changes(vty
, NULL
);
111 static int acl_remove(struct vty
*vty
, const char *iptype
, const char *name
,
114 char xpath
[XPATH_MAXLEN
];
118 xpath
, sizeof(xpath
),
119 "/frr-filter:lib/access-list[type='%s'][name='%s']/entry[sequence='%" PRId64
"']",
121 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
123 rv
= nb_cli_apply_changes(vty
, NULL
);
124 if (rv
== CMD_SUCCESS
)
125 return acl_remove_if_empty(vty
, iptype
, name
);
131 * Cisco (legacy) access lists.
134 access_list_std
, access_list_std_cmd
,
135 "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
137 ACCESS_LIST_ZEBRA_STR
139 ACCESS_LIST_ACTION_STR
140 "A single host address\n"
146 struct acl_dup_args ada
= {};
147 char xpath
[XPATH_MAXLEN
];
148 char xpath_entry
[XPATH_MAXLEN
+ 128];
151 * Backward compatibility: don't complain about duplicated values,
152 * just silently accept.
154 if (seq_str
== NULL
) {
155 ada
.ada_type
= "ipv4";
157 ada
.ada_action
= action
;
158 if (host_str
&& mask_str
== NULL
) {
159 ada
.ada_xpath
[0] = "./host";
160 ada
.ada_value
[0] = host_str
;
161 } else if (host_str
&& mask_str
) {
162 ada
.ada_xpath
[0] = "./network/address";
163 ada
.ada_value
[0] = host_str
;
164 ada
.ada_xpath
[1] = "./network/mask";
165 ada
.ada_value
[1] = mask_str
;
167 ada
.ada_xpath
[0] = "./source-any";
168 ada
.ada_value
[0] = "";
171 /* Duplicated entry without sequence, just quit. */
172 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
177 * Create the access-list first, so we can generate sequence if
178 * none given (backward compatibility).
180 snprintf(xpath
, sizeof(xpath
),
181 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
182 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
183 if (seq_str
== NULL
) {
184 /* Use XPath to find the next sequence number. */
185 sseq
= acl_get_seq(vty
, xpath
);
186 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
187 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
189 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
190 "%s/entry[sequence='%s']", xpath
, seq_str
);
192 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
194 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
195 if (host_str
!= NULL
&& mask_str
== NULL
) {
196 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, host_str
);
197 } else if (host_str
!= NULL
&& mask_str
!= NULL
) {
198 nb_cli_enqueue_change(vty
, "./network/address", NB_OP_MODIFY
,
200 nb_cli_enqueue_change(vty
, "./network/mask", NB_OP_MODIFY
,
203 nb_cli_enqueue_change(vty
, "./source-any", NB_OP_CREATE
, NULL
);
206 return nb_cli_apply_changes(vty
, xpath_entry
);
210 no_access_list_std
, no_access_list_std_cmd
,
211 "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>",
214 ACCESS_LIST_ZEBRA_STR
216 ACCESS_LIST_ACTION_STR
217 "A single host address\n"
223 struct acl_dup_args ada
= {};
225 /* If the user provided sequence number, then just go for it. */
227 return acl_remove(vty
, "ipv4", name
, seq
);
229 /* Otherwise, to keep compatibility, we need to figure it out. */
230 ada
.ada_type
= "ipv4";
232 ada
.ada_action
= action
;
233 if (host_str
&& mask_str
== NULL
) {
234 ada
.ada_xpath
[0] = "./host";
235 ada
.ada_value
[0] = host_str
;
236 } else if (host_str
&& mask_str
) {
237 ada
.ada_xpath
[0] = "./network/address";
238 ada
.ada_value
[0] = host_str
;
239 ada
.ada_xpath
[1] = "./network/mask";
240 ada
.ada_value
[1] = mask_str
;
242 ada
.ada_xpath
[0] = "./source-any";
243 ada
.ada_value
[0] = "";
246 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
249 return CMD_WARNING_CONFIG_FAILED
;
251 return acl_remove(vty
, "ipv4", name
, sseq
);
255 access_list_ext
, access_list_ext_cmd
,
256 "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
258 ACCESS_LIST_ZEBRA_STR
260 ACCESS_LIST_ACTION_STR
262 "Source address to match\n"
263 "Source address mask to apply\n"
264 "Single source host\n"
265 "Source address to match\n"
267 "Destination address to match\n"
268 "Destination address mask to apply\n"
269 "Single destination host\n"
270 "Destination address to match\n"
271 "Any destination host\n")
275 struct acl_dup_args ada
= {};
276 char xpath
[XPATH_MAXLEN
];
277 char xpath_entry
[XPATH_MAXLEN
+ 128];
280 * Backward compatibility: don't complain about duplicated values,
281 * just silently accept.
283 if (seq_str
== NULL
) {
284 ada
.ada_type
= "ipv4";
286 ada
.ada_action
= action
;
287 if (src_str
&& src_mask_str
== NULL
) {
288 ada
.ada_xpath
[idx
] = "./host";
289 ada
.ada_value
[idx
] = src_str
;
291 } else if (src_str
&& src_mask_str
) {
292 ada
.ada_xpath
[idx
] = "./network/address";
293 ada
.ada_value
[idx
] = src_str
;
295 ada
.ada_xpath
[idx
] = "./network/mask";
296 ada
.ada_value
[idx
] = src_mask_str
;
299 ada
.ada_xpath
[idx
] = "./source-any";
300 ada
.ada_value
[idx
] = "";
304 if (dst_str
&& dst_mask_str
== NULL
) {
305 ada
.ada_xpath
[idx
] = "./destination-host";
306 ada
.ada_value
[idx
] = dst_str
;
308 } else if (dst_str
&& dst_mask_str
) {
309 ada
.ada_xpath
[idx
] = "./destination-network/address";
310 ada
.ada_value
[idx
] = dst_str
;
312 ada
.ada_xpath
[idx
] = "./destination-network/mask";
313 ada
.ada_value
[idx
] = dst_mask_str
;
316 ada
.ada_xpath
[idx
] = "./destination-any";
317 ada
.ada_value
[idx
] = "";
321 /* Duplicated entry without sequence, just quit. */
322 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
327 * Create the access-list first, so we can generate sequence if
328 * none given (backward compatibility).
330 snprintf(xpath
, sizeof(xpath
),
331 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
332 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
333 if (seq_str
== NULL
) {
334 /* Use XPath to find the next sequence number. */
335 sseq
= acl_get_seq(vty
, xpath
);
336 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
337 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
339 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
340 "%s/entry[sequence='%s']", xpath
, seq_str
);
342 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
344 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
345 if (src_str
!= NULL
&& src_mask_str
== NULL
) {
346 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, src_str
);
347 } else if (src_str
!= NULL
&& src_mask_str
!= NULL
) {
348 nb_cli_enqueue_change(vty
, "./network/address", NB_OP_MODIFY
,
350 nb_cli_enqueue_change(vty
, "./network/mask", NB_OP_MODIFY
,
353 nb_cli_enqueue_change(vty
, "./source-any", NB_OP_CREATE
, NULL
);
356 if (dst_str
!= NULL
&& dst_mask_str
== NULL
) {
357 nb_cli_enqueue_change(vty
, "./destination-host", NB_OP_MODIFY
,
359 } else if (dst_str
!= NULL
&& dst_mask_str
!= NULL
) {
360 nb_cli_enqueue_change(vty
, "./destination-network/address",
361 NB_OP_MODIFY
, dst_str
);
362 nb_cli_enqueue_change(vty
, "./destination-network/mask",
363 NB_OP_MODIFY
, dst_mask_str
);
365 nb_cli_enqueue_change(vty
, "./destination-any", NB_OP_CREATE
,
369 return nb_cli_apply_changes(vty
, xpath_entry
);
373 no_access_list_ext
, no_access_list_ext_cmd
,
374 "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>",
377 ACCESS_LIST_ZEBRA_STR
379 ACCESS_LIST_ACTION_STR
380 "Any Internet Protocol\n"
381 "Source address to match\n"
382 "Source address mask to apply\n"
383 "Single source host\n"
384 "Source address to match\n"
386 "Destination address to match\n"
387 "Destination address mask to apply\n"
388 "Single destination host\n"
389 "Destination address to match\n"
390 "Any destination host\n")
394 struct acl_dup_args ada
= {};
396 /* If the user provided sequence number, then just go for it. */
398 return acl_remove(vty
, "ipv4", name
, seq
);
400 /* Otherwise, to keep compatibility, we need to figure it out. */
401 ada
.ada_type
= "ipv4";
403 ada
.ada_action
= action
;
404 if (src_str
&& src_mask_str
== NULL
) {
405 ada
.ada_xpath
[idx
] = "./host";
406 ada
.ada_value
[idx
] = src_str
;
408 } else if (src_str
&& src_mask_str
) {
409 ada
.ada_xpath
[idx
] = "./network/address";
410 ada
.ada_value
[idx
] = src_str
;
412 ada
.ada_xpath
[idx
] = "./network/mask";
413 ada
.ada_value
[idx
] = src_mask_str
;
416 ada
.ada_xpath
[idx
] = "./source-any";
417 ada
.ada_value
[idx
] = "";
421 if (dst_str
&& dst_mask_str
== NULL
) {
422 ada
.ada_xpath
[idx
] = "./destination-host";
423 ada
.ada_value
[idx
] = dst_str
;
425 } else if (dst_str
&& dst_mask_str
) {
426 ada
.ada_xpath
[idx
] = "./destination-network/address";
427 ada
.ada_value
[idx
] = dst_str
;
429 ada
.ada_xpath
[idx
] = "./destination-network/mask";
430 ada
.ada_value
[idx
] = dst_mask_str
;
433 ada
.ada_xpath
[idx
] = "./destination-any";
434 ada
.ada_value
[idx
] = "";
438 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
441 return CMD_WARNING_CONFIG_FAILED
;
443 return acl_remove(vty
, "ipv4", name
, sseq
);
447 * Zebra access lists.
450 access_list
, access_list_cmd
,
451 "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
453 ACCESS_LIST_ZEBRA_STR
455 ACCESS_LIST_ACTION_STR
456 "Prefix to match. e.g. 10.0.0.0/8\n"
457 "Exact match of the prefixes\n"
461 struct acl_dup_args ada
= {};
462 char xpath
[XPATH_MAXLEN
];
463 char xpath_entry
[XPATH_MAXLEN
+ 128];
466 * Backward compatibility: don't complain about duplicated values,
467 * just silently accept.
469 if (seq_str
== NULL
) {
470 ada
.ada_type
= "ipv4";
472 ada
.ada_action
= action
;
475 ada
.ada_xpath
[0] = "./ipv4-prefix";
476 ada
.ada_value
[0] = prefix_str
;
478 ada
.ada_xpath
[1] = "./ipv4-exact-match";
479 ada
.ada_value
[1] = "true";
482 ada
.ada_xpath
[0] = "./any";
483 ada
.ada_value
[0] = "";
486 /* Duplicated entry without sequence, just quit. */
487 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
492 * Create the access-list first, so we can generate sequence if
493 * none given (backward compatibility).
495 snprintf(xpath
, sizeof(xpath
),
496 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
497 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
498 if (seq_str
== NULL
) {
499 /* Use XPath to find the next sequence number. */
500 sseq
= acl_get_seq(vty
, xpath
);
501 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
502 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
504 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
505 "%s/entry[sequence='%s']", xpath
, seq_str
);
507 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
509 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
510 if (prefix_str
!= NULL
) {
511 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
513 nb_cli_enqueue_change(vty
, "./ipv4-exact-match", NB_OP_MODIFY
,
514 exact
? "true" : "false");
516 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
519 return nb_cli_apply_changes(vty
, xpath_entry
);
523 no_access_list
, no_access_list_cmd
,
524 "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
527 ACCESS_LIST_ZEBRA_STR
529 ACCESS_LIST_ACTION_STR
530 "Prefix to match. e.g. 10.0.0.0/8\n"
531 "Exact match of the prefixes\n"
535 struct acl_dup_args ada
= {};
537 /* If the user provided sequence number, then just go for it. */
539 return acl_remove(vty
, "ipv4", name
, seq
);
541 /* Otherwise, to keep compatibility, we need to figure it out. */
542 ada
.ada_type
= "ipv4";
544 ada
.ada_action
= action
;
547 ada
.ada_xpath
[0] = "./ipv4-prefix";
548 ada
.ada_value
[0] = prefix_str
;
550 ada
.ada_xpath
[1] = "./ipv4-exact-match";
551 ada
.ada_value
[1] = "true";
554 ada
.ada_xpath
[0] = "./any";
555 ada
.ada_value
[0] = "";
558 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
561 return CMD_WARNING_CONFIG_FAILED
;
563 return acl_remove(vty
, "ipv4", name
, sseq
);
567 no_access_list_all
, no_access_list_all_cmd
,
568 "no access-list WORD$name",
571 ACCESS_LIST_ZEBRA_STR
)
573 char xpath
[XPATH_MAXLEN
];
575 snprintf(xpath
, sizeof(xpath
),
576 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
577 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
579 return nb_cli_apply_changes(vty
, NULL
);
583 access_list_remark
, access_list_remark_cmd
,
584 "access-list WORD$name remark LINE...",
586 ACCESS_LIST_ZEBRA_STR
587 ACCESS_LIST_REMARK_STR
588 ACCESS_LIST_REMARK_LINE_STR
)
592 char xpath
[XPATH_MAXLEN
];
594 snprintf(xpath
, sizeof(xpath
),
595 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
596 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
598 remark
= argv_concat(argv
, argc
, 3);
599 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
600 rv
= nb_cli_apply_changes(vty
, xpath
);
601 XFREE(MTYPE_TMP
, remark
);
607 no_access_list_remark
, no_access_list_remark_cmd
,
608 "no access-list WORD$name remark",
611 ACCESS_LIST_ZEBRA_STR
612 ACCESS_LIST_REMARK_STR
)
614 char xpath
[XPATH_MAXLEN
];
617 snprintf(xpath
, sizeof(xpath
),
618 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
620 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
622 rv
= nb_cli_apply_changes(vty
, NULL
);
623 if (rv
== CMD_SUCCESS
)
624 return acl_remove_if_empty(vty
, "ipv4", name
);
630 no_access_list_remark
, no_access_list_remark_line_cmd
,
631 "no access-list WORD$name remark LINE...",
634 ACCESS_LIST_ZEBRA_STR
635 ACCESS_LIST_REMARK_STR
636 ACCESS_LIST_REMARK_LINE_STR
)
639 ipv6_access_list
, ipv6_access_list_cmd
,
640 "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
643 ACCESS_LIST_ZEBRA_STR
645 ACCESS_LIST_ACTION_STR
647 "Exact match of the prefixes\n"
651 struct acl_dup_args ada
= {};
652 char xpath
[XPATH_MAXLEN
];
653 char xpath_entry
[XPATH_MAXLEN
+ 128];
656 * Backward compatibility: don't complain about duplicated values,
657 * just silently accept.
659 if (seq_str
== NULL
) {
660 ada
.ada_type
= "ipv6";
662 ada
.ada_action
= action
;
665 ada
.ada_xpath
[0] = "./ipv6-prefix";
666 ada
.ada_value
[0] = prefix_str
;
668 ada
.ada_xpath
[1] = "./ipv6-exact-match";
669 ada
.ada_value
[1] = "true";
672 ada
.ada_xpath
[0] = "./any";
673 ada
.ada_value
[0] = "";
676 /* Duplicated entry without sequence, just quit. */
677 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
682 * Create the access-list first, so we can generate sequence if
683 * none given (backward compatibility).
685 snprintf(xpath
, sizeof(xpath
),
686 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
687 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
688 if (seq_str
== NULL
) {
689 /* Use XPath to find the next sequence number. */
690 sseq
= acl_get_seq(vty
, xpath
);
691 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
692 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
694 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
695 "%s/entry[sequence='%s']", xpath
, seq_str
);
697 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
699 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
700 if (prefix_str
!= NULL
) {
701 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
703 nb_cli_enqueue_change(vty
, "./ipv6-exact-match", NB_OP_MODIFY
,
704 exact
? "true" : "false");
706 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
709 return nb_cli_apply_changes(vty
, xpath_entry
);
713 no_ipv6_access_list
, no_ipv6_access_list_cmd
,
714 "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
718 ACCESS_LIST_ZEBRA_STR
720 ACCESS_LIST_ACTION_STR
722 "Exact match of the prefixes\n"
726 struct acl_dup_args ada
= {};
728 /* If the user provided sequence number, then just go for it. */
730 return acl_remove(vty
, "ipv6", name
, seq
);
732 /* Otherwise, to keep compatibility, we need to figure it out. */
733 ada
.ada_type
= "ipv6";
735 ada
.ada_action
= action
;
738 ada
.ada_xpath
[0] = "./ipv6-prefix";
739 ada
.ada_value
[0] = prefix_str
;
741 ada
.ada_xpath
[1] = "./ipv6-exact-match";
742 ada
.ada_value
[1] = "true";
745 ada
.ada_xpath
[0] = "./any";
746 ada
.ada_value
[0] = "";
749 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
752 return CMD_WARNING_CONFIG_FAILED
;
754 return acl_remove(vty
, "ipv6", name
, sseq
);
758 no_ipv6_access_list_all
, no_ipv6_access_list_all_cmd
,
759 "no ipv6 access-list WORD$name",
763 ACCESS_LIST_ZEBRA_STR
)
765 char xpath
[XPATH_MAXLEN
];
767 snprintf(xpath
, sizeof(xpath
),
768 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
769 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
771 return nb_cli_apply_changes(vty
, NULL
);
775 ipv6_access_list_remark
, ipv6_access_list_remark_cmd
,
776 "ipv6 access-list WORD$name remark LINE...",
779 ACCESS_LIST_ZEBRA_STR
780 ACCESS_LIST_REMARK_STR
781 ACCESS_LIST_REMARK_LINE_STR
)
785 char xpath
[XPATH_MAXLEN
];
787 snprintf(xpath
, sizeof(xpath
),
788 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
789 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
791 remark
= argv_concat(argv
, argc
, 4);
792 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
793 rv
= nb_cli_apply_changes(vty
, xpath
);
794 XFREE(MTYPE_TMP
, remark
);
800 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_cmd
,
801 "no ipv6 access-list WORD$name remark",
805 ACCESS_LIST_ZEBRA_STR
806 ACCESS_LIST_REMARK_STR
)
808 char xpath
[XPATH_MAXLEN
];
811 snprintf(xpath
, sizeof(xpath
),
812 "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
814 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
816 rv
= nb_cli_apply_changes(vty
, NULL
);
817 if (rv
== CMD_SUCCESS
)
818 return acl_remove_if_empty(vty
, "ipv6", name
);
824 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_line_cmd
,
825 "no ipv6 access-list ACCESSLIST6_NAME$name remark LINE...",
829 ACCESS_LIST_ZEBRA_STR
830 ACCESS_LIST_REMARK_STR
831 ACCESS_LIST_REMARK_LINE_STR
)
834 mac_access_list
, mac_access_list_cmd
,
835 "mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
838 ACCESS_LIST_ZEBRA_STR
840 ACCESS_LIST_ACTION_STR
842 "Match any MAC address\n")
845 struct acl_dup_args ada
= {};
846 char xpath
[XPATH_MAXLEN
];
847 char xpath_entry
[XPATH_MAXLEN
+ 128];
850 * Backward compatibility: don't complain about duplicated values,
851 * just silently accept.
853 if (seq_str
== NULL
) {
854 ada
.ada_type
= "mac";
856 ada
.ada_action
= action
;
859 ada
.ada_xpath
[0] = "./mac";
860 ada
.ada_value
[0] = mac_str
;
862 ada
.ada_xpath
[0] = "./any";
863 ada
.ada_value
[0] = "";
866 /* Duplicated entry without sequence, just quit. */
867 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
872 * Create the access-list first, so we can generate sequence if
873 * none given (backward compatibility).
875 snprintf(xpath
, sizeof(xpath
),
876 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
877 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
878 if (seq_str
== NULL
) {
879 /* Use XPath to find the next sequence number. */
880 sseq
= acl_get_seq(vty
, xpath
);
881 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
882 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
884 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
885 "%s/entry[sequence='%s']", xpath
, seq_str
);
887 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
889 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
890 if (mac_str
!= NULL
) {
891 nb_cli_enqueue_change(vty
, "./mac", NB_OP_MODIFY
, mac_str
);
893 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
896 return nb_cli_apply_changes(vty
, xpath_entry
);
900 no_mac_access_list
, no_mac_access_list_cmd
,
901 "no mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
905 ACCESS_LIST_ZEBRA_STR
907 ACCESS_LIST_ACTION_STR
909 "Match any MAC address\n")
912 struct acl_dup_args ada
= {};
914 /* If the user provided sequence number, then just go for it. */
916 return acl_remove(vty
, "mac", name
, seq
);
918 /* Otherwise, to keep compatibility, we need to figure it out. */
919 ada
.ada_type
= "mac";
921 ada
.ada_action
= action
;
924 ada
.ada_xpath
[0] = "./mac";
925 ada
.ada_value
[0] = mac_str
;
927 ada
.ada_xpath
[0] = "./any";
928 ada
.ada_value
[0] = "";
931 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
934 return CMD_WARNING_CONFIG_FAILED
;
936 return acl_remove(vty
, "mac", name
, sseq
);
940 no_mac_access_list_all
, no_mac_access_list_all_cmd
,
941 "no mac access-list ACCESSLIST_MAC_NAME$name",
945 ACCESS_LIST_ZEBRA_STR
)
947 char xpath
[XPATH_MAXLEN
];
949 snprintf(xpath
, sizeof(xpath
),
950 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
951 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
953 return nb_cli_apply_changes(vty
, NULL
);
957 mac_access_list_remark
, mac_access_list_remark_cmd
,
958 "mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
961 ACCESS_LIST_ZEBRA_STR
962 ACCESS_LIST_REMARK_STR
963 ACCESS_LIST_REMARK_LINE_STR
)
967 char xpath
[XPATH_MAXLEN
];
969 snprintf(xpath
, sizeof(xpath
),
970 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
971 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
973 remark
= argv_concat(argv
, argc
, 4);
974 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
975 rv
= nb_cli_apply_changes(vty
, xpath
);
976 XFREE(MTYPE_TMP
, remark
);
982 no_mac_access_list_remark
, no_mac_access_list_remark_cmd
,
983 "no mac access-list ACCESSLIST_MAC_NAME$name remark",
987 ACCESS_LIST_ZEBRA_STR
988 ACCESS_LIST_REMARK_STR
)
990 char xpath
[XPATH_MAXLEN
];
993 snprintf(xpath
, sizeof(xpath
),
994 "/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
996 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
998 rv
= nb_cli_apply_changes(vty
, NULL
);
999 if (rv
== CMD_SUCCESS
)
1000 return acl_remove_if_empty(vty
, "mac", name
);
1006 no_mac_access_list_remark
, no_mac_access_list_remark_line_cmd
,
1007 "no mac access-list ACCESSLIST_MAC_NAME$name remark LINE...",
1011 ACCESS_LIST_ZEBRA_STR
1012 ACCESS_LIST_REMARK_STR
1013 ACCESS_LIST_REMARK_LINE_STR
)
1015 int access_list_cmp(const struct lyd_node
*dnode1
,
1016 const struct lyd_node
*dnode2
)
1018 uint32_t seq1
= yang_dnode_get_uint32(dnode1
, "./sequence");
1019 uint32_t seq2
= yang_dnode_get_uint32(dnode2
, "./sequence");
1024 void access_list_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1027 int type
= yang_dnode_get_enum(dnode
, "../type");
1030 bool is_exact
= false;
1031 bool cisco_style
= false;
1032 bool cisco_extended
= false;
1033 struct in_addr addr
, mask
;
1034 char macstr
[PREFIX2STR_BUFFER
];
1036 is_any
= yang_dnode_exists(dnode
, "./any");
1042 if (yang_dnode_exists(dnode
, "./host")
1043 || yang_dnode_exists(dnode
, "./network/address")
1044 || yang_dnode_exists(dnode
, "./source-any")) {
1046 if (yang_dnode_exists(dnode
, "./destination-host")
1047 || yang_dnode_exists(
1048 dnode
, "./destination-network/address")
1049 || yang_dnode_exists(dnode
, "./destination-any"))
1050 cisco_extended
= true;
1052 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1053 is_exact
= yang_dnode_get_bool(dnode
,
1054 "./ipv4-exact-match");
1057 case YALT_IPV6
: /* ipv6 */
1058 vty_out(vty
, "ipv6 ");
1062 yang_dnode_get_prefix(&p
, dnode
, "./ipv6-prefix");
1063 is_exact
= yang_dnode_get_bool(dnode
, "./ipv6-exact-match");
1065 case YALT_MAC
: /* mac */
1066 vty_out(vty
, "mac ");
1070 yang_dnode_get_prefix(&p
, dnode
, "./mac");
1074 vty_out(vty
, "access-list %s seq %s %s",
1075 yang_dnode_get_string(dnode
, "../name"),
1076 yang_dnode_get_string(dnode
, "./sequence"),
1077 yang_dnode_get_string(dnode
, "./action"));
1079 /* Handle Cisco style access lists. */
1082 vty_out(vty
, " ip");
1084 if (yang_dnode_exists(dnode
, "./network")) {
1085 yang_dnode_get_ipv4(&addr
, dnode
, "./network/address");
1086 yang_dnode_get_ipv4(&mask
, dnode
, "./network/mask");
1087 vty_out(vty
, " %pI4 %pI4", &addr
, &mask
);
1088 } else if (yang_dnode_exists(dnode
, "./host")) {
1090 vty_out(vty
, " host");
1093 yang_dnode_get_string(dnode
, "./host"));
1094 } else if (yang_dnode_exists(dnode
, "./source-any"))
1095 vty_out(vty
, " any");
1097 /* Not extended, exit earlier. */
1098 if (!cisco_extended
) {
1103 /* Handle destination address. */
1104 if (yang_dnode_exists(dnode
, "./destination-network")) {
1105 yang_dnode_get_ipv4(&addr
, dnode
,
1106 "./destination-network/address");
1107 yang_dnode_get_ipv4(&mask
, dnode
,
1108 "./destination-network/mask");
1109 vty_out(vty
, " %pI4 %pI4", &addr
, &mask
);
1110 } else if (yang_dnode_exists(dnode
, "./destination-host"))
1111 vty_out(vty
, " host %s",
1112 yang_dnode_get_string(dnode
,
1113 "./destination-host"));
1114 else if (yang_dnode_exists(dnode
, "./destination-any"))
1115 vty_out(vty
, " any");
1121 /* Zebra style access list. */
1123 /* If type is MAC don't show '/mask'. */
1124 if (type
== 2 /* mac */) {
1125 prefix_mac2str(&p
.u
.prefix_eth
, macstr
, sizeof(macstr
));
1126 vty_out(vty
, " %s", macstr
);
1128 vty_out(vty
, " %pFX", &p
);
1130 vty_out(vty
, " any");
1133 vty_out(vty
, " exact-match");
1138 void access_list_remark_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1141 int type
= yang_dnode_get_enum(dnode
, "../type");
1147 vty_out(vty
, "ipv6 ");
1150 vty_out(vty
, "mac ");
1154 vty_out(vty
, "access-list %s remark %s\n",
1155 yang_dnode_get_string(dnode
, "../name"),
1156 yang_dnode_get_string(dnode
, NULL
));
1164 * Remove main data structure prefix list if there are no more entries or
1165 * remark. This fixes compatibility with old CLI and tests.
1167 static int plist_remove_if_empty(struct vty
*vty
, const char *iptype
,
1170 char xpath
[XPATH_MAXLEN
];
1172 snprintf(xpath
, sizeof(xpath
),
1173 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark",
1175 /* List is not empty if there is a remark, check that: */
1176 if (yang_dnode_exists(vty
->candidate_config
->dnode
, xpath
))
1179 /* Check if we have any entries: */
1180 snprintf(xpath
, sizeof(xpath
),
1181 "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype
,
1184 * NOTE: if the list is empty it will return the first sequence
1187 if (acl_get_seq(vty
, xpath
) != 5)
1190 /* Nobody is using this list, lets remove it. */
1191 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1192 return nb_cli_apply_changes(vty
, NULL
);
1195 static int plist_remove(struct vty
*vty
, const char *iptype
, const char *name
,
1196 const char *seq
, const char *action
,
1197 union prefixconstptr prefix
, int ge
, int le
)
1200 struct plist_dup_args pda
= {};
1201 char xpath
[XPATH_MAXLEN
];
1202 char xpath_entry
[XPATH_MAXLEN
+ 32];
1205 /* If the user provided sequence number, then just go for it. */
1208 xpath
, sizeof(xpath
),
1209 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
1211 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1213 rv
= nb_cli_apply_changes(vty
, NULL
);
1214 if (rv
== CMD_SUCCESS
)
1215 return plist_remove_if_empty(vty
, iptype
, name
);
1220 /* Otherwise, to keep compatibility, we need to figure it out. */
1221 pda
.pda_type
= iptype
;
1222 pda
.pda_name
= name
;
1223 pda
.pda_action
= action
;
1225 prefix_copy(&pda
.prefix
, prefix
);
1226 apply_mask(&pda
.prefix
);
1233 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1236 return CMD_WARNING_CONFIG_FAILED
;
1239 xpath_entry
, sizeof(xpath_entry
),
1240 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%" PRId64
"']",
1241 iptype
, name
, sseq
);
1242 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
1244 rv
= nb_cli_apply_changes(vty
, NULL
);
1245 if (rv
== CMD_SUCCESS
)
1246 return plist_remove_if_empty(vty
, iptype
, name
);
1252 ip_prefix_list
, ip_prefix_list_cmd
,
1253 "ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)$ge|le (0-32)$le}]>",
1256 PREFIX_LIST_NAME_STR
1258 ACCESS_LIST_ACTION_STR
1259 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1260 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1261 "Minimum prefix length to be matched\n"
1262 "Minimum prefix length\n"
1263 "Maximum prefix length to be matched\n"
1264 "Maximum prefix length\n")
1267 struct plist_dup_args pda
= {};
1268 char xpath
[XPATH_MAXLEN
];
1269 char xpath_entry
[XPATH_MAXLEN
+ 128];
1272 * Backward compatibility: don't complain about duplicated values,
1273 * just silently accept.
1275 if (seq_str
== NULL
) {
1276 pda
.pda_type
= "ipv4";
1277 pda
.pda_name
= name
;
1278 pda
.pda_action
= action
;
1280 prefix_copy(&pda
.prefix
, prefix
);
1287 /* Duplicated entry without sequence, just quit. */
1288 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1293 * Create the prefix-list first, so we can generate sequence if
1294 * none given (backward compatibility).
1296 snprintf(xpath
, sizeof(xpath
),
1297 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1298 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1299 if (seq_str
== NULL
) {
1300 /* Use XPath to find the next sequence number. */
1301 sseq
= acl_get_seq(vty
, xpath
);
1302 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1303 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1305 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1306 "%s/entry[sequence='%s']", xpath
, seq_str
);
1308 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1310 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1311 if (prefix_str
!= NULL
) {
1312 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
1316 nb_cli_enqueue_change(
1317 vty
, "./ipv4-prefix-length-greater-or-equal",
1318 NB_OP_MODIFY
, ge_str
);
1321 * Remove old ge if not being modified
1323 nb_cli_enqueue_change(
1324 vty
, "./ipv4-prefix-length-greater-or-equal",
1325 NB_OP_DESTROY
, NULL
);
1329 nb_cli_enqueue_change(
1330 vty
, "./ipv4-prefix-length-lesser-or-equal",
1331 NB_OP_MODIFY
, le_str
);
1334 * Remove old le if not being modified
1336 nb_cli_enqueue_change(
1337 vty
, "./ipv4-prefix-length-lesser-or-equal",
1338 NB_OP_DESTROY
, NULL
);
1341 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1344 return nb_cli_apply_changes(vty
, xpath_entry
);
1348 no_ip_prefix_list
, no_ip_prefix_list_cmd
,
1349 "no ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)|le (0-32)}]>",
1353 PREFIX_LIST_NAME_STR
1355 ACCESS_LIST_ACTION_STR
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")
1363 return plist_remove(vty
, "ipv4", name
, seq_str
, action
,
1364 prefix_str
? prefix
: NULL
, ge
, le
);
1368 no_ip_prefix_list_seq
, no_ip_prefix_list_seq_cmd
,
1369 "no ip prefix-list WORD$name seq (1-4294967295)$seq",
1373 PREFIX_LIST_NAME_STR
1374 ACCESS_LIST_SEQ_STR
)
1376 return plist_remove(vty
, "ipv4", name
, seq_str
, NULL
, NULL
, 0, 0);
1380 no_ip_prefix_list_all
, no_ip_prefix_list_all_cmd
,
1381 "no ip prefix-list WORD$name",
1385 PREFIX_LIST_NAME_STR
)
1387 char xpath
[XPATH_MAXLEN
];
1389 snprintf(xpath
, sizeof(xpath
),
1390 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1391 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1393 return nb_cli_apply_changes(vty
, NULL
);
1397 ip_prefix_list_remark
, ip_prefix_list_remark_cmd
,
1398 "ip prefix-list WORD$name description LINE...",
1401 PREFIX_LIST_NAME_STR
1402 ACCESS_LIST_REMARK_STR
1403 ACCESS_LIST_REMARK_LINE_STR
)
1407 char xpath
[XPATH_MAXLEN
];
1409 snprintf(xpath
, sizeof(xpath
),
1410 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1411 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1413 remark
= argv_concat(argv
, argc
, 4);
1414 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1415 rv
= nb_cli_apply_changes(vty
, xpath
);
1416 XFREE(MTYPE_TMP
, remark
);
1422 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_cmd
,
1423 "no ip prefix-list WORD$name description",
1427 PREFIX_LIST_NAME_STR
1428 ACCESS_LIST_REMARK_STR
)
1430 char xpath
[XPATH_MAXLEN
];
1433 snprintf(xpath
, sizeof(xpath
),
1434 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
1436 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1438 rv
= nb_cli_apply_changes(vty
, NULL
);
1439 if (rv
== CMD_SUCCESS
)
1440 return plist_remove_if_empty(vty
, "ipv4", name
);
1446 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_line_cmd
,
1447 "no ip prefix-list WORD$name description LINE...",
1451 PREFIX_LIST_NAME_STR
1452 ACCESS_LIST_REMARK_STR
1453 ACCESS_LIST_REMARK_LINE_STR
)
1456 ipv6_prefix_list
, ipv6_prefix_list_cmd
,
1457 "ipv6 prefix-list WORD$name [seq (1-4294967295)] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
1460 PREFIX_LIST_NAME_STR
1462 ACCESS_LIST_ACTION_STR
1463 "Any prefix match. Same as \"::0/0 le 128\"\n"
1464 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1465 "Maximum prefix length to be matched\n"
1466 "Maximum prefix length\n"
1467 "Minimum prefix length to be matched\n"
1468 "Minimum prefix length\n")
1471 struct plist_dup_args pda
= {};
1472 char xpath
[XPATH_MAXLEN
];
1473 char xpath_entry
[XPATH_MAXLEN
+ 128];
1476 * Backward compatibility: don't complain about duplicated values,
1477 * just silently accept.
1479 if (seq_str
== NULL
) {
1480 pda
.pda_type
= "ipv6";
1481 pda
.pda_name
= name
;
1482 pda
.pda_action
= action
;
1484 prefix_copy(&pda
.prefix
, prefix
);
1491 /* Duplicated entry without sequence, just quit. */
1492 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1497 * Create the prefix-list first, so we can generate sequence if
1498 * none given (backward compatibility).
1500 snprintf(xpath
, sizeof(xpath
),
1501 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1502 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1503 if (seq_str
== NULL
) {
1504 /* Use XPath to find the next sequence number. */
1505 sseq
= acl_get_seq(vty
, xpath
);
1506 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1507 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1509 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1510 "%s/entry[sequence='%s']", xpath
, seq_str
);
1512 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1514 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1515 if (prefix_str
!= NULL
) {
1516 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
1520 nb_cli_enqueue_change(
1521 vty
, "./ipv6-prefix-length-greater-or-equal",
1522 NB_OP_MODIFY
, ge_str
);
1525 * Remove old ge if not being modified
1527 nb_cli_enqueue_change(
1528 vty
, "./ipv6-prefix-length-greater-or-equal",
1529 NB_OP_DESTROY
, NULL
);
1533 nb_cli_enqueue_change(
1534 vty
, "./ipv6-prefix-length-lesser-or-equal",
1535 NB_OP_MODIFY
, le_str
);
1538 * Remove old le if not being modified
1540 nb_cli_enqueue_change(
1541 vty
, "./ipv6-prefix-length-lesser-or-equal",
1542 NB_OP_DESTROY
, NULL
);
1545 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1548 return nb_cli_apply_changes(vty
, xpath_entry
);
1552 no_ipv6_prefix_list
, no_ipv6_prefix_list_cmd
,
1553 "no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
1557 PREFIX_LIST_NAME_STR
1559 ACCESS_LIST_ACTION_STR
1560 "Any prefix match. Same as \"::0/0 le 128\"\n"
1561 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1562 "Maximum prefix length to be matched\n"
1563 "Maximum prefix length\n"
1564 "Minimum prefix length to be matched\n"
1565 "Minimum prefix length\n")
1567 return plist_remove(vty
, "ipv6", name
, seq_str
, action
,
1568 prefix_str
? prefix
: NULL
, ge
, le
);
1572 no_ipv6_prefix_list_seq
, no_ipv6_prefix_list_seq_cmd
,
1573 "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
1577 PREFIX_LIST_NAME_STR
1578 ACCESS_LIST_SEQ_STR
)
1580 return plist_remove(vty
, "ipv6", name
, seq_str
, NULL
, NULL
, 0, 0);
1584 no_ipv6_prefix_list_all
, no_ipv6_prefix_list_all_cmd
,
1585 "no ipv6 prefix-list WORD$name",
1589 PREFIX_LIST_NAME_STR
)
1591 char xpath
[XPATH_MAXLEN
];
1593 snprintf(xpath
, sizeof(xpath
),
1594 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1595 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1597 return nb_cli_apply_changes(vty
, NULL
);
1601 ipv6_prefix_list_remark
, ipv6_prefix_list_remark_cmd
,
1602 "ipv6 prefix-list WORD$name description LINE...",
1605 PREFIX_LIST_NAME_STR
1606 ACCESS_LIST_REMARK_STR
1607 ACCESS_LIST_REMARK_LINE_STR
)
1611 char xpath
[XPATH_MAXLEN
];
1613 snprintf(xpath
, sizeof(xpath
),
1614 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1615 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1617 remark
= argv_concat(argv
, argc
, 4);
1618 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1619 rv
= nb_cli_apply_changes(vty
, xpath
);
1620 XFREE(MTYPE_TMP
, remark
);
1626 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_cmd
,
1627 "no ipv6 prefix-list WORD$name description",
1631 PREFIX_LIST_NAME_STR
1632 ACCESS_LIST_REMARK_STR
)
1634 char xpath
[XPATH_MAXLEN
];
1637 snprintf(xpath
, sizeof(xpath
),
1638 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
1640 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1642 rv
= nb_cli_apply_changes(vty
, NULL
);
1643 if (rv
== CMD_SUCCESS
)
1644 return plist_remove_if_empty(vty
, "ipv6", name
);
1650 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_line_cmd
,
1651 "no ipv6 prefix-list WORD$name description LINE...",
1655 PREFIX_LIST_NAME_STR
1656 ACCESS_LIST_REMARK_STR
1657 ACCESS_LIST_REMARK_LINE_STR
)
1659 int prefix_list_cmp(const struct lyd_node
*dnode1
,
1660 const struct lyd_node
*dnode2
)
1662 uint32_t seq1
= yang_dnode_get_uint32(dnode1
, "./sequence");
1663 uint32_t seq2
= yang_dnode_get_uint32(dnode2
, "./sequence");
1668 void prefix_list_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1671 int type
= yang_dnode_get_enum(dnode
, "../type");
1672 const char *ge_str
= NULL
, *le_str
= NULL
;
1676 is_any
= yang_dnode_exists(dnode
, "./any");
1680 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1681 if (yang_dnode_exists(dnode
,
1682 "./ipv4-prefix-length-greater-or-equal"))
1683 ge_str
= yang_dnode_get_string(
1684 dnode
, "./ipv4-prefix-length-greater-or-equal");
1685 if (yang_dnode_exists(dnode
,
1686 "./ipv4-prefix-length-lesser-or-equal"))
1687 le_str
= yang_dnode_get_string(
1688 dnode
, "./ipv4-prefix-length-lesser-or-equal");
1690 vty_out(vty
, "ip ");
1694 yang_dnode_get_prefix(&p
, dnode
, "ipv6-prefix");
1695 if (yang_dnode_exists(dnode
,
1696 "./ipv6-prefix-length-greater-or-equal"))
1697 ge_str
= yang_dnode_get_string(
1698 dnode
, "./ipv6-prefix-length-greater-or-equal");
1699 if (yang_dnode_exists(dnode
,
1700 "./ipv6-prefix-length-lesser-or-equal"))
1701 le_str
= yang_dnode_get_string(
1702 dnode
, "./ipv6-prefix-length-lesser-or-equal");
1704 vty_out(vty
, "ipv6 ");
1708 vty_out(vty
, "prefix-list %s seq %s %s",
1709 yang_dnode_get_string(dnode
, "../name"),
1710 yang_dnode_get_string(dnode
, "./sequence"),
1711 yang_dnode_get_string(dnode
, "./action"));
1714 vty_out(vty
, " any\n");
1718 vty_out(vty
, " %pFX", &p
);
1720 vty_out(vty
, " ge %s", ge_str
);
1722 vty_out(vty
, " le %s", le_str
);
1727 void prefix_list_remark_show(struct vty
*vty
, const struct lyd_node
*dnode
,
1730 int type
= yang_dnode_get_enum(dnode
, "../type");
1734 vty_out(vty
, "ip ");
1737 vty_out(vty
, "ipv6 ");
1741 vty_out(vty
, "prefix-list %s description %s\n",
1742 yang_dnode_get_string(dnode
, "../name"),
1743 yang_dnode_get_string(dnode
, NULL
));
1746 void filter_cli_init(void)
1748 /* access-list cisco-style (legacy). */
1749 install_element(CONFIG_NODE
, &access_list_std_cmd
);
1750 install_element(CONFIG_NODE
, &no_access_list_std_cmd
);
1751 install_element(CONFIG_NODE
, &access_list_ext_cmd
);
1752 install_element(CONFIG_NODE
, &no_access_list_ext_cmd
);
1754 /* access-list zebra-style. */
1755 install_element(CONFIG_NODE
, &access_list_cmd
);
1756 install_element(CONFIG_NODE
, &no_access_list_cmd
);
1757 install_element(CONFIG_NODE
, &no_access_list_all_cmd
);
1758 install_element(CONFIG_NODE
, &access_list_remark_cmd
);
1759 install_element(CONFIG_NODE
, &no_access_list_remark_cmd
);
1760 install_element(CONFIG_NODE
, &no_access_list_remark_line_cmd
);
1762 install_element(CONFIG_NODE
, &ipv6_access_list_cmd
);
1763 install_element(CONFIG_NODE
, &no_ipv6_access_list_cmd
);
1764 install_element(CONFIG_NODE
, &no_ipv6_access_list_all_cmd
);
1765 install_element(CONFIG_NODE
, &ipv6_access_list_remark_cmd
);
1766 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_cmd
);
1767 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_line_cmd
);
1769 install_element(CONFIG_NODE
, &mac_access_list_cmd
);
1770 install_element(CONFIG_NODE
, &no_mac_access_list_cmd
);
1771 install_element(CONFIG_NODE
, &no_mac_access_list_all_cmd
);
1772 install_element(CONFIG_NODE
, &mac_access_list_remark_cmd
);
1773 install_element(CONFIG_NODE
, &no_mac_access_list_remark_cmd
);
1774 install_element(CONFIG_NODE
, &no_mac_access_list_remark_line_cmd
);
1777 install_element(CONFIG_NODE
, &ip_prefix_list_cmd
);
1778 install_element(CONFIG_NODE
, &no_ip_prefix_list_cmd
);
1779 install_element(CONFIG_NODE
, &no_ip_prefix_list_seq_cmd
);
1780 install_element(CONFIG_NODE
, &no_ip_prefix_list_all_cmd
);
1781 install_element(CONFIG_NODE
, &ip_prefix_list_remark_cmd
);
1782 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_cmd
);
1783 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_line_cmd
);
1785 install_element(CONFIG_NODE
, &ipv6_prefix_list_cmd
);
1786 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_cmd
);
1787 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_seq_cmd
);
1788 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_all_cmd
);
1789 install_element(CONFIG_NODE
, &ipv6_prefix_list_remark_cmd
);
1790 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_cmd
);
1791 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_line_cmd
);