]>
Commit | Line | Data |
---|---|---|
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 | */ | |
38 | static 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 | 57 | static 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 |
72 | static 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 | ||
100 | static 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 | 122 | DEFPY_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 | 198 | DEFPY_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 | 243 | DEFPY_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 | 361 | DEFPY_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 | 438 | DEFPY_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 | 511 | DEFPY_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 | 555 | DEFPY_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 | 571 | DEFPY_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 | 595 | DEFPY_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 |
618 | ALIAS( |
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 | 627 | DEFPY_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 | 701 | DEFPY_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 | 746 | DEFPY_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 | 763 | DEFPY_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 | 788 | DEFPY_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 |
812 | ALIAS( |
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 | 822 | DEFPY_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 | 888 | DEFPY_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 | 928 | DEFPY_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 | 945 | DEFPY_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 | 970 | DEFPY_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 |
994 | ALIAS( |
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 |
1004 | int 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 | 1013 | void 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 | 1127 | void 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 | */ | |
1156 | static 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 | 1184 | static 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 | 1240 | DEFPY_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 | 1336 | DEFPY_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 | 1356 | DEFPY_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 | 1368 | DEFPY_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 | 1385 | DEFPY_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 | 1410 | DEFPY_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 | ||
1434 | ALIAS( | |
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 | 1444 | DEFPY_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 | 1540 | DEFPY_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 | 1560 | DEFPY_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 | 1572 | DEFPY_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 | 1589 | DEFPY_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 | 1614 | DEFPY_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 | ||
1638 | ALIAS( | |
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 |
1648 | int 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 | 1657 | void 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 | 1716 | void 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 |
1735 | void 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 | } |