*
* @param[in] dev
* Pointer to Ethernet device.
+ * @param[in] flow
+ * Parent flow structure pointer.
* @param[in] fm
* Pointer to flow meter structure.
+ * @param[in] attr
+ * Flow rule attributes.
* @param[in] items
* Pattern specification (list terminated by the END pattern item).
* @param[out] sfx_items
* 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.
* @param[out] error
* Perform verbose error reporting if not NULL.
*
*/
static uint32_t
flow_meter_split_prep(struct rte_eth_dev *dev,
- struct mlx5_flow_meter *fm,
+ struct rte_flow *flow,
+ struct mlx5_flow_meter_info *fm,
+ const struct rte_flow_attr *attr,
const struct rte_flow_item items[],
struct rte_flow_item sfx_items[],
const struct rte_flow_action actions[],
struct mlx5_rte_flow_item_tag *tag_item_mask;
uint32_t tag_id = 0;
bool copy_vlan = false;
+ struct rte_flow_action *hw_mtr_action;
+ struct rte_flow_action_jump *jump_data;
+ struct rte_flow_action *action_pre_head = NULL;
+ bool mtr_first = priv->sh->meter_aso_en &&
+ (attr->egress ||
+ (attr->transfer && priv->representor_id != UINT16_MAX));
uint8_t mtr_id_offset = priv->mtr_reg_share ? MLX5_MTR_COLOR_BITS : 0;
uint8_t mtr_reg_bits = priv->mtr_reg_share ?
MLX5_MTR_IDLE_BITS_IN_COLOR_REG : MLX5_REG_BITS;
uint8_t flow_id_bits = 0;
int shift;
+ /* For ASO meter, meter must be before tag in TX direction. */
+ if (mtr_first) {
+ action_pre_head = actions_pre++;
+ /* Leave space for tag action. */
+ tag_action = actions_pre++;
+ }
/* Prepare the actions for prefix and suffix flow. */
for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
- struct rte_flow_action **action_cur = NULL;
+ struct rte_flow_action *action_cur = NULL;
switch (actions->type) {
case RTE_FLOW_ACTION_TYPE_METER:
- /* Add the extra tag action first. */
- tag_action = actions_pre++;
- action_cur = &actions_pre;
+ if (mtr_first) {
+ action_cur = action_pre_head;
+ } else {
+ /* Leave space for tag action. */
+ tag_action = actions_pre++;
+ action_cur = actions_pre++;
+ }
break;
case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
case RTE_FLOW_ACTION_TYPE_NVGRE_DECAP:
- action_cur = &actions_pre;
+ action_cur = actions_pre++;
break;
case RTE_FLOW_ACTION_TYPE_RAW_ENCAP:
raw_encap = actions->conf;
if (raw_encap->size < MLX5_ENCAPSULATION_DECISION_SIZE)
- action_cur = &actions_pre;
+ action_cur = actions_pre++;
break;
case RTE_FLOW_ACTION_TYPE_RAW_DECAP:
raw_decap = actions->conf;
if (raw_decap->size > MLX5_ENCAPSULATION_DECISION_SIZE)
- action_cur = &actions_pre;
+ action_cur = actions_pre++;
break;
case RTE_FLOW_ACTION_TYPE_OF_PUSH_VLAN:
case RTE_FLOW_ACTION_TYPE_OF_SET_VLAN_VID:
break;
}
if (!action_cur)
- action_cur = &actions_sfx;
- memcpy(*action_cur, actions, sizeof(struct rte_flow_action));
- (*action_cur)++;
+ action_cur = actions_sfx++;
+ memcpy(action_cur, actions, sizeof(struct rte_flow_action));
}
/* Add end action to the actions. */
actions_sfx->type = RTE_FLOW_ACTION_TYPE_END;
- actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
- actions_pre++;
+ if (priv->sh->meter_aso_en) {
+ /**
+ * For ASO meter, need to add an extra jump action explicitly,
+ * to jump from meter to policer table.
+ */
+ hw_mtr_action = actions_pre;
+ hw_mtr_action->type = RTE_FLOW_ACTION_TYPE_JUMP;
+ actions_pre++;
+ actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+ actions_pre++;
+ jump_data = (struct rte_flow_action_jump *)actions_pre;
+ jump_data->group = attr->transfer ?
+ (MLX5_FLOW_TABLE_LEVEL_METER - 1) :
+ MLX5_FLOW_TABLE_LEVEL_METER;
+ hw_mtr_action->conf = jump_data;
+ actions_pre = (struct rte_flow_action *)(jump_data + 1);
+ } else {
+ actions_pre->type = RTE_FLOW_ACTION_TYPE_END;
+ actions_pre++;
+ }
+ /* Generate meter flow_id only if support multiple flows per meter. */
mlx5_ipool_malloc(fm->flow_ipool, &tag_id);
if (!tag_id)
return rte_flow_error_set(error, ENOMEM,
0, error),
.offset = mtr_id_offset,
.length = mtr_reg_bits,
- .data = fm->idx,
+ .data = flow->meter,
};
/*
* The color Reg bits used by flow_id are growing from
struct rte_flow_item *sfx_items = NULL;
struct mlx5_flow *dev_flow = NULL;
struct rte_flow_attr sfx_attr = *attr;
- struct mlx5_flow_meter *fm = NULL;
+ struct mlx5_flow_meter_info *fm = NULL;
bool has_mtr = false;
uint32_t meter_id;
+ uint32_t mtr_idx = 0;
uint32_t mtr_tag_id = 0;
size_t act_size;
size_t item_size;
&meter_id);
if (has_mtr) {
if (flow->meter) {
- fm = mlx5_ipool_get(priv->sh->ipool[MLX5_IPOOL_MTR],
- flow->meter);
+ fm = flow_dv_meter_find_by_idx(priv, flow->meter);
if (!fm)
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
NULL, "Meter not found.");
} else {
- fm = mlx5_flow_meter_find(priv, meter_id);
+ fm = mlx5_flow_meter_find(priv, meter_id, &mtr_idx);
if (!fm)
return rte_flow_error_set(error, EINVAL,
RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
&sfx_attr, error);
if (ret)
return -rte_errno;
- flow->meter = fm->idx;
+ flow->meter = mtr_idx;
}
wks->fm = fm;
- /* The prefix actions: meter, decap, encap, tag, end. */
- act_size = sizeof(struct rte_flow_action) * (actions_n + 5) +
- sizeof(struct mlx5_rte_flow_action_set_tag);
- /* The suffix items: tag, vlan, port id, end. */
+ /* Prefix actions: meter, decap, encap, tag, jump, end. */
+ act_size = sizeof(struct rte_flow_action) * (actions_n + 6) +
+ sizeof(struct mlx5_rte_flow_action_set_tag) +
+ sizeof(struct rte_flow_action_jump);
+ /* Suffix items: tag, vlan, port id, end. */
#define METER_SUFFIX_ITEM 4
item_size = sizeof(struct rte_flow_item) * METER_SUFFIX_ITEM +
sizeof(struct mlx5_rte_flow_item_tag) * 2;
sfx_items = (struct rte_flow_item *)((char *)sfx_actions +
act_size);
pre_actions = sfx_actions + actions_n;
- mtr_tag_id = flow_meter_split_prep(dev, fm, items, sfx_items,
- actions, sfx_actions,
- pre_actions, error);
+ mtr_tag_id = flow_meter_split_prep(dev, flow, fm, &sfx_attr,
+ items, sfx_items, actions,
+ sfx_actions, pre_actions,
+ error);
if (!mtr_tag_id) {
ret = -rte_errno;
goto exit;
*/
int
mlx5_flow_prepare_policer_rules(struct rte_eth_dev *dev,
- struct mlx5_flow_meter *fm,
+ struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr)
{
const struct mlx5_flow_driver_ops *fops;
*/
int
mlx5_flow_destroy_policer_rules(struct rte_eth_dev *dev,
- struct mlx5_flow_meter *fm,
+ struct mlx5_flow_meter_info *fm,
const struct rte_flow_attr *attr)
{
const struct mlx5_flow_driver_ops *fops;
return fops->destroy_policer_rules(dev, fm, attr);
}
+/**
+ * Allocate the needed aso flow meter id.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ *
+ * @return
+ * Index to aso flow meter on success, NULL otherwise.
+ */
+uint32_t
+mlx5_flow_mtr_alloc(struct rte_eth_dev *dev)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ return fops->create_meter(dev);
+}
+
+/**
+ * Free the aso flow meter id.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] mtr_idx
+ * Index to aso flow meter to be free.
+ *
+ * @return
+ * 0 on success.
+ */
+void
+mlx5_flow_mtr_free(struct rte_eth_dev *dev, uint32_t mtr_idx)
+{
+ const struct mlx5_flow_driver_ops *fops;
+
+ fops = flow_get_drv_ops(MLX5_FLOW_TYPE_DV);
+ fops->free_meter(dev, mtr_idx);
+}
+
/**
* Allocate a counter.
*