> +static int > +cpfl_json_object_to_int(json_object *object, const char *name, int *value) > +{ > + json_object *subobject; > + > + if (!object) { > + PMD_DRV_LOG(ERR, "object doesn't exist."); > + return -EINVAL; > + } > + subobject = json_object_object_get(object, name); > + if (!subobject) { > + PMD_DRV_LOG(ERR, "%s doesn't exist.", name); > + return -EINVAL; > + } > + *value = json_object_get_int(subobject); > + > + return 0; > +} > + > +static int > +cpfl_json_object_to_uint16(json_object *object, const char *name, uint16_t > *value) > +{ Looks no need to define a new function as there is no difference with cpfl_json_object_to_int func beside the type of return value. [...]
> + > +static int > +cpfl_flow_js_pattern_key_proto_field(json_object *cjson_field, > + struct cpfl_flow_js_pr_key_proto *js_field) > +{ > + int len, i; > + > + if (!cjson_field) > + return 0; > + len = json_object_array_length(cjson_field); > + js_field->fields_size = len; > + if (len == 0) Move if check above, before set js_field->fields_size? > + return 0; > + js_field->fields = > + rte_malloc(NULL, sizeof(struct cpfl_flow_js_pr_key_proto_field) * > len, 0); > + if (!js_field->fields) { > + PMD_DRV_LOG(ERR, "Failed to alloc memory."); > + return -ENOMEM; > + } > + for (i = 0; i < len; i++) { > + json_object *object; > + const char *name, *mask; > + > + object = json_object_array_get_idx(cjson_field, i); > + name = cpfl_json_object_to_string(object, "name"); > + if (!name) { > + PMD_DRV_LOG(ERR, "Can not parse string 'name'."); > + goto err; > + } > + if (strlen(name) > CPFL_FLOW_JSON_STR_SIZE_MAX) { > + PMD_DRV_LOG(ERR, "The 'name' is too long."); > + goto err; > + } > + memcpy(js_field->fields[i].name, name, strlen(name)); Is js_field->fields[i].name zeroed? If not, using strlen() cannot guarantee string copy correct. > + if (js_field->type == RTE_FLOW_ITEM_TYPE_ETH || > + js_field->type == RTE_FLOW_ITEM_TYPE_IPV4) { > + mask = cpfl_json_object_to_string(object, "mask"); > + if (!mask) { > + PMD_DRV_LOG(ERR, "Can not parse string > 'mask'."); > + goto err; > + } > + memcpy(js_field->fields[i].mask, mask, strlen(mask)); The same as above. > + } else { > + uint32_t mask_32b; > + int ret; > + > + ret = cpfl_json_object_to_uint32(object, "mask", > &mask_32b); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse uint32 > 'mask'."); > + goto err; > + } > + js_field->fields[i].mask_32b = mask_32b; > + } > + } > + > + return 0; > + > +err: > + rte_free(js_field->fields); > + return -EINVAL; > +} > + > +static int > +cpfl_flow_js_pattern_key_proto(json_object *cjson_pr_key_proto, struct > cpfl_flow_js_pr *js_pr) > +{ > + int len, i, ret; > + > + len = json_object_array_length(cjson_pr_key_proto); > + js_pr->key.proto_size = len; > + js_pr->key.protocols = rte_malloc(NULL, sizeof(struct > cpfl_flow_js_pr_key_proto) * len, 0); > + if (!js_pr->key.protocols) { > + PMD_DRV_LOG(ERR, "Failed to alloc memory."); > + return -ENOMEM; > + } > + > + for (i = 0; i < len; i++) { > + json_object *object, *cjson_pr_key_proto_fields; > + const char *type; > + enum rte_flow_item_type item_type; > + > + object = json_object_array_get_idx(cjson_pr_key_proto, i); > + /* pr->key->proto->type */ > + type = cpfl_json_object_to_string(object, "type"); > + if (!type) { > + PMD_DRV_LOG(ERR, "Can not parse string 'type'."); > + goto err; > + } > + item_type = cpfl_get_item_type_by_str(type); > + if (item_type == RTE_FLOW_ITEM_TYPE_VOID) > + goto err; > + js_pr->key.protocols[i].type = item_type; > + /* pr->key->proto->fields */ > + cjson_pr_key_proto_fields = json_object_object_get(object, > "fields"); > + ret = > cpfl_flow_js_pattern_key_proto_field(cjson_pr_key_proto_fields, > + &js_pr- > >key.protocols[i]); > + if (ret < 0) > + goto err; > + } > + > + return 0; > + > +err: > + rte_free(js_pr->key.protocols); > + return -EINVAL; > +} > + > +static int > +cpfl_flow_js_pattern_act_fv_proto(json_object *cjson_value, struct > cpfl_flow_js_fv *js_fv) > +{ > + uint16_t layer = 0, offset = 0, mask = 0; > + const char *header; > + enum rte_flow_item_type type; > + int ret; > + > + ret = cpfl_json_object_to_uint16(cjson_value, "layer", &layer); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'value'."); > + return -EINVAL; > + } > + > + header = cpfl_json_object_to_string(cjson_value, "header"); > + if (!header) { > + PMD_DRV_LOG(ERR, "Can not parse string 'header'."); > + return -EINVAL; > + } > + ret = cpfl_json_object_to_uint16(cjson_value, "offset", &offset); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'offset'."); > + return -EINVAL; > + } > + ret = cpfl_json_object_to_uint16(cjson_value, "mask", &mask); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'mask'."); > + return -EINVAL; > + } > + js_fv->proto.layer = layer; > + js_fv->proto.offset = offset; > + js_fv->proto.mask = mask; > + type = cpfl_get_item_type_by_str(header); You can put this after get header, if no item type, return earlier. > + if (type == RTE_FLOW_ITEM_TYPE_VOID) > + return -EINVAL; > + js_fv->proto.header = type; > + > + return 0; > +} > + > +static int > +cpfl_flow_js_pattern_act_fv_metadata(json_object *cjson_value, struct > cpfl_flow_js_fv *js_fv) > +{ > + int ret; > + > + ret = cpfl_json_object_to_uint16(cjson_value, "type", &js_fv- > >meta.type); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'size'."); Is the log correct? > + return ret; > + } > + ret = cpfl_json_object_to_uint16(cjson_value, "offset", &js_fv- > >meta.offset); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'size'."); Same as above. > + return ret; > + } > + ret = cpfl_json_object_to_uint16(cjson_value, "mask", &js_fv- > >meta.mask); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'size'."); > + return ret; > + } > + > + return 0; > +} > + > +static int > +cpfl_flow_js_pattern_act_fv(json_object *cjson_fv, struct > cpfl_flow_js_pr_action *js_act) > +{ > + int len, i; > + > + len = json_object_array_length(cjson_fv); Better to check the len here? > + js_act->sem.fv = rte_malloc(NULL, sizeof(struct cpfl_flow_js_fv) * len, > 0); > + if (!js_act->sem.fv) { > + PMD_DRV_LOG(ERR, "Failed to alloc memory."); > + return -ENOMEM; > + } > + js_act->sem.fv_size = len; > + for (i = 0; i < len; i++) { > + struct cpfl_flow_js_fv *js_fv; > + json_object *object, *cjson_value; > + uint16_t offset = 0; > + const char *type; > + int ret; > + > + object = json_object_array_get_idx(cjson_fv, i); > + js_fv = &js_act->sem.fv[i]; > + ret = cpfl_json_object_to_uint16(object, "offset", &offset); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'offset'."); > + goto err; > + } > + js_fv->offset = offset; > + type = cpfl_json_object_to_string(object, "type"); > + if (!type) { > + PMD_DRV_LOG(ERR, "Can not parse string 'type'."); > + goto err; > + } > + cjson_value = json_object_object_get(object, "value"); > + if (strcmp(type, "immediate") == 0) { > + js_fv->type = CPFL_FV_TYPE_IMMEDIATE; > + js_fv->immediate = json_object_get_int(cjson_value); > + } else if (strcmp(type, "metadata") == 0) { > + js_fv->type = CPFL_FV_TYPE_METADATA; > + cpfl_flow_js_pattern_act_fv_metadata(cjson_value, > js_fv); > + } else if (strcmp(type, "protocol") == 0) { > + js_fv->type = CPFL_FV_TYPE_PROTOCOL; > + cpfl_flow_js_pattern_act_fv_proto(cjson_value, > js_fv); > + } else { > + PMD_DRV_LOG(ERR, "Not support this type: %s.", > type); > + goto err; > + } > + } > + > + return 0; > + > +err: > + rte_free(js_act->sem.fv); > + return -EINVAL; > +} > + > +static int > +cpfl_flow_js_pattern_per_act(json_object *cjson_per_act, struct > cpfl_flow_js_pr_action *js_act) > +{ > + const char *type; > + int ret; > + > + /* pr->actions->type */ > + type = cpfl_json_object_to_string(cjson_per_act, "type"); > + if (!type) { > + PMD_DRV_LOG(ERR, "Can not parse string 'type'."); > + return -EINVAL; > + } > + /* pr->actions->data */ > + if (strcmp(type, "sem") == 0) { > + json_object *cjson_fv, *cjson_pr_action_sem; > + > + js_act->type = CPFL_JS_PR_ACTION_TYPE_SEM; > + cjson_pr_action_sem = > json_object_object_get(cjson_per_act, "data"); > + ret = cpfl_json_object_to_uint16(cjson_pr_action_sem, > "profile", > + &js_act->sem.prof); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'profile'."); > + return -EINVAL; > + } > + ret = cpfl_json_object_to_uint16(cjson_pr_action_sem, > "subprofile", > + &js_act->sem.subprof); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'subprofile'."); > + return -EINVAL; > + } > + ret = cpfl_json_object_to_uint16(cjson_pr_action_sem, > "keysize", > + &js_act->sem.keysize); > + if (ret < 0) { > + PMD_DRV_LOG(ERR, "Can not parse 'keysize'."); > + return -EINVAL; > + } > + cjson_fv = json_object_object_get(cjson_pr_action_sem, > "fieldvectors"); > + ret = cpfl_flow_js_pattern_act_fv(cjson_fv, js_act); > + if (ret < 0) > + return ret; > + } else { > + PMD_DRV_LOG(ERR, "Not support this type: %s.", type); > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int > +cpfl_flow_js_pattern_act(json_object *cjson_pr_act, struct cpfl_flow_js_pr > *js_pr) > +{ > + int i, len, ret; > + > + len = json_object_array_length(cjson_pr_act); Check len? The same comments for following code where get length and them allocate memory, [...] > +int > +cpfl_parser_destroy(struct cpfl_flow_js_parser *parser) > +{ > + int i, j; > + > + if (!parser) > + return 0; > + > + for (i = 0; i < parser->pr_size; i++) { > + struct cpfl_flow_js_pr *pattern = &parser->patterns[i]; > + > + if (!pattern) > + return -EINVAL; I think the destroy might continue, if so, use continue but not just return. > + for (j = 0; j < pattern->key.proto_size; j++) > + rte_free(pattern->key.protocols[j].fields); > + rte_free(pattern->key.protocols); > + rte_free(pattern->key.attributes); > + > + for (j = 0; j < pattern->actions_size; j++) { > + struct cpfl_flow_js_pr_action *pr_act; > + > + pr_act = &pattern->actions[j]; > + cpfl_parser_free_pr_action(pr_act); > + } > + rte_free(pattern->actions); > + } > + rte_free(parser->patterns); > + for (i = 0; i < parser->mr_size; i++) { > + struct cpfl_flow_js_mr *mr = &parser->modifications[i]; > + > + if (!mr) > + return -EINVAL; I think the destroy might continue, if so, use continue but not just return. [...] > +static int > +cpfl_str2mac(const char *mask, uint8_t *addr_bytes) How about to use rte_ether_unformat_addr instead of defining a new one? [...] > + > +/* output: struct cpfl_flow_mr_key_action *mr_key_action */ > +/* check and parse */ > +static int > +cpfl_parse_mr_key_action(struct cpfl_flow_js_mr_key_action *key_acts, int > size, > + const struct rte_flow_action *actions, > + struct cpfl_flow_mr_key_action *mr_key_action) > +{ > + int actions_length, i; > + int j = 0; > + int ret; > + > + actions_length = cpfl_get_actions_length(actions); > + if (size > actions_length - 1) > + return -EINVAL; > + for (i = 0; i < size; i++) { > + enum rte_flow_action_type type; > + struct cpfl_flow_js_mr_key_action *key_act; > + > + key_act = &key_acts[i]; > + /* mr->key->actions->type */ > + type = key_act->type; > + /* mr->key->actions->data */ > + /* match: <type> action matches > RTE_FLOW_ACTION_TYPE_<type> */ > + if (type == RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) { > + int proto_size, k; > + struct cpfl_flow_mr_key_action_vxlan_encap *encap; > + > + while (j < actions_length && > + actions[j].type != > RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP) { > + j++; > + } > + if (j >= actions_length) > + return -EINVAL; > + mr_key_action[i].type = > RTE_FLOW_ACTION_TYPE_VXLAN_ENCAP; > + mr_key_action[i].encap.action = &actions[j]; > + encap = &mr_key_action[i].encap; > + > + proto_size = key_act->encap.proto_size; > + encap->proto_size = proto_size; > + for (k = 0; k < proto_size; k++) { > + enum rte_flow_item_type proto; > + > + proto = key_act->encap.protocols[k]; > + encap->protocols[k] = proto; > + } > + ret = cpfl_check_actions_vxlan_encap(encap, > &actions[j]); > + if (ret < 0) > + return -EINVAL; > + > + j++; > + } else if (type == RTE_FLOW_ACTION_TYPE_VXLAN_DECAP) { > + while (j < actions_length && > + actions[j].type != > RTE_FLOW_ACTION_TYPE_VXLAN_DECAP) { > + j++; > + } > + if (j >= actions_length) > + return -EINVAL; > + > + mr_key_action[i].type = > RTE_FLOW_ACTION_TYPE_VXLAN_DECAP; > + j++; > + } else { > + PMD_DRV_LOG(ERR, "Not support this type: %d.", > type); > + return -EPERM; > + } Shouldn't reset j to 0 after one loop? > + } > + > + return 0; > +} > + > +/* output: uint8_t *buffer, uint16_t *byte_len */ > +static int > +cpfl_parse_layout(struct cpfl_flow_js_mr_layout *layouts, int layout_size, > + struct cpfl_flow_mr_key_action *mr_key_action, > + uint8_t *buffer, uint16_t *byte_len) > +{ > + int i; > + int start = 0; > + > + for (i = 0; i < layout_size; i++) { > + int index, size, offset; > + const char *hint; > + const uint8_t *addr; > + struct cpfl_flow_mr_key_action *temp; > + struct cpfl_flow_js_mr_layout *layout; > + > + layout = &layouts[i]; > + /* index links to the element of the actions array. */ > + index = layout->index; > + size = layout->size; > + offset = layout->offset; > + if (index == -1) { > + hint = "dummpy"; > + start += size; > + continue; > + } > + hint = layout->hint; > + addr = NULL; Why set it to NULL here? [...] > +void > +cpfl_metadata_write16(struct cpfl_metadata *meta, int type, int offset, > uint16_t data) > +{ > + rte_memcpy(&meta->chunks[type].data[offset], > + &data, > + sizeof(uint16_t)); > +} > + > +void > +cpfl_metadata_write32(struct cpfl_metadata *meta, int type, int offset, > uint32_t data) > +{ > + rte_memcpy(&meta->chunks[type].data[offset], > + &data, > + sizeof(uint32_t)); > +} > + > +uint16_t > +cpfl_metadata_read16(struct cpfl_metadata *meta, int type, int offset) > +{ > + return *((uint16_t *)(&meta->chunks[type].data[offset])); > +} > + Those functions seem short enough, how about to define them as inline or macro? > +bool > +cpfl_metadata_write_port_id(struct cpfl_itf *itf) > +{ > + uint32_t dev_id; > + const int type = 0; > + const int offset = 5; > + > + dev_id = cpfl_get_port_id(itf); > + if (dev_id == CPFL_INVALID_HW_ID) { > + PMD_DRV_LOG(ERR, "fail to get hw ID\n"); > + return false; > + } > + dev_id = dev_id << 3; > + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id); > + > + return true; > +} > + > +bool > +cpfl_metadata_write_targetvsi(struct cpfl_itf *itf) > +{ > + uint32_t dev_id; > + const int type = 6; > + const int offset = 2; > + > + dev_id = cpfl_get_vsi_id(itf); > + if (dev_id == CPFL_INVALID_HW_ID) { > + PMD_DRV_LOG(ERR, "fail to get hw ID"); > + return false; > + } > + dev_id = dev_id << 1; > + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id); > + > + return true; > +} > + > +bool > +cpfl_metadata_write_sourcevsi(struct cpfl_itf *itf) > +{ > + uint32_t dev_id; > + const int type = 6; > + const int offset = 0; > + > + dev_id = cpfl_get_vsi_id(itf); > + if (dev_id == CPFL_INVALID_HW_ID) { > + PMD_DRV_LOG(ERR, "fail to get hw ID"); > + return false; > + } > + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id); > + > + return true; > +} > + > +void > +cpfl_metadata_init(struct cpfl_metadata *meta) > +{ > + int i; > + > + for (i = 0; i < CPFL_META_LENGTH; i++) > + meta->chunks[i].type = i; > +} > + > +bool cpfl_metadata_write_vsi(struct cpfl_itf *itf) > +{ > + uint32_t dev_id; > + const int type = 0; > + const int offset = 24; > + > + dev_id = cpfl_get_vsi_id(itf); > + if (dev_id == CPFL_INVALID_HW_ID) { > + PMD_DRV_LOG(ERR, "fail to get hw ID"); > + return false; > + } > + cpfl_metadata_write16(&itf->adapter->meta, type, offset, dev_id); > + > + return true; > +} In general, this patch is too large, better to split for review.