diff options
| -rw-r--r-- | ldpd/lde.c | 1 | ||||
| -rw-r--r-- | zebra/label_manager.c | 172 | ||||
| -rw-r--r-- | zebra/label_manager.h | 53 | ||||
| -rw-r--r-- | zebra/zapi_msg.c | 15 | ||||
| -rw-r--r-- | zebra/zapi_msg.h | 3 | 
5 files changed, 135 insertions, 109 deletions
diff --git a/ldpd/lde.c b/ldpd/lde.c index ae883078dd..2223e32f87 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -1756,6 +1756,7 @@ static void zclient_sync_init(unsigned short instance)  	zclient_sync->sock = -1;  	zclient_sync->redist_default = ZEBRA_ROUTE_LDP;  	zclient_sync->instance = instance; +	zclient_sync->session_id = 1; /* Distinguish from main session */  	zclient_sync->privs = &lde_privs;  	while (zclient_socket_connect(zclient_sync) < 0) { diff --git a/zebra/label_manager.c b/zebra/label_manager.c index 5f2128a09c..93736e672a 100644 --- a/zebra/label_manager.c +++ b/zebra/label_manager.c @@ -52,48 +52,45 @@ DEFINE_MTYPE_STATIC(LBL_MGR, LM_CHUNK, "Label Manager Chunk");   * externally   */ -DEFINE_HOOK(lm_client_connect, -	    (uint8_t proto, uint16_t instance, vrf_id_t vrf_id), -	    (proto, instance, vrf_id)); -DEFINE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance), -	    (proto, instance)); +DEFINE_HOOK(lm_client_connect, (struct zserv *client, vrf_id_t vrf_id), +	    (client, vrf_id)); +DEFINE_HOOK(lm_client_disconnect, (struct zserv *client), (client));  DEFINE_HOOK(lm_get_chunk, -	    (struct label_manager_chunk * *lmc, uint8_t proto, -	     uint16_t instance, uint8_t keep, uint32_t size, uint32_t base, -	     vrf_id_t vrf_id), -	    (lmc, proto, instance, keep, size, base, vrf_id)); +	     (struct label_manager_chunk * *lmc, struct zserv *client, +	      uint8_t keep, uint32_t size, uint32_t base, vrf_id_t vrf_id), +	     (lmc, client, keep, size, base, vrf_id));  DEFINE_HOOK(lm_release_chunk, -	    (uint8_t proto, uint16_t instance, uint32_t start, uint32_t end), -	    (proto, instance, start, end)); +	     (struct zserv *client, uint32_t start, uint32_t end), +	     (client, start, end));  DEFINE_HOOK(lm_cbs_inited, (), ());  /* define wrappers to be called in zapi_msg.c (as hooks must be called in   * source file where they were defined)   */ -void lm_client_connect_call(uint8_t proto, uint16_t instance, vrf_id_t vrf_id) +void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id)  { -	hook_call(lm_client_connect, proto, instance, vrf_id); +	hook_call(lm_client_connect, client, vrf_id);  } -void lm_get_chunk_call(struct label_manager_chunk **lmc, uint8_t proto, -		       uint16_t instance, uint8_t keep, uint32_t size, -		       uint32_t base, vrf_id_t vrf_id) +void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client, +		       uint8_t keep, uint32_t size, uint32_t base, +		       vrf_id_t vrf_id)  { -	hook_call(lm_get_chunk, lmc, proto, instance, keep, size, base, vrf_id); +	hook_call(lm_get_chunk, lmc, client, keep, size, base, vrf_id);  } -void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start, -			   uint32_t end) +void lm_release_chunk_call(struct zserv *client, uint32_t start, uint32_t end)  { -	hook_call(lm_release_chunk, proto, instance, start, end); +	hook_call(lm_release_chunk, client, start, end);  }  /* forward declarations of the static functions to be used for some hooks */ -static int label_manager_connect(uint8_t proto, uint16_t instance, -				 vrf_id_t vrf_id); -static int label_manager_disconnect(uint8_t proto, uint16_t instance); +static int label_manager_connect(struct zserv *client, vrf_id_t vrf_id); +static int label_manager_disconnect(struct zserv *client);  static int label_manager_get_chunk(struct label_manager_chunk **lmc, -				   uint8_t proto, uint16_t instance, -				   uint8_t keep, uint32_t size, uint32_t base, +				   struct zserv *client, uint8_t keep, +				   uint32_t size, uint32_t base,  				   vrf_id_t vrf_id); +static int label_manager_release_label_chunk(struct zserv *client, +					     uint32_t start, uint32_t end);  void delete_label_chunk(void *val)  { @@ -110,7 +107,7 @@ void delete_label_chunk(void *val)   * @param instance Instance, to identify the owner   * @return Number of chunks released   */ -int release_daemon_label_chunks(uint8_t proto, unsigned short instance) +int release_daemon_label_chunks(struct zserv *client)  {  	struct listnode *node;  	struct label_manager_chunk *lmc; @@ -118,13 +115,16 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance)  	int ret;  	if (IS_ZEBRA_DEBUG_PACKET) -		zlog_debug("%s: Releasing chunks for client proto %s, instance %d", -			   __func__, zebra_route_string(proto), instance); +		zlog_debug("%s: Releasing chunks for client proto %s, instance %d, session %u", +			   __func__, zebra_route_string(client->proto), +			   client->instance, client->session_id);  	for (ALL_LIST_ELEMENTS_RO(lbl_mgr.lc_list, node, lmc)) { -		if (lmc->proto == proto && lmc->instance == instance -		    && lmc->keep == 0) { +		if (lmc->proto == client->proto && +		    lmc->instance == client->instance && +		    lmc->session_id == client->session_id && lmc->keep == 0) {  			ret = release_label_chunk(lmc->proto, lmc->instance, +						  lmc->session_id,  						  lmc->start, lmc->end);  			if (ret == 0)  				count++; @@ -139,10 +139,7 @@ int release_daemon_label_chunks(uint8_t proto, unsigned short instance)  int lm_client_disconnect_cb(struct zserv *client)  { -	uint8_t proto = client->proto; -	uint16_t instance = client->instance; - -	hook_call(lm_client_disconnect, proto, instance); +	hook_call(lm_client_disconnect, client);  	return 0;  } @@ -151,14 +148,14 @@ void lm_hooks_register(void)  	hook_register(lm_client_connect, label_manager_connect);  	hook_register(lm_client_disconnect, label_manager_disconnect);  	hook_register(lm_get_chunk, label_manager_get_chunk); -	hook_register(lm_release_chunk, release_label_chunk); +	hook_register(lm_release_chunk, label_manager_release_label_chunk);  }  void lm_hooks_unregister(void)  {  	hook_unregister(lm_client_connect, label_manager_connect);  	hook_unregister(lm_client_disconnect, label_manager_disconnect);  	hook_unregister(lm_get_chunk, label_manager_get_chunk); -	hook_unregister(lm_release_chunk, release_label_chunk); +	hook_unregister(lm_release_chunk, label_manager_release_label_chunk);  }  /** @@ -180,6 +177,7 @@ void label_manager_init(void)  /* alloc and fill a label chunk */  struct label_manager_chunk *create_label_chunk(uint8_t proto,  					       unsigned short instance, +					       uint32_t session_id,  					       uint8_t keep, uint32_t start,  					       uint32_t end)  { @@ -191,6 +189,7 @@ struct label_manager_chunk *create_label_chunk(uint8_t proto,  	lmc->end = end;  	lmc->proto = proto;  	lmc->instance = instance; +	lmc->session_id = session_id;  	lmc->keep = keep;  	return lmc; @@ -199,7 +198,8 @@ struct label_manager_chunk *create_label_chunk(uint8_t proto,  /* attempt to get a specific label chunk */  static struct label_manager_chunk *  assign_specific_label_chunk(uint8_t proto, unsigned short instance, -			    uint8_t keep, uint32_t size, uint32_t base) +			    uint32_t session_id, uint8_t keep, uint32_t size, +			    uint32_t base)  {  	struct label_manager_chunk *lmc;  	struct listnode *node, *next = NULL; @@ -248,7 +248,8 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,  	/* insert chunk between existing chunks */  	if (insert_node) { -		lmc = create_label_chunk(proto, instance, keep, base, end); +		lmc = create_label_chunk(proto, instance, session_id, keep, +					 base, end);  		listnode_add_before(lbl_mgr.lc_list, insert_node, lmc);  		return lmc;  	} @@ -270,7 +271,8 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,  			delete_label_chunk(death);  		} -		lmc = create_label_chunk(proto, instance, keep, base, end); +		lmc = create_label_chunk(proto, instance, session_id, keep, +					 base, end);  		if (last_node)  			listnode_add_before(lbl_mgr.lc_list, last_node, lmc);  		else @@ -280,7 +282,8 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,  	} else {  		/* create a new chunk past all the existing ones and link at  		 * tail */ -		lmc = create_label_chunk(proto, instance, keep, base, end); +		lmc = create_label_chunk(proto, instance, session_id, keep, +					 base, end);  		listnode_add(lbl_mgr.lc_list, lmc);  		return lmc;  	} @@ -301,6 +304,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,   */  struct label_manager_chunk *assign_label_chunk(uint8_t proto,  					       unsigned short instance, +					       uint32_t session_id,  					       uint8_t keep, uint32_t size,  					       uint32_t base)  { @@ -310,8 +314,8 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,  	/* handle chunks request with a specific base label */  	if (base != MPLS_LABEL_BASE_ANY) -		return assign_specific_label_chunk(proto, instance, keep, size, -						   base); +		return assign_specific_label_chunk(proto, instance, session_id, +						   keep, size, base);  	/* appease scan-build, who gets confused by the use of macros */  	assert(lbl_mgr.lc_list); @@ -322,6 +326,7 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,  		    && lmc->end - lmc->start + 1 == size) {  			lmc->proto = proto;  			lmc->instance = instance; +			lmc->session_id = session_id;  			lmc->keep = keep;  			return lmc;  		} @@ -329,8 +334,9 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,  		 */  		if ((lmc->start > prev_end)  		    && (lmc->start - prev_end >= size)) { -			lmc = create_label_chunk(proto, instance, keep, -						 prev_end + 1, prev_end + size); +			lmc = create_label_chunk(proto, instance, session_id, +						 keep, prev_end + 1, +						 prev_end + size);  			listnode_add_before(lbl_mgr.lc_list, node, lmc);  			return lmc;  		} @@ -355,13 +361,31 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,  	}  	/* create chunk and link at tail */ -	lmc = create_label_chunk(proto, instance, keep, start_free, +	lmc = create_label_chunk(proto, instance, session_id, keep, start_free,  				 start_free + size - 1);  	listnode_add(lbl_mgr.lc_list, lmc);  	return lmc;  }  /** + * Release label chunks from a client. + * + * Called on client disconnection or reconnection. It only releases chunks + * with empty keep value. + * + * @param client Client zapi session + * @param start First label of the chunk + * @param end Last label of the chunk + * @return 0 on success + */ +static int label_manager_release_label_chunk(struct zserv *client, +					     uint32_t start, uint32_t end) +{ +	return release_label_chunk(client->proto, client->instance, +				   client->session_id, start, end); +} + +/**   * Core function, release no longer used label chunks   *   * @param proto Daemon protocol of client, to identify the owner @@ -370,8 +394,8 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,   * @param end Last label of the chunk   * @return 0 on success, -1 otherwise   */ -int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start, -			uint32_t end) +int release_label_chunk(uint8_t proto, unsigned short instance, +			uint32_t session_id, uint32_t start, uint32_t end)  {  	struct listnode *node;  	struct label_manager_chunk *lmc; @@ -386,13 +410,15 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,  			continue;  		if (lmc->end != end)  			continue; -		if (lmc->proto != proto || lmc->instance != instance) { +		if (lmc->proto != proto || lmc->instance != instance || +		    lmc->session_id != session_id) {  			flog_err(EC_ZEBRA_LM_DAEMON_MISMATCH,  				 "%s: Daemon mismatch!!", __func__);  			continue;  		}  		lmc->proto = NO_PROTO;  		lmc->instance = 0; +		lmc->session_id = 0;  		lmc->keep = 0;  		ret = 0;  		break; @@ -405,64 +431,60 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,  }  /* default functions to be called on hooks  */ -static int label_manager_connect(uint8_t proto, uint16_t instance, -				 vrf_id_t vrf_id) +static int label_manager_connect(struct zserv *client, vrf_id_t vrf_id)  {  	/*  	 * Release previous labels of same protocol and instance.  	 * This is done in case it restarted from an unexpected shutdown.  	 */ -	release_daemon_label_chunks(proto, instance); -	return lm_client_connect_response(proto, instance, vrf_id, 0); +	release_daemon_label_chunks(client); +	return zsend_label_manager_connect_response(client, vrf_id, 0);  } -static int label_manager_disconnect(uint8_t proto, uint16_t instance) +static int label_manager_disconnect(struct zserv *client)  { -	release_daemon_label_chunks(proto, instance); +	release_daemon_label_chunks(client);  	return 0;  }  static int label_manager_get_chunk(struct label_manager_chunk **lmc, -				   uint8_t proto, uint16_t instance, -				   uint8_t keep, uint32_t size, uint32_t base, +				   struct zserv *client, uint8_t keep, +				   uint32_t size, uint32_t base,  				   vrf_id_t vrf_id)  { -	*lmc = assign_label_chunk(proto, instance, keep, size, base); -	return lm_get_chunk_response(*lmc, proto, instance, vrf_id); +	*lmc = assign_label_chunk(client->proto, client->instance, +				  client->session_id, keep, size, base); +	return lm_get_chunk_response(*lmc, client, vrf_id);  }  /* Respond to a connect request */  int lm_client_connect_response(uint8_t proto, uint16_t instance, -			       vrf_id_t vrf_id, uint8_t result) +			       uint32_t session_id, vrf_id_t vrf_id, +			       uint8_t result)  { -	struct zserv *client = zserv_find_client(proto, instance); +	struct zserv *client = zserv_find_client_session(proto, instance, +							 session_id);  	if (!client) { -		zlog_err("%s: could not find client for daemon %s instance %u", -			 __func__, zebra_route_string(proto), instance); +		zlog_err("%s: could not find client for daemon %s instance %u session %u", +			 __func__, zebra_route_string(proto), instance, +			 session_id);  		return 1;  	}  	return zsend_label_manager_connect_response(client, vrf_id, result);  }  /* Respond to a get_chunk request */ -int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto, -			  uint16_t instance, vrf_id_t vrf_id) +int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client, +			  vrf_id_t vrf_id)  {  	if (!lmc)  		flog_err(EC_ZEBRA_LM_CANNOT_ASSIGN_CHUNK,  			 "Unable to assign Label Chunk to %s instance %u", -			 zebra_route_string(proto), instance); +			 zebra_route_string(client->proto), client->instance);  	else if (IS_ZEBRA_DEBUG_PACKET)  		zlog_debug("Assigned Label Chunk %u - %u to %s instance %u", -			   lmc->start, lmc->end, zebra_route_string(proto), -			   instance); +			   lmc->start, lmc->end, +			   zebra_route_string(client->proto), client->instance); -	struct zserv *client = zserv_find_client(proto, instance); -	if (!client) { -		zlog_err("%s: could not find client for daemon %s instance %u", -			 __func__, zebra_route_string(proto), instance); -		return 1; -	} -	return zsend_assign_label_chunk_response(client, vrf_id, proto, -						 instance, lmc); +	return zsend_assign_label_chunk_response(client, vrf_id, lmc);  }  void label_manager_close(void) diff --git a/zebra/label_manager.h b/zebra/label_manager.h index 4fee34d301..82154982c2 100644 --- a/zebra/label_manager.h +++ b/zebra/label_manager.h @@ -40,19 +40,20 @@ extern "C" {  /*   * Label chunk struct - * Client daemon which the chunk belongs to can be identified by either - * proto (daemon protocol) + instance. + * Client daemon which the chunk belongs to can be identified by a tuple of: + * proto (daemon protocol) + instance + zapi session_id   * If the client then passes a non-empty value to keep field when it requests   * for chunks, the chunks won't be garbage collected and the client will be - * responsible of its release. + * responsible for releasing them.   * Otherwise, if the keep field is not set (value 0) for the chunk, it will be   * automatically released when the client disconnects or when it reconnects   * (in case it died unexpectedly, we can know it's the same because it will have - * the same proto and instance values) + * the same proto+instance+session values)   */  struct label_manager_chunk {  	uint8_t proto;  	unsigned short instance; +	uint32_t session_id;  	uint8_t keep;  	uint32_t start; /* First label of the chunk */  	uint32_t end;   /* Last label of the chunk */ @@ -63,41 +64,40 @@ struct label_manager_chunk {   * so that any external module wanting to replace those can react   */ -DECLARE_HOOK(lm_client_connect, -	     (uint8_t proto, uint16_t instance, vrf_id_t vrf_id), -	     (proto, instance, vrf_id)); -DECLARE_HOOK(lm_client_disconnect, (uint8_t proto, uint16_t instance), -	     (proto, instance)); +DECLARE_HOOK(lm_client_connect, (struct zserv *client, vrf_id_t vrf_id), +	     (client, vrf_id)); +DECLARE_HOOK(lm_client_disconnect, (struct zserv *client), (client));  DECLARE_HOOK(lm_get_chunk, -	     (struct label_manager_chunk * *lmc, uint8_t proto, -	      uint16_t instance, uint8_t keep, uint32_t size, uint32_t base, -	      vrf_id_t vrf_id), -	     (lmc, proto, instance, keep, size, base, vrf_id)); +	     (struct label_manager_chunk * *lmc, struct zserv *client, +	      uint8_t keep, uint32_t size, uint32_t base, vrf_id_t vrf_id), +	     (lmc, client, keep, size, base, vrf_id));  DECLARE_HOOK(lm_release_chunk, -	     (uint8_t proto, uint16_t instance, uint32_t start, uint32_t end), -	     (proto, instance, start, end)); +	     (struct zserv *client, uint32_t start, uint32_t end), +	     (client, start, end));  DECLARE_HOOK(lm_cbs_inited, (), ());  /* declare wrappers to be called in zapi_msg.c (as hooks must be called in   * source file where they were defined)   */ -void lm_client_connect_call(uint8_t proto, uint16_t instance, vrf_id_t vrf_id); -void lm_get_chunk_call(struct label_manager_chunk **lmc, uint8_t proto, -		       uint16_t instance, uint8_t keep, uint32_t size, -		       uint32_t base, vrf_id_t vrf_id); -void lm_release_chunk_call(uint8_t proto, uint16_t instance, uint32_t start, +void lm_client_connect_call(struct zserv *client, vrf_id_t vrf_id); +void lm_get_chunk_call(struct label_manager_chunk **lmc, struct zserv *client, +		       uint8_t keep, uint32_t size, uint32_t base, +		       vrf_id_t vrf_id); +void lm_release_chunk_call(struct zserv *client, uint32_t start,  			   uint32_t end);  /* API for an external LM to return responses for requests */  int lm_client_connect_response(uint8_t proto, uint16_t instance, -			       vrf_id_t vrf_id, uint8_t result); -int lm_get_chunk_response(struct label_manager_chunk *lmc, uint8_t proto, -			  uint16_t instance, vrf_id_t vrf_id); +			       uint32_t session_id, vrf_id_t vrf_id, +			       uint8_t result); +int lm_get_chunk_response(struct label_manager_chunk *lmc, struct zserv *client, +			  vrf_id_t vrf_id);  /* convenience function to allocate an lmc to be consumed by the above API */  struct label_manager_chunk *create_label_chunk(uint8_t proto,  					       unsigned short instance, +					       uint32_t session_id,  					       uint8_t keep, uint32_t start,  					       uint32_t end);  void delete_label_chunk(void *val); @@ -117,12 +117,13 @@ struct label_manager {  void label_manager_init(void);  struct label_manager_chunk *assign_label_chunk(uint8_t proto,  					       unsigned short instance, +					       uint32_t session_id,  					       uint8_t keep, uint32_t size,  					       uint32_t base); -int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start, -			uint32_t end); +int release_label_chunk(uint8_t proto, unsigned short instance, +			uint32_t session_id, uint32_t start, uint32_t end);  int lm_client_disconnect_cb(struct zserv *client); -int release_daemon_label_chunks(uint8_t proto, unsigned short instance); +int release_daemon_label_chunks(struct zserv *client);  void label_manager_close(void);  #ifdef __cplusplus diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d6f23de487..092b5dd3c2 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -957,7 +957,6 @@ int zsend_pw_update(struct zserv *client, struct zebra_pw *pw)  /* Send response to a get label chunk request to client */  int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id, -				      uint8_t proto, uint16_t instance,  				      struct label_manager_chunk *lmc)  {  	int ret; @@ -965,9 +964,9 @@ int zsend_assign_label_chunk_response(struct zserv *client, vrf_id_t vrf_id,  	zclient_create_header(s, ZEBRA_GET_LABEL_CHUNK, vrf_id);  	/* proto */ -	stream_putc(s, proto); +	stream_putc(s, client->proto);  	/* instance */ -	stream_putw(s, instance); +	stream_putw(s, client->instance);  	if (lmc) {  		/* keep */ @@ -2199,7 +2198,7 @@ static void zread_label_manager_connect(struct zserv *client,  	client->instance = instance;  	/* call hook for connection using wrapper */ -	lm_client_connect_call(proto, instance, vrf_id); +	lm_client_connect_call(client, vrf_id);  stream_failure:  	return; @@ -2225,8 +2224,10 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,  	STREAM_GETL(s, size);  	STREAM_GETL(s, base); +	assert(proto == client->proto && instance == client->instance); +  	/* call hook to get a chunk using wrapper */ -	lm_get_chunk_call(&lmc, proto, instance, keep, size, base, vrf_id); +	lm_get_chunk_call(&lmc, client, keep, size, base, vrf_id);  stream_failure:  	return; @@ -2248,8 +2249,10 @@ static void zread_release_label_chunk(struct zserv *client, struct stream *msg)  	STREAM_GETL(s, start);  	STREAM_GETL(s, end); +	assert(proto == client->proto && instance == client->instance); +  	/* call hook to release a chunk using wrapper */ -	lm_release_chunk_call(proto, instance, start, end); +	lm_release_chunk_call(client, start, end);  stream_failure:  	return; diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 996a255ff4..a4f5e74e4d 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -94,8 +94,7 @@ extern void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,  extern void zsend_capabilities_all_clients(void);  extern int zsend_assign_label_chunk_response(struct zserv *client, -					     vrf_id_t vrf_id, uint8_t proto, -					     uint16_t instance, +					     vrf_id_t vrf_id,  					     struct label_manager_chunk *lmc);  extern int zsend_label_manager_connect_response(struct zserv *client,  						vrf_id_t vrf_id,  | 
