net/mlx5: fix default context in flow age action
[dpdk.git] / drivers / net / mlx5 / mlx5_flow_dv.c
index eaa97f7..7fc7efb 100644 (file)
@@ -2623,6 +2623,51 @@ flow_dv_validate_item_ipv6_frag_ext(const struct rte_flow_item *item,
                                  "specified range not supported");
 }
 
+/*
+ * Validate ASO CT item.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ * @param[in] item
+ *   Item specification.
+ * @param[in] item_flags
+ *   Pointer to bit-fields that holds the items detected until now.
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_validate_item_aso_ct(struct rte_eth_dev *dev,
+                            const struct rte_flow_item *item,
+                            uint64_t *item_flags,
+                            struct rte_flow_error *error)
+{
+       const struct rte_flow_item_conntrack *spec = item->spec;
+       const struct rte_flow_item_conntrack *mask = item->mask;
+       RTE_SET_USED(dev);
+       uint32_t flags;
+
+       if (*item_flags & MLX5_FLOW_LAYER_ASO_CT)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+                                         "Only one CT is supported");
+       if (!mask)
+               mask = &rte_flow_item_conntrack_mask;
+       flags = spec->flags & mask->flags;
+       if ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_VALID) &&
+           ((flags & RTE_FLOW_CONNTRACK_PKT_STATE_INVALID) ||
+            (flags & RTE_FLOW_CONNTRACK_PKT_STATE_BAD) ||
+            (flags & RTE_FLOW_CONNTRACK_PKT_STATE_DISABLED)))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ITEM, NULL,
+                                         "Conflict status bits");
+       /* State change also needs to be considered. */
+       *item_flags |= MLX5_FLOW_LAYER_ASO_CT;
+       return 0;
+}
+
 /**
  * Validate the pop VLAN action.
  *
@@ -3442,6 +3487,57 @@ flow_dv_validate_action_raw_encap_decap
        return 0;
 }
 
+/*
+ * Validate the ASO CT action.
+ *
+ * @param[in] dev
+ *   Pointer to the rte_eth_dev structure.
+ * @param[in] action_flags
+ *   Holds the actions detected until now.
+ * @param[in] item_flags
+ *   The items found in this flow rule.
+ * @param[in] attr
+ *   Pointer to flow attributes.
+ * @param[out] error
+ *   Pointer to error structure.
+ *
+ * @return
+ *   0 on success, a negative errno value otherwise and rte_errno is set.
+ */
+static int
+flow_dv_validate_action_aso_ct(struct rte_eth_dev *dev,
+                              uint64_t action_flags,
+                              uint64_t item_flags,
+                              const struct rte_flow_attr *attr,
+                              struct rte_flow_error *error)
+{
+       RTE_SET_USED(dev);
+
+       if (attr->group == 0 && !attr->transfer)
+               return rte_flow_error_set(error, ENOTSUP,
+                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                         NULL,
+                                         "Only support non-root table");
+       if (action_flags & MLX5_FLOW_FATE_ACTIONS)
+               return rte_flow_error_set(error, ENOTSUP,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                         "CT cannot follow a fate action");
+       if ((action_flags & MLX5_FLOW_ACTION_METER) ||
+           (action_flags & MLX5_FLOW_ACTION_AGE))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                         "Only one ASO action is supported");
+       if (action_flags & MLX5_FLOW_ACTION_ENCAP)
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_ACTION, NULL,
+                                         "Encap cannot exist before CT");
+       if (!(item_flags & MLX5_FLOW_LAYER_OUTER_L4_TCP))
+               return rte_flow_error_set(error, EINVAL,
+                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                         "Not a outer TCP packet");
+       return 0;
+}
+
 /**
  * Match encap_decap resource.
  *
@@ -6531,10 +6627,12 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
        uint32_t rw_act_num = 0;
        uint64_t is_root;
        const struct mlx5_flow_tunnel *tunnel;
+       enum mlx5_tof_rule_type tof_rule_type;
        struct flow_grp_info grp_info = {
                .external = !!external,
                .transfer = !!attr->transfer,
                .fdb_def_rule = !!priv->fdb_def_rule,
+               .std_tbl_fix = true,
        };
        const struct rte_eth_hairpin_conf *conf;
        const struct rte_flow_item *rule_items = items;
@@ -6542,23 +6640,22 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 
        if (items == NULL)
                return -1;
-       if (is_flow_tunnel_match_rule(dev, attr, items, actions)) {
-               tunnel = flow_items_to_tunnel(items);
-               action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
-                               MLX5_FLOW_ACTION_DECAP;
-       } else if (is_flow_tunnel_steer_rule(dev, attr, items, actions)) {
-               tunnel = flow_actions_to_tunnel(actions);
-               action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
-       } else {
-               tunnel = NULL;
+       tunnel = is_tunnel_offload_active(dev) ?
+                mlx5_get_tof(items, actions, &tof_rule_type) : NULL;
+       if (tunnel) {
+               if (priv->representor)
+                       return rte_flow_error_set
+                               (error, ENOTSUP,
+                                RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+                                NULL, "decap not supported for VF representor");
+               if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_SET_RULE)
+                       action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
+               else if (tof_rule_type == MLX5_TUNNEL_OFFLOAD_MATCH_RULE)
+                       action_flags |= MLX5_FLOW_ACTION_TUNNEL_MATCH |
+                                       MLX5_FLOW_ACTION_DECAP;
+               grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
+                                       (dev, attr, tunnel, tof_rule_type);
        }
-       if (tunnel && priv->representor)
-               return rte_flow_error_set(error, ENOTSUP,
-                                         RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
-                                         "decap not supported "
-                                         "for VF representor");
-       grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
-                               (dev, tunnel, attr, items, actions);
        ret = flow_dv_validate_attributes(dev, tunnel, attr, &grp_info, error);
        if (ret < 0)
                return ret;
@@ -6572,15 +6669,6 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                                  RTE_FLOW_ERROR_TYPE_ITEM,
                                                  NULL, "item not supported");
                switch (type) {
-               case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
-                       if (items[0].type != (typeof(items[0].type))
-                                               MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL)
-                               return rte_flow_error_set
-                                               (error, EINVAL,
-                                               RTE_FLOW_ERROR_TYPE_ITEM,
-                                               NULL, "MLX5 private items "
-                                               "must be the first");
-                       break;
                case RTE_FLOW_ITEM_TYPE_VOID:
                        break;
                case RTE_FLOW_ITEM_TYPE_PORT_ID:
@@ -6873,6 +6961,17 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                                return ret;
                        last_item = MLX5_FLOW_ITEM_INTEGRITY;
                        break;
+               case RTE_FLOW_ITEM_TYPE_CONNTRACK:
+                       ret = flow_dv_validate_item_aso_ct(dev, items,
+                                                          &item_flags, error);
+                       if (ret < 0)
+                               return ret;
+                       break;
+               case MLX5_RTE_FLOW_ITEM_TYPE_TUNNEL:
+                       /* tunnel offload item was processed before
+                        * list it here as a supported type
+                        */
+                       break;
                default:
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ITEM,
@@ -7414,17 +7513,6 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        action_flags |= MLX5_FLOW_ACTION_SAMPLE;
                        ++actions_n;
                        break;
-               case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
-                       if (actions[0].type != (typeof(actions[0].type))
-                               MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET)
-                               return rte_flow_error_set
-                                               (error, EINVAL,
-                                               RTE_FLOW_ERROR_TYPE_ACTION,
-                                               NULL, "MLX5 private action "
-                                               "must be the first");
-
-                       action_flags |= MLX5_FLOW_ACTION_TUNNEL_SET;
-                       break;
                case RTE_FLOW_ACTION_TYPE_MODIFY_FIELD:
                        ret = flow_dv_validate_action_modify_field(dev,
                                                                   action_flags,
@@ -7441,6 +7529,19 @@ flow_dv_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
                        action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
                        rw_act_num += ret;
                        break;
+               case RTE_FLOW_ACTION_TYPE_CONNTRACK:
+                       ret = flow_dv_validate_action_aso_ct(dev, action_flags,
+                                                            item_flags, attr,
+                                                            error);
+                       if (ret < 0)
+                               return ret;
+                       action_flags |= MLX5_FLOW_ACTION_CT;
+                       break;
+               case MLX5_RTE_FLOW_ACTION_TYPE_TUNNEL_SET:
+                       /* tunnel offload action was processed before
+                        * list it here as a supported type
+                        */
+                       break;
                default:
                        return rte_flow_error_set(error, ENOTSUP,
                                                  RTE_FLOW_ERROR_TYPE_ACTION,
@@ -11382,38 +11483,35 @@ flow_dv_aso_age_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
 }
 
 /**
- * Create a age action using ASO mechanism.
+ * Initialize flow ASO age parameters.
  *
  * @param[in] dev
  *   Pointer to rte_eth_dev structure.
- * @param[in] age
- *   Pointer to the aging action configuration.
- * @param[out] error
- *   Pointer to the error structure.
+ * @param[in] age_idx
+ *   Index of ASO age action.
+ * @param[in] context
+ *   Pointer to flow counter age context.
+ * @param[in] timeout
+ *   Aging timeout in seconds.
  *
- * @return
- *   Index to flow counter on success, 0 otherwise.
  */
-static uint32_t
-flow_dv_translate_create_aso_age(struct rte_eth_dev *dev,
-                                const struct rte_flow_action_age *age,
-                                struct rte_flow_error *error)
+static void
+flow_dv_aso_age_params_init(struct rte_eth_dev *dev,
+                           uint32_t age_idx,
+                           void *context,
+                           uint32_t timeout)
 {
-       uint32_t age_idx = 0;
        struct mlx5_aso_age_action *aso_age;
 
-       age_idx = flow_dv_aso_age_alloc(dev, error);
-       if (!age_idx)
-               return 0;
        aso_age = flow_aso_age_get_by_idx(dev, age_idx);
-       aso_age->age_params.context = age->context;
-       aso_age->age_params.timeout = age->timeout;
+       MLX5_ASSERT(aso_age);
+       aso_age->age_params.context = context;
+       aso_age->age_params.timeout = timeout;
        aso_age->age_params.port_id = dev->data->port_id;
        __atomic_store_n(&aso_age->age_params.sec_since_last_hit, 0,
                         __ATOMIC_RELAXED);
        __atomic_store_n(&aso_age->age_params.state, AGE_CANDIDATE,
                         __ATOMIC_RELAXED);
-       return age_idx;
 }
 
 static void
@@ -11573,7 +11671,7 @@ flow_dv_prepare_counter(struct rte_eth_dev *dev,
 }
 
 /*
- * Release an ASO CT action.
+ * Release an ASO CT action by its own device.
  *
  * @param[in] dev
  *   Pointer to the Ethernet device structure.
@@ -11584,12 +11682,12 @@ flow_dv_prepare_counter(struct rte_eth_dev *dev,
  *   0 when CT action was removed, otherwise the number of references.
  */
 static inline int
-flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t idx)
+flow_dv_aso_ct_dev_release(struct rte_eth_dev *dev, uint32_t idx)
 {
        struct mlx5_priv *priv = dev->data->dev_private;
        struct mlx5_aso_ct_pools_mng *mng = priv->sh->ct_mng;
        uint32_t ret;
-       struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_idx(dev, idx);
+       struct mlx5_aso_ct_action *ct = flow_aso_ct_get_by_dev_idx(dev, idx);
        enum mlx5_aso_ct_state state =
                        __atomic_load_n(&ct->state, __ATOMIC_RELAXED);
 
@@ -11618,7 +11716,21 @@ flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t idx)
                LIST_INSERT_HEAD(&mng->free_cts, ct, next);
                rte_spinlock_unlock(&mng->ct_sl);
        }
-       return ret;
+       return (int)ret;
+}
+
+static inline int
+flow_dv_aso_ct_release(struct rte_eth_dev *dev, uint32_t own_idx)
+{
+       uint16_t owner = (uint16_t)MLX5_INDIRECT_ACT_CT_GET_OWNER(own_idx);
+       uint32_t idx = MLX5_INDIRECT_ACT_CT_GET_IDX(own_idx);
+       struct rte_eth_dev *owndev = &rte_eth_devices[owner];
+       RTE_SET_USED(dev);
+
+       MLX5_ASSERT(owner < RTE_MAX_ETHPORTS);
+       if (dev->data->dev_started != 1)
+               return -1;
+       return flow_dv_aso_ct_dev_release(owndev, idx);
 }
 
 /*
@@ -11770,7 +11882,7 @@ flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
                RTE_SET_USED(reg_c);
 #endif
                if (!ct->dr_action_orig) {
-                       flow_dv_aso_ct_release(dev, ct_idx);
+                       flow_dv_aso_ct_dev_release(dev, ct_idx);
                        rte_flow_error_set(error, rte_errno,
                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                           "failed to create ASO CT action");
@@ -11786,7 +11898,7 @@ flow_dv_aso_ct_alloc(struct rte_eth_dev *dev, struct rte_flow_error *error)
                         reg_c - REG_C_0);
 #endif
                if (!ct->dr_action_rply) {
-                       flow_dv_aso_ct_release(dev, ct_idx);
+                       flow_dv_aso_ct_dev_release(dev, ct_idx);
                        rte_flow_error_set(error, rte_errno,
                                           RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                           "failed to create ASO CT action");
@@ -11828,12 +11940,13 @@ flow_dv_translate_create_conntrack(struct rte_eth_dev *dev,
                return rte_flow_error_set(error, rte_errno,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "Failed to allocate CT object");
-       ct = flow_aso_ct_get_by_idx(dev, idx);
+       ct = flow_aso_ct_get_by_dev_idx(dev, idx);
        if (mlx5_aso_ct_update_by_wqe(sh, ct, pro))
                return rte_flow_error_set(error, EBUSY,
                                          RTE_FLOW_ERROR_TYPE_ACTION, NULL,
                                          "Failed to update CT");
        ct->is_original = !!pro->is_original_dir;
+       ct->peer = pro->peer_port;
        return idx;
 }
 
@@ -11910,13 +12023,14 @@ flow_dv_translate(struct rte_eth_dev *dev,
        int tmp_actions_n = 0;
        uint32_t table;
        int ret = 0;
-       const struct mlx5_flow_tunnel *tunnel;
+       const struct mlx5_flow_tunnel *tunnel = NULL;
        struct flow_grp_info grp_info = {
                .external = !!dev_flow->external,
                .transfer = !!attr->transfer,
                .fdb_def_rule = !!priv->fdb_def_rule,
                .skip_scale = dev_flow->skip_scale &
                        (1 << MLX5_SCALE_FLOW_GROUP_BIT),
+               .std_tbl_fix = true,
        };
        const struct rte_flow_item *head_item = items;
 
@@ -11932,15 +12046,21 @@ flow_dv_translate(struct rte_eth_dev *dev,
                                           MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
        /* update normal path action resource into last index of array */
        sample_act = &mdest_res.sample_act[MLX5_MAX_DEST_NUM - 1];
-       tunnel = is_flow_tunnel_match_rule(dev, attr, items, actions) ?
-                flow_items_to_tunnel(items) :
-                is_flow_tunnel_steer_rule(dev, attr, items, actions) ?
-                flow_actions_to_tunnel(actions) :
-                dev_flow->tunnel ? dev_flow->tunnel : NULL;
+       if (is_tunnel_offload_active(dev)) {
+               if (dev_flow->tunnel) {
+                       RTE_VERIFY(dev_flow->tof_type ==
+                                  MLX5_TUNNEL_OFFLOAD_MISS_RULE);
+                       tunnel = dev_flow->tunnel;
+               } else {
+                       tunnel = mlx5_get_tof(items, actions,
+                                             &dev_flow->tof_type);
+                       dev_flow->tunnel = tunnel;
+               }
+               grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
+                                       (dev, attr, tunnel, dev_flow->tof_type);
+       }
        mhdr_res->ft_type = attr->egress ? MLX5DV_FLOW_TABLE_TYPE_NIC_TX :
                                           MLX5DV_FLOW_TABLE_TYPE_NIC_RX;
-       grp_info.std_tbl_fix = tunnel_use_standard_attr_group_translate
-                               (dev, tunnel, attr, items, actions);
        ret = mlx5_flow_group_to_table(dev, tunnel, attr->group, &table,
                                       &grp_info, error);
        if (ret)
@@ -11950,7 +12070,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
                mhdr_res->ft_type = MLX5DV_FLOW_TABLE_TYPE_FDB;
        /* number of actions must be set to 0 in case of dirty stack. */
        mhdr_res->actions_num = 0;
-       if (is_flow_tunnel_match_rule(dev, attr, items, actions)) {
+       if (is_flow_tunnel_match_rule(dev_flow->tof_type)) {
                /*
                 * do not add decap action if match rule drops packet
                 * HW rejects rules with decap & drop
@@ -11992,7 +12112,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
                int action_type = actions->type;
                const struct rte_flow_action *found_action = NULL;
                uint32_t jump_group = 0;
-               uint32_t ct_idx;
+               uint32_t owner_idx;
                struct mlx5_aso_ct_action *ct;
 
                if (!mlx5_flow_os_action_supported(action_type))
@@ -12448,8 +12568,13 @@ flow_dv_translate(struct rte_eth_dev *dev,
                        action_flags |= MLX5_FLOW_ACTION_MODIFY_FIELD;
                        break;
                case RTE_FLOW_ACTION_TYPE_CONNTRACK:
-                       ct_idx = (uint32_t)(uintptr_t)action->conf;
-                       ct = flow_aso_ct_get_by_idx(dev, ct_idx);
+                       owner_idx = (uint32_t)(uintptr_t)action->conf;
+                       ct = flow_aso_ct_get_by_idx(dev, owner_idx);
+                       if (!ct)
+                               return rte_flow_error_set(error, EINVAL,
+                                               RTE_FLOW_ERROR_TYPE_ACTION,
+                                               NULL,
+                                               "Failed to get CT object.");
                        if (mlx5_aso_ct_available(priv->sh, ct))
                                return rte_flow_error_set(error, rte_errno,
                                                RTE_FLOW_ERROR_TYPE_ACTION,
@@ -12462,7 +12587,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
                                dev_flow->dv.actions[actions_n] =
                                                        ct->dr_action_rply;
                        flow->indirect_type = MLX5_INDIRECT_ACTION_TYPE_CT;
-                       flow->ct = ct_idx;
+                       flow->ct = owner_idx;
                        __atomic_fetch_add(&ct->refcnt, 1, __ATOMIC_RELAXED);
                        actions_n++;
                        action_flags |= MLX5_FLOW_ACTION_CT;
@@ -12485,7 +12610,7 @@ flow_dv_translate(struct rte_eth_dev *dev,
                                if ((non_shared_age &&
                                     count && !count->shared) ||
                                    !(priv->sh->flow_hit_aso_en &&
-                                     attr->group)) {
+                                     (attr->group || attr->transfer))) {
                                        /* Creates age by counters. */
                                        cnt_act = flow_dv_prepare_counter
                                                                (dev, dev_flow,
@@ -12499,17 +12624,17 @@ flow_dv_translate(struct rte_eth_dev *dev,
                                        break;
                                }
                                if (!flow->age && non_shared_age) {
-                                       flow->age =
-                                               flow_dv_translate_create_aso_age
-                                                               (dev,
-                                                                non_shared_age,
-                                                                error);
+                                       flow->age = flow_dv_aso_age_alloc
+                                                               (dev, error);
                                        if (!flow->age)
-                                               return rte_flow_error_set
-                                                   (error, rte_errno,
-                                                    RTE_FLOW_ERROR_TYPE_ACTION,
-                                                    NULL,
-                                                    "can't create ASO age action");
+                                               return -rte_errno;
+                                       flow_dv_aso_age_params_init
+                                                   (dev, flow->age,
+                                                    non_shared_age->context ?
+                                                    non_shared_age->context :
+                                                    (void *)(uintptr_t)
+                                                    (dev_flow->flow_idx),
+                                                    non_shared_age->timeout);
                                }
                                age_act = flow_aso_age_get_by_idx(dev,
                                                                  flow->age);
@@ -14071,6 +14196,8 @@ flow_dv_action_create(struct rte_eth_dev *dev,
                      const struct rte_flow_action *action,
                      struct rte_flow_error *err)
 {
+       struct mlx5_priv *priv = dev->data->dev_private;
+       uint32_t age_idx = 0;
        uint32_t idx = 0;
        uint32_t ret = 0;
 
@@ -14081,17 +14208,22 @@ flow_dv_action_create(struct rte_eth_dev *dev,
                       MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
                break;
        case RTE_FLOW_ACTION_TYPE_AGE:
-               ret = flow_dv_translate_create_aso_age(dev, action->conf, err);
-               idx = (MLX5_INDIRECT_ACTION_TYPE_AGE <<
-                      MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
-               if (ret) {
-                       struct mlx5_aso_age_action *aso_age =
-                                             flow_aso_age_get_by_idx(dev, ret);
-
-                       if (!aso_age->age_params.context)
-                               aso_age->age_params.context =
-                                                        (void *)(uintptr_t)idx;
+               age_idx = flow_dv_aso_age_alloc(dev, err);
+               if (!age_idx) {
+                       ret = -rte_errno;
+                       break;
                }
+               idx = (MLX5_INDIRECT_ACTION_TYPE_AGE <<
+                      MLX5_INDIRECT_ACTION_TYPE_OFFSET) | age_idx;
+               flow_dv_aso_age_params_init(dev, age_idx,
+                                       ((const struct rte_flow_action_age *)
+                                               action->conf)->context ?
+                                       ((const struct rte_flow_action_age *)
+                                               action->conf)->context :
+                                       (void *)(uintptr_t)idx,
+                                       ((const struct rte_flow_action_age *)
+                                               action->conf)->timeout);
+               ret = age_idx;
                break;
        case RTE_FLOW_ACTION_TYPE_COUNT:
                ret = flow_dv_translate_create_counter(dev, NULL, NULL, NULL);
@@ -14101,8 +14233,7 @@ flow_dv_action_create(struct rte_eth_dev *dev,
        case RTE_FLOW_ACTION_TYPE_CONNTRACK:
                ret = flow_dv_translate_create_conntrack(dev, action->conf,
                                                         err);
-               idx = (MLX5_INDIRECT_ACTION_TYPE_CT <<
-                      MLX5_INDIRECT_ACTION_TYPE_OFFSET) | ret;
+               idx = MLX5_INDIRECT_ACT_CT_GEN_IDX(PORT_ID(priv), ret);
                break;
        default:
                rte_flow_error_set(err, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
@@ -14168,7 +14299,9 @@ flow_dv_action_destroy(struct rte_eth_dev *dev,
                return 0;
        case MLX5_INDIRECT_ACTION_TYPE_CT:
                ret = flow_dv_aso_ct_release(dev, idx);
-               if (ret)
+               if (ret < 0)
+                       return ret;
+               if (ret > 0)
                        DRV_LOG(DEBUG, "Connection tracking object %u still "
                                "has references %d.", idx, ret);
                return 0;
@@ -14272,8 +14405,16 @@ __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
        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;
 
-       ct = flow_aso_ct_get_by_idx(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,
@@ -14283,6 +14424,10 @@ __flow_dv_action_ct_update(struct rte_eth_dev *dev, uint32_t idx,
        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,
@@ -14960,6 +15105,8 @@ flow_dv_action_query(struct rte_eth_dev *dev,
        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:
@@ -14976,7 +15123,15 @@ flow_dv_action_query(struct rte_eth_dev *dev,
        case MLX5_INDIRECT_ACTION_TYPE_COUNT:
                return flow_dv_query_count(dev, idx, data, error);
        case MLX5_INDIRECT_ACTION_TYPE_CT:
-               ct = flow_aso_ct_get_by_idx(dev, idx);
+               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,
@@ -16167,6 +16322,12 @@ flow_dv_action_validate(struct rte_eth_dev *dev,
                                                  NULL,
                                                  "Mix shared and indirect counter is not supported");
                return flow_dv_validate_action_count(dev, true, 0, err);
+       case RTE_FLOW_ACTION_TYPE_CONNTRACK:
+               if (!priv->sh->ct_aso_en)
+                       return rte_flow_error_set(err, ENOTSUP,
+                                       RTE_FLOW_ERROR_TYPE_UNSPECIFIED, NULL,
+                                       "ASO CT is not supported");
+               return mlx5_validate_action_ct(dev, action->conf, err);
        default:
                return rte_flow_error_set(err, ENOTSUP,
                                          RTE_FLOW_ERROR_TYPE_ACTION,