2 * Copyright (c) 2004-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) 2008 Xsigo Systems Inc. All rights reserved.
6 * Copyright (c) 2009 HNR Consulting. All rights reserved.
7 * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved.
8 * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
9 * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
11 * This software is available to you under a choice of one of two
12 * licenses. You may choose to be licensed under the terms of the GNU
13 * General Public License (GPL) Version 2, available from the file
14 * COPYING in the main directory of this source tree, or the
15 * OpenIB.org BSD license below:
17 * Redistribution and use in source and binary forms, with or
18 * without modification, are permitted provided that the following
21 * - Redistributions of source code must retain the above
22 * copyright notice, this list of conditions and the following
25 * - Redistributions in binary form must reproduce the above
26 * copyright notice, this list of conditions and the following
27 * disclaimer in the documentation and/or other materials
28 * provided with the distribution.
30 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43 * Implementation of osm_pr_rcv_t.
44 * This object represents the PathRecord Receiver object.
45 * This object is part of the opensm family of objects.
50 #endif /* HAVE_CONFIG_H */
53 #include <arpa/inet.h>
54 #include <sys/socket.h>
55 #include <iba/ib_types.h>
56 #include <complib/cl_qmap.h>
57 #include <complib/cl_passivelock.h>
58 #include <complib/cl_debug.h>
59 #include <complib/cl_qlist.h>
60 #include <opensm/osm_file_ids.h>
61 #define FILE_ID OSM_FILE_SA_PATH_RECORD_C
62 #include <vendor/osm_vendor_api.h>
63 #include <opensm/osm_base.h>
64 #include <opensm/osm_port.h>
65 #include <opensm/osm_node.h>
66 #include <opensm/osm_switch.h>
67 #include <opensm/osm_helper.h>
68 #include <opensm/osm_pkey.h>
69 #include <opensm/osm_multicast.h>
70 #include <opensm/osm_partition.h>
71 #include <opensm/osm_opensm.h>
72 #include <opensm/osm_qos_policy.h>
73 #include <opensm/osm_sa.h>
74 #include <opensm/osm_router.h>
75 #include <opensm/osm_prefix_route.h>
76 #include <opensm/osm_ucast_lash.h>
78 #define SA_PR_RESP_SIZE SA_ITEM_RESP_SIZE(path_rec)
82 static inline boolean_t sa_path_rec_is_tavor_port(IN const osm_port_t * p_port)
84 osm_node_t const *p_node;
87 p_node = p_port->p_node;
88 vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
90 return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
91 ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
92 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
93 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
94 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
98 sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * p_pr,
99 IN const osm_port_t * p_src_port,
100 IN const osm_port_t * p_dest_port,
101 IN const ib_net64_t comp_mask)
103 uint8_t required_mtu;
105 /* only if at least one of the ports is a Tavor device */
106 if (!sa_path_rec_is_tavor_port(p_src_port) &&
107 !sa_path_rec_is_tavor_port(p_dest_port))
111 we can apply the patch if either:
114 3. Required MTU = 1K or 512 or 256
115 4. Required MTU > 256 or 512
117 required_mtu = ib_path_rec_mtu(p_pr);
118 if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
119 (comp_mask & IB_PR_COMPMASK_MTU)) {
120 switch (ib_path_rec_mtu_sel(p_pr)) {
121 case 0: /* must be greater than */
122 case 2: /* exact match */
123 if (IB_MTU_LEN_1024 < required_mtu)
127 case 1: /* must be less than */
128 /* can't be disqualified by this one */
131 case 3: /* largest available */
132 /* the ULP intentionally requested */
133 /* the largest MTU possible */
137 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
146 static ib_api_status_t pr_rcv_get_path_parms(IN osm_sa_t * sa,
147 IN const ib_path_rec_t * p_pr,
148 IN const osm_alias_guid_t * p_src_alias_guid,
149 IN const uint16_t src_lid_ho,
150 IN const osm_alias_guid_t * p_dest_alias_guid,
151 IN const uint16_t dest_lid_ho,
152 IN const ib_net64_t comp_mask,
153 OUT osm_path_parms_t * p_parms)
155 const osm_node_t *p_node;
156 const osm_physp_t *p_physp, *p_physp0;
157 const osm_physp_t *p_src_physp;
158 const osm_physp_t *p_dest_physp;
159 const osm_prtn_t *p_prtn = NULL;
161 struct osm_routing_engine *p_re;
162 const ib_port_info_t *p_pi, *p_pi0;
163 ib_api_status_t status = IB_SUCCESS;
166 uint8_t rate, p0_extended_rate, dest_rate;
168 uint8_t required_mtu;
169 uint8_t required_rate;
170 uint8_t required_pkt_life;
175 ib_slvl_table_t *p_slvl_tbl = NULL;
176 osm_qos_level_t *p_qos_level = NULL;
177 uint16_t valid_sl_mask = 0xffff;
179 int extended, p0_extended;
181 OSM_LOG_ENTER(sa->p_log);
183 dest_lid = cl_hton16(dest_lid_ho);
185 p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
186 p_physp = p_src_alias_guid->p_base_port->p_physp;
187 p_src_physp = p_physp;
188 p_pi = &p_physp->port_info;
189 p_osm = sa->p_subn->p_osm;
190 p_re = p_osm->routing_engine_used;
192 mtu = ib_port_info_get_mtu_cap(p_pi);
193 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
194 rate = ib_port_info_compute_rate(p_pi, extended);
197 Mellanox Tavor device performance is better using 1K MTU.
198 If required MTU and MTU selector are such that 1K is OK
199 and at least one end of the path is Tavor we override the
202 if (sa->p_subn->opt.enable_quirks &&
203 sa_path_rec_apply_tavor_mtu_limit(p_pr,
204 p_src_alias_guid->p_base_port,
205 p_dest_alias_guid->p_base_port,
207 if (mtu > IB_MTU_LEN_1024) {
208 mtu = IB_MTU_LEN_1024;
209 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
210 "Optimized Path MTU to 1K for Mellanox Tavor device\n");
214 Walk the subnet object from source to destination,
215 tracking the most restrictive rate and mtu values along the way...
217 If source port node is a switch, then p_physp should
218 point to the port that routes the destination lid
221 p_node = osm_physp_get_node_ptr(p_physp);
225 * Source node is a switch.
226 * Make sure that p_physp points to the out port of the
227 * switch that routes to the destination lid (dest_lid_ho)
229 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
231 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F02: "
232 "Cannot find routing from LID %u to LID %u on "
233 "switch %s (GUID: 0x%016" PRIx64 ")\n",
234 src_lid_ho, dest_lid_ho, p_node->print_desc,
235 cl_ntoh64(osm_node_get_node_guid(p_node)));
236 status = IB_NOT_FOUND;
241 if (sa->p_subn->opt.qos) {
243 * Whether this node is switch or CA, the IN port for
244 * the sl2vl table is 0, because this is a source node.
246 p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
248 /* update valid SLs that still exist on this route */
249 for (i = 0; i < IB_MAX_NUM_VLS; i++) {
250 if (valid_sl_mask & (1 << i) &&
251 ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
252 valid_sl_mask &= ~(1 << i);
254 if (!valid_sl_mask) {
255 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
256 "All the SLs lead to VL15 on this path\n");
257 status = IB_NOT_FOUND;
265 p_node = osm_physp_get_node_ptr(p_dest_physp);
269 * if destination is switch, we want p_dest_physp to point to port 0
272 osm_switch_get_route_by_lid(p_node->sw, dest_lid);
274 if (p_dest_physp == 0) {
275 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F03: "
276 "Can't find routing from LID %u to LID %u on "
277 "switch %s (GUID: 0x%016" PRIx64 ")\n",
278 src_lid_ho, dest_lid_ho, p_node->print_desc,
279 cl_ntoh64(osm_node_get_node_guid(p_node)));
280 status = IB_NOT_FOUND;
287 * Now go through the path step by step
290 while (p_physp != p_dest_physp) {
292 int tmp_pnum = p_physp->port_num;
293 p_node = osm_physp_get_node_ptr(p_physp);
294 p_physp = osm_physp_get_remote(p_physp);
297 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F05: "
298 "Can't find remote phys port of %s (GUID: "
299 "0x%016"PRIx64") port %d "
300 "while routing from LID %u to LID %u\n",
302 cl_ntoh64(osm_node_get_node_guid(p_node)),
303 tmp_pnum, src_lid_ho, dest_lid_ho);
308 in_port_num = osm_physp_get_port_num(p_physp);
311 This is point to point case (no switch in between)
313 if (p_physp == p_dest_physp)
316 p_node = osm_physp_get_node_ptr(p_physp);
320 There is some sort of problem in the subnet object!
321 If this isn't a switch, we should have reached
322 the destination by now!
324 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F06: "
325 "Internal error, bad path while routing "
326 "%s (GUID: 0x%016"PRIx64") port %d to "
327 "%s (GUID: 0x%016"PRIx64") port %d; "
328 "ended at %s port %d\n",
329 p_src_alias_guid->p_base_port->p_node->print_desc,
330 cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
331 p_src_alias_guid->p_base_port->p_physp->port_num,
332 p_dest_alias_guid->p_base_port->p_node->print_desc,
333 cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
334 p_dest_alias_guid->p_base_port->p_physp->port_num,
342 Check parameters for the ingress port in this switch.
344 p_pi = &p_physp->port_info;
346 if (mtu > ib_port_info_get_mtu_cap(p_pi))
347 mtu = ib_port_info_get_mtu_cap(p_pi);
349 p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
350 p_pi0 = &p_physp0->port_info;
351 p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
352 p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
353 if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
354 rate = p0_extended_rate;
357 Continue with the egress port on this switch.
359 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
361 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F07: "
362 "Dead end path on switch "
363 "%s (GUID: 0x%016"PRIx64") to LID %u\n",
365 cl_ntoh64(osm_node_get_node_guid(p_node)),
371 p_pi = &p_physp->port_info;
373 if (mtu > ib_port_info_get_mtu_cap(p_pi))
374 mtu = ib_port_info_get_mtu_cap(p_pi);
376 p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
377 p_pi0 = &p_physp0->port_info;
378 p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
379 p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
380 if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
381 rate = p0_extended_rate;
383 if (sa->p_subn->opt.qos) {
385 * Check SL2VL table of the switch and update valid SLs
388 osm_physp_get_slvl_tbl(p_physp, in_port_num);
389 for (i = 0; i < IB_MAX_NUM_VLS; i++) {
390 if (valid_sl_mask & (1 << i) &&
391 ib_slvl_table_get(p_slvl_tbl,
393 valid_sl_mask &= ~(1 << i);
395 if (!valid_sl_mask) {
396 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "All the SLs "
397 "lead to VL15 on this path\n");
398 status = IB_NOT_FOUND;
403 /* update number of hops traversed */
405 if (hops > MAX_HOPS) {
406 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F25: "
407 "Path from GUID 0x%016" PRIx64 " (%s port %d) "
408 "to lid %u GUID 0x%016" PRIx64 " (%s port %d) "
409 "needs more than %d hops, max %d hops allowed\n",
410 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
411 p_src_physp->p_node->print_desc,
412 p_src_physp->port_num,
414 cl_ntoh64(osm_physp_get_port_guid
416 p_dest_physp->p_node->print_desc,
417 p_dest_physp->port_num,
420 status = IB_NOT_FOUND;
426 p_physp now points to the destination
428 p_pi = &p_physp->port_info;
430 if (mtu > ib_port_info_get_mtu_cap(p_pi))
431 mtu = ib_port_info_get_mtu_cap(p_pi);
433 extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
434 dest_rate = ib_port_info_compute_rate(p_pi, extended);
435 if (ib_path_compare_rates(rate, dest_rate) > 0)
438 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
439 "Path min MTU = %u, min rate = %u\n", mtu, rate);
442 * Get QoS Level object according to the path request
443 * and adjust path parameters according to QoS settings
445 if (sa->p_subn->opt.qos &&
446 sa->p_subn->p_qos_policy &&
448 osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy,
449 p_pr, p_src_physp, p_dest_physp,
451 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
452 "PathRecord request matches QoS Level '%s' (%s)\n",
453 p_qos_level->name, p_qos_level->use ?
454 p_qos_level->use : "no description");
456 if (p_qos_level->mtu_limit_set
457 && (mtu > p_qos_level->mtu_limit))
458 mtu = p_qos_level->mtu_limit;
460 if (p_qos_level->rate_limit_set
461 && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
462 rate = p_qos_level->rate_limit;
464 if (p_qos_level->sl_set) {
465 sl = p_qos_level->sl;
466 if (!(valid_sl_mask & (1 << sl))) {
467 status = IB_NOT_FOUND;
474 * Set packet lifetime.
475 * According to spec definition IBA 1.2 Table 205
476 * PacketLifeTime description, for loopback paths,
477 * packetLifeTime shall be zero.
479 if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
481 else if (p_qos_level && p_qos_level->pkt_life_set)
482 pkt_life = p_qos_level->pkt_life;
484 pkt_life = sa->p_subn->opt.subnet_timeout;
487 Determine if these values meet the user criteria
488 and adjust appropriately
491 /* we silently ignore cases where only the MTU selector is defined */
492 if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
493 (comp_mask & IB_PR_COMPMASK_MTU)) {
494 required_mtu = ib_path_rec_mtu(p_pr);
495 switch (ib_path_rec_mtu_sel(p_pr)) {
496 case 0: /* must be greater than */
497 if (mtu <= required_mtu)
498 status = IB_NOT_FOUND;
501 case 1: /* must be less than */
502 if (mtu >= required_mtu) {
503 /* adjust to use the highest mtu
504 lower than the required one */
505 if (required_mtu > 1)
506 mtu = required_mtu - 1;
508 status = IB_NOT_FOUND;
512 case 2: /* exact match */
513 if (mtu < required_mtu)
514 status = IB_NOT_FOUND;
519 case 3: /* largest available */
520 /* can't be disqualified by this one */
524 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
530 if (status != IB_SUCCESS)
533 /* we silently ignore cases where only the Rate selector is defined */
534 if ((comp_mask & IB_PR_COMPMASK_RATESELEC) &&
535 (comp_mask & IB_PR_COMPMASK_RATE)) {
536 required_rate = ib_path_rec_rate(p_pr);
537 switch (ib_path_rec_rate_sel(p_pr)) {
538 case 0: /* must be greater than */
539 if (ib_path_compare_rates(rate, required_rate) <= 0)
540 status = IB_NOT_FOUND;
543 case 1: /* must be less than */
544 if (ib_path_compare_rates(rate, required_rate) >= 0) {
545 /* adjust the rate to use the highest rate
546 lower than the required one */
547 rate = ib_path_rate_get_prev(required_rate);
549 status = IB_NOT_FOUND;
553 case 2: /* exact match */
554 if (ib_path_compare_rates(rate, required_rate))
555 status = IB_NOT_FOUND;
557 rate = required_rate;
560 case 3: /* largest available */
561 /* can't be disqualified by this one */
565 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
571 if (status != IB_SUCCESS)
574 /* we silently ignore cases where only the PktLife selector is defined */
575 if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) &&
576 (comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) {
577 required_pkt_life = ib_path_rec_pkt_life(p_pr);
578 switch (ib_path_rec_pkt_life_sel(p_pr)) {
579 case 0: /* must be greater than */
580 if (pkt_life <= required_pkt_life)
581 status = IB_NOT_FOUND;
584 case 1: /* must be less than */
585 if (pkt_life >= required_pkt_life) {
586 /* adjust the lifetime to use the highest possible
587 lower than the required one */
588 if (required_pkt_life > 1)
589 pkt_life = required_pkt_life - 1;
591 status = IB_NOT_FOUND;
595 case 2: /* exact match */
596 if (pkt_life < required_pkt_life)
597 status = IB_NOT_FOUND;
599 pkt_life = required_pkt_life;
602 case 3: /* smallest available */
603 /* can't be disqualified by this one */
607 /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
614 if (status != IB_SUCCESS)
618 * set Pkey for this path record request
621 if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) &&
622 (cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)))
623 pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
624 sa->p_subn->opt.allow_both_pkeys);
626 else if (comp_mask & IB_PR_COMPMASK_PKEY) {
628 * PR request has a specific pkey:
629 * Check that source and destination share this pkey.
630 * If QoS level has pkeys, check that this pkey exists
631 * in the QoS level pkeys.
632 * PR returned pkey is the requested pkey.
635 if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey,
636 sa->p_subn->opt.allow_both_pkeys)) {
637 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: "
638 "Ports 0x%016" PRIx64 " (%s port %d) and "
639 "0x%016" PRIx64 " (%s port %d) "
640 "do not share specified PKey 0x%04x\n",
641 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
642 p_src_physp->p_node->print_desc,
643 p_src_physp->port_num,
644 cl_ntoh64(osm_physp_get_port_guid
646 p_dest_physp->p_node->print_desc,
647 p_dest_physp->port_num,
649 status = IB_NOT_FOUND;
652 if (p_qos_level && p_qos_level->pkey_range_len &&
653 !osm_qos_level_has_pkey(p_qos_level, pkey)) {
654 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: "
655 "QoS level \"%s\" doesn't define specified PKey 0x%04x "
656 "for ports 0x%016" PRIx64 " (%s port %d) and "
657 "0x%016"PRIx64" (%s port %d)\n",
660 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
661 p_src_physp->p_node->print_desc,
662 p_src_alias_guid->p_base_port->p_physp->port_num,
663 cl_ntoh64(osm_physp_get_port_guid
665 p_dest_physp->p_node->print_desc,
666 p_dest_alias_guid->p_base_port->p_physp->port_num);
667 status = IB_NOT_FOUND;
671 } else if (p_qos_level && p_qos_level->pkey_range_len) {
673 * PR request doesn't have a specific pkey, but QoS level
674 * has pkeys - get shared pkey from QoS level pkeys
676 pkey = osm_qos_level_get_shared_pkey(p_qos_level,
677 p_src_physp, p_dest_physp,
678 sa->p_subn->opt.allow_both_pkeys);
680 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: "
681 "Ports 0x%016" PRIx64 " (%s) and "
682 "0x%016" PRIx64 " (%s) do not share "
683 "PKeys defined by QoS level \"%s\"\n",
684 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
685 p_src_physp->p_node->print_desc,
686 cl_ntoh64(osm_physp_get_port_guid
688 p_dest_physp->p_node->print_desc,
690 status = IB_NOT_FOUND;
695 * Neither PR request nor QoS level have pkey.
696 * Just get any shared pkey.
698 pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
699 sa->p_subn->opt.allow_both_pkeys);
701 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: "
702 "Ports src 0x%016"PRIx64" (%s port %d) and "
703 "dst 0x%016"PRIx64" (%s port %d) do not have "
704 "any shared PKeys\n",
705 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
706 p_src_physp->p_node->print_desc,
707 p_src_physp->port_num,
708 cl_ntoh64(osm_physp_get_port_guid
710 p_dest_physp->p_node->print_desc,
711 p_dest_physp->port_num);
712 status = IB_NOT_FOUND;
719 (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
720 pkey & cl_hton16((uint16_t) ~
723 (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
731 if (comp_mask & IB_PR_COMPMASK_SL) {
733 * Specific SL was requested
735 sl = ib_path_rec_sl(p_pr);
737 if (p_qos_level && p_qos_level->sl_set
738 && (p_qos_level->sl != sl)) {
739 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: "
740 "QoS constraints: required PathRecord SL (%u) "
741 "doesn't match QoS policy \"%s\" SL (%u) "
742 "[%s port %d <-> %s port %d]\n", sl,
745 p_src_alias_guid->p_base_port->p_node->print_desc,
746 p_src_alias_guid->p_base_port->p_physp->port_num,
747 p_dest_alias_guid->p_base_port->p_node->print_desc,
748 p_dest_alias_guid->p_base_port->p_physp->port_num);
749 status = IB_NOT_FOUND;
753 } else if (p_qos_level && p_qos_level->sl_set) {
755 * No specific SL was requested, but there is an SL in
758 sl = p_qos_level->sl;
760 if (pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
761 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
762 "QoS level SL (%u) overrides partition SL (%u)\n",
763 p_qos_level->sl, p_prtn->sl);
767 * No specific SL in request or in QoS level - use partition SL
771 /* this may be possible when pkey tables are created somehow in
772 previous runs or things are going wrong here */
773 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1C: "
774 "No partition found for PKey 0x%04x - "
775 "using default SL %d "
776 "[%s port %d <-> %s port %d]\n",
778 p_src_alias_guid->p_base_port->p_node->print_desc,
779 p_src_alias_guid->p_base_port->p_physp->port_num,
780 p_dest_alias_guid->p_base_port->p_node->print_desc,
781 p_dest_alias_guid->p_base_port->p_physp->port_num);
784 } else if (sa->p_subn->opt.qos) {
785 if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
788 for (i = 0; i < IB_MAX_NUM_VLS; i++)
789 if (valid_sl_mask & (1 << i))
796 if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) {
797 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: "
798 "Selected SL (%u) leads to VL15 "
799 "[%s port %d <-> %s port %d]\n",
801 p_src_alias_guid->p_base_port->p_node->print_desc,
802 p_src_alias_guid->p_base_port->p_physp->port_num,
803 p_dest_alias_guid->p_base_port->p_node->print_desc,
804 p_dest_alias_guid->p_base_port->p_physp->port_num);
805 status = IB_NOT_FOUND;
810 * If the routing engine wants to have a say in path SL selection,
811 * send the currently computed SL value as a hint and let the routing
812 * engine override it.
814 if (p_re && p_re->path_sl) {
818 sl = p_re->path_sl(p_re->context, sl,
819 cl_hton16(src_lid_ho), cl_hton16(dest_lid_ho));
821 if ((comp_mask & IB_PR_COMPMASK_SL) && (sl != pr_sl)) {
822 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F2A: "
823 "Requested SL (%u) doesn't match SL calculated"
824 "by routing engine (%u) "
825 "[%s port %d <-> %s port %d]\n",
828 p_src_alias_guid->p_base_port->p_node->print_desc,
829 p_src_alias_guid->p_base_port->p_physp->port_num,
830 p_dest_alias_guid->p_base_port->p_node->print_desc,
831 p_dest_alias_guid->p_base_port->p_physp->port_num);
832 status = IB_NOT_FOUND;
836 /* reset pkey when raw traffic */
837 if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
838 cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))
842 p_parms->rate = rate;
843 p_parms->pkt_life = pkt_life;
844 p_parms->pkey = pkey;
847 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u,"
848 " packet lifetime = %u, pkey = 0x%04X, sl = %u\n",
849 mtu, rate, pkt_life, cl_ntoh16(pkey), sl);
851 OSM_LOG_EXIT(sa->p_log);
855 ib_api_status_t osm_get_path_params(IN osm_sa_t * sa,
856 IN const osm_port_t * p_src_port,
857 IN const uint16_t slid_ho,
858 IN const osm_port_t * p_dest_port,
859 IN const uint16_t dlid_ho,
860 OUT osm_path_parms_t * p_parms)
862 osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
865 if (!p_src_port || !slid_ho || !p_dest_port || !dlid_ho)
866 return IB_INVALID_PARAMETER;
868 memset(&pr, 0, sizeof(ib_path_rec_t));
870 p_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
871 osm_port_get_guid(p_src_port));
872 p_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
873 osm_port_get_guid(p_dest_port));
874 return pr_rcv_get_path_parms(sa, &pr,
875 p_src_alias_guid, slid_ho,
876 p_dest_alias_guid, dlid_ho, 0, p_parms);
879 static void pr_rcv_build_pr(IN osm_sa_t * sa,
880 IN const osm_alias_guid_t * p_src_alias_guid,
881 IN const osm_alias_guid_t * p_dest_alias_guid,
882 IN const ib_gid_t * p_sgid,
883 IN const ib_gid_t * p_dgid,
884 IN const uint16_t src_lid_ho,
885 IN const uint16_t dest_lid_ho,
886 IN const uint8_t preference,
887 IN const osm_path_parms_t * p_parms,
888 OUT ib_path_rec_t * p_pr)
890 const osm_physp_t *p_src_physp, *p_dest_physp;
892 OSM_LOG_ENTER(sa->p_log);
895 p_pr->dgid = *p_dgid;
897 p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
899 p_pr->dgid.unicast.prefix =
900 osm_physp_get_subnet_prefix(p_dest_physp);
901 p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
904 p_pr->sgid = *p_sgid;
906 p_src_physp = p_src_alias_guid->p_base_port->p_physp;
908 p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
909 p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
912 p_pr->dlid = cl_hton16(dest_lid_ho);
913 p_pr->slid = cl_hton16(src_lid_ho);
915 p_pr->hop_flow_raw &= cl_hton32(1 << 31);
917 /* Only set HopLimit if going through a router */
919 p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX);
921 p_pr->pkey = p_parms->pkey;
922 ib_path_rec_set_sl(p_pr, p_parms->sl);
923 ib_path_rec_set_qos_class(p_pr, 0);
924 p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
925 p_pr->rate = (uint8_t) (p_parms->rate | 0x80);
927 /* According to 1.2 spec definition Table 205 PacketLifeTime description,
928 for loopback paths, packetLifeTime shall be zero. */
929 if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
930 p_pr->pkt_life = 0x80; /* loopback */
932 p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
934 p_pr->preference = preference;
936 /* always return num_path = 0 so this is only the reversible component */
937 if (p_parms->reversible)
938 p_pr->num_path = 0x80;
940 OSM_LOG_EXIT(sa->p_log);
943 static osm_sa_item_t *pr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
944 IN const ib_path_rec_t * p_pr,
945 IN const osm_alias_guid_t * p_src_alias_guid,
946 IN const osm_alias_guid_t * p_dest_alias_guid,
947 IN const ib_gid_t * p_sgid,
948 IN const ib_gid_t * p_dgid,
949 IN const uint16_t src_lid_ho,
950 IN const uint16_t dest_lid_ho,
951 IN const ib_net64_t comp_mask,
952 IN const uint8_t preference)
954 osm_path_parms_t path_parms;
955 osm_path_parms_t rev_path_parms;
956 osm_sa_item_t *p_pr_item;
957 ib_api_status_t status, rev_path_status;
959 OSM_LOG_ENTER(sa->p_log);
961 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
962 src_lid_ho, dest_lid_ho);
964 p_pr_item = malloc(SA_PR_RESP_SIZE);
965 if (p_pr_item == NULL) {
966 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: "
967 "Unable to allocate path record\n");
970 memset(p_pr_item, 0, SA_PR_RESP_SIZE);
972 status = pr_rcv_get_path_parms(sa, p_pr, p_src_alias_guid, src_lid_ho,
973 p_dest_alias_guid, dest_lid_ho,
974 comp_mask, &path_parms);
976 if (status != IB_SUCCESS) {
982 /* now try the reversible path */
983 rev_path_status = pr_rcv_get_path_parms(sa, p_pr, p_dest_alias_guid,
984 dest_lid_ho, p_src_alias_guid,
985 src_lid_ho, comp_mask,
988 path_parms.reversible = (rev_path_status == IB_SUCCESS);
990 /* did we get a Reversible Path compmask ? */
992 NOTE that if the reversible component = 0, it is a don't care
993 rather than requiring non-reversible paths ...
994 see Vol1 Ver1.2 p900 l16
996 if ((comp_mask & IB_PR_COMPMASK_REVERSIBLE) &&
997 !path_parms.reversible && (p_pr->num_path & 0x80)) {
998 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
999 "Requested reversible path but failed to get one\n");
1005 pr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, p_sgid, p_dgid,
1006 src_lid_ho, dest_lid_ho, preference, &path_parms,
1007 &p_pr_item->resp.path_rec);
1010 OSM_LOG_EXIT(sa->p_log);
1014 static void pr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
1015 IN const ib_sa_mad_t *sa_mad,
1016 IN const osm_port_t * p_req_port,
1017 IN const osm_alias_guid_t * p_src_alias_guid,
1018 IN const osm_alias_guid_t * p_dest_alias_guid,
1019 IN const ib_gid_t * p_sgid,
1020 IN const ib_gid_t * p_dgid,
1021 IN cl_qlist_t * p_list)
1023 const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1024 ib_net64_t comp_mask = sa_mad->comp_mask;
1025 osm_sa_item_t *p_pr_item;
1026 uint16_t src_lid_min_ho;
1027 uint16_t src_lid_max_ho;
1028 uint16_t dest_lid_min_ho;
1029 uint16_t dest_lid_max_ho;
1030 uint16_t src_lid_ho;
1031 uint16_t dest_lid_ho;
1034 unsigned iterations, src_offset, dest_offset;
1036 OSM_LOG_ENTER(sa->p_log);
1038 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1039 "Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
1040 cl_ntoh64(p_src_alias_guid->alias_guid),
1041 cl_ntoh64(p_dest_alias_guid->alias_guid));
1043 /* Check that the req_port, src_port and dest_port all share a
1044 pkey. The check is done on the default physical port of the ports. */
1045 if (osm_port_share_pkey(sa->p_log, p_req_port,
1046 p_src_alias_guid->p_base_port,
1047 sa->p_subn->opt.allow_both_pkeys) == FALSE
1048 || osm_port_share_pkey(sa->p_log, p_req_port,
1049 p_dest_alias_guid->p_base_port,
1050 sa->p_subn->opt.allow_both_pkeys) == FALSE
1051 || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
1052 p_dest_alias_guid->p_base_port,
1053 sa->p_subn->opt.allow_both_pkeys) == FALSE)
1054 /* One of the pairs doesn't share a pkey so the path is disqualified. */
1058 We shouldn't be here if the paths are disqualified in some way...
1059 Thus, we assume every possible connection is valid.
1061 We desire to return high-quality paths first.
1062 In OpenSM, higher quality means least overlap with other paths.
1063 This is acheived in practice by returning paths with
1064 different LID value on each end, which means these
1065 paths are more redundant that paths with the same LID repeated
1066 on one side. For example, in OpenSM the paths between two
1067 endpoints with LMC = 1 might be as follows:
1069 Port A, LID 1 <-> Port B, LID 3
1070 Port A, LID 1 <-> Port B, LID 4
1071 Port A, LID 2 <-> Port B, LID 3
1072 Port A, LID 2 <-> Port B, LID 4
1074 The OpenSM unicast routing algorithms attempt to disperse each path
1075 to as varied a physical path as is reasonable. 1<->3 and 1<->4 have
1076 more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
1078 OpenSM ranks paths in three preference groups:
1080 Preference Value Description
1081 ---------------- -------------------------------------------
1082 0 Redundant in both directions with other
1083 pref value = 0 paths
1085 1 Redundant in one direction with other
1086 pref value = 0 and pref value = 1 paths
1088 2 Not redundant in either direction with
1093 SA clients don't need to know these details, only that the lower
1094 preference paths are preferred, as stated in the spec. The paths
1095 may not actually be physically redundant depending on the topology
1096 of the subnet, but the point of LMC > 0 is to offer redundancy,
1097 so it is assumed that the subnet is physically appropriate for the
1098 specified LMC value. A more advanced implementation would inspect for
1099 physical redundancy, but I'm not going to bother with that now.
1103 Refine our search if the client specified end-point LIDs
1105 if (comp_mask & IB_PR_COMPMASK_DLID)
1106 dest_lid_max_ho = dest_lid_min_ho = cl_ntoh16(p_pr->dlid);
1108 osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
1109 &dest_lid_min_ho, &dest_lid_max_ho);
1111 if (comp_mask & IB_PR_COMPMASK_SLID)
1112 src_lid_max_ho = src_lid_min_ho = cl_ntoh16(p_pr->slid);
1114 osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
1115 &src_lid_min_ho, &src_lid_max_ho);
1117 if (src_lid_min_ho == 0) {
1118 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1119 "Obtained source LID of 0. No such LID possible "
1121 p_src_alias_guid->p_base_port->p_node->print_desc,
1122 p_src_alias_guid->p_base_port->p_physp->port_num);
1126 if (dest_lid_min_ho == 0) {
1127 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1128 "Obtained destination LID of 0. No such LID possible "
1130 p_dest_alias_guid->p_base_port->p_node->print_desc,
1131 p_dest_alias_guid->p_base_port->p_physp->port_num);
1135 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1136 "Src LIDs [%u-%u], Dest LIDs [%u-%u]\n",
1137 src_lid_min_ho, src_lid_max_ho,
1138 dest_lid_min_ho, dest_lid_max_ho);
1140 src_lid_ho = src_lid_min_ho;
1141 dest_lid_ho = dest_lid_min_ho;
1144 Preferred paths come first in OpenSM
1149 /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
1150 if (sa_mad->method == IB_MAD_METHOD_GET)
1152 else if (comp_mask & IB_PR_COMPMASK_NUMBPATH)
1153 iterations = ib_path_rec_num_path(p_pr);
1155 iterations = (unsigned) (-1);
1157 while (path_num < iterations) {
1159 These paths are "fully redundant"
1162 p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
1165 src_lid_ho, dest_lid_ho,
1166 comp_mask, preference);
1169 cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1173 if (++src_lid_ho > src_lid_max_ho)
1176 if (++dest_lid_ho > dest_lid_max_ho)
1181 Check if we've accumulated all the paths that the user cares to see
1183 if (path_num == iterations)
1187 Don't bother reporting preference 1 paths for now.
1188 It's more trouble than it's worth and can only occur
1189 if ports have different LMC values, which isn't supported
1190 by OpenSM right now anyway.
1193 src_lid_ho = src_lid_min_ho;
1194 dest_lid_ho = dest_lid_min_ho;
1199 Iterate over the remaining paths
1201 while (path_num < iterations) {
1205 if (dest_lid_ho > dest_lid_max_ho) {
1209 if (src_lid_ho > src_lid_max_ho)
1213 dest_lid_ho = dest_lid_min_ho;
1217 These paths are "fully non-redundant" with paths already
1218 identified above and consequently not of much value.
1220 Don't return paths we already identified above, as indicated
1221 by the offset values being equal.
1223 if (src_offset == dest_offset)
1224 continue; /* already reported */
1226 p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
1227 p_dest_alias_guid, p_sgid,
1229 dest_lid_ho, comp_mask,
1233 cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1239 OSM_LOG_EXIT(sa->p_log);
1242 /* Find the router port that is configured to handle this prefix, if any */
1243 static ib_net64_t find_router(const osm_sa_t *sa, ib_net64_t prefix)
1245 osm_prefix_route_t *route = NULL;
1247 cl_qlist_t *l = &sa->p_subn->prefix_routes_list;
1250 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix "
1251 "0x%016" PRIx64 "\n", cl_ntoh64(prefix));
1253 for (i = cl_qlist_head(l); i != cl_qlist_end(l); i = cl_qlist_next(i)) {
1254 osm_prefix_route_t *r = (osm_prefix_route_t *)i;
1255 if (!r->prefix || r->prefix == prefix) {
1263 if (route->guid == 0) /* first router */
1264 rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl);
1266 rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl,
1269 if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl))
1272 return osm_port_get_guid(osm_router_get_port_ptr(rtr));
1275 ib_net16_t osm_pr_get_end_points(IN osm_sa_t * sa,
1276 IN const ib_sa_mad_t *sa_mad,
1277 OUT const osm_alias_guid_t ** pp_src_alias_guid,
1278 OUT const osm_alias_guid_t ** pp_dest_alias_guid,
1279 OUT const osm_port_t ** pp_src_port,
1280 OUT const osm_port_t ** pp_dest_port,
1281 OUT const ib_gid_t ** pp_sgid,
1282 OUT const ib_gid_t ** pp_dgid)
1284 const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1285 ib_net64_t comp_mask = sa_mad->comp_mask;
1286 ib_net64_t dest_guid;
1287 ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
1289 OSM_LOG_ENTER(sa->p_log);
1292 Determine what fields are valid and then get a pointer
1293 to the source and destination port objects, if possible.
1297 Check a few easy disqualifying cases up front before getting
1301 *pp_src_alias_guid = NULL;
1302 *pp_src_port = NULL;
1303 if (comp_mask & IB_PR_COMPMASK_SGID) {
1304 if (!ib_gid_is_link_local(&p_pr->sgid)) {
1305 if (ib_gid_get_subnet_prefix(&p_pr->sgid) !=
1306 sa->p_subn->opt.subnet_prefix) {
1308 This 'error' is the client's fault (bad gid)
1309 so don't enter it as an error in our own log.
1310 Return an error response to the client.
1312 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1313 "Non local SGID subnet prefix 0x%016"
1315 cl_ntoh64(p_pr->sgid.unicast.prefix));
1316 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1321 *pp_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
1322 p_pr->sgid.unicast.interface_id);
1323 if (!*pp_src_alias_guid) {
1325 This 'error' is the client's fault (bad gid) so
1326 don't enter it as an error in our own log.
1327 Return an error response to the client.
1329 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1330 "No source port with GUID 0x%016" PRIx64 "\n",
1331 cl_ntoh64(p_pr->sgid.unicast.interface_id));
1332 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1336 *pp_sgid = &p_pr->sgid;
1339 if (comp_mask & IB_PR_COMPMASK_SLID) {
1340 *pp_src_port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
1341 if (!*pp_src_port) {
1343 This 'error' is the client's fault (bad lid) so
1344 don't enter it as an error in our own log.
1345 Return an error response to the client.
1347 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No source port "
1348 "with LID %u\n", cl_ntoh16(p_pr->slid));
1349 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1354 *pp_dest_alias_guid = NULL;
1355 *pp_dest_port = NULL;
1356 if (comp_mask & IB_PR_COMPMASK_DGID) {
1357 if (!ib_gid_is_link_local(&p_pr->dgid) &&
1358 !ib_gid_is_multicast(&p_pr->dgid) &&
1359 ib_gid_get_subnet_prefix(&p_pr->dgid) !=
1360 sa->p_subn->opt.subnet_prefix) {
1361 dest_guid = find_router(sa, p_pr->dgid.unicast.prefix);
1363 char gid_str[INET6_ADDRSTRLEN];
1364 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1365 "Off subnet DGID %s, but router not "
1367 inet_ntop(AF_INET6, p_pr->dgid.raw,
1368 gid_str, sizeof(gid_str)));
1369 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1373 *pp_dgid = &p_pr->dgid;
1375 dest_guid = p_pr->dgid.unicast.interface_id;
1377 *pp_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
1379 if (!*pp_dest_alias_guid) {
1381 This 'error' is the client's fault (bad gid) so
1382 don't enter it as an error in our own log.
1383 Return an error response to the client.
1385 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1386 "No dest port with GUID 0x%016" PRIx64 "\n",
1387 cl_ntoh64(dest_guid));
1388 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1393 if (comp_mask & IB_PR_COMPMASK_DLID) {
1394 *pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_pr->dlid);
1395 if (!*pp_dest_port) {
1397 This 'error' is the client's fault (bad lid)
1398 so don't enter it as an error in our own log.
1399 Return an error response to the client.
1401 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No dest port "
1402 "with LID %u\n", cl_ntoh16(p_pr->dlid));
1403 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1409 OSM_LOG_EXIT(sa->p_log);
1413 static void pr_rcv_process_world(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1414 IN const osm_port_t * requester_port,
1415 IN const ib_gid_t * p_sgid,
1416 IN const ib_gid_t * p_dgid,
1417 IN cl_qlist_t * p_list)
1419 const cl_qmap_t *p_tbl;
1420 const osm_alias_guid_t *p_dest_alias_guid, *p_src_alias_guid;
1422 OSM_LOG_ENTER(sa->p_log);
1425 Iterate the entire port space over itself.
1426 A path record from a port to itself is legit, so no
1427 need for a special case there.
1429 We compute both A -> B and B -> A, since we don't have
1430 any check to determine the reversability of the paths.
1432 p_tbl = &sa->p_subn->alias_port_guid_tbl;
1434 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1435 while (p_dest_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1436 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1437 while (p_src_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1438 pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1441 p_sgid, p_dgid, p_list);
1442 if (sa_mad->method == IB_MAD_METHOD_GET &&
1443 cl_qlist_count(p_list) > 0)
1447 (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1451 (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1455 OSM_LOG_EXIT(sa->p_log);
1458 void osm_pr_process_half(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1459 IN const osm_port_t * requester_port,
1460 IN const osm_alias_guid_t * p_src_alias_guid,
1461 IN const osm_alias_guid_t * p_dest_alias_guid,
1462 IN const ib_gid_t * p_sgid,
1463 IN const ib_gid_t * p_dgid,
1464 IN cl_qlist_t * p_list)
1466 const cl_qmap_t *p_tbl;
1467 const osm_alias_guid_t *p_alias_guid;
1469 OSM_LOG_ENTER(sa->p_log);
1472 Iterate over every port, looking for matches...
1473 A path record from a port to itself is legit, so no
1474 need to special case that one.
1476 p_tbl = &sa->p_subn->alias_port_guid_tbl;
1478 if (p_src_alias_guid) {
1480 The src port if fixed, so iterate over destination ports.
1482 p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1483 while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1484 pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1487 p_sgid, p_dgid, p_list);
1488 if (sa_mad->method == IB_MAD_METHOD_GET &&
1489 cl_qlist_count(p_list) > 0)
1491 p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
1495 The dest port if fixed, so iterate over source ports.
1497 p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1498 while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1499 pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1501 p_dest_alias_guid, p_sgid,
1503 if (sa_mad->method == IB_MAD_METHOD_GET &&
1504 cl_qlist_count(p_list) > 0)
1506 p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
1510 OSM_LOG_EXIT(sa->p_log);
1513 void osm_pr_process_pair(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1514 IN const osm_port_t * requester_port,
1515 IN const osm_alias_guid_t * p_src_alias_guid,
1516 IN const osm_alias_guid_t * p_dest_alias_guid,
1517 IN const ib_gid_t * p_sgid,
1518 IN const ib_gid_t * p_dgid,
1519 IN cl_qlist_t * p_list)
1521 OSM_LOG_ENTER(sa->p_log);
1523 pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, p_src_alias_guid,
1524 p_dest_alias_guid, p_sgid, p_dgid, p_list);
1526 OSM_LOG_EXIT(sa->p_log);
1529 static ib_api_status_t pr_match_mgrp_attributes(IN osm_sa_t * sa,
1530 IN const ib_sa_mad_t * sa_mad,
1531 IN const osm_mgrp_t * p_mgrp)
1533 const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1534 ib_net64_t comp_mask = sa_mad->comp_mask;
1535 const osm_port_t *port;
1536 ib_api_status_t status = IB_ERROR;
1537 uint32_t flow_label;
1538 uint8_t sl, hop_limit;
1540 OSM_LOG_ENTER(sa->p_log);
1542 /* check that MLID of the MC group matches the PathRecord DLID */
1543 if ((comp_mask & IB_PR_COMPMASK_DLID) && p_mgrp->mlid != p_pr->dlid) {
1544 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1545 "DLID 0x%x is not MLID 0x%x for MC group\n",
1546 cl_ntoh16(p_pr->dlid), cl_ntoh16(p_mgrp->mlid));
1550 /* If SGID and/or SLID specified, should validate as member of MC group */
1551 if (comp_mask & IB_PR_COMPMASK_SGID) {
1552 if (!osm_mgrp_get_mcm_alias_guid(p_mgrp,
1553 p_pr->sgid.unicast.interface_id)) {
1554 char gid_str[INET6_ADDRSTRLEN];
1555 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1556 "SGID %s is not a member of MC group\n",
1557 inet_ntop(AF_INET6, p_pr->sgid.raw,
1558 gid_str, sizeof gid_str));
1563 if (comp_mask & IB_PR_COMPMASK_SLID) {
1564 port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
1565 if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) {
1566 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1567 "Either no port with SLID %u found or "
1568 "SLID not a member of MC group\n",
1569 cl_ntoh16(p_pr->slid));
1574 /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
1575 if ((comp_mask & IB_PR_COMPMASK_PKEY) &&
1576 p_pr->pkey != p_mgrp->mcmember_rec.pkey) {
1577 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1578 "Pkey 0x%x doesn't match MC group Pkey 0x%x\n",
1579 cl_ntoh16(p_pr->pkey),
1580 cl_ntoh16(p_mgrp->mcmember_rec.pkey));
1584 ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
1585 &sl, &flow_label, &hop_limit);
1587 if ((comp_mask & IB_PR_COMPMASK_SL) && ib_path_rec_sl(p_pr) != sl) {
1588 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1589 "SL %d doesn't match MC group SL %d\n",
1590 ib_path_rec_sl(p_pr), sl);
1594 /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
1595 if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) &&
1596 sa_mad->method != IB_MAD_METHOD_GET &&
1597 ib_path_rec_num_path(p_pr) == 0) {
1598 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1599 "Number of paths requested is 0\n");
1603 if ((comp_mask & IB_PR_COMPMASK_FLOWLABEL) &&
1604 ib_path_rec_flow_lbl(p_pr) != flow_label) {
1605 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1606 "Flow label 0x%x doesn't match MC group "
1607 " flow label 0x%x\n",
1608 ib_path_rec_flow_lbl(p_pr), flow_label);
1612 if ((comp_mask & IB_PR_COMPMASK_HOPLIMIT) &&
1613 ib_path_rec_hop_limit(p_pr) != hop_limit) {
1614 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1615 "Hop limit %u doesn't match MC group hop limit %u\n",
1616 ib_path_rec_hop_limit(p_pr), hop_limit);
1621 if ((comp_mask & IB_PR_COMPMASK_TCLASS) &&
1622 p_pr->tclass != p_mgrp->mcmember_rec.tclass) {
1623 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1624 "TClass 0x%02x doesn't match MC group TClass 0x%02x\n",
1625 p_pr->tclass, p_mgrp->mcmember_rec.tclass);
1629 status = IB_SUCCESS;
1632 OSM_LOG_EXIT(sa->p_log);
1636 static void pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad,
1639 ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad);
1641 ib_api_status_t status;
1642 osm_sa_item_t *pr_item;
1643 uint32_t flow_label;
1644 uint8_t sl, hop_limit;
1646 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n");
1648 mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid);
1650 char gid_str[INET6_ADDRSTRLEN];
1651 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: "
1652 "No MC group found for PathRecord destination GID %s\n",
1653 inet_ntop(AF_INET6, pr->dgid.raw, gid_str,
1658 /* Make sure the rest of the PathRecord matches the MC group attributes */
1659 status = pr_match_mgrp_attributes(sa, sa_mad, mgrp);
1660 if (status != IB_SUCCESS) {
1661 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: "
1662 "MC group attributes don't match PathRecord request\n");
1666 pr_item = malloc(SA_PR_RESP_SIZE);
1667 if (pr_item == NULL) {
1668 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: "
1669 "Unable to allocate path record for MC group\n");
1672 memset(pr_item, 0, sizeof(cl_list_item_t));
1674 /* Copy PathRecord request into response */
1675 pr_item->resp.path_rec = *pr;
1677 /* Now, use the MC info to cruft up the PathRecord response */
1678 pr_item->resp.path_rec.dgid = mgrp->mcmember_rec.mgid;
1679 pr_item->resp.path_rec.dlid = mgrp->mcmember_rec.mlid;
1680 pr_item->resp.path_rec.tclass = mgrp->mcmember_rec.tclass;
1681 pr_item->resp.path_rec.num_path = 1;
1682 pr_item->resp.path_rec.pkey = mgrp->mcmember_rec.pkey;
1684 /* MTU, rate, and packet lifetime should be exactly */
1685 pr_item->resp.path_rec.mtu = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.mtu;
1686 pr_item->resp.path_rec.rate = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.rate;
1687 pr_item->resp.path_rec.pkt_life = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.pkt_life;
1689 /* SL, Hop Limit, and Flow Label */
1690 ib_member_get_sl_flow_hop(mgrp->mcmember_rec.sl_flow_hop,
1691 &sl, &flow_label, &hop_limit);
1692 ib_path_rec_set_sl(&pr_item->resp.path_rec, sl);
1693 ib_path_rec_set_qos_class(&pr_item->resp.path_rec, 0);
1695 /* HopLimit is not yet set in non link local MC groups */
1696 /* If it were, this would not be needed */
1697 if (ib_mgid_get_scope(&mgrp->mcmember_rec.mgid) !=
1698 IB_MC_SCOPE_LINK_LOCAL)
1699 hop_limit = IB_HOPLIMIT_MAX;
1701 pr_item->resp.path_rec.hop_flow_raw =
1702 cl_hton32(hop_limit) | (flow_label << 8);
1704 cl_qlist_insert_tail(list, &pr_item->list_item);
1707 void osm_pr_rcv_process(IN void *context, IN void *data)
1709 osm_sa_t *sa = context;
1710 osm_madw_t *p_madw = data;
1711 const ib_sa_mad_t *p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1712 ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(p_sa_mad);
1714 const ib_gid_t *p_sgid = NULL, *p_dgid = NULL;
1715 const osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
1716 const osm_port_t *p_src_port, *p_dest_port;
1717 osm_port_t *requester_port;
1720 OSM_LOG_ENTER(sa->p_log);
1724 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD);
1726 /* we only support SubnAdmGet and SubnAdmGetTable methods */
1727 if (p_sa_mad->method != IB_MAD_METHOD_GET &&
1728 p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
1729 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: "
1730 "Unsupported Method (%s) for PathRecord request\n",
1731 ib_get_sa_method_str(p_sa_mad->method));
1732 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1736 /* Validate rate if supplied */
1737 if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_RATESELEC) &&
1738 (p_sa_mad->comp_mask & IB_PR_COMPMASK_RATE)) {
1739 rate = ib_path_rec_rate(p_pr);
1740 if (!ib_rate_is_valid(rate)) {
1741 osm_sa_send_error(sa, p_madw,
1742 IB_SA_MAD_STATUS_REQ_INVALID);
1746 /* Validate MTU if supplied */
1747 if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
1748 (p_sa_mad->comp_mask & IB_PR_COMPMASK_MTU)) {
1749 mtu = ib_path_rec_mtu(p_pr);
1750 if (!ib_mtu_is_valid(mtu)) {
1751 osm_sa_send_error(sa, p_madw,
1752 IB_SA_MAD_STATUS_REQ_INVALID);
1757 /* Make sure either none or both ServiceID parameters are supplied */
1758 if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) != 0 &&
1759 (p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) !=
1760 IB_PR_COMPMASK_SERVICEID) {
1761 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
1765 cl_qlist_init(&pr_list);
1768 Most SA functions (including this one) are read-only on the
1769 subnet object, so we grab the lock non-exclusively.
1771 cl_plock_acquire(sa->p_lock);
1773 /* update the requester physical port */
1774 requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
1775 osm_madw_get_mad_addr_ptr
1777 if (requester_port == NULL) {
1778 cl_plock_release(sa->p_lock);
1779 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F16: "
1780 "Cannot find requester physical port\n");
1784 if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
1785 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1786 "Requester port GUID 0x%" PRIx64 "\n",
1787 cl_ntoh64(osm_port_get_guid(requester_port)));
1788 osm_dump_path_record_v2(sa->p_log, p_pr, FILE_ID, OSM_LOG_DEBUG);
1791 /* Handle multicast destinations separately */
1792 if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_DGID) &&
1793 ib_gid_is_multicast(&p_pr->dgid)) {
1794 pr_process_multicast(sa, p_sa_mad, &pr_list);
1798 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n");
1800 if (osm_pr_get_end_points(sa, p_sa_mad,
1801 &p_src_alias_guid, &p_dest_alias_guid,
1802 &p_src_port, &p_dest_port,
1803 &p_sgid, &p_dgid) != IB_SA_MAD_STATUS_SUCCESS)
1806 if (p_src_alias_guid && p_src_port &&
1807 p_src_alias_guid->p_base_port != p_src_port) {
1808 cl_plock_release(sa->p_lock);
1809 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1810 "Requester port GUID 0x%" PRIx64 ": Port for SGUID "
1811 "0x%" PRIx64 " not same as port for SLID %u\n",
1812 cl_ntoh64(osm_port_get_guid(requester_port)),
1813 cl_ntoh64(p_pr->sgid.unicast.interface_id),
1814 cl_ntoh16(p_pr->slid));
1815 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1819 if (p_dest_alias_guid && p_dest_port &&
1820 p_dest_alias_guid->p_base_port != p_dest_port) {
1821 cl_plock_release(sa->p_lock);
1822 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1823 "Requester port GUID 0x%" PRIx64 ": Port for DGUID "
1824 "0x%" PRIx64 " not same as port for DLID %u\n",
1825 cl_ntoh64(osm_port_get_guid(requester_port)),
1826 cl_ntoh64(p_pr->dgid.unicast.interface_id),
1827 cl_ntoh16(p_pr->dlid));
1828 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1833 What happens next depends on the type of endpoint information
1834 that was specified....
1836 if (p_src_alias_guid) {
1837 if (p_dest_alias_guid)
1838 osm_pr_process_pair(sa, p_sa_mad, requester_port,
1839 p_src_alias_guid, p_dest_alias_guid,
1840 p_sgid, p_dgid, &pr_list);
1841 else if (!p_dest_port)
1842 osm_pr_process_half(sa, p_sa_mad, requester_port,
1843 p_src_alias_guid, NULL, p_sgid,
1846 /* Get all alias GUIDs for the dest port */
1847 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1848 while (p_dest_alias_guid !=
1849 (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1850 if (osm_get_port_by_alias_guid(sa->p_subn, p_dest_alias_guid->alias_guid) ==
1852 osm_pr_process_pair(sa, p_sa_mad,
1858 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1859 cl_qlist_count(&pr_list) > 0)
1862 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1866 if (p_dest_alias_guid && !p_src_port)
1867 osm_pr_process_half(sa, p_sa_mad, requester_port,
1868 NULL, p_dest_alias_guid, p_sgid,
1870 else if (!p_src_port && !p_dest_port)
1872 Katie, bar the door!
1874 pr_rcv_process_world(sa, p_sa_mad, requester_port,
1875 p_sgid, p_dgid, &pr_list);
1876 else if (p_dest_alias_guid && p_src_port) {
1877 /* Get all alias GUIDs for the src port */
1878 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1879 while (p_src_alias_guid !=
1880 (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1881 if (osm_get_port_by_alias_guid(sa->p_subn,
1882 p_src_alias_guid->alias_guid) ==
1884 osm_pr_process_pair(sa, p_sa_mad,
1890 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1891 cl_qlist_count(&pr_list) > 0)
1893 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1895 } else if (p_src_port && !p_dest_port) {
1896 /* Get all alias GUIDs for the src port */
1897 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1898 while (p_src_alias_guid !=
1899 (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1900 if (osm_get_port_by_alias_guid(sa->p_subn,
1901 p_src_alias_guid->alias_guid) ==
1903 osm_pr_process_half(sa, p_sa_mad,
1908 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1910 } else if (p_dest_port && !p_src_port) {
1911 /* Get all alias GUIDs for the dest port */
1912 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1913 while (p_dest_alias_guid !=
1914 (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1915 if (osm_get_port_by_alias_guid(sa->p_subn,
1916 p_dest_alias_guid->alias_guid) ==
1918 osm_pr_process_half(sa, p_sa_mad,
1924 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1927 /* Get all alias GUIDs for the src port */
1928 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1929 while (p_src_alias_guid !=
1930 (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1931 if (osm_get_port_by_alias_guid(sa->p_subn,
1932 p_src_alias_guid->alias_guid) ==
1934 /* Get all alias GUIDs for the dest port */
1935 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1936 while (p_dest_alias_guid !=
1937 (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1938 if (osm_get_port_by_alias_guid(sa->p_subn,
1939 p_dest_alias_guid->alias_guid) ==
1941 osm_pr_process_pair(sa,
1949 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1950 cl_qlist_count(&pr_list) > 0)
1952 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1955 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1956 cl_qlist_count(&pr_list) > 0)
1958 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1964 cl_plock_release(sa->p_lock);
1966 /* Now, (finally) respond to the PathRecord request */
1967 osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
1970 OSM_LOG_EXIT(sa->p_log);