[v3] net/cpfl: support action prog

Message ID 20231031074816.2391599-1-wenjing.qiao@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Qi Zhang
Headers
Series [v3] net/cpfl: support action prog |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/loongarch-compilation success Compilation OK
ci/loongarch-unit-testing success Unit Testing PASS
ci/Intel-compilation fail Compilation issues
ci/intel-Testing success Testing PASS
ci/intel-Functional success Functional PASS
ci/github-robot: build fail github build: failed
ci/iol-intel-Performance success Performance Testing PASS
ci/iol-broadcom-Performance success Performance Testing PASS
ci/iol-mellanox-Performance success Performance Testing PASS
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-broadcom-Functional success Functional Testing PASS
ci/iol-unit-amd64-testing fail Testing issues
ci/iol-compile-amd64-testing fail Testing issues
ci/iol-unit-arm64-testing fail Testing issues
ci/iol-sample-apps-testing warning Testing issues
ci/iol-compile-arm64-testing fail Testing issues

Commit Message

Wenjing Qiao Oct. 31, 2023, 7:48 a.m. UTC
  From: Wenjing Qiao <wenjing.qiao@intel.com>

Parse JSON file and generate rules that instruct PMD to map an
RTE_FLOW_ACTION_TYPE_PROG to a low-level FXP representation, the
matching follows below guidelines.

Use rte_flow_action_prog->name to match the name of a P4 action
type when provided in the JSON file. In cases where the JSON file
lacks the P4 action type's name but includes the P4 action type ID,
PMD should attempt to convert rte_flow_action_prog->name into a
uint32 value and then match it to the P4 action type ID.

The same method applies when matching a rte_flow_action_prog_argument
to a field of an action type.

Here's an example to create a rule that matches an IPV4/TCP header and
applies a VXLAN encapsulation which is represented by rte_flow_action_prog:

flow create 0 ingress pattern eth src is 00:11:22:33:44:55 dst is
00:01:00:00:03:14 / ipv4 src is 192.168.0.1 dst is 192.168.0.2 / tcp src
is 0x1451 dst is 0x157c / end actions prog name vxlan_encap arguments
src_addr 0xC0A80002 dst_addr 0xC0A80003 src_mac 0x000100000314
dst_mac 0x000600000314 src_port 0x1234 dst_port 0x4789 vni 0x000050
end / port_representor port_id 0 / end

Signed-off-by: Wenjing Qiao <wenjing.qiao@intel.com>
---
 drivers/net/cpfl/cpfl_flow_engine_fxp.c |   2 +
 drivers/net/cpfl/cpfl_flow_parser.c     | 266 ++++++++++++++++++++++--
 drivers/net/cpfl/cpfl_flow_parser.h     |  62 +++++-
 3 files changed, 306 insertions(+), 24 deletions(-)
  

Comments

Qi Zhang Oct. 31, 2023, 8:12 a.m. UTC | #1
> -----Original Message-----
> From: Qiao, Wenjing <wenjing.qiao@intel.com>
> Sent: Tuesday, October 31, 2023 3:48 PM
> To: Wu, Jingjing <jingjing.wu@intel.com>; Xing, Beilei <beilei.xing@intel.com>;
> Zhang, Qi Z <qi.z.zhang@intel.com>
> Cc: dev@dpdk.org; Qiao, Wenjing <wenjing.qiao@intel.com>
> Subject: [PATCH v3] net/cpfl: support action prog
> 

Support new rte_flow action need to update [rte_flow actions] in icpf.ini.

Btw, please always add change log in each version.
  

Patch

diff --git a/drivers/net/cpfl/cpfl_flow_engine_fxp.c b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
index ddede2f553..6b0830afd0 100644
--- a/drivers/net/cpfl/cpfl_flow_engine_fxp.c
+++ b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
@@ -373,6 +373,7 @@  cpfl_fxp_parse_action(struct cpfl_itf *itf,
 			break;
 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+		case RTE_FLOW_ACTION_TYPE_PROG:
 			break;
 		case RTE_FLOW_ACTION_TYPE_VOID:
 			break;
@@ -425,6 +426,7 @@  cpfl_is_mod_action(const struct rte_flow_action actions[])
 		switch (action_type) {
 		case RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP:
 		case RTE_FLOW_ACTION_TYPE_VXLAN_DECAP:
+		case RTE_FLOW_ACTION_TYPE_PROG:
 			return true;
 		default:
 			continue;
diff --git a/drivers/net/cpfl/cpfl_flow_parser.c b/drivers/net/cpfl/cpfl_flow_parser.c
index 412f7feed0..90034458e1 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.c
+++ b/drivers/net/cpfl/cpfl_flow_parser.c
@@ -35,6 +35,8 @@  cpfl_get_action_type_by_str(const char *type)
 		return RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP;
 	else if (strcmp(type, "vxlan_decap") == 0)
 		return RTE_FLOW_ACTION_TYPE_VXLAN_DECAP;
+	else if (strcmp(type, "prog") == 0)
+		return RTE_FLOW_ACTION_TYPE_PROG;
 
 	PMD_DRV_LOG(ERR, "Not support this type: %s.", type);
 	return RTE_FLOW_ACTION_TYPE_VOID;
@@ -612,6 +614,57 @@  cpfl_flow_js_mr_key(json_t *ob_mr_keys, struct cpfl_flow_js_mr_key *js_mr_key)
 				}
 				encap->protocols[j] = proto_type;
 			}
+		} else if (js_mr_key->actions[i].type == RTE_FLOW_ACTION_TYPE_PROG) {
+			int ret;
+			uint32_t param_size, j;
+			uint16_t value = 0;
+			json_t *ob_param, *subobject;
+			const char *name;
+
+			ret = cpfl_json_t_to_uint32(object, "id", &js_mr_key->actions[i].prog.id);
+			if (ret < 0) {
+				PMD_DRV_LOG(ERR, "Can not parse uint32 'id'.");
+				goto err;
+			}
+			if (json_object_get(object, "name")) {
+				js_mr_key->actions[i].prog.has_name = TRUE;
+				name = cpfl_json_t_to_string(object, "name");
+				if (!name) {
+					PMD_DRV_LOG(ERR, "Can not parse string 'name'.");
+					goto err;
+				}
+				strncpy(js_mr_key->actions[i].prog.name, name, strlen(name));
+			}
+
+			ob_param = json_object_get(object, "parameters");
+			param_size = json_array_size(ob_param);
+			js_mr_key->actions[i].prog.param_size = param_size;
+			for (j = 0; j < param_size; j++) {
+				subobject = json_array_get(ob_param, j);
+				ret = cpfl_json_t_to_uint16(subobject, "index", &value);
+				if (ret < 0) {
+					PMD_DRV_LOG(ERR, "Can not parse 'index'.");
+					goto err;
+				}
+				js_mr_key->actions[i].prog.params[j].index = value;
+				if (json_object_get(subobject, "name")) {
+					js_mr_key->actions[i].prog.params[j].has_name = TRUE;
+					name = cpfl_json_t_to_string(subobject, "name");
+					if (!name) {
+						PMD_DRV_LOG(ERR, "Can not parse string 'name'.");
+						goto err;
+					}
+					strncpy(js_mr_key->actions[i].prog.params[j].name, name,
+						strlen(name));
+				}
+				ret = cpfl_json_t_to_uint16(subobject, "size", &value);
+				if (ret < 0) {
+					PMD_DRV_LOG(ERR, "Can not parse 'size'.");
+					goto err;
+				}
+				js_mr_key->actions[i].prog.params[j].size = value;
+			}
+
 		} else if (js_mr_key->actions[i].type != RTE_FLOW_ACTION_TYPE_VXLAN_DECAP) {
 			PMD_DRV_LOG(ERR, "not support this type: %d.", js_mr_key->actions[i].type);
 			goto err;
@@ -634,11 +687,6 @@  cpfl_flow_js_mr_layout(json_t *ob_layouts, struct cpfl_flow_js_mr_action_mod *js
 	js_mod->layout_size = len;
 	if (len == 0)
 		return 0;
-	js_mod->layout = rte_malloc(NULL, sizeof(struct cpfl_flow_js_mr_layout) * len, 0);
-	if (!js_mod->layout) {
-		PMD_DRV_LOG(ERR, "Failed to alloc memory.");
-		return -ENOMEM;
-	}
 
 	for (i = 0; i < len; i++) {
 		json_t *object;
@@ -680,6 +728,79 @@  cpfl_flow_js_mr_layout(json_t *ob_layouts, struct cpfl_flow_js_mr_action_mod *js
 	return -EINVAL;
 }
 
+static int
+cpfl_flow_js_mr_content(json_t *ob_content, struct cpfl_flow_js_mr_action_mod *js_mod)
+{
+	int ret, len, i;
+	json_t *ob_field;
+
+	if (!ob_content)
+		return 0;
+
+	js_mod->is_content = TRUE;
+	ret = cpfl_json_t_to_uint16(ob_content, "size", &js_mod->content.size);
+	if (ret < 0) {
+		PMD_DRV_LOG(ERR, "Can not parse 'size'.");
+		return -EINVAL;
+	}
+
+	ob_field = json_object_get(ob_content, "fields");
+	len = json_array_size(ob_field);
+	js_mod->content.field_size = len;
+	if (len == 0)
+		return 0;
+
+	for (i = 0; i < len; i++) {
+		json_t *object;
+		uint16_t start = 0, width = 0, index = 0;
+		const char *type;
+
+		object = json_array_get(ob_field, i);
+		type = cpfl_json_t_to_string(object, "type");
+		if (!type) {
+			PMD_DRV_LOG(ERR, "Can not parse string 'type'.");
+			goto err;
+		}
+		strncpy(js_mod->content.fields[i].type, type, strlen(type));
+		ret = cpfl_json_t_to_uint16(object, "start", &start);
+		if (ret < 0) {
+			PMD_DRV_LOG(ERR, "Can not parse 'start'.");
+			goto err;
+		}
+		js_mod->content.fields[i].start = start;
+		ret = cpfl_json_t_to_uint16(object, "width", &width);
+		if (ret < 0) {
+			PMD_DRV_LOG(ERR, "Can not parse 'width'.");
+			goto err;
+		}
+		js_mod->content.fields[i].width = width;
+		if (strcmp(type, "parameter") == 0) {
+			ret = cpfl_json_t_to_uint16(object, "index", &index);
+			if (ret < 0) {
+				PMD_DRV_LOG(ERR, "Can not parse 'index'.");
+				goto err;
+			}
+			js_mod->content.fields[i].index = index;
+		} else if (strcmp(type, "constant") == 0) {
+			json_t *ob_value, *subobj;
+			int value_len, j;
+
+			ob_value = json_object_get(object, "value");
+			value_len = json_array_size(ob_value);
+			for (j = 0; j < value_len; j++) {
+				subobj = json_array_get(ob_value, j);
+				js_mod->content.fields[i].value[j] =
+				    (uint8_t)json_integer_value(subobj);
+			}
+		}
+	}
+
+	return 0;
+
+err:
+	return -EINVAL;
+}
+
 static int
 cpfl_flow_js_mr_action(json_t *ob_mr_act, struct cpfl_flow_js_mr_action *js_mr_act)
 {
@@ -695,7 +816,7 @@  cpfl_flow_js_mr_action(json_t *ob_mr_act, struct cpfl_flow_js_mr_action *js_mr_a
 	/* mr->action->data */
 	ob_data = json_object_get(ob_mr_act, "data");
 	if (strcmp(type, "mod") == 0) {
-		json_t *ob_layouts;
+		json_t *ob_layouts, *ob_content;
 		uint16_t profile = 0;
 		int ret;
 
@@ -712,6 +833,12 @@  cpfl_flow_js_mr_action(json_t *ob_mr_act, struct cpfl_flow_js_mr_action *js_mr_a
 			PMD_DRV_LOG(ERR, "Can not parse layout.");
 			return ret;
 		}
+		ob_content = json_object_get(ob_data, "content");
+		ret = cpfl_flow_js_mr_content(ob_content, &js_mr_act->mod);
+		if (ret < 0) {
+			PMD_DRV_LOG(ERR, "Can not parse 'content'.");
+			return ret;
+		}
 	} else  {
 		PMD_DRV_LOG(ERR, "not support this type: %s.", type);
 		return -EINVAL;
@@ -862,7 +989,6 @@  cpfl_parser_destroy(struct cpfl_flow_js_parser *parser)
 		struct cpfl_flow_js_mr *mr = &parser->modifications[i];
 
 		rte_free(mr->key.actions);
-		rte_free(mr->action.mod.layout);
 	}
 	rte_free(parser->modifications);
 	rte_free(parser);
@@ -1544,6 +1670,39 @@  cpfl_check_actions_vxlan_encap(struct cpfl_flow_mr_key_action_vxlan_encap *encap
 	return 0;
 }
 
+static int
+cpfl_parse_check_prog_action(struct cpfl_flow_js_mr_key_action *key_act,
+			     struct cpfl_flow_mr_key_action_prog *mr_key_prog,
+			     const struct rte_flow_action_prog *prog)
+{
+	uint32_t k;
+	bool check_name;
+
+	check_name = key_act->prog.has_name ? strcmp(prog->name, key_act->prog.name) == 0
+					    : atol(prog->name) == key_act->prog.id;
+	if (!check_name) {
+		PMD_DRV_LOG(ERR, "Not support this prog type: %s.", prog->name);
+		return -EINVAL;
+	}
+	if (key_act->prog.param_size != prog->args_num)
+		return -EINVAL;
+	for (k = 0; k < key_act->prog.param_size; k++) {
+		const struct rte_flow_action_prog_argument *arg = &prog->args[k];
+		struct cpfl_flow_js_prog_parameter *param = &key_act->prog.params[k];
+
+		check_name = param->has_name ? strcmp(arg->name, param->name) == 0
+					     : atoi(arg->name) == param->index;
+		if (!check_name || arg->size != param->size)
+			return -EINVAL;
+		if (param->has_name) {
+			mr_key_prog->has_name = TRUE;
+			strncpy(mr_key_prog->name[param->index], param->name, strlen(param->name));
+		}
+	}
+
+	return 0;
+}
+
 /* check and parse */
 static int
 cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
@@ -1575,9 +1734,9 @@  cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
 			}
 			if (j >= actions_length)
 				return -EINVAL;
-			mr_key_action[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP;
-			mr_key_action[i].encap.action = &actions[j];
-			encap = &mr_key_action[i].encap;
+			mr_key_action->mods[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP;
+			mr_key_action->mods[i].encap.action = &actions[j];
+			encap = &mr_key_action->mods[i].encap;
 
 			proto_size = key_act->encap.proto_size;
 			encap->proto_size = proto_size;
@@ -1598,8 +1757,22 @@  cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
 			}
 			if (j >= actions_length)
 				return -EINVAL;
-			mr_key_action[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_DECAP;
+			mr_key_action->mods[i].type = RTE_FLOW_ACTION_TYPE_VXLAN_DECAP;
 			j++;
+		} else if (type == RTE_FLOW_ACTION_TYPE_PROG) {
+			const struct rte_flow_action_prog *prog;
+
+			while (j < actions_length &&
+			       actions[j].type != RTE_FLOW_ACTION_TYPE_PROG) {
+				j++;
+			}
+			if (j >= actions_length)
+				return -EINVAL;
+			prog = actions[j].conf;
+			mr_key_action->prog.prog = prog;
+			ret = cpfl_parse_check_prog_action(key_act, &mr_key_action->prog, prog);
+			if (ret < 0)
+				return -EINVAL;
 		} else {
 			PMD_DRV_LOG(ERR, "Not support this type: %d.", type);
 			return -EPERM;
@@ -1612,7 +1785,7 @@  cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int size,
 /* output: uint8_t *buffer, uint16_t *byte_len */
 static int
 cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
-		  struct cpfl_flow_mr_key_action *mr_key_action,
+		  struct cpfl_flow_mr_key_mod *mods,
 		  uint8_t *buffer, uint16_t *byte_len)
 {
 	int i;
@@ -1622,7 +1795,7 @@  cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
 		int index, size, offset;
 		const char *hint;
 		const uint8_t *addr = NULL;
-		struct cpfl_flow_mr_key_action *temp;
+		struct cpfl_flow_mr_key_mod *temp;
 		struct cpfl_flow_js_mr_layout *layout;
 
 		layout = &layouts[i];
@@ -1636,7 +1809,7 @@  cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
 			continue;
 		}
 		hint = layout->hint;
-		temp = mr_key_action + index;
+		temp = mods + index;
 		if (temp->type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) {
 			const struct rte_flow_action_vxlan_encap *action_vxlan_encap;
 			struct rte_flow_item *definition;
@@ -1685,6 +1858,51 @@  cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size,
 	return 0;
 }
 
+static int
+cpfl_parse_content(struct cpfl_flow_js_mr_content *content,
+		   struct cpfl_flow_mr_key_action_prog *prog, uint8_t *buffer)
+{
+	int i, j;
+
+	for (i = 0; i < content->field_size; i++) {
+		uint16_t start, width, shift_bit;
+
+		start = content->fields[i].start / 8;
+		width = (content->fields[i].width + 7) / 8;
+		shift_bit = (8 - content->fields[i].start % 8 - content->fields[i].width % 8) % 8;
+
+		for (j = 0; j < width; j++) {
+			uint8_t old_value = 0;
+
+			if (strcmp(content->fields[i].type, "parameter") == 0) {
+				uint32_t k;
+				uint16_t index = content->fields[i].index;
+				const struct rte_flow_action_prog *act_prog = prog->prog;
+
+				for (k = 0; k < act_prog->args_num; k++) {
+					const char *name = act_prog->args[k].name;
+
+					if ((prog->has_name &&
+					     strcmp(prog->name[index], name) == 0) ||
+					    (!prog->has_name && atoi(name) == index)) {
+						old_value = act_prog->args[k].value[j];
+						break;
+					}
+				}
+				if (k == act_prog->args_num)
+					return -EINVAL;
+			} else if (strcmp(content->fields[i].type, "constant") == 0) {
+				old_value = content->fields[i].value[j];
+			} else {
+				return -EINVAL;
+			}
+			memset(buffer + start + j, buffer[start + j] | old_value << shift_bit, 1);
+		}
+	}
+
+	return 0;
+}
+
 static int
 cpfl_parse_mr_action(struct cpfl_flow_js_mr_action *action,
 		     struct cpfl_flow_mr_key_action *mr_key_action,
@@ -1695,6 +1913,18 @@  cpfl_parse_mr_action(struct cpfl_flow_js_mr_action *action,
 	/* mr->action->type */
 	type = action->type;
 	/* mr->action->data */
+	if (action->mod.is_content) {
+		struct cpfl_flow_js_mr_content *content = &action->mod.content;
+
+		mr_action->type = CPFL_JS_MR_ACTION_TYPE_MOD;
+		mr_action->mod.byte_len = 0;
+		mr_action->mod.prof = action->mod.prof;
+		mr_action->mod.byte_len = content->size;
+		memset(mr_action->mod.data, 0, sizeof(mr_action->mod.data));
+
+		return cpfl_parse_content(content, &mr_key_action->prog, mr_action->mod.data);
+	}
+
 	if (type == CPFL_JS_MR_ACTION_TYPE_MOD) {
 		struct cpfl_flow_js_mr_layout *layout;
 
@@ -1706,7 +1936,7 @@  cpfl_parse_mr_action(struct cpfl_flow_js_mr_action *action,
 			return 0;
 		memset(mr_action->mod.data, 0, sizeof(mr_action->mod.data));
 
-		return cpfl_parse_layout(layout, action->mod.layout_size, mr_key_action,
+		return cpfl_parse_layout(layout, action->mod.layout_size, mr_key_action->mods,
 					 mr_action->mod.data, &mr_action->mod.byte_len);
 	}
 	PMD_DRV_LOG(ERR, "Not support this type: %d.", type);
@@ -1731,7 +1961,7 @@  cpfl_parse_mod_rules(struct cpfl_flow_js_parser *parser, const struct rte_flow_a
 		     struct cpfl_flow_mr_action *mr_action)
 {
 	int i;
-	struct cpfl_flow_mr_key_action mr_key_action[CPFL_MOD_KEY_NUM_MAX] = {0};
+	struct cpfl_flow_mr_key_action mr_key_action = {0};
 
 	for (i = 0; i < parser->mr_size; i++) {
 		int ret;
@@ -1740,11 +1970,11 @@  cpfl_parse_mod_rules(struct cpfl_flow_js_parser *parser, const struct rte_flow_a
 		mr = &parser->modifications[i];
 		if (!mr)
 			return -EINVAL;
-		ret = cpfl_check_mod_key(mr, actions, mr_key_action);
+		ret = cpfl_check_mod_key(mr, actions, &mr_key_action);
 		if (ret < 0)
 			continue;
 		/* mr->action */
-		return cpfl_parse_mr_action(&mr->action, mr_key_action, mr_action);
+		return cpfl_parse_mr_action(&mr->action, &mr_key_action, mr_action);
 	}
 
 	return -EINVAL;
diff --git a/drivers/net/cpfl/cpfl_flow_parser.h b/drivers/net/cpfl/cpfl_flow_parser.h
index 962667adc2..c9a9772f13 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.h
+++ b/drivers/net/cpfl/cpfl_flow_parser.h
@@ -13,6 +13,9 @@ 
 #define CPFL_MAX_SEM_FV_KEY_SIZE 64
 #define CPFL_FLOW_JS_PROTO_SIZE 16
 #define CPFL_MOD_KEY_NUM_MAX 8
+#define CPFL_PROG_CONTENT_FIELD_NUM_MAX 64
+#define CPFL_PROG_CONSTANT_VALUE_NUM_MAX 8
+#define CPFL_PROG_PARAM_NUM_MAX 10
 
 /* Pattern Rules Storage */
 enum cpfl_flow_pr_action_type {
@@ -117,11 +120,27 @@  struct cpfl_flow_js_mr_key_action_vxlan_encap {
 	int proto_size;
 };
 
+struct cpfl_flow_js_prog_parameter {
+	bool has_name;
+	uint16_t index;
+	char name[CPFL_FLOW_JSON_STR_SIZE_MAX];
+	uint16_t size;
+};
+
+struct cpfl_flow_js_mr_key_action_prog {
+	bool has_name;
+	uint32_t id;
+	char name[CPFL_FLOW_JSON_STR_SIZE_MAX];
+	uint32_t param_size;
+	struct cpfl_flow_js_prog_parameter params[CPFL_PROG_PARAM_NUM_MAX];
+};
+
 /* A set of modification rte_flow_action_xxx objects can be defined as a type / data pair. */
 struct cpfl_flow_js_mr_key_action {
 	enum rte_flow_action_type type;
 	union {
 		struct cpfl_flow_js_mr_key_action_vxlan_encap encap;
+		struct cpfl_flow_js_mr_key_action_prog prog;
 	};
 };
 
@@ -137,6 +156,22 @@  struct cpfl_flow_js_mr_layout {
 	uint16_t size; /*  bytes of the data to be copied to the memory region */
 };
 
+struct cpfl_flow_js_mr_field {
+	char type[CPFL_FLOW_JSON_STR_SIZE_MAX];
+	uint16_t start;
+	uint16_t width;
+	union {
+		uint16_t index;
+		uint8_t value[CPFL_PROG_CONSTANT_VALUE_NUM_MAX];
+	};
+};
+
+struct cpfl_flow_js_mr_content {
+	uint16_t size;
+	struct cpfl_flow_js_mr_field fields[CPFL_PROG_CONTENT_FIELD_NUM_MAX];
+	int field_size;
+};
+
 /** For mod data, besides the profile ID, a layout array defines a set of hints that helps
  * driver composing the MOD memory region when the action need to insert/update some packet
  * data from user input.
@@ -144,8 +179,14 @@  struct cpfl_flow_js_mr_layout {
 struct cpfl_flow_js_mr_action_mod {
 	uint16_t prof;
 	uint16_t byte_len;
-	struct cpfl_flow_js_mr_layout *layout;
-	int layout_size;
+	bool is_content;
+	union {
+		struct {
+			struct cpfl_flow_js_mr_layout layout[CPFL_FLOW_JS_PROTO_SIZE];
+			int layout_size;
+		};
+		struct cpfl_flow_js_mr_content content;
+	};
 };
 
 enum cpfl_flow_mr_action_type {
@@ -203,11 +244,20 @@  struct cpfl_flow_mr_key_action_vxlan_encap {
 	const struct rte_flow_action *action;
 };
 
-struct cpfl_flow_mr_key_action {
+struct cpfl_flow_mr_key_action_prog {
+	const struct rte_flow_action_prog *prog;
+	bool has_name;
+	char name[CPFL_PROG_PARAM_NUM_MAX][CPFL_FLOW_JSON_STR_SIZE_MAX];
+};
+
+struct cpfl_flow_mr_key_mod {
 	enum rte_flow_action_type type;
-	union {
-		struct cpfl_flow_mr_key_action_vxlan_encap encap;
-	};
+	struct cpfl_flow_mr_key_action_vxlan_encap encap;
+};
+
+struct cpfl_flow_mr_key_action {
+	struct cpfl_flow_mr_key_mod mods[CPFL_MOD_KEY_NUM_MAX];
+	struct cpfl_flow_mr_key_action_prog prog;
 };
 
 struct cpfl_flow_mr_action_mod {