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