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