Пример #1
0
/** fmPlatformLoadPropertiesFromLine
 * \ingroup intPlatform
 *
 * \desc            Loads an attribute from a text line
 *                                                                      \lb\lb
 *                  The expected file format for the database is as follows:
 *                                                                      \lb\lb
 *                  [key] [type] [value]
 *                                                                      \lb\lb
 *                  Where key is a dotted string, type is one of int, bool or
 *                  float, and value is the value to set. Space is the only
 *                  valid separator, but multiple spaces are allowed.
 *
 * \param[in]       line is the text line to load to load.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
fm_status fmPlatformLoadPropertiesFromLine(fm_text line)
{
    fm_status status;

    FM_LOG_ENTRY(FM_LOG_CAT_PLATFORM, "line=%s\n", line);

    if (strncmp(line, "api.platform.config.", 20) == 0)
    {
        status = LtCfgLineLoad(line);
    }
    else if (strncmp(line, "api.platform.lib.config.", 24) == 0)
    {
        status = LibCfgLineLoad(line);
    }
    else
    {
        status = ApiPropertyLineLoad(line);
    }

    if (status)
    {
        FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                "%s: Unable to load config: [%s]\n",
                 fmErrorMsg(status), line);

    }

    FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_OK);

}   /* end fmPlatformLoadPropertiesFromLine  */
Пример #2
0
/** InitiatePurge
 * \ingroup intAddr
 *
 * \desc            Initiates an MA table purge operation.
 *
 * \note            The caller is assumed to have taken the purge lock
 *                  (FM_TAKE_MA_PURGE_LOCK).
 *
 * \param[in]       sw is the switch on which to operate.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
static fm_status InitiatePurge(fm_int sw)
{
    fm_switch *         switchPtr;
    fm_maPurge *        purgePtr;
    fm_maPurgeRequest * request;
    fm_status           err;

    switchPtr = GET_SWITCH_PTR(sw);
    purgePtr  = &switchPtr->maPurge;
    request   = &purgePtr->request;

    FM_LOG_DEBUG(FM_LOG_CAT_EVENT_MAC_MAINT,
                 "sw=%d, port=%d, vlan=%d\n",
                 sw,
                 request->port,
                 request->vid1);

    purgePtr->restoreLocked = FALSE;
    purgePtr->purgeTimeout = 0;

    /* Get purge start time. */
    err = fmGetTime( &purgePtr->startTime );
    if (err != FM_OK)
    {
        FM_LOG_ERROR(FM_LOG_CAT_EVENT_MAC_MAINT,
                     "Error getting purge start time: %s\n",
                     fmErrorMsg(err));
    }

    purgePtr->purgeState = FM_PURGE_STATE_ACTIVE;

    return FM_OK;

}   /* end InitiatePurge */
Пример #3
0
/* LtCfgLineLoad
 * \ingroup intPlatform
 *
 * \desc            Load LT text configuration line.
 *                                                                      \lb\lb
 * \param[in]       line is the config line to load.
 *
 * \return          FM_OK if successful.
 * \return          Other ''Status Codes'' as appropriate in case of
 *                  failure.
 *
 *****************************************************************************/
static fm_status LtCfgLineLoad(fm_text line)
{
    fm_status status;
    fm_byte   tlv[FM_TLV_MAX_BUF_SIZE];
    fm_uint   tlvType;

    /* Don't support these properties here, only for NVM image generation */
    if (strstr(line, ".bootCfg.") != NULL)
    {
        return FM_OK;
    }

    status = fmUtilConfigPropertyEncodeTlv(line, tlv, sizeof(tlv));

    if (status)
    {
        FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
            "Unable to encode LT config: [%s]\n", line);
        return status;
    }

    tlvType = (tlv[0] << 8) | tlv[1];
    if (tlvType == FM_TLV_PLAT_FILE_LOCK_NAME)
    {
         /* Shared with platform config */
        status = LibCfgLineLoad(line);
        if (status)
        {
            return status;
        }
    }

    return fmPlatformLoadLTCfgTlv(tlv);

} /* end LtCfgLineLoad */
Пример #4
0
/** fmRawPacketSocketDestroy
 * \ingroup intPlatformCommon
 *
 * \desc            Destroy the raw packet socket and free up resource.
 *
 * \param[in]       sw is the switch number to destroy.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
fm_status fmRawPacketSocketDestroy(fm_int sw)
{
    fm_status  err = FM_OK;
    fm_switch *switchPtr;

    FM_LOG_ENTRY(FM_LOG_CAT_PLATFORM, "sw=%d\n", sw);

    if (close(GET_PLAT_STATE(sw)->rawSocket) == -1)
    {
        FM_LOG_ERROR(FM_LOG_CAT_PLATFORM, 
                     "couldn't not destroy raw packet socket\n");
        err = FM_FAIL;
        FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err);
    }

    switchPtr = GET_SWITCH_PTR(sw);
    if (switchPtr)
    {
        switchPtr->isRawSocketInitialized = FM_DISABLED;
    }

    err = fmGenericPacketDestroy(sw);
    FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err);

ABORT:

    FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, err);

}   /* end fmRawPacketSocketDestroy */
Пример #5
0
/** fmLocalEventHandler
 * \ingroup intSwitch
 *
 * \desc            event handler for local dispatch thread
 *
 * \param[in]       args points to the thread arguments
 *
 * \return          Nothing.
 *
 *****************************************************************************/
void *fmLocalEventHandler(void *args)
{
    fm_thread *thread;
    fm_event * event;
    fm_status  status;
    fm_bool    enablePrioritySchedule; 

    /* grab arguments */
    thread = FM_GET_THREAD_HANDLE(args);

    enablePrioritySchedule = GET_PROPERTY()->priorityBufQueues;
    while (1)
    {
        if (fmGetThreadEvent(thread, &event, FM_WAIT_FOREVER) != FM_OK)
        {
            if (localDispatchThreadExit == TRUE)
            {
                break;
            }
            else
            {
                continue;
            }
        }

        if (enableFramePriority &&
            ( (event->type == FM_EVENT_PKT_RECV) ||
              (event->type == FM_EVENT_SFLOW_PKT_RECV) ) )
        {
            status = fmFreeBufferQueueNode(FM_FIRST_FOCALPOINT, &event->info.fpPktEvent);
            if (status != FM_OK)
            {
                FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_RX,
                             "Freeing Buffer queue node from the queue failed"
                             "status = %d (%s) \n",
                              status,
                              fmErrorMsg(status));

                fmReleaseEvent(event);
                continue;
            }
        }
        
        if (fmEventHandler != NULL)
        {
            fmEventHandler(event->type, event->sw, &event->info);
        }

        fmReleaseEvent(event);
    }

    fmExitThread(thread);

    return NULL;

}   /* end fmLocalEventHandler */
Пример #6
0
/** fmSetProcessEventMask
 * \ingroup api
 *
 * \desc            Set which events are delivered to the current process's
 *                  event handler function (set by ''fmInitialize'' or
 *                  ''fmSetEventHandler'').
 *                                                                      \lb\lb
 *                  Multiple processes may subscribe to the same event. A
 *                  copy of each event will be sent to all processes that
 *                  subscribe to it.
 *
 * \param[in]       mask is a logical OR of ''Event Identifiers''.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
fm_status fmSetProcessEventMask(fm_uint32 mask)
{
    fm_status         err;
    fm_dlist_node *   node;
    fm_uint           count = 0;
    fm_localDelivery *delivery;
    fm_int            myProcessId;
    fm_uint           expectedCount;

    FM_LOG_ENTRY_API(FM_LOG_CAT_API, "mask=%u\n", mask);

    myProcessId = fmGetCurrentProcessId();

    err = fmCaptureLock(&fmRootApi->localDeliveryLock, FM_WAIT_FOREVER);

    if (err == FM_OK)
    {
        expectedCount = fmRootApi->localDeliveryCount;

        for ( node = FM_DLL_GET_FIRST( (&fmRootApi->localDeliveryThreads), head ) ;
             node != NULL ;
             node = FM_DLL_GET_NEXT(node, next) )
        {
            count++;
            delivery = (fm_localDelivery *) node->data;

            if (delivery->processId == myProcessId)
            {
                delivery->mask = mask;
            }
        }

        err = fmReleaseLock(&fmRootApi->localDeliveryLock);

        if (count != expectedCount)
        {
            FM_LOG_ERROR(FM_LOG_CAT_EVENT,
                         "Expected %d processes but found %d\n",
                         expectedCount,
                         count);
            err = FM_FAIL;
        }

    }   /* end if (err == FM_OK) */

    FM_LOG_EXIT_API(FM_LOG_CAT_API, err);

}   /* end fmSetProcessEventMask */
Пример #7
0
/* LibCfgLineLoad
 * \ingroup intPlatform
 *
 * \desc            Save shared lib text configuration line for the
 *                  shared lib to load when it initializes.
 *                                                                      \lb\lb
 * \param[in]       line is the config line to load.
 *
 * \return          FM_OK if successful.
 * \return          Other ''Status Codes'' as appropriate in case of
 *                  failure.
 *
 *****************************************************************************/
static fm_status LibCfgLineLoad(fm_text line)
{
    fm_status status;
    fm_byte   tlv[FM_TLV_MAX_BUF_SIZE];

    status = fmUtilConfigPropertyEncodeTlv(line, tlv, sizeof(tlv));

    if (status)
    {
        FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
            "Unable to encode LT config: [%s]\n", line);
        return status;
    }

    return fmPlatformLoadLibCfgTlv(tlv);

} /* end LibCfgLineLoad */
Пример #8
0
/* ApiPropertyLineLoad
 * \ingroup intPlatform
 *
 * \desc            Load API text configuration line.
 *                                                                      \lb\lb
 * \param[in]       line is the config line to load.
 *
 * \return          FM_OK if successful.
 * \return          Other ''Status Codes'' as appropriate in case of
 *                  failure.
 *
 *****************************************************************************/
static fm_status ApiPropertyLineLoad(fm_text line)
{
    fm_status status;
    fm_byte   tlv[FM_TLV_MAX_BUF_SIZE];

    status = fmUtilConfigPropertyEncodeTlv(line, tlv, sizeof(tlv));

    if (status)
    {
        FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
            "Unable to encode API property: [%s]\n", line);
        return status;
    }

    return fmLoadApiPropertyTlv(tlv);

} /* end ApiPropertyLineLoad */
Пример #9
0
/* _fmPlatformFm10000I2cWriteRead
 * \ingroup intPlatformfm10000I2c
 *
 * \desc            Write to then immediately read from an I2C device with
 *                  handling max response bytes using switch as I2C master.
 *
 * \param[in]       handle is the memory pointer to the switch.
 *
 * \param[in]       device is the I2C device address (0x00 - 0x7F).
 *
 * \param[in,out]   data points to an array from which data is written and
 *                  into which data is read.
 *
 * \param[in]       wl is the number of bytes to write.
 *
 * \param[in]       rl is the number of bytes to read.
 *
 * \return          FM_OK if successful.
 * \return          Other ''Status Codes'' as appropriate in case of
 *                  failure.
 *
 *****************************************************************************/
static fm_status _fmPlatformFm10000I2cWriteRead(fm_uintptr handle,
                                                fm_uint    device,
                                                fm_byte   *data,
                                                fm_uint    wl,
                                                fm_uint    rl)
{
    fm_status      status;
    fm_uint32      regValue;
    fm_uint        i;
    fm_uint        j;
    fm_bool        isTimeout;
    struct timeval startTime;
    fm_uint32     *memPtr;
    fm_uint32      tmp;

    if (i2cDebug & 0x4) 
    {
        FM_LOG_PRINT("fmPlatformfm10000I2cWriteRead "
                     "handle=%p device=0x%x wl=%d rl=%d\n",
                      (void*)handle, device, wl, rl);
    }

    memPtr = (fm_uint32*)handle;

    if (rl > I2C_MAX_LEN)
    {
        FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT);
    }

    if (wl > I2C_MAX_LEN)
    {
        FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT);
    }

    if (data == NULL)
    {
        FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT);
    }

    for (i = 0 ; i < (wl+3)/4 ; i++)
    {
        regValue = 0;
        for (j = 0 ; j < 4 ; j++)
        {
            if ((i*4 + j) < wl)
            {
                regValue |= (data[i*4 + j] << ((3 - j)*8));
            }
        }
        status = WriteSwitchMemMap(memPtr, FM10000_I2C_DATA(i), regValue);
        FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_PLATFORM, status);
        if (i2cDebug & 0x4)
        {
            FM_LOG_PRINT("WRITEDATA#%d : 0x%08x\n",i, regValue); 
        }
    }

    regValue = 0;
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Addr, (device  << 1));
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 0);
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, LengthW, wl);
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, LengthR, rl);

    if (i2cDebug & 0x4)
    {
         FM_LOG_PRINT("WRITE: eg 0x%08x Cmd %d wl %d rl %d "
                      "Comp %x LenSent %d intr %d\n",
                      regValue,
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                      FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));
    }

    status = WriteSwitchMemMap(memPtr, FM10000_I2C_CTRL, regValue);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_PLATFORM, status);

    status = ReadSwitchMemMap(memPtr, FM10000_I2C_CTRL, &tmp);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_PLATFORM, status);
    if (i2cDebug & 0x4)
    {
        FM_LOG_PRINT("READ: %d reg 0x%08x Cmd %d wl %d rl %d "
                     "Comp %x LenSent %d intr %d\n", status, tmp,
                     FM_GET_FIELD(tmp, FM10000_I2C_CTRL, Command),
                     FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthW),
                     FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthR),
                     FM_GET_FIELD(tmp, FM10000_I2C_CTRL, CommandCompleted),
                     FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthSent),
                     FM_GET_BIT(tmp, FM10000_I2C_CTRL, InterruptPending));
    }

    /* Now change command to start the transaction */
    if (rl == 0) 
    {
        /* Write only allow write of 0 length */
        FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 1);
    }
    else if ((wl > 0) && (rl > 0))
    {
        /* Write Read */
        FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 2);
    }
    else
    {
        /* Read */
        FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 3);
    }

    if (i2cDebug & 0x4) 
    {
        FM_LOG_PRINT("WRITE2: reg 0x%08x Cmd %d wl %d rl %d "
                     "Comp %x LenSent %d intr %d\n", regValue,
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                     FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));
    }

    status = WriteSwitchMemMap(memPtr, FM10000_I2C_CTRL, regValue);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_PLATFORM, status);

    status = ReadSwitchMemMap(memPtr, FM10000_I2C_CTRL, &regValue);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_PLATFORM, status);
    if (i2cDebug & 0x4) 
    {
        FM_LOG_PRINT("READ2: %d reg 0x%08x Cmd %d wl %d rl %d "
                     "Comp %x LenSent %d intr %d\n", status, regValue,
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                     FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                     FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));
    }

    /* Poll to check for command done */
    gettimeofday(&startTime, NULL);
    isTimeout = FALSE;
    do
    {
        usleep(10000);
        if (isTimeout)
        {
            FM_LOG_ERROR(
                   FM_LOG_CAT_PLATFORM, 
                   "Dev=0x%02x: Timeout (%d msec) waiting "
                   "for I2C_CTRL(0x%x).CommandCompleted!=0. 0x%02x\n",
                   device,
                   I2C_TIMEOUT,
                   FM10000_I2C_CTRL, 
                   FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted));

            FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_ERR_I2C_NO_RESPONSE);
        }

        /* Variable isTimeout is used to improve the timeout detecting */
        if (GetTimeIntervalMsec(&startTime, NULL) > I2C_TIMEOUT)
        {
            isTimeout = TRUE;
        }

        status = ReadSwitchMemMap(memPtr, FM10000_I2C_CTRL, &regValue);
        if (i2cDebug & 0x4)
        {
            FM_LOG_PRINT(
                   "STATUS: %d reg 0x%08x cmd %d wl %d rl %d "
                   "Comp %x LenSent %d intr %d\n", status, regValue,
                   FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                   FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                   FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                   FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                   FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                   FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));
        }

        if (status) break;

    } while (FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted) == 0);

    if (FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted) != 1)
    {
        if (FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted) == 3)
        {
            if (i2cDebug & 0x4)
            {
                FM_LOG_PRINT("No ACK received for address 0x%02x\n", device);
            }
        }
        else
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Dev=0x%02x: I2C Command completed with error 0x%x. "
                         "I2C_CTRL(0x%x)=0x%x\n",
                         device,
                         FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                         FM10000_I2C_CTRL,
                         regValue);
        }

        FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_ERR_I2C_NO_RESPONSE);
    }

    for (i = 0 ; i < (rl+3)/4 ; i++)
    {
        status = ReadSwitchMemMap(memPtr, FM10000_I2C_DATA(i), &regValue);
        FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_PLATFORM, status);

        if (i2cDebug & 0x4)
        {
            FM_LOG_PRINT("READDATA#%d : 0x%08x\n",i, regValue);
        }

        for (j = 0 ; j < 4 ; j++)
        {
            if ((i*4 + j) < rl)
            {
                data[i*4 + j] = (regValue >> ((3 - j)*8)) & 0xFF;
            }
        }
    }
Пример #10
0
/** fmParityRepairTask
 * \ingroup intParity
 * 
 * \chips           FM10000
 *
 * \desc            Generic thread wrapper for chip specific parity
 *                  repair handler.
 *
 * \param[in]       args contains a pointer to the thread information.
 *
 * \return          Should never exit.
 *
 *****************************************************************************/
void * fmParityRepairTask(void * args)
{
    fm_thread * thread;
    fm_switch * switchPtr;
    fm_thread * eventHandler;
    fm_status   err;
    fm_int      sw;
    fm_bool     switchProtected = FALSE;

    thread       = FM_GET_THREAD_HANDLE(args);
    eventHandler = FM_GET_THREAD_PARAM(fm_thread, args);

    /* If logging is disabled, thread and eventHandler won't be used */
    FM_NOT_USED(thread);
    FM_NOT_USED(eventHandler);

    FM_LOG_ENTRY(FM_LOG_CAT_SWITCH,
                 "thread=%s, eventHandler=%s\n",
                 thread->name,
                 eventHandler->name);

    /**************************************************
     * Loop forever.
     **************************************************/

    for (;;)
    {
        /* Wait for something to do. */
        err = fmWaitSemaphore(&fmRootApi->parityRepairSemaphore,
                              FM_WAIT_FOREVER);

        if (err != FM_OK && err != FM_ERR_SEM_TIMEOUT)
        {
            FM_LOG_ERROR(FM_LOG_CAT_PARITY,
                         "Unexpected error from fmWaitSemaphore: %s\n",
                         fmErrorMsg(err));
            continue;
        }

        /* Process each active switch in turn. */
        for (sw = FM_FIRST_FOCALPOINT ; sw <= FM_LAST_FOCALPOINT ; sw++)
        {
            if (!SWITCH_LOCK_EXISTS(sw))
            {
                continue;
            }

            PROTECT_SWITCH(sw);
            switchProtected = TRUE;

            switchPtr = GET_SWITCH_PTR(sw);

            if ( switchPtr &&
                (switchPtr->state == FM_SWITCH_STATE_UP) &&
                 switchPtr->parityRepairEnabled &&
                 switchPtr->ParityRepairTask )
            {
                switchPtr->ParityRepairTask(sw, &switchProtected, args);
            }

            if (switchProtected)
            {
                UNPROTECT_SWITCH(sw);
            }
        }

        fmYield();
        
    }   /* for (;;) */

    /**************************************************
     * Should never exit.
     **************************************************/

    FM_LOG_ERROR(FM_LOG_CAT_PARITY,
                 "fmParityRepairTask exiting inadvertently!\n");

    fmExitThread(thread);
    return NULL;

}   /* end fmParityRepairTask */
Пример #11
0
/** ProcessSample
 * \ingroup intFastMaint
 *
 * \desc            Processes a register sample from the MA_USED_TABLE.
 *
 * \param[in]       sw is the switch on which to operate
 * 
 * \param[in]       index is the index of the first entry in the
 *                  MA_USED_TABLE to be read.
 * 
 * \param[in]       numWords is the number of entries in the MA_USED_TABLE
 *                  to be read.
 * 
 * \param[in]       currentTime is the current value of the aging timer.
 * 
 * \param[in]       agingTime is the length of time required for an entry
 *                  to age from YOUNG to OLD.
 * 
 * \param[in]       expiryTime is the length of time required for an entry
 *                  to age out.
 * 
 * \param[in,out]   stats points to a structure containing a number of
 *                  counters that will be incremented to show the number
 *                  of MA Table entries that are updated.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
static fm_status ProcessSample(fm_int          sw,
                               fm_int          index,
                               fm_int          numWords,
                               fm_uint64       currentTime,
                               fm_uint64       agingTime,
                               fm_uint64       expiryTime,
                               fm_sweepStats * stats)
{
    fm_internalMacAddrEntry * cachePtr;

    fm_switch *     switchPtr;
    fm_uint32       used[numWords];
    fm_status       status;
    fm_int          entryIndex;
    fm_int          i;
    fm_int          j;
    fm_uint64       elapsedTime;
    fm_sweepStats   sampleStats;

    switchPtr = GET_SWITCH_PTR(sw);

    FM_CLEAR(sampleStats);

    FM_TAKE_L2_LOCK(sw);

    /* Read next sample from MA_USED_TABLE. */
    status = switchPtr->ReadUINT32Mult(sw,
                                       FM10000_MA_USED_TABLE(1, index),
                                       numWords,
                                       used);

    if (status != FM_OK)
    {
        FM_DROP_L2_LOCK(sw);
        FM_LOG_ERROR(FM_LOG_CAT_EVENT_FAST_MAINT,
                     "Error reading MA_USED_TABLE: %s\n",
                     fmErrorMsg(status));
        goto ABORT;
    }

    /* Clear any hits we detected. */
    status = switchPtr->WriteUINT32Mult(sw,
                                        FM10000_MA_USED_TABLE(1, index),
                                        numWords,
                                        used);

    if (status != FM_OK)
    {
        FM_DROP_L2_LOCK(sw);
        FM_LOG_ERROR(FM_LOG_CAT_EVENT_FAST_MAINT,
                     "Error writing MA_USED_TABLE: %s\n",
                     fmErrorMsg(status));
        goto ABORT;
    }

    /* Process each word in the sample. */
    for (i = 0 ; i < numWords ; ++i)
    {
        /* Process each bit in the word. */
        for (j = 0 ; j < ENTRIES_PER_WORD ; ++j)
        {
            /* Get the MA Table entry corresponding to this bit. */
            entryIndex = (index + i) * ENTRIES_PER_WORD + j;
            cachePtr   = &switchPtr->maTable[entryIndex];

            /* We only care about dynamic entries that are eligible
             * for aging. If it's not one of these, keep going. */
            if (cachePtr->state != FM_MAC_ENTRY_STATE_OLD &&
                cachePtr->state != FM_MAC_ENTRY_STATE_YOUNG)
            {
                continue;
            }

            /* If the entry is USED, set its state to YOUNG
             * and restart its aging timer. */
            if (used[i] & (1 << j))
            {
                cachePtr->state = FM_MAC_ENTRY_STATE_YOUNG;
                cachePtr->agingCounter = currentTime;
                ++sampleStats.young;
                continue;
            }

            /* Get the age of this entry. */
            elapsedTime = currentTime - cachePtr->agingCounter;

            if (elapsedTime >= expiryTime)
            {
                /* The entry has aged out. */
                cachePtr->state = FM_MAC_ENTRY_STATE_EXPIRED;
                ++sampleStats.expired;
                FM_LOG_DEBUG(FM_LOG_CAT_EVENT_FAST_MAINT,
                             "expired: index=%d mac=%012llx vid=%u "
                             "elapsed=%llu\n",
                             entryIndex,
                             cachePtr->macAddress,
                             cachePtr->vlanID,
                             elapsedTime);
            }
            else if (cachePtr->state == FM_MAC_ENTRY_STATE_YOUNG &&
                     elapsedTime >= agingTime)
            {
                /* The entry has gone from YOUNG to OLD. */
                cachePtr->state = FM_MAC_ENTRY_STATE_OLD;
                ++sampleStats.old;
                FM_LOG_DEBUG(FM_LOG_CAT_EVENT_FAST_MAINT,
                             "aged: index=%d mac=%012llx vid=%u "
                             "elapsed=%llu\n",
                             entryIndex,
                             cachePtr->macAddress,
                             cachePtr->vlanID,
                             elapsedTime);
            }

        }   /* end for (j = 0 ; j < ENTRIES_PER_WORD ; ++j) */

    }   /* for (i = 0 ; i < numWords ; ++i) */

    FM_DROP_L2_LOCK(sw);

ABORT:
    stats->young   += sampleStats.young;
    stats->old     += sampleStats.old;
    stats->expired += sampleStats.expired;

    return status;

}   /* end ProcessSample */
Пример #12
0
/** fmOpenDynamicLoadLibs
 * \ingroup alosDynLoadLib
 *
 * \desc            Open a Dynamic Load Library.
 *
 * \param[in]       filePath points to the string containing the library path.
 *
 * \param[out]      handle points to caller-provided memory into which the
 *                  dynamic-load-library's handle will be written.
 *
 * \return          FM_ERR_UNINITIALIZED if the ALOS subsystem has not been
 *                  properly initialized.
 * \return          FM_ERR_INVALID_ARGUMENT if one of the arguments is invalid.
 * \return          FM_OK if successful.
 * \return          FM_ERR_NO_MEM if unable to allocate memory.
 * \return          FM_ERR_TABLE_FULL if the dynamic-load library table is full.
 * \return          FM_ERR_NOT_FOUND if the dynamic-load library open failed.
 *
 *****************************************************************************/
fm_status fmOpenDynamicLoadLibrary(fm_text filePath, fm_int *handle)
{
    fm_status      err;
    fm_int         index;
    fm_dynLoadLib *lib;
    fm_int         availIndex;
    fm_int         pathLen;
    fm_bool        lockTaken;
    fm_bool        libAllocated;
    void *         libHandle;

    FM_LOG_ENTRY( FM_LOG_CAT_ALOS_DLLIB,
                  "filePath = %p (%s), handle = %p\n",
                  (void *) filePath,
                  (filePath != NULL) ? filePath : "<NULL>",
                  (void *) handle );

    lib          = NULL;
    availIndex   = -1;
    lockTaken    = FALSE;
    libAllocated = FALSE;

    if (fmRootAlos == NULL)
    {
        FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, FM_ERR_UNINITIALIZED);
    }

    if (filePath == NULL)
    {
        FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, FM_ERR_INVALID_ARGUMENT);
    }

    if (handle == NULL)
    {
        FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, FM_ERR_INVALID_ARGUMENT);
    }

    pathLen = strlen(filePath);

    if (pathLen <= 0)
    {
        FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, FM_ERR_INVALID_ARGUMENT);
    }

    err = fmCaptureLock(&fmRootAlos->dlAccessLock, FM_WAIT_FOREVER);

    FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);

    lockTaken = TRUE;

    for (index = 0 ; index < FM_ALOS_INTERNAL_DYN_LOAD_LIBS ; index++)
    {
        if (fmRootAlos->dlLibs[index] == NULL)
        {
            if (availIndex < 0)
            {
                availIndex = index;
            }
        }
        else
        {
            lib = fmRootAlos->dlLibs[index];

            if ( strcmp(filePath, lib->filePath) == 0 )
            {
                break;
            }
        }
    }

    if (index >= FM_ALOS_INTERNAL_DYN_LOAD_LIBS)
    {
        index = availIndex;
    }

    if (index < 0)
    {
        err = FM_ERR_TABLE_FULL;
        FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);
    }

    lib = fmRootAlos->dlLibs[index];

    if (lib == NULL)
    {
        lib = fmAlloc( sizeof(fm_dynLoadLib) );

        if (lib == NULL)
        {
            err = FM_ERR_NO_MEM;
            FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);
        }

        libAllocated = TRUE;

        FM_CLEAR(*lib);

        lib->filePath = fmAlloc( pathLen + 1 );

        if (lib->filePath == NULL)
        {
            err = FM_ERR_NO_MEM;
            FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);
        }

        FM_STRNCPY_S(lib->filePath, pathLen + 1, filePath, pathLen + 1 );

        lib->useCount = 0;

        fmRootAlos->dlLibs[index] = lib;
    }

    if ( ( fmProcessDynLoadLibStatus & (1 << index) ) == 0 )
    {
        libHandle = dlopen(filePath, RTLD_NOW | RTLD_GLOBAL);

        if (libHandle == NULL)
        {
            char *errMsg = dlerror();
            FM_LOG_ERROR(FM_LOG_CAT_ALOS_DLLIB,
                         "Error opening library %s: %s\n",
                         filePath,
                         errMsg);

            err = FM_ERR_NOT_FOUND;
            FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);
        }

        ProcessHandles[index] = libHandle;

        lib->useCount++;
        
        fmProcessDynLoadLibStatus |= FM_LITERAL_U64(1) << index;
    }

    *handle = index;
    err     = FM_OK;


ABORT:

    if ( (err != FM_OK) && libAllocated )
    {
        if (lib->filePath != NULL)
        {
            fmFree(lib->filePath);
        }

        fmFree(lib);
    }

    if (lockTaken)
    {
        fmReleaseLock(&fmRootAlos->dlAccessLock);
    }

    FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, err);

}   /* end fmOpenDynamicLoadLibrary */
Пример #13
0
/** fmRawPacketSocketSendPackets
 * \ingroup intPlatformCommon
 *
 * \desc            When called, iterates through the packet queue and
 *                  continues to send packets until either the queue empties.
 *
 * \param[in]       sw refers to the switch number to send packets to.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
fm_status fmRawPacketSocketSendPackets(fm_int sw)
{
    fm_status               err = FM_OK;
    fm_switch *             switchPtr;
    fm_packetHandlingState *pktState;
    fm_packetQueue *        txQueue;
    fm_packetEntry *        packet;
    fm_int32                rc;
    fm_buffer               *sendBuf;
    struct msghdr           msg;
    struct iovec            iov[UIO_MAXIOV];
    fm_islTag               islTag;
    fm_uint32               fcs;
    fm_uint64               rawTS;
    char                    strErrBuf[FM_STRERROR_BUF_SIZE];
    errno_t                 strErrNum;
    struct ifreq            ifr;

    FM_LOG_ENTRY(FM_LOG_CAT_EVENT_PKT_TX, "sw = %d\n", sw);

    switchPtr = GET_SWITCH_PTR(sw);
    pktState  = GET_PLAT_PKT_STATE(sw);

    if (GET_PLAT_STATE(sw)->rawSocket <= 0)
    {
        FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_TX, 
                     "Socket is not initialized.\n");
        FM_LOG_EXIT(FM_LOG_CAT_EVENT_PKT_TX, FM_ERR_UNINITIALIZED);
    }

    /* initialize the message header */
    FM_CLEAR(msg);
    msg.msg_name = NULL; /* Optional field */
    msg.msg_namelen = 0;
    msg.msg_iov = iov;
    msg.msg_iovlen = 0;
    msg.msg_flags = 0;

    FM_STRNCPY_S(ifr.ifr_name, IF_NAMESIZE, GET_PLAT_STATE(sw)->ifaceName, IF_NAMESIZE);

    txQueue = &pktState->txQueue;
    fmPacketQueueLock(txQueue);

    if (ioctl(GET_PLAT_STATE(sw)->rawSocket, SIOCGIFFLAGS, &ifr) == -1)
    {
        strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno);
        if (strErrNum == 0)
        {
            FM_LOG_FATAL(FM_LOG_CAT_EVENT_PKT_TX, 
                         "Failed to get socket %d flags for device %s: %s\n",
                         GET_PLAT_STATE(sw)->rawSocket,
                         ifr.ifr_name,
                         strErrBuf);
        }
        else
        {
            FM_LOG_FATAL(FM_LOG_CAT_EVENT_PKT_TX, 
                         "Failed to get socket %d flags for device %s: %d\n",
                         GET_PLAT_STATE(sw)->rawSocket,
                         ifr.ifr_name,
                         errno);
        }
        switchPtr->transmitterLock = TRUE;
        err = FM_FAIL;
        FM_LOG_ABORT(FM_LOG_CAT_EVENT_PKT_TX, err);
    }

    if ((ifr.ifr_flags & IFF_RUNNING) == 0)
    {    
        FM_LOG_WARNING(FM_LOG_CAT_EVENT_PKT_TX,
                       "Network device %s resources are not allocated.\n",
                       ifr.ifr_name);
        switchPtr->transmitterLock = TRUE;
        err = FM_FAIL;
        FM_LOG_ABORT(FM_LOG_CAT_EVENT_PKT_TX, err);
    }

    /* Iterate through the packets in the tx queue */
    for ( ;
          txQueue->pullIndex != txQueue->pushIndex ;
          txQueue->pullIndex = (txQueue->pullIndex + 1) % FM_PACKET_QUEUE_SIZE)
    {
        packet = &txQueue->packetQueueList[txQueue->pullIndex];

        FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_TX,
                     "sending packet in slot %d, length=%d tag=%d fcs=%08x\n",
                     txQueue->pullIndex, packet->length,
                     packet->suppressVlanTag, packet->fcsVal);
        msg.msg_iovlen = 0;

        /* Add the 8 byte timetag iovec. Note that the value is ignored
         * by the driver as it gets overwritten by the PEP. */
        rawTS = 0;
        iov[msg.msg_iovlen].iov_base = &rawTS;
        iov[msg.msg_iovlen].iov_len = sizeof(rawTS);
        msg.msg_iovlen++;

        if (packet->islTagFormat == FM_ISL_TAG_F56)
        {
            /* Add the FTAG (F56) iovec */
            islTag.f56.tag[0] = htonl(packet->islTag.f56.tag[0]);
            islTag.f56.tag[1] = htonl(packet->islTag.f56.tag[1]);
            iov[msg.msg_iovlen].iov_base = &islTag.f56.tag[0];
            iov[msg.msg_iovlen].iov_len = FM_F56_BYTE_LEN;
            msg.msg_iovlen++;
        }
        
        /* iterate through all buffers */
        for ( sendBuf = packet->packet ; sendBuf ; sendBuf = sendBuf->next )
        {
            /* if first buffer ... */
            if (sendBuf == packet->packet)
            {
                /* Cannot modify the send buffer, since the same buffer can be
                 * used multiple times to send to multiple ports */

                /* second iovec is the mac header */
                iov[msg.msg_iovlen].iov_base = sendBuf->data;
                iov[msg.msg_iovlen].iov_len = FM_MAC_HDR_BYTE_LEN;
                msg.msg_iovlen++;

                if (packet->islTagFormat == FM_ISL_TAG_F64)
                {
                    /* Insert the F64 ISL tag */
                    islTag.f64.tag[0] = htonl(packet->islTag.f64.tag[0]);
                    islTag.f64.tag[1] = htonl(packet->islTag.f64.tag[1]);
                    iov[msg.msg_iovlen].iov_base = &islTag.f64.tag[0];
                    iov[msg.msg_iovlen].iov_len = FM_F64_BYTE_LEN;
                    msg.msg_iovlen++;
                }

                /* Third is the data in the first chain */
                if (packet->suppressVlanTag)
                {
                    iov[msg.msg_iovlen].iov_base = &sendBuf->data[4];
                    iov[msg.msg_iovlen].iov_len = sendBuf->len-16;
                    msg.msg_iovlen++;
                }
                else
                {
                    iov[msg.msg_iovlen].iov_base = &sendBuf->data[3];
                    iov[msg.msg_iovlen].iov_len = sendBuf->len-12;
                    msg.msg_iovlen++;
                }
            }
            else
            {
                /* The rest of the chain */
                iov[msg.msg_iovlen].iov_base = sendBuf->data;
                iov[msg.msg_iovlen].iov_len = sendBuf->len;
                msg.msg_iovlen++;
            }

        }   /* end for (...) */

        /* Append user-supplied FCS value to packet. */
        if (pktState->sendUserFcs)
        {
            fcs = htonl(packet->fcsVal);
            iov[msg.msg_iovlen].iov_base = &fcs;
            iov[msg.msg_iovlen].iov_len = sizeof(fcs);
            msg.msg_iovlen++;
        }

        /* now send it to the driver */
        errno = 0;
        rc = sendmsg(GET_PLAT_STATE(sw)->rawSocket, &msg, MSG_DONTWAIT);
        if (rc == -1)
        {
            switchPtr->transmitterLock = TRUE;
            if (errno != EWOULDBLOCK)
            {
                err = FM_FAIL;

                FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_TX,
                             "rawSocket %d\n",
                             GET_PLAT_STATE(sw)->rawSocket);

                strErrNum = FM_STRERROR_S(strErrBuf,
                                          FM_STRERROR_BUF_SIZE,
                                          errno);
                if (strErrNum == 0)
                {
                    FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_TX,
                                 "sendmsg failed: %s - errno %d\n",
                                 strErrBuf,
                                 errno);
                }
                else
                {
                    FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_TX, 
                                 "sendmsg failed - errno %d\n", errno);
                }
            }
            if (errno == EMSGSIZE)
            {
                switchPtr->transmitterLock = FALSE;
            }
            else
            {
                goto ABORT;
            }
        }
        else
        {
            FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_TX, "%d bytes were sent\n", rc);

            switchPtr->transmitterLock = FALSE;
            fmDbgDiagCountIncr(sw, FM_CTR_TX_PKT_COMPLETE, 1);
        }

        /**************************************************
         * free buffer only when
         * (1) sending to a single port;
         * or (2) this is the last packet of multiple 
         * identical packets
         **************************************************/

        if (packet->freePacketBuffer)
        {
            /* ignore the error code since it's better to continue */
            (void) fmFreeBufferChain(sw, packet->packet);

            fmDbgGlobalDiagCountIncr(FM_GLOBAL_CTR_TX_BUFFER_FREES, 1);
        }
    }

ABORT:
    fmPacketQueueUnlock(txQueue);

    FM_LOG_EXIT(FM_LOG_CAT_EVENT_PKT_TX, err);

}   /* end fmRawPacketSocketSendPackets */
Пример #14
0
/** fmReceivePacketTask
 * \ingroup intApi
 *
 * \desc            Handles reception of packets.
 *
 * \param[in]       args contains a pointer to the thread information.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
void *fmReceivePacketTask(void *args)
{
    fm_thread *thread;
    fm_status  err = FM_OK;
    fm_int     sw;

    thread = FM_GET_THREAD_HANDLE(args);

    FM_LOG_ENTRY(FM_LOG_CAT_SWITCH,
                 "thread = %s\n",
                 thread->name);


    /**************************************************
     * Loop forever, waiting for signals from the
     * interrupt handler.
     **************************************************/

    while (TRUE)
    {
        /**************************************************
         * Wait for a signal from the interrupt handler.
         **************************************************/

        FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_RX,
                     "fmLCIReceivePacketTask: waiting for signal..\n");

        err = fmWaitSemaphore(&fmRootApi->packetReceiveSemaphore,
                              FM_WAIT_FOREVER);

        if (err != FM_OK)
        {
            FM_LOG_ERROR( FM_LOG_CAT_SWITCH,
                         "%s: %s\n",
                         thread->name,
                         fmErrorMsg(err) );
            continue;
        }

        FM_LOG_DEBUG(FM_LOG_CAT_EVENT_PKT_RX,
                     "fmReceivePacketTask: signaled!\n");

        for (sw = FM_FIRST_FOCALPOINT ; sw <= FM_LAST_FOCALPOINT ; sw++)
        {
            if ( (fmRootApi->fmSwitchStateTable[sw] != NULL) 
                  && (!fmRootApi->isSwitchFibmSlave[sw]) )
            {

                fmReceivePacket(sw);
            }
        }

    } /* end while (TRUE) */

    /**************************************************
     * Should never exit.
     **************************************************/

    FM_LOG_ERROR(FM_LOG_CAT_SWITCH,
                 "ERROR: fmReceivePacketTask: exiting inadvertently!\n");

    return NULL;

}   /* end fmReceivePacketTask */
Пример #15
0
/** fmDistributeEvent
 * \ingroup intSwitch
 *
 * \desc            distributes events to those processes that have registered
 *                  an interest in the particular event.
 *
 * \param[in]       event points to the event structure.
 *
 * \return          Nothing.
 *
 *****************************************************************************/
void fmDistributeEvent(fm_event *event)
{
    fmCaptureLock(&fmRootApi->localDeliveryLock, FM_WAIT_FOREVER);

    {
        /**************************************************
         * We want to have a consistent snapshot of the
         * local delivery list, but we don't want to hold
         * the lock while we deliver all the events, so we
         * briefly grab the lock and copy the list into a
         * C99 variable-size array.
         **************************************************/

        fm_uint          count = fmRootApi->localDeliveryCount;
        fm_localDelivery delivery[count];
        fm_dlist_node *  node;
        fm_uint          i;
        fm_uint          pktDeliveryCount = 0;
        fm_eventPktRecv *rcvPktEvent = NULL;
        fm_status        status;
        fm_buffer        *buffer;

        node = FM_DLL_GET_FIRST( (&fmRootApi->localDeliveryThreads), head );

        for (i = 0 ; (node != NULL) && (i < count) ; i++)
        {
            delivery[i] = *(fm_localDelivery *) node->data;

            if ( (delivery[i].mask & 
                  (FM_EVENT_PKT_RECV | FM_EVENT_SFLOW_PKT_RECV)) &
                  event->type )
            {
                /* Found thread we need to deliver packet to. */
                pktDeliveryCount++;
            }

            node = FM_DLL_GET_NEXT(node, next);
        }

        /**************************************************
         * If the event is packet receive but no one has
         * registered for the event, free the associated
         * packet buffer and return.
         **************************************************/

        if ( ( (event->type == FM_EVENT_PKT_RECV) ||
               (event->type == FM_EVENT_SFLOW_PKT_RECV) ) 
             && (pktDeliveryCount == 0) )
        {
            rcvPktEvent = &event->info.fpPktEvent;
            if (enableFramePriority)
            {
                status = fmFreeBufferQueueNode(event->sw, rcvPktEvent);
                if (status != FM_OK)
                {
                    FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_RX,
                                 "Freeing Buffer queue node from the queue failed"
                                 "status = %d (%s) \n",
                                  status,
                                  fmErrorMsg(status));

                }
            }
            fmFreeBufferChain(event->sw, rcvPktEvent->pkt);
            fmDbgDiagCountIncr(event->sw, FM_CTR_RX_API_PKT_DROPS, 1);
            fmReleaseLock(&fmRootApi->localDeliveryLock);
            return;
        }

        /* valid actually found */
        count = i;
        fmReleaseLock(&fmRootApi->localDeliveryLock);

        /**************************************************
         * Now we do the actual delivery
         **************************************************/

        for (i = 0 ; i < count ; i++)
        {
            fm_event *localEvent = NULL;
            fm_uint64 nanos      = MIN_WAIT_NANOS;
            fm_status err        = FM_FAIL;
            fm_uint32 numUpdates;

            if ( (delivery[i].mask & event->type) == 0 )
            {
                continue;
            }

            /**************************************************
             * Always use high priority for the locally dispatched
             * events, because DistributeEvent is only called from
             * a single thread (the global event handler), and if
             * we allocated both low and high priority events here,
             * we could get priority inversion.
             **************************************************/

            while (localEvent == NULL)
            {
                localEvent = fmAllocateEvent(event->sw,
                                             event->eventID,
                                             event->type,
                                             FM_EVENT_PRIORITY_HIGH);

                if (localEvent == NULL)
                {
                    DELAY_NANOS(nanos);
                    nanos *= 2;

                    if (nanos > MAX_WAIT_NANOS)
                    {
                        nanos = MAX_WAIT_NANOS;
                        FM_LOG_WARNING(FM_LOG_CAT_EVENT,
                                       "Waiting to allocate event of type %d "
                                       "for switch %d\n",
                                       event->type,
                                       event->sw);
                    }
                }
            }

            if (event->type == FM_EVENT_TABLE_UPDATE)
            {
                /**************************************************
                 * Because the updates field is a pointer to memory
                 * that has been "secretly" allocated after the event,
                 * rather than just being part of the union, we have
                 * to handle it specially.
                 **************************************************/

                numUpdates = event->info.fpUpdateEvent.numUpdates;
                localEvent->info.fpUpdateEvent.numUpdates = numUpdates;
                FM_MEMCPY_S( localEvent->info.fpUpdateEvent.updates,
                             numUpdates * sizeof(fm_eventTableUpdate),
                             event->info.fpUpdateEvent.updates,
                             numUpdates * sizeof(fm_eventTableUpdate) );
            }
            else if (event->type == FM_EVENT_PURGE_SCAN_COMPLETE)
            {
                localEvent->info.purgeScanComplete = event->info.purgeScanComplete;
            } 
            else if ( (event->type == FM_EVENT_PKT_RECV) ||
                      (event->type == FM_EVENT_SFLOW_PKT_RECV) )
            {
                rcvPktEvent = &event->info.fpPktEvent;

                /**************************************************
                 * Copy the whole event, including the packet, to
                 * localEvent. If this is not the last registered
                 * client, we will overwrite the packet with a
                 * clone.
                 **************************************************/

                localEvent->info = event->info;

                /**************************************************
                 * If there is more than one remaining process that is
                 * interested in receive packet events, clone the
                 * receive buffer for delivery.
                 **************************************************/

                if (pktDeliveryCount-- > 1)
                {
                    if (enableFramePriority)
                    {
                        FM_LOG_ERROR(FM_LOG_CAT_EVENT,
                                     "Prioritization is supported only for the"
                                     "first registered process. Subsequent "
                                     "processes follow normal buffer allocation"
                                     " without prioritization.\n");
                    }
                    localEvent->info.fpPktEvent.pkt =
                        fmDuplicateBufferChain(event->sw, rcvPktEvent->pkt);

                    if (localEvent->info.fpPktEvent.pkt == NULL)
                    {
                        /**************************************************
                         * Couldn't copy the packet. Free the event so that
                         * it is not lost and continue the loop.
                         **************************************************/

                        fmReleaseEvent(localEvent);
                        fmDbgDiagCountIncr(event->sw, FM_CTR_RX_API_PKT_DROPS, 1);
                        continue;
                    }

                }

                if (enableFramePriority)
                {
                    buffer = ((fm_buffer *)(localEvent->info.fpPktEvent.pkt));
                    buffer->recvEvent = localEvent;
                }
            }
            else
            {
                /**************************************************
                 * Otherwise, we can just copy the whole union
                 * without worrying what type it is.
                 **************************************************/

                localEvent->info = event->info;
            }

            /**************************************************
             * Now try to send the event to the local dispatch
             * thread, using exponential backoff if the event
             * queue is full.
             **************************************************/

            nanos = MIN_WAIT_NANOS;

            while (err != FM_OK)
            {
                err = fmSendThreadEvent(delivery[i].thread, localEvent);

                if (err != FM_OK)
                {
                    DELAY_NANOS(nanos);
                    nanos *= 2;

                    if (nanos > MAX_WAIT_NANOS)
                    {
                        nanos = MAX_WAIT_NANOS;
                    }

                }   /* end if (err != FM_OK) */

            }   /* end while (err != FM_OK) */

        }   /* end for (i = 0 ; i < count ; i++) */

    }   /* end (local scope) */

}   /* end fmDistributeEvent */
Пример #16
0
/** fmGlobalEventHandler
 * \ingroup intSwitch
 *
 * \desc            event handler for handling system events
 *
 * \param[in]       args points to the thread arguments
 *
 * \return          Nothing.
 *
 *****************************************************************************/
void *fmGlobalEventHandler(void *args)
{
    fm_thread *               thread;
    fm_event *                event;
    fm_status                 err       = FM_OK;
    fm_eventPort *            portEvent = NULL;
    fm_eventTableUpdateBurst *updateEvent;
    fm_int                    physPort;
    fm_int                    logicalPort;
    fm_eventPktRecv *         rcvPktEvent;
    fm_eventSwitchInserted *  insertEvent;
    fm_eventSwitchRemoved *   removeEvent;
    fm_int                    sw = 0;
    fm_bool                   discardEvent;
    fm_port *                 portPtr = NULL;
    fm_bool                   switchIsProtected;
    fm_switch *               switchPtr;
    fm_int                    mode;
    fm_int                    info[8];
    fm_int                    state;
    fm_int                    numLanes;
    fm_uint32                 i;
    fm_bool                   isPhysicalSwitch;
    fm_switchEventHandler     eventHandler;
    fm_bool                   distributeEvent;
    fm_eventTableUpdate *     fpUpdateEvent;

    /* grab arguments */
    thread = FM_GET_THREAD_HANDLE(args);

    /* wait for initialization to finish before processing events */
    fmCaptureSemaphore(&fmRootApi->startGlobalEventHandler, FM_WAIT_FOREVER);

    enableFramePriority = GET_PROPERTY()->priorityBufQueues;

    while (1)
    {
        /* wait forever for an event */
        err = fmGetThreadEvent(thread, &event, FM_WAIT_FOREVER);

        if (err == FM_ERR_NO_EVENTS_AVAILABLE)
        {
            /* A timeout occurred - should never happen. */
            continue;
        }

        if (event == NULL)
        {
            /* NULL event should never happen. */
            continue;
        }

        sw                = event->sw;
        discardEvent      = FALSE;
        switchIsProtected = FALSE;
        switchPtr         = NULL;

        if (sw < 0 || sw >= fmRootPlatform->cfg.numSwitches)
        {
            discardEvent      = TRUE;
            switchIsProtected = FALSE;
        }
        else if ( SWITCH_LOCK_EXISTS(sw) )
        {
            if ( ( err = PROTECT_SWITCH(sw) ) != FM_OK )
            {
                discardEvent      = TRUE;
                switchIsProtected = FALSE;
            }
            else
            {
                switchIsProtected = TRUE;
                switchPtr         = fmRootApi->fmSwitchStateTable[sw];

                if (!fmRootApi->fmSwitchStateTable[sw])
                {
                    if ((event->type != FM_EVENT_SWITCH_REMOVED) &&
                        (event->type != FM_EVENT_SWITCH_INSERTED) )
                    {
                        discardEvent = TRUE;
                    }
                }
                else if (fmRootApi->fmSwitchStateTable[sw]->state != FM_SWITCH_STATE_UP)
                {
                    if ((event->type != FM_EVENT_SWITCH_REMOVED) &&
                        (event->type != FM_EVENT_SWITCH_INSERTED) )
                    {
                        discardEvent = TRUE;
                    }
                }
            }
        }
        else if (event->type != FM_EVENT_SWITCH_INSERTED)
        {
            discardEvent = TRUE;
        }


        if (discardEvent)
        {
            switch (event->type)
            {
                case FM_EVENT_PKT_RECV:
                case FM_EVENT_SFLOW_PKT_RECV:
                    /* Only dig into the event if the switch is valid */
                    if  ( (sw >= 0) && (sw < fmRootPlatform->cfg.numSwitches) )
                    {
                        rcvPktEvent = &event->info.fpPktEvent;
                        if (enableFramePriority)
                        {
                            err = fmFreeBufferQueueNode(sw, rcvPktEvent);
                            if (err != FM_OK)
                            {
                                FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_RX,
                                             "Freeing Buffer queue node from the queue failed"
                                             "status = %d (%s) \n",
                                              err,
                                              fmErrorMsg(err));

                            }
                        }
                        fmFreeBufferChain(sw, rcvPktEvent->pkt);
                        fmDbgDiagCountIncr(sw, FM_CTR_RX_API_PKT_DROPS, 1);
                    }
                    break;

                default:
                    break;
            }

            goto FINISHED;
        }

        eventHandler     = NULL;

        if (switchPtr != NULL)
        {
            /* If the switch state table has an eventHandler pointer,
             * it overrides the global handler.  Call the switch-specific
             * function to handle the event.  This is intended to be used
             * for switches in a switch aggregate (and potentially
             * nested switch aggregates inside other switch aggregates?).
             */
            eventHandler = switchPtr->eventHandler;

            switch (switchPtr->switchModel)
            {
                case FM_SWITCH_MODEL_SWAG:
                    isPhysicalSwitch = FALSE;
                    break;

                default:
                    isPhysicalSwitch = TRUE;
                    break;
            }
        }
        else
        {
            /* Only physical switches should ever get here with a NULL pointer
             * because logical switches such as switch aggregates are always
             * created by application code before any events related to
             * the switch are possible.
             */
            isPhysicalSwitch = TRUE;
        }

        distributeEvent = FALSE;

        switch (event->type)
        {
            case FM_EVENT_SWITCH_INSERTED:
                insertEvent = &event->info.fpSwitchInsertedEvent;
                
                if (switchIsProtected)
                {
                    UNPROTECT_SWITCH(sw);
                    switchIsProtected = FALSE;
                }

                if (switchPtr == NULL)
                {
                    if (fmHandleSwitchInserted(sw, insertEvent) != FM_OK)
                    {
                        /* Don't generate an insert event if there error */
                        goto FINISHED;
                    }
                }

                distributeEvent = TRUE;

                break;

            case FM_EVENT_SWITCH_REMOVED:
                removeEvent = &event->info.fpSwitchRemovedEvent;

                if (switchIsProtected)
                {
                    UNPROTECT_SWITCH(sw);
                    switchIsProtected = FALSE;
                }

                if (switchPtr != NULL)
                {
                    fmHandleSwitchRemoved(sw, removeEvent);
                }

                distributeEvent = TRUE;
                break;

            case FM_EVENT_PORT:
                portEvent = &event->info.fpPortEvent;

                if (isPhysicalSwitch && portEvent->activeMac)
                {
                    logicalPort = portEvent->port;

                    if (switchPtr != NULL)
                    {
                        fmMapLogicalPortToPhysical(switchPtr,
                                                   logicalPort,
                                                   &physPort);

                        portPtr = switchPtr->portTable[logicalPort];
                    }
                    else
                    {
                        portPtr = NULL;
                    }

                    if (portPtr == NULL)
                    {
                        FM_LOG_ERROR(FM_LOG_CAT_EVENT_PORT,
                                     "Unexpected NULL port pointer for logical"
                                     " port %d\n",
                                     logicalPort);
                        break;
                    }

                    /* This attribute indicate whether the API should flush
                     * all the addresses on a port down event or not. */
                    if (GET_PROPERTY()->maFlushOnPortDown)
                    {
                        /* If a link goes down for a non-LAG port, remove any
                         * addresses associated with the port from the MA Table. */
                        if (portEvent->linkStatus == FM_PORT_STATUS_LINK_DOWN)
                        {
                            if (portPtr->portType != FM_PORT_TYPE_LAG)
                            {
                                err = fmFlushPortAddresses(sw, portEvent->port);

                                if (err != FM_OK)
                                {
                                    FM_LOG_WARNING(FM_LOG_CAT_EVENT_PORT,
                                                   "%s\n",
                                                   fmErrorMsg(err));
                                }
                            }
                        }
                    }

                    FM_LOG_DEBUG( FM_LOG_CAT_EVENT_PORT,
                                  "Port %s event reported on port %d.\n",
                                  (portPtr != NULL )
                                    ? ( (portPtr->linkUp) ? "UP  " : "DOWN" )
                                    : "UNKN",
                                  portEvent->port );

                    /* inform LAG module of port state changes */
                    if (portEvent->linkStatus == FM_PORT_STATUS_LINK_UP)
                    {
                        fmInformLAGPortUp(sw, portEvent->port);
                        
                        /* Inform LBGs of port link state change. */
                        FM_API_CALL_FAMILY_VOID(switchPtr->InformLBGLinkChange,
                                                sw, 
                                                portEvent->port, 
                                                FM_PORT_STATUS_LINK_UP);
                    }
                    else if (portEvent->linkStatus == FM_PORT_STATUS_LINK_DOWN)
                    {
                        fmInformLAGPortDown(sw, portEvent->port);
                        
                        /* Inform LBGs of port link state change. */
                        FM_API_CALL_FAMILY_VOID(switchPtr->InformLBGLinkChange,
                                                sw, 
                                                portEvent->port, 
                                                FM_PORT_STATUS_LINK_DOWN);
                    }

                    /* now update all the source masks */
                    fmUpdateSwitchPortMasks(sw);

                    if (switchPtr->UpdateRemoveDownPortsTrigger != NULL)
                    {
                        /**************************************************** 
                         * Update the switchExt->removeDownPortsTrigger
                         * used to drop routed/multicast/special delivery 
                         * frames which can not be handled by the PORT_CFG_2. 
                         * See Bugzilla 11387.
                         ***************************************************/
                        if (portEvent->linkStatus == FM_PORT_STATUS_LINK_UP)
                        {
                            switchPtr->UpdateRemoveDownPortsTrigger(sw, 
                                                                    physPort,
                                                                    FALSE);
                        }
                        else if (portEvent->linkStatus == FM_PORT_STATUS_LINK_DOWN)
                        {
                            if (!portPtr->isPortForceUp)
                            {
                                switchPtr->UpdateRemoveDownPortsTrigger(sw, 
                                                                        physPort,
                                                                        TRUE);
                            }
                        }
                    }

                    if (switchPtr->UpdateMirrorGroups != NULL)
                    {
                        /**************************************************** 
                         * Enable/Disable mirror groups based on the link
                         * status of the mirror port.
                         * See Bugzilla 11387.
                         ***************************************************/
                        if (portEvent->linkStatus == FM_PORT_STATUS_LINK_UP)
                        {
                            switchPtr->UpdateMirrorGroups(sw, 
                                                          logicalPort,
                                                          TRUE);
                        }
                        else if (portEvent->linkStatus == FM_PORT_STATUS_LINK_DOWN)
                        {
                            switchPtr->UpdateMirrorGroups(sw, 
                                                          logicalPort,
                                                          FALSE);
                        }
                    }

                    /* notify anyone else who needs to know */
                    if (portPtr && portPtr->NotifyLinkEvent)
                    {
                        err = portPtr->NotifyLinkEvent(sw, portEvent->port);

                        if (err != FM_OK)
                        {
                            FM_LOG_WARNING(FM_LOG_CAT_EVENT_PORT,
                                           "%s\n",
                                           fmErrorMsg(err));
                        }
                    }

                    /* Get port state and notify platform */

                    err = fmGetPortStateV3( sw,
                                            portEvent->port,
                                            portEvent->mac,
                                            8,
                                            &numLanes,
                                            &mode,
                                            &state,
                                            info );

                    if (err != FM_OK)
                    {
                        FM_LOG_WARNING(FM_LOG_CAT_EVENT_PORT,
                                       "fmGetPortState(%d,%u) failed: %s\n",
                                       sw,
                                       portEvent->port,
                                       fmErrorMsg(err));
                    }

                    fmPlatformNotifyPortState(sw,
                                              portEvent->port,
                                              portEvent->mac,
                                              FALSE,
                                              state);

                    if (switchIsProtected)
                    {
                        UNPROTECT_SWITCH(sw);
                        switchIsProtected = FALSE;
                    }

                }   /* end if (isPhysicalSwitch) */

                distributeEvent = TRUE;
                break;

            case FM_EVENT_PKT_RECV:
            case FM_EVENT_SFLOW_PKT_RECV:
                fmDbgDiagCountIncr(sw, FM_CTR_RX_API_PKT_FWD, 1);
                distributeEvent = TRUE;
                break;

            case FM_EVENT_PURGE_SCAN_COMPLETE:
                distributeEvent = TRUE;
                break; 

            case FM_EVENT_TABLE_UPDATE:
                if (switchPtr == NULL)
                {
                    break;
                }

                /* Update diagnostic counters. */
                updateEvent = &event->info.fpUpdateEvent;
                i = 0;

                while (i < updateEvent->numUpdates)
                {
                    fpUpdateEvent = &updateEvent->updates[i];

                    if (fpUpdateEvent->event == FM_EVENT_ENTRY_LEARNED)
                    {
                        /* Make sure the MA Table entry matches the entry
                         * in the update event. */
                        if (switchPtr->RemoveStaleLearnEvent != NULL &&
                            switchPtr->RemoveStaleLearnEvent(sw, updateEvent, i))
                        {
                            /* The learn event has been removed.
                             * Do not update 'i', since it now contains the 
                             * following event (if any). */
                            fmDbgDiagCountIncr(sw, FM_CTR_MAC_LEARN_DISCARDED, 1);
                        }
                        else
                        {
                            fmDbgDiagCountIncr(sw, FM_CTR_MAC_ALPS_LEARN, 1);
                            i++;
                        }
                    }
                    else
                    {
                        if (fpUpdateEvent->event == FM_EVENT_ENTRY_AGED)
                        {
                            fmDbgDiagCountIncr(sw, FM_CTR_MAC_ALPS_AGE, 1);
                        }
                        i++;
                    }
                }

                /* If all updates have been removed, don't distribute the
                   event */
                if (updateEvent->numUpdates > 0)
                {
                    distributeEvent = TRUE;
                }
                break;

            case FM_EVENT_SECURITY:
            case FM_EVENT_FRAME:
            case FM_EVENT_SOFTWARE:
            case FM_EVENT_PARITY_ERROR:
            case FM_EVENT_FIBM_THRESHOLD:
            case FM_EVENT_CRM:
            case FM_EVENT_ARP:
            case FM_EVENT_EGRESS_TIMESTAMP:
            case FM_EVENT_PLATFORM:
            case FM_EVENT_LOGICAL_PORT:
                distributeEvent = TRUE;
                break;

            default:
                FM_LOG_WARNING(FM_LOG_CAT_EVENT_PORT,
                               "Received unknown event %d\n",
                               event->type);
                break;

        }   /* end switch (event->type) */

        if (distributeEvent)
        {
            if (switchIsProtected)
            {
                UNPROTECT_SWITCH(sw);
                switchIsProtected = FALSE;
            }

            if (eventHandler != NULL)
            {
                if (enableFramePriority && 
                    ( (event->type == FM_EVENT_PKT_RECV) ||
                      (event->type == FM_EVENT_SFLOW_PKT_RECV) ) )
                {
                    rcvPktEvent = &event->info.fpPktEvent;
                    err = fmFreeBufferQueueNode(sw, rcvPktEvent);
                    if (err != FM_OK)
                    {
                        FM_LOG_ERROR(FM_LOG_CAT_EVENT_PKT_RX,
                                     "Freeing Buffer queue node from the queue failed"
                                     "status = %d (%s) \n",
                                      err,
                                      fmErrorMsg(err));

                    }
                }

                eventHandler(event);
            }
            else
            {
                fmDistributeEvent(event);
            }
        }

FINISHED:

        fmReleaseEvent(event);

        /* release the switch lock if any is held */
        if (switchIsProtected)
        {
            UNPROTECT_SWITCH(sw);
        }

    }   /* end while (1) */

    fmExitThread(thread);

    return NULL;

}   /* end fmGlobalEventHandler */
Пример #17
0
/** UsedSweeperActiveState
 * \ingroup intFastMaint
 *
 * \desc            The MAC Address USED Table sweep is in progress.
 *
 * \param[in]       sw is the switch on which to operate
 * 
 * \param[in]       currentTime is the current value of the aging timer.
 *
 * \return          None.
 *
 *****************************************************************************/
static void UsedSweeperActiveState(fm_int sw, fm_uint64 currentTime)
{
    fm_switch *     switchPtr;
    fm10000_switch *switchExt;
    fm_sweepStats   stats;
    fm_int          upperBound;
    fm_int          numWords;

    switchPtr = GET_SWITCH_PTR(sw);
    switchExt = switchPtr->extension;

    FM_CLEAR(stats);

    upperBound = switchExt->usedTableSweeperIndex + USED_TABLE_SAMPLE_SIZE;
    if (upperBound > USED_TABLE_SIZE)
    {
        upperBound = USED_TABLE_SIZE;
    }

    numWords = USED_TABLE_SAMPLE_UNIT;

    while (switchExt->usedTableSweeperIndex < upperBound)
    {
        if ((switchExt->usedTableSweeperIndex + numWords) > upperBound)
        {
            numWords = upperBound - switchExt->usedTableSweeperIndex;
        }

        ProcessSample(sw,
                      switchExt->usedTableSweeperIndex,
                      numWords,
                      currentTime,
                      switchExt->usedTableAgingTime,
                      switchExt->usedTableExpiryTime,
                      &stats);

        switchExt->usedTableSweeperIndex += numWords;

    }   /* end while (switchExt->usedTableSweeperIndex < upperBound) */

    switchExt->usedTableNumExpired += stats.expired;

    if (switchExt->usedTableSweeperIndex >= USED_TABLE_SIZE)
    {
        if (stats.young || stats.old || stats.expired)
        {
            FM_LOG_DEBUG(FM_LOG_CAT_EVENT_FAST_MAINT,
                         "sw=%d young=%d old=%d expired=%d elapsed=%llu\n",
                         sw,
                         stats.young,
                         stats.old,
                         stats.expired,
                         currentTime - switchExt->usedTableLastSweepTime);
        }

        if (switchExt->usedTableNumExpired)
        {
            fm_maWorkTypeData   data;
            fm_status           err;

            FM_CLEAR(data);

            err = fmEnqueueMAPurge(sw, FM_UPD_FLUSH_EXPIRED, data, NULL, NULL);
            if (err != FM_OK)
            {
                FM_LOG_ERROR(FM_LOG_CAT_EVENT_FAST_MAINT,
                             "fmEnqueueMAPurge failed: %s\n",
                             fmErrorMsg(err));
            }
        }

        /* Enter READY state to wait for next pass. */
        switchExt->usedTableSweeperState = FM_USED_SWEEPER_READY;
        FM_LOG_DEBUG(FM_LOG_CAT_EVENT_FAST_MAINT, "sw=%d state=READY\n", sw);
    }

}   /* end UsedSweeperActiveState */
Пример #18
0
/** fmRawPacketSocketHandlingInitialize
 * \ingroup intPlatformCommon
 *
 * \desc            Initializes the raw packet socket transfer module.
 *
 * \param[in]       sw is the switch number to initialize.
 * 
 * \param[in]       hasFcs is TRUE if the packet includes the FCS field.
 * 
 * \param[in]       iface is a string containing the netdev's interface name
 *                  through which the packets should be sent / received.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
fm_status fmRawPacketSocketHandlingInitialize(fm_int  sw, 
                                              fm_bool hasFcs, 
                                              fm_text iface)
{
    fm_status                err = FM_OK;
    fm_int                   rawSock = -1;
    struct ifreq             ifr;
    struct sockaddr_ll       sa;
    struct ethtool_value     ethValue;
#ifdef ENABLE_TIMESTAMP
    struct ifreq             hwtstamp;
    struct hwtstamp_config   hwconfig;
    struct hwtstamp_config   hwconfig_requested;
    fm_int                   val;
    socklen_t                len;
    fm_int                   so_timestamping_flags;
    struct cmsghdr *         cmsg;
#endif
    char                     strErrBuf[FM_STRERROR_BUF_SIZE];
    errno_t                  strErrNum;
    fm_switch               *switchPtr;

    FM_LOG_ENTRY(FM_LOG_CAT_PLATFORM,
                 "sw=%d hasFcs=%s\n",
                 sw,
                 FM_BOOLSTRING(hasFcs));

    if (iface == NULL)
    {
        err = FM_ERR_INVALID_ARGUMENT;
        FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err);
    }

    err = fmGenericPacketHandlingInitializeV2(sw, hasFcs);
    FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err);

    /* initialize the raw packet socket */
    rawSock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_XDSA));
    if (rawSock == -1)
    {
        FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, 
                     "couldn't create raw packet socket\n");
        err = FM_FAIL;
        FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err);
    }

    /* retrieve ethernet interface index */
    FM_STRNCPY_S(ifr.ifr_name, IF_NAMESIZE, iface, IF_NAMESIZE);
    if (ioctl(rawSock, SIOCGIFINDEX, &ifr) == -1) 
    {
        FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, 
                     "Failed to retrieve index for interface %s\n",
                     iface);
        err = FM_ERR_INVALID_ARGUMENT;
        FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err);
    }

    /* initialize sockaddr_ll */
    FM_CLEAR(sa);
    sa.sll_family   = PF_PACKET;
    sa.sll_protocol = htons(ETH_P_XDSA);
    sa.sll_ifindex  = ifr.ifr_ifindex;
    if (bind(rawSock, (struct sockaddr *)&sa, sizeof(sa)) < 0)
    {
        FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, 
                     "Failed to bind to the raw packet socket\n");
        err = FM_FAIL;
        FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_PLATFORM, err);
    }
    
#ifdef ENABLE_TIMESTAMP
    /*Set timestamp related configurations */
    FM_CLEAR(hwconfig);
    FM_CLEAR(hwconfig_requested);
    FM_CLEAR(hwtstamp);

    strncpy(hwtstamp.ifr_name, iface, IF_NAMESIZE);
    hwtstamp.ifr_data = (void *)&hwconfig;
    hwconfig.rx_filter = HWTSTAMP_FILTER_ALL;
    hwconfig_requested = hwconfig;

    errno = 0;
    if (ioctl(rawSock, SIOCSHWTSTAMP, &hwtstamp) < 0) 
    {
        strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno);
        if (strErrNum == 0)
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Failed to configure RX hardware timestamp for all"
                         " received packets. Error: %s\n",
                         strErrBuf);
        }
        else
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Failed to configure RX hardware timestamp for all"
                         " received packets. Error: %d\n",
                         errno);
        }
    }

    FM_LOG_DEBUG(FM_LOG_CAT_PLATFORM,
                 "SIOCSHWTSTAMP: tx_type %d requested, got %d; "
                 " rx_filter %d requested, got %d\n",
                  hwconfig_requested.tx_type, 
                  hwconfig.tx_type,
                  hwconfig_requested.rx_filter, 
                  hwconfig.rx_filter);

    so_timestamping_flags = SOF_TIMESTAMPING_RX_HARDWARE | 
                            SOF_TIMESTAMPING_RAW_HARDWARE;

    if (setsockopt(rawSock,
                   SOL_SOCKET,
                   SO_TIMESTAMPING,
                   &so_timestamping_flags,
                   sizeof(so_timestamping_flags)) < 0)
    {
        FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                     "Failed to set timestamping on socket\n");
        /* Continue without timestamp */
    }

    len = sizeof(val);
    errno = 0;
    if (getsockopt(rawSock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0)
    {
        strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno);
        if (strErrNum == 0)
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Failed to retrieve SO_TIMESTAMPING socket options."
                         " Error %s",
                         strErrBuf);
        }
        else
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Failed to retrieve SO_TIMESTAMPING socket options."
                         " Error %d",
                         errno);
        }
    }
    else
    {
        FM_LOG_DEBUG(FM_LOG_CAT_PLATFORM, "SO_TIMESTAMPING %d\n", val);
        if (val != so_timestamping_flags)
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Expected value %d but retrieved %d\n",
                         so_timestamping_flags,
                         val);
        }
    }
#endif

    /* Set the Driver in ies-tagging mode on management PEP */
    ethValue.cmd = ETHTOOL_SPFLAGS;
    ethValue.data = ETHTOOL_PRV_FLAG_IES;
    ifr.ifr_data = (void*) &ethValue;
    if (ioctl(rawSock, SIOCETHTOOL, &ifr) == -1)
    {
        strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno);
        if (strErrNum == 0)
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Failed to set ies-tagging: %s\n",
                         strErrBuf);
        }
        else
        {
            FM_LOG_ERROR(FM_LOG_CAT_PLATFORM,
                         "Failed to set ies-tagging: %d\n",
                         errno);
        }
    }

    if (ioctl(rawSock, SIOCGIFFLAGS, &ifr) == -1)
    {
        strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno);
        if (strErrNum == 0)
        {
            FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, 
                         "Failed to get socket flags: %s\n",
                         strErrBuf);
        }
        else
        {
            FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, 
                         "Failed to get socket flags: %d\n",
                         errno);
        }

        err = FM_FAIL;
        FM_LOG_ABORT(FM_LOG_CAT_PLATFORM, err);
    }

    if ((ifr.ifr_flags & IFF_UP) == 0)
    {
        /* Bring the NIC up */
        ifr.ifr_flags |= IFF_UP;

        if (ioctl(rawSock, SIOCSIFFLAGS, &ifr) == -1)
        {
            strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno);
            if (strErrNum == 0)
            {
                FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, 
                             "Failed to bring up: %s\n",
                             strErrBuf);
            }
            else
            {
                FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, 
                             "Failed to bring up: %d\n",
                             errno);
            }
            
            err = FM_FAIL;
            FM_LOG_ABORT(FM_LOG_CAT_PLATFORM, err);
        }
    }

    GET_PLAT_STATE(sw)->rawSocket = rawSock;
    FM_STRNCPY_S(GET_PLAT_STATE(sw)->ifaceName, IF_NAMESIZE, iface, IF_NAMESIZE);

    /* Create the receive packet thread */
    err = fmCreateThread("raw_packet_socket receive",
                         FM_EVENT_QUEUE_SIZE_NONE,
                         &fmRawPacketSocketReceivePackets,
                         &(GET_PLAT_STATE(sw)->sw),
                         GET_PLAT_RAW_LISTENER(sw));

    switchPtr = GET_SWITCH_PTR(sw);
    if (switchPtr)
    {
        switchPtr->isRawSocketInitialized = FM_ENABLED;
    }

ABORT:
    if ( (err != FM_OK) &&
         (rawSock != -1) )
    {
        close(rawSock);
    }

    FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, err);

}   /* end fmRawPacketSocketHandlingInitialize */
Пример #19
0
/** fmMapLogicalPortToPhysical
 * \ingroup intSwitch
 *
 * \desc            Maps a logical port number to a physical port number.
 *
 * \param[in]       sstate points to the switch state entry.
 *
 * \param[in]       logPort is the logical port number. Must be a cardinal
 *                  port or one of the supported non-cardinal port types
 *                  (LAG, REMOTE, VIRTUAL).
 *
 * \param[out]      physPort points to the location to receive the physical
 *                  port number.
 *
 * \return          FM_OK if successful.
 * \return          FM_ERR_INVALID_PORT if logPort is not a valid port number.
 * \return          FM_ERR_NO_PORTS_IN_LAG if logPort refers to an empty LAG.
 * \return          FM_ERR_INVALID_ARGUMENT if there is no port structure
 *                  allocated for given port number.
 *
 *****************************************************************************/
fm_status fmMapLogicalPortToPhysical(fm_switch *sstate,
                                     fm_int     logPort,
                                     fm_int *   physPort)
{
    fm_int      sw;
    fm_int      dummySw;
    fm_int      intPort;
    fm_status   err;

    sw = sstate->switchNumber;
    intPort = logPort;

    /*
     * This function is used primarily by code that needs to program the
     * hardware. It is generally applied to cardinal ports.
     *
     * In some cases, however, the function may be applied to certain
     * non-cardinal port types. In these cases, the logical port must be
     * reduced to a cardinal port.
     */
    if (!fmIsCardinalPort(sw, intPort))
    {
        /* If this is a remote logical port, get the internal port. */
        if (fmIsRemotePort(sw, intPort))
        {
            err = fmGetInternalPortFromRemotePort(sw, intPort, &intPort);
            if (err != FM_OK)
            {
                return err;
            }
        }

        /* If this is a LAG logical port, get one of its member ports. */
        if (fmIsLagPort(sw, intPort))
        {
            err = MapLagPortToMemberPort(sw, intPort, &intPort);
            if (err != FM_OK)
            {
                return err;
            }
        }

        /* If this is a virtual logical port, get PEP logical port. */
        if (fmIsVirtualPort(sw, intPort))
        {
            err = MapVirtualPortToPepPort(sw, intPort, &intPort);
            if (err != FM_OK)
            {
                return err;
            }
        }

        /* Verify that the end result is a cardinal port. */
        if (!fmIsCardinalPort(sw, intPort))
        {
#if 1
            /* A failure at this point probably means that there is a bug
             * in the API. Generate an error that will register in the
             * regression test system. */
            if (intPort != logPort)
            {
                FM_LOG_ERROR(FM_LOG_CAT_SWITCH,
                             "Port %d (%s) maps to non-cardinal port %d (%s)\n",
                             logPort,
                             fmGetPortTypeAsText(sw, logPort),
                             intPort,
                             fmGetPortTypeAsText(sw, intPort));
            }
            else
            {
                FM_LOG_ERROR(FM_LOG_CAT_SWITCH,
                             "Port %d (%s) does not map to a cardinal port\n",
                             logPort,
                             fmGetPortTypeAsText(sw, intPort));
            }
#endif

            /* Implement FM_ERR_INVALID_PORT_TYPE? */
            return FM_ERR_INVALID_PORT;
        }

    }   /* end !fmIsCardinalPort(sw, intPort) */

    return fmPlatformMapLogicalPortToPhysical(sw, intPort, &dummySw, physPort);

}   /* end fmMapLogicalPortToPhysical */
Пример #20
0
/** fmRawPacketSocketReceivePackets
 * \ingroup intPlatformCommon
 *
 * \desc            Handles reception of packets by raw packet socket.
 *
 * \param[in]       args is a pointer to the switch number.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
void * fmRawPacketSocketReceivePackets(void *args)
{
    fm_thread *        thread;
    fm_int             sw;
    fm_buffer *        recvChainHead = NULL;
    fm_buffer *        nextBuffer;
    struct pollfd      rfds;
    struct msghdr      msg;
    struct iovec       iov[UIO_MAXIOV];
    struct ifreq       ifr;
    fm_int             retval;
    fm_int             availableBuffers;
    fm_int             len;
    fm_int             iov_offset;
    fm_int             iov_count = 0;
    fm_int             maxMtu = 0;
    fm_int             newMtu;
    fm_status          status;
    char               strErrBuf[FM_STRERROR_BUF_SIZE];
    errno_t            strErrNum;
    fm_byte            rawTS[8];
    fm_pktSideBandData sbData;
#ifdef ENABLE_TIMESTAMP
    struct cmsghdr *   cmsg;
    union {
        struct cmsghdr  cm;
        char            control[512];

    } control;
#endif
    

    thread = FM_GET_THREAD_HANDLE(args);
    sw     = *(FM_GET_THREAD_PARAM(fm_int, args));

    FM_NOT_USED(thread);    /* If logging is disabled, thread won't be used */

    FM_LOG_ENTRY(FM_LOG_CAT_SWITCH,
                 "thread = %s, sw = %d\n",
                 thread->name,
                 sw);

    /* initialize the message header */
    FM_CLEAR(msg);
    msg.msg_name = NULL; /* Optional field */
    msg.msg_namelen = 0;
    msg.msg_iov = iov;
    msg.msg_iovlen = 0;
    msg.msg_flags = 0;
#ifdef ENABLE_TIMESTAMP
    msg.msg_control = &control;
    msg.msg_controllen = sizeof(control);
#endif

    /* Setup the name of the interface */
    FM_STRNCPY_S(ifr.ifr_name, 
                 sizeof(ifr.ifr_name), 
                 GET_PLAT_STATE(sw)->ifaceName, 
                 sizeof(GET_PLAT_STATE(sw)->ifaceName));

    /* Prepare the pollfd struct */
    rfds.fd = GET_PLAT_STATE(sw)->rawSocket;
    rfds.events = POLLIN;
    rfds.revents = 0;

    /**************************************************
     * Loop forever calling packet receive handler.
     **************************************************/

    while (TRUE)
    {
        errno = 0;
        retval = poll(&rfds, 1, FM_FDS_POLL_TIMEOUT_USEC);

        if (retval == -1)
        {
            strErrNum = FM_STRERROR_S(strErrBuf, FM_STRERROR_BUF_SIZE, errno);
            if (strErrNum == 0)
            {
                FM_LOG_WARNING(FM_LOG_CAT_SWITCH,
                               "ERROR: select failed: %s!\n",
                               strErrBuf);
            }
            else
            {
                FM_LOG_WARNING(FM_LOG_CAT_SWITCH,
                               "ERROR: select failed: %d!\n",
                               errno);
            }

            /* Switch was removed, kill the thread */
            if (GET_SWITCH_PTR(sw) == NULL)
            {
                break;
            }

            continue;
        }
        else if (!retval)
        {
            /* Switch was removed, kill the thread */
            if (GET_SWITCH_PTR(sw) == NULL)
            {
                break;
            }

            continue; /* timeout */
        }

        /* get the number of available buffers from the buffer manager*/
        fmPlatformGetAvailableBuffers(&availableBuffers);

        if (availableBuffers <= FM_RECV_BUFFER_THRESHOLD)
        {
            /* wait for buffer to come back, before dequeueing data */
            fmYield();
            continue;
        }

        if (ioctl(GET_PLAT_STATE(sw)->rawSocket, SIOCGIFMTU, &ifr) == -1)
        {
             FM_LOG_WARNING(FM_LOG_CAT_SWITCH,
                            "WARNING: failed to read netdev MTU\n");
             continue;
        }
        else
        {
            newMtu = ifr.ifr_mtu;
        }

        /* MTU Size change */
        if (newMtu != maxMtu)
        {
            if (recvChainHead != NULL)
            {
                /* release the existing buffer chain */
                status = fmFreeBufferChain(FM_FIRST_FOCALPOINT, recvChainHead);

                if (status != FM_OK)
                {
                    FM_LOG_ERROR( FM_LOG_CAT_SWITCH,
                                 "Unable to release prior buffer chain, "
                                 "status = %d (%s)\n",
                                 status,
                                 fmErrorMsg(status) );
                }

                recvChainHead = NULL;
            }

            /* compute new buffer count */
            iov_count = newMtu / FM_BUFFER_SIZE_BYTES;
            if (newMtu % FM_BUFFER_SIZE_BYTES)
            {
                iov_count++;
            }

            maxMtu = newMtu;
        }

        if (recvChainHead == NULL)
        {
            /* allocate a new buffer chain and initialize iovec array */
            msg.msg_iovlen = 0;
            
            /* 8-Byte Timestamp IOV */
            iov[msg.msg_iovlen].iov_base = rawTS;
            iov[msg.msg_iovlen].iov_len  = sizeof(rawTS);
            msg.msg_iovlen++;

            for (iov_offset = 0 ; iov_offset < iov_count ; iov_offset++)
            {
                do
                {
                    nextBuffer = fmAllocateBuffer(FM_FIRST_FOCALPOINT);

                    if (nextBuffer == NULL)
                    {
                        /* Wait a little while for buffer to return */
                        fmDbgGlobalDiagCountIncr(FM_GLOBAL_CTR_RX_OUT_OF_BUFFERS,
                                                 1);
                        fmYield();
                    }
                }
                while (nextBuffer == NULL);

                if (recvChainHead == NULL)
                {
                    recvChainHead    = nextBuffer;
                    nextBuffer->next = NULL;
                }
                else
                {
                    status = fmAddBuffer(recvChainHead, nextBuffer);

                    if (status != FM_OK)
                    {
                        FM_LOG_ERROR( FM_LOG_CAT_SWITCH,
                                     "Unable to add buffer %d (%p) to chain %p\n",
                                     iov_offset,
                                     (void *) nextBuffer,
                                     (void *) recvChainHead );
                        break;
                    }
                }

                iov[msg.msg_iovlen].iov_base = nextBuffer->data;
                iov[msg.msg_iovlen].iov_len  = FM_BUFFER_SIZE_BYTES;
                msg.msg_iovlen++;
            }
        }

        /* now receive from the driver */
        len = recvmsg(GET_PLAT_STATE(sw)->rawSocket,
                      &msg,
                      0);

        if (len == -1)
        {
            continue;
        }

#ifdef ENABLE_TIMESTAMP
        for (cmsg = CMSG_FIRSTHDR(&msg);
             cmsg;
             cmsg = CMSG_NXTHDR(&msg, cmsg)) 
        {
            if ( (cmsg->cmsg_level == SOL_SOCKET) &&
                 (cmsg->cmsg_type  == SO_TIMESTAMPING) &&
                 (cmsg->cmsg_len   == CMSG_LEN(sizeof(struct timespec) * 3)) )
            {
                    struct timespec *stamp =
                        (struct timespec *)CMSG_DATA(cmsg);
                    /* cmsg has 3 different timestamps. Timestamp we are interested is 
                     * located in index 2 */
                    sbData.ingressTimestamp.seconds     = ( (fm_int64)(stamp[2].tv_sec) );
                    sbData.ingressTimestamp.nanoseconds = ( (fm_int64)(stamp[2].tv_nsec) );
            }
            else
            {
                    FM_LOG_WARNING(FM_LOG_CAT_PLATFORM, 
                                  "Unknown control message of level %d type %d len %zu  received\n",
                                  cmsg->cmsg_level, 
                                  cmsg->cmsg_type,
                                  cmsg->cmsg_len);
            }
        }
#endif

        /* Remove the timestamp's length to get the length of the actual
         * packet */
        len -= sizeof(rawTS);

        /* The raw socket does not carry the FCS in either tx or rx, however
         * the API expects it to be present. Because the API clears the 
         * FCS value before sending the packet event to the application, don't 
         * bother about setting the correct FCS value and just increment the 
         * length. The FCS value is undefined (whatever is in the fm_buffer at 
         * the FCS position). */
        len += 4;

        /* fill in the used buffer sizes */
        nextBuffer = recvChainHead;

        while (nextBuffer != NULL)
        {
            if (len > FM_BUFFER_SIZE_BYTES)
            {
                nextBuffer->len = FM_BUFFER_SIZE_BYTES;
            }
            else
            {
                nextBuffer->len = len;
            }

            len -= nextBuffer->len;

            if ( (len <= 0) && (nextBuffer->next != NULL) )
            {
                status = fmFreeBufferChain(FM_FIRST_FOCALPOINT,
                                           nextBuffer->next);

                if (status != FM_OK)
                {
                    FM_LOG_ERROR( FM_LOG_CAT_SWITCH,
                                 "Unable to release unused buffer chain, "
                                 "status = %d (%s)\n",
                                 status,
                                 fmErrorMsg(status) );
                }

                nextBuffer->next = NULL;
            }

            nextBuffer = nextBuffer->next;
        }

        if (recvChainHead == NULL)
        {
            continue;
        }

        /* Store the raw timestamp in 64b format */
        sbData.rawTimeStamp  = ((fm_uint64) (rawTS[0] & 0xFF)) << 56;
        sbData.rawTimeStamp |= ((fm_uint64) (rawTS[1] & 0xFF)) << 48;
        sbData.rawTimeStamp |= ((fm_uint64) (rawTS[2] & 0xFF)) << 40;
        sbData.rawTimeStamp |= ((fm_uint64) (rawTS[3] & 0xFF)) << 32;
        sbData.rawTimeStamp |= ((fm_uint64) (rawTS[4] & 0xFF)) << 24;
        sbData.rawTimeStamp |= ((fm_uint64) (rawTS[5] & 0xFF)) << 16;
        sbData.rawTimeStamp |= ((fm_uint64) (rawTS[6] & 0xFF)) << 8;
        sbData.rawTimeStamp |= ((fm_uint64) (rawTS[7] & 0xFF));

        /* Don't provide an ISL tag pointer, let the API handle the ISL
         * tag information (included in the fm_buffer chain). */
        status = fmPlatformReceiveProcessV2(sw,
                                            recvChainHead,
                                            NULL,
                                            &sbData);

        if (status != FM_OK)
        {
            FM_LOG_ERROR( FM_LOG_CAT_SWITCH,
                         "Returned error status %d "
                         "(%s)\n",
                         status,
                         fmErrorMsg(status) );


        }
        /* Buffer chain has now been consumed */
        recvChainHead = NULL; 

    }   /* end while (TRUE) */

    fmExitThread(thread);

    return NULL;

}   /* end fmRawPacketSocketReceivePackets */
Пример #21
0
/** PerformPurge
 * \ingroup intMacMaint
 *
 * \desc            Initiates an MA table purge operation.
 *
 * \param[in]       sw is the switch on which to operate.
 *
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
static fm_status PerformPurge(fm_int sw)
{
    fm_switch *     switchPtr;
    fm_bool         l2Locked;
    fm_int          numSkipped;
    fm_event *      eventPtr;
    fm_uint32       numUpdates;
    fm_int          entryIndex;
    fm_status       err;

    fm_internalMacAddrEntry *   cachePtr;
    fm_internalMacAddrEntry     oldEntry;

    FM_LOG_ENTRY(FM_LOG_CAT_EVENT_MAC_MAINT, "sw=%d\n", sw);

    switchPtr = GET_SWITCH_PTR(sw);

    l2Locked    = FALSE;
    numSkipped  = 0;
    eventPtr    = NULL;
    numUpdates  = 0;

    /***************************************************
     * Preallocate an event buffer.
     **************************************************/

    /* NOTE: This call will block if the number of free event
     * buffers drops below the acceptable threshold. */
    eventPtr = fmAllocateEvent(sw,
                               FM_EVID_HIGH_TABLE_UPDATE,
                               FM_EVENT_TABLE_UPDATE,
                               FM_EVENT_PRIORITY_LOW);

    if (eventPtr == NULL)
    {
        fmDbgDiagCountIncr(sw, FM_CTR_MAC_EVENT_ALLOC_ERR, 1);

        FM_LOG_ERROR(FM_LOG_CAT_EVENT_MAC_MAINT,
                     "out of event buffers\n");
    }

    /***************************************************
     * Iterate over MAC table cache.
     **************************************************/

    for ( entryIndex = 0 ;
            entryIndex < switchPtr->macTableSize ;
            ++entryIndex )
    {
        if (!l2Locked)
        {
            FM_TAKE_L2_LOCK(sw);
            l2Locked   = TRUE;
            numSkipped = 0;
        }

        cachePtr = &switchPtr->maTable[entryIndex];

        /***************************************************
         * Determine whether to purge this entry.
         **************************************************/

        if (!MeetsPurgeCriteria(sw, cachePtr))
        {
            ++numSkipped;
            if (numSkipped >= SKIP_THRESHOLD)
            {
                FM_DROP_L2_LOCK(sw);
                l2Locked = FALSE;
            }
            continue;
        }

        if (FM_IS_TEST_TRACE_ADDRESS(cachePtr->macAddress))
        {
            FM_LOG_PRINT("fm10000HandlePurgeRequest(%d): "
                         "purging mac address " FM_FORMAT_ADDR "/%u\n",
                         sw,
                         cachePtr->macAddress,
                         cachePtr->vlanID);
        }

        /***************************************************
         * Remove entry from MAC table.
         **************************************************/

        /* Make a copy of the cache entry before we invalidate it.
         * We'll need it to generate the AGED event. */
        oldEntry = *cachePtr;

        /* Invalidate cache and hardware entry. */
        err = fm10000InvalidateEntryAtIndex(sw, entryIndex);
        if (err != FM_OK)
        {
            FM_LOG_ERROR(FM_LOG_CAT_EVENT_MAC_MAINT,
                         "Error purging MA table entry: sw=%d index=%d\n",
                         sw,
                         entryIndex);
        }

        /***************************************************
         * Generate an AGED event.
         **************************************************/

        /* Relinquish lock before generating event. */
        FM_DROP_L2_LOCK(sw);
        l2Locked = FALSE;

        fmGenerateUpdateForEvent(sw,
                                 &fmRootApi->eventThread,
                                 FM_EVENT_ENTRY_AGED,
                                 FM_MAC_REASON_PURGE_AGED,
                                 entryIndex,
                                 &oldEntry,
                                 &numUpdates,
                                 &eventPtr);

        fmDbgDiagCountIncr(sw, FM_CTR_MAC_PURGE_AGED, 1);

    }   /* end for ( entryIndex = 0 ; ... ) */

    if (l2Locked)
    {
        FM_DROP_L2_LOCK(sw);
    }

    if (numUpdates != 0)
    {
        fmSendMacUpdateEvent(sw,
                             &fmRootApi->eventThread,
                             &numUpdates,
                             &eventPtr,
                             FALSE);
    }

    if (eventPtr != NULL)
    {
        fmReleaseEvent(eventPtr);
    }

    err = FinishPurge(sw);

    FM_LOG_EXIT(FM_LOG_CAT_EVENT_MAC_MAINT, err);

}   /* end PerformPurge */
Пример #22
0
/** fmLoadDynamicLoadLibrary
 * \ingroup intAlosDynLoadLib
 *
 * \desc            Load a Dynamic Load Library for a process.
 *                  This function is called when a dynamic load library
 *                  has been loaded and is in use, but the current process
 *                  has not yet loaded it.
 *
 * \param[in]       handle contains the dynamic-load-library's handle.
 *
 * \return          FM_ERR_UNINITIALIZED if the ALOS subsystem has not been
 *                  properly initialized.
 * \return          FM_ERR_INVALID_ARGUMENT if one of the arguments is invalid.
 * \return          FM_OK if successful.
 *
 *****************************************************************************/
fm_status fmLoadDynamicLoadLibrary(fm_int handle)
{
    fm_status      err;
    fm_dynLoadLib *lib;
    fm_bool        lockTaken = FALSE;
    void *         libHandle;

    FM_LOG_ENTRY(FM_LOG_CAT_ALOS_DLLIB, "handle = %d\n", handle);

    if (fmRootAlos == NULL)
    {
        FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, FM_ERR_UNINITIALIZED);
    }

    if ( (handle < 0) || (handle >= FM_ALOS_INTERNAL_DYN_LOAD_LIBS) )
    {
        FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, FM_ERR_INVALID_ARGUMENT);
    }

    err = fmCaptureLock(&fmRootAlos->dlAccessLock, FM_WAIT_FOREVER);

    FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);

    lockTaken = TRUE;

    lib = fmRootAlos->dlLibs[handle];

    if (lib == NULL)
    {
        err = FM_ERR_INVALID_ARGUMENT;

        FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);
    }

    if ( ( fmProcessDynLoadLibStatus & (1 << handle) ) == 0 )
    {
        libHandle = dlopen(lib->filePath, RTLD_NOW | RTLD_GLOBAL);

        if (libHandle == NULL)
        {
            char *errMsg = dlerror();
            FM_LOG_ERROR(FM_LOG_CAT_ALOS_DLLIB,
                         "Error opening library %s: %s\n",
                         lib->filePath,
                         errMsg);

            err = FM_ERR_NOT_FOUND;
            FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err);
        }

        ProcessHandles[handle] = libHandle;

        lib->useCount++;
        
        fmProcessDynLoadLibStatus |= FM_LITERAL_U64(1) << handle;
    }

    err = FM_OK;


ABORT:

    if (lockTaken)
    {
        fmReleaseLock(&fmRootAlos->dlAccessLock);
    }

    FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, err);

}   /* end fmLoadDynamicLoadLibrary */
Пример #23
0
/* I2cWriteRead
 * \ingroup intSwitch 
 *
 * \desc            Write to then immediately read from an I2C device with
 *                  handling max response bytes using switch as I2C master.
 *
 * \param[in]       sw is the switch number.
 *
 * \param[in]       device is the I2C device address (0x00 - 0x7F).
 *
 * \param[in,out]   data points to an array from which data is written and
 *                  into which data is read.
 *
 * \param[in]       wl is the number of bytes to write.
 *
 * \param[in]       rl is the number of bytes to read.
 *
 * \return          FM_OK if successful.
 * \return          Other ''Status Codes'' as appropriate in case of
 *                  failure.
 *
 *****************************************************************************/
static fm_status I2cWriteRead(fm_int     sw,
                              fm_uint    device,
                              fm_byte   *data,
                              fm_uint    wl,
                              fm_uint    rl)
{
    fm_status      status;
    fm_switch     *switchPtr;
    fm_uint32      regValue;
    fm_uint        i;
    fm_uint        j;
    fm_bool        isTimeout;
    fm_timestamp   start;
    fm_timestamp   end;
    fm_timestamp   diff;
    fm_uint        delTime;
    fm_uint32      tmp;

    FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_SWITCH,
                         "sw=%d device=0x%x wl=%d rl=%d\n",
                         sw, device, wl, rl);

    if (rl > I2C_MAX_LEN)
    {
        FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_INVALID_ARGUMENT);
    }

    if (wl > I2C_MAX_LEN)
    {
        FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_INVALID_ARGUMENT);
    }

    if (data == NULL)
    {
        FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_INVALID_ARGUMENT);
    }

    switchPtr = GET_SWITCH_PTR(sw);

    for (i = 0 ; i < (wl+3)/4 ; i++)
    {
        regValue = 0;
        for (j = 0 ; j < 4 ; j++)
        {
            if ((i*4 + j) < wl)
            {
                regValue |= (data[i*4 + j] << ((3 - j)*8));
            }
        }
        status = switchPtr->WriteUINT32(sw, FM10000_I2C_DATA(i), regValue);
        FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status);

        FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "WRITEDATA#%d : 0x%08x\n",i, regValue); 
    }

    regValue = 0;
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Addr, (device  << 1));
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 0);
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, LengthW, wl);
    FM_SET_FIELD(regValue, FM10000_I2C_CTRL, LengthR, rl);

    FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "WRITE: eg 0x%08x Cmd %d wl %d rl %d "
                  "Comp %x LenSent %d intr %d\n",
                  regValue,
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                  FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));

    status = switchPtr->WriteUINT32(sw, FM10000_I2C_CTRL(), regValue);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status);

    status = switchPtr->ReadUINT32(sw, FM10000_I2C_CTRL(), &tmp);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status);

    FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "READ: %d reg 0x%08x Cmd %d wl %d rl %d "
                  "Comp %x LenSent %d intr %d\n", status, tmp,
                  FM_GET_FIELD(tmp, FM10000_I2C_CTRL, Command),
                  FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthW),
                  FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthR),
                  FM_GET_FIELD(tmp, FM10000_I2C_CTRL, CommandCompleted),
                  FM_GET_FIELD(tmp, FM10000_I2C_CTRL, LengthSent),
                  FM_GET_BIT(tmp, FM10000_I2C_CTRL, InterruptPending));

    /* Now change command to start the transaction */
    if (rl == 0) 
    {
        /* Write only allow write of 0 length */
        FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 1);
    }
    else if ((wl > 0) && (rl > 0))
    {
        /* Write Read */
        FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 2);
    }
    else
    {
        /* Read */
        FM_SET_FIELD(regValue, FM10000_I2C_CTRL, Command, 3);
    }

    FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "WRITE2: reg 0x%08x Cmd %d wl %d rl %d "
                  "Comp %x LenSent %d intr %d\n", regValue,
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                  FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));

    status = switchPtr->WriteUINT32(sw, FM10000_I2C_CTRL(), regValue);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status);

    status = switchPtr->ReadUINT32(sw, FM10000_I2C_CTRL(), &regValue);
    FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status);

    FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH, "READ2: %d reg 0x%08x Cmd %d wl %d rl %d "
                  "Comp %x LenSent %d intr %d\n", status, regValue,
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                  FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                  FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));

    /* Poll to check for command done */
    fmGetTime(&start);
    isTimeout = FALSE;
    do
    {
        fmDelay(0, 1000*500);
        if (isTimeout)
        {
            FM_LOG_ERROR(
                   FM_LOG_CAT_SWITCH, 
                   "Dev=0x%02x: Timeout (%d msec) waiting "
                   "for I2C_CTRL(0x%x).CommandCompleted!=0. 0x%02x\n",
                   device,
                   I2C_TIMEOUT_MSEC,
                   FM10000_I2C_CTRL(), 
                   FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted));

            FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_I2C_NO_RESPONSE);
        }

        fmGetTime(&end);
        fmSubTimestamps(&end, &start, &diff);
        delTime = diff.sec*1000 + diff.usec/1000;
        /* Variable isTimeout is used to improve the timeout detecting */
        if (delTime > I2C_TIMEOUT_MSEC)
        {
            isTimeout = TRUE;
        }

        status = switchPtr->ReadUINT32(sw, FM10000_I2C_CTRL(), &regValue);
        FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH,
                      "STATUS: %d reg 0x%08x cmd %d wl %d rl %d "
                      "Comp %x LenSent %d intr %d\n", status, regValue,
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, Command),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthW),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthR),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, LengthSent),
                      FM_GET_BIT(regValue, FM10000_I2C_CTRL, InterruptPending));

        if (status) break;

    } while (FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted) == 0);

    if (FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted) != 1)
    {
        FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH,
                      "Dev=0x%02x: I2C Command completed with error 0x%x. "
                      "I2C_CTRL(0x%x)=0x%x\n",
                      device,
                      FM_GET_FIELD(regValue, FM10000_I2C_CTRL, CommandCompleted),
                      FM10000_I2C_CTRL(),
                      regValue);
        FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_SWITCH, FM_ERR_I2C_NO_RESPONSE);
    }

    for (i = 0 ; i < (rl+3)/4 ; i++)
    {
        status = switchPtr->ReadUINT32(sw, FM10000_I2C_DATA(i), &regValue);
        FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_SWITCH, status);

        FM_LOG_DEBUG_VERBOSE(FM_LOG_CAT_SWITCH,"READDATA#%d : 0x%08x\n",i, regValue);

        for (j = 0 ; j < 4 ; j++)
        {
            if ((i*4 + j) < rl)
            {
                data[i*4 + j] = (regValue >> ((3 - j)*8)) & 0xFF;
            }
        }
    }