diff --git a/drivers/net/mlx5/hws/mlx5dr.h b/drivers/net/mlx5/hws/mlx5dr.h
index ec2230d136..6b96a120f7 100644
--- a/drivers/net/mlx5/hws/mlx5dr.h
+++ b/drivers/net/mlx5/hws/mlx5dr.h
@@ -156,8 +156,21 @@ struct mlx5dr_devx_obj {
 	uint32_t id;
 };
 
-/* In actions that take offset, the offset is unique, and the user should not
- * reuse the same index because data changing is not atomic.
+struct mlx5dr_action_reformat_header {
+	size_t sz;
+	void *data;
+};
+
+struct mlx5dr_action_mh_pattern {
+	/* Byte size of modify actions provided by "data" */
+	size_t sz;
+	/* PRM format modify actions pattern */
+	__be64 *data;
+};
+
+/* In actions that take offset, the offset is unique, pointing to a single
+ * resource and the user should not reuse the same index because data changing
+ * is not atomic.
  */
 struct mlx5dr_rule_action {
 	struct mlx5dr_action *action;
@@ -172,11 +185,13 @@ struct mlx5dr_rule_action {
 
 		struct {
 			uint32_t offset;
+			uint8_t pattern_idx;
 			uint8_t *data;
 		} modify_header;
 
 		struct {
 			uint32_t offset;
+			uint8_t hdr_idx;
 			uint8_t *data;
 		} reformat;
 
@@ -481,12 +496,12 @@ mlx5dr_action_create_counter(struct mlx5dr_context *ctx,
  *	The context in which the new action will be created.
  * @param[in] reformat_type
  *	Type of reformat prefixed with MLX5DR_ACTION_TYP_REFORMAT.
- * @param[in] data_sz
- *	Size in bytes of data.
- * @param[in] inline_data
- *	Header data array in case of inline action.
+ * @param[in] num_of_hdrs
+ *	Number of provided headers in "hdrs" array.
+ * @param[in] hdrs
+ *	Headers array containing header information.
  * @param[in] log_bulk_size
- *	Number of unique values used with this pattern.
+ *	Number of unique values used with this reformat.
  * @param[in] flags
  *	Action creation flags. (enum mlx5dr_action_flags)
  * @return pointer to mlx5dr_action on success NULL otherwise.
@@ -494,8 +509,8 @@ mlx5dr_action_create_counter(struct mlx5dr_context *ctx,
 struct mlx5dr_action *
 mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
 			      enum mlx5dr_action_type reformat_type,
-			      size_t data_sz,
-			      void *inline_data,
+			      uint8_t num_of_hdrs,
+			      struct mlx5dr_action_reformat_header *hdrs,
 			      uint32_t log_bulk_size,
 			      uint32_t flags);
 
@@ -503,10 +518,10 @@ mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
  *
  * @param[in] ctx
  *	The context in which the new action will be created.
- * @param[in] pattern_sz
- *	Byte size of the pattern array.
- * @param[in] pattern
- *	PRM format modify pattern action array.
+ * @param[in] num_of_patterns
+ * 	Number of provided patterns in "patterns" array.
+ * @param[in] patterns
+ *	Patterns array containing pattern information.
  * @param[in] log_bulk_size
  *	Number of unique values used with this pattern.
  * @param[in] flags
@@ -515,8 +530,8 @@ mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
  */
 struct mlx5dr_action *
 mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx,
-				   size_t pattern_sz,
-				   __be64 pattern[],
+				   uint8_t num_of_patterns,
+				   struct mlx5dr_action_mh_pattern *patterns,
 				   uint32_t log_bulk_size,
 				   uint32_t flags);
 
diff --git a/drivers/net/mlx5/hws/mlx5dr_action.c b/drivers/net/mlx5/hws/mlx5dr_action.c
index 920099ba5b..48fb6d3eaa 100644
--- a/drivers/net/mlx5/hws/mlx5dr_action.c
+++ b/drivers/net/mlx5/hws/mlx5dr_action.c
@@ -529,7 +529,7 @@ static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action,
 		} else {
 			attr->action_type = MLX5_IFC_STC_ACTION_TYPE_ACC_MODIFY_LIST;
 			attr->modify_header.arg_id = action->modify_header.arg_obj->id;
-			attr->modify_header.pattern_id = action->modify_header.pattern_obj->id;
+			attr->modify_header.pattern_id = action->modify_header.pat_obj->id;
 		}
 		break;
 	case MLX5DR_ACTION_TYP_TBL:
@@ -705,11 +705,13 @@ mlx5dr_action_is_hws_flags(uint32_t flags)
 }
 
 static struct mlx5dr_action *
-mlx5dr_action_create_generic(struct mlx5dr_context *ctx,
-			     uint32_t flags,
-			     enum mlx5dr_action_type action_type)
+mlx5dr_action_create_generic_bulk(struct mlx5dr_context *ctx,
+				  uint32_t flags,
+				  enum mlx5dr_action_type action_type,
+				  uint8_t bulk_sz)
 {
 	struct mlx5dr_action *action;
+	int i;
 
 	if (!mlx5dr_action_is_root_flags(flags) &&
 	    !mlx5dr_action_is_hws_flags(flags)) {
@@ -725,20 +727,30 @@ mlx5dr_action_create_generic(struct mlx5dr_context *ctx,
 		return NULL;
 	}
 
-	action = simple_calloc(1, sizeof(*action));
+	action = simple_calloc(bulk_sz, sizeof(*action));
 	if (!action) {
 		DR_LOG(ERR, "Failed to allocate memory for action [%d]", action_type);
 		rte_errno = ENOMEM;
 		return NULL;
 	}
 
-	action->ctx = ctx;
-	action->flags = flags;
-	action->type = action_type;
+	for (i = 0; i < bulk_sz; i++) {
+		action[i].ctx = ctx;
+		action[i].flags = flags;
+		action[i].type = action_type;
+	}
 
 	return action;
 }
 
+static struct mlx5dr_action *
+mlx5dr_action_create_generic(struct mlx5dr_context *ctx,
+			     uint32_t flags,
+			     enum mlx5dr_action_type action_type)
+{
+	return mlx5dr_action_create_generic_bulk(ctx, flags, action_type, 1);
+}
+
 struct mlx5dr_action *
 mlx5dr_action_create_dest_table(struct mlx5dr_context *ctx,
 				struct mlx5dr_table *tbl,
@@ -1141,7 +1153,7 @@ mlx5dr_action_create_pop_vlan(struct mlx5dr_context *ctx, uint32_t flags)
 	return NULL;
 }
 
-static void
+static int
 mlx5dr_action_conv_reformat_to_verbs(uint32_t action_type,
 				     uint32_t *verb_reformat_type)
 {
@@ -1149,19 +1161,23 @@ mlx5dr_action_conv_reformat_to_verbs(uint32_t action_type,
 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L2_TO_L2:
 		*verb_reformat_type =
 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TUNNEL_TO_L2;
-		break;
+		return 0;
 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
 		*verb_reformat_type =
 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
-		break;
+		return 0;
 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
 		*verb_reformat_type =
 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L3_TUNNEL_TO_L2;
-		break;
+		return 0;
 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
 		*verb_reformat_type =
 			MLX5DV_FLOW_ACTION_PACKET_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
-		break;
+		return 0;
+	default:
+		DR_LOG(ERR, "Invalid root reformat action type");
+		rte_errno = EINVAL;
+		return rte_errno;
 	}
 }
 
@@ -1199,7 +1215,9 @@ mlx5dr_action_create_reformat_root(struct mlx5dr_action *action,
 	if (ret)
 		return rte_errno;
 
-	mlx5dr_action_conv_reformat_to_verbs(action->type, &verb_reformat_type);
+	ret = mlx5dr_action_conv_reformat_to_verbs(action->type, &verb_reformat_type);
+	if (ret)
+		return rte_errno;
 
 	/* Create the reformat type for root table */
 	ibv_ctx = mlx5dr_context_get_local_ibv(action->ctx);
@@ -1210,6 +1228,7 @@ mlx5dr_action_create_reformat_root(struct mlx5dr_action *action,
 								      verb_reformat_type,
 								      ft_type);
 	if (!action->flow_action) {
+		DR_LOG(ERR, "Failed to create dv_create_flow reformat");
 		rte_errno = errno;
 		return rte_errno;
 	}
@@ -1217,132 +1236,84 @@ mlx5dr_action_create_reformat_root(struct mlx5dr_action *action,
 	return 0;
 }
 
-static int mlx5dr_action_handle_reformat_args(struct mlx5dr_context *ctx,
-					      size_t data_sz,
-					      void *data,
-					      uint32_t bulk_size,
-					      struct mlx5dr_action *action)
-{
-	uint32_t args_log_size;
-	int ret;
-
-	if (data_sz % 2 != 0) {
-		DR_LOG(ERR, "Data size should be multiply of 2");
-		rte_errno = EINVAL;
-		return rte_errno;
-	}
-	action->reformat.header_size = data_sz;
-
-	args_log_size = mlx5dr_arg_data_size_to_arg_log_size(data_sz);
-	if (args_log_size >= MLX5DR_ARG_CHUNK_SIZE_MAX) {
-		DR_LOG(ERR, "Data size is bigger than supported");
-		rte_errno = EINVAL;
-		return rte_errno;
+static int
+mlx5dr_action_handle_l2_to_tunnel_l2(struct mlx5dr_action *action,
+				     uint8_t num_of_hdrs,
+				     struct mlx5dr_action_reformat_header *hdrs,
+				     uint32_t log_bulk_sz)
+{
+	struct mlx5dr_devx_obj *arg_obj;
+	size_t max_sz = 0;
+	int ret, i;
+
+	for (i = 0; i < num_of_hdrs; i++) {
+		if (hdrs[i].sz % 2 != 0) {
+			DR_LOG(ERR, "Header data size should be multiply of 2");
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
+		max_sz = RTE_MAX(hdrs[i].sz, max_sz);
 	}
-	args_log_size += bulk_size;
 
-	if (!mlx5dr_arg_is_valid_arg_request_size(ctx, args_log_size)) {
-		DR_LOG(ERR, "Arg size %d does not fit FW requests",
-		       args_log_size);
-		rte_errno = EINVAL;
+	/* Allocate single shared arg object for all headers */
+	arg_obj = mlx5dr_arg_create(action->ctx,
+				    hdrs->data,
+				    max_sz,
+				    log_bulk_sz,
+				    action->flags & MLX5DR_ACTION_FLAG_SHARED);
+	if (!arg_obj)
 		return rte_errno;
-	}
 
-	action->reformat.arg_obj = mlx5dr_cmd_arg_create(ctx->ibv_ctx,
-							 args_log_size,
-							 ctx->pd_num);
-	if (!action->reformat.arg_obj) {
-		DR_LOG(ERR, "Failed to create arg for reformat");
-		return rte_errno;
-	}
+	for (i = 0; i < num_of_hdrs; i++) {
+		action[i].reformat.arg_obj = arg_obj;
+		action[i].reformat.header_size = hdrs[i].sz;
+		action[i].reformat.num_of_hdrs = num_of_hdrs;
+		action[i].reformat.max_hdr_sz = max_sz;
 
-	/* When INLINE need to write the arg data */
-	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
-		ret = mlx5dr_arg_write_inline_arg_data(ctx,
-						       action->reformat.arg_obj->id,
-						       data,
-						       data_sz);
+		ret = mlx5dr_action_create_stcs(&action[i], NULL);
 		if (ret) {
-			DR_LOG(ERR, "Failed to write inline arg for reformat");
-			goto free_arg;
+			DR_LOG(ERR, "Failed to create stc for reformat");
+			goto free_stc;
 		}
 	}
 
 	return 0;
 
-free_arg:
-	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
-	return ret;
-}
-
-static int mlx5dr_action_handle_l2_to_tunnel_l2(struct mlx5dr_context *ctx,
-						size_t data_sz,
-						void *data,
-						uint32_t bulk_size,
-						struct mlx5dr_action *action)
-{
-	int ret;
+free_stc:
+	while (i--)
+		mlx5dr_action_destroy_stcs(&action[i]);
 
-	ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size,
-						 action);
-	if (ret) {
-		DR_LOG(ERR, "Failed to create args for reformat");
-		return ret;
-	}
-
-	ret = mlx5dr_action_create_stcs(action, NULL);
-	if (ret) {
-		DR_LOG(ERR, "Failed to create stc for reformat");
-		goto free_arg;
-	}
-
-	return 0;
-
-free_arg:
-	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
+	mlx5dr_cmd_destroy_obj(arg_obj);
 	return ret;
 }
 
-static int mlx5dr_action_get_shared_stc_offset(struct mlx5dr_context_common_res *common_res,
-					       enum mlx5dr_context_shared_stc_type stc_type)
-{
-	return common_res->shared_stc[stc_type]->remove_header.offset;
-}
-
-static int mlx5dr_action_handle_l2_to_tunnel_l3(struct mlx5dr_context *ctx,
-						size_t data_sz,
-						void *data,
-						uint32_t bulk_size,
-						struct mlx5dr_action *action)
+static int
+mlx5dr_action_handle_l2_to_tunnel_l3(struct mlx5dr_action *action,
+				     uint8_t num_of_hdrs,
+				     struct mlx5dr_action_reformat_header *hdrs,
+				     uint32_t log_bulk_sz)
 {
 	int ret;
 
-	ret = mlx5dr_action_handle_reformat_args(ctx, data_sz, data, bulk_size,
-						 action);
-	if (ret) {
-		DR_LOG(ERR, "Failed to create args for reformat");
-		return ret;
-	}
-
 	/* The action is remove-l2-header + insert-l3-header */
 	ret = mlx5dr_action_get_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
 	if (ret) {
 		DR_LOG(ERR, "Failed to create remove stc for reformat");
-		goto free_arg;
+		return ret;
 	}
 
-	ret = mlx5dr_action_create_stcs(action, NULL);
-	if (ret) {
-		DR_LOG(ERR, "Failed to create insert stc for reformat");
-		goto down_shared;
-	}
+	/* Reuse the insert with pointer for the L2L3 header */
+	ret = mlx5dr_action_handle_l2_to_tunnel_l2(action,
+						   num_of_hdrs,
+						   hdrs,
+						   log_bulk_sz);
+	if (ret)
+		goto put_shared_stc;
 
 	return 0;
 
-down_shared:
+put_shared_stc:
 	mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
-free_arg:
-	mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
 	return ret;
 }
 
@@ -1393,67 +1364,81 @@ static void mlx5dr_action_prepare_decap_l3_actions(size_t data_sz,
 }
 
 static int
-mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_context *ctx,
-				     size_t data_sz,
-				     void *data,
-				     uint32_t bulk_size,
-				     struct mlx5dr_action *action)
+mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_action *action,
+				     uint8_t num_of_hdrs,
+				     struct mlx5dr_action_reformat_header *hdrs,
+				     uint32_t log_bulk_sz)
 {
 	uint8_t mh_data[MLX5DR_ACTION_REFORMAT_DATA_SIZE] = {0};
+	struct mlx5dr_devx_obj *arg_obj, *pat_obj;
+	struct mlx5dr_context *ctx = action->ctx;
 	int num_of_actions;
 	int mh_data_size;
-	int ret;
+	int ret, i;
 
-	if (data_sz != MLX5DR_ACTION_HDR_LEN_L2 &&
-	    data_sz != MLX5DR_ACTION_HDR_LEN_L2_W_VLAN) {
-		DR_LOG(ERR, "Data size is not supported for decap-l3");
-		rte_errno = EINVAL;
-		return rte_errno;
+	for (i = 0; i < num_of_hdrs; i++) {
+		if (hdrs[i].sz != MLX5DR_ACTION_HDR_LEN_L2 &&
+		    hdrs[i].sz != MLX5DR_ACTION_HDR_LEN_L2_W_VLAN) {
+			DR_LOG(ERR, "Data size is not supported for decap-l3");
+			rte_errno = EINVAL;
+			return rte_errno;
+		}
 	}
 
-	mlx5dr_action_prepare_decap_l3_actions(data_sz, mh_data, &num_of_actions);
+	/* Create a full modify header action list in case shared */
+	mlx5dr_action_prepare_decap_l3_actions(hdrs->sz, mh_data, &num_of_actions);
+	mlx5dr_action_prepare_decap_l3_data(hdrs->data, mh_data, num_of_actions);
 
-	mh_data_size = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE;
+	/* All DecapL3 cases require the same max arg size */
+	arg_obj = mlx5dr_arg_create_modify_header_arg(ctx,
+						      (__be64 *)mh_data,
+						      num_of_actions,
+						      log_bulk_sz,
+						      action->flags & MLX5DR_ACTION_FLAG_SHARED);
+	if (!arg_obj)
+		return rte_errno;
 
-	ret = mlx5dr_pat_arg_create_modify_header(ctx, action, mh_data_size,
-						  (__be64 *)mh_data, bulk_size);
-	if (ret) {
-		DR_LOG(ERR, "Failed allocating modify-header for decap-l3");
-		return ret;
-	}
+	for (i = 0; i < num_of_hdrs; i++) {
+		memset(mh_data, 0, MLX5DR_ACTION_REFORMAT_DATA_SIZE);
+		mlx5dr_action_prepare_decap_l3_actions(hdrs[i].sz, mh_data, &num_of_actions);
+		mh_data_size = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE;
 
-	ret = mlx5dr_action_create_stcs(action, NULL);
-	if (ret)
-		goto free_mh_obj;
-
-	if (action->flags & MLX5DR_ACTION_FLAG_SHARED) {
-		mlx5dr_action_prepare_decap_l3_data(data, mh_data, num_of_actions);
-		ret = mlx5dr_arg_write_inline_arg_data(ctx,
-						       action->modify_header.arg_obj->id,
-						       (uint8_t *)mh_data,
-						       num_of_actions *
-						       MLX5DR_MODIFY_ACTION_SIZE);
+		pat_obj = mlx5dr_pat_get_pattern(ctx, (__be64 *)mh_data, mh_data_size);
+		if (!pat_obj) {
+			DR_LOG(ERR, "Failed to allocate pattern for DecapL3");
+			goto free_stc_and_pat;
+		}
+
+		action[i].modify_header.max_num_of_actions = num_of_actions;
+		action[i].modify_header.num_of_actions = num_of_actions;
+		action[i].modify_header.arg_obj = arg_obj;
+		action[i].modify_header.pat_obj = pat_obj;
+
+		ret = mlx5dr_action_create_stcs(&action[i], NULL);
 		if (ret) {
-			DR_LOG(ERR, "Failed writing INLINE arg decap_l3");
-			goto clean_stc;
+			mlx5dr_pat_put_pattern(ctx, pat_obj);
+			goto free_stc_and_pat;
 		}
 	}
 
 	return 0;
 
-clean_stc:
-	mlx5dr_action_destroy_stcs(action);
-free_mh_obj:
-	mlx5dr_pat_arg_destroy_modify_header(ctx, action);
-	return ret;
+
+free_stc_and_pat:
+	while (i--) {
+		mlx5dr_action_destroy_stcs(&action[i]);
+		mlx5dr_pat_put_pattern(ctx, action[i].modify_header.pat_obj);
+	}
+
+	mlx5dr_cmd_destroy_obj(arg_obj);
+	return 0;
 }
 
 static int
-mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx,
-				  size_t data_sz,
-				  void *data,
-				  uint32_t bulk_size,
-				  struct mlx5dr_action *action)
+mlx5dr_action_create_reformat_hws(struct mlx5dr_action *action,
+				  uint8_t num_of_hdrs,
+				  struct mlx5dr_action_reformat_header *hdrs,
+				  uint32_t bulk_size)
 {
 	int ret;
 
@@ -1462,18 +1447,17 @@ mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx,
 		ret = mlx5dr_action_create_stcs(action, NULL);
 		break;
 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
-		ret = mlx5dr_action_handle_l2_to_tunnel_l2(ctx, data_sz, data, bulk_size, action);
+		ret = mlx5dr_action_handle_l2_to_tunnel_l2(action, num_of_hdrs, hdrs, bulk_size);
 		break;
 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
-		ret = mlx5dr_action_handle_l2_to_tunnel_l3(ctx, data_sz, data, bulk_size, action);
+		ret = mlx5dr_action_handle_l2_to_tunnel_l3(action, num_of_hdrs, hdrs, bulk_size);
 		break;
 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
-		ret = mlx5dr_action_handle_tunnel_l3_to_l2(ctx, data_sz, data, bulk_size, action);
+		ret = mlx5dr_action_handle_tunnel_l3_to_l2(action, num_of_hdrs, hdrs, bulk_size);
 		break;
-
 	default:
-		assert(false);
-		rte_errno = ENOTSUP;
+		DR_LOG(ERR, "Invalid HWS reformat action type");
+		rte_errno = EINVAL;
 		return rte_errno;
 	}
 
@@ -1483,15 +1467,20 @@ mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx,
 struct mlx5dr_action *
 mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
 			      enum mlx5dr_action_type reformat_type,
-			      size_t data_sz,
-			      void *inline_data,
+			      uint8_t num_of_hdrs,
+			      struct mlx5dr_action_reformat_header *hdrs,
 			      uint32_t log_bulk_size,
 			      uint32_t flags)
 {
 	struct mlx5dr_action *action;
 	int ret;
 
-	action = mlx5dr_action_create_generic(ctx, flags, reformat_type);
+	if (!num_of_hdrs) {
+		DR_LOG(ERR, "Reformat num_of_hdrs cannot be zero");
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic_bulk(ctx, flags, reformat_type, num_of_hdrs);
 	if (!action)
 		return NULL;
 
@@ -1502,24 +1491,27 @@ mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
 			goto free_action;
 		}
 
-		ret = mlx5dr_action_create_reformat_root(action, data_sz, inline_data);
-		if (ret)
+		ret = mlx5dr_action_create_reformat_root(action,
+							 hdrs ? hdrs->sz : 0,
+							 hdrs ? hdrs->data : NULL);
+		if (ret) {
+			DR_LOG(ERR, "Failed to create root reformat action");
 			goto free_action;
+		}
 
 		return action;
 	}
 
 	if (!mlx5dr_action_is_hws_flags(flags) ||
-	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
-		DR_LOG(ERR, "Reformat flags don't fit HWS (flags: %x0x)",
-			flags);
+	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_hdrs > 1))) {
+		DR_LOG(ERR, "Reformat flags don't fit HWS (flags: %x0x)", flags);
 		rte_errno = EINVAL;
 		goto free_action;
 	}
 
-	ret = mlx5dr_action_create_reformat_hws(ctx, data_sz, inline_data, log_bulk_size, action);
+	ret = mlx5dr_action_create_reformat_hws(action, num_of_hdrs, hdrs, log_bulk_size);
 	if (ret) {
-		DR_LOG(ERR, "Failed to create reformat.");
+		DR_LOG(ERR, "Failed to create HWS reformat action");
 		rte_errno = EINVAL;
 		goto free_action;
 	}
@@ -1559,17 +1551,104 @@ mlx5dr_action_create_modify_header_root(struct mlx5dr_action *action,
 	return 0;
 }
 
+static int
+mlx5dr_action_create_modify_header_hws(struct mlx5dr_action *action,
+				       uint8_t num_of_patterns,
+				       struct mlx5dr_action_mh_pattern *pattern,
+				       uint32_t log_bulk_size)
+{
+	struct mlx5dr_devx_obj *pat_obj, *arg_obj = NULL;
+	struct mlx5dr_context *ctx = action->ctx;
+	uint16_t max_mh_actions = 0;
+	int i, ret;
+
+	/* Caclulate maximum number of mh actions for shared arg allocation */
+	for (i = 0; i < num_of_patterns; i++)
+		max_mh_actions = RTE_MAX(max_mh_actions, pattern[i].sz / MLX5DR_MODIFY_ACTION_SIZE);
+
+	/* Allocate single shared arg for all patterns based on the max size */
+	if (max_mh_actions > 1) {
+		arg_obj = mlx5dr_arg_create_modify_header_arg(ctx,
+							      pattern->data,
+							      max_mh_actions,
+							      log_bulk_size,
+							      action->flags &
+							      MLX5DR_ACTION_FLAG_SHARED);
+		if (!arg_obj)
+			return rte_errno;
+	}
+
+	for (i = 0; i < num_of_patterns; i++) {
+		if (!mlx5dr_pat_verify_actions(pattern[i].data, pattern[i].sz)) {
+			DR_LOG(ERR, "Fail to verify pattern modify actions");
+			rte_errno = EINVAL;
+			goto free_stc_and_pat;
+		}
+
+		action[i].modify_header.num_of_patterns = num_of_patterns;
+		action[i].modify_header.max_num_of_actions = max_mh_actions;
+		action[i].modify_header.num_of_actions = pattern[i].sz / MLX5DR_MODIFY_ACTION_SIZE;
+
+		if (action[i].modify_header.num_of_actions == 1) {
+			pat_obj = NULL;
+			/* Optimize single modify action to be used inline */
+			action[i].modify_header.single_action = pattern[i].data[0];
+			action[i].modify_header.single_action_type =
+				MLX5_GET(set_action_in, pattern[i].data, action_type);
+		} else {
+			/* Multiple modify actions require a pattern */
+			pat_obj = mlx5dr_pat_get_pattern(ctx, pattern[i].data, pattern[i].sz);
+			if (!pat_obj) {
+				DR_LOG(ERR, "Failed to allocate pattern for modify header");
+				goto free_stc_and_pat;
+			}
+
+			action[i].modify_header.arg_obj = arg_obj;
+			action[i].modify_header.pat_obj = pat_obj;
+		}
+		/* Allocate STC for each action representing a header */
+		ret = mlx5dr_action_create_stcs(&action[i], NULL);
+		if (ret) {
+			if (pat_obj)
+				mlx5dr_pat_put_pattern(ctx, pat_obj);
+			goto free_stc_and_pat;
+		}
+	}
+
+	return 0;
+
+free_stc_and_pat:
+	while (i--) {
+		mlx5dr_action_destroy_stcs(&action[i]);
+		if (action[i].modify_header.pat_obj)
+			mlx5dr_pat_put_pattern(ctx, action[i].modify_header.pat_obj);
+	}
+
+	if (arg_obj)
+		mlx5dr_cmd_destroy_obj(arg_obj);
+
+	return rte_errno;
+}
+
 struct mlx5dr_action *
 mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx,
-				   size_t pattern_sz,
-				   __be64 pattern[],
+				   uint8_t num_of_patterns,
+				   struct mlx5dr_action_mh_pattern *patterns,
 				   uint32_t log_bulk_size,
 				   uint32_t flags)
 {
 	struct mlx5dr_action *action;
 	int ret;
 
-	action = mlx5dr_action_create_generic(ctx, flags, MLX5DR_ACTION_TYP_MODIFY_HDR);
+	if (!num_of_patterns) {
+		DR_LOG(ERR, "Invalid number of patterns");
+		rte_errno = ENOTSUP;
+		return NULL;
+	}
+
+	action = mlx5dr_action_create_generic_bulk(ctx, flags,
+						   MLX5DR_ACTION_TYP_MODIFY_HDR,
+						   num_of_patterns);
 	if (!action)
 		return NULL;
 
@@ -1579,52 +1658,37 @@ mlx5dr_action_create_modify_header(struct mlx5dr_context *ctx,
 			rte_errno = ENOTSUP;
 			goto free_action;
 		}
-		ret = mlx5dr_action_create_modify_header_root(action, pattern_sz, pattern);
+
+		if (num_of_patterns != 1) {
+			DR_LOG(ERR, "Only a single pattern supported over root");
+			rte_errno = ENOTSUP;
+			goto free_action;
+		}
+
+		ret = mlx5dr_action_create_modify_header_root(action,
+							      patterns->sz,
+							      patterns->data);
 		if (ret)
 			goto free_action;
 
 		return action;
 	}
 
-	if (!mlx5dr_action_is_hws_flags(flags) ||
-	    ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
-		DR_LOG(ERR, "Flags don't fit hws (flags: %x0x, log_bulk_size: %d)",
-			flags, log_bulk_size);
+	if ((flags & MLX5DR_ACTION_FLAG_SHARED) && (log_bulk_size || num_of_patterns > 1)) {
+		DR_LOG(ERR, "Action cannot be shared with requested pattern or size");
 		rte_errno = EINVAL;
 		goto free_action;
 	}
 
-	if (!mlx5dr_pat_arg_verify_actions(pattern, pattern_sz / MLX5DR_MODIFY_ACTION_SIZE)) {
-		DR_LOG(ERR, "One of the actions is not supported");
-		rte_errno = EINVAL;
-		goto free_action;
-	}
-
-	if (pattern_sz / MLX5DR_MODIFY_ACTION_SIZE == 1) {
-		/* Optimize single modiy action to be used inline */
-		action->modify_header.single_action = pattern[0];
-		action->modify_header.num_of_actions = 1;
-		action->modify_header.single_action_type =
-			MLX5_GET(set_action_in, pattern, action_type);
-	} else {
-		/* Use multi action pattern and argument */
-		ret = mlx5dr_pat_arg_create_modify_header(ctx, action, pattern_sz,
-							  pattern, log_bulk_size);
-		if (ret) {
-			DR_LOG(ERR, "Failed allocating modify-header");
-			goto free_action;
-		}
-	}
-
-	ret = mlx5dr_action_create_stcs(action, NULL);
+	ret = mlx5dr_action_create_modify_header_hws(action,
+						     num_of_patterns,
+						     patterns,
+						     log_bulk_size);
 	if (ret)
-		goto free_mh_obj;
+		goto free_action;
 
 	return action;
 
-free_mh_obj:
-	if (action->modify_header.num_of_actions > 1)
-		mlx5dr_pat_arg_destroy_modify_header(ctx, action);
 free_action:
 	simple_free(action);
 	return NULL;
@@ -1684,6 +1748,9 @@ mlx5dr_action_create_dest_root(struct mlx5dr_context *ctx,
 
 static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action)
 {
+	struct mlx5dr_devx_obj *obj = NULL;
+	uint32_t i;
+
 	switch (action->type) {
 	case MLX5DR_ACTION_TYP_TIR:
 		mlx5dr_action_destroy_stcs(action);
@@ -1711,17 +1778,28 @@ static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action)
 		break;
 	case MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2:
 	case MLX5DR_ACTION_TYP_MODIFY_HDR:
-		mlx5dr_action_destroy_stcs(action);
-		if (action->modify_header.num_of_actions > 1)
-			mlx5dr_pat_arg_destroy_modify_header(action->ctx, action);
+		for (i = 0; i < action->modify_header.num_of_patterns; i++) {
+			mlx5dr_action_destroy_stcs(&action[i]);
+			if (action[i].modify_header.num_of_actions > 1) {
+				mlx5dr_pat_put_pattern(action[i].ctx,
+						       action[i].modify_header.pat_obj);
+				/* Save shared arg object if was used to free */
+				if (action[i].modify_header.arg_obj)
+					obj = action[i].modify_header.arg_obj;
+			}
+		}
+		if (obj)
+			mlx5dr_cmd_destroy_obj(obj);
 		break;
 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L3:
-		mlx5dr_action_destroy_stcs(action);
 		mlx5dr_action_put_shared_stc(action, MLX5DR_CONTEXT_SHARED_STC_DECAP);
+		for (i = 0; i < action->reformat.num_of_hdrs; i++)
+			mlx5dr_action_destroy_stcs(&action[i]);
 		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
 		break;
 	case MLX5DR_ACTION_TYP_REFORMAT_L2_TO_TNL_L2:
-		mlx5dr_action_destroy_stcs(action);
+		for (i = 0; i < action->reformat.num_of_hdrs; i++)
+			mlx5dr_action_destroy_stcs(&action[i]);
 		mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
 		break;
 	}
@@ -1903,6 +1981,12 @@ mlx5dr_action_prepare_decap_l3_data(uint8_t *src, uint8_t *dst,
 	memcpy(dst, e_src, 2);
 }
 
+static int mlx5dr_action_get_shared_stc_offset(struct mlx5dr_context_common_res *common_res,
+					       enum mlx5dr_context_shared_stc_type stc_type)
+{
+	return common_res->shared_stc[stc_type]->remove_header.offset;
+}
+
 static struct mlx5dr_actions_wqe_setter *
 mlx5dr_action_setter_find_first(struct mlx5dr_actions_wqe_setter *setter,
 				uint8_t req_flags)
@@ -1945,13 +2029,15 @@ mlx5dr_action_setter_modify_header(struct mlx5dr_actions_apply_data *apply,
 				   struct mlx5dr_actions_wqe_setter *setter)
 {
 	struct mlx5dr_rule_action *rule_action;
+	uint32_t stc_idx, arg_sz, arg_idx;
 	struct mlx5dr_action *action;
-	uint32_t arg_sz, arg_idx;
 	uint8_t *single_action;
 
 	rule_action = &apply->rule_action[setter->idx_double];
-	action = rule_action->action;
-	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	action = rule_action->action + rule_action->modify_header.pattern_idx;
+
+	stc_idx = htobe32(action->stc[apply->tbl_type].offset);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx;
 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
 
 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
@@ -1972,7 +2058,7 @@ mlx5dr_action_setter_modify_header(struct mlx5dr_actions_apply_data *apply,
 			*(__be32 *)MLX5_ADDR_OF(set_action_in, single_action, data);
 	} else {
 		/* Argument offset multiple with number of args per these actions */
-		arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions);
+		arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.max_num_of_actions);
 		arg_idx = rule_action->modify_header.offset * arg_sz;
 
 		apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
@@ -1992,26 +2078,29 @@ mlx5dr_action_setter_insert_ptr(struct mlx5dr_actions_apply_data *apply,
 				struct mlx5dr_actions_wqe_setter *setter)
 {
 	struct mlx5dr_rule_action *rule_action;
-	uint32_t arg_idx, arg_sz;
+	uint32_t stc_idx, arg_idx, arg_sz;
+	struct mlx5dr_action *action;
 
 	rule_action = &apply->rule_action[setter->idx_double];
+	action = rule_action->action + rule_action->reformat.hdr_idx;
 
 	/* Argument offset multiple on args required for header size */
-	arg_sz = mlx5dr_arg_data_size_to_arg_size(rule_action->action->reformat.header_size);
+	arg_sz = mlx5dr_arg_data_size_to_arg_size(action->reformat.max_hdr_sz);
 	arg_idx = rule_action->reformat.offset * arg_sz;
 
 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
 
-	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	stc_idx = htobe32(action->stc[apply->tbl_type].offset);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx;
 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
 
-	if (!(rule_action->action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
+	if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
 		apply->require_dep = 1;
 		mlx5dr_arg_write(apply->queue, NULL,
-				 rule_action->action->reformat.arg_obj->id + arg_idx,
+				 action->reformat.arg_obj->id + arg_idx,
 				 rule_action->reformat.data,
-				 rule_action->action->reformat.header_size);
+				 action->reformat.header_size);
 	}
 }
 
@@ -2020,20 +2109,21 @@ mlx5dr_action_setter_tnl_l3_to_l2(struct mlx5dr_actions_apply_data *apply,
 				  struct mlx5dr_actions_wqe_setter *setter)
 {
 	struct mlx5dr_rule_action *rule_action;
+	uint32_t stc_idx, arg_sz, arg_idx;
 	struct mlx5dr_action *action;
-	uint32_t arg_sz, arg_idx;
 
 	rule_action = &apply->rule_action[setter->idx_double];
-	action = rule_action->action;
+	action = rule_action->action + rule_action->reformat.hdr_idx;
 
 	/* Argument offset multiple on args required for num of actions */
-	arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.num_of_actions);
+	arg_sz = mlx5dr_arg_get_arg_size(action->modify_header.max_num_of_actions);
 	arg_idx = rule_action->reformat.offset * arg_sz;
 
 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW6] = 0;
 	apply->wqe_data[MLX5DR_ACTION_OFFSET_DW7] = htobe32(arg_idx);
 
-	mlx5dr_action_apply_stc(apply, MLX5DR_ACTION_STC_IDX_DW6, setter->idx_double);
+	stc_idx = htobe32(action->stc[apply->tbl_type].offset);
+	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW6] = stc_idx;
 	apply->wqe_ctrl->stc_ix[MLX5DR_ACTION_STC_IDX_DW7] = 0;
 
 	if (!(action->flags & MLX5DR_ACTION_FLAG_SHARED)) {
diff --git a/drivers/net/mlx5/hws/mlx5dr_action.h b/drivers/net/mlx5/hws/mlx5dr_action.h
index a85f3b0139..314e289780 100644
--- a/drivers/net/mlx5/hws/mlx5dr_action.h
+++ b/drivers/net/mlx5/hws/mlx5dr_action.h
@@ -120,15 +120,19 @@ struct mlx5dr_action {
 			struct mlx5dr_pool_chunk stc[MLX5DR_TABLE_TYPE_MAX];
 			union {
 				struct {
-					struct mlx5dr_devx_obj *pattern_obj;
+					struct mlx5dr_devx_obj *pat_obj;
 					struct mlx5dr_devx_obj *arg_obj;
 					__be64 single_action;
+					uint8_t num_of_patterns;
 					uint8_t single_action_type;
-					uint16_t num_of_actions;
+					uint8_t num_of_actions;
+					uint8_t max_num_of_actions;
 				} modify_header;
 				struct {
 					struct mlx5dr_devx_obj *arg_obj;
 					uint32_t header_size;
+					uint8_t num_of_hdrs;
+					uint16_t max_hdr_sz;
 				} reformat;
 				struct {
 					struct mlx5dr_devx_obj *devx_obj;
diff --git a/drivers/net/mlx5/hws/mlx5dr_pat_arg.c b/drivers/net/mlx5/hws/mlx5dr_pat_arg.c
index 309a61d477..50da90626c 100644
--- a/drivers/net/mlx5/hws/mlx5dr_pat_arg.c
+++ b/drivers/net/mlx5/hws/mlx5dr_pat_arg.c
@@ -60,22 +60,16 @@ void mlx5dr_pat_uninit_pattern_cache(struct mlx5dr_pattern_cache *cache)
 	simple_free(cache);
 }
 
-static bool mlx5dr_pat_compare_pattern(enum mlx5dr_action_type cur_type,
-				       int cur_num_of_actions,
+static bool mlx5dr_pat_compare_pattern(int cur_num_of_actions,
 				       __be64 cur_actions[],
-				       enum mlx5dr_action_type type,
 				       int num_of_actions,
 				       __be64 actions[])
 {
 	int i;
 
-	if (cur_num_of_actions != num_of_actions || cur_type != type)
+	if (cur_num_of_actions != num_of_actions)
 		return false;
 
-	 /* All decap-l3 look the same, only change is the num of actions */
-	if (type == MLX5DR_ACTION_TYP_REFORMAT_TNL_L3_TO_L2)
-		return true;
-
 	for (i = 0; i < num_of_actions; i++) {
 		u8 action_id =
 			MLX5_GET(set_action_in, &actions[i], action_type);
@@ -96,17 +90,14 @@ static bool mlx5dr_pat_compare_pattern(enum mlx5dr_action_type cur_type,
 
 static struct mlx5dr_pattern_cache_item *
 mlx5dr_pat_find_cached_pattern(struct mlx5dr_pattern_cache *cache,
-			       struct mlx5dr_action *action,
 			       uint16_t num_of_actions,
 			       __be64 *actions)
 {
 	struct mlx5dr_pattern_cache_item *cached_pat;
 
 	LIST_FOREACH(cached_pat, &cache->head, next) {
-		if (mlx5dr_pat_compare_pattern(cached_pat->type,
-					       cached_pat->mh_data.num_of_actions,
+		if (mlx5dr_pat_compare_pattern(cached_pat->mh_data.num_of_actions,
 					       (__be64 *)cached_pat->mh_data.data,
-					       action->type,
 					       num_of_actions,
 					       actions))
 			return cached_pat;
@@ -117,13 +108,12 @@ mlx5dr_pat_find_cached_pattern(struct mlx5dr_pattern_cache *cache,
 
 static struct mlx5dr_pattern_cache_item *
 mlx5dr_pat_get_existing_cached_pattern(struct mlx5dr_pattern_cache *cache,
-				       struct mlx5dr_action *action,
 				       uint16_t num_of_actions,
 				       __be64 *actions)
 {
 	struct mlx5dr_pattern_cache_item *cached_pattern;
 
-	cached_pattern = mlx5dr_pat_find_cached_pattern(cache, action, num_of_actions, actions);
+	cached_pattern = mlx5dr_pat_find_cached_pattern(cache, num_of_actions, actions);
 	if (cached_pattern) {
 		/* LRU: move it to be first in the list */
 		LIST_REMOVE(cached_pattern, next);
@@ -134,24 +124,9 @@ mlx5dr_pat_get_existing_cached_pattern(struct mlx5dr_pattern_cache *cache,
 	return cached_pattern;
 }
 
-static struct mlx5dr_pattern_cache_item *
-mlx5dr_pat_get_cached_pattern_by_action(struct mlx5dr_pattern_cache *cache,
-					struct mlx5dr_action *action)
-{
-	struct mlx5dr_pattern_cache_item *cached_pattern;
-
-	LIST_FOREACH(cached_pattern, &cache->head, next) {
-		if (cached_pattern->mh_data.pattern_obj->id == action->modify_header.pattern_obj->id)
-			return cached_pattern;
-	}
-
-	return NULL;
-}
-
 static struct mlx5dr_pattern_cache_item *
 mlx5dr_pat_add_pattern_to_cache(struct mlx5dr_pattern_cache *cache,
 				struct mlx5dr_devx_obj *pattern_obj,
-				enum mlx5dr_action_type type,
 				uint16_t num_of_actions,
 				__be64 *actions)
 {
@@ -164,7 +139,6 @@ mlx5dr_pat_add_pattern_to_cache(struct mlx5dr_pattern_cache *cache,
 		return NULL;
 	}
 
-	cached_pattern->type = type;
 	cached_pattern->mh_data.num_of_actions = num_of_actions;
 	cached_pattern->mh_data.pattern_obj = pattern_obj;
 	cached_pattern->mh_data.data =
@@ -188,6 +162,20 @@ mlx5dr_pat_add_pattern_to_cache(struct mlx5dr_pattern_cache *cache,
 	return NULL;
 }
 
+static struct mlx5dr_pattern_cache_item *
+mlx5dr_pat_find_cached_pattern_by_obj(struct mlx5dr_pattern_cache *cache,
+				      struct mlx5dr_devx_obj *pat_obj)
+{
+	struct mlx5dr_pattern_cache_item *cached_pattern;
+
+	LIST_FOREACH(cached_pattern, &cache->head, next) {
+		if (cached_pattern->mh_data.pattern_obj->id == pat_obj->id)
+			return cached_pattern;
+	}
+
+	return NULL;
+}
+
 static void
 mlx5dr_pat_remove_pattern(struct mlx5dr_pattern_cache_item *cached_pattern)
 {
@@ -196,14 +184,14 @@ mlx5dr_pat_remove_pattern(struct mlx5dr_pattern_cache_item *cached_pattern)
 	simple_free(cached_pattern);
 }
 
-static void
-mlx5dr_pat_put_pattern(struct mlx5dr_pattern_cache *cache,
-		       struct mlx5dr_action *action)
+void mlx5dr_pat_put_pattern(struct mlx5dr_context *ctx,
+			    struct mlx5dr_devx_obj *pat_obj)
 {
+	struct mlx5dr_pattern_cache *cache = ctx->pattern_cache;
 	struct mlx5dr_pattern_cache_item *cached_pattern;
 
 	pthread_spin_lock(&cache->lock);
-	cached_pattern = mlx5dr_pat_get_cached_pattern_by_action(cache, action);
+	cached_pattern = mlx5dr_pat_find_cached_pattern_by_obj(cache, pat_obj);
 	if (!cached_pattern) {
 		DR_LOG(ERR, "Failed to find pattern according to action with pt");
 		assert(false);
@@ -214,62 +202,56 @@ mlx5dr_pat_put_pattern(struct mlx5dr_pattern_cache *cache,
 		goto out;
 
 	mlx5dr_pat_remove_pattern(cached_pattern);
+	mlx5dr_cmd_destroy_obj(pat_obj);
 
 out:
 	pthread_spin_unlock(&cache->lock);
 }
 
-static int mlx5dr_pat_get_pattern(struct mlx5dr_context *ctx,
-				  struct mlx5dr_action *action,
-				  uint16_t num_of_actions,
-				  size_t pattern_sz,
-				  __be64 *pattern)
+struct mlx5dr_devx_obj *
+mlx5dr_pat_get_pattern(struct mlx5dr_context *ctx,
+		       __be64 *pattern, size_t pattern_sz)
 {
+	uint16_t num_of_actions = pattern_sz / MLX5DR_MODIFY_ACTION_SIZE;
 	struct mlx5dr_pattern_cache_item *cached_pattern;
-	int ret = 0;
+	struct mlx5dr_devx_obj *pat_obj = NULL;
 
 	pthread_spin_lock(&ctx->pattern_cache->lock);
 
 	cached_pattern = mlx5dr_pat_get_existing_cached_pattern(ctx->pattern_cache,
-								action,
 								num_of_actions,
 								pattern);
 	if (cached_pattern) {
-		action->modify_header.pattern_obj = cached_pattern->mh_data.pattern_obj;
+		pat_obj = cached_pattern->mh_data.pattern_obj;
 		goto out_unlock;
 	}
 
-	action->modify_header.pattern_obj =
-		mlx5dr_cmd_header_modify_pattern_create(ctx->ibv_ctx,
-							pattern_sz,
-							(uint8_t *)pattern);
-	if (!action->modify_header.pattern_obj) {
+	pat_obj = mlx5dr_cmd_header_modify_pattern_create(ctx->ibv_ctx,
+							      pattern_sz,
+							      (uint8_t *)pattern);
+	if (!pat_obj) {
 		DR_LOG(ERR, "Failed to create pattern FW object");
-
-		ret = rte_errno;
 		goto out_unlock;
 	}
 
-	cached_pattern =
-		mlx5dr_pat_add_pattern_to_cache(ctx->pattern_cache,
-						action->modify_header.pattern_obj,
-						action->type,
-						num_of_actions,
-						pattern);
+	cached_pattern = mlx5dr_pat_add_pattern_to_cache(ctx->pattern_cache,
+							 pat_obj,
+							 num_of_actions,
+							 pattern);
 	if (!cached_pattern) {
 		DR_LOG(ERR, "Failed to add pattern to cache");
-		ret = rte_errno;
 		goto clean_pattern;
 	}
 
-out_unlock:
 	pthread_spin_unlock(&ctx->pattern_cache->lock);
-	return ret;
+	return pat_obj;
 
 clean_pattern:
-	mlx5dr_cmd_destroy_obj(action->modify_header.pattern_obj);
+	mlx5dr_cmd_destroy_obj(pat_obj);
+	pat_obj = NULL;
+out_unlock:
 	pthread_spin_unlock(&ctx->pattern_cache->lock);
-	return ret;
+	return pat_obj;
 }
 
 static void
@@ -388,64 +370,80 @@ bool mlx5dr_arg_is_valid_arg_request_size(struct mlx5dr_context *ctx,
 	return true;
 }
 
-static int
-mlx5dr_arg_create_modify_header_arg(struct mlx5dr_context *ctx,
-				    struct mlx5dr_action *action,
-				    uint16_t num_of_actions,
-				    __be64 *pattern,
-				    uint32_t bulk_size)
+struct mlx5dr_devx_obj *
+mlx5dr_arg_create(struct mlx5dr_context *ctx,
+		  uint8_t *data,
+		  size_t data_sz,
+		  uint32_t log_bulk_sz,
+		  bool write_data)
 {
-	uint32_t flags = action->flags;
-	uint16_t args_log_size;
-	int ret = 0;
+	struct mlx5dr_devx_obj *arg_obj;
+	uint16_t single_arg_log_sz;
+	uint16_t multi_arg_log_sz;
+	int ret;
 
-	/* Alloc bulk of args */
-	args_log_size = mlx5dr_arg_get_arg_log_size(num_of_actions);
-	if (args_log_size >= MLX5DR_ARG_CHUNK_SIZE_MAX) {
-		DR_LOG(ERR, "Exceed number of allowed actions %u",
-			num_of_actions);
-		rte_errno = EINVAL;
-		return rte_errno;
+	single_arg_log_sz = mlx5dr_arg_data_size_to_arg_log_size(data_sz);
+	multi_arg_log_sz = single_arg_log_sz + log_bulk_sz;
+
+	if (single_arg_log_sz >= MLX5DR_ARG_CHUNK_SIZE_MAX) {
+		DR_LOG(ERR, "Requested single arg %u not supported", single_arg_log_sz);
+		rte_errno = ENOTSUP;
+		return NULL;
 	}
 
-	if (!mlx5dr_arg_is_valid_arg_request_size(ctx, args_log_size + bulk_size)) {
-		DR_LOG(ERR, "Arg size %d does not fit FW capability",
-		       args_log_size + bulk_size);
-		rte_errno = EINVAL;
-		return rte_errno;
+	if (!mlx5dr_arg_is_valid_arg_request_size(ctx, multi_arg_log_sz)) {
+		DR_LOG(ERR, "Argument log size %d not supported by FW", multi_arg_log_sz);
+		rte_errno = ENOTSUP;
+		return NULL;
 	}
 
-	action->modify_header.arg_obj =
-		mlx5dr_cmd_arg_create(ctx->ibv_ctx, args_log_size + bulk_size,
-				      ctx->pd_num);
-	if (!action->modify_header.arg_obj) {
-		DR_LOG(ERR, "Failed allocating arg in order: %d",
-			args_log_size + bulk_size);
-		return rte_errno;
+	/* Alloc bulk of args */
+	arg_obj = mlx5dr_cmd_arg_create(ctx->ibv_ctx, multi_arg_log_sz, ctx->pd_num);
+	if (!arg_obj) {
+		DR_LOG(ERR, "Failed allocating arg in order: %d", multi_arg_log_sz);
+		return NULL;
 	}
 
-	/* When INLINE need to write the arg data */
-	if (flags & MLX5DR_ACTION_FLAG_SHARED)
+	if (write_data) {
 		ret = mlx5dr_arg_write_inline_arg_data(ctx,
-						       action->modify_header.arg_obj->id,
-						       (uint8_t *)pattern,
-						       num_of_actions *
-						       MLX5DR_MODIFY_ACTION_SIZE);
-	if (ret) {
-		DR_LOG(ERR, "Failed writing INLINE arg in order: %d",
-			args_log_size + bulk_size);
-		mlx5dr_cmd_destroy_obj(action->modify_header.arg_obj);
-		return rte_errno;
+						       arg_obj->id,
+						       data, data_sz);
+		if (ret) {
+			DR_LOG(ERR, "Failed writing arg data");
+			mlx5dr_cmd_destroy_obj(arg_obj);
+			return NULL;
+		}
 	}
 
-	return 0;
+	return arg_obj;
 }
 
-bool mlx5dr_pat_arg_verify_actions(__be64 pattern[], uint16_t num_of_actions)
+struct mlx5dr_devx_obj *
+mlx5dr_arg_create_modify_header_arg(struct mlx5dr_context *ctx,
+				    __be64 *data,
+				    uint8_t num_of_actions,
+				    uint32_t log_bulk_sz,
+				    bool write_data)
 {
-	int i;
+	size_t data_sz = num_of_actions * MLX5DR_MODIFY_ACTION_SIZE;
+	struct mlx5dr_devx_obj *arg_obj;
+
+	arg_obj = mlx5dr_arg_create(ctx,
+				    (uint8_t *)data,
+				    data_sz,
+				    log_bulk_sz,
+				    write_data);
+	if (!arg_obj)
+		DR_LOG(ERR, "Failed creating modify header arg");
+
+	return arg_obj;
+}
 
-	for (i = 0; i < num_of_actions; i++) {
+bool mlx5dr_pat_verify_actions(__be64 pattern[], size_t sz)
+{
+	size_t i;
+
+	for (i = 0; i < sz / MLX5DR_MODIFY_ACTION_SIZE; i++) {
 		u8 action_id =
 			MLX5_GET(set_action_in, &pattern[i], action_type);
 		if (action_id >= MLX5_MODIFICATION_TYPE_MAX) {
@@ -456,51 +454,3 @@ bool mlx5dr_pat_arg_verify_actions(__be64 pattern[], uint16_t num_of_actions)
 
 	return true;
 }
-
-int mlx5dr_pat_arg_create_modify_header(struct mlx5dr_context *ctx,
-					struct mlx5dr_action *action,
-					size_t pattern_sz,
-					__be64 pattern[],
-					uint32_t bulk_size)
-{
-	uint16_t num_of_actions;
-	int ret;
-
-	num_of_actions = pattern_sz / MLX5DR_MODIFY_ACTION_SIZE;
-	if (num_of_actions == 0) {
-		DR_LOG(ERR, "Invalid number of actions %u", num_of_actions);
-		rte_errno = EINVAL;
-		return rte_errno;
-	}
-
-	action->modify_header.num_of_actions = num_of_actions;
-
-	ret = mlx5dr_arg_create_modify_header_arg(ctx, action,
-						  num_of_actions,
-						  pattern,
-						  bulk_size);
-	if (ret) {
-		DR_LOG(ERR, "Failed to allocate arg");
-		return ret;
-	}
-
-	ret = mlx5dr_pat_get_pattern(ctx, action, num_of_actions, pattern_sz,
-				     pattern);
-	if (ret) {
-		DR_LOG(ERR, "Failed to allocate pattern");
-		goto free_arg;
-	}
-
-	return 0;
-
-free_arg:
-	mlx5dr_cmd_destroy_obj(action->modify_header.arg_obj);
-	return rte_errno;
-}
-
-void mlx5dr_pat_arg_destroy_modify_header(struct mlx5dr_context *ctx,
-					  struct mlx5dr_action *action)
-{
-	mlx5dr_cmd_destroy_obj(action->modify_header.arg_obj);
-	mlx5dr_pat_put_pattern(ctx->pattern_cache, action);
-}
diff --git a/drivers/net/mlx5/hws/mlx5dr_pat_arg.h b/drivers/net/mlx5/hws/mlx5dr_pat_arg.h
index ec467dbb4b..2a38891c4d 100644
--- a/drivers/net/mlx5/hws/mlx5dr_pat_arg.h
+++ b/drivers/net/mlx5/hws/mlx5dr_pat_arg.h
@@ -28,7 +28,6 @@ struct mlx5dr_pattern_cache {
 };
 
 struct mlx5dr_pattern_cache_item {
-	enum mlx5dr_action_type type;
 	struct {
 		struct mlx5dr_devx_obj *pattern_obj;
 		struct dr_icm_chunk *chunk;
@@ -53,16 +52,29 @@ int mlx5dr_pat_init_pattern_cache(struct mlx5dr_pattern_cache **cache);
 
 void mlx5dr_pat_uninit_pattern_cache(struct mlx5dr_pattern_cache *cache);
 
-bool mlx5dr_pat_arg_verify_actions(__be64 pattern[], uint16_t num_of_actions);
-
-int mlx5dr_pat_arg_create_modify_header(struct mlx5dr_context *ctx,
-					struct mlx5dr_action *action,
-					size_t pattern_sz,
-					__be64 pattern[],
-					uint32_t bulk_size);
-
-void mlx5dr_pat_arg_destroy_modify_header(struct mlx5dr_context *ctx,
-					  struct mlx5dr_action *action);
+bool mlx5dr_pat_verify_actions(__be64 pattern[], size_t sz);
+
+struct mlx5dr_devx_obj *
+mlx5dr_arg_create(struct mlx5dr_context *ctx,
+		  uint8_t *data,
+		  size_t data_sz,
+		  uint32_t log_bulk_sz,
+		  bool write_data);
+
+struct mlx5dr_devx_obj *
+mlx5dr_arg_create_modify_header_arg(struct mlx5dr_context *ctx,
+				    __be64 *data,
+				    uint8_t num_of_actions,
+				    uint32_t log_bulk_sz,
+				    bool write_data);
+
+struct mlx5dr_devx_obj *
+mlx5dr_pat_get_pattern(struct mlx5dr_context *ctx,
+		       __be64 *pattern,
+		       size_t pattern_sz);
+
+void mlx5dr_pat_put_pattern(struct mlx5dr_context *ctx,
+			    struct mlx5dr_devx_obj *pat_obj);
 
 bool mlx5dr_arg_is_valid_arg_request_size(struct mlx5dr_context *ctx,
 					  uint32_t arg_size);
diff --git a/drivers/net/mlx5/mlx5_flow_hw.c b/drivers/net/mlx5/mlx5_flow_hw.c
index 8e146d99e2..271e4aae10 100644
--- a/drivers/net/mlx5/mlx5_flow_hw.c
+++ b/drivers/net/mlx5/mlx5_flow_hw.c
@@ -1770,6 +1770,7 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev,
 		}
 	}
 	if (mhdr.pos != UINT16_MAX) {
+		struct mlx5dr_action_mh_pattern pattern;
 		uint32_t flags;
 		uint32_t bulk_size;
 		size_t mhdr_len;
@@ -1791,14 +1792,17 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev,
 		} else {
 			bulk_size = rte_log2_u32(table_attr->nb_flows);
 		}
+		pattern.data = (__be64 *)acts->mhdr->mhdr_cmds;
+		pattern.sz = mhdr_len;
 		acts->mhdr->action = mlx5dr_action_create_modify_header
-				(priv->dr_ctx, mhdr_len, (__be64 *)acts->mhdr->mhdr_cmds,
+				(priv->dr_ctx, 1, &pattern,
 				 bulk_size, flags);
 		if (!acts->mhdr->action)
 			goto err;
 		acts->rule_acts[acts->mhdr->pos].action = acts->mhdr->action;
 	}
 	if (reformat_used) {
+		struct mlx5dr_action_reformat_header hdr;
 		uint8_t buf[MLX5_ENCAP_MAX_LEN];
 		bool shared_rfmt = true;
 
@@ -1822,9 +1826,12 @@ __flow_hw_actions_translate(struct rte_eth_dev *dev,
 			acts->encap_decap->data_size = data_size;
 			memcpy(acts->encap_decap->data, encap_data, data_size);
 		}
+
+		hdr.sz = data_size;
+		hdr.data = encap_data;
 		acts->encap_decap->action = mlx5dr_action_create_reformat
 				(priv->dr_ctx, refmt_type,
-				 data_size, encap_data,
+				 1, &hdr,
 				 shared_rfmt ? 0 : rte_log2_u32(table_attr->nb_flows),
 				 mlx5_hw_act_flag[!!attr->group][type] |
 				 (shared_rfmt ? MLX5DR_ACTION_FLAG_SHARED : 0));
