]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/ofed/management/opensm/opensm/osm_qos_policy.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / ofed / management / opensm / opensm / osm_qos_policy.c
1 /*
2  * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 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  *
7  * This software is available to you under a choice of one of two
8  * licenses.  You may choose to be licensed under the terms of the GNU
9  * General Public License (GPL) Version 2, available from the file
10  * COPYING in the main directory of this source tree, or the
11  * OpenIB.org BSD license below:
12  *
13  *     Redistribution and use in source and binary forms, with or
14  *     without modification, are permitted provided that the following
15  *     conditions are met:
16  *
17  *      - Redistributions of source code must retain the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer.
20  *
21  *      - Redistributions in binary form must reproduce the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer in the documentation and/or other materials
24  *        provided with the distribution.
25  *
26  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33  * SOFTWARE.
34  *
35  */
36
37 /*
38  * Abstract:
39  *    OSM QoS Policy functions.
40  *
41  * Author:
42  *    Yevgeny Kliteynik, Mellanox
43  */
44
45 #include <stdio.h>
46 #include <assert.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <ctype.h>
50 #include <opensm/osm_log.h>
51 #include <opensm/osm_node.h>
52 #include <opensm/osm_port.h>
53 #include <opensm/osm_partition.h>
54 #include <opensm/osm_opensm.h>
55 #include <opensm/osm_qos_policy.h>
56
57 extern osm_qos_level_t __default_simple_qos_level;
58
59 /***************************************************
60  ***************************************************/
61
62 static void
63 __build_nodebyname_hash(osm_qos_policy_t * p_qos_policy)
64 {
65         osm_node_t * p_node;
66         cl_qmap_t  * p_node_guid_tbl = &p_qos_policy->p_subn->node_guid_tbl;
67
68         p_qos_policy->p_node_hash = st_init_strtable();
69         CL_ASSERT(p_qos_policy->p_node_hash);
70
71         if (!p_node_guid_tbl || !cl_qmap_count(p_node_guid_tbl))
72                 return;
73
74         for (p_node = (osm_node_t *) cl_qmap_head(p_node_guid_tbl);
75              p_node != (osm_node_t *) cl_qmap_end(p_node_guid_tbl);
76              p_node = (osm_node_t *) cl_qmap_next(&p_node->map_item)) {
77                 if (!st_lookup(p_qos_policy->p_node_hash,
78                               (st_data_t)p_node->print_desc, NULL))
79                         st_insert(p_qos_policy->p_node_hash,
80                                   (st_data_t)p_node->print_desc,
81                                   (st_data_t)p_node);
82         }
83 }
84
85 /***************************************************
86  ***************************************************/
87
88 static boolean_t
89 __is_num_in_range_arr(uint64_t ** range_arr,
90                   unsigned range_arr_len, uint64_t num)
91 {
92         unsigned ind_1 = 0;
93         unsigned ind_2 = range_arr_len - 1;
94         unsigned ind_mid;
95
96         if (!range_arr || !range_arr_len)
97                 return FALSE;
98
99         while (ind_1 <= ind_2) {
100             if (num < range_arr[ind_1][0] || num > range_arr[ind_2][1])
101                 return FALSE;
102             else if (num <= range_arr[ind_1][1] || num >= range_arr[ind_2][0])
103                 return TRUE;
104
105             ind_mid = ind_1 + (ind_2 - ind_1 + 1)/2;
106
107             if (num < range_arr[ind_mid][0])
108                 ind_2 = ind_mid;
109             else if (num > range_arr[ind_mid][1])
110                 ind_1 = ind_mid;
111             else
112                 return TRUE;
113
114             ind_1++;
115             ind_2--;
116         }
117
118         return FALSE;
119 }
120
121 /***************************************************
122  ***************************************************/
123
124 static void __free_single_element(void *p_element, void *context)
125 {
126         if (p_element)
127                 free(p_element);
128 }
129
130 /***************************************************
131  ***************************************************/
132
133 osm_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
148 osm_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
164 void 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
192 osm_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
212 void 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
238 osm_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
257 void 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
280 osm_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
293 void 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
316 boolean_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
329 ib_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
360 osm_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
380 void 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
427 osm_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
459 void 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
536 static 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
563 static 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
588 static 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
737 static 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
763 static 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
790 static 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
850 int 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
1008 Exit:
1009         OSM_LOG_EXIT(p_log);
1010         return res;
1011 }                               /* osm_qos_policy_validate() */
1012
1013 /***************************************************
1014  ***************************************************/
1015
1016 static 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
1041 osm_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
1057 osm_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  ***************************************************/