mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-10-31 20:23:36 +00:00 
			
		
		
		
	 fc7d07275e
			
		
	
	
		fc7d07275e
		
	
	
	
	
		
			
			We have several instances of a non-locked mutex being unlocked in path_zebra_router_id_update. Clean this up. Signed-off-by: Donald Sharp <sharpd@nvidia.com>
		
			
				
	
	
		
			295 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			295 lines
		
	
	
		
			8.1 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 "thread.h"
 | |
| #include "log.h"
 | |
| #include "lib_errors.h"
 | |
| #include "if.h"
 | |
| #include "prefix.h"
 | |
| #include "zclient.h"
 | |
| #include "network.h"
 | |
| #include "stream.h"
 | |
| #include "linklist.h"
 | |
| #include "nexthop.h"
 | |
| #include "vrf.h"
 | |
| #include "typesafe.h"
 | |
| 
 | |
| #include "pathd/pathd.h"
 | |
| #include "pathd/path_zebra.h"
 | |
| 
 | |
| static struct zclient *zclient;
 | |
| static struct zclient *zclient_sync;
 | |
| 
 | |
| /* Global Variables */
 | |
| bool g_has_router_id_v4 = false;
 | |
| bool g_has_router_id_v6 = false;
 | |
| struct in_addr g_router_id_v4;
 | |
| struct in6_addr g_router_id_v6;
 | |
| pthread_mutex_t g_router_id_v4_mtx = PTHREAD_MUTEX_INITIALIZER;
 | |
| pthread_mutex_t g_router_id_v6_mtx = PTHREAD_MUTEX_INITIALIZER;
 | |
| 
 | |
| /**
 | |
|  * Gives the IPv4 router ID received from Zebra.
 | |
|  *
 | |
|  * @param router_id The in_addr strucure where to store the router id
 | |
|  * @return true if the router ID was available, false otherwise
 | |
|  */
 | |
| bool get_ipv4_router_id(struct in_addr *router_id)
 | |
| {
 | |
| 	bool retval = false;
 | |
| 	assert(router_id != NULL);
 | |
| 	pthread_mutex_lock(&g_router_id_v4_mtx);
 | |
| 	if (g_has_router_id_v4) {
 | |
| 		memcpy(router_id, &g_router_id_v4, sizeof(*router_id));
 | |
| 		retval = true;
 | |
| 	}
 | |
| 	pthread_mutex_unlock(&g_router_id_v4_mtx);
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Gives the IPv6 router ID received from Zebra.
 | |
|  *
 | |
|  * @param router_id The in6_addr strucure where to store the router id
 | |
|  * @return true if the router ID was available, false otherwise
 | |
|  */
 | |
| bool get_ipv6_router_id(struct in6_addr *router_id)
 | |
| {
 | |
| 	bool retval = false;
 | |
| 	assert(router_id != NULL);
 | |
| 	pthread_mutex_lock(&g_router_id_v6_mtx);
 | |
| 	if (g_has_router_id_v6) {
 | |
| 		memcpy(router_id, &g_router_id_v6, sizeof(*router_id));
 | |
| 		retval = true;
 | |
| 	}
 | |
| 	pthread_mutex_unlock(&g_router_id_v6_mtx);
 | |
| 	return retval;
 | |
| }
 | |
| 
 | |
| static void path_zebra_connected(struct zclient *zclient)
 | |
| {
 | |
| 	struct srte_policy *policy;
 | |
| 
 | |
| 	zclient_send_reg_requests(zclient, VRF_DEFAULT);
 | |
| 	zclient_send_router_id_update(zclient, ZEBRA_ROUTER_ID_ADD, AFI_IP6,
 | |
| 				      VRF_DEFAULT);
 | |
| 
 | |
| 	RB_FOREACH (policy, srte_policy_head, &srte_policies) {
 | |
| 		struct srte_candidate *candidate;
 | |
| 		struct srte_segment_list *segment_list;
 | |
| 
 | |
| 		candidate = policy->best_candidate;
 | |
| 		if (!candidate)
 | |
| 			continue;
 | |
| 
 | |
| 		segment_list = candidate->lsp->segment_list;
 | |
| 		if (!segment_list)
 | |
| 			continue;
 | |
| 
 | |
| 		path_zebra_add_sr_policy(policy, segment_list);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int path_zebra_sr_policy_notify_status(ZAPI_CALLBACK_ARGS)
 | |
| {
 | |
| 	struct zapi_sr_policy zapi_sr_policy;
 | |
| 	struct srte_policy *policy;
 | |
| 	struct srte_candidate *best_candidate_path;
 | |
| 
 | |
| 	if (zapi_sr_policy_notify_status_decode(zclient->ibuf, &zapi_sr_policy))
 | |
| 		return -1;
 | |
| 
 | |
| 	policy = srte_policy_find(zapi_sr_policy.color,
 | |
| 				  &zapi_sr_policy.endpoint);
 | |
| 	if (!policy)
 | |
| 		return -1;
 | |
| 
 | |
| 	best_candidate_path = policy->best_candidate;
 | |
| 	if (!best_candidate_path)
 | |
| 		return -1;
 | |
| 
 | |
| 	srte_candidate_status_update(best_candidate_path,
 | |
| 				     zapi_sr_policy.status);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* Router-id update message from zebra. */
 | |
| static int path_zebra_router_id_update(ZAPI_CALLBACK_ARGS)
 | |
| {
 | |
| 	struct prefix pref;
 | |
| 	const char *family;
 | |
| 	char buf[PREFIX2STR_BUFFER];
 | |
| 	zebra_router_id_update_read(zclient->ibuf, &pref);
 | |
| 	if (pref.family == AF_INET) {
 | |
| 		pthread_mutex_lock(&g_router_id_v4_mtx);
 | |
| 		memcpy(&g_router_id_v4, &pref.u.prefix4,
 | |
| 		       sizeof(g_router_id_v4));
 | |
| 		g_has_router_id_v4 = true;
 | |
| 		inet_ntop(AF_INET, &g_router_id_v4, buf, sizeof(buf));
 | |
| 		pthread_mutex_unlock(&g_router_id_v4_mtx);
 | |
| 		family = "IPv4";
 | |
| 	} else if (pref.family == AF_INET6) {
 | |
| 		pthread_mutex_lock(&g_router_id_v6_mtx);
 | |
| 		memcpy(&g_router_id_v6, &pref.u.prefix6,
 | |
| 		       sizeof(g_router_id_v6));
 | |
| 		g_has_router_id_v6 = true;
 | |
| 		inet_ntop(AF_INET6, &g_router_id_v6, buf, sizeof(buf));
 | |
| 		pthread_mutex_unlock(&g_router_id_v6_mtx);
 | |
| 		family = "IPv6";
 | |
| 	} else {
 | |
| 		zlog_warn("Unexpected router ID address family for vrf %u: %u",
 | |
| 			  vrf_id, pref.family);
 | |
| 		return 0;
 | |
| 	}
 | |
| 	zlog_info("%s Router Id updated for VRF %u: %s", family, vrf_id, buf);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Adds a segment routing policy to Zebra.
 | |
|  *
 | |
|  * @param policy The policy to add
 | |
|  * @param segment_list The segment list for the policy
 | |
|  */
 | |
| void path_zebra_add_sr_policy(struct srte_policy *policy,
 | |
| 			      struct srte_segment_list *segment_list)
 | |
| {
 | |
| 	struct zapi_sr_policy zp = {};
 | |
| 	struct srte_segment_entry *segment;
 | |
| 
 | |
| 	zp.color = policy->color;
 | |
| 	zp.endpoint = policy->endpoint;
 | |
| 	strlcpy(zp.name, policy->name, sizeof(zp.name));
 | |
| 	zp.segment_list.type = ZEBRA_LSP_SRTE;
 | |
| 	zp.segment_list.local_label = policy->binding_sid;
 | |
| 	zp.segment_list.label_num = 0;
 | |
| 	RB_FOREACH (segment, srte_segment_entry_head, &segment_list->segments)
 | |
| 		zp.segment_list.labels[zp.segment_list.label_num++] =
 | |
| 			segment->sid_value;
 | |
| 	policy->status = SRTE_POLICY_STATUS_GOING_UP;
 | |
| 
 | |
| 	(void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_SET, &zp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Deletes a segment policy from Zebra.
 | |
|  *
 | |
|  * @param policy The policy to remove
 | |
|  */
 | |
| void path_zebra_delete_sr_policy(struct srte_policy *policy)
 | |
| {
 | |
| 	struct zapi_sr_policy zp = {};
 | |
| 
 | |
| 	zp.color = policy->color;
 | |
| 	zp.endpoint = policy->endpoint;
 | |
| 	strlcpy(zp.name, policy->name, sizeof(zp.name));
 | |
| 	zp.segment_list.type = ZEBRA_LSP_SRTE;
 | |
| 	zp.segment_list.local_label = policy->binding_sid;
 | |
| 	zp.segment_list.label_num = 0;
 | |
| 	policy->status = SRTE_POLICY_STATUS_DOWN;
 | |
| 
 | |
| 	(void)zebra_send_sr_policy(zclient, ZEBRA_SR_POLICY_DELETE, &zp);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Allocates a label from Zebra's label manager.
 | |
|  *
 | |
|  * @param label the label to be allocated
 | |
|  * @return 0 if the label has been allocated, -1 otherwise
 | |
|  */
 | |
| int path_zebra_request_label(mpls_label_t label)
 | |
| {
 | |
| 	int ret;
 | |
| 	uint32_t start, end;
 | |
| 
 | |
| 	ret = lm_get_label_chunk(zclient_sync, 0, label, 1, &start, &end);
 | |
| 	if (ret < 0) {
 | |
| 		zlog_warn("%s: error getting label range!", __func__);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Releases a previously allocated label from Zebra's label manager.
 | |
|  *
 | |
|  * @param label The label to release
 | |
|  * @return 0 ifthe label has beel released, -1 otherwise
 | |
|  */
 | |
| void path_zebra_release_label(mpls_label_t label)
 | |
| {
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = lm_release_label_chunk(zclient_sync, label, label);
 | |
| 	if (ret < 0)
 | |
| 		zlog_warn("%s: error releasing label range!", __func__);
 | |
| }
 | |
| 
 | |
| static void path_zebra_label_manager_connect(void)
 | |
| {
 | |
| 	/* Connect to label manager. */
 | |
| 	while (zclient_socket_connect(zclient_sync) < 0) {
 | |
| 		zlog_warn("%s: error connecting synchronous zclient!",
 | |
| 			  __func__);
 | |
| 		sleep(1);
 | |
| 	}
 | |
| 	set_nonblocking(zclient_sync->sock);
 | |
| 
 | |
| 	/* Send hello to notify zebra this is a synchronous client */
 | |
| 	while (zclient_send_hello(zclient_sync) < 0) {
 | |
| 		zlog_warn("%s: Error sending hello for synchronous zclient!",
 | |
| 			  __func__);
 | |
| 		sleep(1);
 | |
| 	}
 | |
| 
 | |
| 	while (lm_label_manager_connect(zclient_sync, 0) != 0) {
 | |
| 		zlog_warn("%s: error connecting to label manager!", __func__);
 | |
| 		sleep(1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Initializes Zebra asynchronous connection.
 | |
|  *
 | |
|  * @param master The master thread
 | |
|  */
 | |
| void path_zebra_init(struct thread_master *master)
 | |
| {
 | |
| 	struct zclient_options options = zclient_options_default;
 | |
| 	options.synchronous = true;
 | |
| 
 | |
| 	/* Initialize asynchronous zclient. */
 | |
| 	zclient = zclient_new(master, &zclient_options_default);
 | |
| 	zclient_init(zclient, ZEBRA_ROUTE_SRTE, 0, &pathd_privs);
 | |
| 	zclient->zebra_connected = path_zebra_connected;
 | |
| 	zclient->sr_policy_notify_status = path_zebra_sr_policy_notify_status;
 | |
| 	zclient->router_id_update = path_zebra_router_id_update;
 | |
| 
 | |
| 	/* Initialize special zclient for synchronous message exchanges. */
 | |
| 	zclient_sync = zclient_new(master, &options);
 | |
| 	zclient_sync->sock = -1;
 | |
| 	zclient_sync->redist_default = ZEBRA_ROUTE_SRTE;
 | |
| 	zclient_sync->instance = 1;
 | |
| 	zclient_sync->privs = &pathd_privs;
 | |
| 
 | |
| 	/* Connect to the LM. */
 | |
| 	path_zebra_label_manager_connect();
 | |
| }
 |