Status_t sa_SMInfoRecord(Mai_t *maip, sa_cntxt_t* sa_cntxt) { uint32_t records; uint16_t attribOffset; IB_ENTER("sa_SMInfoRecord", maip, 0, 0, 0); // // Assume failure. // records = 0; // // Check the method. If this is a template lookup, then call the regular // GetTable(*) template lookup routine. // switch (maip->base.method) { case SA_CM_GET: INCREMENT_COUNTER(smCounterSaRxGetSmInfoRecord); (void)sa_SMInfoRecord_GetTable(maip, &records); break; case SA_CM_GETTABLE: INCREMENT_COUNTER(smCounterSaRxGetTblSmInfoRecord); (void)sa_SMInfoRecord_GetTable(maip, &records); break; default: maip->base.status = MAD_STATUS_BAD_METHOD; (void)sa_send_reply(maip, sa_cntxt); IB_LOG_WARN("sa_SMInfoRecord: invalid METHOD:", maip->base.method); IB_EXIT("sa_SMInfoRecord", VSTATUS_OK); return(VSTATUS_OK); break; } // // Determine reply status // if (records == 0) { maip->base.status = MAD_STATUS_SA_NO_RECORDS; } else if ((maip->base.method == SA_CM_GET) && (records != 1)) { IB_LOG_WARN("sa_SMInfoRecord: too many records for SA_CM_GET:", records); records = 0; maip->base.status = MAD_STATUS_SA_TOO_MANY_RECS; } else { maip->base.status = MAD_STATUS_OK; } attribOffset = sizeof(STL_SMINFO_RECORD) + Calculate_Padding(sizeof(STL_SMINFO_RECORD)); /* setup attribute offset for possible RMPP transfer */ sa_cntxt->attribLen = attribOffset; sa_cntxt_data( sa_cntxt, sa_data, records * attribOffset); (void)sa_send_reply(maip, sa_cntxt ); IB_EXIT("sa_SMInfoRecord", VSTATUS_OK); return(VSTATUS_OK); }
/* * Age context and do resends for those that timed out */ void sa_cntxt_age(void) { sa_cntxt_t* sa_cntxt = NULL ; sa_cntxt_t* tout_cntxt ; int i; Status_t status; if ((status = vs_lock(&sa_cntxt_lock)) != VSTATUS_OK) { IB_LOG_ERRORRC("sa_cntxt_age: Failed to lock SA context rc:", status); } else { vs_time_get( &timeLastAged ); for (i=0; i<SA_CNTXT_HASH_TABLE_DEPTH; i++) { sa_cntxt = sa_hash[ i ]; while( sa_cntxt ) { // Iterate before the pointers are destroyed ; tout_cntxt = sa_cntxt ; sa_cntxt = sa_cntxt->next ; // Though list is sorted, it does not hurt to // do a simple comparison if( timeLastAged - tout_cntxt->tstamp > tout_cntxt->RespTimeout) { // used to be VTIMER_1S // Timeout this entry sa_cntxt_delete_entry( sa_hash[ i ], tout_cntxt ); sa_cntxt_insert_head( sa_hash[ i ], tout_cntxt ); // Touch the entry tout_cntxt->tstamp = timeLastAged ; // Call timeout tout_cntxt->sendFd = fd_sa_w; // use sa writer mai handle for restransmits if (tout_cntxt->method == SA_CM_GETMULTI && tout_cntxt->reqInProg) { // resend the getMulti request ACK sa_getMulti_resend_ack(tout_cntxt); /* if need to release the context. Call local safe release */ if( tout_cntxt->retries > sm_config.max_retries ) cntxt_release(sa_cntxt); } else { // resend the reply sa_send_reply( NULL, tout_cntxt ); if( tout_cntxt->retries > sm_config.max_retries ) { /* need to release the context. Call local safe release */ cntxt_release(tout_cntxt); } } } } } if ((status = vs_unlock(&sa_cntxt_lock)) != VSTATUS_OK) { IB_LOG_ERRORRC("cs_cntxt_age: Failed to unlock SA context rc:", status); } } }
void sa_main_reader(uint32_t argc, uint8_t ** argv) { Status_t status; Mai_t in_mad; Filter_t filter; sa_cntxt_t *sa_cntxt=NULL; uint64_t now, delta, max_delta; int tries=0, retry=0; uint64_t reqTimeToLive=0; SAContextGet_t cntxGetStatus=0; int numContextBusy=0; IB_ENTER("sa_main_reader", 0, 0, 0, 0); sa_main_reader_exit = 0; /* * Create the SubnAdm(*) MAD filter for the SA thread. */ SA_Filter_Init(&filter); filter.value.mclass = MAD_CV_SUBN_ADM; filter.mask.mclass = 0xff; filter.value.method = 0x00; filter.mask.method = 0x80; filter.mai_filter_check_packet = sa_reader_filter; MAI_SET_FILTER_NAME (&filter, "SA Reader"); if (mai_filter_create(fd_sa, &filter, VFILTER_SHARE) != VSTATUS_OK) { IB_LOG_ERROR0("sa_main_reader: can't create SubnAdm(*) filter"); (void)vs_thread_exit(&sm_threads[SM_THREAD_SA_READER].handle); } timeMftLastUpdated = 0; /* * calculate request time to live on queue * ~ 3.2secs for defaults: sa_packetLifetime=18 and sa_respTimeValue=18 */ reqTimeToLive = 4ull * ( (2*(1 << sm_config.sa_packet_lifetime_n2)) + (1 << sm_config.sa_resp_time_n2) ); while (1) { status = mai_recv(fd_sa, &in_mad, VTIMER_1S/4); if (sa_main_reader_exit == 1){ #ifdef __VXWORKS__ ESM_LOG_ESMINFO("sa_main_reader: exiting OK.", 0); #endif break; } /* don't process messages if not master SM or still doing first sweep */ if ((sm_state != SM_STATE_MASTER) || (topology_passcount < 1)) { continue; } /* * If the mai layer shuts down we end up in this infinite loop here. * This may happen on initialization */ if( status != VSTATUS_OK ){ if (status != VSTATUS_TIMEOUT) IB_LOG_ERRORRC("sa_main_reader: error on mai_recv rc:", status); } else { /* * Drop new requests that have been sitting on SA reader queue for too long */ if (in_mad.intime) { /* PR 110586 - On some RHEL 5 systems, we've seen weird issues with gettimeofday() [used by vs_time_get()] * where once in a while the time difference calculated from successive calls to gettimeofday() * results in a negative value. Due to this, we might actually consider a request stale even if * its not. Work around this by making calls to gettimeofday() till it returns us some * sane values. Just to be extra cautious, bound the retries so that we don't get stuck in the loop. */ tries = 0; /* Along with negative values also check for unreasonably high values of delta*/ max_delta = 30*reqTimeToLive; do { vs_time_get( &now ); delta = now - in_mad.intime; tries++; if ((now < in_mad.intime) || (delta > max_delta)) { vs_thread_sleep(1); retry = 1; } else { retry = 0; } } while (retry && tries < 20); if (delta > reqTimeToLive) { INCREMENT_COUNTER(smCounterSaDroppedRequests); if (smDebugPerf || saDebugPerf) { IB_LOG_INFINI_INFO_FMT( "sa_main_reader", "Dropping stale %s[%s] request from LID[0x%x], TID="FMT_U64"; On queue for %d.%d seconds.", sa_getMethodText((int)in_mad.base.method), sa_getAidName((int)in_mad.base.aid), in_mad.addrInfo.slid, in_mad.base.tid, (int)(delta/1000000), (int)((delta - delta/1000000*1000000))/1000); } /* drop the request without returning a response; sender will retry */ continue; } } /* * get a context to process request; sa_cntxt can be: * 1. NULL if resources are scarce * 2. NULL if request is dup of existing request * 3. in progress getMulti request context * 4. New context for a brand new request */ cntxGetStatus = sa_cntxt_get( &in_mad, (void *)&sa_cntxt ); if (cntxGetStatus == ContextAllocated) { /* process the new request */ sa_process_mad( &in_mad, sa_cntxt ); /* * This may not necessarily release context based on if someone else has reserved it */ if(sa_cntxt) sa_cntxt_release( sa_cntxt ); } else if (cntxGetStatus == ContextExist) { INCREMENT_COUNTER(smCounterSaDuplicateRequests); /* this is a duplicate request */ if (saDebugPerf || saDebugRmpp) { IB_LOG_INFINI_INFO_FMT( "sa_main_reader", "SA_READER received duplicate %s[%s] from LID [0x%x] with TID ["FMT_U64"] ", sa_getMethodText((int)in_mad.base.method), sa_getAidName((int)in_mad.base.aid),in_mad.addrInfo.slid, in_mad.base.tid); } } else if (cntxGetStatus == ContextNotAvailable) { INCREMENT_COUNTER(smCounterSaContextNotAvailable); /* we are swamped, return BUSY to caller */ if (saDebugPerf || saDebugRmpp) { /* log msg before send changes method and lids */ IB_LOG_INFINI_INFO_FMT( "sa_main_reader", "NO CONTEXT AVAILABLE, returning MAD_STATUS_BUSY to %s[%s] request from LID [0x%x], TID ["FMT_U64"]!", sa_getMethodText((int)in_mad.base.method), sa_getAidName((int)in_mad.base.aid), in_mad.addrInfo.slid, in_mad.base.tid); } in_mad.base.status = MAD_STATUS_BUSY; sa_send_reply( &in_mad, sa_cntxt ); if ((++numContextBusy % sa_max_cntxt) == 0) { IB_LOG_INFINI_INFO_FMT( "sa_main_reader", "Had to drop %d SA requests since start due to no available contexts", numContextBusy); } } else if (cntxGetStatus == ContextExistGetMulti) { /* continue processing the getMulti request */ sa_process_getmulti( &in_mad, sa_cntxt ); if(sa_cntxt) sa_cntxt_release( sa_cntxt ); } else { IB_LOG_WARN("sa_main_reader: Invalid sa_cntxt_get return code:", cntxGetStatus); } } /* * signal sm_top to reprogram the MFTs * Wait one second to allow mcmember requests to accumulate before asking */ vs_time_get( &now ); if (sa_mft_reprog && timeMftLastUpdated == 0) { timeMftLastUpdated = now; } else if (sa_mft_reprog && (now - timeMftLastUpdated) > VTIMER_1S) { topology_wakeup_time = 0ull; if ((status = vs_lock(&sa_lock)) != VSTATUS_OK) { IB_LOG_ERRORRC("sa_main_reader: Failed to lock sa_lock rc:", status); } else { sm_McGroups_Need_Prog = 1; /* tells Topoloy thread that MFT reprogramming is needed */ (void)vs_unlock(&sa_lock); } sm_trigger_sweep(SM_SWEEP_REASON_MCMEMBER); /* clear the indicators */ timeMftLastUpdated = 0; sa_mft_reprog = 0; } } /* cleanup before exit, but allow some time for the other threads to flush out first */ (void)vs_thread_sleep(VTIMER_1S); (void)sa_SubscriberDelete(); (void)sa_ServiceRecDelete(); (void)sa_McGroupDelete(); if (mai_filter_delete(fd_sa, &filter, VFILTER_SHARE) != VSTATUS_OK) { IB_LOG_ERROR0("sa_main_reader: can't delete SubnAdm(*) filter"); } //IB_LOG_INFINI_INFO0("sa_main_reader thread: Exiting OK"); }
Status_t sa_ClassPortInfo(Mai_t *maip, sa_cntxt_t* sa_cntxt) { uint16_t attribOffset; union { STL_CLASS_PORT_INFO stl_version; IB_CLASS_PORT_INFO ib_version; } myCPI; IB_ENTER("sa_ClassPortInfo", maip, 0, 0, 0); // // Check the method. For ClassPortInfo, you can only do a Get(). // if (maip->base.method == SA_CM_GET) { INCREMENT_COUNTER(smCounterSaRxGetClassPortInfo); if (maip->base.cversion == SA_MAD_CVERSION) { memset(&myCPI.ib_version,0,sizeof(IB_CLASS_PORT_INFO)); myCPI.ib_version.BaseVersion = saClassPortInfo.BaseVersion; myCPI.ib_version.ClassVersion = saClassPortInfo.ClassVersion; myCPI.ib_version.CapMask = STL_CLASS_PORT_CAPMASK_CM2 | STL_SA_CAPABILITY_MULTICAST_SUPPORT | STL_SA_CAPABILITY_MULTIPATH_SUPPORT | STL_SA_CAPABILITY_PORTINFO_CAPMASK_MATCH | STL_SA_CAPABILITY_PA_SERVICES_SUPPORT; myCPI.ib_version.u1.s.CapMask2 = STL_SA_CAPABILITY2_QOS_SUPPORT | STL_SA_CAPABILITY2_MFTTOP_SUPPORT | STL_SA_CAPABILITY2_FULL_PORTINFO | STL_SA_CAPABILITY2_EXT_SUPPORT; myCPI.ib_version.u1.s.RespTimeValue = saClassPortInfo.u1.s.RespTimeValue; myCPI.ib_version.u3.s.RedirectQP = saClassPortInfo.u3.s.RedirectQP; myCPI.ib_version.u5.s.TrapHopLimit = saClassPortInfo.u5.s.TrapHopLimit; myCPI.ib_version.u5.s.TrapQP = saClassPortInfo.u5.s.TrapQP; BSWAP_IB_CLASS_PORT_INFO(&myCPI.ib_version); attribOffset = sizeof(IB_CLASS_PORT_INFO) + Calculate_Padding(sizeof(IB_CLASS_PORT_INFO)); sa_cntxt_data( sa_cntxt, &myCPI.ib_version, attribOffset); sa_cntxt->attribLen = attribOffset; maip->base.status = MAD_STATUS_OK; } else if (maip->base.cversion >= STL_SM_CLASS_VERSION) { myCPI.stl_version = saClassPortInfo; BSWAP_STL_CLASS_PORT_INFO(&myCPI.stl_version); attribOffset = sizeof(STL_CLASS_PORT_INFO) + Calculate_Padding(sizeof(STL_CLASS_PORT_INFO)); sa_cntxt_data( sa_cntxt, &myCPI.stl_version, attribOffset); sa_cntxt->attribLen = attribOffset; maip->base.status = MAD_STATUS_OK; } else { maip->base.status = MAD_STATUS_BAD_METHOD; } } else { maip->base.status = MAD_STATUS_BAD_METHOD; } (void)sa_send_reply(maip, sa_cntxt); IB_EXIT("sa_ClassPortInfo", VSTATUS_OK); return(VSTATUS_OK); }