1231200Smm/*
2231200Smm * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3231200Smm * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4231200Smm * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5231200Smm * Copyright (c) 2008 Xsigo Systems Inc.  All rights reserved.
6231200Smm *
7231200Smm * This software is available to you under a choice of one of two
8231200Smm * licenses.  You may choose to be licensed under the terms of the GNU
9231200Smm * General Public License (GPL) Version 2, available from the file
10231200Smm * COPYING in the main directory of this source tree, or the
11231200Smm * OpenIB.org BSD license below:
12231200Smm *
13231200Smm *     Redistribution and use in source and binary forms, with or
14231200Smm *     without modification, are permitted provided that the following
15231200Smm *     conditions are met:
16231200Smm *
17231200Smm *      - Redistributions of source code must retain the above
18231200Smm *        copyright notice, this list of conditions and the following
19231200Smm *        disclaimer.
20231200Smm *
21231200Smm *      - Redistributions in binary form must reproduce the above
22231200Smm *        copyright notice, this list of conditions and the following
23231200Smm *        disclaimer in the documentation and/or other materials
24231200Smm *        provided with the distribution.
25231200Smm *
26231200Smm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27231200Smm * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28231200Smm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29231200Smm * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30231200Smm * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31231200Smm * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32231200Smm * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33231200Smm * SOFTWARE.
34231200Smm *
35231200Smm */
36232153Smm
37231200Smm/*
38231200Smm * Abstract:
39231200Smm *    OSM QoS Policy functions.
40231200Smm *
41231200Smm * Author:
42232153Smm *    Yevgeny Kliteynik, Mellanox
43231200Smm */
44231200Smm
45231200Smm#include <stdio.h>
46231200Smm#include <assert.h>
47231200Smm#include <stdlib.h>
48231200Smm#include <string.h>
49231200Smm#include <ctype.h>
50231200Smm#include <opensm/osm_log.h>
51232153Smm#include <opensm/osm_node.h>
52232153Smm#include <opensm/osm_port.h>
53231200Smm#include <opensm/osm_partition.h>
54232153Smm#include <opensm/osm_opensm.h>
55232153Smm#include <opensm/osm_qos_policy.h>
56231200Smm
57231200Smmextern osm_qos_level_t __default_simple_qos_level;
58231200Smm
59232153Smm/***************************************************
60232153Smm ***************************************************/
61231200Smm
62232153Smmstatic void
63232153Smm__build_nodebyname_hash(osm_qos_policy_t * p_qos_policy)
64231200Smm{
65232153Smm	osm_node_t * p_node;
66231200Smm	cl_qmap_t  * p_node_guid_tbl = &p_qos_policy->p_subn->node_guid_tbl;
67232153Smm
68232153Smm	p_qos_policy->p_node_hash = st_init_strtable();
69232153Smm	CL_ASSERT(p_qos_policy->p_node_hash);
70232153Smm
71231200Smm	if (!p_node_guid_tbl || !cl_qmap_count(p_node_guid_tbl))
72232153Smm		return;
73232153Smm
74232153Smm	for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl);
75232153Smm	     p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl);
76231200Smm	     p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item)) {
77232153Smm		if (!st_lookup(p_qos_policy->p_node_hash,
78232153Smm			      (st_data_t)p_node->print_desc, NULL))
79232153Smm			st_insert(p_qos_policy->p_node_hash,
80232153Smm				  (st_data_t)p_node->print_desc,
81231200Smm				  (st_data_t)p_node);
82232153Smm	}
83232153Smm}
84232153Smm
85232153Smm/***************************************************
86231200Smm ***************************************************/
87231200Smm
88231200Smmstatic boolean_t
89231200Smm__is_num_in_range_arr(uint64_t ** range_arr,
90231200Smm		  unsigned range_arr_len, uint64_t num)
91232153Smm{
92232153Smm	unsigned ind_1 = 0;
93232153Smm	unsigned ind_2 = range_arr_len - 1;
94232153Smm	unsigned ind_mid;
95231200Smm
96232153Smm	if (!range_arr || !range_arr_len)
97232153Smm		return FALSE;
98232153Smm
99232153Smm	while (ind_1 <= ind_2) {
100231200Smm	    if (num < range_arr[ind_1][0] || num > range_arr[ind_2][1])
101232153Smm		return FALSE;
102232153Smm	    else if (num <= range_arr[ind_1][1] || num >= range_arr[ind_2][0])
103232153Smm		return TRUE;
104232153Smm
105232153Smm	    ind_mid = ind_1 + (ind_2 - ind_1 + 1)/2;
106232153Smm
107232153Smm	    if (num < range_arr[ind_mid][0])
108232153Smm		ind_2 = ind_mid;
109231200Smm	    else if (num > range_arr[ind_mid][1])
110232153Smm		ind_1 = ind_mid;
111232153Smm	    else
112232153Smm		return TRUE;
113232153Smm
114232153Smm	    ind_1++;
115232153Smm	    ind_2--;
116232153Smm	}
117232153Smm
118232153Smm	return FALSE;
119248616Smm}
120231200Smm
121231200Smm/***************************************************
122231200Smm ***************************************************/
123231200Smm
124231200Smmstatic void __free_single_element(void *p_element, void *context)
125231200Smm{
126231200Smm	if (p_element)
127		free(p_element);
128}
129
130/***************************************************
131 ***************************************************/
132
133osm_qos_port_t *osm_qos_policy_port_create(osm_physp_t *p_physp)
134{
135	osm_qos_port_t *p =
136	    (osm_qos_port_t *) malloc(sizeof(osm_qos_port_t));
137	if (!p)
138		return NULL;
139	memset(p, 0, sizeof(osm_qos_port_t));
140
141	p->p_physp = p_physp;
142	return p;
143}
144
145/***************************************************
146 ***************************************************/
147
148osm_qos_port_group_t *osm_qos_policy_port_group_create()
149{
150	osm_qos_port_group_t *p =
151	    (osm_qos_port_group_t *) malloc(sizeof(osm_qos_port_group_t));
152	if (!p)
153		return NULL;
154
155	memset(p, 0, sizeof(osm_qos_port_group_t));
156	cl_qmap_init(&p->port_map);
157
158	return p;
159}
160
161/***************************************************
162 ***************************************************/
163
164void osm_qos_policy_port_group_destroy(osm_qos_port_group_t * p)
165{
166	osm_qos_port_t * p_port;
167	osm_qos_port_t * p_old_port;
168
169	if (!p)
170		return;
171
172	if (p->name)
173		free(p->name);
174	if (p->use)
175		free(p->use);
176
177	p_port = (osm_qos_port_t *) cl_qmap_head(&p->port_map);
178	while (p_port != (osm_qos_port_t *) cl_qmap_end(&p->port_map))
179	{
180		p_old_port = p_port;
181		p_port = (osm_qos_port_t *) cl_qmap_next(&p_port->map_item);
182		free(p_old_port);
183	}
184	cl_qmap_remove_all(&p->port_map);
185
186	free(p);
187}
188
189/***************************************************
190 ***************************************************/
191
192osm_qos_vlarb_scope_t *osm_qos_policy_vlarb_scope_create()
193{
194	osm_qos_vlarb_scope_t *p =
195	    (osm_qos_vlarb_scope_t *) malloc(sizeof(osm_qos_sl2vl_scope_t));
196	if (!p)
197		return NULL;
198
199	memset(p, 0, sizeof(osm_qos_vlarb_scope_t));
200
201	cl_list_init(&p->group_list, 10);
202	cl_list_init(&p->across_list, 10);
203	cl_list_init(&p->vlarb_high_list, 10);
204	cl_list_init(&p->vlarb_low_list, 10);
205
206	return p;
207}
208
209/***************************************************
210 ***************************************************/
211
212void osm_qos_policy_vlarb_scope_destroy(osm_qos_vlarb_scope_t * p)
213{
214	if (!p)
215		return;
216
217	cl_list_apply_func(&p->group_list, __free_single_element, NULL);
218	cl_list_apply_func(&p->across_list, __free_single_element, NULL);
219	cl_list_apply_func(&p->vlarb_high_list, __free_single_element, NULL);
220	cl_list_apply_func(&p->vlarb_low_list, __free_single_element, NULL);
221
222	cl_list_remove_all(&p->group_list);
223	cl_list_remove_all(&p->across_list);
224	cl_list_remove_all(&p->vlarb_high_list);
225	cl_list_remove_all(&p->vlarb_low_list);
226
227	cl_list_destroy(&p->group_list);
228	cl_list_destroy(&p->across_list);
229	cl_list_destroy(&p->vlarb_high_list);
230	cl_list_destroy(&p->vlarb_low_list);
231
232	free(p);
233}
234
235/***************************************************
236 ***************************************************/
237
238osm_qos_sl2vl_scope_t *osm_qos_policy_sl2vl_scope_create()
239{
240	osm_qos_sl2vl_scope_t *p =
241	    (osm_qos_sl2vl_scope_t *) malloc(sizeof(osm_qos_sl2vl_scope_t));
242	if (!p)
243		return NULL;
244
245	memset(p, 0, sizeof(osm_qos_sl2vl_scope_t));
246
247	cl_list_init(&p->group_list, 10);
248	cl_list_init(&p->across_from_list, 10);
249	cl_list_init(&p->across_to_list, 10);
250
251	return p;
252}
253
254/***************************************************
255 ***************************************************/
256
257void osm_qos_policy_sl2vl_scope_destroy(osm_qos_sl2vl_scope_t * p)
258{
259	if (!p)
260		return;
261
262	cl_list_apply_func(&p->group_list, __free_single_element, NULL);
263	cl_list_apply_func(&p->across_from_list, __free_single_element, NULL);
264	cl_list_apply_func(&p->across_to_list, __free_single_element, NULL);
265
266	cl_list_remove_all(&p->group_list);
267	cl_list_remove_all(&p->across_from_list);
268	cl_list_remove_all(&p->across_to_list);
269
270	cl_list_destroy(&p->group_list);
271	cl_list_destroy(&p->across_from_list);
272	cl_list_destroy(&p->across_to_list);
273
274	free(p);
275}
276
277/***************************************************
278 ***************************************************/
279
280osm_qos_level_t *osm_qos_policy_qos_level_create()
281{
282	osm_qos_level_t *p =
283	    (osm_qos_level_t *) malloc(sizeof(osm_qos_level_t));
284	if (!p)
285		return NULL;
286	memset(p, 0, sizeof(osm_qos_level_t));
287	return p;
288}
289
290/***************************************************
291 ***************************************************/
292
293void osm_qos_policy_qos_level_destroy(osm_qos_level_t * p)
294{
295	unsigned i;
296
297	if (!p)
298		return;
299
300	if (p->name)
301		free(p->name);
302	if (p->use)
303		free(p->use);
304
305	for (i = 0; i < p->path_bits_range_len; i++)
306		free(p->path_bits_range_arr[i]);
307	if (p->path_bits_range_arr)
308		free(p->path_bits_range_arr);
309
310	free(p);
311}
312
313/***************************************************
314 ***************************************************/
315
316boolean_t osm_qos_level_has_pkey(IN const osm_qos_level_t * p_qos_level,
317				 IN ib_net16_t pkey)
318{
319	if (!p_qos_level || !p_qos_level->pkey_range_len)
320		return FALSE;
321	return __is_num_in_range_arr(p_qos_level->pkey_range_arr,
322				     p_qos_level->pkey_range_len,
323				     cl_ntoh16(pkey));
324}
325
326/***************************************************
327 ***************************************************/
328
329ib_net16_t osm_qos_level_get_shared_pkey(IN const osm_qos_level_t * p_qos_level,
330					 IN const osm_physp_t * p_src_physp,
331					 IN const osm_physp_t * p_dest_physp)
332{
333	unsigned i;
334	uint16_t pkey_ho = 0;
335
336	if (!p_qos_level || !p_qos_level->pkey_range_len)
337		return 0;
338
339	/*
340	 * ToDo: This approach is not optimal.
341	 *       Think how to find shared pkey that also exists
342	 *       in QoS level in less runtime.
343	 */
344
345	for (i = 0; i < p_qos_level->pkey_range_len; i++) {
346		for (pkey_ho = p_qos_level->pkey_range_arr[i][0];
347		     pkey_ho <= p_qos_level->pkey_range_arr[i][1]; pkey_ho++) {
348			if (osm_physp_share_this_pkey
349			    (p_src_physp, p_dest_physp, cl_hton16(pkey_ho)))
350				return cl_hton16(pkey_ho);
351		}
352	}
353
354	return 0;
355}
356
357/***************************************************
358 ***************************************************/
359
360osm_qos_match_rule_t *osm_qos_policy_match_rule_create()
361{
362	osm_qos_match_rule_t *p =
363	    (osm_qos_match_rule_t *) malloc(sizeof(osm_qos_match_rule_t));
364	if (!p)
365		return NULL;
366
367	memset(p, 0, sizeof(osm_qos_match_rule_t));
368
369	cl_list_init(&p->source_list, 10);
370	cl_list_init(&p->source_group_list, 10);
371	cl_list_init(&p->destination_list, 10);
372	cl_list_init(&p->destination_group_list, 10);
373
374	return p;
375}
376
377/***************************************************
378 ***************************************************/
379
380void osm_qos_policy_match_rule_destroy(osm_qos_match_rule_t * p)
381{
382	unsigned i;
383
384	if (!p)
385		return;
386
387	if (p->qos_level_name)
388		free(p->qos_level_name);
389	if (p->use)
390		free(p->use);
391
392	for (i = 0; i < p->service_id_range_len; i++)
393		free(p->service_id_range_arr[i]);
394	if (p->service_id_range_arr)
395		free(p->service_id_range_arr);
396
397	for (i = 0; i < p->qos_class_range_len; i++)
398		free(p->qos_class_range_arr[i]);
399	if (p->qos_class_range_arr)
400		free(p->qos_class_range_arr);
401
402	for (i = 0; i < p->pkey_range_len; i++)
403		free(p->pkey_range_arr[i]);
404	if (p->pkey_range_arr)
405		free(p->pkey_range_arr);
406
407	cl_list_apply_func(&p->source_list, __free_single_element, NULL);
408	cl_list_remove_all(&p->source_list);
409	cl_list_destroy(&p->source_list);
410
411	cl_list_remove_all(&p->source_group_list);
412	cl_list_destroy(&p->source_group_list);
413
414	cl_list_apply_func(&p->destination_list, __free_single_element, NULL);
415	cl_list_remove_all(&p->destination_list);
416	cl_list_destroy(&p->destination_list);
417
418	cl_list_remove_all(&p->destination_group_list);
419	cl_list_destroy(&p->destination_group_list);
420
421	free(p);
422}
423
424/***************************************************
425 ***************************************************/
426
427osm_qos_policy_t * osm_qos_policy_create(osm_subn_t * p_subn)
428{
429	osm_qos_policy_t * p_qos_policy = (osm_qos_policy_t *)malloc(sizeof(osm_qos_policy_t));
430	if (!p_qos_policy)
431		return NULL;
432
433	memset(p_qos_policy, 0, sizeof(osm_qos_policy_t));
434
435	cl_list_construct(&p_qos_policy->port_groups);
436	cl_list_init(&p_qos_policy->port_groups, 10);
437
438	cl_list_construct(&p_qos_policy->vlarb_tables);
439	cl_list_init(&p_qos_policy->vlarb_tables, 10);
440
441	cl_list_construct(&p_qos_policy->sl2vl_tables);
442	cl_list_init(&p_qos_policy->sl2vl_tables, 10);
443
444	cl_list_construct(&p_qos_policy->qos_levels);
445	cl_list_init(&p_qos_policy->qos_levels, 10);
446
447	cl_list_construct(&p_qos_policy->qos_match_rules);
448	cl_list_init(&p_qos_policy->qos_match_rules, 10);
449
450	p_qos_policy->p_subn = p_subn;
451	__build_nodebyname_hash(p_qos_policy);
452
453	return p_qos_policy;
454}
455
456/***************************************************
457 ***************************************************/
458
459void osm_qos_policy_destroy(osm_qos_policy_t * p_qos_policy)
460{
461	cl_list_iterator_t list_iterator;
462	osm_qos_port_group_t *p_port_group = NULL;
463	osm_qos_vlarb_scope_t *p_vlarb_scope = NULL;
464	osm_qos_sl2vl_scope_t *p_sl2vl_scope = NULL;
465	osm_qos_level_t *p_qos_level = NULL;
466	osm_qos_match_rule_t *p_qos_match_rule = NULL;
467
468	if (!p_qos_policy)
469		return;
470
471	list_iterator = cl_list_head(&p_qos_policy->port_groups);
472	while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) {
473		p_port_group =
474		    (osm_qos_port_group_t *) cl_list_obj(list_iterator);
475		if (p_port_group)
476			osm_qos_policy_port_group_destroy(p_port_group);
477		list_iterator = cl_list_next(list_iterator);
478	}
479	cl_list_remove_all(&p_qos_policy->port_groups);
480	cl_list_destroy(&p_qos_policy->port_groups);
481
482	list_iterator = cl_list_head(&p_qos_policy->vlarb_tables);
483	while (list_iterator != cl_list_end(&p_qos_policy->vlarb_tables)) {
484		p_vlarb_scope =
485		    (osm_qos_vlarb_scope_t *) cl_list_obj(list_iterator);
486		if (p_vlarb_scope)
487			osm_qos_policy_vlarb_scope_destroy(p_vlarb_scope);
488		list_iterator = cl_list_next(list_iterator);
489	}
490	cl_list_remove_all(&p_qos_policy->vlarb_tables);
491	cl_list_destroy(&p_qos_policy->vlarb_tables);
492
493	list_iterator = cl_list_head(&p_qos_policy->sl2vl_tables);
494	while (list_iterator != cl_list_end(&p_qos_policy->sl2vl_tables)) {
495		p_sl2vl_scope =
496		    (osm_qos_sl2vl_scope_t *) cl_list_obj(list_iterator);
497		if (p_sl2vl_scope)
498			osm_qos_policy_sl2vl_scope_destroy(p_sl2vl_scope);
499		list_iterator = cl_list_next(list_iterator);
500	}
501	cl_list_remove_all(&p_qos_policy->sl2vl_tables);
502	cl_list_destroy(&p_qos_policy->sl2vl_tables);
503
504	list_iterator = cl_list_head(&p_qos_policy->qos_levels);
505	while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) {
506		p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator);
507		if (p_qos_level)
508			osm_qos_policy_qos_level_destroy(p_qos_level);
509		list_iterator = cl_list_next(list_iterator);
510	}
511	cl_list_remove_all(&p_qos_policy->qos_levels);
512	cl_list_destroy(&p_qos_policy->qos_levels);
513
514	list_iterator = cl_list_head(&p_qos_policy->qos_match_rules);
515	while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) {
516		p_qos_match_rule =
517		    (osm_qos_match_rule_t *) cl_list_obj(list_iterator);
518		if (p_qos_match_rule)
519			osm_qos_policy_match_rule_destroy(p_qos_match_rule);
520		list_iterator = cl_list_next(list_iterator);
521	}
522	cl_list_remove_all(&p_qos_policy->qos_match_rules);
523	cl_list_destroy(&p_qos_policy->qos_match_rules);
524
525	if (p_qos_policy->p_node_hash)
526		st_free_table(p_qos_policy->p_node_hash);
527
528	free(p_qos_policy);
529
530	p_qos_policy = NULL;
531}
532
533/***************************************************
534 ***************************************************/
535
536static boolean_t
537__qos_policy_is_port_in_group(osm_subn_t * p_subn,
538			      const osm_physp_t * p_physp,
539			      osm_qos_port_group_t * p_port_group)
540{
541	osm_node_t *p_node = osm_physp_get_node_ptr(p_physp);
542	ib_net64_t port_guid = osm_physp_get_port_guid(p_physp);
543	uint64_t port_guid_ho = cl_ntoh64(port_guid);
544
545	/* check whether this port's type matches any of group's types */
546
547	if ( p_port_group->node_types &
548	     (((uint8_t)1)<<osm_node_get_type(p_node)) )
549		return TRUE;
550
551	/* check whether this port's guid is in group's port map */
552
553	if (cl_qmap_get(&p_port_group->port_map, port_guid_ho) !=
554	    cl_qmap_end(&p_port_group->port_map))
555		return TRUE;
556
557	return FALSE;
558}				/* __qos_policy_is_port_in_group() */
559
560/***************************************************
561 ***************************************************/
562
563static boolean_t
564__qos_policy_is_port_in_group_list(const osm_qos_policy_t * p_qos_policy,
565				   const osm_physp_t * p_physp,
566				   cl_list_t * p_port_group_list)
567{
568	osm_qos_port_group_t *p_port_group;
569	cl_list_iterator_t list_iterator;
570
571	list_iterator = cl_list_head(p_port_group_list);
572	while (list_iterator != cl_list_end(p_port_group_list)) {
573		p_port_group =
574		    (osm_qos_port_group_t *) cl_list_obj(list_iterator);
575		if (p_port_group) {
576			if (__qos_policy_is_port_in_group
577			    (p_qos_policy->p_subn, p_physp, p_port_group))
578				return TRUE;
579		}
580		list_iterator = cl_list_next(list_iterator);
581	}
582	return FALSE;
583}
584
585/***************************************************
586 ***************************************************/
587
588static osm_qos_match_rule_t *__qos_policy_get_match_rule_by_params(
589			 const osm_qos_policy_t * p_qos_policy,
590			 uint64_t service_id,
591			 uint16_t qos_class,
592			 uint16_t pkey,
593			 const osm_physp_t * p_src_physp,
594			 const osm_physp_t * p_dest_physp,
595			 ib_net64_t comp_mask)
596{
597	osm_qos_match_rule_t *p_qos_match_rule = NULL;
598	cl_list_iterator_t list_iterator;
599	osm_log_t * p_log = &p_qos_policy->p_subn->p_osm->log;
600
601	boolean_t matched_by_sguid = FALSE,
602		  matched_by_dguid = FALSE,
603		  matched_by_class = FALSE,
604		  matched_by_sid = FALSE,
605		  matched_by_pkey = FALSE;
606
607	if (!cl_list_count(&p_qos_policy->qos_match_rules))
608		return NULL;
609
610	OSM_LOG_ENTER(p_log);
611
612	/* Go over all QoS match rules and find the one that matches the request */
613
614	list_iterator = cl_list_head(&p_qos_policy->qos_match_rules);
615	while (list_iterator != cl_list_end(&p_qos_policy->qos_match_rules)) {
616		p_qos_match_rule =
617		    (osm_qos_match_rule_t *) cl_list_obj(list_iterator);
618		if (!p_qos_match_rule) {
619			list_iterator = cl_list_next(list_iterator);
620			continue;
621		}
622
623		/* If a match rule has Source groups, PR request source has to be in this list */
624
625		if (cl_list_count(&p_qos_match_rule->source_group_list)) {
626			if (!__qos_policy_is_port_in_group_list(p_qos_policy,
627								p_src_physp,
628								&p_qos_match_rule->
629								source_group_list))
630			{
631				list_iterator = cl_list_next(list_iterator);
632				continue;
633			}
634			matched_by_sguid = TRUE;
635		}
636
637		/* If a match rule has Destination groups, PR request dest. has to be in this list */
638
639		if (cl_list_count(&p_qos_match_rule->destination_group_list)) {
640			if (!__qos_policy_is_port_in_group_list(p_qos_policy,
641								p_dest_physp,
642								&p_qos_match_rule->
643								destination_group_list))
644			{
645				list_iterator = cl_list_next(list_iterator);
646				continue;
647			}
648			matched_by_dguid = TRUE;
649		}
650
651		/* If a match rule has QoS classes, PR request HAS
652		   to have a matching QoS class to match the rule */
653
654		if (p_qos_match_rule->qos_class_range_len) {
655			if (!(comp_mask & IB_PR_COMPMASK_QOS_CLASS)) {
656				list_iterator = cl_list_next(list_iterator);
657				continue;
658			}
659
660			if (!__is_num_in_range_arr
661			    (p_qos_match_rule->qos_class_range_arr,
662			     p_qos_match_rule->qos_class_range_len,
663			     qos_class)) {
664				list_iterator = cl_list_next(list_iterator);
665				continue;
666			}
667			matched_by_class = TRUE;
668		}
669
670		/* If a match rule has Service IDs, PR request HAS
671		   to have a matching Service ID to match the rule */
672
673		if (p_qos_match_rule->service_id_range_len) {
674			if (!(comp_mask & IB_PR_COMPMASK_SERVICEID_MSB) ||
675			    !(comp_mask & IB_PR_COMPMASK_SERVICEID_LSB)) {
676				list_iterator = cl_list_next(list_iterator);
677				continue;
678			}
679
680			if (!__is_num_in_range_arr
681			    (p_qos_match_rule->service_id_range_arr,
682			     p_qos_match_rule->service_id_range_len,
683			     service_id)) {
684				list_iterator = cl_list_next(list_iterator);
685				continue;
686			}
687			matched_by_sid = TRUE;
688		}
689
690		/* If a match rule has PKeys, PR request HAS
691		   to have a matching PKey to match the rule */
692
693		if (p_qos_match_rule->pkey_range_len) {
694			if (!(comp_mask & IB_PR_COMPMASK_PKEY)) {
695				list_iterator = cl_list_next(list_iterator);
696				continue;
697			}
698
699			if (!__is_num_in_range_arr
700			    (p_qos_match_rule->pkey_range_arr,
701			     p_qos_match_rule->pkey_range_len,
702			     pkey & 0x7FFF)) {
703				list_iterator = cl_list_next(list_iterator);
704				continue;
705			}
706			matched_by_pkey = TRUE;
707		}
708
709		/* if we got here, then this match-rule matched this PR request */
710		break;
711	}
712
713	if (list_iterator == cl_list_end(&p_qos_policy->qos_match_rules))
714		p_qos_match_rule = NULL;
715
716	if (p_qos_match_rule)
717		OSM_LOG(p_log, OSM_LOG_DEBUG,
718			"request matched rule (%s) by:%s%s%s%s%s\n",
719			(p_qos_match_rule->use) ?
720				p_qos_match_rule->use : "no description",
721			(matched_by_sguid) ? " SGUID" : "",
722			(matched_by_dguid) ? " DGUID" : "",
723			(matched_by_class) ? " QoS_Class" : "",
724			(matched_by_sid)   ? " ServiceID" : "",
725			(matched_by_pkey)  ? " PKey" : "");
726	else
727		OSM_LOG(p_log, OSM_LOG_DEBUG,
728			"request not matched any rule\n");
729
730	OSM_LOG_EXIT(p_log);
731	return p_qos_match_rule;
732}				/* __qos_policy_get_match_rule_by_params() */
733
734/***************************************************
735 ***************************************************/
736
737static osm_qos_level_t *__qos_policy_get_qos_level_by_name(
738		const osm_qos_policy_t * p_qos_policy,
739		char *name)
740{
741	osm_qos_level_t *p_qos_level = NULL;
742	cl_list_iterator_t list_iterator;
743
744	list_iterator = cl_list_head(&p_qos_policy->qos_levels);
745	while (list_iterator != cl_list_end(&p_qos_policy->qos_levels)) {
746		p_qos_level = (osm_qos_level_t *) cl_list_obj(list_iterator);
747		if (!p_qos_level)
748			continue;
749
750		/* names are case INsensitive */
751		if (strcasecmp(name, p_qos_level->name) == 0)
752			return p_qos_level;
753
754		list_iterator = cl_list_next(list_iterator);
755	}
756
757	return NULL;
758}
759
760/***************************************************
761 ***************************************************/
762
763static osm_qos_port_group_t *__qos_policy_get_port_group_by_name(
764		const osm_qos_policy_t * p_qos_policy,
765		const char *const name)
766{
767	osm_qos_port_group_t *p_port_group = NULL;
768	cl_list_iterator_t list_iterator;
769
770	list_iterator = cl_list_head(&p_qos_policy->port_groups);
771	while (list_iterator != cl_list_end(&p_qos_policy->port_groups)) {
772		p_port_group =
773		    (osm_qos_port_group_t *) cl_list_obj(list_iterator);
774		if (!p_port_group)
775			continue;
776
777		/* names are case INsensitive */
778		if (strcasecmp(name, p_port_group->name) == 0)
779			return p_port_group;
780
781		list_iterator = cl_list_next(list_iterator);
782	}
783
784	return NULL;
785}
786
787/***************************************************
788 ***************************************************/
789
790static void __qos_policy_validate_pkey(
791			osm_qos_policy_t * p_qos_policy,
792			osm_qos_match_rule_t * p_qos_match_rule,
793			osm_prtn_t * p_prtn)
794{
795	uint8_t sl;
796	uint32_t flow;
797	uint8_t hop;
798	osm_mgrp_t * p_mgrp;
799
800	if (!p_qos_policy || !p_qos_match_rule || !p_prtn)
801		return;
802
803	if (!p_qos_match_rule->p_qos_level->sl_set ||
804	    p_prtn->sl == p_qos_match_rule->p_qos_level->sl)
805		return;
806
807	/* overriding partition's SL */
808	OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_ERROR,
809		"ERR AC15: pkey 0x%04X in match rule - "
810		"overriding partition SL (%u) with QoS Level SL (%u)\n",
811		cl_ntoh16(p_prtn->pkey), p_prtn->sl,
812		p_qos_match_rule->p_qos_level->sl);
813	p_prtn->sl = p_qos_match_rule->p_qos_level->sl;
814
815
816	/* If this partition is an IPoIB partition, there should
817	   be a matching MCast group. Fix this group's SL too */
818
819	if (!p_prtn->mlid)
820		return;
821
822	p_mgrp = osm_get_mgrp_by_mlid(p_qos_policy->p_subn, p_prtn->mlid);
823	if (!p_mgrp) {
824		OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_ERROR,
825			"ERR AC16: MCast group for partition with "
826			"pkey 0x%04X not found\n",
827			cl_ntoh16(p_prtn->pkey));
828		return;
829	}
830
831	CL_ASSERT((cl_ntoh16(p_mgrp->mcmember_rec.pkey) & 0x7fff) ==
832		  (cl_ntoh16(p_prtn->pkey) & 0x7fff));
833
834	ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
835				  &sl, &flow, &hop);
836	if (sl != p_prtn->sl) {
837		OSM_LOG(&p_qos_policy->p_subn->p_osm->log, OSM_LOG_DEBUG,
838			"Updating MCGroup (MLID 0x%04x) SL to "
839			"match partition SL (%u)\n",
840			cl_hton16(p_mgrp->mcmember_rec.mlid),
841			p_prtn->sl);
842		p_mgrp->mcmember_rec.sl_flow_hop =
843			ib_member_set_sl_flow_hop(p_prtn->sl, flow, hop);
844	}
845}
846
847/***************************************************
848 ***************************************************/
849
850int osm_qos_policy_validate(osm_qos_policy_t * p_qos_policy,
851			    osm_log_t *p_log)
852{
853	cl_list_iterator_t match_rules_list_iterator;
854	cl_list_iterator_t list_iterator;
855	osm_qos_port_group_t *p_port_group = NULL;
856	osm_qos_match_rule_t *p_qos_match_rule = NULL;
857	char *str;
858	unsigned i, j;
859	int res = 0;
860	uint64_t pkey_64;
861	ib_net16_t pkey;
862	osm_prtn_t * p_prtn;
863
864	OSM_LOG_ENTER(p_log);
865
866	/* set default qos level */
867
868	p_qos_policy->p_default_qos_level =
869	    __qos_policy_get_qos_level_by_name(p_qos_policy, OSM_QOS_POLICY_DEFAULT_LEVEL_NAME);
870	if (!p_qos_policy->p_default_qos_level) {
871		/* There's no default QoS level in the usual qos-level section.
872		   Check whether the 'simple' default QoS level that can be
873		   defined in the qos-ulp section exists */
874		if (__default_simple_qos_level.sl_set) {
875			p_qos_policy->p_default_qos_level = &__default_simple_qos_level;
876		}
877		else {
878			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC10: "
879				"Default qos-level (%s) not defined.\n",
880				OSM_QOS_POLICY_DEFAULT_LEVEL_NAME);
881			res = 1;
882			goto Exit;
883		}
884	}
885
886	/* scan all the match rules, and fill the lists of pointers to
887	   relevant qos levels and port groups to speed up PR matching */
888
889	i = 1;
890	match_rules_list_iterator =
891	    cl_list_head(&p_qos_policy->qos_match_rules);
892	while (match_rules_list_iterator !=
893	       cl_list_end(&p_qos_policy->qos_match_rules)) {
894		p_qos_match_rule =
895		    (osm_qos_match_rule_t *)
896		    cl_list_obj(match_rules_list_iterator);
897		CL_ASSERT(p_qos_match_rule);
898
899		/* find the matching qos-level for each match-rule */
900
901		if (!p_qos_match_rule->p_qos_level)
902			p_qos_match_rule->p_qos_level =
903				__qos_policy_get_qos_level_by_name(p_qos_policy,
904					       p_qos_match_rule->qos_level_name);
905
906		if (!p_qos_match_rule->p_qos_level) {
907			OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC11: "
908				"qos-match-rule num %u: qos-level '%s' not found\n",
909				i, p_qos_match_rule->qos_level_name);
910			res = 1;
911			goto Exit;
912		}
913
914		/* find the matching port-group for element of source_list */
915
916		if (cl_list_count(&p_qos_match_rule->source_list)) {
917			list_iterator =
918			    cl_list_head(&p_qos_match_rule->source_list);
919			while (list_iterator !=
920			       cl_list_end(&p_qos_match_rule->source_list)) {
921				str = (char *)cl_list_obj(list_iterator);
922				CL_ASSERT(str);
923
924				p_port_group =
925				    __qos_policy_get_port_group_by_name(p_qos_policy, str);
926				if (!p_port_group) {
927					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC12: "
928						"qos-match-rule num %u: source port-group '%s' not found\n",
929						i, str);
930					res = 1;
931					goto Exit;
932				}
933
934				cl_list_insert_tail(&p_qos_match_rule->
935						    source_group_list,
936						    p_port_group);
937
938				list_iterator = cl_list_next(list_iterator);
939			}
940		}
941
942		/* find the matching port-group for element of destination_list */
943
944		if (cl_list_count(&p_qos_match_rule->destination_list)) {
945			list_iterator =
946			    cl_list_head(&p_qos_match_rule->destination_list);
947			while (list_iterator !=
948			       cl_list_end(&p_qos_match_rule->
949					   destination_list)) {
950				str = (char *)cl_list_obj(list_iterator);
951				CL_ASSERT(str);
952
953				p_port_group =
954				    __qos_policy_get_port_group_by_name(p_qos_policy,str);
955				if (!p_port_group) {
956					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC13: "
957						"qos-match-rule num %u: destination port-group '%s' not found\n",
958						i, str);
959					res = 1;
960					goto Exit;
961				}
962
963				cl_list_insert_tail(&p_qos_match_rule->
964						    destination_group_list,
965						    p_port_group);
966
967				list_iterator = cl_list_next(list_iterator);
968			}
969		}
970
971		/*
972		 * Scan all the pkeys in matching rule, and if the
973		 * partition for these pkeys exists, set the SL
974		 * according to the QoS Level.
975		 * Warn if there's mismatch between QoS level SL
976		 * and Partition SL.
977		 */
978
979		for (j = 0; j < p_qos_match_rule->pkey_range_len; j++) {
980			for ( pkey_64 = p_qos_match_rule->pkey_range_arr[j][0];
981			      pkey_64 <= p_qos_match_rule->pkey_range_arr[j][1];
982			      pkey_64++) {
983                                pkey = cl_hton16((uint16_t)(pkey_64 & 0x7fff));
984				p_prtn = (osm_prtn_t *)cl_qmap_get(
985					&p_qos_policy->p_subn->prtn_pkey_tbl, pkey);
986
987				if (p_prtn == (osm_prtn_t *)cl_qmap_end(
988					&p_qos_policy->p_subn->prtn_pkey_tbl))
989					/* partition for this pkey not found */
990					OSM_LOG(p_log, OSM_LOG_ERROR, "ERR AC14: "
991						"pkey 0x%04X in match rule - "
992						"partition doesn't exist\n",
993						cl_ntoh16(pkey));
994				else
995					__qos_policy_validate_pkey(p_qos_policy,
996							p_qos_match_rule,
997							p_prtn);
998			}
999		}
1000
1001		/* done with the current match-rule */
1002
1003		match_rules_list_iterator =
1004		    cl_list_next(match_rules_list_iterator);
1005		i++;
1006	}
1007
1008Exit:
1009	OSM_LOG_EXIT(p_log);
1010	return res;
1011}				/* osm_qos_policy_validate() */
1012
1013/***************************************************
1014 ***************************************************/
1015
1016static osm_qos_level_t * __qos_policy_get_qos_level_by_params(
1017	IN const osm_qos_policy_t * p_qos_policy,
1018	IN const osm_physp_t * p_src_physp,
1019	IN const osm_physp_t * p_dest_physp,
1020	IN uint64_t service_id,
1021	IN uint16_t qos_class,
1022	IN uint16_t pkey,
1023	IN ib_net64_t comp_mask)
1024{
1025	osm_qos_match_rule_t *p_qos_match_rule = NULL;
1026
1027	if (!p_qos_policy)
1028		return NULL;
1029
1030	p_qos_match_rule = __qos_policy_get_match_rule_by_params(
1031		p_qos_policy, service_id, qos_class, pkey,
1032		p_src_physp, p_dest_physp, comp_mask);
1033
1034	return p_qos_match_rule ? p_qos_match_rule->p_qos_level :
1035		p_qos_policy->p_default_qos_level;
1036}				/* __qos_policy_get_qos_level_by_params() */
1037
1038/***************************************************
1039 ***************************************************/
1040
1041osm_qos_level_t * osm_qos_policy_get_qos_level_by_pr(
1042	IN const osm_qos_policy_t * p_qos_policy,
1043	IN const ib_path_rec_t * p_pr,
1044	IN const osm_physp_t * p_src_physp,
1045	IN const osm_physp_t * p_dest_physp,
1046	IN ib_net64_t comp_mask)
1047{
1048	return __qos_policy_get_qos_level_by_params(
1049		p_qos_policy, p_src_physp, p_dest_physp,
1050		cl_ntoh64(p_pr->service_id), ib_path_rec_qos_class(p_pr),
1051		cl_ntoh16(p_pr->pkey), comp_mask);
1052}
1053
1054/***************************************************
1055 ***************************************************/
1056
1057osm_qos_level_t * osm_qos_policy_get_qos_level_by_mpr(
1058	IN const osm_qos_policy_t * p_qos_policy,
1059	IN const ib_multipath_rec_t * p_mpr,
1060	IN const osm_physp_t * p_src_physp,
1061	IN const osm_physp_t * p_dest_physp,
1062	IN ib_net64_t comp_mask)
1063{
1064	ib_net64_t pr_comp_mask = 0;
1065
1066	if (!p_qos_policy)
1067		return NULL;
1068
1069	/*
1070	 * Converting MultiPathRecord compmask to the PathRecord
1071	 * compmask. Note that only relevant bits are set.
1072	 */
1073	pr_comp_mask =
1074		((comp_mask & IB_MPR_COMPMASK_QOS_CLASS) ?
1075		 IB_PR_COMPMASK_QOS_CLASS : 0) |
1076		((comp_mask & IB_MPR_COMPMASK_PKEY) ?
1077		 IB_PR_COMPMASK_PKEY : 0) |
1078		((comp_mask & IB_MPR_COMPMASK_SERVICEID_MSB) ?
1079		 IB_PR_COMPMASK_SERVICEID_MSB : 0) |
1080		((comp_mask & IB_MPR_COMPMASK_SERVICEID_LSB) ?
1081		 IB_PR_COMPMASK_SERVICEID_LSB : 0);
1082
1083	return __qos_policy_get_qos_level_by_params(
1084		p_qos_policy, p_src_physp, p_dest_physp,
1085		cl_ntoh64(ib_multipath_rec_service_id(p_mpr)),
1086		ib_multipath_rec_qos_class(p_mpr),
1087		cl_ntoh16(p_mpr->pkey), pr_comp_mask);
1088}
1089
1090/***************************************************
1091 ***************************************************/
1092