-/*
- * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
- * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.
- * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
- *
- * This software is available to you under the OpenIB.org BSD license
- * below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials
- * provided with the distribution.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * $Id$
- */
-
-
-/*
- * Abstract:
- * Implementation of osm_pr_rcv_t.
- * This object represents the PathRecord Receiver object.
- * This object is part of the opensm family of objects.
- *
- * Environment:
- * Linux User Mode
- *
- * $Revision: 1.10 $
- */
-
-#if HAVE_CONFIG_H
-# include <config.h>
-#endif /* HAVE_CONFIG_H */
-
-#include <string.h>
-#include <iba/ib_types.h>
-#include <complib/cl_qmap.h>
-#include <complib/cl_passivelock.h>
-#include <complib/cl_debug.h>
-#include <complib/cl_qlist.h>
-#include <opensm/osm_base.h>
-#include <opensm/osm_sa_path_record.h>
-#include <opensm/osm_port.h>
-#include <opensm/osm_node.h>
-#include <opensm/osm_switch.h>
-#include <vendor/osm_vendor.h>
-#include <vendor/osm_vendor_api.h>
-#include <opensm/osm_helper.h>
-#include <opensm/osm_pkey.h>
-#include <opensm/osm_multicast.h>
-#include <opensm/osm_partition.h>
-
-#define OSM_PR_RCV_POOL_MIN_SIZE 64
-#define OSM_PR_RCV_POOL_GROW_SIZE 64
-
-typedef struct _osm_pr_item
-{
- cl_pool_item_t pool_item;
- ib_path_rec_t path_rec;
-} osm_pr_item_t;
-
-typedef struct _osm_path_parms
-{
- ib_net16_t pkey;
- uint8_t mtu;
- uint8_t rate;
- uint8_t sl;
- uint8_t pkt_life;
- boolean_t reversible;
-} osm_path_parms_t;
-
-typedef struct osm_sa_pr_mcmr_search_ctxt {
- ib_gid_t *p_mgid;
- osm_mgrp_t *p_mgrp;
- osm_pr_rcv_t *p_rcv;
-} osm_sa_pr_mcmr_search_ctxt_t;
-
-/**********************************************************************
- **********************************************************************/
-void
-osm_pr_rcv_construct(
- IN osm_pr_rcv_t* const p_rcv )
-{
- memset( p_rcv, 0, sizeof(*p_rcv) );
- cl_qlock_pool_construct( &p_rcv->pr_pool );
-}
-
-/**********************************************************************
- **********************************************************************/
-void
-osm_pr_rcv_destroy(
- IN osm_pr_rcv_t* const p_rcv )
-{
- OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_destroy );
- cl_qlock_pool_destroy( &p_rcv->pr_pool );
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-ib_api_status_t
-osm_pr_rcv_init(
- IN osm_pr_rcv_t* const p_rcv,
- IN osm_sa_resp_t* const p_resp,
- IN osm_mad_pool_t* const p_mad_pool,
- IN osm_subn_t* const p_subn,
- IN osm_log_t* const p_log,
- IN cl_plock_t* const p_lock )
-{
- ib_api_status_t status;
-
- OSM_LOG_ENTER( p_log, osm_pr_rcv_init );
-
- osm_pr_rcv_construct( p_rcv );
-
- p_rcv->p_log = p_log;
- p_rcv->p_subn = p_subn;
- p_rcv->p_lock = p_lock;
- p_rcv->p_resp = p_resp;
- p_rcv->p_mad_pool = p_mad_pool;
-
- status = cl_qlock_pool_init( &p_rcv->pr_pool,
- OSM_PR_RCV_POOL_MIN_SIZE,
- 0,
- OSM_PR_RCV_POOL_GROW_SIZE,
- sizeof(osm_pr_item_t),
- NULL, NULL, NULL );
-
- OSM_LOG_EXIT( p_rcv->p_log );
- return( status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static inline boolean_t
-__osm_sa_path_rec_is_tavor_port(
- IN const osm_port_t* const p_port)
-{
- osm_node_t const* p_node;
- ib_net32_t vend_id;
-
- p_node = osm_port_get_parent_node( p_port );
- vend_id = ib_node_info_get_vendor_id( &p_node->node_info );
-
- return( (p_node->node_info.device_id == CL_HTON16(23108)) &&
- ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
- (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
- (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
- (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))) );
-}
-
-/**********************************************************************
- **********************************************************************/
-static boolean_t
- __osm_sa_path_rec_apply_tavor_mtu_limit(
- IN const ib_path_rec_t* const p_pr,
- IN const osm_port_t* const p_src_port,
- IN const osm_port_t* const p_dest_port,
- IN const ib_net64_t comp_mask)
-{
- uint8_t required_mtu;
-
- /* only if at least one of the ports is a Tavor device */
- if (! __osm_sa_path_rec_is_tavor_port(p_src_port) &&
- ! __osm_sa_path_rec_is_tavor_port(p_dest_port) )
- return( FALSE );
-
- /*
- we can apply the patch if either:
- 1. No MTU required
- 2. Required MTU <
- 3. Required MTU = 1K or 512 or 256
- 4. Required MTU > 256 or 512
- */
- required_mtu = ib_path_rec_mtu( p_pr );
- if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&
- ( comp_mask & IB_PR_COMPMASK_MTU ) )
- {
- switch( ib_path_rec_mtu_sel( p_pr ) )
- {
- case 0: /* must be greater than */
- case 2: /* exact match */
- if( IB_MTU_LEN_1024 < required_mtu )
- return(FALSE);
- break;
-
- case 1: /* must be less than */
- /* can't be disqualified by this one */
- break;
-
- case 3: /* largest available */
- /* the ULP intentionally requested */
- /* the largest MTU possible */
- return(FALSE);
- break;
-
- default:
- /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
- CL_ASSERT( FALSE );
- break;
- }
- }
-
- return(TRUE);
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_api_status_t
-__osm_pr_rcv_get_path_parms(
- IN osm_pr_rcv_t* const p_rcv,
- IN const ib_path_rec_t* const p_pr,
- IN const osm_port_t* const p_src_port,
- IN const osm_port_t* const p_dest_port,
- IN const uint16_t dest_lid_ho,
- IN const ib_net64_t comp_mask,
- OUT osm_path_parms_t* const p_parms )
-{
- const osm_node_t* p_node;
- const osm_physp_t* p_physp;
- const osm_physp_t* p_dest_physp;
- const osm_prtn_t* p_prtn;
- const ib_port_info_t* p_pi;
- ib_api_status_t status = IB_SUCCESS;
- ib_net16_t pkey;
- uint8_t mtu;
- uint8_t rate;
- uint8_t pkt_life;
- uint8_t required_mtu;
- uint8_t required_rate;
- uint8_t required_pkt_life;
- uint8_t sl;
- ib_net16_t dest_lid;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_path_parms );
-
- dest_lid = cl_hton16( dest_lid_ho );
-
- p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );
- p_physp = osm_port_get_default_phys_ptr( p_src_port );
- p_pi = osm_physp_get_port_info_ptr( p_physp );
-
- mtu = ib_port_info_get_mtu_cap( p_pi );
- rate = ib_port_info_compute_rate( p_pi );
-
- /*
- Mellanox Tavor device performance is better using 1K MTU.
- If required MTU and MTU selector are such that 1K is OK
- and at least one end of the path is Tavor we override the
- port MTU with 1K.
- */
- if ( p_rcv->p_subn->opt.enable_quirks &&
- __osm_sa_path_rec_apply_tavor_mtu_limit(
- p_pr, p_src_port, p_dest_port, comp_mask) )
- if (mtu > IB_MTU_LEN_1024)
- {
- mtu = IB_MTU_LEN_1024;
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "Optimized Path MTU to 1K for Mellanox Tavor device\n");
- }
-
- /*
- Walk the subnet object from source to destination,
- tracking the most restrictive rate and mtu values along the way...
-
- If source port node is a switch, then p_physp should
- point to the port that routes the destination lid
- */
-
- p_node = osm_physp_get_node_ptr( p_physp );
-
- if( p_node->sw )
- {
- /*
- * If the dest_lid_ho is equal to the lid of the switch pointed by
- * p_sw then p_physp will be the physical port of the switch port zero.
- */
- p_physp = osm_switch_get_route_by_lid(p_node->sw, cl_ntoh16( dest_lid_ho ) );
- if ( p_physp == 0 )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F02: "
- "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",
- dest_lid_ho,
- cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
- status = IB_ERROR;
- goto Exit;
- }
- }
-
- /*
- * Same as above
- */
- p_node = osm_physp_get_node_ptr( p_dest_physp );
-
- if( p_node->sw )
- {
- p_dest_physp = osm_switch_get_route_by_lid( p_node->sw, cl_ntoh16( dest_lid_ho ) );
-
- if ( p_dest_physp == 0 )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F03: "
- "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",
- dest_lid_ho,
- cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
- status = IB_ERROR;
- goto Exit;
- }
-
- }
-
- while( p_physp != p_dest_physp )
- {
- p_physp = osm_physp_get_remote( p_physp );
-
- if ( p_physp == 0 )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F05: "
- "Cannot find remote phys port when routing to LID 0x%X from node GUID 0x%016" PRIx64 "\n",
- dest_lid_ho,
- cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
- status = IB_ERROR;
- goto Exit;
- }
-
- /*
- This is point to point case (no switch in between)
- */
- if( p_physp == p_dest_physp )
- break;
-
- p_node = osm_physp_get_node_ptr( p_physp );
-
- if( !p_node->sw )
- {
- /*
- There is some sort of problem in the subnet object!
- If this isn't a switch, we should have reached
- the destination by now!
- */
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F06: "
- "Internal error, bad path\n" );
- status = IB_ERROR;
- goto Exit;
- }
-
- /*
- Check parameters for the ingress port in this switch.
- */
- p_pi = osm_physp_get_port_info_ptr( p_physp );
-
- if( mtu > ib_port_info_get_mtu_cap( p_pi ) )
- {
- mtu = ib_port_info_get_mtu_cap( p_pi );
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "New smallest MTU = %u at intervening port 0x%016" PRIx64
- " port num 0x%X\n",
- mtu,
- cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
- osm_physp_get_port_num( p_physp ) );
- }
- }
-
- if( rate > ib_port_info_compute_rate( p_pi ) )
- {
- rate = ib_port_info_compute_rate( p_pi );
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "New smallest rate = %u at intervening port 0x%016" PRIx64
- " port num 0x%X\n",
- rate,
- cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
- osm_physp_get_port_num( p_physp ) );
- }
- }
-
- /*
- Continue with the egress port on this switch.
- */
- p_physp = osm_switch_get_route_by_lid( p_node->sw, dest_lid );
-
- if ( p_physp == 0 )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F07: "
- "Dead end on path to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",
- dest_lid_ho,
- cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
- status = IB_ERROR;
- goto Exit;
- }
-
- CL_ASSERT( p_physp );
- CL_ASSERT( osm_physp_is_valid( p_physp ) );
-
- p_pi = osm_physp_get_port_info_ptr( p_physp );
-
- if( mtu > ib_port_info_get_mtu_cap( p_pi ) )
- {
- mtu = ib_port_info_get_mtu_cap( p_pi );
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "New smallest MTU = %u at intervening port 0x%016" PRIx64
- " port num 0x%X\n",
- mtu,
- cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
- osm_physp_get_port_num( p_physp ) );
- }
- }
-
- if( rate > ib_port_info_compute_rate( p_pi ) )
- {
- rate = ib_port_info_compute_rate( p_pi );
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "New smallest rate = %u at intervening port 0x%016" PRIx64
- " port num 0x%X\n",
- rate,
- cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),
- osm_physp_get_port_num( p_physp ) );
- }
- }
-
- }
-
- /*
- p_physp now points to the destination
- */
- p_pi = osm_physp_get_port_info_ptr( p_physp );
-
- if( mtu > ib_port_info_get_mtu_cap( p_pi ) )
- {
- mtu = ib_port_info_get_mtu_cap( p_pi );
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "New smallest MTU = %u at destination port 0x%016" PRIx64 "\n",
- mtu,
- cl_ntoh64(osm_physp_get_port_guid( p_physp )) );
- }
- }
-
- if( rate > ib_port_info_compute_rate( p_pi ) )
- {
- rate = ib_port_info_compute_rate( p_pi );
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "New smallest rate = %u at destination port 0x%016" PRIx64 "\n",
- rate,
- cl_ntoh64(osm_physp_get_port_guid( p_physp )) );
- }
- }
-
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_path_parms: "
- "Path min MTU = %u, min rate = %u\n", mtu, rate );
- }
-
- /*
- Determine if these values meet the user criteria
- and adjust appropriately
- */
-
- /* we silently ignore cases where only the MTU selector is defined */
- if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&
- ( comp_mask & IB_PR_COMPMASK_MTU ) )
- {
- required_mtu = ib_path_rec_mtu( p_pr );
- switch( ib_path_rec_mtu_sel( p_pr ) )
- {
- case 0: /* must be greater than */
- if( mtu <= required_mtu )
- status = IB_NOT_FOUND;
- break;
-
- case 1: /* must be less than */
- if( mtu >= required_mtu )
- {
- /* adjust to use the highest mtu
- lower then the required one */
- if( required_mtu > 1 )
- mtu = required_mtu - 1;
- else
- status = IB_NOT_FOUND;
- }
- break;
-
- case 2: /* exact match */
- if( mtu < required_mtu )
- status = IB_NOT_FOUND;
- else
- mtu = required_mtu;
- break;
-
- case 3: /* largest available */
- /* can't be disqualified by this one */
- break;
-
- default:
- /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
- CL_ASSERT( FALSE );
- status = IB_ERROR;
- break;
- }
- }
-
- /* we silently ignore cases where only the Rate selector is defined */
- if ( ( comp_mask & IB_PR_COMPMASK_RATESELEC ) &&
- ( comp_mask & IB_PR_COMPMASK_RATE ) )
- {
- required_rate = ib_path_rec_rate( p_pr );
- switch( ib_path_rec_rate_sel( p_pr ) )
- {
- case 0: /* must be greater than */
- if( rate <= required_rate )
- status = IB_NOT_FOUND;
- break;
-
- case 1: /* must be less than */
- if( rate >= required_rate )
- {
- /* adjust the rate to use the highest rate
- lower then the required one */
- if( required_rate > 2 )
- rate = required_rate - 1;
- else
- status = IB_NOT_FOUND;
- }
- break;
-
- case 2: /* exact match */
- if( rate < required_rate )
- status = IB_NOT_FOUND;
- else
- rate = required_rate;
- break;
-
- case 3: /* largest available */
- /* can't be disqualified by this one */
- break;
-
- default:
- /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
- CL_ASSERT( FALSE );
- status = IB_ERROR;
- break;
- }
- }
-
- /* Verify the pkt_life_time */
- /* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,
- for loopback paths, packetLifeTime shall be zero. */
- if ( p_src_port == p_dest_port )
- pkt_life = 0; /* loopback */
- else
- pkt_life = OSM_DEFAULT_SUBNET_TIMEOUT;
-
- /* we silently ignore cases where only the PktLife selector is defined */
- if ( ( comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC ) &&
- ( comp_mask & IB_PR_COMPMASK_PKTLIFETIME ) )
- {
- required_pkt_life = ib_path_rec_pkt_life( p_pr );
- switch( ib_path_rec_pkt_life_sel( p_pr ) )
- {
- case 0: /* must be greater than */
- if( pkt_life <= required_pkt_life )
- status = IB_NOT_FOUND;
- break;
-
- case 1: /* must be less than */
- if( pkt_life >= required_pkt_life )
- {
- /* adjust the lifetime to use the highest possible
- lower then the required one */
- if( required_pkt_life > 1 )
- pkt_life = required_pkt_life - 1;
- else
- status = IB_NOT_FOUND;
- }
- break;
-
- case 2: /* exact match */
- if( pkt_life < required_pkt_life )
- status = IB_NOT_FOUND;
- else
- pkt_life = required_pkt_life;
- break;
-
- case 3: /* smallest available */
- /* can't be disqualified by this one */
- break;
-
- default:
- /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
- CL_ASSERT( FALSE );
- status = IB_ERROR;
- break;
- }
- }
-
- if (status != IB_SUCCESS)
- goto Exit;
-
- p_parms->mtu = mtu;
- p_parms->rate = rate;
- p_parms->pkt_life = pkt_life;
-
- if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
- cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )
- pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );
- else if( comp_mask & IB_PR_COMPMASK_PKEY )
- {
- pkey = p_pr->pkey;
- if( !osm_physp_share_this_pkey( p_physp, p_dest_physp, pkey ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F1A: "
- "Ports do not share specified PKey 0x%04x\n", cl_ntoh16(pkey));
- status = IB_NOT_FOUND;
- goto Exit;
- }
- }
- else
- {
- pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );
- if ( !pkey )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F1B: "
- "Ports do not have any shared PKeys\n");
- status = IB_NOT_FOUND;
- goto Exit;
- }
- }
-
- sl = OSM_DEFAULT_SL;
-
- if (pkey) {
- p_prtn = (osm_prtn_t *)cl_qmap_get(&p_rcv->p_subn->prtn_pkey_tbl,
- pkey & cl_ntoh16((uint16_t)~0x8000));
- if ( p_prtn == (osm_prtn_t *)cl_qmap_end(&p_rcv->p_subn->prtn_pkey_tbl) )
- {
- /* this may be possible when pkey tables are created somehow in
- previous runs or things are going wrong here */
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_path_parms: ERR 1F1C: "
- "No partition found for PKey 0x%04x - using default SL %d\n",
- cl_ntoh16(pkey), sl );
- }
- else
- sl = p_prtn->sl;
-
- /* reset pkey when raw traffic */
- if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
- cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )
- pkey = 0;
- }
-
- if ( ( comp_mask & IB_PR_COMPMASK_SL ) && ib_path_rec_sl( p_pr ) != sl )
- {
- status = IB_NOT_FOUND;
- goto Exit;
- }
-
- p_parms->pkey = pkey;
- p_parms->sl = sl;
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
- return( status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_build_pr(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_port_t* const p_src_port,
- IN const osm_port_t* const p_dest_port,
- IN const uint16_t src_lid_ho,
- IN const uint16_t dest_lid_ho,
- IN const uint8_t preference,
- IN const osm_path_parms_t* const p_parms,
- OUT ib_path_rec_t* const p_pr )
-{
- const osm_physp_t* p_src_physp;
- const osm_physp_t* p_dest_physp;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_build_pr );
-
- p_src_physp = osm_port_get_default_phys_ptr( p_src_port );
- p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );
-
- p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix( p_dest_physp );
- p_pr->dgid.unicast.interface_id = osm_physp_get_port_guid( p_dest_physp );
-
- p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix( p_src_physp );
- p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid( p_src_physp );
-
- p_pr->dlid = cl_hton16( dest_lid_ho );
- p_pr->slid = cl_hton16( src_lid_ho );
-
- p_pr->hop_flow_raw &= cl_hton32(1<<31);
-
- p_pr->pkey = p_parms->pkey;
- p_pr->sl = cl_hton16(p_parms->sl);
- p_pr->mtu = (uint8_t)(p_parms->mtu | 0x80);
- p_pr->rate = (uint8_t)(p_parms->rate | 0x80);
-
- /* According to 1.2 spec definition Table 205 PacketLifeTime description,
- for loopback paths, packetLifeTime shall be zero. */
- if ( p_src_port == p_dest_port )
- p_pr->pkt_life = 0x80; /* loopback */
- else
- p_pr->pkt_life = (uint8_t)(p_parms->pkt_life | 0x80);
-
- p_pr->preference = preference;
-
- /* always return num_path = 0 so this is only the reversible component */
- if (p_parms->reversible)
- p_pr->num_path = 0x80;
-
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static osm_pr_item_t*
-__osm_pr_rcv_get_lid_pair_path(
- IN osm_pr_rcv_t* const p_rcv,
- IN const ib_path_rec_t* const p_pr,
- IN const osm_port_t* const p_src_port,
- IN const osm_port_t* const p_dest_port,
- IN const uint16_t src_lid_ho,
- IN const uint16_t dest_lid_ho,
- IN const ib_net64_t comp_mask,
- IN const uint8_t preference )
-{
- osm_path_parms_t path_parms;
- osm_path_parms_t rev_path_parms;
- osm_pr_item_t *p_pr_item;
- ib_api_status_t status, rev_path_status;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_lid_pair_path );
-
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_lid_pair_path: "
- "Src LID 0x%X, Dest LID 0x%X\n",
- src_lid_ho, dest_lid_ho );
- }
-
- p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );
- if( p_pr_item == NULL )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_lid_pair_path: ERR 1F01: "
- "Unable to allocate path record\n" );
- goto Exit;
- }
-
- status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_src_port,
- p_dest_port, dest_lid_ho,
- comp_mask, &path_parms );
-
- if( status != IB_SUCCESS )
- {
- cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
- p_pr_item = NULL;
- goto Exit;
- }
-
- /* now try the reversible path */
- rev_path_status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_dest_port,
- p_src_port, src_lid_ho,
- comp_mask, &rev_path_parms );
- path_parms.reversible = ( rev_path_status == IB_SUCCESS );
-
- /* did we get a Reversible Path compmask ? */
- /*
- NOTE that if the reversible component = 0, it is a don't care
- rather then requiring non-reversible paths ...
- see Vol1 Ver1.2 p900 l16
- */
- if( comp_mask & IB_PR_COMPMASK_REVERSIBLE )
- {
- if( (! path_parms.reversible && ( p_pr->num_path & 0x80 ) ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_lid_pair_path: "
- "Requested reversible path but failed to get one\n");
-
- cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
- p_pr_item = NULL;
- goto Exit;
- }
- }
-
- __osm_pr_rcv_build_pr( p_rcv, p_src_port, p_dest_port, src_lid_ho,
- dest_lid_ho, preference, &path_parms,
- &p_pr_item->path_rec );
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
- return( p_pr_item );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_get_port_pair_paths(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- IN const osm_port_t* const p_req_port,
- IN const osm_port_t* const p_src_port,
- IN const osm_port_t* const p_dest_port,
- IN const ib_net64_t comp_mask,
- IN cl_qlist_t* const p_list )
-{
- const ib_path_rec_t* p_pr;
- const ib_sa_mad_t* p_sa_mad;
- osm_pr_item_t* p_pr_item;
- uint16_t src_lid_min_ho;
- uint16_t src_lid_max_ho;
- uint16_t dest_lid_min_ho;
- uint16_t dest_lid_max_ho;
- uint16_t src_lid_ho;
- uint16_t dest_lid_ho;
- uint32_t path_num;
- uint8_t preference;
- uintn_t iterations;
- uintn_t src_offset;
- uintn_t dest_offset;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_port_pair_paths );
-
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_port_pair_paths: "
- "Src port 0x%016" PRIx64 ", "
- "Dst port 0x%016" PRIx64 "\n",
- cl_ntoh64( osm_port_get_guid( p_src_port ) ),
- cl_ntoh64( osm_port_get_guid( p_dest_port ) ) );
- }
-
- /* Check that the req_port, src_port and dest_port all share a
- pkey. The check is done on the default physical port of the ports. */
- if (osm_port_share_pkey(p_rcv->p_log, p_req_port, p_src_port) == FALSE ||
- osm_port_share_pkey(p_rcv->p_log, p_req_port, p_dest_port) == FALSE ||
- osm_port_share_pkey(p_rcv->p_log, p_src_port, p_dest_port) == FALSE )
- {
- /* One of the pairs doesn't share a pkey so the path is disqualified. */
- goto Exit;
- }
-
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
- /*
- We shouldn't be here if the paths are disqualified in some way...
- Thus, we assume every possible connection is valid.
-
- We desire to return high-quality paths first.
- In OpenSM, higher quality means least overlap with other paths.
- This is acheived in practice by returning paths with
- different LID value on each end, which means these
- paths are more redundant that paths with the same LID repeated
- on one side. For example, in OpenSM the paths between two
- endpoints with LMC = 1 might be as follows:
-
- Port A, LID 1 <-> Port B, LID 3
- Port A, LID 1 <-> Port B, LID 4
- Port A, LID 2 <-> Port B, LID 3
- Port A, LID 2 <-> Port B, LID 4
-
- The OpenSM unicast routing algorithms attempt to disperse each path
- to as varied a physical path as is reasonable. 1<->3 and 1<->4 have
- more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
-
- OpenSM ranks paths in three preference groups:
-
- Preference Value Description
- ---------------- -------------------------------------------
- 0 Redundant in both directions with other
- pref value = 0 paths
-
- 1 Redundant in one direction with other
- pref value = 0 and pref value = 1 paths
-
- 2 Not redundant in either direction with
- other paths
-
- 3-FF Unused
-
-
- SA clients don't need to know these details, only that the lower
- preference paths are preferred, as stated in the spec. The paths
- may not actually be physically redundant depending on the topology
- of the subnet, but the point of LMC > 0 is to offer redundancy,
- so it is assumed that the subnet is physically appropriate for the
- specified LMC value. A more advanced implementation would inspect for
- physical redundancy, but I'm not going to bother with that now.
- */
-
- /*
- Refine our search if the client specified end-point LIDs
- */
- if( comp_mask & IB_PR_COMPMASK_DLID )
- {
- dest_lid_min_ho = cl_ntoh16( p_pr->dlid );
- dest_lid_max_ho = cl_ntoh16( p_pr->dlid );
- }
- else
- {
- osm_port_get_lid_range_ho( p_dest_port, &dest_lid_min_ho,
- &dest_lid_max_ho );
- }
-
- if( comp_mask & IB_PR_COMPMASK_SLID )
- {
- src_lid_min_ho = cl_ntoh16( p_pr->slid );
- src_lid_max_ho = cl_ntoh16( p_pr->slid );
- }
- else
- {
- osm_port_get_lid_range_ho( p_src_port, &src_lid_min_ho,
- &src_lid_max_ho );
- }
-
- if ( src_lid_min_ho == 0 )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_port_pair_paths: ERR 1F20:"
- "Obtained source LID of 0. No such LID possible\n");
- goto Exit;
- }
-
- if ( dest_lid_min_ho == 0 )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_get_port_pair_paths: ERR 1F21:"
- "Obtained destination LID of 0. No such LID possible\n");
- goto Exit;
- }
-
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- {
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_get_port_pair_paths: "
- "Src LIDs [0x%X-0x%X], "
- "Dest LIDs [0x%X-0x%X]\n",
- src_lid_min_ho, src_lid_max_ho,
- dest_lid_min_ho, dest_lid_max_ho );
- }
-
- src_lid_ho = src_lid_min_ho;
- dest_lid_ho = dest_lid_min_ho;
-
- /*
- Preferred paths come first in OpenSM
- */
- preference = 0;
- path_num = 0;
-
- /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
- if( p_sa_mad->method != IB_MAD_METHOD_GET )
- if( comp_mask & IB_PR_COMPMASK_NUMBPATH )
- iterations = ib_path_rec_num_path( p_pr );
- else
- iterations = (uintn_t)(-1);
- else
- iterations = 1;
-
- while( path_num < iterations )
- {
- /*
- These paths are "fully redundant"
- */
-
- p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,
- p_src_port, p_dest_port,
- src_lid_ho, dest_lid_ho,
- comp_mask, preference );
-
- if( p_pr_item )
- {
- cl_qlist_insert_tail( p_list,
- (cl_list_item_t*)&p_pr_item->pool_item );
- ++path_num;
- }
-
- if( ++src_lid_ho > src_lid_max_ho )
- break;
-
- if( ++dest_lid_ho > dest_lid_max_ho )
- break;
- }
-
- /*
- Check if we've accumulated all the paths that the user cares to see
- */
- if( path_num == iterations )
- goto Exit;
-
- /*
- Don't bother reporting preference 1 paths for now.
- It's more trouble than it's worth and can only occur
- if ports have different LMC values, which isn't supported
- by OpenSM right now anyway.
- */
- preference = 2;
- src_lid_ho = src_lid_min_ho;
- dest_lid_ho = dest_lid_min_ho;
- src_offset = 0;
- dest_offset = 0;
-
- /*
- Iterate over the remaining paths
- */
- while( path_num < iterations )
- {
- dest_offset++;
- dest_lid_ho++;
-
- if( dest_lid_ho > dest_lid_max_ho )
- {
- src_offset++;
- src_lid_ho++;
-
- if( src_lid_ho > src_lid_max_ho )
- break; /* done */
-
- dest_offset = 0;
- dest_lid_ho = dest_lid_min_ho;
- }
-
- /*
- These paths are "fully non-redundant" with paths already
- identified above and consequently not of much value.
-
- Don't return paths we already identified above, as indicated
- by the offset values being equal.
- */
- if( src_offset == dest_offset )
- continue; /* already reported */
-
- p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,
- p_src_port, p_dest_port,
- src_lid_ho, dest_lid_ho,
- comp_mask, preference );
-
- if( p_pr_item )
- {
- cl_qlist_insert_tail( p_list,
- (cl_list_item_t*)&p_pr_item->pool_item );
- ++path_num;
- }
- }
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_net16_t
-__osm_pr_rcv_get_end_points(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- OUT const osm_port_t** const pp_src_port,
- OUT const osm_port_t** const pp_dest_port )
-{
- const ib_path_rec_t* p_pr;
- const ib_sa_mad_t* p_sa_mad;
- ib_net64_t comp_mask;
- ib_api_status_t status;
- ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_end_points );
-
- /*
- Determine what fields are valid and then get a pointer
- to the source and destination port objects, if possible.
- */
-
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
- comp_mask = p_sa_mad->comp_mask;
-
- /*
- Check a few easy disqualifying cases up front before getting
- into the endpoints.
- */
-
- if( comp_mask & IB_PR_COMPMASK_SGID )
- {
- if ( ! ib_gid_is_link_local ( &p_pr->sgid ) )
- {
- if ( ib_gid_get_subnet_prefix ( &p_pr->sgid ) != p_rcv->p_subn->opt.subnet_prefix )
- {
- /*
- This 'error' is the client's fault (bad gid) so
- don't enter it as an error in our own log.
- Return an error response to the client.
- */
- osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
- "__osm_pr_rcv_get_end_points: "
- "Non local SGID subnet prefix 0x%016" PRIx64 "\n",
- cl_ntoh64( p_pr->sgid.unicast.prefix ) );
-
- sa_status = IB_SA_MAD_STATUS_INVALID_GID;
- goto Exit;
- }
- }
-
- *pp_src_port = (osm_port_t*)cl_qmap_get(
- &p_rcv->p_subn->port_guid_tbl,
- p_pr->sgid.unicast.interface_id );
-
- if( *pp_src_port == (osm_port_t*)cl_qmap_end(
- &p_rcv->p_subn->port_guid_tbl ) )
- {
- /*
- This 'error' is the client's fault (bad gid) so
- don't enter it as an error in our own log.
- Return an error response to the client.
- */
- osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
- "__osm_pr_rcv_get_end_points: "
- "No source port with GUID 0x%016" PRIx64 "\n",
- cl_ntoh64( p_pr->sgid.unicast.interface_id) );
-
- sa_status = IB_SA_MAD_STATUS_INVALID_GID;
- goto Exit;
- }
- }
- else
- {
- *pp_src_port = 0;
- if( comp_mask & IB_PR_COMPMASK_SLID )
- {
- status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,
- cl_ntoh16(p_pr->slid), (void**)pp_src_port );
-
- if( (status != CL_SUCCESS) || (*pp_src_port == NULL) )
- {
- /*
- This 'error' is the client's fault (bad lid) so
- don't enter it as an error in our own log.
- Return an error response to the client.
- */
- osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
- "__osm_pr_rcv_get_end_points: "
- "No source port with LID = 0x%X\n",
- cl_ntoh16( p_pr->slid) );
-
- sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
- goto Exit;
- }
- }
- }
-
- if( comp_mask & IB_PR_COMPMASK_DGID )
- {
- if ( ! ib_gid_is_link_local ( &p_pr->dgid ) )
- {
- if ( ! ib_gid_is_multicast ( &p_pr->dgid ) &&
- ib_gid_get_subnet_prefix ( &p_pr->dgid ) != p_rcv->p_subn->opt.subnet_prefix )
- {
- /*
- This 'error' is the client's fault (bad gid) so
- don't enter it as an error in our own log.
- Return an error response to the client.
- */
- osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
- "__osm_pr_rcv_get_end_points: "
- "Non local DGID subnet prefix 0x%016" PRIx64 "\n",
- cl_ntoh64( p_pr->dgid.unicast.prefix ) );
-
- sa_status = IB_SA_MAD_STATUS_INVALID_GID;
- goto Exit;
- }
- }
-
- *pp_dest_port = (osm_port_t*)cl_qmap_get(
- &p_rcv->p_subn->port_guid_tbl,
- p_pr->dgid.unicast.interface_id );
-
- if( *pp_dest_port == (osm_port_t*)cl_qmap_end(
- &p_rcv->p_subn->port_guid_tbl ) )
- {
- /*
- This 'error' is the client's fault (bad gid) so
- don't enter it as an error in our own log.
- Return an error response to the client.
- */
- osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
- "__osm_pr_rcv_get_end_points: "
- "No dest port with GUID 0x%016" PRIx64 "\n",
- cl_ntoh64( p_pr->dgid.unicast.interface_id) );
-
- sa_status = IB_SA_MAD_STATUS_INVALID_GID;
- goto Exit;
- }
- }
- else
- {
- *pp_dest_port = 0;
- if( comp_mask & IB_PR_COMPMASK_DLID )
- {
- status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,
- cl_ntoh16(p_pr->dlid), (void**)pp_dest_port );
-
- if( (status != CL_SUCCESS) || (*pp_dest_port == NULL) )
- {
- /*
- This 'error' is the client's fault (bad lid) so
- don't enter it as an error in our own log.
- Return an error response to the client.
- */
- osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
- "__osm_pr_rcv_get_end_points: "
- "No dest port with LID = 0x%X\n",
- cl_ntoh16( p_pr->dlid) );
-
- sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
- goto Exit;
- }
- }
- }
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
- return( sa_status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_process_world(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- IN const osm_port_t* const requester_port,
- IN const ib_net64_t comp_mask,
- IN cl_qlist_t* const p_list )
-{
- const cl_qmap_t* p_tbl;
- const osm_port_t* p_dest_port;
- const osm_port_t* p_src_port;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_world );
-
- /*
- Iterate the entire port space over itself.
- A path record from a port to itself is legit, so no
- need for a special case there.
-
- We compute both A -> B and B -> A, since we don't have
- any check to determine the reversability of the paths.
- */
- p_tbl = &p_rcv->p_subn->port_guid_tbl;
-
- p_dest_port = (osm_port_t*)cl_qmap_head( p_tbl );
- while( p_dest_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
- {
- p_src_port = (osm_port_t*)cl_qmap_head( p_tbl );
- while( p_src_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
- {
- __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,
- p_dest_port, comp_mask, p_list );
-
- p_src_port = (osm_port_t*)cl_qmap_next( &p_src_port->map_item );
- }
-
- p_dest_port = (osm_port_t*)cl_qmap_next( &p_dest_port->map_item );
- }
-
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_process_half(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- IN const osm_port_t* const requester_port,
- IN const osm_port_t* const p_src_port,
- IN const osm_port_t* const p_dest_port,
- IN const ib_net64_t comp_mask,
- IN cl_qlist_t* const p_list )
-{
- const cl_qmap_t* p_tbl;
- const osm_port_t* p_port;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_half );
-
- /*
- Iterate over every port, looking for matches...
- A path record from a port to itself is legit, so no
- need to special case that one.
- */
- p_tbl = &p_rcv->p_subn->port_guid_tbl;
-
- if( p_src_port )
- {
- /*
- The src port if fixed, so iterate over destination ports.
- */
- p_port = (osm_port_t*)cl_qmap_head( p_tbl );
- while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
- {
- __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw , requester_port, p_src_port,
- p_port, comp_mask, p_list );
- p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );
- }
- }
- else
- {
- /*
- The dest port if fixed, so iterate over source ports.
- */
- p_port = (osm_port_t*)cl_qmap_head( p_tbl );
- while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )
- {
- __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_port,
- p_dest_port, comp_mask, p_list );
- p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );
- }
- }
-
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_process_pair(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- IN const osm_port_t* const requester_port,
- IN const osm_port_t* const p_src_port,
- IN const osm_port_t* const p_dest_port,
- IN const ib_net64_t comp_mask,
- IN cl_qlist_t* const p_list )
-{
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_pair );
-
- __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,
- p_dest_port, comp_mask, p_list );
-
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- *********************************************************************/
-static void
-__search_mgrp_by_mgid(
- IN cl_map_item_t* const p_map_item,
- IN void* context )
-{
- osm_mgrp_t* p_mgrp = (osm_mgrp_t*)p_map_item;
- osm_sa_pr_mcmr_search_ctxt_t *p_ctxt = (osm_sa_pr_mcmr_search_ctxt_t *) context;
- const ib_gid_t *p_recvd_mgid;
- osm_pr_rcv_t *p_rcv;
- /* uint32_t i; */
-
- p_recvd_mgid = p_ctxt->p_mgid;
- p_rcv = p_ctxt->p_rcv;
-
- /* ignore groups marked for deletion */
- if ( p_mgrp->to_be_deleted )
- return;
-
- /* compare entire MGID so different scope will not sneak in for
- the same MGID */
- if ( memcmp( &p_mgrp->mcmember_rec.mgid,
- p_recvd_mgid,
- sizeof(ib_gid_t) ) )
- return;
-
-#if 0
- for ( i = 0 ; i < sizeof(p_mgrp->mcmember_rec.mgid.multicast.raw_group_id); i++)
- {
- if ( p_mgrp->mcmember_rec.mgid.multicast.raw_group_id[i] !=
- p_recvd_mgid->mgid.multicast.raw_group_id[i] )
- return;
- }
-#endif
-
- if( p_ctxt->p_mgrp )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__search_mgrp_by_mgid: ERR 1F08: "
- "Multiple MC groups for same MGID\n" );
- return;
- }
- p_ctxt->p_mgrp = p_mgrp;
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_api_status_t
-__get_mgrp_by_mgid(
- IN osm_pr_rcv_t* const p_rcv,
- IN ib_path_rec_t* p_recvd_path_rec,
- OUT osm_mgrp_t ** pp_mgrp )
-{
- osm_sa_pr_mcmr_search_ctxt_t mcmr_search_context;
-
- mcmr_search_context.p_mgid = &p_recvd_path_rec->dgid;
- mcmr_search_context.p_rcv = p_rcv;
- mcmr_search_context.p_mgrp = NULL;
-
- cl_qmap_apply_func( &p_rcv->p_subn->mgrp_mlid_tbl,
- __search_mgrp_by_mgid,
- &mcmr_search_context);
-
- if( mcmr_search_context.p_mgrp == NULL )
- {
- return IB_NOT_FOUND;
- }
-
- *pp_mgrp = mcmr_search_context.p_mgrp;
- return IB_SUCCESS;
-}
-
-/**********************************************************************
- **********************************************************************/
-static osm_mgrp_t *
-__get_mgrp_by_mlid(
- IN const osm_pr_rcv_t* const p_rcv,
- IN ib_net16_t const mlid )
-{
- cl_map_item_t * map_item;
-
- map_item = cl_qmap_get( &p_rcv->p_subn->mgrp_mlid_tbl, mlid );
-
- if( map_item == cl_qmap_end(&p_rcv->p_subn->mgrp_mlid_tbl) )
- {
- return NULL;
- }
-
- return (osm_mgrp_t *)map_item;
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_get_mgrp(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- OUT osm_mgrp_t **pp_mgrp )
-{
- ib_path_rec_t* p_pr;
- const ib_sa_mad_t* p_sa_mad;
- ib_net64_t comp_mask;
- ib_api_status_t status;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_get_mgrp );
-
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
- comp_mask = p_sa_mad->comp_mask;
-
- if( comp_mask & IB_PR_COMPMASK_DGID )
- {
- status = __get_mgrp_by_mgid( p_rcv, p_pr, pp_mgrp );
- if( status != IB_SUCCESS )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_get_mgrp: ERR 1F09: "
- "No MC group found for PathRecord destination GID\n" );
- goto Exit;
- }
- }
-
- if( comp_mask & IB_PR_COMPMASK_DLID )
- {
- if( *pp_mgrp)
- {
- /* check that the MLID in the MC group is */
- /* the same as the DLID in the PathRecord */
- if( (*pp_mgrp)->mlid != p_pr->dlid )
- {
- /* Note: perhaps this might be better indicated as an invalid request */
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_get_mgrp: ERR 1F10: "
- "MC group MLID does not match PathRecord destination LID\n" );
- *pp_mgrp = NULL;
- goto Exit;
- }
- }
- else
- {
- *pp_mgrp = __get_mgrp_by_mlid( p_rcv, p_pr->dlid );
- if( *pp_mgrp == NULL)
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_get_mgrp: ERR 1F11: "
- "No MC group found for PathRecord destination LID\n" );
- }
- }
- }
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-static ib_api_status_t
-__osm_pr_match_mgrp_attributes(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- IN const osm_mgrp_t* const p_mgrp )
-{
- const ib_path_rec_t* p_pr;
- const ib_sa_mad_t* p_sa_mad;
- ib_net64_t comp_mask;
- ib_api_status_t status = IB_ERROR;
- uint32_t flow_label;
- uint8_t sl;
- uint8_t hop_limit;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_match_mgrp_attributes );
-
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
- comp_mask = p_sa_mad->comp_mask;
-
- /* If SGID and/or SLID specified, should validate as member of MC group */
- /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
- if( comp_mask & IB_PR_COMPMASK_PKEY )
- {
- if( p_pr->pkey != p_mgrp->mcmember_rec.pkey )
- goto Exit;
- }
-
- ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,
- &sl, &flow_label, &hop_limit );
-
- if( comp_mask & IB_PR_COMPMASK_SL )
- {
- if( ib_path_rec_sl( p_pr ) != sl )
- goto Exit;
- }
-
- /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
- if( ( comp_mask & IB_PR_COMPMASK_NUMBPATH ) &&
- ( p_sa_mad->method != IB_MAD_METHOD_GET ) )
- {
- if( ib_path_rec_num_path( p_pr ) == 0 )
- goto Exit;
- }
-
- if( comp_mask & IB_PR_COMPMASK_FLOWLABEL )
- {
- if( ib_path_rec_flow_lbl( p_pr ) != flow_label )
- goto Exit;
- }
-
- if( comp_mask & IB_PR_COMPMASK_HOPLIMIT )
- {
- if( ib_path_rec_hop_limit( p_pr ) != hop_limit )
- goto Exit;
- }
-
- if( comp_mask & IB_PR_COMPMASK_TCLASS )
- {
- if( p_pr->tclass != p_mgrp->mcmember_rec.tclass )
- goto Exit;
- }
-
- status = IB_SUCCESS;
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
- return( status );
-}
-
-/**********************************************************************
- **********************************************************************/
-static int
-__osm_pr_rcv_check_mcast_dest(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw )
-{
- const ib_path_rec_t* p_pr;
- const ib_sa_mad_t* p_sa_mad;
- ib_net64_t comp_mask;
- int is_multicast = 0;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_check_mcast_dest );
-
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
- comp_mask = p_sa_mad->comp_mask;
-
- if( comp_mask & IB_PR_COMPMASK_DGID )
- {
- is_multicast = ib_gid_is_multicast( &p_pr->dgid );
- if( !is_multicast )
- goto Exit;
- }
-
- if( comp_mask & IB_PR_COMPMASK_DLID )
- {
- if( cl_ntoh16( p_pr->dlid ) >= IB_LID_MCAST_START_HO &&
- cl_ntoh16( p_pr->dlid ) <= IB_LID_MCAST_END_HO )
- is_multicast = 1;
- else if( is_multicast )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_check_mcast_dest: ERR 1F12: "
- "PathRecord request indicates MGID but not MLID\n" );
- is_multicast = -1;
- }
- }
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
- return( is_multicast );
-}
-
-/**********************************************************************
- **********************************************************************/
-static void
-__osm_pr_rcv_respond(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw,
- IN cl_qlist_t* const p_list )
-{
- osm_madw_t* p_resp_madw;
- const ib_sa_mad_t* p_sa_mad;
- ib_sa_mad_t* p_resp_sa_mad;
- size_t num_rec, pre_trim_num_rec;
-#ifndef VENDOR_RMPP_SUPPORT
- size_t trim_num_rec;
-#endif
- ib_path_rec_t* p_resp_pr;
- ib_api_status_t status;
- const ib_sa_mad_t* p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw );
- osm_pr_item_t* p_pr_item;
- uint32_t i;
-
- OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_respond );
-
- num_rec = cl_qlist_count( p_list );
-
- /*
- * C15-0.1.30:
- * If we do a SubnAdmGet and got more than one record it is an error !
- */
- if (p_rcvd_mad->method == IB_MAD_METHOD_GET)
- {
- if (num_rec == 0)
- {
- osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );
- goto Exit;
- }
- if (num_rec > 1)
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_respond: ERR 1F13: "
- "Got more than one record for SubnAdmGet (%zu)\n",
- num_rec );
- osm_sa_send_error( p_rcv->p_resp, p_madw,
- IB_SA_MAD_STATUS_TOO_MANY_RECORDS );
- /* need to set the mem free ... */
- p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
- while( p_pr_item != (osm_pr_item_t*)cl_qlist_end( p_list ) )
- {
- cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
- p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
- }
- goto Exit;
- }
- }
-
- pre_trim_num_rec = num_rec;
-#ifndef VENDOR_RMPP_SUPPORT
- trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_path_rec_t);
- if (trim_num_rec < num_rec)
- {
- osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
- "__osm_pr_rcv_respond: "
- "Number of records:%u trimmed to:%u to fit in one MAD\n",
- num_rec,trim_num_rec );
- num_rec = trim_num_rec;
- }
-#endif
-
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "__osm_pr_rcv_respond: "
- "Generating response with %zu records\n", num_rec );
-
- if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0))
- {
- osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );
- goto Exit;
- }
-
- /*
- * Get a MAD to reply. Address of Mad is in the received mad_wrapper
- */
- p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, p_madw->h_bind,
- num_rec * sizeof(ib_path_rec_t) + IB_SA_MAD_HDR_SIZE,
- &p_madw->mad_addr );
- if( !p_resp_madw )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_respond: ERR 1F14: "
- "Unable to allocate MAD\n" );
-
- for( i = 0; i < num_rec; i++ )
- {
- p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
- cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
- }
-
- osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES );
- goto Exit;
- }
-
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_resp_madw );
-
- memcpy( p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE );
- p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
- /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
- p_resp_sa_mad->sm_key = 0;
- /* Fill in the offset (paylen will be done by the rmpp SAR) */
- p_resp_sa_mad->attr_offset = ib_get_attr_offset( sizeof(ib_path_rec_t) );
-
- p_resp_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad );
-
-#ifndef VENDOR_RMPP_SUPPORT
- /* we support only one packet RMPP - so we will set the first and
- last flags for gettable */
- if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
- {
- p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;
- p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST | IB_RMPP_FLAG_ACTIVE;
- }
-#else
- /* forcefully define the packet as RMPP one */
- if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)
- p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
-#endif
-
- for ( i = 0; i < pre_trim_num_rec; i++ )
- {
- p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );
- /* copy only if not trimmed */
- if (i < num_rec)
- *p_resp_pr = p_pr_item->path_rec;
-
- cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
- p_resp_pr++;
- }
-
- CL_ASSERT( cl_is_qlist_empty( p_list ) );
-
- status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE );
-
- if( status != IB_SUCCESS )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "__osm_pr_rcv_respond: ERR 1F15: "
- "Unable to send MAD (%s)\n", ib_get_err_str( status ) );
- /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */
- }
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
-/**********************************************************************
- **********************************************************************/
-void
-osm_pr_rcv_process(
- IN osm_pr_rcv_t* const p_rcv,
- IN const osm_madw_t* const p_madw )
-{
- const ib_path_rec_t* p_pr;
- const ib_sa_mad_t* p_sa_mad;
- const osm_port_t* p_src_port;
- const osm_port_t* p_dest_port;
- cl_qlist_t pr_list;
- ib_net16_t sa_status;
- osm_port_t* requester_port;
- int ret;
-
- OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_process );
-
- CL_ASSERT( p_madw );
-
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
-
- CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD );
-
- /* we only support SubnAdmGet and SubnAdmGetTable methods */
- if ((p_sa_mad->method != IB_MAD_METHOD_GET) &&
- (p_sa_mad->method != IB_MAD_METHOD_GETTABLE)) {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "osm_pr_rcv_process: ERR 1F17: "
- "Unsupported Method (%s)\n",
- ib_get_sa_method_str( p_sa_mad->method ) );
- osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR );
- goto Exit;
- }
-
- /* update the requester physical port. */
- requester_port = osm_get_port_by_mad_addr( p_rcv->p_log, p_rcv->p_subn,
- osm_madw_get_mad_addr_ptr( p_madw ) );
- if( requester_port == NULL )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "osm_pr_rcv_process: ERR 1F16: "
- "Cannot find requester physical port\n" );
- goto Exit;
- }
-
- if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
- osm_dump_path_record( p_rcv->p_log, p_pr, OSM_LOG_DEBUG );
-
- cl_qlist_init( &pr_list );
-
- /*
- Most SA functions (including this one) are read-only on the
- subnet object, so we grab the lock non-exclusively.
- */
- cl_plock_acquire( p_rcv->p_lock );
-
- /* Handle multicast destinations separately */
- if( (ret = __osm_pr_rcv_check_mcast_dest( p_rcv, p_madw )) < 0 )
- {
- /* Multicast DGID with unicast DLID */
- cl_plock_release( p_rcv->p_lock );
- osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_INVALID_FIELD );
- goto Exit;
- }
-
- if(ret > 0)
- goto McastDest;
-
- osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
- "osm_pr_rcv_process: "
- "Unicast destination requested\n" );
-
- sa_status = __osm_pr_rcv_get_end_points( p_rcv, p_madw,
- &p_src_port, &p_dest_port );
-
- if( sa_status == IB_SA_MAD_STATUS_SUCCESS )
- {
- /*
- What happens next depends on the type of endpoint information
- that was specified....
- */
- if( p_src_port )
- {
- if( p_dest_port )
- __osm_pr_rcv_process_pair( p_rcv, p_madw, requester_port,
- p_src_port, p_dest_port,
- p_sa_mad->comp_mask, &pr_list );
- else
- __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,
- p_src_port, NULL,
- p_sa_mad->comp_mask, &pr_list );
- }
- else
- {
- if( p_dest_port )
- __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,
- NULL, p_dest_port,
- p_sa_mad->comp_mask, &pr_list );
- else
- /*
- Katie, bar the door!
- */
- __osm_pr_rcv_process_world( p_rcv, p_madw, requester_port,
- p_sa_mad->comp_mask, &pr_list );
- }
- }
- goto Unlock;
-
- McastDest:
- osm_log(p_rcv->p_log, OSM_LOG_DEBUG,
- "osm_pr_rcv_process: "
- "Multicast destination requested\n" );
- {
- osm_mgrp_t *p_mgrp = NULL;
- ib_api_status_t status;
- osm_pr_item_t* p_pr_item;
- uint32_t flow_label;
- uint8_t sl;
- uint8_t hop_limit;
-
- /* First, get the MC info */
- __osm_pr_get_mgrp( p_rcv, p_madw, &p_mgrp );
-
- if ( p_mgrp )
- {
- /* Make sure the rest of the PathRecord matches the MC group attributes */
- status = __osm_pr_match_mgrp_attributes( p_rcv, p_madw, p_mgrp );
- if ( status == IB_SUCCESS )
- {
- p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );
- if( p_pr_item == NULL )
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "osm_pr_rcv_process: ERR 1F18: "
- "Unable to allocate path record for MC group\n" );
- }
- else
- {
- /* Copy PathRecord request into response */
- p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
- p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
- p_pr_item->path_rec = *p_pr;
-
- /* Now, use the MC info to cruft up the PathRecord response */
- p_pr_item->path_rec.dgid = p_mgrp->mcmember_rec.mgid;
- p_pr_item->path_rec.dlid = p_mgrp->mcmember_rec.mlid;
- p_pr_item->path_rec.tclass = p_mgrp->mcmember_rec.tclass;
- p_pr_item->path_rec.num_path = 1;
- p_pr_item->path_rec.pkey = p_mgrp->mcmember_rec.pkey;
-
- /* MTU, rate, and packet lifetime should be exactly */
- p_pr_item->path_rec.mtu = (2<<6) | p_mgrp->mcmember_rec.mtu;
- p_pr_item->path_rec.rate = (2<<6) | p_mgrp->mcmember_rec.rate;
- p_pr_item->path_rec.pkt_life = (2<<6) | p_mgrp->mcmember_rec.pkt_life;
-
- /* SL, Hop Limit, and Flow Label */
- ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,
- &sl, &flow_label, &hop_limit );
- p_pr_item->path_rec.sl = cl_hton16( sl );
- p_pr_item->path_rec.hop_flow_raw = (uint32_t)(hop_limit) |
- (flow_label << 8);
-
- cl_qlist_insert_tail( &pr_list,
- (cl_list_item_t*)&p_pr_item->pool_item );
-
- }
- }
- else
- {
- osm_log( p_rcv->p_log, OSM_LOG_ERROR,
- "osm_pr_rcv_process: ERR 1F19: "
- "MC group attributes don't match PathRecord request\n" );
- }
- }
- }
-
- Unlock:
- cl_plock_release( p_rcv->p_lock );
-
- /* Now, (finally) respond to the PathRecord request */
- __osm_pr_rcv_respond( p_rcv, p_madw, &pr_list );
-
- Exit:
- OSM_LOG_EXIT( p_rcv->p_log );
-}
-
+/*\r
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.\r
+ * Copyright (c) 2002-2006 Mellanox Technologies LTD. All rights reserved.\r
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.\r
+ *\r
+ * This software is available to you under the OpenIB.org BSD license\r
+ * below:\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials\r
+ * provided with the distribution.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
+ * SOFTWARE.\r
+ *\r
+ * $Id$\r
+ */\r
+\r
+\r
+/*\r
+ * Abstract:\r
+ * Implementation of osm_pr_rcv_t.\r
+ * This object represents the PathRecord Receiver object.\r
+ * This object is part of the opensm family of objects.\r
+ *\r
+ * Environment:\r
+ * Linux User Mode\r
+ *\r
+ * $Revision: 1.10 $\r
+ */\r
+\r
+#if HAVE_CONFIG_H\r
+# include <config.h>\r
+#endif /* HAVE_CONFIG_H */\r
+\r
+#include <string.h>\r
+#include <iba/ib_types.h>\r
+#include <complib/cl_qmap.h>\r
+#include <complib/cl_passivelock.h>\r
+#include <complib/cl_debug.h>\r
+#include <complib/cl_qlist.h>\r
+#include <opensm/osm_base.h>\r
+#include <opensm/osm_sa_path_record.h>\r
+#include <opensm/osm_port.h>\r
+#include <opensm/osm_node.h>\r
+#include <opensm/osm_switch.h>\r
+#include <vendor/osm_vendor.h>\r
+#include <vendor/osm_vendor_api.h>\r
+#include <opensm/osm_helper.h>\r
+#include <opensm/osm_pkey.h>\r
+#include <opensm/osm_multicast.h>\r
+#include <opensm/osm_partition.h>\r
+\r
+#define OSM_PR_RCV_POOL_MIN_SIZE 64\r
+#define OSM_PR_RCV_POOL_GROW_SIZE 64\r
+\r
+typedef struct _osm_pr_item\r
+{\r
+ cl_pool_item_t pool_item;\r
+ ib_path_rec_t path_rec;\r
+} osm_pr_item_t;\r
+\r
+typedef struct _osm_path_parms\r
+{\r
+ ib_net16_t pkey;\r
+ uint8_t mtu;\r
+ uint8_t rate;\r
+ uint8_t sl;\r
+ uint8_t pkt_life;\r
+ boolean_t reversible;\r
+} osm_path_parms_t;\r
+\r
+typedef struct osm_sa_pr_mcmr_search_ctxt {\r
+ ib_gid_t *p_mgid;\r
+ osm_mgrp_t *p_mgrp;\r
+ osm_pr_rcv_t *p_rcv;\r
+} osm_sa_pr_mcmr_search_ctxt_t;\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+void\r
+osm_pr_rcv_construct(\r
+ IN osm_pr_rcv_t* const p_rcv )\r
+{\r
+ memset( p_rcv, 0, sizeof(*p_rcv) );\r
+ cl_qlock_pool_construct( &p_rcv->pr_pool );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+void\r
+osm_pr_rcv_destroy(\r
+ IN osm_pr_rcv_t* const p_rcv )\r
+{\r
+ OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_destroy );\r
+ cl_qlock_pool_destroy( &p_rcv->pr_pool );\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+ib_api_status_t\r
+osm_pr_rcv_init(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN osm_sa_resp_t* const p_resp,\r
+ IN osm_mad_pool_t* const p_mad_pool,\r
+ IN osm_subn_t* const p_subn,\r
+ IN osm_log_t* const p_log,\r
+ IN cl_plock_t* const p_lock )\r
+{\r
+ ib_api_status_t status;\r
+\r
+ OSM_LOG_ENTER( p_log, osm_pr_rcv_init );\r
+\r
+ osm_pr_rcv_construct( p_rcv );\r
+\r
+ p_rcv->p_log = p_log;\r
+ p_rcv->p_subn = p_subn;\r
+ p_rcv->p_lock = p_lock;\r
+ p_rcv->p_resp = p_resp;\r
+ p_rcv->p_mad_pool = p_mad_pool;\r
+\r
+ status = cl_qlock_pool_init( &p_rcv->pr_pool,\r
+ OSM_PR_RCV_POOL_MIN_SIZE,\r
+ 0,\r
+ OSM_PR_RCV_POOL_GROW_SIZE,\r
+ sizeof(osm_pr_item_t),\r
+ NULL, NULL, NULL );\r
+\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+ return( status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static inline boolean_t\r
+__osm_sa_path_rec_is_tavor_port(\r
+ IN const osm_port_t* const p_port)\r
+{\r
+ osm_node_t const* p_node;\r
+ ib_net32_t vend_id;\r
+\r
+ p_node = osm_port_get_parent_node( p_port );\r
+ vend_id = ib_node_info_get_vendor_id( &p_node->node_info );\r
+ \r
+ return( (p_node->node_info.device_id == CL_HTON16(23108)) &&\r
+ ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) || \r
+ (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) || \r
+ (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) || \r
+ (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))) );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static boolean_t\r
+ __osm_sa_path_rec_apply_tavor_mtu_limit(\r
+ IN const ib_path_rec_t* const p_pr,\r
+ IN const osm_port_t* const p_src_port,\r
+ IN const osm_port_t* const p_dest_port,\r
+ IN const ib_net64_t comp_mask)\r
+{\r
+ uint8_t required_mtu;\r
+ \r
+ /* only if at least one of the ports is a Tavor device */\r
+ if (! __osm_sa_path_rec_is_tavor_port(p_src_port) && \r
+ ! __osm_sa_path_rec_is_tavor_port(p_dest_port) )\r
+ return( FALSE );\r
+\r
+ /*\r
+ we can apply the patch if either:\r
+ 1. No MTU required\r
+ 2. Required MTU < \r
+ 3. Required MTU = 1K or 512 or 256\r
+ 4. Required MTU > 256 or 512\r
+ */\r
+ required_mtu = ib_path_rec_mtu( p_pr );\r
+ if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&\r
+ ( comp_mask & IB_PR_COMPMASK_MTU ) )\r
+ {\r
+ switch( ib_path_rec_mtu_sel( p_pr ) )\r
+ {\r
+ case 0: /* must be greater than */\r
+ case 2: /* exact match */\r
+ if( IB_MTU_LEN_1024 < required_mtu )\r
+ return(FALSE);\r
+ break;\r
+\r
+ case 1: /* must be less than */\r
+ /* can't be disqualified by this one */\r
+ break;\r
+\r
+ case 3: /* largest available */\r
+ /* the ULP intentionally requested */\r
+ /* the largest MTU possible */\r
+ return(FALSE);\r
+ break;\r
+ \r
+ default:\r
+ /* if we're here, there's a bug in ib_path_rec_mtu_sel() */\r
+ CL_ASSERT( FALSE );\r
+ break;\r
+ }\r
+ }\r
+\r
+ return(TRUE);\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_api_status_t\r
+__osm_pr_rcv_get_path_parms(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const ib_path_rec_t* const p_pr,\r
+ IN const osm_port_t* const p_src_port,\r
+ IN const osm_port_t* const p_dest_port,\r
+ IN const uint16_t dest_lid_ho,\r
+ IN const ib_net64_t comp_mask,\r
+ OUT osm_path_parms_t* const p_parms )\r
+{\r
+ const osm_node_t* p_node;\r
+ const osm_physp_t* p_physp;\r
+ const osm_physp_t* p_dest_physp;\r
+ const osm_prtn_t* p_prtn;\r
+ const ib_port_info_t* p_pi;\r
+ ib_api_status_t status = IB_SUCCESS;\r
+ ib_net16_t pkey;\r
+ uint8_t mtu;\r
+ uint8_t rate;\r
+ uint8_t pkt_life;\r
+ uint8_t required_mtu;\r
+ uint8_t required_rate;\r
+ uint8_t required_pkt_life;\r
+ uint8_t sl;\r
+ ib_net16_t dest_lid;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_path_parms );\r
+\r
+ dest_lid = cl_hton16( dest_lid_ho );\r
+\r
+ p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );\r
+ p_physp = osm_port_get_default_phys_ptr( p_src_port );\r
+ p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+ mtu = ib_port_info_get_mtu_cap( p_pi );\r
+ rate = ib_port_info_compute_rate( p_pi );\r
+\r
+ /* \r
+ Mellanox Tavor device performance is better using 1K MTU.\r
+ If required MTU and MTU selector are such that 1K is OK \r
+ and at least one end of the path is Tavor we override the\r
+ port MTU with 1K.\r
+ */\r
+ if ( p_rcv->p_subn->opt.enable_quirks &&\r
+ __osm_sa_path_rec_apply_tavor_mtu_limit(\r
+ p_pr, p_src_port, p_dest_port, comp_mask) )\r
+ if (mtu > IB_MTU_LEN_1024) \r
+ {\r
+ mtu = IB_MTU_LEN_1024;\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "Optimized Path MTU to 1K for Mellanox Tavor device\n");\r
+ }\r
+\r
+ /*\r
+ Walk the subnet object from source to destination,\r
+ tracking the most restrictive rate and mtu values along the way...\r
+\r
+ If source port node is a switch, then p_physp should\r
+ point to the port that routes the destination lid\r
+ */\r
+\r
+ p_node = osm_physp_get_node_ptr( p_physp );\r
+\r
+ if( p_node->sw )\r
+ {\r
+ /*\r
+ * If the dest_lid_ho is equal to the lid of the switch pointed by\r
+ * p_sw then p_physp will be the physical port of the switch port zero.\r
+ */\r
+ p_physp = osm_switch_get_route_by_lid(p_node->sw, cl_ntoh16( dest_lid_ho ) );\r
+ if ( p_physp == 0 )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F02: "\r
+ "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",\r
+ dest_lid_ho,\r
+ cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+ status = IB_ERROR;\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Same as above\r
+ */\r
+ p_node = osm_physp_get_node_ptr( p_dest_physp );\r
+\r
+ if( p_node->sw )\r
+ {\r
+ p_dest_physp = osm_switch_get_route_by_lid( p_node->sw, cl_ntoh16( dest_lid_ho ) );\r
+\r
+ if ( p_dest_physp == 0 )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F03: "\r
+ "Cannot find routing to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",\r
+ dest_lid_ho,\r
+ cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+ status = IB_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ }\r
+\r
+ while( p_physp != p_dest_physp )\r
+ {\r
+ p_physp = osm_physp_get_remote( p_physp );\r
+\r
+ if ( p_physp == 0 )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F05: "\r
+ "Cannot find remote phys port when routing to LID 0x%X from node GUID 0x%016" PRIx64 "\n",\r
+ dest_lid_ho,\r
+ cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+ status = IB_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ /*\r
+ This is point to point case (no switch in between)\r
+ */\r
+ if( p_physp == p_dest_physp )\r
+ break;\r
+\r
+ p_node = osm_physp_get_node_ptr( p_physp );\r
+\r
+ if( !p_node->sw )\r
+ {\r
+ /*\r
+ There is some sort of problem in the subnet object!\r
+ If this isn't a switch, we should have reached\r
+ the destination by now!\r
+ */\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F06: "\r
+ "Internal error, bad path\n" );\r
+ status = IB_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ /*\r
+ Check parameters for the ingress port in this switch.\r
+ */\r
+ p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+ if( mtu > ib_port_info_get_mtu_cap( p_pi ) )\r
+ {\r
+ mtu = ib_port_info_get_mtu_cap( p_pi );\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "New smallest MTU = %u at intervening port 0x%016" PRIx64\r
+ " port num 0x%X\n",\r
+ mtu,\r
+ cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+ osm_physp_get_port_num( p_physp ) );\r
+ }\r
+ }\r
+\r
+ if( rate > ib_port_info_compute_rate( p_pi ) )\r
+ {\r
+ rate = ib_port_info_compute_rate( p_pi );\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "New smallest rate = %u at intervening port 0x%016" PRIx64\r
+ " port num 0x%X\n",\r
+ rate,\r
+ cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+ osm_physp_get_port_num( p_physp ) );\r
+ }\r
+ }\r
+\r
+ /*\r
+ Continue with the egress port on this switch.\r
+ */\r
+ p_physp = osm_switch_get_route_by_lid( p_node->sw, dest_lid );\r
+\r
+ if ( p_physp == 0 )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F07: "\r
+ "Dead end on path to LID 0x%X from switch for GUID 0x%016" PRIx64 "\n",\r
+ dest_lid_ho,\r
+ cl_ntoh64( osm_node_get_node_guid( p_node ) ) );\r
+ status = IB_ERROR;\r
+ goto Exit;\r
+ }\r
+\r
+ CL_ASSERT( p_physp );\r
+ CL_ASSERT( osm_physp_is_valid( p_physp ) );\r
+\r
+ p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+ if( mtu > ib_port_info_get_mtu_cap( p_pi ) )\r
+ {\r
+ mtu = ib_port_info_get_mtu_cap( p_pi );\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "New smallest MTU = %u at intervening port 0x%016" PRIx64\r
+ " port num 0x%X\n",\r
+ mtu,\r
+ cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+ osm_physp_get_port_num( p_physp ) );\r
+ }\r
+ }\r
+\r
+ if( rate > ib_port_info_compute_rate( p_pi ) )\r
+ {\r
+ rate = ib_port_info_compute_rate( p_pi );\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "New smallest rate = %u at intervening port 0x%016" PRIx64\r
+ " port num 0x%X\n",\r
+ rate,\r
+ cl_ntoh64( osm_physp_get_port_guid( p_physp ) ),\r
+ osm_physp_get_port_num( p_physp ) );\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ /*\r
+ p_physp now points to the destination\r
+ */\r
+ p_pi = osm_physp_get_port_info_ptr( p_physp );\r
+\r
+ if( mtu > ib_port_info_get_mtu_cap( p_pi ) )\r
+ {\r
+ mtu = ib_port_info_get_mtu_cap( p_pi );\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "New smallest MTU = %u at destination port 0x%016" PRIx64 "\n",\r
+ mtu,\r
+ cl_ntoh64(osm_physp_get_port_guid( p_physp )) );\r
+ }\r
+ }\r
+\r
+ if( rate > ib_port_info_compute_rate( p_pi ) )\r
+ {\r
+ rate = ib_port_info_compute_rate( p_pi );\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "New smallest rate = %u at destination port 0x%016" PRIx64 "\n",\r
+ rate,\r
+ cl_ntoh64(osm_physp_get_port_guid( p_physp )) );\r
+ }\r
+ }\r
+\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_path_parms: "\r
+ "Path min MTU = %u, min rate = %u\n", mtu, rate );\r
+ }\r
+\r
+ /*\r
+ Determine if these values meet the user criteria\r
+ and adjust appropriately\r
+ */\r
+\r
+ /* we silently ignore cases where only the MTU selector is defined */\r
+ if ( ( comp_mask & IB_PR_COMPMASK_MTUSELEC ) &&\r
+ ( comp_mask & IB_PR_COMPMASK_MTU ) )\r
+ {\r
+ required_mtu = ib_path_rec_mtu( p_pr );\r
+ switch( ib_path_rec_mtu_sel( p_pr ) )\r
+ {\r
+ case 0: /* must be greater than */\r
+ if( mtu <= required_mtu )\r
+ status = IB_NOT_FOUND;\r
+ break;\r
+\r
+ case 1: /* must be less than */\r
+ if( mtu >= required_mtu )\r
+ {\r
+ /* adjust to use the highest mtu\r
+ lower then the required one */\r
+ if( required_mtu > 1 )\r
+ mtu = required_mtu - 1;\r
+ else\r
+ status = IB_NOT_FOUND;\r
+ }\r
+ break;\r
+\r
+ case 2: /* exact match */\r
+ if( mtu < required_mtu )\r
+ status = IB_NOT_FOUND;\r
+ else\r
+ mtu = required_mtu;\r
+ break;\r
+\r
+ case 3: /* largest available */\r
+ /* can't be disqualified by this one */\r
+ break;\r
+\r
+ default:\r
+ /* if we're here, there's a bug in ib_path_rec_mtu_sel() */\r
+ CL_ASSERT( FALSE );\r
+ status = IB_ERROR;\r
+ break;\r
+ }\r
+ }\r
+\r
+ /* we silently ignore cases where only the Rate selector is defined */\r
+ if ( ( comp_mask & IB_PR_COMPMASK_RATESELEC ) &&\r
+ ( comp_mask & IB_PR_COMPMASK_RATE ) )\r
+ {\r
+ required_rate = ib_path_rec_rate( p_pr );\r
+ switch( ib_path_rec_rate_sel( p_pr ) )\r
+ {\r
+ case 0: /* must be greater than */\r
+ if( rate <= required_rate )\r
+ status = IB_NOT_FOUND;\r
+ break;\r
+\r
+ case 1: /* must be less than */\r
+ if( rate >= required_rate )\r
+ {\r
+ /* adjust the rate to use the highest rate\r
+ lower then the required one */\r
+ if( required_rate > 2 )\r
+ rate = required_rate - 1;\r
+ else\r
+ status = IB_NOT_FOUND;\r
+ }\r
+ break;\r
+\r
+ case 2: /* exact match */\r
+ if( rate < required_rate )\r
+ status = IB_NOT_FOUND;\r
+ else\r
+ rate = required_rate;\r
+ break;\r
+\r
+ case 3: /* largest available */\r
+ /* can't be disqualified by this one */\r
+ break;\r
+\r
+ default:\r
+ /* if we're here, there's a bug in ib_path_rec_mtu_sel() */\r
+ CL_ASSERT( FALSE );\r
+ status = IB_ERROR;\r
+ break;\r
+ }\r
+ }\r
+\r
+ /* Verify the pkt_life_time */\r
+ /* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,\r
+ for loopback paths, packetLifeTime shall be zero. */\r
+ if ( p_src_port == p_dest_port )\r
+ pkt_life = 0; /* loopback */\r
+ else\r
+ pkt_life = OSM_DEFAULT_SUBNET_TIMEOUT;\r
+\r
+ /* we silently ignore cases where only the PktLife selector is defined */\r
+ if ( ( comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC ) &&\r
+ ( comp_mask & IB_PR_COMPMASK_PKTLIFETIME ) )\r
+ {\r
+ required_pkt_life = ib_path_rec_pkt_life( p_pr );\r
+ switch( ib_path_rec_pkt_life_sel( p_pr ) )\r
+ {\r
+ case 0: /* must be greater than */\r
+ if( pkt_life <= required_pkt_life )\r
+ status = IB_NOT_FOUND;\r
+ break;\r
+\r
+ case 1: /* must be less than */\r
+ if( pkt_life >= required_pkt_life )\r
+ {\r
+ /* adjust the lifetime to use the highest possible\r
+ lower then the required one */\r
+ if( required_pkt_life > 1 )\r
+ pkt_life = required_pkt_life - 1;\r
+ else\r
+ status = IB_NOT_FOUND;\r
+ }\r
+ break;\r
+\r
+ case 2: /* exact match */\r
+ if( pkt_life < required_pkt_life )\r
+ status = IB_NOT_FOUND;\r
+ else\r
+ pkt_life = required_pkt_life;\r
+ break;\r
+\r
+ case 3: /* smallest available */\r
+ /* can't be disqualified by this one */\r
+ break;\r
+\r
+ default:\r
+ /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */\r
+ CL_ASSERT( FALSE );\r
+ status = IB_ERROR;\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (status != IB_SUCCESS)\r
+ goto Exit;\r
+\r
+ p_parms->mtu = mtu;\r
+ p_parms->rate = rate;\r
+ p_parms->pkt_life = pkt_life;\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&\r
+ cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )\r
+ pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );\r
+ else if( comp_mask & IB_PR_COMPMASK_PKEY )\r
+ {\r
+ pkey = p_pr->pkey;\r
+ if( !osm_physp_share_this_pkey( p_physp, p_dest_physp, pkey ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F1A: "\r
+ "Ports do not share specified PKey 0x%04x\n", cl_ntoh16(pkey));\r
+ status = IB_NOT_FOUND;\r
+ goto Exit;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ pkey = osm_physp_find_common_pkey( p_physp, p_dest_physp );\r
+ if ( !pkey )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F1B: "\r
+ "Ports do not have any shared PKeys\n");\r
+ status = IB_NOT_FOUND;\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ sl = OSM_DEFAULT_SL;\r
+\r
+ if (pkey) {\r
+ p_prtn = (osm_prtn_t *)cl_qmap_get(&p_rcv->p_subn->prtn_pkey_tbl,\r
+ pkey & cl_ntoh16((uint16_t)~0x8000));\r
+ if ( p_prtn == (osm_prtn_t *)cl_qmap_end(&p_rcv->p_subn->prtn_pkey_tbl) )\r
+ {\r
+ /* this may be possible when pkey tables are created somehow in\r
+ previous runs or things are going wrong here */\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_path_parms: ERR 1F1C: "\r
+ "No partition found for PKey 0x%04x - using default SL %d\n",\r
+ cl_ntoh16(pkey), sl );\r
+ }\r
+ else\r
+ sl = p_prtn->sl;\r
+\r
+ /* reset pkey when raw traffic */\r
+ if( comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&\r
+ cl_ntoh32( p_pr->hop_flow_raw ) & ( 1<<31 ) )\r
+ pkey = 0;\r
+ }\r
+\r
+ if ( ( comp_mask & IB_PR_COMPMASK_SL ) && ib_path_rec_sl( p_pr ) != sl )\r
+ {\r
+ status = IB_NOT_FOUND;\r
+ goto Exit;\r
+ }\r
+\r
+ p_parms->pkey = pkey;\r
+ p_parms->sl = sl;\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+ return( status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_build_pr(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_port_t* const p_src_port,\r
+ IN const osm_port_t* const p_dest_port,\r
+ IN const uint16_t src_lid_ho,\r
+ IN const uint16_t dest_lid_ho,\r
+ IN const uint8_t preference,\r
+ IN const osm_path_parms_t* const p_parms,\r
+ OUT ib_path_rec_t* const p_pr )\r
+{\r
+ const osm_physp_t* p_src_physp;\r
+ const osm_physp_t* p_dest_physp;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_build_pr );\r
+\r
+ p_src_physp = osm_port_get_default_phys_ptr( p_src_port );\r
+ p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );\r
+\r
+ p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix( p_dest_physp );\r
+ p_pr->dgid.unicast.interface_id = osm_physp_get_port_guid( p_dest_physp );\r
+\r
+ p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix( p_src_physp );\r
+ p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid( p_src_physp );\r
+\r
+ p_pr->dlid = cl_hton16( dest_lid_ho );\r
+ p_pr->slid = cl_hton16( src_lid_ho );\r
+\r
+ p_pr->hop_flow_raw &= cl_hton32(1<<31);\r
+\r
+ p_pr->pkey = p_parms->pkey;\r
+ p_pr->qos_class_sl = cl_hton16(p_parms->sl);\r
+ p_pr->mtu = (uint8_t)(p_parms->mtu | 0x80);\r
+ p_pr->rate = (uint8_t)(p_parms->rate | 0x80);\r
+\r
+ /* According to 1.2 spec definition Table 205 PacketLifeTime description,\r
+ for loopback paths, packetLifeTime shall be zero. */\r
+ if ( p_src_port == p_dest_port )\r
+ p_pr->pkt_life = 0x80; /* loopback */\r
+ else\r
+ p_pr->pkt_life = (uint8_t)(p_parms->pkt_life | 0x80);\r
+\r
+ p_pr->preference = preference;\r
+\r
+ /* always return num_path = 0 so this is only the reversible component */\r
+ if (p_parms->reversible)\r
+ p_pr->num_path = 0x80;\r
+\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static osm_pr_item_t*\r
+__osm_pr_rcv_get_lid_pair_path(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const ib_path_rec_t* const p_pr,\r
+ IN const osm_port_t* const p_src_port,\r
+ IN const osm_port_t* const p_dest_port,\r
+ IN const uint16_t src_lid_ho,\r
+ IN const uint16_t dest_lid_ho,\r
+ IN const ib_net64_t comp_mask,\r
+ IN const uint8_t preference )\r
+{\r
+ osm_path_parms_t path_parms;\r
+ osm_path_parms_t rev_path_parms;\r
+ osm_pr_item_t *p_pr_item;\r
+ ib_api_status_t status, rev_path_status;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_lid_pair_path );\r
+\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_lid_pair_path: "\r
+ "Src LID 0x%X, Dest LID 0x%X\n",\r
+ src_lid_ho, dest_lid_ho );\r
+ }\r
+\r
+ p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );\r
+ if( p_pr_item == NULL )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_lid_pair_path: ERR 1F01: "\r
+ "Unable to allocate path record\n" );\r
+ goto Exit;\r
+ }\r
+\r
+ status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_src_port,\r
+ p_dest_port, dest_lid_ho,\r
+ comp_mask, &path_parms );\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+ p_pr_item = NULL;\r
+ goto Exit;\r
+ }\r
+\r
+ /* now try the reversible path */\r
+ rev_path_status = __osm_pr_rcv_get_path_parms( p_rcv, p_pr, p_dest_port,\r
+ p_src_port, src_lid_ho,\r
+ comp_mask, &rev_path_parms );\r
+ path_parms.reversible = ( rev_path_status == IB_SUCCESS );\r
+\r
+ /* did we get a Reversible Path compmask ? */\r
+ /* \r
+ NOTE that if the reversible component = 0, it is a don't care\r
+ rather then requiring non-reversible paths ... \r
+ see Vol1 Ver1.2 p900 l16\r
+ */\r
+ if( comp_mask & IB_PR_COMPMASK_REVERSIBLE )\r
+ {\r
+ if( (! path_parms.reversible && ( p_pr->num_path & 0x80 ) ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_lid_pair_path: "\r
+ "Requested reversible path but failed to get one\n");\r
+\r
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+ p_pr_item = NULL;\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ __osm_pr_rcv_build_pr( p_rcv, p_src_port, p_dest_port, src_lid_ho,\r
+ dest_lid_ho, preference, &path_parms,\r
+ &p_pr_item->path_rec );\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+ return( p_pr_item );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_get_port_pair_paths(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ IN const osm_port_t* const p_req_port,\r
+ IN const osm_port_t* const p_src_port,\r
+ IN const osm_port_t* const p_dest_port,\r
+ IN const ib_net64_t comp_mask,\r
+ IN cl_qlist_t* const p_list )\r
+{\r
+ const ib_path_rec_t* p_pr;\r
+ const ib_sa_mad_t* p_sa_mad;\r
+ osm_pr_item_t* p_pr_item;\r
+ uint16_t src_lid_min_ho;\r
+ uint16_t src_lid_max_ho;\r
+ uint16_t dest_lid_min_ho;\r
+ uint16_t dest_lid_max_ho;\r
+ uint16_t src_lid_ho;\r
+ uint16_t dest_lid_ho;\r
+ uint32_t path_num;\r
+ uint8_t preference;\r
+ uintn_t iterations;\r
+ uintn_t src_offset;\r
+ uintn_t dest_offset;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_port_pair_paths );\r
+\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_port_pair_paths: "\r
+ "Src port 0x%016" PRIx64 ", "\r
+ "Dst port 0x%016" PRIx64 "\n",\r
+ cl_ntoh64( osm_port_get_guid( p_src_port ) ),\r
+ cl_ntoh64( osm_port_get_guid( p_dest_port ) ) );\r
+ }\r
+\r
+ /* Check that the req_port, src_port and dest_port all share a\r
+ pkey. The check is done on the default physical port of the ports. */\r
+ if (osm_port_share_pkey(p_rcv->p_log, p_req_port, p_src_port) == FALSE ||\r
+ osm_port_share_pkey(p_rcv->p_log, p_req_port, p_dest_port) == FALSE ||\r
+ osm_port_share_pkey(p_rcv->p_log, p_src_port, p_dest_port) == FALSE )\r
+ {\r
+ /* One of the pairs doesn't share a pkey so the path is disqualified. */\r
+ goto Exit;\r
+ }\r
+\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+ /*\r
+ We shouldn't be here if the paths are disqualified in some way...\r
+ Thus, we assume every possible connection is valid.\r
+\r
+ We desire to return high-quality paths first.\r
+ In OpenSM, higher quality means least overlap with other paths.\r
+ This is acheived in practice by returning paths with\r
+ different LID value on each end, which means these\r
+ paths are more redundant that paths with the same LID repeated\r
+ on one side. For example, in OpenSM the paths between two\r
+ endpoints with LMC = 1 might be as follows:\r
+\r
+ Port A, LID 1 <-> Port B, LID 3\r
+ Port A, LID 1 <-> Port B, LID 4\r
+ Port A, LID 2 <-> Port B, LID 3\r
+ Port A, LID 2 <-> Port B, LID 4\r
+\r
+ The OpenSM unicast routing algorithms attempt to disperse each path\r
+ to as varied a physical path as is reasonable. 1<->3 and 1<->4 have\r
+ more physical overlap (hence less redundancy) than 1<->3 and 2<->4.\r
+\r
+ OpenSM ranks paths in three preference groups:\r
+\r
+ Preference Value Description\r
+ ---------------- -------------------------------------------\r
+ 0 Redundant in both directions with other\r
+ pref value = 0 paths\r
+\r
+ 1 Redundant in one direction with other\r
+ pref value = 0 and pref value = 1 paths\r
+\r
+ 2 Not redundant in either direction with\r
+ other paths\r
+\r
+ 3-FF Unused\r
+\r
+\r
+ SA clients don't need to know these details, only that the lower\r
+ preference paths are preferred, as stated in the spec. The paths\r
+ may not actually be physically redundant depending on the topology\r
+ of the subnet, but the point of LMC > 0 is to offer redundancy,\r
+ so it is assumed that the subnet is physically appropriate for the\r
+ specified LMC value. A more advanced implementation would inspect for \r
+ physical redundancy, but I'm not going to bother with that now.\r
+ */\r
+\r
+ /*\r
+ Refine our search if the client specified end-point LIDs\r
+ */\r
+ if( comp_mask & IB_PR_COMPMASK_DLID )\r
+ {\r
+ dest_lid_min_ho = cl_ntoh16( p_pr->dlid );\r
+ dest_lid_max_ho = cl_ntoh16( p_pr->dlid );\r
+ }\r
+ else\r
+ {\r
+ osm_port_get_lid_range_ho( p_dest_port, &dest_lid_min_ho,\r
+ &dest_lid_max_ho );\r
+ }\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_SLID )\r
+ {\r
+ src_lid_min_ho = cl_ntoh16( p_pr->slid );\r
+ src_lid_max_ho = cl_ntoh16( p_pr->slid );\r
+ }\r
+ else\r
+ {\r
+ osm_port_get_lid_range_ho( p_src_port, &src_lid_min_ho,\r
+ &src_lid_max_ho );\r
+ }\r
+\r
+ if ( src_lid_min_ho == 0 )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_port_pair_paths: ERR 1F20:"\r
+ "Obtained source LID of 0. No such LID possible\n");\r
+ goto Exit;\r
+ }\r
+\r
+ if ( dest_lid_min_ho == 0 )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_get_port_pair_paths: ERR 1F21:"\r
+ "Obtained destination LID of 0. No such LID possible\n");\r
+ goto Exit;\r
+ }\r
+\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_get_port_pair_paths: "\r
+ "Src LIDs [0x%X-0x%X], "\r
+ "Dest LIDs [0x%X-0x%X]\n",\r
+ src_lid_min_ho, src_lid_max_ho,\r
+ dest_lid_min_ho, dest_lid_max_ho );\r
+ }\r
+\r
+ src_lid_ho = src_lid_min_ho;\r
+ dest_lid_ho = dest_lid_min_ho;\r
+\r
+ /*\r
+ Preferred paths come first in OpenSM\r
+ */\r
+ preference = 0;\r
+ path_num = 0;\r
+\r
+ /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */\r
+ if( p_sa_mad->method != IB_MAD_METHOD_GET )\r
+ if( comp_mask & IB_PR_COMPMASK_NUMBPATH )\r
+ iterations = ib_path_rec_num_path( p_pr );\r
+ else\r
+ iterations = (uintn_t)(-1);\r
+ else\r
+ iterations = 1;\r
+\r
+ while( path_num < iterations )\r
+ {\r
+ /*\r
+ These paths are "fully redundant"\r
+ */\r
+\r
+ p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,\r
+ p_src_port, p_dest_port,\r
+ src_lid_ho, dest_lid_ho,\r
+ comp_mask, preference );\r
+\r
+ if( p_pr_item )\r
+ {\r
+ cl_qlist_insert_tail( p_list,\r
+ (cl_list_item_t*)&p_pr_item->pool_item );\r
+ ++path_num;\r
+ }\r
+\r
+ if( ++src_lid_ho > src_lid_max_ho )\r
+ break;\r
+\r
+ if( ++dest_lid_ho > dest_lid_max_ho )\r
+ break;\r
+ }\r
+\r
+ /*\r
+ Check if we've accumulated all the paths that the user cares to see\r
+ */\r
+ if( path_num == iterations )\r
+ goto Exit;\r
+\r
+ /*\r
+ Don't bother reporting preference 1 paths for now.\r
+ It's more trouble than it's worth and can only occur\r
+ if ports have different LMC values, which isn't supported\r
+ by OpenSM right now anyway.\r
+ */\r
+ preference = 2;\r
+ src_lid_ho = src_lid_min_ho;\r
+ dest_lid_ho = dest_lid_min_ho;\r
+ src_offset = 0;\r
+ dest_offset = 0;\r
+\r
+ /*\r
+ Iterate over the remaining paths\r
+ */\r
+ while( path_num < iterations )\r
+ {\r
+ dest_offset++;\r
+ dest_lid_ho++;\r
+\r
+ if( dest_lid_ho > dest_lid_max_ho )\r
+ {\r
+ src_offset++;\r
+ src_lid_ho++;\r
+\r
+ if( src_lid_ho > src_lid_max_ho )\r
+ break; /* done */\r
+\r
+ dest_offset = 0;\r
+ dest_lid_ho = dest_lid_min_ho;\r
+ }\r
+\r
+ /*\r
+ These paths are "fully non-redundant" with paths already\r
+ identified above and consequently not of much value.\r
+\r
+ Don't return paths we already identified above, as indicated\r
+ by the offset values being equal.\r
+ */\r
+ if( src_offset == dest_offset )\r
+ continue; /* already reported */\r
+\r
+ p_pr_item = __osm_pr_rcv_get_lid_pair_path( p_rcv, p_pr,\r
+ p_src_port, p_dest_port,\r
+ src_lid_ho, dest_lid_ho,\r
+ comp_mask, preference );\r
+\r
+ if( p_pr_item )\r
+ {\r
+ cl_qlist_insert_tail( p_list,\r
+ (cl_list_item_t*)&p_pr_item->pool_item );\r
+ ++path_num;\r
+ }\r
+ }\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_net16_t\r
+__osm_pr_rcv_get_end_points(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ OUT const osm_port_t** const pp_src_port,\r
+ OUT const osm_port_t** const pp_dest_port )\r
+{\r
+ const ib_path_rec_t* p_pr;\r
+ const ib_sa_mad_t* p_sa_mad;\r
+ ib_net64_t comp_mask;\r
+ ib_api_status_t status;\r
+ ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_get_end_points );\r
+\r
+ /*\r
+ Determine what fields are valid and then get a pointer\r
+ to the source and destination port objects, if possible.\r
+ */\r
+\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+ comp_mask = p_sa_mad->comp_mask;\r
+\r
+ /*\r
+ Check a few easy disqualifying cases up front before getting\r
+ into the endpoints.\r
+ */\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_SGID )\r
+ {\r
+ if ( ! ib_gid_is_link_local ( &p_pr->sgid ) )\r
+ {\r
+ if ( ib_gid_get_subnet_prefix ( &p_pr->sgid ) != p_rcv->p_subn->opt.subnet_prefix )\r
+ {\r
+ /*\r
+ This 'error' is the client's fault (bad gid) so\r
+ don't enter it as an error in our own log.\r
+ Return an error response to the client.\r
+ */\r
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+ "__osm_pr_rcv_get_end_points: "\r
+ "Non local SGID subnet prefix 0x%016" PRIx64 "\n",\r
+ cl_ntoh64( p_pr->sgid.unicast.prefix ) );\r
+\r
+ sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ *pp_src_port = (osm_port_t*)cl_qmap_get(\r
+ &p_rcv->p_subn->port_guid_tbl,\r
+ p_pr->sgid.unicast.interface_id );\r
+\r
+ if( *pp_src_port == (osm_port_t*)cl_qmap_end(\r
+ &p_rcv->p_subn->port_guid_tbl ) )\r
+ {\r
+ /*\r
+ This 'error' is the client's fault (bad gid) so\r
+ don't enter it as an error in our own log.\r
+ Return an error response to the client.\r
+ */\r
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+ "__osm_pr_rcv_get_end_points: "\r
+ "No source port with GUID 0x%016" PRIx64 "\n",\r
+ cl_ntoh64( p_pr->sgid.unicast.interface_id) );\r
+\r
+ sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+ goto Exit;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ *pp_src_port = 0;\r
+ if( comp_mask & IB_PR_COMPMASK_SLID )\r
+ {\r
+ status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,\r
+ cl_ntoh16(p_pr->slid), (void**)pp_src_port );\r
+\r
+ if( (status != CL_SUCCESS) || (*pp_src_port == NULL) )\r
+ {\r
+ /*\r
+ This 'error' is the client's fault (bad lid) so\r
+ don't enter it as an error in our own log.\r
+ Return an error response to the client.\r
+ */\r
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+ "__osm_pr_rcv_get_end_points: "\r
+ "No source port with LID = 0x%X\n",\r
+ cl_ntoh16( p_pr->slid) );\r
+\r
+ sa_status = IB_SA_MAD_STATUS_NO_RECORDS;\r
+ goto Exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_DGID )\r
+ {\r
+ if ( ! ib_gid_is_link_local ( &p_pr->dgid ) )\r
+ {\r
+ if ( ! ib_gid_is_multicast ( &p_pr->dgid ) &&\r
+ ib_gid_get_subnet_prefix ( &p_pr->dgid ) != p_rcv->p_subn->opt.subnet_prefix )\r
+ {\r
+ /*\r
+ This 'error' is the client's fault (bad gid) so\r
+ don't enter it as an error in our own log.\r
+ Return an error response to the client.\r
+ */\r
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+ "__osm_pr_rcv_get_end_points: "\r
+ "Non local DGID subnet prefix 0x%016" PRIx64 "\n",\r
+ cl_ntoh64( p_pr->dgid.unicast.prefix ) );\r
+\r
+ sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ *pp_dest_port = (osm_port_t*)cl_qmap_get(\r
+ &p_rcv->p_subn->port_guid_tbl,\r
+ p_pr->dgid.unicast.interface_id );\r
+\r
+ if( *pp_dest_port == (osm_port_t*)cl_qmap_end(\r
+ &p_rcv->p_subn->port_guid_tbl ) )\r
+ {\r
+ /*\r
+ This 'error' is the client's fault (bad gid) so\r
+ don't enter it as an error in our own log.\r
+ Return an error response to the client.\r
+ */\r
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+ "__osm_pr_rcv_get_end_points: "\r
+ "No dest port with GUID 0x%016" PRIx64 "\n",\r
+ cl_ntoh64( p_pr->dgid.unicast.interface_id) );\r
+\r
+ sa_status = IB_SA_MAD_STATUS_INVALID_GID;\r
+ goto Exit;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ *pp_dest_port = 0;\r
+ if( comp_mask & IB_PR_COMPMASK_DLID )\r
+ {\r
+ status = cl_ptr_vector_at( &p_rcv->p_subn->port_lid_tbl,\r
+ cl_ntoh16(p_pr->dlid), (void**)pp_dest_port );\r
+\r
+ if( (status != CL_SUCCESS) || (*pp_dest_port == NULL) )\r
+ {\r
+ /*\r
+ This 'error' is the client's fault (bad lid) so\r
+ don't enter it as an error in our own log.\r
+ Return an error response to the client.\r
+ */\r
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+ "__osm_pr_rcv_get_end_points: "\r
+ "No dest port with LID = 0x%X\n",\r
+ cl_ntoh16( p_pr->dlid) );\r
+\r
+ sa_status = IB_SA_MAD_STATUS_NO_RECORDS;\r
+ goto Exit;\r
+ }\r
+ }\r
+ }\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+ return( sa_status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_process_world(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ IN const osm_port_t* const requester_port,\r
+ IN const ib_net64_t comp_mask,\r
+ IN cl_qlist_t* const p_list )\r
+{\r
+ const cl_qmap_t* p_tbl;\r
+ const osm_port_t* p_dest_port;\r
+ const osm_port_t* p_src_port;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_world );\r
+\r
+ /*\r
+ Iterate the entire port space over itself.\r
+ A path record from a port to itself is legit, so no\r
+ need for a special case there.\r
+\r
+ We compute both A -> B and B -> A, since we don't have\r
+ any check to determine the reversability of the paths.\r
+ */\r
+ p_tbl = &p_rcv->p_subn->port_guid_tbl;\r
+\r
+ p_dest_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+ while( p_dest_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+ {\r
+ p_src_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+ while( p_src_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+ {\r
+ __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,\r
+ p_dest_port, comp_mask, p_list );\r
+\r
+ p_src_port = (osm_port_t*)cl_qmap_next( &p_src_port->map_item );\r
+ }\r
+\r
+ p_dest_port = (osm_port_t*)cl_qmap_next( &p_dest_port->map_item );\r
+ }\r
+\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_process_half(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ IN const osm_port_t* const requester_port,\r
+ IN const osm_port_t* const p_src_port,\r
+ IN const osm_port_t* const p_dest_port,\r
+ IN const ib_net64_t comp_mask,\r
+ IN cl_qlist_t* const p_list )\r
+{\r
+ const cl_qmap_t* p_tbl;\r
+ const osm_port_t* p_port;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_half );\r
+\r
+ /*\r
+ Iterate over every port, looking for matches...\r
+ A path record from a port to itself is legit, so no\r
+ need to special case that one.\r
+ */\r
+ p_tbl = &p_rcv->p_subn->port_guid_tbl;\r
+\r
+ if( p_src_port )\r
+ {\r
+ /*\r
+ The src port if fixed, so iterate over destination ports.\r
+ */\r
+ p_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+ while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+ {\r
+ __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw , requester_port, p_src_port,\r
+ p_port, comp_mask, p_list );\r
+ p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ The dest port if fixed, so iterate over source ports.\r
+ */\r
+ p_port = (osm_port_t*)cl_qmap_head( p_tbl );\r
+ while( p_port != (osm_port_t*)cl_qmap_end( p_tbl ) )\r
+ {\r
+ __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_port,\r
+ p_dest_port, comp_mask, p_list );\r
+ p_port = (osm_port_t*)cl_qmap_next( &p_port->map_item );\r
+ }\r
+ }\r
+\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_process_pair(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ IN const osm_port_t* const requester_port,\r
+ IN const osm_port_t* const p_src_port,\r
+ IN const osm_port_t* const p_dest_port,\r
+ IN const ib_net64_t comp_mask,\r
+ IN cl_qlist_t* const p_list )\r
+{\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_process_pair );\r
+\r
+ __osm_pr_rcv_get_port_pair_paths( p_rcv, p_madw, requester_port, p_src_port,\r
+ p_dest_port, comp_mask, p_list );\r
+\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ *********************************************************************/\r
+static void\r
+__search_mgrp_by_mgid(\r
+ IN cl_map_item_t* const p_map_item,\r
+ IN void* context )\r
+{\r
+ osm_mgrp_t* p_mgrp = (osm_mgrp_t*)p_map_item;\r
+ osm_sa_pr_mcmr_search_ctxt_t *p_ctxt = (osm_sa_pr_mcmr_search_ctxt_t *) context;\r
+ const ib_gid_t *p_recvd_mgid;\r
+ osm_pr_rcv_t *p_rcv;\r
+ /* uint32_t i; */\r
+\r
+ p_recvd_mgid = p_ctxt->p_mgid;\r
+ p_rcv = p_ctxt->p_rcv;\r
+\r
+ /* ignore groups marked for deletion */\r
+ if ( p_mgrp->to_be_deleted )\r
+ return;\r
+\r
+ /* compare entire MGID so different scope will not sneak in for\r
+ the same MGID */\r
+ if ( memcmp( &p_mgrp->mcmember_rec.mgid,\r
+ p_recvd_mgid,\r
+ sizeof(ib_gid_t) ) )\r
+ return;\r
+\r
+#if 0\r
+ for ( i = 0 ; i < sizeof(p_mgrp->mcmember_rec.mgid.multicast.raw_group_id); i++)\r
+ {\r
+ if ( p_mgrp->mcmember_rec.mgid.multicast.raw_group_id[i] !=\r
+ p_recvd_mgid->mgid.multicast.raw_group_id[i] )\r
+ return;\r
+ }\r
+#endif\r
+\r
+ if( p_ctxt->p_mgrp )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__search_mgrp_by_mgid: ERR 1F08: "\r
+ "Multiple MC groups for same MGID\n" );\r
+ return;\r
+ }\r
+ p_ctxt->p_mgrp = p_mgrp;\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_api_status_t\r
+__get_mgrp_by_mgid(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN ib_path_rec_t* p_recvd_path_rec,\r
+ OUT osm_mgrp_t ** pp_mgrp )\r
+{\r
+ osm_sa_pr_mcmr_search_ctxt_t mcmr_search_context;\r
+\r
+ mcmr_search_context.p_mgid = &p_recvd_path_rec->dgid;\r
+ mcmr_search_context.p_rcv = p_rcv;\r
+ mcmr_search_context.p_mgrp = NULL;\r
+\r
+ cl_qmap_apply_func( &p_rcv->p_subn->mgrp_mlid_tbl,\r
+ __search_mgrp_by_mgid,\r
+ &mcmr_search_context);\r
+\r
+ if( mcmr_search_context.p_mgrp == NULL )\r
+ {\r
+ return IB_NOT_FOUND;\r
+ }\r
+\r
+ *pp_mgrp = mcmr_search_context.p_mgrp;\r
+ return IB_SUCCESS;\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static osm_mgrp_t *\r
+__get_mgrp_by_mlid(\r
+ IN const osm_pr_rcv_t* const p_rcv,\r
+ IN ib_net16_t const mlid )\r
+{\r
+ cl_map_item_t * map_item;\r
+\r
+ map_item = cl_qmap_get( &p_rcv->p_subn->mgrp_mlid_tbl, mlid );\r
+\r
+ if( map_item == cl_qmap_end(&p_rcv->p_subn->mgrp_mlid_tbl) )\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ return (osm_mgrp_t *)map_item;\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_get_mgrp(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ OUT osm_mgrp_t **pp_mgrp )\r
+{\r
+ ib_path_rec_t* p_pr;\r
+ const ib_sa_mad_t* p_sa_mad;\r
+ ib_net64_t comp_mask;\r
+ ib_api_status_t status;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_get_mgrp );\r
+\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+ comp_mask = p_sa_mad->comp_mask;\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_DGID )\r
+ {\r
+ status = __get_mgrp_by_mgid( p_rcv, p_pr, pp_mgrp );\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_get_mgrp: ERR 1F09: "\r
+ "No MC group found for PathRecord destination GID\n" );\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_DLID )\r
+ {\r
+ if( *pp_mgrp)\r
+ {\r
+ /* check that the MLID in the MC group is */\r
+ /* the same as the DLID in the PathRecord */\r
+ if( (*pp_mgrp)->mlid != p_pr->dlid )\r
+ {\r
+ /* Note: perhaps this might be better indicated as an invalid request */\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_get_mgrp: ERR 1F10: "\r
+ "MC group MLID does not match PathRecord destination LID\n" );\r
+ *pp_mgrp = NULL;\r
+ goto Exit;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ *pp_mgrp = __get_mgrp_by_mlid( p_rcv, p_pr->dlid );\r
+ if( *pp_mgrp == NULL)\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_get_mgrp: ERR 1F11: "\r
+ "No MC group found for PathRecord destination LID\n" );\r
+ }\r
+ }\r
+ }\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static ib_api_status_t\r
+__osm_pr_match_mgrp_attributes(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ IN const osm_mgrp_t* const p_mgrp )\r
+{\r
+ const ib_path_rec_t* p_pr;\r
+ const ib_sa_mad_t* p_sa_mad;\r
+ ib_net64_t comp_mask;\r
+ ib_api_status_t status = IB_ERROR;\r
+ uint32_t flow_label;\r
+ uint8_t sl;\r
+ uint8_t hop_limit;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_match_mgrp_attributes );\r
+\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+ comp_mask = p_sa_mad->comp_mask;\r
+\r
+ /* If SGID and/or SLID specified, should validate as member of MC group */\r
+ /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */\r
+ if( comp_mask & IB_PR_COMPMASK_PKEY )\r
+ {\r
+ if( p_pr->pkey != p_mgrp->mcmember_rec.pkey )\r
+ goto Exit;\r
+ }\r
+\r
+ ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,\r
+ &sl, &flow_label, &hop_limit );\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_SL )\r
+ {\r
+ if( ib_path_rec_sl( p_pr ) != sl )\r
+ goto Exit;\r
+ }\r
+\r
+ /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */\r
+ if( ( comp_mask & IB_PR_COMPMASK_NUMBPATH ) &&\r
+ ( p_sa_mad->method != IB_MAD_METHOD_GET ) )\r
+ {\r
+ if( ib_path_rec_num_path( p_pr ) == 0 )\r
+ goto Exit;\r
+ }\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_FLOWLABEL )\r
+ {\r
+ if( ib_path_rec_flow_lbl( p_pr ) != flow_label )\r
+ goto Exit;\r
+ }\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_HOPLIMIT )\r
+ {\r
+ if( ib_path_rec_hop_limit( p_pr ) != hop_limit )\r
+ goto Exit;\r
+ }\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_TCLASS )\r
+ {\r
+ if( p_pr->tclass != p_mgrp->mcmember_rec.tclass )\r
+ goto Exit;\r
+ }\r
+\r
+ status = IB_SUCCESS;\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+ return( status );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static int\r
+__osm_pr_rcv_check_mcast_dest(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw )\r
+{\r
+ const ib_path_rec_t* p_pr;\r
+ const ib_sa_mad_t* p_sa_mad;\r
+ ib_net64_t comp_mask;\r
+ int is_multicast = 0;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_check_mcast_dest );\r
+\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+ comp_mask = p_sa_mad->comp_mask;\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_DGID )\r
+ {\r
+ is_multicast = ib_gid_is_multicast( &p_pr->dgid );\r
+ if( !is_multicast )\r
+ goto Exit;\r
+ }\r
+\r
+ if( comp_mask & IB_PR_COMPMASK_DLID )\r
+ {\r
+ if( cl_ntoh16( p_pr->dlid ) >= IB_LID_MCAST_START_HO &&\r
+ cl_ntoh16( p_pr->dlid ) <= IB_LID_MCAST_END_HO )\r
+ is_multicast = 1;\r
+ else if( is_multicast )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_check_mcast_dest: ERR 1F12: "\r
+ "PathRecord request indicates MGID but not MLID\n" );\r
+ is_multicast = -1;\r
+ }\r
+ }\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+ return( is_multicast );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+static void\r
+__osm_pr_rcv_respond(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw,\r
+ IN cl_qlist_t* const p_list )\r
+{\r
+ osm_madw_t* p_resp_madw;\r
+ const ib_sa_mad_t* p_sa_mad;\r
+ ib_sa_mad_t* p_resp_sa_mad;\r
+ size_t num_rec, pre_trim_num_rec;\r
+#ifndef VENDOR_RMPP_SUPPORT\r
+ size_t trim_num_rec;\r
+#endif\r
+ ib_path_rec_t* p_resp_pr;\r
+ ib_api_status_t status;\r
+ const ib_sa_mad_t* p_rcvd_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ osm_pr_item_t* p_pr_item;\r
+ uint32_t i;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_pr_rcv_respond );\r
+\r
+ num_rec = cl_qlist_count( p_list );\r
+\r
+ /*\r
+ * C15-0.1.30:\r
+ * If we do a SubnAdmGet and got more than one record it is an error !\r
+ */\r
+ if (p_rcvd_mad->method == IB_MAD_METHOD_GET)\r
+ {\r
+ if (num_rec == 0)\r
+ {\r
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );\r
+ goto Exit;\r
+ }\r
+ if (num_rec > 1)\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_respond: ERR 1F13: "\r
+ "Got more than one record for SubnAdmGet (%zu)\n",\r
+ num_rec );\r
+ osm_sa_send_error( p_rcv->p_resp, p_madw,\r
+ IB_SA_MAD_STATUS_TOO_MANY_RECORDS );\r
+ /* need to set the mem free ... */\r
+ p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+ while( p_pr_item != (osm_pr_item_t*)cl_qlist_end( p_list ) )\r
+ {\r
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+ p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+ }\r
+ goto Exit;\r
+ }\r
+ }\r
+\r
+ pre_trim_num_rec = num_rec;\r
+#ifndef VENDOR_RMPP_SUPPORT\r
+ trim_num_rec = (MAD_BLOCK_SIZE - IB_SA_MAD_HDR_SIZE) / sizeof(ib_path_rec_t);\r
+ if (trim_num_rec < num_rec)\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,\r
+ "__osm_pr_rcv_respond: "\r
+ "Number of records:%u trimmed to:%u to fit in one MAD\n",\r
+ num_rec,trim_num_rec );\r
+ num_rec = trim_num_rec;\r
+ }\r
+#endif\r
+\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "__osm_pr_rcv_respond: "\r
+ "Generating response with %zu records\n", num_rec );\r
+\r
+ if ((p_rcvd_mad->method == IB_MAD_METHOD_GET) && (num_rec == 0))\r
+ {\r
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RECORDS );\r
+ goto Exit;\r
+ }\r
+\r
+ /*\r
+ * Get a MAD to reply. Address of Mad is in the received mad_wrapper\r
+ */\r
+ p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, p_madw->h_bind,\r
+ num_rec * sizeof(ib_path_rec_t) + IB_SA_MAD_HDR_SIZE,\r
+ &p_madw->mad_addr );\r
+ if( !p_resp_madw )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_respond: ERR 1F14: "\r
+ "Unable to allocate MAD\n" );\r
+\r
+ for( i = 0; i < num_rec; i++ )\r
+ {\r
+ p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+ }\r
+\r
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES );\r
+ goto Exit;\r
+ }\r
+\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_resp_madw );\r
+\r
+ memcpy( p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE );\r
+ p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;\r
+ /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */\r
+ p_resp_sa_mad->sm_key = 0;\r
+ /* Fill in the offset (paylen will be done by the rmpp SAR) */\r
+ p_resp_sa_mad->attr_offset = ib_get_attr_offset( sizeof(ib_path_rec_t) );\r
+\r
+ p_resp_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad );\r
+\r
+#ifndef VENDOR_RMPP_SUPPORT\r
+ /* we support only one packet RMPP - so we will set the first and\r
+ last flags for gettable */\r
+ if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)\r
+ {\r
+ p_resp_sa_mad->rmpp_type = IB_RMPP_TYPE_DATA;\r
+ p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_FIRST | IB_RMPP_FLAG_LAST | IB_RMPP_FLAG_ACTIVE;\r
+ }\r
+#else\r
+ /* forcefully define the packet as RMPP one */\r
+ if (p_resp_sa_mad->method == IB_MAD_METHOD_GETTABLE_RESP)\r
+ p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;\r
+#endif\r
+\r
+ for ( i = 0; i < pre_trim_num_rec; i++ )\r
+ {\r
+ p_pr_item = (osm_pr_item_t*)cl_qlist_remove_head( p_list );\r
+ /* copy only if not trimmed */\r
+ if (i < num_rec)\r
+ *p_resp_pr = p_pr_item->path_rec;\r
+\r
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );\r
+ p_resp_pr++;\r
+ }\r
+\r
+ CL_ASSERT( cl_is_qlist_empty( p_list ) );\r
+\r
+ status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE );\r
+\r
+ if( status != IB_SUCCESS )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "__osm_pr_rcv_respond: ERR 1F15: "\r
+ "Unable to send MAD (%s)\n", ib_get_err_str( status ) );\r
+ /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */\r
+ }\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r
+/**********************************************************************\r
+ **********************************************************************/\r
+void\r
+osm_pr_rcv_process(\r
+ IN osm_pr_rcv_t* const p_rcv,\r
+ IN const osm_madw_t* const p_madw )\r
+{\r
+ const ib_path_rec_t* p_pr;\r
+ const ib_sa_mad_t* p_sa_mad;\r
+ const osm_port_t* p_src_port;\r
+ const osm_port_t* p_dest_port;\r
+ cl_qlist_t pr_list;\r
+ ib_net16_t sa_status;\r
+ osm_port_t* requester_port;\r
+ int ret;\r
+\r
+ OSM_LOG_ENTER( p_rcv->p_log, osm_pr_rcv_process );\r
+\r
+ CL_ASSERT( p_madw );\r
+\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+\r
+ CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD );\r
+\r
+ /* we only support SubnAdmGet and SubnAdmGetTable methods */\r
+ if ((p_sa_mad->method != IB_MAD_METHOD_GET) &&\r
+ (p_sa_mad->method != IB_MAD_METHOD_GETTABLE)) {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "osm_pr_rcv_process: ERR 1F17: " \r
+ "Unsupported Method (%s)\n",\r
+ ib_get_sa_method_str( p_sa_mad->method ) );\r
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR );\r
+ goto Exit;\r
+ }\r
+\r
+ /* update the requester physical port. */\r
+ requester_port = osm_get_port_by_mad_addr( p_rcv->p_log, p_rcv->p_subn,\r
+ osm_madw_get_mad_addr_ptr( p_madw ) );\r
+ if( requester_port == NULL )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "osm_pr_rcv_process: ERR 1F16: "\r
+ "Cannot find requester physical port\n" );\r
+ goto Exit;\r
+ }\r
+\r
+ if( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )\r
+ osm_dump_path_record( p_rcv->p_log, p_pr, OSM_LOG_DEBUG );\r
+\r
+ cl_qlist_init( &pr_list );\r
+\r
+ /*\r
+ Most SA functions (including this one) are read-only on the\r
+ subnet object, so we grab the lock non-exclusively.\r
+ */\r
+ cl_plock_acquire( p_rcv->p_lock );\r
+\r
+ /* Handle multicast destinations separately */\r
+ if( (ret = __osm_pr_rcv_check_mcast_dest( p_rcv, p_madw )) < 0 )\r
+ {\r
+ /* Multicast DGID with unicast DLID */\r
+ cl_plock_release( p_rcv->p_lock );\r
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_MAD_STATUS_INVALID_FIELD );\r
+ goto Exit;\r
+ }\r
+\r
+ if(ret > 0)\r
+ goto McastDest;\r
+\r
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "osm_pr_rcv_process: "\r
+ "Unicast destination requested\n" );\r
+\r
+ sa_status = __osm_pr_rcv_get_end_points( p_rcv, p_madw,\r
+ &p_src_port, &p_dest_port );\r
+\r
+ if( sa_status == IB_SA_MAD_STATUS_SUCCESS )\r
+ {\r
+ /*\r
+ What happens next depends on the type of endpoint information\r
+ that was specified....\r
+ */\r
+ if( p_src_port )\r
+ {\r
+ if( p_dest_port )\r
+ __osm_pr_rcv_process_pair( p_rcv, p_madw, requester_port,\r
+ p_src_port, p_dest_port,\r
+ p_sa_mad->comp_mask, &pr_list );\r
+ else\r
+ __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,\r
+ p_src_port, NULL,\r
+ p_sa_mad->comp_mask, &pr_list );\r
+ }\r
+ else\r
+ {\r
+ if( p_dest_port )\r
+ __osm_pr_rcv_process_half( p_rcv, p_madw, requester_port,\r
+ NULL, p_dest_port,\r
+ p_sa_mad->comp_mask, &pr_list );\r
+ else\r
+ /*\r
+ Katie, bar the door!\r
+ */\r
+ __osm_pr_rcv_process_world( p_rcv, p_madw, requester_port,\r
+ p_sa_mad->comp_mask, &pr_list );\r
+ }\r
+ }\r
+ goto Unlock;\r
+\r
+ McastDest:\r
+ osm_log(p_rcv->p_log, OSM_LOG_DEBUG,\r
+ "osm_pr_rcv_process: "\r
+ "Multicast destination requested\n" );\r
+ {\r
+ osm_mgrp_t *p_mgrp = NULL;\r
+ ib_api_status_t status;\r
+ osm_pr_item_t* p_pr_item;\r
+ uint32_t flow_label;\r
+ uint8_t sl;\r
+ uint8_t hop_limit;\r
+\r
+ /* First, get the MC info */\r
+ __osm_pr_get_mgrp( p_rcv, p_madw, &p_mgrp );\r
+\r
+ if ( p_mgrp )\r
+ {\r
+ /* Make sure the rest of the PathRecord matches the MC group attributes */\r
+ status = __osm_pr_match_mgrp_attributes( p_rcv, p_madw, p_mgrp );\r
+ if ( status == IB_SUCCESS )\r
+ {\r
+ p_pr_item = (osm_pr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );\r
+ if( p_pr_item == NULL )\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "osm_pr_rcv_process: ERR 1F18: "\r
+ "Unable to allocate path record for MC group\n" );\r
+ }\r
+ else\r
+ {\r
+ /* Copy PathRecord request into response */\r
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );\r
+ p_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );\r
+ p_pr_item->path_rec = *p_pr;\r
+\r
+ /* Now, use the MC info to cruft up the PathRecord response */ \r
+ p_pr_item->path_rec.dgid = p_mgrp->mcmember_rec.mgid;\r
+ p_pr_item->path_rec.dlid = p_mgrp->mcmember_rec.mlid;\r
+ p_pr_item->path_rec.tclass = p_mgrp->mcmember_rec.tclass;\r
+ p_pr_item->path_rec.num_path = 1;\r
+ p_pr_item->path_rec.pkey = p_mgrp->mcmember_rec.pkey;\r
+\r
+ /* MTU, rate, and packet lifetime should be exactly */\r
+ p_pr_item->path_rec.mtu = (2<<6) | p_mgrp->mcmember_rec.mtu;\r
+ p_pr_item->path_rec.rate = (2<<6) | p_mgrp->mcmember_rec.rate;\r
+ p_pr_item->path_rec.pkt_life = (2<<6) | p_mgrp->mcmember_rec.pkt_life;\r
+\r
+ /* SL, Hop Limit, and Flow Label */\r
+ ib_member_get_sl_flow_hop( p_mgrp->mcmember_rec.sl_flow_hop,\r
+ &sl, &flow_label, &hop_limit );\r
+ p_pr_item->path_rec.qos_class_sl = cl_hton16( sl );\r
+ p_pr_item->path_rec.hop_flow_raw = (uint32_t)(hop_limit) |\r
+ (flow_label << 8);\r
+\r
+ cl_qlist_insert_tail( &pr_list,\r
+ (cl_list_item_t*)&p_pr_item->pool_item );\r
+\r
+ }\r
+ }\r
+ else\r
+ {\r
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,\r
+ "osm_pr_rcv_process: ERR 1F19: "\r
+ "MC group attributes don't match PathRecord request\n" );\r
+ }\r
+ }\r
+ }\r
+\r
+ Unlock:\r
+ cl_plock_release( p_rcv->p_lock );\r
+\r
+ /* Now, (finally) respond to the PathRecord request */\r
+ __osm_pr_rcv_respond( p_rcv, p_madw, &pr_list );\r
+\r
+ Exit:\r
+ OSM_LOG_EXIT( p_rcv->p_log );\r
+}\r
+\r