@@ -3438,6 +3438,7 @@ enum mlx5_ifc_header_anchors {
MLX5_HEADER_ANCHOR_PACKET_START = 0x0,
MLX5_HEADER_ANCHOR_FIRST_VLAN_START = 0x2,
MLX5_HEADER_ANCHOR_IPV6_IPV4 = 0x07,
+ MLX5_HEADER_ANCHOR_TCP_UDP = 0x09,
MLX5_HEADER_ANCHOR_INNER_MAC = 0x13,
MLX5_HEADER_ANCHOR_INNER_IPV6_IPV4 = 0x19,
};
@@ -45,6 +45,8 @@ enum mlx5dr_action_type {
MLX5DR_ACTION_TYP_PUSH_VLAN,
MLX5DR_ACTION_TYP_ASO_METER,
MLX5DR_ACTION_TYP_ASO_CT,
+ MLX5DR_ACTION_TYP_IPV6_ROUTING_POP,
+ MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH,
MLX5DR_ACTION_TYP_MAX,
};
@@ -186,6 +188,12 @@ struct mlx5dr_rule_action {
uint8_t *data;
} reformat;
+ struct {
+ uint32_t offset;
+ uint8_t *data;
+ uint8_t *mhdr;
+ } recom;
+
struct {
rte_be32_t vlan_hdr;
} push_vlan;
@@ -614,4 +622,37 @@ int mlx5dr_send_queue_action(struct mlx5dr_context *ctx,
*/
int mlx5dr_debug_dump(struct mlx5dr_context *ctx, FILE *f);
+/* Check if mlx5dr action template contain srv6 push or pop actions.
+ *
+ * @param[in] at
+ * The action template going to be parsed.
+ * @return true if containing srv6 push/pop action, false otherwise.
+ */
+bool
+mlx5dr_action_template_contain_srv6(struct mlx5dr_action_template *at);
+
+/* Create multiple direct actions combination action.
+ *
+ * @param[in] ctx
+ * The context in which the new action will be created.
+ * @param[in] type
+ * Type of direct rule action.
+ * @param[in] data_sz
+ * Size in bytes of data.
+ * @param[in] inline_data
+ * Header data array in case of inline action.
+ * @param[in] log_bulk_size
+ * Number of unique values used with this pattern.
+ * @param[in] flags
+ * Action creation flags. (enum mlx5dr_action_flags)
+ * @return pointer to mlx5dr_action on success NULL otherwise.
+ */
+struct mlx5dr_action *
+mlx5dr_action_create_recombination(struct mlx5dr_context *ctx,
+ enum mlx5dr_action_type type,
+ size_t data_sz,
+ void *inline_data,
+ uint32_t log_bulk_size,
+ uint32_t flags);
+
#endif
@@ -19,6 +19,7 @@ static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_
[MLX5DR_TABLE_TYPE_NIC_RX] = {
BIT(MLX5DR_ACTION_TYP_TAG),
BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) |
+ BIT(MLX5DR_ACTION_TYP_IPV6_ROUTING_POP) |
BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2),
BIT(MLX5DR_ACTION_TYP_POP_VLAN),
BIT(MLX5DR_ACTION_TYP_POP_VLAN),
@@ -29,6 +30,7 @@ static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_
BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
+ BIT(MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH) |
BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
BIT(MLX5DR_ACTION_TYP_FT) |
BIT(MLX5DR_ACTION_TYP_MISS) |
@@ -46,6 +48,7 @@ static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_
BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
+ BIT(MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH) |
BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
BIT(MLX5DR_ACTION_TYP_FT) |
BIT(MLX5DR_ACTION_TYP_MISS) |
@@ -54,6 +57,7 @@ static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_
},
[MLX5DR_TABLE_TYPE_FDB] = {
BIT(MLX5DR_ACTION_TYP_TNL_L2_TO_L2) |
+ BIT(MLX5DR_ACTION_TYP_IPV6_ROUTING_POP) |
BIT(MLX5DR_ACTION_TYP_TNL_L3_TO_L2),
BIT(MLX5DR_ACTION_TYP_POP_VLAN),
BIT(MLX5DR_ACTION_TYP_POP_VLAN),
@@ -64,6 +68,7 @@ static const uint32_t action_order_arr[MLX5DR_TABLE_TYPE_MAX][MLX5DR_ACTION_TYP_
BIT(MLX5DR_ACTION_TYP_PUSH_VLAN),
BIT(MLX5DR_ACTION_TYP_MODIFY_HDR),
BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L2) |
+ BIT(MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH) |
BIT(MLX5DR_ACTION_TYP_L2_TO_TNL_L3),
BIT(MLX5DR_ACTION_TYP_FT) |
BIT(MLX5DR_ACTION_TYP_MISS) |
@@ -227,6 +232,18 @@ static void mlx5dr_action_put_shared_stc(struct mlx5dr_action *action,
mlx5dr_action_put_shared_stc_nic(ctx, stc_type, MLX5DR_TABLE_TYPE_FDB);
}
+bool mlx5dr_action_template_contain_srv6(struct mlx5dr_action_template *at)
+{
+ int i = 0;
+
+ for (i = 0; i < at->num_actions; i++) {
+ if (at->action_type_arr[i] == MLX5DR_ACTION_TYP_IPV6_ROUTING_POP ||
+ at->action_type_arr[i] == MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH)
+ return true;
+ }
+ return false;
+}
+
static void mlx5dr_action_print_combo(enum mlx5dr_action_type *user_actions)
{
DR_LOG(ERR, "Invalid action_type sequence");
@@ -501,6 +518,7 @@ static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action,
attr->dest_tir_num = obj->id;
break;
case MLX5DR_ACTION_TYP_TNL_L3_TO_L2:
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_POP:
case MLX5DR_ACTION_TYP_MODIFY_HDR:
attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
if (action->modify_header.num_of_actions == 1) {
@@ -529,10 +547,14 @@ static void mlx5dr_action_fill_stc_attr(struct mlx5dr_action *action,
attr->remove_header.end_anchor = MLX5_HEADER_ANCHOR_INNER_MAC;
break;
case MLX5DR_ACTION_TYP_L2_TO_TNL_L2:
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH:
attr->action_type = MLX5_IFC_STC_ACTION_TYPE_HEADER_INSERT;
attr->action_offset = MLX5DR_ACTION_OFFSET_DW6;
attr->insert_header.encap = 1;
- attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
+ if (action->type == MLX5DR_ACTION_TYP_L2_TO_TNL_L2)
+ attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_PACKET_START;
+ else
+ attr->insert_header.insert_anchor = MLX5_HEADER_ANCHOR_TCP_UDP;
attr->insert_header.arg_id = action->reformat.arg_obj->id;
attr->insert_header.header_size = action->reformat.header_size;
break;
@@ -1452,6 +1474,90 @@ mlx5dr_action_handle_tunnel_l3_to_l2(struct mlx5dr_context *ctx,
return ret;
}
+static int
+mlx5dr_action_handle_ipv6_routing_pop(struct mlx5dr_context *ctx,
+ struct mlx5dr_action *action)
+{
+ uint8_t mh_data[MLX5DR_ACTION_REFORMAT_DATA_SIZE] = {0};
+ void *dev = flow_hw_get_dev_from_ctx(ctx);
+ int mh_data_size, ret;
+ uint8_t *srv6_data;
+ uint8_t anchor_id;
+
+ if (dev == NULL) {
+ DR_LOG(ERR, "Invalid dev handle for IPv6 routing pop\n");
+ return -1;
+ }
+ ret = flow_dv_ipv6_routing_pop_mhdr_cmd(dev, mh_data, &anchor_id);
+ if (ret < 0) {
+ DR_LOG(ERR, "Failed to generate modify-header pattern for IPv6 routing pop\n");
+ return -1;
+ }
+ srv6_data = mh_data + MLX5DR_MODIFY_ACTION_SIZE * ret;
+ /* Remove SRv6 headers */
+ MLX5_SET(stc_ste_param_remove, srv6_data, action_type,
+ MLX5_MODIFICATION_TYPE_REMOVE);
+ MLX5_SET(stc_ste_param_remove, srv6_data, decap, 0x1);
+ MLX5_SET(stc_ste_param_remove, srv6_data, remove_start_anchor, anchor_id);
+ MLX5_SET(stc_ste_param_remove, srv6_data, remove_end_anchor,
+ MLX5_HEADER_ANCHOR_TCP_UDP);
+ mh_data_size = (ret + 1) * MLX5DR_MODIFY_ACTION_SIZE;
+
+ ret = mlx5dr_pat_arg_create_modify_header(ctx, action, mh_data_size,
+ (__be64 *)mh_data, 0);
+ if (ret) {
+ DR_LOG(ERR, "Failed allocating modify-header for IPv6 routing pop\n");
+ return ret;
+ }
+
+ ret = mlx5dr_action_create_stcs(action, NULL);
+ if (ret)
+ goto free_mh_obj;
+
+ ret = mlx5dr_arg_write_inline_arg_data(ctx,
+ action->modify_header.arg_obj->id,
+ mh_data, mh_data_size);
+ if (ret) {
+ DR_LOG(ERR, "Failed writing INLINE arg IPv6 routing pop");
+ goto clean_stc;
+ }
+
+ return 0;
+
+clean_stc:
+ mlx5dr_action_destroy_stcs(action);
+free_mh_obj:
+ mlx5dr_pat_arg_destroy_modify_header(ctx, action);
+ return ret;
+}
+
+static int mlx5dr_action_handle_ipv6_routing_push(struct mlx5dr_context *ctx,
+ size_t data_sz,
+ void *data,
+ uint32_t bulk_size,
+ struct mlx5dr_action *action)
+{
+ 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 ipv6 routing push");
+ return ret;
+ }
+
+ ret = mlx5dr_action_create_stcs(action, NULL);
+ if (ret) {
+ DR_LOG(ERR, "Failed to create stc for ipv6 routing push");
+ goto free_arg;
+ }
+
+ return 0;
+
+free_arg:
+ mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
+ return ret;
+}
+
static int
mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx,
size_t data_sz,
@@ -1484,6 +1590,78 @@ mlx5dr_action_create_reformat_hws(struct mlx5dr_context *ctx,
return ret;
}
+static int
+mlx5dr_action_create_push_pop_hws(struct mlx5dr_context *ctx,
+ size_t data_sz,
+ void *data,
+ uint32_t bulk_size,
+ struct mlx5dr_action *action)
+{
+ int ret;
+
+ switch (action->type) {
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_POP:
+ ret = mlx5dr_action_handle_ipv6_routing_pop(ctx, action);
+ break;
+
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH:
+ *((uint8_t *)data) = 0;
+ ret = mlx5dr_action_handle_ipv6_routing_push(ctx, data_sz, data,
+ bulk_size, action);
+ break;
+
+ default:
+ assert(false);
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ return ret;
+}
+
+static struct mlx5dr_action *
+mlx5dr_action_create_push_pop(struct mlx5dr_context *ctx,
+ enum mlx5dr_action_type action_type,
+ size_t data_sz,
+ void *inline_data,
+ uint32_t log_bulk_size,
+ uint32_t flags)
+{
+ struct mlx5dr_action *action;
+ int ret;
+
+ action = mlx5dr_action_create_generic(ctx, flags, action_type);
+ if (!action)
+ return NULL;
+
+ if (mlx5dr_action_is_root_flags(flags)) {
+ DR_LOG(ERR, "IPv6 routing push/pop is not supported over root");
+ rte_errno = ENOTSUP;
+ goto free_action;
+ }
+
+ if (!mlx5dr_action_is_hws_flags(flags) ||
+ ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
+ DR_LOG(ERR, "Push/pop flags don't fit HWS (flags: %x)\n", flags);
+ rte_errno = EINVAL;
+ goto free_action;
+ }
+
+ ret = mlx5dr_action_create_push_pop_hws(ctx, data_sz, inline_data,
+ log_bulk_size, action);
+ if (ret) {
+ DR_LOG(ERR, "Failed to create push/pop HWS.\n");
+ rte_errno = EINVAL;
+ goto free_action;
+ }
+
+ return action;
+
+free_action:
+ simple_free(action);
+ return NULL;
+}
+
struct mlx5dr_action *
mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
enum mlx5dr_action_reformat_type reformat_type,
@@ -1540,6 +1718,169 @@ mlx5dr_action_create_reformat(struct mlx5dr_context *ctx,
return NULL;
}
+static int
+mlx5dr_action_create_recom_hws(struct mlx5dr_context *ctx,
+ size_t data_sz,
+ void *data,
+ uint32_t bulk_size,
+ struct mlx5dr_action *action)
+{
+ struct mlx5_modification_cmd cmd[MLX5_MHDR_MAX_CMD];
+ void *eth_dev = flow_hw_get_dev_from_ctx(ctx);
+ struct mlx5dr_action *sub_action;
+ int ret;
+
+ if (eth_dev == NULL) {
+ DR_LOG(ERR, "Invalid dev handle for recombination action");
+ rte_errno = EINVAL;
+ return rte_errno;
+ }
+ memset(cmd, 0, sizeof(cmd));
+ switch (action->type) {
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_POP:
+ ret = flow_dv_generate_ipv6_routing_pop_mhdr1(eth_dev, NULL,
+ cmd, MLX5_MHDR_MAX_CMD);
+ if (ret < 0) {
+ DR_LOG(ERR, "Failed to generate IPv6 routing pop action1 pattern");
+ rte_errno = EINVAL;
+ return rte_errno;
+ }
+ sub_action = mlx5dr_action_create_modify_header(ctx,
+ sizeof(struct mlx5_modification_cmd) * ret,
+ (__be64 *)cmd, 0, action->flags);
+ if (!sub_action) {
+ DR_LOG(ERR, "Failed to create IPv6 routing pop action1");
+ rte_errno = EINVAL;
+ return rte_errno;
+ }
+ action->recom.action1 = sub_action;
+ memset(cmd, 0, sizeof(struct mlx5_modification_cmd) * MLX5_MHDR_MAX_CMD);
+ ret = flow_dv_generate_ipv6_routing_pop_mhdr2(eth_dev, NULL,
+ cmd, MLX5_MHDR_MAX_CMD);
+ if (ret < 0) {
+ DR_LOG(ERR, "Failed to generate IPv6 routing pop action2 pattern");
+ goto err;
+ }
+ sub_action = mlx5dr_action_create_modify_header(ctx,
+ sizeof(struct mlx5_modification_cmd) * ret,
+ (__be64 *)cmd, 0, action->flags);
+ if (!sub_action) {
+ DR_LOG(ERR, "Failed to create IPv6 routing pop action2");
+ goto err;
+ }
+ action->recom.action2 = sub_action;
+ sub_action = mlx5dr_action_create_push_pop(ctx,
+ MLX5DR_ACTION_TYP_IPV6_ROUTING_POP,
+ data_sz, data, bulk_size, action->flags);
+ if (!sub_action) {
+ DR_LOG(ERR, "Failed to create IPv6 routing pop action3");
+ goto err;
+ }
+ action->recom.action3 = sub_action;
+ break;
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH:
+ ret = flow_dv_generate_ipv6_routing_push_mhdr1(eth_dev, NULL,
+ cmd, MLX5_MHDR_MAX_CMD);
+ if (ret < 0) {
+ DR_LOG(ERR, "Failed to generate IPv6 routing push action2 pattern");
+ rte_errno = EINVAL;
+ return rte_errno;
+ }
+ sub_action = mlx5dr_action_create_modify_header(ctx,
+ sizeof(struct mlx5_modification_cmd) * ret,
+ (__be64 *)cmd, 0, action->flags | MLX5DR_ACTION_FLAG_SHARED);
+ if (!sub_action) {
+ DR_LOG(ERR, "Failed to create IPv6 routing push action2");
+ rte_errno = EINVAL;
+ return rte_errno;
+ }
+ action->recom.action2 = sub_action;
+ memset(cmd, 0, sizeof(struct mlx5_modification_cmd) * MLX5_MHDR_MAX_CMD);
+ ret = flow_dv_generate_ipv6_routing_push_mhdr2(eth_dev, NULL, cmd,
+ MLX5_MHDR_MAX_CMD, data);
+ if (ret < 0) {
+ DR_LOG(ERR, "Failed to generate IPv6 routing push action3 pattern");
+ goto err;
+ }
+ sub_action = mlx5dr_action_create_modify_header(ctx,
+ sizeof(struct mlx5_modification_cmd) * ret,
+ (__be64 *)cmd, bulk_size, action->flags);
+ if (!sub_action) {
+ DR_LOG(ERR, "Failed to create IPv6 routing push action3");
+ goto err;
+ }
+ action->recom.action3 = sub_action;
+ sub_action = mlx5dr_action_create_push_pop(ctx,
+ MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH,
+ data_sz, data, bulk_size, action->flags);
+ if (!sub_action) {
+ DR_LOG(ERR, "Failed to create IPv6 routing push action1");
+ goto err;
+ }
+ action->recom.action1 = sub_action;
+ break;
+ default:
+ assert(false);
+ rte_errno = ENOTSUP;
+ return rte_errno;
+ }
+
+ return 0;
+
+err:
+ if (action->recom.action1)
+ mlx5dr_action_destroy(action->recom.action1);
+ if (action->recom.action2)
+ mlx5dr_action_destroy(action->recom.action2);
+ if (action->recom.action3)
+ mlx5dr_action_destroy(action->recom.action3);
+ rte_errno = EINVAL;
+ return rte_errno;
+}
+
+struct mlx5dr_action *
+mlx5dr_action_create_recombination(struct mlx5dr_context *ctx,
+ enum mlx5dr_action_type action_type,
+ size_t data_sz,
+ void *inline_data,
+ uint32_t log_bulk_size,
+ uint32_t flags)
+{
+ struct mlx5dr_action *action;
+ int ret;
+
+ action = mlx5dr_action_create_generic(ctx, flags, action_type);
+ if (!action)
+ return NULL;
+
+ if (!mlx5dr_action_is_hws_flags(flags) ||
+ ((flags & MLX5DR_ACTION_FLAG_SHARED) && log_bulk_size)) {
+ DR_LOG(ERR, "Recom flags don't fit HWS (flags: %x)\n", flags);
+ rte_errno = EINVAL;
+ goto free_action;
+ }
+
+ if (action_type == MLX5DR_ACTION_TYP_IPV6_ROUTING_POP && log_bulk_size) {
+ DR_LOG(ERR, "IPv6 POP must be shared");
+ rte_errno = EINVAL;
+ goto free_action;
+ }
+
+ ret = mlx5dr_action_create_recom_hws(ctx, data_sz, inline_data,
+ log_bulk_size, action);
+ if (ret) {
+ DR_LOG(ERR, "Failed to create recombination.\n");
+ rte_errno = EINVAL;
+ goto free_action;
+ }
+
+ return action;
+
+free_action:
+ simple_free(action);
+ return NULL;
+}
+
static int
mlx5dr_action_create_modify_header_root(struct mlx5dr_action *action,
size_t actions_sz,
@@ -1677,6 +2018,43 @@ static void mlx5dr_action_destroy_hws(struct mlx5dr_action *action)
mlx5dr_action_destroy_stcs(action);
mlx5dr_cmd_destroy_obj(action->reformat.arg_obj);
break;
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_POP:
+ if (action->recom.action1) {
+ mlx5dr_action_destroy_stcs(action->recom.action1);
+ mlx5dr_pat_arg_destroy_modify_header(action->recom.action1->ctx,
+ action->recom.action1);
+ simple_free(action->recom.action1);
+ }
+ if (action->recom.action2) {
+ mlx5dr_action_destroy_stcs(action->recom.action2);
+ mlx5dr_pat_arg_destroy_modify_header(action->recom.action2->ctx,
+ action->recom.action2);
+ simple_free(action->recom.action2);
+ }
+ if (action->recom.action3) {
+ mlx5dr_action_destroy_stcs(action->recom.action3);
+ mlx5dr_pat_arg_destroy_modify_header(action->recom.action3->ctx,
+ action->recom.action3);
+ simple_free(action->recom.action3);
+ }
+ break;
+ case MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH:
+ if (action->recom.action1) {
+ mlx5dr_action_destroy_stcs(action->recom.action1);
+ mlx5dr_cmd_destroy_obj(action->recom.action1->reformat.arg_obj);
+ simple_free(action->recom.action1);
+ }
+ if (action->recom.action2) {
+ mlx5dr_action_destroy_stcs(action->recom.action2);
+ simple_free(action->recom.action2);
+ }
+ if (action->recom.action3) {
+ mlx5dr_action_destroy_stcs(action->recom.action3);
+ mlx5dr_pat_arg_destroy_modify_header(action->recom.action3->ctx,
+ action->recom.action3);
+ simple_free(action->recom.action3);
+ }
+ break;
}
}
@@ -130,6 +130,11 @@ struct mlx5dr_action {
struct mlx5dr_devx_obj *arg_obj;
uint32_t header_size;
} reformat;
+ struct {
+ struct mlx5dr_action *action1;
+ struct mlx5dr_action *action2;
+ struct mlx5dr_action *action3;
+ } recom;
struct {
struct mlx5dr_devx_obj *devx_obj;
uint8_t return_reg_id;
@@ -22,6 +22,8 @@ const char *mlx5dr_debug_action_type_str[] = {
[MLX5DR_ACTION_TYP_PUSH_VLAN] = "PUSH_VLAN",
[MLX5DR_ACTION_TYP_ASO_METER] = "ASO_METER",
[MLX5DR_ACTION_TYP_ASO_CT] = "ASO_CT",
+ [MLX5DR_ACTION_TYP_IPV6_ROUTING_POP] = "POP_IPV6_ROUTING",
+ [MLX5DR_ACTION_TYP_IPV6_ROUTING_PUSH] = "PUSH_IPV6_ROUTING",
};
static_assert(ARRAY_SIZE(mlx5dr_debug_action_type_str) == MLX5DR_ACTION_TYP_MAX,