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