+ egress = (domain == MLX5_MTR_DOMAIN_EGRESS) ? 1 : 0;
+ transfer = (domain == MLX5_MTR_DOMAIN_TRANSFER) ? 1 : 0;
+ memset(&dh, 0, sizeof(struct mlx5_flow_handle));
+ memset(&dev_flow, 0, sizeof(struct mlx5_flow));
+ memset(&port_id_action, 0,
+ sizeof(struct mlx5_flow_dv_port_id_action_resource));
+ dev_flow.handle = &dh;
+ dev_flow.dv.port_id_action = &port_id_action;
+ dev_flow.external = true;
+ for (i = 0; i < RTE_COLORS; i++) {
+ if (i < MLX5_MTR_RTE_COLORS)
+ act_cnt = &mtr_policy->act_cnt[i];
+ for (act = actions[i];
+ act && act->type != RTE_FLOW_ACTION_TYPE_END;
+ act++) {
+ switch (act->type) {
+ case RTE_FLOW_ACTION_TYPE_MARK:
+ {
+ uint32_t tag_be = mlx5_flow_mark_set
+ (((const struct rte_flow_action_mark *)
+ (act->conf))->id);
+
+ if (i >= MLX5_MTR_RTE_COLORS)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL,
+ "cannot create policy "
+ "mark action for this color");
+ dev_flow.handle->mark = 1;
+ if (flow_dv_tag_resource_register(dev, tag_be,
+ &dev_flow, &flow_err))
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL,
+ "cannot setup policy mark action");
+ MLX5_ASSERT(dev_flow.dv.tag_resource);
+ act_cnt->rix_mark =
+ dev_flow.handle->dvh.rix_tag;
+ action_flags |= MLX5_FLOW_ACTION_MARK;
+ break;
+ }
+ case RTE_FLOW_ACTION_TYPE_SET_TAG:
+ {
+ struct mlx5_flow_dv_modify_hdr_resource
+ *mhdr_res = &mhdr_dummy.res;
+
+ if (i >= MLX5_MTR_RTE_COLORS)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL,
+ "cannot create policy "
+ "set tag action for this color");
+ memset(mhdr_res, 0, sizeof(*mhdr_res));
+ mhdr_res->ft_type = transfer ?
+ MLX5DV_FLOW_TABLE_TYPE_FDB :
+ egress ?
+ MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
+ MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
+ if (flow_dv_convert_action_set_tag
+ (dev, mhdr_res,
+ (const struct rte_flow_action_set_tag *)
+ act->conf, &flow_err))
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot convert policy "
+ "set tag action");
+ if (!mhdr_res->actions_num)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot find policy "
+ "set tag action");
+ /* create modify action if needed. */
+ dev_flow.dv.group = 1;
+ if (flow_dv_modify_hdr_resource_register
+ (dev, mhdr_res, &dev_flow, &flow_err))
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot register policy "
+ "set tag action");
+ act_cnt->modify_hdr =
+ dev_flow.handle->dvh.modify_hdr;
+ action_flags |= MLX5_FLOW_ACTION_SET_TAG;
+ break;
+ }
+ case RTE_FLOW_ACTION_TYPE_DROP:
+ {
+ struct mlx5_flow_mtr_mng *mtrmng =
+ priv->sh->mtrmng;
+ struct mlx5_flow_tbl_data_entry *tbl_data;
+
+ /*
+ * Create the drop table with
+ * METER DROP level.
+ */
+ if (!mtrmng->drop_tbl[domain]) {
+ mtrmng->drop_tbl[domain] =
+ flow_dv_tbl_resource_get(dev,
+ MLX5_FLOW_TABLE_LEVEL_METER,
+ egress, transfer, false, NULL, 0,
+ 0, MLX5_MTR_TABLE_ID_DROP, &flow_err);
+ if (!mtrmng->drop_tbl[domain])
+ return -rte_mtr_error_set
+ (error, ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL,
+ "Failed to create meter drop table");
+ }
+ tbl_data = container_of
+ (mtrmng->drop_tbl[domain],
+ struct mlx5_flow_tbl_data_entry, tbl);
+ if (i < MLX5_MTR_RTE_COLORS) {
+ act_cnt->dr_jump_action[domain] =
+ tbl_data->jump.action;
+ act_cnt->fate_action =
+ MLX5_FLOW_FATE_DROP;
+ }
+ if (i == RTE_COLOR_RED)
+ mtr_policy->dr_drop_action[domain] =
+ tbl_data->jump.action;
+ action_flags |= MLX5_FLOW_ACTION_DROP;
+ break;
+ }
+ case RTE_FLOW_ACTION_TYPE_QUEUE:
+ {
+ if (i >= MLX5_MTR_RTE_COLORS)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot create policy "
+ "fate queue for this color");
+ act_cnt->queue =
+ ((const struct rte_flow_action_queue *)
+ (act->conf))->index;
+ act_cnt->fate_action =
+ MLX5_FLOW_FATE_QUEUE;
+ dev_flow.handle->fate_action =
+ MLX5_FLOW_FATE_QUEUE;
+ mtr_policy->is_queue = 1;
+ action_flags |= MLX5_FLOW_ACTION_QUEUE;
+ break;
+ }
+ case RTE_FLOW_ACTION_TYPE_RSS:
+ {
+ int rss_size;
+
+ if (i >= MLX5_MTR_RTE_COLORS)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL,
+ "cannot create policy "
+ "rss action for this color");
+ /*
+ * Save RSS conf into policy struct
+ * for translate stage.
+ */
+ rss_size = (int)rte_flow_conv
+ (RTE_FLOW_CONV_OP_ACTION,
+ NULL, 0, act, &flow_err);
+ if (rss_size <= 0)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "Get the wrong "
+ "rss action struct size");
+ act_cnt->rss = mlx5_malloc(MLX5_MEM_ZERO,
+ rss_size, 0, SOCKET_ID_ANY);
+ if (!act_cnt->rss)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL,
+ "Fail to malloc rss action memory");
+ ret = rte_flow_conv(RTE_FLOW_CONV_OP_ACTION,
+ act_cnt->rss, rss_size,
+ act, &flow_err);
+ if (ret < 0)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "Fail to save "
+ "rss action into policy struct");
+ act_cnt->fate_action =
+ MLX5_FLOW_FATE_SHARED_RSS;
+ action_flags |= MLX5_FLOW_ACTION_RSS;
+ break;
+ }
+ case RTE_FLOW_ACTION_TYPE_PORT_ID:
+ {
+ struct mlx5_flow_dv_port_id_action_resource
+ port_id_resource;
+ uint32_t port_id = 0;
+
+ if (i >= MLX5_MTR_RTE_COLORS)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot create policy "
+ "port action for this color");
+ memset(&port_id_resource, 0,
+ sizeof(port_id_resource));
+ if (flow_dv_translate_action_port_id(dev, act,
+ &port_id, &flow_err))
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot translate "
+ "policy port action");
+ port_id_resource.port_id = port_id;
+ if (flow_dv_port_id_action_resource_register
+ (dev, &port_id_resource,
+ &dev_flow, &flow_err))
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot setup "
+ "policy port action");
+ act_cnt->rix_port_id_action =
+ dev_flow.handle->rix_port_id_action;
+ act_cnt->fate_action =
+ MLX5_FLOW_FATE_PORT_ID;
+ action_flags |= MLX5_FLOW_ACTION_PORT_ID;
+ break;
+ }
+ case RTE_FLOW_ACTION_TYPE_JUMP:
+ {
+ uint32_t jump_group = 0;
+ uint32_t table = 0;
+ struct mlx5_flow_tbl_data_entry *tbl_data;
+ struct flow_grp_info grp_info = {
+ .external = !!dev_flow.external,
+ .transfer = !!transfer,
+ .fdb_def_rule = !!priv->fdb_def_rule,
+ .std_tbl_fix = 0,
+ .skip_scale = dev_flow.skip_scale &
+ (1 << MLX5_SCALE_FLOW_GROUP_BIT),
+ };
+ struct mlx5_flow_meter_sub_policy *sub_policy =
+ mtr_policy->sub_policys[domain][0];
+
+ if (i >= MLX5_MTR_RTE_COLORS)
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL,
+ "cannot create policy "
+ "jump action for this color");
+ jump_group =
+ ((const struct rte_flow_action_jump *)
+ act->conf)->group;
+ if (mlx5_flow_group_to_table(dev, NULL,
+ jump_group,
+ &table,
+ &grp_info, &flow_err))
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot setup "
+ "policy jump action");
+ sub_policy->jump_tbl[i] =
+ flow_dv_tbl_resource_get(dev,
+ table, egress,
+ transfer,
+ !!dev_flow.external,
+ NULL, jump_group, 0,
+ 0, &flow_err);
+ if
+ (!sub_policy->jump_tbl[i])
+ return -rte_mtr_error_set(error,
+ ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "cannot create jump action.");
+ tbl_data = container_of
+ (sub_policy->jump_tbl[i],
+ struct mlx5_flow_tbl_data_entry, tbl);
+ act_cnt->dr_jump_action[domain] =
+ tbl_data->jump.action;
+ act_cnt->fate_action =
+ MLX5_FLOW_FATE_JUMP;
+ action_flags |= MLX5_FLOW_ACTION_JUMP;
+ break;
+ }
+ default:
+ return -rte_mtr_error_set(error, ENOTSUP,
+ RTE_MTR_ERROR_TYPE_METER_POLICY,
+ NULL, "action type not supported");
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Create policy action per domain, lock free,
+ * (mutex should be acquired by caller).
+ * Dispatcher for action type specific call.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] mtr_policy
+ * Meter policy struct.
+ * @param[in] action
+ * Action specification used to create meter actions.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL. Initialized in case of
+ * error only.
+ *
+ * @return
+ * 0 on success, otherwise negative errno value.
+ */
+static int
+flow_dv_create_mtr_policy_acts(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy,
+ const struct rte_flow_action *actions[RTE_COLORS],
+ struct rte_mtr_error *error)
+{
+ int ret, i;
+ uint16_t sub_policy_num;
+
+ for (i = 0; i < MLX5_MTR_DOMAIN_MAX; i++) {
+ sub_policy_num = (mtr_policy->sub_policy_num >>
+ (MLX5_MTR_SUB_POLICY_NUM_SHIFT * i)) &
+ MLX5_MTR_SUB_POLICY_NUM_MASK;
+ if (sub_policy_num) {
+ ret = __flow_dv_create_domain_policy_acts(dev,
+ mtr_policy, actions,
+ (enum mlx5_meter_domain)i, error);
+ if (ret)
+ return ret;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Query a DV flow rule for its statistics via DevX.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] cnt_idx
+ * Index to the flow counter.
+ * @param[out] data
+ * Data retrieved by the query.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_query_count(struct rte_eth_dev *dev, uint32_t cnt_idx, void *data,
+ struct rte_flow_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct rte_flow_query_count *qc = data;
+
+ if (!priv->config.devx)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "counters are not supported");
+ if (cnt_idx) {
+ uint64_t pkts, bytes;
+ struct mlx5_flow_counter *cnt;
+ int err = _flow_dv_query_count(dev, cnt_idx, &pkts, &bytes);
+
+ if (err)
+ return rte_flow_error_set(error, -err,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL, "cannot read counters");
+ cnt = flow_dv_counter_get_by_idx(dev, cnt_idx, NULL);
+ qc->hits_set = 1;
+ qc->bytes_set = 1;
+ qc->hits = pkts - cnt->hits;
+ qc->bytes = bytes - cnt->bytes;
+ if (qc->reset) {
+ cnt->hits = pkts;
+ cnt->bytes = bytes;
+ }
+ return 0;
+ }
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "counters are not available");
+}
+
+static int
+flow_dv_action_query(struct rte_eth_dev *dev,
+ const struct rte_flow_action_handle *handle, void *data,
+ struct rte_flow_error *error)
+{
+ struct mlx5_age_param *age_param;
+ struct rte_flow_query_age *resp;
+ uint32_t act_idx = (uint32_t)(uintptr_t)handle;
+ uint32_t type = act_idx >> MLX5_INDIRECT_ACTION_TYPE_OFFSET;
+ uint32_t idx = act_idx & ((1u << MLX5_INDIRECT_ACTION_TYPE_OFFSET) - 1);
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_aso_ct_action *ct;
+ uint16_t owner;
+ uint32_t dev_idx;
+
+ switch (type) {
+ case MLX5_INDIRECT_ACTION_TYPE_AGE:
+ age_param = &flow_aso_age_get_by_idx(dev, idx)->age_params;
+ resp = data;
+ resp->aged = __atomic_load_n(&age_param->state,
+ __ATOMIC_RELAXED) == AGE_TMOUT ?
+ 1 : 0;
+ resp->sec_since_last_hit_valid = !resp->aged;
+ if (resp->sec_since_last_hit_valid)
+ resp->sec_since_last_hit = __atomic_load_n
+ (&age_param->sec_since_last_hit, __ATOMIC_RELAXED);
+ return 0;
+ case MLX5_INDIRECT_ACTION_TYPE_COUNT:
+ return flow_dv_query_count(dev, idx, data, error);
+ case MLX5_INDIRECT_ACTION_TYPE_CT:
+ owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
+ if (owner != PORT_ID(priv))
+ return rte_flow_error_set(error, EACCES,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "CT object owned by another port");
+ dev_idx = MLX5_INDIRECT_ACT_CT_GET_IDX(idx);
+ ct = flow_aso_ct_get_by_dev_idx(dev, dev_idx);
+ MLX5_ASSERT(ct);
+ if (!ct->refcnt)
+ return rte_flow_error_set(error, EFAULT,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "CT object is inactive");
+ ((struct rte_flow_action_conntrack *)data)->peer_port =
+ ct->peer;
+ ((struct rte_flow_action_conntrack *)data)->is_original_dir =
+ ct->is_original;
+ if (mlx5_aso_ct_query_by_wqe(priv->sh, ct, data))
+ return rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Failed to query CT context");
+ return 0;
+ default:
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "action type query not supported");
+ }
+}
+
+/**
+ * Query a flow rule AGE action for aging information.
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] flow
+ * Pointer to the sub flow.
+ * @param[out] data
+ * data retrieved by the query.
+ * @param[out] error
+ * Perform verbose error reporting if not NULL.
+ *
+ * @return
+ * 0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_query_age(struct rte_eth_dev *dev, struct rte_flow *flow,
+ void *data, struct rte_flow_error *error)
+{
+ struct rte_flow_query_age *resp = data;
+ struct mlx5_age_param *age_param;
+
+ if (flow->age) {
+ struct mlx5_aso_age_action *act =
+ flow_aso_age_get_by_idx(dev, flow->age);
+
+ age_param = &act->age_params;
+ } else if (flow->counter) {
+ age_param = flow_dv_counter_idx_get_age(dev, flow->counter);
+
+ if (!age_param || !age_param->timeout)
+ return rte_flow_error_set
+ (error, EINVAL,