[ofa-general] Re: [PATCH 3/7 V2] osm: QoS policy C & H files

Yevgeny Kliteynik kliteyn at dev.mellanox.co.il
Thu Aug 23 01:11:10 PDT 2007


Hi Sasha,

Sasha Khapyorsky wrote:
> Hi Yevgeny,
> 
> Some initial comments below.
> 
> Sasha
> 
> On 14:46 Tue 21 Aug     , Yevgeny Kliteynik wrote:
>> QoS policy data structures and functions
>>
>> Signed-off-by: Yevgeny Kliteynik <kliteyn at dev.mellanox.co.il>
>> ---
>>  opensm/include/opensm/osm_qos_policy.h |  188 +++++++
>>  opensm/opensm/osm_qos_policy.c         |  901 ++++++++++++++++++++++++++++++++
>>  2 files changed, 1089 insertions(+), 0 deletions(-)
>>  create mode 100644 opensm/include/opensm/osm_qos_policy.h
>>  create mode 100644 opensm/opensm/osm_qos_policy.c
>>
>> diff --git a/opensm/include/opensm/osm_qos_policy.h b/opensm/include/opensm/osm_qos_policy.h
>> new file mode 100644
>> index 0000000..05b8dc9
>> --- /dev/null
>> +++ b/opensm/include/opensm/osm_qos_policy.h
>> @@ -0,0 +1,188 @@
>> +/*
>> + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
>> + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
>> + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
>> + *
>> + * This software is available to you under a choice of one of two
>> + * licenses.  You may choose to be licensed under the terms of the GNU
>> + * General Public License (GPL) Version 2, available from the file
>> + * COPYING in the main directory of this source tree, or the
>> + * OpenIB.org BSD license below:
>> + *
>> + *     Redistribution and use in source and binary forms, with or
>> + *     without modification, are permitted provided that the following
>> + *     conditions are met:
>> + *
>> + *      - Redistributions of source code must retain the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer.
>> + *
>> + *      - Redistributions in binary form must reproduce the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer in the documentation and/or other materials
>> + *        provided with the distribution.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + *
>> + */
>> +
>> +/*
>> + * Abstract:
>> + *    Declaration of OSM QoS Policy data types and functions.
>> + *
>> + * Environment:
>> + *    Linux User Mode
>> + *
>> + * Author:
>> + *    Yevgeny Kliteynik, Mellanox
>> + */
>> +
>> +#ifndef OSM_QOS_POLICY_H
>> +#define OSM_QOS_POLICY_H
>> +
>> +#include <stdio.h>
>> +#include <assert.h>
>> +#include <stdlib.h>
>> +#include <string.h>
>> +#include <ctype.h>
>> +#include <iba/ib_types.h>
>> +#include <opensm/osm_log.h>
>> +#include <opensm/osm_opensm.h>
>> +
>> +#define YYSTYPE char *
>> +#define OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH  128
>> +#define OSM_QOS_POLICY_DEFAULT_LEVEL_NAME   "default"
>> +
>> +/***************************************************/
>> +
>> +typedef struct osm_qos_port_group_t_ {
>> +	char *name;		/* single string (this port group name) */
>> +	char *use;		/* single string (description) */
>> +	cl_list_t port_name_list;	/* list of port names (.../.../...) */
>> +	uint64_t **guid_range_arr;	/* array of guid ranges (pair of 64-bit guids) */
>> +	unsigned guid_range_len;	/* num of guid ranges in the array */
>> +	cl_list_t partition_list;	/* list of partition names */
>> +	boolean_t node_type_ca;
>> +	boolean_t node_type_switch;
>> +	boolean_t node_type_router;
>> +	boolean_t node_type_self;
>> +} osm_qos_port_group_t;
> 
> I see you are using this in "run-time", not just during the parsing.
> 
> Instead of having all this config features you can just resolve port
> guids in parse time and keep it here in cl_map() for fast searches.

By saying "config features", do you mean the four boolean flags?
It looks to me that checking the type of node is as fast as it gets,
and it won't hurt to leave these booleans instead of resolving
all the guids.
Moreover, the guids here are stored in range array, which is IMO
better suited for the policy file syntax, because if a user specifies
something like this "0x0-0x0FFF" in guids, it will be only one element
of the array, which is efficient both in memory and in serch time.
(I probably should mention here that the efficient search in the range
  array is not implemented yet, but it would be a simple binary search -
  there's a "todo" comment in the search function right now)

>> +
>> +osm_qos_port_group_t *osm_qos_policy_port_group_create();
>> +void osm_qos_policy_port_group_destroy();
> 
> Would be nice to have function prototypes in one place.
> 
>> +
>> +/***************************************************/
>> +
>> +typedef struct osm_qos_vlarb_scope_t_ {
>> +	cl_list_t group_list;	/* list of group names (strings) */
>> +	cl_list_t across_list;	/* list of 'across' group names (strings) */
>> +	cl_list_t vlarb_high_list;	/* list of num pairs (n:m,...), 32-bit values */
>> +	cl_list_t vlarb_low_list;	/* list of num pairs (n:m,...), 32-bit values */
> 
> Why cl_list for VLArb? it should be short fixed length arrays?

Right.
Since the actual VLArb setup is not implemented yet, I didn't see
this obvious thing.

>> +	uint32_t vl_high_limit;	/* single integer */
>> +	boolean_t vl_high_limit_set;
>> +} osm_qos_vlarb_scope_t;
>> +
>> +osm_qos_vlarb_scope_t *osm_qos_policy_vlarb_scope_create();
>> +void osm_qos_policy_vlarb_scope_destroy();
>> +
>> +/***************************************************/
>> +
>> +typedef struct osm_qos_sl2vl_scope_t_ {
>> +	cl_list_t group_list;	/* list of strings (port group names) */
>> +	boolean_t from[OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH];
>> +	boolean_t to[OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH];
>> +	cl_list_t across_from_list;	/* list of strings (port group names) */
>> +	cl_list_t across_to_list;	/* list of strings (port group names) */
>> +	uint8_t sl2vl_table[16];	/* array of sl2vl values */
>> +	boolean_t sl2vl_table_set;
>> +} osm_qos_sl2vl_scope_t;
> 
> This will be used for sl2vl setup? 
> Same as above - why not to generate final port guid list just in parse time?
>> +
>> +osm_qos_sl2vl_scope_t *osm_qos_policy_sl2vl_scope_create();
>> +void osm_qos_policy_sl2vl_scope_destroy();
>> +
>> +/***************************************************/
>> +
>> +typedef struct osm_qos_level_t_ {
>> +	char *use;
>> +	char *name;
>> +	uint8_t sl;
>> +	boolean_t sl_set;
>> +	uint8_t mtu_limit;
>> +	boolean_t mtu_limit_set;
>> +	uint8_t rate_limit;
>> +	boolean_t rate_limit_set;
>> +	uint8_t pkt_life;
>> +	boolean_t pkt_life_set;
>> +	uint64_t **path_bits_range_arr;	/* array of bit ranges (real values are 32bits) */
>> +	unsigned path_bits_range_len;	/* num of bit ranges in the array */
>> +	uint64_t **pkey_range_arr;	/* array of PKey ranges (real values are 16bits) */
>> +	unsigned pkey_range_len;
>> +} osm_qos_level_t;
>> +
>> +osm_qos_level_t *osm_qos_policy_qos_level_create();
>> +void osm_qos_policy_qos_level_destroy();
>> +
>> +boolean_t osm_qos_level_has_pkey(IN const osm_qos_level_t * p_qos_level,
>> +				 IN ib_net16_t pkey);
>> +
>> +ib_net16_t osm_qos_level_get_shared_pkey(IN const osm_qos_level_t * p_qos_level,
>> +					 IN const osm_physp_t * p_src_physp,
>> +					 IN const osm_physp_t * p_dest_physp);
>> +
>> +/***************************************************/
>> +
>> +typedef struct osm_qos_match_rule_t_ {
>> +	char *use;
>> +	cl_list_t source_list;	/* list of strings */
>> +	cl_list_t source_group_list;	/* list of pointers to relevant port-group */
>> +	cl_list_t destination_list;	/* list of strings */
>> +	cl_list_t destination_group_list;	/* list of pointers to relevant port-group */
> 
> I think you should only keep port guids there (mapped for fast searches).

Same as above.
I think that checking node type and then guid range array is
essentially faster than checking guid map.
You might say, of course, that there can be many port groups
in the same match rule, but I don't see this as a practical
example.

>> +	char *qos_level_name;
>> +	osm_qos_level_t *p_qos_level;
> 
> Why do you need qos_level_name if you keep the pointer to this qos_level
> struct?

In policy file the match rule might appear before the QoS levels,
so matching qos level names to the actual qos levels is done when
the parsing is done.

>> +	uint64_t **service_id_range_arr;	/* array of SID ranges (64-bit values) */
>> +	unsigned service_id_range_len;
>> +	uint64_t **qos_class_range_arr;	/* array of QoS Class ranges (real values are 16bits) */
>> +	unsigned qos_class_range_len;
>> +	uint64_t **pkey_range_arr;	/* array of PKey ranges (real values are 16bits) */
>> +	unsigned pkey_range_len;
>> +} osm_qos_match_rule_t;
>> +
>> +osm_qos_match_rule_t *osm_qos_policy_match_rule_create();
>> +void osm_qos_policy_match_rule_destroy();
>> +
>> +/***************************************************/
>> +
>> +typedef struct osm_qos_policy_t_ {
>> +	cl_list_t port_groups;	/* list of osm_qos_port_group_t */
>> +	cl_list_t sl2vl_tables;	/* list of osm_qos_sl2vl_scope_t */
>> +	cl_list_t vlarb_tables;	/* list of osm_qos_vlarb_scope_t */
>> +	cl_list_t qos_levels;	/* list of osm_qos_level_t */
>> +	cl_list_t qos_match_rules;	/* list of osm_qos_match_rule_t */
>> +	osm_qos_level_t *p_default_qos_level;	/* default QoS level */
>> +} osm_qos_policy_t;
>> +
>> +void osm_qos_policy_create();
>> +void osm_qos_policy_destroy();
>> +int osm_qos_policy_validate();
>> +
>> +void osm_qos_policy_get_qos_level_by_pr(IN const osm_pr_rcv_t * p_rcv,
>> +					IN const ib_path_rec_t * p_pr,
>> +					IN const osm_physp_t * p_src_physp,
>> +					IN const osm_physp_t * p_dest_physp,
>> +					IN ib_net64_t comp_mask,
>> +					OUT osm_qos_level_t ** pp_qos_level);
>> +
>> +/***************************************************/
>> +
>> +int osm_qos_parse_policy_file(IN osm_log_t * p_log, IN const char *policy_file);
>> +
>> +/***************************************************/
>> +
>> +#endif				/* ifndef OSM_QOS_POLICY_H */
>> diff --git a/opensm/opensm/osm_qos_policy.c b/opensm/opensm/osm_qos_policy.c
>> new file mode 100644
>> index 0000000..bc2aa68
>> --- /dev/null
>> +++ b/opensm/opensm/osm_qos_policy.c
>> @@ -0,0 +1,901 @@
>> +/*
>> + * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
>> + * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
>> + * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
>> + *
>> + * This software is available to you under a choice of one of two
>> + * licenses.  You may choose to be licensed under the terms of the GNU
>> + * General Public License (GPL) Version 2, available from the file
>> + * COPYING in the main directory of this source tree, or the
>> + * OpenIB.org BSD license below:
>> + *
>> + *     Redistribution and use in source and binary forms, with or
>> + *     without modification, are permitted provided that the following
>> + *     conditions are met:
>> + *
>> + *      - Redistributions of source code must retain the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer.
>> + *
>> + *      - Redistributions in binary form must reproduce the above
>> + *        copyright notice, this list of conditions and the following
>> + *        disclaimer in the documentation and/or other materials
>> + *        provided with the distribution.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
>> + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
>> + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
>> + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
>> + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
>> + * SOFTWARE.
>> + *
>> + */
>> +
>> +/*
>> + * Abstract:
>> + *    OSM QoS Policy functions.
>> + *
>> + * Environment:
>> + *    Linux User Mode
>> + *
>> + * Author:
>> + *    Yevgeny Kliteynik, Mellanox
>> + */
>> +
>> +#include <opensm/osm_qos_policy.h>
>> +#include <opensm/osm_qos_parser_y.h>
>> +#include <opensm/osm_partition.h>
>> +
>> +extern void yyerror(char *s);
>> +osm_log_t *p_qos_parser_osm_log = NULL;
>> +osm_qos_policy_t *p_qos_policy = NULL;
> 
> Please try to avoid globals - keep it as part of osm_opensm_t or
> osm_subn_t structures.

I thought about it, but didn't want to "condaminate" the osm_opensm_t
or osm_subn_t structures untill the QoS functionality is ready.

-- Yevgeny

>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +static boolean_t
>> +__is_num_in_range_arr(uint64_t ** range_arr,
>> +		      unsigned range_arr_len, uint64_t num)
>> +{
>> +	unsigned i;
>> +
>> +	/*
>> +	 * TODO: although this array should be rather short,
>> +	 *       I should implement a binary search here
>> +	 */
>> +
>> +	if (num < range_arr[0][0] || num > range_arr[range_arr_len - 1][1])
>> +		return FALSE;
>> +
>> +	for (i = 0; i < range_arr_len; i++) {
>> +		if (num >= range_arr[i][0] && num <= range_arr[i][1])
>> +			return TRUE;
>> +		if (num < range_arr[i][0])
>> +			return FALSE;
>> +	}
>> +	return FALSE;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +static void __free_single_element(void *p_element, void *context)
>> +{
>> +	if (p_element)
>> +		free(p_element);
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +osm_qos_port_group_t *osm_qos_policy_port_group_create()
>> +{
>> +	osm_qos_port_group_t *p =
>> +	    (osm_qos_port_group_t *) malloc(sizeof(osm_qos_port_group_t));
>> +	if (!p)
>> +		return NULL;
>> +
>> +	memset(p, 0, sizeof(osm_qos_port_group_t));
>> +
>> +	cl_list_init(&p->port_name_list, 10);
>> +	cl_list_init(&p->partition_list, 10);
>> +
>> +	return p;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_port_group_destroy(osm_qos_port_group_t * p)
>> +{
>> +	unsigned i;
>> +
>> +	if (!p)
>> +		return;
>> +
>> +	if (p->name)
>> +		free(p->name);
>> +	if (p->use)
>> +		free(p->use);
>> +
>> +	for (i = 0; i < p->guid_range_len; i++)
>> +		free(p->guid_range_arr[i]);
>> +	if (p->guid_range_arr)
>> +		free(p->guid_range_arr);
>> +
>> +	cl_list_apply_func(&p->port_name_list, __free_single_element, NULL);
>> +	cl_list_remove_all(&p->port_name_list);
>> +	cl_list_destroy(&p->port_name_list);
>> +
>> +	cl_list_apply_func(&p->partition_list, __free_single_element, NULL);
>> +	cl_list_remove_all(&p->partition_list);
>> +	cl_list_destroy(&p->partition_list);
>> +
>> +	free(p);
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +osm_qos_vlarb_scope_t *osm_qos_policy_vlarb_scope_create()
>> +{
>> +	osm_qos_vlarb_scope_t *p =
>> +	    (osm_qos_vlarb_scope_t *) malloc(sizeof(osm_qos_sl2vl_scope_t));
>> +	if (!p)
>> +		return NULL;
>> +
>> +	memset(p, 0, sizeof(osm_qos_vlarb_scope_t));
>> +
>> +	cl_list_init(&p->group_list, 10);
>> +	cl_list_init(&p->across_list, 10);
>> +	cl_list_init(&p->vlarb_high_list, 10);
>> +	cl_list_init(&p->vlarb_low_list, 10);
>> +
>> +	return p;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_vlarb_scope_destroy(osm_qos_vlarb_scope_t * p)
>> +{
>> +	if (!p)
>> +		return;
>> +
>> +	cl_list_apply_func(&p->group_list, __free_single_element, NULL);
>> +	cl_list_apply_func(&p->across_list, __free_single_element, NULL);
>> +	cl_list_apply_func(&p->vlarb_high_list, __free_single_element, NULL);
>> +	cl_list_apply_func(&p->vlarb_low_list, __free_single_element, NULL);
>> +
>> +	cl_list_remove_all(&p->group_list);
>> +	cl_list_remove_all(&p->across_list);
>> +	cl_list_remove_all(&p->vlarb_high_list);
>> +	cl_list_remove_all(&p->vlarb_low_list);
>> +
>> +	cl_list_destroy(&p->group_list);
>> +	cl_list_destroy(&p->across_list);
>> +	cl_list_destroy(&p->vlarb_high_list);
>> +	cl_list_destroy(&p->vlarb_low_list);
>> +
>> +	free(p);
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +osm_qos_sl2vl_scope_t *osm_qos_policy_sl2vl_scope_create()
>> +{
>> +	osm_qos_sl2vl_scope_t *p =
>> +	    (osm_qos_sl2vl_scope_t *) malloc(sizeof(osm_qos_sl2vl_scope_t));
>> +	if (!p)
>> +		return NULL;
>> +
>> +	memset(p, 0, sizeof(osm_qos_vlarb_scope_t));
>> +
>> +	cl_list_init(&p->group_list, 10);
>> +	cl_list_init(&p->across_from_list, 10);
>> +	cl_list_init(&p->across_to_list, 10);
>> +
>> +	return p;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_sl2vl_scope_destroy(osm_qos_sl2vl_scope_t * p)
>> +{
>> +	if (!p)
>> +		return;
>> +
>> +	cl_list_apply_func(&p->group_list, __free_single_element, NULL);
>> +	cl_list_apply_func(&p->across_from_list, __free_single_element, NULL);
>> +	cl_list_apply_func(&p->across_to_list, __free_single_element, NULL);
>> +
>> +	cl_list_remove_all(&p->group_list);
>> +	cl_list_remove_all(&p->across_from_list);
>> +	cl_list_remove_all(&p->across_to_list);
>> +
>> +	cl_list_destroy(&p->group_list);
>> +	cl_list_destroy(&p->across_from_list);
>> +	cl_list_destroy(&p->across_to_list);
>> +
>> +	free(p);
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +osm_qos_level_t *osm_qos_policy_qos_level_create()
>> +{
>> +	osm_qos_level_t *p =
>> +	    (osm_qos_level_t *) malloc(sizeof(osm_qos_level_t));
>> +	if (!p)
>> +		return NULL;
>> +	memset(p, 0, sizeof(osm_qos_level_t));
>> +	return p;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_qos_level_destroy(osm_qos_level_t * p)
>> +{
>> +	unsigned i;
>> +
>> +	if (!p)
>> +		return;
>> +
>> +	if (p->use)
>> +		free(p->use);
>> +
>> +	for (i = 0; i < p->path_bits_range_len; i++)
>> +		free(p->path_bits_range_arr[i]);
>> +	if (p->path_bits_range_arr)
>> +		free(p->path_bits_range_arr);
>> +
>> +	free(p);
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +boolean_t osm_qos_level_has_pkey(IN const osm_qos_level_t * p_qos_level,
>> +				 IN ib_net16_t pkey)
>> +{
>> +	if (!p_qos_level || !p_qos_level->pkey_range_len)
>> +		return FALSE;
>> +	return __is_num_in_range_arr(p_qos_level->pkey_range_arr,
>> +				     p_qos_level->pkey_range_len,
>> +				     cl_ntoh16(pkey));
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +ib_net16_t osm_qos_level_get_shared_pkey(IN const osm_qos_level_t * p_qos_level,
>> +					 IN const osm_physp_t * p_src_physp,
>> +					 IN const osm_physp_t * p_dest_physp)
>> +{
>> +	unsigned i;
>> +	uint16_t pkey_ho = 0;
>> +
>> +	if (!p_qos_level || !p_qos_level->pkey_range_len)
>> +		return 0;
>> +
>> +	/*
>> +	 * ToDo: This approach is not optimal.
>> +	 *       Think how to find shared pkey that also exists
>> +	 *       in QoS level in less runtime.
>> +	 */
>> +
>> +	for (i = 0; i < p_qos_level->pkey_range_len; i++) {
>> +		for (pkey_ho = p_qos_level->pkey_range_arr[i][0];
>> +		     pkey_ho <= p_qos_level->pkey_range_arr[i][1]; pkey_ho++) {
>> +			if (osm_physp_share_this_pkey
>> +			    (p_src_physp, p_dest_physp, cl_hton16(pkey_ho)))
>> +				return cl_hton16(pkey_ho);
>> +		}
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +osm_qos_match_rule_t *osm_qos_policy_match_rule_create()
>> +{
>> +	osm_qos_match_rule_t *p =
>> +	    (osm_qos_match_rule_t *) malloc(sizeof(osm_qos_match_rule_t));
>> +	if (!p)
>> +		return NULL;
>> +
>> +	memset(p, 0, sizeof(osm_qos_match_rule_t));
>> +
>> +	cl_list_init(&p->source_list, 10);
>> +	cl_list_init(&p->source_group_list, 10);
>> +	cl_list_init(&p->destination_list, 10);
>> +	cl_list_init(&p->destination_group_list, 10);
>> +
>> +	return p;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_match_rule_destroy(osm_qos_match_rule_t * p)
>> +{
>> +	unsigned i;
>> +
>> +	if (!p)
>> +		return;
>> +
>> +	if (p->qos_level_name)
>> +		free(p->qos_level_name);
>> +	if (p->use)
>> +		free(p->use);
>> +
>> +	for (i = 0; i < p->service_id_range_len; i++)
>> +		free(p->service_id_range_arr[i]);
>> +	if (p->service_id_range_arr)
>> +		free(p->service_id_range_arr);
>> +
>> +	for (i = 0; i < p->qos_class_range_len; i++)
>> +		free(p->qos_class_range_arr[i]);
>> +	if (p->qos_class_range_arr)
>> +		free(p->qos_class_range_arr);
>> +
>> +	cl_list_apply_func(&p->source_list, __free_single_element, NULL);
>> +	cl_list_remove_all(&p->source_list);
>> +	cl_list_destroy(&p->source_list);
>> +
>> +	cl_list_remove_all(&p->source_group_list);
>> +	cl_list_destroy(&p->source_group_list);
>> +
>> +	cl_list_apply_func(&p->destination_list, __free_single_element, NULL);
>> +	cl_list_remove_all(&p->destination_list);
>> +	cl_list_destroy(&p->destination_list);
>> +
>> +	cl_list_remove_all(&p->destination_group_list);
>> +	cl_list_destroy(&p->destination_group_list);
>> +
>> +	free(p);
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_create()
>> +{
>> +	if (p_qos_policy)
>> +		osm_qos_policy_destroy();
>> +
>> +	p_qos_policy = (osm_qos_policy_t *) malloc(sizeof(osm_qos_policy_t));
>> +	CL_ASSERT(p_qos_policy);
>> +
>> +	memset(p_qos_policy, 0, sizeof(osm_qos_policy_t));
>> +
>> +	cl_list_construct(&p_qos_policy->port_groups);
>> +	cl_list_init(&p_qos_policy->port_groups, 10);
>> +
>> +	cl_list_construct(&p_qos_policy->vlarb_tables);
>> +	cl_list_init(&p_qos_policy->vlarb_tables, 10);
>> +
>> +	cl_list_construct(&p_qos_policy->sl2vl_tables);
>> +	cl_list_init(&p_qos_policy->sl2vl_tables, 10);
>> +
>> +	cl_list_construct(&p_qos_policy->qos_levels);
>> +	cl_list_init(&p_qos_policy->qos_levels, 10);
>> +
>> +	cl_list_construct(&p_qos_policy->qos_match_rules);
>> +	cl_list_init(&p_qos_policy->qos_match_rules, 10);
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_destroy()
>> +{
>> +	cl_list_iterator_t list_iterator;
>> +	osm_qos_port_group_t *p_port_group = NULL;
>> +	osm_qos_vlarb_scope_t *p_vlarb_scope = NULL;
>> +	osm_qos_sl2vl_scope_t *p_sl2vl_scope = NULL;
>> +	osm_qos_level_t *p_qos_level = NULL;
>> +	osm_qos_match_rule_t *p_qos_match_rule = NULL;
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->port_groups);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) {
>> +		p_port_group =
>> +		    (osm_qos_port_group_t *) cl_list_obj(list_iterator);
>> +		if (p_port_group)
>> +			osm_qos_policy_port_group_destroy(p_port_group);
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +	cl_list_remove_all(&p_qos_policy->port_groups);
>> +	cl_list_destroy(&p_qos_policy->port_groups);
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->vlarb_tables);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->vlarb_tables)) {
>> +		p_vlarb_scope =
>> +		    (osm_qos_vlarb_scope_t *) cl_list_obj(list_iterator);
>> +		if (p_vlarb_scope)
>> +			osm_qos_policy_vlarb_scope_destroy(p_vlarb_scope);
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +	cl_list_remove_all(&p_qos_policy->vlarb_tables);
>> +	cl_list_destroy(&p_qos_policy->vlarb_tables);
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->sl2vl_tables);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->sl2vl_tables)) {
>> +		p_sl2vl_scope =
>> +		    (osm_qos_sl2vl_scope_t *) cl_list_obj(list_iterator);
>> +		if (p_sl2vl_scope)
>> +			osm_qos_policy_sl2vl_scope_destroy(p_sl2vl_scope);
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +	cl_list_remove_all(&p_qos_policy->sl2vl_tables);
>> +	cl_list_destroy(&p_qos_policy->sl2vl_tables);
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->qos_levels);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) {
>> +		p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator);
>> +		if (p_qos_level)
>> +			osm_qos_policy_qos_level_destroy(p_qos_level);
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +	cl_list_remove_all(&p_qos_policy->qos_levels);
>> +	cl_list_destroy(&p_qos_policy->qos_levels);
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->qos_match_rules);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) {
>> +		p_qos_match_rule =
>> +		    (osm_qos_match_rule_t *) cl_list_obj(list_iterator);
>> +		if (p_qos_match_rule)
>> +			osm_qos_policy_match_rule_destroy(p_qos_match_rule);
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +	cl_list_remove_all(&p_qos_policy->qos_match_rules);
>> +	cl_list_destroy(&p_qos_policy->qos_match_rules);
>> +
>> +	free(p_qos_policy);
>> +
>> +	p_qos_policy = NULL;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +static boolean_t
>> +__qos_policy_is_port_in_group(osm_subn_t * p_subn,
>> +			      const osm_physp_t * p_physp,
>> +			      osm_qos_port_group_t * p_port_group)
>> +{
>> +	osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
>> +	osm_prtn_t *p_prtn = NULL;
>> +	ib_net64_t port_guid = osm_physp_get_port_guid(p_physp);
>> +	uint64_t port_guid_ho = cl_ntoh64(port_guid);
>> +	uint8_t node_type = osm_node_get_type(p_node);
>> +	cl_list_iterator_t list_iterator;
>> +	char *partition_name;
>> +
>> +	/* check whether this port's type matches any of group's types */
>> +
>> +	if ((node_type == IB_NODE_TYPE_CA && p_port_group->node_type_ca) ||
>> +	    (node_type == IB_NODE_TYPE_SWITCH && p_port_group->node_type_switch)
>> +	    || (node_type == IB_NODE_TYPE_ROUTER
>> +		&& p_port_group->node_type_router))
>> +		return TRUE;
>> +
>> +	/* check whether this port's guid is in range of this group's guids */
>> +
>> +	if (__is_num_in_range_arr(p_port_group->guid_range_arr,
>> +				  p_port_group->guid_range_len, port_guid_ho))
>> +		return TRUE;
>> +
>> +	/* check whether this port is member of this group's partitions */
>> +
>> +	list_iterator = cl_list_head(&p_port_group->partition_list);
>> +	while (list_iterator != cl_list_end(&p_port_group->partition_list)) {
>> +		partition_name = (char *)cl_list_obj(list_iterator);
>> +		if (partition_name && strlen(partition_name)) {
>> +			p_prtn = osm_prtn_find_by_name(p_subn, partition_name);
>> +			if (p_prtn) {
>> +				if (osm_prtn_is_guid(p_prtn, port_guid))
>> +					return TRUE;
>> +			}
>> +		}
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +
>> +	/* check whether this port's name matches any of group's names */
>> +
>> +	/*
>> +	 * TODO: check port names
>> +	 *
>> +	 *  char desc[IB_NODE_DESCRIPTION_SIZE + 1];
>> +	 *  memcpy(desc, p_node->node_desc.description, IB_NODE_DESCRIPTION_SIZE);
>> +	 *  desc[IB_NODE_DESCRIPTION_SIZE] = '\0';
>> +	 */
>> +
>> +	return FALSE;
>> +}				/* __qos_policy_is_port_in_group() */
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +static boolean_t
>> +__qos_policy_is_port_in_group_list(const osm_pr_rcv_t * p_rcv,
>> +				   const osm_physp_t * p_physp,
>> +				   cl_list_t * p_port_group_list)
>> +{
>> +	osm_qos_port_group_t *p_port_group;
>> +	cl_list_iterator_t list_iterator;
>> +
>> +	list_iterator = cl_list_head(p_port_group_list);
>> +	while (list_iterator != cl_list_end(p_port_group_list)) {
>> +		p_port_group =
>> +		    (osm_qos_port_group_t *) cl_list_obj(list_iterator);
>> +		if (p_port_group) {
>> +			if (__qos_policy_is_port_in_group
>> +			    (p_rcv->p_subn, p_physp, p_port_group))
>> +				return TRUE;
>> +		}
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +	return FALSE;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +static osm_qos_match_rule_t *__qos_policy_get_match_rule_by_pr(
>> +			 const osm_pr_rcv_t * p_rcv,
>> +			 const ib_path_rec_t * p_pr,
>> +			 const osm_physp_t * p_src_physp,
>> +			 const osm_physp_t * p_dest_physp,
>> +			 ib_net64_t comp_mask)
>> +{
>> +	osm_qos_match_rule_t *p_qos_match_rule = NULL;
>> +	cl_list_iterator_t list_iterator;
>> +
>> +	if (!cl_list_count(&p_qos_policy->qos_match_rules))
>> +		return NULL;
>> +
>> +	/* Go over all QoS match rules and find the one that matches the request */
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->qos_match_rules);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) {
>> +		p_qos_match_rule =
>> +		    (osm_qos_match_rule_t *) cl_list_obj(list_iterator);
>> +		if (!p_qos_match_rule) {
>> +			list_iterator = cl_list_next(list_iterator);
>> +			continue;
>> +		}
>> +
>> +		/* If a match rule has Source groups, PR request source has to be in this list */
>> +
>> +		if (cl_list_count(&p_qos_match_rule->source_group_list)) {
>> +			if (!__qos_policy_is_port_in_group_list(p_rcv,
>> +								p_src_physp,
>> +								&p_qos_match_rule->
>> +								source_group_list))
>> +			{
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +		}
>> +
>> +		/* If a match rule has Destination groups, PR request dest. has to be in this list */
>> +
>> +		if (cl_list_count(&p_qos_match_rule->destination_group_list)) {
>> +			if (!__qos_policy_is_port_in_group_list(p_rcv,
>> +								p_dest_physp,
>> +								&p_qos_match_rule->
>> +								destination_group_list))
>> +			{
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +		}
>> +
>> +		/* If a match rule has QoS classes, PR request HAS
>> +		   to have a matching QoS class to match the rule */
>> +
>> +		if (p_qos_match_rule->qos_class_range_len) {
>> +			if (!(comp_mask & IB_PR_COMPMASK_QOS_CLASS)) {
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +
>> +			if (!__is_num_in_range_arr
>> +			    (p_qos_match_rule->qos_class_range_arr,
>> +			     p_qos_match_rule->qos_class_range_len,
>> +			     ib_path_rec_qos_class(p_pr))) {
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +
>> +		}
>> +
>> +		/* If a match rule has Service IDs, PR request HAS
>> +		   to have a matching Service ID to match the rule */
>> +
>> +		if (p_qos_match_rule->service_id_range_len) {
>> +			if (!(comp_mask & IB_PR_COMPMASK_SERVICEID)) {
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +
>> +			if (!__is_num_in_range_arr
>> +			    (p_qos_match_rule->service_id_range_arr,
>> +			     p_qos_match_rule->service_id_range_len,
>> +			     p_pr->service_id)) {
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +
>> +		}
>> +
>> +		/* If a match rule has PKeys, PR request HAS
>> +		   to have a matching PKey to match the rule */
>> +
>> +		if (p_qos_match_rule->pkey_range_len) {
>> +			if (!(comp_mask & IB_PR_COMPMASK_PKEY)) {
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +
>> +			if (!__is_num_in_range_arr
>> +			    (p_qos_match_rule->pkey_range_arr,
>> +			     p_qos_match_rule->pkey_range_len,
>> +			     ib_path_rec_qos_class(p_pr))) {
>> +				list_iterator = cl_list_next(list_iterator);
>> +				continue;
>> +			}
>> +
>> +		}
>> +
>> +		/* if we got here, then this match-rule matched this PR request */
>> +		break;
>> +	}
>> +
>> +	if (list_iterator == cl_list_end(&p_qos_policy->qos_match_rules))
>> +		return NULL;
>> +
>> +	return p_qos_match_rule;
>> +}				/* __qos_policy_get_match_rule_by_pr() */
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +static osm_qos_level_t *__qos_policy_get_qos_level_by_name(char *name)
>> +{
>> +	osm_qos_level_t *p_qos_level = NULL;
>> +	cl_list_iterator_t list_iterator;
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->qos_levels);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) {
>> +		p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator);
>> +		if (!p_qos_level)
>> +			continue;
>> +
>> +		/* names are case INsensitive */
>> +		if (strcasecmp(name, p_qos_level->name) == 0)
>> +			return p_qos_level;
>> +
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +static osm_qos_port_group_t *__qos_policy_get_port_group_by_name(const char
>> +								 *const name)
>> +{
>> +	osm_qos_port_group_t *p_port_group = NULL;
>> +	cl_list_iterator_t list_iterator;
>> +
>> +	list_iterator = cl_list_head(&p_qos_policy->port_groups);
>> +	while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) {
>> +		p_port_group =
>> +		    (osm_qos_port_group_t *) cl_list_obj(list_iterator);
>> +		if (!p_port_group)
>> +			continue;
>> +
>> +		/* names are case INsensitive */
>> +		if (strcasecmp(name, p_port_group->name) == 0)
>> +			return p_port_group;
>> +
>> +		list_iterator = cl_list_next(list_iterator);
>> +	}
>> +
>> +	return NULL;
>> +}
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +int osm_qos_policy_validate()
>> +{
>> +	cl_list_iterator_t match_rules_list_iterator;
>> +	cl_list_iterator_t list_iterator;
>> +	osm_qos_port_group_t *p_port_group = NULL;
>> +	osm_qos_match_rule_t *p_qos_match_rule = NULL;
>> +	char *str;
>> +	unsigned i;
>> +	int res = 0;
>> +
>> +	OSM_LOG_ENTER(p_qos_parser_osm_log, osm_qos_policy_validate);
>> +
>> +	/* set default qos level */
>> +
>> +	p_qos_policy->p_default_qos_level =
>> +	    __qos_policy_get_qos_level_by_name
>> +	    (OSM_QOS_POLICY_DEFAULT_LEVEL_NAME);
>> +	if (!p_qos_policy->p_default_qos_level) {
>> +		osm_log(p_qos_parser_osm_log, OSM_LOG_ERROR,
>> +			"osm_qos_policy_validate: ERR AC10: "
>> +			"Default qos-level (%s) not defined.\n",
>> +			OSM_QOS_POLICY_DEFAULT_LEVEL_NAME);
>> +		res = 1;
>> +		goto Exit;
>> +	}
>> +
>> +	/* scan all the match rules, and fill the lists of pointers to
>> +	   relevant qos levels and port groups to speed up PR matching */
>> +
>> +	i = 1;
>> +	match_rules_list_iterator =
>> +	    cl_list_head(&p_qos_policy->qos_match_rules);
>> +	while (match_rules_list_iterator !=
>> +	       cl_list_end(&p_qos_policy->qos_match_rules)) {
>> +		p_qos_match_rule =
>> +		    (osm_qos_match_rule_t *)
>> +		    cl_list_obj(match_rules_list_iterator);
>> +		CL_ASSERT(p_qos_match_rule);
>> +
>> +		/* find the matching qos-level for each match-rule */
>> +
>> +		p_qos_match_rule->p_qos_level =
>> +		    __qos_policy_get_qos_level_by_name(p_qos_match_rule->
>> +						       qos_level_name);
>> +
>> +		if (!p_qos_match_rule->p_qos_level) {
>> +			osm_log(p_qos_parser_osm_log, OSM_LOG_ERROR,
>> +				"osm_qos_policy_validate: ERR AC11: "
>> +				"qos-match-rule num %u: qos-level '%s' not found\n",
>> +				i, p_qos_match_rule->qos_level_name);
>> +			res = 1;
>> +			goto Exit;
>> +		}
>> +
>> +		/* find the matching port-group for element of source_list */
>> +
>> +		if (cl_list_count(&p_qos_match_rule->source_list)) {
>> +			list_iterator =
>> +			    cl_list_head(&p_qos_match_rule->source_list);
>> +			while (list_iterator !=
>> +			       cl_list_end(&p_qos_match_rule->source_list)) {
>> +				str = (char *)cl_list_obj(list_iterator);
>> +				CL_ASSERT(str);
>> +
>> +				p_port_group =
>> +				    __qos_policy_get_port_group_by_name(str);
>> +				if (!p_port_group) {
>> +					osm_log(p_qos_parser_osm_log,
>> +						OSM_LOG_ERROR,
>> +						"osm_qos_policy_validate: ERR AC12: "
>> +						"qos-match-rule num %u: source port-group '%s' not found\n",
>> +						i, str);
>> +					res = 1;
>> +					goto Exit;
>> +				}
>> +
>> +				cl_list_insert_tail(&p_qos_match_rule->
>> +						    source_group_list,
>> +						    p_port_group);
>> +
>> +				list_iterator = cl_list_next(list_iterator);
>> +			}
>> +		}
>> +
>> +		/* find the matching port-group for element of destination_list */
>> +
>> +		if (cl_list_count(&p_qos_match_rule->destination_list)) {
>> +			list_iterator =
>> +			    cl_list_head(&p_qos_match_rule->destination_list);
>> +			while (list_iterator !=
>> +			       cl_list_end(&p_qos_match_rule->
>> +					   destination_list)) {
>> +				str = (char *)cl_list_obj(list_iterator);
>> +				CL_ASSERT(str);
>> +
>> +				p_port_group =
>> +				    __qos_policy_get_port_group_by_name(str);
>> +				if (!p_port_group) {
>> +					osm_log(p_qos_parser_osm_log,
>> +						OSM_LOG_ERROR,
>> +						"osm_qos_policy_validate: ERR AC13: "
>> +						"qos-match-rule num %u: destination port-group '%s' not found\n",
>> +						i, str);
>> +					res = 1;
>> +					goto Exit;
>> +				}
>> +
>> +				cl_list_insert_tail(&p_qos_match_rule->
>> +						    destination_group_list,
>> +						    p_port_group);
>> +
>> +				list_iterator = cl_list_next(list_iterator);
>> +			}
>> +		}
>> +
>> +		/* done with the current match-rule */
>> +
>> +		match_rules_list_iterator =
>> +		    cl_list_next(match_rules_list_iterator);
>> +		i++;
>> +	}
>> +
>> +      Exit:
>> +	OSM_LOG_EXIT(p_qos_parser_osm_log);
>> +	return res;
>> +}				/* osm_qos_policy_validate() */
>> +
>> +/***************************************************
>> + ***************************************************/
>> +
>> +void osm_qos_policy_get_qos_level_by_pr(IN const osm_pr_rcv_t * p_rcv,
>> +					IN const ib_path_rec_t * p_pr,
>> +					IN const osm_physp_t * p_src_physp,
>> +					IN const osm_physp_t * p_dest_physp,
>> +					IN ib_net64_t comp_mask,
>> +					OUT osm_qos_level_t ** pp_qos_level)
>> +{
>> +	osm_qos_match_rule_t *p_qos_match_rule = NULL;
>> +	osm_qos_level_t *p_qos_level = NULL;
>> +
>> +	OSM_LOG_ENTER(p_rcv->p_log, osm_qos_policy_get_qos_level_by_pr);
>> +
>> +	*pp_qos_level = NULL;
>> +
>> +	if (!p_qos_policy)
>> +		goto Exit;
>> +
>> +	p_qos_match_rule = __qos_policy_get_match_rule_by_pr(p_rcv,
>> +							     p_pr,
>> +							     p_src_physp,
>> +							     p_dest_physp,
>> +							     comp_mask);
>> +
>> +	if (p_qos_match_rule)
>> +		p_qos_level = p_qos_match_rule->p_qos_level;
>> +	else
>> +		p_qos_level = p_qos_policy->p_default_qos_level;
>> +
>> +	osm_log(p_rcv->p_log, OSM_LOG_DEBUG,
>> +		"osm_qos_policy_get_qos_level_by_pr: "
>> +		"PathRecord request:"
>> +		"Src port 0x%016" PRIx64 ", "
>> +		"Dst port 0x%016" PRIx64 "\n",
>> +		cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
>> +		cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)));
>> +	osm_log(p_rcv->p_log, OSM_LOG_DEBUG,
>> +		"osm_qos_policy_get_qos_level_by_pr: "
>> +		"Applying QoS Level %s (%s)\n",
>> +		p_qos_level->name,
>> +		(p_qos_level->use) ? p_qos_level->use : "no description");
>> +
>> +	*pp_qos_level = p_qos_level;
>> +
>> +      Exit:
>> +	OSM_LOG_EXIT(p_rcv->p_log);
>> +}				/* osm_qos_policy_get_qos_level_by_pr() */
>> +
>> +/***************************************************
>> + ***************************************************/
>> -- 
>> 1.5.1.4
>>
> 




More information about the general mailing list