+static int
+enic_action_handle_get(struct enic_flowman *fm, struct fm_action *action_in,
+ struct rte_flow_error *error,
+ struct enic_fm_action **ah_o)
+{
+ struct enic_fm_action *ah;
+ struct fm_action *fma;
+ uint64_t args[2];
+ int ret = 0;
+
+ ret = rte_hash_lookup_data(fm->action_hash, action_in,
+ (void **)&ah);
+ if (ret < 0 && ret != -ENOENT)
+ return rte_flow_error_set(error, -ret,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "enic: rte_hash_lookup(aciton)");
+
+ if (ret == -ENOENT) {
+ /* Allocate a new action on the NIC. */
+ fma = &fm->cmd.va->fm_action;
+ memcpy(fma, action_in, sizeof(*fma));
+
+ ah = calloc(1, sizeof(*ah));
+ memcpy(&ah->key, action_in, sizeof(struct fm_action));
+ if (ah == NULL)
+ return rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_HANDLE,
+ NULL, "enic: calloc(fm-action)");
+ args[0] = FM_ACTION_ALLOC;
+ args[1] = fm->cmd.pa;
+ ret = flowman_cmd(fm, args, 2);
+ if (ret != 0) {
+ rte_flow_error_set(error, -ret,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "enic: devcmd(action-alloc)");
+ goto error_with_ah;
+ }
+ ah->handle = args[0];
+ ret = rte_hash_add_key_data(fm->action_hash,
+ (const void *)action_in,
+ (void *)ah);
+ if (ret != 0) {
+ rte_flow_error_set(error, -ret,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "enic: rte_hash_add_key_data(actn)");
+ goto error_with_action_handle;
+ }
+ ENICPMD_LOG(DEBUG, "action allocated: handle=0x%" PRIx64,
+ ah->handle);
+ }
+
+ /* Action handle struct is valid, increment reference count. */
+ ah->ref++;
+ *ah_o = ah;
+ return 0;
+error_with_action_handle:
+ args[0] = FM_ACTION_FREE;
+ args[1] = ah->handle;
+ ret = flowman_cmd(fm, args, 2);
+ if (ret != 0)
+ rte_flow_error_set(error, -ret,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "enic: devcmd(action-free)");
+error_with_ah:
+ free(ah);
+ return ret;
+}
+