From patchwork Fri Dec 22 10:08:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenjing Qiao X-Patchwork-Id: 135496 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 8A3BA4375D; Fri, 22 Dec 2023 11:10:04 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 7819D402F0; Fri, 22 Dec 2023 11:10:04 +0100 (CET) Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.20]) by mails.dpdk.org (Postfix) with ESMTP id 799F74067C for ; Fri, 22 Dec 2023 11:10:02 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703239802; x=1734775802; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Ow9tbu4BYmF06S7u8KRkX6H5qIvINhV0u3Vr51gsOY0=; b=BNgWdb/1yjrOMzGNCRXJRQNDxAnRsNCiNGEQS43iNSCi8MTmKGlCc9+r hZ2cmnyfQiEGtsIndgqlEzzmatF/XGLMhspRvx5tLP7JxFb3h5Ot22j3s ZmmjGkJSf9rZbh+f8U7WKh8v31wnW4dfZHScpEaDcLmr5cm+lw8fbN5VZ GhKIJEPB1JkOPPWMDSu6J/crd+neeiWKofdf1Eiv3uNNgPwKLt1fElnbk h/F+lPFeobmJSUqY+Ej6nMHZPkxokSPMnwt4qPJCwFBplkK1UKBpcc93t QlbIvu8noYuOftxvPYEdgHndyStvnoyAzImAZI0XYqkLl7PBQB2b/Tx6l w==; X-IronPort-AV: E=McAfee;i="6600,9927,10931"; a="386525288" X-IronPort-AV: E=Sophos;i="6.04,296,1695711600"; d="scan'208";a="386525288" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Dec 2023 02:10:01 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10931"; a="920605319" X-IronPort-AV: E=Sophos;i="6.04,296,1695711600"; d="scan'208";a="920605319" Received: from dpdk-wenjing-02.sh.intel.com ([10.67.118.228]) by fmsmga001.fm.intel.com with ESMTP; 22 Dec 2023 02:09:58 -0800 From: wenjing.qiao@intel.com To: jingjing.wu@intel.com, beilei.xing@intel.com, qi.z.zhang@intel.com Cc: dev@dpdk.org, Wenjing Qiao Subject: [PATCH 1/2] net/cpfl: parse flow offloading hint from P4 context file Date: Fri, 22 Dec 2023 10:08:39 +0000 Message-Id: <20231222100837.260493-2-wenjing.qiao@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231222100837.260493-1-wenjing.qiao@intel.com> References: <20231222100837.260493-1-wenjing.qiao@intel.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Wenjing Qiao 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 --- 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 #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 +#include + +#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 +#include + +#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 From patchwork Fri Dec 22 10:08:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wenjing Qiao X-Patchwork-Id: 135497 X-Patchwork-Delegate: qi.z.zhang@intel.com Return-Path: X-Original-To: patchwork@inbox.dpdk.org Delivered-To: patchwork@inbox.dpdk.org Received: from mails.dpdk.org (mails.dpdk.org [217.70.189.124]) by inbox.dpdk.org (Postfix) with ESMTP id 5A09E4375D; Fri, 22 Dec 2023 11:10:23 +0100 (CET) Received: from mails.dpdk.org (localhost [127.0.0.1]) by mails.dpdk.org (Postfix) with ESMTP id 44BBE4025D; Fri, 22 Dec 2023 11:10:23 +0100 (CET) Received: from mgamail.intel.com (mgamail.intel.com [134.134.136.20]) by mails.dpdk.org (Postfix) with ESMTP id EA8E54003C for ; Fri, 22 Dec 2023 11:10:21 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1703239822; x=1734775822; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eCC5NRFKu9BNAwsCe44TiXkxfokxcrVOwfWFnYYZyIg=; b=fgOp061VHSeQ6PiqOTmVAobMkjF4yYbz6tgeFKUlBGgWQjwPuzs/H1ul aaGyJ/FTeizkvgLHC8WRLd73NtYEjphmjrEUZYVZ+rWi30tDwpP/CW+nG yXB52HjhgEpQTOmChJVlki8BTUeKzEqUm4V1Z7d0AfxB8xHPrQiY2NuUg cZ4pCW1AgumAJqBgpEYWilZE0Bjo9Nr0ByetyZo77AEucTZ64/rB76MIv gDF0aVm7e6LArTdy7Y0mNduE3G5NaYc3RVxNvlGI18HwTCwE7P5Li2s3D tWDuSwhWrA0AekclS2AWFp81IVadQYo3XcDM+P4Dwd1+bRs51qnsriNv2 g==; X-IronPort-AV: E=McAfee;i="6600,9927,10931"; a="386525305" X-IronPort-AV: E=Sophos;i="6.04,296,1695711600"; d="scan'208";a="386525305" Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 22 Dec 2023 02:10:20 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10931"; a="920605426" X-IronPort-AV: E=Sophos;i="6.04,296,1695711600"; d="scan'208";a="920605426" Received: from dpdk-wenjing-02.sh.intel.com ([10.67.118.228]) by fmsmga001.fm.intel.com with ESMTP; 22 Dec 2023 02:10:18 -0800 From: wenjing.qiao@intel.com To: jingjing.wu@intel.com, beilei.xing@intel.com, qi.z.zhang@intel.com Cc: dev@dpdk.org, Wenjing Qiao Subject: [PATCH 2/2] net/cpfl: add TDI to flow engine Date: Fri, 22 Dec 2023 10:08:41 +0000 Message-Id: <20231222100837.260493-3-wenjing.qiao@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20231222100837.260493-1-wenjing.qiao@intel.com> References: <20231222100837.260493-1-wenjing.qiao@intel.com> MIME-Version: 1.0 X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org From: Wenjing Qiao Add TDI implementation to a flow engine. Signed-off-by: Wenjing Qiao --- 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 +#include +#include +#include +#include + +#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