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 union prefixconstptr prefix
, int ge
, int le
)
1202 struct plist_dup_args pda
= {};
1203 char xpath
[XPATH_MAXLEN
];
1204 char xpath_entry
[XPATH_MAXLEN
+ 32];
1207 /* If the user provided sequence number, then just go for it. */
1210 xpath
, sizeof(xpath
),
1211 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
1213 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1215 rv
= nb_cli_apply_changes(vty
, NULL
);
1216 if (rv
== CMD_SUCCESS
)
1217 return plist_remove_if_empty(vty
, iptype
, name
);
1222 /* Otherwise, to keep compatibility, we need to figure it out. */
1223 pda
.pda_type
= iptype
;
1224 pda
.pda_name
= name
;
1225 pda
.pda_action
= action
;
1227 prefix_copy(&pda
.prefix
, prefix
);
1228 apply_mask(&pda
.prefix
);
1235 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1238 return CMD_WARNING_CONFIG_FAILED
;
1241 xpath_entry
, sizeof(xpath_entry
),
1242 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%" PRId64
"']",
1243 iptype
, name
, sseq
);
1244 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
1246 rv
= nb_cli_apply_changes(vty
, NULL
);
1247 if (rv
== CMD_SUCCESS
)
1248 return plist_remove_if_empty(vty
, iptype
, name
);
1254 ip_prefix_list
, ip_prefix_list_cmd
,
1255 "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}]>",
1258 PREFIX_LIST_NAME_STR
1260 ACCESS_LIST_ACTION_STR
1261 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1262 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1263 "Minimum prefix length to be matched\n"
1264 "Minimum prefix length\n"
1265 "Maximum prefix length to be matched\n"
1266 "Maximum prefix length\n")
1269 struct plist_dup_args pda
= {};
1270 char xpath
[XPATH_MAXLEN
];
1271 char xpath_entry
[XPATH_MAXLEN
+ 128];
1274 * Backward compatibility: don't complain about duplicated values,
1275 * just silently accept.
1277 if (seq_str
== NULL
) {
1278 pda
.pda_type
= "ipv4";
1279 pda
.pda_name
= name
;
1280 pda
.pda_action
= action
;
1282 prefix_copy(&pda
.prefix
, prefix
);
1289 /* Duplicated entry without sequence, just quit. */
1290 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1295 * Create the prefix-list first, so we can generate sequence if
1296 * none given (backward compatibility).
1298 snprintf(xpath
, sizeof(xpath
),
1299 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1300 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1301 if (seq_str
== NULL
) {
1302 /* Use XPath to find the next sequence number. */
1303 sseq
= acl_get_seq(vty
, xpath
);
1304 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1305 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1307 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1308 "%s/entry[sequence='%s']", xpath
, seq_str
);
1310 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1312 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1313 if (prefix_str
!= NULL
) {
1314 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
1318 nb_cli_enqueue_change(
1319 vty
, "./ipv4-prefix-length-greater-or-equal",
1320 NB_OP_MODIFY
, ge_str
);
1323 * Remove old ge if not being modified
1325 nb_cli_enqueue_change(
1326 vty
, "./ipv4-prefix-length-greater-or-equal",
1327 NB_OP_DESTROY
, NULL
);
1331 nb_cli_enqueue_change(
1332 vty
, "./ipv4-prefix-length-lesser-or-equal",
1333 NB_OP_MODIFY
, le_str
);
1336 * Remove old le if not being modified
1338 nb_cli_enqueue_change(
1339 vty
, "./ipv4-prefix-length-lesser-or-equal",
1340 NB_OP_DESTROY
, NULL
);
1343 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1346 return nb_cli_apply_changes(vty
, xpath_entry
);
1350 no_ip_prefix_list
, no_ip_prefix_list_cmd
,
1351 "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)}]>",
1355 PREFIX_LIST_NAME_STR
1357 ACCESS_LIST_ACTION_STR
1358 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1359 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1360 "Minimum prefix length to be matched\n"
1361 "Minimum prefix length\n"
1362 "Maximum prefix length to be matched\n"
1363 "Maximum prefix length\n")
1365 return plist_remove(vty
, "ipv4", name
, seq_str
, action
,
1366 prefix_str
? prefix
: NULL
, ge
, le
);
1370 no_ip_prefix_list_seq
, no_ip_prefix_list_seq_cmd
,
1371 "no ip prefix-list WORD$name seq (1-4294967295)$seq",
1375 PREFIX_LIST_NAME_STR
1376 ACCESS_LIST_SEQ_STR
)
1378 return plist_remove(vty
, "ipv4", name
, seq_str
, NULL
, NULL
, 0, 0);
1382 no_ip_prefix_list_all
, no_ip_prefix_list_all_cmd
,
1383 "no ip prefix-list WORD$name",
1387 PREFIX_LIST_NAME_STR
)
1389 char xpath
[XPATH_MAXLEN
];
1391 snprintf(xpath
, sizeof(xpath
),
1392 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1393 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1395 return nb_cli_apply_changes(vty
, NULL
);
1399 ip_prefix_list_remark
, ip_prefix_list_remark_cmd
,
1400 "ip prefix-list WORD$name description LINE...",
1403 PREFIX_LIST_NAME_STR
1404 ACCESS_LIST_REMARK_STR
1405 ACCESS_LIST_REMARK_LINE_STR
)
1409 char xpath
[XPATH_MAXLEN
];
1411 snprintf(xpath
, sizeof(xpath
),
1412 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1413 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1415 remark
= argv_concat(argv
, argc
, 4);
1416 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1417 rv
= nb_cli_apply_changes(vty
, xpath
);
1418 XFREE(MTYPE_TMP
, remark
);
1424 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_cmd
,
1425 "no ip prefix-list WORD$name description",
1429 PREFIX_LIST_NAME_STR
1430 ACCESS_LIST_REMARK_STR
)
1432 char xpath
[XPATH_MAXLEN
];
1435 snprintf(xpath
, sizeof(xpath
),
1436 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
1438 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1440 rv
= nb_cli_apply_changes(vty
, NULL
);
1441 if (rv
== CMD_SUCCESS
)
1442 return plist_remove_if_empty(vty
, "ipv4", name
);
1448 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_line_cmd
,
1449 "no ip prefix-list WORD$name description LINE...",
1453 PREFIX_LIST_NAME_STR
1454 ACCESS_LIST_REMARK_STR
1455 ACCESS_LIST_REMARK_LINE_STR
)
1458 ipv6_prefix_list
, ipv6_prefix_list_cmd
,
1459 "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}]>",
1462 PREFIX_LIST_NAME_STR
1464 ACCESS_LIST_ACTION_STR
1465 "Any prefix match. Same as \"::0/0 le 128\"\n"
1466 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1467 "Maximum prefix length to be matched\n"
1468 "Maximum prefix length\n"
1469 "Minimum prefix length to be matched\n"
1470 "Minimum prefix length\n")
1473 struct plist_dup_args pda
= {};
1474 char xpath
[XPATH_MAXLEN
];
1475 char xpath_entry
[XPATH_MAXLEN
+ 128];
1478 * Backward compatibility: don't complain about duplicated values,
1479 * just silently accept.
1481 if (seq_str
== NULL
) {
1482 pda
.pda_type
= "ipv6";
1483 pda
.pda_name
= name
;
1484 pda
.pda_action
= action
;
1486 prefix_copy(&pda
.prefix
, prefix
);
1493 /* Duplicated entry without sequence, just quit. */
1494 if (plist_is_dup(vty
->candidate_config
->dnode
, &pda
))
1499 * Create the prefix-list first, so we can generate sequence if
1500 * none given (backward compatibility).
1502 snprintf(xpath
, sizeof(xpath
),
1503 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1504 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1505 if (seq_str
== NULL
) {
1506 /* Use XPath to find the next sequence number. */
1507 sseq
= acl_get_seq(vty
, xpath
);
1508 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1509 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1511 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1512 "%s/entry[sequence='%s']", xpath
, seq_str
);
1514 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1516 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1517 if (prefix_str
!= NULL
) {
1518 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
1522 nb_cli_enqueue_change(
1523 vty
, "./ipv6-prefix-length-greater-or-equal",
1524 NB_OP_MODIFY
, ge_str
);
1527 * Remove old ge if not being modified
1529 nb_cli_enqueue_change(
1530 vty
, "./ipv6-prefix-length-greater-or-equal",
1531 NB_OP_DESTROY
, NULL
);
1535 nb_cli_enqueue_change(
1536 vty
, "./ipv6-prefix-length-lesser-or-equal",
1537 NB_OP_MODIFY
, le_str
);
1540 * Remove old le if not being modified
1542 nb_cli_enqueue_change(
1543 vty
, "./ipv6-prefix-length-lesser-or-equal",
1544 NB_OP_DESTROY
, NULL
);
1547 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1550 return nb_cli_apply_changes(vty
, xpath_entry
);
1554 no_ipv6_prefix_list
, no_ipv6_prefix_list_cmd
,
1555 "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}]>",
1559 PREFIX_LIST_NAME_STR
1561 ACCESS_LIST_ACTION_STR
1562 "Any prefix match. Same as \"::0/0 le 128\"\n"
1563 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1564 "Maximum prefix length to be matched\n"
1565 "Maximum prefix length\n"
1566 "Minimum prefix length to be matched\n"
1567 "Minimum prefix length\n")
1569 return plist_remove(vty
, "ipv6", name
, seq_str
, action
,
1570 prefix_str
? prefix
: NULL
, ge
, le
);
1574 no_ipv6_prefix_list_seq
, no_ipv6_prefix_list_seq_cmd
,
1575 "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
1579 PREFIX_LIST_NAME_STR
1580 ACCESS_LIST_SEQ_STR
)
1582 return plist_remove(vty
, "ipv6", name
, seq_str
, NULL
, NULL
, 0, 0);
1586 no_ipv6_prefix_list_all
, no_ipv6_prefix_list_all_cmd
,
1587 "no ipv6 prefix-list WORD$name",
1591 PREFIX_LIST_NAME_STR
)
1593 char xpath
[XPATH_MAXLEN
];
1595 snprintf(xpath
, sizeof(xpath
),
1596 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1597 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1599 return nb_cli_apply_changes(vty
, NULL
);
1603 ipv6_prefix_list_remark
, ipv6_prefix_list_remark_cmd
,
1604 "ipv6 prefix-list WORD$name description LINE...",
1607 PREFIX_LIST_NAME_STR
1608 ACCESS_LIST_REMARK_STR
1609 ACCESS_LIST_REMARK_LINE_STR
)
1613 char xpath
[XPATH_MAXLEN
];
1615 snprintf(xpath
, sizeof(xpath
),
1616 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1617 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1619 remark
= argv_concat(argv
, argc
, 4);
1620 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1621 rv
= nb_cli_apply_changes(vty
, xpath
);
1622 XFREE(MTYPE_TMP
, remark
);
1628 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_cmd
,
1629 "no ipv6 prefix-list WORD$name description",
1633 PREFIX_LIST_NAME_STR
1634 ACCESS_LIST_REMARK_STR
)
1636 char xpath
[XPATH_MAXLEN
];
1639 snprintf(xpath
, sizeof(xpath
),
1640 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
1642 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1644 rv
= nb_cli_apply_changes(vty
, NULL
);
1645 if (rv
== CMD_SUCCESS
)
1646 return plist_remove_if_empty(vty
, "ipv6", name
);
1652 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_line_cmd
,
1653 "no ipv6 prefix-list WORD$name description LINE...",
1657 PREFIX_LIST_NAME_STR
1658 ACCESS_LIST_REMARK_STR
1659 ACCESS_LIST_REMARK_LINE_STR
)
1661 int prefix_list_cmp(struct lyd_node
*dnode1
, struct lyd_node
*dnode2
)
1663 uint32_t seq1
= yang_dnode_get_uint32(dnode1
, "./sequence");
1664 uint32_t seq2
= yang_dnode_get_uint32(dnode2
, "./sequence");
1669 void prefix_list_show(struct vty
*vty
, struct lyd_node
*dnode
,
1672 int type
= yang_dnode_get_enum(dnode
, "../type");
1673 const char *ge_str
= NULL
, *le_str
= NULL
;
1677 is_any
= yang_dnode_exists(dnode
, "./any");
1681 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1682 if (yang_dnode_exists(dnode
,
1683 "./ipv4-prefix-length-greater-or-equal"))
1684 ge_str
= yang_dnode_get_string(
1685 dnode
, "./ipv4-prefix-length-greater-or-equal");
1686 if (yang_dnode_exists(dnode
,
1687 "./ipv4-prefix-length-lesser-or-equal"))
1688 le_str
= yang_dnode_get_string(
1689 dnode
, "./ipv4-prefix-length-lesser-or-equal");
1691 vty_out(vty
, "ip ");
1695 yang_dnode_get_prefix(&p
, dnode
, "ipv6-prefix");
1696 if (yang_dnode_exists(dnode
,
1697 "./ipv6-prefix-length-greater-or-equal"))
1698 ge_str
= yang_dnode_get_string(
1699 dnode
, "./ipv6-prefix-length-greater-or-equal");
1700 if (yang_dnode_exists(dnode
,
1701 "./ipv6-prefix-length-lesser-or-equal"))
1702 le_str
= yang_dnode_get_string(
1703 dnode
, "./ipv6-prefix-length-lesser-or-equal");
1705 vty_out(vty
, "ipv6 ");
1709 vty_out(vty
, "prefix-list %s seq %s %s",
1710 yang_dnode_get_string(dnode
, "../name"),
1711 yang_dnode_get_string(dnode
, "./sequence"),
1712 yang_dnode_get_string(dnode
, "./action"));
1715 vty_out(vty
, " any\n");
1719 vty_out(vty
, " %pFX", &p
);
1721 vty_out(vty
, " ge %s", ge_str
);
1723 vty_out(vty
, " le %s", le_str
);
1728 void prefix_list_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
1731 int type
= yang_dnode_get_enum(dnode
, "../type");
1735 vty_out(vty
, "ip ");
1738 vty_out(vty
, "ipv6 ");
1742 vty_out(vty
, "prefix-list %s description %s\n",
1743 yang_dnode_get_string(dnode
, "../name"),
1744 yang_dnode_get_string(dnode
, NULL
));
1747 void filter_cli_init(void)
1749 /* access-list cisco-style (legacy). */
1750 install_element(CONFIG_NODE
, &access_list_std_cmd
);
1751 install_element(CONFIG_NODE
, &no_access_list_std_cmd
);
1752 install_element(CONFIG_NODE
, &access_list_ext_cmd
);
1753 install_element(CONFIG_NODE
, &no_access_list_ext_cmd
);
1755 /* access-list zebra-style. */
1756 install_element(CONFIG_NODE
, &access_list_cmd
);
1757 install_element(CONFIG_NODE
, &no_access_list_cmd
);
1758 install_element(CONFIG_NODE
, &no_access_list_all_cmd
);
1759 install_element(CONFIG_NODE
, &access_list_remark_cmd
);
1760 install_element(CONFIG_NODE
, &no_access_list_remark_cmd
);
1761 install_element(CONFIG_NODE
, &no_access_list_remark_line_cmd
);
1763 install_element(CONFIG_NODE
, &ipv6_access_list_cmd
);
1764 install_element(CONFIG_NODE
, &no_ipv6_access_list_cmd
);
1765 install_element(CONFIG_NODE
, &no_ipv6_access_list_all_cmd
);
1766 install_element(CONFIG_NODE
, &ipv6_access_list_remark_cmd
);
1767 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_cmd
);
1768 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_line_cmd
);
1770 install_element(CONFIG_NODE
, &mac_access_list_cmd
);
1771 install_element(CONFIG_NODE
, &no_mac_access_list_cmd
);
1772 install_element(CONFIG_NODE
, &no_mac_access_list_all_cmd
);
1773 install_element(CONFIG_NODE
, &mac_access_list_remark_cmd
);
1774 install_element(CONFIG_NODE
, &no_mac_access_list_remark_cmd
);
1775 install_element(CONFIG_NODE
, &no_mac_access_list_remark_line_cmd
);
1778 install_element(CONFIG_NODE
, &ip_prefix_list_cmd
);
1779 install_element(CONFIG_NODE
, &no_ip_prefix_list_cmd
);
1780 install_element(CONFIG_NODE
, &no_ip_prefix_list_seq_cmd
);
1781 install_element(CONFIG_NODE
, &no_ip_prefix_list_all_cmd
);
1782 install_element(CONFIG_NODE
, &ip_prefix_list_remark_cmd
);
1783 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_cmd
);
1784 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_line_cmd
);
1786 install_element(CONFIG_NODE
, &ipv6_prefix_list_cmd
);
1787 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_cmd
);
1788 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_seq_cmd
);
1789 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_all_cmd
);
1790 install_element(CONFIG_NODE
, &ipv6_prefix_list_remark_cmd
);
1791 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_cmd
);
1792 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_line_cmd
);