|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Copyright (c) 2006-2009 Voltaire, Inc. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* This software is available to you under a choice of one of two
|
|
Packit |
13e616 |
* licenses. You may choose to be licensed under the terms of the GNU
|
|
Packit |
13e616 |
* General Public License (GPL) Version 2, available from the file
|
|
Packit |
13e616 |
* COPYING in the main directory of this source tree, or the
|
|
Packit |
13e616 |
* OpenIB.org BSD license below:
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* Redistribution and use in source and binary forms, with or
|
|
Packit |
13e616 |
* without modification, are permitted provided that the following
|
|
Packit |
13e616 |
* conditions are met:
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* - Redistributions of source code must retain the above
|
|
Packit |
13e616 |
* copyright notice, this list of conditions and the following
|
|
Packit |
13e616 |
* disclaimer.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* - Redistributions in binary form must reproduce the above
|
|
Packit |
13e616 |
* copyright notice, this list of conditions and the following
|
|
Packit |
13e616 |
* disclaimer in the documentation and/or other materials
|
|
Packit |
13e616 |
* provided with the distribution.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
13e616 |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
Packit |
13e616 |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
13e616 |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
Packit |
13e616 |
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
Packit |
13e616 |
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
Packit |
13e616 |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
Packit |
13e616 |
* SOFTWARE.
|
|
Packit |
13e616 |
*
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Abstract:
|
|
Packit |
13e616 |
* Implementation of osm_mpr_rcv_t.
|
|
Packit |
13e616 |
* This object represents the MultiPath Record Receiver object.
|
|
Packit |
13e616 |
* This object is part of the opensm family of objects.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#if HAVE_CONFIG_H
|
|
Packit |
13e616 |
# include <config.h>
|
|
Packit |
13e616 |
#endif /* HAVE_CONFIG_H */
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#include <string.h>
|
|
Packit |
13e616 |
#include <iba/ib_types.h>
|
|
Packit |
13e616 |
#include <complib/cl_qmap.h>
|
|
Packit |
13e616 |
#include <complib/cl_passivelock.h>
|
|
Packit |
13e616 |
#include <complib/cl_debug.h>
|
|
Packit |
13e616 |
#include <complib/cl_qlist.h>
|
|
Packit |
13e616 |
#include <opensm/osm_file_ids.h>
|
|
Packit |
13e616 |
#define FILE_ID OSM_FILE_SA_MULTIPATH_RECORD_C
|
|
Packit |
13e616 |
#include <vendor/osm_vendor_api.h>
|
|
Packit |
13e616 |
#include <opensm/osm_port.h>
|
|
Packit |
13e616 |
#include <opensm/osm_node.h>
|
|
Packit |
13e616 |
#include <opensm/osm_switch.h>
|
|
Packit |
13e616 |
#include <opensm/osm_partition.h>
|
|
Packit |
13e616 |
#include <opensm/osm_helper.h>
|
|
Packit |
13e616 |
#include <opensm/osm_qos_policy.h>
|
|
Packit |
13e616 |
#include <opensm/osm_sa.h>
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#define OSM_SA_MPR_MAX_NUM_PATH 127
|
|
Packit |
13e616 |
#define MAX_HOPS 64
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#define SA_MPR_RESP_SIZE SA_ITEM_RESP_SIZE(mpr_rec)
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static boolean_t sa_multipath_rec_is_tavor_port(IN const osm_port_t * p_port)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_node_t const *p_node;
|
|
Packit |
13e616 |
ib_net32_t vend_id;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_node = p_port->p_node;
|
|
Packit |
13e616 |
vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
|
|
Packit |
13e616 |
((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
|
|
Packit |
13e616 |
(vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
|
|
Packit |
13e616 |
(vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
|
|
Packit |
13e616 |
(vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static boolean_t
|
|
Packit |
13e616 |
sa_multipath_rec_apply_tavor_mtu_limit(IN const ib_multipath_rec_t * p_mpr,
|
|
Packit |
13e616 |
IN const osm_port_t * p_src_port,
|
|
Packit |
13e616 |
IN const osm_port_t * p_dest_port,
|
|
Packit |
13e616 |
IN const ib_net64_t comp_mask)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
uint8_t required_mtu;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* only if at least one of the ports is a Tavor device */
|
|
Packit |
13e616 |
if (!sa_multipath_rec_is_tavor_port(p_src_port) &&
|
|
Packit |
13e616 |
!sa_multipath_rec_is_tavor_port(p_dest_port))
|
|
Packit |
13e616 |
return FALSE;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
we can apply the patch if either:
|
|
Packit |
13e616 |
1. No MTU required
|
|
Packit |
13e616 |
2. Required MTU <
|
|
Packit |
13e616 |
3. Required MTU = 1K or 512 or 256
|
|
Packit |
13e616 |
4. Required MTU > 256 or 512
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
required_mtu = ib_multipath_rec_mtu(p_mpr);
|
|
Packit |
13e616 |
if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_MPR_COMPMASK_MTU)) {
|
|
Packit |
13e616 |
switch (ib_multipath_rec_mtu_sel(p_mpr)) {
|
|
Packit |
13e616 |
case 0: /* must be greater than */
|
|
Packit |
13e616 |
case 2: /* exact match */
|
|
Packit |
13e616 |
if (IB_MTU_LEN_1024 < required_mtu)
|
|
Packit |
13e616 |
return FALSE;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 1: /* must be less than */
|
|
Packit |
13e616 |
/* can't be disqualified by this one */
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 3: /* largest available */
|
|
Packit |
13e616 |
/* the ULP intentionally requested */
|
|
Packit |
13e616 |
/* the largest MTU possible */
|
|
Packit |
13e616 |
return FALSE;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
default:
|
|
Packit |
13e616 |
/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
|
|
Packit |
13e616 |
CL_ASSERT(FALSE);
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
return TRUE;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static ib_api_status_t mpr_rcv_get_path_parms(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_multipath_rec_t *
|
|
Packit |
13e616 |
p_mpr,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_src_alias_guid,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_dest_alias_guid,
|
|
Packit |
13e616 |
IN const uint16_t src_lid_ho,
|
|
Packit |
13e616 |
IN const uint16_t dest_lid_ho,
|
|
Packit |
13e616 |
IN const ib_net64_t comp_mask,
|
|
Packit |
13e616 |
OUT osm_path_parms_t * p_parms)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const osm_node_t *p_node;
|
|
Packit |
13e616 |
const osm_physp_t *p_physp, *p_physp0;
|
|
Packit |
13e616 |
const osm_physp_t *p_src_physp;
|
|
Packit |
13e616 |
const osm_physp_t *p_dest_physp;
|
|
Packit |
13e616 |
const osm_prtn_t *p_prtn = NULL;
|
|
Packit |
13e616 |
const ib_port_info_t *p_pi, *p_pi0;
|
|
Packit |
13e616 |
ib_slvl_table_t *p_slvl_tbl;
|
|
Packit |
13e616 |
ib_api_status_t status = IB_SUCCESS;
|
|
Packit |
13e616 |
uint8_t mtu;
|
|
Packit |
13e616 |
uint8_t rate, p0_extended_rate, dest_rate;
|
|
Packit |
13e616 |
uint8_t pkt_life;
|
|
Packit |
13e616 |
uint8_t required_mtu;
|
|
Packit |
13e616 |
uint8_t required_rate;
|
|
Packit |
13e616 |
ib_net16_t required_pkey;
|
|
Packit |
13e616 |
uint8_t required_sl;
|
|
Packit |
13e616 |
uint8_t required_pkt_life;
|
|
Packit |
13e616 |
ib_net16_t dest_lid;
|
|
Packit |
13e616 |
int hops = 0;
|
|
Packit |
13e616 |
int in_port_num = 0;
|
|
Packit |
13e616 |
uint8_t i;
|
|
Packit |
13e616 |
osm_qos_level_t *p_qos_level = NULL;
|
|
Packit |
13e616 |
uint16_t valid_sl_mask = 0xffff;
|
|
Packit |
13e616 |
int extended, p0_extended;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
dest_lid = cl_hton16(dest_lid_ho);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
|
|
Packit |
13e616 |
p_physp = p_src_alias_guid->p_base_port->p_physp;
|
|
Packit |
13e616 |
p_src_physp = p_physp;
|
|
Packit |
13e616 |
p_pi = &p_physp->port_info;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
mtu = ib_port_info_get_mtu_cap(p_pi);
|
|
Packit |
13e616 |
extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
|
|
Packit |
13e616 |
rate = ib_port_info_compute_rate(p_pi, extended);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Mellanox Tavor device performance is better using 1K MTU.
|
|
Packit |
13e616 |
If required MTU and MTU selector are such that 1K is OK
|
|
Packit |
13e616 |
and at least one end of the path is Tavor we override the
|
|
Packit |
13e616 |
port MTU with 1K.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (sa->p_subn->opt.enable_quirks &&
|
|
Packit |
13e616 |
sa_multipath_rec_apply_tavor_mtu_limit(p_mpr,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port,
|
|
Packit |
13e616 |
comp_mask))
|
|
Packit |
13e616 |
if (mtu > IB_MTU_LEN_1024) {
|
|
Packit |
13e616 |
mtu = IB_MTU_LEN_1024;
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Optimized Path MTU to 1K for Mellanox Tavor device\n");
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Walk the subnet object from source to destination,
|
|
Packit |
13e616 |
tracking the most restrictive rate and mtu values along the way...
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
If source port node is a switch, then p_physp should
|
|
Packit |
13e616 |
point to the port that routes the destination lid
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_node = osm_physp_get_node_ptr(p_physp);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_node->sw) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Source node is a switch.
|
|
Packit |
13e616 |
* Make sure that p_physp points to the out port of the
|
|
Packit |
13e616 |
* switch that routes to the destination lid (dest_lid_ho)
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
|
|
Packit |
13e616 |
if (p_physp == 0) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4514: "
|
|
Packit |
13e616 |
"Can't find routing from LID %u to LID %u on "
|
|
Packit |
13e616 |
"switch %s (GUID 0x%016" PRIx64 ")\n",
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho, p_node->print_desc,
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(p_node)));
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (sa->p_subn->opt.qos) {
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Whether this node is switch or CA, the IN port for
|
|
Packit |
13e616 |
* the sl2vl table is 0, because this is a source node.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* update valid SLs that still exist on this route */
|
|
Packit |
13e616 |
for (i = 0; i < IB_MAX_NUM_VLS; i++) {
|
|
Packit |
13e616 |
if (valid_sl_mask & (1 << i) &&
|
|
Packit |
13e616 |
ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
|
|
Packit |
13e616 |
valid_sl_mask &= ~(1 << i);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (!valid_sl_mask) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"All the SLs lead to VL15 on this path\n");
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Same as above
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_node = osm_physp_get_node_ptr(p_dest_physp);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_node->sw) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* if destination is switch, we want p_dest_physp to point to port 0
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_dest_physp =
|
|
Packit |
13e616 |
osm_switch_get_route_by_lid(p_node->sw, dest_lid);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_dest_physp == 0) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4515: "
|
|
Packit |
13e616 |
"Can't find routing from LID %u to LID %u on "
|
|
Packit |
13e616 |
"switch %s (GUID 0x%016" PRIx64 ")\n",
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho, p_node->print_desc,
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(p_node)));
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Now go through the path step by step
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
while (p_physp != p_dest_physp) {
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
int tmp_pnum = p_physp->port_num;
|
|
Packit |
13e616 |
p_node = osm_physp_get_node_ptr(p_physp);
|
|
Packit |
13e616 |
p_physp = osm_physp_get_remote(p_physp);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_physp == 0) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4505: "
|
|
Packit |
13e616 |
"Can't find remote phys port of %s (GUID "
|
|
Packit |
13e616 |
"0x%016" PRIx64 ") port %d "
|
|
Packit |
13e616 |
"while routing from LID %u to LID %u",
|
|
Packit |
13e616 |
p_node->print_desc,
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(p_node)),
|
|
Packit |
13e616 |
tmp_pnum, src_lid_ho, dest_lid_ho);
|
|
Packit |
13e616 |
status = IB_ERROR;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* update number of hops traversed */
|
|
Packit |
13e616 |
hops++;
|
|
Packit |
13e616 |
if (hops > MAX_HOPS) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4520: "
|
|
Packit |
13e616 |
"Path from GUID 0x%016" PRIx64 " (%s) to"
|
|
Packit |
13e616 |
" lid %u GUID 0x%016" PRIx64 " (%s) needs"
|
|
Packit |
13e616 |
" more than %d hops, max %d hops allowed\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
|
|
Packit |
13e616 |
p_src_physp->p_node->print_desc, dest_lid_ho,
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid
|
|
Packit |
13e616 |
(p_dest_physp)),
|
|
Packit |
13e616 |
p_dest_physp->p_node->print_desc, hops,
|
|
Packit |
13e616 |
MAX_HOPS);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
in_port_num = osm_physp_get_port_num(p_physp);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
This is point to point case (no switch in between)
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (p_physp == p_dest_physp)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_node = osm_physp_get_node_ptr(p_physp);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (!p_node->sw) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
There is some sort of problem in the subnet object!
|
|
Packit |
13e616 |
If this isn't a switch, we should have reached
|
|
Packit |
13e616 |
the destination by now!
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4503: "
|
|
Packit |
13e616 |
"Internal error, bad path while routing "
|
|
Packit |
13e616 |
"from %s (GUID: 0x%016"PRIx64") port %d "
|
|
Packit |
13e616 |
"to %s (GUID: 0x%016"PRIx64") port %d; "
|
|
Packit |
13e616 |
"ended at %s port %d\n",
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_physp->port_num,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_physp->port_num,
|
|
Packit |
13e616 |
p_node->print_desc,
|
|
Packit |
13e616 |
p_physp->port_num);
|
|
Packit |
13e616 |
status = IB_ERROR;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Check parameters for the ingress port in this switch.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_pi = &p_physp->port_info;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (mtu > ib_port_info_get_mtu_cap(p_pi))
|
|
Packit |
13e616 |
mtu = ib_port_info_get_mtu_cap(p_pi);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
|
|
Packit |
13e616 |
p_pi0 = &p_physp0->port_info;
|
|
Packit |
13e616 |
p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
|
|
Packit |
13e616 |
p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
|
|
Packit |
13e616 |
if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
|
|
Packit |
13e616 |
rate = p0_extended_rate;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Continue with the egress port on this switch.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
|
|
Packit |
13e616 |
if (p_physp == 0) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4516: "
|
|
Packit |
13e616 |
"Dead end path on switch "
|
|
Packit |
13e616 |
"%s (GUID: 0x%016"PRIx64") to LID %u\n",
|
|
Packit |
13e616 |
p_node->print_desc,
|
|
Packit |
13e616 |
cl_ntoh64(osm_node_get_node_guid(p_node)),
|
|
Packit |
13e616 |
dest_lid_ho);
|
|
Packit |
13e616 |
status = IB_ERROR;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pi = &p_physp->port_info;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (mtu > ib_port_info_get_mtu_cap(p_pi))
|
|
Packit |
13e616 |
mtu = ib_port_info_get_mtu_cap(p_pi);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
|
|
Packit |
13e616 |
if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
|
|
Packit |
13e616 |
rate = p0_extended_rate;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (sa->p_subn->opt.qos) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Check SL2VL table of the switch and update valid SLs
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_slvl_tbl =
|
|
Packit |
13e616 |
osm_physp_get_slvl_tbl(p_physp, in_port_num);
|
|
Packit |
13e616 |
for (i = 0; i < IB_MAX_NUM_VLS; i++) {
|
|
Packit |
13e616 |
if (valid_sl_mask & (1 << i) &&
|
|
Packit |
13e616 |
ib_slvl_table_get(p_slvl_tbl,
|
|
Packit |
13e616 |
i) == IB_DROP_VL)
|
|
Packit |
13e616 |
valid_sl_mask &= ~(1 << i);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (!valid_sl_mask) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"All the SLs lead to VL15 "
|
|
Packit |
13e616 |
"on this path\n");
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
p_physp now points to the destination
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_pi = &p_physp->port_info;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (mtu > ib_port_info_get_mtu_cap(p_pi))
|
|
Packit |
13e616 |
mtu = ib_port_info_get_mtu_cap(p_pi);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
|
|
Packit |
13e616 |
dest_rate = ib_port_info_compute_rate(p_pi, extended);
|
|
Packit |
13e616 |
if (ib_path_compare_rates(rate, dest_rate) > 0)
|
|
Packit |
13e616 |
rate = dest_rate;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Path min MTU = %u, min rate = %u\n", mtu, rate);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Get QoS Level object according to the MultiPath request
|
|
Packit |
13e616 |
* and adjust MultiPath parameters according to QoS settings
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (sa->p_subn->opt.qos && sa->p_subn->p_qos_policy &&
|
|
Packit |
13e616 |
(p_qos_level =
|
|
Packit |
13e616 |
osm_qos_policy_get_qos_level_by_mpr(sa->p_subn->p_qos_policy,
|
|
Packit |
13e616 |
p_mpr, p_src_physp,
|
|
Packit |
13e616 |
p_dest_physp, comp_mask))) {
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"MultiPathRecord request matches QoS Level '%s' (%s)\n",
|
|
Packit |
13e616 |
p_qos_level->name,
|
|
Packit |
13e616 |
p_qos_level->use ? p_qos_level->use : "no description");
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_qos_level->mtu_limit_set
|
|
Packit |
13e616 |
&& (mtu > p_qos_level->mtu_limit))
|
|
Packit |
13e616 |
mtu = p_qos_level->mtu_limit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_qos_level->rate_limit_set
|
|
Packit |
13e616 |
&& (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
|
|
Packit |
13e616 |
rate = p_qos_level->rate_limit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_qos_level->sl_set) {
|
|
Packit |
13e616 |
required_sl = p_qos_level->sl;
|
|
Packit |
13e616 |
if (!(valid_sl_mask & (1 << required_sl))) {
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Determine if these values meet the user criteria
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* we silently ignore cases where only the MTU selector is defined */
|
|
Packit |
13e616 |
if ((comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_MPR_COMPMASK_MTU)) {
|
|
Packit |
13e616 |
required_mtu = ib_multipath_rec_mtu(p_mpr);
|
|
Packit |
13e616 |
switch (ib_multipath_rec_mtu_sel(p_mpr)) {
|
|
Packit |
13e616 |
case 0: /* must be greater than */
|
|
Packit |
13e616 |
if (mtu <= required_mtu)
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 1: /* must be less than */
|
|
Packit |
13e616 |
if (mtu >= required_mtu) {
|
|
Packit |
13e616 |
/* adjust to use the highest mtu
|
|
Packit |
13e616 |
lower then the required one */
|
|
Packit |
13e616 |
if (required_mtu > 1)
|
|
Packit |
13e616 |
mtu = required_mtu - 1;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 2: /* exact match */
|
|
Packit |
13e616 |
if (mtu < required_mtu)
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
mtu = required_mtu;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 3: /* largest available */
|
|
Packit |
13e616 |
/* can't be disqualified by this one */
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
default:
|
|
Packit |
13e616 |
/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
|
|
Packit |
13e616 |
CL_ASSERT(FALSE);
|
|
Packit |
13e616 |
status = IB_ERROR;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (status != IB_SUCCESS)
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* we silently ignore cases where only the Rate selector is defined */
|
|
Packit |
13e616 |
if ((comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_MPR_COMPMASK_RATE)) {
|
|
Packit |
13e616 |
required_rate = ib_multipath_rec_rate(p_mpr);
|
|
Packit |
13e616 |
switch (ib_multipath_rec_rate_sel(p_mpr)) {
|
|
Packit |
13e616 |
case 0: /* must be greater than */
|
|
Packit |
13e616 |
if (ib_path_compare_rates(rate, required_rate) <= 0)
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 1: /* must be less than */
|
|
Packit |
13e616 |
if (ib_path_compare_rates(rate, required_rate) >= 0) {
|
|
Packit |
13e616 |
/* adjust the rate to use the highest rate
|
|
Packit |
13e616 |
lower then the required one */
|
|
Packit |
13e616 |
rate = ib_path_rate_get_prev(required_rate);
|
|
Packit |
13e616 |
if (!rate)
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 2: /* exact match */
|
|
Packit |
13e616 |
if (ib_path_compare_rates(rate, required_rate))
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
rate = required_rate;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 3: /* largest available */
|
|
Packit |
13e616 |
/* can't be disqualified by this one */
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
default:
|
|
Packit |
13e616 |
/* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
|
|
Packit |
13e616 |
CL_ASSERT(FALSE);
|
|
Packit |
13e616 |
status = IB_ERROR;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (status != IB_SUCCESS)
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Verify the pkt_life_time */
|
|
Packit |
13e616 |
/* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,
|
|
Packit |
13e616 |
for loopback paths, packetLifeTime shall be zero. */
|
|
Packit |
13e616 |
if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
|
|
Packit |
13e616 |
pkt_life = 0; /* loopback */
|
|
Packit |
13e616 |
else if (p_qos_level && p_qos_level->pkt_life_set)
|
|
Packit |
13e616 |
pkt_life = p_qos_level->pkt_life;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
pkt_life = sa->p_subn->opt.subnet_timeout;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* we silently ignore cases where only the PktLife selector is defined */
|
|
Packit |
13e616 |
if ((comp_mask & IB_MPR_COMPMASK_PKTLIFETIMESELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_MPR_COMPMASK_PKTLIFETIME)) {
|
|
Packit |
13e616 |
required_pkt_life = ib_multipath_rec_pkt_life(p_mpr);
|
|
Packit |
13e616 |
switch (ib_multipath_rec_pkt_life_sel(p_mpr)) {
|
|
Packit |
13e616 |
case 0: /* must be greater than */
|
|
Packit |
13e616 |
if (pkt_life <= required_pkt_life)
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 1: /* must be less than */
|
|
Packit |
13e616 |
if (pkt_life >= required_pkt_life) {
|
|
Packit |
13e616 |
/* adjust the lifetime to use the highest possible
|
|
Packit |
13e616 |
lower then the required one */
|
|
Packit |
13e616 |
if (required_pkt_life > 1)
|
|
Packit |
13e616 |
pkt_life = required_pkt_life - 1;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 2: /* exact match */
|
|
Packit |
13e616 |
if (pkt_life < required_pkt_life)
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
pkt_life = required_pkt_life;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
case 3: /* smallest available */
|
|
Packit |
13e616 |
/* can't be disqualified by this one */
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
default:
|
|
Packit |
13e616 |
/* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
|
|
Packit |
13e616 |
CL_ASSERT(FALSE);
|
|
Packit |
13e616 |
status = IB_ERROR;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (status != IB_SUCCESS)
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* set Pkey for this MultiPath record request
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
|
|
Packit |
13e616 |
cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
|
|
Packit |
13e616 |
required_pkey =
|
|
Packit |
13e616 |
osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
else if (comp_mask & IB_MPR_COMPMASK_PKEY) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* MPR request has a specific pkey:
|
|
Packit |
13e616 |
* Check that source and destination share this pkey.
|
|
Packit |
13e616 |
* If QoS level has pkeys, check that this pkey exists
|
|
Packit |
13e616 |
* in the QoS level pkeys.
|
|
Packit |
13e616 |
* MPR returned pkey is the requested pkey.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
required_pkey = p_mpr->pkey;
|
|
Packit |
13e616 |
if (!osm_physp_share_this_pkey
|
|
Packit |
13e616 |
(p_src_physp, p_dest_physp, required_pkey,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys)) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4518: "
|
|
Packit |
13e616 |
"Ports src 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"and dst 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"do not share the specified PKey 0x%04x\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
|
|
Packit |
13e616 |
p_src_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_src_physp->port_num,
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid
|
|
Packit |
13e616 |
(p_dest_physp)),
|
|
Packit |
13e616 |
p_dest_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_dest_physp->port_num,
|
|
Packit |
13e616 |
cl_ntoh16(required_pkey));
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (p_qos_level && p_qos_level->pkey_range_len &&
|
|
Packit |
13e616 |
!osm_qos_level_has_pkey(p_qos_level, required_pkey)) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451C: "
|
|
Packit |
13e616 |
"Ports src 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"and dst 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"do not share specified PKey (0x%04x) as "
|
|
Packit |
13e616 |
"defined by QoS level \"%s\"\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
|
|
Packit |
13e616 |
p_src_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_src_physp->port_num,
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid
|
|
Packit |
13e616 |
(p_dest_physp)),
|
|
Packit |
13e616 |
p_dest_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_dest_physp->port_num,
|
|
Packit |
13e616 |
cl_ntoh16(required_pkey),
|
|
Packit |
13e616 |
p_qos_level->name);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
} else if (p_qos_level && p_qos_level->pkey_range_len) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* MPR request doesn't have a specific pkey, but QoS level
|
|
Packit |
13e616 |
* has pkeys - get shared pkey from QoS level pkeys
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
required_pkey = osm_qos_level_get_shared_pkey(p_qos_level,
|
|
Packit |
13e616 |
p_src_physp,
|
|
Packit |
13e616 |
p_dest_physp,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys);
|
|
Packit |
13e616 |
if (!required_pkey) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451D: "
|
|
Packit |
13e616 |
"Ports src 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"and dst 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"do not share a PKey as defined by QoS "
|
|
Packit |
13e616 |
"level \"%s\"\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
|
|
Packit |
13e616 |
p_src_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_src_physp->port_num,
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid
|
|
Packit |
13e616 |
(p_dest_physp)),
|
|
Packit |
13e616 |
p_dest_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_dest_physp->port_num,
|
|
Packit |
13e616 |
p_qos_level->name);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Neither MPR request nor QoS level have pkey.
|
|
Packit |
13e616 |
* Just get any shared pkey.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
required_pkey =
|
|
Packit |
13e616 |
osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys);
|
|
Packit |
13e616 |
if (!required_pkey) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4519: "
|
|
Packit |
13e616 |
"Ports src 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"and dst 0x%016"PRIx64" (%s port %d) "
|
|
Packit |
13e616 |
"do not have any shared PKeys\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
|
|
Packit |
13e616 |
p_src_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_src_physp->port_num,
|
|
Packit |
13e616 |
cl_ntoh64(osm_physp_get_port_guid
|
|
Packit |
13e616 |
(p_dest_physp)),
|
|
Packit |
13e616 |
p_dest_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_dest_physp->port_num);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (required_pkey) {
|
|
Packit |
13e616 |
p_prtn =
|
|
Packit |
13e616 |
(osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
|
|
Packit |
13e616 |
required_pkey &
|
|
Packit |
13e616 |
cl_ntoh16((uint16_t) ~ 0x8000));
|
|
Packit |
13e616 |
if (p_prtn ==
|
|
Packit |
13e616 |
(osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
|
|
Packit |
13e616 |
p_prtn = NULL;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Set MultiPathRecord SL.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_MPR_COMPMASK_SL) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Specific SL was requested
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
required_sl = ib_multipath_rec_sl(p_mpr);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_qos_level && p_qos_level->sl_set &&
|
|
Packit |
13e616 |
p_qos_level->sl != required_sl) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451E: "
|
|
Packit |
13e616 |
"QoS constraints: required MultiPathRecord SL "
|
|
Packit |
13e616 |
"(%u) doesn't match QoS policy \"%s\" SL (%u) "
|
|
Packit |
13e616 |
"[%s port %d <-> %s port %d]\n", required_sl,
|
|
Packit |
13e616 |
p_qos_level->name,
|
|
Packit |
13e616 |
p_qos_level->sl,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_physp->port_num,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_physp->port_num);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
} else if (p_qos_level && p_qos_level->sl_set) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* No specific SL was requested,
|
|
Packit |
13e616 |
* but there is an SL in QoS level.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
required_sl = p_qos_level->sl;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (required_pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"QoS level SL (%u) overrides partition SL (%u)\n",
|
|
Packit |
13e616 |
p_qos_level->sl, p_prtn->sl);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
} else if (required_pkey) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* No specific SL in request or in QoS level - use partition SL
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_prtn =
|
|
Packit |
13e616 |
(osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
|
|
Packit |
13e616 |
required_pkey &
|
|
Packit |
13e616 |
cl_ntoh16((uint16_t) ~ 0x8000));
|
|
Packit |
13e616 |
if (!p_prtn) {
|
|
Packit |
13e616 |
required_sl = OSM_DEFAULT_SL;
|
|
Packit |
13e616 |
/* this may be possible when pkey tables are created somehow in
|
|
Packit |
13e616 |
previous runs or things are going wrong here */
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451A: "
|
|
Packit |
13e616 |
"No partition found for PKey 0x%04x - "
|
|
Packit |
13e616 |
"using default SL %d "
|
|
Packit |
13e616 |
"[%s port %d <-> %s port %d]\n",
|
|
Packit |
13e616 |
cl_ntoh16(required_pkey), required_sl,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_physp->port_num,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_physp->port_num);
|
|
Packit |
13e616 |
} else
|
|
Packit |
13e616 |
required_sl = p_prtn->sl;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
} else if (sa->p_subn->opt.qos) {
|
|
Packit |
13e616 |
if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
|
|
Packit |
13e616 |
required_sl = OSM_DEFAULT_SL;
|
|
Packit |
13e616 |
else {
|
|
Packit |
13e616 |
for (i = 0; i < IB_MAX_NUM_VLS; i++)
|
|
Packit |
13e616 |
if (valid_sl_mask & (1 << i))
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
required_sl = i;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else
|
|
Packit |
13e616 |
required_sl = OSM_DEFAULT_SL;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << required_sl))) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 451F: "
|
|
Packit |
13e616 |
"Selected SL (%u) leads to VL15 "
|
|
Packit |
13e616 |
"[%s port %d <-> %s port %d]\n",
|
|
Packit |
13e616 |
required_sl,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port->p_physp->port_num,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_node->print_desc,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port->p_physp->port_num);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* reset pkey when raw traffic */
|
|
Packit |
13e616 |
if (comp_mask & IB_MPR_COMPMASK_RAWTRAFFIC &&
|
|
Packit |
13e616 |
cl_ntoh32(p_mpr->hop_flow_raw) & (1 << 31))
|
|
Packit |
13e616 |
required_pkey = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_parms->mtu = mtu;
|
|
Packit |
13e616 |
p_parms->rate = rate;
|
|
Packit |
13e616 |
p_parms->pkey = required_pkey;
|
|
Packit |
13e616 |
p_parms->pkt_life = pkt_life;
|
|
Packit |
13e616 |
p_parms->sl = required_sl;
|
|
Packit |
13e616 |
p_parms->hops = hops;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "MultiPath params:"
|
|
Packit |
13e616 |
" mtu = %u, rate = %u, packet lifetime = %u,"
|
|
Packit |
13e616 |
" pkey = 0x%04X, sl = %u, hops = %u\n", mtu, rate,
|
|
Packit |
13e616 |
pkt_life, cl_ntoh16(required_pkey), required_sl, hops);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
return status;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void mpr_rcv_build_pr(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_src_alias_guid,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_dest_alias_guid,
|
|
Packit |
13e616 |
IN uint16_t src_lid_ho, IN uint16_t dest_lid_ho,
|
|
Packit |
13e616 |
IN uint8_t preference,
|
|
Packit |
13e616 |
IN const osm_path_parms_t * p_parms,
|
|
Packit |
13e616 |
OUT ib_path_rec_t * p_pr)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const osm_physp_t *p_src_physp, *p_dest_physp;
|
|
Packit |
13e616 |
uint8_t rate, new_rate;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_src_physp = p_src_alias_guid->p_base_port->p_physp;
|
|
Packit |
13e616 |
p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix(p_dest_physp);
|
|
Packit |
13e616 |
p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
|
|
Packit |
13e616 |
p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->dlid = cl_hton16(dest_lid_ho);
|
|
Packit |
13e616 |
p_pr->slid = cl_hton16(src_lid_ho);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->hop_flow_raw &= cl_hton32(1 << 31);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->pkey = p_parms->pkey;
|
|
Packit |
13e616 |
ib_path_rec_set_qos_class(p_pr, 0);
|
|
Packit |
13e616 |
ib_path_rec_set_sl(p_pr, p_parms->sl);
|
|
Packit |
13e616 |
p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
|
|
Packit |
13e616 |
rate = p_parms->rate;
|
|
Packit |
13e616 |
if (sa->p_subn->opt.use_original_extended_sa_rates_only) {
|
|
Packit |
13e616 |
new_rate = ib_path_rate_max_12xedr(rate);
|
|
Packit |
13e616 |
if (new_rate != rate) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Rate decreased from %u to %u\n",
|
|
Packit |
13e616 |
rate, new_rate);
|
|
Packit |
13e616 |
rate = new_rate;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else if (rate >= IB_PATH_RECORD_RATE_28_GBS) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* If one of the new 2x or HDR rates, make sure that
|
|
Packit |
13e616 |
* src (and dest if reversible) ports support this
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
rate = ib_path_rate_2x_hdr_fixups(&p_src_physp->port_info, rate);
|
|
Packit |
13e616 |
if (p_parms->reversible)
|
|
Packit |
13e616 |
rate = ib_path_rate_2x_hdr_fixups(&p_dest_physp->port_info, rate);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
p_pr->rate = (uint8_t) (rate | 0x80);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* According to 1.2 spec definition Table 205 PacketLifeTime description,
|
|
Packit |
13e616 |
for loopback paths, packetLifeTime shall be zero. */
|
|
Packit |
13e616 |
if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
|
|
Packit |
13e616 |
p_pr->pkt_life = 0x80; /* loopback */
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->preference = preference;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* always return num_path = 0 so this is only the reversible component */
|
|
Packit |
13e616 |
if (p_parms->reversible)
|
|
Packit |
13e616 |
p_pr->num_path = 0x80;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static osm_sa_item_t *mpr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_multipath_rec_t *
|
|
Packit |
13e616 |
p_mpr,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t *
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t *
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
IN const uint16_t src_lid_ho,
|
|
Packit |
13e616 |
IN const uint16_t dest_lid_ho,
|
|
Packit |
13e616 |
IN const ib_net64_t comp_mask,
|
|
Packit |
13e616 |
IN const uint8_t preference)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_path_parms_t path_parms;
|
|
Packit |
13e616 |
osm_path_parms_t rev_path_parms;
|
|
Packit |
13e616 |
osm_sa_item_t *p_pr_item;
|
|
Packit |
13e616 |
ib_api_status_t status, rev_path_status;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr_item = malloc(SA_MPR_RESP_SIZE);
|
|
Packit |
13e616 |
if (p_pr_item == NULL) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4501: "
|
|
Packit |
13e616 |
"Unable to allocate path record\n");
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
memset(p_pr_item, 0, SA_MPR_RESP_SIZE);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
status = mpr_rcv_get_path_parms(sa, p_mpr, p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho,
|
|
Packit |
13e616 |
comp_mask, &path_parms);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (status != IB_SUCCESS) {
|
|
Packit |
13e616 |
free(p_pr_item);
|
|
Packit |
13e616 |
p_pr_item = NULL;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* now try the reversible path */
|
|
Packit |
13e616 |
rev_path_status = mpr_rcv_get_path_parms(sa, p_mpr, p_dest_alias_guid,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
dest_lid_ho, src_lid_ho,
|
|
Packit |
13e616 |
comp_mask, &rev_path_parms);
|
|
Packit |
13e616 |
path_parms.reversible = (rev_path_status == IB_SUCCESS);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* did we get a Reversible Path compmask ? */
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
NOTE that if the reversible component = 0, it is a don't care
|
|
Packit |
13e616 |
rather then requiring non-reversible paths ...
|
|
Packit |
13e616 |
see Vol1 Ver1.2 p900 l16
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (comp_mask & IB_MPR_COMPMASK_REVERSIBLE) {
|
|
Packit |
13e616 |
if ((!path_parms.reversible && (p_mpr->num_path & 0x80))) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Requested reversible path but failed to get one\n");
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
free(p_pr_item);
|
|
Packit |
13e616 |
p_pr_item = NULL;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr_item->resp.mpr_rec.p_src_port = p_src_alias_guid->p_base_port;
|
|
Packit |
13e616 |
p_pr_item->resp.mpr_rec.p_dest_port = p_dest_alias_guid->p_base_port;
|
|
Packit |
13e616 |
p_pr_item->resp.mpr_rec.hops = path_parms.hops;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
mpr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, src_lid_ho,
|
|
Packit |
13e616 |
dest_lid_ho, preference, &path_parms,
|
|
Packit |
13e616 |
&p_pr_item->resp.mpr_rec.path_rec);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
return p_pr_item;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static uint32_t mpr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_multipath_rec_t * p_mpr,
|
|
Packit |
13e616 |
IN const osm_port_t * p_req_port,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_src_alias_guid,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_dest_alias_guid,
|
|
Packit |
13e616 |
IN const uint32_t rem_paths,
|
|
Packit |
13e616 |
IN const ib_net64_t comp_mask,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_sa_item_t *p_pr_item;
|
|
Packit |
13e616 |
uint16_t src_lid_min_ho;
|
|
Packit |
13e616 |
uint16_t src_lid_max_ho;
|
|
Packit |
13e616 |
uint16_t dest_lid_min_ho;
|
|
Packit |
13e616 |
uint16_t dest_lid_max_ho;
|
|
Packit |
13e616 |
uint16_t src_lid_ho;
|
|
Packit |
13e616 |
uint16_t dest_lid_ho;
|
|
Packit |
13e616 |
uint32_t path_num = 0;
|
|
Packit |
13e616 |
uint8_t preference;
|
|
Packit |
13e616 |
unsigned src_offset, dest_offset;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(p_src_alias_guid->alias_guid),
|
|
Packit |
13e616 |
cl_ntoh64(p_dest_alias_guid->alias_guid));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Check that the req_port, src_port and dest_port all share a
|
|
Packit |
13e616 |
pkey. The check is done on the default physical port of the ports. */
|
|
Packit |
13e616 |
if (osm_port_share_pkey(sa->p_log, p_req_port,
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys) == FALSE
|
|
Packit |
13e616 |
|| osm_port_share_pkey(sa->p_log, p_req_port,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys) == FALSE
|
|
Packit |
13e616 |
|| osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys) == FALSE)
|
|
Packit |
13e616 |
/* One of the pairs doesn't share a pkey so the path is disqualified. */
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
We shouldn't be here if the paths are disqualified in some way...
|
|
Packit |
13e616 |
Thus, we assume every possible connection is valid.
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
We desire to return high-quality paths first.
|
|
Packit |
13e616 |
In OpenSM, higher quality mean least overlap with other paths.
|
|
Packit |
13e616 |
This is acheived in practice by returning paths with
|
|
Packit |
13e616 |
different LID value on each end, which means these
|
|
Packit |
13e616 |
paths are more redundant that paths with the same LID repeated
|
|
Packit |
13e616 |
on one side. For example, in OpenSM the paths between two
|
|
Packit |
13e616 |
endpoints with LMC = 1 might be as follows:
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Port A, LID 1 <-> Port B, LID 3
|
|
Packit |
13e616 |
Port A, LID 1 <-> Port B, LID 4
|
|
Packit |
13e616 |
Port A, LID 2 <-> Port B, LID 3
|
|
Packit |
13e616 |
Port A, LID 2 <-> Port B, LID 4
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
The OpenSM unicast routing algorithms attempt to disperse each path
|
|
Packit |
13e616 |
to as varied a physical path as is reasonable. 1<->3 and 1<->4 have
|
|
Packit |
13e616 |
more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OpenSM ranks paths in three preference groups:
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Preference Value Description
|
|
Packit |
13e616 |
---------------- -------------------------------------------
|
|
Packit |
13e616 |
0 Redundant in both directions with other
|
|
Packit |
13e616 |
pref value = 0 paths
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
1 Redundant in one direction with other
|
|
Packit |
13e616 |
pref value = 0 and pref value = 1 paths
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
2 Not redundant in either direction with
|
|
Packit |
13e616 |
other paths
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
3-FF Unused
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
SA clients don't need to know these details, only that the lower
|
|
Packit |
13e616 |
preference paths are preferred, as stated in the spec. The paths
|
|
Packit |
13e616 |
may not actually be physically redundant depending on the topology
|
|
Packit |
13e616 |
of the subnet, but the point of LMC > 0 is to offer redundancy,
|
|
Packit |
13e616 |
so I assume the subnet is physically appropriate for the specified
|
|
Packit |
13e616 |
LMC value. A more advanced implementation could inspect for physical
|
|
Packit |
13e616 |
redundancy, but I'm not going to bother with that now.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
|
|
Packit |
13e616 |
&src_lid_min_ho, &src_lid_max_ho);
|
|
Packit |
13e616 |
osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
|
|
Packit |
13e616 |
&dest_lid_min_ho, &dest_lid_max_ho);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID [%u-%u], Dest LID [%u-%u]\n",
|
|
Packit |
13e616 |
src_lid_min_ho, src_lid_max_ho,
|
|
Packit |
13e616 |
dest_lid_min_ho, dest_lid_max_ho);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
src_lid_ho = src_lid_min_ho;
|
|
Packit |
13e616 |
dest_lid_ho = dest_lid_min_ho;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Preferred paths come first in OpenSM
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
preference = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
while (path_num < rem_paths) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
These paths are "fully redundant"
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho,
|
|
Packit |
13e616 |
comp_mask, preference);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_pr_item) {
|
|
Packit |
13e616 |
cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
|
|
Packit |
13e616 |
++path_num;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (++src_lid_ho > src_lid_max_ho)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (++dest_lid_ho > dest_lid_max_ho)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Check if we've accumulated all the paths that the user cares to see
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (path_num == rem_paths)
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Don't bother reporting preference 1 paths for now.
|
|
Packit |
13e616 |
It's more trouble than it's worth and can only occur
|
|
Packit |
13e616 |
if ports have different LMC values, which isn't supported
|
|
Packit |
13e616 |
by OpenSM right now anyway.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
preference = 2;
|
|
Packit |
13e616 |
src_lid_ho = src_lid_min_ho;
|
|
Packit |
13e616 |
dest_lid_ho = dest_lid_min_ho;
|
|
Packit |
13e616 |
src_offset = 0;
|
|
Packit |
13e616 |
dest_offset = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Iterate over the remaining paths
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
while (path_num < rem_paths) {
|
|
Packit |
13e616 |
dest_offset++;
|
|
Packit |
13e616 |
dest_lid_ho++;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (dest_lid_ho > dest_lid_max_ho) {
|
|
Packit |
13e616 |
src_offset++;
|
|
Packit |
13e616 |
src_lid_ho++;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (src_lid_ho > src_lid_max_ho)
|
|
Packit |
13e616 |
break; /* done */
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
dest_offset = 0;
|
|
Packit |
13e616 |
dest_lid_ho = dest_lid_min_ho;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
These paths are "fully non-redundant" with paths already
|
|
Packit |
13e616 |
identified above and consequently not of much value.
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Don't return paths we already identified above, as indicated
|
|
Packit |
13e616 |
by the offset values being equal.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (src_offset == dest_offset)
|
|
Packit |
13e616 |
continue; /* already reported */
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho,
|
|
Packit |
13e616 |
comp_mask, preference);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_pr_item) {
|
|
Packit |
13e616 |
cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
|
|
Packit |
13e616 |
++path_num;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
return path_num;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#undef min
|
|
Packit |
13e616 |
#define min(x,y) (((x) < (y)) ? (x) : (y))
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static osm_sa_item_t *mpr_rcv_get_apm_port_pair_paths(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const
|
|
Packit |
13e616 |
ib_multipath_rec_t *
|
|
Packit |
13e616 |
p_mpr,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t *
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t *
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
IN int base_offs,
|
|
Packit |
13e616 |
IN const ib_net64_t
|
|
Packit |
13e616 |
comp_mask,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_sa_item_t *p_pr_item = 0;
|
|
Packit |
13e616 |
uint16_t src_lid_min_ho;
|
|
Packit |
13e616 |
uint16_t src_lid_max_ho;
|
|
Packit |
13e616 |
uint16_t dest_lid_min_ho;
|
|
Packit |
13e616 |
uint16_t dest_lid_max_ho;
|
|
Packit |
13e616 |
uint16_t src_lid_ho;
|
|
Packit |
13e616 |
uint16_t dest_lid_ho;
|
|
Packit |
13e616 |
unsigned iterations;
|
|
Packit |
13e616 |
int src_lids, dest_lids;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src port 0x%016" PRIx64 ", "
|
|
Packit |
13e616 |
"Dst port 0x%016" PRIx64 ", base offs %d\n",
|
|
Packit |
13e616 |
cl_ntoh64(p_src_alias_guid->alias_guid),
|
|
Packit |
13e616 |
cl_ntoh64(p_dest_alias_guid->alias_guid),
|
|
Packit |
13e616 |
base_offs);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
|
|
Packit |
13e616 |
&src_lid_min_ho, &src_lid_max_ho);
|
|
Packit |
13e616 |
osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
|
|
Packit |
13e616 |
&dest_lid_min_ho, &dest_lid_max_ho);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
src_lid_ho = src_lid_min_ho;
|
|
Packit |
13e616 |
dest_lid_ho = dest_lid_min_ho;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
src_lids = src_lid_max_ho - src_lid_min_ho + 1;
|
|
Packit |
13e616 |
dest_lids = dest_lid_max_ho - dest_lid_min_ho + 1;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
src_lid_ho += base_offs % src_lids;
|
|
Packit |
13e616 |
dest_lid_ho += base_offs % dest_lids;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Src LIDs [%u-%u] hashed %u, "
|
|
Packit |
13e616 |
"Dest LIDs [%u-%u] hashed %u\n",
|
|
Packit |
13e616 |
src_lid_min_ho, src_lid_max_ho, src_lid_ho,
|
|
Packit |
13e616 |
dest_lid_min_ho, dest_lid_max_ho, dest_lid_ho);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
iterations = min(src_lids, dest_lids);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
while (iterations--) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
These paths are "fully redundant"
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_pr_item = mpr_rcv_get_lid_pair_path(sa, p_mpr,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho,
|
|
Packit |
13e616 |
comp_mask, 0);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_pr_item) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Found matching path from Src LID %u to Dest LID %u with %d hops\n",
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho, p_pr_item->resp.mpr_rec.hops);
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (++src_lid_ho > src_lid_max_ho)
|
|
Packit |
13e616 |
src_lid_ho = src_lid_min_ho;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (++dest_lid_ho > dest_lid_max_ho)
|
|
Packit |
13e616 |
dest_lid_ho = dest_lid_min_ho;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
return p_pr_item;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static ib_net16_t mpr_rcv_get_gids(IN osm_sa_t * sa, IN const ib_gid_t * gids,
|
|
Packit |
13e616 |
IN int ngids, IN int is_sgid,
|
|
Packit |
13e616 |
OUT osm_alias_guid_t ** pp_alias_guid)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_alias_guid_t *p_alias_guid;
|
|
Packit |
13e616 |
ib_net16_t ib_status = IB_SUCCESS;
|
|
Packit |
13e616 |
int i;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (i = 0; i < ngids; i++, gids++) {
|
|
Packit |
13e616 |
if (!ib_gid_is_link_local(gids)) {
|
|
Packit |
13e616 |
if ((is_sgid && ib_gid_is_multicast(gids)) ||
|
|
Packit |
13e616 |
(ib_gid_get_subnet_prefix(gids) !=
|
|
Packit |
13e616 |
sa->p_subn->opt.subnet_prefix)) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
This 'error' is the client's fault (bad gid)
|
|
Packit |
13e616 |
so don't enter it as an error in our own log.
|
|
Packit |
13e616 |
Return an error response to the client.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "ERR 451B: "
|
|
Packit |
13e616 |
"%sGID 0x%016" PRIx64
|
|
Packit |
13e616 |
" is multicast or non local subnet prefix\n",
|
|
Packit |
13e616 |
is_sgid ? "S" : "D",
|
|
Packit |
13e616 |
cl_ntoh64(gids->unicast.prefix));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ib_status = IB_SA_MAD_STATUS_INVALID_GID;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_alias_guid =
|
|
Packit |
13e616 |
osm_get_alias_guid_by_guid(sa->p_subn,
|
|
Packit |
13e616 |
gids->unicast.interface_id);
|
|
Packit |
13e616 |
if (!p_alias_guid) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
This 'error' is the client's fault (bad gid) so
|
|
Packit |
13e616 |
don't enter it as an error in our own log.
|
|
Packit |
13e616 |
Return an error response to the client.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4506: "
|
|
Packit |
13e616 |
"No port with GUID 0x%016" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(gids->unicast.interface_id));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ib_status = IB_SA_MAD_STATUS_INVALID_GID;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
pp_alias_guid[i] = p_alias_guid;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
return ib_status;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static ib_net16_t mpr_rcv_get_end_points(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const osm_madw_t * p_madw,
|
|
Packit |
13e616 |
OUT osm_alias_guid_t ** pp_alias_guids,
|
|
Packit |
13e616 |
OUT int *nsrc, OUT int *ndest)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const ib_multipath_rec_t *p_mpr;
|
|
Packit |
13e616 |
const ib_sa_mad_t *p_sa_mad;
|
|
Packit |
13e616 |
ib_net64_t comp_mask;
|
|
Packit |
13e616 |
ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
|
|
Packit |
13e616 |
ib_gid_t *gids;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Determine what fields are valid and then get a pointer
|
|
Packit |
13e616 |
to the source and destination port objects, if possible.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
|
|
Packit |
13e616 |
p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
|
|
Packit |
13e616 |
gids = (ib_gid_t *) p_mpr->gids;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
comp_mask = p_sa_mad->comp_mask;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Check a few easy disqualifying cases up front before getting
|
|
Packit |
13e616 |
into the endpoints.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
*nsrc = *ndest = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) {
|
|
Packit |
13e616 |
*nsrc = p_mpr->sgid_count;
|
|
Packit |
13e616 |
if (*nsrc > IB_MULTIPATH_MAX_GIDS)
|
|
Packit |
13e616 |
*nsrc = IB_MULTIPATH_MAX_GIDS;
|
|
Packit |
13e616 |
sa_status = mpr_rcv_get_gids(sa, gids, *nsrc, 1, pp_alias_guids);
|
|
Packit |
13e616 |
if (sa_status != IB_SUCCESS)
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_MPR_COMPMASK_DGIDCOUNT) {
|
|
Packit |
13e616 |
*ndest = p_mpr->dgid_count;
|
|
Packit |
13e616 |
if (*ndest + *nsrc > IB_MULTIPATH_MAX_GIDS)
|
|
Packit |
13e616 |
*ndest = IB_MULTIPATH_MAX_GIDS - *nsrc;
|
|
Packit |
13e616 |
sa_status =
|
|
Packit |
13e616 |
mpr_rcv_get_gids(sa, gids + *nsrc, *ndest, 0,
|
|
Packit |
13e616 |
pp_alias_guids + *nsrc);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
return sa_status;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#define hash_lids(a, b, lmc) \
|
|
Packit |
13e616 |
(((((a) >> (lmc)) << 4) | ((b) >> (lmc))) % 103)
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void mpr_rcv_get_apm_paths(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_multipath_rec_t * p_mpr,
|
|
Packit |
13e616 |
IN const osm_port_t * p_req_port,
|
|
Packit |
13e616 |
IN osm_alias_guid_t ** _pp_alias_guids,
|
|
Packit |
13e616 |
IN const ib_net64_t comp_mask,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_alias_guid_t *pp_alias_guids[4];
|
|
Packit |
13e616 |
osm_sa_item_t *matrix[2][2];
|
|
Packit |
13e616 |
int base_offs, src_lid_ho, dest_lid_ho;
|
|
Packit |
13e616 |
int sumA, sumB, minA, minB;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* We want to:
|
|
Packit |
13e616 |
* 1. use different lid offsets (from base) for the resultant paths
|
|
Packit |
13e616 |
* to increase the probability of redundant paths or in case
|
|
Packit |
13e616 |
* of Clos - to ensure it (different offset => different spine!)
|
|
Packit |
13e616 |
* 2. keep consistent paths no matter of direction and order of ports
|
|
Packit |
13e616 |
* 3. distibute the lid offsets to balance the load
|
|
Packit |
13e616 |
* So, we sort the ports (within the srcs, and within the dests),
|
|
Packit |
13e616 |
* hash the lids of S0, D0 (after the sort), and call mpr_rcv_get_apm_port_pair_paths
|
|
Packit |
13e616 |
* with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get
|
|
Packit |
13e616 |
* always the same offsets - order independent, and make sure different spines are used.
|
|
Packit |
13e616 |
* Note that the diagonals on a Clos have the same number of hops, so it doesn't
|
|
Packit |
13e616 |
* really matter which diagonal we use.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (_pp_alias_guids[0]->p_base_port->guid <
|
|
Packit |
13e616 |
_pp_alias_guids[1]->p_base_port->guid) {
|
|
Packit |
13e616 |
pp_alias_guids[0] = _pp_alias_guids[0];
|
|
Packit |
13e616 |
pp_alias_guids[1] = _pp_alias_guids[1];
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
pp_alias_guids[0] = _pp_alias_guids[1];
|
|
Packit |
13e616 |
pp_alias_guids[1] = _pp_alias_guids[0];
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (_pp_alias_guids[2]->p_base_port->guid <
|
|
Packit |
13e616 |
_pp_alias_guids[3]->p_base_port->guid) {
|
|
Packit |
13e616 |
pp_alias_guids[2] = _pp_alias_guids[2];
|
|
Packit |
13e616 |
pp_alias_guids[3] = _pp_alias_guids[3];
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
pp_alias_guids[2] = _pp_alias_guids[3];
|
|
Packit |
13e616 |
pp_alias_guids[3] = _pp_alias_guids[2];
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
src_lid_ho = osm_port_get_base_lid(pp_alias_guids[0]->p_base_port);
|
|
Packit |
13e616 |
dest_lid_ho = osm_port_get_base_lid(pp_alias_guids[2]->p_base_port);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
base_offs = src_lid_ho < dest_lid_ho ?
|
|
Packit |
13e616 |
hash_lids(src_lid_ho, dest_lid_ho, sa->p_subn->opt.lmc) :
|
|
Packit |
13e616 |
hash_lids(dest_lid_ho, src_lid_ho, sa->p_subn->opt.lmc);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
matrix[0][0] =
|
|
Packit |
13e616 |
mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
|
|
Packit |
13e616 |
pp_alias_guids[2], base_offs,
|
|
Packit |
13e616 |
comp_mask, p_list);
|
|
Packit |
13e616 |
matrix[0][1] =
|
|
Packit |
13e616 |
mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[0],
|
|
Packit |
13e616 |
pp_alias_guids[3], base_offs,
|
|
Packit |
13e616 |
comp_mask, p_list);
|
|
Packit |
13e616 |
matrix[1][0] =
|
|
Packit |
13e616 |
mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
|
|
Packit |
13e616 |
pp_alias_guids[2], base_offs + 1,
|
|
Packit |
13e616 |
comp_mask, p_list);
|
|
Packit |
13e616 |
matrix[1][1] =
|
|
Packit |
13e616 |
mpr_rcv_get_apm_port_pair_paths(sa, p_mpr, pp_alias_guids[1],
|
|
Packit |
13e616 |
pp_alias_guids[3], base_offs + 1,
|
|
Packit |
13e616 |
comp_mask, p_list);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "APM matrix:\n"
|
|
Packit |
13e616 |
"\t{0,0} 0x%X->0x%X (%d)\t| {0,1} 0x%X->0x%X (%d)\n"
|
|
Packit |
13e616 |
"\t{1,0} 0x%X->0x%X (%d)\t| {1,1} 0x%X->0x%X (%d)\n",
|
|
Packit |
13e616 |
matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
|
|
Packit |
13e616 |
matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
|
|
Packit |
13e616 |
matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
|
|
Packit |
13e616 |
matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
|
|
Packit |
13e616 |
matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid : 0,
|
|
Packit |
13e616 |
matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0,
|
|
Packit |
13e616 |
matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
|
|
Packit |
13e616 |
matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
sumA = minA = sumB = minB = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* check diagonal A {(0,0), (1,1)} */
|
|
Packit |
13e616 |
if (matrix[0][0]) {
|
|
Packit |
13e616 |
sumA += matrix[0][0]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
minA = matrix[0][0]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (matrix[1][1]) {
|
|
Packit |
13e616 |
sumA += matrix[1][1]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
if (minA)
|
|
Packit |
13e616 |
minA = min(minA, matrix[1][1]->resp.mpr_rec.hops);
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
minA = matrix[1][1]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* check diagonal B {(0,1), (1,0)} */
|
|
Packit |
13e616 |
if (matrix[0][1]) {
|
|
Packit |
13e616 |
sumB += matrix[0][1]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
minB = matrix[0][1]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (matrix[1][0]) {
|
|
Packit |
13e616 |
sumB += matrix[1][0]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
if (minB)
|
|
Packit |
13e616 |
minB = min(minB, matrix[1][0]->resp.mpr_rec.hops);
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
minB = matrix[1][0]->resp.mpr_rec.hops;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* and the winner is... */
|
|
Packit |
13e616 |
if (minA <= minB || (minA == minB && sumA < sumB)) {
|
|
Packit |
13e616 |
/* Diag A */
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Diag {0,0} & {1,1} is the best:\n"
|
|
Packit |
13e616 |
"\t{0,0} 0x%X->0x%X (%d)\t & {1,1} 0x%X->0x%X (%d)\n",
|
|
Packit |
13e616 |
matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[0][0] ? matrix[0][0]->resp.mpr_rec.path_rec.dlid : 0,
|
|
Packit |
13e616 |
matrix[0][0] ? matrix[0][0]->resp.mpr_rec.hops : 0,
|
|
Packit |
13e616 |
matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[1][1] ? matrix[1][1]->resp.mpr_rec.path_rec.dlid : 0,
|
|
Packit |
13e616 |
matrix[1][1] ? matrix[1][1]->resp.mpr_rec.hops : 0);
|
|
Packit |
13e616 |
if (matrix[0][0])
|
|
Packit |
13e616 |
cl_qlist_insert_tail(p_list, &matrix[0][0]->list_item);
|
|
Packit |
13e616 |
if (matrix[1][1])
|
|
Packit |
13e616 |
cl_qlist_insert_tail(p_list, &matrix[1][1]->list_item);
|
|
Packit |
13e616 |
free(matrix[0][1]);
|
|
Packit |
13e616 |
free(matrix[1][0]);
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
/* Diag B */
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Diag {0,1} & {1,0} is the best:\n"
|
|
Packit |
13e616 |
"\t{0,1} 0x%X->0x%X (%d)\t & {1,0} 0x%X->0x%X (%d)\n",
|
|
Packit |
13e616 |
matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[0][1] ? matrix[0][1]->resp.mpr_rec.path_rec.dlid : 0,
|
|
Packit |
13e616 |
matrix[0][1] ? matrix[0][1]->resp.mpr_rec.hops : 0,
|
|
Packit |
13e616 |
matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.slid : 0,
|
|
Packit |
13e616 |
matrix[1][0] ? matrix[1][0]->resp.mpr_rec.path_rec.dlid: 0,
|
|
Packit |
13e616 |
matrix[1][0] ? matrix[1][0]->resp.mpr_rec.hops : 0);
|
|
Packit |
13e616 |
if (matrix[0][1])
|
|
Packit |
13e616 |
cl_qlist_insert_tail(p_list, &matrix[0][1]->list_item);
|
|
Packit |
13e616 |
if (matrix[1][0])
|
|
Packit |
13e616 |
cl_qlist_insert_tail(p_list, &matrix[1][0]->list_item);
|
|
Packit |
13e616 |
free(matrix[0][0]);
|
|
Packit |
13e616 |
free(matrix[1][1]);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void mpr_rcv_process_pairs(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_multipath_rec_t * p_mpr,
|
|
Packit |
13e616 |
IN osm_port_t * p_req_port,
|
|
Packit |
13e616 |
IN osm_alias_guid_t ** pp_alias_guids,
|
|
Packit |
13e616 |
IN const int nsrc, IN int ndest,
|
|
Packit |
13e616 |
IN ib_net64_t comp_mask,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_alias_guid_t **pp_src_alias_guid, **pp_es;
|
|
Packit |
13e616 |
osm_alias_guid_t **pp_dest_alias_guid, **pp_ed;
|
|
Packit |
13e616 |
uint32_t max_paths, num_paths, total_paths = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_MPR_COMPMASK_NUMBPATH)
|
|
Packit |
13e616 |
max_paths = p_mpr->num_path & 0x7F;
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
max_paths = OSM_SA_MPR_MAX_NUM_PATH;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (pp_src_alias_guid = pp_alias_guids, pp_es = pp_alias_guids + nsrc;
|
|
Packit |
13e616 |
pp_src_alias_guid < pp_es; pp_src_alias_guid++) {
|
|
Packit |
13e616 |
for (pp_dest_alias_guid = pp_es, pp_ed = pp_es + ndest;
|
|
Packit |
13e616 |
pp_dest_alias_guid < pp_ed; pp_dest_alias_guid++) {
|
|
Packit |
13e616 |
num_paths =
|
|
Packit |
13e616 |
mpr_rcv_get_port_pair_paths(sa, p_mpr, p_req_port,
|
|
Packit |
13e616 |
*pp_src_alias_guid,
|
|
Packit |
13e616 |
*pp_dest_alias_guid,
|
|
Packit |
13e616 |
max_paths - total_paths,
|
|
Packit |
13e616 |
comp_mask, p_list);
|
|
Packit |
13e616 |
total_paths += num_paths;
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"%d paths %d total paths %d max paths\n",
|
|
Packit |
13e616 |
num_paths, total_paths, max_paths);
|
|
Packit |
13e616 |
/* Just take first NumbPaths found */
|
|
Packit |
13e616 |
if (total_paths >= max_paths)
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
void osm_mpr_rcv_process(IN void *context, IN void *data)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_sa_t *sa = context;
|
|
Packit |
13e616 |
osm_madw_t *p_madw = data;
|
|
Packit |
13e616 |
const ib_multipath_rec_t *p_mpr;
|
|
Packit |
13e616 |
ib_sa_mad_t *p_sa_mad;
|
|
Packit |
13e616 |
osm_port_t *requester_port;
|
|
Packit |
13e616 |
osm_alias_guid_t *pp_alias_guids[IB_MULTIPATH_MAX_GIDS];
|
|
Packit |
13e616 |
cl_qlist_t pr_list;
|
|
Packit |
13e616 |
ib_net16_t sa_status;
|
|
Packit |
13e616 |
int nsrc, ndest;
|
|
Packit |
13e616 |
uint8_t rate, mtu;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
CL_ASSERT(p_madw);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
|
|
Packit |
13e616 |
p_mpr = (ib_multipath_rec_t *) ib_sa_mad_get_payload_ptr(p_sa_mad);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if ((p_sa_mad->rmpp_flags & IB_RMPP_FLAG_ACTIVE) != IB_RMPP_FLAG_ACTIVE) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4510: "
|
|
Packit |
13e616 |
"Invalid request since RMPP_FLAG_ACTIVE is not set\n");
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* we only support SubnAdmGetMulti method */
|
|
Packit |
13e616 |
if (p_sa_mad->method != IB_MAD_METHOD_GETMULTI) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4513: "
|
|
Packit |
13e616 |
"Unsupported Method (%s) for MultiPathRecord request\n",
|
|
Packit |
13e616 |
ib_get_sa_method_str(p_sa_mad->method));
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG))
|
|
Packit |
13e616 |
osm_dump_multipath_record_v2(sa->p_log, p_mpr, FILE_ID, OSM_LOG_DEBUG);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Make sure required components (S/DGIDCount) are supplied */
|
|
Packit |
13e616 |
if (!(p_sa_mad->comp_mask & IB_MPR_COMPMASK_SGIDCOUNT) ||
|
|
Packit |
13e616 |
!(p_sa_mad->comp_mask & IB_MPR_COMPMASK_DGIDCOUNT)) {
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Validate rate if supplied */
|
|
Packit |
13e616 |
if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATESELEC) &&
|
|
Packit |
13e616 |
(p_sa_mad->comp_mask & IB_MPR_COMPMASK_RATE)) {
|
|
Packit |
13e616 |
rate = ib_multipath_rec_rate(p_mpr);
|
|
Packit |
13e616 |
if (!ib_rate_is_valid(rate)) {
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw,
|
|
Packit |
13e616 |
IB_SA_MAD_STATUS_REQ_INVALID);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
/* Validate MTU if supplied */
|
|
Packit |
13e616 |
if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTUSELEC) &&
|
|
Packit |
13e616 |
(p_sa_mad->comp_mask & IB_MPR_COMPMASK_MTU)) {
|
|
Packit |
13e616 |
mtu = ib_multipath_rec_mtu(p_mpr);
|
|
Packit |
13e616 |
if (!ib_mtu_is_valid(mtu)) {
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw,
|
|
Packit |
13e616 |
IB_SA_MAD_STATUS_REQ_INVALID);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Make sure either none or both ServiceID parameters are supplied */
|
|
Packit |
13e616 |
if ((p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) != 0 &&
|
|
Packit |
13e616 |
(p_sa_mad->comp_mask & IB_MPR_COMPMASK_SERVICEID) !=
|
|
Packit |
13e616 |
IB_MPR_COMPMASK_SERVICEID) {
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
cl_qlist_init(&pr_list);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Most SA functions (including this one) are read-only on the
|
|
Packit |
13e616 |
subnet object, so we grab the lock non-exclusively.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
cl_plock_acquire(sa->p_lock);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* update the requester physical port */
|
|
Packit |
13e616 |
requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
|
|
Packit |
13e616 |
osm_madw_get_mad_addr_ptr
|
|
Packit |
13e616 |
(p_madw));
|
|
Packit |
13e616 |
if (requester_port == NULL) {
|
|
Packit |
13e616 |
cl_plock_release(sa->p_lock);
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4517: "
|
|
Packit |
13e616 |
"Cannot find requester physical port\n");
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Requester port GUID 0x%" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_port_get_guid(requester_port)));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
sa_status = mpr_rcv_get_end_points(sa, p_madw, pp_alias_guids,
|
|
Packit |
13e616 |
&nsrc, &ndest);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (sa_status != IB_SA_MAD_STATUS_SUCCESS || !nsrc || !ndest) {
|
|
Packit |
13e616 |
cl_plock_release(sa->p_lock);
|
|
Packit |
13e616 |
if (sa_status == IB_SA_MAD_STATUS_SUCCESS && (!nsrc || !ndest))
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 4512: "
|
|
Packit |
13e616 |
"mpr_rcv_get_end_points failed, # GIDs found; "
|
|
Packit |
13e616 |
"src %d; dest %d)\n", nsrc, ndest);
|
|
Packit |
13e616 |
if (sa_status == IB_SA_MAD_STATUS_SUCCESS)
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw,
|
|
Packit |
13e616 |
IB_SA_MAD_STATUS_REQ_INVALID);
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
osm_sa_send_error(sa, p_madw, sa_status);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* APM request */
|
|
Packit |
13e616 |
if (nsrc == 2 && ndest == 2 && (p_mpr->num_path & 0x7F) == 2)
|
|
Packit |
13e616 |
mpr_rcv_get_apm_paths(sa, p_mpr, requester_port, pp_alias_guids,
|
|
Packit |
13e616 |
p_sa_mad->comp_mask, &pr_list);
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
mpr_rcv_process_pairs(sa, p_mpr, requester_port, pp_alias_guids,
|
|
Packit |
13e616 |
nsrc, ndest, p_sa_mad->comp_mask,
|
|
Packit |
13e616 |
&pr_list);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
cl_plock_release(sa->p_lock);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* o15-0.2.7: If MultiPath is supported, then SA shall respond to a
|
|
Packit |
13e616 |
SubnAdmGetMulti() containing a valid MultiPathRecord attribute with
|
|
Packit |
13e616 |
a set of zero or more PathRecords satisfying the constraints
|
|
Packit |
13e616 |
indicated in the MultiPathRecord received. The PathRecord Attribute
|
|
Packit |
13e616 |
ID shall be used in the response.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
|
|
Packit |
13e616 |
osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
#endif
|