1 /*
2 * Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 * Copyright (c) 2013 Oracle and/or its affiliates. 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 * Implementation of osm_mpr_rcv_t.
40 * This object represents the MultiPath Record Receiver object.
41 * This object is part of the opensm family of objects.
42 */
43
44 #if HAVE_CONFIG_H
45 # include <config.h>
46 #endif /* HAVE_CONFIG_H */
47
48 #if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
49
50 #include <string.h>
51 #include <iba/ib_types.h>
52 #include <complib/cl_qmap.h>
53 #include <complib/cl_passivelock.h>
54 #include <complib/cl_debug.h>
55 #include <complib/cl_qlist.h>
56 #include <opensm/osm_file_ids.h>
57 #define FILE_ID OSM_FILE_SA_MULTIPATH_RECORD_C
58 #include <vendor/osm_vendor_api.h>
59 #include <opensm/osm_port.h>
60 #include <opensm/osm_node.h>
61 #include <opensm/osm_switch.h>
62 #include <opensm/osm_partition.h>
63 #include <opensm/osm_helper.h>
64 #include <opensm/osm_qos_policy.h>
65 #include <opensm/osm_sa.h>
66
67 #define OSM_SA_MPR_MAX_NUM_PATH 127
68 #define MAX_HOPS 64
69
70 #define SA_MPR_RESP_SIZE SA_ITEM_RESP_SIZE(mpr_rec)
71
sa_multipath_rec_is_tavor_port(IN const osm_port_t * p_port)72 static boolean_t sa_multipath_rec_is_tavor_port(IN const osm_port_t * p_port)
73 {
74 osm_node_t const *p_node;
75 ib_net32_t vend_id;
76
77 p_node = p_port->p_node;
78 vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
79
80 return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
81 ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
82 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
83 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
84 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
85 }
86
87 static boolean_t
sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * p_mpr,IN const osm_port_t * p_src_port,IN const osm_port_t * p_dest_port,IN const ib_net64_t comp_mask)88 sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * p_mpr,
89 IN const osm_port_t * p_src_port,
90 IN const osm_port_t * p_dest_port,
91 IN const ib_net64_t comp_mask)
92 {
93 uint8_t required_mtu;
94
95 /* only if at least one of the ports is a Tavor device */
96 if (!sa_multipath_rec_is_tavor_port(p_src_port) &&
97 !sa_multipath_rec_is_tavor_port(p_dest_port))
98 return FALSE;
99
100 /*
101 we can apply the patch if either:
102 1. No MTU required
103 2. Required MTU <
104 3. Required MTU = 1K or 512 or 256
105 4. Required MTU > 256 or 512
106 */
107 required_mtu = ib_multipath_rec_mtu(p_mpr);
108 if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
109 (comp_mask & IB_MPR_COMPMASK_MTU)) {
110 switch (ib_multipath_rec_mtu_sel(p_mpr)) {
111 case 0: /* must be greater than */
112 case 2: /* exact match */
113 if (IB_MTU_LEN_1024 < required_mtu)
114 return FALSE;
115 break;
116
117 case 1: /* must be less than */
118 /* can't be disqualified by this one */
119 break;
120
121 case 3: /* largest available */
122 /* the ULP intentionally requested */
123 /* the largest MTU possible */
124 return FALSE;
125 break;
126
127 default:
128 /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
129 CL_ASSERT(FALSE);
130 break;
131 }
132 }
133
134 return TRUE;
135 }
136
mpr_rcv_get_path_parms(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN const uint16_t src_lid_ho,IN const uint16_t dest_lid_ho,IN const ib_net64_t comp_mask,OUT osm_path_parms_t * p_parms)137 static ib_api_status_t mpr_rcv_get_path_parms(IN osm_sa_t * sa,
138 IN const ib_multipath_rec_t *
139 p_mpr,
140 IN const osm_alias_guid_t * p_src_alias_guid,
141 IN const osm_alias_guid_t * p_dest_alias_guid,
142 IN const uint16_t src_lid_ho,
143 IN const uint16_t dest_lid_ho,
144 IN const ib_net64_t comp_mask,
145 OUT osm_path_parms_t * p_parms)
146 {
147 const osm_node_t *p_node;
148 const osm_physp_t *p_physp, *p_physp0;
149 const osm_physp_t *p_src_physp;
150 const osm_physp_t *p_dest_physp;
151 const osm_prtn_t *p_prtn = NULL;
152 const ib_port_info_t *p_pi, *p_pi0;
153 ib_slvl_table_t *p_slvl_tbl;
154 ib_api_status_t status = IB_SUCCESS;
155 uint8_t mtu;
156 uint8_t rate, p0_extended_rate, dest_rate;
157 uint8_t pkt_life;
158 uint8_t required_mtu;
159 uint8_t required_rate;
160 ib_net16_t required_pkey;
161 uint8_t required_sl;
162 uint8_t required_pkt_life;
163 ib_net16_t dest_lid;
164 int hops = 0;
165 int in_port_num = 0;
166 uint8_t i;
167 osm_qos_level_t *p_qos_level = NULL;
168 uint16_t valid_sl_mask = 0xffff;
169 int extended, p0_extended;
170
171 OSM_LOG_ENTER(sa->p_log);
172
173 dest_lid = cl_hton16(dest_lid_ho);
174
175 p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
176 p_physp = p_src_alias_guid->p_base_port->p_physp;
177 p_src_physp = p_physp;
178 p_pi = &p_physp->port_info;
179
180 mtu = ib_port_info_get_mtu_cap(p_pi);
181 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
182 rate = ib_port_info_compute_rate(p_pi, extended);
183
184 /*
185 Mellanox Tavor device performance is better using 1K MTU.
186 If required MTU and MTU selector are such that 1K is OK
187 and at least one end of the path is Tavor we override the
188 port MTU with 1K.
189 */
190 if (sa->p_subn->opt.enable_quirks &&
191 sa_multipath_rec_apply_tavor_mtu_limit(p_mpr,
192 p_src_alias_guid->p_base_port,
193 p_dest_alias_guid->p_base_port,
194 comp_mask))
195 if (mtu > IB_MTU_LEN_1024) {
196 mtu = IB_MTU_LEN_1024;
197 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
198 "Optimized Path MTU to 1K for Mellanox Tavor device\n");
199 }
200
201 /*
202 Walk the subnet object from source to destination,
203 tracking the most restrictive rate and mtu values along the way...
204
205 If source port node is a switch, then p_physp should
206 point to the port that routes the destination lid
207 */
208
209 p_node = osm_physp_get_node_ptr(p_physp);
210
211 if (p_node->sw) {
212 /*
213 * Source node is a switch.
214 * Make sure that p_physp points to the out port of the
215 * switch that routes to the destination lid (dest_lid_ho)
216 */
217 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
218 if (p_physp == 0) {
219 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4514: "
220 "Can't find routing from LID %u to LID %u on "
221 "switch %s (GUID 0x%016" PRIx64 ")\n",
222 src_lid_ho, dest_lid_ho, p_node->print_desc,
223 cl_ntoh64(osm_node_get_node_guid(p_node)));
224 status = IB_NOT_FOUND;
225 goto Exit;
226 }
227 }
228
229 if (sa->p_subn->opt.qos) {
230
231 /*
232 * Whether this node is switch or CA, the IN port for
233 * the sl2vl table is 0, because this is a source node.
234 */
235 p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
236
237 /* update valid SLs that still exist on this route */
238 for (i = 0; i < IB_MAX_NUM_VLS; i++) {
239 if (valid_sl_mask & (1 << i) &&
240 ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
241 valid_sl_mask &= ~(1 << i);
242 }
243 if (!valid_sl_mask) {
244 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
245 "All the SLs lead to VL15 on this path\n");
246 status = IB_NOT_FOUND;
247 goto Exit;
248 }
249 }
250
251 /*
252 * Same as above
253 */
254 p_node = osm_physp_get_node_ptr(p_dest_physp);
255
256 if (p_node->sw) {
257 /*
258 * if destination is switch, we want p_dest_physp to point to port 0
259 */
260 p_dest_physp =
261 osm_switch_get_route_by_lid(p_node->sw, dest_lid);
262
263 if (p_dest_physp == 0) {
264 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4515: "
265 "Can't find routing from LID %u to LID %u on "
266 "switch %s (GUID 0x%016" PRIx64 ")\n",
267 src_lid_ho, dest_lid_ho, p_node->print_desc,
268 cl_ntoh64(osm_node_get_node_guid(p_node)));
269 status = IB_NOT_FOUND;
270 goto Exit;
271 }
272
273 }
274
275 /*
276 * Now go through the path step by step
277 */
278
279 while (p_physp != p_dest_physp) {
280
281 int tmp_pnum = p_physp->port_num;
282 p_node = osm_physp_get_node_ptr(p_physp);
283 p_physp = osm_physp_get_remote(p_physp);
284
285 if (p_physp == 0) {
286 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4505: "
287 "Can't find remote phys port of %s (GUID "
288 "0x%016" PRIx64 ") port %d "
289 "while routing from LID %u to LID %u",
290 p_node->print_desc,
291 cl_ntoh64(osm_node_get_node_guid(p_node)),
292 tmp_pnum, src_lid_ho, dest_lid_ho);
293 status = IB_ERROR;
294 goto Exit;
295 }
296
297 /* update number of hops traversed */
298 hops++;
299 if (hops > MAX_HOPS) {
300 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4520: "
301 "Path from GUID 0x%016" PRIx64 " (%s) to"
302 " lid %u GUID 0x%016" PRIx64 " (%s) needs"
303 " more than %d hops, max %d hops allowed\n",
304 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
305 p_src_physp->p_node->print_desc, dest_lid_ho,
306 cl_ntoh64(osm_physp_get_port_guid
307 (p_dest_physp)),
308 p_dest_physp->p_node->print_desc, hops,
309 MAX_HOPS);
310 status = IB_NOT_FOUND;
311 goto Exit;
312 }
313
314 in_port_num = osm_physp_get_port_num(p_physp);
315
316 /*
317 This is point to point case (no switch in between)
318 */
319 if (p_physp == p_dest_physp)
320 break;
321
322 p_node = osm_physp_get_node_ptr(p_physp);
323
324 if (!p_node->sw) {
325 /*
326 There is some sort of problem in the subnet object!
327 If this isn't a switch, we should have reached
328 the destination by now!
329 */
330 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4503: "
331 "Internal error, bad path while routing "
332 "from %s (GUID: 0x%016"PRIx64") port %d "
333 "to %s (GUID: 0x%016"PRIx64") port %d; "
334 "ended at %s port %d\n",
335 p_src_alias_guid->p_base_port->p_node->print_desc,
336 cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
337 p_src_alias_guid->p_base_port->p_physp->port_num,
338 p_dest_alias_guid->p_base_port->p_node->print_desc,
339 cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
340 p_dest_alias_guid->p_base_port->p_physp->port_num,
341 p_node->print_desc,
342 p_physp->port_num);
343 status = IB_ERROR;
344 goto Exit;
345 }
346
347 /*
348 Check parameters for the ingress port in this switch.
349 */
350 p_pi = &p_physp->port_info;
351
352 if (mtu > ib_port_info_get_mtu_cap(p_pi))
353 mtu = ib_port_info_get_mtu_cap(p_pi);
354
355 p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
356 p_pi0 = &p_physp0->port_info;
357 p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
358 p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
359 if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
360 rate = p0_extended_rate;
361
362 /*
363 Continue with the egress port on this switch.
364 */
365 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
366 if (p_physp == 0) {
367 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4516: "
368 "Dead end path on switch "
369 "%s (GUID: 0x%016"PRIx64") to LID %u\n",
370 p_node->print_desc,
371 cl_ntoh64(osm_node_get_node_guid(p_node)),
372 dest_lid_ho);
373 status = IB_ERROR;
374 goto Exit;
375 }
376
377 p_pi = &p_physp->port_info;
378
379 if (mtu > ib_port_info_get_mtu_cap(p_pi))
380 mtu = ib_port_info_get_mtu_cap(p_pi);
381
382 p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
383 p_pi0 = &p_physp0->port_info;
384 p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
385 p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
386 if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
387 rate = p0_extended_rate;
388
389 if (sa->p_subn->opt.qos) {
390 /*
391 * Check SL2VL table of the switch and update valid SLs
392 */
393 p_slvl_tbl =
394 osm_physp_get_slvl_tbl(p_physp, in_port_num);
395 for (i = 0; i < IB_MAX_NUM_VLS; i++) {
396 if (valid_sl_mask & (1 << i) &&
397 ib_slvl_table_get(p_slvl_tbl,
398 i) == IB_DROP_VL)
399 valid_sl_mask &= ~(1 << i);
400 }
401 if (!valid_sl_mask) {
402 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
403 "All the SLs lead to VL15 "
404 "on this path\n");
405 status = IB_NOT_FOUND;
406 goto Exit;
407 }
408 }
409 }
410
411 /*
412 p_physp now points to the destination
413 */
414 p_pi = &p_physp->port_info;
415
416 if (mtu > ib_port_info_get_mtu_cap(p_pi))
417 mtu = ib_port_info_get_mtu_cap(p_pi);
418
419 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
420 dest_rate = ib_port_info_compute_rate(p_pi, extended);
421 if (ib_path_compare_rates(rate, dest_rate) > 0)
422 rate = dest_rate;
423
424 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
425 "Path min MTU = %u, min rate = %u\n", mtu, rate);
426
427 /*
428 * Get QoS Level object according to the MultiPath request
429 * and adjust MultiPath parameters according to QoS settings
430 */
431 if (sa->p_subn->opt.qos && sa->p_subn->p_qos_policy &&
432 (p_qos_level =
433 osm_qos_policy_get_qos_level_by_mpr(sa->p_subn->p_qos_policy,
434 p_mpr, p_src_physp,
435 p_dest_physp, comp_mask))) {
436
437 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
438 "MultiPathRecord request matches QoS Level '%s' (%s)\n",
439 p_qos_level->name,
440 p_qos_level->use ? p_qos_level->use : "no description");
441
442 if (p_qos_level->mtu_limit_set
443 && (mtu > p_qos_level->mtu_limit))
444 mtu = p_qos_level->mtu_limit;
445
446 if (p_qos_level->rate_limit_set
447 && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
448 rate = p_qos_level->rate_limit;
449
450 if (p_qos_level->sl_set) {
451 required_sl = p_qos_level->sl;
452 if (!(valid_sl_mask & (1 << required_sl))) {
453 status = IB_NOT_FOUND;
454 goto Exit;
455 }
456 }
457 }
458
459 /*
460 Determine if these values meet the user criteria
461 */
462
463 /* we silently ignore cases where only the MTU selector is defined */
464 if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
465 (comp_mask & IB_MPR_COMPMASK_MTU)) {
466 required_mtu = ib_multipath_rec_mtu(p_mpr);
467 switch (ib_multipath_rec_mtu_sel(p_mpr)) {
468 case 0: /* must be greater than */
469 if (mtu <= required_mtu)
470 status = IB_NOT_FOUND;
471 break;
472
473 case 1: /* must be less than */
474 if (mtu >= required_mtu) {
475 /* adjust to use the highest mtu
476 lower then the required one */
477 if (required_mtu > 1)
478 mtu = required_mtu - 1;
479 else
480 status = IB_NOT_FOUND;
481 }
482 break;
483
484 case 2: /* exact match */
485 if (mtu < required_mtu)
486 status = IB_NOT_FOUND;
487 else
488 mtu = required_mtu;
489 break;
490
491 case 3: /* largest available */
492 /* can't be disqualified by this one */
493 break;
494
495 default:
496 /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
497 CL_ASSERT(FALSE);
498 status = IB_ERROR;
499 break;
500 }
501 }
502 if (status != IB_SUCCESS)
503 goto Exit;
504
505 /* we silently ignore cases where only the Rate selector is defined */
506 if ((comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
507 (comp_mask & IB_MPR_COMPMASK_RATE)) {
508 required_rate = ib_multipath_rec_rate(p_mpr);
509 switch (ib_multipath_rec_rate_sel(p_mpr)) {
510 case 0: /* must be greater than */
511 if (ib_path_compare_rates(rate, required_rate) <= 0)
512 status = IB_NOT_FOUND;
513 break;
514
515 case 1: /* must be less than */
516 if (ib_path_compare_rates(rate, required_rate) >= 0) {
517 /* adjust the rate to use the highest rate
518 lower then the required one */
519 rate = ib_path_rate_get_prev(required_rate);
520 if (!rate)
521 status = IB_NOT_FOUND;
522 }
523 break;
524
525 case 2: /* exact match */
526 if (ib_path_compare_rates(rate, required_rate))
527 status = IB_NOT_FOUND;
528 else
529 rate = required_rate;
530 break;
531
532 case 3: /* largest available */
533 /* can't be disqualified by this one */
534 break;
535
536 default:
537 /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
538 CL_ASSERT(FALSE);
539 status = IB_ERROR;
540 break;
541 }
542 }
543 if (status != IB_SUCCESS)
544 goto Exit;
545
546 /* Verify the pkt_life_time */
547 /* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,
548 for loopback paths, packetLifeTime shall be zero. */
549 if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
550 pkt_life = 0; /* loopback */
551 else if (p_qos_level && p_qos_level->pkt_life_set)
552 pkt_life = p_qos_level->pkt_life;
553 else
554 pkt_life = sa->p_subn->opt.subnet_timeout;
555
556 /* we silently ignore cases where only the PktLife selector is defined */
557 if ((comp_mask & IB_MPR_COMPMASK_PKTLIFETIMESELEC) &&
558 (comp_mask & IB_MPR_COMPMASK_PKTLIFETIME)) {
559 required_pkt_life = ib_multipath_rec_pkt_life(p_mpr);
560 switch (ib_multipath_rec_pkt_life_sel(p_mpr)) {
561 case 0: /* must be greater than */
562 if (pkt_life <= required_pkt_life)
563 status = IB_NOT_FOUND;
564 break;
565
566 case 1: /* must be less than */
567 if (pkt_life >= required_pkt_life) {
568 /* adjust the lifetime to use the highest possible
569 lower then the required one */
570 if (required_pkt_life > 1)
571 pkt_life = required_pkt_life - 1;
572 else
573 status = IB_NOT_FOUND;
574 }
575 break;
576
577 case 2: /* exact match */
578 if (pkt_life < required_pkt_life)
579 status = IB_NOT_FOUND;
580 else
581 pkt_life = required_pkt_life;
582 break;
583
584 case 3: /* smallest available */
585 /* can't be disqualified by this one */
586 break;
587
588 default:
589 /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
590 CL_ASSERT(FALSE);
591 status = IB_ERROR;
592 break;
593 }
594 }
595
596 if (status != IB_SUCCESS)
597 goto Exit;
598
599 /*
600 * set Pkey for this MultiPath record request
601 */
602
603 if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
604 cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
605 required_pkey =
606 osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
607 sa->p_subn->opt.allow_both_pkeys);
608
609 else if (comp_mask & IB_MPR_COMPMASK_PKEY) {
610 /*
611 * MPR request has a specific pkey:
612 * Check that source and destination share this pkey.
613 * If QoS level has pkeys, check that this pkey exists
614 * in the QoS level pkeys.
615 * MPR returned pkey is the requested pkey.
616 */
617 required_pkey = p_mpr->pkey;
618 if (!osm_physp_share_this_pkey
619 (p_src_physp, p_dest_physp, required_pkey,
620 sa->p_subn->opt.allow_both_pkeys)) {
621 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4518: "
622 "Ports src 0x%016"PRIx64" (%s port %d) "
623 "and dst 0x%016"PRIx64" (%s port %d) "
624 "do not share the specified PKey 0x%04x\n",
625 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
626 p_src_physp->p_node->print_desc,
627 p_src_physp->port_num,
628 cl_ntoh64(osm_physp_get_port_guid
629 (p_dest_physp)),
630 p_dest_physp->p_node->print_desc,
631 p_dest_physp->port_num,
632 cl_ntoh16(required_pkey));
633 status = IB_NOT_FOUND;
634 goto Exit;
635 }
636 if (p_qos_level && p_qos_level->pkey_range_len &&
637 !osm_qos_level_has_pkey(p_qos_level, required_pkey)) {
638 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451C: "
639 "Ports src 0x%016"PRIx64" (%s port %d) "
640 "and dst 0x%016"PRIx64" (%s port %d) "
641 "do not share specified PKey (0x%04x) as "
642 "defined by QoS level \"%s\"\n",
643 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
644 p_src_physp->p_node->print_desc,
645 p_src_physp->port_num,
646 cl_ntoh64(osm_physp_get_port_guid
647 (p_dest_physp)),
648 p_dest_physp->p_node->print_desc,
649 p_dest_physp->port_num,
650 cl_ntoh16(required_pkey),
651 p_qos_level->name);
652 status = IB_NOT_FOUND;
653 goto Exit;
654 }
655
656 } else if (p_qos_level && p_qos_level->pkey_range_len) {
657 /*
658 * MPR request doesn't have a specific pkey, but QoS level
659 * has pkeys - get shared pkey from QoS level pkeys
660 */
661 required_pkey = osm_qos_level_get_shared_pkey(p_qos_level,
662 p_src_physp,
663 p_dest_physp,
664 sa->p_subn->opt.allow_both_pkeys);
665 if (!required_pkey) {
666 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451D: "
667 "Ports src 0x%016"PRIx64" (%s port %d) "
668 "and dst 0x%016"PRIx64" (%s port %d) "
669 "do not share a PKey as defined by QoS "
670 "level \"%s\"\n",
671 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
672 p_src_physp->p_node->print_desc,
673 p_src_physp->port_num,
674 cl_ntoh64(osm_physp_get_port_guid
675 (p_dest_physp)),
676 p_dest_physp->p_node->print_desc,
677 p_dest_physp->port_num,
678 p_qos_level->name);
679 status = IB_NOT_FOUND;
680 goto Exit;
681 }
682
683 } else {
684 /*
685 * Neither MPR request nor QoS level have pkey.
686 * Just get any shared pkey.
687 */
688 required_pkey =
689 osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
690 sa->p_subn->opt.allow_both_pkeys);
691 if (!required_pkey) {
692 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4519: "
693 "Ports src 0x%016"PRIx64" (%s port %d) "
694 "and dst 0x%016"PRIx64" (%s port %d) "
695 "do not have any shared PKeys\n",
696 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
697 p_src_physp->p_node->print_desc,
698 p_src_physp->port_num,
699 cl_ntoh64(osm_physp_get_port_guid
700 (p_dest_physp)),
701 p_dest_physp->p_node->print_desc,
702 p_dest_physp->port_num);
703 status = IB_NOT_FOUND;
704 goto Exit;
705 }
706 }
707
708 if (required_pkey) {
709 p_prtn =
710 (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
711 required_pkey &
712 cl_ntoh16((uint16_t) ~ 0x8000));
713 if (p_prtn ==
714 (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
715 p_prtn = NULL;
716 }
717
718 /*
719 * Set MultiPathRecord SL.
720 */
721
722 if (comp_mask & IB_MPR_COMPMASK_SL) {
723 /*
724 * Specific SL was requested
725 */
726 required_sl = ib_multipath_rec_sl(p_mpr);
727
728 if (p_qos_level && p_qos_level->sl_set &&
729 p_qos_level->sl != required_sl) {
730 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451E: "
731 "QoS constraints: required MultiPathRecord SL "
732 "(%u) doesn't match QoS policy \"%s\" SL (%u) "
733 "[%s port %d <-> %s port %d]\n", required_sl,
734 p_qos_level->name,
735 p_qos_level->sl,
736 p_src_alias_guid->p_base_port->p_node->print_desc,
737 p_src_alias_guid->p_base_port->p_physp->port_num,
738 p_dest_alias_guid->p_base_port->p_node->print_desc,
739 p_dest_alias_guid->p_base_port->p_physp->port_num);
740 status = IB_NOT_FOUND;
741 goto Exit;
742 }
743
744 } else if (p_qos_level && p_qos_level->sl_set) {
745 /*
746 * No specific SL was requested,
747 * but there is an SL in QoS level.
748 */
749 required_sl = p_qos_level->sl;
750
751 if (required_pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
752 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
753 "QoS level SL (%u) overrides partition SL (%u)\n",
754 p_qos_level->sl, p_prtn->sl);
755
756 } else if (required_pkey) {
757 /*
758 * No specific SL in request or in QoS level - use partition SL
759 */
760 p_prtn =
761 (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
762 required_pkey &
763 cl_ntoh16((uint16_t) ~ 0x8000));
764 if (!p_prtn) {
765 required_sl = OSM_DEFAULT_SL;
766 /* this may be possible when pkey tables are created somehow in
767 previous runs or things are going wrong here */
768 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451A: "
769 "No partition found for PKey 0x%04x - "
770 "using default SL %d "
771 "[%s port %d <-> %s port %d]\n",
772 cl_ntoh16(required_pkey), required_sl,
773 p_src_alias_guid->p_base_port->p_node->print_desc,
774 p_src_alias_guid->p_base_port->p_physp->port_num,
775 p_dest_alias_guid->p_base_port->p_node->print_desc,
776 p_dest_alias_guid->p_base_port->p_physp->port_num);
777 } else
778 required_sl = p_prtn->sl;
779
780 } else if (sa->p_subn->opt.qos) {
781 if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
782 required_sl = OSM_DEFAULT_SL;
783 else {
784 for (i = 0; i < IB_MAX_NUM_VLS; i++)
785 if (valid_sl_mask & (1 << i))
786 break;
787 required_sl = i;
788 }
789 } else
790 required_sl = OSM_DEFAULT_SL;
791
792 if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << required_sl))) {
793 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451F: "
794 "Selected SL (%u) leads to VL15 "
795 "[%s port %d <-> %s port %d]\n",
796 required_sl,
797 p_src_alias_guid->p_base_port->p_node->print_desc,
798 p_src_alias_guid->p_base_port->p_physp->port_num,
799 p_dest_alias_guid->p_base_port->p_node->print_desc,
800 p_dest_alias_guid->p_base_port->p_physp->port_num);
801 status = IB_NOT_FOUND;
802 goto Exit;
803 }
804
805 /* reset pkey when raw traffic */
806 if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
807 cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
808 required_pkey = 0;
809
810 p_parms->mtu = mtu;
811 p_parms->rate = rate;
812 p_parms->pkey = required_pkey;
813 p_parms->pkt_life = pkt_life;
814 p_parms->sl = required_sl;
815 p_parms->hops = hops;
816
817 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MultiPath params:"
818 " mtu = %u, rate = %u, packet lifetime = %u,"
819 " pkey = 0x%04X, sl = %u, hops = %u\n", mtu, rate,
820 pkt_life, cl_ntoh16(required_pkey), required_sl, hops);
821
822 Exit:
823 OSM_LOG_EXIT(sa->p_log);
824 return status;
825 }
826
mpr_rcv_build_pr(IN osm_sa_t * sa,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN uint16_t src_lid_ho,IN uint16_t dest_lid_ho,IN uint8_t preference,IN const osm_path_parms_t * p_parms,OUT ib_path_rec_t * p_pr)827 static void mpr_rcv_build_pr(IN osm_sa_t * sa,
828 IN const osm_alias_guid_t * p_src_alias_guid,
829 IN const osm_alias_guid_t * p_dest_alias_guid,
830 IN uint16_t src_lid_ho, IN uint16_t dest_lid_ho,
831 IN uint8_t preference,
832 IN const osm_path_parms_t * p_parms,
833 OUT ib_path_rec_t * p_pr)
834 {
835 const osm_physp_t *p_src_physp, *p_dest_physp;
836
837 OSM_LOG_ENTER(sa->p_log);
838
839 p_src_physp = p_src_alias_guid->p_base_port->p_physp;
840 p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
841
842 p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix(p_dest_physp);
843 p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
844
845 p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
846 p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
847
848 p_pr->dlid = cl_hton16(dest_lid_ho);
849 p_pr->slid = cl_hton16(src_lid_ho);
850
851 p_pr->hop_flow_raw &= cl_hton32(1 << 31);
852
853 p_pr->pkey = p_parms->pkey;
854 ib_path_rec_set_qos_class(p_pr, 0);
855 ib_path_rec_set_sl(p_pr, p_parms->sl);
856 p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
857 p_pr->rate = (uint8_t) (p_parms->rate | 0x80);
858
859 /* According to 1.2 spec definition Table 205 PacketLifeTime description,
860 for loopback paths, packetLifeTime shall be zero. */
861 if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
862 p_pr->pkt_life = 0x80; /* loopback */
863 else
864 p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
865
866 p_pr->preference = preference;
867
868 /* always return num_path = 0 so this is only the reversible component */
869 if (p_parms->reversible)
870 p_pr->num_path = 0x80;
871
872 OSM_LOG_EXIT(sa->p_log);
873 }
874
mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN const uint16_t src_lid_ho,IN const uint16_t dest_lid_ho,IN const ib_net64_t comp_mask,IN const uint8_t preference)875 static osm_sa_item_t *mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
876 IN const ib_multipath_rec_t *
877 p_mpr,
878 IN const osm_alias_guid_t *
879 p_src_alias_guid,
880 IN const osm_alias_guid_t *
881 p_dest_alias_guid,
882 IN const uint16_t src_lid_ho,
883 IN const uint16_t dest_lid_ho,
884 IN const ib_net64_t comp_mask,
885 IN const uint8_t preference)
886 {
887 osm_path_parms_t path_parms;
888 osm_path_parms_t rev_path_parms;
889 osm_sa_item_t *p_pr_item;
890 ib_api_status_t status, rev_path_status;
891
892 OSM_LOG_ENTER(sa->p_log);
893
894 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
895 src_lid_ho, dest_lid_ho);
896
897 p_pr_item = malloc(SA_MPR_RESP_SIZE);
898 if (p_pr_item == NULL) {
899 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4501: "
900 "Unable to allocate path record\n");
901 goto Exit;
902 }
903 memset(p_pr_item, 0, SA_MPR_RESP_SIZE);
904
905 status = mpr_rcv_get_path_parms(sa, p_mpr, p_src_alias_guid,
906 p_dest_alias_guid,
907 src_lid_ho, dest_lid_ho,
908 comp_mask, &path_parms);
909
910 if (status != IB_SUCCESS) {
911 free(p_pr_item);
912 p_pr_item = NULL;
913 goto Exit;
914 }
915
916 /* now try the reversible path */
917 rev_path_status = mpr_rcv_get_path_parms(sa, p_mpr, p_dest_alias_guid,
918 p_src_alias_guid,
919 dest_lid_ho, src_lid_ho,
920 comp_mask, &rev_path_parms);
921 path_parms.reversible = (rev_path_status == IB_SUCCESS);
922
923 /* did we get a Reversible Path compmask ? */
924 /*
925 NOTE that if the reversible component = 0, it is a don't care
926 rather then requiring non-reversible paths ...
927 see Vol1 Ver1.2 p900 l16
928 */
929 if (comp_mask & IB_MPR_COMPMASK_REVERSIBLE) {
930 if ((!path_parms.reversible && (p_mpr->num_path & 0x80))) {
931 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
932 "Requested reversible path but failed to get one\n");
933
934 free(p_pr_item);
935 p_pr_item = NULL;
936 goto Exit;
937 }
938 }
939
940 p_pr_item->resp.mpr_rec.p_src_port = p_src_alias_guid->p_base_port;
941 p_pr_item->resp.mpr_rec.p_dest_port = p_dest_alias_guid->p_base_port;
942 p_pr_item->resp.mpr_rec.hops = path_parms.hops;
943
944 mpr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, src_lid_ho,
945 dest_lid_ho, preference, &path_parms,
946 &p_pr_item->resp.mpr_rec.path_rec);
947
948 Exit:
949 OSM_LOG_EXIT(sa->p_log);
950 return p_pr_item;
951 }
952
mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_port_t * p_req_port,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN const uint32_t rem_paths,IN const ib_net64_t comp_mask,IN cl_qlist_t * p_list)953 static uint32_t mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
954 IN const ib_multipath_rec_t * p_mpr,
955 IN const osm_port_t * p_req_port,
956 IN const osm_alias_guid_t * p_src_alias_guid,
957 IN const osm_alias_guid_t * p_dest_alias_guid,
958 IN const uint32_t rem_paths,
959 IN const ib_net64_t comp_mask,
960 IN cl_qlist_t * p_list)
961 {
962 osm_sa_item_t *p_pr_item;
963 uint16_t src_lid_min_ho;
964 uint16_t src_lid_max_ho;
965 uint16_t dest_lid_min_ho;
966 uint16_t dest_lid_max_ho;
967 uint16_t src_lid_ho;
968 uint16_t dest_lid_ho;
969 uint32_t path_num = 0;
970 uint8_t preference;
971 unsigned src_offset, dest_offset;
972
973 OSM_LOG_ENTER(sa->p_log);
974
975 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
976 "Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
977 cl_ntoh64(p_src_alias_guid->alias_guid),
978 cl_ntoh64(p_dest_alias_guid->alias_guid));
979
980 /* Check that the req_port, src_port and dest_port all share a
981 pkey. The check is done on the default physical port of the ports. */
982 if (osm_port_share_pkey(sa->p_log, p_req_port,
983 p_src_alias_guid->p_base_port,
984 sa->p_subn->opt.allow_both_pkeys) == FALSE
985 || osm_port_share_pkey(sa->p_log, p_req_port,
986 p_dest_alias_guid->p_base_port,
987 sa->p_subn->opt.allow_both_pkeys) == FALSE
988 || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
989 p_dest_alias_guid->p_base_port,
990 sa->p_subn->opt.allow_both_pkeys) == FALSE)
991 /* One of the pairs doesn't share a pkey so the path is disqualified. */
992 goto Exit;
993
994 /*
995 We shouldn't be here if the paths are disqualified in some way...
996 Thus, we assume every possible connection is valid.
997
998 We desire to return high-quality paths first.
999 In OpenSM, higher quality mean least overlap with other paths.
1000 This is acheived in practice by returning paths with
1001 different LID value on each end, which means these
1002 paths are more redundant that paths with the same LID repeated
1003 on one side. For example, in OpenSM the paths between two
1004 endpoints with LMC = 1 might be as follows:
1005
1006 Port A, LID 1 <-> Port B, LID 3
1007 Port A, LID 1 <-> Port B, LID 4
1008 Port A, LID 2 <-> Port B, LID 3
1009 Port A, LID 2 <-> Port B, LID 4
1010
1011 The OpenSM unicast routing algorithms attempt to disperse each path
1012 to as varied a physical path as is reasonable. 1<->3 and 1<->4 have
1013 more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
1014
1015 OpenSM ranks paths in three preference groups:
1016
1017 Preference Value Description
1018 ---------------- -------------------------------------------
1019 0 Redundant in both directions with other
1020 pref value = 0 paths
1021
1022 1 Redundant in one direction with other
1023 pref value = 0 and pref value = 1 paths
1024
1025 2 Not redundant in either direction with
1026 other paths
1027
1028 3-FF Unused
1029
1030 SA clients don't need to know these details, only that the lower
1031 preference paths are preferred, as stated in the spec. The paths
1032 may not actually be physically redundant depending on the topology
1033 of the subnet, but the point of LMC > 0 is to offer redundancy,
1034 so I assume the subnet is physically appropriate for the specified
1035 LMC value. A more advanced implementation could inspect for physical
1036 redundancy, but I'm not going to bother with that now.
1037 */
1038
1039 osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
1040 &src_lid_min_ho, &src_lid_max_ho);
1041 osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
1042 &dest_lid_min_ho, &dest_lid_max_ho);
1043
1044 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID [%u-%u], Dest LID [%u-%u]\n",
1045 src_lid_min_ho, src_lid_max_ho,
1046 dest_lid_min_ho, dest_lid_max_ho);
1047
1048 src_lid_ho = src_lid_min_ho;
1049 dest_lid_ho = dest_lid_min_ho;
1050
1051 /*
1052 Preferred paths come first in OpenSM
1053 */
1054 preference = 0;
1055
1056 while (path_num < rem_paths) {
1057 /*
1058 These paths are "fully redundant"
1059 */
1060 p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
1061 p_src_alias_guid,
1062 p_dest_alias_guid,
1063 src_lid_ho, dest_lid_ho,
1064 comp_mask, preference);
1065
1066 if (p_pr_item) {
1067 cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1068 ++path_num;
1069 }
1070
1071 if (++src_lid_ho > src_lid_max_ho)
1072 break;
1073
1074 if (++dest_lid_ho > dest_lid_max_ho)
1075 break;
1076 }
1077
1078 /*
1079 Check if we've accumulated all the paths that the user cares to see
1080 */
1081 if (path_num == rem_paths)
1082 goto Exit;
1083
1084 /*
1085 Don't bother reporting preference 1 paths for now.
1086 It's more trouble than it's worth and can only occur
1087 if ports have different LMC values, which isn't supported
1088 by OpenSM right now anyway.
1089 */
1090 preference = 2;
1091 src_lid_ho = src_lid_min_ho;
1092 dest_lid_ho = dest_lid_min_ho;
1093 src_offset = 0;
1094 dest_offset = 0;
1095
1096 /*
1097 Iterate over the remaining paths
1098 */
1099 while (path_num < rem_paths) {
1100 dest_offset++;
1101 dest_lid_ho++;
1102
1103 if (dest_lid_ho > dest_lid_max_ho) {
1104 src_offset++;
1105 src_lid_ho++;
1106
1107 if (src_lid_ho > src_lid_max_ho)
1108 break; /* done */
1109
1110 dest_offset = 0;
1111 dest_lid_ho = dest_lid_min_ho;
1112 }
1113
1114 /*
1115 These paths are "fully non-redundant" with paths already
1116 identified above and consequently not of much value.
1117
1118 Don't return paths we already identified above, as indicated
1119 by the offset values being equal.
1120 */
1121 if (src_offset == dest_offset)
1122 continue; /* already reported */
1123
1124 p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
1125 p_src_alias_guid,
1126 p_dest_alias_guid,
1127 src_lid_ho, dest_lid_ho,
1128 comp_mask, preference);
1129
1130 if (p_pr_item) {
1131 cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1132 ++path_num;
1133 }
1134 }
1135
1136 Exit:
1137 OSM_LOG_EXIT(sa->p_log);
1138 return path_num;
1139 }
1140
1141 #undef min
1142 #define min(x,y) (((x) < (y)) ? (x) : (y))
1143
mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_alias_guid_t * p_src_alias_guid,IN const osm_alias_guid_t * p_dest_alias_guid,IN int base_offs,IN const ib_net64_t comp_mask,IN cl_qlist_t * p_list)1144 static osm_sa_item_t *mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa,
1145 IN const
1146 ib_multipath_rec_t *
1147 p_mpr,
1148 IN const osm_alias_guid_t *
1149 p_src_alias_guid,
1150 IN const osm_alias_guid_t *
1151 p_dest_alias_guid,
1152 IN int base_offs,
1153 IN const ib_net64_t
1154 comp_mask,
1155 IN cl_qlist_t * p_list)
1156 {
1157 osm_sa_item_t *p_pr_item = 0;
1158 uint16_t src_lid_min_ho;
1159 uint16_t src_lid_max_ho;
1160 uint16_t dest_lid_min_ho;
1161 uint16_t dest_lid_max_ho;
1162 uint16_t src_lid_ho;
1163 uint16_t dest_lid_ho;
1164 unsigned iterations;
1165 int src_lids, dest_lids;
1166
1167 OSM_LOG_ENTER(sa->p_log);
1168
1169 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src port 0x%016" PRIx64 ", "
1170 "Dst port 0x%016" PRIx64 ", base offs %d\n",
1171 cl_ntoh64(p_src_alias_guid->alias_guid),
1172 cl_ntoh64(p_dest_alias_guid->alias_guid),
1173 base_offs);
1174
1175 osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
1176 &src_lid_min_ho, &src_lid_max_ho);
1177 osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
1178 &dest_lid_min_ho, &dest_lid_max_ho);
1179
1180 src_lid_ho = src_lid_min_ho;
1181 dest_lid_ho = dest_lid_min_ho;
1182
1183 src_lids = src_lid_max_ho - src_lid_min_ho + 1;
1184 dest_lids = dest_lid_max_ho - dest_lid_min_ho + 1;
1185
1186 src_lid_ho += base_offs % src_lids;
1187 dest_lid_ho += base_offs % dest_lids;
1188
1189 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1190 "Src LIDs [%u-%u] hashed %u, "
1191 "Dest LIDs [%u-%u] hashed %u\n",
1192 src_lid_min_ho, src_lid_max_ho, src_lid_ho,
1193 dest_lid_min_ho, dest_lid_max_ho, dest_lid_ho);
1194
1195 iterations = min(src_lids, dest_lids);
1196
1197 while (iterations--) {
1198 /*
1199 These paths are "fully redundant"
1200 */
1201 p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
1202 p_src_alias_guid,
1203 p_dest_alias_guid,
1204 src_lid_ho, dest_lid_ho,
1205 comp_mask, 0);
1206
1207 if (p_pr_item) {
1208 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1209 "Found matching path from Src LID %u to Dest LID %u with %d hops\n",
1210 src_lid_ho, dest_lid_ho, p_pr_item->resp.mpr_rec.hops);
1211 break;
1212 }
1213
1214 if (++src_lid_ho > src_lid_max_ho)
1215 src_lid_ho = src_lid_min_ho;
1216
1217 if (++dest_lid_ho > dest_lid_max_ho)
1218 dest_lid_ho = dest_lid_min_ho;
1219 }
1220
1221 OSM_LOG_EXIT(sa->p_log);
1222 return p_pr_item;
1223 }
1224
mpr_rcv_get_gids(IN osm_sa_t * sa,IN const ib_gid_t * gids,IN int ngids,IN int is_sgid,OUT osm_alias_guid_t ** pp_alias_guid)1225 static ib_net16_t mpr_rcv_get_gids(IN osm_sa_t * sa, IN const ib_gid_t * gids,
1226 IN int ngids, IN int is_sgid,
1227 OUT osm_alias_guid_t ** pp_alias_guid)
1228 {
1229 osm_alias_guid_t *p_alias_guid;
1230 ib_net16_t ib_status = IB_SUCCESS;
1231 int i;
1232
1233 OSM_LOG_ENTER(sa->p_log);
1234
1235 for (i = 0; i < ngids; i++, gids++) {
1236 if (!ib_gid_is_link_local(gids)) {
1237 if ((is_sgid && ib_gid_is_multicast(gids)) ||
1238 (ib_gid_get_subnet_prefix(gids) !=
1239 sa->p_subn->opt.subnet_prefix)) {
1240 /*
1241 This 'error' is the client's fault (bad gid)
1242 so don't enter it as an error in our own log.
1243 Return an error response to the client.
1244 */
1245 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "ERR 451B: "
1246 "%sGID 0x%016" PRIx64
1247 " is multicast or non local subnet prefix\n",
1248 is_sgid ? "S" : "D",
1249 cl_ntoh64(gids->unicast.prefix));
1250
1251 ib_status = IB_SA_MAD_STATUS_INVALID_GID;
1252 goto Exit;
1253 }
1254 }
1255
1256 p_alias_guid =
1257 osm_get_alias_guid_by_guid(sa->p_subn,
1258 gids->unicast.interface_id);
1259 if (!p_alias_guid) {
1260 /*
1261 This 'error' is the client's fault (bad gid) so
1262 don't enter it as an error in our own log.
1263 Return an error response to the client.
1264 */
1265 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4506: "
1266 "No port with GUID 0x%016" PRIx64 "\n",
1267 cl_ntoh64(gids->unicast.interface_id));
1268
1269 ib_status = IB_SA_MAD_STATUS_INVALID_GID;
1270 goto Exit;
1271 }
1272
1273 pp_alias_guid[i] = p_alias_guid;
1274 }
1275
1276 Exit:
1277 OSM_LOG_EXIT(sa->p_log);
1278
1279 return ib_status;
1280 }
1281
mpr_rcv_get_end_points(IN osm_sa_t * sa,IN const osm_madw_t * p_madw,OUT osm_alias_guid_t ** pp_alias_guids,OUT int * nsrc,OUT int * ndest)1282 static ib_net16_t mpr_rcv_get_end_points(IN osm_sa_t * sa,
1283 IN const osm_madw_t * p_madw,
1284 OUT osm_alias_guid_t ** pp_alias_guids,
1285 OUT int *nsrc, OUT int *ndest)
1286 {
1287 const ib_multipath_rec_t *p_mpr;
1288 const ib_sa_mad_t *p_sa_mad;
1289 ib_net64_t comp_mask;
1290 ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
1291 ib_gid_t *gids;
1292
1293 OSM_LOG_ENTER(sa->p_log);
1294
1295 /*
1296 Determine what fields are valid and then get a pointer
1297 to the source and destination port objects, if possible.
1298 */
1299 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1300 p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1301 gids = (ib_gid_t *) p_mpr->gids;
1302
1303 comp_mask = p_sa_mad->comp_mask;
1304
1305 /*
1306 Check a few easy disqualifying cases up front before getting
1307 into the endpoints.
1308 */
1309 *nsrc = *ndest = 0;
1310
1311 if (comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) {
1312 *nsrc = p_mpr->sgid_count;
1313 if (*nsrc > IB_MULTIPATH_MAX_GIDS)
1314 *nsrc = IB_MULTIPATH_MAX_GIDS;
1315 sa_status = mpr_rcv_get_gids(sa, gids, *nsrc, 1, pp_alias_guids);
1316 if (sa_status != IB_SUCCESS)
1317 goto Exit;
1318 }
1319
1320 if (comp_mask & IB_MPR_COMPMASK_DGIDCOUNT) {
1321 *ndest = p_mpr->dgid_count;
1322 if (*ndest + *nsrc > IB_MULTIPATH_MAX_GIDS)
1323 *ndest = IB_MULTIPATH_MAX_GIDS - *nsrc;
1324 sa_status =
1325 mpr_rcv_get_gids(sa, gids + *nsrc, *ndest, 0,
1326 pp_alias_guids + *nsrc);
1327 }
1328
1329 Exit:
1330 OSM_LOG_EXIT(sa->p_log);
1331 return sa_status;
1332 }
1333
1334 #define hash_lids(a, b, lmc) \
1335 (((((a) >> (lmc)) << 4) | ((b) >> (lmc))) % 103)
1336
mpr_rcv_get_apm_paths(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN const osm_port_t * p_req_port,IN osm_alias_guid_t ** _pp_alias_guids,IN const ib_net64_t comp_mask,IN cl_qlist_t * p_list)1337 static void mpr_rcv_get_apm_paths(IN osm_sa_t * sa,
1338 IN const ib_multipath_rec_t * p_mpr,
1339 IN const osm_port_t * p_req_port,
1340 IN osm_alias_guid_t ** _pp_alias_guids,
1341 IN const ib_net64_t comp_mask,
1342 IN cl_qlist_t * p_list)
1343 {
1344 osm_alias_guid_t *pp_alias_guids[4];
1345 osm_sa_item_t *matrix[2][2];
1346 int base_offs, src_lid_ho, dest_lid_ho;
1347 int sumA, sumB, minA, minB;
1348
1349 OSM_LOG_ENTER(sa->p_log);
1350
1351 /*
1352 * We want to:
1353 * 1. use different lid offsets (from base) for the resultant paths
1354 * to increase the probability of redundant paths or in case
1355 * of Clos - to ensure it (different offset => different spine!)
1356 * 2. keep consistent paths no matter of direction and order of ports
1357 * 3. distibute the lid offsets to balance the load
1358 * So, we sort the ports (within the srcs, and within the dests),
1359 * hash the lids of S0, D0 (after the sort), and call mpr_rcv_get_apm_port_pair_paths
1360 * with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get
1361 * always the same offsets - order independent, and make sure different spines are used.
1362 * Note that the diagonals on a Clos have the same number of hops, so it doesn't
1363 * really matter which diagonal we use.
1364 */
1365 if (_pp_alias_guids[0]->p_base_port->guid <
1366 _pp_alias_guids[1]->p_base_port->guid) {
1367 pp_alias_guids[0] = _pp_alias_guids[0];
1368 pp_alias_guids[1] = _pp_alias_guids[1];
1369 } else {
1370 pp_alias_guids[0] = _pp_alias_guids[1];
1371 pp_alias_guids[1] = _pp_alias_guids[0];
1372 }
1373 if (_pp_alias_guids[2]->p_base_port->guid <
1374 _pp_alias_guids[3]->p_base_port->guid) {
1375 pp_alias_guids[2] = _pp_alias_guids[2];
1376 pp_alias_guids[3] = _pp_alias_guids[3];
1377 } else {
1378 pp_alias_guids[2] = _pp_alias_guids[3];
1379 pp_alias_guids[3] = _pp_alias_guids[2];
1380 }
1381
1382 src_lid_ho = osm_port_get_base_lid(pp_alias_guids[0]->p_base_port);
1383 dest_lid_ho = osm_port_get_base_lid(pp_alias_guids[2]->p_base_port);
1384
1385 base_offs = src_lid_ho < dest_lid_ho ?
1386 hash_lids(src_lid_ho, dest_lid_ho, sa->p_subn->opt.lmc) :
1387 hash_lids(dest_lid_ho, src_lid_ho, sa->p_subn->opt.lmc);
1388
1389 matrix[0][0] =
1390 mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
1391 pp_alias_guids[2], base_offs,
1392 comp_mask, p_list);
1393 matrix[0][1] =
1394 mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
1395 pp_alias_guids[3], base_offs,
1396 comp_mask, p_list);
1397 matrix[1][0] =
1398 mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
1399 pp_alias_guids[2], base_offs + 1,
1400 comp_mask, p_list);
1401 matrix[1][1] =
1402 mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
1403 pp_alias_guids[3], base_offs + 1,
1404 comp_mask, p_list);
1405
1406 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "APM matrix:\n"
1407 "\t{0,0} 0x%X->0x%X (%d)\t| {0,1} 0x%X->0x%X (%d)\n"
1408 "\t{1,0} 0x%X->0x%X (%d)\t| {1,1} 0x%X->0x%X (%d)\n",
1409 matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
1410 matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
1411 matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
1412 matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
1413 matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
1414 matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
1415 matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
1416 matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid : 0,
1417 matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0,
1418 matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
1419 matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
1420 matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
1421
1422 sumA = minA = sumB = minB = 0;
1423
1424 /* check diagonal A {(0,0), (1,1)} */
1425 if (matrix[0][0]) {
1426 sumA += matrix[0][0]->resp.mpr_rec.hops;
1427 minA = matrix[0][0]->resp.mpr_rec.hops;
1428 }
1429 if (matrix[1][1]) {
1430 sumA += matrix[1][1]->resp.mpr_rec.hops;
1431 if (minA)
1432 minA = min(minA, matrix[1][1]->resp.mpr_rec.hops);
1433 else
1434 minA = matrix[1][1]->resp.mpr_rec.hops;
1435 }
1436
1437 /* check diagonal B {(0,1), (1,0)} */
1438 if (matrix[0][1]) {
1439 sumB += matrix[0][1]->resp.mpr_rec.hops;
1440 minB = matrix[0][1]->resp.mpr_rec.hops;
1441 }
1442 if (matrix[1][0]) {
1443 sumB += matrix[1][0]->resp.mpr_rec.hops;
1444 if (minB)
1445 minB = min(minB, matrix[1][0]->resp.mpr_rec.hops);
1446 else
1447 minB = matrix[1][0]->resp.mpr_rec.hops;
1448 }
1449
1450 /* and the winner is... */
1451 if (minA <= minB || (minA == minB && sumA < sumB)) {
1452 /* Diag A */
1453 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1454 "Diag {0,0} & {1,1} is the best:\n"
1455 "\t{0,0} 0x%X->0x%X (%d)\t & {1,1} 0x%X->0x%X (%d)\n",
1456 matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
1457 matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
1458 matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
1459 matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
1460 matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
1461 matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
1462 if (matrix[0][0])
1463 cl_qlist_insert_tail(p_list, &matrix[0][0]->list_item);
1464 if (matrix[1][1])
1465 cl_qlist_insert_tail(p_list, &matrix[1][1]->list_item);
1466 free(matrix[0][1]);
1467 free(matrix[1][0]);
1468 } else {
1469 /* Diag B */
1470 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1471 "Diag {0,1} & {1,0} is the best:\n"
1472 "\t{0,1} 0x%X->0x%X (%d)\t & {1,0} 0x%X->0x%X (%d)\n",
1473 matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
1474 matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
1475 matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
1476 matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
1477 matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid: 0,
1478 matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0);
1479 if (matrix[0][1])
1480 cl_qlist_insert_tail(p_list, &matrix[0][1]->list_item);
1481 if (matrix[1][0])
1482 cl_qlist_insert_tail(p_list, &matrix[1][0]->list_item);
1483 free(matrix[0][0]);
1484 free(matrix[1][1]);
1485 }
1486
1487 OSM_LOG_EXIT(sa->p_log);
1488 }
1489
mpr_rcv_process_pairs(IN osm_sa_t * sa,IN const ib_multipath_rec_t * p_mpr,IN osm_port_t * p_req_port,IN osm_alias_guid_t ** pp_alias_guids,IN const int nsrc,IN int ndest,IN ib_net64_t comp_mask,IN cl_qlist_t * p_list)1490 static void mpr_rcv_process_pairs(IN osm_sa_t * sa,
1491 IN const ib_multipath_rec_t * p_mpr,
1492 IN osm_port_t * p_req_port,
1493 IN osm_alias_guid_t ** pp_alias_guids,
1494 IN const int nsrc, IN int ndest,
1495 IN ib_net64_t comp_mask,
1496 IN cl_qlist_t * p_list)
1497 {
1498 osm_alias_guid_t **pp_src_alias_guid, **pp_es;
1499 osm_alias_guid_t **pp_dest_alias_guid, **pp_ed;
1500 uint32_t max_paths, num_paths, total_paths = 0;
1501
1502 OSM_LOG_ENTER(sa->p_log);
1503
1504 if (comp_mask & IB_MPR_COMPMASK_NUMBPATH)
1505 max_paths = p_mpr->num_path & 0x7F;
1506 else
1507 max_paths = OSM_SA_MPR_MAX_NUM_PATH;
1508
1509 for (pp_src_alias_guid = pp_alias_guids, pp_es = pp_alias_guids + nsrc;
1510 pp_src_alias_guid < pp_es; pp_src_alias_guid++) {
1511 for (pp_dest_alias_guid = pp_es, pp_ed = pp_es + ndest;
1512 pp_dest_alias_guid < pp_ed; pp_dest_alias_guid++) {
1513 num_paths =
1514 mpr_rcv_get_port_pair_paths(sa, p_mpr, p_req_port,
1515 *pp_src_alias_guid,
1516 *pp_dest_alias_guid,
1517 max_paths - total_paths,
1518 comp_mask, p_list);
1519 total_paths += num_paths;
1520 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1521 "%d paths %d total paths %d max paths\n",
1522 num_paths, total_paths, max_paths);
1523 /* Just take first NumbPaths found */
1524 if (total_paths >= max_paths)
1525 goto Exit;
1526 }
1527 }
1528
1529 Exit:
1530 OSM_LOG_EXIT(sa->p_log);
1531 }
1532
osm_mpr_rcv_process(IN void * context,IN void * data)1533 void osm_mpr_rcv_process(IN void *context, IN void *data)
1534 {
1535 osm_sa_t *sa = context;
1536 osm_madw_t *p_madw = data;
1537 const ib_multipath_rec_t *p_mpr;
1538 ib_sa_mad_t *p_sa_mad;
1539 osm_port_t *requester_port;
1540 osm_alias_guid_t *pp_alias_guids[IB_MULTIPATH_MAX_GIDS];
1541 cl_qlist_t pr_list;
1542 ib_net16_t sa_status;
1543 int nsrc, ndest;
1544 uint8_t rate, mtu;
1545
1546 OSM_LOG_ENTER(sa->p_log);
1547
1548 CL_ASSERT(p_madw);
1549
1550 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1551 p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1552
1553 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD);
1554
1555 if ((p_sa_mad->rmpp_flags & IB_RMPP_FLAG_ACTIVE) != IB_RMPP_FLAG_ACTIVE) {
1556 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4510: "
1557 "Invalid request since RMPP_FLAG_ACTIVE is not set\n");
1558 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1559 goto Exit;
1560 }
1561
1562 /* we only support SubnAdmGetMulti method */
1563 if (p_sa_mad->method != IB_MAD_METHOD_GETMULTI) {
1564 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4513: "
1565 "Unsupported Method (%s) for MultiPathRecord request\n",
1566 ib_get_sa_method_str(p_sa_mad->method));
1567 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1568 goto Exit;
1569 }
1570
1571 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
1572 osm_dump_multipath_record_v2(sa->p_log, p_mpr, FILE_ID, OSM_LOG_DEBUG);
1573
1574 /* Make sure required components (S/DGIDCount) are supplied */
1575 if (!(p_sa_mad->comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) ||
1576 !(p_sa_mad->comp_mask & IB_MPR_COMPMASK_DGIDCOUNT)) {
1577 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
1578 goto Exit;
1579 }
1580
1581 /* Validate rate if supplied */
1582 if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
1583 (p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATE)) {
1584 rate = ib_multipath_rec_rate(p_mpr);
1585 if (!ib_rate_is_valid(rate)) {
1586 osm_sa_send_error(sa, p_madw,
1587 IB_SA_MAD_STATUS_REQ_INVALID);
1588 goto Exit;
1589 }
1590 }
1591 /* Validate MTU if supplied */
1592 if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
1593 (p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTU)) {
1594 mtu = ib_multipath_rec_mtu(p_mpr);
1595 if (!ib_mtu_is_valid(mtu)) {
1596 osm_sa_send_error(sa, p_madw,
1597 IB_SA_MAD_STATUS_REQ_INVALID);
1598 goto Exit;
1599 }
1600 }
1601
1602 /* Make sure either none or both ServiceID parameters are supplied */
1603 if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) != 0 &&
1604 (p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) !=
1605 IB_MPR_COMPMASK_SERVICEID) {
1606 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
1607 goto Exit;
1608 }
1609
1610 cl_qlist_init(&pr_list);
1611
1612 /*
1613 Most SA functions (including this one) are read-only on the
1614 subnet object, so we grab the lock non-exclusively.
1615 */
1616 cl_plock_acquire(sa->p_lock);
1617
1618 /* update the requester physical port */
1619 requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
1620 osm_madw_get_mad_addr_ptr
1621 (p_madw));
1622 if (requester_port == NULL) {
1623 cl_plock_release(sa->p_lock);
1624 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4517: "
1625 "Cannot find requester physical port\n");
1626 goto Exit;
1627 }
1628
1629 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1630 "Requester port GUID 0x%" PRIx64 "\n",
1631 cl_ntoh64(osm_port_get_guid(requester_port)));
1632
1633 sa_status = mpr_rcv_get_end_points(sa, p_madw, pp_alias_guids,
1634 &nsrc, &ndest);
1635
1636 if (sa_status != IB_SA_MAD_STATUS_SUCCESS || !nsrc || !ndest) {
1637 cl_plock_release(sa->p_lock);
1638 if (sa_status == IB_SA_MAD_STATUS_SUCCESS && (!nsrc || !ndest))
1639 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4512: "
1640 "mpr_rcv_get_end_points failed, # GIDs found; "
1641 "src %d; dest %d)\n", nsrc, ndest);
1642 if (sa_status == IB_SA_MAD_STATUS_SUCCESS)
1643 osm_sa_send_error(sa, p_madw,
1644 IB_SA_MAD_STATUS_REQ_INVALID);
1645 else
1646 osm_sa_send_error(sa, p_madw, sa_status);
1647 goto Exit;
1648 }
1649
1650 /* APM request */
1651 if (nsrc == 2 && ndest == 2 && (p_mpr->num_path & 0x7F) == 2)
1652 mpr_rcv_get_apm_paths(sa, p_mpr, requester_port, pp_alias_guids,
1653 p_sa_mad->comp_mask, &pr_list);
1654 else
1655 mpr_rcv_process_pairs(sa, p_mpr, requester_port, pp_alias_guids,
1656 nsrc, ndest, p_sa_mad->comp_mask,
1657 &pr_list);
1658
1659 cl_plock_release(sa->p_lock);
1660
1661 /* o15-0.2.7: If MultiPath is supported, then SA shall respond to a
1662 SubnAdmGetMulti() containing a valid MultiPathRecord attribute with
1663 a set of zero or more PathRecords satisfying the constraints
1664 indicated in the MultiPathRecord received. The PathRecord Attribute
1665 ID shall be used in the response.
1666 */
1667 p_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
1668 osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
1669
1670 Exit:
1671 OSM_LOG_EXIT(sa->p_log);
1672 }
1673 #endif
1674