mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 10:07:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			547 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			547 lines
		
	
	
		
			17 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 <northbound.h>
 | 
						|
#include <yang.h>
 | 
						|
#include <printfrr.h>
 | 
						|
#include "pceplib/pcep_msg_objects.h"
 | 
						|
#include "pathd/pathd.h"
 | 
						|
#include "pathd/path_pcep.h"
 | 
						|
#include "pathd/path_pcep_config.h"
 | 
						|
#include "pathd/path_pcep_debug.h"
 | 
						|
#include "thread.h"
 | 
						|
 | 
						|
#define MAX_XPATH 256
 | 
						|
#define MAX_FLOAT_LEN 22
 | 
						|
#define INETADDR4_MAXLEN 16
 | 
						|
#define INETADDR6_MAXLEN 40
 | 
						|
#define INITIATED_CANDIDATE_PREFERENCE 255
 | 
						|
#define INITIATED_POLICY_COLOR 1
 | 
						|
 | 
						|
 | 
						|
static void copy_candidate_objfun_info(struct srte_candidate *candidate,
 | 
						|
				       struct path *path);
 | 
						|
static void copy_candidate_affinity_filters(struct srte_candidate *candidate,
 | 
						|
					    struct path *path);
 | 
						|
static struct path_hop *
 | 
						|
path_pcep_config_list_path_hops(struct srte_segment_list *segment_list);
 | 
						|
static struct srte_candidate *lookup_candidate(struct lsp_nb_key *key);
 | 
						|
static char *candidate_name(struct srte_candidate *candidate);
 | 
						|
static enum pcep_lsp_operational_status
 | 
						|
status_int_to_ext(enum srte_policy_status status);
 | 
						|
static enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type);
 | 
						|
static enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type);
 | 
						|
 | 
						|
void path_pcep_refine_path(struct path *path)
 | 
						|
{
 | 
						|
	struct srte_candidate *candidate = lookup_candidate(&path->nbkey);
 | 
						|
	struct srte_lsp *lsp;
 | 
						|
 | 
						|
	if (candidate == NULL)
 | 
						|
		return;
 | 
						|
 | 
						|
	lsp = candidate->lsp;
 | 
						|
 | 
						|
	if (path->name == NULL)
 | 
						|
		path->name = candidate_name(candidate);
 | 
						|
	if (path->type == SRTE_CANDIDATE_TYPE_UNDEFINED)
 | 
						|
		path->type = candidate->type;
 | 
						|
	if (path->create_origin == SRTE_ORIGIN_UNDEFINED)
 | 
						|
		path->create_origin = candidate->protocol_origin;
 | 
						|
	if ((path->update_origin == SRTE_ORIGIN_UNDEFINED)
 | 
						|
	    && (lsp->segment_list != NULL))
 | 
						|
		path->update_origin = lsp->segment_list->protocol_origin;
 | 
						|
}
 | 
						|
 | 
						|
struct path *path_pcep_config_get_path(struct lsp_nb_key *key)
 | 
						|
{
 | 
						|
	struct srte_candidate *candidate = lookup_candidate(key);
 | 
						|
	if (candidate == NULL)
 | 
						|
		return NULL;
 | 
						|
	return candidate_to_path(candidate);
 | 
						|
}
 | 
						|
 | 
						|
void path_pcep_config_list_path(path_list_cb_t cb, void *arg)
 | 
						|
{
 | 
						|
	struct path *path;
 | 
						|
	struct srte_policy *policy;
 | 
						|
	struct srte_candidate *candidate;
 | 
						|
 | 
						|
	RB_FOREACH (policy, srte_policy_head, &srte_policies) {
 | 
						|
		RB_FOREACH (candidate, srte_candidate_head,
 | 
						|
			    &policy->candidate_paths) {
 | 
						|
			path = candidate_to_path(candidate);
 | 
						|
			if (!cb(path, arg))
 | 
						|
				return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
struct path *candidate_to_path(struct srte_candidate *candidate)
 | 
						|
{
 | 
						|
	char *name;
 | 
						|
	struct path *path;
 | 
						|
	struct path_hop *hop = NULL;
 | 
						|
	struct path_metric *metric = NULL;
 | 
						|
	struct srte_policy *policy;
 | 
						|
	struct srte_lsp *lsp;
 | 
						|
	enum pcep_lsp_operational_status status;
 | 
						|
	enum srte_protocol_origin update_origin = 0;
 | 
						|
	char *originator = NULL;
 | 
						|
 | 
						|
	policy = candidate->policy;
 | 
						|
	lsp = candidate->lsp;
 | 
						|
 | 
						|
	if (lsp->segment_list != NULL) {
 | 
						|
		hop = path_pcep_config_list_path_hops(lsp->segment_list);
 | 
						|
		update_origin = lsp->segment_list->protocol_origin;
 | 
						|
		originator = XSTRDUP(MTYPE_PCEP, lsp->segment_list->originator);
 | 
						|
	}
 | 
						|
	path = pcep_new_path();
 | 
						|
	name = candidate_name(candidate);
 | 
						|
	if (CHECK_FLAG(candidate->flags, F_CANDIDATE_BEST)) {
 | 
						|
		status = status_int_to_ext(policy->status);
 | 
						|
	} else {
 | 
						|
		status = PCEP_LSP_OPERATIONAL_DOWN;
 | 
						|
	}
 | 
						|
	for (uint32_t i = 0; i < MAX_METRIC_TYPE; i++) {
 | 
						|
		struct path_metric *path_metric;
 | 
						|
		struct srte_metric *srte_metric = &lsp->metrics[i];
 | 
						|
		if (CHECK_FLAG(srte_metric->flags, F_METRIC_IS_DEFINED)) {
 | 
						|
			path_metric = pcep_new_metric();
 | 
						|
			path_metric->next = metric;
 | 
						|
			metric = path_metric;
 | 
						|
			metric->type = i + 1;
 | 
						|
			metric->value = srte_metric->value;
 | 
						|
			metric->enforce = CHECK_FLAG(srte_metric->flags,
 | 
						|
						     F_METRIC_IS_REQUIRED);
 | 
						|
			metric->is_bound = CHECK_FLAG(srte_metric->flags,
 | 
						|
						      F_METRIC_IS_BOUND);
 | 
						|
			metric->is_computed = CHECK_FLAG(srte_metric->flags,
 | 
						|
							 F_METRIC_IS_COMPUTED);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	*path = (struct path){
 | 
						|
		.nbkey = (struct lsp_nb_key){.color = policy->color,
 | 
						|
					     .endpoint = policy->endpoint,
 | 
						|
					     .preference =
 | 
						|
						     candidate->preference},
 | 
						|
		.create_origin = lsp->protocol_origin,
 | 
						|
		.update_origin = update_origin,
 | 
						|
		.originator = originator,
 | 
						|
		.plsp_id = 0,
 | 
						|
		.name = name,
 | 
						|
		.type = candidate->type,
 | 
						|
		.srp_id = policy->srp_id,
 | 
						|
		.req_id = 0,
 | 
						|
		.binding_sid = policy->binding_sid,
 | 
						|
		.status = status,
 | 
						|
		.do_remove = false,
 | 
						|
		.go_active = false,
 | 
						|
		.was_created = false,
 | 
						|
		.was_removed = false,
 | 
						|
		.is_synching = false,
 | 
						|
		.is_delegated = false,
 | 
						|
		.first_hop = hop,
 | 
						|
		.first_metric = metric};
 | 
						|
 | 
						|
	path->has_bandwidth = CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
 | 
						|
	if (path->has_bandwidth) {
 | 
						|
		path->enforce_bandwidth =
 | 
						|
			CHECK_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
 | 
						|
		path->bandwidth = lsp->bandwidth;
 | 
						|
	} else {
 | 
						|
		path->enforce_bandwidth = true;
 | 
						|
		path->bandwidth = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	copy_candidate_objfun_info(candidate, path);
 | 
						|
	copy_candidate_affinity_filters(candidate, path);
 | 
						|
 | 
						|
	return path;
 | 
						|
}
 | 
						|
 | 
						|
void copy_candidate_objfun_info(struct srte_candidate *candidate,
 | 
						|
				struct path *path)
 | 
						|
{
 | 
						|
	struct srte_lsp *lsp = candidate->lsp;
 | 
						|
 | 
						|
	if (lsp != NULL) {
 | 
						|
		if (CHECK_FLAG(lsp->flags, F_CANDIDATE_HAS_OBJFUN)) {
 | 
						|
			path->has_pce_objfun = true;
 | 
						|
			path->pce_objfun = lsp->objfun;
 | 
						|
		} else {
 | 
						|
			path->has_pce_objfun = false;
 | 
						|
			path->pce_objfun = OBJFUN_UNDEFINED;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN)) {
 | 
						|
		path->has_pcc_objfun = true;
 | 
						|
		path->pcc_objfun = candidate->objfun;
 | 
						|
		path->enforce_pcc_objfun = CHECK_FLAG(
 | 
						|
			candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
 | 
						|
 | 
						|
	} else {
 | 
						|
		path->has_pcc_objfun = false;
 | 
						|
		path->pcc_objfun = OBJFUN_UNDEFINED;
 | 
						|
		UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void copy_candidate_affinity_filters(struct srte_candidate *candidate,
 | 
						|
				     struct path *path)
 | 
						|
{
 | 
						|
	bool eany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_EXCLUDE_ANY);
 | 
						|
	bool iany = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ANY);
 | 
						|
	bool iall = CHECK_FLAG(candidate->flags, F_CANDIDATE_HAS_INCLUDE_ALL);
 | 
						|
	path->has_affinity_filters = eany || iany || iall;
 | 
						|
	path->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY - 1] =
 | 
						|
		eany ? candidate->affinity_filters[AFFINITY_FILTER_EXCLUDE_ANY
 | 
						|
						   - 1]
 | 
						|
		     : 0;
 | 
						|
	path->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY - 1] =
 | 
						|
		iany ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ANY
 | 
						|
						   - 1]
 | 
						|
		     : 0;
 | 
						|
	path->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL - 1] =
 | 
						|
		iall ? candidate->affinity_filters[AFFINITY_FILTER_INCLUDE_ALL
 | 
						|
						   - 1]
 | 
						|
		     : 0;
 | 
						|
}
 | 
						|
 | 
						|
struct path_hop *
 | 
						|
path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
 | 
						|
{
 | 
						|
	struct srte_segment_entry *segment;
 | 
						|
	struct path_hop *hop = NULL, *last_hop = NULL;
 | 
						|
 | 
						|
	RB_FOREACH_REVERSE (segment, srte_segment_entry_head,
 | 
						|
			    &segment_list->segments) {
 | 
						|
		hop = pcep_new_hop();
 | 
						|
		*hop = (struct path_hop){
 | 
						|
			.next = last_hop,
 | 
						|
			.is_loose = false,
 | 
						|
			.has_sid = true,
 | 
						|
			.is_mpls = true,
 | 
						|
			.has_attribs = false,
 | 
						|
			.sid = {.mpls = {.label = segment->sid_value}},
 | 
						|
			.has_nai =
 | 
						|
				segment->nai_type != SRTE_SEGMENT_NAI_TYPE_NONE,
 | 
						|
			.nai = {.type = pcep_nai_type(segment->nai_type)}};
 | 
						|
		switch (segment->nai_type) {
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
 | 
						|
			memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
 | 
						|
			       sizeof(struct ipaddr));
 | 
						|
			break;
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
 | 
						|
			memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
 | 
						|
			       sizeof(struct ipaddr));
 | 
						|
			memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
 | 
						|
			       sizeof(struct ipaddr));
 | 
						|
			break;
 | 
						|
		case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
 | 
						|
			memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
 | 
						|
			       sizeof(struct ipaddr));
 | 
						|
			hop->nai.local_iface = segment->nai_local_iface;
 | 
						|
			memcpy(&hop->nai.remote_addr, &segment->nai_remote_addr,
 | 
						|
			       sizeof(struct ipaddr));
 | 
						|
			hop->nai.remote_iface = segment->nai_remote_iface;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		last_hop = hop;
 | 
						|
	}
 | 
						|
	return hop;
 | 
						|
}
 | 
						|
 | 
						|
int path_pcep_config_initiate_path(struct path *path)
 | 
						|
{
 | 
						|
	struct srte_policy *policy;
 | 
						|
	struct srte_candidate *candidate;
 | 
						|
 | 
						|
	if (path->do_remove) {
 | 
						|
		zlog_warn("PCE %s tried to REMOVE pce-initiate a path ",
 | 
						|
			  path->originator);
 | 
						|
		candidate = lookup_candidate(&path->nbkey);
 | 
						|
		if (candidate) {
 | 
						|
			if (!path->is_delegated) {
 | 
						|
				zlog_warn(
 | 
						|
					"(%s)PCE tried to REMOVE but it's not Delegated!",
 | 
						|
					__func__);
 | 
						|
				return ERROR_19_1;
 | 
						|
			}
 | 
						|
			if (candidate->type != SRTE_CANDIDATE_TYPE_DYNAMIC) {
 | 
						|
				zlog_warn(
 | 
						|
					"(%s)PCE tried to REMOVE but it's not PCE origin!",
 | 
						|
					__func__);
 | 
						|
				return ERROR_19_9;
 | 
						|
			}
 | 
						|
			zlog_warn(
 | 
						|
				"(%s)PCE tried to REMOVE found candidate!, let's remove",
 | 
						|
				__func__);
 | 
						|
			candidate->policy->srp_id = path->srp_id;
 | 
						|
			SET_FLAG(candidate->policy->flags, F_POLICY_DELETED);
 | 
						|
			SET_FLAG(candidate->flags, F_CANDIDATE_DELETED);
 | 
						|
		} else {
 | 
						|
			zlog_warn("(%s)PCE tried to REMOVE not existing LSP!",
 | 
						|
				  __func__);
 | 
						|
			return ERROR_19_3;
 | 
						|
		}
 | 
						|
		srte_apply_changes();
 | 
						|
	} else {
 | 
						|
		assert(!IS_IPADDR_NONE(&path->nbkey.endpoint));
 | 
						|
 | 
						|
		if (path->nbkey.preference == 0)
 | 
						|
			path->nbkey.preference = INITIATED_CANDIDATE_PREFERENCE;
 | 
						|
 | 
						|
		if (path->nbkey.color == 0)
 | 
						|
			path->nbkey.color = INITIATED_POLICY_COLOR;
 | 
						|
 | 
						|
		candidate = lookup_candidate(&path->nbkey);
 | 
						|
		if (!candidate) {
 | 
						|
			policy = srte_policy_add(
 | 
						|
				path->nbkey.color, &path->nbkey.endpoint,
 | 
						|
				SRTE_ORIGIN_PCEP, path->originator);
 | 
						|
			strlcpy(policy->name, path->name, sizeof(policy->name));
 | 
						|
			policy->binding_sid = path->binding_sid;
 | 
						|
			SET_FLAG(policy->flags, F_POLICY_NEW);
 | 
						|
			candidate = srte_candidate_add(
 | 
						|
				policy, path->nbkey.preference,
 | 
						|
				SRTE_ORIGIN_PCEP, path->originator);
 | 
						|
			candidate->policy->srp_id = path->srp_id;
 | 
						|
			strlcpy(candidate->name, path->name,
 | 
						|
				sizeof(candidate->name));
 | 
						|
			SET_FLAG(candidate->flags, F_CANDIDATE_NEW);
 | 
						|
		} else {
 | 
						|
			policy = candidate->policy;
 | 
						|
			if ((path->originator != candidate->originator)
 | 
						|
			    || (path->originator != policy->originator)) {
 | 
						|
				/* There is already an initiated path from
 | 
						|
				 * another PCE, show a warning and regect the
 | 
						|
				 * initiated path */
 | 
						|
				zlog_warn(
 | 
						|
					"PCE %s tried to initiate a path already initiated by PCE %s",
 | 
						|
					path->originator,
 | 
						|
					candidate->originator);
 | 
						|
				return 1;
 | 
						|
			}
 | 
						|
			if ((policy->protocol_origin != SRTE_ORIGIN_PCEP)
 | 
						|
			    || (candidate->protocol_origin
 | 
						|
				!= SRTE_ORIGIN_PCEP)) {
 | 
						|
				/* There is already an initiated path from
 | 
						|
				 * another PCE, show a warning and regect the
 | 
						|
				 * initiated path */
 | 
						|
				zlog_warn(
 | 
						|
					"PCE %s tried to initiate a path created localy",
 | 
						|
					path->originator);
 | 
						|
				return 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		return path_pcep_config_update_path(path);
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int path_pcep_config_update_path(struct path *path)
 | 
						|
{
 | 
						|
	assert(path != NULL);
 | 
						|
	assert(path->nbkey.preference != 0);
 | 
						|
	assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
 | 
						|
 | 
						|
	int number_of_sid_clashed = 0;
 | 
						|
	struct path_hop *hop;
 | 
						|
	struct path_metric *metric;
 | 
						|
	int index;
 | 
						|
	char segment_list_name_buff[64 + 1 + 64 + 1 + 11 + 1];
 | 
						|
	char *segment_list_name = NULL;
 | 
						|
	struct srte_candidate *candidate;
 | 
						|
	struct srte_segment_list *segment_list = NULL;
 | 
						|
	struct srte_segment_entry *segment;
 | 
						|
 | 
						|
	candidate = lookup_candidate(&path->nbkey);
 | 
						|
 | 
						|
	// if there is no candidate to update we are done
 | 
						|
	if (!candidate)
 | 
						|
		return 0;
 | 
						|
 | 
						|
	candidate->policy->srp_id = path->srp_id;
 | 
						|
	// first clean up old segment list if present
 | 
						|
	if (candidate->lsp->segment_list) {
 | 
						|
		SET_FLAG(candidate->lsp->segment_list->flags,
 | 
						|
			 F_SEGMENT_LIST_DELETED);
 | 
						|
		srte_segment_list_del(candidate->lsp->segment_list);
 | 
						|
		candidate->lsp->segment_list = NULL;
 | 
						|
	}
 | 
						|
 | 
						|
	if (path->first_hop == NULL)
 | 
						|
		return PATH_NB_ERR;
 | 
						|
 | 
						|
	snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
 | 
						|
		 "%s-%u", path->name, path->plsp_id);
 | 
						|
	segment_list_name = segment_list_name_buff;
 | 
						|
 | 
						|
	segment_list = srte_segment_list_add(segment_list_name);
 | 
						|
	segment_list->protocol_origin = path->update_origin;
 | 
						|
	strlcpy(segment_list->originator, path->originator,
 | 
						|
		sizeof(segment_list->originator));
 | 
						|
	SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
 | 
						|
	SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
 | 
						|
 | 
						|
	for (hop = path->first_hop, index = 10; hop != NULL;
 | 
						|
	     hop = hop->next, index += 10) {
 | 
						|
		assert(hop->has_sid);
 | 
						|
		assert(hop->is_mpls);
 | 
						|
 | 
						|
		segment = srte_segment_entry_add(segment_list, index);
 | 
						|
 | 
						|
		segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
 | 
						|
		SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
 | 
						|
 | 
						|
		if (!hop->has_nai)
 | 
						|
			continue;
 | 
						|
		if (srte_segment_entry_set_nai(
 | 
						|
			    segment, srte_nai_type(hop->nai.type),
 | 
						|
			    &hop->nai.local_addr, hop->nai.local_iface,
 | 
						|
			    &hop->nai.remote_addr, hop->nai.remote_iface, 0, 0)
 | 
						|
		    == PATH_SID_ERROR)
 | 
						|
			/* TED queries don't match PCE */
 | 
						|
			/* Don't apply srte,zebra changes */
 | 
						|
			number_of_sid_clashed++;
 | 
						|
	}
 | 
						|
 | 
						|
	candidate->lsp->segment_list = segment_list;
 | 
						|
	SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
 | 
						|
 | 
						|
	for (metric = path->first_metric; metric != NULL; metric = metric->next)
 | 
						|
		srte_lsp_set_metric(
 | 
						|
			candidate->lsp,
 | 
						|
			(enum srte_candidate_metric_type)metric->type,
 | 
						|
			metric->value, metric->enforce, metric->is_bound,
 | 
						|
			metric->is_computed);
 | 
						|
 | 
						|
	if (path->has_bandwidth)
 | 
						|
		srte_lsp_set_bandwidth(candidate->lsp, path->bandwidth,
 | 
						|
				       path->enforce_bandwidth);
 | 
						|
 | 
						|
	if (path->has_pce_objfun) {
 | 
						|
		SET_FLAG(candidate->lsp->flags, F_CANDIDATE_HAS_OBJFUN);
 | 
						|
		candidate->lsp->objfun = path->pce_objfun;
 | 
						|
	}
 | 
						|
 | 
						|
	if (number_of_sid_clashed)
 | 
						|
		SET_FLAG(segment->segment_list->flags,
 | 
						|
			 F_SEGMENT_LIST_SID_CONFLICT);
 | 
						|
	else
 | 
						|
		srte_apply_changes();
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
struct srte_candidate *lookup_candidate(struct lsp_nb_key *key)
 | 
						|
{
 | 
						|
	struct srte_policy *policy = NULL;
 | 
						|
	policy = srte_policy_find(key->color, &key->endpoint);
 | 
						|
	if (policy == NULL)
 | 
						|
		return NULL;
 | 
						|
	return srte_candidate_find(policy, key->preference);
 | 
						|
}
 | 
						|
 | 
						|
char *candidate_name(struct srte_candidate *candidate)
 | 
						|
{
 | 
						|
	if (candidate->protocol_origin == SRTE_ORIGIN_PCEP
 | 
						|
	    || candidate->protocol_origin == SRTE_ORIGIN_BGP)
 | 
						|
		return asprintfrr(MTYPE_PCEP, "%s", candidate->policy->name);
 | 
						|
	else
 | 
						|
		return asprintfrr(MTYPE_PCEP, "%s-%s", candidate->policy->name,
 | 
						|
				  candidate->name);
 | 
						|
}
 | 
						|
 | 
						|
enum pcep_lsp_operational_status
 | 
						|
status_int_to_ext(enum srte_policy_status status)
 | 
						|
{
 | 
						|
	switch (status) {
 | 
						|
	case SRTE_POLICY_STATUS_UP:
 | 
						|
		return PCEP_LSP_OPERATIONAL_ACTIVE;
 | 
						|
	case SRTE_POLICY_STATUS_GOING_UP:
 | 
						|
		return PCEP_LSP_OPERATIONAL_GOING_UP;
 | 
						|
	case SRTE_POLICY_STATUS_GOING_DOWN:
 | 
						|
		return PCEP_LSP_OPERATIONAL_GOING_DOWN;
 | 
						|
	default:
 | 
						|
		return PCEP_LSP_OPERATIONAL_DOWN;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
 | 
						|
{
 | 
						|
	switch (type) {
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_NONE:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_ABSENT;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
 | 
						|
	case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
 | 
						|
	default:
 | 
						|
		return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
enum srte_segment_nai_type srte_nai_type(enum pcep_sr_subobj_nai type)
 | 
						|
{
 | 
						|
	switch (type) {
 | 
						|
	case PCEP_SR_SUBOBJ_NAI_ABSENT:
 | 
						|
		return SRTE_SEGMENT_NAI_TYPE_NONE;
 | 
						|
	case PCEP_SR_SUBOBJ_NAI_IPV4_NODE:
 | 
						|
		return SRTE_SEGMENT_NAI_TYPE_IPV4_NODE;
 | 
						|
	case PCEP_SR_SUBOBJ_NAI_IPV6_NODE:
 | 
						|
		return SRTE_SEGMENT_NAI_TYPE_IPV6_NODE;
 | 
						|
	case PCEP_SR_SUBOBJ_NAI_IPV4_ADJACENCY:
 | 
						|
		return SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY;
 | 
						|
	case PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY:
 | 
						|
		return SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY;
 | 
						|
	case PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY:
 | 
						|
		return SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY;
 | 
						|
	default:
 | 
						|
		return SRTE_SEGMENT_NAI_TYPE_NONE;
 | 
						|
	}
 | 
						|
}
 |