2 * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2006 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.
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:
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
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.
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
39 * Implementation of osm_pr_rcv_t.
40 * This object represents the PathRecord Receiver object.
41 * This object is part of the opensm family of objects.
46 #endif /* HAVE_CONFIG_H */
49 #include <arpa/inet.h>
50 #include <iba/ib_types.h>
51 #include <complib/cl_qmap.h>
52 #include <complib/cl_passivelock.h>
53 #include <complib/cl_debug.h>
54 #include <complib/cl_qlist.h>
55 #include <vendor/osm_vendor_api.h>
56 #include <opensm/osm_base.h>
57 #include <opensm/osm_port.h>
58 #include <opensm/osm_node.h>
59 #include <opensm/osm_switch.h>
60 #include <opensm/osm_helper.h>
61 #include <opensm/osm_pkey.h>
62 #include <opensm/osm_multicast.h>
63 #include <opensm/osm_partition.h>
64 #include <opensm/osm_opensm.h>
65 #include <opensm/osm_qos_policy.h>
66 #include <opensm/osm_sa.h>
67 #include <opensm/osm_router.h>
68 #include <opensm/osm_prefix_route.h>
70 #include <sys/socket.h>
72 extern uint8_t osm_get_lash_sl(osm_opensm_t * p_osm,
73 const osm_port_t * p_src_port,
74 const osm_port_t * p_dst_port);
76 typedef struct osm_pr_item {
77 cl_list_item_t list_item;
78 ib_path_rec_t path_rec;
81 typedef struct osm_path_parms {
90 static const ib_gid_t zero_gid = { {0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00,
92 0x00, 0x00, 0x00, 0x00,
93 0x00, 0x00, 0x00, 0x00},
96 /**********************************************************************
97 **********************************************************************/
98 static inline boolean_t
99 __osm_sa_path_rec_is_tavor_port(IN const osm_port_t * const p_port)
101 osm_node_t const *p_node;
104 p_node = p_port->p_node;
105 vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
107 return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
108 ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
109 (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
110 (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
111 (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
114 /**********************************************************************
115 **********************************************************************/
117 __osm_sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * const p_pr,
118 IN const osm_port_t * const p_src_port,
119 IN const osm_port_t * const p_dest_port,
120 IN const ib_net64_t comp_mask)
122 uint8_t required_mtu;
124 /* only if at least one of the ports is a Tavor device */
125 if (!__osm_sa_path_rec_is_tavor_port(p_src_port) &&
126 !__osm_sa_path_rec_is_tavor_port(p_dest_port))
130 we can apply the patch if either:
133 3. Required MTU = 1K or 512 or 256
134 4. Required MTU > 256 or 512
136 required_mtu = ib_path_rec_mtu(p_pr);
137 if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
138 (comp_mask & IB_PR_COMPMASK_MTU)) {
139 switch (ib_path_rec_mtu_sel(p_pr)) {
140 case 0: /* must be greater than */
141 case 2: /* exact match */
142 if (IB_MTU_LEN_1024 < required_mtu)
146 case 1: /* must be less than */
147 /* can't be disqualified by this one */
150 case 3: /* largest available */
151 /* the ULP intentionally requested */
152 /* the largest MTU possible */
157 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
166 /**********************************************************************
167 **********************************************************************/
168 static ib_api_status_t
169 __osm_pr_rcv_get_path_parms(IN osm_sa_t * sa,
170 IN const ib_path_rec_t * const p_pr,
171 IN const osm_port_t * const p_src_port,
172 IN const osm_port_t * const p_dest_port,
173 IN const uint16_t dest_lid_ho,
174 IN const ib_net64_t comp_mask,
175 OUT osm_path_parms_t * const p_parms)
177 const osm_node_t *p_node;
178 const osm_physp_t *p_physp;
179 const osm_physp_t *p_src_physp;
180 const osm_physp_t *p_dest_physp;
181 const osm_prtn_t *p_prtn = NULL;
183 const ib_port_info_t *p_pi;
184 ib_api_status_t status = IB_SUCCESS;
189 uint8_t required_mtu;
190 uint8_t required_rate;
191 uint8_t required_pkt_life;
196 ib_slvl_table_t *p_slvl_tbl = NULL;
197 osm_qos_level_t *p_qos_level = NULL;
198 uint16_t valid_sl_mask = 0xffff;
201 OSM_LOG_ENTER(sa->p_log);
203 dest_lid = cl_hton16(dest_lid_ho);
205 p_dest_physp = p_dest_port->p_physp;
206 p_physp = p_src_port->p_physp;
207 p_src_physp = p_physp;
208 p_pi = &p_physp->port_info;
209 p_osm = sa->p_subn->p_osm;
211 mtu = ib_port_info_get_mtu_cap(p_pi);
212 rate = ib_port_info_compute_rate(p_pi);
215 Mellanox Tavor device performance is better using 1K MTU.
216 If required MTU and MTU selector are such that 1K is OK
217 and at least one end of the path is Tavor we override the
220 if (sa->p_subn->opt.enable_quirks &&
221 __osm_sa_path_rec_apply_tavor_mtu_limit(p_pr, p_src_port,
222 p_dest_port, comp_mask))
223 if (mtu > IB_MTU_LEN_1024) {
224 mtu = IB_MTU_LEN_1024;
225 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
226 "Optimized Path MTU to 1K for Mellanox Tavor device\n");
230 Walk the subnet object from source to destination,
231 tracking the most restrictive rate and mtu values along the way...
233 If source port node is a switch, then p_physp should
234 point to the port that routes the destination lid
237 p_node = osm_physp_get_node_ptr(p_physp);
241 * Source node is a switch.
242 * Make sure that p_physp points to the out port of the
243 * switch that routes to the destination lid (dest_lid_ho)
245 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
247 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F02: "
248 "Cannot find routing to LID %u from switch for GUID 0x%016"
249 PRIx64 "\n", dest_lid_ho,
250 cl_ntoh64(osm_node_get_node_guid(p_node)));
251 status = IB_NOT_FOUND;
256 if (sa->p_subn->opt.qos) {
259 * Whether this node is switch or CA, the IN port for
260 * the sl2vl table is 0, because this is a source node.
262 p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
264 /* update valid SLs that still exist on this route */
265 for (i = 0; i < IB_MAX_NUM_VLS; i++) {
266 if (valid_sl_mask & (1 << i) &&
267 ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
268 valid_sl_mask &= ~(1 << i);
270 if (!valid_sl_mask) {
271 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
272 "All the SLs lead to VL15 on this path\n");
273 status = IB_NOT_FOUND;
281 p_node = osm_physp_get_node_ptr(p_dest_physp);
285 * if destination is switch, we want p_dest_physp to point to port 0
287 p_dest_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
289 if (p_dest_physp == 0) {
290 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F03: "
291 "Cannot find routing to LID %u from switch for GUID 0x%016"
292 PRIx64 "\n", dest_lid_ho,
293 cl_ntoh64(osm_node_get_node_guid(p_node)));
294 status = IB_NOT_FOUND;
301 * Now go through the path step by step
304 while (p_physp != p_dest_physp) {
306 p_node = osm_physp_get_node_ptr(p_physp);
307 p_physp = osm_physp_get_remote(p_physp);
310 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F05: "
311 "Cannot find remote phys port when routing to LID %u from node GUID 0x%016"
312 PRIx64 "\n", dest_lid_ho,
313 cl_ntoh64(osm_node_get_node_guid(p_node)));
318 in_port_num = osm_physp_get_port_num(p_physp);
321 This is point to point case (no switch in between)
323 if (p_physp == p_dest_physp)
326 p_node = osm_physp_get_node_ptr(p_physp);
330 There is some sort of problem in the subnet object!
331 If this isn't a switch, we should have reached
332 the destination by now!
334 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F06: "
335 "Internal error, bad path\n");
341 Check parameters for the ingress port in this switch.
343 p_pi = &p_physp->port_info;
345 if (mtu > ib_port_info_get_mtu_cap(p_pi))
346 mtu = ib_port_info_get_mtu_cap(p_pi);
348 if (rate > ib_port_info_compute_rate(p_pi))
349 rate = ib_port_info_compute_rate(p_pi);
352 Continue with the egress port on this switch.
354 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
356 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F07: "
357 "Dead end on path to LID %u from switch for GUID 0x%016"
358 PRIx64 "\n", dest_lid_ho,
359 cl_ntoh64(osm_node_get_node_guid(p_node)));
364 p_pi = &p_physp->port_info;
366 if (mtu > ib_port_info_get_mtu_cap(p_pi))
367 mtu = ib_port_info_get_mtu_cap(p_pi);
369 if (rate > ib_port_info_compute_rate(p_pi))
370 rate = ib_port_info_compute_rate(p_pi);
372 if (sa->p_subn->opt.qos) {
374 * Check SL2VL table of the switch and update valid SLs
376 p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, in_port_num);
377 for (i = 0; i < IB_MAX_NUM_VLS; i++) {
378 if (valid_sl_mask & (1 << i) &&
379 ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
380 valid_sl_mask &= ~(1 << i);
382 if (!valid_sl_mask) {
383 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "All the SLs "
384 "lead to VL15 on this path\n");
385 status = IB_NOT_FOUND;
392 p_physp now points to the destination
394 p_pi = &p_physp->port_info;
396 if (mtu > ib_port_info_get_mtu_cap(p_pi))
397 mtu = ib_port_info_get_mtu_cap(p_pi);
399 if (rate > ib_port_info_compute_rate(p_pi))
400 rate = ib_port_info_compute_rate(p_pi);
402 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
403 "Path min MTU = %u, min rate = %u\n", mtu, rate);
406 * Get QoS Level object according to the path request
407 * and adjust path parameters according to QoS settings
409 if (sa->p_subn->opt.qos &&
410 sa->p_subn->p_qos_policy &&
412 osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy,
413 p_pr, p_src_physp, p_dest_physp,
415 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
416 "PathRecord request matches QoS Level '%s' (%s)\n",
417 p_qos_level->name, p_qos_level->use ?
418 p_qos_level->use : "no description");
420 if (p_qos_level->mtu_limit_set
421 && (mtu > p_qos_level->mtu_limit))
422 mtu = p_qos_level->mtu_limit;
424 if (p_qos_level->rate_limit_set
425 && (rate > p_qos_level->rate_limit))
426 rate = p_qos_level->rate_limit;
428 if (p_qos_level->sl_set) {
429 sl = p_qos_level->sl;
430 if (!(valid_sl_mask & (1 << sl))) {
431 status = IB_NOT_FOUND;
438 * Set packet lifetime.
439 * According to spec definition IBA 1.2 Table 205
440 * PacketLifeTime description, for loopback paths,
441 * packetLifeTime shall be zero.
443 if (p_src_port == p_dest_port)
445 else if (p_qos_level && p_qos_level->pkt_life_set)
446 pkt_life = p_qos_level->pkt_life;
448 pkt_life = sa->p_subn->opt.subnet_timeout;
451 Determine if these values meet the user criteria
452 and adjust appropriately
455 /* we silently ignore cases where only the MTU selector is defined */
456 if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
457 (comp_mask & IB_PR_COMPMASK_MTU)) {
458 required_mtu = ib_path_rec_mtu(p_pr);
459 switch (ib_path_rec_mtu_sel(p_pr)) {
460 case 0: /* must be greater than */
461 if (mtu <= required_mtu)
462 status = IB_NOT_FOUND;
465 case 1: /* must be less than */
466 if (mtu >= required_mtu) {
467 /* adjust to use the highest mtu
468 lower then the required one */
469 if (required_mtu > 1)
470 mtu = required_mtu - 1;
472 status = IB_NOT_FOUND;
476 case 2: /* exact match */
477 if (mtu < required_mtu)
478 status = IB_NOT_FOUND;
483 case 3: /* largest available */
484 /* can't be disqualified by this one */
488 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
494 if (status != IB_SUCCESS)
497 /* we silently ignore cases where only the Rate selector is defined */
498 if ((comp_mask & IB_PR_COMPMASK_RATESELEC) &&
499 (comp_mask & IB_PR_COMPMASK_RATE)) {
500 required_rate = ib_path_rec_rate(p_pr);
501 switch (ib_path_rec_rate_sel(p_pr)) {
502 case 0: /* must be greater than */
503 if (rate <= required_rate)
504 status = IB_NOT_FOUND;
507 case 1: /* must be less than */
508 if (rate >= required_rate) {
509 /* adjust the rate to use the highest rate
510 lower then the required one */
511 if (required_rate > 2)
512 rate = required_rate - 1;
514 status = IB_NOT_FOUND;
518 case 2: /* exact match */
519 if (rate < required_rate)
520 status = IB_NOT_FOUND;
522 rate = required_rate;
525 case 3: /* largest available */
526 /* can't be disqualified by this one */
530 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
536 if (status != IB_SUCCESS)
539 /* we silently ignore cases where only the PktLife selector is defined */
540 if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) &&
541 (comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) {
542 required_pkt_life = ib_path_rec_pkt_life(p_pr);
543 switch (ib_path_rec_pkt_life_sel(p_pr)) {
544 case 0: /* must be greater than */
545 if (pkt_life <= required_pkt_life)
546 status = IB_NOT_FOUND;
549 case 1: /* must be less than */
550 if (pkt_life >= required_pkt_life) {
551 /* adjust the lifetime to use the highest possible
552 lower then the required one */
553 if (required_pkt_life > 1)
554 pkt_life = required_pkt_life - 1;
556 status = IB_NOT_FOUND;
560 case 2: /* exact match */
561 if (pkt_life < required_pkt_life)
562 status = IB_NOT_FOUND;
564 pkt_life = required_pkt_life;
567 case 3: /* smallest available */
568 /* can't be disqualified by this one */
572 /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
579 if (status != IB_SUCCESS)
583 * set Pkey for this path record request
586 if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) &&
587 (cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)))
588 pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp);
590 else if (comp_mask & IB_PR_COMPMASK_PKEY) {
592 * PR request has a specific pkey:
593 * Check that source and destination share this pkey.
594 * If QoS level has pkeys, check that this pkey exists
595 * in the QoS level pkeys.
596 * PR returned pkey is the requested pkey.
599 if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey)) {
600 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: "
601 "Ports 0x%016" PRIx64 " 0x%016" PRIx64
602 " do not share specified PKey 0x%04x\n",
603 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
604 cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)),
606 status = IB_NOT_FOUND;
609 if (p_qos_level && p_qos_level->pkey_range_len &&
610 !osm_qos_level_has_pkey(p_qos_level, pkey)) {
611 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: "
612 "Ports do not share PKeys defined by QoS level\n");
613 status = IB_NOT_FOUND;
617 } else if (p_qos_level && p_qos_level->pkey_range_len) {
619 * PR request doesn't have a specific pkey, but QoS level
620 * has pkeys - get shared pkey from QoS level pkeys
622 pkey = osm_qos_level_get_shared_pkey(p_qos_level,
623 p_src_physp, p_dest_physp);
625 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: "
626 "Ports 0x%016" PRIx64 " 0x%016" PRIx64
627 " do not share PKeys defined by QoS level\n",
628 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
629 cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)));
630 status = IB_NOT_FOUND;
635 * Neither PR request nor QoS level have pkey.
636 * Just get any shared pkey.
638 pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp);
640 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: "
641 "Ports 0x%016" PRIx64 " 0x%016" PRIx64
642 " do not have any shared PKeys\n",
643 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
644 cl_ntoh64(osm_physp_get_port_guid(p_dest_physp)));
645 status = IB_NOT_FOUND;
652 (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
653 pkey & cl_hton16((uint16_t) ~
656 (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
664 is_lash = (p_osm->routing_engine_used == OSM_ROUTING_ENGINE_TYPE_LASH);
666 if (comp_mask & IB_PR_COMPMASK_SL) {
668 * Specific SL was requested
670 sl = ib_path_rec_sl(p_pr);
672 if (p_qos_level && p_qos_level->sl_set
673 && (p_qos_level->sl != sl)) {
674 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: "
675 "QoS constaraints: required PathRecord SL (%u) "
676 "doesn't match QoS policy SL (%u)\n", sl,
678 status = IB_NOT_FOUND;
683 && osm_get_lash_sl(p_osm, p_src_port, p_dest_port) != sl) {
684 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F23: "
685 "Required PathRecord SL (%u) doesn't "
686 "match LASH SL\n", sl);
687 status = IB_NOT_FOUND;
691 } else if (is_lash) {
693 * No specific SL in PathRecord request.
694 * If it's LASH routing - use its SL.
695 * slid and dest_lid are stored in network in lash.
697 sl = osm_get_lash_sl(p_osm, p_src_port, p_dest_port);
698 } else if (p_qos_level && p_qos_level->sl_set) {
700 * No specific SL was requested, and we're not in
701 * LASH routing, but there is an SL in QoS level.
703 sl = p_qos_level->sl;
705 if (pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
706 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
707 "QoS level SL (%u) overrides partition SL (%u)\n",
708 p_qos_level->sl, p_prtn->sl);
712 * No specific SL in request or in QoS level - use partition SL
716 /* this may be possible when pkey tables are created somehow in
717 previous runs or things are going wrong here */
718 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1C: "
719 "No partition found for PKey 0x%04x - using default SL %d\n",
720 cl_ntoh16(pkey), sl);
723 } else if (sa->p_subn->opt.qos) {
724 if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
727 for (i = 0; i < IB_MAX_NUM_VLS; i++)
728 if (valid_sl_mask & (1 << i))
735 if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) {
736 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: "
737 "Selected SL (%u) leads to VL15\n", sl);
738 status = IB_NOT_FOUND;
742 /* reset pkey when raw traffic */
743 if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
744 cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))
748 p_parms->rate = rate;
749 p_parms->pkt_life = pkt_life;
750 p_parms->pkey = pkey;
753 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u,"
754 " packet lifetime = %u, pkey = 0x%04X, sl = %u\n",
755 mtu, rate, pkt_life, cl_ntoh16(pkey), sl);
757 OSM_LOG_EXIT(sa->p_log);
761 /**********************************************************************
762 **********************************************************************/
764 __osm_pr_rcv_build_pr(IN osm_sa_t * sa,
765 IN const osm_port_t * const p_src_port,
766 IN const osm_port_t * const p_dest_port,
767 IN const ib_gid_t * const p_dgid,
768 IN const uint16_t src_lid_ho,
769 IN const uint16_t dest_lid_ho,
770 IN const uint8_t preference,
771 IN const osm_path_parms_t * const p_parms,
772 OUT ib_path_rec_t * const p_pr)
774 const osm_physp_t *p_src_physp;
775 const osm_physp_t *p_dest_physp;
776 boolean_t is_nonzero_gid = 0;
778 OSM_LOG_ENTER(sa->p_log);
780 p_src_physp = p_src_port->p_physp;
783 if (memcmp(p_dgid, &zero_gid, sizeof(*p_dgid)))
788 p_pr->dgid = *p_dgid;
790 p_dest_physp = p_dest_port->p_physp;
792 p_pr->dgid.unicast.prefix =
793 osm_physp_get_subnet_prefix(p_dest_physp);
794 p_pr->dgid.unicast.interface_id =
795 osm_physp_get_port_guid(p_dest_physp);
798 p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
799 p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid(p_src_physp);
801 p_pr->dlid = cl_hton16(dest_lid_ho);
802 p_pr->slid = cl_hton16(src_lid_ho);
804 p_pr->hop_flow_raw &= cl_hton32(1 << 31);
806 /* Only set HopLimit if going through a router */
808 p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX);
810 p_pr->pkey = p_parms->pkey;
811 ib_path_rec_set_sl(p_pr, p_parms->sl);
812 ib_path_rec_set_qos_class(p_pr, 0);
813 p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
814 p_pr->rate = (uint8_t) (p_parms->rate | 0x80);
816 /* According to 1.2 spec definition Table 205 PacketLifeTime description,
817 for loopback paths, packetLifeTime shall be zero. */
818 if (p_src_port == p_dest_port)
819 p_pr->pkt_life = 0x80; /* loopback */
821 p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
823 p_pr->preference = preference;
825 /* always return num_path = 0 so this is only the reversible component */
826 if (p_parms->reversible)
827 p_pr->num_path = 0x80;
829 OSM_LOG_EXIT(sa->p_log);
832 /**********************************************************************
833 **********************************************************************/
834 static osm_pr_item_t *
835 __osm_pr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
836 IN const ib_path_rec_t * const p_pr,
837 IN const osm_port_t * const p_src_port,
838 IN const osm_port_t * const p_dest_port,
839 IN const ib_gid_t * const p_dgid,
840 IN const uint16_t src_lid_ho,
841 IN const uint16_t dest_lid_ho,
842 IN const ib_net64_t comp_mask,
843 IN const uint8_t preference)
845 osm_path_parms_t path_parms;
846 osm_path_parms_t rev_path_parms;
847 osm_pr_item_t *p_pr_item;
848 ib_api_status_t status, rev_path_status;
850 OSM_LOG_ENTER(sa->p_log);
852 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
853 src_lid_ho, dest_lid_ho);
855 p_pr_item = malloc(sizeof(*p_pr_item));
856 if (p_pr_item == NULL) {
857 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: "
858 "Unable to allocate path record\n");
861 memset(p_pr_item, 0, sizeof(*p_pr_item));
863 status = __osm_pr_rcv_get_path_parms(sa, p_pr, p_src_port,
864 p_dest_port, dest_lid_ho,
865 comp_mask, &path_parms);
867 if (status != IB_SUCCESS) {
873 /* now try the reversible path */
874 rev_path_status = __osm_pr_rcv_get_path_parms(sa, p_pr, p_dest_port,
875 p_src_port, src_lid_ho,
878 path_parms.reversible = (rev_path_status == IB_SUCCESS);
880 /* did we get a Reversible Path compmask ? */
882 NOTE that if the reversible component = 0, it is a don't care
883 rather then requiring non-reversible paths ...
884 see Vol1 Ver1.2 p900 l16
886 if (comp_mask & IB_PR_COMPMASK_REVERSIBLE) {
887 if ((!path_parms.reversible && (p_pr->num_path & 0x80))) {
888 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
889 "Requested reversible path but failed to get one\n");
897 __osm_pr_rcv_build_pr(sa, p_src_port, p_dest_port, p_dgid,
898 src_lid_ho, dest_lid_ho, preference, &path_parms,
899 &p_pr_item->path_rec);
902 OSM_LOG_EXIT(sa->p_log);
906 /**********************************************************************
907 **********************************************************************/
909 __osm_pr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
910 IN const osm_madw_t * const p_madw,
911 IN const osm_port_t * const p_req_port,
912 IN const osm_port_t * const p_src_port,
913 IN const osm_port_t * const p_dest_port,
914 IN const ib_gid_t * const p_dgid,
915 IN const ib_net64_t comp_mask,
916 IN cl_qlist_t * const p_list)
918 const ib_path_rec_t *p_pr;
919 const ib_sa_mad_t *p_sa_mad;
920 osm_pr_item_t *p_pr_item;
921 uint16_t src_lid_min_ho;
922 uint16_t src_lid_max_ho;
923 uint16_t dest_lid_min_ho;
924 uint16_t dest_lid_max_ho;
926 uint16_t dest_lid_ho;
933 OSM_LOG_ENTER(sa->p_log);
935 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
936 "Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
937 cl_ntoh64(osm_port_get_guid(p_src_port)),
938 cl_ntoh64(osm_port_get_guid(p_dest_port)));
940 /* Check that the req_port, src_port and dest_port all share a
941 pkey. The check is done on the default physical port of the ports. */
942 if (osm_port_share_pkey(sa->p_log, p_req_port, p_src_port) == FALSE
943 || osm_port_share_pkey(sa->p_log, p_req_port,
944 p_dest_port) == FALSE
945 || osm_port_share_pkey(sa->p_log, p_src_port,
946 p_dest_port) == FALSE)
947 /* One of the pairs doesn't share a pkey so the path is disqualified. */
950 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
951 p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
954 We shouldn't be here if the paths are disqualified in some way...
955 Thus, we assume every possible connection is valid.
957 We desire to return high-quality paths first.
958 In OpenSM, higher quality means least overlap with other paths.
959 This is acheived in practice by returning paths with
960 different LID value on each end, which means these
961 paths are more redundant that paths with the same LID repeated
962 on one side. For example, in OpenSM the paths between two
963 endpoints with LMC = 1 might be as follows:
965 Port A, LID 1 <-> Port B, LID 3
966 Port A, LID 1 <-> Port B, LID 4
967 Port A, LID 2 <-> Port B, LID 3
968 Port A, LID 2 <-> Port B, LID 4
970 The OpenSM unicast routing algorithms attempt to disperse each path
971 to as varied a physical path as is reasonable. 1<->3 and 1<->4 have
972 more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
974 OpenSM ranks paths in three preference groups:
976 Preference Value Description
977 ---------------- -------------------------------------------
978 0 Redundant in both directions with other
981 1 Redundant in one direction with other
982 pref value = 0 and pref value = 1 paths
984 2 Not redundant in either direction with
989 SA clients don't need to know these details, only that the lower
990 preference paths are preferred, as stated in the spec. The paths
991 may not actually be physically redundant depending on the topology
992 of the subnet, but the point of LMC > 0 is to offer redundancy,
993 so it is assumed that the subnet is physically appropriate for the
994 specified LMC value. A more advanced implementation would inspect for
995 physical redundancy, but I'm not going to bother with that now.
999 Refine our search if the client specified end-point LIDs
1001 if (comp_mask & IB_PR_COMPMASK_DLID) {
1002 dest_lid_min_ho = cl_ntoh16(p_pr->dlid);
1003 dest_lid_max_ho = cl_ntoh16(p_pr->dlid);
1005 osm_port_get_lid_range_ho(p_dest_port, &dest_lid_min_ho,
1008 if (comp_mask & IB_PR_COMPMASK_SLID) {
1009 src_lid_min_ho = cl_ntoh16(p_pr->slid);
1010 src_lid_max_ho = cl_ntoh16(p_pr->slid);
1012 osm_port_get_lid_range_ho(p_src_port, &src_lid_min_ho,
1015 if (src_lid_min_ho == 0) {
1016 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F20:"
1017 "Obtained source LID of 0. No such LID possible\n");
1021 if (dest_lid_min_ho == 0) {
1022 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F21:"
1023 "Obtained destination LID of 0. No such LID possible\n");
1027 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1028 "Src LIDs [%u-%u], Dest LIDs [%u-%u]\n",
1029 src_lid_min_ho, src_lid_max_ho,
1030 dest_lid_min_ho, dest_lid_max_ho);
1032 src_lid_ho = src_lid_min_ho;
1033 dest_lid_ho = dest_lid_min_ho;
1036 Preferred paths come first in OpenSM
1041 /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
1042 if (p_sa_mad->method != IB_MAD_METHOD_GET)
1043 if (comp_mask & IB_PR_COMPMASK_NUMBPATH)
1044 iterations = ib_path_rec_num_path(p_pr);
1046 iterations = (uintn_t) (-1);
1050 while (path_num < iterations) {
1052 These paths are "fully redundant"
1055 p_pr_item = __osm_pr_rcv_get_lid_pair_path(sa, p_pr,
1057 p_dest_port, p_dgid,
1064 cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1068 if (++src_lid_ho > src_lid_max_ho)
1071 if (++dest_lid_ho > dest_lid_max_ho)
1076 Check if we've accumulated all the paths that the user cares to see
1078 if (path_num == iterations)
1082 Don't bother reporting preference 1 paths for now.
1083 It's more trouble than it's worth and can only occur
1084 if ports have different LMC values, which isn't supported
1085 by OpenSM right now anyway.
1088 src_lid_ho = src_lid_min_ho;
1089 dest_lid_ho = dest_lid_min_ho;
1094 Iterate over the remaining paths
1096 while (path_num < iterations) {
1100 if (dest_lid_ho > dest_lid_max_ho) {
1104 if (src_lid_ho > src_lid_max_ho)
1108 dest_lid_ho = dest_lid_min_ho;
1112 These paths are "fully non-redundant" with paths already
1113 identified above and consequently not of much value.
1115 Don't return paths we already identified above, as indicated
1116 by the offset values being equal.
1118 if (src_offset == dest_offset)
1119 continue; /* already reported */
1121 p_pr_item = __osm_pr_rcv_get_lid_pair_path(sa, p_pr,
1123 p_dest_port, p_dgid,
1130 cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1136 OSM_LOG_EXIT(sa->p_log);
1139 /**********************************************************************
1140 **********************************************************************/
1142 __osm_pr_rcv_get_end_points(IN osm_sa_t * sa,
1143 IN const osm_madw_t * const p_madw,
1144 OUT const osm_port_t ** const pp_src_port,
1145 OUT const osm_port_t ** const pp_dest_port,
1146 OUT ib_gid_t * const p_dgid)
1148 const ib_path_rec_t *p_pr;
1149 const ib_sa_mad_t *p_sa_mad;
1150 ib_net64_t comp_mask;
1151 ib_net64_t dest_guid;
1152 ib_api_status_t status;
1153 ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
1154 osm_router_t *p_rtr;
1155 osm_port_t *p_rtr_port;
1157 OSM_LOG_ENTER(sa->p_log);
1160 Determine what fields are valid and then get a pointer
1161 to the source and destination port objects, if possible.
1164 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1165 p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1167 comp_mask = p_sa_mad->comp_mask;
1170 Check a few easy disqualifying cases up front before getting
1174 if (comp_mask & IB_PR_COMPMASK_SGID) {
1175 if (!ib_gid_is_link_local(&p_pr->sgid)) {
1176 if (ib_gid_get_subnet_prefix(&p_pr->sgid) !=
1177 sa->p_subn->opt.subnet_prefix) {
1179 This 'error' is the client's fault (bad gid)
1180 so don't enter it as an error in our own log.
1181 Return an error response to the client.
1183 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1184 "Non local SGID subnet prefix 0x%016"
1186 cl_ntoh64(p_pr->sgid.unicast.prefix));
1188 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1193 *pp_src_port = osm_get_port_by_guid(sa->p_subn,
1196 if (!*pp_src_port) {
1198 This 'error' is the client's fault (bad gid) so
1199 don't enter it as an error in our own log.
1200 Return an error response to the client.
1202 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1203 "No source port with GUID 0x%016" PRIx64 "\n",
1204 cl_ntoh64(p_pr->sgid.unicast.interface_id));
1206 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1211 if (comp_mask & IB_PR_COMPMASK_SLID) {
1212 status = cl_ptr_vector_at(&sa->p_subn->port_lid_tbl,
1213 cl_ntoh16(p_pr->slid),
1214 (void **)pp_src_port);
1216 if ((status != CL_SUCCESS) || (*pp_src_port == NULL)) {
1218 This 'error' is the client's fault (bad lid) so
1219 don't enter it as an error in our own log.
1220 Return an error response to the client.
1222 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1223 "No source port with LID %u\n",
1224 cl_ntoh16(p_pr->slid));
1226 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1233 memset(p_dgid, 0, sizeof(*p_dgid));
1235 if (comp_mask & IB_PR_COMPMASK_DGID) {
1236 dest_guid = p_pr->dgid.unicast.interface_id;
1237 if (!ib_gid_is_link_local(&p_pr->dgid)) {
1238 if (!ib_gid_is_multicast(&p_pr->dgid) &&
1239 ib_gid_get_subnet_prefix(&p_pr->dgid) !=
1240 sa->p_subn->opt.subnet_prefix) {
1241 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1242 "Non local DGID subnet prefix 0x%016"
1244 cl_ntoh64(p_pr->dgid.unicast.prefix));
1246 /* Find the router port that is configured to
1247 handle this prefix, if any */
1248 osm_prefix_route_t *route = NULL;
1249 osm_prefix_route_t *r = (osm_prefix_route_t *)
1250 cl_qlist_head(&sa->p_subn->prefix_routes_list);
1252 while (r != (osm_prefix_route_t *)
1253 cl_qlist_end(&sa->p_subn->prefix_routes_list))
1255 if (r->prefix == p_pr->dgid.unicast.prefix ||
1261 r = (osm_prefix_route_t *) cl_qlist_next(&r->list_item);
1266 This 'error' is the client's fault (bad gid) so
1267 don't enter it as an error in our own log.
1268 Return an error response to the client.
1270 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1272 } else if (route->guid == 0) {
1274 p_rtr = (osm_router_t *)
1279 p_rtr = (osm_router_t *)
1287 (osm_router_t *) cl_qmap_end(&sa->
1291 OSM_LOG(sa->p_log, OSM_LOG_ERROR,
1293 "Off subnet DGID but router not found\n");
1295 IB_SA_MAD_STATUS_INVALID_GID;
1299 p_rtr_port = osm_router_get_port_ptr(p_rtr);
1300 dest_guid = osm_port_get_guid(p_rtr_port);
1302 *p_dgid = p_pr->dgid;
1306 *pp_dest_port = osm_get_port_by_guid(sa->p_subn, dest_guid);
1307 if (!*pp_dest_port) {
1309 This 'error' is the client's fault (bad gid) so
1310 don't enter it as an error in our own log.
1311 Return an error response to the client.
1313 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1314 "No dest port with GUID 0x%016" PRIx64 "\n",
1315 cl_ntoh64(dest_guid));
1317 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1322 if (comp_mask & IB_PR_COMPMASK_DLID) {
1323 status = cl_ptr_vector_at(&sa->p_subn->port_lid_tbl,
1324 cl_ntoh16(p_pr->dlid),
1325 (void **)pp_dest_port);
1327 if ((status != CL_SUCCESS) || (*pp_dest_port == NULL)) {
1329 This 'error' is the client's fault (bad lid)
1330 so don't enter it as an error in our own log.
1331 Return an error response to the client.
1333 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1334 "No dest port with LID %u\n",
1335 cl_ntoh16(p_pr->dlid));
1337 sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1344 OSM_LOG_EXIT(sa->p_log);
1348 /**********************************************************************
1349 **********************************************************************/
1351 __osm_pr_rcv_process_world(IN osm_sa_t * sa,
1352 IN const osm_madw_t * const p_madw,
1353 IN const osm_port_t * const requester_port,
1354 IN const ib_gid_t * const p_dgid,
1355 IN const ib_net64_t comp_mask,
1356 IN cl_qlist_t * const p_list)
1358 const cl_qmap_t *p_tbl;
1359 const osm_port_t *p_dest_port;
1360 const osm_port_t *p_src_port;
1362 OSM_LOG_ENTER(sa->p_log);
1365 Iterate the entire port space over itself.
1366 A path record from a port to itself is legit, so no
1367 need for a special case there.
1369 We compute both A -> B and B -> A, since we don't have
1370 any check to determine the reversability of the paths.
1372 p_tbl = &sa->p_subn->port_guid_tbl;
1374 p_dest_port = (osm_port_t *) cl_qmap_head(p_tbl);
1375 while (p_dest_port != (osm_port_t *) cl_qmap_end(p_tbl)) {
1376 p_src_port = (osm_port_t *) cl_qmap_head(p_tbl);
1377 while (p_src_port != (osm_port_t *) cl_qmap_end(p_tbl)) {
1378 __osm_pr_rcv_get_port_pair_paths(sa, p_madw,
1381 p_dest_port, p_dgid,
1385 (osm_port_t *) cl_qmap_next(&p_src_port->map_item);
1389 (osm_port_t *) cl_qmap_next(&p_dest_port->map_item);
1392 OSM_LOG_EXIT(sa->p_log);
1395 /**********************************************************************
1396 **********************************************************************/
1398 __osm_pr_rcv_process_half(IN osm_sa_t * sa,
1399 IN const osm_madw_t * const p_madw,
1400 IN const osm_port_t * const requester_port,
1401 IN const osm_port_t * const p_src_port,
1402 IN const osm_port_t * const p_dest_port,
1403 IN const ib_gid_t * const p_dgid,
1404 IN const ib_net64_t comp_mask,
1405 IN cl_qlist_t * const p_list)
1407 const cl_qmap_t *p_tbl;
1408 const osm_port_t *p_port;
1410 OSM_LOG_ENTER(sa->p_log);
1413 Iterate over every port, looking for matches...
1414 A path record from a port to itself is legit, so no
1415 need to special case that one.
1417 p_tbl = &sa->p_subn->port_guid_tbl;
1421 The src port if fixed, so iterate over destination ports.
1423 p_port = (osm_port_t *) cl_qmap_head(p_tbl);
1424 while (p_port != (osm_port_t *) cl_qmap_end(p_tbl)) {
1425 __osm_pr_rcv_get_port_pair_paths(sa, p_madw,
1430 p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item);
1434 The dest port if fixed, so iterate over source ports.
1436 p_port = (osm_port_t *) cl_qmap_head(p_tbl);
1437 while (p_port != (osm_port_t *) cl_qmap_end(p_tbl)) {
1438 __osm_pr_rcv_get_port_pair_paths(sa, p_madw,
1439 requester_port, p_port,
1440 p_dest_port, p_dgid,
1442 p_port = (osm_port_t *) cl_qmap_next(&p_port->map_item);
1446 OSM_LOG_EXIT(sa->p_log);
1449 /**********************************************************************
1450 **********************************************************************/
1452 __osm_pr_rcv_process_pair(IN osm_sa_t * sa,
1453 IN const osm_madw_t * const p_madw,
1454 IN const osm_port_t * const requester_port,
1455 IN const osm_port_t * const p_src_port,
1456 IN const osm_port_t * const p_dest_port,
1457 IN const ib_gid_t * const p_dgid,
1458 IN const ib_net64_t comp_mask,
1459 IN cl_qlist_t * const p_list)
1461 OSM_LOG_ENTER(sa->p_log);
1463 __osm_pr_rcv_get_port_pair_paths(sa, p_madw, requester_port,
1464 p_src_port, p_dest_port, p_dgid,
1467 OSM_LOG_EXIT(sa->p_log);
1470 /**********************************************************************
1471 **********************************************************************/
1472 static osm_mgrp_t *pr_get_mgrp(IN osm_sa_t * sa,
1473 IN const osm_madw_t * const p_madw)
1475 ib_path_rec_t *p_pr;
1476 const ib_sa_mad_t *p_sa_mad;
1477 ib_net64_t comp_mask;
1478 osm_mgrp_t *mgrp = NULL;
1480 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1481 p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1483 comp_mask = p_sa_mad->comp_mask;
1485 if ((comp_mask & IB_PR_COMPMASK_DGID) &&
1486 !(mgrp = osm_get_mgrp_by_mgid(sa, &p_pr->dgid))) {
1487 char gid_str[INET6_ADDRSTRLEN];
1488 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: "
1489 "No MC group found for PathRecord destination GID %s\n",
1490 inet_ntop(AF_INET6, p_pr->dgid.raw, gid_str,
1495 if (comp_mask & IB_PR_COMPMASK_DLID) {
1497 /* check that the MLID in the MC group is */
1498 /* the same as the DLID in the PathRecord */
1499 if (mgrp->mlid != p_pr->dlid) {
1500 /* Note: perhaps this might be better indicated as an invalid request */
1501 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F10: "
1502 "MC group MLID 0x%x does not match "
1503 "PathRecord destination LID 0x%x\n",
1504 mgrp->mlid, p_pr->dlid);
1508 } else if (!(mgrp = osm_get_mgrp_by_mlid(sa->p_subn, p_pr->dlid)))
1509 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F11: "
1510 "No MC group found for PathRecord "
1511 "destination LID 0x%x\n", p_pr->dlid);
1518 /**********************************************************************
1519 **********************************************************************/
1520 static ib_api_status_t
1521 __osm_pr_match_mgrp_attributes(IN osm_sa_t * sa,
1522 IN const osm_madw_t * const p_madw,
1523 IN const osm_mgrp_t * const p_mgrp)
1525 const ib_path_rec_t *p_pr;
1526 const ib_sa_mad_t *p_sa_mad;
1527 ib_net64_t comp_mask;
1528 ib_api_status_t status = IB_ERROR;
1529 uint32_t flow_label;
1533 OSM_LOG_ENTER(sa->p_log);
1535 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1536 p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1538 comp_mask = p_sa_mad->comp_mask;
1540 /* If SGID and/or SLID specified, should validate as member of MC group */
1541 /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
1542 if (comp_mask & IB_PR_COMPMASK_PKEY) {
1543 if (p_pr->pkey != p_mgrp->mcmember_rec.pkey)
1547 ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
1548 &sl, &flow_label, &hop_limit);
1550 if (comp_mask & IB_PR_COMPMASK_SL) {
1551 if (ib_path_rec_sl(p_pr) != sl)
1555 /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
1556 if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) &&
1557 (p_sa_mad->method != IB_MAD_METHOD_GET)) {
1558 if (ib_path_rec_num_path(p_pr) == 0)
1562 if (comp_mask & IB_PR_COMPMASK_FLOWLABEL) {
1563 if (ib_path_rec_flow_lbl(p_pr) != flow_label)
1567 if (comp_mask & IB_PR_COMPMASK_HOPLIMIT) {
1568 if (ib_path_rec_hop_limit(p_pr) != hop_limit)
1572 if (comp_mask & IB_PR_COMPMASK_TCLASS) {
1573 if (p_pr->tclass != p_mgrp->mcmember_rec.tclass)
1577 status = IB_SUCCESS;
1580 OSM_LOG_EXIT(sa->p_log);
1584 /**********************************************************************
1585 **********************************************************************/
1587 __osm_pr_rcv_check_mcast_dest(IN osm_sa_t * sa,
1588 IN const osm_madw_t * const p_madw)
1590 const ib_path_rec_t *p_pr;
1591 const ib_sa_mad_t *p_sa_mad;
1592 ib_net64_t comp_mask;
1593 int is_multicast = 0;
1595 OSM_LOG_ENTER(sa->p_log);
1597 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1598 p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1600 comp_mask = p_sa_mad->comp_mask;
1602 if (comp_mask & IB_PR_COMPMASK_DGID) {
1603 is_multicast = ib_gid_is_multicast(&p_pr->dgid);
1608 if (comp_mask & IB_PR_COMPMASK_DLID) {
1609 if (cl_ntoh16(p_pr->dlid) >= IB_LID_MCAST_START_HO &&
1610 cl_ntoh16(p_pr->dlid) <= IB_LID_MCAST_END_HO)
1612 else if (is_multicast) {
1613 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F12: "
1614 "PathRecord request indicates MGID but not MLID\n");
1620 OSM_LOG_EXIT(sa->p_log);
1621 return (is_multicast);
1624 /**********************************************************************
1625 **********************************************************************/
1626 void osm_pr_rcv_process(IN void *context, IN void *data)
1628 osm_sa_t *sa = context;
1629 osm_madw_t *p_madw = data;
1630 const ib_path_rec_t *p_pr;
1631 const ib_sa_mad_t *p_sa_mad;
1632 const osm_port_t *p_src_port;
1633 const osm_port_t *p_dest_port;
1636 ib_net16_t sa_status;
1637 osm_port_t *requester_port;
1640 OSM_LOG_ENTER(sa->p_log);
1644 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1645 p_pr = (ib_path_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
1647 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD);
1649 /* we only support SubnAdmGet and SubnAdmGetTable methods */
1650 if (p_sa_mad->method != IB_MAD_METHOD_GET &&
1651 p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
1652 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: "
1653 "Unsupported Method (%s)\n",
1654 ib_get_sa_method_str(p_sa_mad->method));
1655 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1659 /* update the requester physical port. */
1660 requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
1661 osm_madw_get_mad_addr_ptr
1663 if (requester_port == NULL) {
1664 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F16: "
1665 "Cannot find requester physical port\n");
1669 if (osm_log_is_active(sa->p_log, OSM_LOG_DEBUG))
1670 osm_dump_path_record(sa->p_log, p_pr, OSM_LOG_DEBUG);
1672 cl_qlist_init(&pr_list);
1675 Most SA functions (including this one) are read-only on the
1676 subnet object, so we grab the lock non-exclusively.
1678 cl_plock_acquire(sa->p_lock);
1680 /* Handle multicast destinations separately */
1681 if ((ret = __osm_pr_rcv_check_mcast_dest(sa, p_madw)) < 0) {
1682 /* Multicast DGID with unicast DLID */
1683 cl_plock_release(sa->p_lock);
1684 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_INVALID_FIELD);
1691 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n");
1693 sa_status = __osm_pr_rcv_get_end_points(sa, p_madw,
1694 &p_src_port, &p_dest_port,
1697 if (sa_status == IB_SA_MAD_STATUS_SUCCESS) {
1699 What happens next depends on the type of endpoint information
1700 that was specified....
1704 __osm_pr_rcv_process_pair(sa, p_madw,
1708 p_sa_mad->comp_mask,
1711 __osm_pr_rcv_process_half(sa, p_madw,
1715 p_sa_mad->comp_mask,
1719 __osm_pr_rcv_process_half(sa, p_madw,
1720 requester_port, NULL,
1722 p_sa_mad->comp_mask,
1726 Katie, bar the door!
1728 __osm_pr_rcv_process_world(sa, p_madw,
1731 p_sa_mad->comp_mask,
1738 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n");
1740 osm_mgrp_t *p_mgrp = NULL;
1741 ib_api_status_t status;
1742 osm_pr_item_t *p_pr_item;
1743 uint32_t flow_label;
1747 /* First, get the MC info */
1748 p_mgrp = pr_get_mgrp(sa, p_madw);
1753 /* Make sure the rest of the PathRecord matches the MC group attributes */
1754 status = __osm_pr_match_mgrp_attributes(sa, p_madw, p_mgrp);
1755 if (status != IB_SUCCESS) {
1756 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: "
1757 "MC group attributes don't match PathRecord request\n");
1761 p_pr_item = malloc(sizeof(*p_pr_item));
1762 if (p_pr_item == NULL) {
1763 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: "
1764 "Unable to allocate path record for MC group\n");
1767 memset(p_pr_item, 0, sizeof(*p_pr_item));
1769 /* Copy PathRecord request into response */
1770 p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1771 p_pr = (ib_path_rec_t *)
1772 ib_sa_mad_get_payload_ptr(p_sa_mad);
1773 p_pr_item->path_rec = *p_pr;
1775 /* Now, use the MC info to cruft up the PathRecord response */
1776 p_pr_item->path_rec.dgid = p_mgrp->mcmember_rec.mgid;
1777 p_pr_item->path_rec.dlid = p_mgrp->mcmember_rec.mlid;
1778 p_pr_item->path_rec.tclass = p_mgrp->mcmember_rec.tclass;
1779 p_pr_item->path_rec.num_path = 1;
1780 p_pr_item->path_rec.pkey = p_mgrp->mcmember_rec.pkey;
1782 /* MTU, rate, and packet lifetime should be exactly */
1783 p_pr_item->path_rec.mtu = (2 << 6) | p_mgrp->mcmember_rec.mtu;
1784 p_pr_item->path_rec.rate = (2 << 6) | p_mgrp->mcmember_rec.rate;
1785 p_pr_item->path_rec.pkt_life =
1786 (2 << 6) | p_mgrp->mcmember_rec.pkt_life;
1788 /* SL, Hop Limit, and Flow Label */
1789 ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
1790 &sl, &flow_label, &hop_limit);
1791 ib_path_rec_set_sl(&p_pr_item->path_rec, sl);
1792 ib_path_rec_set_qos_class(&p_pr_item->path_rec, 0);
1794 /* HopLimit is not yet set in non link local MC groups */
1795 /* If it were, this would not be needed */
1796 if (ib_mgid_get_scope(&p_mgrp->mcmember_rec.mgid) != IB_MC_SCOPE_LINK_LOCAL)
1797 hop_limit = IB_HOPLIMIT_MAX;
1799 p_pr_item->path_rec.hop_flow_raw =
1800 cl_hton32(hop_limit) | (flow_label << 8);
1802 cl_qlist_insert_tail(&pr_list, &p_pr_item->list_item);
1806 cl_plock_release(sa->p_lock);
1808 /* Now, (finally) respond to the PathRecord request */
1809 osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
1812 OSM_LOG_EXIT(sa->p_log);