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