/* BEGIN_ICS_COPYRIGHT7 ****************************************
Copyright (c) 2015-2020, Intel Corporation
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.
* Neither the name of Intel Corporation nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** END_ICS_COPYRIGHT7 ****************************************/
/* [ICS VERSION STRING: unknown] */
//===========================================================================//
//
// FILE NAME
// sm_topology_rcv.c
//
// DESCRIPTION
// This thread will process asynchronous SM set responses. Used for
// ucast and mcast tables primarily.
//
// DATA STRUCTURES
// None
//
// FUNCTIONS
// sm_topology_rcv main entry point
//
// DEPENDENCIES
// ib_mad.h
// ib_status.h
// ib_const.h
//
//
//===========================================================================//
#include "os_g.h"
#include "ib_types.h"
#include "ib_macros.h"
#include "ib_mad.h"
#include "ib_status.h"
#include "cs_g.h"
#include "sm_counters.h"
#include "sm_l.h"
#include "cs_context.h"
#include "cs_queue.h"
//********** sm asynchronous send receive context **********
generic_cntxt_t sm_async_send_rcv_cntxt;
// SM asynchronous send response queue
cs_Queue_ptr sm_async_rcv_resp_queue;
// static variables
static uint32_t topology_rcv_exit=0;
static void
createFilter(uint16_t aid, char* filterName, char* filterErrName) {
Status_t status=VSTATUS_OK;
Filter_t filter;
//
// Set the filter for catching set responses on fd_atopology.
//
SM_Filter_Init(&filter);
filter.value.bversion = STL_BASE_VERSION;
filter.value.cversion = STL_SM_CLASS_VERSION;
filter.value.mclass = MAD_CV_SUBN_LR & 0x7f; // LR or DR
//filter.value.mclass = MAD_CV_SUBN_LR;
filter.value.method = MAD_CM_GET_RESP;
filter.value.aid = aid;
filter.mask.bversion = MAI_FMASK_ALL;
filter.mask.cversion = MAI_FMASK_ALL;
//filter.mask.mclass = MAI_FMASK_ALL;
filter.mask.mclass = 0x7f;
filter.mask.method = MAI_FMASK_ALL;
filter.mask.aid = MAI_FMASK_ALL;
MAI_SET_FILTER_NAME (&filter, filterName);
status = mai_filter_create(fd_atopology->fdMai, &filter, VFILTER_SHARE | VFILTER_PURGE);
if (status != VSTATUS_OK) {
IB_LOG_ERRORRC("topology_rcv: can't create topology async receive filter for set responses rc:", status);
(void)vs_thread_exit(&sm_threads[SM_THREAD_ASYNC].handle);
}
//
// Set the filter for catching set errors on fd_atopology.
//
SM_Filter_Init(&filter);
filter.type = MAI_TYPE_ERROR;
filter.value.bversion = STL_BASE_VERSION;
filter.value.cversion = STL_SM_CLASS_VERSION;
filter.value.mclass = MAD_CV_SUBN_LR & 0x7f; // LR or DR
//filter.value.method = MAD_CM_GET_RESP;
filter.value.aid = aid;
filter.mask.bversion = MAI_FMASK_ALL;
filter.mask.cversion = MAI_FMASK_ALL;
filter.mask.mclass = 0x7f;
//filter.mask.method = MAI_FMASK_ALL;
filter.mask.aid = MAI_FMASK_ALL;
MAI_SET_FILTER_NAME (&filter, filterErrName);
status = mai_filter_create(fd_atopology->fdMai, &filter, VFILTER_SHARE | VFILTER_PURGE);
if (status != VSTATUS_OK) {
IB_LOG_ERRORRC("topology_rcv: can't create topology async receive filter for set errors rc:", status);
(void)vs_thread_exit(&sm_threads[SM_THREAD_ASYNC].handle);
}
}
void
topology_rcv(uint32_t argc, uint8_t ** argv) {
Status_t status=VSTATUS_OK;
Filter_t filter;
Mai_t mad;
uint64_t timeout=0;
uint64_t lastTimeAged=0, now=0;
topology_rcv_exit = 0;
(void)vs_thread_name(&sm_threads[SM_THREAD_TOP_RCV].name);
//
// initialize the SM async send receive response queue
// +1 for depth to be safe
// round to to 32 to keep MinQueueSize happy and for some headroom
if ((sm_async_rcv_resp_queue = cs_queue_CreateQueue( &sm_pool, MAX(32, sm_config.max_parallel_reqs)+1 )) == NULL) {
IB_LOG_ERROR0("sm_async: failed to initialize the SM async receive response queue, terminating");
(void)vs_thread_exit(&sm_threads[SM_THREAD_TOP_RCV].handle);
}
//
// initialize SM send receive context pool
//
memset((void *)&sm_async_send_rcv_cntxt, 0, sizeof(sm_async_send_rcv_cntxt));
// all LR packets - use hash
sm_async_send_rcv_cntxt.hashTableDepth = CNTXT_HASH_TABLE_DEPTH;
sm_async_send_rcv_cntxt.poolSize = MAX(32, sm_config.max_parallel_reqs);
sm_async_send_rcv_cntxt.maxRetries = sm_config.max_retries;
sm_async_send_rcv_cntxt.ibHandle = fd_atopology->fdMai;
sm_async_send_rcv_cntxt.errorOnSendFail = 0;
#ifdef IB_STACK_OPENIB
// for openib we let umad do the timeouts. Hence we add 1 second to
// the timeout as a safety net just in case umad loses our response.
sm_async_send_rcv_cntxt.timeoutAdder = VTIMER_1S;
#endif
sm_async_send_rcv_cntxt.resp_queue = sm_async_rcv_resp_queue; // queue to post responses
sm_async_send_rcv_cntxt.totalTimeout = (sm_config.rcv_wait_msec * sm_config.max_retries * 1000); // (*1000) to convert from milliseconds to microseconds
/* PR 110945 - Stepped and randomized retries */
/* If MinRcvWaitInterval is available, then set the default timeout of the cntxt to the smallest
* retry interval.
*/
if (sm_config.min_rcv_wait_msec) {
timeout = sm_config.min_rcv_wait_msec * 1000; // convert from milliseconds to microseconds
sm_async_send_rcv_cntxt.MinRespTimeout = timeout;
}
else {
timeout = sm_config.rcv_wait_msec * 1000; // convert from milliseconds to microseconds
sm_async_send_rcv_cntxt.MinRespTimeout = 0;
}
status = cs_cntxt_instance_init (&sm_pool, &sm_async_send_rcv_cntxt, timeout);
if (status != VSTATUS_OK) {
IB_LOG_ERRORRC("topology_rcv: failed to initialize the SM send receive context instance, rc:", status);
(void)vs_thread_exit(&sm_threads[SM_THREAD_TOP_RCV].handle);
}
createFilter(STL_MCLASS_ATTRIB_ID_LINEAR_FWD_TABLE, "top_rcv_lft", "top_rcv_lft_err");
createFilter(STL_MCLASS_ATTRIB_ID_MCAST_FWD_TABLE, "top_rcv_mft", "top_rcv_mft_err");
createFilter(STL_MCLASS_ATTRIB_ID_PART_TABLE, "top_rcv_pkey", "top_rcv_pkey_err");
createFilter(STL_MCLASS_ATTRIB_ID_PORT_INFO, "top_rcv_pi", "top_rcv_pi_err");
createFilter(STL_MCLASS_ATTRIB_ID_PORT_STATE_INFO, "top_rcv_psi", "top_rcv_psi_err");
//
// Set the filter for catching LID routed get GUIDINFO responses on fd_atopology.
//
SM_Filter_Init(&filter);
filter.value.bversion = MAD_BVERSION;
filter.value.cversion = MAD_CVERSION;
filter.value.mclass = MAD_CV_SUBN_LR;
filter.value.method = MAD_CM_GET_RESP;
filter.value.aid = MAD_SMA_GUIDINFO;
filter.mask.bversion = 0xff;
filter.mask.cversion = 0xff;
filter.mask.mclass = MAI_FMASK_ALL;
filter.mask.method = 0xff;
filter.mask.aid = 0xffff;
MAI_SET_FILTER_NAME (&filter, "top_rcv_guid");
status = mai_filter_create(fd_atopology->fdMai, &filter, VFILTER_SHARE | VFILTER_PURGE);
if (status != VSTATUS_OK) {
IB_LOG_ERRORRC("topology_rcv: can't create topology async receive filter for GuidInfo set responses rc:", status);
(void)vs_thread_exit(&sm_threads[SM_THREAD_ASYNC].handle);
}
//
// Set the filter for catching LID routed get GUIDINFO errors on fd_atopology.
//
SM_Filter_Init(&filter);
filter.type = MAI_TYPE_ERROR;
filter.value.bversion = MAD_BVERSION;
filter.value.cversion = MAD_CVERSION;
filter.value.mclass = MAD_CV_SUBN_LR;
//filter.value.method = MAD_CM_GET_RESP;
filter.value.aid = MAD_SMA_GUIDINFO;
filter.mask.bversion = 0xff;
filter.mask.cversion = 0xff;
filter.mask.mclass = MAI_FMASK_ALL;
//filter.mask.method = 0xff;
filter.mask.aid = 0xffff;
MAI_SET_FILTER_NAME (&filter, "top_rcv_guid_er");
status = mai_filter_create(fd_atopology->fdMai, &filter, VFILTER_SHARE | VFILTER_PURGE);
if (status != VSTATUS_OK) {
IB_LOG_ERRORRC("topology_rcv: can't create topology async receive filter for GuidInfo set errors rc:", status);
(void)vs_thread_exit(&sm_threads[SM_THREAD_ASYNC].handle);
}
// tell topology thread we are ready
(void)cs_vsema(&topology_rcv_sema);
(void)vs_time_get(&lastTimeAged);
// process sm responses
while (topology_rcv_exit == 0) {
//
// check for LFT RESP on file descriptor (QP0)
//
/* If using stepped retry logic, use the smallest timeout of a context otherwise use 50ms as timeout.
* timeout variable has been initialized above to sm_config.min_rcv_wait_msec*1000 and will get updated based
* on return value from cs_cntxt_age() below.
*/
if (sm_config.min_rcv_wait_msec) {
status = mai_recv(fd_atopology->fdMai, &mad, timeout);
}
else
status = mai_recv(fd_atopology->fdMai, &mad, 50000ull);
if (status == VSTATUS_OK) {
switch (mad.type) {
case MAI_TYPE_EXTERNAL:
switch (mad.base.method) {
case MAD_CM_GET_RESP:
INCREMENT_COUNTER(smCounterRxGetResp);
INCREMENT_MAD_STATUS_COUNTERS(&mad);
if (sm_state == SM_STATE_MASTER) {
// find and release the context
cs_cntxt_find_release(&mad, &sm_async_send_rcv_cntxt);
}
break;
default:
IB_LOG_ERROR("topology_rcv: bad method received on sm receive file descriptor (QP0), method:", mad.base.method);
(void)sm_dump_mai("topology_rcv", &mad);
break;
}
break;
case MAI_TYPE_ERROR:
// only happens for openib. This return indicated the
// lower level stack has returned our original sent MAD
// to indicate a failure sending it or a lack of a response
switch (mad.base.method) {
case MAD_CM_GET:
case MAD_CM_SET:
if (sm_state == SM_STATE_MASTER) {
// find and release the context
cs_cntxt_find_release_error(&mad, &sm_async_send_rcv_cntxt);
}
break;
default:
IB_LOG_ERROR("topology_rcv: bad method received on sm receive file descriptor (QP0), method:", mad.base.method);
(void)sm_dump_mai("sm_async", &mad);
break;
}
default:
break;
}
} else if (status != VSTATUS_TIMEOUT) {
IB_LOG_WARNRC("topology_rcv: error on mai_recv for SM async receive fd (QP0), rc:", status);
}
// age context entries if necessary
(void)vs_time_get(&now);
if ((now - lastTimeAged) >= timeout) {
/* cs_cntxt_age returns the smallest timeout of all contexts */
timeout = cs_cntxt_age(&sm_async_send_rcv_cntxt);
/* if there are no context entries (timeout will be 0) or timeout
* value is too small, set timeout to sm_config.min_rcv_wait_msec/4
* this avoids giving too small a timeout value to mai_recv()
*/
if (timeout == 0 || timeout < (sm_config.min_rcv_wait_msec*1000/4))
timeout = sm_config.min_rcv_wait_msec *1000;
// since this loop also checks for SM shutdown, make sure we don't
// use too long a timeout either
if (timeout > VTIMER_1S/10)
timeout = VTIMER_1S/10;
lastTimeAged = now;
}
sm_dispatch_update(&sm_asyncDispatch);
} // end while loop
// Delete the filter.
if (mai_filter_delete(fd_atopology->fdMai, &filter, VFILTER_SHARE | VFILTER_PURGE) != VSTATUS_OK) {
IB_LOG_ERROR0("topology_rcv: can't delete topology async receive filter");
}
// release the SM async send rcv context pool
status = cs_cntxt_instance_free (&sm_pool, &sm_async_send_rcv_cntxt);
// free the SM SM async send rcv queue
cs_queue_DisposeQueue( &sm_pool, sm_async_rcv_resp_queue );
//IB_LOG_INFINI_INFO0("topology_rcv thread: Exiting OK");
} // end topology_rcv
void
topology_rcv_kill(void){
topology_rcv_exit = 1;
}