[dpdk-dev] [PATCH v8 1/4] librte_flow_classify: add flow classify library
Iremonger, Bernard
bernard.iremonger at intel.com
Fri Oct 20 18:59:36 CEST 2017
Hi Jasvinder,
Thanks for the review.
> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Thursday, October 19, 2017 3:22 PM
> To: Iremonger, Bernard <bernard.iremonger at intel.com>; dev at dpdk.org;
> Yigit, Ferruh <ferruh.yigit at intel.com>; Ananyev, Konstantin
> <konstantin.ananyev at intel.com>; Dumitrescu, Cristian
> <cristian.dumitrescu at intel.com>; adrien.mazarguil at 6wind.com
> Subject: RE: [PATCH v8 1/4] librte_flow_classify: add flow classify library
>
>
> <snip>
>
> > +
> > +struct acl_keys {
> > + struct rte_table_acl_rule_add_params key_add; /**< add key */
> > + struct rte_table_acl_rule_delete_params key_del; /**< delete
> > key */
> > +};
> > +
> > +struct rte_flow_classify_rule {
> > + uint32_t id; /**< unique ID of classify rule */
> > + enum rte_flow_classify_rule_type rule_type; /**< classify rule type
> > */
> > + struct rte_flow_action action; /**< action when match found */
> > + struct rte_flow_classify_ipv4_5tuple ipv4_5tuple; /**< ipv4 5tuple */
> > + union {
> > + struct acl_keys key;
> > + } u;
> > + int key_found; /**< rule key found in table */
> > + void *entry; /**< pointer to buffer to hold rule meta data*/
> > + void *entry_ptr; /**< handle to the table entry for rule meta data*/
> > +};
>
> In my opnion, the above struct should have the provision to accommodate
> other types of rules, not only ipv4_5tuples.
> Making this structure modular will help in extending it for other rule types in
> the future.
I will refactor by adding struct classify_rules{} to struct rte_flow_classif_rule{}:
struct classify_rules {
enum rte_flow_classify_rule_type type;
union {
struct rte_flow_classify_ipv4_5tuple ipv4_5tuple;
} u;
};
struct rte_flow_classify_rule {
uint32_t id; /* unique ID of classify rule */
struct rte_flow_action action; /* action when match found */
struct classify_rules rules; /* union of rules */
union {
struct acl_keys key;
} u;
int key_found; /* rule key found in table */
void *entry; /* pointer to buffer to hold rule meta data */
void *entry_ptr; /* handle to the table entry for rule meta data */
};
> > +int
> > +rte_flow_classify_validate(
> > + const struct rte_flow_attr *attr,
> > + const struct rte_flow_item pattern[],
> > + const struct rte_flow_action actions[],
> > + struct rte_flow_error *error)
> > +{
> > + struct rte_flow_item *items;
> > + parse_filter_t parse_filter;
> > + uint32_t item_num = 0;
> > + uint32_t i = 0;
> > + int ret;
> > +
> > + if (!error)
> > + return -EINVAL;
> > +
> > + if (!pattern) {
> > + rte_flow_error_set(error, EINVAL,
> > RTE_FLOW_ERROR_TYPE_ITEM_NUM,
> > + NULL, "NULL pattern.");
> > + return -EINVAL;
> > + }
> > +
> > + if (!actions) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_ACTION_NUM,
> > + NULL, "NULL action.");
> > + return -EINVAL;
> > + }
> > +
> > + if (!attr) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_ATTR,
> > + NULL, "NULL attribute.");
> > + return -EINVAL;
> > + }
> > +
> > + memset(&ntuple_filter, 0, sizeof(ntuple_filter));
> > +
> > + /* Get the non-void item number of pattern */
> > + while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
> > + if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID)
> > + item_num++;
> > + i++;
> > + }
> > + item_num++;
> > +
> > + items = malloc(item_num * sizeof(struct rte_flow_item));
> > + if (!items) {
> > + rte_flow_error_set(error, ENOMEM,
> > RTE_FLOW_ERROR_TYPE_ITEM_NUM,
> > + NULL, "No memory for pattern items.");
> > + return -ENOMEM;
> > + }
> > +
> > + memset(items, 0, item_num * sizeof(struct rte_flow_item));
> > + classify_pattern_skip_void_item(items, pattern);
> > +
> > + parse_filter = classify_find_parse_filter_func(items);
> > + if (!parse_filter) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_ITEM,
> > + pattern, "Unsupported pattern");
> > + free(items);
> > + return -EINVAL;
> > + }
> > +
> > + ret = parse_filter(attr, items, actions, &ntuple_filter, error);
> > + free(items);
> > + return ret;
> > +}
>
> This function mainly parses the flow pattern, actions etc and fill the entries in
> internal ntuple_filter.It is invoked only in flow_entry_add(). Is there any
> reason to make this function available as public API?
This function does not need to be a public API.
The flow_classify API's started out mirroring the flow API's but this is no longer the case.
Probably better to make it internal and it could be made public later if needed.
> > +#ifdef RTE_LIBRTE_CLASSIFY_DEBUG
> > +#define uint32_t_to_char(ip, a, b, c, d) do {\
> > + *a = (unsigned char)(ip >> 24 & 0xff);\
> > + *b = (unsigned char)(ip >> 16 & 0xff);\
> > + *c = (unsigned char)(ip >> 8 & 0xff);\
> > + *d = (unsigned char)(ip & 0xff);\
> > + } while (0)
> > +
> > +static inline void
> > +print_ipv4_key_add(struct rte_table_acl_rule_add_params *key) {
> > + unsigned char a, b, c, d;
> > +
> > + printf("ipv4_key_add: 0x%02hhx/0x%hhx ",
> > + key->field_value[PROTO_FIELD_IPV4].value.u8,
> > + key->field_value[PROTO_FIELD_IPV4].mask_range.u8);
> > +
> > + uint32_t_to_char(key->field_value[SRC_FIELD_IPV4].value.u32,
> > + &a, &b, &c, &d);
> > + printf(" %hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
> > + key-
> > >field_value[SRC_FIELD_IPV4].mask_range.u32);
> > +
> > + uint32_t_to_char(key->field_value[DST_FIELD_IPV4].value.u32,
> > + &a, &b, &c, &d);
> > + printf("%hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
> > + key-
> > >field_value[DST_FIELD_IPV4].mask_range.u32);
> > +
> > + printf("%hu : 0x%x %hu : 0x%x",
> > + key->field_value[SRCP_FIELD_IPV4].value.u16,
> > + key->field_value[SRCP_FIELD_IPV4].mask_range.u16,
> > + key->field_value[DSTP_FIELD_IPV4].value.u16,
> > + key->field_value[DSTP_FIELD_IPV4].mask_range.u16);
> > +
> > + printf(" priority: 0x%x\n", key->priority); }
>
> The above function is specific to printing acl table keys. How about making
> this function little generic by passing the parameters to distinguish the rule,
> table type, etc. and do the printing?
>
> Same comments for the print_ipv4_key_delete().
>
This is debug code, could it be left as is until another table type is added?
I will rename to include acl in the function names.
>
> > +static inline void
> > +print_ipv4_key_delete(struct rte_table_acl_rule_delete_params *key) {
> > + unsigned char a, b, c, d;
> > +
> > + printf("ipv4_key_del: 0x%02hhx/0x%hhx ",
> > + key->field_value[PROTO_FIELD_IPV4].value.u8,
> > + key->field_value[PROTO_FIELD_IPV4].mask_range.u8);
> > +
> > + uint32_t_to_char(key->field_value[SRC_FIELD_IPV4].value.u32,
> > + &a, &b, &c, &d);
> > + printf(" %hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
> > + key-
> > >field_value[SRC_FIELD_IPV4].mask_range.u32);
> > +
> > + uint32_t_to_char(key->field_value[DST_FIELD_IPV4].value.u32,
> > + &a, &b, &c, &d);
> > + printf("%hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
> > + key-
> > >field_value[DST_FIELD_IPV4].mask_range.u32);
> > +
> > + printf("%hu : 0x%x %hu : 0x%x\n",
> > + key->field_value[SRCP_FIELD_IPV4].value.u16,
> > + key->field_value[SRCP_FIELD_IPV4].mask_range.u16,
> > + key->field_value[DSTP_FIELD_IPV4].value.u16,
> > + key->field_value[DSTP_FIELD_IPV4].mask_range.u16);
> > +}
> > +#endif
> > +
> > +static int
> > +rte_flow_classifier_check_params(struct rte_flow_classifier_params
> > *params)
> > +{
> > + if (params == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: Incorrect value for parameter params\n",
> > __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* name */
> > + if (params->name == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: Incorrect value for parameter name\n",
> > __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* socket */
> > + if ((params->socket_id < 0) ||
> > + (params->socket_id >= RTE_MAX_NUMA_NODES)) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: Incorrect value for parameter socket_id\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +struct rte_flow_classifier *
> > +rte_flow_classifier_create(struct rte_flow_classifier_params *params)
> > +{
> > + struct rte_flow_classifier *cls;
> > + int ret;
> > +
> > + /* Check input parameters */
> > + ret = rte_flow_classifier_check_params(params);
> > + if (ret != 0) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: flow classifier params check failed (%d)\n",
> > + __func__, ret);
> > + return NULL;
> > + }
> > +
> > + /* Allocate memory for the flow classifier */
> > + cls = rte_zmalloc_socket("FLOW_CLASSIFIER",
> > + sizeof(struct rte_flow_classifier),
> > + RTE_CACHE_LINE_SIZE, params->socket_id);
> > +
> > + if (cls == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: flow classifier memory allocation failed\n",
> > + __func__);
> > + return NULL;
> > + }
> > +
> > + /* Save input parameters */
> > + snprintf(cls->name, RTE_FLOW_CLASSIFIER_MAX_NAME_SZ, "%s",
> > + params->name);
> > + cls->socket_id = params->socket_id;
> > + cls->type = params->type;
> > +
> > + /* Initialize flow classifier internal data structure */
> > + cls->num_tables = 0;
> > +
> > + return cls;
> > +}
> > +
> > +static void
> > +rte_flow_classify_table_free(struct rte_table *table) {
> > + if (table->ops.f_free != NULL)
> > + table->ops.f_free(table->h_table);
> > +
> > + rte_free(table->default_entry);
> > +}
>
> This is internal function. There is an API for creating a table for classifier
> instance but not for destroying the table. What if application requires
> destroying the specific table of the classifier but want to keep the classifier
> instance?
Yes, there should probably be an API to delete a table.
I will add an rte_flow_classify_table_delete() API.
> > +int
> > +rte_flow_classifier_free(struct rte_flow_classifier *cls) {
> > + uint32_t i;
> > +
> > + /* Check input parameters */
> > + if (cls == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: rte_flow_classifier parameter is NULL\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* Free tables */
> > + for (i = 0; i < cls->num_tables; i++) {
> > + struct rte_table *table = &cls->tables[i];
> > +
> > + rte_flow_classify_table_free(table);
> > + }
> > +
> > + /* Free flow classifier memory */
> > + rte_free(cls);
> > +
> > + return 0;
> > +}
> > +
> > +static int
> > +rte_table_check_params(struct rte_flow_classifier *cls,
> > + struct rte_flow_classify_table_params *params,
> > + uint32_t *table_id)
> > +{
> > + if (cls == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: flow classifier parameter is NULL\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > + if (params == NULL) {
> > + RTE_LOG(ERR, CLASSIFY, "%s: params parameter is NULL\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > + if (table_id == NULL) {
> > + RTE_LOG(ERR, CLASSIFY, "%s: table_id parameter is NULL\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* ops */
> > + if (params->ops == NULL) {
> > + RTE_LOG(ERR, CLASSIFY, "%s: params->ops is NULL\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > +
> > + if (params->ops->f_create == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: f_create function pointer is NULL\n", __func__);
> > + return -EINVAL;
> > + }
> > +
> > + if (params->ops->f_lookup == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: f_lookup function pointer is NULL\n",
> > __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* De we have room for one more table? */
> > + if (cls->num_tables == RTE_FLOW_CLASSIFY_TABLE_MAX) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: Incorrect value for num_tables parameter\n",
> > + __func__);
> > + return -EINVAL;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +int
> > +rte_flow_classify_table_create(struct rte_flow_classifier *cls,
> > + struct rte_flow_classify_table_params *params,
> > + uint32_t *table_id)
> > +{
> > + struct rte_table *table;
> > + struct rte_flow_classify_table_entry *default_entry;
> > + void *h_table;
> > + uint32_t entry_size, id;
> > + int ret;
> > +
> > + /* Check input arguments */
> > + ret = rte_table_check_params(cls, params, table_id);
> > + if (ret != 0)
> > + return ret;
> > +
> > + id = cls->num_tables;
> > + table = &cls->tables[id];
> > +
> > + /* Allocate space for the default table entry */
> > + entry_size = sizeof(struct rte_flow_classify_table_entry) +
> > + params->table_metadata_size;
> > + default_entry =
> > + (struct rte_flow_classify_table_entry *) rte_zmalloc_socket(
> > + "Flow Classify default entry", entry_size,
> > + RTE_CACHE_LINE_SIZE, cls->socket_id);
> > + if (default_entry == NULL) {
> > + RTE_LOG(ERR, CLASSIFY,
> > + "%s: Failed to allocate default entry\n", __func__);
> > + return -EINVAL;
> > + }
>
> what is the purpose of default_entry as I don't see its usage anywhere in the
> library?
This came from the ip_pipeline code in earlier discussions, it is not used at present.
I will remove it.
> > + /* Create the table */
> > + h_table = params->ops->f_create(params->arg_create, cls-
> > >socket_id,
> > + entry_size);
> > + if (h_table == NULL) {
> > + rte_free(default_entry);
> > + RTE_LOG(ERR, CLASSIFY, "%s: Table creation failed\n",
> > __func__);
> > + return -EINVAL;
> > + }
> > +
> > + /* Commit current table to the classifier */
> > + cls->num_tables++;
> > + *table_id = id;
> > +
> > + /* Save input parameters */
> > + memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
> > +
> > + table->entry_size = entry_size;
> > + table->default_entry = default_entry;
> > +
> > + /* Initialize table internal data structure */
> > + table->h_table = h_table;
> > +
> > + return 0;
> > +}
> > +
> > +static struct rte_flow_classify_rule *
> > +allocate_ipv4_5tuple_rule(void)
> > +{
> > + struct rte_flow_classify_rule *rule;
> > +
> > + rule = malloc(sizeof(struct rte_flow_classify_rule));
> > + if (!rule)
> > + return rule;
> > +
> > + memset(rule, 0, sizeof(struct rte_flow_classify_rule));
> > + rule->id = unique_id++;
> > + rule->rule_type = RTE_FLOW_CLASSIFY_RULE_TYPE_IPV4_5TUPLE;
> > +
> > + memcpy(&rule->action, classify_get_flow_action(),
> > + sizeof(struct rte_flow_action));
> > +
> > + /* key add values */
> > + rule->u.key.key_add.priority = ntuple_filter.priority;
> > + rule-
> > >u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
> > + ntuple_filter.proto_mask;
> > + rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
> > + ntuple_filter.proto;
> > + rule->ipv4_5tuple.proto = ntuple_filter.proto;
> > + rule->ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
> > +
> > + rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32
> > =
> > + ntuple_filter.src_ip_mask;
> > + rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
> > + ntuple_filter.src_ip;
> > + rule->ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
> > + rule->ipv4_5tuple.src_ip = ntuple_filter.src_ip;
> > +
> > + rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32
> > =
> > + ntuple_filter.dst_ip_mask;
> > + rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
> > + ntuple_filter.dst_ip;
> > + rule->ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
> > + rule->ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
> > +
> > + rule-
> > >u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
> > + ntuple_filter.src_port_mask;
> > + rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
> > + ntuple_filter.src_port;
> > + rule->ipv4_5tuple.src_port_mask = ntuple_filter.src_port_mask;
> > + rule->ipv4_5tuple.src_port = ntuple_filter.src_port;
> > +
> > + rule-
> > >u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
> > + ntuple_filter.dst_port_mask;
> > + rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
> > + ntuple_filter.dst_port;
> > + rule->ipv4_5tuple.dst_port_mask = ntuple_filter.dst_port_mask;
> > + rule->ipv4_5tuple.dst_port = ntuple_filter.dst_port;
> > +
> > +#ifdef RTE_LIBRTE_CLASSIFY_DEBUG
> > + print_ipv4_key_add(&rule->u.key.key_add);
> > +#endif
> > +
> > + /* key delete values */
> > + memcpy(&rule->u.key.key_del.field_value[PROTO_FIELD_IPV4],
> > + &rule->u.key.key_add.field_value[PROTO_FIELD_IPV4],
> > + NUM_FIELDS_IPV4 * sizeof(struct rte_acl_field));
> > +
> > +#ifdef RTE_LIBRTE_CLASSIFY_DEBUG
> > + print_ipv4_key_delete(&rule->u.key.key_del);
> > +#endif
> > + return rule;
> > +}
> > +
> > +struct rte_flow_classify_rule *
> > +rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> > + uint32_t table_id,
> > + const struct rte_flow_attr *attr,
> > + const struct rte_flow_item pattern[],
> > + const struct rte_flow_action actions[],
> > + struct rte_flow_error *error)
> > +{
> > + struct rte_flow_classify_rule *rule;
> > + struct rte_flow_classify_table_entry *table_entry;
> > + int ret;
> > +
> > + if (!error)
> > + return NULL;
> > +
> > + if (!cls) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "NULL classifier.");
> > + return NULL;
> > + }
> > +
> > + if (table_id >= cls->num_tables) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "invalid table_id.");
> > + return NULL;
> > + }
> > +
> > + if (!pattern) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_ITEM_NUM,
> > + NULL, "NULL pattern.");
> > + return NULL;
> > + }
> > +
> > + if (!actions) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_ACTION_NUM,
> > + NULL, "NULL action.");
> > + return NULL;
> > + }
> > +
> > + if (!attr) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_ATTR,
> > + NULL, "NULL attribute.");
> > + return NULL;
> > + }
> > +
> > + /* parse attr, pattern and actions */
> > + ret = rte_flow_classify_validate(attr, pattern, actions, error);
> > + if (ret < 0)
> > + return NULL;
> > +
> > + switch (cls->type) {
> > + case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
> > + rule = allocate_ipv4_5tuple_rule();
> > + if (!rule)
> > + return NULL;
> > + break;
> > + default:
> > + return NULL;
> > + }
> > +
> > + rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
> > + if (!rule->entry) {
> > + free(rule);
> > + rule = NULL;
> > + return NULL;
> > + }
> > +
> > + table_entry = rule->entry;
> > + table_entry->rule_id = rule->id;
> > +
> > + ret = cls->tables[table_id].ops.f_add(
> > + cls->tables[table_id].h_table,
> > + &rule->u.key.key_add,
> > + rule->entry,
> > + &rule->key_found,
> > + &rule->entry_ptr);
> > + if (ret) {
> > + free(rule->entry);
> > + free(rule);
> > + rule = NULL;
> > + return NULL;
> > + }
> > + return rule;
> > +}
>
> It is not clear if the pattern to be added already exists in the table? how this
> information will be propagated to the application?
The key found flag will be set if the key is already present.
I will add a key_found parameter to the API to return the key found data.
> > +int
> > +rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> > + uint32_t table_id,
> > + struct rte_flow_classify_rule *rule,
> > + struct rte_flow_error *error)
> > +{
> > + int ret = -EINVAL;
> > +
> > + if (!error)
> > + return ret;
> > +
> > + if (!cls) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "NULL classifier.");
> > + return ret;
> > + }
> > +
> > + if (table_id >= cls->num_tables) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "invalid table_id.");
> > + return ret;
> > + }
> > +
> > + if (!rule) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "NULL rule.");
> > + return ret;
> > + }
> > +
> > + ret = cls->tables[table_id].ops.f_delete(
> > + cls->tables[table_id].h_table,
> > + &rule->u.key.key_del,
> > + &rule->key_found,
> > + &rule->entry);
>
> Please introduce check for f_delete, shouldn't be NULL.
I will add a check that f_delete is not NULL.
> > +
> > +int
> > +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > + uint32_t table_id,
> > + struct rte_mbuf **pkts,
> > + const uint16_t nb_pkts,
> > + struct rte_flow_error *error)
> > +{
> > + int ret = -EINVAL;
> > + uint64_t pkts_mask;
> > + uint64_t lookup_hit_mask;
> > +
> > + if (!error)
> > + return ret;
> > +
> > + if (!cls || !pkts || nb_pkts == 0) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "invalid input");
> > + return ret;
> > + }
> > +
> > + if (table_id >= cls->num_tables) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "invalid table_id.");
> > + return ret;
> > + }
> > +
> > + pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> > + ret = cls->tables[table_id].ops.f_lookup(
> > + cls->tables[table_id].h_table,
> > + pkts, pkts_mask, &lookup_hit_mask,
> > + (void **)cls->entries);
> > +
> > + if (!ret && lookup_hit_mask)
> > + cls->nb_pkts = nb_pkts;
> > + else
> > + cls->nb_pkts = 0;
> > +
> > + return ret;
> > +}
> > +
> > +static int
> > +action_apply(struct rte_flow_classifier *cls,
> > + struct rte_flow_classify_rule *rule,
> > + struct rte_flow_classify_stats *stats) {
> > + struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
> > + uint64_t count = 0;
> > + int i;
> > + int ret = -ENODATA;
> > +
> > + switch (rule->action.type) {
> > + case RTE_FLOW_ACTION_TYPE_COUNT:
> > + for (i = 0; i < cls->nb_pkts; i++) {
> > + if (rule->id == cls->entries[i]->rule_id)
> > + count++;
> > + }
> > + if (count) {
> > + ret = 0;
> > + ntuple_stats =
> > + (struct rte_flow_classify_ipv4_5tuple_stats
> > *)
> > + stats->stats;
> > + ntuple_stats->counter1 = count;
> > + ntuple_stats->ipv4_5tuple = rule->ipv4_5tuple;
> > + }
> > + break;
> > + default:
> > + ret = -ENOTSUP;
> > + break;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +int
> > +rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > + struct rte_flow_classify_rule *rule,
> > + struct rte_flow_classify_stats *stats,
> > + struct rte_flow_error *error)
> > +{
> > + int ret = -EINVAL;
> > +
> > + if (!error)
> > + return ret;
> > +
> > + if (!cls || !rule || !stats) {
> > + rte_flow_error_set(error, EINVAL,
> > + RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > + NULL, "invalid input");
> > + return ret;
> > + }
> > +
> > + ret = action_apply(cls, rule, stats);
> > + return ret;
> > +}
>
> The rte_flow_classify_run and rte_flow_classify_query API should be
> invoked consecutively in the application, true?
Yes, they should be invoked consecutively.
I will merge the rte_flow_classify_run API with the rte_flow_classify_query API and
drop the rte_flow_classif_run API.
> > diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> > b/lib/librte_flow_classify/rte_flow_classify.h
> > new file mode 100644
> > index 0000000..9bd6cf4
> > --- /dev/null
> > +++ b/lib/librte_flow_classify/rte_flow_classify.h
> > @@ -0,0 +1,321 @@
> > +/*-
> > + * BSD LICENSE
> > + *
> > + * Copyright(c) 2017 Intel Corporation. All rights reserved.
> > + * All rights reserved.
> > + *
> > + * Redistribution and use in source and binary forms, with or without
> > + * modification, are permitted provided that the following conditions
> > + * are met:
> > + *
> > + * * Redistributions of source code must retain the above copyright
> > + * notice, this list of conditions and the following disclaimer.
> > + * * Redistributions in binary form must reproduce the above copyright
> > + * notice, this list of conditions and the following disclaimer in
> > + * the documentation and/or other materials provided with the
> > + * distribution.
> > + * * Neither the name of Intel Corporation nor the names of its
> > + * contributors may be used to endorse or promote products derived
> > + * from this software without specific prior written permission.
> > + *
> > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> > CONTRIBUTORS
> > + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
> > NOT
> > + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
> > FITNESS FOR
> > + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
> > COPYRIGHT
> > + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
> > INCIDENTAL,
> > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> BUT
> > NOT
> > + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
> LOSS
> > OF USE,
> > + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
> > AND ON ANY
> > + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
> > TORT
> > + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
> OF
> > THE USE
> > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
> > DAMAGE.
> > + */
> > +
> > +#ifndef _RTE_FLOW_CLASSIFY_H_
> > +#define _RTE_FLOW_CLASSIFY_H_
> > +
> > +/**
> > + * @file
> > + *
> > + * RTE Flow Classify Library
> > + *
> > + * This library provides flow record information with some measured
> > properties.
> > + *
> > + * Application should define the flow and measurement criteria
> > + (action) for
> > it.
> > + *
> > + * Library doesn't maintain any flow records itself, instead flow
> > + information
> > is
> > + * returned to upper layer only for given packets.
> > + *
> > + * It is application's responsibility to call
> > + rte_flow_classify_query()
> > + * for group of packets, just after receiving them or before
> > + transmitting
> > them.
> > + * Application should provide the flow type interested in,
> > + measurement to
> > apply
> > + * to that flow in rte_flow_classify_create() API, and should provide
> > + * rte_flow_classify object and storage to put results in
> > + * rte_flow_classify_query() API.
> > + *
> > + * Usage:
> > + * - application calls rte_flow_classify_create() to create a
> rte_flow_classify
> > + * object.
> > + * - application calls rte_flow_classify_query() in a polling manner,
> > + * preferably after rte_eth_rx_burst(). This will cause the library to
> > + * convert packet information to flow information with some
> > measurements.
> > + * - rte_flow_classify object can be destroyed when they are no more
> > needed
> > + * via rte_flow_classify_destroy()
> > + */
> > +
> > +#include <rte_ethdev.h>
> > +#include <rte_ether.h>
> > +#include <rte_flow.h>
> > +#include <rte_acl.h>
> > +#include <rte_table_acl.h>
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +
> > +#define RTE_FLOW_CLASSIFY_TABLE_MAX 1
> > +
> > +/** Opaque data type for flow classifier */ struct
> > +rte_flow_classifier;
> > +
> > +/** Opaque data type for flow classify rule */ struct
> > +rte_flow_classify_rule;
> > +
> > +enum rte_flow_classify_rule_type {
> > + RTE_FLOW_CLASSIFY_RULE_TYPE_NONE, /**< no type */
> > + RTE_FLOW_CLASSIFY_RULE_TYPE_IPV4_5TUPLE, /**< IPv4 5tuple
> > type */
> > +};
> > +
> > +enum rte_flow_classify_table_type {
> > + RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE, /**< no type */
> > + RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL, /**< ACL type */ };
> > +
> > +/** Parameters for flow classifier creation */ struct
> > +rte_flow_classifier_params {
> > + /**< flow classifier name */
> > + const char *name;
> > +
> > + /**< CPU socket ID where memory for the flow classifier and its */
> > + /**< elements (tables) should be allocated */
> > + int socket_id;
> > +
> > + /**< Table type */
> > + enum rte_flow_classify_table_type type;
> > +
> > + /**< Table id */
> > + uint32_t table_id;
> > +};
> > +
> > +struct rte_flow_classify_table_params {
> > + /**<Table operations (specific to each table type) */
> > + struct rte_table_ops *ops;
> > +
> > + /**< Opaque param to be passed to the table create operation */
> > + void *arg_create;
> > +
> > + /**< Memory size to be reserved per classifier object entry for */
> > + /**< storing meta data */
> > + uint32_t table_metadata_size;
> > +};
> > +
> > +struct rte_flow_classify_ipv4_5tuple {
> > + uint32_t dst_ip; /**< Destination IP address in big endian. */
> > + uint32_t dst_ip_mask; /**< Mask of destination IP address. */
> > + uint32_t src_ip; /**< Source IP address in big endian. */
> > + uint32_t src_ip_mask; /**< Mask of destination IP address. */
> > + uint16_t dst_port; /**< Destination port in big endian. */
> > + uint16_t dst_port_mask; /**< Mask of destination port. */
> > + uint16_t src_port; /**< Source Port in big endian. */
> > + uint16_t src_port_mask; /**< Mask of source port. */
> > + uint8_t proto; /**< L4 protocol. */
> > + uint8_t proto_mask; /**< Mask of L4 protocol. */
> > +};
> > +
> > +struct rte_flow_classify_table_entry {
> > + /**< meta-data for classify rule */
> > + uint32_t rule_id;
> > +
> > + /**< Start of table entry area for user defined meta data */
> > + __extension__ uint8_t meta_data[0];
> > +};
>
> The above structure is not used by any of the public API ?
>
> > + * Flow stats
> > + *
> > + * For the count action, stats can be returned by the query API.
> > + *
> > + * Storage for stats is provided by application.
> > + */
> > +struct rte_flow_classify_stats {
> > + void *stats;
> > +};
> > +
> > +struct rte_flow_classify_ipv4_5tuple_stats {
> > + /**< count of packets that match IPv4 5tuple pattern */
> > + uint64_t counter1;
> > + /**< IPv4 5tuple data */
> > + struct rte_flow_classify_ipv4_5tuple ipv4_5tuple; };
> > +
> > +/**
> > + * Flow classifier create
> > + *
> > + * @param params
> > + * Parameters for flow classifier creation
> > + * @return
> > + * Handle to flow classifier instance on success or NULL otherwise
> > + */
> > +struct rte_flow_classifier *rte_flow_classifier_create(
> > + struct rte_flow_classifier_params *params);
> > +
> > +/**
> > + * Flow classifier free
> > + *
> > + * @param cls
> > + * Handle to flow classifier instance
> > + * @return
> > + * 0 on success, error code otherwise
> > + */
> > +int rte_flow_classifier_free(struct rte_flow_classifier *cls);
> > +
> > +/**
> > + * Flow classify table create
> > + *
> > + * @param cls
> > + * Handle to flow classifier instance
> > + * @param params
> > + * Parameters for flow_classify table creation
> > + * @param table_id
> > + * Table ID. Valid only within the scope of table IDs of the current
> > + * classifier. Only returned after a successful invocation.
> > + * @return
> > + * 0 on success, error code otherwise
> > + */
> > +int rte_flow_classify_table_create(struct rte_flow_classifier *cls,
> > + struct rte_flow_classify_table_params *params,
> > + uint32_t *table_id);
> > +
> > +/**
> > + * Validate a flow classify rule.
> > + *
> > + * @param[in] attr
> > + * Flow rule attributes
> > + * @param[in] pattern
> > + * Pattern specification (list terminated by the END pattern item).
> > + * @param[in] actions
> > + * Associated actions (list terminated by the END pattern item).
> > + * @param[out] error
> > + * Perform verbose error reporting if not NULL. Structure
> > + * initialised in case of error only.
> > + *
> > + * @return
> > + * 0 on success, error code otherwise.
> > + */
> > +int
> > +rte_flow_classify_validate(
> > + const struct rte_flow_attr *attr,
> > + const struct rte_flow_item pattern[],
> > + const struct rte_flow_action actions[],
> > + struct rte_flow_error *error);
> > +
> > +/**
> > + * Add a flow classify rule to the flow_classifer table.
> > + *
> > + * @param[in] cls
> > + * Flow classifier handle
> > + * @param[in] table_id
> > + * id of table
> > + * @param[in] attr
> > + * Flow rule attributes
> > + * @param[in] pattern
> > + * Pattern specification (list terminated by the END pattern item).
> > + * @param[in] actions
> > + * Associated actions (list terminated by the END pattern item).
> > + * @param[out] error
> > + * Perform verbose error reporting if not NULL. Structure
> > + * initialised in case of error only.
> > + * @return
> > + * A valid handle in case of success, NULL otherwise.
> > + */
> > +struct rte_flow_classify_rule *
> > +rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> > + uint32_t table_id,
> > + const struct rte_flow_attr *attr,
> > + const struct rte_flow_item pattern[],
> > + const struct rte_flow_action actions[],
> > + struct rte_flow_error *error);
> > +
> > +/**
> > + * Delete a flow classify rule from the flow_classifer table.
> > + *
> > + * @param[in] cls
> > + * Flow classifier handle
> > + * @param[in] table_id
> > + * id of table
> > + * @param[in] rule
> > + * Flow classify rule
> > + * @param[out] error
> > + * Perform verbose error reporting if not NULL. Structure
> > + * initialised in case of error only.
> > + * @return
> > + * 0 on success, error code otherwise.
> > + */
> > +int
> > +rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> > + uint32_t table_id,
> > + struct rte_flow_classify_rule *rule,
> > + struct rte_flow_error *error);
> > +
> > +/**
> > + * Run flow classifier for given packets.
> > + *
> > + * @param[in] cls
> > + * Flow classifier handle
> > + * @param[in] table_id
> > + * id of table
> > + * @param[in] pkts
> > + * Pointer to packets to process
> > + * @param[in] nb_pkts
> > + * Number of packets to process
> > + * @param[out] error
> > + * Perform verbose error reporting if not NULL. Structure
> > + * initialised in case of error only.
> > + *
> > + * @return
> > + * 0 on success, error code otherwise.
> > + */
> > +
> > +int rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > + uint32_t table_id,
> > + struct rte_mbuf **pkts,
> > + const uint16_t nb_pkts,
> > + struct rte_flow_error *error);
> > +
> > +/**
> > + * Query flow classifier for given rule.
> > + *
> > + * @param[in] cls
> > + * Flow classifier handle
> > + * @param[in] rule
> > + * Flow classify rule
> > + * @param[in] stats
> > + * Flow classify stats
> > + * @param[out] error
> > + * Perform verbose error reporting if not NULL. Structure
> > + * initialised in case of error only.
> > + *
> > + * @return
> > + * 0 on success, error code otherwise.
> > + */
> > +int rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > + struct rte_flow_classify_rule *rule,
> > + struct rte_flow_classify_stats *stats,
> > + struct rte_flow_error *error);
> > +
> > +#ifdef __cplusplus
> > +}
> > +#endif
> > +
> > +#endif /* _RTE_FLOW_CLASSIFY_H_ */
>
>
> There are doxygen rendering issues in this document. Please cross check the
> header file with "make doc-api-html" output.
I will check the doxygen output.
I will send a v9 patch set with the above changes.
Regards,
Bernard.
More information about the dev
mailing list