/** fmResetLBGMember * \ingroup intLbg * * \desc Resets LBGMember to initial values. * * \param[out] lbgMember is the LBG member which should be reset. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmResetLBGMember(fm_LBGMember *lbgMember) { fm_status err = FM_OK; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_LBG, "lbgMember=%p\n", (void *) lbgMember ); if (lbgMember == NULL) { err = FM_ERR_INVALID_ARGUMENT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_LBG, err); } /* Reset lbgMember to default values */ FM_CLEAR(*lbgMember); lbgMember->lbgMemberType = FM_LBG_MEMBER_TYPE_PORT; lbgMember->port = FM_PORT_DROP; lbgMember->mcastGroup = -1; lbgMember->l234Lbg = -1; ABORT: FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_LBG, err); } /* end fmResetLBGMember */
/** fmInitDynamicLoadLibs * \ingroup intAlosDynLoadLib * * \desc Initialize ALOS Dynamic Load Library support. * * \param[in] None. * * \return FM_ERR_UNINITIALIZED if fmRootAlos has not been initialized. * \return FM_OK if successful. * \return FM_ERR_NO_MEM if unable to allocate memory. * \return FM_ERR_LOCK_INIT if unable to initialize the access lock. * *****************************************************************************/ fm_status fmInitDynamicLoadLibs(void) { fm_status err; FM_LOG_ENTRY(FM_LOG_CAT_ALOS_DLLIB, "(no arguments)\n"); if (fmRootAlos == NULL) { FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, FM_ERR_UNINITIALIZED); } FM_CLEAR(fmRootAlos->dlLibs); err = fmCreateLock("DynLibLock", &fmRootAlos->dlAccessLock); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_ALOS_DLLIB, err); FM_LOG_EXIT(FM_LOG_CAT_ALOS_DLLIB, err); } /* end fmInitDynamicLoadLibs */
/** fm10000InitSFlows * \ingroup intSflow * * \desc Initializes the SFlow subsystem. * * \param[in] sw is the switch to operate on. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fm10000InitSFlows(fm_int sw) { fm10000_sflowEntry *sflowEntry; fm_int sflowId; FM_LOG_ENTRY(FM_LOG_CAT_SFLOW, "sw=%d\n", sw); for (sflowId = 0 ; sflowId < FM10000_MAX_SFLOWS ; ++sflowId) { sflowEntry = GetSflowEntry(sw, sflowId); FM_CLEAR(*sflowEntry); sflowEntry->mirrorId = GET_SWITCH_PTR(sw)->mirrorTableSize - sflowId - 1; sflowEntry->isValid = FALSE; sflowEntry->trapCodeId = sflowId; } FM_LOG_EXIT(FM_LOG_CAT_SFLOW, FM_OK); } /* end fm10000InitSFlows */
/** 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 */
/** 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 */
/** 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 */
/** 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*) ðValue; 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 */
/** fmWaitForNetworkEvent * \ingroup platformUtil * * \desc Waits for network events. * * \param[out] sockets points to an array of active and inactive sockets. * This function can activate inactive sockets when a client * attempts to make a connection. The array must be maxSockets * in length. * * \param[in] numSockets is the current number of active sockets; it must * be in the range [1..maxSockets). * * \param[in] maxSockets is the maximum number of sockets this function * can activate. * * \param[out] eventReceived points to an array where this function places * the network event type for each active socket. The array * must be maxSockets elements in length. * * \param[in] timeout is the amount of time to wait for a network event. * Set to ''FM_WAIT_FOREVER'' to wait indefinitely. * * \return FM_OK if successful. * \return Other ''Status Codes'' as appropriate in case of failure. * *****************************************************************************/ fm_status fmWaitForNetworkEvent(fm_socket ** sockets, fm_int * numSockets, fm_int maxSockets, fm_int * eventReceived, fm_timestamp *timeout) { fm_int currNumSockets; fm_int errResult; fm_int i; fm_int j; fm_int slot; fm_bool doIncrement; struct pollfd fds[FM_MAX_FDS_NUM] = { {0} }; fm_int fdsCnt; socklen_t addrLen = SOCKET_ADDRLEN; struct timeval ts; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "sockets=%p, numSockets=%p(%d), maxSockets=%d, " "eventReceived=%p, timeout=%p\n", (void *) sockets, (void *) numSockets, (numSockets ? *numSockets : -1), maxSockets, (void *) eventReceived, (void *) timeout); if ((!sockets || !eventReceived || !numSockets || (*numSockets == 0) || \ (maxSockets > FM_MAX_FDS_NUM) || (*numSockets > FM_MAX_FDS_NUM))) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } currNumSockets = *numSockets; for ( i = 0, fdsCnt = 0 ; i < currNumSockets ; i++ ) { #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Watching descriptor %d\n", sockets[i]->sock); #endif if (sockets[i]->type != FM_SOCKET_TYPE_CLOSED) { fds[fdsCnt].fd = sockets[i]->sock; fds[fdsCnt].events = POLLIN; fds[fdsCnt].revents = 0; fdsCnt++; } } if (timeout != FM_WAIT_FOREVER) { FM_CLEAR(ts); ts.tv_sec = (int) timeout->sec; ts.tv_usec = (int) timeout->usec; } errResult = poll(fds, fdsCnt, ((timeout == FM_WAIT_FOREVER) ? -1 : \ ((ts.tv_sec * 1000) + (ts.tv_usec / 1000)) )); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); for ( i = 0, fdsCnt = 0 ; i < currNumSockets ; i++, fdsCnt++) { /* Default case */ eventReceived[i] = FM_NETWORK_EVENT_NONE; if (sockets[i]->type != FM_SOCKET_TYPE_CLOSED && fds[fdsCnt].revents & POLLIN) { /* Handle TCP connection on server socket */ if ((sockets[i]->type == FM_SOCKET_TYPE_TCP) && (sockets[i]->serverPort > 0)) { doIncrement = TRUE; slot = *numSockets; for ( j = 0 ; j < currNumSockets ; j++ ) { if (sockets[j]->type == FM_SOCKET_TYPE_CLOSED) { doIncrement = FALSE; slot = j; break; } } if (slot >= maxSockets) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Not enough socket slots left to accept client\n"); break; } FM_CLEAR(*sockets[slot]); sockets[slot]->sock = accept(sockets[i]->sock, (struct sockaddr *) &sockets[slot]->address, &addrLen); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, sockets[slot]->sock == -1); sockets[slot]->type = FM_SOCKET_TYPE_TCP; eventReceived[i] = FM_NETWORK_EVENT_NEW_CLIENT; #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Handled new client connection\n"); #endif if (doIncrement) { (*numSockets)++; } break; } else { eventReceived[i] = FM_NETWORK_EVENT_DATA_AVAILABLE; #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Data available on client #%d\n", i - 1); #endif } } } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmWaitForNetworkEvent */
/** fmCreateNetworkClient * \ingroup platformUtil * * \desc Creates a network client socket. * * \param[out] socketInfo points to the information structure for the * client socket. * * \param[in] type is the type of socket to create. * * \param[in] host points to a string specifying the hostname. * * \param[in] port is the port number. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmCreateNetworkClient(fm_socket * socketInfo, fm_socketType type, fm_text host, fm_int port) { struct hostent h; struct hostent *hp; fm_int errResult; char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; char buf[FM_GETHOSTBYNAME_BUF_SIZE]; int herrno; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "socketInfo=%p, port=%d\n", (void *) socketInfo, port); if (!socketInfo) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } FM_CLEAR(*socketInfo); if (type == FM_SOCKET_TYPE_TCP) { socketInfo->sock = socket(AF_INET, SOCK_STREAM, 0); } else if (type == FM_SOCKET_TYPE_UDP) { socketInfo->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); } if (socketInfo->sock == -1) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Unable to create socket type %d\n", type); FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_FAIL); } FM_CLEAR(socketInfo->address); socketInfo->address.sin_family = AF_INET; if ((gethostbyname_r(host, &h, buf, FM_GETHOSTBYNAME_BUF_SIZE, &hp, &herrno) != 0) || (hp == NULL)) { FM_LOG_FATAL(FM_LOG_CAT_PLATFORM, "Unable to resolve hostname: %s\n", host); } FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, !hp); FM_MEMCPY_S(&socketInfo->address.sin_addr.s_addr, sizeof(socketInfo->address.sin_addr.s_addr), hp->h_addr, hp->h_length); socketInfo->address.sin_port = htons(port); if (type == FM_SOCKET_TYPE_TCP) { errResult = connect(socketInfo->sock, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult != 0); } FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_OK); } /* end fmCreateNetworkClient */
/** fmCreateNetworkServer * \ingroup platformUtil * * \desc Creates a network server socket. * * \param[out] socketInfo points to the information structure for the * server socket. * * \param[in] type is the type of socket to create. * * \param[in] port is the port number for the socket. * * \param[in] backlog is unused. * * \return FM_OK if successful. * *****************************************************************************/ fm_status fmCreateNetworkServer(fm_socket * socketInfo, fm_socketType type, fm_int port, fm_int backlog) { fm_status status = FM_OK; fm_int errResult; struct sockaddr_in addrInfo; socklen_t addrLen = sizeof(addrInfo); char strErrBuf[FM_STRERROR_BUF_SIZE]; errno_t strErrNum; FM_LOG_ENTRY_VERBOSE(FM_LOG_CAT_PLATFORM, "socketInfo=%p, port=%d, backlog=%d\n", (void *) socketInfo, port, backlog); if (!socketInfo) { FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } FM_CLEAR(*socketInfo); if (type == FM_SOCKET_TYPE_TCP) { socketInfo->sock = socket(AF_INET, SOCK_STREAM, 0); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, socketInfo->sock == -1); socketInfo->address.sin_family = AF_INET; socketInfo->address.sin_addr.s_addr = htonl(INADDR_ANY); socketInfo->address.sin_port = htons(port); errResult = bind(socketInfo->sock, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); errResult = listen(socketInfo->sock, 3); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); #ifdef VERBOSE FM_LOG_DEBUG2(FM_LOG_CAT_PLATFORM, "Socket descriptor %d initialized\n", socketInfo->sock); #endif } else if (type == FM_SOCKET_TYPE_UDP) { socketInfo->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, socketInfo->sock == -1); socketInfo->address.sin_addr.s_addr = htonl(INADDR_ANY); socketInfo->address.sin_port = htons(port); errResult = bind(socketInfo->sock, (struct sockaddr *) &socketInfo->address, SOCKET_ADDRLEN); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); } else { FM_LOG_ASSERT(FM_LOG_CAT_PLATFORM, FALSE, "Unexpected socket type %d\n", type); FM_LOG_EXIT(FM_LOG_CAT_PLATFORM, FM_ERR_INVALID_ARGUMENT); } errResult = getsockname(socketInfo->sock, (struct sockaddr *) &addrInfo, &addrLen); FM_LOG_SYS_EXIT_ON_COND(FM_LOG_CAT_PLATFORM, errResult == -1); socketInfo->serverPort = ntohs(addrInfo.sin_port); FM_LOG_EXIT_VERBOSE(FM_LOG_CAT_PLATFORM, status); } /* end fmCreateNetworkServer */
/** fmLoadPortRemapTable * \ingroup intSwitch * * \desc Load a new port mapping table from a given file. * * \param[in] filename is the file name. * * \param[in] portTable is ptr to table where to store port read from file * * \param[in] origTable is ptr to the original port mapping table * * \param[in] maxport is number of entries in portTable * * \return FM_OK or FM_FAIL if unable to read table from file * *****************************************************************************/ fm_status fmLoadPortRemapTable(fm_char *filename, fm_int *portTable, fm_int *origTable, fm_int maxport) { FILE *fp; fm_char *pch; fm_char line[200]; fm_int i; fm_int j; fm_int portNum; fm_char * context; fm_uint s1max; fm_uint lineLeft; if ((fp = fopen(filename,"r")) == NULL) { FM_LOG_PRINT("cannot open file %s \n", filename); return(FM_FAIL); } /* Display the original port mapping table. */ FM_CLEAR(line); lineLeft = sizeof(line); FM_SPRINTF_S(line, lineLeft, "\noriginalTable[%d,", origTable[0]); i = strlen(line); lineLeft -= i; pch = &line[i]; for (i = 1 ; i < maxport ; i++) { FM_SPRINTF_S(pch, lineLeft, "%d,",origTable[i]); j = strlen(pch); lineLeft -= j; pch += j; } /* Reposition back to the trailing comma, then overwrite it */ --pch; *pch = ']'; FM_LOG_PRINT("%s\n", line); while ( fgets(line,200,fp) != NULL ) { if (strstr(line,"mappingTable") != NULL) { FM_LOG_PRINT("%s\n", line); if ((pch = strchr(line,'[')) != NULL) { i = 0; context = NULL; s1max = RSIZE_MAX - 1; pch = FM_STRTOK_S(++pch, &s1max, " ,", &context); while (pch != NULL && i < maxport) { portNum = atoi(pch); if (portNum >= 0 && portNum < maxport) { portTable[i++] = portNum; pch = FM_STRTOK_S(NULL, &s1max, " ,]", &context); } else { FM_LOG_PRINT("*** Invalid port number %d ***\n",portNum); fclose(fp); return(FM_FAIL); } } } } } fclose(fp); return FM_OK; } /* end fmLoadPortRemapTable */
/** 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 */
/** 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 */