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