/* * Copyright (C) 2020 NetDEF, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; see the file COPYING; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include "northbound.h" #include "libfrr.h" #include "pathd/path_zebra.h" #include "pathd/path_nb.h" /* * XPath: /frr-pathd:pathd */ void pathd_apply_finish(struct nb_cb_apply_finish_args *args) { srte_apply_changes(); } /* * XPath: /frr-pathd:pathd/srte/segment-list */ int pathd_srte_segment_list_create(struct nb_cb_create_args *args) { struct srte_segment_list *segment_list; const char *name; if (args->event != NB_EV_APPLY) return NB_OK; name = yang_dnode_get_string(args->dnode, "./name"); segment_list = srte_segment_list_add(name); nb_running_set_entry(args->dnode, segment_list); SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW); return NB_OK; } int pathd_srte_segment_list_destroy(struct nb_cb_destroy_args *args) { struct srte_segment_list *segment_list; if (args->event != NB_EV_APPLY) return NB_OK; segment_list = nb_running_unset_entry(args->dnode); SET_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/segment-list/protocol-origin */ int pathd_srte_segment_list_protocol_origin_modify( struct nb_cb_modify_args *args) { struct srte_segment_list *segment_list; if (args->event != NB_EV_APPLY) return NB_OK; segment_list = nb_running_get_entry(args->dnode, NULL, true); segment_list->protocol_origin = yang_dnode_get_enum(args->dnode, NULL); SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/segment-list/originator */ int pathd_srte_segment_list_originator_modify(struct nb_cb_modify_args *args) { struct srte_segment_list *segment_list; const char *originator; if (args->event != NB_EV_APPLY) return NB_OK; segment_list = nb_running_get_entry(args->dnode, NULL, true); originator = yang_dnode_get_string(args->dnode, NULL); strlcpy(segment_list->originator, originator, sizeof(segment_list->originator)); SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/segment-list/segment */ int pathd_srte_segment_list_segment_create(struct nb_cb_create_args *args) { struct srte_segment_list *segment_list; struct srte_segment_entry *segment; uint32_t index; if (args->event != NB_EV_APPLY) return NB_OK; segment_list = nb_running_get_entry(args->dnode, NULL, true); index = yang_dnode_get_uint32(args->dnode, "./index"); segment = srte_segment_entry_add(segment_list, index); nb_running_set_entry(args->dnode, segment); SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED); return NB_OK; } int pathd_srte_segment_list_segment_destroy(struct nb_cb_destroy_args *args) { struct srte_segment_entry *segment; if (args->event != NB_EV_APPLY) return NB_OK; segment = nb_running_unset_entry(args->dnode); SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED); srte_segment_entry_del(segment); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/segment-list/segment/sid-value */ int pathd_srte_segment_list_segment_sid_value_modify( struct nb_cb_modify_args *args) { mpls_label_t sid_value; struct srte_segment_entry *segment; if (args->event != NB_EV_APPLY) return NB_OK; segment = nb_running_get_entry(args->dnode, NULL, true); sid_value = yang_dnode_get_uint32(args->dnode, NULL); segment->sid_value = sid_value; SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED); return NB_OK; } int pathd_srte_segment_list_segment_sid_value_destroy( struct nb_cb_destroy_args *args) { struct srte_segment_entry *segment; if (args->event != NB_EV_APPLY) return NB_OK; segment = nb_running_get_entry(args->dnode, NULL, true); segment->sid_value = MPLS_LABEL_NONE; SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED); return NB_OK; } int pathd_srte_segment_list_segment_nai_destroy(struct nb_cb_destroy_args *args) { struct srte_segment_entry *segment; if (args->event != NB_EV_APPLY) return NB_OK; segment = nb_running_get_entry(args->dnode, NULL, true); segment->nai_type = SRTE_SEGMENT_NAI_TYPE_NONE; segment->nai_local_addr.ipa_type = IPADDR_NONE; segment->nai_local_iface = 0; segment->nai_remote_addr.ipa_type = IPADDR_NONE; segment->nai_remote_iface = 0; return NB_OK; } void pathd_srte_segment_list_segment_nai_apply_finish( struct nb_cb_apply_finish_args *args) { struct srte_segment_entry *segment; enum srte_segment_nai_type type; struct ipaddr local_addr, remote_addr; uint32_t local_iface = 0, remote_iface = 0; uint8_t algo = 0, local_prefix_len = 0; const char *algo_buf, *local_prefix_len_buf; segment = nb_running_get_entry(args->dnode, NULL, true); type = yang_dnode_get_enum(args->dnode, "./type"); yang_dnode_get_ip(&local_addr, args->dnode, "./local-address"); switch (type) { case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE: case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE: break; case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY: case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY: yang_dnode_get_ip(&remote_addr, args->dnode, "./remote-address"); break; case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY: yang_dnode_get_ip(&remote_addr, args->dnode, "./remote-address"); local_iface = yang_dnode_get_uint32(args->dnode, "./local-interface"); remote_iface = yang_dnode_get_uint32(args->dnode, "./remote-interface"); break; case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM: algo_buf = yang_dnode_get_string(args->dnode, "./algorithm"); algo = atoi(algo_buf); local_prefix_len_buf = yang_dnode_get_string( args->dnode, "./local-prefix-len"); local_prefix_len = atoi(local_prefix_len_buf); break; case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE: local_iface = yang_dnode_get_uint32(args->dnode, "./local-interface"); local_prefix_len_buf = yang_dnode_get_string( args->dnode, "./local-prefix-len"); local_prefix_len = atoi(local_prefix_len_buf); break; default: break; } zlog_debug(" Segment list name (%d) index (%s) ", segment->index, segment->segment_list->name); if (srte_segment_entry_set_nai(segment, type, &local_addr, local_iface, &remote_addr, remote_iface, algo, local_prefix_len)) SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_SID_CONFLICT); } /* * XPath: /frr-pathd:pathd/srte/policy */ int pathd_srte_policy_create(struct nb_cb_create_args *args) { struct srte_policy *policy; uint32_t color; struct ipaddr endpoint; if (args->event != NB_EV_APPLY) return NB_OK; color = yang_dnode_get_uint32(args->dnode, "./color"); yang_dnode_get_ip(&endpoint, args->dnode, "./endpoint"); policy = srte_policy_add(color, &endpoint, SRTE_ORIGIN_LOCAL, NULL); nb_running_set_entry(args->dnode, policy); SET_FLAG(policy->flags, F_POLICY_NEW); return NB_OK; } int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args) { struct srte_policy *policy; if (args->event != NB_EV_APPLY) return NB_OK; policy = nb_running_unset_entry(args->dnode); SET_FLAG(policy->flags, F_POLICY_DELETED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/name */ int pathd_srte_policy_name_modify(struct nb_cb_modify_args *args) { struct srte_policy *policy; const char *name; if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE) return NB_OK; policy = nb_running_get_entry(args->dnode, NULL, true); if (args->event == NB_EV_VALIDATE) { /* the policy name is fixed after setting it once */ if (strlen(policy->name) > 0) { flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, "The SR Policy name is fixed!"); return NB_ERR_RESOURCE; } else return NB_OK; } name = yang_dnode_get_string(args->dnode, NULL); strlcpy(policy->name, name, sizeof(policy->name)); SET_FLAG(policy->flags, F_POLICY_MODIFIED); return NB_OK; } int pathd_srte_policy_name_destroy(struct nb_cb_destroy_args *args) { struct srte_policy *policy; if (args->event != NB_EV_APPLY) return NB_OK; policy = nb_running_get_entry(args->dnode, NULL, true); policy->name[0] = '\0'; SET_FLAG(policy->flags, F_POLICY_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/binding-sid */ int pathd_srte_policy_binding_sid_modify(struct nb_cb_modify_args *args) { struct srte_policy *policy; mpls_label_t binding_sid; binding_sid = yang_dnode_get_uint32(args->dnode, NULL); switch (args->event) { case NB_EV_VALIDATE: break; case NB_EV_PREPARE: if (path_zebra_request_label(binding_sid) < 0) return NB_ERR_RESOURCE; break; case NB_EV_ABORT: break; case NB_EV_APPLY: policy = nb_running_get_entry(args->dnode, NULL, true); srte_policy_update_binding_sid(policy, binding_sid); SET_FLAG(policy->flags, F_POLICY_MODIFIED); break; } return NB_OK; } int pathd_srte_policy_binding_sid_destroy(struct nb_cb_destroy_args *args) { struct srte_policy *policy; if (args->event != NB_EV_APPLY) return NB_OK; policy = nb_running_get_entry(args->dnode, NULL, true); srte_policy_update_binding_sid(policy, MPLS_LABEL_NONE); SET_FLAG(policy->flags, F_POLICY_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path */ int pathd_srte_policy_candidate_path_create(struct nb_cb_create_args *args) { struct srte_policy *policy; struct srte_candidate *candidate; uint32_t preference; if (args->event != NB_EV_APPLY) return NB_OK; policy = nb_running_get_entry(args->dnode, NULL, true); preference = yang_dnode_get_uint32(args->dnode, "./preference"); candidate = srte_candidate_add(policy, preference, SRTE_ORIGIN_LOCAL, NULL); nb_running_set_entry(args->dnode, candidate); SET_FLAG(candidate->flags, F_CANDIDATE_NEW); return NB_OK; } int pathd_srte_policy_candidate_path_destroy(struct nb_cb_destroy_args *args) { struct srte_candidate *candidate; if (args->event != NB_EV_APPLY) return NB_OK; candidate = nb_running_unset_entry(args->dnode); SET_FLAG(candidate->flags, F_CANDIDATE_DELETED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path/name */ int pathd_srte_policy_candidate_path_name_modify(struct nb_cb_modify_args *args) { struct srte_candidate *candidate; const char *name; char xpath[XPATH_MAXLEN]; char xpath_buf[XPATH_MAXLEN - 3]; if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE) return NB_OK; /* the candidate name is fixed after setting it once, this is checked * here */ if (args->event == NB_EV_VALIDATE) { /* first get the precise path to the candidate path */ yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf)); snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/.."); candidate = nb_running_get_entry_non_rec(NULL, xpath, false); /* then check if it exists and if the name was provided */ if (candidate && strlen(candidate->name) > 0) { flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, "The candidate name is fixed!"); return NB_ERR_RESOURCE; } else return NB_OK; } candidate = nb_running_get_entry(args->dnode, NULL, true); name = yang_dnode_get_string(args->dnode, NULL); strlcpy(candidate->name, name, sizeof(candidate->name)); SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); return NB_OK; } static int affinity_filter_modify(struct nb_cb_modify_args *args, enum affinity_filter_type type) { uint32_t filter; struct srte_candidate *candidate; if (args->event != NB_EV_APPLY) return NB_OK; assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); filter = yang_dnode_get_uint32(args->dnode, NULL); srte_candidate_set_affinity_filter(candidate, type, filter); return NB_OK; } static int affinity_filter_destroy(struct nb_cb_destroy_args *args, enum affinity_filter_type type) { struct srte_candidate *candidate; if (args->event != NB_EV_APPLY) return NB_OK; assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); srte_candidate_unset_affinity_filter(candidate, type); return NB_OK; } /* * XPath: * /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/exclude-any */ int pathd_srte_policy_candidate_path_exclude_any_modify( struct nb_cb_modify_args *args) { return affinity_filter_modify(args, AFFINITY_FILTER_EXCLUDE_ANY); } int pathd_srte_policy_candidate_path_exclude_any_destroy( struct nb_cb_destroy_args *args) { return affinity_filter_destroy(args, AFFINITY_FILTER_EXCLUDE_ANY); } /* * XPath: * /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-any */ int pathd_srte_policy_candidate_path_include_any_modify( struct nb_cb_modify_args *args) { return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ANY); } int pathd_srte_policy_candidate_path_include_any_destroy( struct nb_cb_destroy_args *args) { return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ANY); } /* * XPath: * /frr-pathd:pathd/srte/policy/candidate-path/constraints/affinity/include-all */ int pathd_srte_policy_candidate_path_include_all_modify( struct nb_cb_modify_args *args) { return affinity_filter_modify(args, AFFINITY_FILTER_INCLUDE_ALL); } int pathd_srte_policy_candidate_path_include_all_destroy( struct nb_cb_destroy_args *args) { return affinity_filter_destroy(args, AFFINITY_FILTER_INCLUDE_ALL); } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/metrics */ int pathd_srte_policy_candidate_path_metrics_destroy( struct nb_cb_destroy_args *args) { struct srte_candidate *candidate; enum srte_candidate_metric_type type; if (args->event != NB_EV_APPLY) return NB_OK; assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); type = yang_dnode_get_enum(args->dnode, "./type"); srte_candidate_unset_metric(candidate, type); return NB_OK; } void pathd_srte_policy_candidate_path_metrics_apply_finish( struct nb_cb_apply_finish_args *args) { struct srte_candidate *candidate; enum srte_candidate_metric_type type; float value; bool required, is_bound = false, is_computed = false; assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); type = yang_dnode_get_enum(args->dnode, "./type"); value = (float)yang_dnode_get_dec64(args->dnode, "./value"); required = yang_dnode_get_bool(args->dnode, "./required"); if (yang_dnode_exists(args->dnode, "./is-bound")) is_bound = yang_dnode_get_bool(args->dnode, "./is-bound"); if (yang_dnode_exists(args->dnode, "./is-computed")) is_computed = yang_dnode_get_bool(args->dnode, "./is-computed"); srte_candidate_set_metric(candidate, type, value, required, is_bound, is_computed); } /* * XPath: * /frr-pathd:pathd/srte/policy/candidate-path/constraints/objective-function */ int pathd_srte_policy_candidate_path_objfun_destroy( struct nb_cb_destroy_args *args) { struct srte_candidate *candidate; if (args->event != NB_EV_APPLY) return NB_OK; assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); srte_candidate_unset_objfun(candidate); return NB_OK; } void pathd_srte_policy_candidate_path_objfun_apply_finish( struct nb_cb_apply_finish_args *args) { struct srte_candidate *candidate; enum objfun_type type; bool required; candidate = nb_running_get_entry(args->dnode, NULL, true); required = yang_dnode_get_bool(args->dnode, "./required"); type = yang_dnode_get_enum(args->dnode, "./type"); srte_candidate_set_objfun(candidate, required, type); } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path/protocol-origin */ int pathd_srte_policy_candidate_path_protocol_origin_modify( struct nb_cb_modify_args *args) { struct srte_candidate *candidate; enum srte_protocol_origin protocol_origin; if (args->event != NB_EV_APPLY) return NB_OK; candidate = nb_running_get_entry(args->dnode, NULL, true); protocol_origin = yang_dnode_get_enum(args->dnode, NULL); candidate->protocol_origin = protocol_origin; candidate->lsp->protocol_origin = protocol_origin; SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path/originator */ int pathd_srte_policy_candidate_path_originator_modify( struct nb_cb_modify_args *args) { struct srte_candidate *candidate; const char *originator; if (args->event != NB_EV_APPLY) return NB_OK; candidate = nb_running_get_entry(args->dnode, NULL, true); originator = yang_dnode_get_string(args->dnode, NULL); strlcpy(candidate->originator, originator, sizeof(candidate->originator)); strlcpy(candidate->lsp->originator, originator, sizeof(candidate->lsp->originator)); SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path/type */ int pathd_srte_policy_candidate_path_type_modify(struct nb_cb_modify_args *args) { struct srte_candidate *candidate; enum srte_candidate_type type; char xpath[XPATH_MAXLEN]; char xpath_buf[XPATH_MAXLEN - 3]; if (args->event != NB_EV_APPLY && args->event != NB_EV_VALIDATE) return NB_OK; /* the candidate type is fixed after setting it once, this is checked * here */ if (args->event == NB_EV_VALIDATE) { /* first get the precise path to the candidate path */ yang_dnode_get_path(args->dnode, xpath_buf, sizeof(xpath_buf)); snprintf(xpath, sizeof(xpath), "%s%s", xpath_buf, "/.."); candidate = nb_running_get_entry_non_rec(NULL, xpath, false); /* then check if it exists and if the type was provided */ if (candidate && candidate->type != SRTE_CANDIDATE_TYPE_UNDEFINED) { flog_warn(EC_LIB_NB_CB_CONFIG_VALIDATE, "The candidate type is fixed!"); return NB_ERR_RESOURCE; } else return NB_OK; } candidate = nb_running_get_entry(args->dnode, NULL, true); type = yang_dnode_get_enum(args->dnode, NULL); candidate->type = type; SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path/segment-list-name */ int pathd_srte_policy_candidate_path_segment_list_name_modify( struct nb_cb_modify_args *args) { struct srte_candidate *candidate; const char *segment_list_name; if (args->event != NB_EV_APPLY) return NB_OK; candidate = nb_running_get_entry(args->dnode, NULL, true); segment_list_name = yang_dnode_get_string(args->dnode, NULL); candidate->segment_list = srte_segment_list_find(segment_list_name); candidate->lsp->segment_list = candidate->segment_list; assert(candidate->segment_list); SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); return NB_OK; } int pathd_srte_policy_candidate_path_segment_list_name_destroy( struct nb_cb_destroy_args *args) { struct srte_candidate *candidate; if (args->event != NB_EV_APPLY) return NB_OK; candidate = nb_running_get_entry(args->dnode, NULL, true); candidate->segment_list = NULL; candidate->lsp->segment_list = NULL; SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED); return NB_OK; } /* * XPath: /frr-pathd:pathd/srte/policy/candidate-path/constraints/bandwidth */ void pathd_srte_policy_candidate_path_bandwidth_apply_finish( struct nb_cb_apply_finish_args *args) { struct srte_candidate *candidate; float value; bool required; assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); value = (float)yang_dnode_get_dec64(args->dnode, "./value"); required = yang_dnode_get_bool(args->dnode, "./required"); srte_candidate_set_bandwidth(candidate, value, required); } int pathd_srte_policy_candidate_path_bandwidth_destroy( struct nb_cb_destroy_args *args) { struct srte_candidate *candidate; if (args->event != NB_EV_APPLY) return NB_OK; assert(args->context != NULL); candidate = nb_running_get_entry(args->dnode, NULL, true); srte_candidate_unset_bandwidth(candidate); return NB_OK; }