1 /* 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. 10 * 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: 16 * 17 * Redistribution and use in source and binary forms, with or 18 * without modification, are permitted provided that the following 19 * conditions are met: 20 * 21 * - Redistributions of source code must retain the above 22 * copyright notice, this list of conditions and the following 23 * disclaimer. 24 * 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. 29 * 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 37 * SOFTWARE. 38 * 39 */ 40 41 /* 42 * Abstract: 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. 46 */ 47 48 #if HAVE_CONFIG_H 49 # include <config.h> 50 #endif /* HAVE_CONFIG_H */ 51 52 #include <string.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> 77 78 #define SA_PR_RESP_SIZE SA_ITEM_RESP_SIZE(path_rec) 79 80 #define MAX_HOPS 64 81 82 static inline boolean_t sa_path_rec_is_tavor_port(IN const osm_port_t * p_port) 83 { 84 osm_node_t const *p_node; 85 ib_net32_t vend_id; 86 87 p_node = p_port->p_node; 88 vend_id = ib_node_info_get_vendor_id(&p_node->node_info); 89 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)))); 95 } 96 97 static boolean_t 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) 102 { 103 uint8_t required_mtu; 104 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)) 108 return FALSE; 109 110 /* 111 we can apply the patch if either: 112 1. No MTU required 113 2. Required MTU < 114 3. Required MTU = 1K or 512 or 256 115 4. Required MTU > 256 or 512 116 */ 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) 124 return FALSE; 125 break; 126 127 case 1: /* must be less than */ 128 /* can't be disqualified by this one */ 129 break; 130 131 case 3: /* largest available */ 132 /* the ULP intentionally requested */ 133 /* the largest MTU possible */ 134 return FALSE; 135 136 default: 137 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */ 138 CL_ASSERT(FALSE); 139 break; 140 } 141 } 142 143 return TRUE; 144 } 145 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) 154 { 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; 160 osm_opensm_t *p_osm; 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; 164 ib_net16_t pkey; 165 uint8_t mtu; 166 uint8_t rate, p0_extended_rate, dest_rate; 167 uint8_t pkt_life; 168 uint8_t required_mtu; 169 uint8_t required_rate; 170 uint8_t required_pkt_life; 171 uint8_t sl; 172 uint8_t in_port_num; 173 ib_net16_t dest_lid; 174 uint8_t i; 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; 178 int hops = 0; 179 int extended, p0_extended; 180 181 OSM_LOG_ENTER(sa->p_log); 182 183 dest_lid = cl_hton16(dest_lid_ho); 184 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; 191 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); 195 196 /* 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 200 port MTU with 1K. 201 */ 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, 206 comp_mask)) 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"); 211 } 212 213 /* 214 Walk the subnet object from source to destination, 215 tracking the most restrictive rate and mtu values along the way... 216 217 If source port node is a switch, then p_physp should 218 point to the port that routes the destination lid 219 */ 220 221 p_node = osm_physp_get_node_ptr(p_physp); 222 223 if (p_node->sw) { 224 /* 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) 228 */ 229 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); 230 if (p_physp == 0) { 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; 237 goto Exit; 238 } 239 } 240 241 if (sa->p_subn->opt.qos) { 242 /* 243 * Whether this node is switch or CA, the IN port for 244 * the sl2vl table is 0, because this is a source node. 245 */ 246 p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0); 247 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); 253 } 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; 258 goto Exit; 259 } 260 } 261 262 /* 263 * Same as above 264 */ 265 p_node = osm_physp_get_node_ptr(p_dest_physp); 266 267 if (p_node->sw) { 268 /* 269 * if destination is switch, we want p_dest_physp to point to port 0 270 */ 271 p_dest_physp = 272 osm_switch_get_route_by_lid(p_node->sw, dest_lid); 273 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; 281 goto Exit; 282 } 283 284 } 285 286 /* 287 * Now go through the path step by step 288 */ 289 290 while (p_physp != p_dest_physp) { 291 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); 295 296 if (p_physp == 0) { 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", 301 p_node->print_desc, 302 cl_ntoh64(osm_node_get_node_guid(p_node)), 303 tmp_pnum, src_lid_ho, dest_lid_ho); 304 status = IB_ERROR; 305 goto Exit; 306 } 307 308 in_port_num = osm_physp_get_port_num(p_physp); 309 310 /* 311 This is point to point case (no switch in between) 312 */ 313 if (p_physp == p_dest_physp) 314 break; 315 316 p_node = osm_physp_get_node_ptr(p_physp); 317 318 if (!p_node->sw) { 319 /* 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! 323 */ 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, 335 p_node->print_desc, 336 p_physp->port_num); 337 status = IB_ERROR; 338 goto Exit; 339 } 340 341 /* 342 Check parameters for the ingress port in this switch. 343 */ 344 p_pi = &p_physp->port_info; 345 346 if (mtu > ib_port_info_get_mtu_cap(p_pi)) 347 mtu = ib_port_info_get_mtu_cap(p_pi); 348 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; 355 356 /* 357 Continue with the egress port on this switch. 358 */ 359 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid); 360 if (p_physp == 0) { 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", 364 p_node->print_desc, 365 cl_ntoh64(osm_node_get_node_guid(p_node)), 366 dest_lid_ho); 367 status = IB_ERROR; 368 goto Exit; 369 } 370 371 p_pi = &p_physp->port_info; 372 373 if (mtu > ib_port_info_get_mtu_cap(p_pi)) 374 mtu = ib_port_info_get_mtu_cap(p_pi); 375 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; 382 383 if (sa->p_subn->opt.qos) { 384 /* 385 * Check SL2VL table of the switch and update valid SLs 386 */ 387 p_slvl_tbl = 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, 392 i) == IB_DROP_VL) 393 valid_sl_mask &= ~(1 << i); 394 } 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; 399 goto Exit; 400 } 401 } 402 403 /* update number of hops traversed */ 404 hops++; 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, 413 dest_lid_ho, 414 cl_ntoh64(osm_physp_get_port_guid 415 (p_dest_physp)), 416 p_dest_physp->p_node->print_desc, 417 p_dest_physp->port_num, 418 hops, 419 MAX_HOPS); 420 status = IB_NOT_FOUND; 421 goto Exit; 422 } 423 } 424 425 /* 426 p_physp now points to the destination 427 */ 428 p_pi = &p_physp->port_info; 429 430 if (mtu > ib_port_info_get_mtu_cap(p_pi)) 431 mtu = ib_port_info_get_mtu_cap(p_pi); 432 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) 436 rate = dest_rate; 437 438 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, 439 "Path min MTU = %u, min rate = %u\n", mtu, rate); 440 441 /* 442 * Get QoS Level object according to the path request 443 * and adjust path parameters according to QoS settings 444 */ 445 if (sa->p_subn->opt.qos && 446 sa->p_subn->p_qos_policy && 447 (p_qos_level = 448 osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy, 449 p_pr, p_src_physp, p_dest_physp, 450 comp_mask))) { 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"); 455 456 if (p_qos_level->mtu_limit_set 457 && (mtu > p_qos_level->mtu_limit)) 458 mtu = p_qos_level->mtu_limit; 459 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; 463 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; 468 goto Exit; 469 } 470 } 471 } 472 473 /* 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. 478 */ 479 if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port) 480 pkt_life = 0; 481 else if (p_qos_level && p_qos_level->pkt_life_set) 482 pkt_life = p_qos_level->pkt_life; 483 else 484 pkt_life = sa->p_subn->opt.subnet_timeout; 485 486 /* 487 Determine if these values meet the user criteria 488 and adjust appropriately 489 */ 490 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; 499 break; 500 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; 507 else 508 status = IB_NOT_FOUND; 509 } 510 break; 511 512 case 2: /* exact match */ 513 if (mtu < required_mtu) 514 status = IB_NOT_FOUND; 515 else 516 mtu = required_mtu; 517 break; 518 519 case 3: /* largest available */ 520 /* can't be disqualified by this one */ 521 break; 522 523 default: 524 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */ 525 CL_ASSERT(FALSE); 526 status = IB_ERROR; 527 break; 528 } 529 } 530 if (status != IB_SUCCESS) 531 goto Exit; 532 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; 541 break; 542 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); 548 if (!rate) 549 status = IB_NOT_FOUND; 550 } 551 break; 552 553 case 2: /* exact match */ 554 if (ib_path_compare_rates(rate, required_rate)) 555 status = IB_NOT_FOUND; 556 else 557 rate = required_rate; 558 break; 559 560 case 3: /* largest available */ 561 /* can't be disqualified by this one */ 562 break; 563 564 default: 565 /* if we're here, there's a bug in ib_path_rec_mtu_sel() */ 566 CL_ASSERT(FALSE); 567 status = IB_ERROR; 568 break; 569 } 570 } 571 if (status != IB_SUCCESS) 572 goto Exit; 573 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; 582 break; 583 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; 590 else 591 status = IB_NOT_FOUND; 592 } 593 break; 594 595 case 2: /* exact match */ 596 if (pkt_life < required_pkt_life) 597 status = IB_NOT_FOUND; 598 else 599 pkt_life = required_pkt_life; 600 break; 601 602 case 3: /* smallest available */ 603 /* can't be disqualified by this one */ 604 break; 605 606 default: 607 /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */ 608 CL_ASSERT(FALSE); 609 status = IB_ERROR; 610 break; 611 } 612 } 613 614 if (status != IB_SUCCESS) 615 goto Exit; 616 617 /* 618 * set Pkey for this path record request 619 */ 620 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); 625 626 else if (comp_mask & IB_PR_COMPMASK_PKEY) { 627 /* 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. 633 */ 634 pkey = p_pr->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 645 (p_dest_physp)), 646 p_dest_physp->p_node->print_desc, 647 p_dest_physp->port_num, 648 cl_ntoh16(pkey)); 649 status = IB_NOT_FOUND; 650 goto Exit; 651 } 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", 658 p_qos_level->name, 659 cl_ntoh16(pkey), 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 664 (p_dest_physp)), 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; 668 goto Exit; 669 } 670 671 } else if (p_qos_level && p_qos_level->pkey_range_len) { 672 /* 673 * PR request doesn't have a specific pkey, but QoS level 674 * has pkeys - get shared pkey from QoS level pkeys 675 */ 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); 679 if (!pkey) { 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 687 (p_dest_physp)), 688 p_dest_physp->p_node->print_desc, 689 p_qos_level->name); 690 status = IB_NOT_FOUND; 691 goto Exit; 692 } 693 } else { 694 /* 695 * Neither PR request nor QoS level have pkey. 696 * Just get any shared pkey. 697 */ 698 pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp, 699 sa->p_subn->opt.allow_both_pkeys); 700 if (!pkey) { 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 709 (p_dest_physp)), 710 p_dest_physp->p_node->print_desc, 711 p_dest_physp->port_num); 712 status = IB_NOT_FOUND; 713 goto Exit; 714 } 715 } 716 717 if (pkey) { 718 p_prtn = 719 (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl, 720 pkey & cl_hton16((uint16_t) ~ 721 0x8000)); 722 if (p_prtn == 723 (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl)) 724 p_prtn = NULL; 725 } 726 727 /* 728 * Set PathRecord SL 729 */ 730 731 if (comp_mask & IB_PR_COMPMASK_SL) { 732 /* 733 * Specific SL was requested 734 */ 735 sl = ib_path_rec_sl(p_pr); 736 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, 743 p_qos_level->name, 744 p_qos_level->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; 750 goto Exit; 751 } 752 753 } else if (p_qos_level && p_qos_level->sl_set) { 754 /* 755 * No specific SL was requested, but there is an SL in 756 * QoS level. 757 */ 758 sl = p_qos_level->sl; 759 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); 764 765 } else if (pkey) { 766 /* 767 * No specific SL in request or in QoS level - use partition SL 768 */ 769 if (!p_prtn) { 770 sl = OSM_DEFAULT_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", 777 cl_ntoh16(pkey), sl, 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); 782 } else 783 sl = p_prtn->sl; 784 } else if (sa->p_subn->opt.qos) { 785 if (valid_sl_mask & (1 << OSM_DEFAULT_SL)) 786 sl = OSM_DEFAULT_SL; 787 else { 788 for (i = 0; i < IB_MAX_NUM_VLS; i++) 789 if (valid_sl_mask & (1 << i)) 790 break; 791 sl = i; 792 } 793 } else 794 sl = OSM_DEFAULT_SL; 795 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", 800 sl, 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; 806 goto Exit; 807 } 808 809 /* 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. 813 */ 814 if (p_re && p_re->path_sl) { 815 uint8_t pr_sl; 816 pr_sl = sl; 817 818 sl = p_re->path_sl(p_re->context, sl, 819 cl_hton16(src_lid_ho), cl_hton16(dest_lid_ho)); 820 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", 826 pr_sl, 827 sl, 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; 833 goto Exit; 834 } 835 } 836 /* reset pkey when raw traffic */ 837 if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC && 838 cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)) 839 pkey = 0; 840 841 p_parms->mtu = mtu; 842 p_parms->rate = rate; 843 p_parms->pkt_life = pkt_life; 844 p_parms->pkey = pkey; 845 p_parms->sl = sl; 846 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); 850 Exit: 851 OSM_LOG_EXIT(sa->p_log); 852 return status; 853 } 854 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) 861 { 862 osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid; 863 ib_path_rec_t pr; 864 865 if (!p_src_port || !slid_ho || !p_dest_port || !dlid_ho) 866 return IB_INVALID_PARAMETER; 867 868 memset(&pr, 0, sizeof(ib_path_rec_t)); 869 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); 877 } 878 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) 889 { 890 const osm_physp_t *p_src_physp, *p_dest_physp; 891 892 OSM_LOG_ENTER(sa->p_log); 893 894 if (p_dgid) 895 p_pr->dgid = *p_dgid; 896 else { 897 p_dest_physp = p_dest_alias_guid->p_base_port->p_physp; 898 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; 902 } 903 if (p_sgid) 904 p_pr->sgid = *p_sgid; 905 else { 906 p_src_physp = p_src_alias_guid->p_base_port->p_physp; 907 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; 910 } 911 912 p_pr->dlid = cl_hton16(dest_lid_ho); 913 p_pr->slid = cl_hton16(src_lid_ho); 914 915 p_pr->hop_flow_raw &= cl_hton32(1 << 31); 916 917 /* Only set HopLimit if going through a router */ 918 if (p_dgid) 919 p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX); 920 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); 926 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 */ 931 else 932 p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80); 933 934 p_pr->preference = preference; 935 936 /* always return num_path = 0 so this is only the reversible component */ 937 if (p_parms->reversible) 938 p_pr->num_path = 0x80; 939 940 OSM_LOG_EXIT(sa->p_log); 941 } 942 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) 953 { 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; 958 959 OSM_LOG_ENTER(sa->p_log); 960 961 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n", 962 src_lid_ho, dest_lid_ho); 963 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"); 968 goto Exit; 969 } 970 memset(p_pr_item, 0, SA_PR_RESP_SIZE); 971 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); 975 976 if (status != IB_SUCCESS) { 977 free(p_pr_item); 978 p_pr_item = NULL; 979 goto Exit; 980 } 981 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, 986 &rev_path_parms); 987 988 path_parms.reversible = (rev_path_status == IB_SUCCESS); 989 990 /* did we get a Reversible Path compmask ? */ 991 /* 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 995 */ 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"); 1000 free(p_pr_item); 1001 p_pr_item = NULL; 1002 goto Exit; 1003 } 1004 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); 1008 1009 Exit: 1010 OSM_LOG_EXIT(sa->p_log); 1011 return p_pr_item; 1012 } 1013 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) 1022 { 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; 1032 uint32_t path_num; 1033 uint8_t preference; 1034 unsigned iterations, src_offset, dest_offset; 1035 1036 OSM_LOG_ENTER(sa->p_log); 1037 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)); 1042 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. */ 1055 goto Exit; 1056 1057 /* 1058 We shouldn't be here if the paths are disqualified in some way... 1059 Thus, we assume every possible connection is valid. 1060 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: 1068 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 1073 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. 1077 1078 OpenSM ranks paths in three preference groups: 1079 1080 Preference Value Description 1081 ---------------- ------------------------------------------- 1082 0 Redundant in both directions with other 1083 pref value = 0 paths 1084 1085 1 Redundant in one direction with other 1086 pref value = 0 and pref value = 1 paths 1087 1088 2 Not redundant in either direction with 1089 other paths 1090 1091 3-FF Unused 1092 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. 1100 */ 1101 1102 /* 1103 Refine our search if the client specified end-point LIDs 1104 */ 1105 if (comp_mask & IB_PR_COMPMASK_DLID) 1106 dest_lid_max_ho = dest_lid_min_ho = cl_ntoh16(p_pr->dlid); 1107 else 1108 osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port, 1109 &dest_lid_min_ho, &dest_lid_max_ho); 1110 1111 if (comp_mask & IB_PR_COMPMASK_SLID) 1112 src_lid_max_ho = src_lid_min_ho = cl_ntoh16(p_pr->slid); 1113 else 1114 osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port, 1115 &src_lid_min_ho, &src_lid_max_ho); 1116 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 " 1120 "(%s port %d)\n", 1121 p_src_alias_guid->p_base_port->p_node->print_desc, 1122 p_src_alias_guid->p_base_port->p_physp->port_num); 1123 goto Exit; 1124 } 1125 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 " 1129 "(%s port %d)\n", 1130 p_dest_alias_guid->p_base_port->p_node->print_desc, 1131 p_dest_alias_guid->p_base_port->p_physp->port_num); 1132 goto Exit; 1133 } 1134 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); 1139 1140 src_lid_ho = src_lid_min_ho; 1141 dest_lid_ho = dest_lid_min_ho; 1142 1143 /* 1144 Preferred paths come first in OpenSM 1145 */ 1146 preference = 0; 1147 path_num = 0; 1148 1149 /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */ 1150 if (sa_mad->method == IB_MAD_METHOD_GET) 1151 iterations = 1; 1152 else if (comp_mask & IB_PR_COMPMASK_NUMBPATH) 1153 iterations = ib_path_rec_num_path(p_pr); 1154 else 1155 iterations = (unsigned) (-1); 1156 1157 while (path_num < iterations) { 1158 /* 1159 These paths are "fully redundant" 1160 */ 1161 1162 p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid, 1163 p_dest_alias_guid, 1164 p_sgid, p_dgid, 1165 src_lid_ho, dest_lid_ho, 1166 comp_mask, preference); 1167 1168 if (p_pr_item) { 1169 cl_qlist_insert_tail(p_list, &p_pr_item->list_item); 1170 ++path_num; 1171 } 1172 1173 if (++src_lid_ho > src_lid_max_ho) 1174 break; 1175 1176 if (++dest_lid_ho > dest_lid_max_ho) 1177 break; 1178 } 1179 1180 /* 1181 Check if we've accumulated all the paths that the user cares to see 1182 */ 1183 if (path_num == iterations) 1184 goto Exit; 1185 1186 /* 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. 1191 */ 1192 preference = 2; 1193 src_lid_ho = src_lid_min_ho; 1194 dest_lid_ho = dest_lid_min_ho; 1195 src_offset = 0; 1196 dest_offset = 0; 1197 1198 /* 1199 Iterate over the remaining paths 1200 */ 1201 while (path_num < iterations) { 1202 dest_offset++; 1203 dest_lid_ho++; 1204 1205 if (dest_lid_ho > dest_lid_max_ho) { 1206 src_offset++; 1207 src_lid_ho++; 1208 1209 if (src_lid_ho > src_lid_max_ho) 1210 break; /* done */ 1211 1212 dest_offset = 0; 1213 dest_lid_ho = dest_lid_min_ho; 1214 } 1215 1216 /* 1217 These paths are "fully non-redundant" with paths already 1218 identified above and consequently not of much value. 1219 1220 Don't return paths we already identified above, as indicated 1221 by the offset values being equal. 1222 */ 1223 if (src_offset == dest_offset) 1224 continue; /* already reported */ 1225 1226 p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid, 1227 p_dest_alias_guid, p_sgid, 1228 p_dgid, src_lid_ho, 1229 dest_lid_ho, comp_mask, 1230 preference); 1231 1232 if (p_pr_item) { 1233 cl_qlist_insert_tail(p_list, &p_pr_item->list_item); 1234 ++path_num; 1235 } 1236 } 1237 1238 Exit: 1239 OSM_LOG_EXIT(sa->p_log); 1240 } 1241 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) 1244 { 1245 osm_prefix_route_t *route = NULL; 1246 osm_router_t *rtr; 1247 cl_qlist_t *l = &sa->p_subn->prefix_routes_list; 1248 cl_list_item_t *i; 1249 1250 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix " 1251 "0x%016" PRIx64 "\n", cl_ntoh64(prefix)); 1252 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) { 1256 route = r; 1257 break; 1258 } 1259 } 1260 if (!route) 1261 return 0; 1262 1263 if (route->guid == 0) /* first router */ 1264 rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl); 1265 else 1266 rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl, 1267 route->guid); 1268 1269 if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl)) 1270 return 0; 1271 1272 return osm_port_get_guid(osm_router_get_port_ptr(rtr)); 1273 } 1274 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) 1283 { 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; 1288 1289 OSM_LOG_ENTER(sa->p_log); 1290 1291 /* 1292 Determine what fields are valid and then get a pointer 1293 to the source and destination port objects, if possible. 1294 */ 1295 1296 /* 1297 Check a few easy disqualifying cases up front before getting 1298 into the endpoints. 1299 */ 1300 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) { 1307 /* 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. 1311 */ 1312 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, 1313 "Non local SGID subnet prefix 0x%016" 1314 PRIx64 "\n", 1315 cl_ntoh64(p_pr->sgid.unicast.prefix)); 1316 sa_status = IB_SA_MAD_STATUS_INVALID_GID; 1317 goto Exit; 1318 } 1319 } 1320 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) { 1324 /* 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. 1328 */ 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; 1333 goto Exit; 1334 } 1335 if (pp_sgid) 1336 *pp_sgid = &p_pr->sgid; 1337 } 1338 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) { 1342 /* 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. 1346 */ 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; 1350 goto Exit; 1351 } 1352 } 1353 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); 1362 if (!dest_guid) { 1363 char gid_str[INET6_ADDRSTRLEN]; 1364 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, 1365 "Off subnet DGID %s, but router not " 1366 "found\n", 1367 inet_ntop(AF_INET6, p_pr->dgid.raw, 1368 gid_str, sizeof(gid_str))); 1369 sa_status = IB_SA_MAD_STATUS_INVALID_GID; 1370 goto Exit; 1371 } 1372 if (pp_dgid) 1373 *pp_dgid = &p_pr->dgid; 1374 } else 1375 dest_guid = p_pr->dgid.unicast.interface_id; 1376 1377 *pp_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn, 1378 dest_guid); 1379 if (!*pp_dest_alias_guid) { 1380 /* 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. 1384 */ 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; 1389 goto Exit; 1390 } 1391 } 1392 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) { 1396 /* 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. 1400 */ 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; 1404 goto Exit; 1405 } 1406 } 1407 1408 Exit: 1409 OSM_LOG_EXIT(sa->p_log); 1410 return sa_status; 1411 } 1412 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) 1418 { 1419 const cl_qmap_t *p_tbl; 1420 const osm_alias_guid_t *p_dest_alias_guid, *p_src_alias_guid; 1421 1422 OSM_LOG_ENTER(sa->p_log); 1423 1424 /* 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. 1428 1429 We compute both A -> B and B -> A, since we don't have 1430 any check to determine the reversability of the paths. 1431 */ 1432 p_tbl = &sa->p_subn->alias_port_guid_tbl; 1433 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, 1439 p_src_alias_guid, 1440 p_dest_alias_guid, 1441 p_sgid, p_dgid, p_list); 1442 if (sa_mad->method == IB_MAD_METHOD_GET && 1443 cl_qlist_count(p_list) > 0) 1444 goto Exit; 1445 1446 p_src_alias_guid = 1447 (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item); 1448 } 1449 1450 p_dest_alias_guid = 1451 (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item); 1452 } 1453 1454 Exit: 1455 OSM_LOG_EXIT(sa->p_log); 1456 } 1457 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) 1465 { 1466 const cl_qmap_t *p_tbl; 1467 const osm_alias_guid_t *p_alias_guid; 1468 1469 OSM_LOG_ENTER(sa->p_log); 1470 1471 /* 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. 1475 */ 1476 p_tbl = &sa->p_subn->alias_port_guid_tbl; 1477 1478 if (p_src_alias_guid) { 1479 /* 1480 The src port if fixed, so iterate over destination ports. 1481 */ 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, 1485 p_src_alias_guid, 1486 p_alias_guid, 1487 p_sgid, p_dgid, p_list); 1488 if (sa_mad->method == IB_MAD_METHOD_GET && 1489 cl_qlist_count(p_list) > 0) 1490 break; 1491 p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item); 1492 } 1493 } else { 1494 /* 1495 The dest port if fixed, so iterate over source ports. 1496 */ 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, 1500 p_alias_guid, 1501 p_dest_alias_guid, p_sgid, 1502 p_dgid, p_list); 1503 if (sa_mad->method == IB_MAD_METHOD_GET && 1504 cl_qlist_count(p_list) > 0) 1505 break; 1506 p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item); 1507 } 1508 } 1509 1510 OSM_LOG_EXIT(sa->p_log); 1511 } 1512 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) 1520 { 1521 OSM_LOG_ENTER(sa->p_log); 1522 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); 1525 1526 OSM_LOG_EXIT(sa->p_log); 1527 } 1528 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) 1532 { 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; 1539 1540 OSM_LOG_ENTER(sa->p_log); 1541 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)); 1547 goto Exit; 1548 } 1549 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)); 1559 goto Exit; 1560 } 1561 } 1562 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)); 1570 goto Exit; 1571 } 1572 } 1573 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)); 1581 goto Exit; 1582 } 1583 1584 ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop, 1585 &sl, &flow_label, &hop_limit); 1586 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); 1591 goto Exit; 1592 } 1593 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"); 1600 goto Exit; 1601 } 1602 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); 1609 goto Exit; 1610 } 1611 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); 1617 goto Exit; 1618 } 1619 1620 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); 1626 goto Exit; 1627 } 1628 1629 status = IB_SUCCESS; 1630 1631 Exit: 1632 OSM_LOG_EXIT(sa->p_log); 1633 return status; 1634 } 1635 1636 static void pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad, 1637 cl_qlist_t *list) 1638 { 1639 ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad); 1640 osm_mgrp_t *mgrp; 1641 ib_api_status_t status; 1642 osm_sa_item_t *pr_item; 1643 uint32_t flow_label; 1644 uint8_t sl, hop_limit; 1645 1646 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n"); 1647 1648 mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid); 1649 if (!mgrp) { 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, 1654 sizeof gid_str)); 1655 return; 1656 } 1657 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"); 1663 return; 1664 } 1665 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"); 1670 return; 1671 } 1672 memset(pr_item, 0, sizeof(cl_list_item_t)); 1673 1674 /* Copy PathRecord request into response */ 1675 pr_item->resp.path_rec = *pr; 1676 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; 1683 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; 1688 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); 1694 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; 1700 1701 pr_item->resp.path_rec.hop_flow_raw = 1702 cl_hton32(hop_limit) | (flow_label << 8); 1703 1704 cl_qlist_insert_tail(list, &pr_item->list_item); 1705 } 1706 1707 void osm_pr_rcv_process(IN void *context, IN void *data) 1708 { 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); 1713 cl_qlist_t pr_list; 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; 1718 uint8_t rate, mtu; 1719 1720 OSM_LOG_ENTER(sa->p_log); 1721 1722 CL_ASSERT(p_madw); 1723 1724 CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD); 1725 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); 1733 goto Exit; 1734 } 1735 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); 1743 goto Exit; 1744 } 1745 } 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); 1753 goto Exit; 1754 } 1755 } 1756 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); 1762 goto Exit; 1763 } 1764 1765 cl_qlist_init(&pr_list); 1766 1767 /* 1768 Most SA functions (including this one) are read-only on the 1769 subnet object, so we grab the lock non-exclusively. 1770 */ 1771 cl_plock_acquire(sa->p_lock); 1772 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 1776 (p_madw)); 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"); 1781 goto Exit; 1782 } 1783 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); 1789 } 1790 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); 1795 goto Unlock; 1796 } 1797 1798 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n"); 1799 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) 1804 goto Unlock; 1805 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); 1816 goto Exit; 1817 } 1818 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); 1829 goto Exit; 1830 } 1831 1832 /* 1833 What happens next depends on the type of endpoint information 1834 that was specified.... 1835 */ 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, 1844 p_dgid, &pr_list); 1845 else { 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) == 1851 p_dest_port) 1852 osm_pr_process_pair(sa, p_sa_mad, 1853 requester_port, 1854 p_src_alias_guid, 1855 p_dest_alias_guid, 1856 p_sgid, p_dgid, 1857 &pr_list); 1858 if (p_sa_mad->method == IB_MAD_METHOD_GET && 1859 cl_qlist_count(&pr_list) > 0) 1860 break; 1861 1862 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item); 1863 } 1864 } 1865 } else { 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, 1869 p_dgid, &pr_list); 1870 else if (!p_src_port && !p_dest_port) 1871 /* 1872 Katie, bar the door! 1873 */ 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) == 1883 p_src_port) 1884 osm_pr_process_pair(sa, p_sa_mad, 1885 requester_port, 1886 p_src_alias_guid, 1887 p_dest_alias_guid, 1888 p_sgid, p_dgid, 1889 &pr_list); 1890 if (p_sa_mad->method == IB_MAD_METHOD_GET && 1891 cl_qlist_count(&pr_list) > 0) 1892 break; 1893 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item); 1894 } 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) == 1902 p_src_port) 1903 osm_pr_process_half(sa, p_sa_mad, 1904 requester_port, 1905 p_src_alias_guid, 1906 NULL, p_sgid, 1907 p_dgid, &pr_list); 1908 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item); 1909 } 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) == 1917 p_dest_port) 1918 osm_pr_process_half(sa, p_sa_mad, 1919 requester_port, 1920 NULL, 1921 p_dest_alias_guid, 1922 p_sgid, p_dgid, 1923 &pr_list); 1924 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item); 1925 } 1926 } else { 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) == 1933 p_src_port) { 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) == 1940 p_dest_port) 1941 osm_pr_process_pair(sa, 1942 p_sa_mad, 1943 requester_port, 1944 p_src_alias_guid, 1945 p_dest_alias_guid, 1946 p_sgid, 1947 p_dgid, 1948 &pr_list); 1949 if (p_sa_mad->method == IB_MAD_METHOD_GET && 1950 cl_qlist_count(&pr_list) > 0) 1951 break; 1952 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item); 1953 } 1954 } 1955 if (p_sa_mad->method == IB_MAD_METHOD_GET && 1956 cl_qlist_count(&pr_list) > 0) 1957 break; 1958 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item); 1959 } 1960 } 1961 } 1962 1963 Unlock: 1964 cl_plock_release(sa->p_lock); 1965 1966 /* Now, (finally) respond to the PathRecord request */ 1967 osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list); 1968 1969 Exit: 1970 OSM_LOG_EXIT(sa->p_log); 1971 } 1972