/** fmGetPolicerFirst * \ingroup policer * * \chips FM3000, FM4000, FM6000, FM10000 * * \desc Retrieve the first policer number. * * \param[in] sw is the switch on which to operate. * * \param[out] firstPolicer points to caller-allocated storage * where this function should place the number of the first * policer. Will be set to -1 if no policers are found. * * \return FM_OK if successful. * \return FM_ERR_INVALID_SWITCH if sw is invalid. * \return FM_ERR_NO_POLICERS if no policers found. * *****************************************************************************/ fm_status fmGetPolicerFirst(fm_int sw, fm_int *firstPolicer) { fm_policerInfo *info; fm_treeIterator it; fm_uint64 nextKey; void * nextValue; FM_API_PREAMBLE("sw = %d, firstPolicer = %p\n", sw, (void *) firstPolicer); if (firstPolicer == NULL) { err = FM_ERR_INVALID_ARGUMENT; goto ABORT; } info = &GET_SWITCH_PTR(sw)->policerInfo; fmTreeIterInit(&it, &info->policers); err = fmTreeIterNext(&it, &nextKey, &nextValue); if (err == FM_OK) { *firstPolicer = nextKey; } else if (err == FM_ERR_NO_MORE) { *firstPolicer = -1; err = FM_ERR_NO_POLICERS; } FM_API_POSTAMBLE; } /* end fmGetPolicerFirst */
/** fmGetPolicerList * \ingroup policer * * \chips FM3000, FM4000, FM6000, FM10000 * * \desc Return a list of valid policer numbers. * * \param[in] sw is the switch on which to operate. * * \param[out] numPolicers points to caller allocated storage where * this function should place the number of valid policers * returned in policers. * * \param[out] policers is an array that this function will fill * with the list of valid policer numbers. * * \param[in] max is the size of policers, being the maximum number of * policer numbers that policers can hold. * * \return FM_OK if successful. * \return FM_ERR_INVALID_SWITCH if sw is invalid. * \return FM_ERR_BUFFER_FULL if max was too small to accommodate * the entire list of valid policer numbers. * *****************************************************************************/ fm_status fmGetPolicerList(fm_int sw, fm_int *numPolicers, fm_int *policers, fm_int max) { fm_policerInfo *info; fm_treeIterator it; fm_uint64 nextKey; void * nextValue; FM_API_PREAMBLE("sw = %d, numPolicers = %p, policers = %p, max = %d\n", sw, (void *) numPolicers, (void *) policers, max); if ((numPolicers == NULL) || (policers == NULL)) { err = FM_ERR_INVALID_ARGUMENT; goto ABORT; } *numPolicers = 0; info = &GET_SWITCH_PTR(sw)->policerInfo; for (fmTreeIterInit(&it, &info->policers) ; ( err = fmTreeIterNext(&it, &nextKey, &nextValue) ) == FM_OK ; ) { FM_API_REQUIRE(*numPolicers < max, FM_ERR_BUFFER_FULL); policers[(*numPolicers)++] = nextKey; } if (err == FM_ERR_NO_MORE) { err = FM_OK; } FM_API_POSTAMBLE; } /* end fmGetPolicerList */
/** fm10000CreateLogicalPortForGlort * \ingroup intStacking * * \desc Creates a logical port for the given glort. This occurs * only if the glort is not local to the current switch and * a forwarding rule exists for the glort, otherwise an * error is returned. * * \param[in] sw is the switch number to operate on. * * \param[in] glort is the glort for which a logical port is to be created * * \param[out] logicalPort is a pointer to an integer into which the * new logical port will be written. * * \return FM_OK if successful. * \return FM_ERR_GLORT_IN_USE if the specified is already being used * by others. * \return FM_ERR_NO_FORWARDING_RULES if no forwarding rule associated * with glort. * \return FM_ERR_NO_FREE_RESOURCES if logical port numbers available * for allocation. * \return FM_ERR_NO_MEM if no memory available to store logical * port data structure. * *****************************************************************************/ fm_status fm10000CreateLogicalPortForGlort(fm_int sw, fm_uint32 glort, fm_int * logicalPort) { fm_status err; fm_switch * switchPtr; fm_stackingInfo * stackingInfo; fm_port * portPtr; fm_glortCamEntry * camEntry; fm10000_port * portExt; fm_treeIterator iter; fm_forwardRuleInternal *tmpRule; fm_uint64 tmpId; fm_bool found; FM_LOG_ENTRY( FM_LOG_CAT_STACKING, "sw=%d, glort=%d, logicalPort=%p\n", sw, glort, (void *) logicalPort ); switchPtr = GET_SWITCH_PTR(sw); stackingInfo = &switchPtr->stackingInfo; found = FALSE; /* If there is an existing entry already, then return the existing one */ err = fmGetGlortLogicalPort(sw, glort, logicalPort); if (err == FM_OK) { /* The port already exists, see if it is the same type */ portPtr = GET_PORT_PTR(sw, *logicalPort); if (portPtr->portType == FM_PORT_TYPE_REMOTE) { /* Yes, return the existing port */ FM_LOG_EXIT(FM_LOG_CAT_STACKING, FM_OK); } else { /* The glort is being used for something else */ FM_LOG_EXIT(FM_LOG_CAT_STACKING, FM_ERR_GLORT_IN_USE); } } /*************************************************** * Search the tree for a forwarding rule with a * matching glort. **************************************************/ fmTreeIterInit(&iter, &stackingInfo->fwdRules); err = fmTreeIterNext( &iter, &tmpId, (void **) &tmpRule ); while (err != FM_ERR_NO_MORE) { if ( ( ~tmpRule->rule.mask & tmpRule->rule.glort ) == ( ~tmpRule->rule.mask & glort ) ) { found = TRUE; break; } err = fmTreeIterNext( &iter, &tmpId, (void **) &tmpRule ); } if ( !found ) { FM_LOG_DEBUG(FM_LOG_CAT_STACKING, "Glort 0x%x was not matched to a forwarding rule\n", glort); FM_LOG_EXIT(FM_LOG_CAT_STACKING, FM_ERR_NO_FORWARDING_RULES); } FM_LOG_DEBUG(FM_LOG_CAT_STACKING, "Glort 0x%x was matched to forwarding rule #%lld\n", glort, tmpId); camEntry = ( (fm10000_forwardRuleInternal *) tmpRule->extension )->camEntry; /*************************************************** * Find an unused logical port number. **************************************************/ *logicalPort = fmFindUnusedLogicalPorts(sw, 1); if (*logicalPort == -1) { FM_LOG_EXIT(FM_LOG_CAT_STACKING, FM_ERR_NO_FREE_RESOURCES); } /*************************************************** * Create an entry for the remote logical port. **************************************************/ portPtr = (fm_port *) fmAlloc(sizeof(fm_port)); if (portPtr == NULL) { FM_LOG_EXIT(FM_LOG_CAT_STACKING, FM_ERR_NO_MEM); } FM_MEMSET_S( portPtr, sizeof(fm_port), 0, sizeof(fm_port) ); portExt = (fm10000_port *) fmAlloc( sizeof(fm10000_port) ); if (portExt == NULL) { fmFree(portPtr); FM_LOG_EXIT(FM_LOG_CAT_STACKING, FM_ERR_NO_MEM); } FM_MEMSET_S( portExt, sizeof(fm10000_port), 0, sizeof(fm10000_port) ); portPtr->switchPtr = switchPtr; portPtr->portNumber = *logicalPort; portPtr->portType = FM_PORT_TYPE_REMOTE; portPtr->extension = portExt; portPtr->lagIndex = -1; portPtr->memberIndex = -1; portPtr->glort = glort; portPtr->swagPort = -1; portPtr->camEntry = camEntry; /* Increase the CAM reference use count */ portPtr->camEntry->useCount++; portPtr->destEntry = NULL; portPtr->numDestEntries = 0; /* Initialize multicast group membership list */ fmTreeInit(&portPtr->mcastGroupList); /* Set the default to down, the application must * bring it up, similar to physical port. */ portPtr->mode = FM_PORT_STATE_DOWN; /*************************************************** * Add it to the logical port table. **************************************************/ switchPtr->portTable[*logicalPort] = portPtr; FM_LOG_EXIT(FM_LOG_CAT_STACKING, err); } /* end fm10000CreateLogicalPortForGlort */
/** MoveListenersToReplicationGroup * \ingroup intMulticast * * \desc Move a group of listeners to a replication group. * * \param[in] sw is the switch number. * * \param[in] repliGroup is the replication group number. * * \param[in] mcastGroup points to the multicast group entry, * * \return FM_OK if successful. * \return FM_ERR_INVALID_PORT if a listener port is invalid * *****************************************************************************/ static fm_status MoveListenersToReplicationGroup(fm_int sw, fm_int repliGroup, fm_intMulticastGroup *mcastGroup) { fm_status err; fm_switch * switchPtr; fm_int mcastLogicalPort; fm_intMulticastListener *intListener; fm_int listenerCount; fm_int i; fm_treeIterator iter; fm_uint64 key; fm10000_mtableEntry listener; fm_port *portPtr; fm_int port; FM_LOG_ENTRY( FM_LOG_CAT_MULTICAST, "sw=%d repliGroup=%d mcastLogPort=%d\n", sw, repliGroup, mcastGroup->logicalPort); switchPtr = GET_SWITCH_PTR(sw); err = FM_OK; listenerCount = 0; mcastLogicalPort = mcastGroup->logicalPort; /* Get the number of listeners to move */ listenerCount = (fm_int) fmTreeSize(&mcastGroup->listenerTree); if (listenerCount > 0) { i = 0; fmTreeIterInit(&iter, &mcastGroup->listenerTree); while (1) { err = fmTreeIterNext(&iter, &key, (void **) &intListener); if (err != FM_OK) { if (err != FM_ERR_NO_MORE) { FM_LOG_ABORT(FM_LOG_CAT_MULTICAST, err); } err = FM_OK; break; } if (intListener->listener.listenerType != FM_MCAST_GROUP_LISTENER_PORT_VLAN) { continue; } if (i++ >= listenerCount) { err = FM_FAIL; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } listener.vlan = intListener->listener.info.portVlanListener.vlan; listener.vlanUpdate = TRUE; if ( (intListener->listener.info.portVlanListener.vlan == 0) && (intListener->listener.info.portVlanListener.port == -1) ) { port = switchPtr->cpuPort; portPtr = NULL; } else { port = intListener->listener.info.portVlanListener.port; portPtr = GET_PORT_PTR(sw, port); if (!portPtr) { FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, FM_ERR_INVALID_PORT); } } if ( (portPtr != NULL) && (portPtr->portType == FM_PORT_TYPE_VIRTUAL) ) { err = fm10000MapVirtualGlortToLogicalPort(sw, portPtr->glort, &listener.port); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); listener.dglortUpdate = TRUE; listener.dglort = portPtr->glort; if (intListener->listener.info.portVlanListener.vlan == 0) { listener.vlanUpdate = FALSE; } } else { listener.port = port; listener.dglortUpdate = FALSE; listener.dglort = 0; } err = fm10000MTableAddListener(sw, mcastLogicalPort, repliGroup, listener); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } /* Sanity check */ if (i != listenerCount) { err = FM_FAIL; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } } ABORT: FM_LOG_EXIT(FM_LOG_CAT_MULTICAST, err); } /* end MoveListenersToReplicationGroup */
/** fm10000MoveReplicationGroupMcastGroup * \ingroup intMulticast * * \desc Move the mcast group to a given replication group. * * \param[in] sw is the switch number. * * \param[in] groupHandle is the new replication group handle. * * \param[in] mcastGroup is the mcast group number. * * \return FM_OK if successful. * \return FM_ERR_INVALID_MULTICAST_GROUP if the replication group * is invalid. * \return FM_ERR_INVALID_PORT if a listener port is invalid * *****************************************************************************/ fm_status fm10000MoveReplicationGroupMcastGroup(fm_int sw, fm_int groupHandle, fm_int mcastGroup) { fm_status err=FM_OK; fm_switch * switchPtr; fm_intReplicationGroup *repliGroup; fm_intReplicationGroup *prevGroup; fm_intMulticastGroup * mcastGroupPtr; fm_intMulticastGroup * mcastGroupTmp; fm10000_MulticastGroup *mcastGroupExt; fm_int groupDestIndex; fm_int newGroupId=FM_MCASTGROUP_REPLICATION_GROUP_DISABLE; fm_int mtableDestIndex; fm_int privateGroup=FALSE; fm_bool removeFromPreviousTree=FALSE; fm_treeIterator iter; fm_uint64 key; fm_intMulticastEcmp * ecmpGroup; FM_LOG_ENTRY( FM_LOG_CAT_MULTICAST, "sw=%d newrepliGroup=%d mcastGroup=%d\n", sw, groupHandle, mcastGroup); switchPtr = GET_SWITCH_PTR(sw); mcastGroupPtr = fmFindMcastGroup(sw, mcastGroup); if ( mcastGroupPtr == NULL ) { err = FM_ERR_INVALID_MULTICAST_GROUP; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } mcastGroupExt = mcastGroupPtr->extension; groupDestIndex = -1; /* If the given new replication group is -1, i.e. disable, then we * need to allocate a private replication group for this mcast group * if the latter is active */ if ( groupHandle == FM_MCASTGROUP_REPLICATION_GROUP_DISABLE ) { if (mcastGroupPtr->activated) { privateGroup = TRUE; err = fmCreateReplicationGroupInt(sw, &newGroupId, mcastGroupPtr->logicalPort, &mtableDestIndex, TRUE); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); FM_LOG_DEBUG(FM_LOG_CAT_MULTICAST, "newRepliGroup %d DestIndex=%d\n", newGroupId, mtableDestIndex); } } else { privateGroup = FALSE; newGroupId = groupHandle; } if (newGroupId != FM_MCASTGROUP_REPLICATION_GROUP_DISABLE) { /* We have to move the mcast group to a new replication group */ repliGroup = findReplicationGroup(sw, newGroupId); if (repliGroup == NULL) { err = FM_ERR_INVALID_MULTICAST_GROUP; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } /* Search the tree of mcast groups for a matching entry. */ err = fmTreeFind( &repliGroup->mcastGroupList, (fm_uint64) mcastGroup, (void **) &mcastGroupTmp ); if (err == FM_OK) { /* Error if already in group */ err = FM_ERR_ALREADY_EXISTS; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } groupDestIndex = repliGroup->hwDestIndex; if (mcastGroupPtr->activated) { /* This mcast group is active; move all its listeners to the * new replication group. */ /* Update the multicast index attribute for this mcast group */ err = switchPtr->SetLogicalPortAttribute(sw, mcastGroupPtr->logicalPort, FM_LPORT_MULTICAST_INDEX, &groupDestIndex); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); if (!mcastGroupPtr->readOnlyRepliGroup) { err = MoveListenersToReplicationGroup(sw, newGroupId, mcastGroupPtr); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } /* Update the NextHop entry to use the new replicate group. */ mcastGroupExt->mtableDestIndex = groupDestIndex; err = fm10000UpdateNextHopMulticast(sw, mcastGroupPtr->ecmpGroup); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); fmTreeIterInit(&iter, &mcastGroupPtr->ecmpTree); while (1) { err = fmTreeIterNext(&iter, &key, (void **) &ecmpGroup); if (err != FM_OK) { if (err == FM_ERR_NO_MORE) { err = FM_OK; } break; } err = fm10000UpdateNextHopMulticast(sw, ecmpGroup->ecmpId); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); /* Remove the mcastgroup's listeners from previous replication group */ if (!mcastGroupPtr->readOnlyRepliGroup) { err = RemoveListenersFromReplicationGroup(sw, mcastGroupPtr->repliGroup, mcastGroupPtr); FM_LOG_ABORT_ON_ERR ( FM_LOG_CAT_MULTICAST, err ); } /* Release the previous replication group if it was a private one */ if (mcastGroupPtr->privateGroup) { /* No need to remove it from previous group Tree since * the group will be deleted or freed */ removeFromPreviousTree = FALSE; err = fmDeleteReplicationGroupInt(sw, mcastGroupPtr->repliGroup, TRUE); FM_LOG_ABORT_ON_ERR ( FM_LOG_CAT_MULTICAST, err ); } else { /* Remove mcast group from the list of the previous * replication group */ removeFromPreviousTree = TRUE; } } else if (mcastGroupPtr->repliGroup != FM_MCASTGROUP_REPLICATION_GROUP_DISABLE) { /* Remove mcast group from the list of the previous * replication group */ removeFromPreviousTree = TRUE; } /* Insert the mcast group in the list of the new replication group */ err = fmTreeInsert(&repliGroup->mcastGroupList, (fm_uint64) mcastGroup, (void *) mcastGroupPtr); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } else if (mcastGroupPtr->repliGroup != FM_MCASTGROUP_REPLICATION_GROUP_DISABLE) { /* Removing a none active mcast group from its replication group */ privateGroup = FALSE; groupDestIndex = -1; removeFromPreviousTree = TRUE; } if (removeFromPreviousTree) { /* Remove mcast group from the list of the previous replication group */ prevGroup = findReplicationGroup(sw, mcastGroupPtr->repliGroup); if (prevGroup == NULL) { err = FM_ERR_INVALID_MULTICAST_GROUP; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); } err = fmTreeRemove(&prevGroup->mcastGroupList, (fm_uint64) mcastGroup, NULL ); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_MULTICAST, err); FM_LOG_DEBUG(FM_LOG_CAT_MULTICAST, "mcast group %d deleted from Replication group %d\n", mcastGroup, prevGroup->handle); } /* Update mcast group with info from the new replication group */ mcastGroupPtr->repliGroup = newGroupId; mcastGroupPtr->privateGroup = privateGroup; mcastGroupExt->mtableDestIndex = groupDestIndex; FM_LOG_DEBUG(FM_LOG_CAT_MULTICAST, "mcastgroup %d moved to Replication group %d, index %d\n", mcastGroup, mcastGroupPtr->repliGroup, groupDestIndex); ABORT: FM_LOG_EXIT(FM_LOG_CAT_MULTICAST, err); } /* end fm10000MoveReplicationGroupMcastGroup */