diff options
Diffstat (limited to 'pathd/path_nb_config.c')
-rw-r--r-- | pathd/path_nb_config.c | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/pathd/path_nb_config.c b/pathd/path_nb_config.c new file mode 100644 index 0000000..e1fbb37 --- /dev/null +++ b/pathd/path_nb_config.c @@ -0,0 +1,769 @@ +/* + * 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 <zebra.h> +#include <lib_errors.h> + +#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; +} |