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. */
acl_notify_route_map(struct access_list * acl,int route_map_event)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 
prefix_list_length_validate(struct nb_cb_modify_args * args)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  */
prefix_list_entry_set_empty(struct prefix_list_entry * ple)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 /**
124  * Unsets the cisco style rule for addresses so it becomes disabled (the
125  * equivalent of setting: `0.0.0.0/32`).
126  *
127  * \param addr address part.
128  * \param mask mask part.
129  */
cisco_unset_addr_mask(struct in_addr * addr,struct in_addr * mask)130 static void cisco_unset_addr_mask(struct in_addr *addr, struct in_addr *mask)
131 {
132 	addr->s_addr = INADDR_ANY;
133 	mask->s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
134 }
135 
_acl_is_dup(const struct lyd_node * dnode,void * arg)136 static int _acl_is_dup(const struct lyd_node *dnode, void *arg)
137 {
138 	struct acl_dup_args *ada = arg;
139 	int idx;
140 
141 	/* This entry is the caller, so skip it. */
142 	if (ada->ada_entry_dnode
143 	    && ada->ada_entry_dnode == dnode)
144 		return YANG_ITER_CONTINUE;
145 
146 	/* Check if all values match. */
147 	for (idx = 0; idx < ADA_MAX_VALUES; idx++) {
148 		/* No more values. */
149 		if (ada->ada_xpath[idx] == NULL)
150 			break;
151 
152 		/* Not same type, just skip it. */
153 		if (!yang_dnode_exists(dnode, ada->ada_xpath[idx]))
154 			return YANG_ITER_CONTINUE;
155 
156 		/* Check if different value. */
157 		if (strcmp(yang_dnode_get_string(dnode, ada->ada_xpath[idx]),
158 			   ada->ada_value[idx]))
159 			return YANG_ITER_CONTINUE;
160 	}
161 
162 	ada->ada_found = true;
163 
164 	return YANG_ITER_STOP;
165 }
166 
acl_is_dup(const struct lyd_node * dnode,struct acl_dup_args * ada)167 bool acl_is_dup(const struct lyd_node *dnode, struct acl_dup_args *ada)
168 {
169 	ada->ada_found = false;
170 
171 	yang_dnode_iterate(
172 		_acl_is_dup, ada, dnode,
173 		"/frr-filter:lib/access-list[type='%s'][name='%s']/entry",
174 		ada->ada_type, ada->ada_name);
175 
176 	return ada->ada_found;
177 }
178 
acl_cisco_is_dup(const struct lyd_node * dnode)179 static bool acl_cisco_is_dup(const struct lyd_node *dnode)
180 {
181 	const struct lyd_node *entry_dnode =
182 		yang_dnode_get_parent(dnode, "entry");
183 	struct acl_dup_args ada = {};
184 	int idx = 0, arg_idx = 0;
185 	static const char *cisco_entries[] = {
186 		"./host",
187 		"./network/address",
188 		"./network/mask",
189 		"./source-any",
190 		"./destination-host",
191 		"./destination-network/address",
192 		"./destination-network/mask",
193 		"./destination-any",
194 		NULL
195 	};
196 
197 	/* Initialize. */
198 	ada.ada_type = "ipv4";
199 	ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
200 	ada.ada_entry_dnode = entry_dnode;
201 
202 	/* Load all values/XPaths. */
203 	while (cisco_entries[idx] != NULL) {
204 		if (!yang_dnode_exists(entry_dnode, cisco_entries[idx])) {
205 			idx++;
206 			continue;
207 		}
208 
209 		ada.ada_xpath[arg_idx] = cisco_entries[idx];
210 		ada.ada_value[arg_idx] =
211 			yang_dnode_get_string(entry_dnode, cisco_entries[idx]);
212 		arg_idx++;
213 		idx++;
214 	}
215 
216 	return acl_is_dup(entry_dnode, &ada);
217 }
218 
acl_zebra_is_dup(const struct lyd_node * dnode,enum yang_access_list_type type)219 static bool acl_zebra_is_dup(const struct lyd_node *dnode,
220 			     enum yang_access_list_type type)
221 {
222 	const struct lyd_node *entry_dnode =
223 		yang_dnode_get_parent(dnode, "entry");
224 	struct acl_dup_args ada = {};
225 	int idx = 0, arg_idx = 0;
226 	static const char *zebra_entries[] = {
227 		"./ipv4-prefix",
228 		"./ipv4-exact-match",
229 		"./ipv6-prefix",
230 		"./ipv6-exact-match",
231 		"./mac",
232 		"./any",
233 		NULL
234 	};
235 
236 	/* Initialize. */
237 	switch (type) {
238 	case YALT_IPV4:
239 		ada.ada_type = "ipv4";
240 		break;
241 	case YALT_IPV6:
242 		ada.ada_type = "ipv6";
243 		break;
244 	case YALT_MAC:
245 		ada.ada_type = "mac";
246 		break;
247 	}
248 	ada.ada_name = yang_dnode_get_string(entry_dnode, "../name");
249 	ada.ada_entry_dnode = entry_dnode;
250 
251 	/* Load all values/XPaths. */
252 	while (zebra_entries[idx] != NULL) {
253 		if (!yang_dnode_exists(entry_dnode, zebra_entries[idx])) {
254 			idx++;
255 			continue;
256 		}
257 
258 		ada.ada_xpath[arg_idx] = zebra_entries[idx];
259 		ada.ada_value[arg_idx] =
260 			yang_dnode_get_string(entry_dnode, zebra_entries[idx]);
261 		arg_idx++;
262 		idx++;
263 	}
264 
265 	return acl_is_dup(entry_dnode, &ada);
266 }
267 
_plist_is_dup(const struct lyd_node * dnode,void * arg)268 static int _plist_is_dup(const struct lyd_node *dnode, void *arg)
269 {
270 	struct plist_dup_args *pda = arg;
271 	int idx;
272 
273 	/* This entry is the caller, so skip it. */
274 	if (pda->pda_entry_dnode
275 	    && pda->pda_entry_dnode == dnode)
276 		return YANG_ITER_CONTINUE;
277 
278 	/* Check if all values match. */
279 	for (idx = 0; idx < PDA_MAX_VALUES; idx++) {
280 		/* No more values. */
281 		if (pda->pda_xpath[idx] == NULL)
282 			break;
283 
284 		/* Not same type, just skip it. */
285 		if (!yang_dnode_exists(dnode, pda->pda_xpath[idx]))
286 			return YANG_ITER_CONTINUE;
287 
288 		/* Check if different value. */
289 		if (strcmp(yang_dnode_get_string(dnode, pda->pda_xpath[idx]),
290 			   pda->pda_value[idx]))
291 			return YANG_ITER_CONTINUE;
292 	}
293 
294 	pda->pda_found = true;
295 
296 	return YANG_ITER_STOP;
297 }
298 
plist_is_dup(const struct lyd_node * dnode,struct plist_dup_args * pda)299 bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda)
300 {
301 	pda->pda_found = false;
302 
303 	yang_dnode_iterate(
304 		_plist_is_dup, pda, dnode,
305 		"/frr-filter:lib/prefix-list[type='%s'][name='%s']/entry",
306 		pda->pda_type, pda->pda_name);
307 
308 	return pda->pda_found;
309 }
310 
plist_is_dup_nb(const struct lyd_node * dnode)311 static bool plist_is_dup_nb(const struct lyd_node *dnode)
312 {
313 	const struct lyd_node *entry_dnode =
314 		yang_dnode_get_parent(dnode, "entry");
315 	struct plist_dup_args pda = {};
316 	int idx = 0, arg_idx = 0;
317 	static const char *entries[] = {
318 		"./ipv4-prefix",
319 		"./ipv4-prefix-length-greater-or-equal",
320 		"./ipv4-prefix-length-lesser-or-equal",
321 		"./ipv6-prefix",
322 		"./ipv6-prefix-length-greater-or-equal",
323 		"./ipv6-prefix-length-lesser-or-equal",
324 		"./any",
325 		NULL
326 	};
327 
328 	/* Initialize. */
329 	pda.pda_type = yang_dnode_get_string(entry_dnode, "../type");
330 	pda.pda_name = yang_dnode_get_string(entry_dnode, "../name");
331 	pda.pda_entry_dnode = entry_dnode;
332 
333 	/* Load all values/XPaths. */
334 	while (entries[idx] != NULL) {
335 		if (!yang_dnode_exists(entry_dnode, entries[idx])) {
336 			idx++;
337 			continue;
338 		}
339 
340 		pda.pda_xpath[arg_idx] = entries[idx];
341 		pda.pda_value[arg_idx] =
342 			yang_dnode_get_string(entry_dnode, entries[idx]);
343 		arg_idx++;
344 		idx++;
345 	}
346 
347 	return plist_is_dup(entry_dnode, &pda);
348 }
349 
350 /*
351  * XPath: /frr-filter:lib/access-list
352  */
lib_access_list_create(struct nb_cb_create_args * args)353 static int lib_access_list_create(struct nb_cb_create_args *args)
354 {
355 	struct access_list *acl = NULL;
356 	const char *acl_name;
357 	int type;
358 
359 	if (args->event != NB_EV_APPLY)
360 		return NB_OK;
361 
362 	type = yang_dnode_get_enum(args->dnode, "./type");
363 	acl_name = yang_dnode_get_string(args->dnode, "./name");
364 
365 	switch (type) {
366 	case YALT_IPV4:
367 		acl = access_list_get(AFI_IP, acl_name);
368 		break;
369 	case YALT_IPV6:
370 		acl = access_list_get(AFI_IP6, acl_name);
371 		break;
372 	case YALT_MAC:
373 		acl = access_list_get(AFI_L2VPN, acl_name);
374 		break;
375 	}
376 
377 	nb_running_set_entry(args->dnode, acl);
378 
379 	return NB_OK;
380 }
381 
lib_access_list_destroy(struct nb_cb_destroy_args * args)382 static int lib_access_list_destroy(struct nb_cb_destroy_args *args)
383 {
384 	struct access_master *am;
385 	struct access_list *acl;
386 
387 	if (args->event != NB_EV_APPLY)
388 		return NB_OK;
389 
390 	acl = nb_running_unset_entry(args->dnode);
391 	am = acl->master;
392 	if (am->delete_hook)
393 		am->delete_hook(acl);
394 
395 	access_list_delete(acl);
396 
397 	return NB_OK;
398 }
399 
400 /*
401  * XPath: /frr-filter:lib/access-list/remark
402  */
lib_access_list_remark_modify(struct nb_cb_modify_args * args)403 static int lib_access_list_remark_modify(struct nb_cb_modify_args *args)
404 {
405 	struct access_list *acl;
406 	const char *remark;
407 
408 	if (args->event != NB_EV_APPLY)
409 		return NB_OK;
410 
411 	acl = nb_running_get_entry(args->dnode, NULL, true);
412 	if (acl->remark)
413 		XFREE(MTYPE_TMP, acl->remark);
414 
415 	remark = yang_dnode_get_string(args->dnode, NULL);
416 	acl->remark = XSTRDUP(MTYPE_TMP, remark);
417 
418 	return NB_OK;
419 }
420 
421 static int
lib_access_list_remark_destroy(struct nb_cb_destroy_args * args)422 lib_access_list_remark_destroy(struct nb_cb_destroy_args *args)
423 {
424 	struct access_list *acl;
425 
426 	if (args->event != NB_EV_APPLY)
427 		return NB_OK;
428 
429 	acl = nb_running_get_entry(args->dnode, NULL, true);
430 	if (acl->remark)
431 		XFREE(MTYPE_TMP, acl->remark);
432 
433 	return NB_OK;
434 }
435 
436 
437 /*
438  * XPath: /frr-filter:lib/access-list/entry
439  */
lib_access_list_entry_create(struct nb_cb_create_args * args)440 static int lib_access_list_entry_create(struct nb_cb_create_args *args)
441 {
442 	struct access_list *acl;
443 	struct filter *f;
444 
445 	if (args->event != NB_EV_APPLY)
446 		return NB_OK;
447 
448 	f = filter_new();
449 	f->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
450 
451 	acl = nb_running_get_entry(args->dnode, NULL, true);
452 	f->acl = acl;
453 	access_list_filter_add(acl, f);
454 	nb_running_set_entry(args->dnode, f);
455 
456 	return NB_OK;
457 }
458 
lib_access_list_entry_destroy(struct nb_cb_destroy_args * args)459 static int lib_access_list_entry_destroy(struct nb_cb_destroy_args *args)
460 {
461 	struct access_list *acl;
462 	struct filter *f;
463 
464 	if (args->event != NB_EV_APPLY)
465 		return NB_OK;
466 
467 	f = nb_running_unset_entry(args->dnode);
468 	acl = f->acl;
469 	access_list_filter_delete(acl, f);
470 
471 	return NB_OK;
472 }
473 
474 /*
475  * XPath: /frr-filter:lib/access-list/entry/action
476  */
477 static int
lib_access_list_entry_action_modify(struct nb_cb_modify_args * args)478 lib_access_list_entry_action_modify(struct nb_cb_modify_args *args)
479 {
480 	const char *filter_type;
481 	struct filter *f;
482 
483 	if (args->event != NB_EV_APPLY)
484 		return NB_OK;
485 
486 	f = nb_running_get_entry(args->dnode, NULL, true);
487 	filter_type = yang_dnode_get_string(args->dnode, NULL);
488 	if (strcmp(filter_type, "permit") == 0)
489 		f->type = FILTER_PERMIT;
490 	else
491 		f->type = FILTER_DENY;
492 
493 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
494 
495 	return NB_OK;
496 }
497 
498 /*
499  * XPath: /frr-filter:lib/access-list/entry/ipv4-prefix
500  */
501 static int
lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args * args)502 lib_access_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
503 {
504 	struct filter_zebra *fz;
505 	struct filter *f;
506 
507 	/* Don't allow duplicated values. */
508 	if (args->event == NB_EV_VALIDATE) {
509 		if (acl_zebra_is_dup(
510 			    args->dnode,
511 			    yang_dnode_get_enum(args->dnode, "../../type"))) {
512 			snprintfrr(args->errmsg, args->errmsg_len,
513 				   "duplicated access list value: %s",
514 				   yang_dnode_get_string(args->dnode, NULL));
515 			return NB_ERR_VALIDATION;
516 		}
517 		return NB_OK;
518 	}
519 
520 	if (args->event != NB_EV_APPLY)
521 		return NB_OK;
522 
523 	f = nb_running_get_entry(args->dnode, NULL, true);
524 	f->cisco = 0;
525 	fz = &f->u.zfilter;
526 	yang_dnode_get_prefix(&fz->prefix, args->dnode, NULL);
527 
528 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
529 
530 	return NB_OK;
531 }
532 
533 static int
lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args * args)534 lib_access_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
535 {
536 	struct filter_zebra *fz;
537 	struct filter *f;
538 
539 	if (args->event != NB_EV_APPLY)
540 		return NB_OK;
541 
542 	f = nb_running_get_entry(args->dnode, NULL, true);
543 	fz = &f->u.zfilter;
544 	memset(&fz->prefix, 0, sizeof(fz->prefix));
545 
546 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
547 
548 	return NB_OK;
549 }
550 
551 /*
552  * XPath: /frr-filter:lib/access-list/entry/ipv4-exact-match
553  */
554 static int
lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args * args)555 lib_access_list_entry_ipv4_exact_match_modify(struct nb_cb_modify_args *args)
556 {
557 	struct filter_zebra *fz;
558 	struct filter *f;
559 
560 	/* Don't allow duplicated values. */
561 	if (args->event == NB_EV_VALIDATE) {
562 		if (acl_zebra_is_dup(
563 			    args->dnode,
564 			    yang_dnode_get_enum(args->dnode, "../../type"))) {
565 			snprintfrr(args->errmsg, args->errmsg_len,
566 				   "duplicated access list value: %s",
567 				   yang_dnode_get_string(args->dnode, NULL));
568 			return NB_ERR_VALIDATION;
569 		}
570 		return NB_OK;
571 	}
572 
573 	if (args->event != NB_EV_APPLY)
574 		return NB_OK;
575 
576 	f = nb_running_get_entry(args->dnode, NULL, true);
577 	fz = &f->u.zfilter;
578 	fz->exact = yang_dnode_get_bool(args->dnode, NULL);
579 
580 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
581 
582 	return NB_OK;
583 }
584 
585 static int
lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args * args)586 lib_access_list_entry_ipv4_exact_match_destroy(struct nb_cb_destroy_args *args)
587 {
588 	struct filter_zebra *fz;
589 	struct filter *f;
590 
591 	if (args->event != NB_EV_APPLY)
592 		return NB_OK;
593 
594 	f = nb_running_get_entry(args->dnode, NULL, true);
595 	fz = &f->u.zfilter;
596 	fz->exact = 0;
597 
598 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
599 
600 	return NB_OK;
601 }
602 
603 /*
604  * XPath: /frr-filter:lib/access-list/entry/host
605  */
606 static int
lib_access_list_entry_host_modify(struct nb_cb_modify_args * args)607 lib_access_list_entry_host_modify(struct nb_cb_modify_args *args)
608 {
609 	struct filter_cisco *fc;
610 	struct filter *f;
611 
612 	/* Don't allow duplicated values. */
613 	if (args->event == NB_EV_VALIDATE) {
614 		if (acl_cisco_is_dup(args->dnode)) {
615 			snprintfrr(args->errmsg, args->errmsg_len,
616 				   "duplicated access list value: %s",
617 				   yang_dnode_get_string(args->dnode, NULL));
618 			return NB_ERR_VALIDATION;
619 		}
620 		return NB_OK;
621 	}
622 
623 	if (args->event != NB_EV_APPLY)
624 		return NB_OK;
625 
626 	f = nb_running_get_entry(args->dnode, NULL, true);
627 	f->cisco = 1;
628 	fc = &f->u.cfilter;
629 	yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
630 	fc->addr_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
631 
632 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
633 
634 	return NB_OK;
635 }
636 
637 static int
lib_access_list_entry_host_destroy(struct nb_cb_destroy_args * args)638 lib_access_list_entry_host_destroy(struct nb_cb_destroy_args *args)
639 {
640 	struct filter_cisco *fc;
641 	struct filter *f;
642 
643 	if (args->event != NB_EV_APPLY)
644 		return NB_OK;
645 
646 	f = nb_running_get_entry(args->dnode, NULL, true);
647 	fc = &f->u.cfilter;
648 	cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
649 
650 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
651 
652 	return NB_OK;
653 }
654 
655 /*
656  * XPath: /frr-filter:lib/access-list/entry/network/address
657  */
658 static int
lib_access_list_entry_network_address_modify(struct nb_cb_modify_args * args)659 lib_access_list_entry_network_address_modify(struct nb_cb_modify_args *args)
660 {
661 	struct filter_cisco *fc;
662 	struct filter *f;
663 
664 	/* Don't allow duplicated values. */
665 	if (args->event == NB_EV_VALIDATE) {
666 		if (acl_cisco_is_dup(args->dnode)) {
667 			snprintfrr(args->errmsg, args->errmsg_len,
668 				   "duplicated access list value: %s",
669 				   yang_dnode_get_string(args->dnode, NULL));
670 			return NB_ERR_VALIDATION;
671 		}
672 		return NB_OK;
673 	}
674 
675 	if (args->event != NB_EV_APPLY)
676 		return NB_OK;
677 
678 	f = nb_running_get_entry(args->dnode, NULL, true);
679 	f->cisco = 1;
680 	fc = &f->u.cfilter;
681 	yang_dnode_get_ipv4(&fc->addr, args->dnode, NULL);
682 
683 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
684 
685 	return NB_OK;
686 }
687 
688 /*
689  * XPath: /frr-filter:lib/access-list/entry/network/mask
690  */
691 static int
lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args * args)692 lib_access_list_entry_network_mask_modify(struct nb_cb_modify_args *args)
693 {
694 	struct filter_cisco *fc;
695 	struct filter *f;
696 
697 	/* Don't allow duplicated values. */
698 	if (args->event == NB_EV_VALIDATE) {
699 		if (acl_cisco_is_dup(args->dnode)) {
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 	f->cisco = 1;
713 	fc = &f->u.cfilter;
714 	yang_dnode_get_ipv4(&fc->addr_mask, args->dnode, NULL);
715 
716 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
717 
718 	return NB_OK;
719 }
720 
721 /*
722  * XPath: /frr-filter:lib/access-list/entry/source-any
723  */
724 static int
lib_access_list_entry_source_any_create(struct nb_cb_create_args * args)725 lib_access_list_entry_source_any_create(struct nb_cb_create_args *args)
726 {
727 	struct filter_cisco *fc;
728 	struct filter *f;
729 
730 	/* Don't allow duplicated values. */
731 	if (args->event == NB_EV_VALIDATE) {
732 		if (acl_cisco_is_dup(args->dnode)) {
733 			snprintfrr(args->errmsg, args->errmsg_len,
734 				   "duplicated access list value: %s",
735 				   yang_dnode_get_string(args->dnode, NULL));
736 			return NB_ERR_VALIDATION;
737 		}
738 		return NB_OK;
739 	}
740 
741 	if (args->event != NB_EV_APPLY)
742 		return NB_OK;
743 
744 	f = nb_running_get_entry(args->dnode, NULL, true);
745 	f->cisco = 1;
746 	fc = &f->u.cfilter;
747 	fc->addr.s_addr = INADDR_ANY;
748 	fc->addr_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
749 
750 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
751 
752 	return NB_OK;
753 }
754 
755 static int
lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args * args)756 lib_access_list_entry_source_any_destroy(struct nb_cb_destroy_args *args)
757 {
758 	struct filter_cisco *fc;
759 	struct filter *f;
760 
761 	if (args->event != NB_EV_APPLY)
762 		return NB_OK;
763 
764 	f = nb_running_get_entry(args->dnode, NULL, true);
765 	fc = &f->u.cfilter;
766 	cisco_unset_addr_mask(&fc->addr, &fc->addr_mask);
767 
768 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
769 
770 	return NB_OK;
771 }
772 
773 /*
774  * XPath: /frr-filter:lib/access-list/entry/destination-host
775  */
lib_access_list_entry_destination_host_modify(struct nb_cb_modify_args * args)776 static int lib_access_list_entry_destination_host_modify(
777 	struct nb_cb_modify_args *args)
778 {
779 	struct filter_cisco *fc;
780 	struct filter *f;
781 
782 	/* Don't allow duplicated values. */
783 	if (args->event == NB_EV_VALIDATE) {
784 		if (acl_cisco_is_dup(args->dnode)) {
785 			snprintfrr(args->errmsg, args->errmsg_len,
786 				   "duplicated access list value: %s",
787 				   yang_dnode_get_string(args->dnode, NULL));
788 			return NB_ERR_VALIDATION;
789 		}
790 		return NB_OK;
791 	}
792 
793 	if (args->event != NB_EV_APPLY)
794 		return NB_OK;
795 
796 	f = nb_running_get_entry(args->dnode, NULL, true);
797 	fc = &f->u.cfilter;
798 	fc->extended = 1;
799 	yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
800 	fc->mask_mask.s_addr = CISCO_BIN_HOST_WILDCARD_MASK;
801 
802 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
803 
804 	return NB_OK;
805 }
806 
lib_access_list_entry_destination_host_destroy(struct nb_cb_destroy_args * args)807 static int lib_access_list_entry_destination_host_destroy(
808 	struct nb_cb_destroy_args *args)
809 {
810 	struct filter_cisco *fc;
811 	struct filter *f;
812 
813 	if (args->event != NB_EV_APPLY)
814 		return NB_OK;
815 
816 	f = nb_running_get_entry(args->dnode, NULL, true);
817 	fc = &f->u.cfilter;
818 	fc->extended = 0;
819 	cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
820 
821 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
822 
823 	return NB_OK;
824 }
825 
826 /*
827  * XPath: /frr-filter:lib/access-list/entry/destination-network/address
828  */
lib_access_list_entry_destination_network_address_modify(struct nb_cb_modify_args * args)829 static int lib_access_list_entry_destination_network_address_modify(
830 	struct nb_cb_modify_args *args)
831 {
832 	struct filter_cisco *fc;
833 	struct filter *f;
834 
835 	/* Don't allow duplicated values. */
836 	if (args->event == NB_EV_VALIDATE) {
837 		if (acl_cisco_is_dup(args->dnode)) {
838 			snprintfrr(args->errmsg, args->errmsg_len,
839 				   "duplicated access list value: %s",
840 				   yang_dnode_get_string(args->dnode, NULL));
841 			return NB_ERR_VALIDATION;
842 		}
843 		return NB_OK;
844 	}
845 
846 	if (args->event != NB_EV_APPLY)
847 		return NB_OK;
848 
849 	f = nb_running_get_entry(args->dnode, NULL, true);
850 	fc = &f->u.cfilter;
851 	fc->extended = 1;
852 	yang_dnode_get_ipv4(&fc->mask, args->dnode, NULL);
853 
854 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
855 
856 	return NB_OK;
857 }
858 
859 /*
860  * XPath: /frr-filter:lib/access-list/entry/destination-network/mask
861  */
lib_access_list_entry_destination_network_mask_modify(struct nb_cb_modify_args * args)862 static int lib_access_list_entry_destination_network_mask_modify(
863 	struct nb_cb_modify_args *args)
864 {
865 	struct filter_cisco *fc;
866 	struct filter *f;
867 
868 	/* Don't allow duplicated values. */
869 	if (args->event == NB_EV_VALIDATE) {
870 		if (acl_cisco_is_dup(args->dnode)) {
871 			snprintfrr(args->errmsg, args->errmsg_len,
872 				   "duplicated access list value: %s",
873 				   yang_dnode_get_string(args->dnode, NULL));
874 			return NB_ERR_VALIDATION;
875 		}
876 		return NB_OK;
877 	}
878 
879 	if (args->event != NB_EV_APPLY)
880 		return NB_OK;
881 
882 	f = nb_running_get_entry(args->dnode, NULL, true);
883 	fc = &f->u.cfilter;
884 	fc->extended = 1;
885 	yang_dnode_get_ipv4(&fc->mask_mask, args->dnode, NULL);
886 
887 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
888 
889 	return NB_OK;
890 }
891 
892 /*
893  * XPath: /frr-filter:lib/access-list/entry/destination-any
894  */
lib_access_list_entry_destination_any_create(struct nb_cb_create_args * args)895 static int lib_access_list_entry_destination_any_create(
896 	struct nb_cb_create_args *args)
897 {
898 	struct filter_cisco *fc;
899 	struct filter *f;
900 
901 	/* Don't allow duplicated values. */
902 	if (args->event == NB_EV_VALIDATE) {
903 		if (acl_cisco_is_dup(args->dnode)) {
904 			snprintfrr(args->errmsg, args->errmsg_len,
905 				   "duplicated access list value: %s",
906 				   yang_dnode_get_string(args->dnode, NULL));
907 			return NB_ERR_VALIDATION;
908 		}
909 		return NB_OK;
910 	}
911 
912 	if (args->event != NB_EV_APPLY)
913 		return NB_OK;
914 
915 	f = nb_running_get_entry(args->dnode, NULL, true);
916 	fc = &f->u.cfilter;
917 	fc->extended = 1;
918 	fc->mask.s_addr = INADDR_ANY;
919 	fc->mask_mask.s_addr = CISCO_BIN_ANY_WILDCARD_MASK;
920 
921 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
922 
923 	return NB_OK;
924 }
925 
lib_access_list_entry_destination_any_destroy(struct nb_cb_destroy_args * args)926 static int lib_access_list_entry_destination_any_destroy(
927 	struct nb_cb_destroy_args *args)
928 {
929 	struct filter_cisco *fc;
930 	struct filter *f;
931 
932 	if (args->event != NB_EV_APPLY)
933 		return NB_OK;
934 
935 	f = nb_running_get_entry(args->dnode, NULL, true);
936 	fc = &f->u.cfilter;
937 	fc->extended = 0;
938 	cisco_unset_addr_mask(&fc->mask, &fc->mask_mask);
939 
940 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
941 
942 	return NB_OK;
943 }
944 
945 /*
946  * XPath: /frr-filter:lib/access-list/entry/any
947  */
lib_access_list_entry_any_create(struct nb_cb_create_args * args)948 static int lib_access_list_entry_any_create(struct nb_cb_create_args *args)
949 {
950 	struct filter_zebra *fz;
951 	struct filter *f;
952 	int type;
953 
954 	/* Don't allow duplicated values. */
955 	if (args->event == NB_EV_VALIDATE) {
956 		if (acl_zebra_is_dup(
957 			    args->dnode,
958 			    yang_dnode_get_enum(args->dnode, "../../type"))) {
959 			snprintfrr(args->errmsg, args->errmsg_len,
960 				   "duplicated access list value: %s",
961 				   yang_dnode_get_string(args->dnode, NULL));
962 			return NB_ERR_VALIDATION;
963 		}
964 		return NB_OK;
965 	}
966 
967 	if (args->event != NB_EV_APPLY)
968 		return NB_OK;
969 
970 	f = nb_running_get_entry(args->dnode, NULL, true);
971 	f->cisco = 0;
972 	fz = &f->u.zfilter;
973 	memset(&fz->prefix, 0, sizeof(fz->prefix));
974 
975 	type = yang_dnode_get_enum(args->dnode, "../../type");
976 	switch (type) {
977 	case YALT_IPV4:
978 		fz->prefix.family = AF_INET;
979 		break;
980 	case YALT_IPV6:
981 		fz->prefix.family = AF_INET6;
982 		break;
983 	case YALT_MAC:
984 		fz->prefix.family = AF_ETHERNET;
985 		break;
986 	}
987 
988 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_ADDED);
989 
990 	return NB_OK;
991 }
992 
lib_access_list_entry_any_destroy(struct nb_cb_destroy_args * args)993 static int lib_access_list_entry_any_destroy(struct nb_cb_destroy_args *args)
994 {
995 	struct filter_zebra *fz;
996 	struct filter *f;
997 
998 	if (args->event != NB_EV_APPLY)
999 		return NB_OK;
1000 
1001 	f = nb_running_get_entry(args->dnode, NULL, true);
1002 	fz = &f->u.zfilter;
1003 	fz->prefix.family = 0;
1004 
1005 	acl_notify_route_map(f->acl, RMAP_EVENT_FILTER_DELETED);
1006 
1007 	return NB_OK;
1008 }
1009 
1010 /*
1011  * XPath: /frr-filter:lib/prefix-list
1012  */
lib_prefix_list_create(struct nb_cb_create_args * args)1013 static int lib_prefix_list_create(struct nb_cb_create_args *args)
1014 {
1015 	struct prefix_list *pl = NULL;
1016 	const char *name;
1017 	int type;
1018 
1019 	if (args->event != NB_EV_APPLY)
1020 		return NB_OK;
1021 
1022 	type = yang_dnode_get_enum(args->dnode, "./type");
1023 	name = yang_dnode_get_string(args->dnode, "./name");
1024 	switch (type) {
1025 	case 0: /* ipv4 */
1026 		pl = prefix_list_get(AFI_IP, 0, name);
1027 		break;
1028 	case 1: /* ipv6 */
1029 		pl = prefix_list_get(AFI_IP6, 0, name);
1030 		break;
1031 	}
1032 
1033 	nb_running_set_entry(args->dnode, pl);
1034 
1035 	return NB_OK;
1036 }
1037 
lib_prefix_list_destroy(struct nb_cb_destroy_args * args)1038 static int lib_prefix_list_destroy(struct nb_cb_destroy_args *args)
1039 {
1040 	struct prefix_list *pl;
1041 
1042 	if (args->event != NB_EV_APPLY)
1043 		return NB_OK;
1044 
1045 	pl = nb_running_unset_entry(args->dnode);
1046 	prefix_list_delete(pl);
1047 
1048 	return NB_OK;
1049 }
1050 
1051 /*
1052  * XPath: /frr-filter:lib/prefix-list/remark
1053  */
lib_prefix_list_remark_modify(struct nb_cb_modify_args * args)1054 static int lib_prefix_list_remark_modify(struct nb_cb_modify_args *args)
1055 {
1056 	struct prefix_list *pl;
1057 	const char *remark;
1058 
1059 	if (args->event != NB_EV_APPLY)
1060 		return NB_OK;
1061 
1062 	pl = nb_running_get_entry(args->dnode, NULL, true);
1063 	if (pl->desc)
1064 		XFREE(MTYPE_TMP, pl->desc);
1065 
1066 	remark = yang_dnode_get_string(args->dnode, NULL);
1067 	pl->desc = XSTRDUP(MTYPE_TMP, remark);
1068 
1069 	return NB_OK;
1070 }
1071 
lib_prefix_list_remark_destroy(struct nb_cb_destroy_args * args)1072 static int lib_prefix_list_remark_destroy(struct nb_cb_destroy_args *args)
1073 {
1074 	struct prefix_list *pl;
1075 
1076 	if (args->event != NB_EV_APPLY)
1077 		return NB_OK;
1078 
1079 	pl = nb_running_get_entry(args->dnode, NULL, true);
1080 	if (pl->desc)
1081 		XFREE(MTYPE_TMP, pl->desc);
1082 
1083 	return NB_OK;
1084 }
1085 
1086 /*
1087  * XPath: /frr-filter:lib/prefix-list/entry
1088  */
lib_prefix_list_entry_create(struct nb_cb_create_args * args)1089 static int lib_prefix_list_entry_create(struct nb_cb_create_args *args)
1090 {
1091 	struct prefix_list_entry *ple;
1092 	struct prefix_list *pl;
1093 
1094 	if (args->event != NB_EV_APPLY)
1095 		return NB_OK;
1096 
1097 	pl = nb_running_get_entry(args->dnode, NULL, true);
1098 	ple = prefix_list_entry_new();
1099 	ple->pl = pl;
1100 	ple->seq = yang_dnode_get_uint32(args->dnode, "./sequence");
1101 	prefix_list_entry_set_empty(ple);
1102 	nb_running_set_entry(args->dnode, ple);
1103 
1104 	return NB_OK;
1105 }
1106 
lib_prefix_list_entry_destroy(struct nb_cb_destroy_args * args)1107 static int lib_prefix_list_entry_destroy(struct nb_cb_destroy_args *args)
1108 {
1109 	struct prefix_list_entry *ple;
1110 
1111 	if (args->event != NB_EV_APPLY)
1112 		return NB_OK;
1113 
1114 	ple = nb_running_unset_entry(args->dnode);
1115 	if (ple->installed)
1116 		prefix_list_entry_delete2(ple);
1117 	else
1118 		prefix_list_entry_free(ple);
1119 
1120 	return NB_OK;
1121 }
1122 
1123 /*
1124  * XPath: /frr-filter:lib/prefix-list/entry/action
1125  */
lib_prefix_list_entry_action_modify(struct nb_cb_modify_args * args)1126 static int lib_prefix_list_entry_action_modify(struct nb_cb_modify_args *args)
1127 {
1128 	struct prefix_list_entry *ple;
1129 	int action_type;
1130 
1131 	if (args->event != NB_EV_APPLY)
1132 		return NB_OK;
1133 
1134 	ple = nb_running_get_entry(args->dnode, NULL, true);
1135 
1136 	/* Start prefix entry update procedure. */
1137 	prefix_list_entry_update_start(ple);
1138 
1139 	action_type = yang_dnode_get_enum(args->dnode, NULL);
1140 	if (action_type == YPLA_PERMIT)
1141 		ple->type = PREFIX_PERMIT;
1142 	else
1143 		ple->type = PREFIX_DENY;
1144 
1145 	/* Finish prefix entry update procedure. */
1146 	prefix_list_entry_update_finish(ple);
1147 
1148 	return NB_OK;
1149 }
1150 
1151 /*
1152  * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix
1153  */
1154 static int
lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args * args)1155 lib_prefix_list_entry_ipv4_prefix_modify(struct nb_cb_modify_args *args)
1156 {
1157 	struct prefix_list_entry *ple;
1158 	struct prefix p;
1159 
1160 	if (args->event == NB_EV_VALIDATE) {
1161 		if (plist_is_dup_nb(args->dnode)) {
1162 			snprintf(args->errmsg, args->errmsg_len,
1163 				 "duplicated prefix list value: %s",
1164 				 yang_dnode_get_string(args->dnode, NULL));
1165 			return NB_ERR_VALIDATION;
1166 		}
1167 		return NB_OK;
1168 	}
1169 
1170 	if (args->event != NB_EV_APPLY)
1171 		return NB_OK;
1172 
1173 	ple = nb_running_get_entry(args->dnode, NULL, true);
1174 
1175 	/* Start prefix entry update procedure. */
1176 	prefix_list_entry_update_start(ple);
1177 
1178 	yang_dnode_get_prefix(&ple->prefix, args->dnode, NULL);
1179 
1180 	/* Apply mask and correct original address if necessary. */
1181 	prefix_copy(&p, &ple->prefix);
1182 	apply_mask(&p);
1183 	if (!prefix_same(&ple->prefix, &p)) {
1184 		zlog_info("%s: bad network %pFX correcting it to %pFX",
1185 			  __func__, &ple->prefix, &p);
1186 		prefix_copy(&ple->prefix, &p);
1187 	}
1188 
1189 
1190 	/* Finish prefix entry update procedure. */
1191 	prefix_list_entry_update_finish(ple);
1192 
1193 	return NB_OK;
1194 }
1195 
1196 static int
lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args * args)1197 lib_prefix_list_entry_ipv4_prefix_destroy(struct nb_cb_destroy_args *args)
1198 {
1199 	struct prefix_list_entry *ple;
1200 
1201 	if (args->event != NB_EV_APPLY)
1202 		return NB_OK;
1203 
1204 	ple = nb_running_get_entry(args->dnode, NULL, true);
1205 
1206 	/* Start prefix entry update procedure. */
1207 	prefix_list_entry_update_start(ple);
1208 
1209 	memset(&ple->prefix, 0, sizeof(ple->prefix));
1210 
1211 	/* Finish prefix entry update procedure. */
1212 	prefix_list_entry_update_finish(ple);
1213 
1214 	return NB_OK;
1215 }
1216 
1217 /*
1218  * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal
1219  */
lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(struct nb_cb_modify_args * args)1220 static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify(
1221 	struct nb_cb_modify_args *args)
1222 {
1223 	struct prefix_list_entry *ple;
1224 
1225 	if (args->event == NB_EV_VALIDATE &&
1226 	    prefix_list_length_validate(args) != NB_OK)
1227 		return NB_ERR_VALIDATION;
1228 
1229 	if (args->event == NB_EV_VALIDATE) {
1230 		if (plist_is_dup_nb(args->dnode)) {
1231 			snprintf(args->errmsg, args->errmsg_len,
1232 				 "duplicated prefix list value: %s",
1233 				 yang_dnode_get_string(args->dnode, NULL));
1234 			return NB_ERR_VALIDATION;
1235 		}
1236 		return NB_OK;
1237 	}
1238 
1239 	if (args->event != NB_EV_APPLY)
1240 		return NB_OK;
1241 
1242 	ple = nb_running_get_entry(args->dnode, NULL, true);
1243 
1244 	/* Start prefix entry update procedure. */
1245 	prefix_list_entry_update_start(ple);
1246 
1247 	ple->ge = yang_dnode_get_uint8(args->dnode, NULL);
1248 
1249 	/* Finish prefix entry update procedure. */
1250 	prefix_list_entry_update_finish(ple);
1251 
1252 	return NB_OK;
1253 }
1254 
lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(struct nb_cb_destroy_args * args)1255 static int lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy(
1256 	struct nb_cb_destroy_args *args)
1257 {
1258 	struct prefix_list_entry *ple;
1259 
1260 	if (args->event != NB_EV_APPLY)
1261 		return NB_OK;
1262 
1263 	ple = nb_running_get_entry(args->dnode, NULL, true);
1264 
1265 	/* Start prefix entry update procedure. */
1266 	prefix_list_entry_update_start(ple);
1267 
1268 	ple->ge = 0;
1269 
1270 	/* Finish prefix entry update procedure. */
1271 	prefix_list_entry_update_finish(ple);
1272 
1273 	return NB_OK;
1274 }
1275 
1276 /*
1277  * XPath: /frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal
1278  */
lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(struct nb_cb_modify_args * args)1279 static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify(
1280 	struct nb_cb_modify_args *args)
1281 {
1282 	struct prefix_list_entry *ple;
1283 
1284 	if (args->event == NB_EV_VALIDATE &&
1285 	    prefix_list_length_validate(args) != NB_OK)
1286 		return NB_ERR_VALIDATION;
1287 
1288 	if (args->event == NB_EV_VALIDATE) {
1289 		if (plist_is_dup_nb(args->dnode)) {
1290 			snprintf(args->errmsg, args->errmsg_len,
1291 				 "duplicated prefix list value: %s",
1292 				 yang_dnode_get_string(args->dnode, NULL));
1293 			return NB_ERR_VALIDATION;
1294 		}
1295 		return NB_OK;
1296 	}
1297 
1298 	if (args->event != NB_EV_APPLY)
1299 		return NB_OK;
1300 
1301 	ple = nb_running_get_entry(args->dnode, NULL, true);
1302 
1303 	/* Start prefix entry update procedure. */
1304 	prefix_list_entry_update_start(ple);
1305 
1306 	ple->le = yang_dnode_get_uint8(args->dnode, NULL);
1307 
1308 	/* Finish prefix entry update procedure. */
1309 	prefix_list_entry_update_finish(ple);
1310 
1311 	return NB_OK;
1312 }
1313 
lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(struct nb_cb_destroy_args * args)1314 static int lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy(
1315 	struct nb_cb_destroy_args *args)
1316 {
1317 	struct prefix_list_entry *ple;
1318 
1319 	if (args->event != NB_EV_APPLY)
1320 		return NB_OK;
1321 
1322 	ple = nb_running_get_entry(args->dnode, NULL, true);
1323 
1324 	/* Start prefix entry update procedure. */
1325 	prefix_list_entry_update_start(ple);
1326 
1327 	ple->le = 0;
1328 
1329 	/* Finish prefix entry update procedure. */
1330 	prefix_list_entry_update_finish(ple);
1331 
1332 	return NB_OK;
1333 }
1334 
1335 /*
1336  * XPath: /frr-filter:lib/prefix-list/entry/any
1337  */
lib_prefix_list_entry_any_create(struct nb_cb_create_args * args)1338 static int lib_prefix_list_entry_any_create(struct nb_cb_create_args *args)
1339 {
1340 	struct prefix_list_entry *ple;
1341 	int type;
1342 
1343 	if (args->event == NB_EV_VALIDATE) {
1344 		if (plist_is_dup_nb(args->dnode)) {
1345 			snprintf(args->errmsg, args->errmsg_len,
1346 				 "duplicated prefix list value: %s",
1347 				 yang_dnode_get_string(args->dnode, NULL));
1348 			return NB_ERR_VALIDATION;
1349 		}
1350 		return NB_OK;
1351 	}
1352 
1353 	if (args->event != NB_EV_APPLY)
1354 		return NB_OK;
1355 
1356 	ple = nb_running_get_entry(args->dnode, NULL, true);
1357 
1358 	/* Start prefix entry update procedure. */
1359 	prefix_list_entry_update_start(ple);
1360 
1361 	ple->any = true;
1362 
1363 	/* Fill prefix struct from scratch. */
1364 	memset(&ple->prefix, 0, sizeof(ple->prefix));
1365 
1366 	type = yang_dnode_get_enum(args->dnode, "../../type");
1367 	switch (type) {
1368 	case YPLT_IPV4:
1369 		ple->prefix.family = AF_INET;
1370 		ple->ge = 0;
1371 		ple->le = IPV4_MAX_BITLEN;
1372 		break;
1373 	case YPLT_IPV6:
1374 		ple->prefix.family = AF_INET6;
1375 		ple->ge = 0;
1376 		ple->le = IPV6_MAX_BITLEN;
1377 		break;
1378 	}
1379 
1380 	/* Finish prefix entry update procedure. */
1381 	prefix_list_entry_update_finish(ple);
1382 
1383 	return NB_OK;
1384 }
1385 
lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args * args)1386 static int lib_prefix_list_entry_any_destroy(struct nb_cb_destroy_args *args)
1387 {
1388 	struct prefix_list_entry *ple;
1389 
1390 	if (args->event != NB_EV_APPLY)
1391 		return NB_OK;
1392 
1393 	ple = nb_running_get_entry(args->dnode, NULL, true);
1394 
1395 	/* Start prefix entry update procedure. */
1396 	prefix_list_entry_update_start(ple);
1397 
1398 	prefix_list_entry_set_empty(ple);
1399 
1400 	/* Finish prefix entry update procedure. */
1401 	prefix_list_entry_update_finish(ple);
1402 
1403 	return NB_OK;
1404 }
1405 
1406 /* clang-format off */
1407 const struct frr_yang_module_info frr_filter_info = {
1408 	.name = "frr-filter",
1409 	.nodes = {
1410 		{
1411 			.xpath = "/frr-filter:lib/access-list",
1412 			.cbs = {
1413 				.create = lib_access_list_create,
1414 				.destroy = lib_access_list_destroy,
1415 			}
1416 		},
1417 		{
1418 			.xpath = "/frr-filter:lib/access-list/remark",
1419 			.cbs = {
1420 				.modify = lib_access_list_remark_modify,
1421 				.destroy = lib_access_list_remark_destroy,
1422 				.cli_show = access_list_remark_show,
1423 			}
1424 		},
1425 		{
1426 			.xpath = "/frr-filter:lib/access-list/entry",
1427 			.cbs = {
1428 				.create = lib_access_list_entry_create,
1429 				.destroy = lib_access_list_entry_destroy,
1430 				.cli_show = access_list_show,
1431 			}
1432 		},
1433 		{
1434 			.xpath = "/frr-filter:lib/access-list/entry/action",
1435 			.cbs = {
1436 				.modify = lib_access_list_entry_action_modify,
1437 			}
1438 		},
1439 		{
1440 			.xpath = "/frr-filter:lib/access-list/entry/ipv4-prefix",
1441 			.cbs = {
1442 				.modify = lib_access_list_entry_ipv4_prefix_modify,
1443 				.destroy = lib_access_list_entry_ipv4_prefix_destroy,
1444 			}
1445 		},
1446 		{
1447 			.xpath = "/frr-filter:lib/access-list/entry/ipv4-exact-match",
1448 			.cbs = {
1449 				.modify = lib_access_list_entry_ipv4_exact_match_modify,
1450 				.destroy = lib_access_list_entry_ipv4_exact_match_destroy,
1451 			}
1452 		},
1453 		{
1454 			.xpath = "/frr-filter:lib/access-list/entry/host",
1455 			.cbs = {
1456 				.modify = lib_access_list_entry_host_modify,
1457 				.destroy = lib_access_list_entry_host_destroy,
1458 			}
1459 		},
1460 		{
1461 			.xpath = "/frr-filter:lib/access-list/entry/network/address",
1462 			.cbs = {
1463 				.modify = lib_access_list_entry_network_address_modify,
1464 			}
1465 		},
1466 		{
1467 			.xpath = "/frr-filter:lib/access-list/entry/network/mask",
1468 			.cbs = {
1469 				.modify = lib_access_list_entry_network_mask_modify,
1470 			}
1471 		},
1472 		{
1473 			.xpath = "/frr-filter:lib/access-list/entry/source-any",
1474 			.cbs = {
1475 				.create = lib_access_list_entry_source_any_create,
1476 				.destroy = lib_access_list_entry_source_any_destroy,
1477 			}
1478 		},
1479 		{
1480 			.xpath = "/frr-filter:lib/access-list/entry/destination-host",
1481 			.cbs = {
1482 				.modify = lib_access_list_entry_destination_host_modify,
1483 				.destroy = lib_access_list_entry_destination_host_destroy,
1484 			}
1485 		},
1486 		{
1487 			.xpath = "/frr-filter:lib/access-list/entry/destination-network/address",
1488 			.cbs = {
1489 				.modify = lib_access_list_entry_destination_network_address_modify,
1490 			}
1491 		},
1492 		{
1493 			.xpath = "/frr-filter:lib/access-list/entry/destination-network/mask",
1494 			.cbs = {
1495 				.modify = lib_access_list_entry_destination_network_mask_modify,
1496 			}
1497 		},
1498 		{
1499 			.xpath = "/frr-filter:lib/access-list/entry/destination-any",
1500 			.cbs = {
1501 				.create = lib_access_list_entry_destination_any_create,
1502 				.destroy = lib_access_list_entry_destination_any_destroy,
1503 			}
1504 		},
1505 		{
1506 			.xpath = "/frr-filter:lib/access-list/entry/ipv6-prefix",
1507 			.cbs = {
1508 				.modify = lib_access_list_entry_ipv4_prefix_modify,
1509 				.destroy = lib_access_list_entry_ipv4_prefix_destroy,
1510 			}
1511 		},
1512 		{
1513 			.xpath = "/frr-filter:lib/access-list/entry/ipv6-exact-match",
1514 			.cbs = {
1515 				.modify = lib_access_list_entry_ipv4_exact_match_modify,
1516 				.destroy = lib_access_list_entry_ipv4_exact_match_destroy,
1517 			}
1518 		},
1519 		{
1520 			.xpath = "/frr-filter:lib/access-list/entry/mac",
1521 			.cbs = {
1522 				.modify = lib_access_list_entry_ipv4_prefix_modify,
1523 				.destroy = lib_access_list_entry_ipv4_prefix_destroy,
1524 			}
1525 		},
1526 		{
1527 			.xpath = "/frr-filter:lib/access-list/entry/any",
1528 			.cbs = {
1529 				.create = lib_access_list_entry_any_create,
1530 				.destroy = lib_access_list_entry_any_destroy,
1531 			}
1532 		},
1533 		{
1534 			.xpath = "/frr-filter:lib/prefix-list",
1535 			.cbs = {
1536 				.create = lib_prefix_list_create,
1537 				.destroy = lib_prefix_list_destroy,
1538 			}
1539 		},
1540 		{
1541 			.xpath = "/frr-filter:lib/prefix-list/remark",
1542 			.cbs = {
1543 				.modify = lib_prefix_list_remark_modify,
1544 				.destroy = lib_prefix_list_remark_destroy,
1545 				.cli_show = prefix_list_remark_show,
1546 			}
1547 		},
1548 		{
1549 			.xpath = "/frr-filter:lib/prefix-list/entry",
1550 			.cbs = {
1551 				.create = lib_prefix_list_entry_create,
1552 				.destroy = lib_prefix_list_entry_destroy,
1553 				.cli_show = prefix_list_show,
1554 			}
1555 		},
1556 		{
1557 			.xpath = "/frr-filter:lib/prefix-list/entry/action",
1558 			.cbs = {
1559 				.modify = lib_prefix_list_entry_action_modify,
1560 			}
1561 		},
1562 		{
1563 			.xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix",
1564 			.cbs = {
1565 				.modify = lib_prefix_list_entry_ipv4_prefix_modify,
1566 				.destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
1567 			}
1568 		},
1569 		{
1570 			.xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-greater-or-equal",
1571 			.cbs = {
1572 				.modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
1573 				.destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
1574 			}
1575 		},
1576 		{
1577 			.xpath = "/frr-filter:lib/prefix-list/entry/ipv4-prefix-length-lesser-or-equal",
1578 			.cbs = {
1579 				.modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
1580 				.destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
1581 			}
1582 		},
1583 		{
1584 			.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix",
1585 			.cbs = {
1586 				.modify = lib_prefix_list_entry_ipv4_prefix_modify,
1587 				.destroy = lib_prefix_list_entry_ipv4_prefix_destroy,
1588 			}
1589 		},
1590 		{
1591 			.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-greater-or-equal",
1592 			.cbs = {
1593 				.modify = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_modify,
1594 				.destroy = lib_prefix_list_entry_ipv4_prefix_length_greater_or_equal_destroy,
1595 			}
1596 		},
1597 		{
1598 			.xpath = "/frr-filter:lib/prefix-list/entry/ipv6-prefix-length-lesser-or-equal",
1599 			.cbs = {
1600 				.modify = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_modify,
1601 				.destroy = lib_prefix_list_entry_ipv4_prefix_length_lesser_or_equal_destroy,
1602 			}
1603 		},
1604 		{
1605 			.xpath = "/frr-filter:lib/prefix-list/entry/any",
1606 			.cbs = {
1607 				.create = lib_prefix_list_entry_any_create,
1608 				.destroy = lib_prefix_list_entry_any_destroy,
1609 			}
1610 		},
1611 		{
1612 			.xpath = NULL,
1613 		},
1614 	}
1615 };
1616