* [PATCH 0/2] net/cpfl: support flow offloading for P4
@ 2023-12-22 10:08 wenjing.qiao
2023-12-22 10:08 ` [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
2023-12-22 10:08 ` [PATCH " wenjing.qiao
0 siblings, 2 replies; 8+ messages in thread
From: wenjing.qiao @ 2023-12-22 10:08 UTC (permalink / raw)
To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao
From: Wenjing Qiao <wenjing.qiao@intel.com>
Enable TDI flow engine which can program hardware offloading rules
for a P4 programmable network controller.
Wenjing Qiao (2):
net/cpfl: parse flow offloading hint from P4 context file
net/cpfl: add TDI to flow engine
doc/guides/nics/cpfl.rst | 10 +
doc/guides/nics/features/cpfl.ini | 1 +
drivers/net/cpfl/cpfl_ethdev.h | 17 +-
drivers/net/cpfl/cpfl_flow.c | 13 +-
drivers/net/cpfl/cpfl_flow.h | 1 +
drivers/net/cpfl/cpfl_flow_engine_fxp.c | 21 +-
drivers/net/cpfl/cpfl_flow_parser.c | 68 +-
drivers/net/cpfl/cpfl_flow_parser.h | 2 +-
drivers/net/cpfl/cpfl_fxp_rule.h | 12 +
drivers/net/cpfl/cpfl_tdi.c | 1244 ++++++++++++++++
drivers/net/cpfl/cpfl_tdi.h | 123 ++
drivers/net/cpfl/cpfl_tdi_parser.c | 1715 +++++++++++++++++++++++
drivers/net/cpfl/cpfl_tdi_parser.h | 293 ++++
drivers/net/cpfl/meson.build | 2 +
14 files changed, 3488 insertions(+), 34 deletions(-)
create mode 100644 drivers/net/cpfl/cpfl_tdi.c
create mode 100644 drivers/net/cpfl/cpfl_tdi.h
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.c
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.h
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file
2023-12-22 10:08 [PATCH 0/2] net/cpfl: support flow offloading for P4 wenjing.qiao
@ 2023-12-22 10:08 ` wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 0/2] net/cpfl: support flow offloading for P4 wenjing.qiao
` (2 more replies)
2023-12-22 10:08 ` [PATCH " wenjing.qiao
1 sibling, 3 replies; 8+ messages in thread
From: wenjing.qiao @ 2023-12-22 10:08 UTC (permalink / raw)
To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao
From: Wenjing Qiao <wenjing.qiao@intel.com>
To supporting P4-programmed network controller, reuse devargs
"flow_parser" to specify the path of a p4 context JSON configure
file. The cpfl PMD use the JSON configuration file to translate
rte_flow tokens into low level hardware representation.
Note, the p4 context JSON file is generated by the P4 compiler
and is intended to work exclusively with a specific P4 pipeline
configuration, which must be compiled and programmed into the hardware.
Signed-off-by: Wenjing Qiao <wenjing.qiao@intel.com>
---
drivers/net/cpfl/cpfl_ethdev.h | 9 +-
drivers/net/cpfl/cpfl_flow.c | 10 +-
drivers/net/cpfl/cpfl_flow_engine_fxp.c | 9 +-
drivers/net/cpfl/cpfl_flow_parser.c | 60 +-
drivers/net/cpfl/cpfl_flow_parser.h | 2 +-
drivers/net/cpfl/cpfl_tdi_parser.c | 1715 +++++++++++++++++++++++
drivers/net/cpfl/cpfl_tdi_parser.h | 293 ++++
drivers/net/cpfl/meson.build | 1 +
8 files changed, 2077 insertions(+), 22 deletions(-)
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.c
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.h
diff --git a/drivers/net/cpfl/cpfl_ethdev.h b/drivers/net/cpfl/cpfl_ethdev.h
index 457db6d6be..e580f80f2f 100644
--- a/drivers/net/cpfl/cpfl_ethdev.h
+++ b/drivers/net/cpfl/cpfl_ethdev.h
@@ -185,6 +185,12 @@ struct cpfl_repr {
bool func_up; /* If the represented function is up */
};
+struct cpfl_flow_parser {
+ struct cpfl_flow_js_parser *fixed_parser;
+ struct cpfl_tdi_program *p4_parser;
+ bool is_p4_parser;
+};
+
struct cpfl_metadata_chunk {
int type;
uint8_t data[CPFL_META_CHUNK_LENGTH];
@@ -218,8 +224,7 @@ struct cpfl_adapter_ext {
rte_spinlock_t repr_lock;
struct rte_hash *repr_allowlist_hash;
-
- struct cpfl_flow_js_parser *flow_parser;
+ struct cpfl_flow_parser flow_parser;
struct rte_bitmap *mod_bm;
void *mod_bm_mem;
diff --git a/drivers/net/cpfl/cpfl_flow.c b/drivers/net/cpfl/cpfl_flow.c
index 3ba6c0f0e7..1c4131da2c 100644
--- a/drivers/net/cpfl/cpfl_flow.c
+++ b/drivers/net/cpfl/cpfl_flow.c
@@ -6,6 +6,7 @@
#include "cpfl_flow.h"
#include "cpfl_flow_parser.h"
+#include "cpfl_tdi_parser.h"
TAILQ_HEAD(cpfl_flow_engine_list, cpfl_flow_engine);
@@ -331,9 +332,14 @@ cpfl_flow_init(struct cpfl_adapter_ext *ad, struct cpfl_devargs *devargs)
void
cpfl_flow_uninit(struct cpfl_adapter_ext *ad)
{
- if (ad->flow_parser == NULL)
+ if (ad->flow_parser.fixed_parser == NULL && ad->flow_parser.p4_parser == NULL)
return;
- cpfl_parser_destroy(ad->flow_parser);
+ if (ad->flow_parser.fixed_parser)
+ cpfl_parser_destroy(ad->flow_parser.fixed_parser);
+
+ if (ad->flow_parser.p4_parser)
+ cpfl_tdi_program_destroy(ad->flow_parser.p4_parser);
+
cpfl_flow_engine_uninit(ad);
}
diff --git a/drivers/net/cpfl/cpfl_flow_engine_fxp.c b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
index 8a4e1419b4..f269ff97e1 100644
--- a/drivers/net/cpfl/cpfl_flow_engine_fxp.c
+++ b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
@@ -503,20 +503,25 @@ cpfl_fxp_parse_pattern_action(struct rte_eth_dev *dev,
struct cpfl_rule_info_meta *rim;
int ret;
+ if (adapter->flow_parser.is_p4_parser)
+ return -EINVAL;
+
ret = cpfl_fxp_get_metadata_port(itf, actions);
if (!ret) {
PMD_DRV_LOG(ERR, "Fail to save metadata.");
return -EINVAL;
}
- ret = cpfl_flow_parse_items(itf, adapter->flow_parser, pattern, attr, &pr_action);
+ ret = cpfl_flow_parse_items(itf, adapter->flow_parser.fixed_parser, pattern, attr,
+ &pr_action);
if (ret) {
PMD_DRV_LOG(ERR, "No Match pattern support.");
return -EINVAL;
}
if (cpfl_is_mod_action(actions)) {
- ret = cpfl_flow_parse_actions(adapter->flow_parser, actions, mr_action);
+ ret = cpfl_flow_parse_actions(adapter->flow_parser.fixed_parser,
+ actions, mr_action);
if (ret) {
PMD_DRV_LOG(ERR, "action parse fails.");
return -EINVAL;
diff --git a/drivers/net/cpfl/cpfl_flow_parser.c b/drivers/net/cpfl/cpfl_flow_parser.c
index a8f0488f21..e7f8a8a6cc 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 "cpfl_tdi_parser.h"
static enum rte_flow_item_type
cpfl_get_item_type_by_str(const char *type)
@@ -938,36 +939,65 @@ cpfl_parser_init(json_t *ob_root, struct cpfl_flow_js_parser *parser)
return 0;
}
+static int
+cpfl_check_is_p4_mode(json_t *ob_root)
+{
+ return json_object_get(ob_root, "patterns") ? false : true;
+}
+
int
-cpfl_parser_create(struct cpfl_flow_js_parser **flow_parser, const char *filename)
+cpfl_parser_create(struct cpfl_flow_parser *flow_parser, const char *filename)
{
struct cpfl_flow_js_parser *parser;
+ struct cpfl_tdi_program *prog;
json_error_t json_error;
json_t *root;
int ret;
- parser = rte_zmalloc("flow_parser", sizeof(struct cpfl_flow_js_parser), 0);
- if (!parser) {
- PMD_DRV_LOG(ERR, "Not enough memory to create flow parser.");
- return -ENOMEM;
- }
root = json_load_file(filename, 0, &json_error);
if (!root) {
PMD_DRV_LOG(ERR, "Bad JSON file \"%s\": %s", filename, json_error.text);
- goto free_parser;
+ return -EINVAL;
}
- ret = cpfl_parser_init(root, parser);
- if (ret < 0) {
- PMD_DRV_LOG(ERR, "parser init failed.");
- goto free_parser;
+
+ if (cpfl_check_is_p4_mode(root)) {
+ PMD_DRV_LOG(NOTICE, "flow parser mode is p4 mode.");
+ prog = rte_zmalloc("tdi_parser", sizeof(struct cpfl_tdi_program), 0);
+ if (prog == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create program object.");
+ return -ENOMEM;
+ }
+ ret = cpfl_tdi_program_create(root, prog);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to create tdi program from file %s", filename);
+ rte_free(prog);
+ return -EINVAL;
+ }
+ flow_parser->p4_parser = prog;
+ flow_parser->fixed_parser = NULL;
+ flow_parser->is_p4_parser = true;
+ } else {
+ PMD_DRV_LOG(NOTICE, "flow parser mode is fixed function mode.");
+ parser = rte_zmalloc("flow_parser", sizeof(struct cpfl_flow_js_parser), 0);
+ if (!parser) {
+ PMD_DRV_LOG(ERR, "Not enough memory to create flow parser.");
+ return -ENOMEM;
+ }
+
+ ret = cpfl_parser_init(root, parser);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "parser init failed.");
+ rte_free(parser);
+ return -EINVAL;
+ }
+ flow_parser->fixed_parser = parser;
+ flow_parser->p4_parser = NULL;
+ flow_parser->is_p4_parser = false;
}
- *flow_parser = parser;
+
json_decref(root);
return 0;
-free_parser:
- rte_free(parser);
- return -EINVAL;
}
static void
diff --git a/drivers/net/cpfl/cpfl_flow_parser.h b/drivers/net/cpfl/cpfl_flow_parser.h
index 23904e39f1..d420464d5c 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.h
+++ b/drivers/net/cpfl/cpfl_flow_parser.h
@@ -273,7 +273,7 @@ struct cpfl_flow_mr_action {
};
};
-int cpfl_parser_create(struct cpfl_flow_js_parser **parser, const char *filename);
+int cpfl_parser_create(struct cpfl_flow_parser *flow_parser, const char *filename);
int cpfl_parser_destroy(struct cpfl_flow_js_parser *parser);
int cpfl_flow_parse_items(struct cpfl_itf *itf,
struct cpfl_flow_js_parser *parser,
diff --git a/drivers/net/cpfl/cpfl_tdi_parser.c b/drivers/net/cpfl/cpfl_tdi_parser.c
new file mode 100644
index 0000000000..ed12ef04ad
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi_parser.c
@@ -0,0 +1,1715 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#include <errno.h>
+#include <rte_malloc.h>
+
+#include "cpfl_tdi_parser.h"
+
+static int
+cpfl_tdi_get_integer_obj(json_t *jobj, const char *key, int *output)
+{
+ json_t *int_obj = json_object_get(jobj, key);
+
+ if (int_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_integer(int_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a integer object.", key);
+ return -EINVAL;
+ }
+
+ *output = json_integer_value(int_obj);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_string_obj(json_t *jobj, const char *key, char *output)
+{
+ json_t *str_obj = json_object_get(jobj, key);
+
+ if (str_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_string(str_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a string object.", key);
+ return -EINVAL;
+ }
+
+ strncpy(output, json_string_value(str_obj), CPFL_TDI_JSON_STR_SIZE_MAX - 1);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_boolean_obj(json_t *jobj, const char *key, bool *output)
+{
+ json_t *bool_obj = json_object_get(jobj, key);
+
+ if (bool_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_boolean(bool_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a boolean object.", key);
+ return -EINVAL;
+ }
+
+ *output = (bool)json_integer_value(bool_obj);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_array_obj(json_t *jobj, const char *key, json_t **output)
+{
+ json_t *array_obj = json_object_get(jobj, key);
+
+ if (array_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_array(array_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a array object.", key);
+ return -EINVAL;
+ }
+
+ *output = array_obj;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_object_obj(json_t *jobj, const char *key, json_t **output)
+{
+ json_t *obj_obj = json_object_get(jobj, key);
+
+ if (obj_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_object(obj_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a array object.", key);
+ return -EINVAL;
+ }
+
+ *output = obj_obj;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_table_type(json_t *root, struct cpfl_tdi_table *table)
+{
+ char tt[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "table_type", tt);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(tt, "match")) {
+ table->table_type = CPFL_TDI_TABLE_TYPE_MATCH;
+ } else if (!strcmp(tt, "match_value_lookup_table")) {
+ table->table_type = CPFL_TDI_TABLE_TYPE_MATCH_VALUE_LOOKUP_TABLE;
+ } else if (!strcmp(tt, "policer_meter")) {
+ table->table_type = CPFL_TDI_TABLE_TYPE_POLICER_METER;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown table type %s", tt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_table_dir(json_t *root, struct cpfl_tdi_table *table)
+{
+ char dir[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "direction", dir);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(dir, "RX")) {
+ table->direction = CPFL_TDI_TABLE_DIR_RX;
+ } else if (!strcmp(dir, "TX")) {
+ table->direction = CPFL_TDI_TABLE_DIR_TX;
+ } else if (!strcmp(dir, "BIDIRECTIONAL")) {
+ table->direction = CPFL_TDI_TABLE_DIR_BI;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown direction type %s", dir);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_type(json_t *root, struct cpfl_tdi_match_key_field *mkf)
+{
+ char mt[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "match_type", mt);
+ if (ret != 0)
+ return ret;
+
+ if (!strcmp(mt, "exact")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_EXACT;
+ } else if (!strcmp(mt, "selector")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_SELECTOR;
+ } else if (!strcmp(mt, "ternary")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_TERNARY;
+ } else if (!strcmp(mt, "lpm")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_LPM;
+ } else {
+ PMD_DRV_LOG(ERR, "Unsupported match type %s.", mt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_field_obj(json_t *root, struct cpfl_tdi_match_key_field *mkf)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", mkf->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "instance_name", mkf->instance_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "field_name", mkf->field_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_match_type(root, mkf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->bit_width = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "index", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->index = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "position", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->position = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_fields(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ table->match_key_field_num = (uint16_t)array_len;
+ table->match_key_fields =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_match_key_field) * array_len, 0);
+ if (table->match_key_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create match key field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *mkf_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_match_key_field_obj(mkf_object, &table->match_key_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_byte_order(json_t *root, struct cpfl_tdi_match_key_format *mkf)
+{
+ char bo[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "byte_order", bo);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(bo, "HOST")) {
+ mkf->byte_order = CPFL_TDI_BYTE_ORDER_HOST;
+ } else if (!strcmp(bo, "NETWORK")) {
+ mkf->byte_order = CPFL_TDI_BYTE_ORDER_NETWORK;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown byte order type %s", bo);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_format_obj(json_t *root, struct cpfl_tdi_match_key_format *mkf)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_integer_obj(root, "match_key_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->match_key_handle = (uint32_t)val;
+
+ ret = cpfl_tdi_parse_byte_order(root, mkf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "byte_array_index", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->byte_array_index = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "start_bit_offset", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->start_bit_offset = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->bit_width = (uint16_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_format_array(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ table->match_key_format_num = (uint16_t)array_len;
+ table->match_key_format =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_match_key_format) * array_len, 0);
+ if (table->match_key_format == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create match key format array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *mkf_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_match_key_format_obj(mkf_object, &table->match_key_format[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_p4_parameter_obj(json_t *root, struct cpfl_tdi_p4_parameter *param)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", param->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ param->bit_width = (uint16_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_p4_parameters(json_t *root, struct cpfl_tdi_action *act)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ act->p4_parameter_num = (uint16_t)array_len;
+ act->p4_parameters = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_p4_parameter) * array_len, 0);
+ if (act->p4_parameters == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create p4 parameter array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *pp_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_p4_parameter_obj(pp_object, &act->p4_parameters[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_action_obj(json_t *root, struct cpfl_tdi_action *act)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", act->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
+ if (ret != 0)
+ return ret;
+
+ act->handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "constant_default_action",
+ &act->constant_default_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "is_compiler_added_action",
+ &act->is_compiler_added_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "allowed_as_hit_action", &act->allowed_as_hit_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "allowed_as_default_action",
+ &act->allowed_as_default_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "p4_parameters", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_p4_parameters(jobj, act);
+}
+
+static int
+cpfl_tdi_parse_actions(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ table->action_num = (uint16_t)array_len;
+ table->actions = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_action) * array_len, 0);
+ if (table->actions == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create action array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *act_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_action_obj(act_object, &table->actions[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_ma_hw_block(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", name);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(name, "SEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_SEM;
+ } else if (!strcmp(name, "LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_LEM;
+ } else if (!strcmp(name, "WCM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_WCM;
+ } else if (!strcmp(name, "LPM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_LPM;
+ } else if (!strcmp(name, "MOD")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_MOD;
+ } else if (!strcmp(name, "HASH")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_HASH;
+ } else if (!strcmp(name, "RC")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_RC;
+ } else if (!strcmp(name, "CXP_LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_CXP_LEM;
+ } else if (!strcmp(name, "METER")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_METER;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown hardware block type %s", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_profiles(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int array_len = json_array_size(root);
+
+ if (array_len > 16) {
+ PMD_DRV_LOG(ERR, "Profile array out of bound: %d.", array_len);
+ return -EINVAL;
+ }
+
+ if (array_len == 0)
+ return 0;
+
+ hb->profile_num = (uint16_t)array_len;
+ for (int i = 0; i < array_len; i++) {
+ int val;
+ json_t *int_obj = json_array_get(root, i);
+
+ if (!json_is_integer(int_obj)) {
+ PMD_DRV_LOG(ERR, "Invalid profile id, not an integer.");
+ return -EINVAL;
+ }
+ val = json_integer_value(int_obj);
+ hb->profile[i] = (uint8_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_immediate_field_obj(json_t *root, struct cpfl_tdi_immediate_field *imf)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "param_name", imf->param_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "param_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->param_handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "dest_start", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->dest_start = (uint16_t)val;
+ if (json_object_get(root, "start_bit_offset")) {
+ ret = cpfl_tdi_get_integer_obj(root, "start_bit_offset", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->start_bit_offset = (uint16_t)val;
+ }
+
+ ret = cpfl_tdi_get_integer_obj(root, "dest_width", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->dest_width = (uint16_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_af_immediate_fields(json_t *root, struct cpfl_tdi_action_format *af)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ af->immediate_field_num = (uint16_t)array_len;
+ af->immediate_fields =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_immediate_field) * array_len, 0);
+ if (af->immediate_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to immediate field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *if_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_immediate_field_obj(if_object, &af->immediate_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_type(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ char t[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+ int val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "type", t);
+ if (ret != 0)
+ return ret;
+
+ if (!strcmp("parameter", t)) {
+ mf->type = CPFL_TDI_MOD_FIELD_TYPE_PARAMETER;
+ ret = cpfl_tdi_get_integer_obj(root, "param_handle", &val);
+ if (ret != 0)
+ return ret;
+ mf->param_handle = (uint32_t)val;
+ } else if (!strcmp("constant", t)) {
+ mf->type = CPFL_TDI_MOD_FIELD_TYPE_CONSTANT;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown mod field type %s.", t);
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_byte_order(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ char bo[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "byte_order", bo);
+ if (ret != 0)
+ return ret;
+
+ if (!strcmp("HOST", bo))
+ mf->byte_order = CPFL_TDI_BYTE_ORDER_HOST;
+ else if (!strcmp("NETWORK", bo))
+ mf->byte_order = CPFL_TDI_BYTE_ORDER_NETWORK;
+ else
+ PMD_DRV_LOG(ERR, "Unknown byte order type %s.", bo);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_value(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ if (array_len > CPFL_TDI_VALUE_SIZE_MAX) {
+ PMD_DRV_LOG(ERR, "Value array out of bound.");
+ return -EINVAL;
+ }
+
+ mf->value_size = (uint16_t)array_len;
+ for (int i = 0; i < array_len; i++) {
+ int val;
+ json_t *val_obj = json_array_get(root, i);
+
+ if (!json_is_integer(val_obj)) {
+ PMD_DRV_LOG(ERR, "Invalid value item, not an integer.");
+ return -EINVAL;
+ }
+ val = json_integer_value(val_obj);
+ mf->value[i] = (uint8_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_obj(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ json_t *jobj = NULL;
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", mf->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->handle = (uint32_t)val;
+
+ ret = cpfl_tdi_parse_mod_field_type(root, mf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_mod_field_byte_order(root, mf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "byte_array_index", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->byte_array_index = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "start_bit_offset", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->start_bit_offset = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->bit_width = (uint16_t)val;
+
+ ret = cpfl_tdi_get_array_obj(root, "value", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_mod_field_value(jobj, mf);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_fields(json_t *root, struct cpfl_tdi_mod_content_format *mcf)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ mcf->mod_field_num = (uint16_t)array_len;
+ mcf->mod_fields = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_mod_field) * array_len, 0);
+ if (mcf->mod_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create mod field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *mf_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_mod_field_obj(mf_object, &mcf->mod_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_content_format(json_t *root, struct cpfl_tdi_mod_content_format *mcf)
+{
+ json_t *jobj = NULL;
+ int ret, val = 0;
+
+ if (json_object_get(root, "mod_profile")) {
+ ret = cpfl_tdi_get_integer_obj(root, "mod_profile", &val);
+ if (ret != 0)
+ return ret;
+ mcf->mod_profile = (uint16_t)val;
+ } else if (json_object_get(root, "mod_lut_num")) {
+ ret = cpfl_tdi_get_integer_obj(root, "mod_lut_num", &val);
+ if (ret != 0)
+ return ret;
+ mcf->mod_lut_num = (uint16_t)val;
+ } else {
+ PMD_DRV_LOG(ERR, "Failed to parse mod_content_format.");
+ return -EINVAL;
+ }
+
+ ret = cpfl_tdi_get_integer_obj(root, "mod_obj_size", &val);
+ if (ret != 0)
+ return ret;
+
+ mcf->mod_obj_size = (uint16_t)val;
+
+ if (json_object_get(root, "mod_fields") != NULL) {
+ ret = cpfl_tdi_get_array_obj(root, "mod_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_mod_fields(jobj, mcf);
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_pparse_action_code(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ char ac[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "action_code", ac);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(ac, "SET10_1b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET10_1b;
+ } else if (!strcmp(ac, "SET1_16b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET1_16b;
+ } else if (!strcmp(ac, "SET1A_24b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET1A_24b;
+ } else if (!strcmp(ac, "SET1B_24b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET1B_24b;
+ } else if (!strcmp(ac, "SET2_8b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET2_8b;
+ } else if (!strcmp(ac, "NOP")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_NOP;
+ } else if (!strcmp(ac, "AUX_DATA")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_AUX_DATA;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown action code type %s", ac);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_setmd_action_code(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ char ac[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ /* allow no value */
+ if (json_object_get(root, "setmd_action_code") == NULL) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_NONE;
+ return 0;
+ }
+
+ ret = cpfl_tdi_get_string_obj(root, "setmd_action_code", ac);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(ac, "SET_8b")) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_SET_8b;
+ } else if (!strcmp(ac, "SET_16b")) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_SET_16b;
+ } else if (!strcmp(ac, "SET_32b_AUX")) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_SET_32b_AUX;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown setmd action code type %s", ac);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_action_parameter_obj(json_t *root, struct cpfl_tdi_hw_action_parameter *param)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "param_name", param->param_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "param_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ param->param_handle = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_action_parameters(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ ha->parameter_num = (uint16_t)array_len;
+ ha->parameters =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_hw_action_parameter) * array_len, 0);
+ if (ha->parameters == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create hw action parameter array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *p_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_hw_action_parameter_obj(p_object, &ha->parameters[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_action_obj(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_integer_obj(root, "prec", &val);
+ if (ret != 0)
+ return ret;
+
+ ha->prec = (uint16_t)val;
+
+ ret = cpfl_tdi_pparse_action_code(root, ha);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_setmd_action_code(root, ha);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "index", &val);
+ if (ret != 0)
+ return ret;
+
+ ha->index = (uint32_t)val;
+
+ if (json_object_get(root, "mod_profile") != NULL) {
+ ret = cpfl_tdi_get_integer_obj(root, "mod_profile", &val);
+ if (ret != 0)
+ return ret;
+ ha->mod_profile = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "prefetch") != NULL) {
+ ret = cpfl_tdi_get_integer_obj(root, "prefetch", &val);
+ if (ret != 0)
+ return ret;
+ ha->prefetch = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "parameters") != NULL) {
+ ret = cpfl_tdi_get_array_obj(root, "parameters", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_hw_action_parameters(jobj, ha);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (json_object_get(root, "p4_ref_action_handle")) {
+ ret = cpfl_tdi_get_integer_obj(root, "p4_ref_action_handle", &val);
+ if (ret != 0)
+ return ret;
+ ha->p4_ref_action_handle = (uint32_t)val;
+ }
+
+ if (json_object_get(root, "p4_ref_table_handle")) {
+ ret = cpfl_tdi_get_integer_obj(root, "p4_ref_table_handle", &val);
+ if (ret != 0)
+ return ret;
+ ha->p4_ref_table_handle = (uint32_t)val;
+ }
+
+ if (json_object_get(root, "value")) {
+ ret = cpfl_tdi_get_integer_obj(root, "value", &val);
+ if (ret != 0)
+ return ret;
+ ha->value = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "mask")) {
+ ret = cpfl_tdi_get_integer_obj(root, "mask", &val);
+ if (ret != 0)
+ return ret;
+ ha->mask = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "type_id")) {
+ ret = cpfl_tdi_get_integer_obj(root, "type_id", &val);
+ if (ret != 0)
+ return ret;
+ ha->type_id = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "offset")) {
+ ret = cpfl_tdi_get_integer_obj(root, "offset", &val);
+ if (ret != 0)
+ return ret;
+ ha->offset = (uint16_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_actions_list(json_t *root, struct cpfl_tdi_action_format *af)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ af->hw_action_num = (uint16_t)array_len;
+ af->hw_actions_list = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_hw_action) * array_len, 0);
+ if (af->hw_actions_list == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create hw action array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *ha_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_hw_action_obj(ha_object, &af->hw_actions_list[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_action_format_obj(json_t *root, struct cpfl_tdi_action_format *af)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_string_obj(root, "action_name", af->action_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "action_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ af->action_handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_array_obj(root, "immediate_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_af_immediate_fields(jobj, af);
+ if (ret != 0)
+ return ret;
+
+ jobj = json_object_get(root, "mod_content_format");
+ if (jobj != NULL) {
+ ret = cpfl_tdi_parse_mod_content_format(jobj, &af->mod_content_format);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = cpfl_tdi_get_array_obj(root, "hw_actions_list", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_hw_actions_list(jobj, af);
+}
+
+static int
+cpfl_tdi_parse_action_format_array(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ hb->action_format_num = (uint16_t)array_len;
+ hb->action_format = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_action_format) * array_len, 0);
+ if (hb->action_format == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create action format array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *af_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_action_format_obj(af_object, &hb->action_format[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_act_rams(json_t *root, struct cpfl_tdi_wcm_params *wm)
+{
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ if (array_len > 16) {
+ PMD_DRV_LOG(ERR, "Action ram array out of bound.");
+ return -EINVAL;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ int val;
+ json_t *am_obj = json_array_get(root, i);
+
+ if (!json_is_integer(am_obj)) {
+ PMD_DRV_LOG(ERR, "Invalid action ram index, not an integer.");
+ return -EINVAL;
+ }
+ val = json_integer_value(am_obj);
+ wm->act_rams[i] = (uint8_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_wcm_params(json_t *root, struct cpfl_tdi_wcm_params *wm)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_integer_obj(root, "wcm_group", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->wcm_group = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "slice_start_idx", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->slice_start_idx = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "table_width", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->table_width = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "entry_cnt", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->entry_cnt = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "entry_idx", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->entry_idx = (uint16_t)val;
+
+ ret = cpfl_tdi_get_array_obj(root, "act_rams", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_act_rams(jobj, wm);
+}
+
+static int
+cpfl_tdi_parse_hb_immediate_fields(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ hb->meter.immediate_field_num = (uint16_t)array_len;
+ hb->meter.immediate_fields =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_immediate_field) * array_len, 0);
+ if (hb->meter.immediate_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to immediate field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *if_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_immediate_field_obj(if_object, &hb->meter.immediate_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_ma_hardware_block_obj(json_t *root,
+ enum cpfl_tdi_table_type table_type,
+ struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_parse_ma_hw_block(root, hb);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "id", &val);
+ if (ret != 0)
+ return ret;
+
+ hb->id = (uint32_t)val;
+
+ ret = cpfl_tdi_get_string_obj(root, "hw_interface", hb->hw_interface);
+ if (ret != 0)
+ return ret;
+ if (table_type == CPFL_TDI_TABLE_TYPE_MATCH) {
+ ret = cpfl_tdi_get_array_obj(root, "profile", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_profiles(jobj, hb);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "action_format", &jobj);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_parse_action_format_array(jobj, hb);
+ if (ret != 0)
+ return ret;
+ }
+
+ switch (hb->hw_block) {
+ case CPFL_TDI_HW_BLOCK_SEM:
+ ret = cpfl_tdi_get_integer_obj(root, "sub_profile", &val);
+ if (ret != 0)
+ return ret;
+
+ hb->sem.sub_profile = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "obj_id", &val);
+ if (ret != 0)
+ return ret;
+
+ hb->sem.obj_id = (uint32_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_WCM:
+ ret = cpfl_tdi_get_object_obj(root, "wcm_params", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_wcm_params(jobj, &hb->wcm.wcm_params);
+ if (ret != 0)
+ return ret;
+ break;
+ case CPFL_TDI_HW_BLOCK_MOD:
+ ret = cpfl_tdi_get_string_obj(root, "hw_resource", hb->mod.hw_resource);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "hw_resource_id", &val);
+ if (ret != 0)
+ return ret;
+ hb->mod.hw_resource_id = (uint32_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_METER:
+ ret = cpfl_tdi_get_string_obj(root, "hw_resource", hb->mod.hw_resource);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_integer_obj(root, "hw_resource_id", &val);
+ if (ret != 0)
+ return ret;
+ hb->mod.hw_resource_id = (uint32_t)val;
+ ret = cpfl_tdi_get_array_obj(root, "immediate_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_hb_immediate_fields(jobj, hb);
+ if (ret != 0)
+ return ret;
+ break;
+ case CPFL_TDI_HW_BLOCK_LEM:
+ case CPFL_TDI_HW_BLOCK_CXP_LEM:
+ ret = cpfl_tdi_get_integer_obj(root, "hash_size", &val);
+ if (ret != 0)
+ return ret;
+ hb->lem.hash_size = (uint16_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_LPM:
+ ret = cpfl_tdi_get_integer_obj(root, "max_prefix_len", &val);
+ if (ret != 0)
+ return ret;
+ hb->lpm.max_prefix_len = (uint16_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_HASH:
+ break;
+ default:
+ printf("not support this hardware_block type: %d\n", hb->hw_block);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_ma_hardware_blocks(json_t *root,
+ enum cpfl_tdi_table_type table_type,
+ struct cpfl_tdi_match_attributes *ma)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ ma->hardware_block_num = (uint16_t)array_len;
+ ma->hardware_blocks =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_ma_hardware_block) * array_len, 0);
+ if (ma->hardware_blocks == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create match attribute's hardware block array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *hb_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_ma_hardware_block_obj(hb_object, table_type,
+ &ma->hardware_blocks[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_attributes(json_t *root,
+ enum cpfl_tdi_table_type table_type,
+ struct cpfl_tdi_match_attributes *ma)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "hardware_blocks", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_ma_hardware_blocks(jobj, table_type, ma);
+}
+
+static int
+cpfl_tdi_parse_table_obj(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret, val = 0;
+ struct json_t *jobj = NULL;
+
+ ret = cpfl_tdi_parse_table_type(root, table);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
+ if (ret != 0)
+ return ret;
+ table->handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", table->name);
+ if (ret != 0)
+ return ret;
+
+ if (table->table_type == CPFL_TDI_TABLE_TYPE_POLICER_METER) {
+ /* TODO */
+ return 0;
+ }
+
+ if (table->table_type == CPFL_TDI_TABLE_TYPE_MATCH) {
+ ret = cpfl_tdi_parse_table_dir(root, table);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_boolean_obj(root, "add_on_miss", &table->add_on_miss);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_boolean_obj(root, "idle_timeout_with_auto_delete",
+ &table->idle_timeout_with_auto_delete);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_integer_obj(root, "default_action_handle", &val);
+ if (ret != 0)
+ return ret;
+ table->default_action_handle = (uint32_t)val;
+ ret = cpfl_tdi_get_array_obj(root, "actions", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_actions(jobj, table);
+ if (ret != 0)
+ return ret;
+ } else if (table->table_type == CPFL_TDI_TABLE_TYPE_MATCH_VALUE_LOOKUP_TABLE) {
+ ret = cpfl_tdi_get_integer_obj(root, "size", &val);
+ if (ret != 0)
+ return ret;
+ table->size = (uint16_t)val;
+ ret = cpfl_tdi_get_boolean_obj(root, "p4_hidden", &table->p4_hidden);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = cpfl_tdi_get_array_obj(root, "match_key_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_match_key_fields(jobj, table);
+ if (ret != 0)
+ return ret;
+
+ if (json_object_get(root, "match_key_format") != NULL) {
+ ret = cpfl_tdi_get_array_obj(root, "match_key_format", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_match_key_format_array(jobj, table);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = cpfl_tdi_get_object_obj(root, "match_attributes", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_match_attributes(jobj, table->table_type, &table->match_attributes);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_tables(json_t *root, struct cpfl_tdi_program *prog)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ prog->table_num = (uint16_t)array_len;
+ prog->tables = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_table) * array_len, 0);
+ if (prog->tables == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create table array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *table_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_table_obj(table_object, &prog->tables[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hash_space_cfg(json_t *root, struct cpfl_tdi_hash_space_cfg *cfg)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_integer_obj(root, "base_128_entries", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->base_128_entries = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "base_256_entries", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->base_256_entries = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_rc_entry_space_cfg(json_t *root, struct cpfl_tdi_rc_entry_space_cfg *cfg)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_integer_obj(root, "rc_num_banks", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->rc_num_banks = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "rc_num_entries", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->rc_num_entries = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_gc_hw_block(json_t *root, struct cpfl_tdi_gc_hardware_block *hb)
+{
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", name);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(name, "SEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_SEM;
+ } else if (!strcmp(name, "LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_LEM;
+ } else if (!strcmp(name, "WCM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_WCM;
+ } else if (!strcmp(name, "MOD")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_MOD;
+ } else if (!strcmp(name, "HASH")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_HASH;
+ } else if (!strcmp(name, "RC")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_RC;
+ } else if (!strcmp(name, "CXP_LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_CXP_LEM;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown hardware block type %s", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_gc_hardware_block(json_t *root, struct cpfl_tdi_gc_hardware_block *hb)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_parse_gc_hw_block(root, hb);
+ if (ret != 0)
+ return ret;
+
+ switch (hb->hw_block) {
+ case CPFL_TDI_HW_BLOCK_MOD:
+ ret = cpfl_tdi_get_object_obj(root, "hash_space_cfg", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_hash_space_cfg(jobj, &hb->hash_space_cfg);
+ case CPFL_TDI_HW_BLOCK_RC:
+ ret = cpfl_tdi_get_object_obj(root, "rc_entry_space_cfg", &jobj);
+ if (ret != 0)
+ return ret;
+ return cpfl_tdi_parse_rc_entry_space_cfg(jobj, &hb->rc_entry_space_cfg);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_gc_hardware_blocks(json_t *root, struct cpfl_tdi_global_configs *gc)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ gc->hardware_block_num = (uint16_t)array_len;
+ gc->hardware_blocks =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_gc_hardware_block) * array_len, 0);
+ if (gc->hardware_blocks == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create hardware block array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *hb_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_gc_hardware_block(hb_object, &gc->hardware_blocks[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_global_configs(json_t *root, struct cpfl_tdi_global_configs *gc)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "hardware_blocks", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_gc_hardware_blocks(jobj, gc);
+}
+
+int
+cpfl_tdi_program_create(json_t *root, struct cpfl_tdi_program *prog)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "program_name", prog->program_name);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "build_date", prog->build_date);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "compile_command", prog->compile_command);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "compiler_version", prog->compiler_version);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "schema_version", prog->schema_version);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "target", prog->target);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_object_obj(root, "global_configs", &jobj);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_parse_global_configs(jobj, &prog->global_configs);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_array_obj(root, "tables", &jobj);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_parse_tables(jobj, prog);
+ if (ret != 0)
+ goto err;
+
+ json_decref(root);
+
+ return 0;
+
+err:
+ cpfl_tdi_program_destroy(prog);
+ return ret;
+}
+
+static void
+cpfl_tdi_destroy_hw_action(struct cpfl_tdi_hw_action *action)
+{
+ if (action->parameter_num > 0)
+ rte_free(action->parameters);
+}
+
+static void
+cpfl_tdi_cpfl_tdi_destroy_action_format(struct cpfl_tdi_action_format *format)
+{
+ uint16_t i;
+
+ if (format->immediate_field_num > 0)
+ rte_free(format->immediate_fields);
+
+ if (format->mod_content_format.mod_field_num > 0)
+ rte_free(format->mod_content_format.mod_fields);
+
+ for (i = 0; i < format->hw_action_num; i++)
+ cpfl_tdi_destroy_hw_action(&format->hw_actions_list[i]);
+
+ if (format->hw_action_num > 0)
+ rte_free(format->hw_actions_list);
+}
+
+static void
+cpfl_tdi_destroy_hardware_block(struct cpfl_tdi_ma_hardware_block *hb)
+{
+ uint16_t i;
+
+ for (i = 0; i < hb->action_format_num; i++)
+ cpfl_tdi_cpfl_tdi_destroy_action_format(&hb->action_format[i]);
+
+ if (hb->action_format_num > 0)
+ rte_free(hb->action_format);
+}
+
+static void
+cpfl_tdi_destroy_action(struct cpfl_tdi_action *action)
+{
+ if (action->p4_parameter_num > 0)
+ rte_free(action->p4_parameters);
+}
+
+static void
+cpfl_tdi_destroy_table(struct cpfl_tdi_table *table)
+{
+ uint16_t i;
+
+ if (table->match_key_field_num > 0)
+ rte_free(table->match_key_fields);
+
+ if (table->match_key_format_num > 0)
+ rte_free(table->match_key_format);
+
+ for (i = 0; i < table->action_num; i++)
+ cpfl_tdi_destroy_action(&table->actions[i]);
+
+ if (table->action_num > 0)
+ rte_free(table->actions);
+
+ for (i = 0; i < table->match_attributes.hardware_block_num; i++)
+ cpfl_tdi_destroy_hardware_block(&table->match_attributes.hardware_blocks[i]);
+
+ if (table->match_attributes.hardware_block_num > 0)
+ rte_free(table->match_attributes.hardware_blocks);
+}
+
+void
+cpfl_tdi_program_destroy(struct cpfl_tdi_program *program)
+{
+ uint16_t i;
+
+ for (i = 0; i < program->table_num; i++)
+ cpfl_tdi_destroy_table(&program->tables[i]);
+
+ if (program->table_num > 0)
+ rte_free(program->tables);
+
+ rte_free(program);
+}
diff --git a/drivers/net/cpfl/cpfl_tdi_parser.h b/drivers/net/cpfl/cpfl_tdi_parser.h
new file mode 100644
index 0000000000..c3d84adb77
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi_parser.h
@@ -0,0 +1,293 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#ifndef _CPFL_TDI_PARSER_H_
+#define _CPFL_TDI_PARSER_H_
+
+#include <jansson.h>
+#include <rte_flow.h>
+
+#include "cpfl_ethdev.h"
+
+#define CPFL_TDI_JSON_STR_SIZE_MAX 100
+
+enum cpfl_tdi_table_type {
+ CPFL_TDI_TABLE_TYPE_MATCH,
+ CPFL_TDI_TABLE_TYPE_MATCH_VALUE_LOOKUP_TABLE,
+ CPFL_TDI_TABLE_TYPE_POLICER_METER,
+};
+
+enum cpfl_tdi_table_dir {
+ CPFL_TDI_TABLE_DIR_RX,
+ CPFL_TDI_TABLE_DIR_TX,
+ CPFL_TDI_TABLE_DIR_BI,
+};
+
+enum cpfl_tdi_match_type {
+ CPFL_TDI_MATCH_TYPE_EXACT,
+ CPFL_TDI_MATCH_TYPE_SELECTOR,
+ CPFL_TDI_MATCH_TYPE_TERNARY,
+ CPFL_TDI_MATCH_TYPE_LPM,
+};
+
+/**
+ * Byte order.
+ *
+ * To specify the byte order of table key / action field value in bytes.
+ */
+enum cpfl_tdi_byte_order {
+ CPFL_TDI_BYTE_ORDER_HOST, /**< follow host byte order. */
+ CPFL_TDI_BYTE_ORDER_NETWORK, /**< follow network byte order. */
+};
+
+#define CPFL_TDI_NAME_SIZE_MAX 80
+
+struct cpfl_tdi_match_key_format {
+ uint32_t match_key_handle;
+ enum cpfl_tdi_byte_order byte_order;
+ uint16_t byte_array_index;
+ uint16_t start_bit_offset;
+ uint16_t bit_width;
+};
+
+struct cpfl_tdi_match_key_field {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char instance_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char field_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ enum cpfl_tdi_match_type match_type;
+ uint16_t bit_width;
+ uint32_t index;
+ uint32_t position;
+};
+
+struct cpfl_tdi_p4_parameter {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint16_t bit_width;
+};
+
+struct cpfl_tdi_action {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t handle;
+ bool constant_default_action;
+ bool is_compiler_added_action;
+ bool allowed_as_hit_action;
+ bool allowed_as_default_action;
+ uint16_t p4_parameter_num;
+ struct cpfl_tdi_p4_parameter *p4_parameters;
+};
+
+struct cpfl_tdi_immediate_field {
+ char param_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t param_handle;
+ uint16_t dest_start;
+ uint16_t start_bit_offset;
+ uint16_t dest_width;
+};
+
+enum cpfl_tdi_mod_field_type {
+ CPFL_TDI_MOD_FIELD_TYPE_PARAMETER,
+ CPFL_TDI_MOD_FIELD_TYPE_CONSTANT,
+};
+
+#define CPFL_TDI_VALUE_SIZE_MAX 16
+
+struct cpfl_tdi_mod_field {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t handle;
+ uint32_t param_handle;
+ enum cpfl_tdi_mod_field_type type;
+ enum cpfl_tdi_byte_order byte_order;
+ uint16_t byte_array_index;
+ uint16_t start_bit_offset;
+ uint16_t bit_width;
+ uint16_t value_size;
+ uint8_t value[CPFL_TDI_VALUE_SIZE_MAX];
+};
+
+struct cpfl_tdi_mod_content_format {
+ union {
+ uint16_t mod_profile;
+ uint16_t mod_lut_num;
+ };
+ uint16_t mod_obj_size;
+ uint16_t mod_field_num;
+ struct cpfl_tdi_mod_field *mod_fields;
+};
+
+struct cpfl_tdi_hw_action_parameter {
+ char param_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t param_handle;
+};
+
+enum cpfl_tdi_action_code {
+ CPFL_TDI_ACTION_CODE_NONE,
+ CPFL_TDI_ACTION_CODE_SET10_1b,
+ CPFL_TDI_ACTION_CODE_SET1_16b,
+ CPFL_TDI_ACTION_CODE_SET1A_24b,
+ CPFL_TDI_ACTION_CODE_SET1B_24b,
+ CPFL_TDI_ACTION_CODE_SET2_8b,
+ CPFL_TDI_ACTION_CODE_NOP,
+ CPFL_TDI_ACTION_CODE_AUX_DATA,
+};
+
+enum cpfl_tdi_setmd_action_code {
+ CPFL_TDI_SETMD_ACTION_CODE_NONE,
+ CPFL_TDI_SETMD_ACTION_CODE_SET_8b,
+ CPFL_TDI_SETMD_ACTION_CODE_SET_16b,
+ CPFL_TDI_SETMD_ACTION_CODE_SET_32b_AUX,
+};
+
+struct cpfl_tdi_hw_action {
+ uint16_t prec;
+ enum cpfl_tdi_action_code action_code;
+ enum cpfl_tdi_setmd_action_code setmd_action_code;
+ uint16_t index;
+ uint16_t mod_profile;
+ uint16_t prefetch;
+ uint16_t parameter_num;
+ struct cpfl_tdi_hw_action_parameter *parameters;
+ uint32_t p4_ref_action_handle;
+ uint32_t p4_ref_table_handle;
+ uint16_t value;
+ uint16_t mask;
+ uint16_t type_id;
+ uint16_t offset;
+};
+
+struct cpfl_tdi_action_format {
+ char action_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t action_handle;
+ uint16_t immediate_field_num;
+ struct cpfl_tdi_immediate_field *immediate_fields;
+ struct cpfl_tdi_mod_content_format mod_content_format;
+ uint16_t hw_action_num;
+ struct cpfl_tdi_hw_action *hw_actions_list;
+};
+
+enum cpfl_tdi_hw_block {
+ CPFL_TDI_HW_BLOCK_SEM,
+ CPFL_TDI_HW_BLOCK_LEM,
+ CPFL_TDI_HW_BLOCK_WCM,
+ CPFL_TDI_HW_BLOCK_LPM,
+ CPFL_TDI_HW_BLOCK_MOD,
+ CPFL_TDI_HW_BLOCK_METER,
+ CPFL_TDI_HW_BLOCK_HASH,
+ CPFL_TDI_HW_BLOCK_RC,
+ CPFL_TDI_HW_BLOCK_CXP_LEM,
+};
+
+struct cpfl_tdi_wcm_params {
+ uint16_t wcm_group;
+ uint16_t slice_start_idx;
+ uint16_t table_width;
+ uint16_t entry_cnt;
+ uint16_t entry_idx;
+ uint8_t act_rams[16];
+};
+
+struct cpfl_tdi_ma_hardware_block {
+ enum cpfl_tdi_hw_block hw_block;
+ uint32_t id;
+ char hw_interface[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint16_t profile_num;
+ uint16_t profile[16];
+ uint16_t action_format_num;
+ struct cpfl_tdi_action_format *action_format;
+ union {
+ struct {
+ uint16_t sub_profile;
+ uint32_t obj_id;
+ } sem;
+ struct {
+ struct cpfl_tdi_wcm_params wcm_params;
+ } wcm;
+ struct {
+ char hw_resource[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t hw_resource_id;
+ } mod;
+ struct {
+ char hw_resource[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t hw_resource_id;
+ uint16_t immediate_field_num;
+ struct cpfl_tdi_immediate_field *immediate_fields;
+ } meter;
+ struct {
+ uint16_t hash_size;
+ } lem;
+ struct {
+ uint16_t max_prefix_len;
+ } lpm;
+ };
+};
+
+struct cpfl_tdi_match_attributes {
+ uint16_t hardware_block_num;
+ struct cpfl_tdi_ma_hardware_block *hardware_blocks;
+};
+
+struct cpfl_tdi_table {
+ enum cpfl_tdi_table_type table_type;
+ uint32_t handle;
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ union {
+ /* "table_type": "match" */
+ struct {
+ enum cpfl_tdi_table_dir direction;
+ bool add_on_miss;
+ bool idle_timeout_with_auto_delete;
+ };
+ /* "table_type": "match_value_lookup_table" */
+ struct {
+ uint16_t size;
+ bool p4_hidden;
+ };
+ };
+ uint16_t match_key_field_num;
+ struct cpfl_tdi_match_key_field *match_key_fields;
+ uint16_t match_key_format_num;
+ struct cpfl_tdi_match_key_format *match_key_format;
+ uint32_t default_action_handle;
+ uint16_t action_num;
+ struct cpfl_tdi_action *actions;
+ struct cpfl_tdi_match_attributes match_attributes;
+};
+
+struct cpfl_tdi_hash_space_cfg {
+ uint32_t base_128_entries;
+ uint32_t base_256_entries;
+};
+
+struct cpfl_tdi_rc_entry_space_cfg {
+ uint32_t rc_num_banks;
+ uint32_t rc_num_entries;
+};
+
+struct cpfl_tdi_gc_hardware_block {
+ enum cpfl_tdi_hw_block hw_block;
+ union {
+ struct cpfl_tdi_hash_space_cfg hash_space_cfg;
+ struct cpfl_tdi_rc_entry_space_cfg rc_entry_space_cfg;
+ };
+};
+
+struct cpfl_tdi_global_configs {
+ uint16_t hardware_block_num;
+ struct cpfl_tdi_gc_hardware_block *hardware_blocks;
+};
+
+struct cpfl_tdi_program {
+ char program_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char build_date[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char compile_command[2 * CPFL_TDI_JSON_STR_SIZE_MAX];
+ char compiler_version[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char schema_version[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char target[CPFL_TDI_JSON_STR_SIZE_MAX];
+ struct cpfl_tdi_global_configs global_configs;
+ uint16_t table_num;
+ struct cpfl_tdi_table *tables;
+};
+
+int cpfl_tdi_program_create(json_t *ob_root, struct cpfl_tdi_program *program);
+void cpfl_tdi_program_destroy(struct cpfl_tdi_program *program);
+
+#endif
diff --git a/drivers/net/cpfl/meson.build b/drivers/net/cpfl/meson.build
index e4e0e269bd..f948033f1f 100644
--- a/drivers/net/cpfl/meson.build
+++ b/drivers/net/cpfl/meson.build
@@ -47,6 +47,7 @@ if dpdk_conf.has('RTE_HAS_JANSSON')
'cpfl_flow_engine_fxp.c',
'cpfl_flow_parser.c',
'cpfl_fxp_rule.c',
+ 'cpfl_tdi_parser.c',
)
ext_deps += jansson_dep
endif
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] net/cpfl: add TDI to flow engine
2023-12-22 10:08 [PATCH 0/2] net/cpfl: support flow offloading for P4 wenjing.qiao
2023-12-22 10:08 ` [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
@ 2023-12-22 10:08 ` wenjing.qiao
1 sibling, 0 replies; 8+ messages in thread
From: wenjing.qiao @ 2023-12-22 10:08 UTC (permalink / raw)
To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao
From: Wenjing Qiao <wenjing.qiao@intel.com>
Add TDI implementation to a flow engine.
Signed-off-by: Wenjing Qiao <wenjing.qiao@intel.com>
---
doc/guides/nics/cpfl.rst | 10 +
doc/guides/nics/features/cpfl.ini | 1 +
drivers/net/cpfl/cpfl_ethdev.h | 8 +
drivers/net/cpfl/cpfl_flow.c | 5 +-
drivers/net/cpfl/cpfl_flow.h | 1 +
drivers/net/cpfl/cpfl_flow_engine_fxp.c | 12 -
drivers/net/cpfl/cpfl_flow_parser.c | 8 +
drivers/net/cpfl/cpfl_fxp_rule.h | 12 +
drivers/net/cpfl/cpfl_tdi.c | 1244 +++++++++++++++++++++++
drivers/net/cpfl/cpfl_tdi.h | 123 +++
drivers/net/cpfl/meson.build | 1 +
11 files changed, 1412 insertions(+), 13 deletions(-)
create mode 100644 drivers/net/cpfl/cpfl_tdi.c
create mode 100644 drivers/net/cpfl/cpfl_tdi.h
diff --git a/doc/guides/nics/cpfl.rst b/doc/guides/nics/cpfl.rst
index 9b7a99c894..591bd496e6 100644
--- a/doc/guides/nics/cpfl.rst
+++ b/doc/guides/nics/cpfl.rst
@@ -213,6 +213,16 @@ low level hardware resources.
flow create X ingress group M pattern eth dst is 00:01:00:00:03:14 / ipv4 src is 192.168.0.1 \
dst is 192.168.0.2 / tcp / end actions port_representor port_id Y / end
+#. Create one flow for TDI engine to forward ETH-IPV4-TCP from I/O port to a local(CPF's) vport. Flow should
+ be created on vport X. Group M should be table id. Prog name N should be action id. Prog arguments
+ port_representor Y means forward packet to local vport Y::
+
+ .. code-block:: console
+
+ flow create X ingress group M pattern prog key is 0x00 / prog key is 0x000100000314 / prog key
+ is 0x001122334455 / prog key is 0xC0A80001 / prog key is 0xC0A80002 / prog key is 0x1451 / prog key
+ is 0x157C / end actions prog name N arguments port_representor Y end / end
+
#. Send a matched packet, and it should be displayed on PMD::
.. code-block:: console
diff --git a/doc/guides/nics/features/cpfl.ini b/doc/guides/nics/features/cpfl.ini
index 4eadaca6e7..85b8011a54 100644
--- a/doc/guides/nics/features/cpfl.ini
+++ b/doc/guides/nics/features/cpfl.ini
@@ -33,6 +33,7 @@ tcp = Y
udp = Y
vlan = Y
vxlan = Y
+flex = Y
[rte_flow actions]
count = Y
diff --git a/drivers/net/cpfl/cpfl_ethdev.h b/drivers/net/cpfl/cpfl_ethdev.h
index e580f80f2f..7dfa4a0183 100644
--- a/drivers/net/cpfl/cpfl_ethdev.h
+++ b/drivers/net/cpfl/cpfl_ethdev.h
@@ -185,10 +185,18 @@ struct cpfl_repr {
bool func_up; /* If the represented function is up */
};
+struct cpfl_tdi_table_node;
+TAILQ_HEAD(cpfl_tdi_table_list, cpfl_tdi_table_node);
+
+struct cpfl_tdi_action_node;
+TAILQ_HEAD(cpfl_tdi_action_list, cpfl_tdi_action_node);
+
struct cpfl_flow_parser {
struct cpfl_flow_js_parser *fixed_parser;
struct cpfl_tdi_program *p4_parser;
bool is_p4_parser;
+ struct cpfl_tdi_table_list tdi_table_list;
+ struct cpfl_tdi_action_list tdi_action_list;
};
struct cpfl_metadata_chunk {
diff --git a/drivers/net/cpfl/cpfl_flow.c b/drivers/net/cpfl/cpfl_flow.c
index 1c4131da2c..15c7cc6d8b 100644
--- a/drivers/net/cpfl/cpfl_flow.c
+++ b/drivers/net/cpfl/cpfl_flow.c
@@ -6,6 +6,7 @@
#include "cpfl_flow.h"
#include "cpfl_flow_parser.h"
+#include "cpfl_tdi.h"
#include "cpfl_tdi_parser.h"
TAILQ_HEAD(cpfl_flow_engine_list, cpfl_flow_engine);
@@ -338,8 +339,10 @@ cpfl_flow_uninit(struct cpfl_adapter_ext *ad)
if (ad->flow_parser.fixed_parser)
cpfl_parser_destroy(ad->flow_parser.fixed_parser);
- if (ad->flow_parser.p4_parser)
+ if (ad->flow_parser.p4_parser) {
+ cpfl_tdi_free_table_list(&ad->flow_parser);
cpfl_tdi_program_destroy(ad->flow_parser.p4_parser);
+ }
cpfl_flow_engine_uninit(ad);
}
diff --git a/drivers/net/cpfl/cpfl_flow.h b/drivers/net/cpfl/cpfl_flow.h
index 1bde847763..1de9c25b17 100644
--- a/drivers/net/cpfl/cpfl_flow.h
+++ b/drivers/net/cpfl/cpfl_flow.h
@@ -15,6 +15,7 @@ extern const struct rte_flow_ops cpfl_flow_ops;
enum cpfl_flow_engine_type {
CPFL_FLOW_ENGINE_NONE = 0,
CPFL_FLOW_ENGINE_FXP,
+ CPFL_FLOW_ENGINE_TDI,
};
typedef int (*engine_init_t)(struct cpfl_adapter_ext *ad);
diff --git a/drivers/net/cpfl/cpfl_flow_engine_fxp.c b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
index f269ff97e1..6a5e7ed770 100644
--- a/drivers/net/cpfl/cpfl_flow_engine_fxp.c
+++ b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
@@ -27,23 +27,11 @@
#include "cpfl_fxp_rule.h"
#include "cpfl_flow_parser.h"
-#define CPFL_COOKIE_DEF 0x1000
-#define CPFL_MOD_COOKIE_DEF 0x1237561
#define CPFL_PREC_DEF 1
#define CPFL_PREC_SET 5
#define CPFL_TYPE_ID 3
#define CPFL_OFFSET 0x0a
-#define CPFL_HOST_ID_DEF 0
#define CPFL_PF_NUM_DEF 0
-#define CPFL_PORT_NUM_DEF 0
-#define CPFL_RESP_REQ_DEF 2
-#define CPFL_PIN_TO_CACHE_DEF 0
-#define CPFL_CLEAR_MIRROR_1ST_STATE_DEF 0
-#define CPFL_FIXED_FETCH_DEF 0
-#define CPFL_PTI_DEF 0
-#define CPFL_MOD_OBJ_SIZE_DEF 0
-#define CPFL_PIN_MOD_CONTENT_DEF 0
-
#define CPFL_MAX_MOD_CONTENT_INDEX 256
#define CPFL_MAX_MR_ACTION_NUM 8
diff --git a/drivers/net/cpfl/cpfl_flow_parser.c b/drivers/net/cpfl/cpfl_flow_parser.c
index e7f8a8a6cc..a3572e32d5 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.c
+++ b/drivers/net/cpfl/cpfl_flow_parser.c
@@ -6,6 +6,7 @@
#include "cpfl_flow_parser.h"
#include "cpfl_tdi_parser.h"
+#include "cpfl_tdi.h"
static enum rte_flow_item_type
cpfl_get_item_type_by_str(const char *type)
@@ -976,6 +977,13 @@ cpfl_parser_create(struct cpfl_flow_parser *flow_parser, const char *filename)
flow_parser->p4_parser = prog;
flow_parser->fixed_parser = NULL;
flow_parser->is_p4_parser = true;
+
+ ret = cpfl_tdi_build(flow_parser);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to build tdi program %s", filename);
+ rte_free(prog);
+ return -EINVAL;
+ }
} else {
PMD_DRV_LOG(NOTICE, "flow parser mode is fixed function mode.");
parser = rte_zmalloc("flow_parser", sizeof(struct cpfl_flow_js_parser), 0);
diff --git a/drivers/net/cpfl/cpfl_fxp_rule.h b/drivers/net/cpfl/cpfl_fxp_rule.h
index ed757b80b1..f089155353 100644
--- a/drivers/net/cpfl/cpfl_fxp_rule.h
+++ b/drivers/net/cpfl/cpfl_fxp_rule.h
@@ -9,6 +9,18 @@
#define CPFL_MAX_KEY_LEN 128
#define CPFL_MAX_RULE_ACTIONS 32
+#define CPFL_RESP_REQ_DEF 2
+#define CPFL_PIN_TO_CACHE_DEF 0
+#define CPFL_CLEAR_MIRROR_1ST_STATE_DEF 0
+#define CPFL_FIXED_FETCH_DEF 0
+#define CPFL_PTI_DEF 0
+#define CPFL_MOD_OBJ_SIZE_DEF 0
+#define CPFL_PIN_MOD_CONTENT_DEF 0
+#define CPFL_HOST_ID_DEF 0
+#define CPFL_PORT_NUM_DEF 0
+#define CPFL_VSI_DEF 0
+#define CPFL_COOKIE_DEF 0x1000
+#define CPFL_MOD_COOKIE_DEF 0x1237561
struct cpfl_sem_rule_info {
uint16_t prof_id;
diff --git a/drivers/net/cpfl/cpfl_tdi.c b/drivers/net/cpfl/cpfl_tdi.c
new file mode 100644
index 0000000000..b7dd3e4764
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi.c
@@ -0,0 +1,1244 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#include <asm-generic/errno-base.h>
+#include <rte_hash_crc.h>
+#include <rte_tailq.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "cpfl_actions.h"
+#include "cpfl_flow.h"
+#include "cpfl_fxp_rule.h"
+#include "cpfl_tdi.h"
+#include "cpfl_tdi_parser.h"
+#include "rte_common.h"
+#include "rte_flow.h"
+
+uint64_t cpfl_tdi_rule_cookie = CPFL_COOKIE_DEF;
+
+/*help function to do left shift on a byte array */
+static void
+cpfl_tdi_shift_left(uint8_t *buf, int length, uint32_t shift_amount)
+{
+ uint32_t i;
+ int j;
+ uint32_t carry = 0;
+
+ if (shift_amount == 0)
+ return;
+
+ for (i = 0; i < shift_amount; i += 8) {
+ for (j = 0; j < length; j++) {
+ uint32_t temp = (buf[j] << (shift_amount - i)) | carry;
+
+ carry = (temp >> 8) & 0xff;
+ buf[j] = temp & 0xff;
+ }
+ }
+}
+
+/* help function to init a mask array with bit_width */
+static void
+cpfl_tdi_init_msk_buf(uint8_t *buf, int length, uint32_t bit_width)
+{
+ uint32_t i;
+
+ memset(buf, 0, length);
+ for (i = 0; i < bit_width; i++) {
+ cpfl_tdi_shift_left(buf, length, 1);
+ buf[0] += 1;
+ }
+}
+
+/* help function to OR a byte array with value and mask */
+static void
+cpfl_tdi_or_buf(uint8_t *buf, int length, uint8_t *values, uint8_t *mask)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ buf[i] = (values[i] & mask[i]) | (buf[i] & ~mask[i]);
+}
+
+static uint32_t
+cpfl_tdi_to_action_code(struct cpfl_tdi_hw_action *ha, uint8_t *val)
+{
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ switch (ha->index) {
+ case 0: /* mod addr */
+ return cpfl_act_mod_addr(ha->prec, (uint32_t)*val).data;
+ case 8: /* todo */
+ break;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported SET1A_24b index %d", ha->index);
+ break;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1_16b:
+ switch (ha->index) {
+ case 2: /* set vsi */
+ return cpfl_act_fwd_vsi(0, ha->prec, CPFL_PE_LAN, (uint16_t)*val).data;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported SET1_16b index %d", ha->index);
+ break;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+ switch (ha->setmd_action_code) {
+ case CPFL_TDI_SETMD_ACTION_CODE_SET_16b:
+ return cpfl_act_set_md16(ha->index, ha->prec, ha->type_id, ha->offset,
+ (uint16_t)*val)
+ .data;
+ case CPFL_TDI_SETMD_ACTION_CODE_SET_32b_AUX: /* todo */
+ return cpfl_act_fwd_vsi(0, ha->prec, CPFL_PE_LAN, (uint16_t)*val).data;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported SET1b_24b setmd code %d",
+ ha->setmd_action_code);
+ break;
+ }
+ break;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported action code %d", ha->action_code);
+ break;
+ }
+
+ return 0;
+}
+
+static void
+cpfl_tdi_pack_sem_entry(struct cpfl_tdi_rule_info *rinfo,
+ struct cpfl_tdi_ma_hardware_block *hb,
+ enum cpfl_tdi_table_entry_op op,
+ struct idpf_dma_mem *dma,
+ struct idpf_ctlq_msg *msg)
+{
+ union cpfl_rule_cfg_pkt_record *blob;
+ struct cpfl_rule_cfg_data cfg = {0};
+ uint16_t cfg_ctrl;
+ enum cpfl_ctlq_rule_cfg_opc opc = 0;
+ const struct cpfl_tdi_table_key_obj *key = &rinfo->kobj;
+ const struct cpfl_tdi_action_obj *action = &rinfo->aobj;
+
+ blob = (void *)dma->va;
+ memset(blob, 0, sizeof(*blob));
+
+ cfg_ctrl = CPFL_GET_MEV_SEM_RULE_CFG_CTRL(hb->profile[0], hb->sem.sub_profile, 0, 0);
+
+ switch (op) {
+ case CPFL_TDI_TABLE_ENTRY_OP_ADD:
+ cpfl_prep_sem_rule_blob(key->buf, key->buf_len, action->buf, action->buf_len,
+ cfg_ctrl, blob);
+ opc = cpfl_ctlq_sem_add_rule;
+ break;
+ case CPFL_TDI_TABLE_ENTRY_OP_DEL:
+ cpfl_prep_sem_rule_blob(key->buf, key->buf_len, NULL, 0, cfg_ctrl, blob);
+ opc = cpfl_ctlq_sem_del_rule;
+ break;
+ case CPFL_TDI_TABLE_ENTRY_OP_QRY:
+ cpfl_prep_sem_rule_blob(key->buf, key->buf_len, NULL, 0, cfg_ctrl, blob);
+ opc = cpfl_ctlq_sem_query_rule;
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown ops, this is a bug.");
+ break;
+ }
+
+ cpfl_fill_rule_cfg_data_common(opc,
+ rinfo->cookie,
+ rinfo->vsi,
+ rinfo->port_num,
+ rinfo->host_id,
+ 0, /* time_sel */
+ 0, /* time_sel_val */
+ 0, /* cache_wr_thru */
+ rinfo->resp_req,
+ sizeof(union cpfl_rule_cfg_pkt_record),
+ dma,
+ &cfg.common);
+
+ cpfl_prep_rule_desc(&cfg, msg);
+}
+
+static void
+cpfl_tdi_pack_mod_entry(struct cpfl_tdi_rule_info *rinfo,
+ enum cpfl_tdi_table_entry_op op,
+ struct idpf_dma_mem *dma,
+ struct idpf_ctlq_msg *msg)
+{
+ union cpfl_rule_cfg_pkt_record *blob;
+ struct cpfl_rule_cfg_data cfg = {0};
+ uint32_t mod_index;
+ enum cpfl_ctlq_rule_cfg_opc opc = 0;
+ const struct cpfl_tdi_table_key_obj *key = &rinfo->kobj;
+ const struct cpfl_tdi_action_obj *action = &rinfo->aobj;
+
+ blob = (void *)dma->va;
+ memset(blob, 0, sizeof(*blob));
+
+ mod_index = *(const uint32_t *)&key->buf[0];
+
+ switch (op) {
+ case CPFL_TDI_TABLE_ENTRY_OP_ADD:
+ cpfl_fill_rule_mod_content(CPFL_MOD_OBJ_SIZE_DEF, CPFL_PIN_MOD_CONTENT_DEF,
+ mod_index, &cfg.ext.mod_content);
+
+ rte_memcpy(blob->mod_blob, action->buf, action->buf_len);
+ opc = cpfl_ctlq_mod_add_update_rule;
+ break;
+ case CPFL_TDI_TABLE_ENTRY_OP_QRY:
+ opc = cpfl_ctlq_mod_query_rule;
+ break;
+ default:
+ break;
+ }
+
+ cpfl_fill_rule_cfg_data_common(opc,
+ CPFL_MOD_COOKIE_DEF,
+ 0, /* vsi_id not used for mod */
+ CPFL_PORT_NUM_DEF,
+ 0,
+ 0, /* time_sel */
+ 0, /* time_sel_val */
+ 0, /* cache_wr_thru */
+ CPFL_RESP_REQ_DEF,
+ sizeof(union cpfl_rule_cfg_pkt_record),
+ dma,
+ &cfg.common);
+
+ cpfl_prep_rule_desc(&cfg, msg);
+}
+
+static int
+cpfl_tdi_rule_process(struct cpfl_itf *itf,
+ struct idpf_ctlq_info *tx_cq,
+ struct idpf_ctlq_info *rx_cq,
+ struct cpfl_tdi_rule_info *rinfo,
+ int rule_num,
+ enum cpfl_tdi_table_entry_op op)
+{
+ const struct cpfl_tdi_table_key_obj *kobj;
+ struct idpf_hw *hw = &itf->adapter->base.hw;
+ struct cpfl_tdi_ma_hardware_block *hb;
+ const struct cpfl_tdi_table *table;
+ int ret = 0;
+
+ if (rule_num == 0)
+ return 0;
+
+ kobj = &rinfo->kobj;
+
+ table = kobj->tnode->table;
+ if (table->match_attributes.hardware_block_num == 0) {
+ PMD_DRV_LOG(ERR, "No valid hardware block be specified");
+ return -EINVAL;
+ }
+ hb = &table->match_attributes.hardware_blocks[0];
+ switch (hb->hw_block) {
+ case CPFL_TDI_HW_BLOCK_SEM:
+ cpfl_tdi_pack_sem_entry(rinfo, hb, op, &itf->dma[0], &itf->msg[0]);
+ break;
+ case CPFL_TDI_HW_BLOCK_MOD:
+ if (op == CPFL_TDI_TABLE_ENTRY_OP_DEL)
+ /* do nothing */
+ return 0;
+ cpfl_tdi_pack_mod_entry(rinfo, op, &itf->dma[0], &itf->msg[0]);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unsupported hardware block %d", hb->hw_block);
+ return -EINVAL;
+ }
+
+ ret = cpfl_send_ctlq_msg(hw, tx_cq, 1, itf->msg);
+ if (ret != 0) {
+ PMD_DRV_LOG(ERR, "Failed to send control message");
+ return -EINVAL;
+ }
+
+ ret = cpfl_receive_ctlq_msg(hw, rx_cq, 1, itf->msg);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to update rule");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+cpfl_tdi_fxp_rule_create(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ void *meta,
+ struct rte_flow_error *error)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *ad = itf->adapter;
+ int ret;
+ uint32_t cpq_id = 0;
+ struct cpfl_vport *vport;
+ struct cpfl_repr *repr;
+ struct cpfl_tdi_rule_info *rinfo = meta;
+
+ if (!rinfo)
+ goto err;
+
+ if (itf->type == CPFL_ITF_TYPE_VPORT) {
+ vport = (struct cpfl_vport *)itf;
+ /* Every vport has one pair control queues configured to handle message.
+ * Even index is tx queue and odd index is rx queue.
+ */
+ cpq_id = vport->base.devarg_id * 2;
+ } else if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) {
+ repr = (struct cpfl_repr *)itf;
+ cpq_id = ((repr->repr_id.pf_id + repr->repr_id.vf_id) & (CPFL_TX_CFGQ_NUM - 1)) * 2;
+ } else {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "fail to find correct control queue");
+ return -rte_errno;
+ }
+
+ ret = cpfl_tdi_rule_process(itf, ad->ctlqp[cpq_id], ad->ctlqp[cpq_id + 1], rinfo, 1,
+ CPFL_TDI_TABLE_ENTRY_OP_ADD);
+ if (ret)
+ goto err;
+
+ flow->rule = rinfo;
+
+ return 0;
+
+err:
+ return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "cpfl filter create flow fail");
+}
+
+static int
+cpfl_tdi_fxp_rule_destroy(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ struct rte_flow_error *error)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *ad = itf->adapter;
+ struct cpfl_vport *vport;
+ struct cpfl_repr *repr;
+ struct cpfl_tdi_rule_info *rinfo = (struct cpfl_tdi_rule_info *)flow->rule;
+ int ret = 0;
+ uint32_t cpq_id = 0;
+
+ if (itf->type == CPFL_ITF_TYPE_VPORT) {
+ vport = (struct cpfl_vport *)itf;
+ cpq_id = vport->base.devarg_id * 2;
+ } else if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) {
+ repr = (struct cpfl_repr *)itf;
+ cpq_id = ((repr->repr_id.pf_id + repr->repr_id.vf_id) & (CPFL_TX_CFGQ_NUM - 1)) * 2;
+ } else {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "fail to find correct control queue");
+ ret = -rte_errno;
+ goto err;
+ }
+
+ ret = cpfl_tdi_rule_process(itf, ad->ctlqp[cpq_id], ad->ctlqp[cpq_id + 1], rinfo, 1,
+ CPFL_TDI_TABLE_ENTRY_OP_DEL);
+ if (ret)
+ goto err;
+
+err:
+ rte_free(rinfo);
+ flow->rule = NULL;
+ return ret;
+}
+
+void
+cpfl_tdi_free_table_list(struct cpfl_flow_parser *flow_parser)
+{
+ struct cpfl_tdi_table_node *node;
+
+ while ((node = TAILQ_FIRST(&flow_parser->tdi_table_list))) {
+ TAILQ_REMOVE(&flow_parser->tdi_table_list, node, next);
+ rte_free(node);
+ }
+}
+
+static int
+cpfl_tdi_build_table_list(struct cpfl_flow_parser *flow_parser)
+{
+ struct cpfl_tdi_program *prog = flow_parser->p4_parser;
+ int i;
+
+ TAILQ_INIT(&flow_parser->tdi_table_list);
+
+ for (i = 0; i < prog->table_num; i++) {
+ struct cpfl_tdi_table *table = &prog->tables[i];
+ struct cpfl_tdi_table_node *node;
+
+ node = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_table_node), 0);
+ if (node == NULL)
+ return -ENOMEM;
+
+ node->table = table;
+ TAILQ_INSERT_TAIL(&flow_parser->tdi_table_list, node, next);
+ }
+
+ return 0;
+}
+
+static void
+cpfl_tdi_build_hw_action_buf(struct cpfl_tdi_action_node *node)
+{
+ int i, j;
+
+ for (i = 0; i < node->format->hw_action_num; i++) {
+ struct cpfl_tdi_hw_action *ha = &node->format->hw_actions_list[i];
+ struct cpfl_tdi_hw_action_parameter *hap = &ha->parameters[0];
+ uint32_t msk = UINT32_MAX;
+ uint32_t action_code = 0;
+ uint16_t offset;
+ uint16_t size;
+
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET10_1b:
+ case CPFL_TDI_ACTION_CODE_SET1_16b:
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ case CPFL_TDI_ACTION_CODE_SET1B_24b:
+ offset = node->buf_len;
+ size = 4;
+ node->buf_len += 4; /* 32 bit action encode */
+ break;
+ default:
+ continue;
+ }
+
+ if (ha->parameter_num == 0) {
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET10_1b:
+ switch (ha->index) {
+ case 0: /* drop */
+ action_code = CPFL_ACT_MAKE_1B(ha->prec,
+ CPFL_ACT_1B_OP_DROP,
+ ha->value & ha->mask);
+ break;
+ default:
+ continue;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ switch (ha->index) {
+ case 9: /* mod profile */
+ action_code =
+ cpfl_act_mod_profile(ha->prec, ha->mod_profile, 0, 0, 0,
+ CPFL_ACT_MOD_PROFILE_PREFETCH_256B)
+ .data;
+ break;
+ case 8: /* queue */
+ /* todo */
+ break;
+ default:
+ break;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+ switch (ha->setmd_action_code) {
+ case CPFL_TDI_SETMD_ACTION_CODE_SET_8b:
+ action_code =
+ cpfl_act_set_md8(ha->index, ha->prec, ha->type_id,
+ ha->offset, ha->value, ha->mask)
+ .data;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ rte_memcpy(&node->init_buf[offset], &action_code, 4);
+ rte_memcpy(&node->query_msk[offset], &msk, 4);
+ continue;
+ } else {
+ uint32_t code_msk = 0;
+ uint32_t dummy = 0;
+ uint32_t action_code = cpfl_tdi_to_action_code(ha, (void *)&dummy);
+
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET10_1b:
+ code_msk = ~CPFL_ACT_1B_VAL_M;
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1_16b:
+ code_msk = ~CPFL_ACT_16B_VAL_M;
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ code_msk = ~CPFL_ACT_24B_A_VAL_M;
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+ code_msk = ~CPFL_ACT_24B_B_VAL_M;
+ break;
+ default:
+ continue;
+ }
+
+ rte_memcpy(&node->init_buf[offset], &action_code, 4);
+ rte_memcpy(&node->query_msk[offset], &code_msk, 4);
+ }
+
+ /* only check the first parameter */
+ for (j = 0; j < node->format->immediate_field_num; j++) {
+ struct cpfl_tdi_immediate_field *imf = &node->format->immediate_fields[j];
+
+ if (imf->param_handle == hap->param_handle) {
+ node->params[j].id = imf->param_handle;
+ node->params[j].offset = offset;
+ node->params[j].size = size;
+ }
+ }
+ }
+}
+
+static void
+cpfl_tdi_build_mod_content_format_buf(struct cpfl_tdi_action_node *node)
+{
+ int i, j;
+ uint8_t val_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+ uint8_t msk_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+
+ for (i = 0; i < node->format->mod_content_format.mod_field_num; i++) {
+ struct cpfl_tdi_mod_field *mf = &node->format->mod_content_format.mod_fields[i];
+ uint16_t size = (uint16_t)((mf->start_bit_offset + mf->bit_width) >> 3);
+
+ node->buf_len += size;
+
+ if (mf->type == CPFL_TDI_MOD_FIELD_TYPE_CONSTANT) {
+ rte_memcpy(val_buf, mf->value, size);
+ cpfl_tdi_shift_left(val_buf, size, mf->start_bit_offset);
+ cpfl_tdi_init_msk_buf(msk_buf, size, mf->bit_width);
+ cpfl_tdi_shift_left(msk_buf, size, mf->start_bit_offset);
+ cpfl_tdi_or_buf(&node->init_buf[mf->byte_array_index], size, val_buf,
+ msk_buf);
+ continue;
+ }
+
+ for (j = 0; j < node->format->immediate_field_num; j++) {
+ struct cpfl_tdi_immediate_field *imf = &node->format->immediate_fields[j];
+
+ if (imf->param_handle == mf->param_handle) {
+ node->params[j].id = imf->param_handle;
+ node->params[j].offset = mf->byte_array_index;
+ node->params[j].size = size;
+ break;
+ }
+ }
+ }
+}
+
+static void
+cpfl_tdi_build_action_params(struct cpfl_tdi_action_node *node)
+{
+ node->buf_len = 0;
+ /* build mod content layout */
+ if (node->format->mod_content_format.mod_field_num > 0) {
+ cpfl_tdi_build_mod_content_format_buf(node);
+ /* build action buffer layout */
+ } else if (node->format->hw_action_num > 0) {
+ cpfl_tdi_build_hw_action_buf(node);
+ }
+}
+
+static void
+cpfl_tdi_free_action_list(struct cpfl_flow_parser *flow_parser)
+{
+ struct cpfl_tdi_action_node *action;
+
+ while ((action = TAILQ_FIRST(&flow_parser->tdi_action_list))) {
+ TAILQ_REMOVE(&flow_parser->tdi_action_list, action, next);
+ rte_free(action);
+ }
+}
+
+static int
+cpfl_tdi_build_action_list(struct cpfl_flow_parser *flow_parser)
+{
+#define _HASH_TABLE_NAME_SIZE 32
+#define _HASH_TABLE_ENTRY_SIZE 1024
+ struct cpfl_tdi_program *prog = flow_parser->p4_parser;
+ char hname[_HASH_TABLE_NAME_SIZE];
+ struct rte_hash *ht;
+ int ret = 0;
+ int i, j, k;
+
+ snprintf(hname, _HASH_TABLE_NAME_SIZE, "cpfl_tdi_action_hash");
+
+ struct rte_hash_parameters params = {
+ .name = hname,
+ .entries = _HASH_TABLE_ENTRY_SIZE,
+ .key_len = sizeof(uint32_t),
+ .hash_func = rte_hash_crc,
+ .hash_func_init_val = 0,
+ .socket_id = SOCKET_ID_ANY,
+ .extra_flag = 0,
+ };
+
+ ht = rte_hash_create(¶ms);
+
+ if (ht == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to create hash table %s", hname);
+ return -EINVAL;
+ }
+
+ TAILQ_INIT(&flow_parser->tdi_action_list);
+
+ for (i = 0; i < prog->table_num; i++) {
+ struct cpfl_tdi_table *table = &prog->tables[i];
+
+ for (j = 0; j < table->action_num; j++) {
+ struct cpfl_tdi_action *action = &table->actions[j];
+ uint32_t handle = action->handle;
+ struct cpfl_tdi_action_node *node;
+
+ /* skip if already exist */
+ if (rte_hash_lookup(ht, &handle) >= 0)
+ continue;
+
+ node = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_action_node), 0);
+ if (node == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ node->action = action;
+ ret = rte_hash_add_key_data(ht, &handle, node);
+ if (ret != 0)
+ goto err;
+
+ TAILQ_INSERT_TAIL(&flow_parser->tdi_action_list, node, next);
+ }
+
+ for (j = 0; j < table->match_attributes.hardware_block_num; j++) {
+ struct cpfl_tdi_ma_hardware_block *hb =
+ &table->match_attributes.hardware_blocks[j];
+
+ for (k = 0; k < hb->action_format_num; k++) {
+ struct cpfl_tdi_action_format *format = &hb->action_format[k];
+ uint32_t handle = format->action_handle;
+ struct cpfl_tdi_action_node *node = NULL;
+
+ if (rte_hash_lookup_data(ht, &handle, (void **)&node) >= 0) {
+ node->hw_block_type = hb->hw_block;
+ if (node->format == NULL) {
+ node->format = format;
+ cpfl_tdi_build_action_params(node);
+ }
+ }
+ }
+ }
+ }
+
+ rte_hash_free(ht);
+
+ return 0;
+
+err:
+
+ rte_hash_free(ht);
+ cpfl_tdi_free_action_list(flow_parser);
+ return ret;
+}
+
+static int
+cpfl_tdi_table_info_get(struct rte_eth_dev *dev,
+ uint32_t table_id,
+ struct cpfl_tdi_table_node **table_node)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *adapter = itf->adapter;
+ struct cpfl_tdi_table_node *node;
+ void *temp;
+ int i;
+
+ RTE_TAILQ_FOREACH_SAFE(node, &adapter->flow_parser.tdi_table_list, next, temp)
+ {
+ const struct cpfl_tdi_table *table = node->table;
+
+ if (table->handle != table_id)
+ continue;
+
+ if (table->match_key_field_num > CPFL_TDI_KEY_FIELD_NUM_MAX) {
+ PMD_DRV_LOG(ERR, "Too many fields (%d) in tdi table %s",
+ table->match_key_field_num, table->name);
+ goto err;
+ }
+
+ if (table->action_num > CPFL_TDI_ACTION_SPEC_NUM_MAX) {
+ PMD_DRV_LOG(ERR, "Too many action types (%d) in tdi table %s",
+ table->action_num, table->name);
+ goto err;
+ }
+
+ /* match_key_field first */
+ if (table->match_key_format_num == 0) {
+ node->buf_len = 0;
+ for (i = 0; i < table->match_key_field_num; i++) {
+ struct cpfl_tdi_match_key_field *field =
+ &table->match_key_fields[i];
+ uint32_t size = (uint16_t)(field->bit_width >> 3);
+
+ node->params[i].id = field->index;
+ node->params[i].offset =
+ node->buf_len; /* equal with field->position */
+ node->params[i].size = size;
+ node->buf_len += size;
+ }
+ } else {
+ for (i = 0; i < table->match_key_format_num; i++) {
+ struct cpfl_tdi_match_key_format *format =
+ &table->match_key_format[i];
+
+ node->buf_len =
+ format->byte_array_index + (uint16_t)(format->bit_width >> 3);
+ node->params[i].id = format->match_key_handle;
+ node->params[i].offset = format->byte_array_index;
+ node->params[i].size = (uint16_t)(format->bit_width >> 3);
+ }
+ }
+ *table_node = node;
+
+ return 0;
+ }
+
+err:
+ return -EINVAL;
+}
+
+static int
+cpfl_tdi_table_key_node_init(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_table_node *node,
+ struct cpfl_tdi_table_key_obj *kobj)
+{
+ kobj->tnode = node;
+ kobj->buf_len = node->buf_len;
+ kobj->sem.pin_to_cache = CPFL_PIN_TO_CACHE_DEF;
+ kobj->sem.fixed_fetch = CPFL_FIXED_FETCH_DEF;
+ return 0;
+}
+
+static int
+cpfl_tdi_table_key_create(struct rte_eth_dev *dev,
+ uint32_t table_id,
+ struct cpfl_tdi_table_node **table_node,
+ struct cpfl_tdi_table_key_obj *kobj)
+{
+ int ret;
+
+ if (!kobj)
+ return -EINVAL;
+
+ ret = cpfl_tdi_table_info_get(dev, table_id, table_node);
+ if (ret != 0)
+ return -EINVAL;
+
+ ret = cpfl_tdi_table_key_node_init(dev, *table_node, kobj);
+ if (ret != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_table_key_field_info_get(__rte_unused struct rte_eth_dev *dev,
+ struct cpfl_tdi_table_node *node,
+ uint32_t field_id,
+ struct cpfl_tdi_table_key_field_info **key_field_info)
+{
+ const struct cpfl_tdi_table *table = node->table;
+ int i, j;
+
+ for (i = 0; i < table->match_key_field_num; i++) {
+ struct cpfl_tdi_match_key_field *field = &table->match_key_fields[i];
+ struct cpfl_tdi_table_key_field_info *tkfinfo;
+
+ if (field->index != field_id)
+ continue;
+
+ tkfinfo = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_table_key_field_info), 0);
+ if (tkfinfo == NULL)
+ return -ENOMEM;
+
+ tkfinfo->field = field;
+ tkfinfo->param = node->params[i];
+ *key_field_info = tkfinfo;
+
+ /* adjust byte width */
+ for (j = 0; j < table->match_key_format_num; j++) {
+ struct cpfl_tdi_match_key_format *format = &table->match_key_format[j];
+
+ if (format->match_key_handle != field_id)
+ continue;
+ tkfinfo->format = format;
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int
+_cpfl_tdi_table_key_field_set(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_table_key_obj *kobj,
+ struct cpfl_tdi_table_key_field_info *tkfinfo,
+ const uint8_t *value,
+ uint16_t size)
+{
+ struct cpfl_tdi_param_info *pi = &tkfinfo->param;
+ uint8_t *target = &kobj->buf[pi->offset];
+
+ rte_memcpy(target, value, size);
+
+ /* Need to fix as this will overwrite. */
+ if (tkfinfo->format != NULL)
+ cpfl_tdi_shift_left(target, pi->size, tkfinfo->format->start_bit_offset);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_table_key_field_set(struct rte_eth_dev *dev,
+ struct cpfl_tdi_table_node *table_node,
+ struct cpfl_tdi_table_key_obj *kobj,
+ uint32_t field_id,
+ const uint8_t *value,
+ uint16_t size)
+{
+ struct cpfl_tdi_table_key_field_info *key_field_info;
+ int ret;
+
+ if (!kobj || !value)
+ return -EINVAL;
+
+ ret = cpfl_tdi_table_key_field_info_get(dev, table_node, field_id, &key_field_info);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (key_field_info->field->match_type != CPFL_TDI_MATCH_TYPE_EXACT)
+ return -EINVAL;
+
+ ret = _cpfl_tdi_table_key_field_set(dev, kobj, key_field_info, value, size);
+ if (ret != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_action_spec_info_get(struct rte_eth_dev *dev,
+ uint32_t spec_id,
+ struct cpfl_tdi_action_node **action_node)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *adapter = itf->adapter;
+ struct cpfl_tdi_action_node *node;
+ void *temp;
+
+ RTE_TAILQ_FOREACH_SAFE(node, &adapter->flow_parser.tdi_action_list, next, temp)
+ {
+ if (node->action->handle != spec_id)
+ continue;
+ *action_node = node;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int
+cpfl_tdi_action_obj_init(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_table_node *tnode,
+ struct cpfl_tdi_action_node *anode,
+ struct cpfl_tdi_action_obj *aobj)
+{
+ aobj->table = tnode->table;
+ aobj->node = anode;
+ aobj->buf_len = anode->buf_len;
+
+ rte_memcpy(aobj->buf, anode->init_buf, anode->buf_len);
+
+ return 0;
+}
+
+static inline bool __rte_unused
+verify_action(struct cpfl_tdi_table_node *table_node, uint32_t spec_id)
+{
+ int i;
+ const struct cpfl_tdi_table *table = table_node->table;
+
+ for (i = 0; i < table->action_num; i++)
+ if (spec_id == table->actions[i].handle)
+ return true;
+
+ return false;
+}
+
+static int
+cpfl_tdi_action_node_get_by_spec_id(struct rte_eth_dev *dev,
+ uint32_t table_id __rte_unused,
+ uint32_t spec_id,
+ struct cpfl_tdi_action_node **action_node)
+{
+ return cpfl_tdi_action_spec_info_get(dev, spec_id, action_node);
+}
+
+static int
+cpfl_tdi_action_spec_field_info_get(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_action_node *anode,
+ uint32_t field_id,
+ struct cpfl_tdi_action_spec_field_info **info)
+{
+ int ret = -EINVAL;
+ int i, j;
+
+ if (anode->format == NULL)
+ goto err;
+
+ for (i = 0; i < anode->format->immediate_field_num; i++) {
+ struct cpfl_tdi_immediate_field *field = &anode->format->immediate_fields[i];
+ struct cpfl_tdi_action_spec_field_info *asfinfo;
+
+ if (field->param_handle != field_id)
+ continue;
+
+ asfinfo = rte_malloc(NULL, sizeof(struct cpfl_tdi_action_spec_field_info), 0);
+ if (asfinfo == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ asfinfo->field = field;
+ asfinfo->param = anode->params[i];
+
+ for (j = 0; j < anode->format->mod_content_format.mod_field_num; j++) {
+ struct cpfl_tdi_mod_field *mod_field =
+ &anode->format->mod_content_format.mod_fields[j];
+
+ if (mod_field->type != CPFL_TDI_MOD_FIELD_TYPE_PARAMETER)
+ continue;
+
+ if (mod_field->param_handle != field_id)
+ continue;
+
+ asfinfo->mod_field = mod_field;
+ }
+
+ for (i = 0; i < anode->format->hw_action_num; i++) {
+ struct cpfl_tdi_hw_action *hw_action = &anode->format->hw_actions_list[i];
+
+ if (hw_action->parameter_num == 0)
+ continue;
+
+ if (hw_action->parameters[0].param_handle != field_id)
+ continue;
+
+ asfinfo->hw_action = hw_action;
+ }
+
+ *info = asfinfo;
+
+ return 0;
+ }
+ PMD_DRV_LOG(WARNING, "No immediate_field_num!!!");
+err:
+ return ret;
+}
+
+static int
+_cpfl_tdi_action_field_set(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_action_obj *aobj,
+ struct cpfl_tdi_action_spec_field_info *asfinfo,
+ const uint8_t *value,
+ uint16_t size)
+{
+ struct cpfl_tdi_action_node *node = aobj->node;
+ struct cpfl_tdi_param_info *pi = &asfinfo->param;
+ uint8_t val_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+ uint8_t msk_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+
+ rte_memcpy(val_buf, value, size);
+
+ if (node->format->mod_content_format.mod_field_num > 0) {
+ struct cpfl_tdi_mod_field *mf = asfinfo->mod_field;
+
+ cpfl_tdi_shift_left(val_buf, pi->size, mf->start_bit_offset);
+ cpfl_tdi_init_msk_buf(msk_buf, pi->size, mf->bit_width);
+ cpfl_tdi_shift_left(msk_buf, pi->size, mf->start_bit_offset);
+ cpfl_tdi_or_buf(&aobj->buf[pi->offset], pi->size, val_buf, msk_buf);
+ } else {
+ struct cpfl_tdi_hw_action *ha = asfinfo->hw_action;
+ uint32_t action_code = cpfl_tdi_to_action_code(ha, val_buf);
+
+ rte_memcpy(&aobj->buf[pi->offset], &action_code, 4);
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_action_field_set(struct rte_eth_dev *dev,
+ struct cpfl_tdi_action_obj *aobj,
+ struct cpfl_tdi_action_node *action_node,
+ uint32_t field_id,
+ const struct rte_flow_action_prog_argument *arg)
+{
+ struct cpfl_tdi_action_spec_field_info *asfinfo;
+ enum rte_flow_action_type action_type;
+ /* used when action is PORT_REPRESENTOR type */
+ struct cpfl_itf *dst_itf;
+ uint16_t dev_id; /* vsi id */
+ uint8_t value;
+ bool is_vsi;
+ int ret;
+
+ if (!aobj || !arg)
+ return -EINVAL;
+
+ ret = cpfl_tdi_action_spec_field_info_get(dev, action_node, field_id, &asfinfo);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(arg->name, "port_representor"))
+ action_type = RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR;
+ else if (!strcmp(arg->name, "represented_port"))
+ action_type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT;
+ else
+ return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, arg->value, arg->size);
+
+ if (arg->size != 1)
+ return -EINVAL;
+
+ dst_itf = cpfl_get_itf_by_port_id(arg->value[0]);
+ if (!dst_itf)
+ goto err;
+
+ is_vsi = (action_type == RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR ||
+ dst_itf->type == CPFL_ITF_TYPE_REPRESENTOR);
+ if (is_vsi)
+ dev_id = cpfl_get_vsi_id(dst_itf);
+ else
+ dev_id = cpfl_get_port_id(dst_itf);
+
+ if (dev_id == CPFL_INVALID_HW_ID)
+ goto err;
+
+ value = (uint8_t)dev_id;
+
+ return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, &value, arg->size);
+err:
+ PMD_DRV_LOG(ERR, "Can not get dev id.");
+ return -EINVAL;
+
+ return 0;
+}
+
+int
+cpfl_tdi_build(struct cpfl_flow_parser *flow_parser)
+{
+ int ret;
+
+ ret = cpfl_tdi_build_table_list(flow_parser);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to build tdi table list");
+ return ret;
+ }
+
+ ret = cpfl_tdi_build_action_list(flow_parser);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to build tdi action list");
+ cpfl_tdi_free_table_list(flow_parser);
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool
+cpfl_flow_items_all_is_flex(const struct rte_flow_item pattern[])
+{
+ int i;
+
+ for (i = 0; pattern[i].type != RTE_FLOW_ITEM_TYPE_END; i++) {
+ if (pattern[i].type != RTE_FLOW_ITEM_TYPE_FLEX)
+ return false;
+ }
+ return true;
+}
+
+static void
+cpfl_fill_rinfo_default_value(struct cpfl_tdi_rule_info *rinfo)
+{
+ if (cpfl_tdi_rule_cookie == ~0llu)
+ cpfl_tdi_rule_cookie = CPFL_COOKIE_DEF;
+ rinfo->cookie = cpfl_tdi_rule_cookie++;
+ rinfo->host_id = CPFL_HOST_ID_DEF;
+ rinfo->port_num = CPFL_PORT_NUM_DEF;
+ rinfo->resp_req = CPFL_RESP_REQ_DEF;
+ rinfo->vsi = CPFL_VSI_DEF;
+ rinfo->clear_mirror_1st_state = CPFL_CLEAR_MIRROR_1ST_STATE_DEF;
+}
+
+static int
+cpfl_tdi_parse_pattern(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ uint32_t table_id,
+ struct cpfl_tdi_table_node **table_node,
+ struct cpfl_tdi_table_key_obj *kobj)
+{
+ const struct rte_flow_item_flex *flex;
+ int i, ret;
+
+ /* Create the key */
+ ret = cpfl_tdi_table_key_create(dev, table_id, table_node, kobj);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to create table key obj.");
+ return -EINVAL;
+ }
+
+ for (i = 0; pattern[i].type != RTE_FLOW_ITEM_TYPE_END; i++) {
+ if (pattern[i].type != RTE_FLOW_ITEM_TYPE_FLEX) {
+ PMD_INIT_LOG(ERR, "All pattern type should be RTE_FLOW_ITEM_TYPE_FLEX.");
+ return -EINVAL;
+ }
+ flex = pattern[i].spec;
+ /* Set the key fields */
+ ret = cpfl_tdi_table_key_field_set(dev, *table_node, kobj, i, flex->pattern,
+ flex->length);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to set table key field.");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_action(struct rte_eth_dev *dev,
+ const struct rte_flow_action actions[],
+ uint32_t table_id,
+ struct cpfl_tdi_table_node *table_node,
+ struct cpfl_tdi_action_node **action_node,
+ struct cpfl_tdi_action_obj *aobj)
+{
+ const struct rte_flow_action_prog *prog;
+ const struct rte_flow_action_prog_argument *arg;
+ uint32_t action_spec_id;
+ int i, ret;
+ uint32_t j;
+
+ for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
+ if (actions[i].type != RTE_FLOW_ACTION_TYPE_PROG)
+ continue;
+
+ prog = actions[i].conf;
+ action_spec_id = atoi(prog->name);
+ /* Get action node */
+ ret =
+ cpfl_tdi_action_node_get_by_spec_id(dev, table_id, action_spec_id, action_node);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to get action node.");
+ return -EINVAL;
+ }
+
+ ret = cpfl_tdi_action_obj_init(dev, table_node, *action_node, aobj);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init action obj.");
+ return -EINVAL;
+ }
+
+ for (j = 0; j < prog->args_num; j++) {
+ arg = &prog->args[j];
+ /* Set the action fields */
+ ret = cpfl_tdi_action_field_set(dev, aobj, *action_node, j, arg);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to set action field.");
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_pattern_action(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ void **meta)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *adapter = itf->adapter;
+ int ret;
+ struct cpfl_tdi_rule_info *rinfo;
+ struct cpfl_tdi_table_node *table_node;
+ struct cpfl_tdi_action_node *action_node;
+ struct cpfl_tdi_table_key_obj *kobj;
+ struct cpfl_tdi_action_obj *aobj;
+ uint32_t table_id = attr->group;
+
+ if (!adapter->flow_parser.is_p4_parser || !cpfl_flow_items_all_is_flex(pattern))
+ return -EINVAL;
+
+ rinfo = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_rule_info), 0);
+ if (!rinfo)
+ return -ENOMEM;
+
+ kobj = &rinfo->kobj;
+ aobj = &rinfo->aobj;
+ memset(kobj, 0, sizeof(struct cpfl_tdi_table_key_obj));
+ memset(aobj, 0, sizeof(struct cpfl_tdi_action_obj));
+
+ ret = cpfl_tdi_parse_pattern(dev, pattern, table_id, &table_node, kobj);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Invalid pattern");
+ rte_free(rinfo);
+ return -EINVAL;
+ }
+
+ ret = cpfl_tdi_parse_action(dev, actions, table_id, table_node, &action_node, aobj);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Invalid action");
+ rte_free(rinfo);
+ return -EINVAL;
+ }
+
+ cpfl_fill_rinfo_default_value(rinfo);
+ if (!meta)
+ rte_free(rinfo);
+ else
+ *meta = rinfo;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_fxp_init(struct cpfl_adapter_ext *ad __rte_unused)
+{
+ return 0;
+}
+
+static void
+cpfl_tdi_fxp_uninit(struct cpfl_adapter_ext *ad __rte_unused)
+{
+}
+
+static struct cpfl_flow_engine cpfl_tdi_engine = {
+ .type = CPFL_FLOW_ENGINE_TDI,
+ .init = cpfl_tdi_fxp_init,
+ .uninit = cpfl_tdi_fxp_uninit,
+ .create = cpfl_tdi_fxp_rule_create,
+ .destroy = cpfl_tdi_fxp_rule_destroy,
+ .parse_pattern_action = cpfl_tdi_parse_pattern_action,
+};
+
+RTE_INIT(cpfl_sw_engine_init)
+{
+ struct cpfl_flow_engine *engine = &cpfl_tdi_engine;
+
+ cpfl_flow_engine_register(engine);
+}
diff --git a/drivers/net/cpfl/cpfl_tdi.h b/drivers/net/cpfl/cpfl_tdi.h
new file mode 100644
index 0000000000..c7b8c38657
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#ifndef _CPFL_TDI_H_
+#define _CPFL_TDI_H_
+
+#include "cpfl_ethdev.h"
+#include "cpfl_fxp_rule.h"
+#include "cpfl_tdi_parser.h"
+
+#define CPFL_TDI_KEY_FIELD_NUM_MAX 256 /* Max number of key field in a table. */
+#define CPFL_TDI_ACTION_SPEC_NUM_MAX 64 /* Max number of action spec in a table. */
+#define CPFL_TDI_ACTION_PARAMETER_NUM_MAX 16
+#define CPFL_TDI_ACTION_BUF_SIZE_MAX 256
+#define CPFL_TDI_TABLE_KEY_FIELD_MAX 32
+#define CPFL_TDI_MAX_TABLE_KEY_SIZE 128
+
+/**
+ *
+ * Table entry operation type.
+ */
+
+enum cpfl_tdi_table_entry_op {
+ CPFL_TDI_TABLE_ENTRY_OP_ADD, /* Add an entry */
+ CPFL_TDI_TABLE_ENTRY_OP_DEL, /* Delete an entry */
+ CPFL_TDI_TABLE_ENTRY_OP_QRY, /* Query an entry */
+};
+
+/**
+ * Table key match type.
+ *
+ * To specify the key match type of a table.
+ */
+enum cpfl_tdi_table_key_match_type {
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_EXACT, /**< Exact match. */
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_WILDCARD, /**< Wildcard match. */
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_RANGE, /**< Range match. */
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_LPM, /**< longest prefix match. */
+};
+
+struct cpfl_tdi_param_info {
+ uint32_t id;
+ uint16_t offset;
+ uint16_t size;
+};
+
+struct cpfl_tdi_action_spec_field_info {
+ struct cpfl_tdi_immediate_field *field;
+ struct cpfl_tdi_param_info param;
+ struct cpfl_tdi_mod_field *mod_field;
+ struct cpfl_tdi_hw_action *hw_action;
+};
+
+struct cpfl_tdi_table_key_field_info {
+ struct cpfl_tdi_match_key_field *field;
+ struct cpfl_tdi_match_key_format *format;
+ struct cpfl_tdi_param_info param;
+};
+
+struct cpfl_tdi_action_node {
+ TAILQ_ENTRY(cpfl_tdi_action_node) next;
+ enum cpfl_tdi_hw_block hw_block_type;
+ const struct cpfl_tdi_action *action;
+ const struct cpfl_tdi_action_format *format;
+ uint32_t buf_len;
+ struct cpfl_tdi_param_info params[CPFL_TDI_ACTION_PARAMETER_NUM_MAX];
+ uint8_t init_buf[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+ uint8_t query_msk[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+};
+
+struct cpfl_tdi_table_node {
+ TAILQ_ENTRY(cpfl_tdi_table_node) next;
+ const struct cpfl_tdi_table *table;
+ struct cpfl_tdi_action_node **actions;
+ uint16_t buf_len;
+ struct cpfl_tdi_param_info params[CPFL_TDI_TABLE_KEY_FIELD_MAX];
+};
+
+struct cpfl_tdi_table_key_obj {
+ uint16_t buf_len;
+ uint8_t buf[CPFL_TDI_MAX_TABLE_KEY_SIZE];
+ const struct cpfl_tdi_table_node *tnode;
+ union {
+ struct {
+ uint16_t prof_id;
+ uint8_t sub_prof_id;
+ uint8_t pin_to_cache;
+ uint8_t fixed_fetch;
+ } sem;
+ struct {
+ uint32_t mod_index;
+ uint8_t pin_mod_content;
+ uint8_t mod_obj_size;
+ } mod;
+ };
+};
+
+struct cpfl_tdi_action_obj {
+ const struct cpfl_tdi_table *table;
+ struct cpfl_tdi_action_node *node;
+ uint16_t buf_len;
+ uint8_t buf[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+};
+
+TAILQ_HEAD(tdi_table_key_obj_list, tdi_table_key_obj);
+TAILQ_HEAD(tdi_action_obj_list, tdi_action_obj);
+
+struct cpfl_tdi_rule_info {
+ enum cpfl_rule_type type;
+ struct cpfl_tdi_table_key_obj kobj;
+ struct cpfl_tdi_action_obj aobj;
+ uint64_t cookie;
+ uint8_t host_id;
+ uint8_t port_num;
+ uint8_t resp_req;
+ /* vsi is used for lem and lpm rules */
+ uint16_t vsi;
+ uint8_t clear_mirror_1st_state;
+};
+
+void cpfl_tdi_free_table_list(struct cpfl_flow_parser *flow_parser);
+int cpfl_tdi_build(struct cpfl_flow_parser *flow_parser);
+#endif
diff --git a/drivers/net/cpfl/meson.build b/drivers/net/cpfl/meson.build
index f948033f1f..a2e5c9d25b 100644
--- a/drivers/net/cpfl/meson.build
+++ b/drivers/net/cpfl/meson.build
@@ -48,6 +48,7 @@ if dpdk_conf.has('RTE_HAS_JANSSON')
'cpfl_flow_parser.c',
'cpfl_fxp_rule.c',
'cpfl_tdi_parser.c',
+ 'cpfl_tdi.c',
)
ext_deps += jansson_dep
endif
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 0/2] net/cpfl: support flow offloading for P4
2023-12-22 10:08 ` [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
@ 2024-01-05 8:16 ` wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 2/2] net/cpfl: add TDI to flow engine wenjing.qiao
2 siblings, 0 replies; 8+ messages in thread
From: wenjing.qiao @ 2024-01-05 8:16 UTC (permalink / raw)
To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao
From: Wenjing Qiao <wenjing.qiao@intel.com>
Enable TDI flow engine which can program hardware offloading rules
for a P4 programmable network controller.
Wenjing Qiao (2):
net/cpfl: parse flow offloading hint from P4 context file
net/cpfl: add TDI to flow engine
v2:
- fix typos.
- parse vsi id for key.
doc/guides/nics/cpfl.rst | 10 +
doc/guides/nics/features/cpfl.ini | 1 +
drivers/net/cpfl/cpfl_ethdev.h | 17 +-
drivers/net/cpfl/cpfl_flow.c | 13 +-
drivers/net/cpfl/cpfl_flow.h | 1 +
drivers/net/cpfl/cpfl_flow_engine_fxp.c | 21 +-
drivers/net/cpfl/cpfl_flow_parser.c | 68 +-
drivers/net/cpfl/cpfl_flow_parser.h | 2 +-
drivers/net/cpfl/cpfl_fxp_rule.h | 12 +
drivers/net/cpfl/cpfl_tdi.c | 1282 +++++++++++++++++
drivers/net/cpfl/cpfl_tdi.h | 123 ++
drivers/net/cpfl/cpfl_tdi_parser.c | 1721 +++++++++++++++++++++++
drivers/net/cpfl/cpfl_tdi_parser.h | 294 ++++
drivers/net/cpfl/meson.build | 2 +
14 files changed, 3533 insertions(+), 34 deletions(-)
create mode 100644 drivers/net/cpfl/cpfl_tdi.c
create mode 100644 drivers/net/cpfl/cpfl_tdi.h
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.c
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.h
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/2] net/cpfl: parse flow offloading hint from P4 context file
2023-12-22 10:08 ` [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 0/2] net/cpfl: support flow offloading for P4 wenjing.qiao
@ 2024-01-05 8:16 ` wenjing.qiao
2024-02-09 16:20 ` Medvedkin, Vladimir
2024-01-05 8:16 ` [PATCH v2 2/2] net/cpfl: add TDI to flow engine wenjing.qiao
2 siblings, 1 reply; 8+ messages in thread
From: wenjing.qiao @ 2024-01-05 8:16 UTC (permalink / raw)
To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao
From: Wenjing Qiao <wenjing.qiao@intel.com>
To supporting P4-programmed network controller, reuse devargs
"flow_parser" to specify the path of a p4 context JSON configure
file. The cpfl PMD use the JSON configuration file to translate
rte_flow tokens into low level hardware representation.
Note, the p4 context JSON file is generated by the P4 compiler
and is intended to work exclusively with a specific P4 pipeline
configuration, which must be compiled and programmed into the hardware.
Signed-off-by: Wenjing Qiao <wenjing.qiao@intel.com>
---
drivers/net/cpfl/cpfl_ethdev.h | 9 +-
drivers/net/cpfl/cpfl_flow.c | 10 +-
drivers/net/cpfl/cpfl_flow_engine_fxp.c | 9 +-
drivers/net/cpfl/cpfl_flow_parser.c | 60 +-
drivers/net/cpfl/cpfl_flow_parser.h | 2 +-
drivers/net/cpfl/cpfl_tdi_parser.c | 1721 +++++++++++++++++++++++
drivers/net/cpfl/cpfl_tdi_parser.h | 294 ++++
drivers/net/cpfl/meson.build | 1 +
8 files changed, 2084 insertions(+), 22 deletions(-)
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.c
create mode 100644 drivers/net/cpfl/cpfl_tdi_parser.h
diff --git a/drivers/net/cpfl/cpfl_ethdev.h b/drivers/net/cpfl/cpfl_ethdev.h
index 457db6d6be..e580f80f2f 100644
--- a/drivers/net/cpfl/cpfl_ethdev.h
+++ b/drivers/net/cpfl/cpfl_ethdev.h
@@ -185,6 +185,12 @@ struct cpfl_repr {
bool func_up; /* If the represented function is up */
};
+struct cpfl_flow_parser {
+ struct cpfl_flow_js_parser *fixed_parser;
+ struct cpfl_tdi_program *p4_parser;
+ bool is_p4_parser;
+};
+
struct cpfl_metadata_chunk {
int type;
uint8_t data[CPFL_META_CHUNK_LENGTH];
@@ -218,8 +224,7 @@ struct cpfl_adapter_ext {
rte_spinlock_t repr_lock;
struct rte_hash *repr_allowlist_hash;
-
- struct cpfl_flow_js_parser *flow_parser;
+ struct cpfl_flow_parser flow_parser;
struct rte_bitmap *mod_bm;
void *mod_bm_mem;
diff --git a/drivers/net/cpfl/cpfl_flow.c b/drivers/net/cpfl/cpfl_flow.c
index 3ba6c0f0e7..1c4131da2c 100644
--- a/drivers/net/cpfl/cpfl_flow.c
+++ b/drivers/net/cpfl/cpfl_flow.c
@@ -6,6 +6,7 @@
#include "cpfl_flow.h"
#include "cpfl_flow_parser.h"
+#include "cpfl_tdi_parser.h"
TAILQ_HEAD(cpfl_flow_engine_list, cpfl_flow_engine);
@@ -331,9 +332,14 @@ cpfl_flow_init(struct cpfl_adapter_ext *ad, struct cpfl_devargs *devargs)
void
cpfl_flow_uninit(struct cpfl_adapter_ext *ad)
{
- if (ad->flow_parser == NULL)
+ if (ad->flow_parser.fixed_parser == NULL && ad->flow_parser.p4_parser == NULL)
return;
- cpfl_parser_destroy(ad->flow_parser);
+ if (ad->flow_parser.fixed_parser)
+ cpfl_parser_destroy(ad->flow_parser.fixed_parser);
+
+ if (ad->flow_parser.p4_parser)
+ cpfl_tdi_program_destroy(ad->flow_parser.p4_parser);
+
cpfl_flow_engine_uninit(ad);
}
diff --git a/drivers/net/cpfl/cpfl_flow_engine_fxp.c b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
index 8a4e1419b4..f269ff97e1 100644
--- a/drivers/net/cpfl/cpfl_flow_engine_fxp.c
+++ b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
@@ -503,20 +503,25 @@ cpfl_fxp_parse_pattern_action(struct rte_eth_dev *dev,
struct cpfl_rule_info_meta *rim;
int ret;
+ if (adapter->flow_parser.is_p4_parser)
+ return -EINVAL;
+
ret = cpfl_fxp_get_metadata_port(itf, actions);
if (!ret) {
PMD_DRV_LOG(ERR, "Fail to save metadata.");
return -EINVAL;
}
- ret = cpfl_flow_parse_items(itf, adapter->flow_parser, pattern, attr, &pr_action);
+ ret = cpfl_flow_parse_items(itf, adapter->flow_parser.fixed_parser, pattern, attr,
+ &pr_action);
if (ret) {
PMD_DRV_LOG(ERR, "No Match pattern support.");
return -EINVAL;
}
if (cpfl_is_mod_action(actions)) {
- ret = cpfl_flow_parse_actions(adapter->flow_parser, actions, mr_action);
+ ret = cpfl_flow_parse_actions(adapter->flow_parser.fixed_parser,
+ actions, mr_action);
if (ret) {
PMD_DRV_LOG(ERR, "action parse fails.");
return -EINVAL;
diff --git a/drivers/net/cpfl/cpfl_flow_parser.c b/drivers/net/cpfl/cpfl_flow_parser.c
index a8f0488f21..e7f8a8a6cc 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 "cpfl_tdi_parser.h"
static enum rte_flow_item_type
cpfl_get_item_type_by_str(const char *type)
@@ -938,36 +939,65 @@ cpfl_parser_init(json_t *ob_root, struct cpfl_flow_js_parser *parser)
return 0;
}
+static int
+cpfl_check_is_p4_mode(json_t *ob_root)
+{
+ return json_object_get(ob_root, "patterns") ? false : true;
+}
+
int
-cpfl_parser_create(struct cpfl_flow_js_parser **flow_parser, const char *filename)
+cpfl_parser_create(struct cpfl_flow_parser *flow_parser, const char *filename)
{
struct cpfl_flow_js_parser *parser;
+ struct cpfl_tdi_program *prog;
json_error_t json_error;
json_t *root;
int ret;
- parser = rte_zmalloc("flow_parser", sizeof(struct cpfl_flow_js_parser), 0);
- if (!parser) {
- PMD_DRV_LOG(ERR, "Not enough memory to create flow parser.");
- return -ENOMEM;
- }
root = json_load_file(filename, 0, &json_error);
if (!root) {
PMD_DRV_LOG(ERR, "Bad JSON file \"%s\": %s", filename, json_error.text);
- goto free_parser;
+ return -EINVAL;
}
- ret = cpfl_parser_init(root, parser);
- if (ret < 0) {
- PMD_DRV_LOG(ERR, "parser init failed.");
- goto free_parser;
+
+ if (cpfl_check_is_p4_mode(root)) {
+ PMD_DRV_LOG(NOTICE, "flow parser mode is p4 mode.");
+ prog = rte_zmalloc("tdi_parser", sizeof(struct cpfl_tdi_program), 0);
+ if (prog == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create program object.");
+ return -ENOMEM;
+ }
+ ret = cpfl_tdi_program_create(root, prog);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to create tdi program from file %s", filename);
+ rte_free(prog);
+ return -EINVAL;
+ }
+ flow_parser->p4_parser = prog;
+ flow_parser->fixed_parser = NULL;
+ flow_parser->is_p4_parser = true;
+ } else {
+ PMD_DRV_LOG(NOTICE, "flow parser mode is fixed function mode.");
+ parser = rte_zmalloc("flow_parser", sizeof(struct cpfl_flow_js_parser), 0);
+ if (!parser) {
+ PMD_DRV_LOG(ERR, "Not enough memory to create flow parser.");
+ return -ENOMEM;
+ }
+
+ ret = cpfl_parser_init(root, parser);
+ if (ret < 0) {
+ PMD_DRV_LOG(ERR, "parser init failed.");
+ rte_free(parser);
+ return -EINVAL;
+ }
+ flow_parser->fixed_parser = parser;
+ flow_parser->p4_parser = NULL;
+ flow_parser->is_p4_parser = false;
}
- *flow_parser = parser;
+
json_decref(root);
return 0;
-free_parser:
- rte_free(parser);
- return -EINVAL;
}
static void
diff --git a/drivers/net/cpfl/cpfl_flow_parser.h b/drivers/net/cpfl/cpfl_flow_parser.h
index 23904e39f1..d420464d5c 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.h
+++ b/drivers/net/cpfl/cpfl_flow_parser.h
@@ -273,7 +273,7 @@ struct cpfl_flow_mr_action {
};
};
-int cpfl_parser_create(struct cpfl_flow_js_parser **parser, const char *filename);
+int cpfl_parser_create(struct cpfl_flow_parser *flow_parser, const char *filename);
int cpfl_parser_destroy(struct cpfl_flow_js_parser *parser);
int cpfl_flow_parse_items(struct cpfl_itf *itf,
struct cpfl_flow_js_parser *parser,
diff --git a/drivers/net/cpfl/cpfl_tdi_parser.c b/drivers/net/cpfl/cpfl_tdi_parser.c
new file mode 100644
index 0000000000..f771e8a60a
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi_parser.c
@@ -0,0 +1,1721 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+
+#include "cpfl_tdi_parser.h"
+#include "base/idpf_osdep.h"
+
+static int
+cpfl_tdi_get_integer_obj(json_t *jobj, const char *key, int *output)
+{
+ json_t *int_obj = json_object_get(jobj, key);
+
+ if (int_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_integer(int_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a integer object.", key);
+ return -EINVAL;
+ }
+
+ *output = json_integer_value(int_obj);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_string_obj(json_t *jobj, const char *key, char *output)
+{
+ json_t *str_obj = json_object_get(jobj, key);
+
+ if (str_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_string(str_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a string object.", key);
+ return -EINVAL;
+ }
+
+ strncpy(output, json_string_value(str_obj), CPFL_TDI_JSON_STR_SIZE_MAX - 1);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_boolean_obj(json_t *jobj, const char *key, bool *output)
+{
+ json_t *bool_obj = json_object_get(jobj, key);
+
+ if (bool_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_boolean(bool_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a boolean object.", key);
+ return -EINVAL;
+ }
+
+ *output = (bool)json_integer_value(bool_obj);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_array_obj(json_t *jobj, const char *key, json_t **output)
+{
+ json_t *array_obj = json_object_get(jobj, key);
+
+ if (array_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_array(array_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a array object.", key);
+ return -EINVAL;
+ }
+
+ *output = array_obj;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_get_object_obj(json_t *jobj, const char *key, json_t **output)
+{
+ json_t *obj_obj = json_object_get(jobj, key);
+
+ if (obj_obj == NULL) {
+ PMD_DRV_LOG(ERR, "Missing %s", key);
+ return -EINVAL;
+ }
+
+ if (!json_is_object(obj_obj)) {
+ PMD_DRV_LOG(ERR, "%s is not a array object.", key);
+ return -EINVAL;
+ }
+
+ *output = obj_obj;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_table_type(json_t *root, struct cpfl_tdi_table *table)
+{
+ char tt[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "table_type", tt);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(tt, "match")) {
+ table->table_type = CPFL_TDI_TABLE_TYPE_MATCH;
+ } else if (!strcmp(tt, "match_value_lookup_table")) {
+ table->table_type = CPFL_TDI_TABLE_TYPE_MATCH_VALUE_LOOKUP_TABLE;
+ } else if (!strcmp(tt, "policer_meter")) {
+ table->table_type = CPFL_TDI_TABLE_TYPE_POLICER_METER;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown table type %s", tt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_table_dir(json_t *root, struct cpfl_tdi_table *table)
+{
+ char dir[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "direction", dir);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(dir, "RX")) {
+ table->direction = CPFL_TDI_TABLE_DIR_RX;
+ } else if (!strcmp(dir, "TX")) {
+ table->direction = CPFL_TDI_TABLE_DIR_TX;
+ } else if (!strcmp(dir, "BIDIRECTIONAL")) {
+ table->direction = CPFL_TDI_TABLE_DIR_BI;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown direction type %s", dir);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_type(json_t *root, struct cpfl_tdi_match_key_field *mkf)
+{
+ char mt[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "match_type", mt);
+ if (ret != 0)
+ return ret;
+
+ if (!strcmp(mt, "exact")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_EXACT;
+ } else if (!strcmp(mt, "selector")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_SELECTOR;
+ } else if (!strcmp(mt, "ternary")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_TERNARY;
+ } else if (!strcmp(mt, "lpm")) {
+ mkf->match_type = CPFL_TDI_MATCH_TYPE_LPM;
+ } else {
+ PMD_DRV_LOG(ERR, "Unsupported match type %s.", mt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_field_obj(json_t *root, struct cpfl_tdi_match_key_field *mkf)
+{
+ int ret, val = 0;
+ char last3char[4];
+
+ ret = cpfl_tdi_get_string_obj(root, "name", mkf->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "instance_name", mkf->instance_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "field_name", mkf->field_name);
+ if (ret != 0)
+ return ret;
+ strncpy(last3char, mkf->field_name + strlen(mkf->field_name) - 3, 3);
+ last3char[3] = '\0';
+ if (!strcmp(last3char, "VSI") || !strcmp(last3char, "vsi"))
+ mkf->is_vsi = true;
+ else
+ mkf->is_vsi = false;
+
+ ret = cpfl_tdi_parse_match_type(root, mkf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->bit_width = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "index", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->index = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "position", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->position = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_fields(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ table->match_key_field_num = (uint16_t)array_len;
+ table->match_key_fields =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_match_key_field) * array_len, 0);
+ if (table->match_key_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create match key field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *mkf_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_match_key_field_obj(mkf_object, &table->match_key_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_byte_order(json_t *root, struct cpfl_tdi_match_key_format *mkf)
+{
+ char bo[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "byte_order", bo);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(bo, "HOST")) {
+ mkf->byte_order = CPFL_TDI_BYTE_ORDER_HOST;
+ } else if (!strcmp(bo, "NETWORK")) {
+ mkf->byte_order = CPFL_TDI_BYTE_ORDER_NETWORK;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown byte order type %s", bo);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_format_obj(json_t *root, struct cpfl_tdi_match_key_format *mkf)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_integer_obj(root, "match_key_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->match_key_handle = (uint32_t)val;
+
+ ret = cpfl_tdi_parse_byte_order(root, mkf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "byte_array_index", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->byte_array_index = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "start_bit_offset", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->start_bit_offset = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ mkf->bit_width = (uint16_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_key_format_array(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ table->match_key_format_num = (uint16_t)array_len;
+ table->match_key_format =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_match_key_format) * array_len, 0);
+ if (table->match_key_format == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create match key format array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *mkf_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_match_key_format_obj(mkf_object, &table->match_key_format[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_p4_parameter_obj(json_t *root, struct cpfl_tdi_p4_parameter *param)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", param->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ param->bit_width = (uint16_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_p4_parameters(json_t *root, struct cpfl_tdi_action *act)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ act->p4_parameter_num = (uint16_t)array_len;
+ act->p4_parameters = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_p4_parameter) * array_len, 0);
+ if (act->p4_parameters == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create p4 parameter array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *pp_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_p4_parameter_obj(pp_object, &act->p4_parameters[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_action_obj(json_t *root, struct cpfl_tdi_action *act)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", act->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
+ if (ret != 0)
+ return ret;
+
+ act->handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "constant_default_action",
+ &act->constant_default_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "is_compiler_added_action",
+ &act->is_compiler_added_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "allowed_as_hit_action", &act->allowed_as_hit_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_boolean_obj(root, "allowed_as_default_action",
+ &act->allowed_as_default_action);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "p4_parameters", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_p4_parameters(jobj, act);
+}
+
+static int
+cpfl_tdi_parse_actions(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ table->action_num = (uint16_t)array_len;
+ table->actions = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_action) * array_len, 0);
+ if (table->actions == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create action array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *act_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_action_obj(act_object, &table->actions[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_ma_hw_block(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", name);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(name, "SEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_SEM;
+ } else if (!strcmp(name, "LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_LEM;
+ } else if (!strcmp(name, "WCM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_WCM;
+ } else if (!strcmp(name, "LPM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_LPM;
+ } else if (!strcmp(name, "MOD")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_MOD;
+ } else if (!strcmp(name, "HASH")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_HASH;
+ } else if (!strcmp(name, "RC")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_RC;
+ } else if (!strcmp(name, "CXP_LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_CXP_LEM;
+ } else if (!strcmp(name, "METER")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_METER;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown hardware block type %s", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_profiles(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int array_len = json_array_size(root);
+
+ if (array_len > 16) {
+ PMD_DRV_LOG(ERR, "Profile array out of bound: %d.", array_len);
+ return -EINVAL;
+ }
+
+ if (array_len == 0)
+ return 0;
+
+ hb->profile_num = (uint16_t)array_len;
+ for (int i = 0; i < array_len; i++) {
+ int val;
+ json_t *int_obj = json_array_get(root, i);
+
+ if (!json_is_integer(int_obj)) {
+ PMD_DRV_LOG(ERR, "Invalid profile id, not an integer.");
+ return -EINVAL;
+ }
+ val = json_integer_value(int_obj);
+ hb->profile[i] = (uint8_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_immediate_field_obj(json_t *root, struct cpfl_tdi_immediate_field *imf)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "param_name", imf->param_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "param_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->param_handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "dest_start", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->dest_start = (uint16_t)val;
+ if (json_object_get(root, "start_bit_offset")) {
+ ret = cpfl_tdi_get_integer_obj(root, "start_bit_offset", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->start_bit_offset = (uint16_t)val;
+ }
+
+ ret = cpfl_tdi_get_integer_obj(root, "dest_width", &val);
+ if (ret != 0)
+ return ret;
+
+ imf->dest_width = (uint16_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_af_immediate_fields(json_t *root, struct cpfl_tdi_action_format *af)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ af->immediate_field_num = (uint16_t)array_len;
+ af->immediate_fields =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_immediate_field) * array_len, 0);
+ if (af->immediate_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to immediate field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *if_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_immediate_field_obj(if_object, &af->immediate_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_type(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ char t[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+ int val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "type", t);
+ if (ret != 0)
+ return ret;
+
+ if (!strcmp("parameter", t)) {
+ mf->type = CPFL_TDI_MOD_FIELD_TYPE_PARAMETER;
+ ret = cpfl_tdi_get_integer_obj(root, "param_handle", &val);
+ if (ret != 0)
+ return ret;
+ mf->param_handle = (uint32_t)val;
+ } else if (!strcmp("constant", t)) {
+ mf->type = CPFL_TDI_MOD_FIELD_TYPE_CONSTANT;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown mod field type %s.", t);
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_byte_order(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ char bo[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "byte_order", bo);
+ if (ret != 0)
+ return ret;
+
+ if (!strcmp("HOST", bo))
+ mf->byte_order = CPFL_TDI_BYTE_ORDER_HOST;
+ else if (!strcmp("NETWORK", bo))
+ mf->byte_order = CPFL_TDI_BYTE_ORDER_NETWORK;
+ else
+ PMD_DRV_LOG(ERR, "Unknown byte order type %s.", bo);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_value(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ if (array_len > CPFL_TDI_VALUE_SIZE_MAX) {
+ PMD_DRV_LOG(ERR, "Value array out of bound.");
+ return -EINVAL;
+ }
+
+ mf->value_size = (uint16_t)array_len;
+ for (int i = 0; i < array_len; i++) {
+ int val;
+ json_t *val_obj = json_array_get(root, i);
+
+ if (!json_is_integer(val_obj)) {
+ PMD_DRV_LOG(ERR, "Invalid value item, not an integer.");
+ return -EINVAL;
+ }
+ val = json_integer_value(val_obj);
+ mf->value[i] = (uint8_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_field_obj(json_t *root, struct cpfl_tdi_mod_field *mf)
+{
+ json_t *jobj = NULL;
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", mf->name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->handle = (uint32_t)val;
+
+ ret = cpfl_tdi_parse_mod_field_type(root, mf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_mod_field_byte_order(root, mf);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "byte_array_index", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->byte_array_index = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "start_bit_offset", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->start_bit_offset = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
+ if (ret != 0)
+ return ret;
+
+ mf->bit_width = (uint16_t)val;
+
+ ret = cpfl_tdi_get_array_obj(root, "value", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_mod_field_value(jobj, mf);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_fields(json_t *root, struct cpfl_tdi_mod_content_format *mcf)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ mcf->mod_field_num = (uint16_t)array_len;
+ mcf->mod_fields = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_mod_field) * array_len, 0);
+ if (mcf->mod_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create mod field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *mf_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_mod_field_obj(mf_object, &mcf->mod_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_mod_content_format(json_t *root, struct cpfl_tdi_mod_content_format *mcf)
+{
+ json_t *jobj = NULL;
+ int ret, val = 0;
+
+ if (json_object_get(root, "mod_profile")) {
+ ret = cpfl_tdi_get_integer_obj(root, "mod_profile", &val);
+ if (ret != 0)
+ return ret;
+ mcf->mod_profile = (uint16_t)val;
+ } else if (json_object_get(root, "mod_lut_num")) {
+ ret = cpfl_tdi_get_integer_obj(root, "mod_lut_num", &val);
+ if (ret != 0)
+ return ret;
+ mcf->mod_lut_num = (uint16_t)val;
+ } else {
+ PMD_DRV_LOG(ERR, "Failed to parse mod_content_format.");
+ return -EINVAL;
+ }
+
+ ret = cpfl_tdi_get_integer_obj(root, "mod_obj_size", &val);
+ if (ret != 0)
+ return ret;
+
+ mcf->mod_obj_size = (uint16_t)val;
+
+ if (json_object_get(root, "mod_fields") != NULL) {
+ ret = cpfl_tdi_get_array_obj(root, "mod_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_mod_fields(jobj, mcf);
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_pparse_action_code(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ char ac[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "action_code", ac);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(ac, "SET10_1b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET10_1b;
+ } else if (!strcmp(ac, "SET1_16b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET1_16b;
+ } else if (!strcmp(ac, "SET1A_24b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET1A_24b;
+ } else if (!strcmp(ac, "SET1B_24b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET1B_24b;
+ } else if (!strcmp(ac, "SET2_8b")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_SET2_8b;
+ } else if (!strcmp(ac, "NOP")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_NOP;
+ } else if (!strcmp(ac, "AUX_DATA")) {
+ ha->action_code = CPFL_TDI_ACTION_CODE_AUX_DATA;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown action code type %s", ac);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_setmd_action_code(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ char ac[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ /* allow no value */
+ if (json_object_get(root, "setmd_action_code") == NULL) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_NONE;
+ return 0;
+ }
+
+ ret = cpfl_tdi_get_string_obj(root, "setmd_action_code", ac);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(ac, "SET_8b")) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_SET_8b;
+ } else if (!strcmp(ac, "SET_16b")) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_SET_16b;
+ } else if (!strcmp(ac, "SET_32b_AUX")) {
+ ha->setmd_action_code = CPFL_TDI_SETMD_ACTION_CODE_SET_32b_AUX;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown setmd action code type %s", ac);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_action_parameter_obj(json_t *root, struct cpfl_tdi_hw_action_parameter *param)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_string_obj(root, "param_name", param->param_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "param_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ param->param_handle = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_action_parameters(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ ha->parameter_num = (uint16_t)array_len;
+ ha->parameters =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_hw_action_parameter) * array_len, 0);
+ if (ha->parameters == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create hw action parameter array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *p_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_hw_action_parameter_obj(p_object, &ha->parameters[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_action_obj(json_t *root, struct cpfl_tdi_hw_action *ha)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_integer_obj(root, "prec", &val);
+ if (ret != 0)
+ return ret;
+
+ ha->prec = (uint16_t)val;
+
+ ret = cpfl_tdi_pparse_action_code(root, ha);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_setmd_action_code(root, ha);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "index", &val);
+ if (ret != 0)
+ return ret;
+
+ ha->index = (uint32_t)val;
+
+ if (json_object_get(root, "mod_profile") != NULL) {
+ ret = cpfl_tdi_get_integer_obj(root, "mod_profile", &val);
+ if (ret != 0)
+ return ret;
+ ha->mod_profile = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "prefetch") != NULL) {
+ ret = cpfl_tdi_get_integer_obj(root, "prefetch", &val);
+ if (ret != 0)
+ return ret;
+ ha->prefetch = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "parameters") != NULL) {
+ ret = cpfl_tdi_get_array_obj(root, "parameters", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_hw_action_parameters(jobj, ha);
+ if (ret != 0)
+ return ret;
+ }
+
+ if (json_object_get(root, "p4_ref_action_handle")) {
+ ret = cpfl_tdi_get_integer_obj(root, "p4_ref_action_handle", &val);
+ if (ret != 0)
+ return ret;
+ ha->p4_ref_action_handle = (uint32_t)val;
+ }
+
+ if (json_object_get(root, "p4_ref_table_handle")) {
+ ret = cpfl_tdi_get_integer_obj(root, "p4_ref_table_handle", &val);
+ if (ret != 0)
+ return ret;
+ ha->p4_ref_table_handle = (uint32_t)val;
+ }
+
+ if (json_object_get(root, "value")) {
+ ret = cpfl_tdi_get_integer_obj(root, "value", &val);
+ if (ret != 0)
+ return ret;
+ ha->value = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "mask")) {
+ ret = cpfl_tdi_get_integer_obj(root, "mask", &val);
+ if (ret != 0)
+ return ret;
+ ha->mask = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "type_id")) {
+ ret = cpfl_tdi_get_integer_obj(root, "type_id", &val);
+ if (ret != 0)
+ return ret;
+ ha->type_id = (uint16_t)val;
+ }
+
+ if (json_object_get(root, "offset")) {
+ ret = cpfl_tdi_get_integer_obj(root, "offset", &val);
+ if (ret != 0)
+ return ret;
+ ha->offset = (uint16_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hw_actions_list(json_t *root, struct cpfl_tdi_action_format *af)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ af->hw_action_num = (uint16_t)array_len;
+ af->hw_actions_list = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_hw_action) * array_len, 0);
+ if (af->hw_actions_list == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create hw action array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *ha_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_hw_action_obj(ha_object, &af->hw_actions_list[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_action_format_obj(json_t *root, struct cpfl_tdi_action_format *af)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_string_obj(root, "action_name", af->action_name);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "action_handle", &val);
+ if (ret != 0)
+ return ret;
+
+ af->action_handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_array_obj(root, "immediate_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_af_immediate_fields(jobj, af);
+ if (ret != 0)
+ return ret;
+
+ jobj = json_object_get(root, "mod_content_format");
+ if (jobj != NULL) {
+ ret = cpfl_tdi_parse_mod_content_format(jobj, &af->mod_content_format);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = cpfl_tdi_get_array_obj(root, "hw_actions_list", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_hw_actions_list(jobj, af);
+}
+
+static int
+cpfl_tdi_parse_action_format_array(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ hb->action_format_num = (uint16_t)array_len;
+ hb->action_format = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_action_format) * array_len, 0);
+ if (hb->action_format == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create action format array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *af_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_action_format_obj(af_object, &hb->action_format[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_act_rams(json_t *root, struct cpfl_tdi_wcm_params *wm)
+{
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ if (array_len > 16) {
+ PMD_DRV_LOG(ERR, "Action ram array out of bound.");
+ return -EINVAL;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ int val;
+ json_t *am_obj = json_array_get(root, i);
+
+ if (!json_is_integer(am_obj)) {
+ PMD_DRV_LOG(ERR, "Invalid action ram index, not an integer.");
+ return -EINVAL;
+ }
+ val = json_integer_value(am_obj);
+ wm->act_rams[i] = (uint8_t)val;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_wcm_params(json_t *root, struct cpfl_tdi_wcm_params *wm)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_get_integer_obj(root, "wcm_group", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->wcm_group = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "slice_start_idx", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->slice_start_idx = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "table_width", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->table_width = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "entry_cnt", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->entry_cnt = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "entry_idx", &val);
+ if (ret != 0)
+ return ret;
+
+ wm->entry_idx = (uint16_t)val;
+
+ ret = cpfl_tdi_get_array_obj(root, "act_rams", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_act_rams(jobj, wm);
+}
+
+static int
+cpfl_tdi_parse_hb_immediate_fields(json_t *root, struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ hb->meter.immediate_field_num = (uint16_t)array_len;
+ hb->meter.immediate_fields =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_immediate_field) * array_len, 0);
+ if (hb->meter.immediate_fields == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to immediate field array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *if_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_immediate_field_obj(if_object, &hb->meter.immediate_fields[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_ma_hardware_block_obj(json_t *root,
+ enum cpfl_tdi_table_type table_type,
+ struct cpfl_tdi_ma_hardware_block *hb)
+{
+ int ret, val = 0;
+ json_t *jobj = NULL;
+
+ ret = cpfl_tdi_parse_ma_hw_block(root, hb);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "id", &val);
+ if (ret != 0)
+ return ret;
+
+ hb->id = (uint32_t)val;
+
+ ret = cpfl_tdi_get_string_obj(root, "hw_interface", hb->hw_interface);
+ if (ret != 0)
+ return ret;
+ if (table_type == CPFL_TDI_TABLE_TYPE_MATCH) {
+ ret = cpfl_tdi_get_array_obj(root, "profile", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_profiles(jobj, hb);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "action_format", &jobj);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_parse_action_format_array(jobj, hb);
+ if (ret != 0)
+ return ret;
+ }
+
+ switch (hb->hw_block) {
+ case CPFL_TDI_HW_BLOCK_SEM:
+ ret = cpfl_tdi_get_integer_obj(root, "sub_profile", &val);
+ if (ret != 0)
+ return ret;
+
+ hb->sem.sub_profile = (uint16_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "obj_id", &val);
+ if (ret != 0)
+ return ret;
+
+ hb->sem.obj_id = (uint32_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_WCM:
+ ret = cpfl_tdi_get_object_obj(root, "wcm_params", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_wcm_params(jobj, &hb->wcm.wcm_params);
+ if (ret != 0)
+ return ret;
+ break;
+ case CPFL_TDI_HW_BLOCK_MOD:
+ ret = cpfl_tdi_get_string_obj(root, "hw_resource", hb->mod.hw_resource);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "hw_resource_id", &val);
+ if (ret != 0)
+ return ret;
+ hb->mod.hw_resource_id = (uint32_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_METER:
+ ret = cpfl_tdi_get_string_obj(root, "hw_resource", hb->mod.hw_resource);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_integer_obj(root, "hw_resource_id", &val);
+ if (ret != 0)
+ return ret;
+ hb->mod.hw_resource_id = (uint32_t)val;
+ ret = cpfl_tdi_get_array_obj(root, "immediate_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_hb_immediate_fields(jobj, hb);
+ if (ret != 0)
+ return ret;
+ break;
+ case CPFL_TDI_HW_BLOCK_LEM:
+ case CPFL_TDI_HW_BLOCK_CXP_LEM:
+ ret = cpfl_tdi_get_integer_obj(root, "hash_size", &val);
+ if (ret != 0)
+ return ret;
+ hb->lem.hash_size = (uint16_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_LPM:
+ ret = cpfl_tdi_get_integer_obj(root, "max_prefix_len", &val);
+ if (ret != 0)
+ return ret;
+ hb->lpm.max_prefix_len = (uint16_t)val;
+ break;
+ case CPFL_TDI_HW_BLOCK_HASH:
+ break;
+ default:
+ printf("not support this hardware_block type: %d\n", hb->hw_block);
+ break;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_ma_hardware_blocks(json_t *root,
+ enum cpfl_tdi_table_type table_type,
+ struct cpfl_tdi_match_attributes *ma)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ ma->hardware_block_num = (uint16_t)array_len;
+ ma->hardware_blocks =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_ma_hardware_block) * array_len, 0);
+ if (ma->hardware_blocks == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create match attribute's hardware block array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *hb_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_ma_hardware_block_obj(hb_object, table_type,
+ &ma->hardware_blocks[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_match_attributes(json_t *root,
+ enum cpfl_tdi_table_type table_type,
+ struct cpfl_tdi_match_attributes *ma)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "hardware_blocks", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_ma_hardware_blocks(jobj, table_type, ma);
+}
+
+static int
+cpfl_tdi_parse_table_obj(json_t *root, struct cpfl_tdi_table *table)
+{
+ int ret, val = 0;
+ struct json_t *jobj = NULL;
+
+ ret = cpfl_tdi_parse_table_type(root, table);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
+ if (ret != 0)
+ return ret;
+ table->handle = (uint32_t)val;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", table->name);
+ if (ret != 0)
+ return ret;
+
+ if (table->table_type == CPFL_TDI_TABLE_TYPE_POLICER_METER) {
+ /* TODO */
+ return 0;
+ }
+
+ if (table->table_type == CPFL_TDI_TABLE_TYPE_MATCH) {
+ ret = cpfl_tdi_parse_table_dir(root, table);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_boolean_obj(root, "add_on_miss", &table->add_on_miss);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_boolean_obj(root, "idle_timeout_with_auto_delete",
+ &table->idle_timeout_with_auto_delete);
+ if (ret != 0)
+ return ret;
+ ret = cpfl_tdi_get_integer_obj(root, "default_action_handle", &val);
+ if (ret != 0)
+ return ret;
+ table->default_action_handle = (uint32_t)val;
+ ret = cpfl_tdi_get_array_obj(root, "actions", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_actions(jobj, table);
+ if (ret != 0)
+ return ret;
+ } else if (table->table_type == CPFL_TDI_TABLE_TYPE_MATCH_VALUE_LOOKUP_TABLE) {
+ ret = cpfl_tdi_get_integer_obj(root, "size", &val);
+ if (ret != 0)
+ return ret;
+ table->size = (uint16_t)val;
+ ret = cpfl_tdi_get_boolean_obj(root, "p4_hidden", &table->p4_hidden);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = cpfl_tdi_get_array_obj(root, "match_key_fields", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_match_key_fields(jobj, table);
+ if (ret != 0)
+ return ret;
+
+ if (json_object_get(root, "match_key_format") != NULL) {
+ ret = cpfl_tdi_get_array_obj(root, "match_key_format", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_match_key_format_array(jobj, table);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = cpfl_tdi_get_object_obj(root, "match_attributes", &jobj);
+ if (ret != 0)
+ return ret;
+
+ ret = cpfl_tdi_parse_match_attributes(jobj, table->table_type, &table->match_attributes);
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_tables(json_t *root, struct cpfl_tdi_program *prog)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ prog->table_num = (uint16_t)array_len;
+ prog->tables = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_table) * array_len, 0);
+ if (prog->tables == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create table array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *table_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_table_obj(table_object, &prog->tables[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_hash_space_cfg(json_t *root, struct cpfl_tdi_hash_space_cfg *cfg)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_integer_obj(root, "base_128_entries", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->base_128_entries = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "base_256_entries", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->base_256_entries = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_rc_entry_space_cfg(json_t *root, struct cpfl_tdi_rc_entry_space_cfg *cfg)
+{
+ int ret, val = 0;
+
+ ret = cpfl_tdi_get_integer_obj(root, "rc_num_banks", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->rc_num_banks = (uint32_t)val;
+
+ ret = cpfl_tdi_get_integer_obj(root, "rc_num_entries", &val);
+ if (ret != 0)
+ return ret;
+
+ cfg->rc_num_entries = (uint32_t)val;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_gc_hw_block(json_t *root, struct cpfl_tdi_gc_hardware_block *hb)
+{
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "name", name);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(name, "SEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_SEM;
+ } else if (!strcmp(name, "LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_LEM;
+ } else if (!strcmp(name, "WCM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_WCM;
+ } else if (!strcmp(name, "MOD")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_MOD;
+ } else if (!strcmp(name, "HASH")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_HASH;
+ } else if (!strcmp(name, "RC")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_RC;
+ } else if (!strcmp(name, "CXP_LEM")) {
+ hb->hw_block = CPFL_TDI_HW_BLOCK_CXP_LEM;
+ } else {
+ PMD_DRV_LOG(ERR, "Unknown hardware block type %s", name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_gc_hardware_block(json_t *root, struct cpfl_tdi_gc_hardware_block *hb)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_parse_gc_hw_block(root, hb);
+ if (ret != 0)
+ return ret;
+
+ switch (hb->hw_block) {
+ case CPFL_TDI_HW_BLOCK_MOD:
+ ret = cpfl_tdi_get_object_obj(root, "hash_space_cfg", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_hash_space_cfg(jobj, &hb->hash_space_cfg);
+ case CPFL_TDI_HW_BLOCK_RC:
+ ret = cpfl_tdi_get_object_obj(root, "rc_entry_space_cfg", &jobj);
+ if (ret != 0)
+ return ret;
+ return cpfl_tdi_parse_rc_entry_space_cfg(jobj, &hb->rc_entry_space_cfg);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_gc_hardware_blocks(json_t *root, struct cpfl_tdi_global_configs *gc)
+{
+ int ret;
+ int array_len = json_array_size(root);
+
+ if (array_len == 0)
+ return 0;
+
+ gc->hardware_block_num = (uint16_t)array_len;
+ gc->hardware_blocks =
+ rte_zmalloc(NULL, sizeof(struct cpfl_tdi_gc_hardware_block) * array_len, 0);
+ if (gc->hardware_blocks == NULL) {
+ PMD_DRV_LOG(ERR, "Failed to create hardware block array.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i < array_len; i++) {
+ json_t *hb_object = json_array_get(root, i);
+
+ ret = cpfl_tdi_parse_gc_hardware_block(hb_object, &gc->hardware_blocks[i]);
+ if (ret != 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_global_configs(json_t *root, struct cpfl_tdi_global_configs *gc)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_get_array_obj(root, "hardware_blocks", &jobj);
+ if (ret != 0)
+ return ret;
+
+ return cpfl_tdi_parse_gc_hardware_blocks(jobj, gc);
+}
+
+int
+cpfl_tdi_program_create(json_t *root, struct cpfl_tdi_program *prog)
+{
+ json_t *jobj = NULL;
+ int ret;
+
+ ret = cpfl_tdi_get_string_obj(root, "program_name", prog->program_name);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "build_date", prog->build_date);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "compile_command", prog->compile_command);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "compiler_version", prog->compiler_version);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "schema_version", prog->schema_version);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_string_obj(root, "target", prog->target);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_object_obj(root, "global_configs", &jobj);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_parse_global_configs(jobj, &prog->global_configs);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_get_array_obj(root, "tables", &jobj);
+ if (ret != 0)
+ goto err;
+
+ ret = cpfl_tdi_parse_tables(jobj, prog);
+ if (ret != 0)
+ goto err;
+
+ json_decref(root);
+
+ return 0;
+
+err:
+ cpfl_tdi_program_destroy(prog);
+ return ret;
+}
+
+static void
+cpfl_tdi_destroy_hw_action(struct cpfl_tdi_hw_action *action)
+{
+ if (action->parameter_num > 0)
+ rte_free(action->parameters);
+}
+
+static void
+cpfl_tdi_cpfl_tdi_destroy_action_format(struct cpfl_tdi_action_format *format)
+{
+ uint16_t i;
+
+ if (format->immediate_field_num > 0)
+ rte_free(format->immediate_fields);
+
+ if (format->mod_content_format.mod_field_num > 0)
+ rte_free(format->mod_content_format.mod_fields);
+
+ for (i = 0; i < format->hw_action_num; i++)
+ cpfl_tdi_destroy_hw_action(&format->hw_actions_list[i]);
+
+ if (format->hw_action_num > 0)
+ rte_free(format->hw_actions_list);
+}
+
+static void
+cpfl_tdi_destroy_hardware_block(struct cpfl_tdi_ma_hardware_block *hb)
+{
+ uint16_t i;
+
+ for (i = 0; i < hb->action_format_num; i++)
+ cpfl_tdi_cpfl_tdi_destroy_action_format(&hb->action_format[i]);
+
+ if (hb->action_format_num > 0)
+ rte_free(hb->action_format);
+}
+
+static void
+cpfl_tdi_destroy_action(struct cpfl_tdi_action *action)
+{
+ if (action->p4_parameter_num > 0)
+ rte_free(action->p4_parameters);
+}
+
+static void
+cpfl_tdi_destroy_table(struct cpfl_tdi_table *table)
+{
+ uint16_t i;
+
+ if (table->match_key_field_num > 0)
+ rte_free(table->match_key_fields);
+
+ if (table->match_key_format_num > 0)
+ rte_free(table->match_key_format);
+
+ for (i = 0; i < table->action_num; i++)
+ cpfl_tdi_destroy_action(&table->actions[i]);
+
+ if (table->action_num > 0)
+ rte_free(table->actions);
+
+ for (i = 0; i < table->match_attributes.hardware_block_num; i++)
+ cpfl_tdi_destroy_hardware_block(&table->match_attributes.hardware_blocks[i]);
+
+ if (table->match_attributes.hardware_block_num > 0)
+ rte_free(table->match_attributes.hardware_blocks);
+}
+
+void
+cpfl_tdi_program_destroy(struct cpfl_tdi_program *program)
+{
+ uint16_t i;
+
+ for (i = 0; i < program->table_num; i++)
+ cpfl_tdi_destroy_table(&program->tables[i]);
+
+ if (program->table_num > 0)
+ rte_free(program->tables);
+
+ rte_free(program);
+}
diff --git a/drivers/net/cpfl/cpfl_tdi_parser.h b/drivers/net/cpfl/cpfl_tdi_parser.h
new file mode 100644
index 0000000000..9e036e762c
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi_parser.h
@@ -0,0 +1,294 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#ifndef _CPFL_TDI_PARSER_H_
+#define _CPFL_TDI_PARSER_H_
+
+#include <jansson.h>
+#include <rte_flow.h>
+
+#include "cpfl_ethdev.h"
+
+#define CPFL_TDI_JSON_STR_SIZE_MAX 100
+
+enum cpfl_tdi_table_type {
+ CPFL_TDI_TABLE_TYPE_MATCH,
+ CPFL_TDI_TABLE_TYPE_MATCH_VALUE_LOOKUP_TABLE,
+ CPFL_TDI_TABLE_TYPE_POLICER_METER,
+};
+
+enum cpfl_tdi_table_dir {
+ CPFL_TDI_TABLE_DIR_RX,
+ CPFL_TDI_TABLE_DIR_TX,
+ CPFL_TDI_TABLE_DIR_BI,
+};
+
+enum cpfl_tdi_match_type {
+ CPFL_TDI_MATCH_TYPE_EXACT,
+ CPFL_TDI_MATCH_TYPE_SELECTOR,
+ CPFL_TDI_MATCH_TYPE_TERNARY,
+ CPFL_TDI_MATCH_TYPE_LPM,
+};
+
+/**
+ * Byte order.
+ *
+ * To specify the byte order of table key / action field value in bytes.
+ */
+enum cpfl_tdi_byte_order {
+ CPFL_TDI_BYTE_ORDER_HOST, /**< follow host byte order. */
+ CPFL_TDI_BYTE_ORDER_NETWORK, /**< follow network byte order. */
+};
+
+#define CPFL_TDI_NAME_SIZE_MAX 80
+
+struct cpfl_tdi_match_key_format {
+ uint32_t match_key_handle;
+ enum cpfl_tdi_byte_order byte_order;
+ uint16_t byte_array_index;
+ uint16_t start_bit_offset;
+ uint16_t bit_width;
+};
+
+struct cpfl_tdi_match_key_field {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char instance_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char field_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ bool is_vsi;
+ enum cpfl_tdi_match_type match_type;
+ uint16_t bit_width;
+ uint32_t index;
+ uint32_t position;
+};
+
+struct cpfl_tdi_p4_parameter {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint16_t bit_width;
+};
+
+struct cpfl_tdi_action {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t handle;
+ bool constant_default_action;
+ bool is_compiler_added_action;
+ bool allowed_as_hit_action;
+ bool allowed_as_default_action;
+ uint16_t p4_parameter_num;
+ struct cpfl_tdi_p4_parameter *p4_parameters;
+};
+
+struct cpfl_tdi_immediate_field {
+ char param_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t param_handle;
+ uint16_t dest_start;
+ uint16_t start_bit_offset;
+ uint16_t dest_width;
+};
+
+enum cpfl_tdi_mod_field_type {
+ CPFL_TDI_MOD_FIELD_TYPE_PARAMETER,
+ CPFL_TDI_MOD_FIELD_TYPE_CONSTANT,
+};
+
+#define CPFL_TDI_VALUE_SIZE_MAX 16
+
+struct cpfl_tdi_mod_field {
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t handle;
+ uint32_t param_handle;
+ enum cpfl_tdi_mod_field_type type;
+ enum cpfl_tdi_byte_order byte_order;
+ uint16_t byte_array_index;
+ uint16_t start_bit_offset;
+ uint16_t bit_width;
+ uint16_t value_size;
+ uint8_t value[CPFL_TDI_VALUE_SIZE_MAX];
+};
+
+struct cpfl_tdi_mod_content_format {
+ union {
+ uint16_t mod_profile;
+ uint16_t mod_lut_num;
+ };
+ uint16_t mod_obj_size;
+ uint16_t mod_field_num;
+ struct cpfl_tdi_mod_field *mod_fields;
+};
+
+struct cpfl_tdi_hw_action_parameter {
+ char param_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t param_handle;
+};
+
+enum cpfl_tdi_action_code {
+ CPFL_TDI_ACTION_CODE_NONE,
+ CPFL_TDI_ACTION_CODE_SET10_1b,
+ CPFL_TDI_ACTION_CODE_SET1_16b,
+ CPFL_TDI_ACTION_CODE_SET1A_24b,
+ CPFL_TDI_ACTION_CODE_SET1B_24b,
+ CPFL_TDI_ACTION_CODE_SET2_8b,
+ CPFL_TDI_ACTION_CODE_NOP,
+ CPFL_TDI_ACTION_CODE_AUX_DATA,
+};
+
+enum cpfl_tdi_setmd_action_code {
+ CPFL_TDI_SETMD_ACTION_CODE_NONE,
+ CPFL_TDI_SETMD_ACTION_CODE_SET_8b,
+ CPFL_TDI_SETMD_ACTION_CODE_SET_16b,
+ CPFL_TDI_SETMD_ACTION_CODE_SET_32b_AUX,
+};
+
+struct cpfl_tdi_hw_action {
+ uint16_t prec;
+ enum cpfl_tdi_action_code action_code;
+ enum cpfl_tdi_setmd_action_code setmd_action_code;
+ uint16_t index;
+ uint16_t mod_profile;
+ uint16_t prefetch;
+ uint16_t parameter_num;
+ struct cpfl_tdi_hw_action_parameter *parameters;
+ uint32_t p4_ref_action_handle;
+ uint32_t p4_ref_table_handle;
+ uint16_t value;
+ uint16_t mask;
+ uint16_t type_id;
+ uint16_t offset;
+};
+
+struct cpfl_tdi_action_format {
+ char action_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t action_handle;
+ uint16_t immediate_field_num;
+ struct cpfl_tdi_immediate_field *immediate_fields;
+ struct cpfl_tdi_mod_content_format mod_content_format;
+ uint16_t hw_action_num;
+ struct cpfl_tdi_hw_action *hw_actions_list;
+};
+
+enum cpfl_tdi_hw_block {
+ CPFL_TDI_HW_BLOCK_SEM,
+ CPFL_TDI_HW_BLOCK_LEM,
+ CPFL_TDI_HW_BLOCK_WCM,
+ CPFL_TDI_HW_BLOCK_LPM,
+ CPFL_TDI_HW_BLOCK_MOD,
+ CPFL_TDI_HW_BLOCK_METER,
+ CPFL_TDI_HW_BLOCK_HASH,
+ CPFL_TDI_HW_BLOCK_RC,
+ CPFL_TDI_HW_BLOCK_CXP_LEM,
+};
+
+struct cpfl_tdi_wcm_params {
+ uint16_t wcm_group;
+ uint16_t slice_start_idx;
+ uint16_t table_width;
+ uint16_t entry_cnt;
+ uint16_t entry_idx;
+ uint8_t act_rams[16];
+};
+
+struct cpfl_tdi_ma_hardware_block {
+ enum cpfl_tdi_hw_block hw_block;
+ uint32_t id;
+ char hw_interface[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint16_t profile_num;
+ uint16_t profile[16];
+ uint16_t action_format_num;
+ struct cpfl_tdi_action_format *action_format;
+ union {
+ struct {
+ uint16_t sub_profile;
+ uint32_t obj_id;
+ } sem;
+ struct {
+ struct cpfl_tdi_wcm_params wcm_params;
+ } wcm;
+ struct {
+ char hw_resource[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t hw_resource_id;
+ } mod;
+ struct {
+ char hw_resource[CPFL_TDI_JSON_STR_SIZE_MAX];
+ uint32_t hw_resource_id;
+ uint16_t immediate_field_num;
+ struct cpfl_tdi_immediate_field *immediate_fields;
+ } meter;
+ struct {
+ uint16_t hash_size;
+ } lem;
+ struct {
+ uint16_t max_prefix_len;
+ } lpm;
+ };
+};
+
+struct cpfl_tdi_match_attributes {
+ uint16_t hardware_block_num;
+ struct cpfl_tdi_ma_hardware_block *hardware_blocks;
+};
+
+struct cpfl_tdi_table {
+ enum cpfl_tdi_table_type table_type;
+ uint32_t handle;
+ char name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ union {
+ /* "table_type": "match" */
+ struct {
+ enum cpfl_tdi_table_dir direction;
+ bool add_on_miss;
+ bool idle_timeout_with_auto_delete;
+ };
+ /* "table_type": "match_value_lookup_table" */
+ struct {
+ uint16_t size;
+ bool p4_hidden;
+ };
+ };
+ uint16_t match_key_field_num;
+ struct cpfl_tdi_match_key_field *match_key_fields;
+ uint16_t match_key_format_num;
+ struct cpfl_tdi_match_key_format *match_key_format;
+ uint32_t default_action_handle;
+ uint16_t action_num;
+ struct cpfl_tdi_action *actions;
+ struct cpfl_tdi_match_attributes match_attributes;
+};
+
+struct cpfl_tdi_hash_space_cfg {
+ uint32_t base_128_entries;
+ uint32_t base_256_entries;
+};
+
+struct cpfl_tdi_rc_entry_space_cfg {
+ uint32_t rc_num_banks;
+ uint32_t rc_num_entries;
+};
+
+struct cpfl_tdi_gc_hardware_block {
+ enum cpfl_tdi_hw_block hw_block;
+ union {
+ struct cpfl_tdi_hash_space_cfg hash_space_cfg;
+ struct cpfl_tdi_rc_entry_space_cfg rc_entry_space_cfg;
+ };
+};
+
+struct cpfl_tdi_global_configs {
+ uint16_t hardware_block_num;
+ struct cpfl_tdi_gc_hardware_block *hardware_blocks;
+};
+
+struct cpfl_tdi_program {
+ char program_name[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char build_date[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char compile_command[2 * CPFL_TDI_JSON_STR_SIZE_MAX];
+ char compiler_version[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char schema_version[CPFL_TDI_JSON_STR_SIZE_MAX];
+ char target[CPFL_TDI_JSON_STR_SIZE_MAX];
+ struct cpfl_tdi_global_configs global_configs;
+ uint16_t table_num;
+ struct cpfl_tdi_table *tables;
+};
+
+int cpfl_tdi_program_create(json_t *ob_root, struct cpfl_tdi_program *program);
+void cpfl_tdi_program_destroy(struct cpfl_tdi_program *program);
+
+#endif
diff --git a/drivers/net/cpfl/meson.build b/drivers/net/cpfl/meson.build
index e4e0e269bd..f948033f1f 100644
--- a/drivers/net/cpfl/meson.build
+++ b/drivers/net/cpfl/meson.build
@@ -47,6 +47,7 @@ if dpdk_conf.has('RTE_HAS_JANSSON')
'cpfl_flow_engine_fxp.c',
'cpfl_flow_parser.c',
'cpfl_fxp_rule.c',
+ 'cpfl_tdi_parser.c',
)
ext_deps += jansson_dep
endif
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 2/2] net/cpfl: add TDI to flow engine
2023-12-22 10:08 ` [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 0/2] net/cpfl: support flow offloading for P4 wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
@ 2024-01-05 8:16 ` wenjing.qiao
2024-02-14 17:21 ` Medvedkin, Vladimir
2 siblings, 1 reply; 8+ messages in thread
From: wenjing.qiao @ 2024-01-05 8:16 UTC (permalink / raw)
To: jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev, Wenjing Qiao
From: Wenjing Qiao <wenjing.qiao@intel.com>
Add TDI implementation to a flow engine.
Signed-off-by: Wenjing Qiao <wenjing.qiao@intel.com>
---
doc/guides/nics/cpfl.rst | 10 +
doc/guides/nics/features/cpfl.ini | 1 +
drivers/net/cpfl/cpfl_ethdev.h | 8 +
drivers/net/cpfl/cpfl_flow.c | 5 +-
drivers/net/cpfl/cpfl_flow.h | 1 +
drivers/net/cpfl/cpfl_flow_engine_fxp.c | 12 -
drivers/net/cpfl/cpfl_flow_parser.c | 8 +
drivers/net/cpfl/cpfl_fxp_rule.h | 12 +
drivers/net/cpfl/cpfl_tdi.c | 1282 +++++++++++++++++++++++
drivers/net/cpfl/cpfl_tdi.h | 123 +++
drivers/net/cpfl/meson.build | 1 +
11 files changed, 1450 insertions(+), 13 deletions(-)
create mode 100644 drivers/net/cpfl/cpfl_tdi.c
create mode 100644 drivers/net/cpfl/cpfl_tdi.h
diff --git a/doc/guides/nics/cpfl.rst b/doc/guides/nics/cpfl.rst
index 9b7a99c894..591bd496e6 100644
--- a/doc/guides/nics/cpfl.rst
+++ b/doc/guides/nics/cpfl.rst
@@ -213,6 +213,16 @@ low level hardware resources.
flow create X ingress group M pattern eth dst is 00:01:00:00:03:14 / ipv4 src is 192.168.0.1 \
dst is 192.168.0.2 / tcp / end actions port_representor port_id Y / end
+#. Create one flow for TDI engine to forward ETH-IPV4-TCP from I/O port to a local(CPF's) vport. Flow should
+ be created on vport X. Group M should be table id. Prog name N should be action id. Prog arguments
+ port_representor Y means forward packet to local vport Y::
+
+ .. code-block:: console
+
+ flow create X ingress group M pattern prog key is 0x00 / prog key is 0x000100000314 / prog key
+ is 0x001122334455 / prog key is 0xC0A80001 / prog key is 0xC0A80002 / prog key is 0x1451 / prog key
+ is 0x157C / end actions prog name N arguments port_representor Y end / end
+
#. Send a matched packet, and it should be displayed on PMD::
.. code-block:: console
diff --git a/doc/guides/nics/features/cpfl.ini b/doc/guides/nics/features/cpfl.ini
index 4eadaca6e7..85b8011a54 100644
--- a/doc/guides/nics/features/cpfl.ini
+++ b/doc/guides/nics/features/cpfl.ini
@@ -33,6 +33,7 @@ tcp = Y
udp = Y
vlan = Y
vxlan = Y
+flex = Y
[rte_flow actions]
count = Y
diff --git a/drivers/net/cpfl/cpfl_ethdev.h b/drivers/net/cpfl/cpfl_ethdev.h
index e580f80f2f..7dfa4a0183 100644
--- a/drivers/net/cpfl/cpfl_ethdev.h
+++ b/drivers/net/cpfl/cpfl_ethdev.h
@@ -185,10 +185,18 @@ struct cpfl_repr {
bool func_up; /* If the represented function is up */
};
+struct cpfl_tdi_table_node;
+TAILQ_HEAD(cpfl_tdi_table_list, cpfl_tdi_table_node);
+
+struct cpfl_tdi_action_node;
+TAILQ_HEAD(cpfl_tdi_action_list, cpfl_tdi_action_node);
+
struct cpfl_flow_parser {
struct cpfl_flow_js_parser *fixed_parser;
struct cpfl_tdi_program *p4_parser;
bool is_p4_parser;
+ struct cpfl_tdi_table_list tdi_table_list;
+ struct cpfl_tdi_action_list tdi_action_list;
};
struct cpfl_metadata_chunk {
diff --git a/drivers/net/cpfl/cpfl_flow.c b/drivers/net/cpfl/cpfl_flow.c
index 1c4131da2c..15c7cc6d8b 100644
--- a/drivers/net/cpfl/cpfl_flow.c
+++ b/drivers/net/cpfl/cpfl_flow.c
@@ -6,6 +6,7 @@
#include "cpfl_flow.h"
#include "cpfl_flow_parser.h"
+#include "cpfl_tdi.h"
#include "cpfl_tdi_parser.h"
TAILQ_HEAD(cpfl_flow_engine_list, cpfl_flow_engine);
@@ -338,8 +339,10 @@ cpfl_flow_uninit(struct cpfl_adapter_ext *ad)
if (ad->flow_parser.fixed_parser)
cpfl_parser_destroy(ad->flow_parser.fixed_parser);
- if (ad->flow_parser.p4_parser)
+ if (ad->flow_parser.p4_parser) {
+ cpfl_tdi_free_table_list(&ad->flow_parser);
cpfl_tdi_program_destroy(ad->flow_parser.p4_parser);
+ }
cpfl_flow_engine_uninit(ad);
}
diff --git a/drivers/net/cpfl/cpfl_flow.h b/drivers/net/cpfl/cpfl_flow.h
index 1bde847763..1de9c25b17 100644
--- a/drivers/net/cpfl/cpfl_flow.h
+++ b/drivers/net/cpfl/cpfl_flow.h
@@ -15,6 +15,7 @@ extern const struct rte_flow_ops cpfl_flow_ops;
enum cpfl_flow_engine_type {
CPFL_FLOW_ENGINE_NONE = 0,
CPFL_FLOW_ENGINE_FXP,
+ CPFL_FLOW_ENGINE_TDI,
};
typedef int (*engine_init_t)(struct cpfl_adapter_ext *ad);
diff --git a/drivers/net/cpfl/cpfl_flow_engine_fxp.c b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
index f269ff97e1..6a5e7ed770 100644
--- a/drivers/net/cpfl/cpfl_flow_engine_fxp.c
+++ b/drivers/net/cpfl/cpfl_flow_engine_fxp.c
@@ -27,23 +27,11 @@
#include "cpfl_fxp_rule.h"
#include "cpfl_flow_parser.h"
-#define CPFL_COOKIE_DEF 0x1000
-#define CPFL_MOD_COOKIE_DEF 0x1237561
#define CPFL_PREC_DEF 1
#define CPFL_PREC_SET 5
#define CPFL_TYPE_ID 3
#define CPFL_OFFSET 0x0a
-#define CPFL_HOST_ID_DEF 0
#define CPFL_PF_NUM_DEF 0
-#define CPFL_PORT_NUM_DEF 0
-#define CPFL_RESP_REQ_DEF 2
-#define CPFL_PIN_TO_CACHE_DEF 0
-#define CPFL_CLEAR_MIRROR_1ST_STATE_DEF 0
-#define CPFL_FIXED_FETCH_DEF 0
-#define CPFL_PTI_DEF 0
-#define CPFL_MOD_OBJ_SIZE_DEF 0
-#define CPFL_PIN_MOD_CONTENT_DEF 0
-
#define CPFL_MAX_MOD_CONTENT_INDEX 256
#define CPFL_MAX_MR_ACTION_NUM 8
diff --git a/drivers/net/cpfl/cpfl_flow_parser.c b/drivers/net/cpfl/cpfl_flow_parser.c
index e7f8a8a6cc..a3572e32d5 100644
--- a/drivers/net/cpfl/cpfl_flow_parser.c
+++ b/drivers/net/cpfl/cpfl_flow_parser.c
@@ -6,6 +6,7 @@
#include "cpfl_flow_parser.h"
#include "cpfl_tdi_parser.h"
+#include "cpfl_tdi.h"
static enum rte_flow_item_type
cpfl_get_item_type_by_str(const char *type)
@@ -976,6 +977,13 @@ cpfl_parser_create(struct cpfl_flow_parser *flow_parser, const char *filename)
flow_parser->p4_parser = prog;
flow_parser->fixed_parser = NULL;
flow_parser->is_p4_parser = true;
+
+ ret = cpfl_tdi_build(flow_parser);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to build tdi program %s", filename);
+ rte_free(prog);
+ return -EINVAL;
+ }
} else {
PMD_DRV_LOG(NOTICE, "flow parser mode is fixed function mode.");
parser = rte_zmalloc("flow_parser", sizeof(struct cpfl_flow_js_parser), 0);
diff --git a/drivers/net/cpfl/cpfl_fxp_rule.h b/drivers/net/cpfl/cpfl_fxp_rule.h
index ed757b80b1..f089155353 100644
--- a/drivers/net/cpfl/cpfl_fxp_rule.h
+++ b/drivers/net/cpfl/cpfl_fxp_rule.h
@@ -9,6 +9,18 @@
#define CPFL_MAX_KEY_LEN 128
#define CPFL_MAX_RULE_ACTIONS 32
+#define CPFL_RESP_REQ_DEF 2
+#define CPFL_PIN_TO_CACHE_DEF 0
+#define CPFL_CLEAR_MIRROR_1ST_STATE_DEF 0
+#define CPFL_FIXED_FETCH_DEF 0
+#define CPFL_PTI_DEF 0
+#define CPFL_MOD_OBJ_SIZE_DEF 0
+#define CPFL_PIN_MOD_CONTENT_DEF 0
+#define CPFL_HOST_ID_DEF 0
+#define CPFL_PORT_NUM_DEF 0
+#define CPFL_VSI_DEF 0
+#define CPFL_COOKIE_DEF 0x1000
+#define CPFL_MOD_COOKIE_DEF 0x1237561
struct cpfl_sem_rule_info {
uint16_t prof_id;
diff --git a/drivers/net/cpfl/cpfl_tdi.c b/drivers/net/cpfl/cpfl_tdi.c
new file mode 100644
index 0000000000..ac681ecc01
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi.c
@@ -0,0 +1,1282 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#include <rte_hash_crc.h>
+#include <rte_tailq.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "cpfl_actions.h"
+#include "cpfl_flow.h"
+#include "cpfl_fxp_rule.h"
+#include "cpfl_tdi.h"
+#include "cpfl_tdi_parser.h"
+#include "rte_branch_prediction.h"
+#include "rte_common.h"
+#include "rte_flow.h"
+
+#define CPFL_NO_FWD 0
+uint64_t cpfl_tdi_rule_cookie = CPFL_COOKIE_DEF;
+
+/*help function to do left shift on a byte array */
+static void
+cpfl_tdi_shift_left(uint8_t *buf, int length, uint32_t shift_amount)
+{
+ uint32_t i;
+ int j;
+ uint32_t carry = 0;
+
+ if (shift_amount == 0)
+ return;
+
+ for (i = 0; i < shift_amount; i += 8) {
+ for (j = 0; j < length; j++) {
+ uint32_t temp = (buf[j] << (shift_amount - i)) | carry;
+
+ carry = (temp >> 8) & 0xff;
+ buf[j] = temp & 0xff;
+ }
+ }
+}
+
+/* help function to init a mask array with bit_width */
+static void
+cpfl_tdi_init_msk_buf(uint8_t *buf, int length, uint32_t bit_width)
+{
+ uint32_t i;
+
+ memset(buf, 0, length);
+ for (i = 0; i < bit_width; i++) {
+ cpfl_tdi_shift_left(buf, length, 1);
+ buf[0] += 1;
+ }
+}
+
+/* help function to OR a byte array with value and mask */
+static void
+cpfl_tdi_or_buf(uint8_t *buf, int length, uint8_t *values, uint8_t *mask)
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ buf[i] = (values[i] & mask[i]) | (buf[i] & ~mask[i]);
+}
+
+static uint32_t
+cpfl_tdi_to_action_code(struct cpfl_tdi_hw_action *ha,
+ uint8_t *val,
+ enum cpfl_act_fwd_type fwd_type)
+{
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ switch (ha->index) {
+ case 0: /* mod addr */
+ return cpfl_act_mod_addr(ha->prec, (uint32_t)*val).data;
+ case 8: /* todo */
+ break;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported SET1A_24b index %d", ha->index);
+ break;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1_16b:
+ switch (ha->index) {
+ case 2: /* set vsi */
+ if (fwd_type == CPFL_ACT_FWD_VSI)
+ return cpfl_act_fwd_vsi(0, ha->prec, CPFL_PE_LAN, (uint16_t)*val)
+ .data;
+ else if (fwd_type == CPFL_ACT_FWD_PORT)
+ return cpfl_act_fwd_port(0, ha->prec, CPFL_PE_LAN, (uint16_t)*val)
+ .data;
+ else
+ PMD_DRV_LOG(WARNING, "Unsupported fwd type %d", fwd_type);
+ break;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported SET1_16b index %d", ha->index);
+ break;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+ switch (ha->setmd_action_code) {
+ case CPFL_TDI_SETMD_ACTION_CODE_SET_16b:
+ return cpfl_act_set_md16(ha->index, ha->prec, ha->type_id, ha->offset,
+ (uint16_t)*val)
+ .data;
+ case CPFL_TDI_SETMD_ACTION_CODE_SET_32b_AUX: /* todo */
+ break;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported SET1b_24b setmd code %d",
+ ha->setmd_action_code);
+ break;
+ }
+ break;
+ default:
+ PMD_DRV_LOG(WARNING, "Unsupported action code %d", ha->action_code);
+ break;
+ }
+
+ return 0;
+}
+
+static void
+cpfl_tdi_pack_sem_entry(struct cpfl_tdi_rule_info *rinfo,
+ struct cpfl_tdi_ma_hardware_block *hb,
+ enum cpfl_tdi_table_entry_op op,
+ struct idpf_dma_mem *dma,
+ struct idpf_ctlq_msg *msg)
+{
+ union cpfl_rule_cfg_pkt_record *blob;
+ struct cpfl_rule_cfg_data cfg = {0};
+ uint16_t cfg_ctrl;
+ enum cpfl_ctlq_rule_cfg_opc opc = 0;
+ const struct cpfl_tdi_table_key_obj *key = &rinfo->kobj;
+ const struct cpfl_tdi_action_obj *action = &rinfo->aobj;
+
+ blob = (void *)dma->va;
+ memset(blob, 0, sizeof(*blob));
+
+ cfg_ctrl = CPFL_GET_MEV_SEM_RULE_CFG_CTRL(hb->profile[0], hb->sem.sub_profile, 0, 0);
+
+ switch (op) {
+ case CPFL_TDI_TABLE_ENTRY_OP_ADD:
+ cpfl_prep_sem_rule_blob(key->buf, key->buf_len, action->buf, action->buf_len,
+ cfg_ctrl, blob);
+ opc = cpfl_ctlq_sem_add_rule;
+ break;
+ case CPFL_TDI_TABLE_ENTRY_OP_DEL:
+ cpfl_prep_sem_rule_blob(key->buf, key->buf_len, NULL, 0, cfg_ctrl, blob);
+ opc = cpfl_ctlq_sem_del_rule;
+ break;
+ case CPFL_TDI_TABLE_ENTRY_OP_QRY:
+ cpfl_prep_sem_rule_blob(key->buf, key->buf_len, NULL, 0, cfg_ctrl, blob);
+ opc = cpfl_ctlq_sem_query_rule;
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unknown ops, this is a bug.");
+ break;
+ }
+
+ cpfl_fill_rule_cfg_data_common(opc,
+ rinfo->cookie,
+ rinfo->vsi,
+ rinfo->port_num,
+ rinfo->host_id,
+ 0, /* time_sel */
+ 0, /* time_sel_val */
+ 0, /* cache_wr_thru */
+ rinfo->resp_req,
+ sizeof(union cpfl_rule_cfg_pkt_record),
+ dma,
+ &cfg.common);
+
+ cpfl_prep_rule_desc(&cfg, msg);
+}
+
+static void
+cpfl_tdi_pack_mod_entry(struct cpfl_tdi_rule_info *rinfo,
+ enum cpfl_tdi_table_entry_op op,
+ struct idpf_dma_mem *dma,
+ struct idpf_ctlq_msg *msg)
+{
+ union cpfl_rule_cfg_pkt_record *blob;
+ struct cpfl_rule_cfg_data cfg = {0};
+ uint32_t mod_index;
+ enum cpfl_ctlq_rule_cfg_opc opc = 0;
+ const struct cpfl_tdi_table_key_obj *key = &rinfo->kobj;
+ const struct cpfl_tdi_action_obj *action = &rinfo->aobj;
+
+ blob = (void *)dma->va;
+ memset(blob, 0, sizeof(*blob));
+
+ mod_index = *(const uint32_t *)&key->buf[0];
+
+ switch (op) {
+ case CPFL_TDI_TABLE_ENTRY_OP_ADD:
+ cpfl_fill_rule_mod_content(CPFL_MOD_OBJ_SIZE_DEF, CPFL_PIN_MOD_CONTENT_DEF,
+ mod_index, &cfg.ext.mod_content);
+
+ memcpy(blob->mod_blob, action->buf, action->buf_len);
+ opc = cpfl_ctlq_mod_add_update_rule;
+ break;
+ case CPFL_TDI_TABLE_ENTRY_OP_QRY:
+ opc = cpfl_ctlq_mod_query_rule;
+ break;
+ default:
+ break;
+ }
+
+ cpfl_fill_rule_cfg_data_common(opc,
+ CPFL_MOD_COOKIE_DEF,
+ 0, /* vsi_id not used for mod */
+ CPFL_PORT_NUM_DEF,
+ 0,
+ 0, /* time_sel */
+ 0, /* time_sel_val */
+ 0, /* cache_wr_thru */
+ CPFL_RESP_REQ_DEF,
+ sizeof(union cpfl_rule_cfg_pkt_record),
+ dma,
+ &cfg.common);
+
+ cpfl_prep_rule_desc(&cfg, msg);
+}
+
+static int
+cpfl_tdi_rule_process(struct cpfl_itf *itf,
+ struct idpf_ctlq_info *tx_cq,
+ struct idpf_ctlq_info *rx_cq,
+ struct cpfl_tdi_rule_info *rinfo,
+ int rule_num,
+ enum cpfl_tdi_table_entry_op op)
+{
+ const struct cpfl_tdi_table_key_obj *kobj;
+ struct idpf_hw *hw = &itf->adapter->base.hw;
+ struct cpfl_tdi_ma_hardware_block *hb;
+ const struct cpfl_tdi_table *table;
+ int ret = 0;
+
+ if (rule_num == 0)
+ return 0;
+
+ kobj = &rinfo->kobj;
+
+ table = kobj->tnode->table;
+ if (table->match_attributes.hardware_block_num == 0) {
+ PMD_DRV_LOG(ERR, "No valid hardware block be specified");
+ return -EINVAL;
+ }
+ hb = &table->match_attributes.hardware_blocks[0];
+ switch (hb->hw_block) {
+ case CPFL_TDI_HW_BLOCK_SEM:
+ cpfl_tdi_pack_sem_entry(rinfo, hb, op, &itf->dma[0], &itf->msg[0]);
+ break;
+ case CPFL_TDI_HW_BLOCK_MOD:
+ if (op == CPFL_TDI_TABLE_ENTRY_OP_DEL)
+ /* do nothing */
+ return 0;
+ cpfl_tdi_pack_mod_entry(rinfo, op, &itf->dma[0], &itf->msg[0]);
+ break;
+ default:
+ PMD_DRV_LOG(ERR, "Unsupported hardware block %d", hb->hw_block);
+ return -EINVAL;
+ }
+
+ ret = cpfl_send_ctlq_msg(hw, tx_cq, 1, itf->msg);
+ if (ret != 0) {
+ PMD_DRV_LOG(ERR, "Failed to send control message");
+ return -EINVAL;
+ }
+
+ ret = cpfl_receive_ctlq_msg(hw, rx_cq, 1, itf->msg);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to update rule");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int
+cpfl_tdi_fxp_rule_create(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ void *meta,
+ struct rte_flow_error *error)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *ad = itf->adapter;
+ int ret;
+ uint32_t cpq_id = 0;
+ struct cpfl_vport *vport;
+ struct cpfl_repr *repr;
+ struct cpfl_tdi_rule_info *rinfo = meta;
+
+ if (!rinfo)
+ goto err;
+
+ if (itf->type == CPFL_ITF_TYPE_VPORT) {
+ vport = (struct cpfl_vport *)itf;
+ /* Every vport has one pair control queues configured to handle message.
+ * Even index is tx queue and odd index is rx queue.
+ */
+ cpq_id = vport->base.devarg_id * 2;
+ } else if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) {
+ repr = (struct cpfl_repr *)itf;
+ cpq_id = ((repr->repr_id.pf_id + repr->repr_id.vf_id) & (CPFL_TX_CFGQ_NUM - 1)) * 2;
+ } else {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "fail to find correct control queue");
+ return -rte_errno;
+ }
+
+ ret = cpfl_tdi_rule_process(itf, ad->ctlqp[cpq_id], ad->ctlqp[cpq_id + 1], rinfo, 1,
+ CPFL_TDI_TABLE_ENTRY_OP_ADD);
+ if (ret)
+ goto err;
+
+ flow->rule = rinfo;
+
+ return 0;
+
+err:
+ return rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "cpfl filter create flow fail");
+}
+
+static int
+cpfl_tdi_fxp_rule_destroy(struct rte_eth_dev *dev,
+ struct rte_flow *flow,
+ struct rte_flow_error *error)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *ad = itf->adapter;
+ struct cpfl_vport *vport;
+ struct cpfl_repr *repr;
+ struct cpfl_tdi_rule_info *rinfo = (struct cpfl_tdi_rule_info *)flow->rule;
+ int ret = 0;
+ uint32_t cpq_id = 0;
+
+ if (itf->type == CPFL_ITF_TYPE_VPORT) {
+ vport = (struct cpfl_vport *)itf;
+ cpq_id = vport->base.devarg_id * 2;
+ } else if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) {
+ repr = (struct cpfl_repr *)itf;
+ cpq_id = ((repr->repr_id.pf_id + repr->repr_id.vf_id) & (CPFL_TX_CFGQ_NUM - 1)) * 2;
+ } else {
+ rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
+ "fail to find correct control queue");
+ ret = -rte_errno;
+ goto err;
+ }
+
+ ret = cpfl_tdi_rule_process(itf, ad->ctlqp[cpq_id], ad->ctlqp[cpq_id + 1], rinfo, 1,
+ CPFL_TDI_TABLE_ENTRY_OP_DEL);
+ if (ret)
+ goto err;
+
+err:
+ rte_free(rinfo);
+ flow->rule = NULL;
+ return ret;
+}
+
+void
+cpfl_tdi_free_table_list(struct cpfl_flow_parser *flow_parser)
+{
+ struct cpfl_tdi_table_node *node;
+
+ while ((node = TAILQ_FIRST(&flow_parser->tdi_table_list))) {
+ TAILQ_REMOVE(&flow_parser->tdi_table_list, node, next);
+ rte_free(node);
+ }
+}
+
+static int
+cpfl_tdi_build_table_list(struct cpfl_flow_parser *flow_parser)
+{
+ struct cpfl_tdi_program *prog = flow_parser->p4_parser;
+ int i;
+
+ TAILQ_INIT(&flow_parser->tdi_table_list);
+
+ for (i = 0; i < prog->table_num; i++) {
+ struct cpfl_tdi_table *table = &prog->tables[i];
+ struct cpfl_tdi_table_node *node;
+
+ node = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_table_node), 0);
+ if (node == NULL)
+ return -ENOMEM;
+
+ node->table = table;
+ TAILQ_INSERT_TAIL(&flow_parser->tdi_table_list, node, next);
+ }
+
+ return 0;
+}
+
+static void
+cpfl_tdi_build_hw_action_buf(struct cpfl_tdi_action_node *node)
+{
+ int i, j;
+
+ for (i = 0; i < node->format->hw_action_num; i++) {
+ struct cpfl_tdi_hw_action *ha = &node->format->hw_actions_list[i];
+ struct cpfl_tdi_hw_action_parameter *hap = &ha->parameters[0];
+ uint32_t msk = UINT32_MAX;
+ uint32_t action_code = 0;
+ uint16_t offset;
+ uint16_t size;
+
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET10_1b:
+ case CPFL_TDI_ACTION_CODE_SET1_16b:
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ case CPFL_TDI_ACTION_CODE_SET1B_24b:
+ offset = node->buf_len;
+ size = 4;
+ node->buf_len += 4; /* 32 bit action encode */
+ break;
+ default:
+ continue;
+ }
+
+ if (ha->parameter_num == 0) {
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET10_1b:
+ switch (ha->index) {
+ case 0: /* drop */
+ action_code = CPFL_ACT_MAKE_1B(ha->prec,
+ CPFL_ACT_1B_OP_DROP,
+ ha->value & ha->mask);
+ break;
+ default:
+ continue;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ switch (ha->index) {
+ case 9: /* mod profile */
+ action_code =
+ cpfl_act_mod_profile(ha->prec, ha->mod_profile, 0, 0, 0,
+ CPFL_ACT_MOD_PROFILE_PREFETCH_256B)
+ .data;
+ break;
+ case 8: /* queue */
+ /* todo */
+ break;
+ default:
+ break;
+ }
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+ switch (ha->setmd_action_code) {
+ case CPFL_TDI_SETMD_ACTION_CODE_SET_8b:
+ action_code =
+ cpfl_act_set_md8(ha->index, ha->prec, ha->type_id,
+ ha->offset, ha->value, ha->mask)
+ .data;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ continue;
+ }
+
+ memcpy(&node->init_buf[offset], &action_code, 4);
+ memcpy(&node->query_msk[offset], &msk, 4);
+ continue;
+ } else {
+ uint32_t code_msk = 0;
+ uint32_t dummy = 0;
+ uint32_t action_code =
+ cpfl_tdi_to_action_code(ha, (void *)&dummy, CPFL_NO_FWD);
+
+ switch (ha->action_code) {
+ case CPFL_TDI_ACTION_CODE_SET10_1b:
+ code_msk = ~CPFL_ACT_1B_VAL_M;
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1_16b:
+ code_msk = ~CPFL_ACT_16B_VAL_M;
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1A_24b:
+ code_msk = ~CPFL_ACT_24B_A_VAL_M;
+ break;
+ case CPFL_TDI_ACTION_CODE_SET1B_24b: /* set metadata */
+ code_msk = ~CPFL_ACT_24B_B_VAL_M;
+ break;
+ default:
+ continue;
+ }
+
+ memcpy(&node->init_buf[offset], &action_code, 4);
+ memcpy(&node->query_msk[offset], &code_msk, 4);
+ }
+
+ /* only check the first parameter */
+ for (j = 0; j < node->format->immediate_field_num; j++) {
+ struct cpfl_tdi_immediate_field *imf = &node->format->immediate_fields[j];
+
+ if (imf->param_handle == hap->param_handle) {
+ node->params[j].id = imf->param_handle;
+ node->params[j].offset = offset;
+ node->params[j].size = size;
+ }
+ }
+ }
+}
+
+static void
+cpfl_tdi_build_mod_content_format_buf(struct cpfl_tdi_action_node *node)
+{
+ int i, j;
+ uint8_t val_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+ uint8_t msk_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+
+ for (i = 0; i < node->format->mod_content_format.mod_field_num; i++) {
+ struct cpfl_tdi_mod_field *mf = &node->format->mod_content_format.mod_fields[i];
+ uint16_t size = (uint16_t)((mf->start_bit_offset + mf->bit_width) >> 3);
+
+ node->buf_len += size;
+
+ if (mf->type == CPFL_TDI_MOD_FIELD_TYPE_CONSTANT) {
+ memcpy(val_buf, mf->value, size);
+ cpfl_tdi_shift_left(val_buf, size, mf->start_bit_offset);
+ cpfl_tdi_init_msk_buf(msk_buf, size, mf->bit_width);
+ cpfl_tdi_shift_left(msk_buf, size, mf->start_bit_offset);
+ cpfl_tdi_or_buf(&node->init_buf[mf->byte_array_index], size, val_buf,
+ msk_buf);
+ continue;
+ }
+
+ for (j = 0; j < node->format->immediate_field_num; j++) {
+ struct cpfl_tdi_immediate_field *imf = &node->format->immediate_fields[j];
+
+ if (imf->param_handle == mf->param_handle) {
+ node->params[j].id = imf->param_handle;
+ node->params[j].offset = mf->byte_array_index;
+ node->params[j].size = size;
+ break;
+ }
+ }
+ }
+}
+
+static void
+cpfl_tdi_build_action_params(struct cpfl_tdi_action_node *node)
+{
+ node->buf_len = 0;
+ /* build mod content layout */
+ if (node->format->mod_content_format.mod_field_num > 0) {
+ cpfl_tdi_build_mod_content_format_buf(node);
+ /* build action buffer layout */
+ } else if (node->format->hw_action_num > 0) {
+ cpfl_tdi_build_hw_action_buf(node);
+ }
+}
+
+static void
+cpfl_tdi_free_action_list(struct cpfl_flow_parser *flow_parser)
+{
+ struct cpfl_tdi_action_node *action;
+
+ while ((action = TAILQ_FIRST(&flow_parser->tdi_action_list))) {
+ TAILQ_REMOVE(&flow_parser->tdi_action_list, action, next);
+ rte_free(action);
+ }
+}
+
+static int
+cpfl_tdi_build_action_list(struct cpfl_flow_parser *flow_parser)
+{
+#define _HASH_TABLE_NAME_SIZE 32
+#define _HASH_TABLE_ENTRY_SIZE 1024
+ struct cpfl_tdi_program *prog = flow_parser->p4_parser;
+ char hname[_HASH_TABLE_NAME_SIZE];
+ struct rte_hash *ht;
+ int ret = 0;
+ int i, j, k;
+
+ snprintf(hname, _HASH_TABLE_NAME_SIZE, "cpfl_tdi_action_hash");
+
+ struct rte_hash_parameters params = {
+ .name = hname,
+ .entries = _HASH_TABLE_ENTRY_SIZE,
+ .key_len = sizeof(uint32_t),
+ .hash_func = rte_hash_crc,
+ .hash_func_init_val = 0,
+ .socket_id = SOCKET_ID_ANY,
+ .extra_flag = 0,
+ };
+
+ ht = rte_hash_create(¶ms);
+
+ if (ht == NULL) {
+ PMD_INIT_LOG(ERR, "Failed to create hash table %s", hname);
+ return -EINVAL;
+ }
+
+ TAILQ_INIT(&flow_parser->tdi_action_list);
+
+ for (i = 0; i < prog->table_num; i++) {
+ struct cpfl_tdi_table *table = &prog->tables[i];
+
+ for (j = 0; j < table->action_num; j++) {
+ struct cpfl_tdi_action *action = &table->actions[j];
+ uint32_t handle = action->handle;
+ struct cpfl_tdi_action_node *node;
+
+ /* skip if already exist */
+ if (rte_hash_lookup(ht, &handle) >= 0)
+ continue;
+
+ node = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_action_node), 0);
+ if (node == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ node->action = action;
+ ret = rte_hash_add_key_data(ht, &handle, node);
+ if (ret != 0)
+ goto err;
+
+ TAILQ_INSERT_TAIL(&flow_parser->tdi_action_list, node, next);
+ }
+
+ for (j = 0; j < table->match_attributes.hardware_block_num; j++) {
+ struct cpfl_tdi_ma_hardware_block *hb =
+ &table->match_attributes.hardware_blocks[j];
+
+ for (k = 0; k < hb->action_format_num; k++) {
+ struct cpfl_tdi_action_format *format = &hb->action_format[k];
+ uint32_t handle = format->action_handle;
+ struct cpfl_tdi_action_node *node = NULL;
+
+ if (rte_hash_lookup_data(ht, &handle, (void **)&node) >= 0) {
+ node->hw_block_type = hb->hw_block;
+ if (node->format == NULL) {
+ node->format = format;
+ cpfl_tdi_build_action_params(node);
+ }
+ }
+ }
+ }
+ }
+
+ rte_hash_free(ht);
+
+ return 0;
+
+err:
+
+ rte_hash_free(ht);
+ cpfl_tdi_free_action_list(flow_parser);
+ return ret;
+}
+
+static int
+cpfl_tdi_table_info_get(struct rte_eth_dev *dev,
+ uint32_t table_id,
+ struct cpfl_tdi_table_node **table_node)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *adapter = itf->adapter;
+ struct cpfl_tdi_table_node *node;
+ void *temp;
+ int i;
+
+ RTE_TAILQ_FOREACH_SAFE(node, &adapter->flow_parser.tdi_table_list, next, temp)
+ {
+ const struct cpfl_tdi_table *table = node->table;
+
+ if (table->handle != table_id)
+ continue;
+
+ if (table->match_key_field_num > CPFL_TDI_KEY_FIELD_NUM_MAX) {
+ PMD_DRV_LOG(ERR, "Too many fields (%d) in tdi table %s",
+ table->match_key_field_num, table->name);
+ goto err;
+ }
+
+ if (table->action_num > CPFL_TDI_ACTION_SPEC_NUM_MAX) {
+ PMD_DRV_LOG(ERR, "Too many action types (%d) in tdi table %s",
+ table->action_num, table->name);
+ goto err;
+ }
+
+ /* match_key_field first */
+ if (table->match_key_format_num == 0) {
+ node->buf_len = 0;
+ for (i = 0; i < table->match_key_field_num; i++) {
+ struct cpfl_tdi_match_key_field *field =
+ &table->match_key_fields[i];
+ uint32_t size = (uint16_t)(field->bit_width >> 3);
+
+ node->params[i].id = field->index;
+ node->params[i].offset =
+ node->buf_len; /* equal with field->position */
+ node->params[i].size = size;
+ node->buf_len += size;
+ }
+ } else {
+ for (i = 0; i < table->match_key_format_num; i++) {
+ struct cpfl_tdi_match_key_format *format =
+ &table->match_key_format[i];
+
+ node->buf_len =
+ format->byte_array_index + (uint16_t)(format->bit_width >> 3);
+ node->params[i].id = format->match_key_handle;
+ node->params[i].offset = format->byte_array_index;
+ node->params[i].size = (uint16_t)(format->bit_width >> 3);
+ }
+ }
+ *table_node = node;
+
+ return 0;
+ }
+
+err:
+ return -EINVAL;
+}
+
+static int
+cpfl_tdi_table_key_node_init(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_table_node *node,
+ struct cpfl_tdi_table_key_obj *kobj)
+{
+ kobj->tnode = node;
+ kobj->buf_len = node->buf_len;
+ kobj->sem.pin_to_cache = CPFL_PIN_TO_CACHE_DEF;
+ kobj->sem.fixed_fetch = CPFL_FIXED_FETCH_DEF;
+ return 0;
+}
+
+static int
+cpfl_tdi_table_key_create(struct rte_eth_dev *dev,
+ uint32_t table_id,
+ struct cpfl_tdi_table_node **table_node,
+ struct cpfl_tdi_table_key_obj *kobj)
+{
+ int ret;
+
+ if (!kobj)
+ return -EINVAL;
+
+ ret = cpfl_tdi_table_info_get(dev, table_id, table_node);
+ if (ret != 0)
+ return -EINVAL;
+
+ ret = cpfl_tdi_table_key_node_init(dev, *table_node, kobj);
+ if (ret != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_table_key_field_info_get(__rte_unused struct rte_eth_dev *dev,
+ struct cpfl_tdi_table_node *node,
+ uint32_t field_id,
+ struct cpfl_tdi_table_key_field_info **key_field_info)
+{
+ const struct cpfl_tdi_table *table = node->table;
+ int i, j;
+
+ for (i = 0; i < table->match_key_field_num; i++) {
+ struct cpfl_tdi_match_key_field *field = &table->match_key_fields[i];
+ struct cpfl_tdi_table_key_field_info *tkfinfo;
+
+ if (field->index != field_id)
+ continue;
+
+ tkfinfo = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_table_key_field_info), 0);
+ if (tkfinfo == NULL)
+ return -ENOMEM;
+
+ tkfinfo->field = field;
+ tkfinfo->param = node->params[i];
+ *key_field_info = tkfinfo;
+
+ /* adjust byte width */
+ for (j = 0; j < table->match_key_format_num; j++) {
+ struct cpfl_tdi_match_key_format *format = &table->match_key_format[j];
+
+ if (format->match_key_handle != field_id)
+ continue;
+ tkfinfo->format = format;
+ return 0;
+ }
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int
+_cpfl_tdi_table_key_field_set(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_table_key_obj *kobj,
+ struct cpfl_tdi_table_key_field_info *tkfinfo,
+ const uint8_t *value,
+ uint16_t size)
+{
+ struct cpfl_tdi_param_info *pi = &tkfinfo->param;
+ uint8_t *target = &kobj->buf[pi->offset];
+
+ memcpy(target, value, size);
+
+ /* Need to fix as this will overwrite. */
+ if (tkfinfo->format != NULL)
+ cpfl_tdi_shift_left(target, pi->size, tkfinfo->format->start_bit_offset);
+
+ return 0;
+}
+
+static int
+cpfl_tdi_table_key_field_set(struct rte_eth_dev *dev,
+ struct cpfl_tdi_table_node *table_node,
+ struct cpfl_tdi_table_key_obj *kobj,
+ uint32_t field_id,
+ const uint8_t *value,
+ uint16_t size)
+{
+ struct cpfl_tdi_table_key_field_info *key_field_info;
+ int ret;
+
+ if (!kobj || !value)
+ return -EINVAL;
+
+ ret = cpfl_tdi_table_key_field_info_get(dev, table_node, field_id, &key_field_info);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (key_field_info->field->match_type != CPFL_TDI_MATCH_TYPE_EXACT)
+ return -EINVAL;
+
+ if (unlikely(key_field_info->field->is_vsi)) {
+ struct cpfl_itf *src_itf;
+ uint16_t vsi_id, port_id;
+ uint8_t ids[2];
+
+ if (size != 1 && size != 2) /* input port id should be 8/16 bits */
+ return -EINVAL;
+ port_id = size == 1 ? value[0] : value[0] << 8 | value[1];
+ src_itf = cpfl_get_itf_by_port_id(port_id);
+ if (!src_itf)
+ return -EINVAL;
+ vsi_id = cpfl_get_vsi_id(src_itf);
+ if (vsi_id == CPFL_INVALID_HW_ID)
+ return -EINVAL;
+ ids[0] = (uint8_t)vsi_id;
+ ids[1] = (uint8_t)vsi_id >> 8;
+
+ ret = _cpfl_tdi_table_key_field_set(dev, kobj, key_field_info, ids, size);
+ if (ret != 0)
+ return -EINVAL;
+ } else {
+ ret = _cpfl_tdi_table_key_field_set(dev, kobj, key_field_info, value, size);
+ if (ret != 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_action_spec_info_get(struct rte_eth_dev *dev,
+ uint32_t spec_id,
+ struct cpfl_tdi_action_node **action_node)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *adapter = itf->adapter;
+ struct cpfl_tdi_action_node *node;
+ void *temp;
+
+ RTE_TAILQ_FOREACH_SAFE(node, &adapter->flow_parser.tdi_action_list, next, temp)
+ {
+ if (node->action->handle != spec_id)
+ continue;
+ *action_node = node;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int
+cpfl_tdi_action_obj_init(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_table_node *tnode,
+ struct cpfl_tdi_action_node *anode,
+ struct cpfl_tdi_action_obj *aobj)
+{
+ aobj->table = tnode->table;
+ aobj->node = anode;
+ aobj->buf_len = anode->buf_len;
+
+ memcpy(aobj->buf, anode->init_buf, anode->buf_len);
+
+ return 0;
+}
+
+static inline bool __rte_unused
+verify_action(struct cpfl_tdi_table_node *table_node, uint32_t spec_id)
+{
+ int i;
+ const struct cpfl_tdi_table *table = table_node->table;
+
+ for (i = 0; i < table->action_num; i++)
+ if (spec_id == table->actions[i].handle)
+ return true;
+
+ return false;
+}
+
+static int
+cpfl_tdi_action_node_get_by_spec_id(struct rte_eth_dev *dev,
+ uint32_t table_id __rte_unused,
+ uint32_t spec_id,
+ struct cpfl_tdi_action_node **action_node)
+{
+ return cpfl_tdi_action_spec_info_get(dev, spec_id, action_node);
+}
+
+static int
+cpfl_tdi_action_spec_field_info_get(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_action_node *anode,
+ uint32_t field_id,
+ struct cpfl_tdi_action_spec_field_info **info)
+{
+ int ret = -EINVAL;
+ int i, j;
+
+ if (anode->format == NULL)
+ goto err;
+
+ for (i = 0; i < anode->format->immediate_field_num; i++) {
+ struct cpfl_tdi_immediate_field *field = &anode->format->immediate_fields[i];
+ struct cpfl_tdi_action_spec_field_info *asfinfo;
+
+ if (field->param_handle != field_id)
+ continue;
+
+ asfinfo = rte_malloc(NULL, sizeof(struct cpfl_tdi_action_spec_field_info), 0);
+ if (asfinfo == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ asfinfo->field = field;
+ asfinfo->param = anode->params[i];
+
+ for (j = 0; j < anode->format->mod_content_format.mod_field_num; j++) {
+ struct cpfl_tdi_mod_field *mod_field =
+ &anode->format->mod_content_format.mod_fields[j];
+
+ if (mod_field->type != CPFL_TDI_MOD_FIELD_TYPE_PARAMETER)
+ continue;
+
+ if (mod_field->param_handle != field_id)
+ continue;
+
+ asfinfo->mod_field = mod_field;
+ }
+
+ for (i = 0; i < anode->format->hw_action_num; i++) {
+ struct cpfl_tdi_hw_action *hw_action = &anode->format->hw_actions_list[i];
+
+ if (hw_action->parameter_num == 0)
+ continue;
+
+ if (hw_action->parameters[0].param_handle != field_id)
+ continue;
+
+ asfinfo->hw_action = hw_action;
+ }
+
+ *info = asfinfo;
+
+ return 0;
+ }
+ PMD_DRV_LOG(WARNING, "No immediate_field_num!!!");
+err:
+ return ret;
+}
+
+static int
+_cpfl_tdi_action_field_set(struct rte_eth_dev *dev __rte_unused,
+ struct cpfl_tdi_action_obj *aobj,
+ struct cpfl_tdi_action_spec_field_info *asfinfo,
+ const uint8_t *value,
+ uint16_t size,
+ enum cpfl_act_fwd_type fwd_type)
+{
+ struct cpfl_tdi_action_node *node = aobj->node;
+ struct cpfl_tdi_param_info *pi = &asfinfo->param;
+ uint8_t val_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+ uint8_t msk_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
+
+ memcpy(val_buf, value, size);
+
+ if (node->format->mod_content_format.mod_field_num > 0) {
+ struct cpfl_tdi_mod_field *mf = asfinfo->mod_field;
+
+ cpfl_tdi_shift_left(val_buf, pi->size, mf->start_bit_offset);
+ cpfl_tdi_init_msk_buf(msk_buf, pi->size, mf->bit_width);
+ cpfl_tdi_shift_left(msk_buf, pi->size, mf->start_bit_offset);
+ cpfl_tdi_or_buf(&aobj->buf[pi->offset], pi->size, val_buf, msk_buf);
+ } else {
+ struct cpfl_tdi_hw_action *ha = asfinfo->hw_action;
+ uint32_t action_code = cpfl_tdi_to_action_code(ha, val_buf, fwd_type);
+
+ memcpy(&aobj->buf[pi->offset], &action_code, 4);
+ }
+
+ return 0;
+}
+
+static int
+cpfl_tdi_action_field_set(struct rte_eth_dev *dev,
+ struct cpfl_tdi_action_obj *aobj,
+ struct cpfl_tdi_action_node *action_node,
+ uint32_t field_id,
+ const struct rte_flow_action_prog_argument *arg)
+{
+ struct cpfl_tdi_action_spec_field_info *asfinfo;
+ enum rte_flow_action_type action_type;
+ /* used when action is PORT_REPRESENTOR type */
+ struct cpfl_itf *dst_itf;
+ uint16_t dev_id; /* vsi id */
+ uint16_t port_id;
+ uint8_t value;
+ bool is_vsi;
+ int ret;
+ enum cpfl_act_fwd_type fwd_type;
+
+ if (!aobj || !arg)
+ return -EINVAL;
+
+ ret = cpfl_tdi_action_spec_field_info_get(dev, action_node, field_id, &asfinfo);
+ if (ret != 0)
+ return -EINVAL;
+
+ if (!strcmp(arg->name, "port_representor"))
+ action_type = RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR;
+ else if (!strcmp(arg->name, "represented_port"))
+ action_type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT;
+ else
+ return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, arg->value, arg->size,
+ CPFL_NO_FWD);
+
+ if (arg->size != 1 && arg->size != 2) /* input port_id should be 8/16 bits */
+ return -EINVAL;
+
+ port_id = arg->size == 1 ? arg->value[0] : arg->value[0] << 8 | arg->value[1];
+ dst_itf = cpfl_get_itf_by_port_id(port_id);
+ if (!dst_itf)
+ goto err;
+
+ is_vsi = (action_type == RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR ||
+ dst_itf->type == CPFL_ITF_TYPE_REPRESENTOR);
+ if (is_vsi)
+ dev_id = cpfl_get_vsi_id(dst_itf);
+ else
+ dev_id = cpfl_get_port_id(dst_itf);
+
+ if (dev_id == CPFL_INVALID_HW_ID)
+ goto err;
+
+ value = (uint8_t)dev_id;
+ fwd_type = is_vsi ? CPFL_ACT_FWD_VSI : CPFL_ACT_FWD_PORT;
+
+ return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, &value, arg->size, fwd_type);
+err:
+ PMD_DRV_LOG(ERR, "Can not get dev id.");
+ return -EINVAL;
+}
+
+int
+cpfl_tdi_build(struct cpfl_flow_parser *flow_parser)
+{
+ int ret;
+
+ ret = cpfl_tdi_build_table_list(flow_parser);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to build tdi table list");
+ return ret;
+ }
+
+ ret = cpfl_tdi_build_action_list(flow_parser);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to build tdi action list");
+ cpfl_tdi_free_table_list(flow_parser);
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool
+cpfl_flow_items_all_is_flex(const struct rte_flow_item pattern[])
+{
+ int i;
+
+ for (i = 0; pattern[i].type != RTE_FLOW_ITEM_TYPE_END; i++) {
+ if (pattern[i].type != RTE_FLOW_ITEM_TYPE_FLEX)
+ return false;
+ }
+ return true;
+}
+
+static void
+cpfl_fill_rinfo_default_value(struct cpfl_tdi_rule_info *rinfo)
+{
+ if (cpfl_tdi_rule_cookie == ~0llu)
+ cpfl_tdi_rule_cookie = CPFL_COOKIE_DEF;
+ rinfo->cookie = cpfl_tdi_rule_cookie++;
+ rinfo->host_id = CPFL_HOST_ID_DEF;
+ rinfo->port_num = CPFL_PORT_NUM_DEF;
+ rinfo->resp_req = CPFL_RESP_REQ_DEF;
+ rinfo->vsi = CPFL_VSI_DEF;
+ rinfo->clear_mirror_1st_state = CPFL_CLEAR_MIRROR_1ST_STATE_DEF;
+}
+
+static int
+cpfl_tdi_parse_pattern(struct rte_eth_dev *dev,
+ const struct rte_flow_item pattern[],
+ uint32_t table_id,
+ struct cpfl_tdi_table_node **table_node,
+ struct cpfl_tdi_table_key_obj *kobj)
+{
+ const struct rte_flow_item_flex *flex;
+ int i, ret;
+
+ /* Create the key */
+ ret = cpfl_tdi_table_key_create(dev, table_id, table_node, kobj);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to create table key obj.");
+ return -EINVAL;
+ }
+
+ for (i = 0; pattern[i].type != RTE_FLOW_ITEM_TYPE_END; i++) {
+ if (pattern[i].type != RTE_FLOW_ITEM_TYPE_FLEX) {
+ PMD_INIT_LOG(ERR, "All pattern type should be RTE_FLOW_ITEM_TYPE_FLEX.");
+ return -EINVAL;
+ }
+ flex = pattern[i].spec;
+ /* Set the key fields */
+ ret = cpfl_tdi_table_key_field_set(dev, *table_node, kobj, i, flex->pattern,
+ flex->length);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to set table key field.");
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_action(struct rte_eth_dev *dev,
+ const struct rte_flow_action actions[],
+ uint32_t table_id,
+ struct cpfl_tdi_table_node *table_node,
+ struct cpfl_tdi_action_node **action_node,
+ struct cpfl_tdi_action_obj *aobj)
+{
+ const struct rte_flow_action_prog *prog;
+ const struct rte_flow_action_prog_argument *arg;
+ uint32_t action_spec_id;
+ int i, ret;
+ uint32_t j;
+
+ for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
+ if (actions[i].type != RTE_FLOW_ACTION_TYPE_PROG)
+ continue;
+
+ prog = actions[i].conf;
+ action_spec_id = atoi(prog->name);
+ /* Get action node */
+ ret =
+ cpfl_tdi_action_node_get_by_spec_id(dev, table_id, action_spec_id, action_node);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to get action node.");
+ return -EINVAL;
+ }
+
+ ret = cpfl_tdi_action_obj_init(dev, table_node, *action_node, aobj);
+ if (ret != 0) {
+ PMD_INIT_LOG(ERR, "Failed to init action obj.");
+ return -EINVAL;
+ }
+
+ for (j = 0; j < prog->args_num; j++) {
+ arg = &prog->args[j];
+ /* Set the action fields */
+ ret = cpfl_tdi_action_field_set(dev, aobj, *action_node, j, arg);
+ if (ret) {
+ PMD_INIT_LOG(ERR, "Failed to set action field.");
+ return -EINVAL;
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+cpfl_tdi_parse_pattern_action(struct rte_eth_dev *dev,
+ const struct rte_flow_attr *attr,
+ const struct rte_flow_item pattern[],
+ const struct rte_flow_action actions[],
+ void **meta)
+{
+ struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
+ struct cpfl_adapter_ext *adapter = itf->adapter;
+ int ret;
+ struct cpfl_tdi_rule_info *rinfo;
+ struct cpfl_tdi_table_node *table_node;
+ struct cpfl_tdi_action_node *action_node;
+ struct cpfl_tdi_table_key_obj *kobj;
+ struct cpfl_tdi_action_obj *aobj;
+ uint32_t table_id = attr->group;
+
+ if (!adapter->flow_parser.is_p4_parser || !cpfl_flow_items_all_is_flex(pattern))
+ return -EINVAL;
+
+ rinfo = rte_zmalloc(NULL, sizeof(struct cpfl_tdi_rule_info), 0);
+ if (!rinfo)
+ return -ENOMEM;
+
+ kobj = &rinfo->kobj;
+ aobj = &rinfo->aobj;
+ memset(kobj, 0, sizeof(struct cpfl_tdi_table_key_obj));
+ memset(aobj, 0, sizeof(struct cpfl_tdi_action_obj));
+
+ ret = cpfl_tdi_parse_pattern(dev, pattern, table_id, &table_node, kobj);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Invalid pattern");
+ rte_free(rinfo);
+ return -EINVAL;
+ }
+
+ ret = cpfl_tdi_parse_action(dev, actions, table_id, table_node, &action_node, aobj);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "Invalid action");
+ rte_free(rinfo);
+ return -EINVAL;
+ }
+
+ cpfl_fill_rinfo_default_value(rinfo);
+ if (!meta)
+ rte_free(rinfo);
+ else
+ *meta = rinfo;
+
+ return 0;
+}
+
+static int
+cpfl_tdi_fxp_init(struct cpfl_adapter_ext *ad __rte_unused)
+{
+ return 0;
+}
+
+static void
+cpfl_tdi_fxp_uninit(struct cpfl_adapter_ext *ad __rte_unused)
+{
+}
+
+static struct cpfl_flow_engine cpfl_tdi_engine = {
+ .type = CPFL_FLOW_ENGINE_TDI,
+ .init = cpfl_tdi_fxp_init,
+ .uninit = cpfl_tdi_fxp_uninit,
+ .create = cpfl_tdi_fxp_rule_create,
+ .destroy = cpfl_tdi_fxp_rule_destroy,
+ .parse_pattern_action = cpfl_tdi_parse_pattern_action,
+};
+
+RTE_INIT(cpfl_sw_engine_init)
+{
+ struct cpfl_flow_engine *engine = &cpfl_tdi_engine;
+
+ cpfl_flow_engine_register(engine);
+}
diff --git a/drivers/net/cpfl/cpfl_tdi.h b/drivers/net/cpfl/cpfl_tdi.h
new file mode 100644
index 0000000000..c7b8c38657
--- /dev/null
+++ b/drivers/net/cpfl/cpfl_tdi.h
@@ -0,0 +1,123 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Intel Corporation
+ */
+#ifndef _CPFL_TDI_H_
+#define _CPFL_TDI_H_
+
+#include "cpfl_ethdev.h"
+#include "cpfl_fxp_rule.h"
+#include "cpfl_tdi_parser.h"
+
+#define CPFL_TDI_KEY_FIELD_NUM_MAX 256 /* Max number of key field in a table. */
+#define CPFL_TDI_ACTION_SPEC_NUM_MAX 64 /* Max number of action spec in a table. */
+#define CPFL_TDI_ACTION_PARAMETER_NUM_MAX 16
+#define CPFL_TDI_ACTION_BUF_SIZE_MAX 256
+#define CPFL_TDI_TABLE_KEY_FIELD_MAX 32
+#define CPFL_TDI_MAX_TABLE_KEY_SIZE 128
+
+/**
+ *
+ * Table entry operation type.
+ */
+
+enum cpfl_tdi_table_entry_op {
+ CPFL_TDI_TABLE_ENTRY_OP_ADD, /* Add an entry */
+ CPFL_TDI_TABLE_ENTRY_OP_DEL, /* Delete an entry */
+ CPFL_TDI_TABLE_ENTRY_OP_QRY, /* Query an entry */
+};
+
+/**
+ * Table key match type.
+ *
+ * To specify the key match type of a table.
+ */
+enum cpfl_tdi_table_key_match_type {
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_EXACT, /**< Exact match. */
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_WILDCARD, /**< Wildcard match. */
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_RANGE, /**< Range match. */
+ CPFL_TDI_TABLE_KEY_MATCH_TYPE_LPM, /**< longest prefix match. */
+};
+
+struct cpfl_tdi_param_info {
+ uint32_t id;
+ uint16_t offset;
+ uint16_t size;
+};
+
+struct cpfl_tdi_action_spec_field_info {
+ struct cpfl_tdi_immediate_field *field;
+ struct cpfl_tdi_param_info param;
+ struct cpfl_tdi_mod_field *mod_field;
+ struct cpfl_tdi_hw_action *hw_action;
+};
+
+struct cpfl_tdi_table_key_field_info {
+ struct cpfl_tdi_match_key_field *field;
+ struct cpfl_tdi_match_key_format *format;
+ struct cpfl_tdi_param_info param;
+};
+
+struct cpfl_tdi_action_node {
+ TAILQ_ENTRY(cpfl_tdi_action_node) next;
+ enum cpfl_tdi_hw_block hw_block_type;
+ const struct cpfl_tdi_action *action;
+ const struct cpfl_tdi_action_format *format;
+ uint32_t buf_len;
+ struct cpfl_tdi_param_info params[CPFL_TDI_ACTION_PARAMETER_NUM_MAX];
+ uint8_t init_buf[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+ uint8_t query_msk[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+};
+
+struct cpfl_tdi_table_node {
+ TAILQ_ENTRY(cpfl_tdi_table_node) next;
+ const struct cpfl_tdi_table *table;
+ struct cpfl_tdi_action_node **actions;
+ uint16_t buf_len;
+ struct cpfl_tdi_param_info params[CPFL_TDI_TABLE_KEY_FIELD_MAX];
+};
+
+struct cpfl_tdi_table_key_obj {
+ uint16_t buf_len;
+ uint8_t buf[CPFL_TDI_MAX_TABLE_KEY_SIZE];
+ const struct cpfl_tdi_table_node *tnode;
+ union {
+ struct {
+ uint16_t prof_id;
+ uint8_t sub_prof_id;
+ uint8_t pin_to_cache;
+ uint8_t fixed_fetch;
+ } sem;
+ struct {
+ uint32_t mod_index;
+ uint8_t pin_mod_content;
+ uint8_t mod_obj_size;
+ } mod;
+ };
+};
+
+struct cpfl_tdi_action_obj {
+ const struct cpfl_tdi_table *table;
+ struct cpfl_tdi_action_node *node;
+ uint16_t buf_len;
+ uint8_t buf[CPFL_TDI_ACTION_BUF_SIZE_MAX];
+};
+
+TAILQ_HEAD(tdi_table_key_obj_list, tdi_table_key_obj);
+TAILQ_HEAD(tdi_action_obj_list, tdi_action_obj);
+
+struct cpfl_tdi_rule_info {
+ enum cpfl_rule_type type;
+ struct cpfl_tdi_table_key_obj kobj;
+ struct cpfl_tdi_action_obj aobj;
+ uint64_t cookie;
+ uint8_t host_id;
+ uint8_t port_num;
+ uint8_t resp_req;
+ /* vsi is used for lem and lpm rules */
+ uint16_t vsi;
+ uint8_t clear_mirror_1st_state;
+};
+
+void cpfl_tdi_free_table_list(struct cpfl_flow_parser *flow_parser);
+int cpfl_tdi_build(struct cpfl_flow_parser *flow_parser);
+#endif
diff --git a/drivers/net/cpfl/meson.build b/drivers/net/cpfl/meson.build
index f948033f1f..a2e5c9d25b 100644
--- a/drivers/net/cpfl/meson.build
+++ b/drivers/net/cpfl/meson.build
@@ -48,6 +48,7 @@ if dpdk_conf.has('RTE_HAS_JANSSON')
'cpfl_flow_parser.c',
'cpfl_fxp_rule.c',
'cpfl_tdi_parser.c',
+ 'cpfl_tdi.c',
)
ext_deps += jansson_dep
endif
--
2.34.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/2] net/cpfl: parse flow offloading hint from P4 context file
2024-01-05 8:16 ` [PATCH v2 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
@ 2024-02-09 16:20 ` Medvedkin, Vladimir
0 siblings, 0 replies; 8+ messages in thread
From: Medvedkin, Vladimir @ 2024-02-09 16:20 UTC (permalink / raw)
To: wenjing.qiao, jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev
Hi Wenjing,
Please find comments inlined
On 05/01/2024 08:16, wenjing.qiao@intel.com wrote:
> From: Wenjing Qiao <wenjing.qiao@intel.com>
>
> To supporting P4-programmed network controller, reuse devargs
> "flow_parser" to specify the path of a p4 context JSON configure
> file. The cpfl PMD use the JSON configuration file to translate
> rte_flow tokens into low level hardware representation.
>
> Note, the p4 context JSON file is generated by the P4 compiler
> and is intended to work exclusively with a specific P4 pipeline
> configuration, which must be compiled and programmed into the hardware.
>
> Signed-off-by: Wenjing Qiao <wenjing.qiao@intel.com>
> ---
<snip>
> + if (cpfl_check_is_p4_mode(root)) {
> + PMD_DRV_LOG(NOTICE, "flow parser mode is p4 mode.");
> + prog = rte_zmalloc("tdi_parser", sizeof(struct cpfl_tdi_program), 0);
> + if (prog == NULL) {
> + PMD_DRV_LOG(ERR, "Failed to create program object.");
> + return -ENOMEM;
> + }
> + ret = cpfl_tdi_program_create(root, prog);
> + if (ret != 0) {
> + PMD_INIT_LOG(ERR, "Failed to create tdi program from file %s", filename);
> + rte_free(prog);
This looks like doublefree to me because cpfl_tdi_program_create() on
fail calls cpfl_tdi_program_destroy() which in turn does rte_free for
program.
On a separate note maybe cpfl_tdi_program_create() function should not
call cpfl_tdi_program_destroy() and maybe it should be responsibility of
whoever calls _create().
<snip>
> +static int
> +cpfl_tdi_parse_match_key_field_obj(json_t *root, struct cpfl_tdi_match_key_field *mkf)
> +{
> + int ret, val = 0;
> + char last3char[4];
> +
> + ret = cpfl_tdi_get_string_obj(root, "name", mkf->name);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "instance_name", mkf->instance_name);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "field_name", mkf->field_name);
> + if (ret != 0)
> + return ret;
> + strncpy(last3char, mkf->field_name + strlen(mkf->field_name) - 3, 3);
> + last3char[3] = '\0';
> + if (!strcmp(last3char, "VSI") || !strcmp(last3char, "vsi"))
If this is now case sensitive then I'd suggest to make contents of the
last3char lower case to handle all variations of "VSi".
> + mkf->is_vsi = true;
> + else
> + mkf->is_vsi = false;
> +
> + ret = cpfl_tdi_parse_match_type(root, mkf);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
> + if (ret != 0)
> + return ret;
> +
> + mkf->bit_width = (uint16_t)val;
Here and several places below, does it need to be range checked?
> +
> + ret = cpfl_tdi_get_integer_obj(root, "index", &val);
> + if (ret != 0)
> + return ret;
> +
> + mkf->index = (uint32_t)val;
> +
> + ret = cpfl_tdi_get_integer_obj(root, "position", &val);
> + if (ret != 0)
> + return ret;
> +
> + mkf->position = (uint32_t)val;
> +
> + return 0;
> +}
> +
> +static int
> +cpfl_tdi_parse_match_key_fields(json_t *root, struct cpfl_tdi_table *table)
> +{
> + int ret;
> + int array_len = json_array_size(root);
> +
> + if (array_len == 0)
> + return 0;
> +
> + table->match_key_field_num = (uint16_t)array_len;
> + table->match_key_fields =
> + rte_zmalloc(NULL, sizeof(struct cpfl_tdi_match_key_field) * array_len, 0);
> + if (table->match_key_fields == NULL) {
> + PMD_DRV_LOG(ERR, "Failed to create match key field array.");
> + return -ENOMEM;
> + }
> +
> + for (int i = 0; i < array_len; i++) {
> + json_t *mkf_object = json_array_get(root, i);
> +
> + ret = cpfl_tdi_parse_match_key_field_obj(mkf_object, &table->match_key_fields[i]);
> + if (ret != 0)
Possible memory leak due to earlier rte_zmalloc(). There are several
places below with the same problem.
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +cpfl_tdi_parse_byte_order(json_t *root, struct cpfl_tdi_match_key_format *mkf)
> +{
> + char bo[CPFL_TDI_JSON_STR_SIZE_MAX];
> + int ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "byte_order", bo);
> + if (ret != 0)
> + return -EINVAL;
> +
> + if (!strcmp(bo, "HOST")) {
Is it expected to be upper case always?
> + mkf->byte_order = CPFL_TDI_BYTE_ORDER_HOST;
> + } else if (!strcmp(bo, "NETWORK")) {
> + mkf->byte_order = CPFL_TDI_BYTE_ORDER_NETWORK;
> + } else {
> + PMD_DRV_LOG(ERR, "Unknown byte order type %s", bo);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
<snip>
> +
> +static int
> +cpfl_tdi_pparse_action_code(json_t *root, struct cpfl_tdi_hw_action *ha)
double "p"
<snip>
> +static int
> +cpfl_tdi_parse_table_obj(json_t *root, struct cpfl_tdi_table *table)
> +{
> + int ret, val = 0;
> + struct json_t *jobj = NULL;
> +
> + ret = cpfl_tdi_parse_table_type(root, table);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
> + if (ret != 0)
> + return ret;
> + table->handle = (uint32_t)val;
> +
> + ret = cpfl_tdi_get_string_obj(root, "name", table->name);
> + if (ret != 0)
> + return ret;
> +
> + if (table->table_type == CPFL_TDI_TABLE_TYPE_POLICER_METER) {
> + /* TODO */
It looks like not implemented yet, should this return 0? Does it need to
have some kind of logging?
> + return 0;
> + }
<snip>
> +static int
> +cpfl_tdi_parse_global_configs(json_t *root, struct cpfl_tdi_global_configs *gc)
> +{
> + json_t *jobj = NULL;
> + int ret;
> +
> + ret = cpfl_tdi_get_array_obj(root, "hardware_blocks", &jobj);
> + if (ret != 0)
> + return ret;
> +
> + return cpfl_tdi_parse_gc_hardware_blocks(jobj, gc);
> +}
> +
> +int
> +cpfl_tdi_program_create(json_t *root, struct cpfl_tdi_program *prog)
Should input parameters be checked against NULL?
> +{
> + json_t *jobj = NULL;
> + int ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "program_name", prog->program_name);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "build_date", prog->build_date);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "compile_command", prog->compile_command);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "compiler_version", prog->compiler_version);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "schema_version", prog->schema_version);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "target", prog->target);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_object_obj(root, "global_configs", &jobj);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_parse_global_configs(jobj, &prog->global_configs);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_array_obj(root, "tables", &jobj);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_parse_tables(jobj, prog);
> + if (ret != 0)
> + goto err;
> +
> + json_decref(root);
is this json_decref() needed? This function is called from
cpfl_parser_create() which already does json_decref().
> +
> + return 0;
> +
> +err:
> + cpfl_tdi_program_destroy(prog);
> + return ret;
> +}
> +
<snip>
--
Regards,
Vladimir
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/2] net/cpfl: add TDI to flow engine
2024-01-05 8:16 ` [PATCH v2 2/2] net/cpfl: add TDI to flow engine wenjing.qiao
@ 2024-02-14 17:21 ` Medvedkin, Vladimir
0 siblings, 0 replies; 8+ messages in thread
From: Medvedkin, Vladimir @ 2024-02-14 17:21 UTC (permalink / raw)
To: wenjing.qiao, jingjing.wu, beilei.xing, qi.z.zhang; +Cc: dev
[-- Attachment #1: Type: text/plain, Size: 16725 bytes --]
Hi Wenjing,
Please find comments inlined
On 05/01/2024 08:16, wenjing.qiao@intel.com wrote:
> From: Wenjing Qiao<wenjing.qiao@intel.com>
>
> Add TDI implementation to a flow engine.
>
> Signed-off-by: Wenjing Qiao<wenjing.qiao@intel.com>
> ---
<snip>
> --- /dev/null
> +++ b/drivers/net/cpfl/cpfl_tdi.c
> @@ -0,0 +1,1282 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2023 Intel Corporation
> + */
> +#include <rte_hash_crc.h>
> +#include <rte_tailq.h>
RTE includes should be after system includes
> +#include <stdint.h>
> +#include <string.h>
> +
> +#include "cpfl_actions.h"
> +#include "cpfl_flow.h"
> +#include "cpfl_fxp_rule.h"
> +#include "cpfl_tdi.h"
> +#include "cpfl_tdi_parser.h"
> +#include "rte_branch_prediction.h"
> +#include "rte_common.h"
> +#include "rte_flow.h"
Those includes should be together with other RTE includes and have angle
brackets
> +
> +#define CPFL_NO_FWD 0
> +uint64_t cpfl_tdi_rule_cookie = CPFL_COOKIE_DEF;
> +
> +/*help function to do left shift on a byte array */
> +static void
> +cpfl_tdi_shift_left(uint8_t *buf, int length, uint32_t shift_amount)
> +{
> + uint32_t i;
> + int j;
> + uint32_t carry = 0;
> +
> + if (shift_amount == 0)
> + return;
> +
> + for (i = 0; i < shift_amount; i += 8) {
> + for (j = 0; j < length; j++) {
> + uint32_t temp = (buf[j] << (shift_amount - i)) | carry;
> +
> + carry = (temp >> 8) & 0xff;
> + buf[j] = temp & 0xff;
> + }
> + }
> +}
This function does not looks correct to me, at least in case when
shift_amount is larger than 8.
You can try something like:
static void
cpfl_tdi_shift_left(uint8_t *buf, int length, uint32_t shift_amount)
{
int i;
int bit_shift = shift_amount & 0x7;
int byte_shift = shift_amount >> 3;
if (shift_amount >= (length * 8))
return;
uint8_t prev = 0;
for (i = 0; i < length; i++) {
uint8_t val = (buf[i] << bit_shift) | prev;
prev = buf[i] >> (8 - bit_shift);
buf[i] = val;
}
for (i = length - 1; i >= byte_shift; i--) {
buf[i] = buf[i - byte_shift];
}
for(; i >= 0; i--)
buf[i] = 0;
}
> +
> +/* help function to init a mask array with bit_width */
> +static void
> +cpfl_tdi_init_msk_buf(uint8_t *buf, int length, uint32_t bit_width)
> +{
> + uint32_t i;
> +
> + memset(buf, 0, length);
> + for (i = 0; i < bit_width; i++) {
> + cpfl_tdi_shift_left(buf, length, 1);
> + buf[0] += 1;
> + }
> +}
It seems like this function sets bit_width bits into the buf starting
from the LSB. If so I'd suggest to make it simpler and not use
cpfl_tdi_shift_left(). Instead you can just write UINT8/16/32/64_MAX
into the corresponding buffer and decrease bit_width accordingly if it
is bigger than 8/16/32/64 and finally write (1 << bit_width) - 1.
> +
> +/* help function to OR a byte array with value and mask */
> +static void
> +cpfl_tdi_or_buf(uint8_t *buf, int length, uint8_t *values, uint8_t *mask)
> +{
> + int i;
> +
> + for (i = 0; i < length; i++)
> + buf[i] = (values[i] & mask[i]) | (buf[i] & ~mask[i]);
I guess "& ~mask[i]" is not necessary here if this function is really OR.
> +}
<snip>
> +
> +static void
> +cpfl_tdi_pack_sem_entry(struct cpfl_tdi_rule_info *rinfo,
> + struct cpfl_tdi_ma_hardware_block *hb,
> + enum cpfl_tdi_table_entry_op op,
> + struct idpf_dma_mem *dma,
> + struct idpf_ctlq_msg *msg)
> +{
> + union cpfl_rule_cfg_pkt_record *blob;
> + struct cpfl_rule_cfg_data cfg = {0};
> + uint16_t cfg_ctrl;
> + enum cpfl_ctlq_rule_cfg_opc opc = 0;
> + const struct cpfl_tdi_table_key_obj *key = &rinfo->kobj;
> + const struct cpfl_tdi_action_obj *action = &rinfo->aobj;
> +
> + blob = (void *)dma->va;
Why not cast to (union cpfl_rule_cfg_pkt_record *)?
> + memset(blob, 0, sizeof(*blob));
> +
> + cfg_ctrl = CPFL_GET_MEV_SEM_RULE_CFG_CTRL(hb->profile[0], hb->sem.sub_profile, 0, 0);
> +
<snip>
> +static int
> +cpfl_tdi_rule_process(struct cpfl_itf *itf,
> + struct idpf_ctlq_info *tx_cq,
> + struct idpf_ctlq_info *rx_cq,
> + struct cpfl_tdi_rule_info *rinfo,
> + int rule_num,
> + enum cpfl_tdi_table_entry_op op)
> +{
> + const struct cpfl_tdi_table_key_obj *kobj;
> + struct idpf_hw *hw = &itf->adapter->base.hw;
> + struct cpfl_tdi_ma_hardware_block *hb;
> + const struct cpfl_tdi_table *table;
> + int ret = 0;
> +
> + if (rule_num == 0)
> + return 0;
Is it necessary to check this value? This function is called with
nonzero value always.
As a general question, do we need to check input parameters in all these
static functions? It seems some of them are callbacks and their
parameters are probably checked by API, but for others it may be the case.
> +
> + kobj = &rinfo->kobj;
> +
> + table = kobj->tnode->table;
<snip>
> +static int
> +cpfl_tdi_fxp_rule_destroy(struct rte_eth_dev *dev,
> + struct rte_flow *flow,
> + struct rte_flow_error *error)
> +{
> + struct cpfl_itf *itf = CPFL_DEV_TO_ITF(dev);
> + struct cpfl_adapter_ext *ad = itf->adapter;
> + struct cpfl_vport *vport;
> + struct cpfl_repr *repr;
> + struct cpfl_tdi_rule_info *rinfo = (struct cpfl_tdi_rule_info *)flow->rule;
> + int ret = 0;
> + uint32_t cpq_id = 0;
> +
> + if (itf->type == CPFL_ITF_TYPE_VPORT) {
> + vport = (struct cpfl_vport *)itf;
> + cpq_id = vport->base.devarg_id * 2;
> + } else if (itf->type == CPFL_ITF_TYPE_REPRESENTOR) {
> + repr = (struct cpfl_repr *)itf;
> + cpq_id = ((repr->repr_id.pf_id + repr->repr_id.vf_id) & (CPFL_TX_CFGQ_NUM - 1)) * 2;
> + } else {
> + rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
> + "fail to find correct control queue");
> + ret = -rte_errno;
> + goto err;
> + }
> +
> + ret = cpfl_tdi_rule_process(itf, ad->ctlqp[cpq_id], ad->ctlqp[cpq_id + 1], rinfo, 1,
> + CPFL_TDI_TABLE_ENTRY_OP_DEL);
> + if (ret)
> + goto err;
What's the purpose of this goto here?
> +
> +err:
> + rte_free(rinfo);
> + flow->rule = NULL;
> + return ret;
> +}
> +
> +void
> +cpfl_tdi_free_table_list(struct cpfl_flow_parser *flow_parser)
> +{
> + struct cpfl_tdi_table_node *node;
Should this parameter be checked since this is non static function?
> +
> + while ((node = TAILQ_FIRST(&flow_parser->tdi_table_list))) {
> + TAILQ_REMOVE(&flow_parser->tdi_table_list, node, next);
> + rte_free(node);
> + }
> +}
> +
<snip>
> +
> +static int
> +cpfl_tdi_table_key_create(struct rte_eth_dev *dev,
> + uint32_t table_id,
> + struct cpfl_tdi_table_node **table_node,
> + struct cpfl_tdi_table_key_obj *kobj)
> +{
> + int ret;
> +
> + if (!kobj)
> + return -EINVAL;
is it required for static function? in cpfl_tdi_parse_pattern_action()
kobj is zero inited, so in can not be NULL here. Otherwise it would make
sense to check all other arguments as well. I'd suggest to replace
runtime if check with RTE_ASSERT on all input arguments instead.
> +
> + ret = cpfl_tdi_table_info_get(dev, table_id, table_node);
> + if (ret != 0)
> + return -EINVAL;
> +
> + ret = cpfl_tdi_table_key_node_init(dev, *table_node, kobj);
> + if (ret != 0)
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int
> +cpfl_tdi_table_key_field_info_get(__rte_unused struct rte_eth_dev *dev,
why not remove this argument is it is unused? Same applied to several
other functions
> + struct cpfl_tdi_table_node *node,
> + uint32_t field_id,
> + struct cpfl_tdi_table_key_field_info **key_field_info)
> +{
<snip>
> +static int
> +cpfl_tdi_table_key_field_set(struct rte_eth_dev *dev,
> + struct cpfl_tdi_table_node *table_node,
> + struct cpfl_tdi_table_key_obj *kobj,
> + uint32_t field_id,
> + const uint8_t *value,
> + uint16_t size)
> +{
> + struct cpfl_tdi_table_key_field_info *key_field_info;
> + int ret;
> +
> + if (!kobj || !value)
> + return -EINVAL;
> +
> + ret = cpfl_tdi_table_key_field_info_get(dev, table_node, field_id, &key_field_info);
> + if (ret != 0)
> + return -EINVAL;
> +
> + if (key_field_info->field->match_type != CPFL_TDI_MATCH_TYPE_EXACT)
> + return -EINVAL;
possible memory leak since cpfl_tdi_table_key_field_info_get() allocated
memory for key_field_info. Also it would be better to name properly
functions where memory allocation was done.
> +
> + if (unlikely(key_field_info->field->is_vsi)) {
No need to use branch predictor hints since this is not a fast path
> + struct cpfl_itf *src_itf;
> + uint16_t vsi_id, port_id;
> + uint8_t ids[2];
> +
> + if (size != 1 && size != 2) /* input port id should be 8/16 bits */
> + return -EINVAL;
> + port_id = size == 1 ? value[0] : value[0] << 8 | value[1];
please use parenthesis for easier reading
> + src_itf = cpfl_get_itf_by_port_id(port_id);
> + if (!src_itf)
> + return -EINVAL;
> + vsi_id = cpfl_get_vsi_id(src_itf);
> + if (vsi_id == CPFL_INVALID_HW_ID)
> + return -EINVAL;
> + ids[0] = (uint8_t)vsi_id;
> + ids[1] = (uint8_t)vsi_id >> 8;
> +
> + ret = _cpfl_tdi_table_key_field_set(dev, kobj, key_field_info, ids, size);
I think here it would be safer to set size = 2. otherwise stack overflow
can happen
> + if (ret != 0)
> + return -EINVAL;
> + } else {
> + ret = _cpfl_tdi_table_key_field_set(dev, kobj, key_field_info, value, size);
> + if (ret != 0)
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
<snip>
> +
> +static inline bool __rte_unused
is this function necessary in this patch series?
> +verify_action(struct cpfl_tdi_table_node *table_node, uint32_t spec_id)
> +{
> + int i;
> + const struct cpfl_tdi_table *table = table_node->table;
> +
> + for (i = 0; i < table->action_num; i++)
> + if (spec_id == table->actions[i].handle)
> + return true;
> +
> + return false;
> +}
> +
> +static int
> +cpfl_tdi_action_node_get_by_spec_id(struct rte_eth_dev *dev,
> + uint32_t table_id __rte_unused,
> + uint32_t spec_id,
> + struct cpfl_tdi_action_node **action_node)
> +{
> + return cpfl_tdi_action_spec_info_get(dev, spec_id, action_node);
> +}
What's the purpose of this static wrapper function?
> +
> +static int
> +cpfl_tdi_action_spec_field_info_get(struct rte_eth_dev *dev __rte_unused,
> + struct cpfl_tdi_action_node *anode,
> + uint32_t field_id,
> + struct cpfl_tdi_action_spec_field_info **info)
> +{
> + int ret = -EINVAL;
> + int i, j;
> +
> + if (anode->format == NULL)
> + goto err;
> +
> + for (i = 0; i < anode->format->immediate_field_num; i++) {
> + struct cpfl_tdi_immediate_field *field = &anode->format->immediate_fields[i];
> + struct cpfl_tdi_action_spec_field_info *asfinfo;
> +
> + if (field->param_handle != field_id)
> + continue;
> +
> + asfinfo = rte_malloc(NULL, sizeof(struct cpfl_tdi_action_spec_field_info), 0);
> + if (asfinfo == NULL) {
> + ret = -ENOMEM;
> + goto err;
why not just return from here?
> + }
> +
> + asfinfo->field = field;
> + asfinfo->param = anode->params[i];
> +
<snip>
> +static int
> +_cpfl_tdi_action_field_set(struct rte_eth_dev *dev __rte_unused,
> + struct cpfl_tdi_action_obj *aobj,
> + struct cpfl_tdi_action_spec_field_info *asfinfo,
> + const uint8_t *value,
> + uint16_t size,
> + enum cpfl_act_fwd_type fwd_type)
> +{
> + struct cpfl_tdi_action_node *node = aobj->node;
> + struct cpfl_tdi_param_info *pi = &asfinfo->param;
> + uint8_t val_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
> + uint8_t msk_buf[CPFL_TDI_VALUE_SIZE_MAX] = {0};
> +
> + memcpy(val_buf, value, size);
> +
> + if (node->format->mod_content_format.mod_field_num > 0) {
> + struct cpfl_tdi_mod_field *mf = asfinfo->mod_field;
> +
> + cpfl_tdi_shift_left(val_buf, pi->size, mf->start_bit_offset);
how it is guaranteed that pi->size is less than CPFL_TDI_VALUE_SIZE_MAX?
What is the difference between size argument and pi->size here?
> + cpfl_tdi_init_msk_buf(msk_buf, pi->size, mf->bit_width);
> + cpfl_tdi_shift_left(msk_buf, pi->size, mf->start_bit_offset);
> + cpfl_tdi_or_buf(&aobj->buf[pi->offset], pi->size, val_buf, msk_buf);
> + } else {
> + struct cpfl_tdi_hw_action *ha = asfinfo->hw_action;
> + uint32_t action_code = cpfl_tdi_to_action_code(ha, val_buf, fwd_type);
> +
> + memcpy(&aobj->buf[pi->offset], &action_code, 4);
> + }
> +
> + return 0;
why this function returns anything when it always returns 0?
> +}
> +
> +static int
> +cpfl_tdi_action_field_set(struct rte_eth_dev *dev,
> + struct cpfl_tdi_action_obj *aobj,
> + struct cpfl_tdi_action_node *action_node,
> + uint32_t field_id,
> + const struct rte_flow_action_prog_argument *arg)
> +{
> + struct cpfl_tdi_action_spec_field_info *asfinfo;
> + enum rte_flow_action_type action_type;
> + /* used when action is PORT_REPRESENTOR type */
> + struct cpfl_itf *dst_itf;
> + uint16_t dev_id; /* vsi id */
> + uint16_t port_id;
> + uint8_t value;
> + bool is_vsi;
> + int ret;
> + enum cpfl_act_fwd_type fwd_type;
> +
> + if (!aobj || !arg)
> + return -EINVAL;
> +
> + ret = cpfl_tdi_action_spec_field_info_get(dev, action_node, field_id, &asfinfo);
it seems like asfinfo that was allocated inside
cpfl_tdi_action_spec_field_info_get() is only used locally inside the
cpfl_tdi_action_field_set(). It should be freed somewhere in this
function before it returns.
Or as a better solution why not just have this struct as stack
allocated, don't allocate memory for it at all and just init it inside
the cpfl_tdi_action_spec_field_info_get()? Otherwise you'll have
problems with possible memory leak.
> + if (ret != 0)
> + return -EINVAL;
> +
> + if (!strcmp(arg->name, "port_representor"))
> + action_type = RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR;
> + else if (!strcmp(arg->name, "represented_port"))
> + action_type = RTE_FLOW_ACTION_TYPE_REPRESENTED_PORT;
> + else
> + return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, arg->value, arg->size,
> + CPFL_NO_FWD);
> +
> + if (arg->size != 1 && arg->size != 2) /* input port_id should be 8/16 bits */
> + return -EINVAL;
same problem with memory leak after cpfl_tdi_action_spec_field_info_get()
> +
> + port_id = arg->size == 1 ? arg->value[0] : arg->value[0] << 8 | arg->value[1];
> + dst_itf = cpfl_get_itf_by_port_id(port_id);
> + if (!dst_itf)
> + goto err;
> +
> + is_vsi = (action_type == RTE_FLOW_ACTION_TYPE_PORT_REPRESENTOR ||
> + dst_itf->type == CPFL_ITF_TYPE_REPRESENTOR);
> + if (is_vsi)
> + dev_id = cpfl_get_vsi_id(dst_itf);
> + else
> + dev_id = cpfl_get_port_id(dst_itf);
> +
> + if (dev_id == CPFL_INVALID_HW_ID)
> + goto err;
> +
> + value = (uint8_t)dev_id;
> + fwd_type = is_vsi ? CPFL_ACT_FWD_VSI : CPFL_ACT_FWD_PORT;
> +
> + return _cpfl_tdi_action_field_set(dev, aobj, asfinfo, &value, arg->size, fwd_type);
> +err:
> + PMD_DRV_LOG(ERR, "Can not get dev id.");
> + return -EINVAL;
> +}
> +
> +int
> +cpfl_tdi_build(struct cpfl_flow_parser *flow_parser)
> +{
> + int ret;
> +
for non static function input arguments should probably be checked.
> + ret = cpfl_tdi_build_table_list(flow_parser);
> + if (ret != 0) {
> + PMD_INIT_LOG(ERR, "Failed to build tdi table list");
> + return ret;
> + }
> +
<snip>
> +static int
> +cpfl_tdi_parse_action(struct rte_eth_dev *dev,
> + const struct rte_flow_action actions[],
> + uint32_t table_id,
> + struct cpfl_tdi_table_node *table_node,
> + struct cpfl_tdi_action_node **action_node,
> + struct cpfl_tdi_action_obj *aobj)
> +{
> + const struct rte_flow_action_prog *prog;
> + const struct rte_flow_action_prog_argument *arg;
> + uint32_t action_spec_id;
> + int i, ret;
> + uint32_t j;
> +
> + for (i = 0; actions[i].type != RTE_FLOW_ACTION_TYPE_END; i++) {
> + if (actions[i].type != RTE_FLOW_ACTION_TYPE_PROG)
> + continue;
> +
> + prog = actions[i].conf;
> + action_spec_id = atoi(prog->name);
> + /* Get action node */
> + ret =
> + cpfl_tdi_action_node_get_by_spec_id(dev, table_id, action_spec_id, action_node);
> + if (ret) {
> + PMD_INIT_LOG(ERR, "Failed to get action node.");
> + return -EINVAL;
> + }
> +
> + ret = cpfl_tdi_action_obj_init(dev, table_node, *action_node, aobj);
> + if (ret != 0) {
nothing can happen inside cpfl_tdi_action_obj_init(), it always returns 0
> + PMD_INIT_LOG(ERR, "Failed to init action obj.");
> + return -EINVAL;
> + }
> +
> + for (j = 0; j < prog->args_num; j++) {
> + arg = &prog->args[j];
> + /* Set the action fields */
> + ret = cpfl_tdi_action_field_set(dev, aobj, *action_node, j, arg);
> + if (ret) {
> + PMD_INIT_LOG(ERR, "Failed to set action field.");
> + return -EINVAL;
> + }
> + }
> + }
> + return 0;
> +}
> +
<snip>
> --
Regards,
Vladimir
[-- Attachment #2: Type: text/html, Size: 23809 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-02-14 17:21 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-12-22 10:08 [PATCH 0/2] net/cpfl: support flow offloading for P4 wenjing.qiao
2023-12-22 10:08 ` [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 0/2] net/cpfl: support flow offloading for P4 wenjing.qiao
2024-01-05 8:16 ` [PATCH v2 1/2] net/cpfl: parse flow offloading hint from P4 context file wenjing.qiao
2024-02-09 16:20 ` Medvedkin, Vladimir
2024-01-05 8:16 ` [PATCH v2 2/2] net/cpfl: add TDI to flow engine wenjing.qiao
2024-02-14 17:21 ` Medvedkin, Vladimir
2023-12-22 10:08 ` [PATCH " wenjing.qiao
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).