DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH] net/cpfl: support action prog
@ 2023-10-27  9:42 wenjing.qiao
  2023-10-30  2:13 ` [PATCH v2] " wenjing.qiao
  0 siblings, 1 reply; 6+ messages in thread
From: wenjing.qiao @ 2023-10-27  9:42 UTC (permalink / raw)
  To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao

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>
---
Depends-on: series-30022 ("ethdev: fix flow API support for P4-programmable devices")
---
 drivers/net/cpfl/cpfl_flow_engine_fxp.c |   2 +
 drivers/net/cpfl/cpfl_flow_parser.c     | 268 ++++++++++++++++++++++--
 drivers/net/cpfl/cpfl_flow_parser.h     |  62 +++++-
 3 files changed, 308 insertions(+), 24 deletions(-)

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..9e3f55fe1c 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.c
+++ b/drivers/net/cpfl/cpfl_flow_parser.c
@@ -5,6 +5,7 @@
 #include <arpa/inet.h>
 
 #include "cpfl_flow_parser.h"
+#include "rte_flow.h"
 
 static enum rte_flow_item_type
 cpfl_get_item_type_by_str(const char *type)
@@ -35,6 +36,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 +615,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;
+			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;
+				}
+				memcpy(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;
+					}
+					memcpy(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 +688,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 +729,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;
+		}
+		memcpy(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 +817,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 +834,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 +990,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 +1671,40 @@ 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;
+			memcpy(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 +1736,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 +1759,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 +1787,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 +1797,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 +1811,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 +1860,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 +1915,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 +1938,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 +1963,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 +1972,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..ff04813994 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_FLOW_PROG_CONTENT_FIELD_NUM 64
+#define CPFL_FLOW_PROG_CONSTANT_VALUE_NUM 8
+#define CPFL_FLOW_PROG_PARAM_NUM 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_FLOW_PROG_PARAM_NUM];
+};
+
 /* 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_FLOW_PROG_CONSTANT_VALUE_NUM];
+	};
+};
+
+struct cpfl_flow_js_mr_content {
+	uint16_t size;
+	struct cpfl_flow_js_mr_field fields[CPFL_FLOW_PROG_CONTENT_FIELD_NUM];
+	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_FLOW_PROG_PARAM_NUM][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 {
-- 
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2] net/cpfl: support action prog
  2023-10-27  9:42 [PATCH] net/cpfl: support action prog wenjing.qiao
@ 2023-10-30  2:13 ` wenjing.qiao
  2023-10-31  7:48   ` [PATCH v3] " wenjing.qiao
  0 siblings, 1 reply; 6+ messages in thread
From: wenjing.qiao @ 2023-10-30  2:13 UTC (permalink / raw)
  To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao

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     | 268 ++++++++++++++++++++++--
 drivers/net/cpfl/cpfl_flow_parser.h     |  62 +++++-
 3 files changed, 308 insertions(+), 24 deletions(-)

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..7df66ab7ec 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.c
+++ b/drivers/net/cpfl/cpfl_flow_parser.c
@@ -5,6 +5,7 @@
 #include <arpa/inet.h>
 
 #include "cpfl_flow_parser.h"
+#include "rte_flow.h"
 
 static enum rte_flow_item_type
 cpfl_get_item_type_by_str(const char *type)
@@ -35,6 +36,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 +615,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;
+				}
+				memcpy(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;
+					}
+					memcpy(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 +688,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 +729,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;
+		}
+		memcpy(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 +817,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 +834,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 +990,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 +1671,40 @@ 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;
+			memcpy(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 +1736,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 +1759,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 +1787,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 +1797,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 +1811,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 +1860,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 +1915,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 +1938,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 +1963,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 +1972,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..ff04813994 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_FLOW_PROG_CONTENT_FIELD_NUM 64
+#define CPFL_FLOW_PROG_CONSTANT_VALUE_NUM 8
+#define CPFL_FLOW_PROG_PARAM_NUM 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_FLOW_PROG_PARAM_NUM];
+};
+
 /* 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_FLOW_PROG_CONSTANT_VALUE_NUM];
+	};
+};
+
+struct cpfl_flow_js_mr_content {
+	uint16_t size;
+	struct cpfl_flow_js_mr_field fields[CPFL_FLOW_PROG_CONTENT_FIELD_NUM];
+	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_FLOW_PROG_PARAM_NUM][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 {
-- 
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v3] net/cpfl: support action prog
  2023-10-30  2:13 ` [PATCH v2] " wenjing.qiao
@ 2023-10-31  7:48   ` wenjing.qiao
  2023-10-31  8:12     ` Zhang, Qi Z
  2023-11-02  8:50     ` [PATCH v4] " wenjing.qiao
  0 siblings, 2 replies; 6+ messages in thread
From: wenjing.qiao @ 2023-10-31  7:48 UTC (permalink / raw)
  To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao

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(-)

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 {
-- 
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH v3] net/cpfl: support action prog
  2023-10-31  7:48   ` [PATCH v3] " wenjing.qiao
@ 2023-10-31  8:12     ` Zhang, Qi Z
  2023-11-02  8:50     ` [PATCH v4] " wenjing.qiao
  1 sibling, 0 replies; 6+ messages in thread
From: Zhang, Qi Z @ 2023-10-31  8:12 UTC (permalink / raw)
  To: Qiao, Wenjing, Wu, Jingjing, Xing, Beilei; +Cc: dev



> -----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.



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v4] net/cpfl: support action prog
  2023-10-31  7:48   ` [PATCH v3] " wenjing.qiao
  2023-10-31  8:12     ` Zhang, Qi Z
@ 2023-11-02  8:50     ` wenjing.qiao
  2023-11-06  1:50       ` Zhang, Qi Z
  1 sibling, 1 reply; 6+ messages in thread
From: wenjing.qiao @ 2023-11-02  8:50 UTC (permalink / raw)
  To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao

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>
---
v4:
- fix compile issues.
- update [rte_flow actions] in icpf.ini.

v3:
- use strncpy instead of memcpy for string copy.
- refactor the coding style.

v2:
- fix compile issues.

 doc/guides/nics/features/cpfl.ini       |   1 +
 drivers/net/cpfl/cpfl_flow_engine_fxp.c |   2 +
 drivers/net/cpfl/cpfl_flow_parser.c     | 268 ++++++++++++++++++++++--
 drivers/net/cpfl/cpfl_flow_parser.h     |  62 +++++-
 4 files changed, 309 insertions(+), 24 deletions(-)

diff --git a/doc/guides/nics/features/cpfl.ini b/doc/guides/nics/features/cpfl.ini
index 9563267513..babec2ccab 100644
--- a/doc/guides/nics/features/cpfl.ini
+++ b/doc/guides/nics/features/cpfl.ini
@@ -43,3 +43,4 @@ represented_port     = Y
 rss                  = Y
 vxlan_decap          = Y
 vxlan_encap          = Y
+prog                 = Y
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..1e0ba289c2 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,58 @@ 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,
+					CPFL_FLOW_JSON_STR_SIZE_MAX - 1);
+			}
+
+			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,
+						CPFL_FLOW_JSON_STR_SIZE_MAX - 1);
+				}
+				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 +688,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 +729,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, CPFL_FLOW_JSON_STR_SIZE_MAX - 1);
+		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 +817,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 +834,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 +990,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 +1671,40 @@ 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,
+				CPFL_FLOW_JSON_STR_SIZE_MAX - 1);
+		}
+	}
+
+	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 +1736,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 +1759,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 +1787,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 +1797,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 +1811,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 +1860,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 +1915,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 +1938,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 +1963,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 +1972,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 {
-- 
2.34.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* RE: [PATCH v4] net/cpfl: support action prog
  2023-11-02  8:50     ` [PATCH v4] " wenjing.qiao
@ 2023-11-06  1:50       ` Zhang, Qi Z
  0 siblings, 0 replies; 6+ messages in thread
From: Zhang, Qi Z @ 2023-11-06  1:50 UTC (permalink / raw)
  To: Qiao, Wenjing, Wu, Jingjing, Xing, Beilei; +Cc: dev



> -----Original Message-----
> From: Qiao, Wenjing <wenjing.qiao@intel.com>
> Sent: Thursday, November 2, 2023 4:51 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 v4] net/cpfl: support action prog
> 
> 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>

Acked-by: Qi Zhang <qi.z.zhang@intel.com> 

The CI build error in patchwork is covered by below fix
https://patchwork.dpdk.org/project/dpdk/patch/20231106091453.1599496-1-qi.z.zhang@intel.com/

Applied to dpdk-next-net-intel.

Thanks
Qi



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-11-06  1:50 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-27  9:42 [PATCH] net/cpfl: support action prog wenjing.qiao
2023-10-30  2:13 ` [PATCH v2] " wenjing.qiao
2023-10-31  7:48   ` [PATCH v3] " wenjing.qiao
2023-10-31  8:12     ` Zhang, Qi Z
2023-11-02  8:50     ` [PATCH v4] " wenjing.qiao
2023-11-06  1:50       ` Zhang, Qi Z

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).