|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Copyright (c) 2004-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) 2008 Xsigo Systems Inc. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 2009 HNR Consulting. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved.
|
|
Packit |
13e616 |
* Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. 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_pr_rcv_t.
|
|
Packit |
13e616 |
* This object represents the PathRecord 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 |
#include <string.h>
|
|
Packit |
13e616 |
#include <arpa/inet.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_PATH_RECORD_C
|
|
Packit |
13e616 |
#include <vendor/osm_vendor_api.h>
|
|
Packit |
13e616 |
#include <opensm/osm_base.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_helper.h>
|
|
Packit |
13e616 |
#include <opensm/osm_pkey.h>
|
|
Packit |
13e616 |
#include <opensm/osm_multicast.h>
|
|
Packit |
13e616 |
#include <opensm/osm_partition.h>
|
|
Packit |
13e616 |
#include <opensm/osm_opensm.h>
|
|
Packit |
13e616 |
#include <opensm/osm_qos_policy.h>
|
|
Packit |
13e616 |
#include <opensm/osm_sa.h>
|
|
Packit |
13e616 |
#include <opensm/osm_router.h>
|
|
Packit |
13e616 |
#include <opensm/osm_prefix_route.h>
|
|
Packit |
13e616 |
#include <opensm/osm_ucast_lash.h>
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#define SA_PR_RESP_SIZE SA_ITEM_RESP_SIZE(path_rec)
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
#define MAX_HOPS 64
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static inline boolean_t sa_path_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_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * p_pr,
|
|
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_path_rec_is_tavor_port(p_src_port) &&
|
|
Packit |
13e616 |
!sa_path_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_path_rec_mtu(p_pr);
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_PR_COMPMASK_MTU)) {
|
|
Packit |
13e616 |
switch (ib_path_rec_mtu_sel(p_pr)) {
|
|
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 |
|
|
Packit |
13e616 |
default:
|
|
Packit |
13e616 |
/* if we're here, there's a bug in ib_path_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 pr_rcv_get_path_parms(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_path_rec_t * p_pr,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_src_alias_guid,
|
|
Packit |
13e616 |
IN const uint16_t src_lid_ho,
|
|
Packit |
13e616 |
IN const osm_alias_guid_t * p_dest_alias_guid,
|
|
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 |
osm_opensm_t *p_osm;
|
|
Packit |
13e616 |
struct osm_routing_engine *p_re;
|
|
Packit |
13e616 |
const ib_port_info_t *p_pi, *p_pi0;
|
|
Packit |
13e616 |
ib_api_status_t status = IB_SUCCESS;
|
|
Packit |
13e616 |
ib_net16_t pkey;
|
|
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 |
uint8_t required_pkt_life;
|
|
Packit |
13e616 |
uint8_t sl;
|
|
Packit |
13e616 |
uint8_t in_port_num;
|
|
Packit |
13e616 |
ib_net16_t dest_lid;
|
|
Packit |
13e616 |
uint8_t i;
|
|
Packit |
13e616 |
ib_slvl_table_t *p_slvl_tbl = NULL;
|
|
Packit |
13e616 |
osm_qos_level_t *p_qos_level = NULL;
|
|
Packit |
13e616 |
uint16_t valid_sl_mask = 0xffff;
|
|
Packit |
13e616 |
int hops = 0;
|
|
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 |
p_osm = sa->p_subn->p_osm;
|
|
Packit |
13e616 |
p_re = p_osm->routing_engine_used;
|
|
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_path_rec_apply_tavor_mtu_limit(p_pr,
|
|
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 1F02: "
|
|
Packit |
13e616 |
"Cannot 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 |
* 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 1F03: "
|
|
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 1F05: "
|
|
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\n",
|
|
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 |
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 1F06: "
|
|
Packit |
13e616 |
"Internal error, bad path while routing "
|
|
Packit |
13e616 |
"%s (GUID: 0x%016"PRIx64") port %d to "
|
|
Packit |
13e616 |
"%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 1F07: "
|
|
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, "All the SLs "
|
|
Packit |
13e616 |
"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 |
/* 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 1F25: "
|
|
Packit |
13e616 |
"Path from GUID 0x%016" PRIx64 " (%s port %d) "
|
|
Packit |
13e616 |
"to lid %u GUID 0x%016" PRIx64 " (%s port %d) "
|
|
Packit |
13e616 |
"needs 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,
|
|
Packit |
13e616 |
p_src_physp->port_num,
|
|
Packit |
13e616 |
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,
|
|
Packit |
13e616 |
p_dest_physp->port_num,
|
|
Packit |
13e616 |
hops,
|
|
Packit |
13e616 |
MAX_HOPS);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
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 path request
|
|
Packit |
13e616 |
* and adjust path parameters according to QoS settings
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (sa->p_subn->opt.qos &&
|
|
Packit |
13e616 |
sa->p_subn->p_qos_policy &&
|
|
Packit |
13e616 |
(p_qos_level =
|
|
Packit |
13e616 |
osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy,
|
|
Packit |
13e616 |
p_pr, p_src_physp, p_dest_physp,
|
|
Packit |
13e616 |
comp_mask))) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"PathRecord request matches QoS Level '%s' (%s)\n",
|
|
Packit |
13e616 |
p_qos_level->name, p_qos_level->use ?
|
|
Packit |
13e616 |
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 |
sl = p_qos_level->sl;
|
|
Packit |
13e616 |
if (!(valid_sl_mask & (1 << sl))) {
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Set packet lifetime.
|
|
Packit |
13e616 |
* According to spec definition IBA 1.2 Table 205
|
|
Packit |
13e616 |
* PacketLifeTime description, for loopback paths,
|
|
Packit |
13e616 |
* packetLifeTime shall be zero.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
|
|
Packit |
13e616 |
pkt_life = 0;
|
|
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 |
/*
|
|
Packit |
13e616 |
Determine if these values meet the user criteria
|
|
Packit |
13e616 |
and adjust appropriately
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* we silently ignore cases where only the MTU selector is defined */
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_PR_COMPMASK_MTU)) {
|
|
Packit |
13e616 |
required_mtu = ib_path_rec_mtu(p_pr);
|
|
Packit |
13e616 |
switch (ib_path_rec_mtu_sel(p_pr)) {
|
|
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 than 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_path_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_PR_COMPMASK_RATESELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_PR_COMPMASK_RATE)) {
|
|
Packit |
13e616 |
required_rate = ib_path_rec_rate(p_pr);
|
|
Packit |
13e616 |
switch (ib_path_rec_rate_sel(p_pr)) {
|
|
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 than 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_path_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 PktLife selector is defined */
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) &&
|
|
Packit |
13e616 |
(comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) {
|
|
Packit |
13e616 |
required_pkt_life = ib_path_rec_pkt_life(p_pr);
|
|
Packit |
13e616 |
switch (ib_path_rec_pkt_life_sel(p_pr)) {
|
|
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 than 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 path record request
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) &&
|
|
Packit |
13e616 |
(cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)))
|
|
Packit |
13e616 |
pkey = 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_PR_COMPMASK_PKEY) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* PR 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 |
* PR returned pkey is the requested pkey.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
pkey = p_pr->pkey;
|
|
Packit |
13e616 |
if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys)) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: "
|
|
Packit |
13e616 |
"Ports 0x%016" PRIx64 " (%s port %d) and "
|
|
Packit |
13e616 |
"0x%016" PRIx64 " (%s port %d) "
|
|
Packit |
13e616 |
"do not share 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(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, pkey)) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: "
|
|
Packit |
13e616 |
"QoS level \"%s\" doesn't define specified PKey 0x%04x "
|
|
Packit |
13e616 |
"for ports 0x%016" PRIx64 " (%s port %d) and "
|
|
Packit |
13e616 |
"0x%016"PRIx64" (%s port %d)\n",
|
|
Packit |
13e616 |
p_qos_level->name,
|
|
Packit |
13e616 |
cl_ntoh16(pkey),
|
|
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_alias_guid->p_base_port->p_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_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->pkey_range_len) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* PR 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 |
pkey = osm_qos_level_get_shared_pkey(p_qos_level,
|
|
Packit |
13e616 |
p_src_physp, p_dest_physp,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys);
|
|
Packit |
13e616 |
if (!pkey) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: "
|
|
Packit |
13e616 |
"Ports 0x%016" PRIx64 " (%s) and "
|
|
Packit |
13e616 |
"0x%016" PRIx64 " (%s) do not share "
|
|
Packit |
13e616 |
"PKeys 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 |
cl_ntoh64(osm_physp_get_port_guid
|
|
Packit |
13e616 |
(p_dest_physp)),
|
|
Packit |
13e616 |
p_dest_physp->p_node->print_desc,
|
|
Packit |
13e616 |
p_qos_level->name);
|
|
Packit |
13e616 |
status = IB_NOT_FOUND;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Neither PR request nor QoS level have pkey.
|
|
Packit |
13e616 |
* Just get any shared pkey.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
|
|
Packit |
13e616 |
sa->p_subn->opt.allow_both_pkeys);
|
|
Packit |
13e616 |
if (!pkey) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: "
|
|
Packit |
13e616 |
"Ports src 0x%016"PRIx64" (%s port %d) and "
|
|
Packit |
13e616 |
"dst 0x%016"PRIx64" (%s port %d) do not have "
|
|
Packit |
13e616 |
"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 (pkey) {
|
|
Packit |
13e616 |
p_prtn =
|
|
Packit |
13e616 |
(osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
|
|
Packit |
13e616 |
pkey & cl_hton16((uint16_t) ~
|
|
Packit |
13e616 |
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 PathRecord SL
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_SL) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* Specific SL was requested
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
sl = ib_path_rec_sl(p_pr);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_qos_level && p_qos_level->sl_set
|
|
Packit |
13e616 |
&& (p_qos_level->sl != sl)) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: "
|
|
Packit |
13e616 |
"QoS constraints: required PathRecord SL (%u) "
|
|
Packit |
13e616 |
"doesn't match QoS policy \"%s\" SL (%u) "
|
|
Packit |
13e616 |
"[%s port %d <-> %s port %d]\n", 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, but there is an SL in
|
|
Packit |
13e616 |
* QoS level.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
sl = p_qos_level->sl;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (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 (pkey) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
* No specific SL in request or in QoS level - use partition SL
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (!p_prtn) {
|
|
Packit |
13e616 |
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 1F1C: "
|
|
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(pkey), 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 |
sl = p_prtn->sl;
|
|
Packit |
13e616 |
} else if (sa->p_subn->opt.qos) {
|
|
Packit |
13e616 |
if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
|
|
Packit |
13e616 |
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 |
sl = i;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else
|
|
Packit |
13e616 |
sl = OSM_DEFAULT_SL;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: "
|
|
Packit |
13e616 |
"Selected SL (%u) leads to VL15 "
|
|
Packit |
13e616 |
"[%s port %d <-> %s port %d]\n",
|
|
Packit |
13e616 |
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 |
/*
|
|
Packit |
13e616 |
* If the routing engine wants to have a say in path SL selection,
|
|
Packit |
13e616 |
* send the currently computed SL value as a hint and let the routing
|
|
Packit |
13e616 |
* engine override it.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (p_re && p_re->path_sl) {
|
|
Packit |
13e616 |
uint8_t pr_sl;
|
|
Packit |
13e616 |
pr_sl = sl;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
sl = p_re->path_sl(p_re->context, sl,
|
|
Packit |
13e616 |
cl_hton16(src_lid_ho), cl_hton16(dest_lid_ho));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_SL) && (sl != pr_sl)) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F2A: "
|
|
Packit |
13e616 |
"Requested SL (%u) doesn't match SL calculated"
|
|
Packit |
13e616 |
"by routing engine (%u) "
|
|
Packit |
13e616 |
"[%s port %d <-> %s port %d]\n",
|
|
Packit |
13e616 |
pr_sl,
|
|
Packit |
13e616 |
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_PR_COMPMASK_RAWTRAFFIC &&
|
|
Packit |
13e616 |
cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))
|
|
Packit |
13e616 |
pkey = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_parms->mtu = mtu;
|
|
Packit |
13e616 |
p_parms->rate = rate;
|
|
Packit |
13e616 |
p_parms->pkt_life = pkt_life;
|
|
Packit |
13e616 |
p_parms->pkey = pkey;
|
|
Packit |
13e616 |
p_parms->sl = sl;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u,"
|
|
Packit |
13e616 |
" packet lifetime = %u, pkey = 0x%04X, sl = %u\n",
|
|
Packit |
13e616 |
mtu, rate, pkt_life, cl_ntoh16(pkey), sl);
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
return status;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ib_api_status_t osm_get_path_params(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const osm_port_t * p_src_port,
|
|
Packit |
13e616 |
IN const uint16_t slid_ho,
|
|
Packit |
13e616 |
IN const osm_port_t * p_dest_port,
|
|
Packit |
13e616 |
IN const uint16_t dlid_ho,
|
|
Packit |
13e616 |
OUT osm_path_parms_t * p_parms)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
|
|
Packit |
13e616 |
ib_path_rec_t pr;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (!p_src_port || !slid_ho || !p_dest_port || !dlid_ho)
|
|
Packit |
13e616 |
return IB_INVALID_PARAMETER;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
memset(&pr, 0, sizeof(ib_path_rec_t));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
|
|
Packit |
13e616 |
osm_port_get_guid(p_src_port));
|
|
Packit |
13e616 |
p_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
|
|
Packit |
13e616 |
osm_port_get_guid(p_dest_port));
|
|
Packit |
13e616 |
return pr_rcv_get_path_parms(sa, &pr,
|
|
Packit |
13e616 |
p_src_alias_guid, slid_ho,
|
|
Packit |
13e616 |
p_dest_alias_guid, dlid_ho, 0, p_parms);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static void pr_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 const ib_gid_t * p_sgid,
|
|
Packit |
13e616 |
IN const ib_gid_t * p_dgid,
|
|
Packit |
13e616 |
IN const uint16_t src_lid_ho,
|
|
Packit |
13e616 |
IN const uint16_t dest_lid_ho,
|
|
Packit |
13e616 |
IN const 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 = NULL, *p_dest_physp = NULL;
|
|
Packit |
13e616 |
osm_port_t *p_port;
|
|
Packit |
13e616 |
uint8_t rate, new_rate;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_dgid)
|
|
Packit |
13e616 |
p_pr->dgid = *p_dgid;
|
|
Packit |
13e616 |
else {
|
|
Packit |
13e616 |
p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->dgid.unicast.prefix =
|
|
Packit |
13e616 |
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 |
if (p_sgid)
|
|
Packit |
13e616 |
p_pr->sgid = *p_sgid;
|
|
Packit |
13e616 |
else {
|
|
Packit |
13e616 |
p_src_physp = p_src_alias_guid->p_base_port->p_physp;
|
|
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 |
|
|
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 |
/* Only set HopLimit if going through a router */
|
|
Packit |
13e616 |
if (p_dgid)
|
|
Packit |
13e616 |
p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr->pkey = p_parms->pkey;
|
|
Packit |
13e616 |
ib_path_rec_set_sl(p_pr, p_parms->sl);
|
|
Packit |
13e616 |
ib_path_rec_set_qos_class(p_pr, 0);
|
|
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 |
if (p_src_physp == NULL) {
|
|
Packit |
13e616 |
p_port = osm_get_port_by_lid_ho(sa->p_subn, src_lid_ho);
|
|
Packit |
13e616 |
if (p_port)
|
|
Packit |
13e616 |
p_src_physp = p_port->p_physp;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_src_physp)
|
|
Packit |
13e616 |
rate = ib_path_rate_2x_hdr_fixups(&p_src_physp->port_info, rate);
|
|
Packit |
13e616 |
if (p_parms->reversible) {
|
|
Packit |
13e616 |
if (p_dest_physp == NULL) {
|
|
Packit |
13e616 |
p_port = osm_get_port_by_lid_ho(sa->p_subn,
|
|
Packit |
13e616 |
dest_lid_ho);
|
|
Packit |
13e616 |
if (p_port)
|
|
Packit |
13e616 |
p_dest_physp = p_port->p_physp;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (p_dest_physp)
|
|
Packit |
13e616 |
rate = ib_path_rate_2x_hdr_fixups(&p_dest_physp->port_info, rate);
|
|
Packit |
13e616 |
}
|
|
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 *pr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_path_rec_t * p_pr,
|
|
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 ib_gid_t * p_sgid,
|
|
Packit |
13e616 |
IN const ib_gid_t * p_dgid,
|
|
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_PR_RESP_SIZE);
|
|
Packit |
13e616 |
if (p_pr_item == NULL) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: "
|
|
Packit |
13e616 |
"Unable to allocate path record\n");
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
memset(p_pr_item, 0, SA_PR_RESP_SIZE);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
status = pr_rcv_get_path_parms(sa, p_pr, p_src_alias_guid, src_lid_ho,
|
|
Packit |
13e616 |
p_dest_alias_guid, 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 = pr_rcv_get_path_parms(sa, p_pr, p_dest_alias_guid,
|
|
Packit |
13e616 |
dest_lid_ho, p_src_alias_guid,
|
|
Packit |
13e616 |
src_lid_ho, comp_mask,
|
|
Packit |
13e616 |
&rev_path_parms);
|
|
Packit |
13e616 |
|
|
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 than requiring non-reversible paths ...
|
|
Packit |
13e616 |
see Vol1 Ver1.2 p900 l16
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_REVERSIBLE) &&
|
|
Packit |
13e616 |
!path_parms.reversible && (p_pr->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 |
free(p_pr_item);
|
|
Packit |
13e616 |
p_pr_item = NULL;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
pr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, p_sgid, p_dgid,
|
|
Packit |
13e616 |
src_lid_ho, dest_lid_ho, preference, &path_parms,
|
|
Packit |
13e616 |
&p_pr_item->resp.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 void pr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_sa_mad_t *sa_mad,
|
|
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 ib_gid_t * p_sgid,
|
|
Packit |
13e616 |
IN const ib_gid_t * p_dgid,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
|
|
Packit |
13e616 |
ib_net64_t comp_mask = sa_mad->comp_mask;
|
|
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;
|
|
Packit |
13e616 |
uint8_t preference;
|
|
Packit |
13e616 |
unsigned iterations, 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 means 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 it is assumed that the subnet is physically appropriate for the
|
|
Packit |
13e616 |
specified LMC value. A more advanced implementation would inspect for
|
|
Packit |
13e616 |
physical redundancy, but I'm not going to bother with that now.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Refine our search if the client specified end-point LIDs
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_DLID)
|
|
Packit |
13e616 |
dest_lid_max_ho = dest_lid_min_ho = cl_ntoh16(p_pr->dlid);
|
|
Packit |
13e616 |
else
|
|
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 |
if (comp_mask & IB_PR_COMPMASK_SLID)
|
|
Packit |
13e616 |
src_lid_max_ho = src_lid_min_ho = cl_ntoh16(p_pr->slid);
|
|
Packit |
13e616 |
else
|
|
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 |
|
|
Packit |
13e616 |
if (src_lid_min_ho == 0) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Obtained source LID of 0. No such LID possible "
|
|
Packit |
13e616 |
"(%s port %d)\n",
|
|
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 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (dest_lid_min_ho == 0) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Obtained destination LID of 0. No such LID possible "
|
|
Packit |
13e616 |
"(%s port %d)\n",
|
|
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 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Src LIDs [%u-%u], Dest LIDs [%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 |
path_num = 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
|
|
Packit |
13e616 |
if (sa_mad->method == IB_MAD_METHOD_GET)
|
|
Packit |
13e616 |
iterations = 1;
|
|
Packit |
13e616 |
else if (comp_mask & IB_PR_COMPMASK_NUMBPATH)
|
|
Packit |
13e616 |
iterations = ib_path_rec_num_path(p_pr);
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
iterations = (unsigned) (-1);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
while (path_num < iterations) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
These paths are "fully redundant"
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
p_sgid, p_dgid,
|
|
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 == iterations)
|
|
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 < iterations) {
|
|
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 = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid, p_sgid,
|
|
Packit |
13e616 |
p_dgid, src_lid_ho,
|
|
Packit |
13e616 |
dest_lid_ho, comp_mask,
|
|
Packit |
13e616 |
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 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Find the router port that is configured to handle this prefix, if any */
|
|
Packit |
13e616 |
static ib_net64_t find_router(const osm_sa_t *sa, ib_net64_t prefix)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
osm_prefix_route_t *route = NULL;
|
|
Packit |
13e616 |
osm_router_t *rtr;
|
|
Packit |
13e616 |
cl_qlist_t *l = &sa->p_subn->prefix_routes_list;
|
|
Packit |
13e616 |
cl_list_item_t *i;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix "
|
|
Packit |
13e616 |
"0x%016" PRIx64 "\n", cl_ntoh64(prefix));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
for (i = cl_qlist_head(l); i != cl_qlist_end(l); i = cl_qlist_next(i)) {
|
|
Packit |
13e616 |
osm_prefix_route_t *r = (osm_prefix_route_t *)i;
|
|
Packit |
13e616 |
if (!r->prefix || r->prefix == prefix) {
|
|
Packit |
13e616 |
route = r;
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (!route)
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (route->guid == 0) /* first router */
|
|
Packit |
13e616 |
rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl);
|
|
Packit |
13e616 |
else
|
|
Packit |
13e616 |
rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl,
|
|
Packit |
13e616 |
route->guid);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl))
|
|
Packit |
13e616 |
return 0;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
return osm_port_get_guid(osm_router_get_port_ptr(rtr));
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ib_net16_t osm_pr_get_end_points(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_sa_mad_t *sa_mad,
|
|
Packit |
13e616 |
OUT const osm_alias_guid_t ** pp_src_alias_guid,
|
|
Packit |
13e616 |
OUT const osm_alias_guid_t ** pp_dest_alias_guid,
|
|
Packit |
13e616 |
OUT const osm_port_t ** pp_src_port,
|
|
Packit |
13e616 |
OUT const osm_port_t ** pp_dest_port,
|
|
Packit |
13e616 |
OUT const ib_gid_t ** pp_sgid,
|
|
Packit |
13e616 |
OUT const ib_gid_t ** pp_dgid)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
|
|
Packit |
13e616 |
ib_net64_t comp_mask = sa_mad->comp_mask;
|
|
Packit |
13e616 |
ib_net64_t dest_guid;
|
|
Packit |
13e616 |
ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
|
|
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 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Check a few easy disqualifying cases up front before getting
|
|
Packit |
13e616 |
into the endpoints.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
*pp_src_alias_guid = NULL;
|
|
Packit |
13e616 |
*pp_src_port = NULL;
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_SGID) {
|
|
Packit |
13e616 |
if (!ib_gid_is_link_local(&p_pr->sgid)) {
|
|
Packit |
13e616 |
if (ib_gid_get_subnet_prefix(&p_pr->sgid) !=
|
|
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,
|
|
Packit |
13e616 |
"Non local SGID subnet prefix 0x%016"
|
|
Packit |
13e616 |
PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(p_pr->sgid.unicast.prefix));
|
|
Packit |
13e616 |
sa_status = IB_SA_MAD_STATUS_INVALID_GID;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
*pp_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
|
|
Packit |
13e616 |
p_pr->sgid.unicast.interface_id);
|
|
Packit |
13e616 |
if (!*pp_src_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_VERBOSE,
|
|
Packit |
13e616 |
"No source port with GUID 0x%016" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(p_pr->sgid.unicast.interface_id));
|
|
Packit |
13e616 |
sa_status = IB_SA_MAD_STATUS_INVALID_GID;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (pp_sgid)
|
|
Packit |
13e616 |
*pp_sgid = &p_pr->sgid;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_SLID) {
|
|
Packit |
13e616 |
*pp_src_port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
|
|
Packit |
13e616 |
if (!*pp_src_port) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
This 'error' is the client's fault (bad lid) 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_VERBOSE, "No source port "
|
|
Packit |
13e616 |
"with LID %u\n", cl_ntoh16(p_pr->slid));
|
|
Packit |
13e616 |
sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
*pp_dest_alias_guid = NULL;
|
|
Packit |
13e616 |
*pp_dest_port = NULL;
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_DGID) {
|
|
Packit |
13e616 |
if (!ib_gid_is_link_local(&p_pr->dgid) &&
|
|
Packit |
13e616 |
!ib_gid_is_multicast(&p_pr->dgid) &&
|
|
Packit |
13e616 |
ib_gid_get_subnet_prefix(&p_pr->dgid) !=
|
|
Packit |
13e616 |
sa->p_subn->opt.subnet_prefix) {
|
|
Packit |
13e616 |
dest_guid = find_router(sa, p_pr->dgid.unicast.prefix);
|
|
Packit |
13e616 |
if (!dest_guid) {
|
|
Packit |
13e616 |
char gid_str[INET6_ADDRSTRLEN];
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Off subnet DGID %s, but router not "
|
|
Packit |
13e616 |
"found\n",
|
|
Packit |
13e616 |
inet_ntop(AF_INET6, p_pr->dgid.raw,
|
|
Packit |
13e616 |
gid_str, sizeof(gid_str)));
|
|
Packit |
13e616 |
sa_status = IB_SA_MAD_STATUS_INVALID_GID;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (pp_dgid)
|
|
Packit |
13e616 |
*pp_dgid = &p_pr->dgid;
|
|
Packit |
13e616 |
} else
|
|
Packit |
13e616 |
dest_guid = p_pr->dgid.unicast.interface_id;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
*pp_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
|
|
Packit |
13e616 |
dest_guid);
|
|
Packit |
13e616 |
if (!*pp_dest_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_VERBOSE,
|
|
Packit |
13e616 |
"No dest port with GUID 0x%016" PRIx64 "\n",
|
|
Packit |
13e616 |
cl_ntoh64(dest_guid));
|
|
Packit |
13e616 |
sa_status = IB_SA_MAD_STATUS_INVALID_GID;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_DLID) {
|
|
Packit |
13e616 |
*pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_pr->dlid);
|
|
Packit |
13e616 |
if (!*pp_dest_port) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
This 'error' is the client's fault (bad lid)
|
|
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, "No dest port "
|
|
Packit |
13e616 |
"with LID %u\n", cl_ntoh16(p_pr->dlid));
|
|
Packit |
13e616 |
sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
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 |
static void pr_rcv_process_world(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
|
|
Packit |
13e616 |
IN const osm_port_t * requester_port,
|
|
Packit |
13e616 |
IN const ib_gid_t * p_sgid,
|
|
Packit |
13e616 |
IN const ib_gid_t * p_dgid,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const cl_qmap_t *p_tbl;
|
|
Packit |
13e616 |
const osm_alias_guid_t *p_dest_alias_guid, *p_src_alias_guid;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Iterate the entire port space over itself.
|
|
Packit |
13e616 |
A path record from a port to itself is legit, so no
|
|
Packit |
13e616 |
need for a special case there.
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
We compute both A -> B and B -> A, since we don't have
|
|
Packit |
13e616 |
any check to determine the reversability of the paths.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_tbl = &sa->p_subn->alias_port_guid_tbl;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
|
|
Packit |
13e616 |
while (p_dest_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
|
|
Packit |
13e616 |
p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
|
|
Packit |
13e616 |
while (p_src_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
|
|
Packit |
13e616 |
pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
p_sgid, p_dgid, p_list);
|
|
Packit |
13e616 |
if (sa_mad->method == IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
cl_qlist_count(p_list) > 0)
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_src_alias_guid =
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_dest_alias_guid =
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Exit:
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
void osm_pr_process_half(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
|
|
Packit |
13e616 |
IN const osm_port_t * requester_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 ib_gid_t * p_sgid,
|
|
Packit |
13e616 |
IN const ib_gid_t * p_dgid,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const cl_qmap_t *p_tbl;
|
|
Packit |
13e616 |
const osm_alias_guid_t *p_alias_guid;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Iterate over every port, looking for matches...
|
|
Packit |
13e616 |
A path record from a port to itself is legit, so no
|
|
Packit |
13e616 |
need to special case that one.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_tbl = &sa->p_subn->alias_port_guid_tbl;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_src_alias_guid) {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
The src port if fixed, so iterate over destination ports.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
|
|
Packit |
13e616 |
while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
|
|
Packit |
13e616 |
pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_alias_guid,
|
|
Packit |
13e616 |
p_sgid, p_dgid, p_list);
|
|
Packit |
13e616 |
if (sa_mad->method == IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
cl_qlist_count(p_list) > 0)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
The dest port if fixed, so iterate over source ports.
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
|
|
Packit |
13e616 |
while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
|
|
Packit |
13e616 |
pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
|
|
Packit |
13e616 |
p_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid, p_sgid,
|
|
Packit |
13e616 |
p_dgid, p_list);
|
|
Packit |
13e616 |
if (sa_mad->method == IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
cl_qlist_count(p_list) > 0)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
void osm_pr_process_pair(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
|
|
Packit |
13e616 |
IN const osm_port_t * requester_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 ib_gid_t * p_sgid,
|
|
Packit |
13e616 |
IN const ib_gid_t * p_dgid,
|
|
Packit |
13e616 |
IN cl_qlist_t * p_list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid, p_sgid, p_dgid, p_list);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_EXIT(sa->p_log);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
static ib_api_status_t pr_match_mgrp_attributes(IN osm_sa_t * sa,
|
|
Packit |
13e616 |
IN const ib_sa_mad_t * sa_mad,
|
|
Packit |
13e616 |
IN const osm_mgrp_t * p_mgrp)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
|
|
Packit |
13e616 |
ib_net64_t comp_mask = sa_mad->comp_mask;
|
|
Packit |
13e616 |
const osm_port_t *port;
|
|
Packit |
13e616 |
ib_api_status_t status = IB_ERROR;
|
|
Packit |
13e616 |
uint32_t flow_label;
|
|
Packit |
13e616 |
uint8_t sl, hop_limit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG_ENTER(sa->p_log);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* check that MLID of the MC group matches the PathRecord DLID */
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_DLID) && p_mgrp->mlid != p_pr->dlid) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"DLID 0x%x is not MLID 0x%x for MC group\n",
|
|
Packit |
13e616 |
cl_ntoh16(p_pr->dlid), cl_ntoh16(p_mgrp->mlid));
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* If SGID and/or SLID specified, should validate as member of MC group */
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_SGID) {
|
|
Packit |
13e616 |
if (!osm_mgrp_get_mcm_alias_guid(p_mgrp,
|
|
Packit |
13e616 |
p_pr->sgid.unicast.interface_id)) {
|
|
Packit |
13e616 |
char gid_str[INET6_ADDRSTRLEN];
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"SGID %s is not a member of MC group\n",
|
|
Packit |
13e616 |
inet_ntop(AF_INET6, p_pr->sgid.raw,
|
|
Packit |
13e616 |
gid_str, sizeof gid_str));
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (comp_mask & IB_PR_COMPMASK_SLID) {
|
|
Packit |
13e616 |
port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
|
|
Packit |
13e616 |
if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Either no port with SLID %u found or "
|
|
Packit |
13e616 |
"SLID not a member of MC group\n",
|
|
Packit |
13e616 |
cl_ntoh16(p_pr->slid));
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_PKEY) &&
|
|
Packit |
13e616 |
p_pr->pkey != p_mgrp->mcmember_rec.pkey) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Pkey 0x%x doesn't match MC group Pkey 0x%x\n",
|
|
Packit |
13e616 |
cl_ntoh16(p_pr->pkey),
|
|
Packit |
13e616 |
cl_ntoh16(p_mgrp->mcmember_rec.pkey));
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
|
|
Packit |
13e616 |
&sl, &flow_label, &hop_limit);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_SL) && ib_path_rec_sl(p_pr) != sl) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"SL %d doesn't match MC group SL %d\n",
|
|
Packit |
13e616 |
ib_path_rec_sl(p_pr), sl);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) &&
|
|
Packit |
13e616 |
sa_mad->method != IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
ib_path_rec_num_path(p_pr) == 0) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Number of paths requested is 0\n");
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_FLOWLABEL) &&
|
|
Packit |
13e616 |
ib_path_rec_flow_lbl(p_pr) != flow_label) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Flow label 0x%x doesn't match MC group "
|
|
Packit |
13e616 |
" flow label 0x%x\n",
|
|
Packit |
13e616 |
ib_path_rec_flow_lbl(p_pr), flow_label);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_HOPLIMIT) &&
|
|
Packit |
13e616 |
ib_path_rec_hop_limit(p_pr) != hop_limit) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"Hop limit %u doesn't match MC group hop limit %u\n",
|
|
Packit |
13e616 |
ib_path_rec_hop_limit(p_pr), hop_limit);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if ((comp_mask & IB_PR_COMPMASK_TCLASS) &&
|
|
Packit |
13e616 |
p_pr->tclass != p_mgrp->mcmember_rec.tclass) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
|
|
Packit |
13e616 |
"TClass 0x%02x doesn't match MC group TClass 0x%02x\n",
|
|
Packit |
13e616 |
p_pr->tclass, p_mgrp->mcmember_rec.tclass);
|
|
Packit |
13e616 |
goto Exit;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
status = IB_SUCCESS;
|
|
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 pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad,
|
|
Packit |
13e616 |
cl_qlist_t *list)
|
|
Packit |
13e616 |
{
|
|
Packit |
13e616 |
ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad);
|
|
Packit |
13e616 |
osm_mgrp_t *mgrp;
|
|
Packit |
13e616 |
ib_api_status_t status;
|
|
Packit |
13e616 |
osm_sa_item_t *pr_item;
|
|
Packit |
13e616 |
uint32_t flow_label;
|
|
Packit |
13e616 |
uint8_t sl, hop_limit;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n");
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid);
|
|
Packit |
13e616 |
if (!mgrp) {
|
|
Packit |
13e616 |
char gid_str[INET6_ADDRSTRLEN];
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: "
|
|
Packit |
13e616 |
"No MC group found for PathRecord destination GID %s\n",
|
|
Packit |
13e616 |
inet_ntop(AF_INET6, pr->dgid.raw, gid_str,
|
|
Packit |
13e616 |
sizeof gid_str));
|
|
Packit |
13e616 |
return;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Make sure the rest of the PathRecord matches the MC group attributes */
|
|
Packit |
13e616 |
status = pr_match_mgrp_attributes(sa, sa_mad, mgrp);
|
|
Packit |
13e616 |
if (status != IB_SUCCESS) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: "
|
|
Packit |
13e616 |
"MC group attributes don't match PathRecord request\n");
|
|
Packit |
13e616 |
return;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
pr_item = malloc(SA_PR_RESP_SIZE);
|
|
Packit |
13e616 |
if (pr_item == NULL) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: "
|
|
Packit |
13e616 |
"Unable to allocate path record for MC group\n");
|
|
Packit |
13e616 |
return;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
memset(pr_item, 0, sizeof(cl_list_item_t));
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Copy PathRecord request into response */
|
|
Packit |
13e616 |
pr_item->resp.path_rec = *pr;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Now, use the MC info to cruft up the PathRecord response */
|
|
Packit |
13e616 |
pr_item->resp.path_rec.dgid = mgrp->mcmember_rec.mgid;
|
|
Packit |
13e616 |
pr_item->resp.path_rec.dlid = mgrp->mcmember_rec.mlid;
|
|
Packit |
13e616 |
pr_item->resp.path_rec.tclass = mgrp->mcmember_rec.tclass;
|
|
Packit |
13e616 |
pr_item->resp.path_rec.num_path = 1;
|
|
Packit |
13e616 |
pr_item->resp.path_rec.pkey = mgrp->mcmember_rec.pkey;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* MTU, rate, and packet lifetime should be exactly */
|
|
Packit |
13e616 |
pr_item->resp.path_rec.mtu = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.mtu;
|
|
Packit |
13e616 |
pr_item->resp.path_rec.rate = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.rate;
|
|
Packit |
13e616 |
pr_item->resp.path_rec.pkt_life = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.pkt_life;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* SL, Hop Limit, and Flow Label */
|
|
Packit |
13e616 |
ib_member_get_sl_flow_hop(mgrp->mcmember_rec.sl_flow_hop,
|
|
Packit |
13e616 |
&sl, &flow_label, &hop_limit);
|
|
Packit |
13e616 |
ib_path_rec_set_sl(&pr_item->resp.path_rec, sl);
|
|
Packit |
13e616 |
ib_path_rec_set_qos_class(&pr_item->resp.path_rec, 0);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* HopLimit is not yet set in non link local MC groups */
|
|
Packit |
13e616 |
/* If it were, this would not be needed */
|
|
Packit |
13e616 |
if (ib_mgid_get_scope(&mgrp->mcmember_rec.mgid) !=
|
|
Packit |
13e616 |
IB_MC_SCOPE_LINK_LOCAL)
|
|
Packit |
13e616 |
hop_limit = IB_HOPLIMIT_MAX;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
pr_item->resp.path_rec.hop_flow_raw =
|
|
Packit |
13e616 |
cl_hton32(hop_limit) | (flow_label << 8);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
cl_qlist_insert_tail(list, &pr_item->list_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
void osm_pr_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_sa_mad_t *p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
|
|
Packit |
13e616 |
ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(p_sa_mad);
|
|
Packit |
13e616 |
cl_qlist_t pr_list;
|
|
Packit |
13e616 |
const ib_gid_t *p_sgid = NULL, *p_dgid = NULL;
|
|
Packit |
13e616 |
const osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
|
|
Packit |
13e616 |
const osm_port_t *p_src_port, *p_dest_port;
|
|
Packit |
13e616 |
osm_port_t *requester_port;
|
|
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 |
CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* we only support SubnAdmGet and SubnAdmGetTable methods */
|
|
Packit |
13e616 |
if (p_sa_mad->method != IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: "
|
|
Packit |
13e616 |
"Unsupported Method (%s) for PathRecord 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 |
/* Validate rate if supplied */
|
|
Packit |
13e616 |
if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_RATESELEC) &&
|
|
Packit |
13e616 |
(p_sa_mad->comp_mask & IB_PR_COMPMASK_RATE)) {
|
|
Packit |
13e616 |
rate = ib_path_rec_rate(p_pr);
|
|
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_PR_COMPMASK_MTUSELEC) &&
|
|
Packit |
13e616 |
(p_sa_mad->comp_mask & IB_PR_COMPMASK_MTU)) {
|
|
Packit |
13e616 |
mtu = ib_path_rec_mtu(p_pr);
|
|
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_PR_COMPMASK_SERVICEID) != 0 &&
|
|
Packit |
13e616 |
(p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) !=
|
|
Packit |
13e616 |
IB_PR_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 1F16: "
|
|
Packit |
13e616 |
"Cannot find requester physical port\n");
|
|
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_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 |
osm_dump_path_record_v2(sa->p_log, p_pr, FILE_ID, OSM_LOG_DEBUG);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Handle multicast destinations separately */
|
|
Packit |
13e616 |
if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_DGID) &&
|
|
Packit |
13e616 |
ib_gid_is_multicast(&p_pr->dgid)) {
|
|
Packit |
13e616 |
pr_process_multicast(sa, p_sa_mad, &pr_list);
|
|
Packit |
13e616 |
goto Unlock;
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n");
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (osm_pr_get_end_points(sa, p_sa_mad,
|
|
Packit |
13e616 |
&p_src_alias_guid, &p_dest_alias_guid,
|
|
Packit |
13e616 |
&p_src_port, &p_dest_port,
|
|
Packit |
13e616 |
&p_sgid, &p_dgid) != IB_SA_MAD_STATUS_SUCCESS)
|
|
Packit |
13e616 |
goto Unlock;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
if (p_src_alias_guid && p_src_port &&
|
|
Packit |
13e616 |
p_src_alias_guid->p_base_port != p_src_port) {
|
|
Packit |
13e616 |
cl_plock_release(sa->p_lock);
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Requester port GUID 0x%" PRIx64 ": Port for SGUID "
|
|
Packit |
13e616 |
"0x%" PRIx64 " not same as port for SLID %u\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_port_get_guid(requester_port)),
|
|
Packit |
13e616 |
cl_ntoh64(p_pr->sgid.unicast.interface_id),
|
|
Packit |
13e616 |
cl_ntoh16(p_pr->slid));
|
|
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 |
if (p_dest_alias_guid && p_dest_port &&
|
|
Packit |
13e616 |
p_dest_alias_guid->p_base_port != p_dest_port) {
|
|
Packit |
13e616 |
cl_plock_release(sa->p_lock);
|
|
Packit |
13e616 |
OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
|
|
Packit |
13e616 |
"Requester port GUID 0x%" PRIx64 ": Port for DGUID "
|
|
Packit |
13e616 |
"0x%" PRIx64 " not same as port for DLID %u\n",
|
|
Packit |
13e616 |
cl_ntoh64(osm_port_get_guid(requester_port)),
|
|
Packit |
13e616 |
cl_ntoh64(p_pr->dgid.unicast.interface_id),
|
|
Packit |
13e616 |
cl_ntoh16(p_pr->dlid));
|
|
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 |
/*
|
|
Packit |
13e616 |
What happens next depends on the type of endpoint information
|
|
Packit |
13e616 |
that was specified....
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
if (p_src_alias_guid) {
|
|
Packit |
13e616 |
if (p_dest_alias_guid)
|
|
Packit |
13e616 |
osm_pr_process_pair(sa, p_sa_mad, requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid, p_dest_alias_guid,
|
|
Packit |
13e616 |
p_sgid, p_dgid, &pr_list);
|
|
Packit |
13e616 |
else if (!p_dest_port)
|
|
Packit |
13e616 |
osm_pr_process_half(sa, p_sa_mad, requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid, NULL, p_sgid,
|
|
Packit |
13e616 |
p_dgid, &pr_list);
|
|
Packit |
13e616 |
else {
|
|
Packit |
13e616 |
/* Get all alias GUIDs for the dest port */
|
|
Packit |
13e616 |
p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
|
|
Packit |
13e616 |
while (p_dest_alias_guid !=
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
|
|
Packit |
13e616 |
if (osm_get_port_by_alias_guid(sa->p_subn, p_dest_alias_guid->alias_guid) ==
|
|
Packit |
13e616 |
p_dest_port)
|
|
Packit |
13e616 |
osm_pr_process_pair(sa, p_sa_mad,
|
|
Packit |
13e616 |
requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
p_sgid, p_dgid,
|
|
Packit |
13e616 |
&pr_list);
|
|
Packit |
13e616 |
if (p_sa_mad->method == IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
cl_qlist_count(&pr_list) > 0)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
if (p_dest_alias_guid && !p_src_port)
|
|
Packit |
13e616 |
osm_pr_process_half(sa, p_sa_mad, requester_port,
|
|
Packit |
13e616 |
NULL, p_dest_alias_guid, p_sgid,
|
|
Packit |
13e616 |
p_dgid, &pr_list);
|
|
Packit |
13e616 |
else if (!p_src_port && !p_dest_port)
|
|
Packit |
13e616 |
/*
|
|
Packit |
13e616 |
Katie, bar the door!
|
|
Packit |
13e616 |
*/
|
|
Packit |
13e616 |
pr_rcv_process_world(sa, p_sa_mad, requester_port,
|
|
Packit |
13e616 |
p_sgid, p_dgid, &pr_list);
|
|
Packit |
13e616 |
else if (p_dest_alias_guid && p_src_port) {
|
|
Packit |
13e616 |
/* Get all alias GUIDs for the src port */
|
|
Packit |
13e616 |
p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
|
|
Packit |
13e616 |
while (p_src_alias_guid !=
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
|
|
Packit |
13e616 |
if (osm_get_port_by_alias_guid(sa->p_subn,
|
|
Packit |
13e616 |
p_src_alias_guid->alias_guid) ==
|
|
Packit |
13e616 |
p_src_port)
|
|
Packit |
13e616 |
osm_pr_process_pair(sa, p_sa_mad,
|
|
Packit |
13e616 |
requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
p_sgid, p_dgid,
|
|
Packit |
13e616 |
&pr_list);
|
|
Packit |
13e616 |
if (p_sa_mad->method == IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
cl_qlist_count(&pr_list) > 0)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else if (p_src_port && !p_dest_port) {
|
|
Packit |
13e616 |
/* Get all alias GUIDs for the src port */
|
|
Packit |
13e616 |
p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
|
|
Packit |
13e616 |
while (p_src_alias_guid !=
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
|
|
Packit |
13e616 |
if (osm_get_port_by_alias_guid(sa->p_subn,
|
|
Packit |
13e616 |
p_src_alias_guid->alias_guid) ==
|
|
Packit |
13e616 |
p_src_port)
|
|
Packit |
13e616 |
osm_pr_process_half(sa, p_sa_mad,
|
|
Packit |
13e616 |
requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
NULL, p_sgid,
|
|
Packit |
13e616 |
p_dgid, &pr_list);
|
|
Packit |
13e616 |
p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else if (p_dest_port && !p_src_port) {
|
|
Packit |
13e616 |
/* Get all alias GUIDs for the dest port */
|
|
Packit |
13e616 |
p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
|
|
Packit |
13e616 |
while (p_dest_alias_guid !=
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
|
|
Packit |
13e616 |
if (osm_get_port_by_alias_guid(sa->p_subn,
|
|
Packit |
13e616 |
p_dest_alias_guid->alias_guid) ==
|
|
Packit |
13e616 |
p_dest_port)
|
|
Packit |
13e616 |
osm_pr_process_half(sa, p_sa_mad,
|
|
Packit |
13e616 |
requester_port,
|
|
Packit |
13e616 |
NULL,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
p_sgid, p_dgid,
|
|
Packit |
13e616 |
&pr_list);
|
|
Packit |
13e616 |
p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
} else {
|
|
Packit |
13e616 |
/* Get all alias GUIDs for the src port */
|
|
Packit |
13e616 |
p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
|
|
Packit |
13e616 |
while (p_src_alias_guid !=
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
|
|
Packit |
13e616 |
if (osm_get_port_by_alias_guid(sa->p_subn,
|
|
Packit |
13e616 |
p_src_alias_guid->alias_guid) ==
|
|
Packit |
13e616 |
p_src_port) {
|
|
Packit |
13e616 |
/* Get all alias GUIDs for the dest port */
|
|
Packit |
13e616 |
p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
|
|
Packit |
13e616 |
while (p_dest_alias_guid !=
|
|
Packit |
13e616 |
(osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
|
|
Packit |
13e616 |
if (osm_get_port_by_alias_guid(sa->p_subn,
|
|
Packit |
13e616 |
p_dest_alias_guid->alias_guid) ==
|
|
Packit |
13e616 |
p_dest_port)
|
|
Packit |
13e616 |
osm_pr_process_pair(sa,
|
|
Packit |
13e616 |
p_sa_mad,
|
|
Packit |
13e616 |
requester_port,
|
|
Packit |
13e616 |
p_src_alias_guid,
|
|
Packit |
13e616 |
p_dest_alias_guid,
|
|
Packit |
13e616 |
p_sgid,
|
|
Packit |
13e616 |
p_dgid,
|
|
Packit |
13e616 |
&pr_list);
|
|
Packit |
13e616 |
if (p_sa_mad->method == IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
cl_qlist_count(&pr_list) > 0)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
if (p_sa_mad->method == IB_MAD_METHOD_GET &&
|
|
Packit |
13e616 |
cl_qlist_count(&pr_list) > 0)
|
|
Packit |
13e616 |
break;
|
|
Packit |
13e616 |
p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
}
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
Unlock:
|
|
Packit |
13e616 |
cl_plock_release(sa->p_lock);
|
|
Packit |
13e616 |
|
|
Packit |
13e616 |
/* Now, (finally) respond to the PathRecord request */
|
|
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 |
}
|