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