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