X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fenic%2Fenic_fm_flow.c;h=cd364ee16b38164c7731f5ae14fac418fa337d0b;hb=0604b1f2208f54ae76030e437db40f9da558497b;hp=34c9005ee2ff88941aee714c3c4f1bdc58b070cf;hpb=a4ab862e99c49b7b9e57c5844a1843b0e3d93ebc;p=dpdk.git diff --git a/drivers/net/enic/enic_fm_flow.c b/drivers/net/enic/enic_fm_flow.c index 34c9005ee2..cd364ee16b 100644 --- a/drivers/net/enic/enic_fm_flow.c +++ b/drivers/net/enic/enic_fm_flow.c @@ -5,9 +5,11 @@ #include #include #include -#include +#include #include #include +#include +#include #include #include #include @@ -43,6 +45,9 @@ /* Tag used for implicit VF <-> representor flows */ #define FM_VF_REP_TAG 1 +/* Max number of actions supported by VIC is 2K. Make hash table double that. */ +#define FM_MAX_ACTION_TABLE_SIZE 4096 + /* * Flow exact match tables (FET) in the VIC and rte_flow groups. * Use a simple scheme to map groups to tables. @@ -90,11 +95,17 @@ struct enic_fm_counter { uint32_t handle; }; +struct enic_fm_action { + int ref; + uint64_t handle; + struct fm_action key; +}; + /* rte_flow.fm */ struct enic_fm_flow { bool counter_valid; uint64_t entry_handle; - uint64_t action_handle; + struct enic_fm_action *action; struct enic_fm_counter *counter; struct enic_fm_fet *fet; /* Auto-added steer action for hairpin flows (e.g. vnic->vnic) */ @@ -155,6 +166,8 @@ struct enic_flowman { */ struct enic_fm_fet *default_eg_fet; struct enic_fm_fet *default_ig_fet; + /* hash table for Action reuse */ + struct rte_hash *action_hash; /* Flows that jump to the default table above */ TAILQ_HEAD(jump_flow_list, enic_fm_jump_flow) jump_list; /* @@ -355,8 +368,8 @@ enic_fm_copy_item_eth(struct copy_item_args *arg) fm_mask = &entry->ftm_mask.fk_hdrset[lvl]; fm_data->fk_header_select |= FKH_ETHER; fm_mask->fk_header_select |= FKH_ETHER; - memcpy(&fm_data->l2.eth, spec, sizeof(*spec)); - memcpy(&fm_mask->l2.eth, mask, sizeof(*mask)); + memcpy(&fm_data->l2.eth, spec, sizeof(struct rte_ether_hdr)); + memcpy(&fm_mask->l2.eth, mask, sizeof(struct rte_ether_hdr)); return 0; } @@ -466,8 +479,8 @@ enic_fm_copy_item_ipv6(struct copy_item_args *arg) fm_data->fk_header_select |= FKH_IPV6; fm_mask->fk_header_select |= FKH_IPV6; - memcpy(&fm_data->l3.ip6, spec, sizeof(*spec)); - memcpy(&fm_mask->l3.ip6, mask, sizeof(*mask)); + memcpy(&fm_data->l3.ip6, spec, sizeof(struct rte_ipv6_hdr)); + memcpy(&fm_mask->l3.ip6, mask, sizeof(struct rte_ipv6_hdr)); return 0; } @@ -1034,7 +1047,7 @@ enic_fm_copy_vxlan_encap(struct enic_flowman *fm, eth = (struct rte_ether_hdr *)template; ethertype = ð->ether_type; append_template(&template, &off, item->spec, - sizeof(struct rte_flow_item_eth)); + sizeof(struct rte_ether_hdr)); item++; flow_item_skip_void(&item); /* Optional VLAN */ @@ -1301,6 +1314,8 @@ enic_fm_copy_action(struct enic_flowman *fm, const struct rte_flow_action_mark *mark = actions->conf; + if (enic->use_noscatter_vec_rx_handler) + goto unsupported; if (mark->id >= ENIC_MAGIC_FILTER_ID - 1) return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, @@ -1314,6 +1329,8 @@ enic_fm_copy_action(struct enic_flowman *fm, break; } case RTE_FLOW_ACTION_TYPE_FLAG: { + if (enic->use_noscatter_vec_rx_handler) + goto unsupported; /* ENIC_MAGIC_FILTER_ID is reserved for flagging */ memset(&fm_op, 0, sizeof(fm_op)); fm_op.fa_op = FMOP_MARK; @@ -1953,19 +1970,26 @@ enic_fm_counter_alloc(struct enic_flowman *fm, struct rte_flow_error *error, } static int -enic_fm_action_free(struct enic_flowman *fm, uint64_t handle) +enic_fm_action_free(struct enic_flowman *fm, struct enic_fm_action *ah) { uint64_t args[2]; - int rc; + int ret = 0; ENICPMD_FUNC_TRACE(); - args[0] = FM_ACTION_FREE; - args[1] = handle; - rc = flowman_cmd(fm, args, 2); - if (rc) - ENICPMD_LOG(ERR, "cannot free action: rc=%d handle=0x%" PRIx64, - rc, handle); - return rc; + RTE_ASSERT(ah->ref > 0); + ah->ref--; + if (ah->ref == 0) { + args[0] = FM_ACTION_FREE; + args[1] = ah->handle; + ret = flowman_cmd(fm, args, 2); + if (ret) + /* This is a "should never happen" error. */ + ENICPMD_LOG(ERR, "freeing action rc=%d handle=0x%" + PRIx64, ret, ah->handle); + rte_hash_del_key(fm->action_hash, (const void *)&ah->key); + free(ah); + } + return ret; } static int @@ -2041,9 +2065,9 @@ __enic_fm_flow_free(struct enic_flowman *fm, struct enic_fm_flow *fm_flow) enic_fm_entry_free(fm, fm_flow->entry_handle); fm_flow->entry_handle = FM_INVALID_HANDLE; } - if (fm_flow->action_handle != FM_INVALID_HANDLE) { - enic_fm_action_free(fm, fm_flow->action_handle); - fm_flow->action_handle = FM_INVALID_HANDLE; + if (fm_flow->action != NULL) { + enic_fm_action_free(fm, fm_flow->action); + fm_flow->action = NULL; } enic_fm_counter_free(fm, fm_flow); if (fm_flow->fet) { @@ -2153,6 +2177,75 @@ enic_fm_add_exact_entry(struct enic_flowman *fm, return 0; } +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; +} + /* Push match-action to the NIC. */ static int __enic_fm_flow_add_entry(struct enic_flowman *fm, @@ -2164,29 +2257,18 @@ __enic_fm_flow_add_entry(struct enic_flowman *fm, struct rte_flow_error *error) { struct enic_fm_counter *ctr; - struct fm_action *fma; - uint64_t action_h; + struct enic_fm_action *ah = NULL; uint64_t entry_h; - uint64_t args[3]; int ret; ENICPMD_FUNC_TRACE(); - /* Allocate action. */ - fma = &fm->cmd.va->fm_action; - memcpy(fma, action_in, sizeof(*fma)); - args[0] = FM_ACTION_ALLOC; - args[1] = fm->cmd.pa; - ret = flowman_cmd(fm, args, 2); - if (ret != 0) { - ENICPMD_LOG(ERR, "allocating TCAM table action rc=%d", ret); - rte_flow_error_set(error, ret, RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "enic: devcmd(action-alloc)"); + + /* Get or create an aciton handle. */ + ret = enic_action_handle_get(fm, action_in, error, &ah); + if (ret) return ret; - } - action_h = args[0]; - fm_flow->action_handle = action_h; - match_in->ftm_action = action_h; - ENICPMD_LOG(DEBUG, "action allocated: handle=0x%" PRIx64, action_h); + match_in->ftm_action = ah->handle; + fm_flow->action = ah; /* Allocate counter if requested. */ if (match_in->ftm_flags & FMEF_COUNTER) { @@ -2260,7 +2342,7 @@ enic_fm_flow_add_entry(struct enic_flowman *fm, return NULL; } flow->fm = fm_flow; - fm_flow->action_handle = FM_INVALID_HANDLE; + fm_flow->action = NULL; fm_flow->entry_handle = FM_INVALID_HANDLE; if (__enic_fm_flow_add_entry(fm, fm_flow, match_in, action_in, attrs->group, attrs->ingress, error)) { @@ -2356,7 +2438,7 @@ add_hairpin_steer(struct enic_flowman *fm, struct rte_flow *flow, if (ret) goto error_with_flow; /* Add the ingress flow */ - fm_flow->action_handle = FM_INVALID_HANDLE; + fm_flow->action = NULL; fm_flow->entry_handle = FM_INVALID_HANDLE; ret = __enic_fm_flow_add_entry(fm, fm_flow, fm_tcam_entry, fm_action, FM_TCAM_RTE_GROUP, 1 /* ingress */, error); @@ -2610,7 +2692,7 @@ enic_fm_flow_flush(struct rte_eth_dev *dev, */ if (fm->ig_tcam_hndl == FM_INVALID_HANDLE) { fm_flow->entry_handle = FM_INVALID_HANDLE; - fm_flow->action_handle = FM_INVALID_HANDLE; + fm_flow->action = NULL; fm_flow->fet = NULL; } enic_fm_flow_free(fm, flow); @@ -2666,6 +2748,31 @@ enic_fm_tcam_tbl_alloc(struct enic_flowman *fm, uint32_t direction, return 0; } +static int +enic_fm_init_actions(struct enic_flowman *fm) +{ + struct rte_hash *a_hash; + char name[RTE_HASH_NAMESIZE]; + struct rte_hash_parameters params = { + .entries = FM_MAX_ACTION_TABLE_SIZE, + .key_len = sizeof(struct fm_action), + .hash_func = rte_jhash, + .hash_func_init_val = 0, + .socket_id = rte_socket_id(), + }; + + ENICPMD_FUNC_TRACE(); + snprintf((char *)name, sizeof(name), "fm-ah-%s", + fm->owner_enic->bdf_name); + params.name = name; + + a_hash = rte_hash_create(¶ms); + if (a_hash == NULL) + return -rte_errno; + fm->action_hash = a_hash; + return 0; +} + static int enic_fm_init_counters(struct enic_flowman *fm) { @@ -2779,6 +2886,12 @@ enic_fm_init(struct enic *enic) ENICPMD_LOG(ERR, "cannot alloc counters"); goto error_tables; } + /* set up action handle hash */ + rc = enic_fm_init_actions(fm); + if (rc) { + ENICPMD_LOG(ERR, "cannot create action hash, error:%d", rc); + goto error_counters; + } /* * One default exact match table for each direction. We hold onto * it until close. @@ -2786,7 +2899,7 @@ enic_fm_init(struct enic *enic) rc = enic_fet_alloc(fm, 1, NULL, 128, &fm->default_ig_fet); if (rc) { ENICPMD_LOG(ERR, "cannot alloc default IG exact match table"); - goto error_counters; + goto error_actions; } fm->default_ig_fet->ref = 1; rc = enic_fet_alloc(fm, 0, NULL, 128, &fm->default_eg_fet); @@ -2801,6 +2914,8 @@ enic_fm_init(struct enic *enic) error_ig_fet: enic_fet_free(fm, fm->default_ig_fet); +error_actions: + rte_hash_free(fm->action_hash); error_counters: enic_fm_free_all_counters(fm); error_tables: @@ -2827,6 +2942,7 @@ enic_fm_destroy(struct enic *enic) if (enic->fm == NULL) return; fm = enic->fm; + enic_fm_flow_flush(enic->rte_dev, NULL); enic_fet_free(fm, fm->default_eg_fet); enic_fet_free(fm, fm->default_ig_fet); /* Free all exact match tables still open */ @@ -2836,6 +2952,7 @@ enic_fm_destroy(struct enic *enic) } enic_fm_free_tcam_tables(fm); enic_fm_free_all_counters(fm); + rte_hash_free(fm->action_hash); enic_free_consistent(enic, sizeof(union enic_flowman_cmd_mem), fm->cmd.va, fm->cmd.pa); fm->cmd.va = NULL;