]> git.proxmox.com Git - mirror_frr.git/blob - lib/filter_nb.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / lib / filter_nb.c
1 /*
2 * FRR filter northbound implementation.
3 *
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
5 * Rafael Zalamena
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23 #include "zebra.h"
24
25 #include "lib/northbound.h"
26 #include "lib/prefix.h"
27 #include "lib/printfrr.h"
28
29 #include "lib/filter.h"
30 #include "lib/plist.h"
31 #include "lib/plist_int.h"
32 #include "lib/routemap.h"
33
34 /* Helper function. */
35 static void acl_notify_route_map(struct access_list *acl, int route_map_event)
36 {
37 switch (route_map_event) {
38 case RMAP_EVENT_FILTER_ADDED:
39 if (acl->master->add_hook)
40 (*acl->master->add_hook)(acl);
41 break;
42 case RMAP_EVENT_FILTER_DELETED:
43 if (acl->master->delete_hook)
44 (*acl->master->delete_hook)(acl);
45 break;
46 }
47
48 route_map_notify_dependencies(acl->name, route_map_event);
49 }
50
51 static enum nb_error prefix_list_length_validate(struct nb_cb_modify_args *args)
52 {
53 int type = yang_dnode_get_enum(args->dnode, "../../type");
54 const char *xpath_le = NULL, *xpath_ge = NULL;
55 struct prefix p;
56 uint8_t le, ge;
57
58 if (type == YPLT_IPV4) {
59 yang_dnode_get_prefix(&p, args->dnode, "../ipv4-prefix");
60 xpath_le = "../ipv4-prefix-length-lesser-or-equal";
61 xpath_ge = "../ipv4-prefix-length-greater-or-equal";
62 } else {
63 yang_dnode_get_prefix(&p, args->dnode, "../ipv6-prefix");
64 xpath_le = "../ipv6-prefix-length-lesser-or-equal";
65 xpath_ge = "../ipv6-prefix-length-greater-or-equal";
66 }
67
68 /*
69 * Check rule:
70 * prefix length <= le.
71 */
72 if (yang_dnode_exists(args->dnode, xpath_le)) {
73 le = yang_dnode_get_uint8(args->dnode, "%s", xpath_le);
74 if (p.prefixlen > le)
75 goto log_and_fail;
76 }
77
78 /*
79 * Check rule:
80 * prefix length <= ge.
81 */
82 if (yang_dnode_exists(args->dnode, xpath_ge)) {
83 ge = yang_dnode_get_uint8(args->dnode, "%s", xpath_ge);
84 if (p.prefixlen > ge)
85 goto log_and_fail;
86 }
87
88 /*
89 * Check rule:
90 * ge <= le.
91 */
92 if (yang_dnode_exists(args->dnode, xpath_le)
93 && yang_dnode_exists(args->dnode, xpath_ge)) {
94 le = yang_dnode_get_uint8(args->dnode, "%s", xpath_le);
95 ge = yang_dnode_get_uint8(args->dnode, "%s", xpath_ge);
96 if (ge > le)
97 goto log_and_fail;
98 }
99
100 return NB_OK;
101
102 log_and_fail:
103 snprintfrr(
104 args->errmsg, args->errmsg_len,
105 "Invalid prefix range for %pFX: Make sure that mask length <= ge <= le",
106 &p);
107 return NB_ERR_VALIDATION;
108 }
109
110 /**
111 * Sets prefix list entry to blank value.
112 *
113 * \param[out] ple prefix list entry to modify.
114 */
115 static void prefix_list_entry_set_empty(struct prefix_list_entry *ple)
116 {
117 ple->any = false;
118 memset(&ple->prefix, 0, sizeof(ple->prefix));
119 ple->ge = 0;
120 ple->le = 0;
121 }
122
123 static int
124 prefix_list_nb_validate_v4_af_type(const struct lyd_node *plist_dnode,
125 char *errmsg, size_t errmsg_len)
126 {
127 int af_type;
128
129 af_type = yang_dnode_get_enum(plist_dnode, "./type");
130 if (af_type != YPLT_IPV4) {
131 snprintf(errmsg, errmsg_len,
132 "prefix-list type %u is mismatched.", af_type);
133 return NB_ERR_VALIDATION;
134 }
135
136 return NB_OK;
137 }
138
139 static int
140 prefix_list_nb_validate_v6_af_type(const struct lyd_node *plist_dnode,
141 char *errmsg, size_t errmsg_len)
142 {
143 int af_type;
144
145 af_type = yang_dnode_get_enum(plist_dnode, "./type");
146 if (af_type != YPLT_IPV6) {
147 snprintf(errmsg, errmsg_len,
148 "prefix-list type %u is mismatched.", af_type);
149 return NB_ERR_VALIDATION;
150 }
151
152 return NB_OK;
153 }
154
155 static int lib_prefix_list_entry_prefix_length_greater_or_equal_modify(
156 struct nb_cb_modify_args *args)
157 {
158 struct prefix_list_entry *ple;
159
160 if (args->event != NB_EV_APPLY)
161 return NB_OK;
162
163 ple = nb_running_get_entry(args->dnode, NULL, true);
164
165 /* Start prefix entry update procedure. */
166 prefix_list_entry_update_start(ple);
167
168 ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
169
170 /* Finish prefix entry update procedure. */
171 prefix_list_entry_update_finish(ple);
172
173 return NB_OK;
174 }
175
176 static int lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
177 struct nb_cb_modify_args *args)
178 {
179 struct prefix_list_entry *ple;
180
181 if (args->event != NB_EV_APPLY)
182 return NB_OK;
183
184 ple = nb_running_get_entry(args->dnode, NULL, true);
185
186 /* Start prefix entry update procedure. */
187 prefix_list_entry_update_start(ple);
188
189 ple->le = yang_dnode_get_uint8(args->dnode, NULL);
190
191 /* Finish prefix entry update procedure. */
192 prefix_list_entry_update_finish(ple);
193
194 return NB_OK;
195 }
196
197 static int lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
198 struct nb_cb_destroy_args *args)
199 {
200 struct prefix_list_entry *ple;
201
202 if (args->event != NB_EV_APPLY)
203 return NB_OK;
204
205 ple = nb_running_get_entry(args->dnode, NULL, true);
206
207 /* Start prefix entry update procedure. */
208 prefix_list_entry_update_start(ple);
209
210 ple->ge = 0;
211
212 /* Finish prefix entry update procedure. */
213 prefix_list_entry_update_finish(ple);
214
215 return NB_OK;
216 }
217
218 static int lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
219 struct nb_cb_destroy_args *args)
220 {
221 struct prefix_list_entry *ple;
222
223 if (args->event != NB_EV_APPLY)
224 return NB_OK;
225
226 ple = nb_running_get_entry(args->dnode, NULL, true);
227
228 /* Start prefix entry update procedure. */
229 prefix_list_entry_update_start(ple);
230
231 ple->le = 0;
232
233 /* Finish prefix entry update procedure. */
234 prefix_list_entry_update_finish(ple);
235
236 return NB_OK;
237 }
238
239 /**
240 * Unsets the cisco style rule for addresses so it becomes disabled (the
241 * equivalent of setting: `0.0.0.0/32`).
242 *
243 * \param addr address part.
244 * \param mask mask part.
245 */
246 static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask)
247 {
248 addr->s_addr = INADDR_ANY;
249 mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
250 }
251
252 static int _acl_is_dup(const struct lyd_node *dnode, void *arg)
253 {
254 struct acl_dup_args *ada = arg;
255 int idx;
256
257 /* This entry is the caller, so skip it. */
258 if (ada->ada_entry_dnode
259 && ada->ada_entry_dnode == dnode)
260 return YANG_ITER_CONTINUE;
261
262 if (strcmp(yang_dnode_get_string(dnode, "action"), ada->ada_action))
263 return YANG_ITER_CONTINUE;
264
265 /* Check if all values match. */
266 for (idx = 0; idx < ADA_MAX_VALUES; idx++) {
267 /* No more values. */
268 if (ada->ada_xpath[idx] == NULL)
269 break;
270
271 /* Not same type, just skip it. */
272 if (!yang_dnode_exists(dnode, ada->ada_xpath[idx]))
273 return YANG_ITER_CONTINUE;
274
275 /* Check if different value. */
276 if (strcmp(yang_dnode_get_string(dnode, "%s",
277 ada->ada_xpath[idx]),
278 ada->ada_value[idx]))
279 return YANG_ITER_CONTINUE;
280 }
281
282 ada->ada_found = true;
283 ada->ada_seq = yang_dnode_get_uint32(dnode, "sequence");
284
285 return YANG_ITER_STOP;
286 }
287
288 bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada)
289 {
290 ada->ada_found = false;
291
292 yang_dnode_iterate(
293 _acl_is_dup, ada, dnode,
294 "/frr-filter:lib/access-list[type='%s'][name='%s']/entry",
295 ada->ada_type, ada->ada_name);
296
297 return ada->ada_found;
298 }
299
300 static bool acl_cisco_is_dup(const struct lyd_node *dnode)
301 {
302 const struct lyd_node *entry_dnode =
303 yang_dnode_get_parent(dnode, "entry");
304 struct acl_dup_args ada = {};
305 int idx = 0, arg_idx = 0;
306 static const char *cisco_entries[] = {
307 "./host",
308 "./network/address",
309 "./network/mask",
310 "./source-any",
311 "./destination-host",
312 "./destination-network/address",
313 "./destination-network/mask",
314 "./destination-any",
315 NULL
316 };
317
318 /* Initialize. */
319 ada.ada_type = "ipv4";
320 ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
321 ada.ada_action = yang_dnode_get_string(entry_dnode, "action");
322 ada.ada_entry_dnode = entry_dnode;
323
324 /* Load all values/XPaths. */
325 while (cisco_entries[idx] != NULL) {
326 if (!yang_dnode_exists(entry_dnode, cisco_entries[idx])) {
327 idx++;
328 continue;
329 }
330
331 ada.ada_xpath[arg_idx] = cisco_entries[idx];
332 ada.ada_value[arg_idx] = yang_dnode_get_string(
333 entry_dnode, "%s", cisco_entries[idx]);
334 arg_idx++;
335 idx++;
336 }
337
338 return acl_is_dup(entry_dnode, &ada);
339 }
340
341 static bool acl_zebra_is_dup(const struct lyd_node *dnode,
342 enum yang_access_list_type type)
343 {
344 const struct lyd_node *entry_dnode =
345 yang_dnode_get_parent(dnode, "entry");
346 struct acl_dup_args ada = {};
347 int idx = 0, arg_idx = 0;
348 static const char *zebra_entries[] = {
349 "./ipv4-prefix",
350 "./ipv4-exact-match",
351 "./ipv6-prefix",
352 "./ipv6-exact-match",
353 "./mac",
354 "./any",
355 NULL
356 };
357
358 /* Initialize. */
359 switch (type) {
360 case YALT_IPV4:
361 ada.ada_type = "ipv4";
362 break;
363 case YALT_IPV6:
364 ada.ada_type = "ipv6";
365 break;
366 case YALT_MAC:
367 ada.ada_type = "mac";
368 break;
369 }
370 ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
371 ada.ada_action = yang_dnode_get_string(entry_dnode, "action");
372 ada.ada_entry_dnode = entry_dnode;
373
374 /* Load all values/XPaths. */
375 while (zebra_entries[idx] != NULL) {
376 if (!yang_dnode_exists(entry_dnode, zebra_entries[idx])) {
377 idx++;
378 continue;
379 }
380
381 ada.ada_xpath[arg_idx] = zebra_entries[idx];
382 ada.ada_value[arg_idx] = yang_dnode_get_string(
383 entry_dnode, "%s", zebra_entries[idx]);
384 arg_idx++;
385 idx++;
386 }
387
388 return acl_is_dup(entry_dnode, &ada);
389 }
390
391 static void plist_dnode_to_prefix(const struct lyd_node *dnode, bool *any,
392 struct prefix *p, int *ge, int *le)
393 {
394 *any = false;
395 *ge = 0;
396 *le = 0;
397
398 if (yang_dnode_exists(dnode, "./any")) {
399 *any = true;
400 return;
401 }
402
403 switch (yang_dnode_get_enum(dnode, "../type")) {
404 case YPLT_IPV4:
405 yang_dnode_get_prefix(p, dnode, "./ipv4-prefix");
406 if (yang_dnode_exists(dnode,
407 "./ipv4-prefix-length-greater-or-equal"))
408 *ge = yang_dnode_get_uint8(
409 dnode, "./ipv4-prefix-length-greater-or-equal");
410 if (yang_dnode_exists(dnode,
411 "./ipv4-prefix-length-lesser-or-equal"))
412 *le = yang_dnode_get_uint8(
413 dnode, "./ipv4-prefix-length-lesser-or-equal");
414 break;
415 case YPLT_IPV6:
416 yang_dnode_get_prefix(p, dnode, "./ipv6-prefix");
417 if (yang_dnode_exists(dnode,
418 "./ipv6-prefix-length-greater-or-equal"))
419 *ge = yang_dnode_get_uint8(
420 dnode, "./ipv6-prefix-length-greater-or-equal");
421 if (yang_dnode_exists(dnode,
422 "./ipv6-prefix-length-lesser-or-equal"))
423 *le = yang_dnode_get_uint8(
424 dnode, "./ipv6-prefix-length-lesser-or-equal");
425 break;
426 }
427 }
428
429 static int _plist_is_dup(const struct lyd_node *dnode, void *arg)
430 {
431 struct plist_dup_args *pda = arg;
432 struct prefix p = {};
433 int ge, le;
434 bool any;
435
436 /* This entry is the caller, so skip it. */
437 if (pda->pda_entry_dnode
438 && pda->pda_entry_dnode == dnode)
439 return YANG_ITER_CONTINUE;
440
441 if (strcmp(yang_dnode_get_string(dnode, "action"), pda->pda_action))
442 return YANG_ITER_CONTINUE;
443
444 plist_dnode_to_prefix(dnode, &any, &p, &ge, &le);
445
446 if (pda->any) {
447 if (!any)
448 return YANG_ITER_CONTINUE;
449 } else {
450 if (!prefix_same(&pda->prefix, &p) || pda->ge != ge
451 || pda->le != le)
452 return YANG_ITER_CONTINUE;
453 }
454
455 pda->pda_found = true;
456 pda->pda_seq = yang_dnode_get_uint32(dnode, "sequence");
457
458 return YANG_ITER_STOP;
459 }
460
461 bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda)
462 {
463 pda->pda_found = false;
464
465 yang_dnode_iterate(
466 _plist_is_dup, pda, dnode,
467 "/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry",
468 pda->pda_type, pda->pda_name);
469
470 return pda->pda_found;
471 }
472
473 static bool plist_is_dup_nb(const struct lyd_node *dnode)
474 {
475 const struct lyd_node *entry_dnode =
476 yang_dnode_get_parent(dnode, "entry");
477 struct plist_dup_args pda = {};
478
479 /* Initialize. */
480 pda.pda_type = yang_dnode_get_string(entry_dnode, "../type");
481 pda.pda_name = yang_dnode_get_string(entry_dnode, "../name");
482 pda.pda_action = yang_dnode_get_string(entry_dnode, "action");
483 pda.pda_entry_dnode = entry_dnode;
484
485 plist_dnode_to_prefix(entry_dnode, &pda.any, &pda.prefix, &pda.ge,
486 &pda.le);
487
488 return plist_is_dup(entry_dnode, &pda);
489 }
490
491 /*
492 * XPath: /frr-filter:lib/access-list
493 */
494 static int lib_access_list_create(struct nb_cb_create_args *args)
495 {
496 struct access_list *acl = NULL;
497 const char *acl_name;
498 int type;
499
500 if (args->event != NB_EV_APPLY)
501 return NB_OK;
502
503 type = yang_dnode_get_enum(args->dnode, "./type");
504 acl_name = yang_dnode_get_string(args->dnode, "./name");
505
506 switch (type) {
507 case YALT_IPV4:
508 acl = access_list_get(AFI_IP, acl_name);
509 break;
510 case YALT_IPV6:
511 acl = access_list_get(AFI_IP6, acl_name);
512 break;
513 case YALT_MAC:
514 acl = access_list_get(AFI_L2VPN, acl_name);
515 break;
516 }
517
518 nb_running_set_entry(args->dnode, acl);
519
520 return NB_OK;
521 }
522
523 static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
524 {
525 struct access_list *acl;
526
527 if (args->event != NB_EV_APPLY)
528 return NB_OK;
529
530 acl = nb_running_unset_entry(args->dnode);
531 access_list_delete(acl);
532
533 return NB_OK;
534 }
535
536 /*
537 * XPath: /frr-filter:lib/access-list/remark
538 */
539 static int lib_access_list_remark_modify(struct nb_cb_modify_args *args)
540 {
541 struct access_list *acl;
542 const char *remark;
543
544 if (args->event != NB_EV_APPLY)
545 return NB_OK;
546
547 acl = nb_running_get_entry(args->dnode, NULL, true);
548 if (acl->remark)
549 XFREE(MTYPE_TMP, acl->remark);
550
551 remark = yang_dnode_get_string(args->dnode, NULL);
552 acl->remark = XSTRDUP(MTYPE_TMP, remark);
553
554 return NB_OK;
555 }
556
557 static int
558 lib_access_list_remark_destroy(struct nb_cb_destroy_args *args)
559 {
560 struct access_list *acl;
561
562 if (args->event != NB_EV_APPLY)
563 return NB_OK;
564
565 acl = nb_running_get_entry(args->dnode, NULL, true);
566 if (acl->remark)
567 XFREE(MTYPE_TMP, acl->remark);
568
569 return NB_OK;
570 }
571
572
573 /*
574 * XPath: /frr-filter:lib/access-list/entry
575 */
576 static int lib_access_list_entry_create(struct nb_cb_create_args *args)
577 {
578 struct access_list *acl;
579 struct filter *f;
580
581 if (args->event != NB_EV_APPLY)
582 return NB_OK;
583
584 f = filter_new();
585 f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
586
587 acl = nb_running_get_entry(args->dnode, NULL, true);
588 f->acl = acl;
589 access_list_filter_add(acl, f);
590 nb_running_set_entry(args->dnode, f);
591
592 return NB_OK;
593 }
594
595 static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
596 {
597 struct access_list *acl;
598 struct filter *f;
599
600 if (args->event != NB_EV_APPLY)
601 return NB_OK;
602
603 f = nb_running_unset_entry(args->dnode);
604 acl = f->acl;
605 access_list_filter_delete(acl, f);
606
607 return NB_OK;
608 }
609
610 /*
611 * XPath: /frr-filter:lib/access-list/entry/action
612 */
613 static int
614 lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
615 {
616 const char *filter_type;
617 struct filter *f;
618
619 if (args->event != NB_EV_APPLY)
620 return NB_OK;
621
622 f = nb_running_get_entry(args->dnode, NULL, true);
623 filter_type = yang_dnode_get_string(args->dnode, NULL);
624 if (strcmp(filter_type, "permit") == 0)
625 f->type = FILTER_PERMIT;
626 else
627 f->type = FILTER_DENY;
628
629 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
630
631 return NB_OK;
632 }
633
634 /*
635 * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix
636 */
637 static int
638 lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
639 {
640 struct filter_zebra *fz;
641 struct filter *f;
642
643 /* Don't allow duplicated values. */
644 if (args->event == NB_EV_VALIDATE) {
645 if (acl_zebra_is_dup(
646 args->dnode,
647 yang_dnode_get_enum(args->dnode, "../../type"))) {
648 snprintfrr(args->errmsg, args->errmsg_len,
649 "duplicated access list value: %s",
650 yang_dnode_get_string(args->dnode, NULL));
651 return NB_ERR_VALIDATION;
652 }
653 return NB_OK;
654 }
655
656 if (args->event != NB_EV_APPLY)
657 return NB_OK;
658
659 f = nb_running_get_entry(args->dnode, NULL, true);
660 f->cisco = 0;
661 fz = &f->u.zfilter;
662 yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
663
664 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
665
666 return NB_OK;
667 }
668
669 static int
670 lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
671 {
672 struct filter_zebra *fz;
673 struct filter *f;
674
675 if (args->event != NB_EV_APPLY)
676 return NB_OK;
677
678 f = nb_running_get_entry(args->dnode, NULL, true);
679 fz = &f->u.zfilter;
680 memset(&fz->prefix, 0, sizeof(fz->prefix));
681
682 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
683
684 return NB_OK;
685 }
686
687 /*
688 * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match
689 */
690 static int
691 lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
692 {
693 struct filter_zebra *fz;
694 struct filter *f;
695
696 /* Don't allow duplicated values. */
697 if (args->event == NB_EV_VALIDATE) {
698 if (acl_zebra_is_dup(
699 args->dnode,
700 yang_dnode_get_enum(args->dnode, "../../type"))) {
701 snprintfrr(args->errmsg, args->errmsg_len,
702 "duplicated access list value: %s",
703 yang_dnode_get_string(args->dnode, NULL));
704 return NB_ERR_VALIDATION;
705 }
706 return NB_OK;
707 }
708
709 if (args->event != NB_EV_APPLY)
710 return NB_OK;
711
712 f = nb_running_get_entry(args->dnode, NULL, true);
713 fz = &f->u.zfilter;
714 fz->exact = yang_dnode_get_bool(args->dnode, NULL);
715
716 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
717
718 return NB_OK;
719 }
720
721 static int
722 lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
723 {
724 struct filter_zebra *fz;
725 struct filter *f;
726
727 if (args->event != NB_EV_APPLY)
728 return NB_OK;
729
730 f = nb_running_get_entry(args->dnode, NULL, true);
731 fz = &f->u.zfilter;
732 fz->exact = 0;
733
734 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
735
736 return NB_OK;
737 }
738
739 /*
740 * XPath: /frr-filter:lib/access-list/entry/host
741 */
742 static int
743 lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
744 {
745 struct filter_cisco *fc;
746 struct filter *f;
747
748 /* Don't allow duplicated values. */
749 if (args->event == NB_EV_VALIDATE) {
750 if (acl_cisco_is_dup(args->dnode)) {
751 snprintfrr(args->errmsg, args->errmsg_len,
752 "duplicated access list value: %s",
753 yang_dnode_get_string(args->dnode, NULL));
754 return NB_ERR_VALIDATION;
755 }
756 return NB_OK;
757 }
758
759 if (args->event != NB_EV_APPLY)
760 return NB_OK;
761
762 f = nb_running_get_entry(args->dnode, NULL, true);
763 f->cisco = 1;
764 fc = &f->u.cfilter;
765 yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
766 fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
767
768 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
769
770 return NB_OK;
771 }
772
773 static int
774 lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
775 {
776 struct filter_cisco *fc;
777 struct filter *f;
778
779 if (args->event != NB_EV_APPLY)
780 return NB_OK;
781
782 f = nb_running_get_entry(args->dnode, NULL, true);
783 fc = &f->u.cfilter;
784 cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
785
786 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
787
788 return NB_OK;
789 }
790
791 /*
792 * XPath: /frr-filter:lib/access-list/entry/network/address
793 */
794 static int
795 lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args)
796 {
797 struct filter_cisco *fc;
798 struct filter *f;
799
800 /* Don't allow duplicated values. */
801 if (args->event == NB_EV_VALIDATE) {
802 if (acl_cisco_is_dup(args->dnode)) {
803 snprintfrr(args->errmsg, args->errmsg_len,
804 "duplicated access list value: %s",
805 yang_dnode_get_string(args->dnode, NULL));
806 return NB_ERR_VALIDATION;
807 }
808 return NB_OK;
809 }
810
811 if (args->event != NB_EV_APPLY)
812 return NB_OK;
813
814 f = nb_running_get_entry(args->dnode, NULL, true);
815 f->cisco = 1;
816 fc = &f->u.cfilter;
817 yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
818
819 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
820
821 return NB_OK;
822 }
823
824 /*
825 * XPath: /frr-filter:lib/access-list/entry/network/mask
826 */
827 static int
828 lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args)
829 {
830 struct filter_cisco *fc;
831 struct filter *f;
832
833 /* Don't allow duplicated values. */
834 if (args->event == NB_EV_VALIDATE) {
835 if (acl_cisco_is_dup(args->dnode)) {
836 snprintfrr(args->errmsg, args->errmsg_len,
837 "duplicated access list value: %s",
838 yang_dnode_get_string(args->dnode, NULL));
839 return NB_ERR_VALIDATION;
840 }
841 return NB_OK;
842 }
843
844 if (args->event != NB_EV_APPLY)
845 return NB_OK;
846
847 f = nb_running_get_entry(args->dnode, NULL, true);
848 f->cisco = 1;
849 fc = &f->u.cfilter;
850 yang_dnode_get_ipv4(&fc->addr_mask, args->dnode, NULL);
851
852 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
853
854 return NB_OK;
855 }
856
857 /*
858 * XPath: /frr-filter:lib/access-list/entry/source-any
859 */
860 static int
861 lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
862 {
863 struct filter_cisco *fc;
864 struct filter *f;
865
866 /* Don't allow duplicated values. */
867 if (args->event == NB_EV_VALIDATE) {
868 if (acl_cisco_is_dup(args->dnode)) {
869 snprintfrr(args->errmsg, args->errmsg_len,
870 "duplicated access list value: %s",
871 yang_dnode_get_string(args->dnode, NULL));
872 return NB_ERR_VALIDATION;
873 }
874 return NB_OK;
875 }
876
877 if (args->event != NB_EV_APPLY)
878 return NB_OK;
879
880 f = nb_running_get_entry(args->dnode, NULL, true);
881 f->cisco = 1;
882 fc = &f->u.cfilter;
883 fc->addr.s_addr = INADDR_ANY;
884 fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
885
886 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
887
888 return NB_OK;
889 }
890
891 static int
892 lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)
893 {
894 struct filter_cisco *fc;
895 struct filter *f;
896
897 if (args->event != NB_EV_APPLY)
898 return NB_OK;
899
900 f = nb_running_get_entry(args->dnode, NULL, true);
901 fc = &f->u.cfilter;
902 cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
903
904 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
905
906 return NB_OK;
907 }
908
909 /*
910 * XPath: /frr-filter:lib/access-list/entry/destination-host
911 */
912 static int lib_access_list_entry_destination_host_modify(
913 struct nb_cb_modify_args *args)
914 {
915 struct filter_cisco *fc;
916 struct filter *f;
917
918 /* Don't allow duplicated values. */
919 if (args->event == NB_EV_VALIDATE) {
920 if (acl_cisco_is_dup(args->dnode)) {
921 snprintfrr(args->errmsg, args->errmsg_len,
922 "duplicated access list value: %s",
923 yang_dnode_get_string(args->dnode, NULL));
924 return NB_ERR_VALIDATION;
925 }
926 return NB_OK;
927 }
928
929 if (args->event != NB_EV_APPLY)
930 return NB_OK;
931
932 f = nb_running_get_entry(args->dnode, NULL, true);
933 fc = &f->u.cfilter;
934 fc->extended = 1;
935 yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
936 fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
937
938 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
939
940 return NB_OK;
941 }
942
943 static int lib_access_list_entry_destination_host_destroy(
944 struct nb_cb_destroy_args *args)
945 {
946 struct filter_cisco *fc;
947 struct filter *f;
948
949 if (args->event != NB_EV_APPLY)
950 return NB_OK;
951
952 f = nb_running_get_entry(args->dnode, NULL, true);
953 fc = &f->u.cfilter;
954 fc->extended = 0;
955 cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
956
957 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
958
959 return NB_OK;
960 }
961
962 /*
963 * XPath: /frr-filter:lib/access-list/entry/destination-network/address
964 */
965 static int lib_access_list_entry_destination_network_address_modify(
966 struct nb_cb_modify_args *args)
967 {
968 struct filter_cisco *fc;
969 struct filter *f;
970
971 /* Don't allow duplicated values. */
972 if (args->event == NB_EV_VALIDATE) {
973 if (acl_cisco_is_dup(args->dnode)) {
974 snprintfrr(args->errmsg, args->errmsg_len,
975 "duplicated access list value: %s",
976 yang_dnode_get_string(args->dnode, NULL));
977 return NB_ERR_VALIDATION;
978 }
979 return NB_OK;
980 }
981
982 if (args->event != NB_EV_APPLY)
983 return NB_OK;
984
985 f = nb_running_get_entry(args->dnode, NULL, true);
986 fc = &f->u.cfilter;
987 fc->extended = 1;
988 yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
989
990 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
991
992 return NB_OK;
993 }
994
995 /*
996 * XPath: /frr-filter:lib/access-list/entry/destination-network/mask
997 */
998 static int lib_access_list_entry_destination_network_mask_modify(
999 struct nb_cb_modify_args *args)
1000 {
1001 struct filter_cisco *fc;
1002 struct filter *f;
1003
1004 /* Don't allow duplicated values. */
1005 if (args->event == NB_EV_VALIDATE) {
1006 if (acl_cisco_is_dup(args->dnode)) {
1007 snprintfrr(args->errmsg, args->errmsg_len,
1008 "duplicated access list value: %s",
1009 yang_dnode_get_string(args->dnode, NULL));
1010 return NB_ERR_VALIDATION;
1011 }
1012 return NB_OK;
1013 }
1014
1015 if (args->event != NB_EV_APPLY)
1016 return NB_OK;
1017
1018 f = nb_running_get_entry(args->dnode, NULL, true);
1019 fc = &f->u.cfilter;
1020 fc->extended = 1;
1021 yang_dnode_get_ipv4(&fc->mask_mask, args->dnode, NULL);
1022
1023 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
1024
1025 return NB_OK;
1026 }
1027
1028 /*
1029 * XPath: /frr-filter:lib/access-list/entry/destination-any
1030 */
1031 static int lib_access_list_entry_destination_any_create(
1032 struct nb_cb_create_args *args)
1033 {
1034 struct filter_cisco *fc;
1035 struct filter *f;
1036
1037 /* Don't allow duplicated values. */
1038 if (args->event == NB_EV_VALIDATE) {
1039 if (acl_cisco_is_dup(args->dnode)) {
1040 snprintfrr(args->errmsg, args->errmsg_len,
1041 "duplicated access list value: %s",
1042 yang_dnode_get_string(args->dnode, NULL));
1043 return NB_ERR_VALIDATION;
1044 }
1045 return NB_OK;
1046 }
1047
1048 if (args->event != NB_EV_APPLY)
1049 return NB_OK;
1050
1051 f = nb_running_get_entry(args->dnode, NULL, true);
1052 fc = &f->u.cfilter;
1053 fc->extended = 1;
1054 fc->mask.s_addr = INADDR_ANY;
1055 fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
1056
1057 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
1058
1059 return NB_OK;
1060 }
1061
1062 static int lib_access_list_entry_destination_any_destroy(
1063 struct nb_cb_destroy_args *args)
1064 {
1065 struct filter_cisco *fc;
1066 struct filter *f;
1067
1068 if (args->event != NB_EV_APPLY)
1069 return NB_OK;
1070
1071 f = nb_running_get_entry(args->dnode, NULL, true);
1072 fc = &f->u.cfilter;
1073 fc->extended = 0;
1074 cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
1075
1076 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
1077
1078 return NB_OK;
1079 }
1080
1081 /*
1082 * XPath: /frr-filter:lib/access-list/entry/any
1083 */
1084 static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
1085 {
1086 struct filter_zebra *fz;
1087 struct filter *f;
1088 int type;
1089
1090 /* Don't allow duplicated values. */
1091 if (args->event == NB_EV_VALIDATE) {
1092 if (acl_zebra_is_dup(
1093 args->dnode,
1094 yang_dnode_get_enum(args->dnode, "../../type"))) {
1095 snprintfrr(args->errmsg, args->errmsg_len,
1096 "duplicated access list value: %s",
1097 yang_dnode_get_string(args->dnode, NULL));
1098 return NB_ERR_VALIDATION;
1099 }
1100 return NB_OK;
1101 }
1102
1103 if (args->event != NB_EV_APPLY)
1104 return NB_OK;
1105
1106 f = nb_running_get_entry(args->dnode, NULL, true);
1107 f->cisco = 0;
1108 fz = &f->u.zfilter;
1109 memset(&fz->prefix, 0, sizeof(fz->prefix));
1110
1111 type = yang_dnode_get_enum(args->dnode, "../../type");
1112 switch (type) {
1113 case YALT_IPV4:
1114 fz->prefix.family = AF_INET;
1115 break;
1116 case YALT_IPV6:
1117 fz->prefix.family = AF_INET6;
1118 break;
1119 case YALT_MAC:
1120 fz->prefix.family = AF_ETHERNET;
1121 break;
1122 }
1123
1124 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
1125
1126 return NB_OK;
1127 }
1128
1129 static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
1130 {
1131 struct filter_zebra *fz;
1132 struct filter *f;
1133
1134 if (args->event != NB_EV_APPLY)
1135 return NB_OK;
1136
1137 f = nb_running_get_entry(args->dnode, NULL, true);
1138 fz = &f->u.zfilter;
1139 fz->prefix.family = AF_UNSPEC;
1140
1141 acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
1142
1143 return NB_OK;
1144 }
1145
1146 /*
1147 * XPath: /frr-filter:lib/prefix-list
1148 */
1149 static int lib_prefix_list_create(struct nb_cb_create_args *args)
1150 {
1151 struct prefix_list *pl = NULL;
1152 const char *name;
1153 int type;
1154
1155 if (args->event != NB_EV_APPLY)
1156 return NB_OK;
1157
1158 type = yang_dnode_get_enum(args->dnode, "./type");
1159 name = yang_dnode_get_string(args->dnode, "./name");
1160 switch (type) {
1161 case 0: /* ipv4 */
1162 pl = prefix_list_get(AFI_IP, 0, name);
1163 break;
1164 case 1: /* ipv6 */
1165 pl = prefix_list_get(AFI_IP6, 0, name);
1166 break;
1167 }
1168
1169 nb_running_set_entry(args->dnode, pl);
1170
1171 return NB_OK;
1172 }
1173
1174 static int lib_prefix_list_destroy(struct nb_cb_destroy_args *args)
1175 {
1176 struct prefix_list *pl;
1177
1178 if (args->event != NB_EV_APPLY)
1179 return NB_OK;
1180
1181 pl = nb_running_unset_entry(args->dnode);
1182 prefix_list_delete(pl);
1183
1184 return NB_OK;
1185 }
1186
1187 /*
1188 * XPath: /frr-filter:lib/prefix-list/remark
1189 */
1190 static int lib_prefix_list_remark_modify(struct nb_cb_modify_args *args)
1191 {
1192 struct prefix_list *pl;
1193 const char *remark;
1194
1195 if (args->event != NB_EV_APPLY)
1196 return NB_OK;
1197
1198 pl = nb_running_get_entry(args->dnode, NULL, true);
1199 if (pl->desc)
1200 XFREE(MTYPE_TMP, pl->desc);
1201
1202 remark = yang_dnode_get_string(args->dnode, NULL);
1203 pl->desc = XSTRDUP(MTYPE_TMP, remark);
1204
1205 return NB_OK;
1206 }
1207
1208 static int lib_prefix_list_remark_destroy(struct nb_cb_destroy_args *args)
1209 {
1210 struct prefix_list *pl;
1211
1212 if (args->event != NB_EV_APPLY)
1213 return NB_OK;
1214
1215 pl = nb_running_get_entry(args->dnode, NULL, true);
1216 if (pl->desc)
1217 XFREE(MTYPE_TMP, pl->desc);
1218
1219 return NB_OK;
1220 }
1221
1222 /*
1223 * XPath: /frr-filter:lib/prefix-list/entry
1224 */
1225 static int lib_prefix_list_entry_create(struct nb_cb_create_args *args)
1226 {
1227 struct prefix_list_entry *ple;
1228 struct prefix_list *pl;
1229
1230 if (args->event != NB_EV_APPLY)
1231 return NB_OK;
1232
1233 pl = nb_running_get_entry(args->dnode, NULL, true);
1234 ple = prefix_list_entry_new();
1235 ple->pl = pl;
1236 ple->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
1237 prefix_list_entry_set_empty(ple);
1238 nb_running_set_entry(args->dnode, ple);
1239
1240 return NB_OK;
1241 }
1242
1243 static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args)
1244 {
1245 struct prefix_list_entry *ple;
1246
1247 if (args->event != NB_EV_APPLY)
1248 return NB_OK;
1249
1250 ple = nb_running_unset_entry(args->dnode);
1251 if (ple->installed)
1252 prefix_list_entry_delete2(ple);
1253 else
1254 prefix_list_entry_free(ple);
1255
1256 return NB_OK;
1257 }
1258
1259 /*
1260 * XPath: /frr-filter:lib/prefix-list/entry/action
1261 */
1262 static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args)
1263 {
1264 struct prefix_list_entry *ple;
1265 int action_type;
1266
1267 if (args->event != NB_EV_APPLY)
1268 return NB_OK;
1269
1270 ple = nb_running_get_entry(args->dnode, NULL, true);
1271
1272 /* Start prefix entry update procedure. */
1273 prefix_list_entry_update_start(ple);
1274
1275 action_type = yang_dnode_get_enum(args->dnode, NULL);
1276 if (action_type == YPLA_PERMIT)
1277 ple->type = PREFIX_PERMIT;
1278 else
1279 ple->type = PREFIX_DENY;
1280
1281 /* Finish prefix entry update procedure. */
1282 prefix_list_entry_update_finish(ple);
1283
1284 return NB_OK;
1285 }
1286
1287 static int lib_prefix_list_entry_prefix_modify(struct nb_cb_modify_args *args)
1288 {
1289 struct prefix_list_entry *ple;
1290 struct prefix p;
1291
1292 if (args->event != NB_EV_APPLY)
1293 return NB_OK;
1294
1295 ple = nb_running_get_entry(args->dnode, NULL, true);
1296
1297 /* Start prefix entry update procedure. */
1298 prefix_list_entry_update_start(ple);
1299
1300 yang_dnode_get_prefix(&ple->prefix, args->dnode, NULL);
1301
1302 /* Apply mask and correct original address if necessary. */
1303 prefix_copy(&p, &ple->prefix);
1304 apply_mask(&p);
1305 if (!prefix_same(&ple->prefix, &p)) {
1306 zlog_info("%s: bad network %pFX correcting it to %pFX",
1307 __func__, &ple->prefix, &p);
1308 prefix_copy(&ple->prefix, &p);
1309 }
1310
1311
1312 /* Finish prefix entry update procedure. */
1313 prefix_list_entry_update_finish(ple);
1314
1315 return NB_OK;
1316 }
1317
1318 static int lib_prefix_list_entry_prefix_destroy(struct nb_cb_destroy_args *args)
1319 {
1320 struct prefix_list_entry *ple;
1321
1322 if (args->event != NB_EV_APPLY)
1323 return NB_OK;
1324
1325 ple = nb_running_get_entry(args->dnode, NULL, true);
1326
1327 /* Start prefix entry update procedure. */
1328 prefix_list_entry_update_start(ple);
1329
1330 memset(&ple->prefix, 0, sizeof(ple->prefix));
1331
1332 /* Finish prefix entry update procedure. */
1333 prefix_list_entry_update_finish(ple);
1334
1335 return NB_OK;
1336 }
1337
1338 /*
1339 * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
1340 */
1341 static int
1342 lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
1343 {
1344 if (args->event == NB_EV_VALIDATE) {
1345 const struct lyd_node *plist_dnode =
1346 yang_dnode_get_parent(args->dnode, "prefix-list");
1347
1348 if (plist_is_dup_nb(args->dnode)) {
1349 snprintf(args->errmsg, args->errmsg_len,
1350 "duplicated prefix list value: %s",
1351 yang_dnode_get_string(args->dnode, NULL));
1352 return NB_ERR_VALIDATION;
1353 }
1354
1355 return prefix_list_nb_validate_v4_af_type(
1356 plist_dnode, args->errmsg, args->errmsg_len);
1357 }
1358
1359 return lib_prefix_list_entry_prefix_modify(args);
1360 }
1361
1362 static int
1363 lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
1364 {
1365
1366 if (args->event != NB_EV_APPLY)
1367 return NB_OK;
1368
1369 return lib_prefix_list_entry_prefix_destroy(args);
1370 }
1371
1372 /*
1373 * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix
1374 */
1375 static int
1376 lib_prefix_list_entry_ipv6_prefix_modify(struct nb_cb_modify_args *args)
1377 {
1378
1379 if (args->event == NB_EV_VALIDATE) {
1380 const struct lyd_node *plist_dnode =
1381 yang_dnode_get_parent(args->dnode, "prefix-list");
1382
1383 if (plist_is_dup_nb(args->dnode)) {
1384 snprintf(args->errmsg, args->errmsg_len,
1385 "duplicated prefix list value: %s",
1386 yang_dnode_get_string(args->dnode, NULL));
1387 return NB_ERR_VALIDATION;
1388 }
1389
1390 return prefix_list_nb_validate_v6_af_type(
1391 plist_dnode, args->errmsg, args->errmsg_len);
1392 }
1393
1394 return lib_prefix_list_entry_prefix_modify(args);
1395 }
1396
1397 static int
1398 lib_prefix_list_entry_ipv6_prefix_destroy(struct nb_cb_destroy_args *args)
1399 {
1400
1401 if (args->event != NB_EV_APPLY)
1402 return NB_OK;
1403
1404 return lib_prefix_list_entry_prefix_destroy(args);
1405 }
1406
1407 /*
1408 * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal
1409 */
1410 static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
1411 struct nb_cb_modify_args *args)
1412 {
1413 if (args->event == NB_EV_VALIDATE
1414 && prefix_list_length_validate(args) != NB_OK)
1415 return NB_ERR_VALIDATION;
1416
1417 if (args->event == NB_EV_VALIDATE) {
1418 const struct lyd_node *plist_dnode =
1419 yang_dnode_get_parent(args->dnode, "prefix-list");
1420
1421 if (plist_is_dup_nb(args->dnode)) {
1422 snprintf(args->errmsg, args->errmsg_len,
1423 "duplicated prefix list value: %s",
1424 yang_dnode_get_string(args->dnode, NULL));
1425 return NB_ERR_VALIDATION;
1426 }
1427
1428 return prefix_list_nb_validate_v4_af_type(
1429 plist_dnode, args->errmsg, args->errmsg_len);
1430 }
1431
1432 return lib_prefix_list_entry_prefix_length_greater_or_equal_modify(
1433 args);
1434 }
1435
1436 static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
1437 struct nb_cb_destroy_args *args)
1438 {
1439 if (args->event == NB_EV_VALIDATE) {
1440 const struct lyd_node *plist_dnode =
1441 yang_dnode_get_parent(args->dnode, "prefix-list");
1442
1443 return prefix_list_nb_validate_v4_af_type(
1444 plist_dnode, args->errmsg, args->errmsg_len);
1445 }
1446
1447 return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
1448 args);
1449 }
1450
1451 /*
1452 * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
1453 */
1454 static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
1455 struct nb_cb_modify_args *args)
1456 {
1457 if (args->event == NB_EV_VALIDATE
1458 && prefix_list_length_validate(args) != NB_OK)
1459 return NB_ERR_VALIDATION;
1460
1461 if (args->event == NB_EV_VALIDATE) {
1462 const struct lyd_node *plist_dnode =
1463 yang_dnode_get_parent(args->dnode, "prefix-list");
1464
1465 if (plist_is_dup_nb(args->dnode)) {
1466 snprintf(args->errmsg, args->errmsg_len,
1467 "duplicated prefix list value: %s",
1468 yang_dnode_get_string(args->dnode, NULL));
1469 return NB_ERR_VALIDATION;
1470 }
1471
1472 return prefix_list_nb_validate_v4_af_type(
1473 plist_dnode, args->errmsg, args->errmsg_len);
1474 }
1475
1476 return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
1477 args);
1478 }
1479
1480 static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
1481 struct nb_cb_destroy_args *args)
1482 {
1483 if (args->event == NB_EV_VALIDATE) {
1484 const struct lyd_node *plist_dnode =
1485 yang_dnode_get_parent(args->dnode, "prefix-list");
1486
1487 return prefix_list_nb_validate_v4_af_type(
1488 plist_dnode, args->errmsg, args->errmsg_len);
1489 }
1490
1491 return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
1492 args);
1493 }
1494
1495 /*
1496 * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal
1497 */
1498 static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify(
1499 struct nb_cb_modify_args *args)
1500 {
1501 if (args->event == NB_EV_VALIDATE
1502 && prefix_list_length_validate(args) != NB_OK)
1503 return NB_ERR_VALIDATION;
1504
1505 if (args->event == NB_EV_VALIDATE) {
1506 const struct lyd_node *plist_dnode =
1507 yang_dnode_get_parent(args->dnode, "prefix-list");
1508
1509 if (plist_is_dup_nb(args->dnode)) {
1510 snprintf(args->errmsg, args->errmsg_len,
1511 "duplicated prefix list value: %s",
1512 yang_dnode_get_string(args->dnode, NULL));
1513 return NB_ERR_VALIDATION;
1514 }
1515
1516 return prefix_list_nb_validate_v6_af_type(
1517 plist_dnode, args->errmsg, args->errmsg_len);
1518 }
1519
1520 return lib_prefix_list_entry_prefix_length_greater_or_equal_modify(
1521 args);
1522 }
1523
1524 static int lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy(
1525 struct nb_cb_destroy_args *args)
1526 {
1527 if (args->event == NB_EV_VALIDATE) {
1528 const struct lyd_node *plist_dnode =
1529 yang_dnode_get_parent(args->dnode, "prefix-list");
1530
1531 return prefix_list_nb_validate_v6_af_type(
1532 plist_dnode, args->errmsg, args->errmsg_len);
1533 }
1534
1535 return lib_prefix_list_entry_prefix_length_greater_or_equal_destroy(
1536 args);
1537 }
1538
1539 /*
1540 * XPath: /frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal
1541 */
1542 static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify(
1543 struct nb_cb_modify_args *args)
1544 {
1545 if (args->event == NB_EV_VALIDATE
1546 && prefix_list_length_validate(args) != NB_OK)
1547 return NB_ERR_VALIDATION;
1548
1549 if (args->event == NB_EV_VALIDATE) {
1550 const struct lyd_node *plist_dnode =
1551 yang_dnode_get_parent(args->dnode, "prefix-list");
1552
1553 if (plist_is_dup_nb(args->dnode)) {
1554 snprintf(args->errmsg, args->errmsg_len,
1555 "duplicated prefix list value: %s",
1556 yang_dnode_get_string(args->dnode, NULL));
1557 return NB_ERR_VALIDATION;
1558 }
1559
1560 return prefix_list_nb_validate_v6_af_type(
1561 plist_dnode, args->errmsg, args->errmsg_len);
1562 }
1563
1564 return lib_prefix_list_entry_prefix_length_lesser_or_equal_modify(
1565 args);
1566 }
1567
1568 static int lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy(
1569 struct nb_cb_destroy_args *args)
1570 {
1571 if (args->event == NB_EV_VALIDATE) {
1572 const struct lyd_node *plist_dnode =
1573 yang_dnode_get_parent(args->dnode, "prefix-list");
1574
1575 return prefix_list_nb_validate_v6_af_type(
1576 plist_dnode, args->errmsg, args->errmsg_len);
1577 }
1578
1579 return lib_prefix_list_entry_prefix_length_lesser_or_equal_destroy(
1580 args);
1581 }
1582
1583 /*
1584 * XPath: /frr-filter:lib/prefix-list/entry/any
1585 */
1586 static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
1587 {
1588 struct prefix_list_entry *ple;
1589 int type;
1590
1591 if (args->event == NB_EV_VALIDATE) {
1592 if (plist_is_dup_nb(args->dnode)) {
1593 snprintf(args->errmsg, args->errmsg_len,
1594 "duplicated prefix list value: %s",
1595 yang_dnode_get_string(args->dnode, NULL));
1596 return NB_ERR_VALIDATION;
1597 }
1598
1599 return NB_OK;
1600 }
1601
1602 if (args->event != NB_EV_APPLY)
1603 return NB_OK;
1604
1605 ple = nb_running_get_entry(args->dnode, NULL, true);
1606
1607 /* Start prefix entry update procedure. */
1608 prefix_list_entry_update_start(ple);
1609
1610 ple->any = true;
1611
1612 /* Fill prefix struct from scratch. */
1613 memset(&ple->prefix, 0, sizeof(ple->prefix));
1614
1615 type = yang_dnode_get_enum(args->dnode, "../../type");
1616 switch (type) {
1617 case YPLT_IPV4:
1618 ple->prefix.family = AF_INET;
1619 ple->ge = 0;
1620 ple->le = IPV4_MAX_BITLEN;
1621 break;
1622 case YPLT_IPV6:
1623 ple->prefix.family = AF_INET6;
1624 ple->ge = 0;
1625 ple->le = IPV6_MAX_BITLEN;
1626 break;
1627 }
1628
1629 /* Finish prefix entry update procedure. */
1630 prefix_list_entry_update_finish(ple);
1631
1632 return NB_OK;
1633 }
1634
1635 static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args)
1636 {
1637 struct prefix_list_entry *ple;
1638
1639 if (args->event != NB_EV_APPLY)
1640 return NB_OK;
1641
1642 ple = nb_running_get_entry(args->dnode, NULL, true);
1643
1644 /* Start prefix entry update procedure. */
1645 prefix_list_entry_update_start(ple);
1646
1647 prefix_list_entry_set_empty(ple);
1648
1649 /* Finish prefix entry update procedure. */
1650 prefix_list_entry_update_finish(ple);
1651
1652 return NB_OK;
1653 }
1654
1655 /* clang-format off */
1656 const struct frr_yang_module_info frr_filter_info = {
1657 .name = "frr-filter",
1658 .nodes = {
1659 {
1660 .xpath = "/frr-filter:lib/access-list",
1661 .cbs = {
1662 .create = lib_access_list_create,
1663 .destroy = lib_access_list_destroy,
1664 }
1665 },
1666 {
1667 .xpath = "/frr-filter:lib/access-list/remark",
1668 .cbs = {
1669 .modify = lib_access_list_remark_modify,
1670 .destroy = lib_access_list_remark_destroy,
1671 .cli_show = access_list_remark_show,
1672 }
1673 },
1674 {
1675 .xpath = "/frr-filter:lib/access-list/entry",
1676 .cbs = {
1677 .create = lib_access_list_entry_create,
1678 .destroy = lib_access_list_entry_destroy,
1679 .cli_cmp = access_list_cmp,
1680 .cli_show = access_list_show,
1681 }
1682 },
1683 {
1684 .xpath = "/frr-filter:lib/access-list/entry/action",
1685 .cbs = {
1686 .modify = lib_access_list_entry_action_modify,
1687 }
1688 },
1689 {
1690 .xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix",
1691 .cbs = {
1692 .modify = lib_access_list_entry_ipv4_prefix_modify,
1693 .destroy = lib_access_list_entry_ipv4_prefix_destroy,
1694 }
1695 },
1696 {
1697 .xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match",
1698 .cbs = {
1699 .modify = lib_access_list_entry_ipv4_exact_match_modify,
1700 .destroy = lib_access_list_entry_ipv4_exact_match_destroy,
1701 }
1702 },
1703 {
1704 .xpath = "/frr-filter:lib/access-list/entry/host",
1705 .cbs = {
1706 .modify = lib_access_list_entry_host_modify,
1707 .destroy = lib_access_list_entry_host_destroy,
1708 }
1709 },
1710 {
1711 .xpath = "/frr-filter:lib/access-list/entry/network/address",
1712 .cbs = {
1713 .modify = lib_access_list_entry_network_address_modify,
1714 }
1715 },
1716 {
1717 .xpath = "/frr-filter:lib/access-list/entry/network/mask",
1718 .cbs = {
1719 .modify = lib_access_list_entry_network_mask_modify,
1720 }
1721 },
1722 {
1723 .xpath = "/frr-filter:lib/access-list/entry/source-any",
1724 .cbs = {
1725 .create = lib_access_list_entry_source_any_create,
1726 .destroy = lib_access_list_entry_source_any_destroy,
1727 }
1728 },
1729 {
1730 .xpath = "/frr-filter:lib/access-list/entry/destination-host",
1731 .cbs = {
1732 .modify = lib_access_list_entry_destination_host_modify,
1733 .destroy = lib_access_list_entry_destination_host_destroy,
1734 }
1735 },
1736 {
1737 .xpath = "/frr-filter:lib/access-list/entry/destination-network/address",
1738 .cbs = {
1739 .modify = lib_access_list_entry_destination_network_address_modify,
1740 }
1741 },
1742 {
1743 .xpath = "/frr-filter:lib/access-list/entry/destination-network/mask",
1744 .cbs = {
1745 .modify = lib_access_list_entry_destination_network_mask_modify,
1746 }
1747 },
1748 {
1749 .xpath = "/frr-filter:lib/access-list/entry/destination-any",
1750 .cbs = {
1751 .create = lib_access_list_entry_destination_any_create,
1752 .destroy = lib_access_list_entry_destination_any_destroy,
1753 }
1754 },
1755 {
1756 .xpath = "/frr-filter:lib/access-list/entry/ipv6-prefix",
1757 .cbs = {
1758 .modify = lib_access_list_entry_ipv4_prefix_modify,
1759 .destroy = lib_access_list_entry_ipv4_prefix_destroy,
1760 }
1761 },
1762 {
1763 .xpath = "/frr-filter:lib/access-list/entry/ipv6-exact-match",
1764 .cbs = {
1765 .modify = lib_access_list_entry_ipv4_exact_match_modify,
1766 .destroy = lib_access_list_entry_ipv4_exact_match_destroy,
1767 }
1768 },
1769 {
1770 .xpath = "/frr-filter:lib/access-list/entry/mac",
1771 .cbs = {
1772 .modify = lib_access_list_entry_ipv4_prefix_modify,
1773 .destroy = lib_access_list_entry_ipv4_prefix_destroy,
1774 }
1775 },
1776 {
1777 .xpath = "/frr-filter:lib/access-list/entry/any",
1778 .cbs = {
1779 .create = lib_access_list_entry_any_create,
1780 .destroy = lib_access_list_entry_any_destroy,
1781 }
1782 },
1783 {
1784 .xpath = "/frr-filter:lib/prefix-list",
1785 .cbs = {
1786 .create = lib_prefix_list_create,
1787 .destroy = lib_prefix_list_destroy,
1788 }
1789 },
1790 {
1791 .xpath = "/frr-filter:lib/prefix-list/remark",
1792 .cbs = {
1793 .modify = lib_prefix_list_remark_modify,
1794 .destroy = lib_prefix_list_remark_destroy,
1795 .cli_show = prefix_list_remark_show,
1796 }
1797 },
1798 {
1799 .xpath = "/frr-filter:lib/prefix-list/entry",
1800 .cbs = {
1801 .create = lib_prefix_list_entry_create,
1802 .destroy = lib_prefix_list_entry_destroy,
1803 .cli_cmp = prefix_list_cmp,
1804 .cli_show = prefix_list_show,
1805 }
1806 },
1807 {
1808 .xpath = "/frr-filter:lib/prefix-list/entry/action",
1809 .cbs = {
1810 .modify = lib_prefix_list_entry_action_modify,
1811 }
1812 },
1813 {
1814 .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix",
1815 .cbs = {
1816 .modify = lib_prefix_list_entry_ipv4_prefix_modify,
1817 .destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
1818 }
1819 },
1820 {
1821 .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal",
1822 .cbs = {
1823 .modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
1824 .destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
1825 }
1826 },
1827 {
1828 .xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal",
1829 .cbs = {
1830 .modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
1831 .destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
1832 }
1833 },
1834 {
1835 .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix",
1836 .cbs = {
1837 .modify = lib_prefix_list_entry_ipv6_prefix_modify,
1838 .destroy = lib_prefix_list_entry_ipv6_prefix_destroy,
1839 }
1840 },
1841 {
1842 .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal",
1843 .cbs = {
1844 .modify = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_modify,
1845 .destroy = lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy,
1846 }
1847 },
1848 {
1849 .xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal",
1850 .cbs = {
1851 .modify = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_modify,
1852 .destroy = lib_prefix_list_entry_ipv6_prefix_length_lesser_or_equal_destroy,
1853 }
1854 },
1855 {
1856 .xpath = "/frr-filter:lib/prefix-list/entry/any",
1857 .cbs = {
1858 .create = lib_prefix_list_entry_any_create,
1859 .destroy = lib_prefix_list_entry_any_destroy,
1860 }
1861 },
1862 {
1863 .xpath = NULL,
1864 },
1865 }
1866 };