DWORD WINAPI moveFileWorker (VOID* data) { Task* task = (Task*) data; int result = 0; WIN32_FIND_DATA findData; TCHAR* tmpDst = (TCHAR*) fmAlloc (FM_MAX_PATH); TCHAR* tmpSrc = (TCHAR*) fmAlloc (FM_MAX_PATH); while (task->nextPath()) { lstrcpy (tmpDst, task->getDstFolder()); lstrcpy (tmpSrc, task->getCurSrcPath()); result = recurseOperation (&findData, tmpSrc, tmpDst, progressRoutine, (void*)task->getProgress(), MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH | MOVEFILE_REPLACE_EXISTING, FM_OPERATION_MOVE, NULL); } SendMessage (task->getProgress()->hDlg, FM_MOVE_FINISHED, 0, (LPARAM) data); fmFree ((HLOCAL*)&tmpSrc); fmFree ((HLOCAL*)&tmpDst); return result; }
/** * assumes the list is already sorted, and the key function is defined as: * * key(d1, d2) > 0 => d1 > d2 * key(d1, d2) == 0 => d1 == d2 * key(d1, d2) < 0 => d1 < d2 * * the new node is inserted prior to the node T such that T_data > data */ int fmDListInsertSorted(fm_dlist *list, int (*key)(void *, void *), void *data) { fm_dlist_node *p, *nnode; nnode = (fm_dlist_node *) fmAlloc( sizeof(fm_dlist_node) ); if (!nnode) { return FM_ERR_NO_MEM; } nnode->data = data; for (p = list->head ; p && (key(p->data, nnode->data) <= 0) ; p = p->nextPtr) { ; } /* p is now at a node that is "greater" than the new one */ FM_DLL_INSERT_BEFORE(list, head, tail, p, nextPtr, prev, nnode); return FM_OK; } /* end fmDListInsertSorted */
fm_status fmDListInsertBegin(fm_dlist *list, void *data) { fm_dlist_node *nnode = (fm_dlist_node *) fmAlloc( sizeof(fm_dlist_node) ); if (!nnode) { return FM_ERR_NO_MEM; } nnode->data = data; FM_DLL_INSERT_FIRST(list, head, tail, nnode, nextPtr, prev); return FM_OK; } /* end fmDListInsertBegin */
/** fmDListInsertEndV2 * \ingroup intList * * \desc Insert item at the end of the list and return the inserted * node. * * \param[in] list is the dlist on which to add the item at the end. * * \param[in] data is pointer to the item to be added. * * \param[out] node is the pointer to the node that is added in the list. * * \return None * *****************************************************************************/ fm_status fmDListInsertEndV2(fm_dlist *list, void *data, fm_dlist_node **node) { fm_dlist_node *nnode = (fm_dlist_node *) fmAlloc( sizeof(fm_dlist_node) ); if (!nnode) { return FM_ERR_NO_MEM; } nnode->data = data; FM_DLL_INSERT_LAST(list, head, tail, nnode, nextPtr, prev); *node = nnode; return FM_OK; } /* end fmDListInsertEnd */
INT_PTR onMovePauseToggle (HWND hDlg, WPARAM wParam, LPARAM lParam) { UINT buttonStrId = 0; if (isOperationThreadSuspended (hDlg)) { resumeOperationThread (hDlg); buttonStrId = IDS_COPY_PAUSE; } else { suspendOperationThread (hDlg); buttonStrId = IDS_COPY_RESUME; } TCHAR* str = (TCHAR*) fmAlloc (MAX_PATH); loadStringFromResource (hDlg, buttonStrId, str, MAX_PATH); SendDlgItemMessage (hDlg, IDC_PAUSE_TOGGLE, WM_SETTEXT, 0, (LPARAM) str); fmFree ((HLOCAL*)&str); return 0; }
/** 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 */
/** fm10000CreateLogicalPortForMailboxGlort * \ingroup intStacking * * \desc Creates a logical port for the given mailbox glort. * This occurs only if the glort is not local * to the current switch. * * \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_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 fm10000CreateLogicalPortForMailboxGlort(fm_int sw, fm_uint32 glort, fm_int * logicalPort) { fm_status err; fm_switch * switchPtr; fm_stackingInfo *stackingInfo; fm_port * portPtr; fm10000_port * portExt; 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); } } err = FM_OK; /*************************************************** * 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; /* Remote port structures created for mailbox purpose does not have CAM entries assigned, as these entries are not created dynamically. Mailbox CAM entries are created at the mailbox init stage to optimise GLORT_CAM/GLORT_RAM entries usage. */ portPtr->camEntry = NULL; /* Initialize multicast group membership list */ fmTreeInit(&portPtr->mcastGroupList); /*************************************************** * Add it to the logical port table. **************************************************/ switchPtr->portTable[*logicalPort] = portPtr; FM_LOG_EXIT(FM_LOG_CAT_STACKING, err); } /* end fm10000CreateLogicalPortForMailboxGlort */
/** 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 */
/** 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 */
/** fmAlosRootInit * \ingroup intAlosInit * * \desc Initialize ALOS state. * * \param[in] None. * * \return FM_OK if successful. * \return FM_ERR_NO_MEM if unable to allocate memory. * *****************************************************************************/ static fm_status fmAlosRootInit(void) { fm_status err; int ret; pthread_mutexattr_t attr; FM_LOG_ENTRY(FM_LOG_CAT_ALOS, "(no arguments)\n"); /* Allocate memory for ALOS state. */ fmRootAlos = fmAlloc( sizeof(fm_rootAlos) ); if (fmRootAlos == NULL) { /* Could not get memory. */ FM_LOG_EXIT(FM_LOG_CAT_ALOS, FM_ERR_NO_MEM); } err = fmAlosLockInit(); FM_LOG_EXIT_ON_ERR(FM_LOG_CAT_ALOS, err); if ( pthread_mutexattr_init(&attr) != 0 ) { FM_LOG_EXIT(FM_LOG_CAT_ALOS_SEM, FM_ERR_LOCK_INIT); } /* * From this point on, attr has been initialized, and we may ABORT. */ if ( pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED) != 0 ) { err = FM_ERR_LOCK_INIT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS_SEM, err); } ret = pthread_mutex_init(&fmRootAlos->treeTreeLock, &attr); if (ret != 0) { err = FM_ERR_LOCK_INIT; FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_DEBUG, err); } /* Initialize the tree of trees */ fmTreeInit(&fmRootAlos->treeTree); err = fmAlosRwlockInit(); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS, err); err = fmAlosSemInit(); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS, err); err = fmAlosLoggingInit(); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS, err); err = fmInitializeApiProperties(); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS, err); err = fmInitDynamicLoadLibs(); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS, err); err = fmAlosRandInit(); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS, err); err = fmAlosTimeInit(); FM_LOG_ABORT_ON_ERR(FM_LOG_CAT_ALOS, err); ABORT: pthread_mutexattr_destroy(&attr); FM_LOG_EXIT(FM_LOG_CAT_ALOS, err); } /* end fmAlosRootInit */
/** 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 */