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
23 #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"
33 #ifndef VTYSH_EXTRACT_PL
34 #include "lib/filter_cli_clippy.c"
35 #endif /* VTYSH_EXTRACT_PL */
37 #define ACCESS_LIST_STR "Access list entry\n"
38 #define ACCESS_LIST_LEG_STR "IP standard access list\n"
39 #define ACCESS_LIST_LEG_EXT_STR "IP standard access list (expanded range)\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_XLEG_STR \
44 ACCESS_LIST_LEG_EXT_STR \
45 ACCESS_LIST_ELEG_STR \
46 ACCESS_LIST_ELEG_EXT_STR
47 #define ACCESS_LIST_ZEBRA_STR "Access list entry\n"
48 #define ACCESS_LIST_SEQ_STR \
49 "Sequence number of an entry\n" \
51 #define ACCESS_LIST_ACTION_STR \
52 "Specify packets to reject\n" \
53 "Specify packets to forward\n"
54 #define ACCESS_LIST_REMARK_STR "Access list entry comment\n"
55 #define ACCESS_LIST_REMARK_LINE_STR "Comment up to 100 characters\n"
57 #define PREFIX_LIST_NAME_STR "Prefix list entry name\n"
60 * Helper function to locate filter data structures for Cisco-style ACLs.
62 static int64_t acl_cisco_get_seq(struct access_list
*acl
, const char *action
,
63 const char *src
, const char *src_mask
,
64 const char *dst
, const char *dst_mask
)
66 struct filter_cisco
*fc
;
69 memset(&f
, 0, sizeof(f
));
70 memset(&fc
, 0, sizeof(fc
));
72 if (strcmp(action
, "permit") == 0)
73 f
.type
= FILTER_PERMIT
;
78 inet_pton(AF_INET
, src
, &fc
->addr
);
79 inet_pton(AF_INET
, src_mask
, &fc
->addr_mask
);
80 fc
->addr
.s_addr
&= ~fc
->addr_mask
.s_addr
;
83 inet_pton(AF_INET
, dst
, &fc
->mask
);
84 inet_pton(AF_INET
, dst_mask
, &fc
->mask_mask
);
85 fc
->mask
.s_addr
&= ~fc
->mask_mask
.s_addr
;
88 fn
= filter_lookup_cisco(acl
, &f
);
96 * Helper function to locate filter data structures for zebra-style ACLs.
98 static int64_t acl_zebra_get_seq(struct access_list
*acl
, const char *action
,
99 const struct prefix
*p
, bool exact
)
101 struct filter_zebra
*fz
;
102 struct filter f
, *fn
;
104 memset(&f
, 0, sizeof(f
));
105 memset(&fz
, 0, sizeof(fz
));
106 if (strcmp(action
, "permit") == 0)
107 f
.type
= FILTER_PERMIT
;
109 f
.type
= FILTER_DENY
;
115 fn
= filter_lookup_zebra(acl
, &f
);
123 * Helper function to concatenate address with mask in Cisco style.
125 static void concat_addr_mask_v4(const char *addr
, const char *mask
, char *dst
,
131 assert(inet_pton(AF_INET
, mask
, &ia
) == 1);
132 plen
= ip_masklen(ia
);
133 snprintf(dst
, dstlen
, "%s/%d", addr
, plen
);
137 * Helper function to generate a sequence number for legacy commands.
139 static int acl_get_seq_cb(const struct lyd_node
*dnode
, void *arg
)
142 int64_t cur_seq
= yang_dnode_get_uint32(dnode
, "sequence");
147 return YANG_ITER_CONTINUE
;
151 * Helper function that iterates over the XPath `xpath` on the candidate
152 * configuration in `vty->candidate_config`.
154 * \param[in] vty shell context with the candidate configuration.
155 * \param[in] xpath the XPath to look for the sequence leaf.
156 * \returns next unused sequence number.
158 static long acl_get_seq(struct vty
*vty
, const char *xpath
)
162 yang_dnode_iterate(acl_get_seq_cb
, &seq
, vty
->candidate_config
->dnode
,
169 * Cisco (legacy) access lists.
172 access_list_std
, access_list_std_cmd
,
173 "access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
176 ACCESS_LIST_LEG_EXT_STR
178 ACCESS_LIST_ACTION_STR
179 "A single host address\n"
187 char xpath
[XPATH_MAXLEN
];
188 char xpath_entry
[XPATH_MAXLEN
+ 128];
191 * Create the access-list first, so we can generate sequence if
192 * none given (backward compatibility).
194 snprintf(xpath
, sizeof(xpath
),
195 "/frr-filter:lib/access-list-legacy[number='%s']", number_str
);
196 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
197 if (seq_str
== NULL
) {
198 /* Use XPath to find the next sequence number. */
199 sseq
= acl_get_seq(vty
, xpath
);
200 snprintf(xpath_entry
, sizeof(xpath_entry
),
201 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
203 snprintf(xpath_entry
, sizeof(xpath_entry
),
204 "%s/entry[sequence='%s']", xpath
, seq_str
);
206 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
208 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
209 if (host_str
!= NULL
&& mask_str
== NULL
) {
210 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, host_str
);
211 } else if (host_str
!= NULL
&& mask_str
!= NULL
) {
212 concat_addr_mask_v4(host_str
, mask_str
, ipmask
, sizeof(ipmask
));
213 nb_cli_enqueue_change(vty
, "./network", NB_OP_MODIFY
, ipmask
);
215 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
218 return nb_cli_apply_changes(vty
, xpath_entry
);
222 no_access_list_std
, no_access_list_std_cmd
,
223 "no access-list <(1-99)|(1300-1999)>$number [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask|any>",
227 ACCESS_LIST_LEG_EXT_STR
229 ACCESS_LIST_ACTION_STR
230 "A single host address\n"
236 struct access_list
*acl
;
237 struct lyd_node
*dnode
;
239 char xpath
[XPATH_MAXLEN
];
240 char xpath_entry
[XPATH_MAXLEN
+ 32];
242 /* If the user provided sequence number, then just go for it. */
243 if (seq_str
!= NULL
) {
245 xpath
, sizeof(xpath
),
246 "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']",
247 number_str
, seq_str
);
248 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
249 return nb_cli_apply_changes(vty
, NULL
);
252 /* Otherwise, to keep compatibility, we need to figure it out. */
253 snprintf(xpath
, sizeof(xpath
),
254 "/frr-filter:lib/access-list-legacy[number='%s']", number_str
);
256 /* Access-list must exist before entries. */
257 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
260 /* Use access-list data structure to fetch sequence. */
261 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
262 acl
= nb_running_get_entry(dnode
, NULL
, true);
263 if (host_str
!= NULL
)
264 sseq
= acl_cisco_get_seq(acl
, action
, host_str
,
265 mask_str
? mask_str
: "0.0.0.0", NULL
,
268 sseq
= acl_cisco_get_seq(acl
, action
, "0.0.0.0",
269 "255.255.255.255", NULL
, NULL
);
273 snprintf(xpath_entry
, sizeof(xpath_entry
),
274 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
275 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
277 return nb_cli_apply_changes(vty
, NULL
);
281 access_list_ext
, access_list_ext_cmd
,
282 "access-list <(100-199)|(2000-2699)>$number [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>",
285 ACCESS_LIST_ELEG_EXT_STR
287 ACCESS_LIST_ACTION_STR
289 "Source address to match\n"
290 "Source address mask to apply\n"
291 "Single source host\n"
292 "Source address to match\n"
294 "Destination address to match\n"
295 "Destination address mask to apply\n"
296 "Single destination host\n"
297 "Destination address to match\n"
298 "Any destination host\n")
302 char xpath
[XPATH_MAXLEN
];
303 char xpath_entry
[XPATH_MAXLEN
+ 128];
306 * Create the access-list first, so we can generate sequence if
307 * none given (backward compatibility).
309 snprintf(xpath
, sizeof(xpath
),
310 "/frr-filter:lib/access-list-legacy[number='%s']", number_str
);
311 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
312 if (seq_str
== NULL
) {
313 /* Use XPath to find the next sequence number. */
314 sseq
= acl_get_seq(vty
, xpath
);
315 snprintf(xpath_entry
, sizeof(xpath_entry
),
316 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
318 snprintf(xpath_entry
, sizeof(xpath_entry
),
319 "%s/entry[sequence='%s']", xpath
, seq_str
);
321 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
323 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
324 if (src_str
!= NULL
&& src_mask_str
== NULL
) {
325 nb_cli_enqueue_change(vty
, "./host", NB_OP_MODIFY
, src_str
);
326 } else if (src_str
!= NULL
&& src_mask_str
!= NULL
) {
327 concat_addr_mask_v4(src_str
, src_mask_str
, ipmask
,
329 nb_cli_enqueue_change(vty
, "./network", NB_OP_MODIFY
, ipmask
);
331 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
334 if (dst_str
!= NULL
&& dst_mask_str
== NULL
) {
335 nb_cli_enqueue_change(vty
, "./destination-host", NB_OP_MODIFY
,
337 } else if (dst_str
!= NULL
&& dst_mask_str
!= NULL
) {
338 concat_addr_mask_v4(dst_str
, dst_mask_str
, ipmask
,
340 nb_cli_enqueue_change(vty
, "./destination-network",
341 NB_OP_MODIFY
, ipmask
);
343 nb_cli_enqueue_change(vty
, "./destination-any", NB_OP_CREATE
,
347 return nb_cli_apply_changes(vty
, xpath_entry
);
351 no_access_list_ext
, no_access_list_ext_cmd
,
352 "no access-list <(100-199)|(2000-2699)>$number [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>",
356 ACCESS_LIST_ELEG_EXT_STR
358 ACCESS_LIST_ACTION_STR
359 "Any Internet Protocol\n"
360 "Source address to match\n"
361 "Source address mask to apply\n"
362 "Single source host\n"
363 "Source address to match\n"
365 "Destination address to match\n"
366 "Destination address mask to apply\n"
367 "Single destination host\n"
368 "Destination address to match\n"
369 "Any destination host\n")
371 struct access_list
*acl
;
372 struct lyd_node
*dnode
;
374 char xpath
[XPATH_MAXLEN
];
375 char xpath_entry
[XPATH_MAXLEN
+ 32];
377 /* If the user provided sequence number, then just go for it. */
378 if (seq_str
!= NULL
) {
380 xpath
, sizeof(xpath
),
381 "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']",
382 number_str
, seq_str
);
383 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
384 return nb_cli_apply_changes(vty
, NULL
);
387 /* Otherwise, to keep compatibility, we need to figure it out. */
388 snprintf(xpath
, sizeof(xpath
),
389 "/frr-filter:lib/access-list-legacy[number='%s']", number_str
);
391 /* Access-list must exist before entries. */
392 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
395 /* Use access-list data structure to fetch sequence. */
396 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
397 acl
= nb_running_get_entry(dnode
, NULL
, true);
398 if (src_str
!= NULL
) {
400 sseq
= acl_cisco_get_seq(
401 acl
, action
, src_str
,
402 src_mask_str
? src_mask_str
: "0.0.0.0",
404 dst_mask_str
? dst_mask_str
: "0.0.0.0");
406 sseq
= acl_cisco_get_seq(acl
, action
, src_str
,
407 src_mask_str
? src_mask_str
409 "0.0.0.0", "255.255.255.255");
412 sseq
= acl_cisco_get_seq(acl
, action
, "0.0.0.0",
413 "255.255.255.255", dst_str
,
414 dst_mask_str
? dst_mask_str
417 sseq
= acl_cisco_get_seq(acl
, action
, "0.0.0.0",
418 "255.255.255.255", "0.0.0.0",
424 snprintf(xpath_entry
, sizeof(xpath_entry
),
425 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
426 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
428 return nb_cli_apply_changes(vty
, NULL
);
432 no_access_list_legacy
, no_access_list_legacy_cmd
,
433 "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number",
436 ACCESS_LIST_XLEG_STR
)
438 char xpath
[XPATH_MAXLEN
];
440 snprintf(xpath
, sizeof(xpath
),
441 "/frr-filter:lib/access-list-legacy[number='%s']", number_str
);
442 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
444 return nb_cli_apply_changes(vty
, NULL
);
447 void access_list_legacy_show(struct vty
*vty
, struct lyd_node
*dnode
,
450 uint16_t number
= yang_dnode_get_uint16(dnode
, "../number");
455 vty_out(vty
, "access-list %d seq %s %s", number
,
456 yang_dnode_get_string(dnode
, "./sequence"),
457 yang_dnode_get_string(dnode
, "./action"));
459 extended
= (number
>= 100 && number
<= 199)
460 || (number
>= 2000 && number
<= 2699);
464 if (yang_dnode_exists(dnode
, "./network")) {
465 yang_dnode_get_prefix(&p
, dnode
, "./network");
466 masklen2ip(p
.prefixlen
, &mask
);
467 vty_out(vty
, " %pI4 %pI4", &p
.u
.prefix4
, &mask
);
468 } else if (yang_dnode_exists(dnode
, "./host")) {
470 vty_out(vty
, " host");
472 vty_out(vty
, " %s", yang_dnode_get_string(dnode
, "./host"));
473 } else if (yang_dnode_exists(dnode
, "./any"))
474 vty_out(vty
, " any");
477 if (yang_dnode_exists(dnode
, "./destination-network")) {
478 yang_dnode_get_prefix(&p
, dnode
,
479 "./destination-network");
480 masklen2ip(p
.prefixlen
, &mask
);
481 vty_out(vty
, " %pI4 %pI4", &p
.u
.prefix4
, &mask
);
482 } else if (yang_dnode_exists(dnode
, "./destination-host"))
483 vty_out(vty
, " host %s",
484 yang_dnode_get_string(dnode
,
485 "./destination-host"));
486 else if (yang_dnode_exists(dnode
, "./destination-any"))
487 vty_out(vty
, " any");
494 access_list_legacy_remark
, access_list_legacy_remark_cmd
,
495 "access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...",
498 ACCESS_LIST_REMARK_STR
499 ACCESS_LIST_REMARK_LINE_STR
)
503 char xpath
[XPATH_MAXLEN
];
505 snprintf(xpath
, sizeof(xpath
),
506 "/frr-filter:lib/access-list-legacy[number='%s']", number_str
);
507 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
509 remark
= argv_concat(argv
, argc
, 3);
510 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
511 rv
= nb_cli_apply_changes(vty
, xpath
);
512 XFREE(MTYPE_TMP
, remark
);
518 no_access_list_legacy_remark
, no_access_list_legacy_remark_cmd
,
519 "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark",
523 ACCESS_LIST_REMARK_STR
)
525 char xpath
[XPATH_MAXLEN
];
527 snprintf(xpath
, sizeof(xpath
),
528 "/frr-filter:lib/access-list-legacy[number='%s']/remark",
530 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
532 return nb_cli_apply_changes(vty
, NULL
);
536 no_access_list_legacy_remark
, no_access_list_legacy_remark_line_cmd
,
537 "no access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)>$number remark LINE...",
541 ACCESS_LIST_REMARK_STR
542 ACCESS_LIST_REMARK_LINE_STR
)
544 void access_list_legacy_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
547 vty_out(vty
, "access-list %s remark %s\n",
548 yang_dnode_get_string(dnode
, "../number"),
549 yang_dnode_get_string(dnode
, NULL
));
553 * Zebra access lists.
556 access_list
, access_list_cmd
,
557 "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
559 ACCESS_LIST_ZEBRA_STR
561 ACCESS_LIST_ACTION_STR
562 "Prefix to match. e.g. 10.0.0.0/8\n"
563 "Exact match of the prefixes\n"
567 char xpath
[XPATH_MAXLEN
];
568 char xpath_entry
[XPATH_MAXLEN
+ 128];
571 * Create the access-list first, so we can generate sequence if
572 * none given (backward compatibility).
574 snprintf(xpath
, sizeof(xpath
),
575 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
576 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
577 if (seq_str
== NULL
) {
578 /* Use XPath to find the next sequence number. */
579 sseq
= acl_get_seq(vty
, xpath
);
580 snprintf(xpath_entry
, sizeof(xpath_entry
),
581 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
583 snprintf(xpath_entry
, sizeof(xpath_entry
),
584 "%s/entry[sequence='%s']", xpath
, seq_str
);
586 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
588 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
589 if (prefix_str
!= NULL
) {
590 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
592 nb_cli_enqueue_change(vty
, "./ipv4-exact-match", NB_OP_MODIFY
,
593 exact
? "true" : "false");
595 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
598 return nb_cli_apply_changes(vty
, xpath_entry
);
602 no_access_list
, no_access_list_cmd
,
603 "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <A.B.C.D/M$prefix [exact-match$exact]|any>",
606 ACCESS_LIST_ZEBRA_STR
608 ACCESS_LIST_ACTION_STR
609 "Prefix to match. e.g. 10.0.0.0/8\n"
610 "Exact match of the prefixes\n"
613 struct access_list
*acl
;
614 struct lyd_node
*dnode
;
617 char xpath
[XPATH_MAXLEN
];
618 char xpath_entry
[XPATH_MAXLEN
+ 32];
620 /* If the user provided sequence number, then just go for it. */
621 if (seq_str
!= NULL
) {
623 xpath
, sizeof(xpath
),
624 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/entry[sequence='%s']",
626 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
627 return nb_cli_apply_changes(vty
, NULL
);
630 /* Otherwise, to keep compatibility, we need to figure it out. */
631 snprintf(xpath
, sizeof(xpath
),
632 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
634 /* Access-list must exist before entries. */
635 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
638 /* Use access-list data structure to fetch sequence. */
639 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
640 acl
= nb_running_get_entry(dnode
, NULL
, true);
641 if (prefix
== NULL
) {
642 memset(&pany
, 0, sizeof(pany
));
643 pany
.family
= AF_INET
;
644 sseq
= acl_zebra_get_seq(acl
, action
, &pany
, exact
);
646 sseq
= acl_zebra_get_seq(acl
, action
, (struct prefix
*)prefix
,
651 snprintf(xpath_entry
, sizeof(xpath_entry
),
652 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
653 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
655 return nb_cli_apply_changes(vty
, NULL
);
659 no_access_list_all
, no_access_list_all_cmd
,
660 "no access-list WORD$name",
663 ACCESS_LIST_ZEBRA_STR
)
665 char xpath
[XPATH_MAXLEN
];
667 snprintf(xpath
, sizeof(xpath
),
668 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
669 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
671 return nb_cli_apply_changes(vty
, NULL
);
675 access_list_remark
, access_list_remark_cmd
,
676 "access-list WORD$name remark LINE...",
678 ACCESS_LIST_ZEBRA_STR
679 ACCESS_LIST_REMARK_STR
680 ACCESS_LIST_REMARK_LINE_STR
)
684 char xpath
[XPATH_MAXLEN
];
686 snprintf(xpath
, sizeof(xpath
),
687 "/frr-filter:lib/access-list[type='ipv4'][name='%s']", name
);
688 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
690 remark
= argv_concat(argv
, argc
, 3);
691 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
692 rv
= nb_cli_apply_changes(vty
, xpath
);
693 XFREE(MTYPE_TMP
, remark
);
699 no_access_list_remark
, no_access_list_remark_cmd
,
700 "no access-list WORD$name remark",
703 ACCESS_LIST_ZEBRA_STR
704 ACCESS_LIST_REMARK_STR
)
706 char xpath
[XPATH_MAXLEN
];
708 snprintf(xpath
, sizeof(xpath
),
709 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
711 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
713 return nb_cli_apply_changes(vty
, NULL
);
717 no_access_list_remark
, no_access_list_remark_line_cmd
,
718 "no access-list WORD$name remark LINE...",
721 ACCESS_LIST_ZEBRA_STR
722 ACCESS_LIST_REMARK_STR
723 ACCESS_LIST_REMARK_LINE_STR
)
726 ipv6_access_list
, ipv6_access_list_cmd
,
727 "ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
730 ACCESS_LIST_ZEBRA_STR
732 ACCESS_LIST_ACTION_STR
734 "Exact match of the prefixes\n"
738 char xpath
[XPATH_MAXLEN
];
739 char xpath_entry
[XPATH_MAXLEN
+ 128];
742 * Create the access-list first, so we can generate sequence if
743 * none given (backward compatibility).
745 snprintf(xpath
, sizeof(xpath
),
746 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
747 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
748 if (seq_str
== NULL
) {
749 /* Use XPath to find the next sequence number. */
750 sseq
= acl_get_seq(vty
, xpath
);
751 snprintf(xpath_entry
, sizeof(xpath_entry
),
752 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
754 snprintf(xpath_entry
, sizeof(xpath_entry
),
755 "%s/entry[sequence='%s']", xpath
, seq_str
);
757 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
759 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
760 if (prefix_str
!= NULL
) {
761 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
763 nb_cli_enqueue_change(vty
, "./ipv6-exact-match", NB_OP_MODIFY
,
764 exact
? "true" : "false");
766 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
769 return nb_cli_apply_changes(vty
, xpath_entry
);
773 no_ipv6_access_list
, no_ipv6_access_list_cmd
,
774 "no ipv6 access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X::X:X/M$prefix [exact-match$exact]|any>",
778 ACCESS_LIST_ZEBRA_STR
780 ACCESS_LIST_ACTION_STR
782 "Exact match of the prefixes\n"
785 struct access_list
*acl
;
786 struct lyd_node
*dnode
;
789 char xpath
[XPATH_MAXLEN
];
790 char xpath_entry
[XPATH_MAXLEN
+ 32];
792 /* If the user provided sequence number, then just go for it. */
793 if (seq_str
!= NULL
) {
795 xpath
, sizeof(xpath
),
796 "/frr-filter:lib/access-list[type='ipv6'][name='%s']/entry[sequence='%s']",
798 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
799 return nb_cli_apply_changes(vty
, NULL
);
802 /* Otherwise, to keep compatibility, we need to figure it out. */
803 snprintf(xpath
, sizeof(xpath
),
804 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
806 /* Access-list must exist before entries. */
807 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
810 /* Use access-list data structure to fetch sequence. */
811 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
812 acl
= nb_running_get_entry(dnode
, NULL
, true);
813 if (prefix
== NULL
) {
814 memset(&pany
, 0, sizeof(pany
));
815 pany
.family
= AF_INET6
;
816 sseq
= acl_zebra_get_seq(acl
, action
, &pany
, exact
);
818 sseq
= acl_zebra_get_seq(acl
, action
, (struct prefix
*)prefix
,
823 snprintf(xpath_entry
, sizeof(xpath_entry
),
824 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
825 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
827 return nb_cli_apply_changes(vty
, NULL
);
831 no_ipv6_access_list_all
, no_ipv6_access_list_all_cmd
,
832 "no ipv6 access-list WORD$name",
836 ACCESS_LIST_ZEBRA_STR
)
838 char xpath
[XPATH_MAXLEN
];
840 snprintf(xpath
, sizeof(xpath
),
841 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
842 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
844 return nb_cli_apply_changes(vty
, NULL
);
848 ipv6_access_list_remark
, ipv6_access_list_remark_cmd
,
849 "ipv6 access-list WORD$name remark LINE...",
852 ACCESS_LIST_ZEBRA_STR
853 ACCESS_LIST_REMARK_STR
854 ACCESS_LIST_REMARK_LINE_STR
)
858 char xpath
[XPATH_MAXLEN
];
860 snprintf(xpath
, sizeof(xpath
),
861 "/frr-filter:lib/access-list[type='ipv6'][name='%s']", name
);
862 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
864 remark
= argv_concat(argv
, argc
, 4);
865 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
866 rv
= nb_cli_apply_changes(vty
, xpath
);
867 XFREE(MTYPE_TMP
, remark
);
873 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_cmd
,
874 "no ipv6 access-list WORD$name remark",
878 ACCESS_LIST_ZEBRA_STR
879 ACCESS_LIST_REMARK_STR
)
881 char xpath
[XPATH_MAXLEN
];
883 snprintf(xpath
, sizeof(xpath
),
884 "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
886 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
888 return nb_cli_apply_changes(vty
, NULL
);
892 no_ipv6_access_list_remark
, no_ipv6_access_list_remark_line_cmd
,
893 "no ipv6 access-list WORD$name remark LINE...",
897 ACCESS_LIST_ZEBRA_STR
898 ACCESS_LIST_REMARK_STR
899 ACCESS_LIST_REMARK_LINE_STR
)
902 mac_access_list
, mac_access_list_cmd
,
903 "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>",
906 ACCESS_LIST_ZEBRA_STR
908 ACCESS_LIST_ACTION_STR
910 "Match any MAC address\n")
913 char xpath
[XPATH_MAXLEN
];
914 char xpath_entry
[XPATH_MAXLEN
+ 128];
917 * Create the access-list first, so we can generate sequence if
918 * none given (backward compatibility).
920 snprintf(xpath
, sizeof(xpath
),
921 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
922 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
923 if (seq_str
== NULL
) {
924 /* Use XPath to find the next sequence number. */
925 sseq
= acl_get_seq(vty
, xpath
);
926 snprintf(xpath_entry
, sizeof(xpath_entry
),
927 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
929 snprintf(xpath_entry
, sizeof(xpath_entry
),
930 "%s/entry[sequence='%s']", xpath
, seq_str
);
932 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
934 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
935 if (mac_str
!= NULL
) {
936 nb_cli_enqueue_change(vty
, "./mac", NB_OP_MODIFY
, mac_str
);
938 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
941 return nb_cli_apply_changes(vty
, xpath_entry
);
945 no_mac_access_list
, no_mac_access_list_cmd
,
946 "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$prefix|any>",
950 ACCESS_LIST_ZEBRA_STR
952 ACCESS_LIST_ACTION_STR
954 "Match any MAC address\n")
956 struct access_list
*acl
;
957 struct lyd_node
*dnode
;
960 char xpath
[XPATH_MAXLEN
];
961 char xpath_entry
[XPATH_MAXLEN
+ 32];
963 /* If the user provided sequence number, then just go for it. */
964 if (seq_str
!= NULL
) {
966 xpath
, sizeof(xpath
),
967 "/frr-filter:lib/access-list[type='mac'][name='%s']/entry[sequence='%s']",
969 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
970 return nb_cli_apply_changes(vty
, NULL
);
973 /* Otherwise, to keep compatibility, we need to figure it out. */
974 snprintf(xpath
, sizeof(xpath
),
975 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
977 /* Access-list must exist before entries. */
978 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
981 /* Use access-list data structure to fetch sequence. */
982 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
983 acl
= nb_running_get_entry(dnode
, NULL
, true);
984 if (prefix
== NULL
) {
985 memset(&pany
, 0, sizeof(pany
));
986 pany
.family
= AF_ETHERNET
;
987 sseq
= acl_zebra_get_seq(acl
, action
, &pany
, false);
989 sseq
= acl_zebra_get_seq(acl
, action
, (struct prefix
*)prefix
,
994 snprintf(xpath_entry
, sizeof(xpath_entry
),
995 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
996 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
998 return nb_cli_apply_changes(vty
, NULL
);
1002 no_mac_access_list_all
, no_mac_access_list_all_cmd
,
1003 "no mac access-list WORD$name",
1007 ACCESS_LIST_ZEBRA_STR
)
1009 char xpath
[XPATH_MAXLEN
];
1011 snprintf(xpath
, sizeof(xpath
),
1012 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
1013 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1015 return nb_cli_apply_changes(vty
, NULL
);
1019 mac_access_list_remark
, mac_access_list_remark_cmd
,
1020 "mac access-list WORD$name remark LINE...",
1023 ACCESS_LIST_ZEBRA_STR
1024 ACCESS_LIST_REMARK_STR
1025 ACCESS_LIST_REMARK_LINE_STR
)
1029 char xpath
[XPATH_MAXLEN
];
1031 snprintf(xpath
, sizeof(xpath
),
1032 "/frr-filter:lib/access-list[type='mac'][name='%s']", name
);
1033 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1035 remark
= argv_concat(argv
, argc
, 4);
1036 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1037 rv
= nb_cli_apply_changes(vty
, xpath
);
1038 XFREE(MTYPE_TMP
, remark
);
1044 no_mac_access_list_remark
, no_mac_access_list_remark_cmd
,
1045 "no mac access-list WORD$name remark",
1049 ACCESS_LIST_ZEBRA_STR
1050 ACCESS_LIST_REMARK_STR
)
1052 char xpath
[XPATH_MAXLEN
];
1054 snprintf(xpath
, sizeof(xpath
),
1055 "/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
1057 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1059 return nb_cli_apply_changes(vty
, NULL
);
1063 no_mac_access_list_remark
, no_mac_access_list_remark_line_cmd
,
1064 "no mac access-list WORD$name remark LINE...",
1068 ACCESS_LIST_ZEBRA_STR
1069 ACCESS_LIST_REMARK_STR
1070 ACCESS_LIST_REMARK_LINE_STR
)
1072 void access_list_show(struct vty
*vty
, struct lyd_node
*dnode
,
1075 int type
= yang_dnode_get_enum(dnode
, "../type");
1078 bool is_exact
= false;
1079 char macstr
[PREFIX2STR_BUFFER
];
1081 is_any
= yang_dnode_exists(dnode
, "./any");
1087 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1088 is_exact
= yang_dnode_get_bool(dnode
, "./ipv4-exact-match");
1090 case YALT_IPV6
: /* ipv6 */
1091 vty_out(vty
, "ipv6 ");
1095 yang_dnode_get_prefix(&p
, dnode
, "./ipv6-prefix");
1096 is_exact
= yang_dnode_get_bool(dnode
, "./ipv6-exact-match");
1098 case YALT_MAC
: /* mac */
1099 vty_out(vty
, "mac ");
1103 yang_dnode_get_prefix(&p
, dnode
, "./mac");
1107 vty_out(vty
, "access-list %s seq %s %s",
1108 yang_dnode_get_string(dnode
, "../name"),
1109 yang_dnode_get_string(dnode
, "./sequence"),
1110 yang_dnode_get_string(dnode
, "./action"));
1113 /* If type is MAC don't show '/mask'. */
1114 if (type
== 2 /* mac */) {
1115 prefix_mac2str(&p
.u
.prefix_eth
, macstr
, sizeof(macstr
));
1116 vty_out(vty
, " %s", macstr
);
1118 vty_out(vty
, " %pFX", &p
);
1120 vty_out(vty
, " any");
1123 vty_out(vty
, " exact-match");
1128 void access_list_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
1131 int type
= yang_dnode_get_enum(dnode
, "../type");
1137 vty_out(vty
, "ipv6 ");
1140 vty_out(vty
, "mac ");
1144 vty_out(vty
, "access-list %s remark %s\n",
1145 yang_dnode_get_string(dnode
, "../name"),
1146 yang_dnode_get_string(dnode
, NULL
));
1154 * Remove main data structure prefix list if there are no more entries or
1155 * remark. This fixes compatibility with old CLI and tests.
1157 static int plist_remove_if_empty(struct vty
*vty
, const char *iptype
,
1160 char xpath
[XPATH_MAXLEN
];
1162 snprintf(xpath
, sizeof(xpath
),
1163 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark",
1165 /* List is not empty if there is a remark, check that: */
1166 if (yang_dnode_exists(vty
->candidate_config
->dnode
, xpath
))
1169 /* Check if we have any entries: */
1170 snprintf(xpath
, sizeof(xpath
),
1171 "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype
,
1174 * NOTE: if the list is empty it will return the first sequence
1177 if (acl_get_seq(vty
, xpath
) != 5)
1180 /* Nobody is using this list, lets remove it. */
1181 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1182 return nb_cli_apply_changes(vty
, NULL
);
1185 static int plist_remove(struct vty
*vty
, const char *iptype
, const char *name
,
1186 const char *seq
, const char *action
, struct prefix
*p
,
1189 struct prefix_list_entry
*pentry
;
1190 enum prefix_list_type plt
;
1191 struct prefix_list
*pl
;
1192 struct lyd_node
*dnode
;
1193 char xpath
[XPATH_MAXLEN
];
1194 char xpath_entry
[XPATH_MAXLEN
+ 32];
1197 /* If the user provided sequence number, then just go for it. */
1200 xpath
, sizeof(xpath
),
1201 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
1203 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1205 rv
= nb_cli_apply_changes(vty
, NULL
);
1206 if (rv
== CMD_SUCCESS
)
1207 return plist_remove_if_empty(vty
, iptype
, name
);
1212 /* Otherwise, to keep compatibility, we need to figure it out. */
1213 snprintf(xpath
, sizeof(xpath
),
1214 "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype
,
1217 /* Access-list must exist before entries. */
1218 if (yang_dnode_exists(running_config
->dnode
, xpath
) == false)
1221 /* Use access-list data structure to fetch sequence. */
1222 assert(action
!= NULL
);
1223 if (strcmp(action
, "permit") == 0)
1224 plt
= PREFIX_PERMIT
;
1228 dnode
= yang_dnode_get(running_config
->dnode
, xpath
);
1229 pl
= nb_running_get_entry(dnode
, NULL
, true);
1230 pentry
= prefix_list_entry_lookup(pl
, p
, plt
, -1, le
, ge
);
1234 snprintf(xpath_entry
, sizeof(xpath_entry
),
1235 "%s/entry[sequence='%" PRId64
"']", xpath
, pentry
->seq
);
1236 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_DESTROY
, NULL
);
1238 rv
= nb_cli_apply_changes(vty
, NULL
);
1239 if (rv
== CMD_SUCCESS
)
1240 return plist_remove_if_empty(vty
, iptype
, name
);
1246 ip_prefix_list
, ip_prefix_list_cmd
,
1247 "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}]>",
1250 PREFIX_LIST_NAME_STR
1252 ACCESS_LIST_ACTION_STR
1253 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1254 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1255 "Minimum prefix length to be matched\n"
1256 "Minimum prefix length\n"
1257 "Maximum prefix length to be matched\n"
1258 "Maximum prefix length\n")
1261 char xpath
[XPATH_MAXLEN
];
1262 char xpath_entry
[XPATH_MAXLEN
+ 128];
1265 * Create the prefix-list first, so we can generate sequence if
1266 * none given (backward compatibility).
1268 snprintf(xpath
, sizeof(xpath
),
1269 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1270 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1271 if (seq_str
== NULL
) {
1272 /* Use XPath to find the next sequence number. */
1273 sseq
= acl_get_seq(vty
, xpath
);
1274 snprintf(xpath_entry
, sizeof(xpath_entry
),
1275 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1277 snprintf(xpath_entry
, sizeof(xpath_entry
),
1278 "%s/entry[sequence='%s']", xpath
, seq_str
);
1280 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1282 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1283 if (prefix_str
!= NULL
) {
1284 nb_cli_enqueue_change(vty
, "./ipv4-prefix", NB_OP_MODIFY
,
1288 nb_cli_enqueue_change(
1289 vty
, "./ipv4-prefix-length-greater-or-equal",
1290 NB_OP_MODIFY
, ge_str
);
1292 nb_cli_enqueue_change(
1293 vty
, "./ipv4-prefix-length-lesser-or-equal",
1294 NB_OP_MODIFY
, le_str
);
1296 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1299 return nb_cli_apply_changes(vty
, xpath_entry
);
1303 no_ip_prefix_list
, no_ip_prefix_list_cmd
,
1304 "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)}]>",
1308 PREFIX_LIST_NAME_STR
1310 ACCESS_LIST_ACTION_STR
1311 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1312 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1313 "Minimum prefix length to be matched\n"
1314 "Minimum prefix length\n"
1315 "Maximum prefix length to be matched\n"
1316 "Maximum prefix length\n")
1318 return plist_remove(vty
, "ipv4", name
, seq_str
, action
,
1319 (struct prefix
*)prefix
, ge
, le
);
1323 no_ip_prefix_list_seq
, no_ip_prefix_list_seq_cmd
,
1324 "no ip prefix-list WORD$name seq (1-4294967295)$seq",
1328 PREFIX_LIST_NAME_STR
1329 ACCESS_LIST_SEQ_STR
)
1331 return plist_remove(vty
, "ipv4", name
, seq_str
, NULL
, NULL
, 0, 0);
1335 no_ip_prefix_list_all
, no_ip_prefix_list_all_cmd
,
1336 "no ip prefix-list WORD$name",
1340 PREFIX_LIST_NAME_STR
)
1342 char xpath
[XPATH_MAXLEN
];
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_DESTROY
, NULL
);
1348 return nb_cli_apply_changes(vty
, NULL
);
1352 ip_prefix_list_remark
, ip_prefix_list_remark_cmd
,
1353 "ip prefix-list WORD$name description LINE...",
1356 PREFIX_LIST_NAME_STR
1357 ACCESS_LIST_REMARK_STR
1358 ACCESS_LIST_REMARK_LINE_STR
)
1362 char xpath
[XPATH_MAXLEN
];
1364 snprintf(xpath
, sizeof(xpath
),
1365 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name
);
1366 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1368 remark
= argv_concat(argv
, argc
, 4);
1369 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1370 rv
= nb_cli_apply_changes(vty
, xpath
);
1371 XFREE(MTYPE_TMP
, remark
);
1377 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_cmd
,
1378 "no ip prefix-list WORD$name description",
1382 PREFIX_LIST_NAME_STR
1383 ACCESS_LIST_REMARK_STR
)
1385 char xpath
[XPATH_MAXLEN
];
1387 snprintf(xpath
, sizeof(xpath
),
1388 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
1390 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1392 return nb_cli_apply_changes(vty
, NULL
);
1396 no_ip_prefix_list_remark
, no_ip_prefix_list_remark_line_cmd
,
1397 "no ip prefix-list WORD$name description LINE...",
1401 PREFIX_LIST_NAME_STR
1402 ACCESS_LIST_REMARK_STR
1403 ACCESS_LIST_REMARK_LINE_STR
)
1406 ipv6_prefix_list
, ipv6_prefix_list_cmd
,
1407 "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}]>",
1410 PREFIX_LIST_NAME_STR
1412 ACCESS_LIST_ACTION_STR
1413 "Any prefix match. Same as \"::0/0 le 128\"\n"
1414 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1415 "Maximum prefix length to be matched\n"
1416 "Maximum prefix length\n"
1417 "Minimum prefix length to be matched\n"
1418 "Minimum prefix length\n")
1421 char xpath
[XPATH_MAXLEN
];
1422 char xpath_entry
[XPATH_MAXLEN
+ 128];
1425 * Create the prefix-list first, so we can generate sequence if
1426 * none given (backward compatibility).
1428 snprintf(xpath
, sizeof(xpath
),
1429 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1430 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1431 if (seq_str
== NULL
) {
1432 /* Use XPath to find the next sequence number. */
1433 sseq
= acl_get_seq(vty
, xpath
);
1434 snprintf(xpath_entry
, sizeof(xpath_entry
),
1435 "%s/entry[sequence='%" PRId64
"']", xpath
, sseq
);
1437 snprintf(xpath_entry
, sizeof(xpath_entry
),
1438 "%s/entry[sequence='%s']", xpath
, seq_str
);
1440 nb_cli_enqueue_change(vty
, xpath_entry
, NB_OP_CREATE
, NULL
);
1442 nb_cli_enqueue_change(vty
, "./action", NB_OP_MODIFY
, action
);
1443 if (prefix_str
!= NULL
) {
1444 nb_cli_enqueue_change(vty
, "./ipv6-prefix", NB_OP_MODIFY
,
1448 nb_cli_enqueue_change(
1449 vty
, "./ipv6-prefix-length-greater-or-equal",
1450 NB_OP_MODIFY
, ge_str
);
1452 nb_cli_enqueue_change(
1453 vty
, "./ipv6-prefix-length-lesser-or-equal",
1454 NB_OP_MODIFY
, le_str
);
1456 nb_cli_enqueue_change(vty
, "./any", NB_OP_CREATE
, NULL
);
1459 return nb_cli_apply_changes(vty
, xpath_entry
);
1463 no_ipv6_prefix_list
, no_ipv6_prefix_list_cmd
,
1464 "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}]>",
1468 PREFIX_LIST_NAME_STR
1470 ACCESS_LIST_ACTION_STR
1471 "Any prefix match. Same as \"::0/0 le 128\"\n"
1472 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1473 "Maximum prefix length to be matched\n"
1474 "Maximum prefix length\n"
1475 "Minimum prefix length to be matched\n"
1476 "Minimum prefix length\n")
1478 return plist_remove(vty
, "ipv6", name
, seq_str
, action
,
1479 (struct prefix
*)prefix
, ge
, le
);
1483 no_ipv6_prefix_list_seq
, no_ipv6_prefix_list_seq_cmd
,
1484 "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
1488 PREFIX_LIST_NAME_STR
1489 ACCESS_LIST_SEQ_STR
)
1491 return plist_remove(vty
, "ipv6", name
, seq_str
, NULL
, NULL
, 0, 0);
1495 no_ipv6_prefix_list_all
, no_ipv6_prefix_list_all_cmd
,
1496 "no ipv6 prefix-list WORD$name",
1500 PREFIX_LIST_NAME_STR
)
1502 char xpath
[XPATH_MAXLEN
];
1504 snprintf(xpath
, sizeof(xpath
),
1505 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1506 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1508 return nb_cli_apply_changes(vty
, NULL
);
1512 ipv6_prefix_list_remark
, ipv6_prefix_list_remark_cmd
,
1513 "ipv6 prefix-list WORD$name description LINE...",
1516 PREFIX_LIST_NAME_STR
1517 ACCESS_LIST_REMARK_STR
1518 ACCESS_LIST_REMARK_LINE_STR
)
1522 char xpath
[XPATH_MAXLEN
];
1524 snprintf(xpath
, sizeof(xpath
),
1525 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name
);
1526 nb_cli_enqueue_change(vty
, xpath
, NB_OP_CREATE
, NULL
);
1528 remark
= argv_concat(argv
, argc
, 4);
1529 nb_cli_enqueue_change(vty
, "./remark", NB_OP_CREATE
, remark
);
1530 rv
= nb_cli_apply_changes(vty
, xpath
);
1531 XFREE(MTYPE_TMP
, remark
);
1537 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_cmd
,
1538 "no ipv6 prefix-list WORD$name description",
1542 PREFIX_LIST_NAME_STR
1543 ACCESS_LIST_REMARK_STR
)
1545 char xpath
[XPATH_MAXLEN
];
1547 snprintf(xpath
, sizeof(xpath
),
1548 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
1550 nb_cli_enqueue_change(vty
, xpath
, NB_OP_DESTROY
, NULL
);
1552 return nb_cli_apply_changes(vty
, NULL
);
1556 no_ipv6_prefix_list_remark
, no_ipv6_prefix_list_remark_line_cmd
,
1557 "no ipv6 prefix-list WORD$name description LINE...",
1561 PREFIX_LIST_NAME_STR
1562 ACCESS_LIST_REMARK_STR
1563 ACCESS_LIST_REMARK_LINE_STR
)
1565 void prefix_list_show(struct vty
*vty
, struct lyd_node
*dnode
,
1568 int type
= yang_dnode_get_enum(dnode
, "../type");
1569 const char *ge_str
= NULL
, *le_str
= NULL
;
1573 is_any
= yang_dnode_exists(dnode
, "./any");
1577 yang_dnode_get_prefix(&p
, dnode
, "./ipv4-prefix");
1578 if (yang_dnode_exists(dnode
,
1579 "./ipv4-prefix-length-greater-or-equal"))
1580 ge_str
= yang_dnode_get_string(
1581 dnode
, "./ipv4-prefix-length-greater-or-equal");
1582 if (yang_dnode_exists(dnode
,
1583 "./ipv4-prefix-length-lesser-or-equal"))
1584 le_str
= yang_dnode_get_string(
1585 dnode
, "./ipv4-prefix-length-lesser-or-equal");
1587 vty_out(vty
, "ip ");
1591 yang_dnode_get_prefix(&p
, dnode
, "ipv6-prefix");
1592 if (yang_dnode_exists(dnode
,
1593 "./ipv6-prefix-length-greater-or-equal"))
1594 ge_str
= yang_dnode_get_string(
1595 dnode
, "./ipv6-prefix-length-greater-or-equal");
1596 if (yang_dnode_exists(dnode
,
1597 "./ipv6-prefix-length-lesser-or-equal"))
1598 le_str
= yang_dnode_get_string(
1599 dnode
, "./ipv6-prefix-length-lesser-or-equal");
1601 vty_out(vty
, "ipv6 ");
1605 vty_out(vty
, "prefix-list %s seq %s %s",
1606 yang_dnode_get_string(dnode
, "../name"),
1607 yang_dnode_get_string(dnode
, "./sequence"),
1608 yang_dnode_get_string(dnode
, "./action"));
1611 vty_out(vty
, " any\n");
1615 vty_out(vty
, " %pFX", &p
);
1617 vty_out(vty
, " ge %s", ge_str
);
1619 vty_out(vty
, " le %s", le_str
);
1624 void prefix_list_remark_show(struct vty
*vty
, struct lyd_node
*dnode
,
1627 int type
= yang_dnode_get_enum(dnode
, "../type");
1631 vty_out(vty
, "ip ");
1634 vty_out(vty
, "ipv6 ");
1638 vty_out(vty
, "prefix-list %s description %s\n",
1639 yang_dnode_get_string(dnode
, "../name"),
1640 yang_dnode_get_string(dnode
, NULL
));
1643 void filter_cli_init(void)
1645 /* access-list cisco-style (legacy). */
1646 install_element(CONFIG_NODE
, &access_list_std_cmd
);
1647 install_element(CONFIG_NODE
, &no_access_list_std_cmd
);
1648 install_element(CONFIG_NODE
, &access_list_ext_cmd
);
1649 install_element(CONFIG_NODE
, &no_access_list_ext_cmd
);
1650 install_element(CONFIG_NODE
, &no_access_list_legacy_cmd
);
1651 install_element(CONFIG_NODE
, &access_list_legacy_remark_cmd
);
1652 install_element(CONFIG_NODE
, &no_access_list_legacy_remark_cmd
);
1653 install_element(CONFIG_NODE
, &no_access_list_legacy_remark_line_cmd
);
1655 /* access-list zebra-style. */
1656 install_element(CONFIG_NODE
, &access_list_cmd
);
1657 install_element(CONFIG_NODE
, &no_access_list_cmd
);
1658 install_element(CONFIG_NODE
, &no_access_list_all_cmd
);
1659 install_element(CONFIG_NODE
, &access_list_remark_cmd
);
1660 install_element(CONFIG_NODE
, &no_access_list_remark_cmd
);
1661 install_element(CONFIG_NODE
, &no_access_list_remark_line_cmd
);
1663 install_element(CONFIG_NODE
, &ipv6_access_list_cmd
);
1664 install_element(CONFIG_NODE
, &no_ipv6_access_list_cmd
);
1665 install_element(CONFIG_NODE
, &no_ipv6_access_list_all_cmd
);
1666 install_element(CONFIG_NODE
, &ipv6_access_list_remark_cmd
);
1667 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_cmd
);
1668 install_element(CONFIG_NODE
, &no_ipv6_access_list_remark_line_cmd
);
1670 install_element(CONFIG_NODE
, &mac_access_list_cmd
);
1671 install_element(CONFIG_NODE
, &no_mac_access_list_cmd
);
1672 install_element(CONFIG_NODE
, &no_mac_access_list_all_cmd
);
1673 install_element(CONFIG_NODE
, &mac_access_list_remark_cmd
);
1674 install_element(CONFIG_NODE
, &no_mac_access_list_remark_cmd
);
1675 install_element(CONFIG_NODE
, &no_mac_access_list_remark_line_cmd
);
1678 install_element(CONFIG_NODE
, &ip_prefix_list_cmd
);
1679 install_element(CONFIG_NODE
, &no_ip_prefix_list_cmd
);
1680 install_element(CONFIG_NODE
, &no_ip_prefix_list_seq_cmd
);
1681 install_element(CONFIG_NODE
, &no_ip_prefix_list_all_cmd
);
1682 install_element(CONFIG_NODE
, &ip_prefix_list_remark_cmd
);
1683 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_cmd
);
1684 install_element(CONFIG_NODE
, &no_ip_prefix_list_remark_line_cmd
);
1686 install_element(CONFIG_NODE
, &ipv6_prefix_list_cmd
);
1687 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_cmd
);
1688 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_seq_cmd
);
1689 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_all_cmd
);
1690 install_element(CONFIG_NODE
, &ipv6_prefix_list_remark_cmd
);
1691 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_cmd
);
1692 install_element(CONFIG_NODE
, &no_ipv6_prefix_list_remark_line_cmd
);