]> git.proxmox.com Git - mirror_frr.git/blob - lib/filter_cli.c
Merge pull request #8535 from opensourcerouting/zlog-rnode
[mirror_frr.git] / lib / filter_cli.c
1 /*
2 * FRR filter CLI implementation.
3 *
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
5 * Rafael Zalamena
6 *
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.
11 *
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.
16 *
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
20 * 02110-1301 USA.
21 */
22
23 #include "zebra.h"
24 #include "northbound.h"
25 #include "prefix.h"
26
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"
33
34 #ifndef VTYSH_EXTRACT_PL
35 #include "lib/filter_cli_clippy.c"
36 #endif /* VTYSH_EXTRACT_PL */
37
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" \
45 "Sequence number\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"
51
52 #define PREFIX_LIST_NAME_STR "Prefix list entry name\n"
53
54 /*
55 * Helper function to generate a sequence number for legacy commands.
56 */
57 static int acl_get_seq_cb(const struct lyd_node *dnode, void *arg)
58 {
59 int64_t *seq = arg;
60 int64_t cur_seq = yang_dnode_get_uint32(dnode, "sequence");
61
62 if (cur_seq > *seq)
63 *seq = cur_seq;
64
65 return YANG_ITER_CONTINUE;
66 }
67
68 /**
69 * Helper function that iterates over the XPath `xpath` on the candidate
70 * configuration in `vty->candidate_config`.
71 *
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.
75 */
76 static long acl_get_seq(struct vty *vty, const char *xpath)
77 {
78 int64_t seq = 0;
79
80 yang_dnode_iterate(acl_get_seq_cb, &seq, vty->candidate_config->dnode,
81 "%s/entry", xpath);
82
83 return seq + 5;
84 }
85
86 static int acl_remove_if_empty(struct vty *vty, const char *iptype,
87 const char *name)
88 {
89 char xpath[XPATH_MAXLEN];
90
91 snprintf(xpath, sizeof(xpath),
92 "/frr-filter:lib/access-list[type='%s'][name='%s']/remark",
93 iptype, name);
94 /* List is not empty if there is a remark, check that: */
95 if (yang_dnode_exists(vty->candidate_config->dnode, xpath))
96 return CMD_SUCCESS;
97
98 /* Check if we have any entries: */
99 snprintf(xpath, sizeof(xpath),
100 "/frr-filter:lib/access-list[type='%s'][name='%s']", iptype,
101 name);
102 /*
103 * NOTE: if the list is empty it will return the first sequence
104 * number: 5.
105 */
106 if (acl_get_seq(vty, xpath) != 5)
107 return CMD_SUCCESS;
108
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);
112 }
113
114 static int acl_remove(struct vty *vty, const char *iptype, const char *name,
115 int64_t sseq)
116 {
117 char xpath[XPATH_MAXLEN];
118 int rv;
119
120 snprintfrr(
121 xpath, sizeof(xpath),
122 "/frr-filter:lib/access-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']",
123 iptype, name, sseq);
124 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
125
126 rv = nb_cli_apply_changes(vty, NULL);
127 if (rv == CMD_SUCCESS)
128 return acl_remove_if_empty(vty, iptype, name);
129
130 return rv;
131 }
132
133 /*
134 * Cisco (legacy) access lists.
135 */
136 DEFPY_YANG(
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>",
139 ACCESS_LIST_STR
140 ACCESS_LIST_LEG_STR
141 ACCESS_LIST_SEQ_STR
142 ACCESS_LIST_ACTION_STR
143 "A single host address\n"
144 "Address to match\n"
145 "Address to match\n"
146 "Wildcard bits\n")
147 {
148 int64_t sseq;
149 struct acl_dup_args ada = {};
150 char xpath[XPATH_MAXLEN];
151 char xpath_entry[XPATH_MAXLEN + 128];
152
153 /*
154 * Backward compatibility: don't complain about duplicated values,
155 * just silently accept.
156 */
157 if (seq_str == NULL) {
158 ada.ada_type = "ipv4";
159 ada.ada_name = name;
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;
169 } else {
170 ada.ada_xpath[0] = "./source-any";
171 ada.ada_value[0] = "";
172 }
173
174 /* Duplicated entry without sequence, just quit. */
175 if (acl_is_dup(vty->candidate_config->dnode, &ada))
176 return CMD_SUCCESS;
177 }
178
179 /*
180 * Create the access-list first, so we can generate sequence if
181 * none given (backward compatibility).
182 */
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);
191 } else
192 snprintfrr(xpath_entry, sizeof(xpath_entry),
193 "%s/entry[sequence='%s']", xpath, seq_str);
194
195 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
196
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,
202 host_str);
203 nb_cli_enqueue_change(vty, "./network/mask", NB_OP_MODIFY,
204 mask_str);
205 } else {
206 nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL);
207 }
208
209 return nb_cli_apply_changes(vty, xpath_entry);
210 }
211
212 DEFPY_YANG(
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>",
215 NO_STR
216 ACCESS_LIST_STR
217 ACCESS_LIST_LEG_STR
218 ACCESS_LIST_SEQ_STR
219 ACCESS_LIST_ACTION_STR
220 "A single host address\n"
221 "Address to match\n"
222 "Address to match\n"
223 "Wildcard bits\n")
224 {
225 int64_t sseq;
226 struct acl_dup_args ada = {};
227
228 /* If the user provided sequence number, then just go for it. */
229 if (seq_str != NULL)
230 return acl_remove(vty, "ipv4", name, seq);
231
232 /* Otherwise, to keep compatibility, we need to figure it out. */
233 ada.ada_type = "ipv4";
234 ada.ada_name = name;
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;
244 } else {
245 ada.ada_xpath[0] = "./source-any";
246 ada.ada_value[0] = "";
247 }
248
249 if (acl_is_dup(vty->candidate_config->dnode, &ada))
250 sseq = ada.ada_seq;
251 else
252 return CMD_WARNING_CONFIG_FAILED;
253
254 return acl_remove(vty, "ipv4", name, sseq);
255 }
256
257 DEFPY_YANG(
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>",
260 ACCESS_LIST_STR
261 ACCESS_LIST_ELEG_STR
262 ACCESS_LIST_SEQ_STR
263 ACCESS_LIST_ACTION_STR
264 "IPv4 address\n"
265 "Source address to match\n"
266 "Source address mask to apply\n"
267 "Single source host\n"
268 "Source address to match\n"
269 "Any source host\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")
275 {
276 int idx = 0;
277 int64_t sseq;
278 struct acl_dup_args ada = {};
279 char xpath[XPATH_MAXLEN];
280 char xpath_entry[XPATH_MAXLEN + 128];
281
282 /*
283 * Backward compatibility: don't complain about duplicated values,
284 * just silently accept.
285 */
286 if (seq_str == NULL) {
287 ada.ada_type = "ipv4";
288 ada.ada_name = name;
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;
293 idx++;
294 } else if (src_str && src_mask_str) {
295 ada.ada_xpath[idx] = "./network/address";
296 ada.ada_value[idx] = src_str;
297 idx++;
298 ada.ada_xpath[idx] = "./network/mask";
299 ada.ada_value[idx] = src_mask_str;
300 idx++;
301 } else {
302 ada.ada_xpath[idx] = "./source-any";
303 ada.ada_value[idx] = "";
304 idx++;
305 }
306
307 if (dst_str && dst_mask_str == NULL) {
308 ada.ada_xpath[idx] = "./destination-host";
309 ada.ada_value[idx] = dst_str;
310 idx++;
311 } else if (dst_str && dst_mask_str) {
312 ada.ada_xpath[idx] = "./destination-network/address";
313 ada.ada_value[idx] = dst_str;
314 idx++;
315 ada.ada_xpath[idx] = "./destination-network/mask";
316 ada.ada_value[idx] = dst_mask_str;
317 idx++;
318 } else {
319 ada.ada_xpath[idx] = "./destination-any";
320 ada.ada_value[idx] = "";
321 idx++;
322 }
323
324 /* Duplicated entry without sequence, just quit. */
325 if (acl_is_dup(vty->candidate_config->dnode, &ada))
326 return CMD_SUCCESS;
327 }
328
329 /*
330 * Create the access-list first, so we can generate sequence if
331 * none given (backward compatibility).
332 */
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);
341 } else
342 snprintfrr(xpath_entry, sizeof(xpath_entry),
343 "%s/entry[sequence='%s']", xpath, seq_str);
344
345 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
346
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,
352 src_str);
353 nb_cli_enqueue_change(vty, "./network/mask", NB_OP_MODIFY,
354 src_mask_str);
355 } else {
356 nb_cli_enqueue_change(vty, "./source-any", NB_OP_CREATE, NULL);
357 }
358
359 if (dst_str != NULL && dst_mask_str == NULL) {
360 nb_cli_enqueue_change(vty, "./destination-host", NB_OP_MODIFY,
361 dst_str);
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);
367 } else {
368 nb_cli_enqueue_change(vty, "./destination-any", NB_OP_CREATE,
369 NULL);
370 }
371
372 return nb_cli_apply_changes(vty, xpath_entry);
373 }
374
375 DEFPY_YANG(
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>",
378 NO_STR
379 ACCESS_LIST_STR
380 ACCESS_LIST_ELEG_STR
381 ACCESS_LIST_SEQ_STR
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"
388 "Any source host\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")
394 {
395 int idx = 0;
396 int64_t sseq;
397 struct acl_dup_args ada = {};
398
399 /* If the user provided sequence number, then just go for it. */
400 if (seq_str != NULL)
401 return acl_remove(vty, "ipv4", name, seq);
402
403 /* Otherwise, to keep compatibility, we need to figure it out. */
404 ada.ada_type = "ipv4";
405 ada.ada_name = name;
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;
410 idx++;
411 } else if (src_str && src_mask_str) {
412 ada.ada_xpath[idx] = "./network/address";
413 ada.ada_value[idx] = src_str;
414 idx++;
415 ada.ada_xpath[idx] = "./network/mask";
416 ada.ada_value[idx] = src_mask_str;
417 idx++;
418 } else {
419 ada.ada_xpath[idx] = "./source-any";
420 ada.ada_value[idx] = "";
421 idx++;
422 }
423
424 if (dst_str && dst_mask_str == NULL) {
425 ada.ada_xpath[idx] = "./destination-host";
426 ada.ada_value[idx] = dst_str;
427 idx++;
428 } else if (dst_str && dst_mask_str) {
429 ada.ada_xpath[idx] = "./destination-network/address";
430 ada.ada_value[idx] = dst_str;
431 idx++;
432 ada.ada_xpath[idx] = "./destination-network/mask";
433 ada.ada_value[idx] = dst_mask_str;
434 idx++;
435 } else {
436 ada.ada_xpath[idx] = "./destination-any";
437 ada.ada_value[idx] = "";
438 idx++;
439 }
440
441 if (acl_is_dup(vty->candidate_config->dnode, &ada))
442 sseq = ada.ada_seq;
443 else
444 return CMD_WARNING_CONFIG_FAILED;
445
446 return acl_remove(vty, "ipv4", name, sseq);
447 }
448
449 /*
450 * Zebra access lists.
451 */
452 DEFPY_YANG(
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>",
455 ACCESS_LIST_STR
456 ACCESS_LIST_ZEBRA_STR
457 ACCESS_LIST_SEQ_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"
461 "Match any IPv4\n")
462 {
463 int64_t sseq;
464 struct acl_dup_args ada = {};
465 char xpath[XPATH_MAXLEN];
466 char xpath_entry[XPATH_MAXLEN + 128];
467
468 /*
469 * Backward compatibility: don't complain about duplicated values,
470 * just silently accept.
471 */
472 if (seq_str == NULL) {
473 ada.ada_type = "ipv4";
474 ada.ada_name = name;
475 ada.ada_action = action;
476
477 if (prefix_str) {
478 ada.ada_xpath[0] = "./ipv4-prefix";
479 ada.ada_value[0] = prefix_str;
480 if (exact) {
481 ada.ada_xpath[1] = "./ipv4-exact-match";
482 ada.ada_value[1] = "true";
483 }
484 } else {
485 ada.ada_xpath[0] = "./any";
486 ada.ada_value[0] = "";
487 }
488
489 /* Duplicated entry without sequence, just quit. */
490 if (acl_is_dup(vty->candidate_config->dnode, &ada))
491 return CMD_SUCCESS;
492 }
493
494 /*
495 * Create the access-list first, so we can generate sequence if
496 * none given (backward compatibility).
497 */
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);
506 } else
507 snprintfrr(xpath_entry, sizeof(xpath_entry),
508 "%s/entry[sequence='%s']", xpath, seq_str);
509
510 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
511
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,
515 prefix_str);
516 nb_cli_enqueue_change(vty, "./ipv4-exact-match", NB_OP_MODIFY,
517 exact ? "true" : "false");
518 } else {
519 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
520 }
521
522 return nb_cli_apply_changes(vty, xpath_entry);
523 }
524
525 DEFPY_YANG(
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>",
528 NO_STR
529 ACCESS_LIST_STR
530 ACCESS_LIST_ZEBRA_STR
531 ACCESS_LIST_SEQ_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"
535 "Match any IPv4\n")
536 {
537 int64_t sseq;
538 struct acl_dup_args ada = {};
539
540 /* If the user provided sequence number, then just go for it. */
541 if (seq_str != NULL)
542 return acl_remove(vty, "ipv4", name, seq);
543
544 /* Otherwise, to keep compatibility, we need to figure it out. */
545 ada.ada_type = "ipv4";
546 ada.ada_name = name;
547 ada.ada_action = action;
548
549 if (prefix_str) {
550 ada.ada_xpath[0] = "./ipv4-prefix";
551 ada.ada_value[0] = prefix_str;
552 if (exact) {
553 ada.ada_xpath[1] = "./ipv4-exact-match";
554 ada.ada_value[1] = "true";
555 }
556 } else {
557 ada.ada_xpath[0] = "./any";
558 ada.ada_value[0] = "";
559 }
560
561 if (acl_is_dup(vty->candidate_config->dnode, &ada))
562 sseq = ada.ada_seq;
563 else
564 return CMD_WARNING_CONFIG_FAILED;
565
566 return acl_remove(vty, "ipv4", name, sseq);
567 }
568
569 DEFPY_YANG(
570 no_access_list_all, no_access_list_all_cmd,
571 "no access-list WORD$name",
572 NO_STR
573 ACCESS_LIST_STR
574 ACCESS_LIST_ZEBRA_STR)
575 {
576 char xpath[XPATH_MAXLEN];
577
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);
581
582 return nb_cli_apply_changes(vty, NULL);
583 }
584
585 DEFPY_YANG(
586 access_list_remark, access_list_remark_cmd,
587 "access-list WORD$name remark LINE...",
588 ACCESS_LIST_STR
589 ACCESS_LIST_ZEBRA_STR
590 ACCESS_LIST_REMARK_STR
591 ACCESS_LIST_REMARK_LINE_STR)
592 {
593 int rv;
594 char *remark;
595 char xpath[XPATH_MAXLEN];
596
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);
600
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);
605
606 return rv;
607 }
608
609 DEFPY_YANG(
610 no_access_list_remark, no_access_list_remark_cmd,
611 "no access-list WORD$name remark",
612 NO_STR
613 ACCESS_LIST_STR
614 ACCESS_LIST_ZEBRA_STR
615 ACCESS_LIST_REMARK_STR)
616 {
617 char xpath[XPATH_MAXLEN];
618 int rv;
619
620 snprintf(xpath, sizeof(xpath),
621 "/frr-filter:lib/access-list[type='ipv4'][name='%s']/remark",
622 name);
623 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
624
625 rv = nb_cli_apply_changes(vty, NULL);
626 if (rv == CMD_SUCCESS)
627 return acl_remove_if_empty(vty, "ipv4", name);
628
629 return rv;
630 }
631
632 ALIAS(
633 no_access_list_remark, no_access_list_remark_line_cmd,
634 "no access-list WORD$name remark LINE...",
635 NO_STR
636 ACCESS_LIST_STR
637 ACCESS_LIST_ZEBRA_STR
638 ACCESS_LIST_REMARK_STR
639 ACCESS_LIST_REMARK_LINE_STR)
640
641 DEFPY_YANG(
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>",
644 IPV6_STR
645 ACCESS_LIST_STR
646 ACCESS_LIST_ZEBRA_STR
647 ACCESS_LIST_SEQ_STR
648 ACCESS_LIST_ACTION_STR
649 "IPv6 prefix\n"
650 "Exact match of the prefixes\n"
651 "Match any IPv6\n")
652 {
653 int64_t sseq;
654 struct acl_dup_args ada = {};
655 char xpath[XPATH_MAXLEN];
656 char xpath_entry[XPATH_MAXLEN + 128];
657
658 /*
659 * Backward compatibility: don't complain about duplicated values,
660 * just silently accept.
661 */
662 if (seq_str == NULL) {
663 ada.ada_type = "ipv6";
664 ada.ada_name = name;
665 ada.ada_action = action;
666
667 if (prefix_str) {
668 ada.ada_xpath[0] = "./ipv6-prefix";
669 ada.ada_value[0] = prefix_str;
670 if (exact) {
671 ada.ada_xpath[1] = "./ipv6-exact-match";
672 ada.ada_value[1] = "true";
673 }
674 } else {
675 ada.ada_xpath[0] = "./any";
676 ada.ada_value[0] = "";
677 }
678
679 /* Duplicated entry without sequence, just quit. */
680 if (acl_is_dup(vty->candidate_config->dnode, &ada))
681 return CMD_SUCCESS;
682 }
683
684 /*
685 * Create the access-list first, so we can generate sequence if
686 * none given (backward compatibility).
687 */
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);
696 } else
697 snprintfrr(xpath_entry, sizeof(xpath_entry),
698 "%s/entry[sequence='%s']", xpath, seq_str);
699
700 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
701
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,
705 prefix_str);
706 nb_cli_enqueue_change(vty, "./ipv6-exact-match", NB_OP_MODIFY,
707 exact ? "true" : "false");
708 } else {
709 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
710 }
711
712 return nb_cli_apply_changes(vty, xpath_entry);
713 }
714
715 DEFPY_YANG(
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>",
718 NO_STR
719 IPV6_STR
720 ACCESS_LIST_STR
721 ACCESS_LIST_ZEBRA_STR
722 ACCESS_LIST_SEQ_STR
723 ACCESS_LIST_ACTION_STR
724 "IPv6 prefix\n"
725 "Exact match of the prefixes\n"
726 "Match any IPv6\n")
727 {
728 int64_t sseq;
729 struct acl_dup_args ada = {};
730
731 /* If the user provided sequence number, then just go for it. */
732 if (seq_str != NULL)
733 return acl_remove(vty, "ipv6", name, seq);
734
735 /* Otherwise, to keep compatibility, we need to figure it out. */
736 ada.ada_type = "ipv6";
737 ada.ada_name = name;
738 ada.ada_action = action;
739
740 if (prefix_str) {
741 ada.ada_xpath[0] = "./ipv6-prefix";
742 ada.ada_value[0] = prefix_str;
743 if (exact) {
744 ada.ada_xpath[1] = "./ipv6-exact-match";
745 ada.ada_value[1] = "true";
746 }
747 } else {
748 ada.ada_xpath[0] = "./any";
749 ada.ada_value[0] = "";
750 }
751
752 if (acl_is_dup(vty->candidate_config->dnode, &ada))
753 sseq = ada.ada_seq;
754 else
755 return CMD_WARNING_CONFIG_FAILED;
756
757 return acl_remove(vty, "ipv6", name, sseq);
758 }
759
760 DEFPY_YANG(
761 no_ipv6_access_list_all, no_ipv6_access_list_all_cmd,
762 "no ipv6 access-list WORD$name",
763 NO_STR
764 IPV6_STR
765 ACCESS_LIST_STR
766 ACCESS_LIST_ZEBRA_STR)
767 {
768 char xpath[XPATH_MAXLEN];
769
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);
773
774 return nb_cli_apply_changes(vty, NULL);
775 }
776
777 DEFPY_YANG(
778 ipv6_access_list_remark, ipv6_access_list_remark_cmd,
779 "ipv6 access-list WORD$name remark LINE...",
780 IPV6_STR
781 ACCESS_LIST_STR
782 ACCESS_LIST_ZEBRA_STR
783 ACCESS_LIST_REMARK_STR
784 ACCESS_LIST_REMARK_LINE_STR)
785 {
786 int rv;
787 char *remark;
788 char xpath[XPATH_MAXLEN];
789
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);
793
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);
798
799 return rv;
800 }
801
802 DEFPY_YANG(
803 no_ipv6_access_list_remark, no_ipv6_access_list_remark_cmd,
804 "no ipv6 access-list WORD$name remark",
805 NO_STR
806 IPV6_STR
807 ACCESS_LIST_STR
808 ACCESS_LIST_ZEBRA_STR
809 ACCESS_LIST_REMARK_STR)
810 {
811 char xpath[XPATH_MAXLEN];
812 int rv;
813
814 snprintf(xpath, sizeof(xpath),
815 "/frr-filter:lib/access-list[type='ipv6'][name='%s']/remark",
816 name);
817 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
818
819 rv = nb_cli_apply_changes(vty, NULL);
820 if (rv == CMD_SUCCESS)
821 return acl_remove_if_empty(vty, "ipv6", name);
822
823 return rv;
824 }
825
826 ALIAS(
827 no_ipv6_access_list_remark, no_ipv6_access_list_remark_line_cmd,
828 "no ipv6 access-list WORD$name remark LINE...",
829 NO_STR
830 IPV6_STR
831 ACCESS_LIST_STR
832 ACCESS_LIST_ZEBRA_STR
833 ACCESS_LIST_REMARK_STR
834 ACCESS_LIST_REMARK_LINE_STR)
835
836 DEFPY_YANG(
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>",
839 MAC_STR
840 ACCESS_LIST_STR
841 ACCESS_LIST_ZEBRA_STR
842 ACCESS_LIST_SEQ_STR
843 ACCESS_LIST_ACTION_STR
844 "MAC address\n"
845 "Match any MAC address\n")
846 {
847 int64_t sseq;
848 struct acl_dup_args ada = {};
849 char xpath[XPATH_MAXLEN];
850 char xpath_entry[XPATH_MAXLEN + 128];
851
852 /*
853 * Backward compatibility: don't complain about duplicated values,
854 * just silently accept.
855 */
856 if (seq_str == NULL) {
857 ada.ada_type = "mac";
858 ada.ada_name = name;
859 ada.ada_action = action;
860
861 if (mac_str) {
862 ada.ada_xpath[0] = "./mac";
863 ada.ada_value[0] = mac_str;
864 } else {
865 ada.ada_xpath[0] = "./any";
866 ada.ada_value[0] = "";
867 }
868
869 /* Duplicated entry without sequence, just quit. */
870 if (acl_is_dup(vty->candidate_config->dnode, &ada))
871 return CMD_SUCCESS;
872 }
873
874 /*
875 * Create the access-list first, so we can generate sequence if
876 * none given (backward compatibility).
877 */
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);
886 } else
887 snprintfrr(xpath_entry, sizeof(xpath_entry),
888 "%s/entry[sequence='%s']", xpath, seq_str);
889
890 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
891
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);
895 } else {
896 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
897 }
898
899 return nb_cli_apply_changes(vty, xpath_entry);
900 }
901
902 DEFPY_YANG(
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>",
905 NO_STR
906 MAC_STR
907 ACCESS_LIST_STR
908 ACCESS_LIST_ZEBRA_STR
909 ACCESS_LIST_SEQ_STR
910 ACCESS_LIST_ACTION_STR
911 "MAC address\n"
912 "Match any MAC address\n")
913 {
914 int64_t sseq;
915 struct acl_dup_args ada = {};
916
917 /* If the user provided sequence number, then just go for it. */
918 if (seq_str != NULL)
919 return acl_remove(vty, "mac", name, seq);
920
921 /* Otherwise, to keep compatibility, we need to figure it out. */
922 ada.ada_type = "mac";
923 ada.ada_name = name;
924 ada.ada_action = action;
925
926 if (mac_str) {
927 ada.ada_xpath[0] = "./mac";
928 ada.ada_value[0] = mac_str;
929 } else {
930 ada.ada_xpath[0] = "./any";
931 ada.ada_value[0] = "";
932 }
933
934 if (acl_is_dup(vty->candidate_config->dnode, &ada))
935 sseq = ada.ada_seq;
936 else
937 return CMD_WARNING_CONFIG_FAILED;
938
939 return acl_remove(vty, "mac", name, sseq);
940 }
941
942 DEFPY_YANG(
943 no_mac_access_list_all, no_mac_access_list_all_cmd,
944 "no mac access-list WORD$name",
945 NO_STR
946 MAC_STR
947 ACCESS_LIST_STR
948 ACCESS_LIST_ZEBRA_STR)
949 {
950 char xpath[XPATH_MAXLEN];
951
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);
955
956 return nb_cli_apply_changes(vty, NULL);
957 }
958
959 DEFPY_YANG(
960 mac_access_list_remark, mac_access_list_remark_cmd,
961 "mac access-list WORD$name remark LINE...",
962 MAC_STR
963 ACCESS_LIST_STR
964 ACCESS_LIST_ZEBRA_STR
965 ACCESS_LIST_REMARK_STR
966 ACCESS_LIST_REMARK_LINE_STR)
967 {
968 int rv;
969 char *remark;
970 char xpath[XPATH_MAXLEN];
971
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);
975
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);
980
981 return rv;
982 }
983
984 DEFPY_YANG(
985 no_mac_access_list_remark, no_mac_access_list_remark_cmd,
986 "no mac access-list WORD$name remark",
987 NO_STR
988 MAC_STR
989 ACCESS_LIST_STR
990 ACCESS_LIST_ZEBRA_STR
991 ACCESS_LIST_REMARK_STR)
992 {
993 char xpath[XPATH_MAXLEN];
994 int rv;
995
996 snprintf(xpath, sizeof(xpath),
997 "/frr-filter:lib/access-list[type='mac'][name='%s']/remark",
998 name);
999 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
1000
1001 rv = nb_cli_apply_changes(vty, NULL);
1002 if (rv == CMD_SUCCESS)
1003 return acl_remove_if_empty(vty, "mac", name);
1004
1005 return rv;
1006 }
1007
1008 ALIAS(
1009 no_mac_access_list_remark, no_mac_access_list_remark_line_cmd,
1010 "no mac access-list WORD$name remark LINE...",
1011 NO_STR
1012 MAC_STR
1013 ACCESS_LIST_STR
1014 ACCESS_LIST_ZEBRA_STR
1015 ACCESS_LIST_REMARK_STR
1016 ACCESS_LIST_REMARK_LINE_STR)
1017
1018 int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
1019 {
1020 uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
1021 uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
1022
1023 return seq1 - seq2;
1024 }
1025
1026 void access_list_show(struct vty *vty, struct lyd_node *dnode,
1027 bool show_defaults)
1028 {
1029 int type = yang_dnode_get_enum(dnode, "../type");
1030 struct prefix p;
1031 bool is_any;
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];
1037
1038 is_any = yang_dnode_exists(dnode, "./any");
1039 switch (type) {
1040 case YALT_IPV4:
1041 if (is_any)
1042 break;
1043
1044 if (yang_dnode_exists(dnode, "./host")
1045 || yang_dnode_exists(dnode, "./network/address")
1046 || yang_dnode_exists(dnode, "./source-any")) {
1047 cisco_style = true;
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;
1053 } else {
1054 yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
1055 is_exact = yang_dnode_get_bool(dnode,
1056 "./ipv4-exact-match");
1057 }
1058 break;
1059 case YALT_IPV6: /* ipv6 */
1060 vty_out(vty, "ipv6 ");
1061 if (is_any)
1062 break;
1063
1064 yang_dnode_get_prefix(&p, dnode, "./ipv6-prefix");
1065 is_exact = yang_dnode_get_bool(dnode, "./ipv6-exact-match");
1066 break;
1067 case YALT_MAC: /* mac */
1068 vty_out(vty, "mac ");
1069 if (is_any)
1070 break;
1071
1072 yang_dnode_get_prefix(&p, dnode, "./mac");
1073 break;
1074 }
1075
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"));
1080
1081 /* Handle Cisco style access lists. */
1082 if (cisco_style) {
1083 if (cisco_extended)
1084 vty_out(vty, " ip");
1085
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")) {
1091 if (cisco_extended)
1092 vty_out(vty, " host");
1093
1094 vty_out(vty, " %s",
1095 yang_dnode_get_string(dnode, "./host"));
1096 } else if (yang_dnode_exists(dnode, "./source-any"))
1097 vty_out(vty, " any");
1098
1099 /* Not extended, exit earlier. */
1100 if (!cisco_extended) {
1101 vty_out(vty, "\n");
1102 return;
1103 }
1104
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");
1118
1119 vty_out(vty, "\n");
1120 return;
1121 }
1122
1123 /* Zebra style access list. */
1124 if (!is_any) {
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);
1129 } else
1130 vty_out(vty, " %pFX", &p);
1131 } else
1132 vty_out(vty, " any");
1133
1134 if (is_exact)
1135 vty_out(vty, " exact-match");
1136
1137 vty_out(vty, "\n");
1138 }
1139
1140 void access_list_remark_show(struct vty *vty, struct lyd_node *dnode,
1141 bool show_defaults)
1142 {
1143 int type = yang_dnode_get_enum(dnode, "../type");
1144
1145 switch (type) {
1146 case YALT_IPV4:
1147 break;
1148 case YALT_IPV6:
1149 vty_out(vty, "ipv6 ");
1150 break;
1151 case YALT_MAC:
1152 vty_out(vty, "mac ");
1153 break;
1154 }
1155
1156 vty_out(vty, "access-list %s remark %s\n",
1157 yang_dnode_get_string(dnode, "../name"),
1158 yang_dnode_get_string(dnode, NULL));
1159 }
1160
1161 /*
1162 * Prefix lists.
1163 */
1164
1165 /**
1166 * Remove main data structure prefix list if there are no more entries or
1167 * remark. This fixes compatibility with old CLI and tests.
1168 */
1169 static int plist_remove_if_empty(struct vty *vty, const char *iptype,
1170 const char *name)
1171 {
1172 char xpath[XPATH_MAXLEN];
1173
1174 snprintf(xpath, sizeof(xpath),
1175 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/remark",
1176 iptype, name);
1177 /* List is not empty if there is a remark, check that: */
1178 if (yang_dnode_exists(vty->candidate_config->dnode, xpath))
1179 return CMD_SUCCESS;
1180
1181 /* Check if we have any entries: */
1182 snprintf(xpath, sizeof(xpath),
1183 "/frr-filter:lib/prefix-list[type='%s'][name='%s']", iptype,
1184 name);
1185 /*
1186 * NOTE: if the list is empty it will return the first sequence
1187 * number: 5.
1188 */
1189 if (acl_get_seq(vty, xpath) != 5)
1190 return CMD_SUCCESS;
1191
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);
1195 }
1196
1197 static int plist_remove(struct vty *vty, const char *iptype, const char *name,
1198 const char *seq, const char *action,
1199 const char *prefix_str, const char *ge_str,
1200 const char *le_str)
1201 {
1202 int64_t sseq;
1203 int arg_idx = 0;
1204 struct plist_dup_args pda = {};
1205 char xpath[XPATH_MAXLEN];
1206 char xpath_entry[XPATH_MAXLEN + 32];
1207 int rv;
1208
1209 /* If the user provided sequence number, then just go for it. */
1210 if (seq != NULL) {
1211 snprintf(
1212 xpath, sizeof(xpath),
1213 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%s']",
1214 iptype, name, seq);
1215 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
1216
1217 rv = nb_cli_apply_changes(vty, NULL);
1218 if (rv == CMD_SUCCESS)
1219 return plist_remove_if_empty(vty, iptype, name);
1220
1221 return rv;
1222 }
1223
1224 /* Otherwise, to keep compatibility, we need to figure it out. */
1225 pda.pda_type = iptype;
1226 pda.pda_name = name;
1227 pda.pda_action = action;
1228 if (prefix_str) {
1229 if (strmatch(iptype, "ipv4")) {
1230 pda.pda_xpath[arg_idx] = "./ipv4-prefix";
1231 pda.pda_value[arg_idx] = prefix_str;
1232 arg_idx++;
1233 if (ge_str) {
1234 pda.pda_xpath[arg_idx] =
1235 "./ipv4-prefix-length-greater-or-equal";
1236 pda.pda_value[arg_idx] = ge_str;
1237 arg_idx++;
1238 }
1239 if (le_str) {
1240 pda.pda_xpath[arg_idx] =
1241 "./ipv4-prefix-length-lesser-or-equal";
1242 pda.pda_value[arg_idx] = le_str;
1243 arg_idx++;
1244 }
1245 } else {
1246 pda.pda_xpath[arg_idx] = "./ipv6-prefix";
1247 pda.pda_value[arg_idx] = prefix_str;
1248 arg_idx++;
1249 if (ge_str) {
1250 pda.pda_xpath[arg_idx] =
1251 "./ipv6-prefix-length-greater-or-equal";
1252 pda.pda_value[arg_idx] = ge_str;
1253 arg_idx++;
1254 }
1255 if (le_str) {
1256 pda.pda_xpath[arg_idx] =
1257 "./ipv6-prefix-length-lesser-or-equal";
1258 pda.pda_value[arg_idx] = le_str;
1259 arg_idx++;
1260 }
1261 }
1262 } else {
1263 pda.pda_xpath[0] = "./any";
1264 pda.pda_value[0] = "";
1265 }
1266
1267 if (plist_is_dup(vty->candidate_config->dnode, &pda))
1268 sseq = pda.pda_seq;
1269 else
1270 return CMD_WARNING_CONFIG_FAILED;
1271
1272 snprintfrr(
1273 xpath_entry, sizeof(xpath_entry),
1274 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry[sequence='%" PRId64 "']",
1275 iptype, name, sseq);
1276 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL);
1277
1278 rv = nb_cli_apply_changes(vty, NULL);
1279 if (rv == CMD_SUCCESS)
1280 return plist_remove_if_empty(vty, iptype, name);
1281
1282 return rv;
1283 }
1284
1285 DEFPY_YANG(
1286 ip_prefix_list, ip_prefix_list_cmd,
1287 "ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)$ge|le (0-32)$le}]>",
1288 IP_STR
1289 PREFIX_LIST_STR
1290 PREFIX_LIST_NAME_STR
1291 ACCESS_LIST_SEQ_STR
1292 ACCESS_LIST_ACTION_STR
1293 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1294 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1295 "Minimum prefix length to be matched\n"
1296 "Minimum prefix length\n"
1297 "Maximum prefix length to be matched\n"
1298 "Maximum prefix length\n")
1299 {
1300 int64_t sseq;
1301 int arg_idx = 0;
1302 struct plist_dup_args pda = {};
1303 char xpath[XPATH_MAXLEN];
1304 char xpath_entry[XPATH_MAXLEN + 128];
1305
1306 /*
1307 * Backward compatibility: don't complain about duplicated values,
1308 * just silently accept.
1309 */
1310 if (seq_str == NULL) {
1311 pda.pda_type = "ipv4";
1312 pda.pda_name = name;
1313 pda.pda_action = action;
1314 if (prefix_str) {
1315 pda.pda_xpath[arg_idx] = "./ipv4-prefix";
1316 pda.pda_value[arg_idx] = prefix_str;
1317 arg_idx++;
1318 if (ge_str) {
1319 pda.pda_xpath[arg_idx] =
1320 "./ipv4-prefix-length-greater-or-equal";
1321 pda.pda_value[arg_idx] = ge_str;
1322 arg_idx++;
1323 }
1324 if (le_str) {
1325 pda.pda_xpath[arg_idx] =
1326 "./ipv4-prefix-length-lesser-or-equal";
1327 pda.pda_value[arg_idx] = le_str;
1328 arg_idx++;
1329 }
1330 } else {
1331 pda.pda_xpath[0] = "./any";
1332 pda.pda_value[0] = "";
1333 }
1334
1335 /* Duplicated entry without sequence, just quit. */
1336 if (plist_is_dup(vty->candidate_config->dnode, &pda))
1337 return CMD_SUCCESS;
1338 }
1339
1340 /*
1341 * Create the prefix-list first, so we can generate sequence if
1342 * none given (backward compatibility).
1343 */
1344 snprintf(xpath, sizeof(xpath),
1345 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
1346 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1347 if (seq_str == NULL) {
1348 /* Use XPath to find the next sequence number. */
1349 sseq = acl_get_seq(vty, xpath);
1350 snprintfrr(xpath_entry, sizeof(xpath_entry),
1351 "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
1352 } else
1353 snprintfrr(xpath_entry, sizeof(xpath_entry),
1354 "%s/entry[sequence='%s']", xpath, seq_str);
1355
1356 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
1357
1358 nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
1359 if (prefix_str != NULL) {
1360 nb_cli_enqueue_change(vty, "./ipv4-prefix", NB_OP_MODIFY,
1361 prefix_str);
1362
1363 if (ge_str) {
1364 nb_cli_enqueue_change(
1365 vty, "./ipv4-prefix-length-greater-or-equal",
1366 NB_OP_MODIFY, ge_str);
1367 } else {
1368 /*
1369 * Remove old ge if not being modified
1370 */
1371 nb_cli_enqueue_change(
1372 vty, "./ipv4-prefix-length-greater-or-equal",
1373 NB_OP_DESTROY, NULL);
1374 }
1375
1376 if (le_str) {
1377 nb_cli_enqueue_change(
1378 vty, "./ipv4-prefix-length-lesser-or-equal",
1379 NB_OP_MODIFY, le_str);
1380 } else {
1381 /*
1382 * Remove old le if not being modified
1383 */
1384 nb_cli_enqueue_change(
1385 vty, "./ipv4-prefix-length-lesser-or-equal",
1386 NB_OP_DESTROY, NULL);
1387 }
1388 } else {
1389 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
1390 }
1391
1392 return nb_cli_apply_changes(vty, xpath_entry);
1393 }
1394
1395 DEFPY_YANG(
1396 no_ip_prefix_list, no_ip_prefix_list_cmd,
1397 "no ip prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|A.B.C.D/M$prefix [{ge (0-32)|le (0-32)}]>",
1398 NO_STR
1399 IP_STR
1400 PREFIX_LIST_STR
1401 PREFIX_LIST_NAME_STR
1402 ACCESS_LIST_SEQ_STR
1403 ACCESS_LIST_ACTION_STR
1404 "Any prefix match. Same as \"0.0.0.0/0 le 32\"\n"
1405 "IP prefix <network>/<length>, e.g., 35.0.0.0/8\n"
1406 "Minimum prefix length to be matched\n"
1407 "Minimum prefix length\n"
1408 "Maximum prefix length to be matched\n"
1409 "Maximum prefix length\n")
1410 {
1411 return plist_remove(vty, "ipv4", name, seq_str, action, prefix_str,
1412 ge_str, le_str);
1413 }
1414
1415 DEFPY_YANG(
1416 no_ip_prefix_list_seq, no_ip_prefix_list_seq_cmd,
1417 "no ip prefix-list WORD$name seq (1-4294967295)$seq",
1418 NO_STR
1419 IP_STR
1420 PREFIX_LIST_STR
1421 PREFIX_LIST_NAME_STR
1422 ACCESS_LIST_SEQ_STR)
1423 {
1424 return plist_remove(vty, "ipv4", name, seq_str, NULL, NULL, NULL, NULL);
1425 }
1426
1427 DEFPY_YANG(
1428 no_ip_prefix_list_all, no_ip_prefix_list_all_cmd,
1429 "no ip prefix-list WORD$name",
1430 NO_STR
1431 IP_STR
1432 PREFIX_LIST_STR
1433 PREFIX_LIST_NAME_STR)
1434 {
1435 char xpath[XPATH_MAXLEN];
1436
1437 snprintf(xpath, sizeof(xpath),
1438 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
1439 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
1440
1441 return nb_cli_apply_changes(vty, NULL);
1442 }
1443
1444 DEFPY_YANG(
1445 ip_prefix_list_remark, ip_prefix_list_remark_cmd,
1446 "ip prefix-list WORD$name description LINE...",
1447 IP_STR
1448 PREFIX_LIST_STR
1449 PREFIX_LIST_NAME_STR
1450 ACCESS_LIST_REMARK_STR
1451 ACCESS_LIST_REMARK_LINE_STR)
1452 {
1453 int rv;
1454 char *remark;
1455 char xpath[XPATH_MAXLEN];
1456
1457 snprintf(xpath, sizeof(xpath),
1458 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']", name);
1459 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1460
1461 remark = argv_concat(argv, argc, 4);
1462 nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
1463 rv = nb_cli_apply_changes(vty, xpath);
1464 XFREE(MTYPE_TMP, remark);
1465
1466 return rv;
1467 }
1468
1469 DEFPY_YANG(
1470 no_ip_prefix_list_remark, no_ip_prefix_list_remark_cmd,
1471 "no ip prefix-list WORD$name description",
1472 NO_STR
1473 IP_STR
1474 PREFIX_LIST_STR
1475 PREFIX_LIST_NAME_STR
1476 ACCESS_LIST_REMARK_STR)
1477 {
1478 char xpath[XPATH_MAXLEN];
1479 int rv;
1480
1481 snprintf(xpath, sizeof(xpath),
1482 "/frr-filter:lib/prefix-list[type='ipv4'][name='%s']/remark",
1483 name);
1484 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
1485
1486 rv = nb_cli_apply_changes(vty, NULL);
1487 if (rv == CMD_SUCCESS)
1488 return plist_remove_if_empty(vty, "ipv4", name);
1489
1490 return rv;
1491 }
1492
1493 ALIAS(
1494 no_ip_prefix_list_remark, no_ip_prefix_list_remark_line_cmd,
1495 "no ip prefix-list WORD$name description LINE...",
1496 NO_STR
1497 IP_STR
1498 PREFIX_LIST_STR
1499 PREFIX_LIST_NAME_STR
1500 ACCESS_LIST_REMARK_STR
1501 ACCESS_LIST_REMARK_LINE_STR)
1502
1503 DEFPY_YANG(
1504 ipv6_prefix_list, ipv6_prefix_list_cmd,
1505 "ipv6 prefix-list WORD$name [seq (1-4294967295)] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
1506 IPV6_STR
1507 PREFIX_LIST_STR
1508 PREFIX_LIST_NAME_STR
1509 ACCESS_LIST_SEQ_STR
1510 ACCESS_LIST_ACTION_STR
1511 "Any prefix match. Same as \"::0/0 le 128\"\n"
1512 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1513 "Maximum prefix length to be matched\n"
1514 "Maximum prefix length\n"
1515 "Minimum prefix length to be matched\n"
1516 "Minimum prefix length\n")
1517 {
1518 int64_t sseq;
1519 int arg_idx = 0;
1520 struct plist_dup_args pda = {};
1521 char xpath[XPATH_MAXLEN];
1522 char xpath_entry[XPATH_MAXLEN + 128];
1523
1524 /*
1525 * Backward compatibility: don't complain about duplicated values,
1526 * just silently accept.
1527 */
1528 if (seq_str == NULL) {
1529 pda.pda_type = "ipv6";
1530 pda.pda_name = name;
1531 pda.pda_action = action;
1532 if (prefix_str) {
1533 pda.pda_xpath[arg_idx] = "./ipv6-prefix";
1534 pda.pda_value[arg_idx] = prefix_str;
1535 arg_idx++;
1536 if (ge_str) {
1537 pda.pda_xpath[arg_idx] =
1538 "./ipv6-prefix-length-greater-or-equal";
1539 pda.pda_value[arg_idx] = ge_str;
1540 arg_idx++;
1541 }
1542 if (le_str) {
1543 pda.pda_xpath[arg_idx] =
1544 "./ipv6-prefix-length-lesser-or-equal";
1545 pda.pda_value[arg_idx] = le_str;
1546 arg_idx++;
1547 }
1548 } else {
1549 pda.pda_xpath[0] = "./any";
1550 pda.pda_value[0] = "";
1551 }
1552
1553 /* Duplicated entry without sequence, just quit. */
1554 if (plist_is_dup(vty->candidate_config->dnode, &pda))
1555 return CMD_SUCCESS;
1556 }
1557
1558 /*
1559 * Create the prefix-list first, so we can generate sequence if
1560 * none given (backward compatibility).
1561 */
1562 snprintf(xpath, sizeof(xpath),
1563 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
1564 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1565 if (seq_str == NULL) {
1566 /* Use XPath to find the next sequence number. */
1567 sseq = acl_get_seq(vty, xpath);
1568 snprintfrr(xpath_entry, sizeof(xpath_entry),
1569 "%s/entry[sequence='%" PRId64 "']", xpath, sseq);
1570 } else
1571 snprintfrr(xpath_entry, sizeof(xpath_entry),
1572 "%s/entry[sequence='%s']", xpath, seq_str);
1573
1574 nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL);
1575
1576 nb_cli_enqueue_change(vty, "./action", NB_OP_MODIFY, action);
1577 if (prefix_str != NULL) {
1578 nb_cli_enqueue_change(vty, "./ipv6-prefix", NB_OP_MODIFY,
1579 prefix_str);
1580
1581 if (ge_str) {
1582 nb_cli_enqueue_change(
1583 vty, "./ipv6-prefix-length-greater-or-equal",
1584 NB_OP_MODIFY, ge_str);
1585 } else {
1586 /*
1587 * Remove old ge if not being modified
1588 */
1589 nb_cli_enqueue_change(
1590 vty, "./ipv6-prefix-length-greater-or-equal",
1591 NB_OP_DESTROY, NULL);
1592 }
1593
1594 if (le_str) {
1595 nb_cli_enqueue_change(
1596 vty, "./ipv6-prefix-length-lesser-or-equal",
1597 NB_OP_MODIFY, le_str);
1598 } else {
1599 /*
1600 * Remove old le if not being modified
1601 */
1602 nb_cli_enqueue_change(
1603 vty, "./ipv6-prefix-length-lesser-or-equal",
1604 NB_OP_DESTROY, NULL);
1605 }
1606 } else {
1607 nb_cli_enqueue_change(vty, "./any", NB_OP_CREATE, NULL);
1608 }
1609
1610 return nb_cli_apply_changes(vty, xpath_entry);
1611 }
1612
1613 DEFPY_YANG(
1614 no_ipv6_prefix_list, no_ipv6_prefix_list_cmd,
1615 "no ipv6 prefix-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <any|X:X::X:X/M$prefix [{ge (0-128)$ge|le (0-128)$le}]>",
1616 NO_STR
1617 IPV6_STR
1618 PREFIX_LIST_STR
1619 PREFIX_LIST_NAME_STR
1620 ACCESS_LIST_SEQ_STR
1621 ACCESS_LIST_ACTION_STR
1622 "Any prefix match. Same as \"::0/0 le 128\"\n"
1623 "IPv6 prefix <network>/<length>, e.g., 3ffe::/16\n"
1624 "Maximum prefix length to be matched\n"
1625 "Maximum prefix length\n"
1626 "Minimum prefix length to be matched\n"
1627 "Minimum prefix length\n")
1628 {
1629 return plist_remove(vty, "ipv6", name, seq_str, action, prefix_str,
1630 ge_str, le_str);
1631 }
1632
1633 DEFPY_YANG(
1634 no_ipv6_prefix_list_seq, no_ipv6_prefix_list_seq_cmd,
1635 "no ipv6 prefix-list WORD$name seq (1-4294967295)$seq",
1636 NO_STR
1637 IPV6_STR
1638 PREFIX_LIST_STR
1639 PREFIX_LIST_NAME_STR
1640 ACCESS_LIST_SEQ_STR)
1641 {
1642 return plist_remove(vty, "ipv6", name, seq_str, NULL, NULL, NULL, NULL);
1643 }
1644
1645 DEFPY_YANG(
1646 no_ipv6_prefix_list_all, no_ipv6_prefix_list_all_cmd,
1647 "no ipv6 prefix-list WORD$name",
1648 NO_STR
1649 IPV6_STR
1650 PREFIX_LIST_STR
1651 PREFIX_LIST_NAME_STR)
1652 {
1653 char xpath[XPATH_MAXLEN];
1654
1655 snprintf(xpath, sizeof(xpath),
1656 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
1657 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
1658
1659 return nb_cli_apply_changes(vty, NULL);
1660 }
1661
1662 DEFPY_YANG(
1663 ipv6_prefix_list_remark, ipv6_prefix_list_remark_cmd,
1664 "ipv6 prefix-list WORD$name description LINE...",
1665 IPV6_STR
1666 PREFIX_LIST_STR
1667 PREFIX_LIST_NAME_STR
1668 ACCESS_LIST_REMARK_STR
1669 ACCESS_LIST_REMARK_LINE_STR)
1670 {
1671 int rv;
1672 char *remark;
1673 char xpath[XPATH_MAXLEN];
1674
1675 snprintf(xpath, sizeof(xpath),
1676 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']", name);
1677 nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
1678
1679 remark = argv_concat(argv, argc, 4);
1680 nb_cli_enqueue_change(vty, "./remark", NB_OP_CREATE, remark);
1681 rv = nb_cli_apply_changes(vty, xpath);
1682 XFREE(MTYPE_TMP, remark);
1683
1684 return rv;
1685 }
1686
1687 DEFPY_YANG(
1688 no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_cmd,
1689 "no ipv6 prefix-list WORD$name description",
1690 NO_STR
1691 IPV6_STR
1692 PREFIX_LIST_STR
1693 PREFIX_LIST_NAME_STR
1694 ACCESS_LIST_REMARK_STR)
1695 {
1696 char xpath[XPATH_MAXLEN];
1697 int rv;
1698
1699 snprintf(xpath, sizeof(xpath),
1700 "/frr-filter:lib/prefix-list[type='ipv6'][name='%s']/remark",
1701 name);
1702 nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
1703
1704 rv = nb_cli_apply_changes(vty, NULL);
1705 if (rv == CMD_SUCCESS)
1706 return plist_remove_if_empty(vty, "ipv6", name);
1707
1708 return rv;
1709 }
1710
1711 ALIAS(
1712 no_ipv6_prefix_list_remark, no_ipv6_prefix_list_remark_line_cmd,
1713 "no ipv6 prefix-list WORD$name description LINE...",
1714 NO_STR
1715 IPV6_STR
1716 PREFIX_LIST_STR
1717 PREFIX_LIST_NAME_STR
1718 ACCESS_LIST_REMARK_STR
1719 ACCESS_LIST_REMARK_LINE_STR)
1720
1721 int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2)
1722 {
1723 uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence");
1724 uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence");
1725
1726 return seq1 - seq2;
1727 }
1728
1729 void prefix_list_show(struct vty *vty, struct lyd_node *dnode,
1730 bool show_defaults)
1731 {
1732 int type = yang_dnode_get_enum(dnode, "../type");
1733 const char *ge_str = NULL, *le_str = NULL;
1734 bool is_any;
1735 struct prefix p;
1736
1737 is_any = yang_dnode_exists(dnode, "./any");
1738 switch (type) {
1739 case YPLT_IPV4:
1740 if (!is_any)
1741 yang_dnode_get_prefix(&p, dnode, "./ipv4-prefix");
1742 if (yang_dnode_exists(dnode,
1743 "./ipv4-prefix-length-greater-or-equal"))
1744 ge_str = yang_dnode_get_string(
1745 dnode, "./ipv4-prefix-length-greater-or-equal");
1746 if (yang_dnode_exists(dnode,
1747 "./ipv4-prefix-length-lesser-or-equal"))
1748 le_str = yang_dnode_get_string(
1749 dnode, "./ipv4-prefix-length-lesser-or-equal");
1750
1751 vty_out(vty, "ip ");
1752 break;
1753 case YPLT_IPV6:
1754 if (!is_any)
1755 yang_dnode_get_prefix(&p, dnode, "ipv6-prefix");
1756 if (yang_dnode_exists(dnode,
1757 "./ipv6-prefix-length-greater-or-equal"))
1758 ge_str = yang_dnode_get_string(
1759 dnode, "./ipv6-prefix-length-greater-or-equal");
1760 if (yang_dnode_exists(dnode,
1761 "./ipv6-prefix-length-lesser-or-equal"))
1762 le_str = yang_dnode_get_string(
1763 dnode, "./ipv6-prefix-length-lesser-or-equal");
1764
1765 vty_out(vty, "ipv6 ");
1766 break;
1767 }
1768
1769 vty_out(vty, "prefix-list %s seq %s %s",
1770 yang_dnode_get_string(dnode, "../name"),
1771 yang_dnode_get_string(dnode, "./sequence"),
1772 yang_dnode_get_string(dnode, "./action"));
1773
1774 if (is_any) {
1775 vty_out(vty, " any\n");
1776 return;
1777 }
1778
1779 vty_out(vty, " %pFX", &p);
1780 if (ge_str)
1781 vty_out(vty, " ge %s", ge_str);
1782 if (le_str)
1783 vty_out(vty, " le %s", le_str);
1784
1785 vty_out(vty, "\n");
1786 }
1787
1788 void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode,
1789 bool show_defaults)
1790 {
1791 int type = yang_dnode_get_enum(dnode, "../type");
1792
1793 switch (type) {
1794 case YPLT_IPV4:
1795 vty_out(vty, "ip ");
1796 break;
1797 case YPLT_IPV6:
1798 vty_out(vty, "ipv6 ");
1799 break;
1800 }
1801
1802 vty_out(vty, "prefix-list %s description %s\n",
1803 yang_dnode_get_string(dnode, "../name"),
1804 yang_dnode_get_string(dnode, NULL));
1805 }
1806
1807 void filter_cli_init(void)
1808 {
1809 /* access-list cisco-style (legacy). */
1810 install_element(CONFIG_NODE, &access_list_std_cmd);
1811 install_element(CONFIG_NODE, &no_access_list_std_cmd);
1812 install_element(CONFIG_NODE, &access_list_ext_cmd);
1813 install_element(CONFIG_NODE, &no_access_list_ext_cmd);
1814
1815 /* access-list zebra-style. */
1816 install_element(CONFIG_NODE, &access_list_cmd);
1817 install_element(CONFIG_NODE, &no_access_list_cmd);
1818 install_element(CONFIG_NODE, &no_access_list_all_cmd);
1819 install_element(CONFIG_NODE, &access_list_remark_cmd);
1820 install_element(CONFIG_NODE, &no_access_list_remark_cmd);
1821 install_element(CONFIG_NODE, &no_access_list_remark_line_cmd);
1822
1823 install_element(CONFIG_NODE, &ipv6_access_list_cmd);
1824 install_element(CONFIG_NODE, &no_ipv6_access_list_cmd);
1825 install_element(CONFIG_NODE, &no_ipv6_access_list_all_cmd);
1826 install_element(CONFIG_NODE, &ipv6_access_list_remark_cmd);
1827 install_element(CONFIG_NODE, &no_ipv6_access_list_remark_cmd);
1828 install_element(CONFIG_NODE, &no_ipv6_access_list_remark_line_cmd);
1829
1830 install_element(CONFIG_NODE, &mac_access_list_cmd);
1831 install_element(CONFIG_NODE, &no_mac_access_list_cmd);
1832 install_element(CONFIG_NODE, &no_mac_access_list_all_cmd);
1833 install_element(CONFIG_NODE, &mac_access_list_remark_cmd);
1834 install_element(CONFIG_NODE, &no_mac_access_list_remark_cmd);
1835 install_element(CONFIG_NODE, &no_mac_access_list_remark_line_cmd);
1836
1837 /* prefix lists. */
1838 install_element(CONFIG_NODE, &ip_prefix_list_cmd);
1839 install_element(CONFIG_NODE, &no_ip_prefix_list_cmd);
1840 install_element(CONFIG_NODE, &no_ip_prefix_list_seq_cmd);
1841 install_element(CONFIG_NODE, &no_ip_prefix_list_all_cmd);
1842 install_element(CONFIG_NODE, &ip_prefix_list_remark_cmd);
1843 install_element(CONFIG_NODE, &no_ip_prefix_list_remark_cmd);
1844 install_element(CONFIG_NODE, &no_ip_prefix_list_remark_line_cmd);
1845
1846 install_element(CONFIG_NODE, &ipv6_prefix_list_cmd);
1847 install_element(CONFIG_NODE, &no_ipv6_prefix_list_cmd);
1848 install_element(CONFIG_NODE, &no_ipv6_prefix_list_seq_cmd);
1849 install_element(CONFIG_NODE, &no_ipv6_prefix_list_all_cmd);
1850 install_element(CONFIG_NODE, &ipv6_prefix_list_remark_cmd);
1851 install_element(CONFIG_NODE, &no_ipv6_prefix_list_remark_cmd);
1852 install_element(CONFIG_NODE, &no_ipv6_prefix_list_remark_line_cmd);
1853 }