X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fmlx5%2Fmlx5_flow.c;h=5c78ea7f3caa7bf70c67a971f905e8cce09960d3;hb=4a73c86ff616498768aa77ebad8115f99feff2aa;hp=61afc48ea51b16b1a02185d01d6170d3f01786b0;hpb=dd3c774f6ffb446ede55037b69fd6862fd0fd40f;p=dpdk.git diff --git a/drivers/net/mlx5/mlx5_flow.c b/drivers/net/mlx5/mlx5_flow.c index 61afc48ea5..5c78ea7f3c 100644 --- a/drivers/net/mlx5/mlx5_flow.c +++ b/drivers/net/mlx5/mlx5_flow.c @@ -344,6 +344,7 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev, { struct mlx5_priv *priv = dev->data->dev_private; struct mlx5_dev_config *config = &priv->config; + enum modify_reg start_reg; switch (feature) { case MLX5_HAIRPIN_RX: @@ -363,7 +364,15 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev, case MLX5_METADATA_TX: return REG_A; case MLX5_METADATA_FDB: - return REG_C_0; + switch (config->dv_xmeta_en) { + case MLX5_XMETA_MODE_LEGACY: + return REG_NONE; + case MLX5_XMETA_MODE_META16: + return REG_C_0; + case MLX5_XMETA_MODE_META32: + return REG_C_1; + } + break; case MLX5_FLOW_MARK: switch (config->dv_xmeta_en) { case MLX5_XMETA_MODE_LEGACY: @@ -375,24 +384,53 @@ mlx5_flow_get_reg_id(struct rte_eth_dev *dev, } break; case MLX5_COPY_MARK: - return REG_C_3; + case MLX5_MTR_SFX: + /* + * Metadata COPY_MARK register using is in meter suffix sub + * flow while with meter. It's safe to share the same register. + */ + return priv->mtr_color_reg != REG_C_2 ? REG_C_2 : REG_C_3; + case MLX5_MTR_COLOR: + RTE_ASSERT(priv->mtr_color_reg != REG_NONE); + return priv->mtr_color_reg; case MLX5_APP_TAG: /* - * Suppose engaging reg_c_2 .. reg_c_7 registers. - * reg_c_2 is reserved for coloring by meters. - * reg_c_3 is reserved for split flows TAG. + * If meter is enable, it will engage two registers for color + * match and flow match. If meter color match is not using the + * REG_C_2, need to skip the REG_C_x be used by meter color + * match. + * If meter is disable, free to use all available registers. */ - if (id > (REG_C_7 - REG_C_4)) - return rte_flow_error_set - (error, EINVAL, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "invalid tag id"); - if (config->flow_mreg_c[id + REG_C_4 - REG_C_0] == REG_NONE) - return rte_flow_error_set - (error, ENOTSUP, - RTE_FLOW_ERROR_TYPE_UNSPECIFIED, - NULL, "unsupported tag id"); - return config->flow_mreg_c[id + REG_C_4 - REG_C_0]; + if (priv->mtr_color_reg != REG_NONE) + start_reg = priv->mtr_color_reg != REG_C_2 ? REG_C_3 : + REG_C_4; + else + start_reg = REG_C_2; + if (id > (REG_C_7 - start_reg)) + return rte_flow_error_set(error, EINVAL, + RTE_FLOW_ERROR_TYPE_ITEM, + NULL, "invalid tag id"); + if (config->flow_mreg_c[id + start_reg - REG_C_0] == REG_NONE) + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + NULL, "unsupported tag id"); + /* + * This case means meter is using the REG_C_x great than 2. + * Take care not to conflict with meter color REG_C_x. + * If the available index REG_C_y >= REG_C_x, skip the + * color register. + */ + if (start_reg == REG_C_3 && config->flow_mreg_c + [id + REG_C_3 - REG_C_0] >= priv->mtr_color_reg) { + if (config->flow_mreg_c[id + 1 + REG_C_3 - REG_C_0] != + REG_NONE) + return config->flow_mreg_c + [id + 1 + REG_C_3 - REG_C_0]; + return rte_flow_error_set(error, ENOTSUP, + RTE_FLOW_ERROR_TYPE_ITEM, + NULL, "unsupported tag id"); + } + return config->flow_mreg_c[id + start_reg - REG_C_0]; } assert(false); return rte_flow_error_set(error, EINVAL, @@ -1121,6 +1159,11 @@ mlx5_flow_validate_action_rss(const struct rte_flow_action *action, RTE_FLOW_ERROR_TYPE_ACTION_CONF, NULL, "No queues configured"); for (i = 0; i != rss->queue_num; ++i) { + if (rss->queue[i] >= priv->rxqs_n) + return rte_flow_error_set + (error, EINVAL, + RTE_FLOW_ERROR_TYPE_ACTION_CONF, + &rss->queue[i], "queue index out of range"); if (!(*priv->rxqs)[rss->queue[i]]) return rte_flow_error_set (error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION_CONF, @@ -1955,8 +1998,8 @@ mlx5_flow_validate_item_gre_key(const struct rte_flow_item *item, const rte_be32_t *mask = item->mask; int ret = 0; rte_be32_t gre_key_default_mask = RTE_BE32(UINT32_MAX); - const struct rte_flow_item_gre *gre_spec = gre_item->spec; - const struct rte_flow_item_gre *gre_mask = gre_item->mask; + const struct rte_flow_item_gre *gre_spec; + const struct rte_flow_item_gre *gre_mask; if (item_flags & MLX5_FLOW_LAYER_GRE_KEY) return rte_flow_error_set(error, ENOTSUP, @@ -1970,8 +2013,10 @@ mlx5_flow_validate_item_gre_key(const struct rte_flow_item *item, return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM, item, "GRE key following a wrong item"); + gre_mask = gre_item->mask; if (!gre_mask) gre_mask = &rte_flow_item_gre_mask; + gre_spec = gre_item->spec; if (gre_spec && (gre_mask->c_rsvd0_ver & RTE_BE16(0x2000)) && !(gre_spec->c_rsvd0_ver & RTE_BE16(0x2000))) return rte_flow_error_set(error, EINVAL, @@ -2614,6 +2659,26 @@ mlx5_flow_validate(struct rte_eth_dev *dev, return 0; } +/** + * Get port id item from the item list. + * + * @param[in] item + * Pointer to the list of items. + * + * @return + * Pointer to the port id item if exist, else return NULL. + */ +static const struct rte_flow_item * +find_port_id_item(const struct rte_flow_item *item) +{ + assert(item); + for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) { + if (item->type == RTE_FLOW_ITEM_TYPE_PORT_ID) + return item; + } + return NULL; +} + /** * Get RSS action from the action list. * @@ -2692,6 +2757,38 @@ flow_parse_qrss_action(const struct rte_flow_action actions[], return actions_n + 1; } +/** + * Check meter action from the action list. + * + * @param[in] actions + * Pointer to the list of actions. + * @param[out] mtr + * Pointer to the meter exist flag. + * + * @return + * Total number of actions. + */ +static int +flow_check_meter_action(const struct rte_flow_action actions[], uint32_t *mtr) +{ + int actions_n = 0; + + assert(mtr); + *mtr = 0; + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { + switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_METER: + *mtr = 1; + break; + default: + break; + } + actions_n++; + } + /* Count RTE_FLOW_ACTION_TYPE_END. */ + return actions_n + 1; +} + /** * Check if the flow should be splited due to hairpin. * The reason for the split is that in current HW we can't @@ -2727,6 +2824,8 @@ flow_check_hairpin_split(struct rte_eth_dev *dev, switch (actions->type) { case RTE_FLOW_ACTION_TYPE_QUEUE: queue = actions->conf; + if (queue == NULL) + return 0; if (mlx5_rxq_get_type(dev, queue->index) != MLX5_RXQ_TYPE_HAIRPIN) return 0; @@ -2735,6 +2834,8 @@ flow_check_hairpin_split(struct rte_eth_dev *dev, break; case RTE_FLOW_ACTION_TYPE_RSS: rss = actions->conf; + if (rss == NULL || rss->queue_num == 0) + return 0; if (mlx5_rxq_get_type(dev, rss->queue[0]) != MLX5_RXQ_TYPE_HAIRPIN) return 0; @@ -3335,6 +3436,113 @@ flow_create_split_inner(struct rte_eth_dev *dev, return flow_drv_translate(dev, dev_flow, attr, items, actions, error); } +/** + * Split the meter flow. + * + * As meter flow will split to three sub flow, other than meter + * action, the other actions make sense to only meter accepts + * the packet. If it need to be dropped, no other additional + * actions should be take. + * + * One kind of special action which decapsulates the L3 tunnel + * header will be in the prefix sub flow, as not to take the + * L3 tunnel header into account. + * + * @param dev + * Pointer to Ethernet device. + * @param[in] actions + * Associated actions (list terminated by the END action). + * @param[out] actions_sfx + * Suffix flow actions. + * @param[out] actions_pre + * Prefix flow actions. + * @param[out] pattern_sfx + * The pattern items for the suffix flow. + * @param[out] tag_sfx + * Pointer to suffix flow tag. + * + * @return + * 0 on success. + */ +static int +flow_meter_split_prep(struct rte_eth_dev *dev, + const struct rte_flow_action actions[], + struct rte_flow_action actions_sfx[], + struct rte_flow_action actions_pre[]) +{ + struct rte_flow_action *tag_action; + struct mlx5_rte_flow_action_set_tag *set_tag; + struct rte_flow_error error; + const struct rte_flow_action_raw_encap *raw_encap; + const struct rte_flow_action_raw_decap *raw_decap; + uint32_t tag_id; + + /* Add the extra tag action first. */ + tag_action = actions_pre; + tag_action->type = MLX5_RTE_FLOW_ACTION_TYPE_TAG; + actions_pre++; + /* Prepare the actions for prefix and suffix flow. */ + for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) { + switch (actions->type) { + case RTE_FLOW_ACTION_TYPE_METER: + case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP: + case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP: + memcpy(actions_pre, actions, + sizeof(struct rte_flow_action)); + actions_pre++; + break; + case RTE_FLOW_ACTION_TYPE_RAW_ENCAP: + raw_encap = actions->conf; + if (raw_encap->size > + (sizeof(struct rte_flow_item_eth) + + sizeof(struct rte_flow_item_ipv4))) { + memcpy(actions_sfx, actions, + sizeof(struct rte_flow_action)); + actions_sfx++; + } else { + rte_memcpy(actions_pre, actions, + sizeof(struct rte_flow_action)); + actions_pre++; + } + break; + case RTE_FLOW_ACTION_TYPE_RAW_DECAP: + raw_decap = actions->conf; + /* Size 0 decap means 50 bytes as vxlan decap. */ + if (raw_decap->size && (raw_decap->size < + (sizeof(struct rte_flow_item_eth) + + sizeof(struct rte_flow_item_ipv4)))) { + memcpy(actions_sfx, actions, + sizeof(struct rte_flow_action)); + actions_sfx++; + } else { + rte_memcpy(actions_pre, actions, + sizeof(struct rte_flow_action)); + actions_pre++; + } + break; + default: + memcpy(actions_sfx, actions, + sizeof(struct rte_flow_action)); + actions_sfx++; + break; + } + } + /* Add end action to the actions. */ + actions_sfx->type = RTE_FLOW_ACTION_TYPE_END; + actions_pre->type = RTE_FLOW_ACTION_TYPE_END; + actions_pre++; + /* Set the tag. */ + set_tag = (void *)actions_pre; + set_tag->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, &error); + /* + * Get the id from the qrss_pool to make qrss share the id with meter. + */ + tag_id = flow_qrss_get_id(dev); + set_tag->data = rte_cpu_to_be_32(tag_id); + tag_action->conf = set_tag; + return tag_id; +} + /** * Split action list having QUEUE/RSS for metadata register copy. * @@ -3386,7 +3594,7 @@ flow_mreg_split_qrss_prep(struct rte_eth_dev *dev, struct mlx5_rte_flow_action_set_tag *set_tag; struct rte_flow_action_jump *jump; const int qrss_idx = qrss - actions; - uint32_t flow_id; + uint32_t flow_id = 0; int ret = 0; /* @@ -3396,43 +3604,50 @@ flow_mreg_split_qrss_prep(struct rte_eth_dev *dev, * As a result, there will be one more action. */ ++actions_n; + memcpy(split_actions, actions, sizeof(*split_actions) * actions_n); + set_tag = (void *)(split_actions + actions_n); /* - * Allocate the new subflow ID. This one is unique within - * device and not shared with representors. Otherwise, - * we would have to resolve multi-thread access synch - * issue. Each flow on the shared device is appended - * with source vport identifier, so the resulting - * flows will be unique in the shared (by master and - * representors) domain even if they have coinciding - * IDs. + * If tag action is not set to void(it means we are not the meter + * suffix flow), add the tag action. Since meter suffix flow already + * has the tag added. */ - flow_id = flow_qrss_get_id(dev); - if (!flow_id) - return rte_flow_error_set(error, ENOMEM, - RTE_FLOW_ERROR_TYPE_ACTION, - NULL, "can't allocate id " - "for split Q/RSS subflow"); - /* Internal SET_TAG action to set flow ID. */ - set_tag = (void *)(split_actions + actions_n); - *set_tag = (struct mlx5_rte_flow_action_set_tag){ - .data = flow_id, - }; - ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error); - if (ret < 0) - return ret; - set_tag->id = ret; + if (split_actions[qrss_idx].type != RTE_FLOW_ACTION_TYPE_VOID) { + /* + * Allocate the new subflow ID. This one is unique within + * device and not shared with representors. Otherwise, + * we would have to resolve multi-thread access synch + * issue. Each flow on the shared device is appended + * with source vport identifier, so the resulting + * flows will be unique in the shared (by master and + * representors) domain even if they have coinciding + * IDs. + */ + flow_id = flow_qrss_get_id(dev); + if (!flow_id) + return rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, "can't allocate id " + "for split Q/RSS subflow"); + /* Internal SET_TAG action to set flow ID. */ + *set_tag = (struct mlx5_rte_flow_action_set_tag){ + .data = flow_id, + }; + ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error); + if (ret < 0) + return ret; + set_tag->id = ret; + /* Construct new actions array. */ + /* Replace QUEUE/RSS action. */ + split_actions[qrss_idx] = (struct rte_flow_action){ + .type = MLX5_RTE_FLOW_ACTION_TYPE_TAG, + .conf = set_tag, + }; + } /* JUMP action to jump to mreg copy table (CP_TBL). */ jump = (void *)(set_tag + 1); *jump = (struct rte_flow_action_jump){ .group = MLX5_FLOW_MREG_CP_TABLE_GROUP, }; - /* Construct new actions array. */ - memcpy(split_actions, actions, sizeof(*split_actions) * actions_n); - /* Replace QUEUE/RSS action. */ - split_actions[qrss_idx] = (struct rte_flow_action){ - .type = MLX5_RTE_FLOW_ACTION_TYPE_TAG, - .conf = set_tag, - }; split_actions[actions_n - 2] = (struct rte_flow_action){ .type = RTE_FLOW_ACTION_TYPE_JUMP, .conf = jump, @@ -3533,6 +3748,7 @@ flow_create_split_metadata(struct rte_eth_dev *dev, struct rte_flow_action *ext_actions = NULL; struct mlx5_flow *dev_flow = NULL; uint32_t qrss_id = 0; + int mtr_sfx = 0; size_t act_size; int actions_n; int ret; @@ -3563,6 +3779,10 @@ flow_create_split_metadata(struct rte_eth_dev *dev, } } if (qrss) { + /* Check if it is in meter suffix table. */ + mtr_sfx = attr->group == (attr->transfer ? + (MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) : + MLX5_FLOW_TABLE_LEVEL_SUFFIX); /* * Q/RSS action on NIC Rx should be split in order to pass by * the mreg copy table (RX_CP_TBL) and then it jumps to the @@ -3577,6 +3797,16 @@ flow_create_split_metadata(struct rte_eth_dev *dev, RTE_FLOW_ERROR_TYPE_ACTION, NULL, "no memory to split " "metadata flow"); + /* + * If we are the suffix flow of meter, tag already exist. + * Set the tag action to void. + */ + if (mtr_sfx) + ext_actions[qrss - actions].type = + RTE_FLOW_ACTION_TYPE_VOID; + else + ext_actions[qrss - actions].type = + MLX5_RTE_FLOW_ACTION_TYPE_TAG; /* * Create the new actions list with removed Q/RSS action * and appended set tag and jump to register copy table @@ -3585,7 +3815,7 @@ flow_create_split_metadata(struct rte_eth_dev *dev, */ qrss_id = flow_mreg_split_qrss_prep(dev, ext_actions, actions, qrss, actions_n, error); - if (!qrss_id) { + if (!mtr_sfx && !qrss_id) { ret = -rte_errno; goto exit; } @@ -3615,7 +3845,7 @@ flow_create_split_metadata(struct rte_eth_dev *dev, if (ret < 0) goto exit; assert(dev_flow); - if (qrss_id) { + if (qrss) { const struct rte_flow_attr q_attr = { .group = MLX5_FLOW_MREG_ACT_TABLE_GROUP, .ingress = 1, @@ -3646,22 +3876,35 @@ flow_create_split_metadata(struct rte_eth_dev *dev, }, }; uint64_t hash_fields = dev_flow->hash_fields; + /* - * Put unique id in prefix flow due to it is destroyed after - * prefix flow and id will be freed after there is no actual - * flows with this id and identifier reallocation becomes - * possible (for example, for other flows in other threads). + * Configure the tag item only if there is no meter subflow. + * Since tag is already marked in the meter suffix subflow + * we can just use the meter suffix items as is. */ - dev_flow->qrss_id = qrss_id; - qrss_id = 0; + if (qrss_id) { + /* Not meter subflow. */ + assert(!mtr_sfx); + /* + * Put unique id in prefix flow due to it is destroyed + * after suffix flow and id will be freed after there + * is no actual flows with this id and identifier + * reallocation becomes possible (for example, for + * other flows in other threads). + */ + dev_flow->qrss_id = qrss_id; + qrss_id = 0; + ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, + error); + if (ret < 0) + goto exit; + q_tag_spec.id = ret; + } dev_flow = NULL; - ret = mlx5_flow_get_reg_id(dev, MLX5_COPY_MARK, 0, error); - if (ret < 0) - goto exit; - q_tag_spec.id = ret; /* Add suffix subflow to execute Q/RSS. */ ret = flow_create_split_inner(dev, flow, &dev_flow, - &q_attr, q_items, q_actions, + &q_attr, mtr_sfx ? items : + q_items, q_actions, external, error); if (ret < 0) goto exit; @@ -3680,6 +3923,124 @@ exit: return ret; } +/** + * The splitting for meter feature. + * + * - The meter flow will be split to two flows as prefix and + * suffix flow. The packets make sense only it pass the prefix + * meter action. + * + * - Reg_C_5 is used for the packet to match betweend prefix and + * suffix flow. + * + * @param dev + * Pointer to Ethernet device. + * @param[in] flow + * Parent flow structure pointer. + * @param[in] attr + * Flow rule attributes. + * @param[in] items + * Pattern specification (list terminated by the END pattern item). + * @param[in] actions + * Associated actions (list terminated by the END action). + * @param[in] external + * This flow rule is created by request external to PMD. + * @param[out] error + * Perform verbose error reporting if not NULL. + * @return + * 0 on success, negative value otherwise + */ +static int +flow_create_split_meter(struct rte_eth_dev *dev, + struct rte_flow *flow, + const struct rte_flow_attr *attr, + const struct rte_flow_item items[], + const struct rte_flow_action actions[], + bool external, struct rte_flow_error *error) +{ + struct mlx5_priv *priv = dev->data->dev_private; + struct rte_flow_action *sfx_actions = NULL; + struct rte_flow_action *pre_actions = NULL; + struct rte_flow_item *sfx_items = NULL; + const struct rte_flow_item *sfx_port_id_item; + struct mlx5_flow *dev_flow = NULL; + struct rte_flow_attr sfx_attr = *attr; + uint32_t mtr = 0; + uint32_t mtr_tag_id = 0; + size_t act_size; + size_t item_size; + int actions_n = 0; + int ret; + + if (priv->mtr_en) + actions_n = flow_check_meter_action(actions, &mtr); + if (mtr) { + struct mlx5_rte_flow_item_tag *tag_spec; + /* The five prefix actions: meter, decap, encap, tag, end. */ + act_size = sizeof(struct rte_flow_action) * (actions_n + 5) + + sizeof(struct rte_flow_action_set_tag); + /* tag, end. */ +#define METER_SUFFIX_ITEM 3 + item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM + + sizeof(struct mlx5_rte_flow_item_tag); + sfx_actions = rte_zmalloc(__func__, (act_size + item_size), 0); + if (!sfx_actions) + return rte_flow_error_set(error, ENOMEM, + RTE_FLOW_ERROR_TYPE_ACTION, + NULL, "no memory to split " + "meter flow"); + pre_actions = sfx_actions + actions_n; + mtr_tag_id = flow_meter_split_prep(dev, actions, sfx_actions, + pre_actions); + if (!mtr_tag_id) { + ret = -rte_errno; + goto exit; + } + /* Add the prefix subflow. */ + ret = flow_create_split_inner(dev, flow, &dev_flow, attr, items, + pre_actions, external, error); + if (ret) { + ret = -rte_errno; + goto exit; + } + dev_flow->mtr_flow_id = mtr_tag_id; + /* Prepare the suffix flow match pattern. */ + sfx_items = (struct rte_flow_item *)((char *)sfx_actions + + act_size); + tag_spec = (struct mlx5_rte_flow_item_tag *)(sfx_items + + METER_SUFFIX_ITEM); + tag_spec->data = rte_cpu_to_be_32(dev_flow->mtr_flow_id); + tag_spec->id = mlx5_flow_get_reg_id(dev, MLX5_MTR_SFX, 0, + error); + sfx_items->type = MLX5_RTE_FLOW_ITEM_TYPE_TAG; + sfx_items->spec = tag_spec; + sfx_items->last = NULL; + sfx_items->mask = NULL; + sfx_items++; + sfx_port_id_item = find_port_id_item(items); + if (sfx_port_id_item) { + memcpy(sfx_items, sfx_port_id_item, + sizeof(*sfx_items)); + sfx_items++; + } + sfx_items->type = RTE_FLOW_ITEM_TYPE_END; + sfx_items -= METER_SUFFIX_ITEM; + /* Setting the sfx group atrr. */ + sfx_attr.group = sfx_attr.transfer ? + (MLX5_FLOW_TABLE_LEVEL_SUFFIX - 1) : + MLX5_FLOW_TABLE_LEVEL_SUFFIX; + } + /* Add the prefix subflow. */ + ret = flow_create_split_metadata(dev, flow, &sfx_attr, + sfx_items ? sfx_items : items, + sfx_actions ? sfx_actions : actions, + external, error); +exit: + if (sfx_actions) + rte_free(sfx_actions); + return ret; +} + /** * Split the flow to subflow set. The splitters might be linked * in the chain, like this: @@ -3725,7 +4086,7 @@ flow_create_split_outer(struct rte_eth_dev *dev, { int ret; - ret = flow_create_split_metadata(dev, flow, attr, items, + ret = flow_create_split_meter(dev, flow, attr, items, actions, external, error); assert(ret <= 0); return ret; @@ -4881,6 +5242,177 @@ mlx5_dev_filter_ctrl(struct rte_eth_dev *dev, return 0; } +/** + * Create the needed meter and suffix tables. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] fm + * Pointer to the flow meter. + * + * @return + * Pointer to table set on success, NULL otherwise. + */ +struct mlx5_meter_domains_infos * +mlx5_flow_create_mtr_tbls(struct rte_eth_dev *dev, + const struct mlx5_flow_meter *fm) +{ + const struct mlx5_flow_driver_ops *fops; + + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); + return fops->create_mtr_tbls(dev, fm); +} + +/** + * Destroy the meter table set. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] tbl + * Pointer to the meter table set. + * + * @return + * 0 on success. + */ +int +mlx5_flow_destroy_mtr_tbls(struct rte_eth_dev *dev, + struct mlx5_meter_domains_infos *tbls) +{ + const struct mlx5_flow_driver_ops *fops; + + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); + return fops->destroy_mtr_tbls(dev, tbls); +} + +/** + * Create policer rules. + * + * @param[in] dev + * Pointer to Ethernet device. + * @param[in] fm + * Pointer to flow meter structure. + * @param[in] attr + * Pointer to flow attributes. + * + * @return + * 0 on success, -1 otherwise. + */ +int +mlx5_flow_create_policer_rules(struct rte_eth_dev *dev, + struct mlx5_flow_meter *fm, + const struct rte_flow_attr *attr) +{ + const struct mlx5_flow_driver_ops *fops; + + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); + return fops->create_policer_rules(dev, fm, attr); +} + +/** + * Destroy policer rules. + * + * @param[in] fm + * Pointer to flow meter structure. + * @param[in] attr + * Pointer to flow attributes. + * + * @return + * 0 on success, -1 otherwise. + */ +int +mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev, + struct mlx5_flow_meter *fm, + const struct rte_flow_attr *attr) +{ + const struct mlx5_flow_driver_ops *fops; + + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); + return fops->destroy_policer_rules(dev, fm, attr); +} + +/** + * Allocate a counter. + * + * @param[in] dev + * Pointer to Ethernet device structure. + * + * @return + * Pointer to allocated counter on success, NULL otherwise. + */ +struct mlx5_flow_counter * +mlx5_counter_alloc(struct rte_eth_dev *dev) +{ + const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = { .transfer = 0 }; + + if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) { + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); + return fops->counter_alloc(dev); + } + DRV_LOG(ERR, + "port %u counter allocate is not supported.", + dev->data->port_id); + return NULL; +} + +/** + * Free a counter. + * + * @param[in] dev + * Pointer to Ethernet device structure. + * @param[in] cnt + * Pointer to counter to be free. + */ +void +mlx5_counter_free(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt) +{ + const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = { .transfer = 0 }; + + if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) { + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); + fops->counter_free(dev, cnt); + return; + } + DRV_LOG(ERR, + "port %u counter free is not supported.", + dev->data->port_id); +} + +/** + * Query counter statistics. + * + * @param[in] dev + * Pointer to Ethernet device structure. + * @param[in] cnt + * Pointer to counter to query. + * @param[in] clear + * Set to clear counter statistics. + * @param[out] pkts + * The counter hits packets number to save. + * @param[out] bytes + * The counter hits bytes number to save. + * + * @return + * 0 on success, a negative errno value otherwise. + */ +int +mlx5_counter_query(struct rte_eth_dev *dev, struct mlx5_flow_counter *cnt, + bool clear, uint64_t *pkts, uint64_t *bytes) +{ + const struct mlx5_flow_driver_ops *fops; + struct rte_flow_attr attr = { .transfer = 0 }; + + if (flow_get_drv_type(dev, &attr) == MLX5_FLOW_TYPE_DV) { + fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV); + return fops->counter_query(dev, cnt, clear, pkts, bytes); + } + DRV_LOG(ERR, + "port %u counter query is not supported.", + dev->data->port_id); + return -ENOTSUP; +} + #define MLX5_POOL_QUERY_FREQ_US 1000000 /**