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 locate filter data structures for Cisco-style ACLs.
57 static int64_t acl_cisco_get_seq(struct access_list
*acl
, const char *action
,
58 const char *src
, const char *src_mask
,
59 const char *dst
, const char *dst_mask
)
61 struct filter_cisco
*fc
;
64 memset(&f
, 0, sizeof(f
));
66 if (strcmp(action
, "permit") == 0)
67 f
.type
= FILTER_PERMIT
;
72 inet_pton(AF_INET
, src
, &fc
->addr
);
73 inet_pton(AF_INET
, src_mask
, &fc
->addr_mask
);
74 fc
->addr
.s_addr
&= ~fc
->addr_mask
.s_addr
;
77 inet_pton(AF_INET
, dst
, &fc
->mask
);
78 inet_pton(AF_INET
, dst_mask
, &fc
->mask_mask
);
79 fc
->mask
.s_addr
&= ~fc
->mask_mask
.s_addr
;
82 fn
= filter_lookup_cisco(acl
, &f
);
90 * Helper function to locate filter data structures for zebra-style ACLs.
92 static int64_t acl_zebra_get_seq(struct access_list
*acl
, const char *action
,
93 const struct prefix
*p
, bool exact
)
95 struct filter_zebra
*fz
;
98 memset(&f
, 0, sizeof(f
));
99 memset(&fz
, 0, sizeof(fz
));
100 if (strcmp(action
, "permit") == 0)
101 f
.type
= FILTER_PERMIT
;
103 f
.type
= FILTER_DENY
;
107 prefix_copy(&fz
->prefix
, p
);
110 fn
= filter_lookup_zebra(acl
, &f
);
118 * Helper function to concatenate address with mask in Cisco style.
120 static void concat_addr_mask_v4(const char *addr
, const char *mask
, char *dst
,
126 assert(inet_pton(AF_INET
, mask
, &ia
) == 1);
127 ia
.s_addr
= ~ia
.s_addr
;
128 plen
= ip_masklen(ia
);
129 snprintf(dst
, dstlen
, "%s/%d", addr
, plen
);
133 * Helper function to generate a sequence number for legacy commands.
135 static int acl_get_seq_cb(const struct lyd_node
*dnode
, void *arg
)
138 int64_t cur_seq
= yang_dnode_get_uint32(dnode
, "sequence");
143 return YANG_ITER_CONTINUE
;
147 * Helper function that iterates over the XPath `xpath` on the candidate
148 * configuration in `vty->candidate_config`.
150 * \param[in] vty shell context with the candidate configuration.
151 * \param[in] xpath the XPath to look for the sequence leaf.
152 * \returns next unused sequence number.
154 static long acl_get_seq(struct vty
*vty
, const char *xpath
)
158 yang_dnode_iterate(acl_get_seq_cb
, &seq
, vty
->candidate_config
->dnode
,
165 * Cisco (legacy) access lists.
168 access_list_std
, access_list_std_cmd
,
169 "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>",
173 ACCESS_LIST_ACTION_STR
174 "A single host address\n"
181 char xpath
[XPATH_MAXLEN
];
182 char xpath_entry
[XPATH_MAXLEN
+ 128];
185 * Create the access-list first, so we can generate sequence if
186 * none given (backward compatibility).
188 snprintf(xpath
, sizeof(xpath
),
189 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
190 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
191 if (seq_str
== NULL
) {
192 /* Use XPath to find the next sequence number. */
193 sseq
= acl_get_seq(vty
, xpath
);
194 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
195 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
197 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
198 "%s/entry[sequence='%s']", xpath
, seq_str
);
200 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
202 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
203 if (host_str
!= NULL
&& mask_str
== NULL
) {
204 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, host_str
);
205 } else if (host_str
!= NULL
&& mask_str
!= NULL
) {
206 concat_addr_mask_v4(host_str
, mask_str
, ipmask
, sizeof(ipmask
));
207 nb_cli_enqueue_change(vty
, "./network", NB_OP_MODIFY
, ipmask
);
209 nb_cli_enqueue_change(vty
, "./source-any", NB_OP_CREATE
, NULL
);
212 return nb_cli_apply_changes(vty
, xpath_entry
);
216 no_access_list_std
, no_access_list_std_cmd
,
217 "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>",
222 ACCESS_LIST_ACTION_STR
223 "A single host address\n"
228 struct access_list
*acl
;
229 struct lyd_node
*dnode
;
231 char xpath
[XPATH_MAXLEN
];
232 char xpath_entry
[XPATH_MAXLEN
+ 32];
234 /* If the user provided sequence number, then just go for it. */
235 if (seq_str
!= NULL
) {
237 xpath
, sizeof(xpath
),
238 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
240 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
241 return nb_cli_apply_changes(vty
, NULL
);
244 /* Otherwise, to keep compatibility, we need to figure it out. */
245 snprintf(xpath
, sizeof(xpath
),
246 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
248 /* Access-list must exist before entries. */
249 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
252 /* Use access-list data structure to fetch sequence. */
253 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
254 acl
= nb_running_get_entry(dnode
, NULL
, true);
255 sseq
= acl_cisco_get_seq(acl
, action
, host_str
,
256 mask_str
? mask_str
: CISCO_HOST_WILDCARD_MASK
,
261 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
262 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
263 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
265 return nb_cli_apply_changes(vty
, NULL
);
269 access_list_ext
, access_list_ext_cmd
,
270 "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>",
274 ACCESS_LIST_ACTION_STR
276 "Source address to match\n"
277 "Source address mask to apply\n"
278 "Single source host\n"
279 "Source address to match\n"
281 "Destination address to match\n"
282 "Destination address mask to apply\n"
283 "Single destination host\n"
284 "Destination address to match\n"
285 "Any destination host\n")
288 char ipmask
[64], ipmask_dst
[64];
289 char xpath
[XPATH_MAXLEN
];
290 char xpath_entry
[XPATH_MAXLEN
+ 128];
293 * Create the access-list first, so we can generate sequence if
294 * none given (backward compatibility).
296 snprintf(xpath
, sizeof(xpath
),
297 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
298 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
299 if (seq_str
== NULL
) {
300 /* Use XPath to find the next sequence number. */
301 sseq
= acl_get_seq(vty
, xpath
);
302 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
303 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
305 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
306 "%s/entry[sequence='%s']", xpath
, seq_str
);
308 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
310 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
311 if (src_str
!= NULL
&& src_mask_str
== NULL
) {
312 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, src_str
);
313 } else if (src_str
!= NULL
&& src_mask_str
!= NULL
) {
314 concat_addr_mask_v4(src_str
, src_mask_str
, ipmask
,
316 nb_cli_enqueue_change(vty
, "./network", NB_OP_MODIFY
, ipmask
);
318 nb_cli_enqueue_change(vty
, "./source-any", NB_OP_CREATE
, NULL
);
321 if (dst_str
!= NULL
&& dst_mask_str
== NULL
) {
322 nb_cli_enqueue_change(vty
, "./destination-host", NB_OP_MODIFY
,
324 } else if (dst_str
!= NULL
&& dst_mask_str
!= NULL
) {
325 concat_addr_mask_v4(dst_str
, dst_mask_str
, ipmask_dst
,
327 nb_cli_enqueue_change(vty
, "./destination-network",
328 NB_OP_MODIFY
, ipmask_dst
);
330 nb_cli_enqueue_change(vty
, "./destination-any", NB_OP_CREATE
,
334 return nb_cli_apply_changes(vty
, xpath_entry
);
338 no_access_list_ext
, no_access_list_ext_cmd
,
339 "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>",
344 ACCESS_LIST_ACTION_STR
345 "Any Internet Protocol\n"
346 "Source address to match\n"
347 "Source address mask to apply\n"
348 "Single source host\n"
349 "Source address to match\n"
351 "Destination address to match\n"
352 "Destination address mask to apply\n"
353 "Single destination host\n"
354 "Destination address to match\n"
355 "Any destination host\n")
357 struct access_list
*acl
;
358 struct lyd_node
*dnode
;
360 char xpath
[XPATH_MAXLEN
];
361 char xpath_entry
[XPATH_MAXLEN
+ 32];
363 /* If the user provided sequence number, then just go for it. */
364 if (seq_str
!= NULL
) {
366 xpath
, sizeof(xpath
),
367 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
369 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
370 return nb_cli_apply_changes(vty
, NULL
);
373 /* Otherwise, to keep compatibility, we need to figure it out. */
374 snprintf(xpath
, sizeof(xpath
),
375 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
377 /* Access-list must exist before entries. */
378 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
381 /* Use access-list data structure to fetch sequence. */
382 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
383 acl
= nb_running_get_entry(dnode
, NULL
, true);
384 if (src_str
!= NULL
) {
386 sseq
= acl_cisco_get_seq(
387 acl
, action
, src_str
,
388 src_mask_str
? src_mask_str
389 : CISCO_HOST_WILDCARD_MASK
,
391 dst_mask_str
? dst_mask_str
392 : CISCO_HOST_WILDCARD_MASK
);
394 sseq
= acl_cisco_get_seq(
395 acl
, action
, src_str
,
396 src_mask_str
? src_mask_str
397 : CISCO_HOST_WILDCARD_MASK
,
398 "0.0.0.0", CISCO_ANY_WILDCARD_MASK
);
401 sseq
= acl_cisco_get_seq(
402 acl
, action
, "0.0.0.0", CISCO_ANY_WILDCARD_MASK
,
404 dst_mask_str
? dst_mask_str
405 : CISCO_HOST_WILDCARD_MASK
);
407 sseq
= acl_cisco_get_seq(
408 acl
, action
, "0.0.0.0", CISCO_ANY_WILDCARD_MASK
,
409 "0.0.0.0", CISCO_ANY_WILDCARD_MASK
);
414 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
415 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
416 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
418 return nb_cli_apply_changes(vty
, NULL
);
422 * Zebra access lists.
425 access_list
, access_list_cmd
,
426 "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
428 ACCESS_LIST_ZEBRA_STR
430 ACCESS_LIST_ACTION_STR
431 "Prefix to match. e.g. 10.0.0.0/8\n"
432 "Exact match of the prefixes\n"
436 char xpath
[XPATH_MAXLEN
];
437 char xpath_entry
[XPATH_MAXLEN
+ 128];
440 * Create the access-list first, so we can generate sequence if
441 * none given (backward compatibility).
443 snprintf(xpath
, sizeof(xpath
),
444 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
445 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
446 if (seq_str
== NULL
) {
447 /* Use XPath to find the next sequence number. */
448 sseq
= acl_get_seq(vty
, xpath
);
449 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
450 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
452 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
453 "%s/entry[sequence='%s']", xpath
, seq_str
);
455 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
457 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
458 if (prefix_str
!= NULL
) {
459 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
461 nb_cli_enqueue_change(vty
, "./ipv4-exact-match", NB_OP_MODIFY
,
462 exact
? "true" : "false");
464 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
467 return nb_cli_apply_changes(vty
, xpath_entry
);
471 no_access_list
, no_access_list_cmd
,
472 "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
475 ACCESS_LIST_ZEBRA_STR
477 ACCESS_LIST_ACTION_STR
478 "Prefix to match. e.g. 10.0.0.0/8\n"
479 "Exact match of the prefixes\n"
482 struct access_list
*acl
;
483 struct lyd_node
*dnode
;
486 char xpath
[XPATH_MAXLEN
];
487 char xpath_entry
[XPATH_MAXLEN
+ 32];
489 /* If the user provided sequence number, then just go for it. */
490 if (seq_str
!= NULL
) {
492 xpath
, sizeof(xpath
),
493 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
495 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
496 return nb_cli_apply_changes(vty
, NULL
);
499 /* Otherwise, to keep compatibility, we need to figure it out. */
500 snprintf(xpath
, sizeof(xpath
),
501 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
503 /* Access-list must exist before entries. */
504 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
507 /* Use access-list data structure to fetch sequence. */
508 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
509 acl
= nb_running_get_entry(dnode
, NULL
, true);
510 if (prefix_str
== NULL
) {
511 memset(&pany
, 0, sizeof(pany
));
512 pany
.family
= AF_INET
;
513 sseq
= acl_zebra_get_seq(acl
, action
, &pany
, exact
);
515 sseq
= acl_zebra_get_seq(acl
, action
, (struct prefix
*)prefix
,
520 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
521 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
522 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
524 return nb_cli_apply_changes(vty
, NULL
);
528 no_access_list_all
, no_access_list_all_cmd
,
529 "no access-list WORD$name",
532 ACCESS_LIST_ZEBRA_STR
)
534 char xpath
[XPATH_MAXLEN
];
536 snprintf(xpath
, sizeof(xpath
),
537 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
538 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
540 return nb_cli_apply_changes(vty
, NULL
);
544 access_list_remark
, access_list_remark_cmd
,
545 "access-list WORD$name remark LINE...",
547 ACCESS_LIST_ZEBRA_STR
548 ACCESS_LIST_REMARK_STR
549 ACCESS_LIST_REMARK_LINE_STR
)
553 char xpath
[XPATH_MAXLEN
];
555 snprintf(xpath
, sizeof(xpath
),
556 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
557 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
559 remark
= argv_concat(argv
, argc
, 3);
560 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
561 rv
= nb_cli_apply_changes(vty
, xpath
);
562 XFREE(MTYPE_TMP
, remark
);
568 no_access_list_remark
, no_access_list_remark_cmd
,
569 "no access-list WORD$name remark",
572 ACCESS_LIST_ZEBRA_STR
573 ACCESS_LIST_REMARK_STR
)
575 char xpath
[XPATH_MAXLEN
];
577 snprintf(xpath
, sizeof(xpath
),
578 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
580 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
582 return nb_cli_apply_changes(vty
, NULL
);
586 no_access_list_remark
, no_access_list_remark_line_cmd
,
587 "no access-list WORD$name remark LINE...",
590 ACCESS_LIST_ZEBRA_STR
591 ACCESS_LIST_REMARK_STR
592 ACCESS_LIST_REMARK_LINE_STR
)
595 ipv6_access_list
, ipv6_access_list_cmd
,
596 "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
599 ACCESS_LIST_ZEBRA_STR
601 ACCESS_LIST_ACTION_STR
603 "Exact match of the prefixes\n"
607 char xpath
[XPATH_MAXLEN
];
608 char xpath_entry
[XPATH_MAXLEN
+ 128];
611 * Create the access-list first, so we can generate sequence if
612 * none given (backward compatibility).
614 snprintf(xpath
, sizeof(xpath
),
615 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
616 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
617 if (seq_str
== NULL
) {
618 /* Use XPath to find the next sequence number. */
619 sseq
= acl_get_seq(vty
, xpath
);
620 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
621 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
623 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
624 "%s/entry[sequence='%s']", xpath
, seq_str
);
626 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
628 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
629 if (prefix_str
!= NULL
) {
630 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
632 nb_cli_enqueue_change(vty
, "./ipv6-exact-match", NB_OP_MODIFY
,
633 exact
? "true" : "false");
635 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
638 return nb_cli_apply_changes(vty
, xpath_entry
);
642 no_ipv6_access_list
, no_ipv6_access_list_cmd
,
643 "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
647 ACCESS_LIST_ZEBRA_STR
649 ACCESS_LIST_ACTION_STR
651 "Exact match of the prefixes\n"
654 struct access_list
*acl
;
655 struct lyd_node
*dnode
;
658 char xpath
[XPATH_MAXLEN
];
659 char xpath_entry
[XPATH_MAXLEN
+ 32];
661 /* If the user provided sequence number, then just go for it. */
662 if (seq_str
!= NULL
) {
664 xpath
, sizeof(xpath
),
665 "/frr-filter:lib/access-list[type='ipv6'][name='%s']/entry[sequence='%s']",
667 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
668 return nb_cli_apply_changes(vty
, NULL
);
671 /* Otherwise, to keep compatibility, we need to figure it out. */
672 snprintf(xpath
, sizeof(xpath
),
673 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
675 /* Access-list must exist before entries. */
676 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
679 /* Use access-list data structure to fetch sequence. */
680 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
681 acl
= nb_running_get_entry(dnode
, NULL
, true);
682 if (prefix
== NULL
) {
683 memset(&pany
, 0, sizeof(pany
));
684 pany
.family
= AF_INET6
;
685 sseq
= acl_zebra_get_seq(acl
, action
, &pany
, exact
);
687 sseq
= acl_zebra_get_seq(acl
, action
, (struct prefix
*)prefix
,
692 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
693 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
694 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
696 return nb_cli_apply_changes(vty
, NULL
);
700 no_ipv6_access_list_all
, no_ipv6_access_list_all_cmd
,
701 "no ipv6 access-list WORD$name",
705 ACCESS_LIST_ZEBRA_STR
)
707 char xpath
[XPATH_MAXLEN
];
709 snprintf(xpath
, sizeof(xpath
),
710 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
711 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
713 return nb_cli_apply_changes(vty
, NULL
);
717 ipv6_access_list_remark
, ipv6_access_list_remark_cmd
,
718 "ipv6 access-list WORD$name remark LINE...",
721 ACCESS_LIST_ZEBRA_STR
722 ACCESS_LIST_REMARK_STR
723 ACCESS_LIST_REMARK_LINE_STR
)
727 char xpath
[XPATH_MAXLEN
];
729 snprintf(xpath
, sizeof(xpath
),
730 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
731 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
733 remark
= argv_concat(argv
, argc
, 4);
734 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
735 rv
= nb_cli_apply_changes(vty
, xpath
);
736 XFREE(MTYPE_TMP
, remark
);
742 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_cmd
,
743 "no ipv6 access-list WORD$name remark",
747 ACCESS_LIST_ZEBRA_STR
748 ACCESS_LIST_REMARK_STR
)
750 char xpath
[XPATH_MAXLEN
];
752 snprintf(xpath
, sizeof(xpath
),
753 "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
755 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
757 return nb_cli_apply_changes(vty
, NULL
);
761 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_line_cmd
,
762 "no ipv6 access-list WORD$name remark LINE...",
766 ACCESS_LIST_ZEBRA_STR
767 ACCESS_LIST_REMARK_STR
768 ACCESS_LIST_REMARK_LINE_STR
)
771 mac_access_list
, mac_access_list_cmd
,
772 "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
775 ACCESS_LIST_ZEBRA_STR
777 ACCESS_LIST_ACTION_STR
779 "Match any MAC address\n")
782 char xpath
[XPATH_MAXLEN
];
783 char xpath_entry
[XPATH_MAXLEN
+ 128];
786 * Create the access-list first, so we can generate sequence if
787 * none given (backward compatibility).
789 snprintf(xpath
, sizeof(xpath
),
790 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
791 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
792 if (seq_str
== NULL
) {
793 /* Use XPath to find the next sequence number. */
794 sseq
= acl_get_seq(vty
, xpath
);
795 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
796 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
798 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
799 "%s/entry[sequence='%s']", xpath
, seq_str
);
801 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
803 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
804 if (mac_str
!= NULL
) {
805 nb_cli_enqueue_change(vty
, "./mac", NB_OP_MODIFY
, mac_str
);
807 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
810 return nb_cli_apply_changes(vty
, xpath_entry
);
814 no_mac_access_list
, no_mac_access_list_cmd
,
815 "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$prefix|any>",
819 ACCESS_LIST_ZEBRA_STR
821 ACCESS_LIST_ACTION_STR
823 "Match any MAC address\n")
825 struct access_list
*acl
;
826 struct lyd_node
*dnode
;
829 char xpath
[XPATH_MAXLEN
];
830 char xpath_entry
[XPATH_MAXLEN
+ 32];
832 /* If the user provided sequence number, then just go for it. */
833 if (seq_str
!= NULL
) {
835 xpath
, sizeof(xpath
),
836 "/frr-filter:lib/access-list[type='mac'][name='%s']/entry[sequence='%s']",
838 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
839 return nb_cli_apply_changes(vty
, NULL
);
842 /* Otherwise, to keep compatibility, we need to figure it out. */
843 snprintf(xpath
, sizeof(xpath
),
844 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
846 /* Access-list must exist before entries. */
847 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
850 /* Use access-list data structure to fetch sequence. */
851 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
852 acl
= nb_running_get_entry(dnode
, NULL
, true);
853 if (prefix
== NULL
) {
854 memset(&pany
, 0, sizeof(pany
));
855 pany
.family
= AF_ETHERNET
;
856 sseq
= acl_zebra_get_seq(acl
, action
, &pany
, false);
858 sseq
= acl_zebra_get_seq(acl
, action
, (struct prefix
*)prefix
,
863 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
864 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
865 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
867 return nb_cli_apply_changes(vty
, NULL
);
871 no_mac_access_list_all
, no_mac_access_list_all_cmd
,
872 "no mac access-list WORD$name",
876 ACCESS_LIST_ZEBRA_STR
)
878 char xpath
[XPATH_MAXLEN
];
880 snprintf(xpath
, sizeof(xpath
),
881 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
882 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
884 return nb_cli_apply_changes(vty
, NULL
);
888 mac_access_list_remark
, mac_access_list_remark_cmd
,
889 "mac access-list WORD$name remark LINE...",
892 ACCESS_LIST_ZEBRA_STR
893 ACCESS_LIST_REMARK_STR
894 ACCESS_LIST_REMARK_LINE_STR
)
898 char xpath
[XPATH_MAXLEN
];
900 snprintf(xpath
, sizeof(xpath
),
901 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
902 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
904 remark
= argv_concat(argv
, argc
, 4);
905 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
906 rv
= nb_cli_apply_changes(vty
, xpath
);
907 XFREE(MTYPE_TMP
, remark
);
913 no_mac_access_list_remark
, no_mac_access_list_remark_cmd
,
914 "no mac access-list WORD$name remark",
918 ACCESS_LIST_ZEBRA_STR
919 ACCESS_LIST_REMARK_STR
)
921 char xpath
[XPATH_MAXLEN
];
923 snprintf(xpath
, sizeof(xpath
),
924 "/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
926 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
928 return nb_cli_apply_changes(vty
, NULL
);
932 no_mac_access_list_remark
, no_mac_access_list_remark_line_cmd
,
933 "no mac access-list WORD$name remark LINE...",
937 ACCESS_LIST_ZEBRA_STR
938 ACCESS_LIST_REMARK_STR
939 ACCESS_LIST_REMARK_LINE_STR
)
941 void access_list_show(struct vty
*vty
, struct lyd_node
*dnode
,
944 int type
= yang_dnode_get_enum(dnode
, "../type");
947 bool is_exact
= false;
948 bool cisco_style
= false;
949 bool cisco_extended
= false;
951 char macstr
[PREFIX2STR_BUFFER
];
953 is_any
= yang_dnode_exists(dnode
, "./any");
959 if (yang_dnode_exists(dnode
, "./host")
960 || yang_dnode_exists(dnode
, "./network")
961 || yang_dnode_exists(dnode
, "./source-any")) {
963 if (yang_dnode_exists(dnode
, "./destination-host")
964 || yang_dnode_exists(dnode
, "./destination-network")
965 || yang_dnode_exists(dnode
, "./destination-any"))
966 cisco_extended
= true;
968 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
969 is_exact
= yang_dnode_get_bool(dnode
,
970 "./ipv4-exact-match");
973 case YALT_IPV6
: /* ipv6 */
974 vty_out(vty
, "ipv6 ");
978 yang_dnode_get_prefix(&p
, dnode
, "./ipv6-prefix");
979 is_exact
= yang_dnode_get_bool(dnode
, "./ipv6-exact-match");
981 case YALT_MAC
: /* mac */
982 vty_out(vty
, "mac ");
986 yang_dnode_get_prefix(&p
, dnode
, "./mac");
990 vty_out(vty
, "access-list %s seq %s %s",
991 yang_dnode_get_string(dnode
, "../name"),
992 yang_dnode_get_string(dnode
, "./sequence"),
993 yang_dnode_get_string(dnode
, "./action"));
995 /* Handle Cisco style access lists. */
1000 if (yang_dnode_exists(dnode
, "./network")) {
1001 yang_dnode_get_prefix(&p
, dnode
, "./network");
1002 masklen2ip(p
.prefixlen
, &mask
);
1003 vty_out(vty
, " %pI4 %pI4", &p
.u
.prefix4
, &mask
);
1004 } else if (yang_dnode_exists(dnode
, "./host")) {
1006 vty_out(vty
, " host");
1009 yang_dnode_get_string(dnode
, "./host"));
1010 } else if (yang_dnode_exists(dnode
, "./source-any"))
1011 vty_out(vty
, " any");
1013 /* Not extended, exit earlier. */
1014 if (!cisco_extended
) {
1019 /* Handle destination address. */
1020 if (yang_dnode_exists(dnode
, "./destination-network")) {
1021 yang_dnode_get_prefix(&p
, dnode
,
1022 "./destination-network");
1023 masklen2ip(p
.prefixlen
, &mask
);
1024 vty_out(vty
, " %pI4 %pI4", &p
.u
.prefix4
, &mask
);
1025 } else if (yang_dnode_exists(dnode
, "./destination-host"))
1026 vty_out(vty
, " host %s",
1027 yang_dnode_get_string(dnode
,
1028 "./destination-host"));
1029 else if (yang_dnode_exists(dnode
, "./destination-any"))
1030 vty_out(vty
, " any");
1036 /* Zebra style access list. */
1038 /* If type is MAC don't show '/mask'. */
1039 if (type
== 2 /* mac */) {
1040 prefix_mac2str(&p
.u
.prefix_eth
, macstr
, sizeof(macstr
));
1041 vty_out(vty
, " %s", macstr
);
1043 vty_out(vty
, " %pFX", &p
);
1045 vty_out(vty
, " any");
1048 vty_out(vty
, " exact-match");
1053 void access_list_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
1056 int type
= yang_dnode_get_enum(dnode
, "../type");
1062 vty_out(vty
, "ipv6 ");
1065 vty_out(vty
, "mac ");
1069 vty_out(vty
, "access-list %s remark %s\n",
1070 yang_dnode_get_string(dnode
, "../name"),
1071 yang_dnode_get_string(dnode
, NULL
));
1079 * Remove main data structure prefix list if there are no more entries or
1080 * remark. This fixes compatibility with old CLI and tests.
1082 static int plist_remove_if_empty(struct vty
*vty
, const char *iptype
,
1085 char xpath
[XPATH_MAXLEN
];
1087 snprintf(xpath
, sizeof(xpath
),
1088 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark",
1090 /* List is not empty if there is a remark, check that: */
1091 if (yang_dnode_exists(vty
->candidate_config
->dnode
, xpath
))
1094 /* Check if we have any entries: */
1095 snprintf(xpath
, sizeof(xpath
),
1096 "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype
,
1099 * NOTE: if the list is empty it will return the first sequence
1102 if (acl_get_seq(vty
, xpath
) != 5)
1105 /* Nobody is using this list, lets remove it. */
1106 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1107 return nb_cli_apply_changes(vty
, NULL
);
1110 static int plist_remove(struct vty
*vty
, const char *iptype
, const char *name
,
1111 const char *seq
, const char *action
, struct prefix
*p
,
1114 struct prefix_list_entry
*pentry
;
1115 enum prefix_list_type plt
;
1116 struct prefix_list
*pl
;
1117 struct lyd_node
*dnode
;
1118 char xpath
[XPATH_MAXLEN
];
1119 char xpath_entry
[XPATH_MAXLEN
+ 32];
1122 /* If the user provided sequence number, then just go for it. */
1125 xpath
, sizeof(xpath
),
1126 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
1128 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1130 rv
= nb_cli_apply_changes(vty
, NULL
);
1131 if (rv
== CMD_SUCCESS
)
1132 return plist_remove_if_empty(vty
, iptype
, name
);
1137 /* Otherwise, to keep compatibility, we need to figure it out. */
1138 snprintf(xpath
, sizeof(xpath
),
1139 "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype
,
1142 /* Access-list must exist before entries. */
1143 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
1146 /* Use access-list data structure to fetch sequence. */
1147 assert(action
!= NULL
);
1148 if (strcmp(action
, "permit") == 0)
1149 plt
= PREFIX_PERMIT
;
1153 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
1154 pl
= nb_running_get_entry(dnode
, NULL
, true);
1155 pentry
= prefix_list_entry_lookup(pl
, p
, plt
, -1, le
, ge
);
1159 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1160 "%s/entry[sequence='%" PRId64
"']", xpath
, pentry
->seq
);
1161 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
1163 rv
= nb_cli_apply_changes(vty
, NULL
);
1164 if (rv
== CMD_SUCCESS
)
1165 return plist_remove_if_empty(vty
, iptype
, name
);
1171 ip_prefix_list
, ip_prefix_list_cmd
,
1172 "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}]>",
1175 PREFIX_LIST_NAME_STR
1177 ACCESS_LIST_ACTION_STR
1178 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1179 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1180 "Minimum prefix length to be matched\n"
1181 "Minimum prefix length\n"
1182 "Maximum prefix length to be matched\n"
1183 "Maximum prefix length\n")
1186 char xpath
[XPATH_MAXLEN
];
1187 char xpath_entry
[XPATH_MAXLEN
+ 128];
1190 * Create the prefix-list first, so we can generate sequence if
1191 * none given (backward compatibility).
1193 snprintf(xpath
, sizeof(xpath
),
1194 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1195 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1196 if (seq_str
== NULL
) {
1197 /* Use XPath to find the next sequence number. */
1198 sseq
= acl_get_seq(vty
, xpath
);
1199 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1200 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1202 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1203 "%s/entry[sequence='%s']", xpath
, seq_str
);
1205 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1207 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1208 if (prefix_str
!= NULL
) {
1209 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
1213 nb_cli_enqueue_change(
1214 vty
, "./ipv4-prefix-length-greater-or-equal",
1215 NB_OP_MODIFY
, ge_str
);
1217 nb_cli_enqueue_change(
1218 vty
, "./ipv4-prefix-length-lesser-or-equal",
1219 NB_OP_MODIFY
, le_str
);
1221 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1224 return nb_cli_apply_changes(vty
, xpath_entry
);
1228 no_ip_prefix_list
, no_ip_prefix_list_cmd
,
1229 "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)}]>",
1233 PREFIX_LIST_NAME_STR
1235 ACCESS_LIST_ACTION_STR
1236 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1237 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1238 "Minimum prefix length to be matched\n"
1239 "Minimum prefix length\n"
1240 "Maximum prefix length to be matched\n"
1241 "Maximum prefix length\n")
1243 return plist_remove(vty
, "ipv4", name
, seq_str
, action
,
1244 (struct prefix
*)prefix
, ge
, le
);
1248 no_ip_prefix_list_seq
, no_ip_prefix_list_seq_cmd
,
1249 "no ip prefix-list WORD$name seq (1-4294967295)$seq",
1253 PREFIX_LIST_NAME_STR
1254 ACCESS_LIST_SEQ_STR
)
1256 return plist_remove(vty
, "ipv4", name
, seq_str
, NULL
, NULL
, 0, 0);
1260 no_ip_prefix_list_all
, no_ip_prefix_list_all_cmd
,
1261 "no ip prefix-list WORD$name",
1265 PREFIX_LIST_NAME_STR
)
1267 char xpath
[XPATH_MAXLEN
];
1269 snprintf(xpath
, sizeof(xpath
),
1270 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1271 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1273 return nb_cli_apply_changes(vty
, NULL
);
1277 ip_prefix_list_remark
, ip_prefix_list_remark_cmd
,
1278 "ip prefix-list WORD$name description LINE...",
1281 PREFIX_LIST_NAME_STR
1282 ACCESS_LIST_REMARK_STR
1283 ACCESS_LIST_REMARK_LINE_STR
)
1287 char xpath
[XPATH_MAXLEN
];
1289 snprintf(xpath
, sizeof(xpath
),
1290 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1291 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1293 remark
= argv_concat(argv
, argc
, 4);
1294 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1295 rv
= nb_cli_apply_changes(vty
, xpath
);
1296 XFREE(MTYPE_TMP
, remark
);
1302 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_cmd
,
1303 "no ip prefix-list WORD$name description",
1307 PREFIX_LIST_NAME_STR
1308 ACCESS_LIST_REMARK_STR
)
1310 char xpath
[XPATH_MAXLEN
];
1312 snprintf(xpath
, sizeof(xpath
),
1313 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
1315 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1317 return nb_cli_apply_changes(vty
, NULL
);
1321 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_line_cmd
,
1322 "no ip prefix-list WORD$name description LINE...",
1326 PREFIX_LIST_NAME_STR
1327 ACCESS_LIST_REMARK_STR
1328 ACCESS_LIST_REMARK_LINE_STR
)
1331 ipv6_prefix_list
, ipv6_prefix_list_cmd
,
1332 "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}]>",
1335 PREFIX_LIST_NAME_STR
1337 ACCESS_LIST_ACTION_STR
1338 "Any prefix match. Same as \"::0/0 le 128\"\n"
1339 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1340 "Maximum prefix length to be matched\n"
1341 "Maximum prefix length\n"
1342 "Minimum prefix length to be matched\n"
1343 "Minimum prefix length\n")
1346 char xpath
[XPATH_MAXLEN
];
1347 char xpath_entry
[XPATH_MAXLEN
+ 128];
1350 * Create the prefix-list first, so we can generate sequence if
1351 * none given (backward compatibility).
1353 snprintf(xpath
, sizeof(xpath
),
1354 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1355 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1356 if (seq_str
== NULL
) {
1357 /* Use XPath to find the next sequence number. */
1358 sseq
= acl_get_seq(vty
, xpath
);
1359 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1360 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1362 snprintfrr(xpath_entry
, sizeof(xpath_entry
),
1363 "%s/entry[sequence='%s']", xpath
, seq_str
);
1365 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1367 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1368 if (prefix_str
!= NULL
) {
1369 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
1373 nb_cli_enqueue_change(
1374 vty
, "./ipv6-prefix-length-greater-or-equal",
1375 NB_OP_MODIFY
, ge_str
);
1377 nb_cli_enqueue_change(
1378 vty
, "./ipv6-prefix-length-lesser-or-equal",
1379 NB_OP_MODIFY
, le_str
);
1381 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1384 return nb_cli_apply_changes(vty
, xpath_entry
);
1388 no_ipv6_prefix_list
, no_ipv6_prefix_list_cmd
,
1389 "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}]>",
1393 PREFIX_LIST_NAME_STR
1395 ACCESS_LIST_ACTION_STR
1396 "Any prefix match. Same as \"::0/0 le 128\"\n"
1397 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1398 "Maximum prefix length to be matched\n"
1399 "Maximum prefix length\n"
1400 "Minimum prefix length to be matched\n"
1401 "Minimum prefix length\n")
1403 return plist_remove(vty
, "ipv6", name
, seq_str
, action
,
1404 (struct prefix
*)prefix
, ge
, le
);
1408 no_ipv6_prefix_list_seq
, no_ipv6_prefix_list_seq_cmd
,
1409 "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
1413 PREFIX_LIST_NAME_STR
1414 ACCESS_LIST_SEQ_STR
)
1416 return plist_remove(vty
, "ipv6", name
, seq_str
, NULL
, NULL
, 0, 0);
1420 no_ipv6_prefix_list_all
, no_ipv6_prefix_list_all_cmd
,
1421 "no ipv6 prefix-list WORD$name",
1425 PREFIX_LIST_NAME_STR
)
1427 char xpath
[XPATH_MAXLEN
];
1429 snprintf(xpath
, sizeof(xpath
),
1430 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1431 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1433 return nb_cli_apply_changes(vty
, NULL
);
1437 ipv6_prefix_list_remark
, ipv6_prefix_list_remark_cmd
,
1438 "ipv6 prefix-list WORD$name description LINE...",
1441 PREFIX_LIST_NAME_STR
1442 ACCESS_LIST_REMARK_STR
1443 ACCESS_LIST_REMARK_LINE_STR
)
1447 char xpath
[XPATH_MAXLEN
];
1449 snprintf(xpath
, sizeof(xpath
),
1450 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1451 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1453 remark
= argv_concat(argv
, argc
, 4);
1454 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1455 rv
= nb_cli_apply_changes(vty
, xpath
);
1456 XFREE(MTYPE_TMP
, remark
);
1462 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_cmd
,
1463 "no ipv6 prefix-list WORD$name description",
1467 PREFIX_LIST_NAME_STR
1468 ACCESS_LIST_REMARK_STR
)
1470 char xpath
[XPATH_MAXLEN
];
1472 snprintf(xpath
, sizeof(xpath
),
1473 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
1475 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1477 return nb_cli_apply_changes(vty
, NULL
);
1481 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_line_cmd
,
1482 "no ipv6 prefix-list WORD$name description LINE...",
1486 PREFIX_LIST_NAME_STR
1487 ACCESS_LIST_REMARK_STR
1488 ACCESS_LIST_REMARK_LINE_STR
)
1490 void prefix_list_show(struct vty
*vty
, struct lyd_node
*dnode
,
1493 int type
= yang_dnode_get_enum(dnode
, "../type");
1494 const char *ge_str
= NULL
, *le_str
= NULL
;
1498 is_any
= yang_dnode_exists(dnode
, "./any");
1502 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1503 if (yang_dnode_exists(dnode
,
1504 "./ipv4-prefix-length-greater-or-equal"))
1505 ge_str
= yang_dnode_get_string(
1506 dnode
, "./ipv4-prefix-length-greater-or-equal");
1507 if (yang_dnode_exists(dnode
,
1508 "./ipv4-prefix-length-lesser-or-equal"))
1509 le_str
= yang_dnode_get_string(
1510 dnode
, "./ipv4-prefix-length-lesser-or-equal");
1512 vty_out(vty
, "ip ");
1516 yang_dnode_get_prefix(&p
, dnode
, "ipv6-prefix");
1517 if (yang_dnode_exists(dnode
,
1518 "./ipv6-prefix-length-greater-or-equal"))
1519 ge_str
= yang_dnode_get_string(
1520 dnode
, "./ipv6-prefix-length-greater-or-equal");
1521 if (yang_dnode_exists(dnode
,
1522 "./ipv6-prefix-length-lesser-or-equal"))
1523 le_str
= yang_dnode_get_string(
1524 dnode
, "./ipv6-prefix-length-lesser-or-equal");
1526 vty_out(vty
, "ipv6 ");
1530 vty_out(vty
, "prefix-list %s seq %s %s",
1531 yang_dnode_get_string(dnode
, "../name"),
1532 yang_dnode_get_string(dnode
, "./sequence"),
1533 yang_dnode_get_string(dnode
, "./action"));
1536 vty_out(vty
, " any\n");
1540 vty_out(vty
, " %pFX", &p
);
1542 vty_out(vty
, " ge %s", ge_str
);
1544 vty_out(vty
, " le %s", le_str
);
1549 void prefix_list_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
1552 int type
= yang_dnode_get_enum(dnode
, "../type");
1556 vty_out(vty
, "ip ");
1559 vty_out(vty
, "ipv6 ");
1563 vty_out(vty
, "prefix-list %s description %s\n",
1564 yang_dnode_get_string(dnode
, "../name"),
1565 yang_dnode_get_string(dnode
, NULL
));
1568 void filter_cli_init(void)
1570 /* access-list cisco-style (legacy). */
1571 install_element(CONFIG_NODE
, &access_list_std_cmd
);
1572 install_element(CONFIG_NODE
, &no_access_list_std_cmd
);
1573 install_element(CONFIG_NODE
, &access_list_ext_cmd
);
1574 install_element(CONFIG_NODE
, &no_access_list_ext_cmd
);
1576 /* access-list zebra-style. */
1577 install_element(CONFIG_NODE
, &access_list_cmd
);
1578 install_element(CONFIG_NODE
, &no_access_list_cmd
);
1579 install_element(CONFIG_NODE
, &no_access_list_all_cmd
);
1580 install_element(CONFIG_NODE
, &access_list_remark_cmd
);
1581 install_element(CONFIG_NODE
, &no_access_list_remark_cmd
);
1582 install_element(CONFIG_NODE
, &no_access_list_remark_line_cmd
);
1584 install_element(CONFIG_NODE
, &ipv6_access_list_cmd
);
1585 install_element(CONFIG_NODE
, &no_ipv6_access_list_cmd
);
1586 install_element(CONFIG_NODE
, &no_ipv6_access_list_all_cmd
);
1587 install_element(CONFIG_NODE
, &ipv6_access_list_remark_cmd
);
1588 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_cmd
);
1589 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_line_cmd
);
1591 install_element(CONFIG_NODE
, &mac_access_list_cmd
);
1592 install_element(CONFIG_NODE
, &no_mac_access_list_cmd
);
1593 install_element(CONFIG_NODE
, &no_mac_access_list_all_cmd
);
1594 install_element(CONFIG_NODE
, &mac_access_list_remark_cmd
);
1595 install_element(CONFIG_NODE
, &no_mac_access_list_remark_cmd
);
1596 install_element(CONFIG_NODE
, &no_mac_access_list_remark_line_cmd
);
1599 install_element(CONFIG_NODE
, &ip_prefix_list_cmd
);
1600 install_element(CONFIG_NODE
, &no_ip_prefix_list_cmd
);
1601 install_element(CONFIG_NODE
, &no_ip_prefix_list_seq_cmd
);
1602 install_element(CONFIG_NODE
, &no_ip_prefix_list_all_cmd
);
1603 install_element(CONFIG_NODE
, &ip_prefix_list_remark_cmd
);
1604 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_cmd
);
1605 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_line_cmd
);
1607 install_element(CONFIG_NODE
, &ipv6_prefix_list_cmd
);
1608 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_cmd
);
1609 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_seq_cmd
);
1610 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_all_cmd
);
1611 install_element(CONFIG_NODE
, &ipv6_prefix_list_remark_cmd
);
1612 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_cmd
);
1613 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_line_cmd
);