/** 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 */
/** fmCreatePolicer * \ingroup policer * * \chips FM3000, FM4000, FM6000, FM10000 * * \desc Create a policer. Policers are used to manage * ingress bandwidth usage based on traffic flows * characterized by an ACL rule. Once created, a policer is * associated with an ACL rule in a call to ''fmAddACLRuleExt''. * \lb\lb * Policers can be used to manage the bandwidth of a traffic * flow, or merely count frames and octets for a flow. * \lb\lb * Policers are organized into "banks." Multiple ACLs can * simultaneously "hit" multiple policers, as long as they * are in different banks. The application need not be * concerned with the selection of which policers are placed * in which banks; the ACL compiler (''fmCompileACL'') will * make the placements automatically. However, not all * combinations of policer attributes are possible in hardware * (some attributes are per-bank). The user may want to * control the arrangement of policers in banks to better * understand which attribute combinations are foiling the * compiler. Whether bank selection is performed by the * application or by the ACL compiler, the choice should be * consistent for all policers created. * * \param[in] sw is the switch on which to operate. * * \param[in] bank is the bank in which to create the policer. * Set to FM_POLICER_BANK_AUTOMATIC to have the ACL compiler * (''fmCompileACL'') automatically assign the policer to a * bank. * * \param[in] policer is the policer number to create. Policer numbers * are unique across all banks. * * \param[in] config points to a structure of type ''fm_policerConfig'' * that contains the initial configuration of the policer. * Alternatively, config can be NULL and the policer * configuration can be set with calls to * ''fmSetPolicerAttribute'' * * \return FM_OK if successful. * \return FM_ERR_INVALID_SWITCH if sw is invalid. * \return FM_ERR_INVALID_POLICER if policer already created. * \return FM_ERR_INVALID_ARGUMENT if bank or policer values are * out of range. * *****************************************************************************/ fm_status fmCreatePolicer(fm_int sw, fm_int bank, fm_int policer, const fm_policerConfig *config) { fm_policerInfo * info; fm_individualPolicer *entry; fm_switch * switchPtr; FM_API_PREAMBLE("sw = %d, bank = %d, policer = %d, config = %p\n", sw, bank, policer, (void *) config); FM_API_REQUIRE(POLICER_VALID(policer) && BANK_VALID(sw, bank), FM_ERR_INVALID_ARGUMENT); switchPtr = GET_SWITCH_PTR(sw); info = &switchPtr->policerInfo; entry = (fm_individualPolicer *) fmAlloc( sizeof(fm_individualPolicer) ); FM_API_REQUIRE(entry != NULL, FM_ERR_NO_MEM); entry->bank = bank; if (config == NULL) { /* default attribute values */ entry->attributes.mkdnDscp = FM_DISABLED; entry->attributes.mkdnSwPri = FM_DISABLED; entry->attributes.colorSource = FM_POLICER_COLOR_SRC_GREEN; entry->attributes.cirAction = FM_POLICER_ACTION_DROP; entry->attributes.cirCapacity = 0; entry->attributes.cirRate = 0; entry->attributes.eirAction = FM_POLICER_ACTION_DROP; entry->attributes.eirCapacity = 0; entry->attributes.eirRate = 0; entry->attributes.cirActionData.dscp = 0; entry->attributes.cirActionData.swPri = 0; entry->attributes.cirActionData.vPri = 0; entry->attributes.eirActionData.dscp = 0; entry->attributes.eirActionData.swPri = 0; entry->attributes.eirActionData.vPri = 0; } else { entry->attributes = *config; } err = fmTreeInsert(&info->policers, policer, entry); if (err != FM_OK) { fmFree(entry); if (err == FM_ERR_ALREADY_EXISTS) { err = FM_ERR_INVALID_POLICER; } } if ( (err == FM_OK) && (switchPtr->CreatePolicer != NULL) ) { /* for SWAG */ err = switchPtr->CreatePolicer(sw, bank, policer, config); /* Try to return a clean state by removing the policer from switches that * actually created it (if some). Sorting order of creation and deletion * should be the same. */ if (err != FM_OK) { switchPtr->DeletePolicer(sw, policer); fmTreeRemoveCertain(&info->policers, policer, fmFree); } } FM_API_POSTAMBLE; } /* end fmCreatePolicer */