/** fmUpdatePolicer * \ingroup policer * * \chips FM6000, FM10000 * * \desc Updates policer configuration in hardware without * disrupting existing ACLs. The configuration is updated * with values obtained from the policer attributes. * This function is used to update the configuration of a * policer that has already been created, and whose previous * configuration is in hardware. For setting policer * attributes see ''fmSetPolicerAttribute''. * * \param[in] sw is the switch on which to operate. * * \param[in] policer is the policer number to be updated. * * \return FM_OK if successful. * \return FM_ERR_INVALID_POLICER if policer is not present in the * software cache or has invalid attribute values. * \return FM_ERR_INVALID_ACL_IMAGE if no applied acl image is found. * \return FM_ERR_INVALID_COUNTER_BANK if policer's current bank is * invalid. * \return FM_ERR_INVALID_COUNTER_INDEX if policer's index in the bank * is invalid. * \return FM_ERR_UNSUPPORTED if this api is not supported by this * type of switch. * \return FM_ERR_INVALID_SWITCH if sw is invalid. * \return FM_ERR_CONFLICT_POLICER_PARAM if the new configuration * conflicts with the policer bank configuration. * (FM10000 only) * *****************************************************************************/ fm_status fmUpdatePolicer(fm_int sw, fm_int policer) { fm_switch *switchPtr; fm_policerInfo *info; void *value; FM_API_PREAMBLE("sw = %d, policer = %d\n", sw, policer); switchPtr = GET_SWITCH_PTR(sw); info = &switchPtr->policerInfo; err = fmTreeFind(&info->policers, policer, &value); if (value == NULL || err == FM_ERR_NOT_FOUND) { FM_API_ABORT(FM_ERR_INVALID_POLICER); } FM_API_CALL_FAMILY(err, switchPtr->UpdatePolicer, sw, policer); FM_API_POSTAMBLE; } /* end fmUpdatePolicer */
/** fm10000DeleteForwardingRule * \ingroup intStacking * * \desc Deletes a rule given the rule ID. * * \param[in] sw is the switch number to operate on. * * \param[in] ruleId is the ID number of the rule to delete. * * * \return FM_OK if successful. * \return FM_ERR_NOT_FOUND if id not recognized. * *****************************************************************************/ fm_status fm10000DeleteForwardingRule(fm_int sw, fm_int ruleId) { fm_switch * switchPtr; fm_stackingInfo * stackingInfo; fm_forwardRuleInternal * internalRule; fm10000_forwardRuleInternal *fwdExt; fm_status err; FM_LOG_ENTRY(FM_LOG_CAT_STACKING, "sw=%d, id=%d\n", sw, ruleId); switchPtr = GET_SWITCH_PTR(sw); stackingInfo = &switchPtr->stackingInfo; err = fmTreeFind( &stackingInfo->fwdRules, ruleId, (void **) &internalRule ); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_STACKING, err); fwdExt = (fm10000_forwardRuleInternal *) internalRule->extension; /* this invalidates the CAM entry */ fwdExt->camEntry->camKey = 0; fwdExt->camEntry->camMask = 0; err = fm10000WriteGlortCamEntry(sw, fwdExt->camEntry, FM_UPDATE_CAM_ONLY); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_STACKING, err); FM_LOG_DEBUG(FM_LOG_CAT_STACKING, "Reset CAM entry 0x%x\n", fwdExt->camEntry->camIndex); /* mark it available */ fwdExt->camEntry->useCount = 0; FM_LOG_EXIT(FM_LOG_CAT_STACKING, FM_OK); } /* end fm10000DeleteForwardingRule */
/** fm10000CreateForwardingRule * \ingroup intStacking * * \desc Creates a forwarding rule. * * \param[in] sw is the switch number to operate on. * * \param[in] ruleId points to caller allocated storage where the handle * of the new rule is written to. * * \param[in] rule points to caller allocated storage containing the * rule to create. * * \return FM_OK if successful. * \return FM_ERR_NO_FREE_RESOURCES if there are no hardware resources * to accommodate the new forwarding rule. * \return FM_ERR_NO_MEM if there is not enough memory to store * the forwarding rule data structure. * *****************************************************************************/ fm_status fm10000CreateForwardingRule(fm_int sw, fm_int *ruleId, fm_forwardRule *rule) { fm_status err; fm_int camIndex; fm_glortCamEntry * camEntry; fm_switch * switchPtr; fm_logicalPortInfo * lportInfo; fm_forwardRuleInternal * internalRule; fm10000_forwardRuleInternal *fwdExt; fm_stackingInfo * stackingInfo; fm_port * portPtr; FM_LOG_ENTRY( FM_LOG_CAT_STACKING, "sw=%d, ruleId=%p, rule=%p\n", sw, (void *) ruleId, (void *) rule ); switchPtr = GET_SWITCH_PTR(sw); lportInfo = &switchPtr->logicalPortInfo; portPtr = GET_PORT_PTR(sw, rule->logicalPort); fwdExt = NULL; if (portPtr == NULL) { err = FM_ERR_INVALID_PORT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_STACKING, err); } stackingInfo = &switchPtr->stackingInfo; /*************************************************** * Find an unused CAM entry. **************************************************/ camIndex = fmFindUnusedCamEntry(sw); if (camIndex < 0) { err = FM_ERR_NO_FREE_RESOURCES; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_STACKING, err); } camEntry = &lportInfo->camEntries[camIndex]; /*************************************************** * Create an FM10000 forwarding rule extension. **************************************************/ fwdExt = (fm10000_forwardRuleInternal *) fmAlloc( sizeof(fm10000_forwardRuleInternal) ); if (fwdExt == NULL) { err = FM_ERR_NO_MEM; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_STACKING, err); } fwdExt->camEntry = camEntry; /*************************************************** * Initialize the CAM entry. **************************************************/ FM_MEMSET_S( camEntry, sizeof(fm_glortCamEntry), 0, sizeof(fm_glortCamEntry) ); camEntry->camIndex = camIndex; camEntry->camKey = rule->glort; camEntry->camMask = ~rule->mask; /* Hardware stores mask inverted from rule mask */ if ( fmIsCardinalPort(sw, rule->logicalPort) ) { camEntry->strict = FM_GLORT_ENTRY_TYPE_STRICT; } else { /* Needs to be hashed to support LAG on internal port for traffic * to be hashed across the internal LAG link. Especially * CPU traffic, since FTYPE is special delivery and won't * be hashed if set to ISL */ camEntry->strict = FM_GLORT_ENTRY_TYPE_HASHED; } /*************************************************** * This makes the assumption that the rule points * to a physical port that is not going to have its * dest table entry changing. **************************************************/ camEntry->destIndex = portPtr->destEntry->destIndex; camEntry->destCount = 1; camEntry->useCount = 1; /*************************************************** * Write CAM entry to hardware. **************************************************/ err = fm10000WriteGlortCamEntry(sw, camEntry, FM_UPDATE_CAM_AND_RAM); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_STACKING, err); FM_LOG_DEBUG(FM_LOG_CAT_STACKING, "Wrote to CAM entry 0x%x\n", camIndex); /*************************************************** * Get the underlying forwarding rule object. **************************************************/ err = fmTreeFind( &stackingInfo->fwdRules, *ruleId, (void **) &internalRule ); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_STACKING, err); /*************************************************** * Store pointer to extension. **************************************************/ internalRule->extension = fwdExt; err = FM_OK; ABORT: if (err != FM_OK) { if (fwdExt != NULL) { fmFree(fwdExt); } } FM_LOG_EXIT(FM_LOG_CAT_STACKING, err); } /* end fm10000CreateForwardingRule */
/** 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 */
/** GetAttributeLocation * \ingroup intPolicer * * \desc This function contains the logic for the policer * attributes in one place, instead of replicating the * logic in both the get and set functions, as is done * in other attribute systems in the API. This function * returns the location and size of the specified attribute, * and the caller can then copy into or out of it as * appropriate. * * \param[in] sw is the switch on which to operate. * * \param[in] policer is the policer number whose attribute is to be * accessed. This argument is ignored for global attributes. * * \param[in] attr is the policer attribute to access (see * ''Policer Attributes''). * * \param[out] location receives the address of the attribute * * \param[out] size receives the size of the attribute, in bytes * * \return FM_OK if successful. * \return FM_ERR_INVALID_POLICER if policer is invalid. * \return FM_ERR_INVALID_ARGUMENT if unrecognized attribute. * *****************************************************************************/ static fm_status GetAttributeLocation(fm_int sw, fm_int policer, fm_int attr, void ** location, fm_int *size) { void * value; fm_individualPolicer *entry; fm_policerInfo * info; fm_status treeErr; info = &GET_SWITCH_PTR(sw)->policerInfo; treeErr = fmTreeFind(&info->policers, policer, &value); entry = (fm_individualPolicer *) value; if (treeErr == FM_ERR_NOT_FOUND) { treeErr = FM_ERR_INVALID_POLICER; } switch (attr) { case FM_POLICER_MKDN_DSCP: RETURN_POLICER_ATTRIBUTE(mkdnDscp); case FM_POLICER_MKDN_SWPRI: RETURN_POLICER_ATTRIBUTE(mkdnSwPri); case FM_POLICER_COLOR_SOURCE: RETURN_POLICER_ATTRIBUTE(colorSource); case FM_POLICER_CIR_ACTION: RETURN_POLICER_ATTRIBUTE(cirAction); case FM_POLICER_CIR_ACTION_DATA_DSCP: RETURN_POLICER_ATTRIBUTE(cirActionData.dscp); case FM_POLICER_CIR_ACTION_DATA_VPRI: RETURN_POLICER_ATTRIBUTE(cirActionData.vPri); case FM_POLICER_CIR_ACTION_DATA_SWPRI: RETURN_POLICER_ATTRIBUTE(cirActionData.swPri); case FM_POLICER_CIR_CAPACITY: RETURN_POLICER_ATTRIBUTE(cirCapacity); case FM_POLICER_CIR_RATE: RETURN_POLICER_ATTRIBUTE(cirRate); case FM_POLICER_EIR_ACTION: RETURN_POLICER_ATTRIBUTE(eirAction); case FM_POLICER_EIR_ACTION_DATA_DSCP: RETURN_POLICER_ATTRIBUTE(eirActionData.dscp); case FM_POLICER_EIR_ACTION_DATA_VPRI: RETURN_POLICER_ATTRIBUTE(eirActionData.vPri); case FM_POLICER_EIR_ACTION_DATA_SWPRI: RETURN_POLICER_ATTRIBUTE(eirActionData.swPri); case FM_POLICER_EIR_CAPACITY: RETURN_POLICER_ATTRIBUTE(eirCapacity); case FM_POLICER_EIR_RATE: RETURN_POLICER_ATTRIBUTE(eirRate); case FM_POLICER_SWPRI_MKDN_MAP: *location = info->swPriMkdnMap; *size = sizeof(info->swPriMkdnMap); return FM_OK; case FM_POLICER_DSCP_MKDN_MAP: *location = info->dscpMkdnMap; *size = sizeof(info->dscpMkdnMap); return FM_OK; default: return FM_ERR_INVALID_ARGUMENT; } /* end switch (attr) */ } /* end GetAttributeLocation */