+ if (!shared_rss)
+ return rte_flow_error_set(error, EINVAL,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "invalid shared action to update");
+ if (priv->obj_ops.ind_table_modify == NULL)
+ return rte_flow_error_set(error, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "cannot modify indirection table");
+ queue = mlx5_malloc(MLX5_MEM_ZERO,
+ RTE_ALIGN_CEIL(queue_size, sizeof(void *)),
+ 0, SOCKET_ID_ANY);
+ if (!queue)
+ return rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "cannot allocate resource memory");
+ memcpy(queue, action_conf->queue, queue_size);
+ MLX5_ASSERT(shared_rss->ind_tbl);
+ rte_spinlock_lock(&shared_rss->action_rss_sl);
+ queue_old = shared_rss->ind_tbl->queues;
+ ret = mlx5_ind_table_obj_modify(dev, shared_rss->ind_tbl,
+ queue, action_conf->queue_num, true);
+ if (ret) {
+ mlx5_free(queue);
+ ret = rte_flow_error_set(error, rte_errno,
+ RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+ "cannot update indirection table");
+ } else {
+ mlx5_free(queue_old);
+ shared_rss->origin.queue = queue;
+ shared_rss->origin.queue_num = action_conf->queue_num;
+ }
+ rte_spinlock_unlock(&shared_rss->action_rss_sl);
+ return ret;
+}
+
+/*
+ * Updates in place conntrack context or direction.
+ * Context update should be synchronized.
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] idx
+ * The conntrack object ID to be updated.
+ * @param[in] update
+ * Pointer to the structure of information to update.
+ * @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_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
+ const struct rte_flow_modify_conntrack *update,
+ struct rte_flow_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct mlx5_aso_ct_action *ct;
+ const struct rte_flow_action_conntrack *new_prf;
+ int ret = 0;
+ uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(idx);
+ uint32_t dev_idx;
+
+ if (PORT_ID(priv) != owner)
+ 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);
+ if (!ct->refcnt)
+ return rte_flow_error_set(error, ENOMEM,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "CT object is inactive");
+ new_prf = &update->new_ct;
+ if (update->direction)
+ ct->is_original = !!new_prf->is_original_dir;
+ if (update->state) {
+ /* Only validate the profile when it needs to be updated. */
+ ret = mlx5_validate_action_ct(dev, new_prf, error);
+ if (ret)
+ return ret;
+ ret = mlx5_aso_ct_update_by_wqe(priv->sh, ct, new_prf);
+ if (ret)
+ return rte_flow_error_set(error, EIO,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Failed to send CT context update WQE");
+ /* Block until ready or a failure. */
+ ret = mlx5_aso_ct_available(priv->sh, ct);
+ if (ret)
+ rte_flow_error_set(error, rte_errno,
+ RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+ NULL,
+ "Timeout to get the CT update");
+ }
+ return ret;
+}
+
+/**
+ * Updates in place shared action configuration, lock free,
+ * (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ * Pointer to the Ethernet device structure.
+ * @param[in] handle
+ * The indirect action object handle to be updated.
+ * @param[in] update
+ * Action specification used to modify the action pointed by *handle*.
+ * *update* could be of same type with the action pointed by the *handle*
+ * handle argument, or some other structures like a wrapper, depending on
+ * the indirect action type.
+ * @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_action_update(struct rte_eth_dev *dev,
+ struct rte_flow_action_handle *handle,
+ const void *update,
+ struct rte_flow_error *err)
+{
+ 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);
+ const void *action_conf;
+
+ switch (type) {
+ case MLX5_INDIRECT_ACTION_TYPE_RSS:
+ action_conf = ((const struct rte_flow_action *)update)->conf;
+ return __flow_dv_action_rss_update(dev, idx, action_conf, err);
+ case MLX5_INDIRECT_ACTION_TYPE_CT:
+ return __flow_dv_action_ct_update(dev, idx, update, err);
+ default:
+ return rte_flow_error_set(err, ENOTSUP,
+ RTE_FLOW_ERROR_TYPE_ACTION,
+ NULL,
+ "action type update not supported");
+ }
+}
+
+/**
+ * Destroy the meter sub policy table rules.
+ * Lock free, (mutex should be acquired by caller).
+ *
+ * @param[in] dev
+ * Pointer to Ethernet device.
+ * @param[in] sub_policy
+ * Pointer to meter sub policy table.
+ */
+static void
+__flow_dv_destroy_sub_policy_rules(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_sub_policy *sub_policy)
+{
+ struct mlx5_flow_tbl_data_entry *tbl;
+ int i;
+
+ for (i = 0; i < RTE_COLORS; i++) {
+ if (sub_policy->color_rule[i]) {
+ claim_zero(mlx5_flow_os_destroy_flow
+ (sub_policy->color_rule[i]));
+ sub_policy->color_rule[i] = NULL;
+ }
+ if (sub_policy->color_matcher[i]) {
+ tbl = container_of(sub_policy->color_matcher[i]->tbl,
+ typeof(*tbl), tbl);
+ mlx5_cache_unregister(&tbl->matchers,
+ &sub_policy->color_matcher[i]->entry);
+ sub_policy->color_matcher[i] = NULL;
+ }
+ }
+ for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+ if (sub_policy->rix_hrxq[i]) {
+ mlx5_hrxq_release(dev, sub_policy->rix_hrxq[i]);
+ sub_policy->rix_hrxq[i] = 0;
+ }
+ if (sub_policy->jump_tbl[i]) {
+ flow_dv_tbl_resource_release(MLX5_SH(dev),
+ sub_policy->jump_tbl[i]);
+ sub_policy->jump_tbl[i] = NULL;
+ }
+ }
+ if (sub_policy->tbl_rsc) {
+ flow_dv_tbl_resource_release(MLX5_SH(dev),
+ sub_policy->tbl_rsc);
+ sub_policy->tbl_rsc = NULL;
+ }
+}
+
+/**
+ * Destroy policy rules, 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.
+ */
+static void
+flow_dv_destroy_policy_rules(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy)
+{
+ uint32_t i, j;
+ struct mlx5_flow_meter_sub_policy *sub_policy;
+ 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;
+ for (j = 0; j < sub_policy_num; j++) {
+ sub_policy = mtr_policy->sub_policys[i][j];
+ if (sub_policy)
+ __flow_dv_destroy_sub_policy_rules
+ (dev, sub_policy);
+ }
+ }
+}
+
+/**
+ * Destroy policy action, 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.
+ */
+static void
+flow_dv_destroy_mtr_policy_acts(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy)
+{
+ struct rte_flow_action *rss_action;
+ struct mlx5_flow_handle dev_handle;
+ uint32_t i, j;
+
+ for (i = 0; i < MLX5_MTR_RTE_COLORS; i++) {
+ if (mtr_policy->act_cnt[i].rix_mark) {
+ flow_dv_tag_release(dev,
+ mtr_policy->act_cnt[i].rix_mark);
+ mtr_policy->act_cnt[i].rix_mark = 0;
+ }
+ if (mtr_policy->act_cnt[i].modify_hdr) {
+ dev_handle.dvh.modify_hdr =
+ mtr_policy->act_cnt[i].modify_hdr;
+ flow_dv_modify_hdr_resource_release(dev, &dev_handle);
+ }
+ switch (mtr_policy->act_cnt[i].fate_action) {
+ case MLX5_FLOW_FATE_SHARED_RSS:
+ rss_action = mtr_policy->act_cnt[i].rss;
+ mlx5_free(rss_action);
+ break;
+ case MLX5_FLOW_FATE_PORT_ID:
+ if (mtr_policy->act_cnt[i].rix_port_id_action) {
+ flow_dv_port_id_action_resource_release(dev,
+ mtr_policy->act_cnt[i].rix_port_id_action);
+ mtr_policy->act_cnt[i].rix_port_id_action = 0;
+ }
+ break;
+ case MLX5_FLOW_FATE_DROP:
+ case MLX5_FLOW_FATE_JUMP:
+ for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+ mtr_policy->act_cnt[i].dr_jump_action[j] =
+ NULL;
+ break;
+ default:
+ /*Queue action do nothing*/
+ break;
+ }
+ }
+ for (j = 0; j < MLX5_MTR_DOMAIN_MAX; j++)
+ mtr_policy->dr_drop_action[j] = NULL;
+}
+
+/**
+ * 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_domain_policy_acts(struct rte_eth_dev *dev,
+ struct mlx5_flow_meter_policy *mtr_policy,
+ const struct rte_flow_action *actions[RTE_COLORS],
+ enum mlx5_meter_domain domain,
+ struct rte_mtr_error *error)
+{
+ struct mlx5_priv *priv = dev->data->dev_private;
+ struct rte_flow_error flow_err;
+ const struct rte_flow_action *act;
+ uint64_t action_flags = 0;
+ struct mlx5_flow_handle dh;
+ struct mlx5_flow dev_flow;
+ struct mlx5_flow_dv_port_id_action_resource port_id_action;
+ int i, ret;
+ uint8_t egress, transfer;
+ struct mlx5_meter_policy_action_container *act_cnt = NULL;
+ union {
+ struct mlx5_flow_dv_modify_hdr_resource res;
+ uint8_t len[sizeof(struct mlx5_flow_dv_modify_hdr_resource) +
+ sizeof(struct mlx5_modification_cmd) *
+ (MLX5_MAX_MODIFY_NUM + 1)];
+ } mhdr_dummy;
+
+ 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,