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_LEG_STR "IP standard access list\n"
40 #define ACCESS_LIST_ELEG_STR "IP extended access list\n"
41 #define ACCESS_LIST_ELEG_EXT_STR "IP extended access list (expanded range)\n"
42 #define ACCESS_LIST_ZEBRA_STR "Access list entry\n"
43 #define ACCESS_LIST_SEQ_STR \
44 "Sequence number of an entry\n" \
46 #define ACCESS_LIST_ACTION_STR \
47 "Specify packets to reject\n" \
48 "Specify packets to forward\n"
49 #define ACCESS_LIST_REMARK_STR "Access list entry comment\n"
50 #define ACCESS_LIST_REMARK_LINE_STR "Comment up to 100 characters\n"
52 #define PREFIX_LIST_NAME_STR "Prefix list entry name\n"
55 * Helper function to generate a sequence number for legacy commands.
57 static int acl_get_seq_cb(const struct lyd_node
*dnode
, void *arg
)
60 int64_t cur_seq
= yang_dnode_get_uint32(dnode
, "sequence");
65 return YANG_ITER_CONTINUE
;
69 * Helper function that iterates over the XPath `xpath` on the candidate
70 * configuration in `vty->candidate_config`.
72 * \param[in] vty shell context with the candidate configuration.
73 * \param[in] xpath the XPath to look for the sequence leaf.
74 * \returns next unused sequence number.
76 static long acl_get_seq(struct vty
*vty
, const char *xpath
)
80 yang_dnode_iterate(acl_get_seq_cb
, &seq
, vty
->candidate_config
->dnode
,
86 static int acl_remove_if_empty(struct vty
*vty
, const char *iptype
,
89 char xpath
[XPATH_MAXLEN
];
91 snprintf(xpath
, sizeof(xpath
),
92 "/frr-filter:lib/access-list[type='%s'][name='%s']/remark",
94 /* List is not empty if there is a remark, check that: */
95 if (yang_dnode_exists(vty
->candidate_config
->dnode
, xpath
))
98 /* Check if we have any entries: */
99 snprintf(xpath
, sizeof(xpath
),
100 "/frr-filter:lib/access-list[type='%s'][name='%s']", iptype
,
103 * NOTE: if the list is empty it will return the first sequence
106 if (acl_get_seq(vty
, xpath
) != 5)
109 /* Nobody is using this list, lets remove it. */
110 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
111 return nb_cli_apply_changes(vty
, NULL
);
114 static int acl_remove(struct vty
*vty
, const char *iptype
, const char *name
,
117 char xpath
[XPATH_MAXLEN
];
121 xpath
, sizeof(xpath
),
122 "/frr-filter:lib/access-list[type='%s'][name='%s']/entry[sequence='%" PRId64
"']",
124 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
126 rv
= nb_cli_apply_changes(vty
, NULL
);
127 if (rv
== CMD_SUCCESS
)
128 return acl_remove_if_empty(vty
, iptype
, name
);
134 * Cisco (legacy) access lists.
137 access_list_std
, access_list_std_cmd
,
138 "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>",
142 ACCESS_LIST_ACTION_STR
143 "A single host address\n"
149 struct acl_dup_args ada
= {};
150 char xpath
[XPATH_MAXLEN
];
151 char xpath_entry
[XPATH_MAXLEN
+ 128];
154 * Backward compatibility: don't complain about duplicated values,
155 * just silently accept.
157 if (seq_str
== NULL
) {
158 ada
.ada_type
= "ipv4";
160 ada
.ada_action
= action
;
161 if (host_str
&& mask_str
== NULL
) {
162 ada
.ada_xpath
[0] = "./host";
163 ada
.ada_value
[0] = host_str
;
164 } else if (host_str
&& mask_str
) {
165 ada
.ada_xpath
[0] = "./network/address";
166 ada
.ada_value
[0] = host_str
;
167 ada
.ada_xpath
[1] = "./network/mask";
168 ada
.ada_value
[1] = mask_str
;
170 ada
.ada_xpath
[0] = "./source-any";
171 ada
.ada_value
[0] = "";
174 /* Duplicated entry without sequence, just quit. */
175 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
180 * Create the access-list first, so we can generate sequence if
181 * none given (backward compatibility).
183 snprintf(xpath
, sizeof(xpath
),
184 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
185 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
186 if (seq_str
== NULL
) {
187 /* Use XPath to find the next sequence number. */
188 sseq
= acl_get_seq(vty
, xpath
);
189 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
190 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
192 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
193 "%s/entry[sequence='%s']", xpath
, seq_str
);
195 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
197 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
198 if (host_str
!= NULL
&& mask_str
== NULL
) {
199 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, host_str
);
200 } else if (host_str
!= NULL
&& mask_str
!= NULL
) {
201 nb_cli_enqueue_change(vty
, "./network/address", NB_OP_MODIFY
,
203 nb_cli_enqueue_change(vty
, "./network/mask", NB_OP_MODIFY
,
206 nb_cli_enqueue_change(vty
, "./source-any", NB_OP_CREATE
, NULL
);
209 return nb_cli_apply_changes(vty
, xpath_entry
);
213 no_access_list_std
, no_access_list_std_cmd
,
214 "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>",
219 ACCESS_LIST_ACTION_STR
220 "A single host address\n"
226 struct acl_dup_args ada
= {};
228 /* If the user provided sequence number, then just go for it. */
230 return acl_remove(vty
, "ipv4", name
, seq
);
232 /* Otherwise, to keep compatibility, we need to figure it out. */
233 ada
.ada_type
= "ipv4";
235 ada
.ada_action
= action
;
236 if (host_str
&& mask_str
== NULL
) {
237 ada
.ada_xpath
[0] = "./host";
238 ada
.ada_value
[0] = host_str
;
239 } else if (host_str
&& mask_str
) {
240 ada
.ada_xpath
[0] = "./network/address";
241 ada
.ada_value
[0] = host_str
;
242 ada
.ada_xpath
[1] = "./network/mask";
243 ada
.ada_value
[1] = mask_str
;
245 ada
.ada_xpath
[0] = "./source-any";
246 ada
.ada_value
[0] = "";
249 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
252 return CMD_WARNING_CONFIG_FAILED
;
254 return acl_remove(vty
, "ipv4", name
, sseq
);
258 access_list_ext
, access_list_ext_cmd
,
259 "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>",
263 ACCESS_LIST_ACTION_STR
265 "Source address to match\n"
266 "Source address mask to apply\n"
267 "Single source host\n"
268 "Source address to match\n"
270 "Destination address to match\n"
271 "Destination address mask to apply\n"
272 "Single destination host\n"
273 "Destination address to match\n"
274 "Any destination host\n")
278 struct acl_dup_args ada
= {};
279 char xpath
[XPATH_MAXLEN
];
280 char xpath_entry
[XPATH_MAXLEN
+ 128];
283 * Backward compatibility: don't complain about duplicated values,
284 * just silently accept.
286 if (seq_str
== NULL
) {
287 ada
.ada_type
= "ipv4";
289 ada
.ada_action
= action
;
290 if (src_str
&& src_mask_str
== NULL
) {
291 ada
.ada_xpath
[idx
] = "./host";
292 ada
.ada_value
[idx
] = src_str
;
294 } else if (src_str
&& src_mask_str
) {
295 ada
.ada_xpath
[idx
] = "./network/address";
296 ada
.ada_value
[idx
] = src_str
;
298 ada
.ada_xpath
[idx
] = "./network/mask";
299 ada
.ada_value
[idx
] = src_mask_str
;
302 ada
.ada_xpath
[idx
] = "./source-any";
303 ada
.ada_value
[idx
] = "";
307 if (dst_str
&& dst_mask_str
== NULL
) {
308 ada
.ada_xpath
[idx
] = "./destination-host";
309 ada
.ada_value
[idx
] = dst_str
;
311 } else if (dst_str
&& dst_mask_str
) {
312 ada
.ada_xpath
[idx
] = "./destination-network/address";
313 ada
.ada_value
[idx
] = dst_str
;
315 ada
.ada_xpath
[idx
] = "./destination-network/mask";
316 ada
.ada_value
[idx
] = dst_mask_str
;
319 ada
.ada_xpath
[idx
] = "./destination-any";
320 ada
.ada_value
[idx
] = "";
324 /* Duplicated entry without sequence, just quit. */
325 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
330 * Create the access-list first, so we can generate sequence if
331 * none given (backward compatibility).
333 snprintf(xpath
, sizeof(xpath
),
334 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
335 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
336 if (seq_str
== NULL
) {
337 /* Use XPath to find the next sequence number. */
338 sseq
= acl_get_seq(vty
, xpath
);
339 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
340 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
342 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
343 "%s/entry[sequence='%s']", xpath
, seq_str
);
345 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
347 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
348 if (src_str
!= NULL
&& src_mask_str
== NULL
) {
349 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, src_str
);
350 } else if (src_str
!= NULL
&& src_mask_str
!= NULL
) {
351 nb_cli_enqueue_change(vty
, "./network/address", NB_OP_MODIFY
,
353 nb_cli_enqueue_change(vty
, "./network/mask", NB_OP_MODIFY
,
356 nb_cli_enqueue_change(vty
, "./source-any", NB_OP_CREATE
, NULL
);
359 if (dst_str
!= NULL
&& dst_mask_str
== NULL
) {
360 nb_cli_enqueue_change(vty
, "./destination-host", NB_OP_MODIFY
,
362 } else if (dst_str
!= NULL
&& dst_mask_str
!= NULL
) {
363 nb_cli_enqueue_change(vty
, "./destination-network/address",
364 NB_OP_MODIFY
, dst_str
);
365 nb_cli_enqueue_change(vty
, "./destination-network/mask",
366 NB_OP_MODIFY
, dst_mask_str
);
368 nb_cli_enqueue_change(vty
, "./destination-any", NB_OP_CREATE
,
372 return nb_cli_apply_changes(vty
, xpath_entry
);
376 no_access_list_ext
, no_access_list_ext_cmd
,
377 "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>",
382 ACCESS_LIST_ACTION_STR
383 "Any Internet Protocol\n"
384 "Source address to match\n"
385 "Source address mask to apply\n"
386 "Single source host\n"
387 "Source address to match\n"
389 "Destination address to match\n"
390 "Destination address mask to apply\n"
391 "Single destination host\n"
392 "Destination address to match\n"
393 "Any destination host\n")
397 struct acl_dup_args ada
= {};
399 /* If the user provided sequence number, then just go for it. */
401 return acl_remove(vty
, "ipv4", name
, seq
);
403 /* Otherwise, to keep compatibility, we need to figure it out. */
404 ada
.ada_type
= "ipv4";
406 ada
.ada_action
= action
;
407 if (src_str
&& src_mask_str
== NULL
) {
408 ada
.ada_xpath
[idx
] = "./host";
409 ada
.ada_value
[idx
] = src_str
;
411 } else if (src_str
&& src_mask_str
) {
412 ada
.ada_xpath
[idx
] = "./network/address";
413 ada
.ada_value
[idx
] = src_str
;
415 ada
.ada_xpath
[idx
] = "./network/mask";
416 ada
.ada_value
[idx
] = src_mask_str
;
419 ada
.ada_xpath
[idx
] = "./source-any";
420 ada
.ada_value
[idx
] = "";
424 if (dst_str
&& dst_mask_str
== NULL
) {
425 ada
.ada_xpath
[idx
] = "./destination-host";
426 ada
.ada_value
[idx
] = dst_str
;
428 } else if (dst_str
&& dst_mask_str
) {
429 ada
.ada_xpath
[idx
] = "./destination-network/address";
430 ada
.ada_value
[idx
] = dst_str
;
432 ada
.ada_xpath
[idx
] = "./destination-network/mask";
433 ada
.ada_value
[idx
] = dst_mask_str
;
436 ada
.ada_xpath
[idx
] = "./destination-any";
437 ada
.ada_value
[idx
] = "";
441 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
444 return CMD_WARNING_CONFIG_FAILED
;
446 return acl_remove(vty
, "ipv4", name
, sseq
);
450 * Zebra access lists.
453 access_list
, access_list_cmd
,
454 "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
456 ACCESS_LIST_ZEBRA_STR
458 ACCESS_LIST_ACTION_STR
459 "Prefix to match. e.g. 10.0.0.0/8\n"
460 "Exact match of the prefixes\n"
464 struct acl_dup_args ada
= {};
465 char xpath
[XPATH_MAXLEN
];
466 char xpath_entry
[XPATH_MAXLEN
+ 128];
469 * Backward compatibility: don't complain about duplicated values,
470 * just silently accept.
472 if (seq_str
== NULL
) {
473 ada
.ada_type
= "ipv4";
475 ada
.ada_action
= action
;
478 ada
.ada_xpath
[0] = "./ipv4-prefix";
479 ada
.ada_value
[0] = prefix_str
;
481 ada
.ada_xpath
[1] = "./ipv4-exact-match";
482 ada
.ada_value
[1] = "true";
485 ada
.ada_xpath
[0] = "./any";
486 ada
.ada_value
[0] = "";
489 /* Duplicated entry without sequence, just quit. */
490 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
495 * Create the access-list first, so we can generate sequence if
496 * none given (backward compatibility).
498 snprintf(xpath
, sizeof(xpath
),
499 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
500 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
501 if (seq_str
== NULL
) {
502 /* Use XPath to find the next sequence number. */
503 sseq
= acl_get_seq(vty
, xpath
);
504 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
505 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
507 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
508 "%s/entry[sequence='%s']", xpath
, seq_str
);
510 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
512 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
513 if (prefix_str
!= NULL
) {
514 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
516 nb_cli_enqueue_change(vty
, "./ipv4-exact-match", NB_OP_MODIFY
,
517 exact
? "true" : "false");
519 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
522 return nb_cli_apply_changes(vty
, xpath_entry
);
526 no_access_list
, no_access_list_cmd
,
527 "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
530 ACCESS_LIST_ZEBRA_STR
532 ACCESS_LIST_ACTION_STR
533 "Prefix to match. e.g. 10.0.0.0/8\n"
534 "Exact match of the prefixes\n"
538 struct acl_dup_args ada
= {};
540 /* If the user provided sequence number, then just go for it. */
542 return acl_remove(vty
, "ipv4", name
, seq
);
544 /* Otherwise, to keep compatibility, we need to figure it out. */
545 ada
.ada_type
= "ipv4";
547 ada
.ada_action
= action
;
550 ada
.ada_xpath
[0] = "./ipv4-prefix";
551 ada
.ada_value
[0] = prefix_str
;
553 ada
.ada_xpath
[1] = "./ipv4-exact-match";
554 ada
.ada_value
[1] = "true";
557 ada
.ada_xpath
[0] = "./any";
558 ada
.ada_value
[0] = "";
561 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
564 return CMD_WARNING_CONFIG_FAILED
;
566 return acl_remove(vty
, "ipv4", name
, sseq
);
570 no_access_list_all
, no_access_list_all_cmd
,
571 "no access-list WORD$name",
574 ACCESS_LIST_ZEBRA_STR
)
576 char xpath
[XPATH_MAXLEN
];
578 snprintf(xpath
, sizeof(xpath
),
579 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
580 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
582 return nb_cli_apply_changes(vty
, NULL
);
586 access_list_remark
, access_list_remark_cmd
,
587 "access-list WORD$name remark LINE...",
589 ACCESS_LIST_ZEBRA_STR
590 ACCESS_LIST_REMARK_STR
591 ACCESS_LIST_REMARK_LINE_STR
)
595 char xpath
[XPATH_MAXLEN
];
597 snprintf(xpath
, sizeof(xpath
),
598 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
599 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
601 remark
= argv_concat(argv
, argc
, 3);
602 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
603 rv
= nb_cli_apply_changes(vty
, xpath
);
604 XFREE(MTYPE_TMP
, remark
);
610 no_access_list_remark
, no_access_list_remark_cmd
,
611 "no access-list WORD$name remark",
614 ACCESS_LIST_ZEBRA_STR
615 ACCESS_LIST_REMARK_STR
)
617 char xpath
[XPATH_MAXLEN
];
620 snprintf(xpath
, sizeof(xpath
),
621 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
623 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
625 rv
= nb_cli_apply_changes(vty
, NULL
);
626 if (rv
== CMD_SUCCESS
)
627 return acl_remove_if_empty(vty
, "ipv4", name
);
633 no_access_list_remark
, no_access_list_remark_line_cmd
,
634 "no access-list WORD$name remark LINE...",
637 ACCESS_LIST_ZEBRA_STR
638 ACCESS_LIST_REMARK_STR
639 ACCESS_LIST_REMARK_LINE_STR
)
642 ipv6_access_list
, ipv6_access_list_cmd
,
643 "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
646 ACCESS_LIST_ZEBRA_STR
648 ACCESS_LIST_ACTION_STR
650 "Exact match of the prefixes\n"
654 struct acl_dup_args ada
= {};
655 char xpath
[XPATH_MAXLEN
];
656 char xpath_entry
[XPATH_MAXLEN
+ 128];
659 * Backward compatibility: don't complain about duplicated values,
660 * just silently accept.
662 if (seq_str
== NULL
) {
663 ada
.ada_type
= "ipv6";
665 ada
.ada_action
= action
;
668 ada
.ada_xpath
[0] = "./ipv6-prefix";
669 ada
.ada_value
[0] = prefix_str
;
671 ada
.ada_xpath
[1] = "./ipv6-exact-match";
672 ada
.ada_value
[1] = "true";
675 ada
.ada_xpath
[0] = "./any";
676 ada
.ada_value
[0] = "";
679 /* Duplicated entry without sequence, just quit. */
680 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
685 * Create the access-list first, so we can generate sequence if
686 * none given (backward compatibility).
688 snprintf(xpath
, sizeof(xpath
),
689 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
690 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
691 if (seq_str
== NULL
) {
692 /* Use XPath to find the next sequence number. */
693 sseq
= acl_get_seq(vty
, xpath
);
694 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
695 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
697 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
698 "%s/entry[sequence='%s']", xpath
, seq_str
);
700 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
702 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
703 if (prefix_str
!= NULL
) {
704 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
706 nb_cli_enqueue_change(vty
, "./ipv6-exact-match", NB_OP_MODIFY
,
707 exact
? "true" : "false");
709 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
712 return nb_cli_apply_changes(vty
, xpath_entry
);
716 no_ipv6_access_list
, no_ipv6_access_list_cmd
,
717 "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
721 ACCESS_LIST_ZEBRA_STR
723 ACCESS_LIST_ACTION_STR
725 "Exact match of the prefixes\n"
729 struct acl_dup_args ada
= {};
731 /* If the user provided sequence number, then just go for it. */
733 return acl_remove(vty
, "ipv6", name
, seq
);
735 /* Otherwise, to keep compatibility, we need to figure it out. */
736 ada
.ada_type
= "ipv6";
738 ada
.ada_action
= action
;
741 ada
.ada_xpath
[0] = "./ipv6-prefix";
742 ada
.ada_value
[0] = prefix_str
;
744 ada
.ada_xpath
[1] = "./ipv6-exact-match";
745 ada
.ada_value
[1] = "true";
748 ada
.ada_xpath
[0] = "./any";
749 ada
.ada_value
[0] = "";
752 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
755 return CMD_WARNING_CONFIG_FAILED
;
757 return acl_remove(vty
, "ipv6", name
, sseq
);
761 no_ipv6_access_list_all
, no_ipv6_access_list_all_cmd
,
762 "no ipv6 access-list WORD$name",
766 ACCESS_LIST_ZEBRA_STR
)
768 char xpath
[XPATH_MAXLEN
];
770 snprintf(xpath
, sizeof(xpath
),
771 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
772 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
774 return nb_cli_apply_changes(vty
, NULL
);
778 ipv6_access_list_remark
, ipv6_access_list_remark_cmd
,
779 "ipv6 access-list WORD$name remark LINE...",
782 ACCESS_LIST_ZEBRA_STR
783 ACCESS_LIST_REMARK_STR
784 ACCESS_LIST_REMARK_LINE_STR
)
788 char xpath
[XPATH_MAXLEN
];
790 snprintf(xpath
, sizeof(xpath
),
791 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
792 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
794 remark
= argv_concat(argv
, argc
, 4);
795 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
796 rv
= nb_cli_apply_changes(vty
, xpath
);
797 XFREE(MTYPE_TMP
, remark
);
803 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_cmd
,
804 "no ipv6 access-list WORD$name remark",
808 ACCESS_LIST_ZEBRA_STR
809 ACCESS_LIST_REMARK_STR
)
811 char xpath
[XPATH_MAXLEN
];
814 snprintf(xpath
, sizeof(xpath
),
815 "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
817 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
819 rv
= nb_cli_apply_changes(vty
, NULL
);
820 if (rv
== CMD_SUCCESS
)
821 return acl_remove_if_empty(vty
, "ipv6", name
);
827 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_line_cmd
,
828 "no ipv6 access-list WORD$name remark LINE...",
832 ACCESS_LIST_ZEBRA_STR
833 ACCESS_LIST_REMARK_STR
834 ACCESS_LIST_REMARK_LINE_STR
)
837 mac_access_list
, mac_access_list_cmd
,
838 "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
841 ACCESS_LIST_ZEBRA_STR
843 ACCESS_LIST_ACTION_STR
845 "Match any MAC address\n")
848 struct acl_dup_args ada
= {};
849 char xpath
[XPATH_MAXLEN
];
850 char xpath_entry
[XPATH_MAXLEN
+ 128];
853 * Backward compatibility: don't complain about duplicated values,
854 * just silently accept.
856 if (seq_str
== NULL
) {
857 ada
.ada_type
= "mac";
859 ada
.ada_action
= action
;
862 ada
.ada_xpath
[0] = "./mac";
863 ada
.ada_value
[0] = mac_str
;
865 ada
.ada_xpath
[0] = "./any";
866 ada
.ada_value
[0] = "";
869 /* Duplicated entry without sequence, just quit. */
870 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
875 * Create the access-list first, so we can generate sequence if
876 * none given (backward compatibility).
878 snprintf(xpath
, sizeof(xpath
),
879 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
880 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
881 if (seq_str
== NULL
) {
882 /* Use XPath to find the next sequence number. */
883 sseq
= acl_get_seq(vty
, xpath
);
884 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
885 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
887 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
888 "%s/entry[sequence='%s']", xpath
, seq_str
);
890 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
892 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
893 if (mac_str
!= NULL
) {
894 nb_cli_enqueue_change(vty
, "./mac", NB_OP_MODIFY
, mac_str
);
896 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
899 return nb_cli_apply_changes(vty
, xpath_entry
);
903 no_mac_access_list
, no_mac_access_list_cmd
,
904 "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
908 ACCESS_LIST_ZEBRA_STR
910 ACCESS_LIST_ACTION_STR
912 "Match any MAC address\n")
915 struct acl_dup_args ada
= {};
917 /* If the user provided sequence number, then just go for it. */
919 return acl_remove(vty
, "mac", name
, seq
);
921 /* Otherwise, to keep compatibility, we need to figure it out. */
922 ada
.ada_type
= "mac";
924 ada
.ada_action
= action
;
927 ada
.ada_xpath
[0] = "./mac";
928 ada
.ada_value
[0] = mac_str
;
930 ada
.ada_xpath
[0] = "./any";
931 ada
.ada_value
[0] = "";
934 if (acl_is_dup(vty
->candidate_config
->dnode
, &ada
))
937 return CMD_WARNING_CONFIG_FAILED
;
939 return acl_remove(vty
, "mac", name
, sseq
);
943 no_mac_access_list_all
, no_mac_access_list_all_cmd
,
944 "no mac access-list WORD$name",
948 ACCESS_LIST_ZEBRA_STR
)
950 char xpath
[XPATH_MAXLEN
];
952 snprintf(xpath
, sizeof(xpath
),
953 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
954 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
956 return nb_cli_apply_changes(vty
, NULL
);
960 mac_access_list_remark
, mac_access_list_remark_cmd
,
961 "mac access-list WORD$name remark LINE...",
964 ACCESS_LIST_ZEBRA_STR
965 ACCESS_LIST_REMARK_STR
966 ACCESS_LIST_REMARK_LINE_STR
)
970 char xpath
[XPATH_MAXLEN
];
972 snprintf(xpath
, sizeof(xpath
),
973 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
974 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
976 remark
= argv_concat(argv
, argc
, 4);
977 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
978 rv
= nb_cli_apply_changes(vty
, xpath
);
979 XFREE(MTYPE_TMP
, remark
);
985 no_mac_access_list_remark
, no_mac_access_list_remark_cmd
,
986 "no mac access-list WORD$name remark",
990 ACCESS_LIST_ZEBRA_STR
991 ACCESS_LIST_REMARK_STR
)
993 char xpath
[XPATH_MAXLEN
];
996 snprintf(xpath
, sizeof(xpath
),
997 "/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
999 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1001 rv
= nb_cli_apply_changes(vty
, NULL
);
1002 if (rv
== CMD_SUCCESS
)
1003 return acl_remove_if_empty(vty
, "mac", name
);
1009 no_mac_access_list_remark
, no_mac_access_list_remark_line_cmd
,
1010 "no mac access-list WORD$name remark LINE...",
1014 ACCESS_LIST_ZEBRA_STR
1015 ACCESS_LIST_REMARK_STR
1016 ACCESS_LIST_REMARK_LINE_STR
)
1018 int access_list_cmp(struct lyd_node
*dnode1
, struct lyd_node
*dnode2
)
1020 uint32_t seq1
= yang_dnode_get_uint32(dnode1
, "./sequence");
1021 uint32_t seq2
= yang_dnode_get_uint32(dnode2
, "./sequence");
1026 void access_list_show(struct vty
*vty
, struct lyd_node
*dnode
,
1029 int type
= yang_dnode_get_enum(dnode
, "../type");
1032 bool is_exact
= false;
1033 bool cisco_style
= false;
1034 bool cisco_extended
= false;
1035 struct in_addr addr
, mask
;
1036 char macstr
[PREFIX2STR_BUFFER
];
1038 is_any
= yang_dnode_exists(dnode
, "./any");
1044 if (yang_dnode_exists(dnode
, "./host")
1045 || yang_dnode_exists(dnode
, "./network/address")
1046 || yang_dnode_exists(dnode
, "./source-any")) {
1048 if (yang_dnode_exists(dnode
, "./destination-host")
1049 || yang_dnode_exists(
1050 dnode
, "./destination-network/address")
1051 || yang_dnode_exists(dnode
, "./destination-any"))
1052 cisco_extended
= true;
1054 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1055 is_exact
= yang_dnode_get_bool(dnode
,
1056 "./ipv4-exact-match");
1059 case YALT_IPV6
: /* ipv6 */
1060 vty_out(vty
, "ipv6 ");
1064 yang_dnode_get_prefix(&p
, dnode
, "./ipv6-prefix");
1065 is_exact
= yang_dnode_get_bool(dnode
, "./ipv6-exact-match");
1067 case YALT_MAC
: /* mac */
1068 vty_out(vty
, "mac ");
1072 yang_dnode_get_prefix(&p
, dnode
, "./mac");
1076 vty_out(vty
, "access-list %s seq %s %s",
1077 yang_dnode_get_string(dnode
, "../name"),
1078 yang_dnode_get_string(dnode
, "./sequence"),
1079 yang_dnode_get_string(dnode
, "./action"));
1081 /* Handle Cisco style access lists. */
1084 vty_out(vty
, " ip");
1086 if (yang_dnode_exists(dnode
, "./network")) {
1087 yang_dnode_get_ipv4(&addr
, dnode
, "./network/address");
1088 yang_dnode_get_ipv4(&mask
, dnode
, "./network/mask");
1089 vty_out(vty
, " %pI4 %pI4", &addr
, &mask
);
1090 } else if (yang_dnode_exists(dnode
, "./host")) {
1092 vty_out(vty
, " host");
1095 yang_dnode_get_string(dnode
, "./host"));
1096 } else if (yang_dnode_exists(dnode
, "./source-any"))
1097 vty_out(vty
, " any");
1099 /* Not extended, exit earlier. */
1100 if (!cisco_extended
) {
1105 /* Handle destination address. */
1106 if (yang_dnode_exists(dnode
, "./destination-network")) {
1107 yang_dnode_get_ipv4(&addr
, dnode
,
1108 "./destination-network/address");
1109 yang_dnode_get_ipv4(&mask
, dnode
,
1110 "./destination-network/mask");
1111 vty_out(vty
, " %pI4 %pI4", &addr
, &mask
);
1112 } else if (yang_dnode_exists(dnode
, "./destination-host"))
1113 vty_out(vty
, " host %s",
1114 yang_dnode_get_string(dnode
,
1115 "./destination-host"));
1116 else if (yang_dnode_exists(dnode
, "./destination-any"))
1117 vty_out(vty
, " any");
1123 /* Zebra style access list. */
1125 /* If type is MAC don't show '/mask'. */
1126 if (type
== 2 /* mac */) {
1127 prefix_mac2str(&p
.u
.prefix_eth
, macstr
, sizeof(macstr
));
1128 vty_out(vty
, " %s", macstr
);
1130 vty_out(vty
, " %pFX", &p
);
1132 vty_out(vty
, " any");
1135 vty_out(vty
, " exact-match");
1140 void access_list_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
1143 int type
= yang_dnode_get_enum(dnode
, "../type");
1149 vty_out(vty
, "ipv6 ");
1152 vty_out(vty
, "mac ");
1156 vty_out(vty
, "access-list %s remark %s\n",
1157 yang_dnode_get_string(dnode
, "../name"),
1158 yang_dnode_get_string(dnode
, NULL
));
1166 * Remove main data structure prefix list if there are no more entries or
1167 * remark. This fixes compatibility with old CLI and tests.
1169 static int plist_remove_if_empty(struct vty
*vty
, const char *iptype
,
1172 char xpath
[XPATH_MAXLEN
];
1174 snprintf(xpath
, sizeof(xpath
),
1175 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark",
1177 /* List is not empty if there is a remark, check that: */
1178 if (yang_dnode_exists(vty
->candidate_config
->dnode
, xpath
))
1181 /* Check if we have any entries: */
1182 snprintf(xpath
, sizeof(xpath
),
1183 "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype
,
1186 * NOTE: if the list is empty it will return the first sequence
1189 if (acl_get_seq(vty
, xpath
) != 5)
1192 /* Nobody is using this list, lets remove it. */
1193 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1194 return nb_cli_apply_changes(vty
, NULL
);
1197 static int plist_remove(struct vty
*vty
, const char *iptype
, const char *name
,
1198 const char *seq
, const char *action
,
1199 const char *prefix_str
, const char *ge_str
,
1204 struct plist_dup_args pda
= {};
1205 char xpath
[XPATH_MAXLEN
];
1206 char xpath_entry
[XPATH_MAXLEN
+ 32];
1209 /* If the user provided sequence number, then just go for it. */
1212 xpath
, sizeof(xpath
),
1213 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
1215 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1217 rv
= nb_cli_apply_changes(vty
, NULL
);
1218 if (rv
== CMD_SUCCESS
)
1219 return plist_remove_if_empty(vty
, iptype
, name
);
1224 /* Otherwise, to keep compatibility, we need to figure it out. */
1225 pda
.pda_type
= iptype
;
1226 pda
.pda_name
= name
;
1227 pda
.pda_action
= action
;
1229 if (strmatch(iptype
, "ipv4")) {
1230 pda
.pda_xpath
[arg_idx
] = "./ipv4-prefix";
1231 pda
.pda_value
[arg_idx
] = prefix_str
;
1234 pda
.pda_xpath
[arg_idx
] =
1235 "./ipv4-prefix-length-greater-or-equal";
1236 pda
.pda_value
[arg_idx
] = ge_str
;
1240 pda
.pda_xpath
[arg_idx
] =
1241 "./ipv4-prefix-length-lesser-or-equal";
1242 pda
.pda_value
[arg_idx
] = le_str
;
1246 pda
.pda_xpath
[arg_idx
] = "./ipv6-prefix";
1247 pda
.pda_value
[arg_idx
] = prefix_str
;
1250 pda
.pda_xpath
[arg_idx
] =
1251 "./ipv6-prefix-length-greater-or-equal";
1252 pda
.pda_value
[arg_idx
] = ge_str
;
1256 pda
.pda_xpath
[arg_idx
] =
1257 "./ipv6-prefix-length-lesser-or-equal";
1258 pda
.pda_value
[arg_idx
] = le_str
;
1263 pda
.pda_xpath
[0] = "./any";
1264 pda
.pda_value
[0] = "";
1267 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1270 return CMD_WARNING_CONFIG_FAILED
;
1273 xpath_entry
, sizeof(xpath_entry
),
1274 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%" PRId64
"']",
1275 iptype
, name
, sseq
);
1276 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
1278 rv
= nb_cli_apply_changes(vty
, NULL
);
1279 if (rv
== CMD_SUCCESS
)
1280 return plist_remove_if_empty(vty
, iptype
, name
);
1286 ip_prefix_list
, ip_prefix_list_cmd
,
1287 "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}]>",
1290 PREFIX_LIST_NAME_STR
1292 ACCESS_LIST_ACTION_STR
1293 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1294 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1295 "Minimum prefix length to be matched\n"
1296 "Minimum prefix length\n"
1297 "Maximum prefix length to be matched\n"
1298 "Maximum prefix length\n")
1302 struct plist_dup_args pda
= {};
1303 char xpath
[XPATH_MAXLEN
];
1304 char xpath_entry
[XPATH_MAXLEN
+ 128];
1307 * Backward compatibility: don't complain about duplicated values,
1308 * just silently accept.
1310 if (seq_str
== NULL
) {
1311 pda
.pda_type
= "ipv4";
1312 pda
.pda_name
= name
;
1313 pda
.pda_action
= action
;
1315 pda
.pda_xpath
[arg_idx
] = "./ipv4-prefix";
1316 pda
.pda_value
[arg_idx
] = prefix_str
;
1319 pda
.pda_xpath
[arg_idx
] =
1320 "./ipv4-prefix-length-greater-or-equal";
1321 pda
.pda_value
[arg_idx
] = ge_str
;
1325 pda
.pda_xpath
[arg_idx
] =
1326 "./ipv4-prefix-length-lesser-or-equal";
1327 pda
.pda_value
[arg_idx
] = le_str
;
1331 pda
.pda_xpath
[0] = "./any";
1332 pda
.pda_value
[0] = "";
1335 /* Duplicated entry without sequence, just quit. */
1336 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1341 * Create the prefix-list first, so we can generate sequence if
1342 * none given (backward compatibility).
1344 snprintf(xpath
, sizeof(xpath
),
1345 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1346 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1347 if (seq_str
== NULL
) {
1348 /* Use XPath to find the next sequence number. */
1349 sseq
= acl_get_seq(vty
, xpath
);
1350 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1351 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1353 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1354 "%s/entry[sequence='%s']", xpath
, seq_str
);
1356 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1358 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1359 if (prefix_str
!= NULL
) {
1360 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
1364 nb_cli_enqueue_change(
1365 vty
, "./ipv4-prefix-length-greater-or-equal",
1366 NB_OP_MODIFY
, ge_str
);
1369 * Remove old ge if not being modified
1371 nb_cli_enqueue_change(
1372 vty
, "./ipv4-prefix-length-greater-or-equal",
1373 NB_OP_DESTROY
, NULL
);
1377 nb_cli_enqueue_change(
1378 vty
, "./ipv4-prefix-length-lesser-or-equal",
1379 NB_OP_MODIFY
, le_str
);
1382 * Remove old le if not being modified
1384 nb_cli_enqueue_change(
1385 vty
, "./ipv4-prefix-length-lesser-or-equal",
1386 NB_OP_DESTROY
, NULL
);
1389 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1392 return nb_cli_apply_changes(vty
, xpath_entry
);
1396 no_ip_prefix_list
, no_ip_prefix_list_cmd
,
1397 "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)}]>",
1401 PREFIX_LIST_NAME_STR
1403 ACCESS_LIST_ACTION_STR
1404 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1405 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1406 "Minimum prefix length to be matched\n"
1407 "Minimum prefix length\n"
1408 "Maximum prefix length to be matched\n"
1409 "Maximum prefix length\n")
1411 return plist_remove(vty
, "ipv4", name
, seq_str
, action
, prefix_str
,
1416 no_ip_prefix_list_seq
, no_ip_prefix_list_seq_cmd
,
1417 "no ip prefix-list WORD$name seq (1-4294967295)$seq",
1421 PREFIX_LIST_NAME_STR
1422 ACCESS_LIST_SEQ_STR
)
1424 return plist_remove(vty
, "ipv4", name
, seq_str
, NULL
, NULL
, NULL
, NULL
);
1428 no_ip_prefix_list_all
, no_ip_prefix_list_all_cmd
,
1429 "no ip prefix-list WORD$name",
1433 PREFIX_LIST_NAME_STR
)
1435 char xpath
[XPATH_MAXLEN
];
1437 snprintf(xpath
, sizeof(xpath
),
1438 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1439 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1441 return nb_cli_apply_changes(vty
, NULL
);
1445 ip_prefix_list_remark
, ip_prefix_list_remark_cmd
,
1446 "ip prefix-list WORD$name description LINE...",
1449 PREFIX_LIST_NAME_STR
1450 ACCESS_LIST_REMARK_STR
1451 ACCESS_LIST_REMARK_LINE_STR
)
1455 char xpath
[XPATH_MAXLEN
];
1457 snprintf(xpath
, sizeof(xpath
),
1458 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1459 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1461 remark
= argv_concat(argv
, argc
, 4);
1462 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1463 rv
= nb_cli_apply_changes(vty
, xpath
);
1464 XFREE(MTYPE_TMP
, remark
);
1470 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_cmd
,
1471 "no ip prefix-list WORD$name description",
1475 PREFIX_LIST_NAME_STR
1476 ACCESS_LIST_REMARK_STR
)
1478 char xpath
[XPATH_MAXLEN
];
1481 snprintf(xpath
, sizeof(xpath
),
1482 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
1484 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1486 rv
= nb_cli_apply_changes(vty
, NULL
);
1487 if (rv
== CMD_SUCCESS
)
1488 return plist_remove_if_empty(vty
, "ipv4", name
);
1494 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_line_cmd
,
1495 "no ip prefix-list WORD$name description LINE...",
1499 PREFIX_LIST_NAME_STR
1500 ACCESS_LIST_REMARK_STR
1501 ACCESS_LIST_REMARK_LINE_STR
)
1504 ipv6_prefix_list
, ipv6_prefix_list_cmd
,
1505 "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}]>",
1508 PREFIX_LIST_NAME_STR
1510 ACCESS_LIST_ACTION_STR
1511 "Any prefix match. Same as \"::0/0 le 128\"\n"
1512 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1513 "Maximum prefix length to be matched\n"
1514 "Maximum prefix length\n"
1515 "Minimum prefix length to be matched\n"
1516 "Minimum prefix length\n")
1520 struct plist_dup_args pda
= {};
1521 char xpath
[XPATH_MAXLEN
];
1522 char xpath_entry
[XPATH_MAXLEN
+ 128];
1525 * Backward compatibility: don't complain about duplicated values,
1526 * just silently accept.
1528 if (seq_str
== NULL
) {
1529 pda
.pda_type
= "ipv6";
1530 pda
.pda_name
= name
;
1531 pda
.pda_action
= action
;
1533 pda
.pda_xpath
[arg_idx
] = "./ipv6-prefix";
1534 pda
.pda_value
[arg_idx
] = prefix_str
;
1537 pda
.pda_xpath
[arg_idx
] =
1538 "./ipv6-prefix-length-greater-or-equal";
1539 pda
.pda_value
[arg_idx
] = ge_str
;
1543 pda
.pda_xpath
[arg_idx
] =
1544 "./ipv6-prefix-length-lesser-or-equal";
1545 pda
.pda_value
[arg_idx
] = le_str
;
1549 pda
.pda_xpath
[0] = "./any";
1550 pda
.pda_value
[0] = "";
1553 /* Duplicated entry without sequence, just quit. */
1554 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1559 * Create the prefix-list first, so we can generate sequence if
1560 * none given (backward compatibility).
1562 snprintf(xpath
, sizeof(xpath
),
1563 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1564 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1565 if (seq_str
== NULL
) {
1566 /* Use XPath to find the next sequence number. */
1567 sseq
= acl_get_seq(vty
, xpath
);
1568 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1569 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1571 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1572 "%s/entry[sequence='%s']", xpath
, seq_str
);
1574 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1576 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1577 if (prefix_str
!= NULL
) {
1578 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
1582 nb_cli_enqueue_change(
1583 vty
, "./ipv6-prefix-length-greater-or-equal",
1584 NB_OP_MODIFY
, ge_str
);
1587 * Remove old ge if not being modified
1589 nb_cli_enqueue_change(
1590 vty
, "./ipv6-prefix-length-greater-or-equal",
1591 NB_OP_DESTROY
, NULL
);
1595 nb_cli_enqueue_change(
1596 vty
, "./ipv6-prefix-length-lesser-or-equal",
1597 NB_OP_MODIFY
, le_str
);
1600 * Remove old le if not being modified
1602 nb_cli_enqueue_change(
1603 vty
, "./ipv6-prefix-length-lesser-or-equal",
1604 NB_OP_DESTROY
, NULL
);
1607 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1610 return nb_cli_apply_changes(vty
, xpath_entry
);
1614 no_ipv6_prefix_list
, no_ipv6_prefix_list_cmd
,
1615 "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}]>",
1619 PREFIX_LIST_NAME_STR
1621 ACCESS_LIST_ACTION_STR
1622 "Any prefix match. Same as \"::0/0 le 128\"\n"
1623 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1624 "Maximum prefix length to be matched\n"
1625 "Maximum prefix length\n"
1626 "Minimum prefix length to be matched\n"
1627 "Minimum prefix length\n")
1629 return plist_remove(vty
, "ipv6", name
, seq_str
, action
, prefix_str
,
1634 no_ipv6_prefix_list_seq
, no_ipv6_prefix_list_seq_cmd
,
1635 "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
1639 PREFIX_LIST_NAME_STR
1640 ACCESS_LIST_SEQ_STR
)
1642 return plist_remove(vty
, "ipv6", name
, seq_str
, NULL
, NULL
, NULL
, NULL
);
1646 no_ipv6_prefix_list_all
, no_ipv6_prefix_list_all_cmd
,
1647 "no ipv6 prefix-list WORD$name",
1651 PREFIX_LIST_NAME_STR
)
1653 char xpath
[XPATH_MAXLEN
];
1655 snprintf(xpath
, sizeof(xpath
),
1656 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1657 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1659 return nb_cli_apply_changes(vty
, NULL
);
1663 ipv6_prefix_list_remark
, ipv6_prefix_list_remark_cmd
,
1664 "ipv6 prefix-list WORD$name description LINE...",
1667 PREFIX_LIST_NAME_STR
1668 ACCESS_LIST_REMARK_STR
1669 ACCESS_LIST_REMARK_LINE_STR
)
1673 char xpath
[XPATH_MAXLEN
];
1675 snprintf(xpath
, sizeof(xpath
),
1676 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1677 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1679 remark
= argv_concat(argv
, argc
, 4);
1680 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1681 rv
= nb_cli_apply_changes(vty
, xpath
);
1682 XFREE(MTYPE_TMP
, remark
);
1688 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_cmd
,
1689 "no ipv6 prefix-list WORD$name description",
1693 PREFIX_LIST_NAME_STR
1694 ACCESS_LIST_REMARK_STR
)
1696 char xpath
[XPATH_MAXLEN
];
1699 snprintf(xpath
, sizeof(xpath
),
1700 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
1702 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1704 rv
= nb_cli_apply_changes(vty
, NULL
);
1705 if (rv
== CMD_SUCCESS
)
1706 return plist_remove_if_empty(vty
, "ipv6", name
);
1712 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_line_cmd
,
1713 "no ipv6 prefix-list WORD$name description LINE...",
1717 PREFIX_LIST_NAME_STR
1718 ACCESS_LIST_REMARK_STR
1719 ACCESS_LIST_REMARK_LINE_STR
)
1721 int prefix_list_cmp(struct lyd_node
*dnode1
, struct lyd_node
*dnode2
)
1723 uint32_t seq1
= yang_dnode_get_uint32(dnode1
, "./sequence");
1724 uint32_t seq2
= yang_dnode_get_uint32(dnode2
, "./sequence");
1729 void prefix_list_show(struct vty
*vty
, struct lyd_node
*dnode
,
1732 int type
= yang_dnode_get_enum(dnode
, "../type");
1733 const char *ge_str
= NULL
, *le_str
= NULL
;
1737 is_any
= yang_dnode_exists(dnode
, "./any");
1741 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1742 if (yang_dnode_exists(dnode
,
1743 "./ipv4-prefix-length-greater-or-equal"))
1744 ge_str
= yang_dnode_get_string(
1745 dnode
, "./ipv4-prefix-length-greater-or-equal");
1746 if (yang_dnode_exists(dnode
,
1747 "./ipv4-prefix-length-lesser-or-equal"))
1748 le_str
= yang_dnode_get_string(
1749 dnode
, "./ipv4-prefix-length-lesser-or-equal");
1751 vty_out(vty
, "ip ");
1755 yang_dnode_get_prefix(&p
, dnode
, "ipv6-prefix");
1756 if (yang_dnode_exists(dnode
,
1757 "./ipv6-prefix-length-greater-or-equal"))
1758 ge_str
= yang_dnode_get_string(
1759 dnode
, "./ipv6-prefix-length-greater-or-equal");
1760 if (yang_dnode_exists(dnode
,
1761 "./ipv6-prefix-length-lesser-or-equal"))
1762 le_str
= yang_dnode_get_string(
1763 dnode
, "./ipv6-prefix-length-lesser-or-equal");
1765 vty_out(vty
, "ipv6 ");
1769 vty_out(vty
, "prefix-list %s seq %s %s",
1770 yang_dnode_get_string(dnode
, "../name"),
1771 yang_dnode_get_string(dnode
, "./sequence"),
1772 yang_dnode_get_string(dnode
, "./action"));
1775 vty_out(vty
, " any\n");
1779 vty_out(vty
, " %pFX", &p
);
1781 vty_out(vty
, " ge %s", ge_str
);
1783 vty_out(vty
, " le %s", le_str
);
1788 void prefix_list_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
1791 int type
= yang_dnode_get_enum(dnode
, "../type");
1795 vty_out(vty
, "ip ");
1798 vty_out(vty
, "ipv6 ");
1802 vty_out(vty
, "prefix-list %s description %s\n",
1803 yang_dnode_get_string(dnode
, "../name"),
1804 yang_dnode_get_string(dnode
, NULL
));
1807 void filter_cli_init(void)
1809 /* access-list cisco-style (legacy). */
1810 install_element(CONFIG_NODE
, &access_list_std_cmd
);
1811 install_element(CONFIG_NODE
, &no_access_list_std_cmd
);
1812 install_element(CONFIG_NODE
, &access_list_ext_cmd
);
1813 install_element(CONFIG_NODE
, &no_access_list_ext_cmd
);
1815 /* access-list zebra-style. */
1816 install_element(CONFIG_NODE
, &access_list_cmd
);
1817 install_element(CONFIG_NODE
, &no_access_list_cmd
);
1818 install_element(CONFIG_NODE
, &no_access_list_all_cmd
);
1819 install_element(CONFIG_NODE
, &access_list_remark_cmd
);
1820 install_element(CONFIG_NODE
, &no_access_list_remark_cmd
);
1821 install_element(CONFIG_NODE
, &no_access_list_remark_line_cmd
);
1823 install_element(CONFIG_NODE
, &ipv6_access_list_cmd
);
1824 install_element(CONFIG_NODE
, &no_ipv6_access_list_cmd
);
1825 install_element(CONFIG_NODE
, &no_ipv6_access_list_all_cmd
);
1826 install_element(CONFIG_NODE
, &ipv6_access_list_remark_cmd
);
1827 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_cmd
);
1828 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_line_cmd
);
1830 install_element(CONFIG_NODE
, &mac_access_list_cmd
);
1831 install_element(CONFIG_NODE
, &no_mac_access_list_cmd
);
1832 install_element(CONFIG_NODE
, &no_mac_access_list_all_cmd
);
1833 install_element(CONFIG_NODE
, &mac_access_list_remark_cmd
);
1834 install_element(CONFIG_NODE
, &no_mac_access_list_remark_cmd
);
1835 install_element(CONFIG_NODE
, &no_mac_access_list_remark_line_cmd
);
1838 install_element(CONFIG_NODE
, &ip_prefix_list_cmd
);
1839 install_element(CONFIG_NODE
, &no_ip_prefix_list_cmd
);
1840 install_element(CONFIG_NODE
, &no_ip_prefix_list_seq_cmd
);
1841 install_element(CONFIG_NODE
, &no_ip_prefix_list_all_cmd
);
1842 install_element(CONFIG_NODE
, &ip_prefix_list_remark_cmd
);
1843 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_cmd
);
1844 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_line_cmd
);
1846 install_element(CONFIG_NODE
, &ipv6_prefix_list_cmd
);
1847 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_cmd
);
1848 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_seq_cmd
);
1849 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_all_cmd
);
1850 install_element(CONFIG_NODE
, &ipv6_prefix_list_remark_cmd
);
1851 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_cmd
);
1852 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_line_cmd
);