mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 23:29:26 +00:00 
			
		
		
		
	 6f4196d72b
			
		
	
	
		6f4196d72b
		
	
	
	
	
		
			
			rand() should not be used, we should be using the frr_weak_random() call instead. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
		
			
				
	
	
		
			1129 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1129 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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 "memory.h"
 | |
| #include "log.h"
 | |
| #include "lib_errors.h"
 | |
| #include "network.h"
 | |
| 
 | |
| #include "pathd/pathd.h"
 | |
| #include "pathd/path_memory.h"
 | |
| #include "pathd/path_zebra.h"
 | |
| #include "pathd/path_debug.h"
 | |
| 
 | |
| #define HOOK_DELAY 3
 | |
| 
 | |
| DEFINE_MTYPE_STATIC(PATHD, PATH_SEGMENT_LIST, "Segment List")
 | |
| DEFINE_MTYPE_STATIC(PATHD, PATH_SR_POLICY, "SR Policy")
 | |
| DEFINE_MTYPE_STATIC(PATHD, PATH_SR_CANDIDATE, "SR Policy candidate path")
 | |
| 
 | |
| DEFINE_HOOK(pathd_candidate_created, (struct srte_candidate * candidate),
 | |
| 	    (candidate))
 | |
| DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
 | |
| 	    (candidate))
 | |
| DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
 | |
| 	    (candidate))
 | |
| 
 | |
| static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
 | |
| static int trigger_pathd_candidate_created_timer(struct thread *thread);
 | |
| static void trigger_pathd_candidate_updated(struct srte_candidate *candidate);
 | |
| static int trigger_pathd_candidate_updated_timer(struct thread *thread);
 | |
| static void trigger_pathd_candidate_removed(struct srte_candidate *candidate);
 | |
| static const char *
 | |
| srte_candidate_metric_name(enum srte_candidate_metric_type type);
 | |
| 
 | |
| static void srte_set_metric(struct srte_metric *metric, float value,
 | |
| 			    bool required, bool is_bound, bool is_computed);
 | |
| static void srte_unset_metric(struct srte_metric *metric);
 | |
| 
 | |
| 
 | |
| /* Generate rb-tree of Segment List Segment instances. */
 | |
| static inline int srte_segment_entry_compare(const struct srte_segment_entry *a,
 | |
| 					     const struct srte_segment_entry *b)
 | |
| {
 | |
| 	return a->index - b->index;
 | |
| }
 | |
| RB_GENERATE(srte_segment_entry_head, srte_segment_entry, entry,
 | |
| 	    srte_segment_entry_compare)
 | |
| 
 | |
| /* Generate rb-tree of Segment List instances. */
 | |
| static inline int srte_segment_list_compare(const struct srte_segment_list *a,
 | |
| 					    const struct srte_segment_list *b)
 | |
| {
 | |
| 	return strcmp(a->name, b->name);
 | |
| }
 | |
| RB_GENERATE(srte_segment_list_head, srte_segment_list, entry,
 | |
| 	    srte_segment_list_compare)
 | |
| 
 | |
| struct srte_segment_list_head srte_segment_lists =
 | |
| 	RB_INITIALIZER(&srte_segment_lists);
 | |
| 
 | |
| /* Generate rb-tree of Candidate Path instances. */
 | |
| static inline int srte_candidate_compare(const struct srte_candidate *a,
 | |
| 					 const struct srte_candidate *b)
 | |
| {
 | |
| 	return a->preference - b->preference;
 | |
| }
 | |
| RB_GENERATE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
 | |
| 
 | |
| /* Generate rb-tree of SR Policy instances. */
 | |
| static inline int srte_policy_compare(const struct srte_policy *a,
 | |
| 				      const struct srte_policy *b)
 | |
| {
 | |
| 	return sr_policy_compare(&a->endpoint, &b->endpoint, a->color,
 | |
| 				 b->color);
 | |
| }
 | |
| RB_GENERATE(srte_policy_head, srte_policy, entry, srte_policy_compare)
 | |
| 
 | |
| struct srte_policy_head srte_policies = RB_INITIALIZER(&srte_policies);
 | |
| 
 | |
| /**
 | |
|  * Adds a segment list to pathd.
 | |
|  *
 | |
|  * @param name The name of the segment list to add
 | |
|  * @return The added segment list
 | |
|  */
 | |
| struct srte_segment_list *srte_segment_list_add(const char *name)
 | |
| {
 | |
| 	struct srte_segment_list *segment_list;
 | |
| 
 | |
| 	segment_list = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment_list));
 | |
| 	strlcpy(segment_list->name, name, sizeof(segment_list->name));
 | |
| 	RB_INIT(srte_segment_entry_head, &segment_list->segments);
 | |
| 	RB_INSERT(srte_segment_list_head, &srte_segment_lists, segment_list);
 | |
| 
 | |
| 	return segment_list;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Deletes a segment list from pathd.
 | |
|  *
 | |
|  * The given segment list structure will be freed and should not be used anymore
 | |
|  * after calling this function.
 | |
|  *
 | |
|  * @param segment_list the segment list to remove from pathd.
 | |
|  */
 | |
| void srte_segment_list_del(struct srte_segment_list *segment_list)
 | |
| {
 | |
| 	struct srte_segment_entry *segment, *safe_seg;
 | |
| 	RB_FOREACH_SAFE (segment, srte_segment_entry_head,
 | |
| 			 &segment_list->segments, safe_seg) {
 | |
| 		srte_segment_entry_del(segment);
 | |
| 	}
 | |
| 	RB_REMOVE(srte_segment_list_head, &srte_segment_lists, segment_list);
 | |
| 	XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Search for a segment list by name.
 | |
|  *
 | |
|  * @param name The name of the segment list to look for
 | |
|  * @return The segment list if found, NULL otherwise
 | |
|  */
 | |
| struct srte_segment_list *srte_segment_list_find(const char *name)
 | |
| {
 | |
| 	struct srte_segment_list search;
 | |
| 
 | |
| 	strlcpy(search.name, name, sizeof(search.name));
 | |
| 	return RB_FIND(srte_segment_list_head, &srte_segment_lists, &search);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Adds a segment to a segment list.
 | |
|  *
 | |
|  * @param segment_list The segment list the segment should be added to
 | |
|  * @param index	The index of the added segment in the segment list
 | |
|  * @return The added segment
 | |
|  */
 | |
| struct srte_segment_entry *
 | |
| srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index)
 | |
| {
 | |
| 	struct srte_segment_entry *segment;
 | |
| 
 | |
| 	segment = XCALLOC(MTYPE_PATH_SEGMENT_LIST, sizeof(*segment));
 | |
| 	segment->segment_list = segment_list;
 | |
| 	segment->index = index;
 | |
| 	RB_INSERT(srte_segment_entry_head, &segment_list->segments, segment);
 | |
| 
 | |
| 	return segment;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Deletes a segment from a segment list.
 | |
|  *
 | |
|  * @param segment The segment to be removed
 | |
|  */
 | |
| void srte_segment_entry_del(struct srte_segment_entry *segment)
 | |
| {
 | |
| 	RB_REMOVE(srte_segment_entry_head, &segment->segment_list->segments,
 | |
| 		  segment);
 | |
| 	XFREE(MTYPE_PATH_SEGMENT_LIST, segment);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Set the node or adjacency identifier of a segment.
 | |
|  *
 | |
|  * @param segment The segment for which the NAI should be set
 | |
|  * @param type The type of the NAI
 | |
|  * @param type The address of the node or the local address of the adjacency
 | |
|  * @param type The local interface index of the unumbered adjacency
 | |
|  * @param type The remote address of the adjacency
 | |
|  * @param type The remote interface index of the unumbered adjacency
 | |
|  */
 | |
| void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
 | |
| 				enum srte_segment_nai_type type,
 | |
| 				struct ipaddr *local_ip, uint32_t local_iface,
 | |
| 				struct ipaddr *remote_ip, uint32_t remote_iface)
 | |
| {
 | |
| 	segment->nai_type = type;
 | |
| 	memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr));
 | |
| 
 | |
| 	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:
 | |
| 		memcpy(&segment->nai_remote_addr, remote_ip,
 | |
| 		       sizeof(struct ipaddr));
 | |
| 		break;
 | |
| 	case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
 | |
| 		memcpy(&segment->nai_remote_addr, remote_ip,
 | |
| 		       sizeof(struct ipaddr));
 | |
| 		segment->nai_local_iface = local_iface;
 | |
| 		segment->nai_remote_iface = remote_iface;
 | |
| 		break;
 | |
| 	default:
 | |
| 		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;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Add a policy to pathd.
 | |
|  *
 | |
|  * WARNING: The color 0 is a special case as it is the no-color.
 | |
|  *
 | |
|  * @param color The color of the policy.
 | |
|  * @param endpoint The IP address of the policy endpoint
 | |
|  * @return The created policy
 | |
|  */
 | |
| struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint)
 | |
| {
 | |
| 	struct srte_policy *policy;
 | |
| 
 | |
| 	policy = XCALLOC(MTYPE_PATH_SR_POLICY, sizeof(*policy));
 | |
| 	policy->color = color;
 | |
| 	policy->endpoint = *endpoint;
 | |
| 	policy->binding_sid = MPLS_LABEL_NONE;
 | |
| 	RB_INIT(srte_candidate_head, &policy->candidate_paths);
 | |
| 	RB_INSERT(srte_policy_head, &srte_policies, policy);
 | |
| 
 | |
| 	return policy;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Delete a policy from pathd.
 | |
|  *
 | |
|  * The given policy structure will be freed and should never be used again
 | |
|  * after calling this function.
 | |
|  *
 | |
|  * @param policy The policy to be removed
 | |
|  */
 | |
| void srte_policy_del(struct srte_policy *policy)
 | |
| {
 | |
| 	struct srte_candidate *candidate;
 | |
| 
 | |
| 	path_zebra_delete_sr_policy(policy);
 | |
| 
 | |
| 	path_zebra_release_label(policy->binding_sid);
 | |
| 
 | |
| 	while (!RB_EMPTY(srte_candidate_head, &policy->candidate_paths)) {
 | |
| 		candidate =
 | |
| 			RB_ROOT(srte_candidate_head, &policy->candidate_paths);
 | |
| 		trigger_pathd_candidate_removed(candidate);
 | |
| 		srte_candidate_del(candidate);
 | |
| 	}
 | |
| 
 | |
| 	RB_REMOVE(srte_policy_head, &srte_policies, policy);
 | |
| 	XFREE(MTYPE_PATH_SR_POLICY, policy);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Search for a policy by color and endpoint.
 | |
|  *
 | |
|  * WARNING: The color 0 is a special case as it is the no-color.
 | |
|  *
 | |
|  * @param color The color of the policy to look for
 | |
|  * @param endpoint The endpoint of the policy to look for
 | |
|  * @return The policy if found, NULL otherwise
 | |
|  */
 | |
| struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint)
 | |
| {
 | |
| 	struct srte_policy search;
 | |
| 
 | |
| 	search.color = color;
 | |
| 	search.endpoint = *endpoint;
 | |
| 	return RB_FIND(srte_policy_head, &srte_policies, &search);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Update a policy binding SID.
 | |
|  *
 | |
|  * @param policy The policy for which the SID should be updated
 | |
|  * @param binding_sid The new binding SID for the given policy
 | |
|  */
 | |
| void srte_policy_update_binding_sid(struct srte_policy *policy,
 | |
| 				    uint32_t binding_sid)
 | |
| {
 | |
| 	if (policy->binding_sid != MPLS_LABEL_NONE)
 | |
| 		path_zebra_release_label(policy->binding_sid);
 | |
| 
 | |
| 	policy->binding_sid = binding_sid;
 | |
| 
 | |
| 	/* Reinstall the Binding-SID if necessary. */
 | |
| 	if (policy->best_candidate)
 | |
| 		path_zebra_add_sr_policy(
 | |
| 			policy, policy->best_candidate->lsp->segment_list);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gives the policy best candidate path.
 | |
|  *
 | |
|  * @param policy The policy we want the best candidate path from
 | |
|  * @return The best candidate path
 | |
|  */
 | |
| static struct srte_candidate *
 | |
| srte_policy_best_candidate(const struct srte_policy *policy)
 | |
| {
 | |
| 	struct srte_candidate *candidate;
 | |
| 
 | |
| 	RB_FOREACH_REVERSE (candidate, srte_candidate_head,
 | |
| 			    &policy->candidate_paths) {
 | |
| 		/* search for highest preference with existing segment list */
 | |
| 		if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)
 | |
| 		    && candidate->lsp->segment_list)
 | |
| 			return candidate;
 | |
| 	}
 | |
| 
 | |
| 	return NULL;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Apply changes defined by setting the policies, candidate paths
 | |
|  * and segment lists modification flags NEW, MODIFIED and DELETED.
 | |
|  *
 | |
|  * This allows the northbound code to delay all the side effects of adding
 | |
|  * modifying and deleting them to the end.
 | |
|  *
 | |
|  * Example of marking an object as modified:
 | |
|  *   `SET_FLAG(obj->flags, F_XXX_MODIFIED)`
 | |
|  */
 | |
| void srte_apply_changes(void)
 | |
| {
 | |
| 	struct srte_policy *policy, *safe_pol;
 | |
| 	struct srte_segment_list *segment_list, *safe_sl;
 | |
| 
 | |
| 	RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
 | |
| 		if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
 | |
| 			srte_policy_del(policy);
 | |
| 			continue;
 | |
| 		}
 | |
| 		srte_policy_apply_changes(policy);
 | |
| 		UNSET_FLAG(policy->flags, F_POLICY_NEW);
 | |
| 		UNSET_FLAG(policy->flags, F_POLICY_MODIFIED);
 | |
| 	}
 | |
| 
 | |
| 	RB_FOREACH_SAFE (segment_list, srte_segment_list_head,
 | |
| 			 &srte_segment_lists, safe_sl) {
 | |
| 		if (CHECK_FLAG(segment_list->flags, F_SEGMENT_LIST_DELETED)) {
 | |
| 			srte_segment_list_del(segment_list);
 | |
| 			continue;
 | |
| 		}
 | |
| 		UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
 | |
| 		UNSET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Apply changes defined by setting the given policy and its candidate paths
 | |
|  * modification flags NEW, MODIFIED and DELETED.
 | |
|  *
 | |
|  * In moste cases `void srte_apply_changes(void)` should be used instead,
 | |
|  * this function will not handle the changes of segment lists used by the
 | |
|  * policy.
 | |
|  *
 | |
|  * @param policy The policy changes has to be applied to.
 | |
|  */
 | |
| void srte_policy_apply_changes(struct srte_policy *policy)
 | |
| {
 | |
| 	struct srte_candidate *candidate, *safe;
 | |
| 	struct srte_candidate *old_best_candidate;
 | |
| 	struct srte_candidate *new_best_candidate;
 | |
| 	char endpoint[46];
 | |
| 
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 
 | |
| 	/* Get old and new best candidate path. */
 | |
| 	old_best_candidate = policy->best_candidate;
 | |
| 	new_best_candidate = srte_policy_best_candidate(policy);
 | |
| 
 | |
| 	if (new_best_candidate != old_best_candidate) {
 | |
| 		/* TODO: add debug guard. */
 | |
| 		zlog_debug(
 | |
| 			"SR-TE(%s, %u): best candidate changed from %s to %s",
 | |
| 			endpoint, policy->color,
 | |
| 			old_best_candidate ? old_best_candidate->name : "none",
 | |
| 			new_best_candidate ? new_best_candidate->name : "none");
 | |
| 
 | |
| 		if (old_best_candidate) {
 | |
| 			policy->best_candidate = NULL;
 | |
| 			UNSET_FLAG(old_best_candidate->flags, F_CANDIDATE_BEST);
 | |
| 			SET_FLAG(old_best_candidate->flags,
 | |
| 				 F_CANDIDATE_MODIFIED);
 | |
| 
 | |
| 			/*
 | |
| 			 * Rely on replace semantics if there's a new best
 | |
| 			 * candidate.
 | |
| 			 */
 | |
| 			if (!new_best_candidate)
 | |
| 				path_zebra_delete_sr_policy(policy);
 | |
| 		}
 | |
| 		if (new_best_candidate) {
 | |
| 			policy->best_candidate = new_best_candidate;
 | |
| 			SET_FLAG(new_best_candidate->flags, F_CANDIDATE_BEST);
 | |
| 			SET_FLAG(new_best_candidate->flags,
 | |
| 				 F_CANDIDATE_MODIFIED);
 | |
| 
 | |
| 			path_zebra_add_sr_policy(
 | |
| 				policy, new_best_candidate->lsp->segment_list);
 | |
| 		}
 | |
| 	} else if (new_best_candidate) {
 | |
| 		/* The best candidate path did not change, but some of its
 | |
| 		 * attributes or its segment list may have changed.
 | |
| 		 */
 | |
| 
 | |
| 		bool candidate_changed = CHECK_FLAG(new_best_candidate->flags,
 | |
| 						    F_CANDIDATE_MODIFIED);
 | |
| 		bool segment_list_changed =
 | |
| 			new_best_candidate->lsp->segment_list
 | |
| 			&& CHECK_FLAG(
 | |
| 				   new_best_candidate->lsp->segment_list->flags,
 | |
| 				   F_SEGMENT_LIST_MODIFIED);
 | |
| 
 | |
| 		if (candidate_changed || segment_list_changed) {
 | |
| 			/* TODO: add debug guard. */
 | |
| 			zlog_debug("SR-TE(%s, %u): best candidate %s changed",
 | |
| 				   endpoint, policy->color,
 | |
| 				   new_best_candidate->name);
 | |
| 
 | |
| 			path_zebra_add_sr_policy(
 | |
| 				policy, new_best_candidate->lsp->segment_list);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	RB_FOREACH_SAFE (candidate, srte_candidate_head,
 | |
| 			 &policy->candidate_paths, safe) {
 | |
| 		if (CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)) {
 | |
| 			trigger_pathd_candidate_removed(candidate);
 | |
| 			srte_candidate_del(candidate);
 | |
| 			continue;
 | |
| 		} else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_NEW)) {
 | |
| 			trigger_pathd_candidate_created(candidate);
 | |
| 		} else if (CHECK_FLAG(candidate->flags, F_CANDIDATE_MODIFIED)) {
 | |
| 			trigger_pathd_candidate_updated(candidate);
 | |
| 		} else if (candidate->lsp->segment_list
 | |
| 			   && CHECK_FLAG(candidate->lsp->segment_list->flags,
 | |
| 					 F_SEGMENT_LIST_MODIFIED)) {
 | |
| 			trigger_pathd_candidate_updated(candidate);
 | |
| 		}
 | |
| 
 | |
| 		UNSET_FLAG(candidate->flags, F_CANDIDATE_NEW);
 | |
| 		UNSET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Adds a candidate path to a policy.
 | |
|  *
 | |
|  * @param policy The policy the candidate path should be added to
 | |
|  * @param preference The preference of the candidate path to be added
 | |
|  * @return The added candidate path
 | |
|  */
 | |
| struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
 | |
| 					  uint32_t preference)
 | |
| {
 | |
| 	struct srte_candidate *candidate;
 | |
| 	struct srte_lsp *lsp;
 | |
| 
 | |
| 	candidate = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*candidate));
 | |
| 	lsp = XCALLOC(MTYPE_PATH_SR_CANDIDATE, sizeof(*lsp));
 | |
| 
 | |
| 	candidate->preference = preference;
 | |
| 	candidate->policy = policy;
 | |
| 	candidate->type = SRTE_CANDIDATE_TYPE_UNDEFINED;
 | |
| 	candidate->discriminator = frr_weak_random();
 | |
| 
 | |
| 	lsp->candidate = candidate;
 | |
| 	candidate->lsp = lsp;
 | |
| 
 | |
| 	RB_INSERT(srte_candidate_head, &policy->candidate_paths, candidate);
 | |
| 
 | |
| 	return candidate;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Deletes a candidate.
 | |
|  *
 | |
|  * The corresponding LSP will be removed alongside the candidate path.
 | |
|  * The given candidate will be freed and shouldn't be used anymore after the
 | |
|  * calling this function.
 | |
|  *
 | |
|  * @param candidate The candidate path to delete
 | |
|  */
 | |
| void srte_candidate_del(struct srte_candidate *candidate)
 | |
| {
 | |
| 	struct srte_policy *srte_policy = candidate->policy;
 | |
| 
 | |
| 	RB_REMOVE(srte_candidate_head, &srte_policy->candidate_paths,
 | |
| 		  candidate);
 | |
| 
 | |
| 	XFREE(MTYPE_PATH_SR_CANDIDATE, candidate->lsp);
 | |
| 	XFREE(MTYPE_PATH_SR_CANDIDATE, candidate);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets the bandwidth constraint of given candidate path.
 | |
|  *
 | |
|  * The corresponding LSP will be changed too.
 | |
|  *
 | |
|  * @param candidate The candidate path of which the bandwidth should be changed
 | |
|  * @param bandwidth The Bandwidth constraint to set to the candidate path
 | |
|  * @param required If the constraint is required (true) or only desired (false)
 | |
|  */
 | |
| void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
 | |
| 				  float bandwidth, bool required)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug(
 | |
| 		"SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
 | |
| 		endpoint, policy->color, candidate->name,
 | |
| 		required ? "required " : "", bandwidth);
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
 | |
| 	COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
 | |
| 	candidate->bandwidth = bandwidth;
 | |
| 
 | |
| 	srte_lsp_set_bandwidth(candidate->lsp, bandwidth, required);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets the bandwidth constraint of the given LSP.
 | |
|  *
 | |
|  * The changes will not be shown as part of the running configuration.
 | |
|  *
 | |
|  * @param lsp The lsp of which the bandwidth should be changed
 | |
|  * @param bandwidth The Bandwidth constraint to set to the candidate path
 | |
|  * @param required If the constraint is required (true) or only desired (false)
 | |
|  */
 | |
| void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
 | |
| 			    bool required)
 | |
| {
 | |
| 	struct srte_candidate *candidate = lsp->candidate;
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug("SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
 | |
| 		   endpoint, policy->color, candidate->name,
 | |
| 		   required ? "required" : "", bandwidth);
 | |
| 	SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
 | |
| 	COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
 | |
| 	lsp->bandwidth = bandwidth;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Remove a candidate path bandwidth constraint.
 | |
|  *
 | |
|  * The corresponding LSP will be changed too.
 | |
|  *
 | |
|  * @param candidate The candidate path of which the bandwidth should be removed
 | |
|  */
 | |
| void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug("SR-TE(%s, %u): candidate %s config bandwidth unset",
 | |
| 		   endpoint, policy->color, candidate->name);
 | |
| 	UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
 | |
| 	UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
 | |
| 	candidate->bandwidth = 0;
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| 	srte_lsp_unset_bandwidth(candidate->lsp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Remove an LSP bandwidth constraint.
 | |
|  *
 | |
|  * The changes will not be shown as part of the running configuration.
 | |
|  *
 | |
|  * @param lsp The lsp of which the bandwidth should be changed
 | |
|  */
 | |
| void srte_lsp_unset_bandwidth(struct srte_lsp *lsp)
 | |
| {
 | |
| 	struct srte_candidate *candidate = lsp->candidate;
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug("SR-TE(%s, %u): candidate %s lsp bandwidth unset", endpoint,
 | |
| 		   policy->color, candidate->name);
 | |
| 	UNSET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
 | |
| 	UNSET_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| 	lsp->bandwidth = 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets a candidate path metric constraint.
 | |
|  *
 | |
|  * The corresponding LSP will be changed too.
 | |
|  *
 | |
|  * @param candidate The candidate path of which the metric should be changed
 | |
|  * @param type The metric type
 | |
|  * @param value The metric value
 | |
|  * @param required If the constraint is required (true) or only desired (false)
 | |
|  * @param is_bound If the metric is an indicative value or a strict upper bound
 | |
|  * @param is_computed If the metric was computed or configured
 | |
|  */
 | |
| void srte_candidate_set_metric(struct srte_candidate *candidate,
 | |
| 			       enum srte_candidate_metric_type type,
 | |
| 			       float value, bool required, bool is_bound,
 | |
| 			       bool is_computed)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug(
 | |
| 		"SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f "
 | |
| 		"(is-bound: %s; is_computed: %s)",
 | |
| 		endpoint, policy->color, candidate->name,
 | |
| 		required ? "required " : "", srte_candidate_metric_name(type),
 | |
| 		type, value, is_bound ? "true" : "false",
 | |
| 		is_computed ? "true" : "false");
 | |
| 	assert((type > 0) && (type <= MAX_METRIC_TYPE));
 | |
| 	srte_set_metric(&candidate->metrics[type - 1], value, required,
 | |
| 			is_bound, is_computed);
 | |
| 	srte_lsp_set_metric(candidate->lsp, type, value, required, is_bound,
 | |
| 			    is_computed);
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets an LSP metric constraint.
 | |
|  *
 | |
|  * The changes will not be shown as part of the running configuration.
 | |
|  *
 | |
|  * @param lsp The LSP of which the metric should be changed
 | |
|  * @param type The metric type
 | |
|  * @param value The metric value
 | |
|  * @param required If the constraint is required (true) or only desired (false)
 | |
|  * @param is_bound If the metric is an indicative value or a strict upper bound
 | |
|  * @param is_computed If the metric was computed or configured
 | |
|  */
 | |
| void srte_lsp_set_metric(struct srte_lsp *lsp,
 | |
| 			 enum srte_candidate_metric_type type, float value,
 | |
| 			 bool required, bool is_bound, bool is_computed)
 | |
| {
 | |
| 	struct srte_candidate *candidate = lsp->candidate;
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug(
 | |
| 		"SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f "
 | |
| 		"(is-bound: %s; is_computed: %s)",
 | |
| 		endpoint, policy->color, candidate->name,
 | |
| 		required ? "required " : "", srte_candidate_metric_name(type),
 | |
| 		type, value, is_bound ? "true" : "false",
 | |
| 		is_computed ? "true" : "false");
 | |
| 	assert((type > 0) && (type <= MAX_METRIC_TYPE));
 | |
| 	srte_set_metric(&lsp->metrics[type - 1], value, required, is_bound,
 | |
| 			is_computed);
 | |
| }
 | |
| 
 | |
| void srte_set_metric(struct srte_metric *metric, float value, bool required,
 | |
| 		     bool is_bound, bool is_computed)
 | |
| {
 | |
| 	SET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
 | |
| 	COND_FLAG(metric->flags, F_METRIC_IS_REQUIRED, required);
 | |
| 	COND_FLAG(metric->flags, F_METRIC_IS_BOUND, is_bound);
 | |
| 	COND_FLAG(metric->flags, F_METRIC_IS_COMPUTED, is_computed);
 | |
| 	metric->value = value;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Removes a candidate path metric constraint.
 | |
|  *
 | |
|  * The corresponding LSP will be changed too.
 | |
|  *
 | |
|  * @param candidate The candidate path from which the metric should be removed
 | |
|  * @param type The metric type
 | |
|  */
 | |
| void srte_candidate_unset_metric(struct srte_candidate *candidate,
 | |
| 				 enum srte_candidate_metric_type type)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug("SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
 | |
| 		   endpoint, policy->color, candidate->name,
 | |
| 		   srte_candidate_metric_name(type), type);
 | |
| 	assert((type > 0) && (type <= MAX_METRIC_TYPE));
 | |
| 	srte_unset_metric(&candidate->metrics[type - 1]);
 | |
| 	srte_lsp_unset_metric(candidate->lsp, type);
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Removes a candidate path metric constraint.
 | |
|  *
 | |
|  * The changes will not be shown as part of the running configuration.
 | |
|  *
 | |
|  * @param lsp The LSP from which the metric should be removed
 | |
|  * @param type The metric type
 | |
|  */
 | |
| void srte_lsp_unset_metric(struct srte_lsp *lsp,
 | |
| 			   enum srte_candidate_metric_type type)
 | |
| {
 | |
| 	struct srte_candidate *candidate = lsp->candidate;
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug("SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
 | |
| 		   endpoint, policy->color, candidate->name,
 | |
| 		   srte_candidate_metric_name(type), type);
 | |
| 	assert((type > 0) && (type <= MAX_METRIC_TYPE));
 | |
| 	srte_unset_metric(&lsp->metrics[type - 1]);
 | |
| }
 | |
| 
 | |
| void srte_unset_metric(struct srte_metric *metric)
 | |
| {
 | |
| 	UNSET_FLAG(metric->flags, F_METRIC_IS_DEFINED);
 | |
| 	UNSET_FLAG(metric->flags, F_METRIC_IS_BOUND);
 | |
| 	UNSET_FLAG(metric->flags, F_METRIC_IS_COMPUTED);
 | |
| 	metric->value = 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets a candidate path objective function.
 | |
|  *
 | |
|  * @param candidate The candidate path of which the OF should be changed
 | |
|  * @param required If the constraint is required (true) or only desired (false)
 | |
|  * @param type The objective function type
 | |
|  */
 | |
| void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
 | |
| 			       enum objfun_type type)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 
 | |
| 	candidate->objfun = type;
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
 | |
| 	COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN, required);
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| 	zlog_debug("SR-TE(%s, %u): candidate %s %sobjective function set to %s",
 | |
| 		   endpoint, policy->color, candidate->name,
 | |
| 		   required ? "required " : "", objfun_type_name(type));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Removed the objective function constraint from a candidate path.
 | |
|  *
 | |
|  * @param candidate The candidate path from which the OF should be removed
 | |
|  */
 | |
| void srte_candidate_unset_objfun(struct srte_candidate *candidate)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 
 | |
| 	UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
 | |
| 	UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| 	candidate->objfun = OBJFUN_UNDEFINED;
 | |
| 	zlog_debug(
 | |
| 		"SR-TE(%s, %u): candidate %s objective functions preferences unset",
 | |
| 		endpoint, policy->color, candidate->name);
 | |
| }
 | |
| 
 | |
| static uint32_t filter_type_to_flag(enum affinity_filter_type type)
 | |
| {
 | |
| 	switch (type) {
 | |
| 	case AFFINITY_FILTER_EXCLUDE_ANY:
 | |
| 		return F_CANDIDATE_HAS_EXCLUDE_ANY;
 | |
| 	case AFFINITY_FILTER_INCLUDE_ANY:
 | |
| 		return F_CANDIDATE_HAS_INCLUDE_ANY;
 | |
| 	case AFFINITY_FILTER_INCLUDE_ALL:
 | |
| 		return F_CANDIDATE_HAS_INCLUDE_ALL;
 | |
| 	default:
 | |
| 		return 0;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static const char *filter_type_name(enum affinity_filter_type type)
 | |
| {
 | |
| 	switch (type) {
 | |
| 	case AFFINITY_FILTER_EXCLUDE_ANY:
 | |
| 		return "exclude-any";
 | |
| 	case AFFINITY_FILTER_INCLUDE_ANY:
 | |
| 		return "include-any";
 | |
| 	case AFFINITY_FILTER_INCLUDE_ALL:
 | |
| 		return "include-all";
 | |
| 	default:
 | |
| 		return "unknown";
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Sets a candidate path affinity filter constraint.
 | |
|  *
 | |
|  * @param candidate The candidate path of which the constraint should be changed
 | |
|  * @param type The affinity constraint type to set
 | |
|  * @param filter The bitmask filter of the constraint
 | |
|  */
 | |
| void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
 | |
| 					enum affinity_filter_type type,
 | |
| 					uint32_t filter)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 
 | |
| 	assert(type > AFFINITY_FILTER_UNDEFINED);
 | |
| 	assert(type <= MAX_AFFINITY_FILTER_TYPE);
 | |
| 	SET_FLAG(candidate->flags, filter_type_to_flag(type));
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| 	candidate->affinity_filters[type - 1] = filter;
 | |
| 	zlog_debug(
 | |
| 		"SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
 | |
| 		endpoint, policy->color, candidate->name,
 | |
| 		filter_type_name(type), filter);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Removes a candidate path affinity filter constraint.
 | |
|  *
 | |
|  * @param candidate The candidate path from which the constraint should be
 | |
|  * removed
 | |
|  * @param type The affinity constraint type to remove
 | |
|  */
 | |
| void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
 | |
| 					  enum affinity_filter_type type)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 
 | |
| 	assert(type > AFFINITY_FILTER_UNDEFINED);
 | |
| 	assert(type <= MAX_AFFINITY_FILTER_TYPE);
 | |
| 	UNSET_FLAG(candidate->flags, filter_type_to_flag(type));
 | |
| 	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | |
| 	candidate->affinity_filters[type - 1] = 0;
 | |
| 	zlog_debug("SR-TE(%s, %u): candidate %s affinity filter %s unset",
 | |
| 		   endpoint, policy->color, candidate->name,
 | |
| 		   filter_type_name(type));
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Searches for a candidate path of the given policy.
 | |
|  *
 | |
|  * @param policy The policy to search for candidate path
 | |
|  * @param preference The preference of the candidate path you are looking for
 | |
|  * @return The candidate path if found, NULL otherwise
 | |
|  */
 | |
| struct srte_candidate *srte_candidate_find(struct srte_policy *policy,
 | |
| 					   uint32_t preference)
 | |
| {
 | |
| 	struct srte_candidate search;
 | |
| 
 | |
| 	search.preference = preference;
 | |
| 	return RB_FIND(srte_candidate_head, &policy->candidate_paths, &search);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Searches for a an entry of a given segment list.
 | |
|  *
 | |
|  * @param segment_list The segment list to search for the entry
 | |
|  * @param index The index of the entry you are looking for
 | |
|  * @return The segment list entry if found, NULL otherwise.
 | |
|  */
 | |
| struct srte_segment_entry *
 | |
| srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index)
 | |
| {
 | |
| 	struct srte_segment_entry search;
 | |
| 
 | |
| 	search.index = index;
 | |
| 	return RB_FIND(srte_segment_entry_head, &segment_list->segments,
 | |
| 		       &search);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Updates a candidate status.
 | |
|  *
 | |
|  * @param candidate The candidate of which the status should be updated
 | |
|  * @param status The new candidate path status
 | |
|  */
 | |
| void srte_candidate_status_update(struct srte_candidate *candidate, int status)
 | |
| {
 | |
| 	struct srte_policy *policy = candidate->policy;
 | |
| 	char endpoint[46];
 | |
| 	ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
 | |
| 	zlog_debug("SR-TE(%s, %u): zebra updated status to %d", endpoint,
 | |
| 		   policy->color, status);
 | |
| 	switch (status) {
 | |
| 	case ZEBRA_SR_POLICY_DOWN:
 | |
| 		switch (policy->status) {
 | |
| 		/* If the policy is GOING_UP, and zebra faild
 | |
| 		   to install it, we wait for zebra to retry */
 | |
| 		/* TODO: Add some timeout after which we would
 | |
| 				 get is back to DOWN and remove the
 | |
| 				 policy */
 | |
| 		case SRTE_POLICY_STATUS_GOING_UP:
 | |
| 		case SRTE_POLICY_STATUS_DOWN:
 | |
| 			return;
 | |
| 		default:
 | |
| 			zlog_debug("SR-TE(%s, %u): policy is DOWN", endpoint,
 | |
| 				   policy->color);
 | |
| 			policy->status = SRTE_POLICY_STATUS_DOWN;
 | |
| 			break;
 | |
| 		}
 | |
| 		break;
 | |
| 	case ZEBRA_SR_POLICY_UP:
 | |
| 		switch (policy->status) {
 | |
| 		case SRTE_POLICY_STATUS_UP:
 | |
| 			return;
 | |
| 		default:
 | |
| 			zlog_debug("SR-TE(%s, %u): policy is UP", endpoint,
 | |
| 				   policy->color);
 | |
| 			policy->status = SRTE_POLICY_STATUS_UP;
 | |
| 			break;
 | |
| 		}
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	trigger_pathd_candidate_updated(candidate);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Flags the segment lists from give originator for removal.
 | |
|  *
 | |
|  * The function srte_apply_changes must be called afterward for
 | |
|  * the segment list to be removed.
 | |
|  *
 | |
|  * @param originator The originator tag of the segment list to be marked
 | |
|  * @param force If the unset should be forced regardless of the originator
 | |
|  */
 | |
| void srte_candidate_unset_segment_list(const char *originator, bool force)
 | |
| {
 | |
| 	if (originator == NULL) {
 | |
| 		zlog_warn(
 | |
| 			"Cannot unset segment list because originator is NULL");
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	zlog_debug("Unset segment lists for originator %s", originator);
 | |
| 
 | |
| 	/* Iterate the policies, then iterate each policy's candidate path
 | |
| 	 * to check the candidate path's segment list originator */
 | |
| 	struct srte_policy *policy;
 | |
| 	RB_FOREACH (policy, srte_policy_head, &srte_policies) {
 | |
| 		zlog_debug("Unset segment lists checking policy %s",
 | |
| 			   policy->name);
 | |
| 		struct srte_candidate *candidate;
 | |
| 		RB_FOREACH (candidate, srte_candidate_head,
 | |
| 			    &policy->candidate_paths) {
 | |
| 			zlog_debug("Unset segment lists checking candidate %s",
 | |
| 				   candidate->name);
 | |
| 			if (candidate->lsp == NULL) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			/* The candidate->lsp->segment_list is operational data,
 | |
| 			 * configured by the PCE. We dont want to modify the
 | |
| 			 * candidate->segment_list,
 | |
| 			 * which is configuration data. */
 | |
| 			struct srte_segment_list *segment_list =
 | |
| 				candidate->lsp->segment_list;
 | |
| 			if (segment_list == NULL) {
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			if (segment_list->protocol_origin
 | |
| 			    == SRTE_ORIGIN_LOCAL) {
 | |
| 				zlog_warn(
 | |
| 					"Cannot unset segment list %s because it "
 | |
| 					"was created locally",
 | |
| 					segment_list->name);
 | |
| 				continue;
 | |
| 			}
 | |
| 
 | |
| 			/* In the case of last pce,we force the unset
 | |
| 			 * because we don't have pce by prefix (TODO) is all
 | |
| 			 * 'global' */
 | |
| 			if (strncmp(segment_list->originator, originator,
 | |
| 				    sizeof(segment_list->originator))
 | |
| 				    == 0
 | |
| 			    || force) {
 | |
| 				zlog_debug("Unset segment list %s",
 | |
| 					   segment_list->name);
 | |
| 				SET_FLAG(segment_list->flags,
 | |
| 					 F_SEGMENT_LIST_DELETED);
 | |
| 				SET_FLAG(candidate->flags,
 | |
| 					 F_CANDIDATE_MODIFIED);
 | |
| 				candidate->lsp->segment_list = NULL;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gives a string representation of given protocol origin enum.
 | |
|  *
 | |
|  * @param origin The enum you want a string representation of
 | |
|  * @return The string representation of given enum
 | |
|  */
 | |
| const char *srte_origin2str(enum srte_protocol_origin origin)
 | |
| {
 | |
| 	switch (origin) {
 | |
| 	case SRTE_ORIGIN_PCEP:
 | |
| 		return "PCEP";
 | |
| 	case SRTE_ORIGIN_BGP:
 | |
| 		return "BGP";
 | |
| 	case SRTE_ORIGIN_LOCAL:
 | |
| 		return "Local";
 | |
| 	default:
 | |
| 		return "Unknown";
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void trigger_pathd_candidate_created(struct srte_candidate *candidate)
 | |
| {
 | |
| 	/* The hook is called asynchronously to let the PCEP module
 | |
| 	time to send a response to the PCE before receiving any updates from
 | |
| 	pathd. In addition, a minimum amount of time need to pass before
 | |
| 	the hook is called to prevent the hook to be called multiple times
 | |
| 	from changing the candidate by hand with the console */
 | |
| 	if (candidate->hook_timer != NULL)
 | |
| 		return;
 | |
| 	thread_add_timer(master, trigger_pathd_candidate_created_timer,
 | |
| 			 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
 | |
| }
 | |
| 
 | |
| int trigger_pathd_candidate_created_timer(struct thread *thread)
 | |
| {
 | |
| 	struct srte_candidate *candidate = THREAD_ARG(thread);
 | |
| 	candidate->hook_timer = NULL;
 | |
| 	return hook_call(pathd_candidate_created, candidate);
 | |
| }
 | |
| 
 | |
| void trigger_pathd_candidate_updated(struct srte_candidate *candidate)
 | |
| {
 | |
| 	/* The hook is called asynchronously to let the PCEP module
 | |
| 	time to send a response to the PCE before receiving any updates from
 | |
| 	pathd. In addition, a minimum amount of time need to pass before
 | |
| 	the hook is called to prevent the hook to be called multiple times
 | |
| 	from changing the candidate by hand with the console */
 | |
| 	if (candidate->hook_timer != NULL)
 | |
| 		return;
 | |
| 	thread_add_timer(master, trigger_pathd_candidate_updated_timer,
 | |
| 			 (void *)candidate, HOOK_DELAY, &candidate->hook_timer);
 | |
| }
 | |
| 
 | |
| int trigger_pathd_candidate_updated_timer(struct thread *thread)
 | |
| {
 | |
| 	struct srte_candidate *candidate = THREAD_ARG(thread);
 | |
| 	candidate->hook_timer = NULL;
 | |
| 	return hook_call(pathd_candidate_updated, candidate);
 | |
| }
 | |
| 
 | |
| void trigger_pathd_candidate_removed(struct srte_candidate *candidate)
 | |
| {
 | |
| 	/* The hook needs to be call synchronously, otherwise the candidate
 | |
| 	path will be already deleted when the handler is called */
 | |
| 	if (candidate->hook_timer != NULL) {
 | |
| 		thread_cancel(&candidate->hook_timer);
 | |
| 		candidate->hook_timer = NULL;
 | |
| 	}
 | |
| 	hook_call(pathd_candidate_removed, candidate);
 | |
| }
 | |
| 
 | |
| const char *srte_candidate_metric_name(enum srte_candidate_metric_type type)
 | |
| {
 | |
| 	switch (type) {
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_IGP:
 | |
| 		return "IGP";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_TE:
 | |
| 		return "TE";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_HC:
 | |
| 		return "HC";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_ABC:
 | |
| 		return "ABC";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_LMLL:
 | |
| 		return "LMLL";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_CIGP:
 | |
| 		return "CIGP";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_CTE:
 | |
| 		return "CTE";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PIGP:
 | |
| 		return "PIGP";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PTE:
 | |
| 		return "PTE";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PHC:
 | |
| 		return "PHC";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_MSD:
 | |
| 		return "MSD";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PD:
 | |
| 		return "PD";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PDV:
 | |
| 		return "PDV";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PL:
 | |
| 		return "PL";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PPD:
 | |
| 		return "PPD";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PPDV:
 | |
| 		return "PPDV";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_PPL:
 | |
| 		return "PPL";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_NAP:
 | |
| 		return "NAP";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_NLP:
 | |
| 		return "NLP";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_DC:
 | |
| 		return "DC";
 | |
| 	case SRTE_CANDIDATE_METRIC_TYPE_BNC:
 | |
| 		return "BNC";
 | |
| 	default:
 | |
| 		return "UNKNOWN";
 | |
| 	}
 | |
| }
 |