]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_qos_policy.c
MFV r353623: 10473 zfs(1M) missing cross-reference to zfs-program(1M)
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_qos_policy.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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  ***************************************************/