[PATCH v2 1/2] net/cpfl: parse flow offloading hint from P4 context file
Medvedkin, Vladimir
vladimir.medvedkin at intel.com
Fri Feb 9 17:20:02 CET 2024
Hi Wenjing,
Please find comments inlined
On 05/01/2024 08:16, wenjing.qiao at intel.com wrote:
> From: Wenjing Qiao <wenjing.qiao at intel.com>
>
> To supporting P4-programmed network controller, reuse devargs
> "flow_parser" to specify the path of a p4 context JSON configure
> file. The cpfl PMD use the JSON configuration file to translate
> rte_flow tokens into low level hardware representation.
>
> Note, the p4 context JSON file is generated by the P4 compiler
> and is intended to work exclusively with a specific P4 pipeline
> configuration, which must be compiled and programmed into the hardware.
>
> Signed-off-by: Wenjing Qiao <wenjing.qiao at intel.com>
> ---
<snip>
> + if (cpfl_check_is_p4_mode(root)) {
> + PMD_DRV_LOG(NOTICE, "flow parser mode is p4 mode.");
> + prog = rte_zmalloc("tdi_parser", sizeof(struct cpfl_tdi_program), 0);
> + if (prog == NULL) {
> + PMD_DRV_LOG(ERR, "Failed to create program object.");
> + return -ENOMEM;
> + }
> + ret = cpfl_tdi_program_create(root, prog);
> + if (ret != 0) {
> + PMD_INIT_LOG(ERR, "Failed to create tdi program from file %s", filename);
> + rte_free(prog);
This looks like doublefree to me because cpfl_tdi_program_create() on
fail calls cpfl_tdi_program_destroy() which in turn does rte_free for
program.
On a separate note maybe cpfl_tdi_program_create() function should not
call cpfl_tdi_program_destroy() and maybe it should be responsibility of
whoever calls _create().
<snip>
> +static int
> +cpfl_tdi_parse_match_key_field_obj(json_t *root, struct cpfl_tdi_match_key_field *mkf)
> +{
> + int ret, val = 0;
> + char last3char[4];
> +
> + ret = cpfl_tdi_get_string_obj(root, "name", mkf->name);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "instance_name", mkf->instance_name);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "field_name", mkf->field_name);
> + if (ret != 0)
> + return ret;
> + strncpy(last3char, mkf->field_name + strlen(mkf->field_name) - 3, 3);
> + last3char[3] = '\0';
> + if (!strcmp(last3char, "VSI") || !strcmp(last3char, "vsi"))
If this is now case sensitive then I'd suggest to make contents of the
last3char lower case to handle all variations of "VSi".
> + mkf->is_vsi = true;
> + else
> + mkf->is_vsi = false;
> +
> + ret = cpfl_tdi_parse_match_type(root, mkf);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_integer_obj(root, "bit_width", &val);
> + if (ret != 0)
> + return ret;
> +
> + mkf->bit_width = (uint16_t)val;
Here and several places below, does it need to be range checked?
> +
> + ret = cpfl_tdi_get_integer_obj(root, "index", &val);
> + if (ret != 0)
> + return ret;
> +
> + mkf->index = (uint32_t)val;
> +
> + ret = cpfl_tdi_get_integer_obj(root, "position", &val);
> + if (ret != 0)
> + return ret;
> +
> + mkf->position = (uint32_t)val;
> +
> + return 0;
> +}
> +
> +static int
> +cpfl_tdi_parse_match_key_fields(json_t *root, struct cpfl_tdi_table *table)
> +{
> + int ret;
> + int array_len = json_array_size(root);
> +
> + if (array_len == 0)
> + return 0;
> +
> + table->match_key_field_num = (uint16_t)array_len;
> + table->match_key_fields =
> + rte_zmalloc(NULL, sizeof(struct cpfl_tdi_match_key_field) * array_len, 0);
> + if (table->match_key_fields == NULL) {
> + PMD_DRV_LOG(ERR, "Failed to create match key field array.");
> + return -ENOMEM;
> + }
> +
> + for (int i = 0; i < array_len; i++) {
> + json_t *mkf_object = json_array_get(root, i);
> +
> + ret = cpfl_tdi_parse_match_key_field_obj(mkf_object, &table->match_key_fields[i]);
> + if (ret != 0)
Possible memory leak due to earlier rte_zmalloc(). There are several
places below with the same problem.
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int
> +cpfl_tdi_parse_byte_order(json_t *root, struct cpfl_tdi_match_key_format *mkf)
> +{
> + char bo[CPFL_TDI_JSON_STR_SIZE_MAX];
> + int ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "byte_order", bo);
> + if (ret != 0)
> + return -EINVAL;
> +
> + if (!strcmp(bo, "HOST")) {
Is it expected to be upper case always?
> + mkf->byte_order = CPFL_TDI_BYTE_ORDER_HOST;
> + } else if (!strcmp(bo, "NETWORK")) {
> + mkf->byte_order = CPFL_TDI_BYTE_ORDER_NETWORK;
> + } else {
> + PMD_DRV_LOG(ERR, "Unknown byte order type %s", bo);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
<snip>
> +
> +static int
> +cpfl_tdi_pparse_action_code(json_t *root, struct cpfl_tdi_hw_action *ha)
double "p"
<snip>
> +static int
> +cpfl_tdi_parse_table_obj(json_t *root, struct cpfl_tdi_table *table)
> +{
> + int ret, val = 0;
> + struct json_t *jobj = NULL;
> +
> + ret = cpfl_tdi_parse_table_type(root, table);
> + if (ret != 0)
> + return ret;
> +
> + ret = cpfl_tdi_get_integer_obj(root, "handle", &val);
> + if (ret != 0)
> + return ret;
> + table->handle = (uint32_t)val;
> +
> + ret = cpfl_tdi_get_string_obj(root, "name", table->name);
> + if (ret != 0)
> + return ret;
> +
> + if (table->table_type == CPFL_TDI_TABLE_TYPE_POLICER_METER) {
> + /* TODO */
It looks like not implemented yet, should this return 0? Does it need to
have some kind of logging?
> + return 0;
> + }
<snip>
> +static int
> +cpfl_tdi_parse_global_configs(json_t *root, struct cpfl_tdi_global_configs *gc)
> +{
> + json_t *jobj = NULL;
> + int ret;
> +
> + ret = cpfl_tdi_get_array_obj(root, "hardware_blocks", &jobj);
> + if (ret != 0)
> + return ret;
> +
> + return cpfl_tdi_parse_gc_hardware_blocks(jobj, gc);
> +}
> +
> +int
> +cpfl_tdi_program_create(json_t *root, struct cpfl_tdi_program *prog)
Should input parameters be checked against NULL?
> +{
> + json_t *jobj = NULL;
> + int ret;
> +
> + ret = cpfl_tdi_get_string_obj(root, "program_name", prog->program_name);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "build_date", prog->build_date);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "compile_command", prog->compile_command);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "compiler_version", prog->compiler_version);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "schema_version", prog->schema_version);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_string_obj(root, "target", prog->target);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_object_obj(root, "global_configs", &jobj);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_parse_global_configs(jobj, &prog->global_configs);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_get_array_obj(root, "tables", &jobj);
> + if (ret != 0)
> + goto err;
> +
> + ret = cpfl_tdi_parse_tables(jobj, prog);
> + if (ret != 0)
> + goto err;
> +
> + json_decref(root);
is this json_decref() needed? This function is called from
cpfl_parser_create() which already does json_decref().
> +
> + return 0;
> +
> +err:
> + cpfl_tdi_program_destroy(prog);
> + return ret;
> +}
> +
<snip>
--
Regards,
Vladimir
More information about the dev
mailing list