2 * Route map northbound implementation.
4 * Copyright (C) 2019 Network Device Education Foundation, Inc. ("NetDEF")
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.
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.
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
25 #include "lib/command.h"
27 #include "lib/northbound.h"
28 #include "lib/routemap.h"
31 * Auxiliary functions to avoid code duplication:
33 * lib_route_map_entry_set_destroy: unset `set` commands.
34 * lib_route_map_entry_match_destroy: unset `match` commands.
36 int lib_route_map_entry_match_destroy(struct nb_cb_destroy_args
*args
)
38 struct routemap_hook_context
*rhc
;
41 if (args
->event
!= NB_EV_APPLY
)
44 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
45 if (rhc
->rhc_mhook
== NULL
)
48 rv
= rhc
->rhc_mhook(rhc
->rhc_rmi
, rhc
->rhc_rule
, NULL
,
50 args
->errmsg
, args
->errmsg_len
);
51 if (rv
!= CMD_SUCCESS
)
52 return NB_ERR_INCONSISTENCY
;
57 int lib_route_map_entry_set_destroy(struct nb_cb_destroy_args
*args
)
59 struct routemap_hook_context
*rhc
;
62 if (args
->event
!= NB_EV_APPLY
)
65 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
66 if (rhc
->rhc_shook
== NULL
)
69 rv
= rhc
->rhc_shook(rhc
->rhc_rmi
, rhc
->rhc_rule
, NULL
,
70 args
->errmsg
, args
->errmsg_len
);
71 if (rv
!= CMD_SUCCESS
)
72 return NB_ERR_INCONSISTENCY
;
78 * Auxiliary hook context list manipulation functions.
80 struct routemap_hook_context
*
81 routemap_hook_context_insert(struct route_map_index
*rmi
)
83 struct routemap_hook_context
*rhc
;
85 rhc
= XCALLOC(MTYPE_TMP
, sizeof(*rhc
));
87 TAILQ_INSERT_TAIL(&rmi
->rhclist
, rhc
, rhc_entry
);
92 void routemap_hook_context_free(struct routemap_hook_context
*rhc
)
94 struct route_map_index
*rmi
= rhc
->rhc_rmi
;
96 TAILQ_REMOVE(&rmi
->rhclist
, rhc
, rhc_entry
);
97 XFREE(MTYPE_TMP
, rhc
);
101 * XPath: /frr-route-map:lib/route-map
103 static int lib_route_map_create(struct nb_cb_create_args
*args
)
105 struct route_map
*rm
;
108 switch (args
->event
) {
115 rm_name
= yang_dnode_get_string(args
->dnode
, "./name");
116 rm
= route_map_get(rm_name
);
117 nb_running_set_entry(args
->dnode
, rm
);
124 static int lib_route_map_destroy(struct nb_cb_destroy_args
*args
)
126 struct route_map
*rm
;
128 switch (args
->event
) {
135 rm
= nb_running_unset_entry(args
->dnode
);
136 route_map_delete(rm
);
144 * XPath: /frr-route-map:lib/route-map/optimization-disabled
147 lib_route_map_optimization_disabled_modify(struct nb_cb_modify_args
*args
)
149 struct route_map
*rm
;
150 bool disabled
= yang_dnode_get_bool(args
->dnode
, NULL
);
152 switch (args
->event
) {
159 rm
= nb_running_get_entry(args
->dnode
, NULL
, true);
160 rm
->optimization_disabled
= disabled
;
168 * XPath: /frr-route-map:lib/route-map/entry
170 static int lib_route_map_entry_create(struct nb_cb_create_args
*args
)
172 struct route_map_index
*rmi
;
173 struct route_map
*rm
;
177 switch (args
->event
) {
184 sequence
= yang_dnode_get_uint16(args
->dnode
, "./sequence");
185 action
= yang_dnode_get_enum(args
->dnode
, "./action") == 0
188 rm
= nb_running_get_entry(args
->dnode
, NULL
, true);
189 rmi
= route_map_index_get(rm
, action
, sequence
);
190 nb_running_set_entry(args
->dnode
, rmi
);
197 static int lib_route_map_entry_destroy(struct nb_cb_destroy_args
*args
)
199 struct route_map_index
*rmi
;
201 switch (args
->event
) {
208 rmi
= nb_running_unset_entry(args
->dnode
);
209 route_map_index_delete(rmi
, 1);
217 * XPath: /frr-route-map:lib/route-map/entry/description
220 lib_route_map_entry_description_modify(struct nb_cb_modify_args
*args
)
222 struct route_map_index
*rmi
;
223 const char *description
;
225 switch (args
->event
) {
230 description
= yang_dnode_get_string(args
->dnode
, NULL
);
231 args
->resource
->ptr
= XSTRDUP(MTYPE_TMP
, description
);
232 if (args
->resource
->ptr
== NULL
)
233 return NB_ERR_RESOURCE
;
236 XFREE(MTYPE_TMP
, args
->resource
->ptr
);
239 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
240 XFREE(MTYPE_TMP
, rmi
->description
);
241 rmi
->description
= args
->resource
->ptr
;
249 lib_route_map_entry_description_destroy(struct nb_cb_destroy_args
*args
)
251 struct route_map_index
*rmi
;
253 switch (args
->event
) {
260 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
261 XFREE(MTYPE_TMP
, rmi
->description
);
269 * XPath: /frr-route-map:lib/route-map/entry/action
271 static int lib_route_map_entry_action_modify(struct nb_cb_modify_args
*args
)
273 struct route_map_index
*rmi
;
274 struct route_map
*map
;
276 switch (args
->event
) {
283 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
284 rmi
->type
= yang_dnode_get_enum(args
->dnode
, NULL
);
287 /* Execute event hook. */
288 if (route_map_master
.event_hook
) {
289 (*route_map_master
.event_hook
)(map
->name
);
290 route_map_notify_dependencies(map
->name
,
291 RMAP_EVENT_CALL_ADDED
);
301 * XPath: /frr-route-map:lib/route-map/entry/call
303 static int lib_route_map_entry_call_modify(struct nb_cb_modify_args
*args
)
305 struct route_map_index
*rmi
;
306 const char *rm_name
, *rmn_name
;
308 switch (args
->event
) {
310 rm_name
= yang_dnode_get_string(args
->dnode
, "../../name");
311 rmn_name
= yang_dnode_get_string(args
->dnode
, NULL
);
312 /* Don't allow to jump to the same route map instance. */
313 if (strcmp(rm_name
, rmn_name
) == 0)
314 return NB_ERR_VALIDATION
;
316 /* TODO: detect circular route map sequences. */
319 rmn_name
= yang_dnode_get_string(args
->dnode
, NULL
);
320 args
->resource
->ptr
= XSTRDUP(MTYPE_ROUTE_MAP_NAME
, rmn_name
);
323 XFREE(MTYPE_ROUTE_MAP_NAME
, args
->resource
->ptr
);
326 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
328 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
,
329 rmi
->nextrm
, rmi
->map
->name
);
330 XFREE(MTYPE_ROUTE_MAP_NAME
, rmi
->nextrm
);
332 rmi
->nextrm
= args
->resource
->ptr
;
333 route_map_upd8_dependency(RMAP_EVENT_CALL_ADDED
, rmi
->nextrm
,
341 static int lib_route_map_entry_call_destroy(struct nb_cb_destroy_args
*args
)
343 struct route_map_index
*rmi
;
345 switch (args
->event
) {
352 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
353 route_map_upd8_dependency(RMAP_EVENT_CALL_DELETED
, rmi
->nextrm
,
355 XFREE(MTYPE_ROUTE_MAP_NAME
, rmi
->nextrm
);
364 * XPath: /frr-route-map:lib/route-map/entry/exit-policy
367 lib_route_map_entry_exit_policy_modify(struct nb_cb_modify_args
*args
)
369 struct route_map_index
*rmi
;
373 switch (args
->event
) {
375 policy
= yang_dnode_get_enum(args
->dnode
, NULL
);
377 case 0: /* permit-or-deny */
383 yang_dnode_get_enum(args
->dnode
, "../action");
384 if (rm_action
== 1 /* deny */) {
386 * On deny it is not possible to 'goto'
389 return NB_ERR_VALIDATION
;
398 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
399 policy
= yang_dnode_get_enum(args
->dnode
, NULL
);
402 case 0: /* permit-or-deny */
403 rmi
->exitpolicy
= RMAP_EXIT
;
406 rmi
->exitpolicy
= RMAP_NEXT
;
409 rmi
->exitpolicy
= RMAP_GOTO
;
419 * XPath: /frr-route-map:lib/route-map/entry/goto-value
421 static int lib_route_map_entry_goto_value_modify(struct nb_cb_modify_args
*args
)
423 struct route_map_index
*rmi
;
427 switch (args
->event
) {
429 rmi_index
= yang_dnode_get_uint16(args
->dnode
, "../sequence");
430 rmi_next
= yang_dnode_get_uint16(args
->dnode
, NULL
);
431 if (rmi_next
<= rmi_index
) {
432 /* Can't jump backwards on a route map. */
433 return NB_ERR_VALIDATION
;
441 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
442 rmi
->nextpref
= yang_dnode_get_uint16(args
->dnode
, NULL
);
450 lib_route_map_entry_goto_value_destroy(struct nb_cb_destroy_args
*args
)
452 struct route_map_index
*rmi
;
454 switch (args
->event
) {
461 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
470 * XPath: /frr-route-map:lib/route-map/entry/match-condition
473 lib_route_map_entry_match_condition_create(struct nb_cb_create_args
*args
)
475 struct routemap_hook_context
*rhc
;
476 struct route_map_index
*rmi
;
478 switch (args
->event
) {
485 rmi
= nb_running_get_entry(args
->dnode
, NULL
, true);
486 rhc
= routemap_hook_context_insert(rmi
);
487 nb_running_set_entry(args
->dnode
, rhc
);
495 lib_route_map_entry_match_condition_destroy(struct nb_cb_destroy_args
*args
)
497 struct routemap_hook_context
*rhc
;
500 if (args
->event
!= NB_EV_APPLY
)
503 rv
= lib_route_map_entry_match_destroy(args
);
504 rhc
= nb_running_unset_entry(args
->dnode
);
505 routemap_hook_context_free(rhc
);
511 * XPath: /frr-route-map:lib/route-map/entry/match-condition/interface
513 static int lib_route_map_entry_match_condition_interface_modify(
514 struct nb_cb_modify_args
*args
)
516 struct routemap_hook_context
*rhc
;
520 if (args
->event
!= NB_EV_APPLY
)
523 /* Check for hook function. */
524 if (rmap_match_set_hook
.match_interface
== NULL
)
527 /* Add configuration. */
528 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
529 ifname
= yang_dnode_get_string(args
->dnode
, NULL
);
531 /* Set destroy information. */
532 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_interface
;
533 rhc
->rhc_rule
= "interface";
534 rhc
->rhc_event
= RMAP_EVENT_MATCH_DELETED
;
536 rv
= rmap_match_set_hook
.match_interface(rhc
->rhc_rmi
,
538 RMAP_EVENT_MATCH_ADDED
,
539 args
->errmsg
, args
->errmsg_len
);
540 if (rv
!= CMD_SUCCESS
) {
541 rhc
->rhc_mhook
= NULL
;
542 return NB_ERR_INCONSISTENCY
;
548 static int lib_route_map_entry_match_condition_interface_destroy(
549 struct nb_cb_destroy_args
*args
)
551 return lib_route_map_entry_match_destroy(args
);
555 * XPath: /frr-route-map:lib/route-map/entry/match-condition/list-name
557 static int lib_route_map_entry_match_condition_list_name_modify(
558 struct nb_cb_modify_args
*args
)
560 struct routemap_hook_context
*rhc
;
562 const char *condition
;
565 if (args
->event
!= NB_EV_APPLY
)
568 /* Check for hook installation, otherwise we can just stop. */
569 acl
= yang_dnode_get_string(args
->dnode
, NULL
);
570 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
571 condition
= yang_dnode_get_string(args
->dnode
, "../../condition");
573 if (IS_MATCH_IPv4_ADDRESS_LIST(condition
)) {
574 if (rmap_match_set_hook
.match_ip_address
== NULL
)
576 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_ip_address
;
577 rhc
->rhc_rule
= "ip address";
578 rhc
->rhc_event
= RMAP_EVENT_FILTER_DELETED
;
579 rv
= rmap_match_set_hook
.match_ip_address(
580 rhc
->rhc_rmi
, "ip address", acl
,
581 RMAP_EVENT_FILTER_ADDED
,
582 args
->errmsg
, args
->errmsg_len
);
583 } else if (IS_MATCH_IPv4_PREFIX_LIST(condition
)) {
584 if (rmap_match_set_hook
.match_ip_address_prefix_list
== NULL
)
587 rmap_match_set_hook
.no_match_ip_address_prefix_list
;
588 rhc
->rhc_rule
= "ip address prefix-list";
589 rhc
->rhc_event
= RMAP_EVENT_PLIST_DELETED
;
590 rv
= rmap_match_set_hook
.match_ip_address_prefix_list(
591 rhc
->rhc_rmi
, "ip address prefix-list", acl
,
592 RMAP_EVENT_PLIST_ADDED
,
593 args
->errmsg
, args
->errmsg_len
);
594 } else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition
)) {
595 if (rmap_match_set_hook
.match_ip_next_hop
== NULL
)
597 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_ip_next_hop
;
598 rhc
->rhc_rule
= "ip next-hop";
599 rhc
->rhc_event
= RMAP_EVENT_FILTER_DELETED
;
600 rv
= rmap_match_set_hook
.match_ip_next_hop(
601 rhc
->rhc_rmi
, "ip next-hop", acl
,
602 RMAP_EVENT_FILTER_ADDED
,
603 args
->errmsg
, args
->errmsg_len
);
604 } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition
)) {
605 if (rmap_match_set_hook
.match_ipv6_next_hop
== NULL
)
607 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_ipv6_next_hop
;
608 rhc
->rhc_rule
= "ipv6 next-hop";
609 rhc
->rhc_event
= RMAP_EVENT_FILTER_DELETED
;
610 rv
= rmap_match_set_hook
.match_ipv6_next_hop(
611 rhc
->rhc_rmi
, "ipv6 next-hop", acl
,
612 RMAP_EVENT_FILTER_ADDED
, args
->errmsg
,
614 } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition
)) {
615 if (rmap_match_set_hook
.match_ip_next_hop_prefix_list
== NULL
)
618 rmap_match_set_hook
.no_match_ip_next_hop_prefix_list
;
619 rhc
->rhc_rule
= "ip next-hop prefix-list";
620 rhc
->rhc_event
= RMAP_EVENT_PLIST_DELETED
;
621 rv
= rmap_match_set_hook
.match_ip_next_hop_prefix_list(
622 rhc
->rhc_rmi
, "ip next-hop prefix-list", acl
,
623 RMAP_EVENT_PLIST_ADDED
,
624 args
->errmsg
, args
->errmsg_len
);
625 } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition
)) {
626 if (rmap_match_set_hook
.match_ipv6_next_hop_prefix_list
== NULL
)
629 rmap_match_set_hook
.no_match_ipv6_next_hop_prefix_list
;
630 rhc
->rhc_rule
= "ipv6 next-hop prefix-list";
631 rhc
->rhc_event
= RMAP_EVENT_PLIST_DELETED
;
632 rv
= rmap_match_set_hook
.match_ipv6_next_hop_prefix_list(
633 rhc
->rhc_rmi
, "ipv6 next-hop prefix-list", acl
,
634 RMAP_EVENT_PLIST_ADDED
, args
->errmsg
, args
->errmsg_len
);
635 } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition
)) {
636 if (rmap_match_set_hook
.match_ipv6_address
== NULL
)
638 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_ipv6_address
;
639 rhc
->rhc_rule
= "ipv6 address";
640 rhc
->rhc_event
= RMAP_EVENT_FILTER_DELETED
;
641 rv
= rmap_match_set_hook
.match_ipv6_address(
642 rhc
->rhc_rmi
, "ipv6 address", acl
,
643 RMAP_EVENT_FILTER_ADDED
,
644 args
->errmsg
, args
->errmsg_len
);
645 } else if (IS_MATCH_IPv6_PREFIX_LIST(condition
)) {
646 if (rmap_match_set_hook
.match_ipv6_address_prefix_list
== NULL
)
649 rmap_match_set_hook
.no_match_ipv6_address_prefix_list
;
650 rhc
->rhc_rule
= "ipv6 address prefix-list";
651 rhc
->rhc_event
= RMAP_EVENT_PLIST_DELETED
;
652 rv
= rmap_match_set_hook
.match_ipv6_address_prefix_list(
653 rhc
->rhc_rmi
, "ipv6 address prefix-list", acl
,
654 RMAP_EVENT_PLIST_ADDED
,
655 args
->errmsg
, args
->errmsg_len
);
657 rv
= CMD_ERR_NO_MATCH
;
659 if (rv
!= CMD_SUCCESS
) {
660 rhc
->rhc_mhook
= NULL
;
661 return NB_ERR_INCONSISTENCY
;
667 static int lib_route_map_entry_match_condition_list_name_destroy(
668 struct nb_cb_destroy_args
*args
)
670 return lib_route_map_entry_match_destroy(args
);
674 * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv4-next-hop-type
676 static int lib_route_map_entry_match_condition_ipv4_next_hop_type_modify(
677 struct nb_cb_modify_args
*args
)
679 struct routemap_hook_context
*rhc
;
683 if (args
->event
!= NB_EV_APPLY
)
686 /* Check for hook function. */
687 if (rmap_match_set_hook
.match_ip_next_hop_type
== NULL
)
690 /* Add configuration. */
691 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
692 type
= yang_dnode_get_string(args
->dnode
, NULL
);
694 /* Set destroy information. */
695 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_ip_next_hop_type
;
696 rhc
->rhc_rule
= "ip next-hop type";
697 rhc
->rhc_event
= RMAP_EVENT_MATCH_DELETED
;
699 rv
= rmap_match_set_hook
.match_ip_next_hop_type(
700 rhc
->rhc_rmi
, "ip next-hop type", type
,
701 RMAP_EVENT_MATCH_ADDED
,
702 args
->errmsg
, args
->errmsg_len
);
703 if (rv
!= CMD_SUCCESS
) {
704 rhc
->rhc_mhook
= NULL
;
705 return NB_ERR_INCONSISTENCY
;
711 static int lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy(
712 struct nb_cb_destroy_args
*args
)
714 return lib_route_map_entry_match_destroy(args
);
718 * XPath: /frr-route-map:lib/route-map/entry/match-condition/ipv6-next-hop-type
720 static int lib_route_map_entry_match_condition_ipv6_next_hop_type_modify(
721 struct nb_cb_modify_args
*args
)
723 struct routemap_hook_context
*rhc
;
727 if (args
->event
!= NB_EV_APPLY
)
730 /* Check for hook function. */
731 if (rmap_match_set_hook
.match_ipv6_next_hop_type
== NULL
)
734 /* Add configuration. */
735 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
736 type
= yang_dnode_get_string(args
->dnode
, NULL
);
738 /* Set destroy information. */
739 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_ipv6_next_hop_type
;
740 rhc
->rhc_rule
= "ipv6 next-hop type";
741 rhc
->rhc_event
= RMAP_EVENT_MATCH_DELETED
;
743 rv
= rmap_match_set_hook
.match_ipv6_next_hop_type(
744 rhc
->rhc_rmi
, "ipv6 next-hop type", type
,
745 RMAP_EVENT_MATCH_ADDED
,
746 args
->errmsg
, args
->errmsg_len
);
747 if (rv
!= CMD_SUCCESS
) {
748 rhc
->rhc_mhook
= NULL
;
749 return NB_ERR_INCONSISTENCY
;
755 static int lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy(
756 struct nb_cb_destroy_args
*args
)
758 return lib_route_map_entry_match_destroy(args
);
762 * XPath: /frr-route-map:lib/route-map/entry/match-condition/metric
764 static int lib_route_map_entry_match_condition_metric_modify(
765 struct nb_cb_modify_args
*args
)
767 struct routemap_hook_context
*rhc
;
771 if (args
->event
!= NB_EV_APPLY
)
774 /* Check for hook function. */
775 if (rmap_match_set_hook
.match_metric
== NULL
)
778 /* Add configuration. */
779 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
780 type
= yang_dnode_get_string(args
->dnode
, NULL
);
782 /* Set destroy information. */
783 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_metric
;
784 rhc
->rhc_rule
= "metric";
785 rhc
->rhc_event
= RMAP_EVENT_MATCH_DELETED
;
787 rv
= rmap_match_set_hook
.match_metric(rhc
->rhc_rmi
, "metric",
788 type
, RMAP_EVENT_MATCH_ADDED
,
789 args
->errmsg
, args
->errmsg_len
);
790 if (rv
!= CMD_SUCCESS
) {
791 rhc
->rhc_mhook
= NULL
;
792 return NB_ERR_INCONSISTENCY
;
798 static int lib_route_map_entry_match_condition_metric_destroy(
799 struct nb_cb_destroy_args
*args
)
801 return lib_route_map_entry_match_destroy(args
);
805 * XPath: /frr-route-map:lib/route-map/entry/match-condition/tag
808 lib_route_map_entry_match_condition_tag_modify(struct nb_cb_modify_args
*args
)
810 struct routemap_hook_context
*rhc
;
814 if (args
->event
!= NB_EV_APPLY
)
817 /* Check for hook function. */
818 if (rmap_match_set_hook
.match_tag
== NULL
)
821 /* Add configuration. */
822 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
823 tag
= yang_dnode_get_string(args
->dnode
, NULL
);
825 /* Set destroy information. */
826 rhc
->rhc_mhook
= rmap_match_set_hook
.no_match_tag
;
827 rhc
->rhc_rule
= "tag";
828 rhc
->rhc_event
= RMAP_EVENT_MATCH_DELETED
;
830 rv
= rmap_match_set_hook
.match_tag(rhc
->rhc_rmi
, "tag", tag
,
831 RMAP_EVENT_MATCH_ADDED
,
832 args
->errmsg
, args
->errmsg_len
);
833 if (rv
!= CMD_SUCCESS
) {
834 rhc
->rhc_mhook
= NULL
;
835 return NB_ERR_INCONSISTENCY
;
842 lib_route_map_entry_match_condition_tag_destroy(struct nb_cb_destroy_args
*args
)
844 return lib_route_map_entry_match_destroy(args
);
848 * XPath: /frr-route-map:lib/route-map/entry/set-action
850 static int lib_route_map_entry_set_action_create(struct nb_cb_create_args
*args
)
852 return lib_route_map_entry_match_condition_create(args
);
856 lib_route_map_entry_set_action_destroy(struct nb_cb_destroy_args
*args
)
858 struct routemap_hook_context
*rhc
;
861 if (args
->event
!= NB_EV_APPLY
)
864 rv
= lib_route_map_entry_set_destroy(args
);
865 rhc
= nb_running_unset_entry(args
->dnode
);
866 routemap_hook_context_free(rhc
);
872 * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv4-address
874 static int lib_route_map_entry_set_action_ipv4_address_modify(
875 struct nb_cb_modify_args
*args
)
877 struct routemap_hook_context
*rhc
;
882 switch (args
->event
) {
885 * NOTE: validate if 'action' is 'ipv4-next-hop',
886 * currently it is not necessary because this is the
887 * only implemented action.
889 yang_dnode_get_ipv4(&ia
, args
->dnode
, NULL
);
890 if (ia
.s_addr
== INADDR_ANY
|| IPV4_CLASS_DE(ntohl(ia
.s_addr
)))
891 return NB_ERR_VALIDATION
;
900 /* Check for hook function. */
901 if (rmap_match_set_hook
.set_ip_nexthop
== NULL
)
904 /* Add configuration. */
905 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
906 address
= yang_dnode_get_string(args
->dnode
, NULL
);
908 /* Set destroy information. */
909 rhc
->rhc_shook
= rmap_match_set_hook
.no_set_ip_nexthop
;
910 rhc
->rhc_rule
= "ip next-hop";
912 rv
= rmap_match_set_hook
.set_ip_nexthop(rhc
->rhc_rmi
, "ip next-hop",
914 args
->errmsg
, args
->errmsg_len
);
915 if (rv
!= CMD_SUCCESS
) {
916 rhc
->rhc_shook
= NULL
;
917 return NB_ERR_INCONSISTENCY
;
923 static int lib_route_map_entry_set_action_ipv4_address_destroy(
924 struct nb_cb_destroy_args
*args
)
926 return lib_route_map_entry_set_destroy(args
);
930 * XPath: /frr-route-map:lib/route-map/entry/set-action/ipv6-address
932 static int lib_route_map_entry_set_action_ipv6_address_modify(
933 struct nb_cb_modify_args
*args
)
935 struct routemap_hook_context
*rhc
;
940 switch (args
->event
) {
943 * NOTE: validate if 'action' is 'ipv6-next-hop',
944 * currently it is not necessary because this is the
945 * only implemented action. Other actions might have
946 * different validations.
948 yang_dnode_get_ipv6(&i6a
, args
->dnode
, NULL
);
949 if (!IN6_IS_ADDR_LINKLOCAL(&i6a
))
950 return NB_ERR_VALIDATION
;
959 /* Check for hook function. */
960 if (rmap_match_set_hook
.set_ipv6_nexthop_local
== NULL
)
963 /* Add configuration. */
964 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
965 address
= yang_dnode_get_string(args
->dnode
, NULL
);
967 /* Set destroy information. */
968 rhc
->rhc_shook
= rmap_match_set_hook
.no_set_ipv6_nexthop_local
;
969 rhc
->rhc_rule
= "ipv6 next-hop local";
971 rv
= rmap_match_set_hook
.set_ipv6_nexthop_local(
972 rhc
->rhc_rmi
, "ipv6 next-hop local", address
,
973 args
->errmsg
, args
->errmsg_len
);
974 if (rv
!= CMD_SUCCESS
) {
975 rhc
->rhc_shook
= NULL
;
976 return NB_ERR_INCONSISTENCY
;
982 static int lib_route_map_entry_set_action_ipv6_address_destroy(
983 struct nb_cb_destroy_args
*args
)
985 return lib_route_map_entry_set_destroy(args
);
989 * XPath: /frr-route-map:lib/route-map/entry/set-action/value
991 static int set_action_modify(enum nb_event event
, const struct lyd_node
*dnode
,
992 union nb_resource
*resource
, const char *value
,
993 char *errmsg
, size_t errmsg_len
)
995 struct routemap_hook_context
*rhc
;
999 * NOTE: validate if 'action' is 'metric', currently it is not
1000 * necessary because this is the only implemented action. Other
1001 * actions might have different validations.
1003 if (event
!= NB_EV_APPLY
)
1006 /* Check for hook function. */
1007 if (rmap_match_set_hook
.set_metric
== NULL
)
1010 /* Add configuration. */
1011 rhc
= nb_running_get_entry(dnode
, NULL
, true);
1013 /* Set destroy information. */
1014 rhc
->rhc_shook
= rmap_match_set_hook
.no_set_metric
;
1015 rhc
->rhc_rule
= "metric";
1017 rv
= rmap_match_set_hook
.set_metric(rhc
->rhc_rmi
, "metric",
1021 if (rv
!= CMD_SUCCESS
) {
1022 rhc
->rhc_shook
= NULL
;
1023 return NB_ERR_INCONSISTENCY
;
1030 lib_route_map_entry_set_action_value_modify(struct nb_cb_modify_args
*args
)
1032 const char *metric
= yang_dnode_get_string(args
->dnode
, NULL
);
1034 return set_action_modify(args
->event
, args
->dnode
, args
->resource
,
1035 metric
, args
->errmsg
, args
->errmsg_len
);
1039 lib_route_map_entry_set_action_value_destroy(struct nb_cb_destroy_args
*args
)
1041 return lib_route_map_entry_set_destroy(args
);
1045 * XPath: /frr-route-map:lib/route-map/entry/set-action/add-metric
1048 lib_route_map_entry_set_action_add_metric_modify(struct nb_cb_modify_args
*args
)
1050 char metric_str
[16];
1052 if (args
->event
== NB_EV_VALIDATE
1053 && yang_dnode_get_uint32(args
->dnode
, NULL
) == 0) {
1054 snprintf(args
->errmsg
, args
->errmsg_len
,
1055 "Can't add zero to metric");
1056 return NB_ERR_VALIDATION
;
1059 snprintf(metric_str
, sizeof(metric_str
), "+%s",
1060 yang_dnode_get_string(args
->dnode
, NULL
));
1061 return set_action_modify(args
->event
, args
->dnode
, args
->resource
,
1063 args
->errmsg
, args
->errmsg_len
);
1066 static int lib_route_map_entry_set_action_add_metric_destroy(
1067 struct nb_cb_destroy_args
*args
)
1069 return lib_route_map_entry_set_action_value_destroy(args
);
1073 * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-metric
1075 static int lib_route_map_entry_set_action_subtract_metric_modify(
1076 struct nb_cb_modify_args
*args
)
1078 char metric_str
[16];
1080 if (args
->event
== NB_EV_VALIDATE
1081 && yang_dnode_get_uint32(args
->dnode
, NULL
) == 0) {
1082 snprintf(args
->errmsg
, args
->errmsg_len
,
1083 "Can't subtract zero from metric");
1084 return NB_ERR_VALIDATION
;
1087 snprintf(metric_str
, sizeof(metric_str
), "-%s",
1088 yang_dnode_get_string(args
->dnode
, NULL
));
1089 return set_action_modify(args
->event
, args
->dnode
, args
->resource
,
1091 args
->errmsg
, args
->errmsg_len
);
1094 static int lib_route_map_entry_set_action_subtract_metric_destroy(
1095 struct nb_cb_destroy_args
*args
)
1097 return lib_route_map_entry_set_action_value_destroy(args
);
1101 * XPath: /frr-route-map:lib/route-map/entry/set-action/use-round-trip-time
1103 static int lib_route_map_entry_set_action_use_round_trip_time_modify(
1104 struct nb_cb_modify_args
*args
)
1106 return set_action_modify(args
->event
, args
->dnode
, args
->resource
,
1108 args
->errmsg
, args
->errmsg_len
);
1111 static int lib_route_map_entry_set_action_use_round_trip_time_destroy(
1112 struct nb_cb_destroy_args
*args
)
1114 return lib_route_map_entry_set_action_value_destroy(args
);
1118 * XPath: /frr-route-map:lib/route-map/entry/set-action/add-round-trip-time
1120 static int lib_route_map_entry_set_action_add_round_trip_time_modify(
1121 struct nb_cb_modify_args
*args
)
1123 return set_action_modify(args
->event
, args
->dnode
, args
->resource
,
1125 args
->errmsg
, args
->errmsg_len
);
1128 static int lib_route_map_entry_set_action_add_round_trip_time_destroy(
1129 struct nb_cb_destroy_args
*args
)
1131 return lib_route_map_entry_set_action_value_destroy(args
);
1135 * XPath: /frr-route-map:lib/route-map/entry/set-action/subtract-round-trip-time
1137 static int lib_route_map_entry_set_action_subtract_round_trip_time_modify(
1138 struct nb_cb_modify_args
*args
)
1140 return set_action_modify(args
->event
, args
->dnode
, args
->resource
,
1141 "-rtt", args
->errmsg
, args
->errmsg_len
);
1144 static int lib_route_map_entry_set_action_subtract_round_trip_time_destroy(
1145 struct nb_cb_destroy_args
*args
)
1147 return lib_route_map_entry_set_action_value_destroy(args
);
1151 * XPath: /frr-route-map:lib/route-map/entry/set-action/tag
1154 lib_route_map_entry_set_action_tag_modify(struct nb_cb_modify_args
*args
)
1156 struct routemap_hook_context
*rhc
;
1161 * NOTE: validate if 'action' is 'tag', currently it is not
1162 * necessary because this is the only implemented action. Other
1163 * actions might have different validations.
1165 if (args
->event
!= NB_EV_APPLY
)
1168 /* Check for hook function. */
1169 if (rmap_match_set_hook
.set_tag
== NULL
)
1172 /* Add configuration. */
1173 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
1174 tag
= yang_dnode_get_string(args
->dnode
, NULL
);
1176 /* Set destroy information. */
1177 rhc
->rhc_shook
= rmap_match_set_hook
.no_set_tag
;
1178 rhc
->rhc_rule
= "tag";
1180 rv
= rmap_match_set_hook
.set_tag(rhc
->rhc_rmi
, "tag", tag
,
1181 args
->errmsg
, args
->errmsg_len
);
1182 if (rv
!= CMD_SUCCESS
) {
1183 rhc
->rhc_shook
= NULL
;
1184 return NB_ERR_INCONSISTENCY
;
1191 lib_route_map_entry_set_action_tag_destroy(struct nb_cb_destroy_args
*args
)
1193 return lib_route_map_entry_set_destroy(args
);
1197 * XPath: /frr-route-map:lib/route-map/entry/set-action/policy
1200 lib_route_map_entry_set_action_policy_modify(struct nb_cb_modify_args
*args
)
1202 struct routemap_hook_context
*rhc
;
1207 * NOTE: validate if 'action' is 'tag', currently it is not
1208 * necessary because this is the only implemented action. Other
1209 * actions might have different validations.
1211 if (args
->event
!= NB_EV_APPLY
)
1214 /* Check for hook function. */
1215 if (rmap_match_set_hook
.set_srte_color
== NULL
)
1218 /* Add configuration. */
1219 rhc
= nb_running_get_entry(args
->dnode
, NULL
, true);
1220 policy
= yang_dnode_get_string(args
->dnode
, NULL
);
1222 /* Set destroy information. */
1223 rhc
->rhc_shook
= rmap_match_set_hook
.no_set_tag
;
1224 rhc
->rhc_rule
= "sr-te color";
1226 rv
= rmap_match_set_hook
.set_tag(rhc
->rhc_rmi
, "sr-te color", policy
,
1227 args
->errmsg
, args
->errmsg_len
);
1228 if (rv
!= CMD_SUCCESS
) {
1229 rhc
->rhc_shook
= NULL
;
1230 return NB_ERR_INCONSISTENCY
;
1237 lib_route_map_entry_set_action_policy_destroy(struct nb_cb_destroy_args
*args
)
1239 return lib_route_map_entry_set_destroy(args
);
1242 /* clang-format off */
1243 const struct frr_yang_module_info frr_route_map_info
= {
1244 .name
= "frr-route-map",
1247 .xpath
= "/frr-route-map:lib/route-map",
1249 .create
= lib_route_map_create
,
1250 .destroy
= lib_route_map_destroy
,
1254 .xpath
= "/frr-route-map:lib/route-map/optimization-disabled",
1256 .modify
= lib_route_map_optimization_disabled_modify
,
1257 .cli_show
= route_map_optimization_disabled_show
,
1261 .xpath
= "/frr-route-map:lib/route-map/entry",
1263 .create
= lib_route_map_entry_create
,
1264 .destroy
= lib_route_map_entry_destroy
,
1265 .cli_cmp
= route_map_instance_cmp
,
1266 .cli_show
= route_map_instance_show
,
1267 .cli_show_end
= route_map_instance_show_end
,
1271 .xpath
= "/frr-route-map:lib/route-map/entry/description",
1273 .modify
= lib_route_map_entry_description_modify
,
1274 .destroy
= lib_route_map_entry_description_destroy
,
1275 .cli_show
= route_map_description_show
,
1279 .xpath
= "/frr-route-map:lib/route-map/entry/action",
1281 .modify
= lib_route_map_entry_action_modify
,
1285 .xpath
= "/frr-route-map:lib/route-map/entry/call",
1287 .modify
= lib_route_map_entry_call_modify
,
1288 .destroy
= lib_route_map_entry_call_destroy
,
1289 .cli_show
= route_map_call_show
,
1293 .xpath
= "/frr-route-map:lib/route-map/entry/exit-policy",
1295 .modify
= lib_route_map_entry_exit_policy_modify
,
1296 .cli_show
= route_map_exit_policy_show
,
1300 .xpath
= "/frr-route-map:lib/route-map/entry/goto-value",
1302 .modify
= lib_route_map_entry_goto_value_modify
,
1303 .destroy
= lib_route_map_entry_goto_value_destroy
,
1307 .xpath
= "/frr-route-map:lib/route-map/entry/match-condition",
1309 .create
= lib_route_map_entry_match_condition_create
,
1310 .destroy
= lib_route_map_entry_match_condition_destroy
,
1311 .cli_show
= route_map_condition_show
,
1315 .xpath
= "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/interface",
1317 .modify
= lib_route_map_entry_match_condition_interface_modify
,
1318 .destroy
= lib_route_map_entry_match_condition_interface_destroy
,
1322 .xpath
= "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/list-name",
1324 .modify
= lib_route_map_entry_match_condition_list_name_modify
,
1325 .destroy
= lib_route_map_entry_match_condition_list_name_destroy
,
1329 .xpath
= "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv4-next-hop-type",
1331 .modify
= lib_route_map_entry_match_condition_ipv4_next_hop_type_modify
,
1332 .destroy
= lib_route_map_entry_match_condition_ipv4_next_hop_type_destroy
,
1336 .xpath
= "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/ipv6-next-hop-type",
1338 .modify
= lib_route_map_entry_match_condition_ipv6_next_hop_type_modify
,
1339 .destroy
= lib_route_map_entry_match_condition_ipv6_next_hop_type_destroy
,
1343 .xpath
= "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/metric",
1345 .modify
= lib_route_map_entry_match_condition_metric_modify
,
1346 .destroy
= lib_route_map_entry_match_condition_metric_destroy
,
1350 .xpath
= "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/tag",
1352 .modify
= lib_route_map_entry_match_condition_tag_modify
,
1353 .destroy
= lib_route_map_entry_match_condition_tag_destroy
,
1357 .xpath
= "/frr-route-map:lib/route-map/entry/set-action",
1359 .create
= lib_route_map_entry_set_action_create
,
1360 .destroy
= lib_route_map_entry_set_action_destroy
,
1361 .cli_show
= route_map_action_show
,
1365 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv4-address",
1367 .modify
= lib_route_map_entry_set_action_ipv4_address_modify
,
1368 .destroy
= lib_route_map_entry_set_action_ipv4_address_destroy
,
1372 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/ipv6-address",
1374 .modify
= lib_route_map_entry_set_action_ipv6_address_modify
,
1375 .destroy
= lib_route_map_entry_set_action_ipv6_address_destroy
,
1379 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/value",
1381 .modify
= lib_route_map_entry_set_action_value_modify
,
1382 .destroy
= lib_route_map_entry_set_action_value_destroy
,
1386 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-metric",
1388 .modify
= lib_route_map_entry_set_action_add_metric_modify
,
1389 .destroy
= lib_route_map_entry_set_action_add_metric_destroy
,
1393 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-metric",
1395 .modify
= lib_route_map_entry_set_action_subtract_metric_modify
,
1396 .destroy
= lib_route_map_entry_set_action_subtract_metric_destroy
,
1400 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/use-round-trip-time",
1402 .modify
= lib_route_map_entry_set_action_use_round_trip_time_modify
,
1403 .destroy
= lib_route_map_entry_set_action_use_round_trip_time_destroy
,
1407 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/add-round-trip-time",
1409 .modify
= lib_route_map_entry_set_action_add_round_trip_time_modify
,
1410 .destroy
= lib_route_map_entry_set_action_add_round_trip_time_destroy
,
1414 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/subtract-round-trip-time",
1416 .modify
= lib_route_map_entry_set_action_subtract_round_trip_time_modify
,
1417 .destroy
= lib_route_map_entry_set_action_subtract_round_trip_time_destroy
,
1421 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/tag",
1423 .modify
= lib_route_map_entry_set_action_tag_modify
,
1424 .destroy
= lib_route_map_entry_set_action_tag_destroy
,
1428 .xpath
= "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/policy",
1430 .modify
= lib_route_map_entry_set_action_policy_modify
,
1431 .destroy
= lib_route_map_entry_set_action_policy_destroy
,