]> git.proxmox.com Git - mirror_frr.git/blob - lib/routemap_northbound.c
lib, ospfd, yang: add route map set for min/max metric
[mirror_frr.git] / lib / routemap_northbound.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Route map northbound implementation.
4 *
5 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
6 * Rafael Zalamena
7 */
8
9 #include <zebra.h>
10
11 #include "lib/command.h"
12 #include "lib/log.h"
13 #include "lib/northbound.h"
14 #include "lib/routemap.h"
15
16 /*
17 * Auxiliary functions to avoid code duplication:
18 *
19 * lib_route_map_entry_set_destroy: unset `set` commands.
20 * lib_route_map_entry_match_destroy: unset `match` commands.
21 */
22 int lib_route_map_entry_match_destroy(struct nb_cb_destroy_args *args)
23 {
24 struct routemap_hook_context *rhc;
25 int rv;
26
27 if (args->event != NB_EV_APPLY)
28 return NB_OK;
29
30 rhc = nb_running_get_entry(args->dnode, NULL, true);
31 if (rhc->rhc_mhook == NULL)
32 return NB_OK;
33
34 rv = rhc->rhc_mhook(rhc->rhc_rmi, rhc->rhc_rule, NULL,
35 rhc->rhc_event,
36 args->errmsg, args->errmsg_len);
37 if (rv != CMD_SUCCESS)
38 return NB_ERR_INCONSISTENCY;
39
40 return NB_OK;
41 }
42
43 int lib_route_map_entry_set_destroy(struct nb_cb_destroy_args *args)
44 {
45 struct routemap_hook_context *rhc;
46 int rv;
47
48 if (args->event != NB_EV_APPLY)
49 return NB_OK;
50
51 rhc = nb_running_get_entry(args->dnode, NULL, true);
52 if (rhc->rhc_shook == NULL)
53 return NB_OK;
54
55 rv = rhc->rhc_shook(rhc->rhc_rmi, rhc->rhc_rule, NULL,
56 args->errmsg, args->errmsg_len);
57 if (rv != CMD_SUCCESS)
58 return NB_ERR_INCONSISTENCY;
59
60 return NB_OK;
61 }
62
63 /*
64 * Auxiliary hook context list manipulation functions.
65 */
66 struct routemap_hook_context *
67 routemap_hook_context_insert(struct route_map_index *rmi)
68 {
69 struct routemap_hook_context *rhc;
70
71 rhc = XCALLOC(MTYPE_TMP, sizeof(*rhc));
72 rhc->rhc_rmi = rmi;
73 TAILQ_INSERT_TAIL(&rmi->rhclist, rhc, rhc_entry);
74
75 return rhc;
76 }
77
78 void routemap_hook_context_free(struct routemap_hook_context *rhc)
79 {
80 struct route_map_index *rmi = rhc->rhc_rmi;
81
82 TAILQ_REMOVE(&rmi->rhclist, rhc, rhc_entry);
83 XFREE(MTYPE_TMP, rhc);
84 }
85
86 /*
87 * XPath: /frr-route-map:lib/route-map
88 */
89 static int lib_route_map_create(struct nb_cb_create_args *args)
90 {
91 struct route_map *rm;
92 const char *rm_name;
93
94 switch (args->event) {
95 case NB_EV_VALIDATE:
96 case NB_EV_PREPARE:
97 case NB_EV_ABORT:
98 /* NOTHING */
99 break;
100 case NB_EV_APPLY:
101 rm_name = yang_dnode_get_string(args->dnode, "./name");
102 rm = route_map_get(rm_name);
103 nb_running_set_entry(args->dnode, rm);
104 break;
105 }
106
107 return NB_OK;
108 }
109
110 static int lib_route_map_destroy(struct nb_cb_destroy_args *args)
111 {
112 struct route_map *rm;
113
114 switch (args->event) {
115 case NB_EV_VALIDATE:
116 case NB_EV_PREPARE:
117 case NB_EV_ABORT:
118 /* NOTHING */
119 break;
120 case NB_EV_APPLY:
121 rm = nb_running_unset_entry(args->dnode);
122 route_map_delete(rm);
123 break;
124 }
125
126 return NB_OK;
127 }
128
129 /*
130 * XPath: /frr-route-map:lib/route-map/optimization-disabled
131 */
132 static int
133 lib_route_map_optimization_disabled_modify(struct nb_cb_modify_args *args)
134 {
135 struct route_map *rm;
136 bool disabled = yang_dnode_get_bool(args->dnode, NULL);
137
138 switch (args->event) {
139 case NB_EV_VALIDATE:
140 case NB_EV_PREPARE:
141 case NB_EV_ABORT:
142 /* NOTHING */
143 break;
144 case NB_EV_APPLY:
145 rm = nb_running_get_entry(args->dnode, NULL, true);
146 rm->optimization_disabled = disabled;
147 break;
148 }
149
150 return NB_OK;
151 }
152
153 /*
154 * XPath: /frr-route-map:lib/route-map/entry
155 */
156 static int lib_route_map_entry_create(struct nb_cb_create_args *args)
157 {
158 struct route_map_index *rmi;
159 struct route_map *rm;
160 uint16_t sequence;
161 int action;
162
163 switch (args->event) {
164 case NB_EV_VALIDATE:
165 case NB_EV_PREPARE:
166 case NB_EV_ABORT:
167 /* NOTHING */
168 break;
169 case NB_EV_APPLY:
170 sequence = yang_dnode_get_uint16(args->dnode, "./sequence");
171 action = yang_dnode_get_enum(args->dnode, "./action") == 0
172 ? RMAP_PERMIT
173 : RMAP_DENY;
174 rm = nb_running_get_entry(args->dnode, NULL, true);
175 rmi = route_map_index_get(rm, action, sequence);
176 nb_running_set_entry(args->dnode, rmi);
177 break;
178 }
179
180 return NB_OK;
181 }
182
183 static int lib_route_map_entry_destroy(struct nb_cb_destroy_args *args)
184 {
185 struct route_map_index *rmi;
186
187 switch (args->event) {
188 case NB_EV_VALIDATE:
189 case NB_EV_PREPARE:
190 case NB_EV_ABORT:
191 /* NOTHING */
192 break;
193 case NB_EV_APPLY:
194 rmi = nb_running_unset_entry(args->dnode);
195 route_map_index_delete(rmi, 1);
196 break;
197 }
198
199 return NB_OK;
200 }
201
202 /*
203 * XPath: /frr-route-map:lib/route-map/entry/description
204 */
205 static int
206 lib_route_map_entry_description_modify(struct nb_cb_modify_args *args)
207 {
208 struct route_map_index *rmi;
209 const char *description;
210
211 switch (args->event) {
212 case NB_EV_VALIDATE:
213 /* NOTHING */
214 break;
215 case NB_EV_PREPARE:
216 description = yang_dnode_get_string(args->dnode, NULL);
217 args->resource->ptr = XSTRDUP(MTYPE_TMP, description);
218 if (args->resource->ptr == NULL)
219 return NB_ERR_RESOURCE;
220 break;
221 case NB_EV_ABORT:
222 XFREE(MTYPE_TMP, args->resource->ptr);
223 break;
224 case NB_EV_APPLY:
225 rmi = nb_running_get_entry(args->dnode, NULL, true);
226 XFREE(MTYPE_TMP, rmi->description);
227 rmi->description = args->resource->ptr;
228 break;
229 }
230
231 return NB_OK;
232 }
233
234 static int
235 lib_route_map_entry_description_destroy(struct nb_cb_destroy_args *args)
236 {
237 struct route_map_index *rmi;
238
239 switch (args->event) {
240 case NB_EV_VALIDATE:
241 case NB_EV_PREPARE:
242 case NB_EV_ABORT:
243 /* NOTHING */
244 break;
245 case NB_EV_APPLY:
246 rmi = nb_running_get_entry(args->dnode, NULL, true);
247 XFREE(MTYPE_TMP, rmi->description);
248 break;
249 }
250
251 return NB_OK;
252 }
253
254 /*
255 * XPath: /frr-route-map:lib/route-map/entry/action
256 */
257 static int lib_route_map_entry_action_modify(struct nb_cb_modify_args *args)
258 {
259 struct route_map_index *rmi;
260 struct route_map *map;
261
262 switch (args->event) {
263 case NB_EV_VALIDATE:
264 case NB_EV_PREPARE:
265 case NB_EV_ABORT:
266 /* NOTHING */
267 break;
268 case NB_EV_APPLY:
269 rmi = nb_running_get_entry(args->dnode, NULL, true);
270 rmi->type = yang_dnode_get_enum(args->dnode, NULL);
271 map = rmi->map;
272
273 /* Execute event hook. */
274 if (route_map_master.event_hook) {
275 (*route_map_master.event_hook)(map->name);
276 route_map_notify_dependencies(map->name,
277 RMAP_EVENT_CALL_ADDED);
278 }
279
280 break;
281 }
282
283 return NB_OK;
284 }
285
286 /*
287 * XPath: /frr-route-map:lib/route-map/entry/call
288 */
289 static int lib_route_map_entry_call_modify(struct nb_cb_modify_args *args)
290 {
291 struct route_map_index *rmi;
292 const char *rm_name, *rmn_name;
293
294 switch (args->event) {
295 case NB_EV_VALIDATE:
296 rm_name = yang_dnode_get_string(args->dnode, "../../name");
297 rmn_name = yang_dnode_get_string(args->dnode, NULL);
298 /* Don't allow to jump to the same route map instance. */
299 if (strcmp(rm_name, rmn_name) == 0)
300 return NB_ERR_VALIDATION;
301
302 /* TODO: detect circular route map sequences. */
303 break;
304 case NB_EV_PREPARE:
305 rmn_name = yang_dnode_get_string(args->dnode, NULL);
306 args->resource->ptr = XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmn_name);
307 break;
308 case NB_EV_ABORT:
309 XFREE(MTYPE_ROUTE_MAP_NAME, args->resource->ptr);
310 break;
311 case NB_EV_APPLY:
312 rmi = nb_running_get_entry(args->dnode, NULL, true);
313 if (rmi->nextrm) {
314 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED,
315 rmi->nextrm, rmi->map->name);
316 XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
317 }
318 rmi->nextrm = args->resource->ptr;
319 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED, rmi->nextrm,
320 rmi->map->name);
321 break;
322 }
323
324 return NB_OK;
325 }
326
327 static int lib_route_map_entry_call_destroy(struct nb_cb_destroy_args *args)
328 {
329 struct route_map_index *rmi;
330
331 switch (args->event) {
332 case NB_EV_VALIDATE:
333 case NB_EV_PREPARE:
334 case NB_EV_ABORT:
335 /* NOTHING */
336 break;
337 case NB_EV_APPLY:
338 rmi = nb_running_get_entry(args->dnode, NULL, true);
339 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED, rmi->nextrm,
340 rmi->map->name);
341 XFREE(MTYPE_ROUTE_MAP_NAME, rmi->nextrm);
342 rmi->nextrm = NULL;
343 break;
344 }
345
346 return NB_OK;
347 }
348
349 /*
350 * XPath: /frr-route-map:lib/route-map/entry/exit-policy
351 */
352 static int
353 lib_route_map_entry_exit_policy_modify(struct nb_cb_modify_args *args)
354 {
355 struct route_map_index *rmi;
356 int rm_action;
357 int policy;
358
359 switch (args->event) {
360 case NB_EV_VALIDATE:
361 policy = yang_dnode_get_enum(args->dnode, NULL);
362 switch (policy) {
363 case 0: /* permit-or-deny */
364 break;
365 case 1: /* next */
366 /* FALLTHROUGH */
367 case 2: /* goto */
368 rm_action =
369 yang_dnode_get_enum(args->dnode, "../action");
370 if (rm_action == 1 /* deny */) {
371 /*
372 * On deny it is not possible to 'goto'
373 * anywhere.
374 */
375 return NB_ERR_VALIDATION;
376 }
377 break;
378 }
379 break;
380 case NB_EV_PREPARE:
381 case NB_EV_ABORT:
382 break;
383 case NB_EV_APPLY:
384 rmi = nb_running_get_entry(args->dnode, NULL, true);
385 policy = yang_dnode_get_enum(args->dnode, NULL);
386
387 switch (policy) {
388 case 0: /* permit-or-deny */
389 rmi->exitpolicy = RMAP_EXIT;
390 break;
391 case 1: /* next */
392 rmi->exitpolicy = RMAP_NEXT;
393 break;
394 case 2: /* goto */
395 rmi->exitpolicy = RMAP_GOTO;
396 break;
397 }
398 break;
399 }
400
401 return NB_OK;
402 }
403
404 /*
405 * XPath: /frr-route-map:lib/route-map/entry/goto-value
406 */
407 static int lib_route_map_entry_goto_value_modify(struct nb_cb_modify_args *args)
408 {
409 struct route_map_index *rmi;
410 uint16_t rmi_index;
411 uint16_t rmi_next;
412
413 switch (args->event) {
414 case NB_EV_VALIDATE:
415 rmi_index = yang_dnode_get_uint16(args->dnode, "../sequence");
416 rmi_next = yang_dnode_get_uint16(args->dnode, NULL);
417 if (rmi_next <= rmi_index) {
418 /* Can't jump backwards on a route map. */
419 return NB_ERR_VALIDATION;
420 }
421 break;
422 case NB_EV_PREPARE:
423 case NB_EV_ABORT:
424 /* NOTHING */
425 break;
426 case NB_EV_APPLY:
427 rmi = nb_running_get_entry(args->dnode, NULL, true);
428 rmi->nextpref = yang_dnode_get_uint16(args->dnode, NULL);
429 break;
430 }
431
432 return NB_OK;
433 }
434
435 static int
436 lib_route_map_entry_goto_value_destroy(struct nb_cb_destroy_args *args)
437 {
438 struct route_map_index *rmi;
439
440 switch (args->event) {
441 case NB_EV_VALIDATE:
442 case NB_EV_PREPARE:
443 case NB_EV_ABORT:
444 /* NOTHING */
445 break;
446 case NB_EV_APPLY:
447 rmi = nb_running_get_entry(args->dnode, NULL, true);
448 rmi->nextpref = 0;
449 break;
450 }
451
452 return NB_OK;
453 }
454
455 /*
456 * XPath: /frr-route-map:lib/route-map/entry/match-condition
457 */
458 static int
459 lib_route_map_entry_match_condition_create(struct nb_cb_create_args *args)
460 {
461 struct routemap_hook_context *rhc;
462 struct route_map_index *rmi;
463
464 switch (args->event) {
465 case NB_EV_VALIDATE:
466 case NB_EV_PREPARE:
467 case NB_EV_ABORT:
468 /* NOTHING */
469 break;
470 case NB_EV_APPLY:
471 rmi = nb_running_get_entry(args->dnode, NULL, true);
472 rhc = routemap_hook_context_insert(rmi);
473 nb_running_set_entry(args->dnode, rhc);
474 break;
475 }
476
477 return NB_OK;
478 }
479
480 static int
481 lib_route_map_entry_match_condition_destroy(struct nb_cb_destroy_args *args)
482 {
483 struct routemap_hook_context *rhc;
484 int rv;
485
486 if (args->event != NB_EV_APPLY)
487 return NB_OK;
488
489 rv = lib_route_map_entry_match_destroy(args);
490 rhc = nb_running_unset_entry(args->dnode);
491 routemap_hook_context_free(rhc);
492
493 return rv;
494 }
495
496 /*
497 * XPath: /frr-route-map:lib/route-map/entry/match-condition/interface
498 */
499 static int lib_route_map_entry_match_condition_interface_modify(
500 struct nb_cb_modify_args *args)
501 {
502 struct routemap_hook_context *rhc;
503 const char *ifname;
504 int rv;
505
506 if (args->event != NB_EV_APPLY)
507 return NB_OK;
508
509 /* Check for hook function. */
510 if (rmap_match_set_hook.match_interface == NULL)
511 return NB_OK;
512
513 /* Add configuration. */
514 rhc = nb_running_get_entry(args->dnode, NULL, true);
515 ifname = yang_dnode_get_string(args->dnode, NULL);
516
517 /* Set destroy information. */
518 rhc->rhc_mhook = rmap_match_set_hook.no_match_interface;
519 rhc->rhc_rule = "interface";
520 rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
521
522 rv = rmap_match_set_hook.match_interface(rhc->rhc_rmi,
523 "interface", ifname,
524 RMAP_EVENT_MATCH_ADDED,
525 args->errmsg, args->errmsg_len);
526 if (rv != CMD_SUCCESS) {
527 rhc->rhc_mhook = NULL;
528 return NB_ERR_INCONSISTENCY;
529 }
530
531 return NB_OK;
532 }
533
534 static int lib_route_map_entry_match_condition_interface_destroy(
535 struct nb_cb_destroy_args *args)
536 {
537 return lib_route_map_entry_match_destroy(args);
538 }
539
540 /*
541 * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name
542 */
543 static int lib_route_map_entry_match_condition_list_name_modify(
544 struct nb_cb_modify_args *args)
545 {
546 struct routemap_hook_context *rhc;
547 const char *acl;
548 const char *condition;
549 int rv;
550
551 if (args->event != NB_EV_APPLY)
552 return NB_OK;
553
554 /* Check for hook installation, otherwise we can just stop. */
555 acl = yang_dnode_get_string(args->dnode, NULL);
556 rhc = nb_running_get_entry(args->dnode, NULL, true);
557 condition = yang_dnode_get_string(args->dnode, "../../condition");
558
559 if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) {
560 if (rmap_match_set_hook.match_ip_address == NULL)
561 return NB_OK;
562 rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_address;
563 rhc->rhc_rule = "ip address";
564 rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
565 rv = rmap_match_set_hook.match_ip_address(
566 rhc->rhc_rmi, "ip address", acl,
567 RMAP_EVENT_FILTER_ADDED,
568 args->errmsg, args->errmsg_len);
569 } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) {
570 if (rmap_match_set_hook.match_ip_address_prefix_list == NULL)
571 return NB_OK;
572 rhc->rhc_mhook =
573 rmap_match_set_hook.no_match_ip_address_prefix_list;
574 rhc->rhc_rule = "ip address prefix-list";
575 rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
576 rv = rmap_match_set_hook.match_ip_address_prefix_list(
577 rhc->rhc_rmi, "ip address prefix-list", acl,
578 RMAP_EVENT_PLIST_ADDED,
579 args->errmsg, args->errmsg_len);
580 } else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition)) {
581 if (rmap_match_set_hook.match_ip_next_hop == NULL)
582 return NB_OK;
583 rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop;
584 rhc->rhc_rule = "ip next-hop";
585 rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
586 rv = rmap_match_set_hook.match_ip_next_hop(
587 rhc->rhc_rmi, "ip next-hop", acl,
588 RMAP_EVENT_FILTER_ADDED,
589 args->errmsg, args->errmsg_len);
590 } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition)) {
591 if (rmap_match_set_hook.match_ipv6_next_hop == NULL)
592 return NB_OK;
593 rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop;
594 rhc->rhc_rule = "ipv6 next-hop";
595 rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
596 rv = rmap_match_set_hook.match_ipv6_next_hop(
597 rhc->rhc_rmi, "ipv6 next-hop", acl,
598 RMAP_EVENT_FILTER_ADDED, args->errmsg,
599 args->errmsg_len);
600 } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) {
601 if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL)
602 return NB_OK;
603 rhc->rhc_mhook =
604 rmap_match_set_hook.no_match_ip_next_hop_prefix_list;
605 rhc->rhc_rule = "ip next-hop prefix-list";
606 rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
607 rv = rmap_match_set_hook.match_ip_next_hop_prefix_list(
608 rhc->rhc_rmi, "ip next-hop prefix-list", acl,
609 RMAP_EVENT_PLIST_ADDED,
610 args->errmsg, args->errmsg_len);
611 } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) {
612 if (rmap_match_set_hook.match_ipv6_next_hop_prefix_list == NULL)
613 return NB_OK;
614 rhc->rhc_mhook =
615 rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list;
616 rhc->rhc_rule = "ipv6 next-hop prefix-list";
617 rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
618 rv = rmap_match_set_hook.match_ipv6_next_hop_prefix_list(
619 rhc->rhc_rmi, "ipv6 next-hop prefix-list", acl,
620 RMAP_EVENT_PLIST_ADDED, args->errmsg, args->errmsg_len);
621 } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) {
622 if (rmap_match_set_hook.match_ipv6_address == NULL)
623 return NB_OK;
624 rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_address;
625 rhc->rhc_rule = "ipv6 address";
626 rhc->rhc_event = RMAP_EVENT_FILTER_DELETED;
627 rv = rmap_match_set_hook.match_ipv6_address(
628 rhc->rhc_rmi, "ipv6 address", acl,
629 RMAP_EVENT_FILTER_ADDED,
630 args->errmsg, args->errmsg_len);
631 } else if (IS_MATCH_IPv6_PREFIX_LIST(condition)) {
632 if (rmap_match_set_hook.match_ipv6_address_prefix_list == NULL)
633 return NB_OK;
634 rhc->rhc_mhook =
635 rmap_match_set_hook.no_match_ipv6_address_prefix_list;
636 rhc->rhc_rule = "ipv6 address prefix-list";
637 rhc->rhc_event = RMAP_EVENT_PLIST_DELETED;
638 rv = rmap_match_set_hook.match_ipv6_address_prefix_list(
639 rhc->rhc_rmi, "ipv6 address prefix-list", acl,
640 RMAP_EVENT_PLIST_ADDED,
641 args->errmsg, args->errmsg_len);
642 } else
643 rv = CMD_ERR_NO_MATCH;
644
645 if (rv != CMD_SUCCESS) {
646 rhc->rhc_mhook = NULL;
647 return NB_ERR_INCONSISTENCY;
648 }
649
650 return NB_OK;
651 }
652
653 static int lib_route_map_entry_match_condition_list_name_destroy(
654 struct nb_cb_destroy_args *args)
655 {
656 return lib_route_map_entry_match_destroy(args);
657 }
658
659 /*
660 * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type
661 */
662 static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify(
663 struct nb_cb_modify_args *args)
664 {
665 struct routemap_hook_context *rhc;
666 const char *type;
667 int rv;
668
669 if (args->event != NB_EV_APPLY)
670 return NB_OK;
671
672 /* Check for hook function. */
673 if (rmap_match_set_hook.match_ip_next_hop_type == NULL)
674 return NB_OK;
675
676 /* Add configuration. */
677 rhc = nb_running_get_entry(args->dnode, NULL, true);
678 type = yang_dnode_get_string(args->dnode, NULL);
679
680 /* Set destroy information. */
681 rhc->rhc_mhook = rmap_match_set_hook.no_match_ip_next_hop_type;
682 rhc->rhc_rule = "ip next-hop type";
683 rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
684
685 rv = rmap_match_set_hook.match_ip_next_hop_type(
686 rhc->rhc_rmi, "ip next-hop type", type,
687 RMAP_EVENT_MATCH_ADDED,
688 args->errmsg, args->errmsg_len);
689 if (rv != CMD_SUCCESS) {
690 rhc->rhc_mhook = NULL;
691 return NB_ERR_INCONSISTENCY;
692 }
693
694 return NB_OK;
695 }
696
697 static int lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy(
698 struct nb_cb_destroy_args *args)
699 {
700 return lib_route_map_entry_match_destroy(args);
701 }
702
703 /*
704 * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type
705 */
706 static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify(
707 struct nb_cb_modify_args *args)
708 {
709 struct routemap_hook_context *rhc;
710 const char *type;
711 int rv;
712
713 if (args->event != NB_EV_APPLY)
714 return NB_OK;
715
716 /* Check for hook function. */
717 if (rmap_match_set_hook.match_ipv6_next_hop_type == NULL)
718 return NB_OK;
719
720 /* Add configuration. */
721 rhc = nb_running_get_entry(args->dnode, NULL, true);
722 type = yang_dnode_get_string(args->dnode, NULL);
723
724 /* Set destroy information. */
725 rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop_type;
726 rhc->rhc_rule = "ipv6 next-hop type";
727 rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
728
729 rv = rmap_match_set_hook.match_ipv6_next_hop_type(
730 rhc->rhc_rmi, "ipv6 next-hop type", type,
731 RMAP_EVENT_MATCH_ADDED,
732 args->errmsg, args->errmsg_len);
733 if (rv != CMD_SUCCESS) {
734 rhc->rhc_mhook = NULL;
735 return NB_ERR_INCONSISTENCY;
736 }
737
738 return NB_OK;
739 }
740
741 static int lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy(
742 struct nb_cb_destroy_args *args)
743 {
744 return lib_route_map_entry_match_destroy(args);
745 }
746
747 /*
748 * XPath: /frr-route-map:lib/route-map/entry/match-condition/metric
749 */
750 static int lib_route_map_entry_match_condition_metric_modify(
751 struct nb_cb_modify_args *args)
752 {
753 struct routemap_hook_context *rhc;
754 const char *type;
755 int rv;
756
757 if (args->event != NB_EV_APPLY)
758 return NB_OK;
759
760 /* Check for hook function. */
761 if (rmap_match_set_hook.match_metric == NULL)
762 return NB_OK;
763
764 /* Add configuration. */
765 rhc = nb_running_get_entry(args->dnode, NULL, true);
766 type = yang_dnode_get_string(args->dnode, NULL);
767
768 /* Set destroy information. */
769 rhc->rhc_mhook = rmap_match_set_hook.no_match_metric;
770 rhc->rhc_rule = "metric";
771 rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
772
773 rv = rmap_match_set_hook.match_metric(rhc->rhc_rmi, "metric",
774 type, RMAP_EVENT_MATCH_ADDED,
775 args->errmsg, args->errmsg_len);
776 if (rv != CMD_SUCCESS) {
777 rhc->rhc_mhook = NULL;
778 return NB_ERR_INCONSISTENCY;
779 }
780
781 return NB_OK;
782 }
783
784 static int lib_route_map_entry_match_condition_metric_destroy(
785 struct nb_cb_destroy_args *args)
786 {
787 return lib_route_map_entry_match_destroy(args);
788 }
789
790 /*
791 * XPath: /frr-route-map:lib/route-map/entry/match-condition/tag
792 */
793 static int
794 lib_route_map_entry_match_condition_tag_modify(struct nb_cb_modify_args *args)
795 {
796 struct routemap_hook_context *rhc;
797 const char *tag;
798 int rv;
799
800 if (args->event != NB_EV_APPLY)
801 return NB_OK;
802
803 /* Check for hook function. */
804 if (rmap_match_set_hook.match_tag == NULL)
805 return NB_OK;
806
807 /* Add configuration. */
808 rhc = nb_running_get_entry(args->dnode, NULL, true);
809 tag = yang_dnode_get_string(args->dnode, NULL);
810
811 /* Set destroy information. */
812 rhc->rhc_mhook = rmap_match_set_hook.no_match_tag;
813 rhc->rhc_rule = "tag";
814 rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
815
816 rv = rmap_match_set_hook.match_tag(rhc->rhc_rmi, "tag", tag,
817 RMAP_EVENT_MATCH_ADDED,
818 args->errmsg, args->errmsg_len);
819 if (rv != CMD_SUCCESS) {
820 rhc->rhc_mhook = NULL;
821 return NB_ERR_INCONSISTENCY;
822 }
823
824 return NB_OK;
825 }
826
827 static int
828 lib_route_map_entry_match_condition_tag_destroy(struct nb_cb_destroy_args *args)
829 {
830 return lib_route_map_entry_match_destroy(args);
831 }
832
833 /*
834 * XPath: /frr-route-map:lib/route-map/entry/set-action
835 */
836 static int lib_route_map_entry_set_action_create(struct nb_cb_create_args *args)
837 {
838 return lib_route_map_entry_match_condition_create(args);
839 }
840
841 static int
842 lib_route_map_entry_set_action_destroy(struct nb_cb_destroy_args *args)
843 {
844 struct routemap_hook_context *rhc;
845 int rv;
846
847 if (args->event != NB_EV_APPLY)
848 return NB_OK;
849
850 rv = lib_route_map_entry_set_destroy(args);
851 rhc = nb_running_unset_entry(args->dnode);
852 routemap_hook_context_free(rhc);
853
854 return rv;
855 }
856
857 /*
858 * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv4-address
859 */
860 static int lib_route_map_entry_set_action_ipv4_address_modify(
861 struct nb_cb_modify_args *args)
862 {
863 struct routemap_hook_context *rhc;
864 const char *address;
865 struct in_addr ia;
866 int rv;
867
868 switch (args->event) {
869 case NB_EV_VALIDATE:
870 /*
871 * NOTE: validate if 'action' is 'ipv4-next-hop',
872 * currently it is not necessary because this is the
873 * only implemented action.
874 */
875 yang_dnode_get_ipv4(&ia, args->dnode, NULL);
876 if (ia.s_addr == INADDR_ANY || !ipv4_unicast_valid(&ia))
877 return NB_ERR_VALIDATION;
878 /* FALLTHROUGH */
879 case NB_EV_PREPARE:
880 case NB_EV_ABORT:
881 return NB_OK;
882 case NB_EV_APPLY:
883 break;
884 }
885
886 /* Check for hook function. */
887 if (rmap_match_set_hook.set_ip_nexthop == NULL)
888 return NB_OK;
889
890 /* Add configuration. */
891 rhc = nb_running_get_entry(args->dnode, NULL, true);
892 address = yang_dnode_get_string(args->dnode, NULL);
893
894 /* Set destroy information. */
895 rhc->rhc_shook = rmap_match_set_hook.no_set_ip_nexthop;
896 rhc->rhc_rule = "ip next-hop";
897
898 rv = rmap_match_set_hook.set_ip_nexthop(rhc->rhc_rmi, "ip next-hop",
899 address,
900 args->errmsg, args->errmsg_len);
901 if (rv != CMD_SUCCESS) {
902 rhc->rhc_shook = NULL;
903 return NB_ERR_INCONSISTENCY;
904 }
905
906 return NB_OK;
907 }
908
909 static int lib_route_map_entry_set_action_ipv4_address_destroy(
910 struct nb_cb_destroy_args *args)
911 {
912 return lib_route_map_entry_set_destroy(args);
913 }
914
915 /*
916 * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv6-address
917 */
918 static int lib_route_map_entry_set_action_ipv6_address_modify(
919 struct nb_cb_modify_args *args)
920 {
921 struct routemap_hook_context *rhc;
922 const char *address;
923 struct in6_addr i6a;
924 int rv;
925
926 switch (args->event) {
927 case NB_EV_VALIDATE:
928 /*
929 * NOTE: validate if 'action' is 'ipv6-next-hop',
930 * currently it is not necessary because this is the
931 * only implemented action. Other actions might have
932 * different validations.
933 */
934 yang_dnode_get_ipv6(&i6a, args->dnode, NULL);
935 if (!IN6_IS_ADDR_LINKLOCAL(&i6a))
936 return NB_ERR_VALIDATION;
937 /* FALLTHROUGH */
938 case NB_EV_PREPARE:
939 case NB_EV_ABORT:
940 return NB_OK;
941 case NB_EV_APPLY:
942 break;
943 }
944
945 /* Check for hook function. */
946 if (rmap_match_set_hook.set_ipv6_nexthop_local == NULL)
947 return NB_OK;
948
949 /* Add configuration. */
950 rhc = nb_running_get_entry(args->dnode, NULL, true);
951 address = yang_dnode_get_string(args->dnode, NULL);
952
953 /* Set destroy information. */
954 rhc->rhc_shook = rmap_match_set_hook.no_set_ipv6_nexthop_local;
955 rhc->rhc_rule = "ipv6 next-hop local";
956
957 rv = rmap_match_set_hook.set_ipv6_nexthop_local(
958 rhc->rhc_rmi, "ipv6 next-hop local", address,
959 args->errmsg, args->errmsg_len);
960 if (rv != CMD_SUCCESS) {
961 rhc->rhc_shook = NULL;
962 return NB_ERR_INCONSISTENCY;
963 }
964
965 return NB_OK;
966 }
967
968 static int lib_route_map_entry_set_action_ipv6_address_destroy(
969 struct nb_cb_destroy_args *args)
970 {
971 return lib_route_map_entry_set_destroy(args);
972 }
973
974 /*
975 * XPath: /frr-route-map:lib/route-map/entry/set-action/value
976 */
977 static int set_action_modify(enum nb_event event, const struct lyd_node *dnode,
978 union nb_resource *resource, const char *value,
979 char *errmsg, size_t errmsg_len)
980 {
981 struct routemap_hook_context *rhc;
982 int rv;
983
984 /*
985 * NOTE: validate if 'action' is 'metric', currently it is not
986 * necessary because this is the only implemented action. Other
987 * actions might have different validations.
988 */
989 if (event != NB_EV_APPLY)
990 return NB_OK;
991
992 /* Check for hook function. */
993 if (rmap_match_set_hook.set_metric == NULL)
994 return NB_OK;
995
996 /* Add configuration. */
997 rhc = nb_running_get_entry(dnode, NULL, true);
998
999 /* Set destroy information. */
1000 rhc->rhc_shook = rmap_match_set_hook.no_set_metric;
1001 rhc->rhc_rule = "metric";
1002
1003 rv = rmap_match_set_hook.set_metric(rhc->rhc_rmi, "metric",
1004 value,
1005 errmsg, errmsg_len
1006 );
1007 if (rv != CMD_SUCCESS) {
1008 rhc->rhc_shook = NULL;
1009 return NB_ERR_INCONSISTENCY;
1010 }
1011
1012 return NB_OK;
1013 }
1014
1015 static int
1016 lib_route_map_entry_set_action_value_modify(struct nb_cb_modify_args *args)
1017 {
1018 const char *metric = yang_dnode_get_string(args->dnode, NULL);
1019
1020 return set_action_modify(args->event, args->dnode, args->resource,
1021 metric, args->errmsg, args->errmsg_len);
1022 }
1023
1024 static int
1025 lib_route_map_entry_set_action_value_destroy(struct nb_cb_destroy_args *args)
1026 {
1027 return lib_route_map_entry_set_destroy(args);
1028 }
1029
1030 /*
1031 * XPath: /frr-route-map:lib/route-map/entry/set-action/min-metric
1032 */
1033 static int set_action_min_metric_modify(enum nb_event event,
1034 const struct lyd_node *dnode,
1035 union nb_resource *resource,
1036 const char *value, char *errmsg,
1037 size_t errmsg_len)
1038 {
1039 struct routemap_hook_context *rhc;
1040 int rv;
1041
1042 if (event != NB_EV_APPLY)
1043 return NB_OK;
1044
1045 /* Check for hook function. */
1046 if (rmap_match_set_hook.set_min_metric == NULL)
1047 return NB_OK;
1048
1049 /* Add configuration. */
1050 rhc = nb_running_get_entry(dnode, NULL, true);
1051
1052 /* Set destroy information. */
1053 rhc->rhc_shook = rmap_match_set_hook.no_set_min_metric;
1054 rhc->rhc_rule = "min-metric";
1055
1056 rv = rmap_match_set_hook.set_min_metric(rhc->rhc_rmi, "min-metric",
1057 value, errmsg, errmsg_len);
1058 if (rv != CMD_SUCCESS) {
1059 rhc->rhc_shook = NULL;
1060 return NB_ERR_INCONSISTENCY;
1061 }
1062
1063 return NB_OK;
1064 }
1065
1066 static int
1067 lib_route_map_entry_set_action_min_metric_modify(struct nb_cb_modify_args *args)
1068 {
1069 const char *min_metric = yang_dnode_get_string(args->dnode, NULL);
1070
1071 return set_action_min_metric_modify(args->event, args->dnode,
1072 args->resource, min_metric,
1073 args->errmsg, args->errmsg_len);
1074 }
1075
1076 static int lib_route_map_entry_set_action_min_metric_destroy(
1077 struct nb_cb_destroy_args *args)
1078 {
1079 return lib_route_map_entry_set_destroy(args);
1080 }
1081
1082 /*
1083 * XPath: /frr-route-map:lib/route-map/entry/set-action/max-metric
1084 */
1085 static int set_action_max_metric_modify(enum nb_event event,
1086 const struct lyd_node *dnode,
1087 union nb_resource *resource,
1088 const char *value, char *errmsg,
1089 size_t errmsg_len)
1090 {
1091 struct routemap_hook_context *rhc;
1092 int rv;
1093
1094 if (event != NB_EV_APPLY)
1095 return NB_OK;
1096
1097 /* Check for hook function. */
1098 if (rmap_match_set_hook.set_max_metric == NULL)
1099 return NB_OK;
1100
1101 /* Add configuration. */
1102 rhc = nb_running_get_entry(dnode, NULL, true);
1103
1104 /* Set destroy information. */
1105 rhc->rhc_shook = rmap_match_set_hook.no_set_max_metric;
1106 rhc->rhc_rule = "max-metric";
1107
1108 rv = rmap_match_set_hook.set_max_metric(rhc->rhc_rmi, "max-metric",
1109 value, errmsg, errmsg_len);
1110 if (rv != CMD_SUCCESS) {
1111 rhc->rhc_shook = NULL;
1112 return NB_ERR_INCONSISTENCY;
1113 }
1114
1115 return NB_OK;
1116 }
1117
1118 static int
1119 lib_route_map_entry_set_action_max_metric_modify(struct nb_cb_modify_args *args)
1120 {
1121 const char *max_metric = yang_dnode_get_string(args->dnode, NULL);
1122
1123 return set_action_max_metric_modify(args->event, args->dnode,
1124 args->resource, max_metric,
1125 args->errmsg, args->errmsg_len);
1126 }
1127
1128 static int lib_route_map_entry_set_action_max_metric_destroy(
1129 struct nb_cb_destroy_args *args)
1130 {
1131 return lib_route_map_entry_set_destroy(args);
1132 }
1133
1134 /*
1135 * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric
1136 */
1137 static int
1138 lib_route_map_entry_set_action_add_metric_modify(struct nb_cb_modify_args *args)
1139 {
1140 char metric_str[16];
1141
1142 if (args->event == NB_EV_VALIDATE
1143 && yang_dnode_get_uint32(args->dnode, NULL) == 0) {
1144 snprintf(args->errmsg, args->errmsg_len,
1145 "Can't add zero to metric");
1146 return NB_ERR_VALIDATION;
1147 }
1148
1149 snprintf(metric_str, sizeof(metric_str), "+%s",
1150 yang_dnode_get_string(args->dnode, NULL));
1151 return set_action_modify(args->event, args->dnode, args->resource,
1152 metric_str,
1153 args->errmsg, args->errmsg_len);
1154 }
1155
1156 static int lib_route_map_entry_set_action_add_metric_destroy(
1157 struct nb_cb_destroy_args *args)
1158 {
1159 return lib_route_map_entry_set_action_value_destroy(args);
1160 }
1161
1162 /*
1163 * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-metric
1164 */
1165 static int lib_route_map_entry_set_action_subtract_metric_modify(
1166 struct nb_cb_modify_args *args)
1167 {
1168 char metric_str[16];
1169
1170 if (args->event == NB_EV_VALIDATE
1171 && yang_dnode_get_uint32(args->dnode, NULL) == 0) {
1172 snprintf(args->errmsg, args->errmsg_len,
1173 "Can't subtract zero from metric");
1174 return NB_ERR_VALIDATION;
1175 }
1176
1177 snprintf(metric_str, sizeof(metric_str), "-%s",
1178 yang_dnode_get_string(args->dnode, NULL));
1179 return set_action_modify(args->event, args->dnode, args->resource,
1180 metric_str,
1181 args->errmsg, args->errmsg_len);
1182 }
1183
1184 static int lib_route_map_entry_set_action_subtract_metric_destroy(
1185 struct nb_cb_destroy_args *args)
1186 {
1187 return lib_route_map_entry_set_action_value_destroy(args);
1188 }
1189
1190 /*
1191 * XPath: /frr-route-map:lib/route-map/entry/set-action/use-round-trip-time
1192 */
1193 static int lib_route_map_entry_set_action_use_round_trip_time_modify(
1194 struct nb_cb_modify_args *args)
1195 {
1196 return set_action_modify(args->event, args->dnode, args->resource,
1197 "rtt",
1198 args->errmsg, args->errmsg_len);
1199 }
1200
1201 static int lib_route_map_entry_set_action_use_round_trip_time_destroy(
1202 struct nb_cb_destroy_args *args)
1203 {
1204 return lib_route_map_entry_set_action_value_destroy(args);
1205 }
1206
1207 /*
1208 * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time
1209 */
1210 static int lib_route_map_entry_set_action_add_round_trip_time_modify(
1211 struct nb_cb_modify_args *args)
1212 {
1213 return set_action_modify(args->event, args->dnode, args->resource,
1214 "+rtt",
1215 args->errmsg, args->errmsg_len);
1216 }
1217
1218 static int lib_route_map_entry_set_action_add_round_trip_time_destroy(
1219 struct nb_cb_destroy_args *args)
1220 {
1221 return lib_route_map_entry_set_action_value_destroy(args);
1222 }
1223
1224 /*
1225 * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time
1226 */
1227 static int lib_route_map_entry_set_action_subtract_round_trip_time_modify(
1228 struct nb_cb_modify_args *args)
1229 {
1230 return set_action_modify(args->event, args->dnode, args->resource,
1231 "-rtt", args->errmsg, args->errmsg_len);
1232 }
1233
1234 static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy(
1235 struct nb_cb_destroy_args *args)
1236 {
1237 return lib_route_map_entry_set_action_value_destroy(args);
1238 }
1239
1240 /*
1241 * XPath: /frr-route-map:lib/route-map/entry/set-action/tag
1242 */
1243 static int
1244 lib_route_map_entry_set_action_tag_modify(struct nb_cb_modify_args *args)
1245 {
1246 struct routemap_hook_context *rhc;
1247 const char *tag;
1248 int rv;
1249
1250 /*
1251 * NOTE: validate if 'action' is 'tag', currently it is not
1252 * necessary because this is the only implemented action. Other
1253 * actions might have different validations.
1254 */
1255 if (args->event != NB_EV_APPLY)
1256 return NB_OK;
1257
1258 /* Check for hook function. */
1259 if (rmap_match_set_hook.set_tag == NULL)
1260 return NB_OK;
1261
1262 /* Add configuration. */
1263 rhc = nb_running_get_entry(args->dnode, NULL, true);
1264 tag = yang_dnode_get_string(args->dnode, NULL);
1265
1266 /* Set destroy information. */
1267 rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
1268 rhc->rhc_rule = "tag";
1269
1270 rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "tag", tag,
1271 args->errmsg, args->errmsg_len);
1272 if (rv != CMD_SUCCESS) {
1273 rhc->rhc_shook = NULL;
1274 return NB_ERR_INCONSISTENCY;
1275 }
1276
1277 return NB_OK;
1278 }
1279
1280 static int
1281 lib_route_map_entry_set_action_tag_destroy(struct nb_cb_destroy_args *args)
1282 {
1283 return lib_route_map_entry_set_destroy(args);
1284 }
1285
1286 /*
1287 * XPath: /frr-route-map:lib/route-map/entry/set-action/policy
1288 */
1289 static int
1290 lib_route_map_entry_set_action_policy_modify(struct nb_cb_modify_args *args)
1291 {
1292 struct routemap_hook_context *rhc;
1293 const char *policy;
1294 int rv;
1295
1296 /*
1297 * NOTE: validate if 'action' is 'tag', currently it is not
1298 * necessary because this is the only implemented action. Other
1299 * actions might have different validations.
1300 */
1301 if (args->event != NB_EV_APPLY)
1302 return NB_OK;
1303
1304 /* Check for hook function. */
1305 if (rmap_match_set_hook.set_srte_color == NULL)
1306 return NB_OK;
1307
1308 /* Add configuration. */
1309 rhc = nb_running_get_entry(args->dnode, NULL, true);
1310 policy = yang_dnode_get_string(args->dnode, NULL);
1311
1312 /* Set destroy information. */
1313 rhc->rhc_shook = rmap_match_set_hook.no_set_tag;
1314 rhc->rhc_rule = "sr-te color";
1315
1316 rv = rmap_match_set_hook.set_tag(rhc->rhc_rmi, "sr-te color", policy,
1317 args->errmsg, args->errmsg_len);
1318 if (rv != CMD_SUCCESS) {
1319 rhc->rhc_shook = NULL;
1320 return NB_ERR_INCONSISTENCY;
1321 }
1322
1323 return NB_OK;
1324 }
1325
1326 static int
1327 lib_route_map_entry_set_action_policy_destroy(struct nb_cb_destroy_args *args)
1328 {
1329 return lib_route_map_entry_set_destroy(args);
1330 }
1331
1332 /* clang-format off */
1333 const struct frr_yang_module_info frr_route_map_info = {
1334 .name = "frr-route-map",
1335 .nodes = {
1336 {
1337 .xpath = "/frr-route-map:lib/route-map",
1338 .cbs = {
1339 .create = lib_route_map_create,
1340 .destroy = lib_route_map_destroy,
1341 }
1342 },
1343 {
1344 .xpath = "/frr-route-map:lib/route-map/optimization-disabled",
1345 .cbs = {
1346 .modify = lib_route_map_optimization_disabled_modify,
1347 .cli_show = route_map_optimization_disabled_show,
1348 }
1349 },
1350 {
1351 .xpath = "/frr-route-map:lib/route-map/entry",
1352 .cbs = {
1353 .create = lib_route_map_entry_create,
1354 .destroy = lib_route_map_entry_destroy,
1355 .cli_cmp = route_map_instance_cmp,
1356 .cli_show = route_map_instance_show,
1357 .cli_show_end = route_map_instance_show_end,
1358 }
1359 },
1360 {
1361 .xpath = "/frr-route-map:lib/route-map/entry/description",
1362 .cbs = {
1363 .modify = lib_route_map_entry_description_modify,
1364 .destroy = lib_route_map_entry_description_destroy,
1365 .cli_show = route_map_description_show,
1366 }
1367 },
1368 {
1369 .xpath = "/frr-route-map:lib/route-map/entry/action",
1370 .cbs = {
1371 .modify = lib_route_map_entry_action_modify,
1372 }
1373 },
1374 {
1375 .xpath = "/frr-route-map:lib/route-map/entry/call",
1376 .cbs = {
1377 .modify = lib_route_map_entry_call_modify,
1378 .destroy = lib_route_map_entry_call_destroy,
1379 .cli_show = route_map_call_show,
1380 }
1381 },
1382 {
1383 .xpath = "/frr-route-map:lib/route-map/entry/exit-policy",
1384 .cbs = {
1385 .modify = lib_route_map_entry_exit_policy_modify,
1386 .cli_show = route_map_exit_policy_show,
1387 }
1388 },
1389 {
1390 .xpath = "/frr-route-map:lib/route-map/entry/goto-value",
1391 .cbs = {
1392 .modify = lib_route_map_entry_goto_value_modify,
1393 .destroy = lib_route_map_entry_goto_value_destroy,
1394 }
1395 },
1396 {
1397 .xpath = "/frr-route-map:lib/route-map/entry/match-condition",
1398 .cbs = {
1399 .create = lib_route_map_entry_match_condition_create,
1400 .destroy = lib_route_map_entry_match_condition_destroy,
1401 .cli_show = route_map_condition_show,
1402 }
1403 },
1404 {
1405 .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/interface",
1406 .cbs = {
1407 .modify = lib_route_map_entry_match_condition_interface_modify,
1408 .destroy = lib_route_map_entry_match_condition_interface_destroy,
1409 }
1410 },
1411 {
1412 .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/list-name",
1413 .cbs = {
1414 .modify = lib_route_map_entry_match_condition_list_name_modify,
1415 .destroy = lib_route_map_entry_match_condition_list_name_destroy,
1416 }
1417 },
1418 {
1419 .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv4-next-hop-type",
1420 .cbs = {
1421 .modify = lib_route_map_entry_match_condition_ipv4_next_hop_type_modify,
1422 .destroy = lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy,
1423 }
1424 },
1425 {
1426 .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv6-next-hop-type",
1427 .cbs = {
1428 .modify = lib_route_map_entry_match_condition_ipv6_next_hop_type_modify,
1429 .destroy = lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy,
1430 }
1431 },
1432 {
1433 .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/metric",
1434 .cbs = {
1435 .modify = lib_route_map_entry_match_condition_metric_modify,
1436 .destroy = lib_route_map_entry_match_condition_metric_destroy,
1437 }
1438 },
1439 {
1440 .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/tag",
1441 .cbs = {
1442 .modify = lib_route_map_entry_match_condition_tag_modify,
1443 .destroy = lib_route_map_entry_match_condition_tag_destroy,
1444 }
1445 },
1446 {
1447 .xpath = "/frr-route-map:lib/route-map/entry/set-action",
1448 .cbs = {
1449 .create = lib_route_map_entry_set_action_create,
1450 .destroy = lib_route_map_entry_set_action_destroy,
1451 .cli_show = route_map_action_show,
1452 }
1453 },
1454 {
1455 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv4-address",
1456 .cbs = {
1457 .modify = lib_route_map_entry_set_action_ipv4_address_modify,
1458 .destroy = lib_route_map_entry_set_action_ipv4_address_destroy,
1459 }
1460 },
1461 {
1462 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv6-address",
1463 .cbs = {
1464 .modify = lib_route_map_entry_set_action_ipv6_address_modify,
1465 .destroy = lib_route_map_entry_set_action_ipv6_address_destroy,
1466 }
1467 },
1468 {
1469 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/value",
1470 .cbs = {
1471 .modify = lib_route_map_entry_set_action_value_modify,
1472 .destroy = lib_route_map_entry_set_action_value_destroy,
1473 }
1474 },
1475 {
1476 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/min-metric",
1477 .cbs = {
1478 .modify = lib_route_map_entry_set_action_min_metric_modify,
1479 .destroy = lib_route_map_entry_set_action_min_metric_destroy,
1480 }
1481 },
1482 {
1483 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/max-metric",
1484 .cbs = {
1485 .modify = lib_route_map_entry_set_action_max_metric_modify,
1486 .destroy = lib_route_map_entry_set_action_max_metric_destroy,
1487 }
1488 },
1489 {
1490 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-metric",
1491 .cbs = {
1492 .modify = lib_route_map_entry_set_action_add_metric_modify,
1493 .destroy = lib_route_map_entry_set_action_add_metric_destroy,
1494 }
1495 },
1496 {
1497 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-metric",
1498 .cbs = {
1499 .modify = lib_route_map_entry_set_action_subtract_metric_modify,
1500 .destroy = lib_route_map_entry_set_action_subtract_metric_destroy,
1501 }
1502 },
1503 {
1504 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/use-round-trip-time",
1505 .cbs = {
1506 .modify = lib_route_map_entry_set_action_use_round_trip_time_modify,
1507 .destroy = lib_route_map_entry_set_action_use_round_trip_time_destroy,
1508 }
1509 },
1510 {
1511 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-round-trip-time",
1512 .cbs = {
1513 .modify = lib_route_map_entry_set_action_add_round_trip_time_modify,
1514 .destroy = lib_route_map_entry_set_action_add_round_trip_time_destroy,
1515 }
1516 },
1517 {
1518 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-round-trip-time",
1519 .cbs = {
1520 .modify = lib_route_map_entry_set_action_subtract_round_trip_time_modify,
1521 .destroy = lib_route_map_entry_set_action_subtract_round_trip_time_destroy,
1522 }
1523 },
1524 {
1525 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/tag",
1526 .cbs = {
1527 .modify = lib_route_map_entry_set_action_tag_modify,
1528 .destroy = lib_route_map_entry_set_action_tag_destroy,
1529 }
1530 },
1531 {
1532 .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/policy",
1533 .cbs = {
1534 .modify = lib_route_map_entry_set_action_policy_modify,
1535 .destroy = lib_route_map_entry_set_action_policy_destroy,
1536 }
1537 },
1538
1539 {
1540 .xpath = NULL,
1541 },
1542 }
1543 };