DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis
@ 2017-11-23 11:32 Jasvinder Singh
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification Jasvinder Singh
                   ` (3 more replies)
  0 siblings, 4 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-11-23 11:32 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger

This patch removes table id parameter from all the flow
classify apis to reduce the complexity and and does some
cleanup of the code.

The validate api has been exposed as public api to allows
user to validate the flow before adding it to the
classifier.

The sample app and unit tests have been updated to accomodate
the apis changes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/flow_classify/flow_classify.c             |  27 +-
 lib/librte_flow_classify/rte_flow_classify.c       | 320 +++++++++++----------
 lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
 lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
 lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
 .../rte_flow_classify_version.map                  |   1 +
 test/test/test_flow_classify.c                     |  86 +++---
 test/test/test_flow_classify.h                     |  10 +-
 8 files changed, 365 insertions(+), 287 deletions(-)

diff --git a/examples/flow_classify/flow_classify.c b/examples/flow_classify/flow_classify.c
index 766f1dd..37e6904 100644
--- a/examples/flow_classify/flow_classify.c
+++ b/examples/flow_classify/flow_classify.c
@@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default = {
 
 struct flow_classifier {
 	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
 };
 
 struct flow_classifier_acl {
@@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = { RTE_FLOW_ITEM_TYPE_END,
 /* sample actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
 static struct rte_flow_action actions[2];
 
@@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
 	int i = 0;
 
 	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
-			cls_app->table_id[0], rules[7]);
+			rules[7]);
 	if (ret)
 		printf("table_entry_delete failed [7] %d\n\n", ret);
 	else
@@ -317,7 +324,6 @@ lcore_main(struct flow_classifier *cls_app)
 				if (rules[i]) {
 					ret = rte_flow_classifier_query(
 						cls_app->cls,
-						cls_app->table_id[0],
 						bufs, nb_rx, rules[i],
 						&classify_stats);
 					if (ret)
@@ -635,8 +641,8 @@ add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
 	actions[1] = end_action;
 
 	rule = rte_flow_classify_table_entry_add(
-			cls_app->cls, cls_app->table_id[0], &key_found,
-			&attr, pattern_ipv4_5tuple, actions, &error);
+			cls_app->cls, &attr, pattern_ipv4_5tuple,
+			actions, &key_found, &error);
 	if (rule == NULL) {
 		printf("table entry add failed ipv4_proto = %u\n",
 			ipv4_proto);
@@ -809,7 +815,6 @@ main(int argc, char *argv[])
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
 	cls_app->cls = rte_flow_classifier_create(&cls_params);
 	if (cls_app->cls == NULL) {
@@ -824,11 +829,11 @@ main(int argc, char *argv[])
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-			&cls_app->table_id[0]);
+	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
 	if (ret) {
 		rte_flow_classifier_free(cls_app->cls);
 		rte_free(cls_app);
diff --git a/lib/librte_flow_classify/rte_flow_classify.c b/lib/librte_flow_classify/rte_flow_classify.c
index e6f4486..ff1bc86 100644
--- a/lib/librte_flow_classify/rte_flow_classify.c
+++ b/lib/librte_flow_classify/rte_flow_classify.c
@@ -39,16 +39,20 @@
 
 int librte_flow_classify_logtype;
 
-static struct rte_eth_ntuple_filter ntuple_filter;
 static uint32_t unique_id = 1;
 
+enum rte_flow_classify_table_type table_type
+	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
 
 struct rte_flow_classify_table_entry {
 	/* meta-data for classify rule */
 	uint32_t rule_id;
+
+	/* Flow action */
+	struct classify_action action;
 };
 
-struct rte_table {
+struct rte_cls_table {
 	/* Input parameters */
 	struct rte_table_ops ops;
 	uint32_t entry_size;
@@ -64,11 +68,16 @@ struct rte_flow_classifier {
 	/* Input parameters */
 	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
 	int socket_id;
-	enum rte_flow_classify_table_type type;
 
-	/* Internal tables */
-	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	/* Internal */
+	/* ntuple_fliter */
+	struct rte_eth_ntuple_filter ntuple_filter;
+
+	/* clasifier tables */
+	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	uint32_t table_mask;
 	uint32_t num_tables;
+
 	uint16_t nb_pkts;
 	struct rte_flow_classify_table_entry
 		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -97,18 +106,19 @@ struct classify_rules {
 
 struct rte_flow_classify_rule {
 	uint32_t id; /* unique ID of classify rule */
-	struct rte_flow_action action; /* action when match found */
+	enum rte_flow_classify_table_type tbl_type; /* rule table */
 	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 */
+	struct rte_flow_classify_table_entry entry;  /* rule meta data */
 	void *entry_ptr; /* handle to the table entry for rule meta data */
 };
 
-static int
-flow_classify_parse_flow(
+int
+rte_flow_classify_validate(
+		   struct rte_flow_classifier *cls,
 		   const struct rte_flow_attr *attr,
 		   const struct rte_flow_item pattern[],
 		   const struct rte_flow_action actions[],
@@ -120,7 +130,42 @@ flow_classify_parse_flow(
 	uint32_t i = 0;
 	int ret;
 
-	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
+	if (cls == NULL) {
+		RTE_FLOW_CLASSIFY_LOG(ERR,
+			"%s: rte_flow_classifier parameter is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (!attr) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ATTR,
+				   NULL, "NULL attribute.");
+		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 (!error) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
+				   NULL, "NULL error.");
+		return -EINVAL;
+	}
+
+	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
 
 	/* Get the non-void item number of pattern */
 	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
@@ -150,7 +195,7 @@ flow_classify_parse_flow(
 		return -EINVAL;
 	}
 
-	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
+	ret = parse_filter(attr, items, actions, &cls->ntuple_filter, error);
 	free(items);
 	return ret;
 }
@@ -275,17 +320,14 @@ rte_flow_classifier_create(struct rte_flow_classifier_params *params)
 	/* 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;
+	cls->socket_id = params->socket_id;
 
 	return cls;
 }
 
 static void
-rte_flow_classify_table_free(struct rte_table *table)
+rte_flow_classify_table_free(struct rte_cls_table *table)
 {
 	if (table->ops.f_free != NULL)
 		table->ops.f_free(table->h_table);
@@ -306,7 +348,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 	/* Free tables */
 	for (i = 0; i < cls->num_tables; i++) {
-		struct rte_table *table = &cls->tables[i];
+		struct rte_cls_table *table = &cls->tables[i];
 
 		rte_flow_classify_table_free(table);
 	}
@@ -319,8 +361,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 static int
 rte_table_check_params(struct rte_flow_classifier *cls,
-		struct rte_flow_classify_table_params *params,
-		uint32_t *table_id)
+		struct rte_flow_classify_table_params *params)
 {
 	if (cls == NULL) {
 		RTE_FLOW_CLASSIFY_LOG(ERR,
@@ -333,11 +374,6 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 			__func__);
 		return -EINVAL;
 	}
-	if (table_id == NULL) {
-		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is NULL\n",
-			__func__);
-		return -EINVAL;
-	}
 
 	/* ops */
 	if (params->ops == NULL) {
@@ -371,22 +407,18 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 
 int
 rte_flow_classify_table_create(struct rte_flow_classifier *cls,
-	struct rte_flow_classify_table_params *params,
-	uint32_t *table_id)
+	struct rte_flow_classify_table_params *params)
 {
-	struct rte_table *table;
+	struct rte_cls_table *table;
 	void *h_table;
-	uint32_t entry_size, id;
+	uint32_t entry_size;
 	int ret;
 
 	/* Check input arguments */
-	ret = rte_table_check_params(cls, params, table_id);
+	ret = rte_table_check_params(cls, params);
 	if (ret != 0)
 		return ret;
 
-	id = cls->num_tables;
-	table = &cls->tables[id];
-
 	/* calculate table entry size */
 	entry_size = sizeof(struct rte_flow_classify_table_entry);
 
@@ -400,8 +432,9 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 	}
 
 	/* Commit current table to the classifier */
+	table = &cls->tables[cls->num_tables];
+	table->type = params->type;
 	cls->num_tables++;
-	*table_id = id;
 
 	/* Save input parameters */
 	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
@@ -414,7 +447,7 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 }
 
 static struct rte_flow_classify_rule *
-allocate_acl_ipv4_5tuple_rule(void)
+allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
 {
 	struct rte_flow_classify_rule *rule;
 	int log_level;
@@ -427,45 +460,44 @@ allocate_acl_ipv4_5tuple_rule(void)
 	rule->id = unique_id++;
 	rule->rules.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.priority = cls->ntuple_filter.priority;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
-			ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto_mask;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
-			ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto_mask = cls->ntuple_filter.proto_mask;
 
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.src_ip_mask;
+			cls->ntuple_filter.src_ip_mask;
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
-			ntuple_filter.src_ip;
-	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
-	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
+			cls->ntuple_filter.src_ip;
+	rule->rules.u.ipv4_5tuple.src_ip_mask = cls->ntuple_filter.src_ip_mask;
+	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
 
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.dst_ip_mask;
+			cls->ntuple_filter.dst_ip_mask;
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
-			ntuple_filter.dst_ip;
-	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
-	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
+			cls->ntuple_filter.dst_ip;
+	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls->ntuple_filter.dst_ip_mask;
+	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
 
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.src_port_mask;
+			cls->ntuple_filter.src_port_mask;
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
-			ntuple_filter.src_port;
-	rule->rules.u.ipv4_5tuple.src_port_mask = ntuple_filter.src_port_mask;
-	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
+			cls->ntuple_filter.src_port;
+	rule->rules.u.ipv4_5tuple.src_port_mask =
+			cls->ntuple_filter.src_port_mask;
+	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
 
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.dst_port_mask;
+			cls->ntuple_filter.dst_port_mask;
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
-			ntuple_filter.dst_port;
-	rule->rules.u.ipv4_5tuple.dst_port_mask = ntuple_filter.dst_port_mask;
-	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
+			cls->ntuple_filter.dst_port;
+	rule->rules.u.ipv4_5tuple.dst_port_mask =
+			cls->ntuple_filter.dst_port_mask;
+	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
 
 	log_level = rte_log_get_level(librte_flow_classify_logtype);
 
@@ -485,34 +517,18 @@ allocate_acl_ipv4_5tuple_rule(void)
 
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error)
 {
 	struct rte_flow_classify_rule *rule;
 	struct rte_flow_classify_table_entry *table_entry;
+	struct classify_action *action;
+	uint32_t i;
 	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 (key_found == NULL) {
 		rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -520,91 +536,95 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
 		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 = flow_classify_parse_flow(attr, pattern, actions, error);
+	ret = rte_flow_classify_validate(cls, attr, pattern, actions, error);
 	if (ret < 0)
 		return NULL;
 
-	switch (cls->type) {
-	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
-		rule = allocate_acl_ipv4_5tuple_rule();
+	switch (table_type) {
+	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
+		rule = allocate_acl_ipv4_5tuple_rule(cls);
 		if (!rule)
 			return NULL;
+		rule->tbl_type = table_type;
+		cls->table_mask |= table_type;
 		break;
 	default:
 		return NULL;
 	}
 
-	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
-	if (!rule->entry) {
-		free(rule);
-		return NULL;
-	}
-
-	table_entry = rule->entry;
+	action = classify_get_flow_action();
+	table_entry = &rule->entry;
 	table_entry->rule_id = rule->id;
+	table_entry->action.action_mask = action->action_mask;
 
-	if (cls->tables[table_id].ops.f_add != NULL) {
-		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);
-			return NULL;
+	/* Copy actions */
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
+		memcpy(&table_entry->action.act.counter, &action->act.counter,
+				sizeof(table_entry->action.act.counter));
+	}
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_MARK)) {
+		memcpy(&table_entry->action.act.mark, &action->act.mark,
+				sizeof(table_entry->action.act.mark));
+	}
+
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+		if (table->type == table_type) {
+			if (table->ops.f_add != NULL) {
+				ret = table->ops.f_add(
+					table->h_table,
+					&rule->u.key.key_add,
+					&rule->entry,
+					&rule->key_found,
+					&rule->entry_ptr);
+				if (ret) {
+					free(rule);
+					return NULL;
+				}
+
+			*key_found = rule->key_found;
+			}
+
+			return rule;
 		}
-		*key_found = rule->key_found;
 	}
-	return rule;
+	return NULL;
 }
 
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule)
 {
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || table_id >= cls->num_tables)
+	if (!cls || !rule)
 		return ret;
+	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
 
-	if (cls->tables[table_id].ops.f_delete != NULL)
-		ret = cls->tables[table_id].ops.f_delete(
-			cls->tables[table_id].h_table,
-			&rule->u.key.key_del,
-			&rule->key_found,
-			&rule->entry);
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
 
+		if (table->type == tbl_type) {
+			if (table->ops.f_delete != NULL) {
+				ret = table->ops.f_delete(table->h_table,
+						&rule->u.key.key_del,
+						&rule->key_found,
+						&rule->entry);
+
+				return ret;
+			}
+		}
+	}
+	free(rule);
 	return ret;
 }
 
 static int
 flow_classifier_lookup(struct rte_flow_classifier *cls,
-		uint32_t table_id,
+		struct rte_cls_table *table,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts)
 {
@@ -613,8 +633,7 @@ flow_classifier_lookup(struct rte_flow_classifier *cls,
 	uint64_t lookup_hit_mask;
 
 	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
-	ret = cls->tables[table_id].ops.f_lookup(
-		cls->tables[table_id].h_table,
+	ret = table->ops.f_lookup(table->h_table,
 		pkts, pkts_mask, &lookup_hit_mask,
 		(void **)cls->entries);
 
@@ -632,12 +651,12 @@ action_apply(struct rte_flow_classifier *cls,
 		struct rte_flow_classify_stats *stats)
 {
 	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
+	struct rte_flow_classify_table_entry *entry = &rule->entry;
 	uint64_t count = 0;
-	int i;
-	int ret = -EINVAL;
+	uint32_t action_mask = entry->action.action_mask;
+	int i, ret = -EINVAL;
 
-	switch (rule->action.type) {
-	case RTE_FLOW_ACTION_TYPE_COUNT:
+	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
 		for (i = 0; i < cls->nb_pkts; i++) {
 			if (rule->id == cls->entries[i]->rule_id)
 				count++;
@@ -650,32 +669,37 @@ action_apply(struct rte_flow_classifier *cls,
 			ntuple_stats->counter1 = count;
 			ntuple_stats->ipv4_5tuple = rule->rules.u.ipv4_5tuple;
 		}
-		break;
-	default:
-		ret = -ENOTSUP;
-		break;
 	}
-
 	return ret;
 }
 
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
 		struct rte_flow_classify_stats *stats)
 {
+	enum rte_flow_classify_table_type tbl_type;
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
-		table_id >= cls->num_tables)
+	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
 		return ret;
 
-	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
-	if (!ret)
-		ret = action_apply(cls, rule, stats);
+	tbl_type = rule->tbl_type;
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+			if (table->type == tbl_type) {
+				ret = flow_classifier_lookup(cls, table,
+						pkts, nb_pkts);
+				if (!ret) {
+					ret = action_apply(cls, rule, stats);
+					return ret;
+				}
+			}
+	}
 	return ret;
 }
 
diff --git a/lib/librte_flow_classify/rte_flow_classify.h b/lib/librte_flow_classify/rte_flow_classify.h
index 1211873..b9b669f 100644
--- a/lib/librte_flow_classify/rte_flow_classify.h
+++ b/lib/librte_flow_classify/rte_flow_classify.h
@@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
 rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
 	__func__, ## args)
 
+#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
+#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
+#endif
+
 /** Opaque data type for flow classifier */
 struct rte_flow_classifier;
 
@@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
 
 /** Flow classify table type */
 enum rte_flow_classify_table_type {
-	/** no type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
-	/** ACL type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
-};
+	/** No type */
+	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
+	/** ACL IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
+	/** ACL VLAN IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
+	/** ACL QinQ IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
 
-/**
- * Maximum number of tables allowed for any Flow Classifier instance.
- * The value of this parameter cannot be changed.
- */
-#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
+};
 
 /** Parameters for flow classifier creation */
 struct rte_flow_classifier_params {
@@ -122,9 +125,6 @@ struct rte_flow_classifier_params {
 	/** 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;
 };
 
 /** Parameters for table creation */
@@ -134,6 +134,9 @@ struct rte_flow_classify_table_params {
 
 	/** Opaque param to be passed to the table create operation */
 	void *arg_create;
+
+	/** Classifier table type */
+	enum rte_flow_classify_table_type type;
 };
 
 /** IPv4 5-tuple data */
@@ -197,32 +200,50 @@ rte_flow_classifier_free(struct rte_flow_classifier *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);
+		struct rte_flow_classify_table_params *params);
+
+/**
+ * Flow classify validate
+ *
+ * @param cls
+ *   Handle to flow classifier instance
+ * @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(struct rte_flow_classifier *cls,
+		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[out] key_found
- *  returns 1 if key present already, 0 otherwise.
  * @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] key_found
+ *  returns 1 if rule present already, 0 otherwise.
  * @param[out] error
  *   Perform verbose error reporting if not NULL. Structure
  *   initialised in case of error only.
@@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
  */
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error);
 
 /**
@@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  *
  * @param[in] cls
  *   Flow classifier handle
- * @param[in] table_id
- *   id of table
  * @param[in] rule
  *   Flow classify rule
  * @return
@@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule);
 
 /**
@@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  *
  * @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
@@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.c b/lib/librte_flow_classify/rte_flow_classify_parse.c
index dbfa111..9fb3e51 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.c
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
@@ -40,7 +40,7 @@ struct classify_valid_pattern {
 	parse_filter_t parse_filter;
 };
 
-static struct rte_flow_action action;
+static struct classify_action action;
 
 /* Pattern for IPv4 5-tuple UDP filter */
 static enum rte_flow_item_type pattern_ntuple_1[] = {
@@ -80,7 +80,7 @@ static struct classify_valid_pattern classify_supported_patterns[] = {
 	{ pattern_ntuple_3, classify_parse_ntuple_filter },
 };
 
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void)
 {
 	return &action;
@@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	const struct rte_flow_item_udp *udp_mask;
 	const struct rte_flow_item_sctp *sctp_spec;
 	const struct rte_flow_item_sctp *sctp_mask;
+	const struct rte_flow_action_count *count;
+	const struct rte_flow_action_mark *mark_spec;
 	uint32_t index;
 
-	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;
-	}
-
 	/* parse pattern */
 	index = 0;
 
@@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 		return -EINVAL;
 	}
 
-	/* parse action */
-	index = 0;
-
-	/**
-	 * n-tuple only supports count,
-	 * check if the first not void action is COUNT.
-	 */
-	memset(&action, 0, sizeof(action));
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			item, "Not supported action.");
-		return -EINVAL;
-	}
-	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
-
-	/* check if the next not void item is END */
-	index++;
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			act, "Not supported action.");
-		return -EINVAL;
-	}
+	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
 	/* parse attr */
 	/* must be input direction */
@@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
 		filter->priority = FLOW_RULE_MAX_PRIORITY;
 
+	/* parse action */
+	index = 0;
+
+	/**
+	 * n-tuple only supports count and Mark,
+	 * check if the first not void action is COUNT or MARK.
+	 */
+	memset(&action, 0, sizeof(action));
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is MARK or COUNT or END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	case RTE_FLOW_ACTION_TYPE_END:
+		return 0;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
 	return 0;
 }
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h b/lib/librte_flow_classify/rte_flow_classify_parse.h
index 1d4708a..9c1de72 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.h
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
@@ -43,6 +43,20 @@
 extern "C" {
 #endif
 
+extern enum rte_flow_classify_table_type table_type;
+
+struct classify_action {
+	/* Flow action mask */
+	uint64_t action_mask;
+
+	struct action {
+		/** Integer value to return with packets */
+		struct rte_flow_action_mark mark;
+		/** Flow rule counter */
+		struct rte_flow_query_count counter;
+	} act;
+};
+
 typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
 			      const struct rte_flow_item pattern[],
 			      const struct rte_flow_action actions[],
@@ -64,7 +78,7 @@ parse_filter_t
 classify_find_parse_filter_func(struct rte_flow_item *pattern);
 
 /* get action data */
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void);
 
 #ifdef __cplusplus
diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map b/lib/librte_flow_classify/rte_flow_classify_version.map
index f7695cb..49bc25c 100644
--- a/lib/librte_flow_classify/rte_flow_classify_version.map
+++ b/lib/librte_flow_classify/rte_flow_classify_version.map
@@ -7,6 +7,7 @@ EXPERIMENTAL {
 	rte_flow_classify_table_create;
 	rte_flow_classify_table_entry_add;
 	rte_flow_classify_table_entry_delete;
+	rte_flow_classify_validate;
 
 	local: *;
 };
diff --git a/test/test/test_flow_classify.c b/test/test/test_flow_classify.c
index 9f331cd..4ddf4c0 100644
--- a/test/test/test_flow_classify.c
+++ b/test/test/test_flow_classify.c
@@ -51,16 +51,10 @@
 
 
 #define FLOW_CLASSIFY_MAX_RULE_NUM 100
-struct flow_classifier *cls;
-
-struct flow_classifier {
-	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
-	uint32_t n_tables;
-};
+struct flow_classifier_acl *cls;
 
 struct flow_classifier_acl {
-	struct flow_classifier cls;
+	struct rte_flow_classifier *cls;
 } __rte_cache_aligned;
 
 /*
@@ -73,7 +67,7 @@ test_invalid_parameters(void)
 	struct rte_flow_classify_rule *rule;
 	int ret;
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 			NULL, NULL);
 	if (rule) {
 		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
@@ -81,7 +75,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -89,14 +83,14 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
 		return -1;
 	}
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 		NULL, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
@@ -104,7 +98,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -112,7 +106,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
@@ -142,15 +136,16 @@ test_valid_parameters(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
+
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -183,15 +178,15 @@ test_invalid_patterns(void)
 
 	pattern[0] = eth_item;
 	pattern[1] = ipv4_udp_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -202,15 +197,15 @@ test_invalid_patterns(void)
 	pattern[1] = ipv4_udp_item_1;
 	pattern[2] = udp_item_bad;
 	pattern[3] = end_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -241,15 +236,15 @@ test_invalid_actions(void)
 	actions[0] = count_action_bad;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -260,15 +255,15 @@ test_invalid_actions(void)
 	actions[0] = count_action;
 	actions[1] = end_action_bad;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -462,15 +457,15 @@ test_query_udp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &udp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -478,7 +473,7 @@ test_query_udp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -520,15 +515,15 @@ test_query_tcp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &tcp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -536,7 +531,7 @@ test_query_tcp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -578,15 +573,15 @@ test_query_sctp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &sctp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -594,7 +589,7 @@ test_query_sctp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -622,7 +617,6 @@ test_flow_classify(void)
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 	cls->cls = rte_flow_classifier_create(&cls_params);
 
 	/* initialise ACL table params */
@@ -632,11 +626,11 @@ test_flow_classify(void)
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
-			&cls->table_id[0]);
+	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
 	if (ret) {
 		printf("Line %i: f_create has failed!\n", __LINE__);
 		rte_flow_classifier_free(cls->cls);
diff --git a/test/test/test_flow_classify.h b/test/test/test_flow_classify.h
index 39535cf..af293ed 100644
--- a/test/test/test_flow_classify.h
+++ b/test/test/test_flow_classify.h
@@ -197,7 +197,15 @@ static struct rte_flow_item  sctp_item_1 = { RTE_FLOW_ITEM_TYPE_SCTP,
 /* test actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action count_action_bad = { -1, 0};
 
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification
  2017-11-23 11:32 [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
@ 2017-11-23 11:32 ` Jasvinder Singh
  2017-12-04 16:46   ` Iremonger, Bernard
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib Jasvinder Singh
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 41+ messages in thread
From: Jasvinder Singh @ 2017-11-23 11:32 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger

This patch extends the flow classification library by
adding run api. This function classifies the packets
based on the flow rules stored in the classifier table.
During lookup operation, the table entry is identified on
lookup hit and based on meta-data stored at table
entry, actions are performed on the current packet.
The meta-information about the actions stored in the table
entry is determined from the actions fields specified in
flow rules.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_flow_classify/rte_flow_classify.c       | 56 ++++++++++++++++++++++
 lib/librte_flow_classify/rte_flow_classify.h       | 24 ++++++++++
 .../rte_flow_classify_version.map                  |  1 +
 3 files changed, 81 insertions(+)

diff --git a/lib/librte_flow_classify/rte_flow_classify.c b/lib/librte_flow_classify/rte_flow_classify.c
index ff1bc86..5433bfe 100644
--- a/lib/librte_flow_classify/rte_flow_classify.c
+++ b/lib/librte_flow_classify/rte_flow_classify.c
@@ -37,6 +37,9 @@
 #include <rte_table_acl.h>
 #include <stdbool.h>
 
+#define RTE_PKT_METADATA_PTR(pkt, offset)         \
+		(&((uint32_t *)(pkt))[offset])
+
 int librte_flow_classify_logtype;
 
 static uint32_t unique_id = 1;
@@ -674,6 +677,59 @@ action_apply(struct rte_flow_classifier *cls,
 }
 
 int
+rte_flow_classifier_run(struct rte_flow_classifier *cls,
+	struct rte_mbuf **pkts,
+	const uint16_t nb_pkts,
+	uint32_t pkt_offset)
+{
+	struct rte_flow_action_mark *mark;
+	struct classify_action *action;
+	uint64_t pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
+	uint64_t action_mask;
+	uint32_t *ptr, i, j;
+	int ret = -EINVAL;
+
+	if (!cls || !pkts  || nb_pkts == 0)
+		return ret;
+
+	for (i = 0; i < cls->num_tables; i++) {
+		if (cls->table_mask & (1LU << i)) {
+			struct rte_cls_table *table = &cls->tables[i];
+			uint64_t lookup_hit_mask;
+
+			ret = table->ops.f_lookup(table->h_table,
+				pkts, pkts_mask, &lookup_hit_mask,
+				(void **)cls->entries);
+			if (ret)
+				return ret;
+
+			if (lookup_hit_mask) {
+				for (j = 0; j < nb_pkts; j++) {
+					uint64_t pkt_mask = 1LLU << j;
+
+					if ((lookup_hit_mask & pkt_mask) == 0)
+						continue;
+					/* Meta-data */
+					enum rte_flow_action_type act_type =
+						RTE_FLOW_ACTION_TYPE_MARK;
+					action = &cls->entries[j]->action;
+					action_mask = action->action_mask;
+
+					if (action_mask & (1LLU << act_type)) {
+						mark = &action->act.mark;
+						ptr = RTE_PKT_METADATA_PTR(
+							pkts[j], pkt_offset);
+						*ptr = mark->id;
+					}
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
diff --git a/lib/librte_flow_classify/rte_flow_classify.h b/lib/librte_flow_classify/rte_flow_classify.h
index b9b669f..b74bd11 100644
--- a/lib/librte_flow_classify/rte_flow_classify.h
+++ b/lib/librte_flow_classify/rte_flow_classify.h
@@ -273,6 +273,30 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
 		struct rte_flow_classify_rule *rule);
 
 /**
+ * Flow classifier run.
+ *
+ * As a result of lookup operation, flow classifer idenfies the
+ * table entries that are hit and executes the actions on the packets.
+ *
+ * @param[in] cls
+ *   Flow classifier handle
+ * @param[in] pkts
+ *   Pointer to packets to process
+ * @param[in] nb_pkts
+ *   Number of packets to process
+ * @param[in] pkt_offset
+ *    Offset to store action metadata in the mbuf headroom
+ *
+ * @return
+ *   0 on success, error code otherwise.
+ */
+int
+rte_flow_classifier_run(struct rte_flow_classifier *cls,
+		struct rte_mbuf **pkts,
+		const uint16_t nb_pkts,
+		uint32_t pkt_offset);
+
+/**
  * Query flow classifier for given rule.
  *
  * @param[in] cls
diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map b/lib/librte_flow_classify/rte_flow_classify_version.map
index 49bc25c..b51cb1a 100644
--- a/lib/librte_flow_classify/rte_flow_classify_version.map
+++ b/lib/librte_flow_classify/rte_flow_classify_version.map
@@ -4,6 +4,7 @@ EXPERIMENTAL {
 	rte_flow_classifier_create;
 	rte_flow_classifier_free;
 	rte_flow_classifier_query;
+	rte_flow_classifier_run;
 	rte_flow_classify_table_create;
 	rte_flow_classify_table_entry_add;
 	rte_flow_classify_table_entry_delete;
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib
  2017-11-23 11:32 [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification Jasvinder Singh
@ 2017-11-23 11:32 ` Jasvinder Singh
  2017-12-06 12:04   ` Iremonger, Bernard
  2017-12-11 14:54   ` Mcnamara, John
  2017-12-04 16:45 ` [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Iremonger, Bernard
  2017-12-11 16:26 ` [dpdk-dev] [PATCH v2 1/4] " Jasvinder Singh
  3 siblings, 2 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-11-23 11:32 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger

Updates the documentation for flow classification
library and sample application.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 doc/guides/prog_guide/flow_classify_lib.rst | 79 +++++++++++++++++------------
 doc/guides/sample_app_ug/flow_classify.rst  |  8 +--
 2 files changed, 49 insertions(+), 38 deletions(-)

diff --git a/doc/guides/prog_guide/flow_classify_lib.rst b/doc/guides/prog_guide/flow_classify_lib.rst
index 820dc72..519117c 100644
--- a/doc/guides/prog_guide/flow_classify_lib.rst
+++ b/doc/guides/prog_guide/flow_classify_lib.rst
@@ -101,30 +101,26 @@ The library has the following API's
      *   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);
+           struct rte_flow_classify_table_params *params);
 
     /**
      * Add a flow classify rule to the flow_classifier 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] key_found
+     *   returns 1 if rule present already, 0 otherwise.
      * @param[out] error
      *   Perform verbose error reporting if not NULL. Structure
      *   initialised in case of error only.
@@ -133,10 +129,10 @@ The library has the following API's
      */
     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[],
+            int *key_found;
             struct rte_flow_error *error);
 
     /**
@@ -144,8 +140,6 @@ The library has the following API's
      *
      * @param[in] cls
      *   Flow classifier handle
-     * @param[in] table_id
-     *   id of table
      * @param[in] rule
      *   Flow classify rule
      * @return
@@ -153,16 +147,37 @@ The library has the following API's
      */
     int
     rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_flow_classify_rule *rule);
 
     /**
+     * Flow classifier run.
+     *
+     * As a result of lookup operation, flow classifer idenfies the
+     * table entries that are hit and executes the actions on the packets.
+     *
+     * @param[in] cls
+     *   Flow classifier handle
+     * @param[in] pkts
+     *   Pointer to packets to process
+     * @param[in] nb_pkts
+     *   Number of packets to process
+     * @param[in] pkt_offset
+     *    Offset to store action metadata in the mbuf headroom
+     *
+     * @return
+     *   0 on success, error code otherwise.
+     */
+     int
+     rte_flow_classifier_run(struct rte_flow_classifier *cls,
+             struct rte_mbuf **pkts,
+             const uint16_t nb_pkts,
+             uint32_t pkt_offset);
+
+    /**
      * Query flow classifier for given rule.
      *
      * @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
@@ -177,7 +192,6 @@ The library has the following API's
      */
     int
     rte_flow_classifier_query(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_mbuf **pkts,
             const uint16_t nb_pkts,
             struct rte_flow_classify_rule *rule,
@@ -200,16 +214,13 @@ application before calling the API.
         /** 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;
     };
 
 The ``Classifier`` has the following internal structures:
 
 .. code-block:: c
 
-    struct rte_table {
+    struct rte_cls_table {
         /* Input parameters */
         struct rte_table_ops ops;
         uint32_t entry_size;
@@ -225,11 +236,16 @@ The ``Classifier`` has the following internal structures:
         /* Input parameters */
         char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
         int socket_id;
-        enum rte_flow_classify_table_type type;
 
-        /* Internal tables */
-        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        /* Internal */
+        /* ntuple_fliter */
+        struct rte_eth_ntuple_filter ntuple_filter;
+
+        /* clasifier tables */
+        struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        uint32_t table_mask;
         uint32_t num_tables;
+
         uint16_t nb_pkts;
         struct rte_flow_classify_table_entry
             *entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -252,9 +268,8 @@ application before calling the API.
         /** 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;
+        /** Classifier table type */
+        enum rte_flow_classify_table_type type;
      };
 
 To create an ACL table the ``rte_table_acl_params`` structure must be
@@ -321,7 +336,7 @@ IPv4 5-tuple pattern, attributes and actions and returns the 5-tuple data in the
 .. code-block:: c
 
     static int
-    flow_classify_parse_flow(
+    flow_classify_parse_flow(struct rte_flow_classifier *cls,
                    const struct rte_flow_attr *attr,
                    const struct rte_flow_item pattern[],
                    const struct rte_flow_action actions[],
@@ -355,24 +370,24 @@ parses the Flow rule.
 
     struct rte_flow_classify {
         uint32_t id;  /* unique ID of classify object */
-        struct rte_flow_action action; /* action when match found */
-	struct classify_rules rules; /* union of rules */
+        enum rte_flow_classify_table_type tbl_type; /* rule table */
+        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 */
+        struct rte_flow_classify_table_entry entry;  /* rule meta data */
+       void *entry_ptr; /* handle to the table entry for rule meta data */
     };
 
-It then calls the ``table[table_id].ops.f_add`` API to add the rule to the ACL
+It then calls the ``table.ops.f_add`` API to add the rule to the ACL
 table.
 
 Deleting Flow Rules
 ~~~~~~~~~~~~~~~~~~~
 
 The ``rte_flow_classify_table_entry_delete`` API calls the
-``table[table_id].ops.f_delete`` API to delete a rule from the ACL table.
+``table.ops.f_delete`` API to delete a rule from the ACL table.
 
 Packet Matching
 ~~~~~~~~~~~~~~~
@@ -380,7 +395,7 @@ Packet Matching
 The ``rte_flow_classifier_query`` API is used to find packets which match a
 given flow Flow rule in the table.
 This API calls the flow_classify_run internal function which calls the
-``table[table_id].ops.f_lookup`` API to see if any packets in a burst match any
+``table.ops.f_lookup`` API to see if any packets in a burst match any
 of the Flow rules in the table.
 The meta data for the highest priority rule matched for each packet is returned
 in the entries array in the ``rte_flow_classify`` object.
diff --git a/doc/guides/sample_app_ug/flow_classify.rst b/doc/guides/sample_app_ug/flow_classify.rst
index bc12b87..427fded 100644
--- a/doc/guides/sample_app_ug/flow_classify.rst
+++ b/doc/guides/sample_app_ug/flow_classify.rst
@@ -228,7 +228,6 @@ table`` to the flow classifier.
 
     struct flow_classifier {
         struct rte_flow_classifier *cls;
-        uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
     };
 
     struct flow_classifier_acl {
@@ -243,7 +242,6 @@ table`` to the flow classifier.
 
     cls_params.name = "flow_classifier";
     cls_params.socket_id = socket_id;
-    cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
     cls_app->cls = rte_flow_classifier_create(&cls_params);
     if (cls_app->cls == NULL) {
@@ -260,10 +258,9 @@ table`` to the flow classifier.
     /* initialise table create params */
     cls_table_params.ops = &rte_table_acl_ops,
     cls_table_params.arg_create = &table_acl_params,
-    cls_table_params.table_metadata_size = 0;
+    cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-                  &cls->table_id[0]);
+    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
     if (ret) {
         rte_flow_classifier_free(cls_app->cls);
         rte_free(cls);
@@ -495,7 +492,6 @@ following:
                     if (rules[i]) {
                         ret = rte_flow_classifier_query(
                             cls_app->cls,
-                            cls_app->table_id[0],
                             bufs, nb_rx, rules[i],
                             &classify_stats);
                         if (ret)
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis
  2017-11-23 11:32 [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification Jasvinder Singh
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib Jasvinder Singh
@ 2017-12-04 16:45 ` Iremonger, Bernard
  2017-12-05 10:59   ` Iremonger, Bernard
  2017-12-11 16:26 ` [dpdk-dev] [PATCH v2 1/4] " Jasvinder Singh
  3 siblings, 1 reply; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-04 16:45 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Thursday, November 23, 2017 11:32 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [PATCH 1/3] lib/librte_flow_classify: remove table id parameter
> from apis
> 
> This patch removes table id parameter from all the flow classify apis to
> reduce the complexity and and does some cleanup of the code.
> 
> The validate api has been exposed as public api to allows user to validate the
> flow before adding it to the classifier.
> 
> The sample app and unit tests have been updated to accomodate the apis
> changes.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  examples/flow_classify/flow_classify.c             |  27 +-
>  lib/librte_flow_classify/rte_flow_classify.c       | 320 +++++++++++----------
>  lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
>  lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
> lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
>  .../rte_flow_classify_version.map                  |   1 +
>  test/test/test_flow_classify.c                     |  86 +++---
>  test/test/test_flow_classify.h                     |  10 +-
>  8 files changed, 365 insertions(+), 287 deletions(-)
> 
> diff --git a/examples/flow_classify/flow_classify.c
> b/examples/flow_classify/flow_classify.c
> index 766f1dd..37e6904 100644
> --- a/examples/flow_classify/flow_classify.c
> +++ b/examples/flow_classify/flow_classify.c
> @@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default = {
> 
>  struct flow_classifier {
>  	struct rte_flow_classifier *cls;
> -	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
>  };
> 
>  struct flow_classifier_acl {
> @@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = {
> RTE_FLOW_ITEM_TYPE_END,
>  /* sample actions:
>   * "actions count / end"
>   */
> -static struct rte_flow_action count_action = {
> RTE_FLOW_ACTION_TYPE_COUNT, 0};
> +struct rte_flow_query_count count = {
> +	.reset = 1,
> +	.hits_set = 1,
> +	.bytes_set = 1,
> +	.hits = 0,
> +	.bytes = 0,
> +};
> +static struct rte_flow_action count_action = {
> RTE_FLOW_ACTION_TYPE_COUNT,
> +	&count};
>  static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END,
> 0};  static struct rte_flow_action actions[2];
> 
> @@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
>  	int i = 0;
> 
>  	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
> -			cls_app->table_id[0], rules[7]);
> +			rules[7]);
>  	if (ret)
>  		printf("table_entry_delete failed [7] %d\n\n", ret);
>  	else
> @@ -317,7 +324,6 @@ lcore_main(struct flow_classifier *cls_app)
>  				if (rules[i]) {
>  					ret = rte_flow_classifier_query(
>  						cls_app->cls,
> -						cls_app->table_id[0],
>  						bufs, nb_rx, rules[i],
>  						&classify_stats);
>  					if (ret)
> @@ -635,8 +641,8 @@ add_classify_rule(struct rte_eth_ntuple_filter
> *ntuple_filter,
>  	actions[1] = end_action;
> 
>  	rule = rte_flow_classify_table_entry_add(
> -			cls_app->cls, cls_app->table_id[0], &key_found,
> -			&attr, pattern_ipv4_5tuple, actions, &error);
> +			cls_app->cls, &attr, pattern_ipv4_5tuple,
> +			actions, &key_found, &error);
>  	if (rule == NULL) {
>  		printf("table entry add failed ipv4_proto = %u\n",
>  			ipv4_proto);
> @@ -809,7 +815,6 @@ main(int argc, char *argv[])
> 
>  	cls_params.name = "flow_classifier";
>  	cls_params.socket_id = socket_id;
> -	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> 
>  	cls_app->cls = rte_flow_classifier_create(&cls_params);
>  	if (cls_app->cls == NULL) {
> @@ -824,11 +829,11 @@ main(int argc, char *argv[])
>  	memcpy(table_acl_params.field_format, ipv4_defs,
> sizeof(ipv4_defs));
> 
>  	/* initialise table create params */
> -	cls_table_params.ops = &rte_table_acl_ops,
> -	cls_table_params.arg_create = &table_acl_params,
> +	cls_table_params.ops = &rte_table_acl_ops;
> +	cls_table_params.arg_create = &table_acl_params;
> +	cls_table_params.type =
> RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> 
> -	ret = rte_flow_classify_table_create(cls_app->cls,
> &cls_table_params,
> -			&cls_app->table_id[0]);
> +	ret = rte_flow_classify_table_create(cls_app->cls,
> &cls_table_params);
>  	if (ret) {
>  		rte_flow_classifier_free(cls_app->cls);
>  		rte_free(cls_app);
> diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> b/lib/librte_flow_classify/rte_flow_classify.c
> index e6f4486..ff1bc86 100644
> --- a/lib/librte_flow_classify/rte_flow_classify.c
> +++ b/lib/librte_flow_classify/rte_flow_classify.c
> @@ -39,16 +39,20 @@
> 
>  int librte_flow_classify_logtype;
> 
> -static struct rte_eth_ntuple_filter ntuple_filter;  static uint32_t unique_id =
> 1;
> 
> +enum rte_flow_classify_table_type table_type
> +	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
> 
>  struct rte_flow_classify_table_entry {
>  	/* meta-data for classify rule */
>  	uint32_t rule_id;
> +
> +	/* Flow action */
> +	struct classify_action action;
>  };
> 
> -struct rte_table {
> +struct rte_cls_table {
>  	/* Input parameters */
>  	struct rte_table_ops ops;
>  	uint32_t entry_size;
> @@ -64,11 +68,16 @@ struct rte_flow_classifier {
>  	/* Input parameters */
>  	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
>  	int socket_id;
> -	enum rte_flow_classify_table_type type;
> 
> -	/* Internal tables */
> -	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +	/* Internal */
> +	/* ntuple_fliter */
> +	struct rte_eth_ntuple_filter ntuple_filter;
> +
> +	/* clasifier tables */
> +	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +	uint32_t table_mask;
>  	uint32_t num_tables;
> +
>  	uint16_t nb_pkts;
>  	struct rte_flow_classify_table_entry
>  		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
> @@ -97,18 +106,19 @@ struct classify_rules {
> 
>  struct rte_flow_classify_rule {
>  	uint32_t id; /* unique ID of classify rule */
> -	struct rte_flow_action action; /* action when match found */
> +	enum rte_flow_classify_table_type tbl_type; /* rule table */
>  	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 */
> +	struct rte_flow_classify_table_entry entry;  /* rule meta data */
>  	void *entry_ptr; /* handle to the table entry for rule meta data */  };
> 
> -static int
> -flow_classify_parse_flow(
> +int
> +rte_flow_classify_validate(
> +		   struct rte_flow_classifier *cls,
>  		   const struct rte_flow_attr *attr,
>  		   const struct rte_flow_item pattern[],
>  		   const struct rte_flow_action actions[], @@ -120,7 +130,42
> @@ flow_classify_parse_flow(
>  	uint32_t i = 0;
>  	int ret;
> 
> -	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
> +	if (cls == NULL) {
> +		RTE_FLOW_CLASSIFY_LOG(ERR,
> +			"%s: rte_flow_classifier parameter is NULL\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	if (!attr) {
> +		rte_flow_error_set(error, EINVAL,
> +				   RTE_FLOW_ERROR_TYPE_ATTR,
> +				   NULL, "NULL attribute.");
> +		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 (!error) {
> +		rte_flow_error_set(error, EINVAL,
> +				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> +				   NULL, "NULL error.");
> +		return -EINVAL;
> +	}
> +
> +	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
> 
>  	/* Get the non-void item number of pattern */
>  	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { @@ -
> 150,7 +195,7 @@ flow_classify_parse_flow(
>  		return -EINVAL;
>  	}
> 
> -	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
> +	ret = parse_filter(attr, items, actions, &cls->ntuple_filter, error);
>  	free(items);
>  	return ret;
>  }
> @@ -275,17 +320,14 @@ rte_flow_classifier_create(struct
> rte_flow_classifier_params *params)
>  	/* 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;
> +	cls->socket_id = params->socket_id;
> 
>  	return cls;
>  }
> 
>  static void
> -rte_flow_classify_table_free(struct rte_table *table)
> +rte_flow_classify_table_free(struct rte_cls_table *table)
>  {
>  	if (table->ops.f_free != NULL)
>  		table->ops.f_free(table->h_table);
> @@ -306,7 +348,7 @@ rte_flow_classifier_free(struct rte_flow_classifier
> *cls)
> 
>  	/* Free tables */
>  	for (i = 0; i < cls->num_tables; i++) {
> -		struct rte_table *table = &cls->tables[i];
> +		struct rte_cls_table *table = &cls->tables[i];
> 
>  		rte_flow_classify_table_free(table);
>  	}
> @@ -319,8 +361,7 @@ rte_flow_classifier_free(struct rte_flow_classifier
> *cls)
> 
>  static int
>  rte_table_check_params(struct rte_flow_classifier *cls,
> -		struct rte_flow_classify_table_params *params,
> -		uint32_t *table_id)
> +		struct rte_flow_classify_table_params *params)
>  {
>  	if (cls == NULL) {
>  		RTE_FLOW_CLASSIFY_LOG(ERR,
> @@ -333,11 +374,6 @@ rte_table_check_params(struct rte_flow_classifier
> *cls,
>  			__func__);
>  		return -EINVAL;
>  	}
> -	if (table_id == NULL) {
> -		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is
> NULL\n",
> -			__func__);
> -		return -EINVAL;
> -	}
> 
>  	/* ops */
>  	if (params->ops == NULL) {
> @@ -371,22 +407,18 @@ rte_table_check_params(struct rte_flow_classifier
> *cls,
> 
>  int
>  rte_flow_classify_table_create(struct rte_flow_classifier *cls,
> -	struct rte_flow_classify_table_params *params,
> -	uint32_t *table_id)
> +	struct rte_flow_classify_table_params *params)
>  {
> -	struct rte_table *table;
> +	struct rte_cls_table *table;
>  	void *h_table;
> -	uint32_t entry_size, id;
> +	uint32_t entry_size;
>  	int ret;
> 
>  	/* Check input arguments */
> -	ret = rte_table_check_params(cls, params, table_id);
> +	ret = rte_table_check_params(cls, params);
>  	if (ret != 0)
>  		return ret;
> 
> -	id = cls->num_tables;
> -	table = &cls->tables[id];
> -
>  	/* calculate table entry size */
>  	entry_size = sizeof(struct rte_flow_classify_table_entry);
> 
> @@ -400,8 +432,9 @@ rte_flow_classify_table_create(struct
> rte_flow_classifier *cls,
>  	}
> 
>  	/* Commit current table to the classifier */
> +	table = &cls->tables[cls->num_tables];
> +	table->type = params->type;
>  	cls->num_tables++;
> -	*table_id = id;
> 
>  	/* Save input parameters */
>  	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
> @@ -414,7 +447,7 @@ rte_flow_classify_table_create(struct
> rte_flow_classifier *cls,  }
> 
>  static struct rte_flow_classify_rule *
> -allocate_acl_ipv4_5tuple_rule(void)
> +allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
>  {
>  	struct rte_flow_classify_rule *rule;
>  	int log_level;
> @@ -427,45 +460,44 @@ allocate_acl_ipv4_5tuple_rule(void)
>  	rule->id = unique_id++;
>  	rule->rules.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.priority = cls->ntuple_filter.priority;
>  	rule-
> >u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
> -			ntuple_filter.proto_mask;
> +			cls->ntuple_filter.proto_mask;
>  	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
> -			ntuple_filter.proto;
> -	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
> -	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
> +			cls->ntuple_filter.proto;
> +	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
> +	rule->rules.u.ipv4_5tuple.proto_mask = cls-
> >ntuple_filter.proto_mask;
> 
>  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32
> =
> -			ntuple_filter.src_ip_mask;
> +			cls->ntuple_filter.src_ip_mask;
>  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
> -			ntuple_filter.src_ip;
> -	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
> -	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
> +			cls->ntuple_filter.src_ip;
> +	rule->rules.u.ipv4_5tuple.src_ip_mask = cls-
> >ntuple_filter.src_ip_mask;
> +	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
> 
>  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32
> =
> -			ntuple_filter.dst_ip_mask;
> +			cls->ntuple_filter.dst_ip_mask;
>  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
> -			ntuple_filter.dst_ip;
> -	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
> -	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
> +			cls->ntuple_filter.dst_ip;
> +	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls-
> >ntuple_filter.dst_ip_mask;
> +	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
> 
>  	rule-
> >u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
> -			ntuple_filter.src_port_mask;
> +			cls->ntuple_filter.src_port_mask;
>  	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
> -			ntuple_filter.src_port;
> -	rule->rules.u.ipv4_5tuple.src_port_mask =
> ntuple_filter.src_port_mask;
> -	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
> +			cls->ntuple_filter.src_port;
> +	rule->rules.u.ipv4_5tuple.src_port_mask =
> +			cls->ntuple_filter.src_port_mask;
> +	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
> 
>  	rule-
> >u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
> -			ntuple_filter.dst_port_mask;
> +			cls->ntuple_filter.dst_port_mask;
>  	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
> -			ntuple_filter.dst_port;
> -	rule->rules.u.ipv4_5tuple.dst_port_mask =
> ntuple_filter.dst_port_mask;
> -	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
> +			cls->ntuple_filter.dst_port;
> +	rule->rules.u.ipv4_5tuple.dst_port_mask =
> +			cls->ntuple_filter.dst_port_mask;
> +	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
> 
>  	log_level = rte_log_get_level(librte_flow_classify_logtype);
> 
> @@ -485,34 +517,18 @@ allocate_acl_ipv4_5tuple_rule(void)
> 
>  struct rte_flow_classify_rule *
>  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
> -		int *key_found,
>  		const struct rte_flow_attr *attr,
>  		const struct rte_flow_item pattern[],
>  		const struct rte_flow_action actions[],
> +		int *key_found,
>  		struct rte_flow_error *error)
>  {
>  	struct rte_flow_classify_rule *rule;
>  	struct rte_flow_classify_table_entry *table_entry;
> +	struct classify_action *action;
> +	uint32_t i;
>  	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 (key_found == NULL) {
>  		rte_flow_error_set(error, EINVAL,
>  				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> @@ -520,91 +536,95 @@ rte_flow_classify_table_entry_add(struct
> rte_flow_classifier *cls,
>  		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 = flow_classify_parse_flow(attr, pattern, actions, error);
> +	ret = rte_flow_classify_validate(cls, attr, pattern, actions, error);
>  	if (ret < 0)
>  		return NULL;
> 
> -	switch (cls->type) {
> -	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
> -		rule = allocate_acl_ipv4_5tuple_rule();
> +	switch (table_type) {
> +	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
> +		rule = allocate_acl_ipv4_5tuple_rule(cls);
>  		if (!rule)
>  			return NULL;
> +		rule->tbl_type = table_type;
> +		cls->table_mask |= table_type;
>  		break;
>  	default:
>  		return NULL;
>  	}
> 
> -	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
> -	if (!rule->entry) {
> -		free(rule);
> -		return NULL;
> -	}
> -
> -	table_entry = rule->entry;
> +	action = classify_get_flow_action();
> +	table_entry = &rule->entry;
>  	table_entry->rule_id = rule->id;
> +	table_entry->action.action_mask = action->action_mask;
> 
> -	if (cls->tables[table_id].ops.f_add != NULL) {
> -		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);
> -			return NULL;
> +	/* Copy actions */
> +	if (action->action_mask & (1LLU <<
> RTE_FLOW_ACTION_TYPE_COUNT)) {
> +		memcpy(&table_entry->action.act.counter, &action-
> >act.counter,
> +				sizeof(table_entry->action.act.counter));
> +	}
> +	if (action->action_mask & (1LLU <<
> RTE_FLOW_ACTION_TYPE_MARK)) {
> +		memcpy(&table_entry->action.act.mark, &action->act.mark,
> +				sizeof(table_entry->action.act.mark));
> +	}
> +
> +	for (i = 0; i < cls->num_tables; i++) {
> +		struct rte_cls_table *table = &cls->tables[i];
> +
> +		if (table->type == table_type) {
> +			if (table->ops.f_add != NULL) {
> +				ret = table->ops.f_add(
> +					table->h_table,
> +					&rule->u.key.key_add,
> +					&rule->entry,
> +					&rule->key_found,
> +					&rule->entry_ptr);
> +				if (ret) {
> +					free(rule);
> +					return NULL;
> +				}
> +
> +			*key_found = rule->key_found;
> +			}
> +
> +			return rule;
>  		}
> -		*key_found = rule->key_found;
>  	}
> -	return rule;
> +	return NULL;
>  }
> 
>  int
>  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_flow_classify_rule *rule)
>  {
> +	uint32_t i;
>  	int ret = -EINVAL;
> 
> -	if (!cls || !rule || table_id >= cls->num_tables)
> +	if (!cls || !rule)
>  		return ret;
> +	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
> 
> -	if (cls->tables[table_id].ops.f_delete != NULL)
> -		ret = cls->tables[table_id].ops.f_delete(
> -			cls->tables[table_id].h_table,
> -			&rule->u.key.key_del,
> -			&rule->key_found,
> -			&rule->entry);
> +	for (i = 0; i < cls->num_tables; i++) {
> +		struct rte_cls_table *table = &cls->tables[i];
> 
> +		if (table->type == tbl_type) {
> +			if (table->ops.f_delete != NULL) {
> +				ret = table->ops.f_delete(table->h_table,
> +						&rule->u.key.key_del,
> +						&rule->key_found,
> +						&rule->entry);
> +
> +				return ret;
> +			}
> +		}
> +	}
> +	free(rule);
>  	return ret;
>  }
> 
>  static int
>  flow_classifier_lookup(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
> +		struct rte_cls_table *table,
>  		struct rte_mbuf **pkts,
>  		const uint16_t nb_pkts)
>  {
> @@ -613,8 +633,7 @@ flow_classifier_lookup(struct rte_flow_classifier *cls,
>  	uint64_t lookup_hit_mask;
> 
>  	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> -	ret = cls->tables[table_id].ops.f_lookup(
> -		cls->tables[table_id].h_table,
> +	ret = table->ops.f_lookup(table->h_table,
>  		pkts, pkts_mask, &lookup_hit_mask,
>  		(void **)cls->entries);
> 
> @@ -632,12 +651,12 @@ action_apply(struct rte_flow_classifier *cls,
>  		struct rte_flow_classify_stats *stats)  {
>  	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
> +	struct rte_flow_classify_table_entry *entry = &rule->entry;
>  	uint64_t count = 0;
> -	int i;
> -	int ret = -EINVAL;
> +	uint32_t action_mask = entry->action.action_mask;
> +	int i, ret = -EINVAL;
> 
> -	switch (rule->action.type) {
> -	case RTE_FLOW_ACTION_TYPE_COUNT:
> +	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
>  		for (i = 0; i < cls->nb_pkts; i++) {
>  			if (rule->id == cls->entries[i]->rule_id)
>  				count++;
> @@ -650,32 +669,37 @@ action_apply(struct rte_flow_classifier *cls,
>  			ntuple_stats->counter1 = count;
>  			ntuple_stats->ipv4_5tuple = rule-
> >rules.u.ipv4_5tuple;
>  		}
> -		break;
> -	default:
> -		ret = -ENOTSUP;
> -		break;
>  	}
> -
>  	return ret;
>  }
> 
>  int
>  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_mbuf **pkts,
>  		const uint16_t nb_pkts,
>  		struct rte_flow_classify_rule *rule,
>  		struct rte_flow_classify_stats *stats)  {
> +	enum rte_flow_classify_table_type tbl_type;
> +	uint32_t i;
>  	int ret = -EINVAL;
> 
> -	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
> -		table_id >= cls->num_tables)
> +	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
>  		return ret;
> 
> -	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
> -	if (!ret)
> -		ret = action_apply(cls, rule, stats);
> +	tbl_type = rule->tbl_type;
> +	for (i = 0; i < cls->num_tables; i++) {
> +		struct rte_cls_table *table = &cls->tables[i];
> +
> +			if (table->type == tbl_type) {
> +				ret = flow_classifier_lookup(cls, table,
> +						pkts, nb_pkts);
> +				if (!ret) {
> +					ret = action_apply(cls, rule, stats);
> +					return ret;
> +				}
> +			}
> +	}
>  	return ret;
>  }
> 
> diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> b/lib/librte_flow_classify/rte_flow_classify.h
> index 1211873..b9b669f 100644
> --- a/lib/librte_flow_classify/rte_flow_classify.h
> +++ b/lib/librte_flow_classify/rte_flow_classify.h
> @@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
> rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
>  	__func__, ## args)
> 
> +#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
> +#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
> +#endif
> +
>  /** Opaque data type for flow classifier */  struct rte_flow_classifier;
> 
> @@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
> 
>  /** Flow classify table type */
>  enum rte_flow_classify_table_type {
> -	/** no type */
> -	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
> -	/** ACL type */
> -	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
> -};
> +	/** No type */
> +	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
> +	/** ACL IP4 5TUPLE */
> +	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
> +	/** ACL VLAN IP4 5TUPLE */
> +	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
> +	/** ACL QinQ IP4 5TUPLE */
> +	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
> 
> -/**
> - * Maximum number of tables allowed for any Flow Classifier instance.
> - * The value of this parameter cannot be changed.
> - */
> -#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
> +};
> 
>  /** Parameters for flow classifier creation */  struct
> rte_flow_classifier_params { @@ -122,9 +125,6 @@ struct
> rte_flow_classifier_params {
>  	/** 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;
>  };
> 
>  /** Parameters for table creation */
> @@ -134,6 +134,9 @@ struct rte_flow_classify_table_params {
> 
>  	/** Opaque param to be passed to the table create operation */
>  	void *arg_create;
> +
> +	/** Classifier table type */
> +	enum rte_flow_classify_table_type type;
>  };
> 
>  /** IPv4 5-tuple data */
> @@ -197,32 +200,50 @@ rte_flow_classifier_free(struct rte_flow_classifier
> *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);
> +		struct rte_flow_classify_table_params *params);
> +
> +/**
> + * Flow classify validate
> + *
> + * @param cls
> + *   Handle to flow classifier instance
> + * @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(struct rte_flow_classifier *cls,
> +		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[out] key_found
> - *  returns 1 if key present already, 0 otherwise.
>   * @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] key_found
> + *  returns 1 if rule present already, 0 otherwise.
>   * @param[out] error
>   *   Perform verbose error reporting if not NULL. Structure
>   *   initialised in case of error only.
> @@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct
> rte_flow_classifier *cls,
>   */
>  struct rte_flow_classify_rule *
>  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
> -		int *key_found,
>  		const struct rte_flow_attr *attr,
>  		const struct rte_flow_item pattern[],
>  		const struct rte_flow_action actions[],
> +		int *key_found,
>  		struct rte_flow_error *error);
> 
>  /**
> @@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct
> rte_flow_classifier *cls,
>   *
>   * @param[in] cls
>   *   Flow classifier handle
> - * @param[in] table_id
> - *   id of table
>   * @param[in] rule
>   *   Flow classify rule
>   * @return
> @@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct
> rte_flow_classifier *cls,
>   */
>  int
>  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_flow_classify_rule *rule);
> 
>  /**
> @@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct
> rte_flow_classifier *cls,
>   *
>   * @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
> @@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct
> rte_flow_classifier *cls,
>   */
>  int
>  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_mbuf **pkts,
>  		const uint16_t nb_pkts,
>  		struct rte_flow_classify_rule *rule,
> diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.c
> b/lib/librte_flow_classify/rte_flow_classify_parse.c
> index dbfa111..9fb3e51 100644
> --- a/lib/librte_flow_classify/rte_flow_classify_parse.c
> +++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
> @@ -40,7 +40,7 @@ struct classify_valid_pattern {
>  	parse_filter_t parse_filter;
>  };
> 
> -static struct rte_flow_action action;
> +static struct classify_action action;
> 
>  /* Pattern for IPv4 5-tuple UDP filter */  static enum rte_flow_item_type
> pattern_ntuple_1[] = { @@ -80,7 +80,7 @@ static struct
> classify_valid_pattern classify_supported_patterns[] = {
>  	{ pattern_ntuple_3, classify_parse_ntuple_filter },  };
> 
> -struct rte_flow_action *
> +struct classify_action *
>  classify_get_flow_action(void)
>  {
>  	return &action;
> @@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct
> rte_flow_attr *attr,
>  	const struct rte_flow_item_udp *udp_mask;
>  	const struct rte_flow_item_sctp *sctp_spec;
>  	const struct rte_flow_item_sctp *sctp_mask;
> +	const struct rte_flow_action_count *count;
> +	const struct rte_flow_action_mark *mark_spec;
>  	uint32_t index;
> 
> -	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;
> -	}
> -
>  	/* parse pattern */
>  	index = 0;
> 
> @@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct
> rte_flow_attr *attr,
>  		return -EINVAL;
>  	}
> 
> -	/* parse action */
> -	index = 0;
> -
> -	/**
> -	 * n-tuple only supports count,
> -	 * check if the first not void action is COUNT.
> -	 */
> -	memset(&action, 0, sizeof(action));
> -	NEXT_ITEM_OF_ACTION(act, actions, index);
> -	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
> -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> -		rte_flow_error_set(error, EINVAL,
> -			RTE_FLOW_ERROR_TYPE_ACTION,
> -			item, "Not supported action.");
> -		return -EINVAL;
> -	}
> -	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
> -
> -	/* check if the next not void item is END */
> -	index++;
> -	NEXT_ITEM_OF_ACTION(act, actions, index);
> -	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> -		rte_flow_error_set(error, EINVAL,
> -			RTE_FLOW_ERROR_TYPE_ACTION,
> -			act, "Not supported action.");
> -		return -EINVAL;
> -	}
> +	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> 
>  	/* parse attr */
>  	/* must be input direction */
> @@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct
> rte_flow_attr *attr,
>  	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
>  		filter->priority = FLOW_RULE_MAX_PRIORITY;
> 
> +	/* parse action */
> +	index = 0;
> +
> +	/**
> +	 * n-tuple only supports count and Mark,
> +	 * check if the first not void action is COUNT or MARK.
> +	 */
> +	memset(&action, 0, sizeof(action));
> +	NEXT_ITEM_OF_ACTION(act, actions, index);
> +	switch (act->type) {
> +	case RTE_FLOW_ACTION_TYPE_COUNT:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_COUNT;
> +		count = (const struct rte_flow_action_count *)act->conf;
> +		memcpy(&action.act.counter, count,
> sizeof(action.act.counter));
> +		break;
> +	case RTE_FLOW_ACTION_TYPE_MARK:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_MARK;
> +		mark_spec = (const struct rte_flow_action_mark *)act-
> >conf;
> +		memcpy(&action.act.mark, mark_spec,
> sizeof(action.act.mark));
> +		break;
> +	default:
> +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> +		rte_flow_error_set(error, EINVAL,
> +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> +		   "Invalid action.");
> +		return -EINVAL;
> +	}
> +
> +	/* check if the next not void item is MARK or COUNT or END */
> +	index++;
> +	NEXT_ITEM_OF_ACTION(act, actions, index);
> +	switch (act->type) {
> +	case RTE_FLOW_ACTION_TYPE_COUNT:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_COUNT;
> +		count = (const struct rte_flow_action_count *)act->conf;
> +		memcpy(&action.act.counter, count,
> sizeof(action.act.counter));
> +		break;
> +	case RTE_FLOW_ACTION_TYPE_MARK:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_MARK;
> +		mark_spec = (const struct rte_flow_action_mark *)act-
> >conf;
> +		memcpy(&action.act.mark, mark_spec,
> sizeof(action.act.mark));
> +		break;
> +	case RTE_FLOW_ACTION_TYPE_END:
> +		return 0;
> +	default:
> +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> +		rte_flow_error_set(error, EINVAL,
> +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> +		   "Invalid action.");
> +		return -EINVAL;
> +	}
> +
> +	/* check if the next not void item is END */
> +	index++;
> +	NEXT_ITEM_OF_ACTION(act, actions, index);
> +	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> +		rte_flow_error_set(error, EINVAL,
> +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> +		   "Invalid action.");
> +		return -EINVAL;
> +	}
> +
>  	return 0;
>  }
> diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h
> b/lib/librte_flow_classify/rte_flow_classify_parse.h
> index 1d4708a..9c1de72 100644
> --- a/lib/librte_flow_classify/rte_flow_classify_parse.h
> +++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
> @@ -43,6 +43,20 @@
>  extern "C" {
>  #endif
> 
> +extern enum rte_flow_classify_table_type table_type;
> +
> +struct classify_action {
> +	/* Flow action mask */
> +	uint64_t action_mask;
> +
> +	struct action {
> +		/** Integer value to return with packets */
> +		struct rte_flow_action_mark mark;
> +		/** Flow rule counter */
> +		struct rte_flow_query_count counter;
> +	} act;
> +};
> +
>  typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
>  			      const struct rte_flow_item pattern[],
>  			      const struct rte_flow_action actions[], @@ -64,7
> +78,7 @@ parse_filter_t  classify_find_parse_filter_func(struct
> rte_flow_item *pattern);
> 
>  /* get action data */
> -struct rte_flow_action *
> +struct classify_action *
>  classify_get_flow_action(void);
> 
>  #ifdef __cplusplus
> diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map
> b/lib/librte_flow_classify/rte_flow_classify_version.map
> index f7695cb..49bc25c 100644
> --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> @@ -7,6 +7,7 @@ EXPERIMENTAL {
>  	rte_flow_classify_table_create;
>  	rte_flow_classify_table_entry_add;
>  	rte_flow_classify_table_entry_delete;
> +	rte_flow_classify_validate;
> 
>  	local: *;
>  };
> diff --git a/test/test/test_flow_classify.c b/test/test/test_flow_classify.c
> index 9f331cd..4ddf4c0 100644
> --- a/test/test/test_flow_classify.c
> +++ b/test/test/test_flow_classify.c
> @@ -51,16 +51,10 @@
> 
> 
>  #define FLOW_CLASSIFY_MAX_RULE_NUM 100
> -struct flow_classifier *cls;
> -
> -struct flow_classifier {
> -	struct rte_flow_classifier *cls;
> -	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
> -	uint32_t n_tables;
> -};
> +struct flow_classifier_acl *cls;
> 
>  struct flow_classifier_acl {
> -	struct flow_classifier cls;
> +	struct rte_flow_classifier *cls;
>  } __rte_cache_aligned;
> 
>  /*
> @@ -73,7 +67,7 @@ test_invalid_parameters(void)
>  	struct rte_flow_classify_rule *rule;
>  	int ret;
> 
> -	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL,
> NULL,
> +	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
>  			NULL, NULL);
>  	if (rule) {
>  		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
> @@ -81,7 +75,7 @@ test_invalid_parameters(void)
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
> +	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
>  	if (!ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -89,14 +83,14 @@ test_invalid_parameters(void)
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
> +	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
>  	if (!ret) {
>  		printf("Line %i: flow_classifier_query", __LINE__);
>  		printf(" with NULL param should have failed!\n");
>  		return -1;
>  	}
> 
> -	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL,
> NULL,
> +	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
>  		NULL, &error);
>  	if (rule) {
>  		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
> @@ -104,7 +98,7 @@ test_invalid_parameters(void)
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
> +	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
>  	if (!ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -112,7 +106,7 @@ test_invalid_parameters(void)
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
> +	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
>  	if (!ret) {
>  		printf("Line %i: flow_classifier_query", __LINE__);
>  		printf(" with NULL param should have failed!\n"); @@ -
> 142,15 +136,16 @@ test_valid_parameters(void)
>  	actions[0] = count_action;
>  	actions[1] = end_action;
> 
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
> +
>  	if (!rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should not have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -183,15 +178,15 @@ test_invalid_patterns(void)
> 
>  	pattern[0] = eth_item;
>  	pattern[1] = ipv4_udp_item_bad;
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
>  	if (rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (!ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -202,15 +197,15 @@ test_invalid_patterns(void)
>  	pattern[1] = ipv4_udp_item_1;
>  	pattern[2] = udp_item_bad;
>  	pattern[3] = end_item_bad;
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
>  	if (rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (!ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -241,15 +236,15 @@ test_invalid_actions(void)
>  	actions[0] = count_action_bad;
>  	actions[1] = end_action;
> 
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
>  	if (rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (!ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -260,15 +255,15 @@ test_invalid_actions(void)
>  	actions[0] = count_action;
>  	actions[1] = end_action_bad;
> 
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
>  	if (rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (!ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -462,15 +457,15 @@ test_query_udp(void)
>  	actions[0] = count_action;
>  	actions[1] = end_action;
> 
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
>  	if (!rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should not have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
>  			rule, &udp_classify_stats);
>  	if (ret) {
>  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> 478,7 +473,7 @@ test_query_udp(void)
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -520,15 +515,15 @@ test_query_tcp(void)
>  	actions[0] = count_action;
>  	actions[1] = end_action;
> 
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
>  	if (!rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should not have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
>  			rule, &tcp_classify_stats);
>  	if (ret) {
>  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> 536,7 +531,7 @@ test_query_tcp(void)
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -578,15 +573,15 @@ test_query_sctp(void)
>  	actions[0] = count_action;
>  	actions[1] = end_action;
> 
> -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> -			&attr, pattern, actions, &error);
> +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> +			actions, &key_found, &error);
>  	if (!rule) {
>  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
>  		printf(" should not have failed!\n");
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
>  			rule, &sctp_classify_stats);
>  	if (ret) {
>  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> 594,7 +589,7 @@ test_query_sctp(void)
>  		return -1;
>  	}
> 
> -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
>  	if (ret) {
>  		printf("Line %i: rte_flow_classify_table_entry_delete",
>  			__LINE__);
> @@ -622,7 +617,6 @@ test_flow_classify(void)
> 
>  	cls_params.name = "flow_classifier";
>  	cls_params.socket_id = socket_id;
> -	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
>  	cls->cls = rte_flow_classifier_create(&cls_params);
> 
>  	/* initialise ACL table params */
> @@ -632,11 +626,11 @@ test_flow_classify(void)
>  	memcpy(table_acl_params.field_format, ipv4_defs,
> sizeof(ipv4_defs));
> 
>  	/* initialise table create params */
> -	cls_table_params.ops = &rte_table_acl_ops,
> -	cls_table_params.arg_create = &table_acl_params,
> +	cls_table_params.ops = &rte_table_acl_ops;
> +	cls_table_params.arg_create = &table_acl_params;
> +	cls_table_params.type =
> RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> 
> -	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
> -			&cls->table_id[0]);
> +	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
>  	if (ret) {
>  		printf("Line %i: f_create has failed!\n", __LINE__);
>  		rte_flow_classifier_free(cls->cls);
> diff --git a/test/test/test_flow_classify.h b/test/test/test_flow_classify.h
> index 39535cf..af293ed 100644
> --- a/test/test/test_flow_classify.h
> +++ b/test/test/test_flow_classify.h
> @@ -197,7 +197,15 @@ static struct rte_flow_item  sctp_item_1 = {
> RTE_FLOW_ITEM_TYPE_SCTP,
>  /* test actions:
>   * "actions count / end"
>   */
> -static struct rte_flow_action count_action = {
> RTE_FLOW_ACTION_TYPE_COUNT, 0};
> +struct rte_flow_query_count count = {
> +	.reset = 1,
> +	.hits_set = 1,
> +	.bytes_set = 1,
> +	.hits = 0,
> +	.bytes = 0,
> +};
> +static struct rte_flow_action count_action = {
> RTE_FLOW_ACTION_TYPE_COUNT,
> +	&count};
>  static struct rte_flow_action count_action_bad = { -1, 0};
> 
>  static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END,
> 0};
> --
> 2.9.3

This patch fails to apply to the 18.02 master branch, a rebase may be needed.

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification Jasvinder Singh
@ 2017-12-04 16:46   ` Iremonger, Bernard
  2017-12-05 11:01     ` Iremonger, Bernard
  0 siblings, 1 reply; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-04 16:46 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Thursday, November 23, 2017 11:32 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification
> 
> This patch extends the flow classification library by adding run api. This
> function classifies the packets based on the flow rules stored in the classifier
> table.
> During lookup operation, the table entry is identified on lookup hit and based
> on meta-data stored at table entry, actions are performed on the current
> packet.
> The meta-information about the actions stored in the table entry is
> determined from the actions fields specified in flow rules.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  lib/librte_flow_classify/rte_flow_classify.c       | 56
> ++++++++++++++++++++++
>  lib/librte_flow_classify/rte_flow_classify.h       | 24 ++++++++++
>  .../rte_flow_classify_version.map                  |  1 +
>  3 files changed, 81 insertions(+)
> 
> diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> b/lib/librte_flow_classify/rte_flow_classify.c
> index ff1bc86..5433bfe 100644
> --- a/lib/librte_flow_classify/rte_flow_classify.c
> +++ b/lib/librte_flow_classify/rte_flow_classify.c
> @@ -37,6 +37,9 @@
>  #include <rte_table_acl.h>
>  #include <stdbool.h>
> 
> +#define RTE_PKT_METADATA_PTR(pkt, offset)         \
> +		(&((uint32_t *)(pkt))[offset])
> +
>  int librte_flow_classify_logtype;
> 
>  static uint32_t unique_id = 1;
> @@ -674,6 +677,59 @@ action_apply(struct rte_flow_classifier *cls,  }
> 
>  int
> +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> +	struct rte_mbuf **pkts,
> +	const uint16_t nb_pkts,
> +	uint32_t pkt_offset)
> +{
> +	struct rte_flow_action_mark *mark;
> +	struct classify_action *action;
> +	uint64_t pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> +	uint64_t action_mask;
> +	uint32_t *ptr, i, j;
> +	int ret = -EINVAL;
> +
> +	if (!cls || !pkts  || nb_pkts == 0)
> +		return ret;
> +
> +	for (i = 0; i < cls->num_tables; i++) {
> +		if (cls->table_mask & (1LU << i)) {
> +			struct rte_cls_table *table = &cls->tables[i];
> +			uint64_t lookup_hit_mask;
> +
> +			ret = table->ops.f_lookup(table->h_table,
> +				pkts, pkts_mask, &lookup_hit_mask,
> +				(void **)cls->entries);
> +			if (ret)
> +				return ret;
> +
> +			if (lookup_hit_mask) {
> +				for (j = 0; j < nb_pkts; j++) {
> +					uint64_t pkt_mask = 1LLU << j;
> +
> +					if ((lookup_hit_mask & pkt_mask) ==
> 0)
> +						continue;
> +					/* Meta-data */
> +					enum rte_flow_action_type act_type
> =
> +
> 	RTE_FLOW_ACTION_TYPE_MARK;
> +					action = &cls->entries[j]->action;
> +					action_mask = action->action_mask;
> +
> +					if (action_mask & (1LLU << act_type))
> {
> +						mark = &action->act.mark;
> +						ptr =
> RTE_PKT_METADATA_PTR(
> +							pkts[j], pkt_offset);
> +						*ptr = mark->id;
> +					}
> +				}
> +			}
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +int
>  rte_flow_classifier_query(struct rte_flow_classifier *cls,
>  		struct rte_mbuf **pkts,
>  		const uint16_t nb_pkts,
> diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> b/lib/librte_flow_classify/rte_flow_classify.h
> index b9b669f..b74bd11 100644
> --- a/lib/librte_flow_classify/rte_flow_classify.h
> +++ b/lib/librte_flow_classify/rte_flow_classify.h
> @@ -273,6 +273,30 @@ rte_flow_classify_table_entry_delete(struct
> rte_flow_classifier *cls,
>  		struct rte_flow_classify_rule *rule);
> 
>  /**
> + * Flow classifier run.
> + *
> + * As a result of lookup operation, flow classifer idenfies the
> + * table entries that are hit and executes the actions on the packets.
> + *
> + * @param[in] cls
> + *   Flow classifier handle
> + * @param[in] pkts
> + *   Pointer to packets to process
> + * @param[in] nb_pkts
> + *   Number of packets to process
> + * @param[in] pkt_offset
> + *    Offset to store action metadata in the mbuf headroom
> + *
> + * @return
> + *   0 on success, error code otherwise.
> + */
> +int
> +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> +		struct rte_mbuf **pkts,
> +		const uint16_t nb_pkts,
> +		uint32_t pkt_offset);
> +
> +/**
>   * Query flow classifier for given rule.
>   *
>   * @param[in] cls
> diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map
> b/lib/librte_flow_classify/rte_flow_classify_version.map
> index 49bc25c..b51cb1a 100644
> --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> @@ -4,6 +4,7 @@ EXPERIMENTAL {
>  	rte_flow_classifier_create;
>  	rte_flow_classifier_free;
>  	rte_flow_classifier_query;
> +	rte_flow_classifier_run;
>  	rte_flow_classify_table_create;
>  	rte_flow_classify_table_entry_add;
>  	rte_flow_classify_table_entry_delete;
> --
> 2.9.3

This patch fails to apply to the 18.02 master branch, a rebase may be needed.

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-04 16:45 ` [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Iremonger, Bernard
@ 2017-12-05 10:59   ` Iremonger, Bernard
  2017-12-06 12:34     ` Iremonger, Bernard
  0 siblings, 1 reply; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-05 10:59 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Iremonger, Bernard
> Sent: Monday, December 4, 2017 4:45 PM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id
> parameter from apis
> 
> Hi Jasvinder,
> 
> > -----Original Message-----
> > From: Singh, Jasvinder
> > Sent: Thursday, November 23, 2017 11:32 AM
> > To: dev@dpdk.org
> > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > Subject: [PATCH 1/3] lib/librte_flow_classify: remove table id
> > parameter from apis
> >
> > This patch removes table id parameter from all the flow classify apis
> > to reduce the complexity and and does some cleanup of the code.
> >
> > The validate api has been exposed as public api to allows user to
> > validate the flow before adding it to the classifier.
> >
> > The sample app and unit tests have been updated to accomodate the apis
> > changes.
> >
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > ---
> >  examples/flow_classify/flow_classify.c             |  27 +-
> >  lib/librte_flow_classify/rte_flow_classify.c       | 320 +++++++++++----------
> >  lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
> >  lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
> > lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
> >  .../rte_flow_classify_version.map                  |   1 +
> >  test/test/test_flow_classify.c                     |  86 +++---
> >  test/test/test_flow_classify.h                     |  10 +-
> >  8 files changed, 365 insertions(+), 287 deletions(-)
> >
> > diff --git a/examples/flow_classify/flow_classify.c
> > b/examples/flow_classify/flow_classify.c
> > index 766f1dd..37e6904 100644
> > --- a/examples/flow_classify/flow_classify.c
> > +++ b/examples/flow_classify/flow_classify.c
> > @@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default =
> > {
> >
> >  struct flow_classifier {
> >  	struct rte_flow_classifier *cls;
> > -	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
> >  };
> >
> >  struct flow_classifier_acl {
> > @@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = {
> > RTE_FLOW_ITEM_TYPE_END,
> >  /* sample actions:
> >   * "actions count / end"
> >   */
> > -static struct rte_flow_action count_action = {
> > RTE_FLOW_ACTION_TYPE_COUNT, 0};
> > +struct rte_flow_query_count count = {
> > +	.reset = 1,
> > +	.hits_set = 1,
> > +	.bytes_set = 1,
> > +	.hits = 0,
> > +	.bytes = 0,
> > +};
> > +static struct rte_flow_action count_action = {
> > RTE_FLOW_ACTION_TYPE_COUNT,
> > +	&count};
> >  static struct rte_flow_action end_action = {
> > RTE_FLOW_ACTION_TYPE_END, 0};  static struct rte_flow_action
> > actions[2];
> >
> > @@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
> >  	int i = 0;
> >
> >  	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
> > -			cls_app->table_id[0], rules[7]);
> > +			rules[7]);
> >  	if (ret)
> >  		printf("table_entry_delete failed [7] %d\n\n", ret);
> >  	else
> > @@ -317,7 +324,6 @@ lcore_main(struct flow_classifier *cls_app)
> >  				if (rules[i]) {
> >  					ret = rte_flow_classifier_query(
> >  						cls_app->cls,
> > -						cls_app->table_id[0],
> >  						bufs, nb_rx, rules[i],
> >  						&classify_stats);
> >  					if (ret)
> > @@ -635,8 +641,8 @@ add_classify_rule(struct rte_eth_ntuple_filter
> > *ntuple_filter,
> >  	actions[1] = end_action;
> >
> >  	rule = rte_flow_classify_table_entry_add(
> > -			cls_app->cls, cls_app->table_id[0], &key_found,
> > -			&attr, pattern_ipv4_5tuple, actions, &error);
> > +			cls_app->cls, &attr, pattern_ipv4_5tuple,
> > +			actions, &key_found, &error);
> >  	if (rule == NULL) {
> >  		printf("table entry add failed ipv4_proto = %u\n",
> >  			ipv4_proto);
> > @@ -809,7 +815,6 @@ main(int argc, char *argv[])
> >
> >  	cls_params.name = "flow_classifier";
> >  	cls_params.socket_id = socket_id;
> > -	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> >
> >  	cls_app->cls = rte_flow_classifier_create(&cls_params);
> >  	if (cls_app->cls == NULL) {
> > @@ -824,11 +829,11 @@ main(int argc, char *argv[])
> >  	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
> >
> >  	/* initialise table create params */
> > -	cls_table_params.ops = &rte_table_acl_ops,
> > -	cls_table_params.arg_create = &table_acl_params,
> > +	cls_table_params.ops = &rte_table_acl_ops;
> > +	cls_table_params.arg_create = &table_acl_params;
> > +	cls_table_params.type =
> > RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> >
> > -	ret = rte_flow_classify_table_create(cls_app->cls,
> > &cls_table_params,
> > -			&cls_app->table_id[0]);
> > +	ret = rte_flow_classify_table_create(cls_app->cls,
> > &cls_table_params);
> >  	if (ret) {
> >  		rte_flow_classifier_free(cls_app->cls);
> >  		rte_free(cls_app);
> > diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> > b/lib/librte_flow_classify/rte_flow_classify.c
> > index e6f4486..ff1bc86 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify.c
> > +++ b/lib/librte_flow_classify/rte_flow_classify.c
> > @@ -39,16 +39,20 @@
> >
> >  int librte_flow_classify_logtype;
> >
> > -static struct rte_eth_ntuple_filter ntuple_filter;  static uint32_t
> > unique_id = 1;
> >
> > +enum rte_flow_classify_table_type table_type
> > +	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
> >
> >  struct rte_flow_classify_table_entry {
> >  	/* meta-data for classify rule */
> >  	uint32_t rule_id;
> > +
> > +	/* Flow action */
> > +	struct classify_action action;
> >  };
> >
> > -struct rte_table {
> > +struct rte_cls_table {
> >  	/* Input parameters */
> >  	struct rte_table_ops ops;
> >  	uint32_t entry_size;
> > @@ -64,11 +68,16 @@ struct rte_flow_classifier {
> >  	/* Input parameters */
> >  	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
> >  	int socket_id;
> > -	enum rte_flow_classify_table_type type;
> >
> > -	/* Internal tables */
> > -	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > +	/* Internal */
> > +	/* ntuple_fliter */
> > +	struct rte_eth_ntuple_filter ntuple_filter;
> > +
> > +	/* clasifier tables */
> > +	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > +	uint32_t table_mask;
> >  	uint32_t num_tables;
> > +
> >  	uint16_t nb_pkts;
> >  	struct rte_flow_classify_table_entry
> >  		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
> > @@ -97,18 +106,19 @@ struct classify_rules {
> >
> >  struct rte_flow_classify_rule {
> >  	uint32_t id; /* unique ID of classify rule */
> > -	struct rte_flow_action action; /* action when match found */
> > +	enum rte_flow_classify_table_type tbl_type; /* rule table */
> >  	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 */
> > +	struct rte_flow_classify_table_entry entry;  /* rule meta data */
> >  	void *entry_ptr; /* handle to the table entry for rule meta data */
> > };
> >
> > -static int
> > -flow_classify_parse_flow(
> > +int
> > +rte_flow_classify_validate(
> > +		   struct rte_flow_classifier *cls,
> >  		   const struct rte_flow_attr *attr,
> >  		   const struct rte_flow_item pattern[],
> >  		   const struct rte_flow_action actions[], @@ -120,7 +130,42
> @@
> > flow_classify_parse_flow(
> >  	uint32_t i = 0;
> >  	int ret;
> >
> > -	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
> > +	if (cls == NULL) {
> > +		RTE_FLOW_CLASSIFY_LOG(ERR,
> > +			"%s: rte_flow_classifier parameter is NULL\n",
> > +			__func__);
> > +		return -EINVAL;
> > +	}
> > +
> > +	if (!attr) {
> > +		rte_flow_error_set(error, EINVAL,
> > +				   RTE_FLOW_ERROR_TYPE_ATTR,
> > +				   NULL, "NULL attribute.");
> > +		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 (!error) {
> > +		rte_flow_error_set(error, EINVAL,
> > +				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > +				   NULL, "NULL error.");
> > +		return -EINVAL;
> > +	}
> > +
> > +	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
> >
> >  	/* Get the non-void item number of pattern */
> >  	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { @@ -
> > 150,7 +195,7 @@ flow_classify_parse_flow(
> >  		return -EINVAL;
> >  	}
> >
> > -	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
> > +	ret = parse_filter(attr, items, actions, &cls->ntuple_filter,
> > +error);
> >  	free(items);
> >  	return ret;
> >  }
> > @@ -275,17 +320,14 @@ rte_flow_classifier_create(struct
> > rte_flow_classifier_params *params)
> >  	/* 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;
> > +	cls->socket_id = params->socket_id;
> >
> >  	return cls;
> >  }
> >
> >  static void
> > -rte_flow_classify_table_free(struct rte_table *table)
> > +rte_flow_classify_table_free(struct rte_cls_table *table)
> >  {
> >  	if (table->ops.f_free != NULL)
> >  		table->ops.f_free(table->h_table);
> > @@ -306,7 +348,7 @@ rte_flow_classifier_free(struct
> > rte_flow_classifier
> > *cls)
> >
> >  	/* Free tables */
> >  	for (i = 0; i < cls->num_tables; i++) {
> > -		struct rte_table *table = &cls->tables[i];
> > +		struct rte_cls_table *table = &cls->tables[i];
> >
> >  		rte_flow_classify_table_free(table);
> >  	}
> > @@ -319,8 +361,7 @@ rte_flow_classifier_free(struct
> > rte_flow_classifier
> > *cls)
> >
> >  static int
> >  rte_table_check_params(struct rte_flow_classifier *cls,
> > -		struct rte_flow_classify_table_params *params,
> > -		uint32_t *table_id)
> > +		struct rte_flow_classify_table_params *params)
> >  {
> >  	if (cls == NULL) {
> >  		RTE_FLOW_CLASSIFY_LOG(ERR,
> > @@ -333,11 +374,6 @@ rte_table_check_params(struct rte_flow_classifier
> > *cls,
> >  			__func__);
> >  		return -EINVAL;
> >  	}
> > -	if (table_id == NULL) {
> > -		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is
> > NULL\n",
> > -			__func__);
> > -		return -EINVAL;
> > -	}
> >
> >  	/* ops */
> >  	if (params->ops == NULL) {
> > @@ -371,22 +407,18 @@ rte_table_check_params(struct
> > rte_flow_classifier *cls,
> >
> >  int
> >  rte_flow_classify_table_create(struct rte_flow_classifier *cls,
> > -	struct rte_flow_classify_table_params *params,
> > -	uint32_t *table_id)
> > +	struct rte_flow_classify_table_params *params)
> >  {
> > -	struct rte_table *table;
> > +	struct rte_cls_table *table;
> >  	void *h_table;
> > -	uint32_t entry_size, id;
> > +	uint32_t entry_size;
> >  	int ret;
> >
> >  	/* Check input arguments */
> > -	ret = rte_table_check_params(cls, params, table_id);
> > +	ret = rte_table_check_params(cls, params);
> >  	if (ret != 0)
> >  		return ret;
> >
> > -	id = cls->num_tables;
> > -	table = &cls->tables[id];
> > -
> >  	/* calculate table entry size */
> >  	entry_size = sizeof(struct rte_flow_classify_table_entry);
> >
> > @@ -400,8 +432,9 @@ rte_flow_classify_table_create(struct
> > rte_flow_classifier *cls,
> >  	}
> >
> >  	/* Commit current table to the classifier */
> > +	table = &cls->tables[cls->num_tables];
> > +	table->type = params->type;
> >  	cls->num_tables++;
> > -	*table_id = id;
> >
> >  	/* Save input parameters */
> >  	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops)); @@
> > -414,7 +447,7 @@ rte_flow_classify_table_create(struct
> > rte_flow_classifier *cls,  }
> >
> >  static struct rte_flow_classify_rule *
> > -allocate_acl_ipv4_5tuple_rule(void)
> > +allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
> >  {
> >  	struct rte_flow_classify_rule *rule;
> >  	int log_level;
> > @@ -427,45 +460,44 @@ allocate_acl_ipv4_5tuple_rule(void)
> >  	rule->id = unique_id++;
> >  	rule->rules.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.priority = cls->ntuple_filter.priority;
> >  	rule-
> > >u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
> > -			ntuple_filter.proto_mask;
> > +			cls->ntuple_filter.proto_mask;
> >  	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
> > -			ntuple_filter.proto;
> > -	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
> > -	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
> > +			cls->ntuple_filter.proto;
> > +	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
> > +	rule->rules.u.ipv4_5tuple.proto_mask = cls-
> > >ntuple_filter.proto_mask;
> >
> >  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32
> > =
> > -			ntuple_filter.src_ip_mask;
> > +			cls->ntuple_filter.src_ip_mask;
> >  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
> > -			ntuple_filter.src_ip;
> > -	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
> > -	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
> > +			cls->ntuple_filter.src_ip;
> > +	rule->rules.u.ipv4_5tuple.src_ip_mask = cls-
> > >ntuple_filter.src_ip_mask;
> > +	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
> >
> >  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32
> > =
> > -			ntuple_filter.dst_ip_mask;
> > +			cls->ntuple_filter.dst_ip_mask;
> >  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
> > -			ntuple_filter.dst_ip;
> > -	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
> > -	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
> > +			cls->ntuple_filter.dst_ip;
> > +	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls-
> > >ntuple_filter.dst_ip_mask;
> > +	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
> >
> >  	rule-
> > >u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
> > -			ntuple_filter.src_port_mask;
> > +			cls->ntuple_filter.src_port_mask;
> >  	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
> > -			ntuple_filter.src_port;
> > -	rule->rules.u.ipv4_5tuple.src_port_mask =
> > ntuple_filter.src_port_mask;
> > -	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
> > +			cls->ntuple_filter.src_port;
> > +	rule->rules.u.ipv4_5tuple.src_port_mask =
> > +			cls->ntuple_filter.src_port_mask;
> > +	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
> >
> >  	rule-
> > >u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
> > -			ntuple_filter.dst_port_mask;
> > +			cls->ntuple_filter.dst_port_mask;
> >  	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
> > -			ntuple_filter.dst_port;
> > -	rule->rules.u.ipv4_5tuple.dst_port_mask =
> > ntuple_filter.dst_port_mask;
> > -	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
> > +			cls->ntuple_filter.dst_port;
> > +	rule->rules.u.ipv4_5tuple.dst_port_mask =
> > +			cls->ntuple_filter.dst_port_mask;
> > +	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
> >
> >  	log_level = rte_log_get_level(librte_flow_classify_logtype);
> >
> > @@ -485,34 +517,18 @@ allocate_acl_ipv4_5tuple_rule(void)
> >
> >  struct rte_flow_classify_rule *
> >  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> > -		uint32_t table_id,
> > -		int *key_found,
> >  		const struct rte_flow_attr *attr,
> >  		const struct rte_flow_item pattern[],
> >  		const struct rte_flow_action actions[],
> > +		int *key_found,
> >  		struct rte_flow_error *error)
> >  {
> >  	struct rte_flow_classify_rule *rule;
> >  	struct rte_flow_classify_table_entry *table_entry;
> > +	struct classify_action *action;
> > +	uint32_t i;
> >  	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 (key_found == NULL) {
> >  		rte_flow_error_set(error, EINVAL,
> >  				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > @@ -520,91 +536,95 @@ rte_flow_classify_table_entry_add(struct
> > rte_flow_classifier *cls,
> >  		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 = flow_classify_parse_flow(attr, pattern, actions, error);
> > +	ret = rte_flow_classify_validate(cls, attr, pattern, actions,
> > +error);
> >  	if (ret < 0)
> >  		return NULL;
> >
> > -	switch (cls->type) {
> > -	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
> > -		rule = allocate_acl_ipv4_5tuple_rule();
> > +	switch (table_type) {
> > +	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
> > +		rule = allocate_acl_ipv4_5tuple_rule(cls);
> >  		if (!rule)
> >  			return NULL;
> > +		rule->tbl_type = table_type;
> > +		cls->table_mask |= table_type;
> >  		break;
> >  	default:
> >  		return NULL;
> >  	}
> >
> > -	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
> > -	if (!rule->entry) {
> > -		free(rule);
> > -		return NULL;
> > -	}
> > -
> > -	table_entry = rule->entry;
> > +	action = classify_get_flow_action();
> > +	table_entry = &rule->entry;
> >  	table_entry->rule_id = rule->id;
> > +	table_entry->action.action_mask = action->action_mask;
> >
> > -	if (cls->tables[table_id].ops.f_add != NULL) {
> > -		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);
> > -			return NULL;
> > +	/* Copy actions */
> > +	if (action->action_mask & (1LLU <<
> > RTE_FLOW_ACTION_TYPE_COUNT)) {
> > +		memcpy(&table_entry->action.act.counter, &action-
> > >act.counter,
> > +				sizeof(table_entry->action.act.counter));
> > +	}
> > +	if (action->action_mask & (1LLU <<
> > RTE_FLOW_ACTION_TYPE_MARK)) {
> > +		memcpy(&table_entry->action.act.mark, &action->act.mark,
> > +				sizeof(table_entry->action.act.mark));
> > +	}
> > +
> > +	for (i = 0; i < cls->num_tables; i++) {
> > +		struct rte_cls_table *table = &cls->tables[i];
> > +
> > +		if (table->type == table_type) {
> > +			if (table->ops.f_add != NULL) {
> > +				ret = table->ops.f_add(
> > +					table->h_table,
> > +					&rule->u.key.key_add,
> > +					&rule->entry,
> > +					&rule->key_found,
> > +					&rule->entry_ptr);
> > +				if (ret) {
> > +					free(rule);
> > +					return NULL;
> > +				}
> > +
> > +			*key_found = rule->key_found;
> > +			}
> > +
> > +			return rule;
> >  		}
> > -		*key_found = rule->key_found;
> >  	}
> > -	return rule;
> > +	return NULL;
> >  }
> >
> >  int
> >  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> > -		uint32_t table_id,
> >  		struct rte_flow_classify_rule *rule)  {
> > +	uint32_t i;
> >  	int ret = -EINVAL;
> >
> > -	if (!cls || !rule || table_id >= cls->num_tables)
> > +	if (!cls || !rule)
> >  		return ret;
> > +	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
> >
> > -	if (cls->tables[table_id].ops.f_delete != NULL)
> > -		ret = cls->tables[table_id].ops.f_delete(
> > -			cls->tables[table_id].h_table,
> > -			&rule->u.key.key_del,
> > -			&rule->key_found,
> > -			&rule->entry);
> > +	for (i = 0; i < cls->num_tables; i++) {
> > +		struct rte_cls_table *table = &cls->tables[i];
> >
> > +		if (table->type == tbl_type) {
> > +			if (table->ops.f_delete != NULL) {
> > +				ret = table->ops.f_delete(table->h_table,
> > +						&rule->u.key.key_del,
> > +						&rule->key_found,
> > +						&rule->entry);
> > +
> > +				return ret;
> > +			}
> > +		}
> > +	}
> > +	free(rule);
> >  	return ret;
> >  }
> >
> >  static int
> >  flow_classifier_lookup(struct rte_flow_classifier *cls,
> > -		uint32_t table_id,
> > +		struct rte_cls_table *table,
> >  		struct rte_mbuf **pkts,
> >  		const uint16_t nb_pkts)
> >  {
> > @@ -613,8 +633,7 @@ flow_classifier_lookup(struct rte_flow_classifier *cls,
> >  	uint64_t lookup_hit_mask;
> >
> >  	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> > -	ret = cls->tables[table_id].ops.f_lookup(
> > -		cls->tables[table_id].h_table,
> > +	ret = table->ops.f_lookup(table->h_table,
> >  		pkts, pkts_mask, &lookup_hit_mask,
> >  		(void **)cls->entries);
> >
> > @@ -632,12 +651,12 @@ action_apply(struct rte_flow_classifier *cls,
> >  		struct rte_flow_classify_stats *stats)  {
> >  	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
> > +	struct rte_flow_classify_table_entry *entry = &rule->entry;
> >  	uint64_t count = 0;
> > -	int i;
> > -	int ret = -EINVAL;
> > +	uint32_t action_mask = entry->action.action_mask;
> > +	int i, ret = -EINVAL;
> >
> > -	switch (rule->action.type) {
> > -	case RTE_FLOW_ACTION_TYPE_COUNT:
> > +	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
> >  		for (i = 0; i < cls->nb_pkts; i++) {
> >  			if (rule->id == cls->entries[i]->rule_id)
> >  				count++;
> > @@ -650,32 +669,37 @@ action_apply(struct rte_flow_classifier *cls,
> >  			ntuple_stats->counter1 = count;
> >  			ntuple_stats->ipv4_5tuple = rule-
> > >rules.u.ipv4_5tuple;
> >  		}
> > -		break;
> > -	default:
> > -		ret = -ENOTSUP;
> > -		break;
> >  	}
> > -
> >  	return ret;
> >  }
> >
> >  int
> >  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > -		uint32_t table_id,
> >  		struct rte_mbuf **pkts,
> >  		const uint16_t nb_pkts,
> >  		struct rte_flow_classify_rule *rule,
> >  		struct rte_flow_classify_stats *stats)  {
> > +	enum rte_flow_classify_table_type tbl_type;
> > +	uint32_t i;
> >  	int ret = -EINVAL;
> >
> > -	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
> > -		table_id >= cls->num_tables)
> > +	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
> >  		return ret;
> >
> > -	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
> > -	if (!ret)
> > -		ret = action_apply(cls, rule, stats);
> > +	tbl_type = rule->tbl_type;
> > +	for (i = 0; i < cls->num_tables; i++) {
> > +		struct rte_cls_table *table = &cls->tables[i];
> > +
> > +			if (table->type == tbl_type) {
> > +				ret = flow_classifier_lookup(cls, table,
> > +						pkts, nb_pkts);
> > +				if (!ret) {
> > +					ret = action_apply(cls, rule, stats);
> > +					return ret;
> > +				}
> > +			}
> > +	}
> >  	return ret;
> >  }
> >
> > diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> > b/lib/librte_flow_classify/rte_flow_classify.h
> > index 1211873..b9b669f 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify.h
> > +++ b/lib/librte_flow_classify/rte_flow_classify.h
> > @@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
> > rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
> >  	__func__, ## args)
> >
> > +#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
> > +#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
> > +#endif
> > +
> >  /** Opaque data type for flow classifier */  struct
> > rte_flow_classifier;
> >
> > @@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
> >
> >  /** Flow classify table type */
> >  enum rte_flow_classify_table_type {
> > -	/** no type */
> > -	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
> > -	/** ACL type */
> > -	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
> > -};
> > +	/** No type */
> > +	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
> > +	/** ACL IP4 5TUPLE */
> > +	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
> > +	/** ACL VLAN IP4 5TUPLE */
> > +	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
> > +	/** ACL QinQ IP4 5TUPLE */
> > +	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
> >
> > -/**
> > - * Maximum number of tables allowed for any Flow Classifier instance.
> > - * The value of this parameter cannot be changed.
> > - */
> > -#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
> > +};
> >
> >  /** Parameters for flow classifier creation */  struct
> > rte_flow_classifier_params { @@ -122,9 +125,6 @@ struct
> > rte_flow_classifier_params {
> >  	/** 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;
> >  };
> >
> >  /** Parameters for table creation */
> > @@ -134,6 +134,9 @@ struct rte_flow_classify_table_params {
> >
> >  	/** Opaque param to be passed to the table create operation */
> >  	void *arg_create;
> > +
> > +	/** Classifier table type */
> > +	enum rte_flow_classify_table_type type;
> >  };
> >
> >  /** IPv4 5-tuple data */
> > @@ -197,32 +200,50 @@ rte_flow_classifier_free(struct
> > rte_flow_classifier *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);
> > +		struct rte_flow_classify_table_params *params);
> > +
> > +/**
> > + * Flow classify validate
> > + *
> > + * @param cls
> > + *   Handle to flow classifier instance
> > + * @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(struct rte_flow_classifier *cls,
> > +		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[out] key_found
> > - *  returns 1 if key present already, 0 otherwise.
> >   * @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] key_found
> > + *  returns 1 if rule present already, 0 otherwise.
> >   * @param[out] error
> >   *   Perform verbose error reporting if not NULL. Structure
> >   *   initialised in case of error only.
> > @@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct
> > rte_flow_classifier *cls,
> >   */
> >  struct rte_flow_classify_rule *
> >  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> > -		uint32_t table_id,
> > -		int *key_found,
> >  		const struct rte_flow_attr *attr,
> >  		const struct rte_flow_item pattern[],
> >  		const struct rte_flow_action actions[],
> > +		int *key_found,
> >  		struct rte_flow_error *error);
> >
> >  /**
> > @@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct
> > rte_flow_classifier *cls,
> >   *
> >   * @param[in] cls
> >   *   Flow classifier handle
> > - * @param[in] table_id
> > - *   id of table
> >   * @param[in] rule
> >   *   Flow classify rule
> >   * @return
> > @@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct
> > rte_flow_classifier *cls,
> >   */
> >  int
> >  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> > -		uint32_t table_id,
> >  		struct rte_flow_classify_rule *rule);
> >
> >  /**
> > @@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct
> > rte_flow_classifier *cls,
> >   *
> >   * @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
> > @@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct
> > rte_flow_classifier *cls,
> >   */
> >  int
> >  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > -		uint32_t table_id,
> >  		struct rte_mbuf **pkts,
> >  		const uint16_t nb_pkts,
> >  		struct rte_flow_classify_rule *rule, diff --git
> > a/lib/librte_flow_classify/rte_flow_classify_parse.c
> > b/lib/librte_flow_classify/rte_flow_classify_parse.c
> > index dbfa111..9fb3e51 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify_parse.c
> > +++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
> > @@ -40,7 +40,7 @@ struct classify_valid_pattern {
> >  	parse_filter_t parse_filter;
> >  };
> >
> > -static struct rte_flow_action action;
> > +static struct classify_action action;
> >
> >  /* Pattern for IPv4 5-tuple UDP filter */  static enum
> > rte_flow_item_type pattern_ntuple_1[] = { @@ -80,7 +80,7 @@ static
> > struct classify_valid_pattern classify_supported_patterns[] = {
> >  	{ pattern_ntuple_3, classify_parse_ntuple_filter },  };
> >
> > -struct rte_flow_action *
> > +struct classify_action *
> >  classify_get_flow_action(void)
> >  {
> >  	return &action;
> > @@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct
> > rte_flow_attr *attr,
> >  	const struct rte_flow_item_udp *udp_mask;
> >  	const struct rte_flow_item_sctp *sctp_spec;
> >  	const struct rte_flow_item_sctp *sctp_mask;
> > +	const struct rte_flow_action_count *count;
> > +	const struct rte_flow_action_mark *mark_spec;
> >  	uint32_t index;
> >
> > -	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;
> > -	}
> > -
> >  	/* parse pattern */
> >  	index = 0;
> >
> > @@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct
> > rte_flow_attr *attr,
> >  		return -EINVAL;
> >  	}
> >
> > -	/* parse action */
> > -	index = 0;
> > -
> > -	/**
> > -	 * n-tuple only supports count,
> > -	 * check if the first not void action is COUNT.
> > -	 */
> > -	memset(&action, 0, sizeof(action));
> > -	NEXT_ITEM_OF_ACTION(act, actions, index);
> > -	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
> > -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > -		rte_flow_error_set(error, EINVAL,
> > -			RTE_FLOW_ERROR_TYPE_ACTION,
> > -			item, "Not supported action.");
> > -		return -EINVAL;
> > -	}
> > -	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
> > -
> > -	/* check if the next not void item is END */
> > -	index++;
> > -	NEXT_ITEM_OF_ACTION(act, actions, index);
> > -	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> > -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > -		rte_flow_error_set(error, EINVAL,
> > -			RTE_FLOW_ERROR_TYPE_ACTION,
> > -			act, "Not supported action.");
> > -		return -EINVAL;
> > -	}
> > +	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> >
> >  	/* parse attr */
> >  	/* must be input direction */
> > @@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct
> > rte_flow_attr *attr,
> >  	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
> >  		filter->priority = FLOW_RULE_MAX_PRIORITY;
> >
> > +	/* parse action */
> > +	index = 0;
> > +
> > +	/**
> > +	 * n-tuple only supports count and Mark,
> > +	 * check if the first not void action is COUNT or MARK.
> > +	 */
> > +	memset(&action, 0, sizeof(action));
> > +	NEXT_ITEM_OF_ACTION(act, actions, index);
> > +	switch (act->type) {
> > +	case RTE_FLOW_ACTION_TYPE_COUNT:
> > +		action.action_mask |= 1LLU <<
> > RTE_FLOW_ACTION_TYPE_COUNT;
> > +		count = (const struct rte_flow_action_count *)act->conf;
> > +		memcpy(&action.act.counter, count,
> > sizeof(action.act.counter));
> > +		break;
> > +	case RTE_FLOW_ACTION_TYPE_MARK:
> > +		action.action_mask |= 1LLU <<
> > RTE_FLOW_ACTION_TYPE_MARK;
> > +		mark_spec = (const struct rte_flow_action_mark *)act-
> > >conf;
> > +		memcpy(&action.act.mark, mark_spec,
> > sizeof(action.act.mark));
> > +		break;
> > +	default:
> > +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > +		rte_flow_error_set(error, EINVAL,
> > +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> > +		   "Invalid action.");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* check if the next not void item is MARK or COUNT or END */
> > +	index++;
> > +	NEXT_ITEM_OF_ACTION(act, actions, index);
> > +	switch (act->type) {
> > +	case RTE_FLOW_ACTION_TYPE_COUNT:
> > +		action.action_mask |= 1LLU <<
> > RTE_FLOW_ACTION_TYPE_COUNT;
> > +		count = (const struct rte_flow_action_count *)act->conf;
> > +		memcpy(&action.act.counter, count,
> > sizeof(action.act.counter));
> > +		break;
> > +	case RTE_FLOW_ACTION_TYPE_MARK:
> > +		action.action_mask |= 1LLU <<
> > RTE_FLOW_ACTION_TYPE_MARK;
> > +		mark_spec = (const struct rte_flow_action_mark *)act-
> > >conf;
> > +		memcpy(&action.act.mark, mark_spec,
> > sizeof(action.act.mark));
> > +		break;
> > +	case RTE_FLOW_ACTION_TYPE_END:
> > +		return 0;
> > +	default:
> > +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > +		rte_flow_error_set(error, EINVAL,
> > +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> > +		   "Invalid action.");
> > +		return -EINVAL;
> > +	}
> > +
> > +	/* check if the next not void item is END */
> > +	index++;
> > +	NEXT_ITEM_OF_ACTION(act, actions, index);
> > +	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> > +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > +		rte_flow_error_set(error, EINVAL,
> > +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> > +		   "Invalid action.");
> > +		return -EINVAL;
> > +	}
> > +
> >  	return 0;
> >  }
> > diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h
> > b/lib/librte_flow_classify/rte_flow_classify_parse.h
> > index 1d4708a..9c1de72 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify_parse.h
> > +++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
> > @@ -43,6 +43,20 @@
> >  extern "C" {
> >  #endif
> >
> > +extern enum rte_flow_classify_table_type table_type;
> > +
> > +struct classify_action {
> > +	/* Flow action mask */
> > +	uint64_t action_mask;
> > +
> > +	struct action {
> > +		/** Integer value to return with packets */
> > +		struct rte_flow_action_mark mark;
> > +		/** Flow rule counter */
> > +		struct rte_flow_query_count counter;
> > +	} act;
> > +};
> > +
> >  typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
> >  			      const struct rte_flow_item pattern[],
> >  			      const struct rte_flow_action actions[], @@ -64,7
> > +78,7 @@ parse_filter_t  classify_find_parse_filter_func(struct
> > rte_flow_item *pattern);
> >
> >  /* get action data */
> > -struct rte_flow_action *
> > +struct classify_action *
> >  classify_get_flow_action(void);
> >
> >  #ifdef __cplusplus
> > diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map
> > b/lib/librte_flow_classify/rte_flow_classify_version.map
> > index f7695cb..49bc25c 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> > +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> > @@ -7,6 +7,7 @@ EXPERIMENTAL {
> >  	rte_flow_classify_table_create;
> >  	rte_flow_classify_table_entry_add;
> >  	rte_flow_classify_table_entry_delete;
> > +	rte_flow_classify_validate;
> >
> >  	local: *;
> >  };
> > diff --git a/test/test/test_flow_classify.c
> > b/test/test/test_flow_classify.c index 9f331cd..4ddf4c0 100644
> > --- a/test/test/test_flow_classify.c
> > +++ b/test/test/test_flow_classify.c
> > @@ -51,16 +51,10 @@
> >
> >
> >  #define FLOW_CLASSIFY_MAX_RULE_NUM 100 -struct flow_classifier *cls;
> > -
> > -struct flow_classifier {
> > -	struct rte_flow_classifier *cls;
> > -	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > -	uint32_t n_tables;
> > -};
> > +struct flow_classifier_acl *cls;
> >
> >  struct flow_classifier_acl {
> > -	struct flow_classifier cls;
> > +	struct rte_flow_classifier *cls;
> >  } __rte_cache_aligned;
> >
> >  /*
> > @@ -73,7 +67,7 @@ test_invalid_parameters(void)
> >  	struct rte_flow_classify_rule *rule;
> >  	int ret;
> >
> > -	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL,
> > NULL,
> > +	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
> >  			NULL, NULL);
> >  	if (rule) {
> >  		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
> @@
> > -81,7 +75,7 @@ test_invalid_parameters(void)
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
> > +	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
> >  	if (!ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -89,14 +83,14 @@ test_invalid_parameters(void)
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
> > +	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
> >  	if (!ret) {
> >  		printf("Line %i: flow_classifier_query", __LINE__);
> >  		printf(" with NULL param should have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL,
> > NULL,
> > +	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
> >  		NULL, &error);
> >  	if (rule) {
> >  		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
> @@
> > -104,7 +98,7 @@ test_invalid_parameters(void)
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
> > +	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
> >  	if (!ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -112,7 +106,7 @@ test_invalid_parameters(void)
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
> > +	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
> >  	if (!ret) {
> >  		printf("Line %i: flow_classifier_query", __LINE__);
> >  		printf(" with NULL param should have failed!\n"); @@ -
> > 142,15 +136,16 @@ test_valid_parameters(void)
> >  	actions[0] = count_action;
> >  	actions[1] = end_action;
> >
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> > +
> >  	if (!rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should not have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -183,15 +178,15 @@ test_invalid_patterns(void)
> >
> >  	pattern[0] = eth_item;
> >  	pattern[1] = ipv4_udp_item_bad;
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> >  	if (rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (!ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -202,15 +197,15 @@ test_invalid_patterns(void)
> >  	pattern[1] = ipv4_udp_item_1;
> >  	pattern[2] = udp_item_bad;
> >  	pattern[3] = end_item_bad;
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> >  	if (rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (!ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -241,15 +236,15 @@ test_invalid_actions(void)
> >  	actions[0] = count_action_bad;
> >  	actions[1] = end_action;
> >
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> >  	if (rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (!ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -260,15 +255,15 @@ test_invalid_actions(void)
> >  	actions[0] = count_action;
> >  	actions[1] = end_action_bad;
> >
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> >  	if (rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (!ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -462,15 +457,15 @@ test_query_udp(void)
> >  	actions[0] = count_action;
> >  	actions[1] = end_action;
> >
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> >  	if (!rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should not have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> > +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
> >  			rule, &udp_classify_stats);
> >  	if (ret) {
> >  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> > 478,7 +473,7 @@ test_query_udp(void)
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -520,15 +515,15 @@ test_query_tcp(void)
> >  	actions[0] = count_action;
> >  	actions[1] = end_action;
> >
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> >  	if (!rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should not have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> > +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
> >  			rule, &tcp_classify_stats);
> >  	if (ret) {
> >  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> > 536,7 +531,7 @@ test_query_tcp(void)
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -578,15 +573,15 @@ test_query_sctp(void)
> >  	actions[0] = count_action;
> >  	actions[1] = end_action;
> >
> > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > -			&attr, pattern, actions, &error);
> > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > +			actions, &key_found, &error);
> >  	if (!rule) {
> >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> >  		printf(" should not have failed!\n");
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> > +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
> >  			rule, &sctp_classify_stats);
> >  	if (ret) {
> >  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> > 594,7 +589,7 @@ test_query_sctp(void)
> >  		return -1;
> >  	}
> >
> > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> >  	if (ret) {
> >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> >  			__LINE__);
> > @@ -622,7 +617,6 @@ test_flow_classify(void)
> >
> >  	cls_params.name = "flow_classifier";
> >  	cls_params.socket_id = socket_id;
> > -	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> >  	cls->cls = rte_flow_classifier_create(&cls_params);
> >
> >  	/* initialise ACL table params */
> > @@ -632,11 +626,11 @@ test_flow_classify(void)
> >  	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
> >
> >  	/* initialise table create params */
> > -	cls_table_params.ops = &rte_table_acl_ops,
> > -	cls_table_params.arg_create = &table_acl_params,
> > +	cls_table_params.ops = &rte_table_acl_ops;
> > +	cls_table_params.arg_create = &table_acl_params;
> > +	cls_table_params.type =
> > RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> >
> > -	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
> > -			&cls->table_id[0]);
> > +	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
> >  	if (ret) {
> >  		printf("Line %i: f_create has failed!\n", __LINE__);
> >  		rte_flow_classifier_free(cls->cls);
> > diff --git a/test/test/test_flow_classify.h
> > b/test/test/test_flow_classify.h index 39535cf..af293ed 100644
> > --- a/test/test/test_flow_classify.h
> > +++ b/test/test/test_flow_classify.h
> > @@ -197,7 +197,15 @@ static struct rte_flow_item  sctp_item_1 = {
> > RTE_FLOW_ITEM_TYPE_SCTP,
> >  /* test actions:
> >   * "actions count / end"
> >   */
> > -static struct rte_flow_action count_action = {
> > RTE_FLOW_ACTION_TYPE_COUNT, 0};
> > +struct rte_flow_query_count count = {
> > +	.reset = 1,
> > +	.hits_set = 1,
> > +	.bytes_set = 1,
> > +	.hits = 0,
> > +	.bytes = 0,
> > +};
> > +static struct rte_flow_action count_action = {
> > RTE_FLOW_ACTION_TYPE_COUNT,
> > +	&count};
> >  static struct rte_flow_action count_action_bad = { -1, 0};
> >
> >  static struct rte_flow_action end_action = {
> > RTE_FLOW_ACTION_TYPE_END, 0};
> > --
> > 2.9.3
> 
> This patch fails to apply to the 18.02 master branch, a rebase may be needed.
> 
> Regards,
> 
> Bernard.

False alarm, the patch applies ok on a fresh checkout.

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification
  2017-12-04 16:46   ` Iremonger, Bernard
@ 2017-12-05 11:01     ` Iremonger, Bernard
  2017-12-06 12:41       ` Iremonger, Bernard
  0 siblings, 1 reply; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-05 11:01 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Iremonger, Bernard
> Sent: Monday, December 4, 2017 4:46 PM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow
> classification
> 
> Hi Jasvinder,
> 
> > -----Original Message-----
> > From: Singh, Jasvinder
> > Sent: Thursday, November 23, 2017 11:32 AM
> > To: dev@dpdk.org
> > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > Subject: [PATCH 2/3] lib/librte_flow_classy: add run api for flow
> > classification
> >
> > This patch extends the flow classification library by adding run api.
> > This function classifies the packets based on the flow rules stored in
> > the classifier table.
> > During lookup operation, the table entry is identified on lookup hit
> > and based on meta-data stored at table entry, actions are performed on
> > the current packet.
> > The meta-information about the actions stored in the table entry is
> > determined from the actions fields specified in flow rules.
> >
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > ---
> >  lib/librte_flow_classify/rte_flow_classify.c       | 56
> > ++++++++++++++++++++++
> >  lib/librte_flow_classify/rte_flow_classify.h       | 24 ++++++++++
> >  .../rte_flow_classify_version.map                  |  1 +
> >  3 files changed, 81 insertions(+)
> >
> > diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> > b/lib/librte_flow_classify/rte_flow_classify.c
> > index ff1bc86..5433bfe 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify.c
> > +++ b/lib/librte_flow_classify/rte_flow_classify.c
> > @@ -37,6 +37,9 @@
> >  #include <rte_table_acl.h>
> >  #include <stdbool.h>
> >
> > +#define RTE_PKT_METADATA_PTR(pkt, offset)         \
> > +		(&((uint32_t *)(pkt))[offset])
> > +
> >  int librte_flow_classify_logtype;
> >
> >  static uint32_t unique_id = 1;
> > @@ -674,6 +677,59 @@ action_apply(struct rte_flow_classifier *cls,  }
> >
> >  int
> > +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > +	struct rte_mbuf **pkts,
> > +	const uint16_t nb_pkts,
> > +	uint32_t pkt_offset)
> > +{
> > +	struct rte_flow_action_mark *mark;
> > +	struct classify_action *action;
> > +	uint64_t pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> > +	uint64_t action_mask;
> > +	uint32_t *ptr, i, j;
> > +	int ret = -EINVAL;
> > +
> > +	if (!cls || !pkts  || nb_pkts == 0)
> > +		return ret;
> > +
> > +	for (i = 0; i < cls->num_tables; i++) {
> > +		if (cls->table_mask & (1LU << i)) {
> > +			struct rte_cls_table *table = &cls->tables[i];
> > +			uint64_t lookup_hit_mask;
> > +
> > +			ret = table->ops.f_lookup(table->h_table,
> > +				pkts, pkts_mask, &lookup_hit_mask,
> > +				(void **)cls->entries);
> > +			if (ret)
> > +				return ret;
> > +
> > +			if (lookup_hit_mask) {
> > +				for (j = 0; j < nb_pkts; j++) {
> > +					uint64_t pkt_mask = 1LLU << j;
> > +
> > +					if ((lookup_hit_mask & pkt_mask) ==
> > 0)
> > +						continue;
> > +					/* Meta-data */
> > +					enum rte_flow_action_type act_type
> > =
> > +
> > 	RTE_FLOW_ACTION_TYPE_MARK;
> > +					action = &cls->entries[j]->action;
> > +					action_mask = action->action_mask;
> > +
> > +					if (action_mask & (1LLU << act_type))
> > {
> > +						mark = &action->act.mark;
> > +						ptr =
> > RTE_PKT_METADATA_PTR(
> > +							pkts[j], pkt_offset);
> > +						*ptr = mark->id;
> > +					}
> > +				}
> > +			}
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> > +int
> >  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> >  		struct rte_mbuf **pkts,
> >  		const uint16_t nb_pkts,
> > diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> > b/lib/librte_flow_classify/rte_flow_classify.h
> > index b9b669f..b74bd11 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify.h
> > +++ b/lib/librte_flow_classify/rte_flow_classify.h
> > @@ -273,6 +273,30 @@ rte_flow_classify_table_entry_delete(struct
> > rte_flow_classifier *cls,
> >  		struct rte_flow_classify_rule *rule);
> >
> >  /**
> > + * Flow classifier run.
> > + *
> > + * As a result of lookup operation, flow classifer idenfies the
> > + * table entries that are hit and executes the actions on the packets.
> > + *
> > + * @param[in] cls
> > + *   Flow classifier handle
> > + * @param[in] pkts
> > + *   Pointer to packets to process
> > + * @param[in] nb_pkts
> > + *   Number of packets to process
> > + * @param[in] pkt_offset
> > + *    Offset to store action metadata in the mbuf headroom
> > + *
> > + * @return
> > + *   0 on success, error code otherwise.
> > + */
> > +int
> > +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > +		struct rte_mbuf **pkts,
> > +		const uint16_t nb_pkts,
> > +		uint32_t pkt_offset);
> > +
> > +/**
> >   * Query flow classifier for given rule.
> >   *
> >   * @param[in] cls
> > diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map
> > b/lib/librte_flow_classify/rte_flow_classify_version.map
> > index 49bc25c..b51cb1a 100644
> > --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> > +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> > @@ -4,6 +4,7 @@ EXPERIMENTAL {
> >  	rte_flow_classifier_create;
> >  	rte_flow_classifier_free;
> >  	rte_flow_classifier_query;
> > +	rte_flow_classifier_run;
> >  	rte_flow_classify_table_create;
> >  	rte_flow_classify_table_entry_add;
> >  	rte_flow_classify_table_entry_delete;
> > --
> > 2.9.3
> 
> This patch fails to apply to the 18.02 master branch, a rebase may be needed.
> 
> Regards,
> 
> Bernard.

False alarm, the patch applies ok on a fresh checkout.

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib Jasvinder Singh
@ 2017-12-06 12:04   ` Iremonger, Bernard
  2017-12-11 14:54   ` Mcnamara, John
  1 sibling, 0 replies; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-06 12:04 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Thursday, November 23, 2017 11:32 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [PATCH 3/3] doc: update documentation for flow classify lib
> 
> Updates the documentation for flow classification library and sample
> application.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  doc/guides/prog_guide/flow_classify_lib.rst | 79 +++++++++++++++++-----------
> -  doc/guides/sample_app_ug/flow_classify.rst  |  8 +--
>  2 files changed, 49 insertions(+), 38 deletions(-)
> 
> diff --git a/doc/guides/prog_guide/flow_classify_lib.rst
> b/doc/guides/prog_guide/flow_classify_lib.rst
> index 820dc72..519117c 100644
> --- a/doc/guides/prog_guide/flow_classify_lib.rst
> +++ b/doc/guides/prog_guide/flow_classify_lib.rst
> @@ -101,30 +101,26 @@ The library has the following API's
>       *   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);
> +           struct rte_flow_classify_table_params *params);
> 
>      /**
>       * Add a flow classify rule to the flow_classifier 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] key_found
> +     *   returns 1 if rule present already, 0 otherwise.
>       * @param[out] error
>       *   Perform verbose error reporting if not NULL. Structure
>       *   initialised in case of error only.
> @@ -133,10 +129,10 @@ The library has the following API's
>       */
>      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[],
> +            int *key_found;
>              struct rte_flow_error *error);
> 
>      /**
> @@ -144,8 +140,6 @@ The library has the following API's
>       *
>       * @param[in] cls
>       *   Flow classifier handle
> -     * @param[in] table_id
> -     *   id of table
>       * @param[in] rule
>       *   Flow classify rule
>       * @return
> @@ -153,16 +147,37 @@ The library has the following API's
>       */
>      int
>      rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> -            uint32_t table_id,
>              struct rte_flow_classify_rule *rule);
> 
>      /**
> +     * Flow classifier run.
> +     *
> +     * As a result of lookup operation, flow classifer idenfies the
> +     * table entries that are hit and executes the actions on the packets.
> +     *
> +     * @param[in] cls
> +     *   Flow classifier handle
> +     * @param[in] pkts
> +     *   Pointer to packets to process
> +     * @param[in] nb_pkts
> +     *   Number of packets to process
> +     * @param[in] pkt_offset
> +     *    Offset to store action metadata in the mbuf headroom
> +     *
> +     * @return
> +     *   0 on success, error code otherwise.
> +     */
> +     int
> +     rte_flow_classifier_run(struct rte_flow_classifier *cls,
> +             struct rte_mbuf **pkts,
> +             const uint16_t nb_pkts,
> +             uint32_t pkt_offset);
> +
> +    /**
>       * Query flow classifier for given rule.
>       *
>       * @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
> @@ -177,7 +192,6 @@ The library has the following API's
>       */
>      int
>      rte_flow_classifier_query(struct rte_flow_classifier *cls,
> -            uint32_t table_id,
>              struct rte_mbuf **pkts,
>              const uint16_t nb_pkts,
>              struct rte_flow_classify_rule *rule, @@ -200,16 +214,13 @@ application
> before calling the API.
>          /** 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;
>      };
> 
>  The ``Classifier`` has the following internal structures:
> 
>  .. code-block:: c
> 
> -    struct rte_table {
> +    struct rte_cls_table {
>          /* Input parameters */
>          struct rte_table_ops ops;
>          uint32_t entry_size;
> @@ -225,11 +236,16 @@ The ``Classifier`` has the following internal structures:
>          /* Input parameters */
>          char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
>          int socket_id;
> -        enum rte_flow_classify_table_type type;
> 
> -        /* Internal tables */
> -        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +        /* Internal */
> +        /* ntuple_fliter */
> +        struct rte_eth_ntuple_filter ntuple_filter;
> +
> +        /* clasifier tables */
> +        struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +        uint32_t table_mask;
>          uint32_t num_tables;
> +
>          uint16_t nb_pkts;
>          struct rte_flow_classify_table_entry
>              *entries[RTE_PORT_IN_BURST_SIZE_MAX];
> @@ -252,9 +268,8 @@ application before calling the API.
>          /** 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;
> +        /** Classifier table type */
> +        enum rte_flow_classify_table_type type;
>       };
> 
>  To create an ACL table the ``rte_table_acl_params`` structure must be @@ -
> 321,7 +336,7 @@ IPv4 5-tuple pattern, attributes and actions and returns the 5-
> tuple data in the  .. code-block:: c
> 
>      static int
> -    flow_classify_parse_flow(
> +    flow_classify_parse_flow(struct rte_flow_classifier *cls,

This should be rte_flow_classify_validate now.

>                     const struct rte_flow_attr *attr,
>                     const struct rte_flow_item pattern[],
>                     const struct rte_flow_action actions[], @@ -355,24 +370,24 @@
> parses the Flow rule.
> 
>      struct rte_flow_classify {
>          uint32_t id;  /* unique ID of classify object */
> -        struct rte_flow_action action; /* action when match found */
> -	struct classify_rules rules; /* union of rules */
> +        enum rte_flow_classify_table_type tbl_type; /* rule table */
> +        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 */
> +        struct rte_flow_classify_table_entry entry;  /* rule meta data */
> +       void *entry_ptr; /* handle to the table entry for rule meta data
> + */
>      };
> 
> -It then calls the ``table[table_id].ops.f_add`` API to add the rule to the ACL
> +It then calls the ``table.ops.f_add`` API to add the rule to the ACL
>  table.
> 
>  Deleting Flow Rules
>  ~~~~~~~~~~~~~~~~~~~
> 
>  The ``rte_flow_classify_table_entry_delete`` API calls the -
> ``table[table_id].ops.f_delete`` API to delete a rule from the ACL table.
> +``table.ops.f_delete`` API to delete a rule from the ACL table.
> 
>  Packet Matching
>  ~~~~~~~~~~~~~~~
> @@ -380,7 +395,7 @@ Packet Matching
>  The ``rte_flow_classifier_query`` API is used to find packets which match a
> given flow Flow rule in the table.
>  This API calls the flow_classify_run internal function which calls the -
> ``table[table_id].ops.f_lookup`` API to see if any packets in a burst match any
> +``table.ops.f_lookup`` API to see if any packets in a burst match any
>  of the Flow rules in the table.
>  The meta data for the highest priority rule matched for each packet is returned
> in the entries array in the ``rte_flow_classify`` object.
> diff --git a/doc/guides/sample_app_ug/flow_classify.rst
> b/doc/guides/sample_app_ug/flow_classify.rst
> index bc12b87..427fded 100644
> --- a/doc/guides/sample_app_ug/flow_classify.rst
> +++ b/doc/guides/sample_app_ug/flow_classify.rst
> @@ -228,7 +228,6 @@ table`` to the flow classifier.
> 
>      struct flow_classifier {
>          struct rte_flow_classifier *cls;
> -        uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
>      };
> 
>      struct flow_classifier_acl {
> @@ -243,7 +242,6 @@ table`` to the flow classifier.
> 
>      cls_params.name = "flow_classifier";
>      cls_params.socket_id = socket_id;
> -    cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> 
>      cls_app->cls = rte_flow_classifier_create(&cls_params);
>      if (cls_app->cls == NULL) {
> @@ -260,10 +258,9 @@ table`` to the flow classifier.
>      /* initialise table create params */
>      cls_table_params.ops = &rte_table_acl_ops,
>      cls_table_params.arg_create = &table_acl_params,
> -    cls_table_params.table_metadata_size = 0;
> +    cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> 
> -    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
> -                  &cls->table_id[0]);
> +    ret = rte_flow_classify_table_create(cls_app->cls,
> + &cls_table_params);
>      if (ret) {
>          rte_flow_classifier_free(cls_app->cls);
>          rte_free(cls);
> @@ -495,7 +492,6 @@ following:
>                      if (rules[i]) {
>                          ret = rte_flow_classifier_query(
>                              cls_app->cls,
> -                            cls_app->table_id[0],
>                              bufs, nb_rx, rules[i],
>                              &classify_stats);
>                          if (ret)
> --
> 2.9.3

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-05 10:59   ` Iremonger, Bernard
@ 2017-12-06 12:34     ` Iremonger, Bernard
  2017-12-11 15:51       ` Singh, Jasvinder
  0 siblings, 1 reply; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-06 12:34 UTC (permalink / raw)
  To: Iremonger, Bernard, Singh, Jasvinder, dev

Hi Jasvinder,

> > > -----Original Message-----
> > > From: Singh, Jasvinder
> > > Sent: Thursday, November 23, 2017 11:32 AM
> > > To: dev@dpdk.org
> > > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > > Subject: [PATCH 1/3] lib/librte_flow_classify: remove table id
> > > parameter from apis
> > >
> > > This patch removes table id parameter from all the flow classify
> > > apis to reduce the complexity and and does some cleanup of the code.
> > >
> > > The validate api has been exposed as public api to allows user to
> > > validate the flow before adding it to the classifier.
> > >
> > > The sample app and unit tests have been updated to accomodate the
> > > apis changes.
> > >
> > > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > > ---
> > >  examples/flow_classify/flow_classify.c             |  27 +-
> > >  lib/librte_flow_classify/rte_flow_classify.c       | 320 +++++++++++----------
> > >  lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
> > >  lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
> > > lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
> > >  .../rte_flow_classify_version.map                  |   1 +
> > >  test/test/test_flow_classify.c                     |  86 +++---
> > >  test/test/test_flow_classify.h                     |  10 +-
> > >  8 files changed, 365 insertions(+), 287 deletions(-)
> > >

It would be better to break this patch into three patches, a librte_flow_classify patch, a flow_classify sample app patch, and a test_flow_classify patch.
 
flow_classify  test
> > > diff --git a/examples/flow_classify/flow_classify.c
> > > b/examples/flow_classify/flow_classify.c
> > > index 766f1dd..37e6904 100644
> > > --- a/examples/flow_classify/flow_classify.c
> > > +++ b/examples/flow_classify/flow_classify.c

The flow_classify sample app should exercise the rte_flow_classify_validate() and rte_flow_classifier_run() API's.
 
> > > @@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default
> > > = {
> > >
> > >  struct flow_classifier {
> > >  	struct rte_flow_classifier *cls;
> > > -	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > >  };
> > >
> > >  struct flow_classifier_acl {
> > > @@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = {
> > > RTE_FLOW_ITEM_TYPE_END,
> > >  /* sample actions:
> > >   * "actions count / end"
> > >   */
> > > -static struct rte_flow_action count_action = {
> > > RTE_FLOW_ACTION_TYPE_COUNT, 0};
> > > +struct rte_flow_query_count count = {
> > > +	.reset = 1,
> > > +	.hits_set = 1,
> > > +	.bytes_set = 1,
> > > +	.hits = 0,
> > > +	.bytes = 0,
> > > +};
> > > +static struct rte_flow_action count_action = {
> > > RTE_FLOW_ACTION_TYPE_COUNT,
> > > +	&count};
> > >  static struct rte_flow_action end_action = {
> > > RTE_FLOW_ACTION_TYPE_END, 0};  static struct rte_flow_action
> > > actions[2];
> > >
> > > @@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
> > >  	int i = 0;
> > >
> > >  	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
> > > -			cls_app->table_id[0], rules[7]);
> > > +			rules[7]);
> > >  	if (ret)
> > >  		printf("table_entry_delete failed [7] %d\n\n", ret);
> > >  	else
> > > @@ -317,7 +324,6 @@ lcore_main(struct flow_classifier *cls_app)
> > >  				if (rules[i]) {
> > >  					ret = rte_flow_classifier_query(
> > >  						cls_app->cls,
> > > -						cls_app->table_id[0],
> > >  						bufs, nb_rx, rules[i],
> > >  						&classify_stats);
> > >  					if (ret)
> > > @@ -635,8 +641,8 @@ add_classify_rule(struct rte_eth_ntuple_filter
> > > *ntuple_filter,
> > >  	actions[1] = end_action;
> > >
> > >  	rule = rte_flow_classify_table_entry_add(
> > > -			cls_app->cls, cls_app->table_id[0], &key_found,
> > > -			&attr, pattern_ipv4_5tuple, actions, &error);
> > > +			cls_app->cls, &attr, pattern_ipv4_5tuple,
> > > +			actions, &key_found, &error);
> > >  	if (rule == NULL) {
> > >  		printf("table entry add failed ipv4_proto = %u\n",
> > >  			ipv4_proto);
> > > @@ -809,7 +815,6 @@ main(int argc, char *argv[])
> > >
> > >  	cls_params.name = "flow_classifier";
> > >  	cls_params.socket_id = socket_id;
> > > -	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> > >
> > >  	cls_app->cls = rte_flow_classifier_create(&cls_params);
> > >  	if (cls_app->cls == NULL) {
> > > @@ -824,11 +829,11 @@ main(int argc, char *argv[])
> > >  	memcpy(table_acl_params.field_format, ipv4_defs,
> > > sizeof(ipv4_defs));
> > >
> > >  	/* initialise table create params */
> > > -	cls_table_params.ops = &rte_table_acl_ops,
> > > -	cls_table_params.arg_create = &table_acl_params,
> > > +	cls_table_params.ops = &rte_table_acl_ops;
> > > +	cls_table_params.arg_create = &table_acl_params;
> > > +	cls_table_params.type =
> > > RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> > >
> > > -	ret = rte_flow_classify_table_create(cls_app->cls,
> > > &cls_table_params,
> > > -			&cls_app->table_id[0]);
> > > +	ret = rte_flow_classify_table_create(cls_app->cls,
> > > &cls_table_params);
> > >  	if (ret) {
> > >  		rte_flow_classifier_free(cls_app->cls);
> > >  		rte_free(cls_app);
> > > diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> > > b/lib/librte_flow_classify/rte_flow_classify.c
> > > index e6f4486..ff1bc86 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify.c
> > > +++ b/lib/librte_flow_classify/rte_flow_classify.c
> > > @@ -39,16 +39,20 @@
> > >
> > >  int librte_flow_classify_logtype;
> > >
> > > -static struct rte_eth_ntuple_filter ntuple_filter;  static uint32_t
> > > unique_id = 1;
> > >
> > > +enum rte_flow_classify_table_type table_type
> > > +	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
> > >
> > >  struct rte_flow_classify_table_entry {
> > >  	/* meta-data for classify rule */
> > >  	uint32_t rule_id;
> > > +
> > > +	/* Flow action */
> > > +	struct classify_action action;
> > >  };
> > >
> > > -struct rte_table {
> > > +struct rte_cls_table {
> > >  	/* Input parameters */
> > >  	struct rte_table_ops ops;
> > >  	uint32_t entry_size;
> > > @@ -64,11 +68,16 @@ struct rte_flow_classifier {
> > >  	/* Input parameters */
> > >  	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
> > >  	int socket_id;
> > > -	enum rte_flow_classify_table_type type;
> > >
> > > -	/* Internal tables */
> > > -	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > > +	/* Internal */
> > > +	/* ntuple_fliter */
> > > +	struct rte_eth_ntuple_filter ntuple_filter;
> > > +
> > > +	/* clasifier tables */
> > > +	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > > +	uint32_t table_mask;
> > >  	uint32_t num_tables;
> > > +
> > >  	uint16_t nb_pkts;
> > >  	struct rte_flow_classify_table_entry
> > >  		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
> > > @@ -97,18 +106,19 @@ struct classify_rules {
> > >
> > >  struct rte_flow_classify_rule {
> > >  	uint32_t id; /* unique ID of classify rule */
> > > -	struct rte_flow_action action; /* action when match found */
> > > +	enum rte_flow_classify_table_type tbl_type; /* rule table */
> > >  	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 */
> > > +	struct rte_flow_classify_table_entry entry;  /* rule meta data */
> > >  	void *entry_ptr; /* handle to the table entry for rule meta data
> > > */ };
> > >
> > > -static int
> > > -flow_classify_parse_flow(
> > > +int
> > > +rte_flow_classify_validate(
> > > +		   struct rte_flow_classifier *cls,
> > >  		   const struct rte_flow_attr *attr,
> > >  		   const struct rte_flow_item pattern[],
> > >  		   const struct rte_flow_action actions[], @@ -120,7 +130,42
> > @@
> > > flow_classify_parse_flow(
> > >  	uint32_t i = 0;
> > >  	int ret;
> > >
> > > -	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
> > > +	if (cls == NULL) {
> > > +		RTE_FLOW_CLASSIFY_LOG(ERR,
> > > +			"%s: rte_flow_classifier parameter is NULL\n",
> > > +			__func__);
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	if (!attr) {
> > > +		rte_flow_error_set(error, EINVAL,
> > > +				   RTE_FLOW_ERROR_TYPE_ATTR,
> > > +				   NULL, "NULL attribute.");
> > > +		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 (!error) {
> > > +		rte_flow_error_set(error, EINVAL,
> > > +				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > > +				   NULL, "NULL error.");
> > > +		return -EINVAL;
> > > +	}

The check on error, should be the first check and should not use rte_flow_error_set().

> > > +
> > > +	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
> > >
> > >  	/* Get the non-void item number of pattern */
> > >  	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { @@ -
> > > 150,7 +195,7 @@ flow_classify_parse_flow(
> > >  		return -EINVAL;
> > >  	}
> > >
> > > -	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
> > > +	ret = parse_filter(attr, items, actions, &cls->ntuple_filter,
> > > +error);
> > >  	free(items);
> > >  	return ret;
> > >  }
> > > @@ -275,17 +320,14 @@ rte_flow_classifier_create(struct
> > > rte_flow_classifier_params *params)
> > >  	/* 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;
> > > +	cls->socket_id = params->socket_id;
> > >
> > >  	return cls;
> > >  }
> > >
> > >  static void
> > > -rte_flow_classify_table_free(struct rte_table *table)
> > > +rte_flow_classify_table_free(struct rte_cls_table *table)
> > >  {
> > >  	if (table->ops.f_free != NULL)
> > >  		table->ops.f_free(table->h_table);
> > > @@ -306,7 +348,7 @@ rte_flow_classifier_free(struct
> > > rte_flow_classifier
> > > *cls)
> > >
> > >  	/* Free tables */
> > >  	for (i = 0; i < cls->num_tables; i++) {
> > > -		struct rte_table *table = &cls->tables[i];
> > > +		struct rte_cls_table *table = &cls->tables[i];
> > >
> > >  		rte_flow_classify_table_free(table);
> > >  	}
> > > @@ -319,8 +361,7 @@ rte_flow_classifier_free(struct
> > > rte_flow_classifier
> > > *cls)
> > >
> > >  static int
> > >  rte_table_check_params(struct rte_flow_classifier *cls,
> > > -		struct rte_flow_classify_table_params *params,
> > > -		uint32_t *table_id)
> > > +		struct rte_flow_classify_table_params *params)
> > >  {
> > >  	if (cls == NULL) {
> > >  		RTE_FLOW_CLASSIFY_LOG(ERR,
> > > @@ -333,11 +374,6 @@ rte_table_check_params(struct
> > > rte_flow_classifier *cls,
> > >  			__func__);
> > >  		return -EINVAL;
> > >  	}
> > > -	if (table_id == NULL) {
> > > -		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is
> > > NULL\n",
> > > -			__func__);
> > > -		return -EINVAL;
> > > -	}
> > >
> > >  	/* ops */
> > >  	if (params->ops == NULL) {
> > > @@ -371,22 +407,18 @@ rte_table_check_params(struct
> > > rte_flow_classifier *cls,
> > >
> > >  int
> > >  rte_flow_classify_table_create(struct rte_flow_classifier *cls,
> > > -	struct rte_flow_classify_table_params *params,
> > > -	uint32_t *table_id)
> > > +	struct rte_flow_classify_table_params *params)
> > >  {
> > > -	struct rte_table *table;
> > > +	struct rte_cls_table *table;
> > >  	void *h_table;
> > > -	uint32_t entry_size, id;
> > > +	uint32_t entry_size;
> > >  	int ret;
> > >
> > >  	/* Check input arguments */
> > > -	ret = rte_table_check_params(cls, params, table_id);
> > > +	ret = rte_table_check_params(cls, params);
> > >  	if (ret != 0)
> > >  		return ret;
> > >
> > > -	id = cls->num_tables;
> > > -	table = &cls->tables[id];
> > > -
> > >  	/* calculate table entry size */
> > >  	entry_size = sizeof(struct rte_flow_classify_table_entry);
> > >
> > > @@ -400,8 +432,9 @@ rte_flow_classify_table_create(struct
> > > rte_flow_classifier *cls,
> > >  	}
> > >
> > >  	/* Commit current table to the classifier */
> > > +	table = &cls->tables[cls->num_tables];
> > > +	table->type = params->type;
> > >  	cls->num_tables++;
> > > -	*table_id = id;
> > >
> > >  	/* Save input parameters */
> > >  	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops)); @@
> > > -414,7 +447,7 @@ rte_flow_classify_table_create(struct
> > > rte_flow_classifier *cls,  }
> > >
> > >  static struct rte_flow_classify_rule *
> > > -allocate_acl_ipv4_5tuple_rule(void)
> > > +allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
> > >  {
> > >  	struct rte_flow_classify_rule *rule;
> > >  	int log_level;
> > > @@ -427,45 +460,44 @@ allocate_acl_ipv4_5tuple_rule(void)
> > >  	rule->id = unique_id++;
> > >  	rule->rules.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.priority = cls->ntuple_filter.priority;
> > >  	rule-
> > > >u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
> > > -			ntuple_filter.proto_mask;
> > > +			cls->ntuple_filter.proto_mask;
> > >  	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
> > > -			ntuple_filter.proto;
> > > -	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
> > > -	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
> > > +			cls->ntuple_filter.proto;
> > > +	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
> > > +	rule->rules.u.ipv4_5tuple.proto_mask = cls-
> > > >ntuple_filter.proto_mask;
> > >
> > >  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32
> > > =
> > > -			ntuple_filter.src_ip_mask;
> > > +			cls->ntuple_filter.src_ip_mask;
> > >  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
> > > -			ntuple_filter.src_ip;
> > > -	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
> > > -	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
> > > +			cls->ntuple_filter.src_ip;
> > > +	rule->rules.u.ipv4_5tuple.src_ip_mask = cls-
> > > >ntuple_filter.src_ip_mask;
> > > +	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
> > >
> > >  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32
> > > =
> > > -			ntuple_filter.dst_ip_mask;
> > > +			cls->ntuple_filter.dst_ip_mask;
> > >  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
> > > -			ntuple_filter.dst_ip;
> > > -	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
> > > -	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
> > > +			cls->ntuple_filter.dst_ip;
> > > +	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls-
> > > >ntuple_filter.dst_ip_mask;
> > > +	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
> > >
> > >  	rule-
> > > >u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
> > > -			ntuple_filter.src_port_mask;
> > > +			cls->ntuple_filter.src_port_mask;
> > >  	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
> > > -			ntuple_filter.src_port;
> > > -	rule->rules.u.ipv4_5tuple.src_port_mask =
> > > ntuple_filter.src_port_mask;
> > > -	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
> > > +			cls->ntuple_filter.src_port;
> > > +	rule->rules.u.ipv4_5tuple.src_port_mask =
> > > +			cls->ntuple_filter.src_port_mask;
> > > +	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
> > >
> > >  	rule-
> > > >u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
> > > -			ntuple_filter.dst_port_mask;
> > > +			cls->ntuple_filter.dst_port_mask;
> > >  	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
> > > -			ntuple_filter.dst_port;
> > > -	rule->rules.u.ipv4_5tuple.dst_port_mask =
> > > ntuple_filter.dst_port_mask;
> > > -	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
> > > +			cls->ntuple_filter.dst_port;
> > > +	rule->rules.u.ipv4_5tuple.dst_port_mask =
> > > +			cls->ntuple_filter.dst_port_mask;
> > > +	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
> > >
> > >  	log_level = rte_log_get_level(librte_flow_classify_logtype);
> > >
> > > @@ -485,34 +517,18 @@ allocate_acl_ipv4_5tuple_rule(void)
> > >
> > >  struct rte_flow_classify_rule *
> > >  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> > > -		uint32_t table_id,
> > > -		int *key_found,
> > >  		const struct rte_flow_attr *attr,
> > >  		const struct rte_flow_item pattern[],
> > >  		const struct rte_flow_action actions[],
> > > +		int *key_found,
> > >  		struct rte_flow_error *error)
> > >  {
> > >  	struct rte_flow_classify_rule *rule;
> > >  	struct rte_flow_classify_table_entry *table_entry;
> > > +	struct classify_action *action;
> > > +	uint32_t i;
> > >  	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 (key_found == NULL) {
> > >  		rte_flow_error_set(error, EINVAL,
> > >  				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@ -
> 520,91 +536,95 @@
> > > rte_flow_classify_table_entry_add(struct
> > > rte_flow_classifier *cls,
> > >  		return NULL;
> > >  	}
> > >

The check on error should be restored as the first check.

> > > -	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 = flow_classify_parse_flow(attr, pattern, actions, error);
> > > +	ret = rte_flow_classify_validate(cls, attr, pattern, actions,
> > > +error);
> > >  	if (ret < 0)
> > >  		return NULL;
> > >
> > > -	switch (cls->type) {
> > > -	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
> > > -		rule = allocate_acl_ipv4_5tuple_rule();
> > > +	switch (table_type) {
> > > +	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
> > > +		rule = allocate_acl_ipv4_5tuple_rule(cls);
> > >  		if (!rule)
> > >  			return NULL;
> > > +		rule->tbl_type = table_type;
> > > +		cls->table_mask |= table_type;
> > >  		break;
> > >  	default:
> > >  		return NULL;
> > >  	}
> > >
> > > -	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
> > > -	if (!rule->entry) {
> > > -		free(rule);
> > > -		return NULL;
> > > -	}
> > > -
> > > -	table_entry = rule->entry;
> > > +	action = classify_get_flow_action();
> > > +	table_entry = &rule->entry;
> > >  	table_entry->rule_id = rule->id;
> > > +	table_entry->action.action_mask = action->action_mask;
> > >
> > > -	if (cls->tables[table_id].ops.f_add != NULL) {
> > > -		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);
> > > -			return NULL;
> > > +	/* Copy actions */
> > > +	if (action->action_mask & (1LLU <<
> > > RTE_FLOW_ACTION_TYPE_COUNT)) {
> > > +		memcpy(&table_entry->action.act.counter, &action-
> > > >act.counter,
> > > +				sizeof(table_entry->action.act.counter));
> > > +	}
> > > +	if (action->action_mask & (1LLU <<
> > > RTE_FLOW_ACTION_TYPE_MARK)) {
> > > +		memcpy(&table_entry->action.act.mark, &action->act.mark,
> > > +				sizeof(table_entry->action.act.mark));
> > > +	}
> > > +
> > > +	for (i = 0; i < cls->num_tables; i++) {
> > > +		struct rte_cls_table *table = &cls->tables[i];
> > > +
> > > +		if (table->type == table_type) {
> > > +			if (table->ops.f_add != NULL) {
> > > +				ret = table->ops.f_add(
> > > +					table->h_table,
> > > +					&rule->u.key.key_add,
> > > +					&rule->entry,
> > > +					&rule->key_found,
> > > +					&rule->entry_ptr);
> > > +				if (ret) {
> > > +					free(rule);
> > > +					return NULL;
> > > +				}
> > > +
> > > +			*key_found = rule->key_found;
> > > +			}
> > > +
> > > +			return rule;
> > >  		}
> > > -		*key_found = rule->key_found;
> > >  	}
> > > -	return rule;
> > > +	return NULL;
> > >  }
> > >
> > >  int
> > >  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> > > -		uint32_t table_id,
> > >  		struct rte_flow_classify_rule *rule)  {
> > > +	uint32_t i;
> > >  	int ret = -EINVAL;
> > >
> > > -	if (!cls || !rule || table_id >= cls->num_tables)
> > > +	if (!cls || !rule)
> > >  		return ret;
> > > +	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
> > >
> > > -	if (cls->tables[table_id].ops.f_delete != NULL)
> > > -		ret = cls->tables[table_id].ops.f_delete(
> > > -			cls->tables[table_id].h_table,
> > > -			&rule->u.key.key_del,
> > > -			&rule->key_found,
> > > -			&rule->entry);
> > > +	for (i = 0; i < cls->num_tables; i++) {
> > > +		struct rte_cls_table *table = &cls->tables[i];
> > >
> > > +		if (table->type == tbl_type) {
> > > +			if (table->ops.f_delete != NULL) {
> > > +				ret = table->ops.f_delete(table->h_table,
> > > +						&rule->u.key.key_del,
> > > +						&rule->key_found,
> > > +						&rule->entry);
> > > +
> > > +				return ret;
> > > +			}
> > > +		}
> > > +	}
> > > +	free(rule);
> > >  	return ret;
> > >  }
> > >
> > >  static int
> > >  flow_classifier_lookup(struct rte_flow_classifier *cls,
> > > -		uint32_t table_id,
> > > +		struct rte_cls_table *table,
> > >  		struct rte_mbuf **pkts,
> > >  		const uint16_t nb_pkts)
> > >  {
> > > @@ -613,8 +633,7 @@ flow_classifier_lookup(struct rte_flow_classifier
> *cls,
> > >  	uint64_t lookup_hit_mask;
> > >
> > >  	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> > > -	ret = cls->tables[table_id].ops.f_lookup(
> > > -		cls->tables[table_id].h_table,
> > > +	ret = table->ops.f_lookup(table->h_table,
> > >  		pkts, pkts_mask, &lookup_hit_mask,
> > >  		(void **)cls->entries);
> > >
> > > @@ -632,12 +651,12 @@ action_apply(struct rte_flow_classifier *cls,
> > >  		struct rte_flow_classify_stats *stats)  {
> > >  	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
> > > +	struct rte_flow_classify_table_entry *entry = &rule->entry;
> > >  	uint64_t count = 0;
> > > -	int i;
> > > -	int ret = -EINVAL;
> > > +	uint32_t action_mask = entry->action.action_mask;
> > > +	int i, ret = -EINVAL;
> > >
> > > -	switch (rule->action.type) {
> > > -	case RTE_FLOW_ACTION_TYPE_COUNT:
> > > +	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
> > >  		for (i = 0; i < cls->nb_pkts; i++) {
> > >  			if (rule->id == cls->entries[i]->rule_id)
> > >  				count++;
> > > @@ -650,32 +669,37 @@ action_apply(struct rte_flow_classifier *cls,
> > >  			ntuple_stats->counter1 = count;
> > >  			ntuple_stats->ipv4_5tuple = rule-
> > > >rules.u.ipv4_5tuple;
> > >  		}
> > > -		break;
> > > -	default:
> > > -		ret = -ENOTSUP;
> > > -		break;
> > >  	}
> > > -
> > >  	return ret;
> > >  }
> > >
> > >  int
> > >  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > > -		uint32_t table_id,
> > >  		struct rte_mbuf **pkts,
> > >  		const uint16_t nb_pkts,
> > >  		struct rte_flow_classify_rule *rule,
> > >  		struct rte_flow_classify_stats *stats)  {
> > > +	enum rte_flow_classify_table_type tbl_type;
> > > +	uint32_t i;
> > >  	int ret = -EINVAL;
> > >
> > > -	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
> > > -		table_id >= cls->num_tables)
> > > +	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
> > >  		return ret;
> > >
> > > -	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
> > > -	if (!ret)
> > > -		ret = action_apply(cls, rule, stats);
> > > +	tbl_type = rule->tbl_type;
> > > +	for (i = 0; i < cls->num_tables; i++) {
> > > +		struct rte_cls_table *table = &cls->tables[i];
> > > +
> > > +			if (table->type == tbl_type) {
> > > +				ret = flow_classifier_lookup(cls, table,
> > > +						pkts, nb_pkts);
> > > +				if (!ret) {
> > > +					ret = action_apply(cls, rule, stats);
> > > +					return ret;
> > > +				}
> > > +			}
> > > +	}
> > >  	return ret;
> > >  }
> > >
> > > diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> > > b/lib/librte_flow_classify/rte_flow_classify.h
> > > index 1211873..b9b669f 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify.h
> > > +++ b/lib/librte_flow_classify/rte_flow_classify.h
> > > @@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
> > > rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
> > >  	__func__, ## args)
> > >
> > > +#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
> > > +#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
> > > +#endif
> > > +
> > >  /** Opaque data type for flow classifier */  struct
> > > rte_flow_classifier;
> > >
> > > @@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
> > >
> > >  /** Flow classify table type */
> > >  enum rte_flow_classify_table_type {
> > > -	/** no type */
> > > -	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
> > > -	/** ACL type */
> > > -	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
> > > -};
> > > +	/** No type */
> > > +	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
> > > +	/** ACL IP4 5TUPLE */
> > > +	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
> > > +	/** ACL VLAN IP4 5TUPLE */
> > > +	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
> > > +	/** ACL QinQ IP4 5TUPLE */
> > > +	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
> > >
> > > -/**
> > > - * Maximum number of tables allowed for any Flow Classifier instance.
> > > - * The value of this parameter cannot be changed.
> > > - */
> > > -#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
> > > +};
> > >
> > >  /** Parameters for flow classifier creation */  struct
> > > rte_flow_classifier_params { @@ -122,9 +125,6 @@ struct
> > > rte_flow_classifier_params {
> > >  	/** 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;
> > >  };
> > >
> > >  /** Parameters for table creation */ @@ -134,6 +134,9 @@ struct
> > > rte_flow_classify_table_params {
> > >
> > >  	/** Opaque param to be passed to the table create operation */
> > >  	void *arg_create;
> > > +
> > > +	/** Classifier table type */
> > > +	enum rte_flow_classify_table_type type;
> > >  };
> > >
> > >  /** IPv4 5-tuple data */
> > > @@ -197,32 +200,50 @@ rte_flow_classifier_free(struct
> > > rte_flow_classifier *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);
> > > +		struct rte_flow_classify_table_params *params);
> > > +
> > > +/**
> > > + * Flow classify validate
> > > + *
> > > + * @param cls
> > > + *   Handle to flow classifier instance
> > > + * @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(struct rte_flow_classifier *cls,
> > > +		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[out] key_found
> > > - *  returns 1 if key present already, 0 otherwise.
> > >   * @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] key_found
> > > + *  returns 1 if rule present already, 0 otherwise.
> > >   * @param[out] error
> > >   *   Perform verbose error reporting if not NULL. Structure
> > >   *   initialised in case of error only.
> > > @@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct
> > > rte_flow_classifier *cls,
> > >   */
> > >  struct rte_flow_classify_rule *
> > >  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> > > -		uint32_t table_id,
> > > -		int *key_found,
> > >  		const struct rte_flow_attr *attr,
> > >  		const struct rte_flow_item pattern[],
> > >  		const struct rte_flow_action actions[],
> > > +		int *key_found,
> > >  		struct rte_flow_error *error);
> > >
> > >  /**
> > > @@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct
> > > rte_flow_classifier *cls,
> > >   *
> > >   * @param[in] cls
> > >   *   Flow classifier handle
> > > - * @param[in] table_id
> > > - *   id of table
> > >   * @param[in] rule
> > >   *   Flow classify rule
> > >   * @return
> > > @@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct
> > > rte_flow_classifier *cls,
> > >   */
> > >  int
> > >  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> > > -		uint32_t table_id,
> > >  		struct rte_flow_classify_rule *rule);
> > >
> > >  /**
> > > @@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct
> > > rte_flow_classifier *cls,
> > >   *
> > >   * @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
> > > @@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct
> > > rte_flow_classifier *cls,
> > >   */
> > >  int
> > >  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > > -		uint32_t table_id,
> > >  		struct rte_mbuf **pkts,
> > >  		const uint16_t nb_pkts,
> > >  		struct rte_flow_classify_rule *rule, diff --git
> > > a/lib/librte_flow_classify/rte_flow_classify_parse.c
> > > b/lib/librte_flow_classify/rte_flow_classify_parse.c
> > > index dbfa111..9fb3e51 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify_parse.c
> > > +++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
> > > @@ -40,7 +40,7 @@ struct classify_valid_pattern {
> > >  	parse_filter_t parse_filter;
> > >  };
> > >
> > > -static struct rte_flow_action action;
> > > +static struct classify_action action;
> > >
> > >  /* Pattern for IPv4 5-tuple UDP filter */  static enum
> > > rte_flow_item_type pattern_ntuple_1[] = { @@ -80,7 +80,7 @@ static
> > > struct classify_valid_pattern classify_supported_patterns[] = {
> > >  	{ pattern_ntuple_3, classify_parse_ntuple_filter },  };
> > >
> > > -struct rte_flow_action *
> > > +struct classify_action *
> > >  classify_get_flow_action(void)
> > >  {
> > >  	return &action;
> > > @@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct
> > > rte_flow_attr *attr,
> > >  	const struct rte_flow_item_udp *udp_mask;
> > >  	const struct rte_flow_item_sctp *sctp_spec;
> > >  	const struct rte_flow_item_sctp *sctp_mask;
> > > +	const struct rte_flow_action_count *count;
> > > +	const struct rte_flow_action_mark *mark_spec;
> > >  	uint32_t index;
> > >
> > > -	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;
> > > -	}
> > > -
> > >  	/* parse pattern */
> > >  	index = 0;
> > >
> > > @@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct
> > > rte_flow_attr *attr,
> > >  		return -EINVAL;
> > >  	}
> > >
> > > -	/* parse action */
> > > -	index = 0;
> > > -
> > > -	/**
> > > -	 * n-tuple only supports count,
> > > -	 * check if the first not void action is COUNT.
> > > -	 */
> > > -	memset(&action, 0, sizeof(action));
> > > -	NEXT_ITEM_OF_ACTION(act, actions, index);
> > > -	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
> > > -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > > -		rte_flow_error_set(error, EINVAL,
> > > -			RTE_FLOW_ERROR_TYPE_ACTION,
> > > -			item, "Not supported action.");
> > > -		return -EINVAL;
> > > -	}
> > > -	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
> > > -
> > > -	/* check if the next not void item is END */
> > > -	index++;
> > > -	NEXT_ITEM_OF_ACTION(act, actions, index);
> > > -	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> > > -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > > -		rte_flow_error_set(error, EINVAL,
> > > -			RTE_FLOW_ERROR_TYPE_ACTION,
> > > -			act, "Not supported action.");
> > > -		return -EINVAL;
> > > -	}
> > > +	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> > >
> > >  	/* parse attr */
> > >  	/* must be input direction */
> > > @@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct
> > > rte_flow_attr *attr,
> > >  	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
> > >  		filter->priority = FLOW_RULE_MAX_PRIORITY;
> > >
> > > +	/* parse action */
> > > +	index = 0;
> > > +
> > > +	/**
> > > +	 * n-tuple only supports count and Mark,
> > > +	 * check if the first not void action is COUNT or MARK.
> > > +	 */
> > > +	memset(&action, 0, sizeof(action));
> > > +	NEXT_ITEM_OF_ACTION(act, actions, index);
> > > +	switch (act->type) {
> > > +	case RTE_FLOW_ACTION_TYPE_COUNT:
> > > +		action.action_mask |= 1LLU <<
> > > RTE_FLOW_ACTION_TYPE_COUNT;
> > > +		count = (const struct rte_flow_action_count *)act->conf;
> > > +		memcpy(&action.act.counter, count,
> > > sizeof(action.act.counter));
> > > +		break;
> > > +	case RTE_FLOW_ACTION_TYPE_MARK:
> > > +		action.action_mask |= 1LLU <<
> > > RTE_FLOW_ACTION_TYPE_MARK;
> > > +		mark_spec = (const struct rte_flow_action_mark *)act-
> > > >conf;
> > > +		memcpy(&action.act.mark, mark_spec,
> > > sizeof(action.act.mark));
> > > +		break;
> > > +	default:
> > > +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > > +		rte_flow_error_set(error, EINVAL,
> > > +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> > > +		   "Invalid action.");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	/* check if the next not void item is MARK or COUNT or END */
> > > +	index++;
> > > +	NEXT_ITEM_OF_ACTION(act, actions, index);
> > > +	switch (act->type) {
> > > +	case RTE_FLOW_ACTION_TYPE_COUNT:
> > > +		action.action_mask |= 1LLU <<
> > > RTE_FLOW_ACTION_TYPE_COUNT;
> > > +		count = (const struct rte_flow_action_count *)act->conf;
> > > +		memcpy(&action.act.counter, count,
> > > sizeof(action.act.counter));
> > > +		break;
> > > +	case RTE_FLOW_ACTION_TYPE_MARK:
> > > +		action.action_mask |= 1LLU <<
> > > RTE_FLOW_ACTION_TYPE_MARK;
> > > +		mark_spec = (const struct rte_flow_action_mark *)act-
> > > >conf;
> > > +		memcpy(&action.act.mark, mark_spec,
> > > sizeof(action.act.mark));
> > > +		break;
> > > +	case RTE_FLOW_ACTION_TYPE_END:
> > > +		return 0;
> > > +	default:
> > > +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > > +		rte_flow_error_set(error, EINVAL,
> > > +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> > > +		   "Invalid action.");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > > +	/* check if the next not void item is END */
> > > +	index++;
> > > +	NEXT_ITEM_OF_ACTION(act, actions, index);
> > > +	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> > > +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> > > +		rte_flow_error_set(error, EINVAL,
> > > +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> > > +		   "Invalid action.");
> > > +		return -EINVAL;
> > > +	}
> > > +
> > >  	return 0;
> > >  }
> > > diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h
> > > b/lib/librte_flow_classify/rte_flow_classify_parse.h
> > > index 1d4708a..9c1de72 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify_parse.h
> > > +++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
> > > @@ -43,6 +43,20 @@
> > >  extern "C" {
> > >  #endif
> > >
> > > +extern enum rte_flow_classify_table_type table_type;
> > > +
> > > +struct classify_action {
> > > +	/* Flow action mask */
> > > +	uint64_t action_mask;
> > > +
> > > +	struct action {
> > > +		/** Integer value to return with packets */
> > > +		struct rte_flow_action_mark mark;
> > > +		/** Flow rule counter */
> > > +		struct rte_flow_query_count counter;
> > > +	} act;
> > > +};
> > > +
> > >  typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
> > >  			      const struct rte_flow_item pattern[],
> > >  			      const struct rte_flow_action actions[], @@ -64,7
> > > +78,7 @@ parse_filter_t  classify_find_parse_filter_func(struct
> > > rte_flow_item *pattern);
> > >
> > >  /* get action data */
> > > -struct rte_flow_action *
> > > +struct classify_action *
> > >  classify_get_flow_action(void);
> > >
> > >  #ifdef __cplusplus
> > > diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map
> > > b/lib/librte_flow_classify/rte_flow_classify_version.map
> > > index f7695cb..49bc25c 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> > > +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> > > @@ -7,6 +7,7 @@ EXPERIMENTAL {
> > >  	rte_flow_classify_table_create;
> > >  	rte_flow_classify_table_entry_add;
> > >  	rte_flow_classify_table_entry_delete;
> > > +	rte_flow_classify_validate;
> > >
> > >  	local: *;
> > >  };
> > > diff --git a/test/test/test_flow_classify.c
> > > b/test/test/test_flow_classify.c index 9f331cd..4ddf4c0 100644
> > > --- a/test/test/test_flow_classify.c
> > > +++ b/test/test/test_flow_classify.c
> > > @@ -51,16 +51,10 @@
> > >
> > >

Tests should be added for rte_flow_classify_validate() and rte_flow_classifier_run  API's

> > >  #define FLOW_CLASSIFY_MAX_RULE_NUM 100 -struct flow_classifier
> > > *cls;
> > > -
> > > -struct flow_classifier {
> > > -	struct rte_flow_classifier *cls;
> > > -	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > > -	uint32_t n_tables;
> > > -};
> > > +struct flow_classifier_acl *cls;
> > >
> > >  struct flow_classifier_acl {
> > > -	struct flow_classifier cls;
> > > +	struct rte_flow_classifier *cls;
> > >  } __rte_cache_aligned;
> > >
> > >  /*
> > > @@ -73,7 +67,7 @@ test_invalid_parameters(void)
> > >  	struct rte_flow_classify_rule *rule;
> > >  	int ret;
> > >
> > > -	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL,
> > > NULL,
> > > +	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
> > >  			NULL, NULL);
> > >  	if (rule) {
> > >  		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
> > @@
> > > -81,7 +75,7 @@ test_invalid_parameters(void)
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
> > > +	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
> > >  	if (!ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -89,14 +83,14 @@ test_invalid_parameters(void)
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
> > > +	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
> > >  	if (!ret) {
> > >  		printf("Line %i: flow_classifier_query", __LINE__);
> > >  		printf(" with NULL param should have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL,
> > > NULL,
> > > +	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
> > >  		NULL, &error);
> > >  	if (rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
> > @@
> > > -104,7 +98,7 @@ test_invalid_parameters(void)
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
> > > +	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
> > >  	if (!ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -112,7 +106,7 @@ test_invalid_parameters(void)
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
> > > +	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
> > >  	if (!ret) {
> > >  		printf("Line %i: flow_classifier_query", __LINE__);
> > >  		printf(" with NULL param should have failed!\n"); @@ -
> > > 142,15 +136,16 @@ test_valid_parameters(void)
> > >  	actions[0] = count_action;
> > >  	actions[1] = end_action;
> > >
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > > +
> > >  	if (!rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should not have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -183,15 +178,15 @@ test_invalid_patterns(void)
> > >
> > >  	pattern[0] = eth_item;
> > >  	pattern[1] = ipv4_udp_item_bad;
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > >  	if (rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (!ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -202,15 +197,15 @@ test_invalid_patterns(void)
> > >  	pattern[1] = ipv4_udp_item_1;
> > >  	pattern[2] = udp_item_bad;
> > >  	pattern[3] = end_item_bad;
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > >  	if (rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (!ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -241,15 +236,15 @@ test_invalid_actions(void)
> > >  	actions[0] = count_action_bad;
> > >  	actions[1] = end_action;
> > >
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > >  	if (rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (!ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -260,15 +255,15 @@ test_invalid_actions(void)
> > >  	actions[0] = count_action;
> > >  	actions[1] = end_action_bad;
> > >
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > >  	if (rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (!ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -462,15 +457,15 @@ test_query_udp(void)
> > >  	actions[0] = count_action;
> > >  	actions[1] = end_action;
> > >
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > >  	if (!rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should not have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> > > +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
> > >  			rule, &udp_classify_stats);
> > >  	if (ret) {
> > >  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> > > 478,7 +473,7 @@ test_query_udp(void)
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -520,15 +515,15 @@ test_query_tcp(void)
> > >  	actions[0] = count_action;
> > >  	actions[1] = end_action;
> > >
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > >  	if (!rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should not have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> > > +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
> > >  			rule, &tcp_classify_stats);
> > >  	if (ret) {
> > >  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> > > 536,7 +531,7 @@ test_query_tcp(void)
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -578,15 +573,15 @@ test_query_sctp(void)
> > >  	actions[0] = count_action;
> > >  	actions[1] = end_action;
> > >
> > > -	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
> > > -			&attr, pattern, actions, &error);
> > > +	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
> > > +			actions, &key_found, &error);
> > >  	if (!rule) {
> > >  		printf("Line %i: flow_classify_table_entry_add", __LINE__);
> > >  		printf(" should not have failed!\n");
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
> > > +	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
> > >  			rule, &sctp_classify_stats);
> > >  	if (ret) {
> > >  		printf("Line %i: flow_classifier_query", __LINE__); @@ -
> > > 594,7 +589,7 @@ test_query_sctp(void)
> > >  		return -1;
> > >  	}
> > >
> > > -	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
> > > +	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
> > >  	if (ret) {
> > >  		printf("Line %i: rte_flow_classify_table_entry_delete",
> > >  			__LINE__);
> > > @@ -622,7 +617,6 @@ test_flow_classify(void)
> > >
> > >  	cls_params.name = "flow_classifier";
> > >  	cls_params.socket_id = socket_id;
> > > -	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> > >  	cls->cls = rte_flow_classifier_create(&cls_params);
> > >
> > >  	/* initialise ACL table params */
> > > @@ -632,11 +626,11 @@ test_flow_classify(void)
> > >  	memcpy(table_acl_params.field_format, ipv4_defs,
> > > sizeof(ipv4_defs));
> > >
> > >  	/* initialise table create params */
> > > -	cls_table_params.ops = &rte_table_acl_ops,
> > > -	cls_table_params.arg_create = &table_acl_params,
> > > +	cls_table_params.ops = &rte_table_acl_ops;
> > > +	cls_table_params.arg_create = &table_acl_params;
> > > +	cls_table_params.type =
> > > RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> > >
> > > -	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
> > > -			&cls->table_id[0]);
> > > +	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
> > >  	if (ret) {
> > >  		printf("Line %i: f_create has failed!\n", __LINE__);
> > >  		rte_flow_classifier_free(cls->cls);
> > > diff --git a/test/test/test_flow_classify.h
> > > b/test/test/test_flow_classify.h index 39535cf..af293ed 100644
> > > --- a/test/test/test_flow_classify.h
> > > +++ b/test/test/test_flow_classify.h
> > > @@ -197,7 +197,15 @@ static struct rte_flow_item  sctp_item_1 = {
> > > RTE_FLOW_ITEM_TYPE_SCTP,
> > >  /* test actions:
> > >   * "actions count / end"
> > >   */
> > > -static struct rte_flow_action count_action = {
> > > RTE_FLOW_ACTION_TYPE_COUNT, 0};
> > > +struct rte_flow_query_count count = {
> > > +	.reset = 1,
> > > +	.hits_set = 1,
> > > +	.bytes_set = 1,
> > > +	.hits = 0,
> > > +	.bytes = 0,
> > > +};
> > > +static struct rte_flow_action count_action = {
> > > RTE_FLOW_ACTION_TYPE_COUNT,
> > > +	&count};
> > >  static struct rte_flow_action count_action_bad = { -1, 0};
> > >
> > >  static struct rte_flow_action end_action = {
> > > RTE_FLOW_ACTION_TYPE_END, 0};
> > > --
> > > 2.9.3
> >
> > This patch fails to apply to the 18.02 master branch, a rebase may be needed.
> >
> > Regards,
> >
> > Bernard.
> 
> False alarm, the patch applies ok on a fresh checkout.
> 
> Regards,
> 
> Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification
  2017-12-05 11:01     ` Iremonger, Bernard
@ 2017-12-06 12:41       ` Iremonger, Bernard
  2017-12-11 15:52         ` Singh, Jasvinder
  0 siblings, 1 reply; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-06 12:41 UTC (permalink / raw)
  To: Iremonger, Bernard, Singh, Jasvinder, dev

Hi Jasvinder,

<snip>

> > > -----Original Message-----
> > > From: Singh, Jasvinder
> > > Sent: Thursday, November 23, 2017 11:32 AM
> > > To: dev@dpdk.org
> > > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > > Subject: [PATCH 2/3] lib/librte_flow_classy: add run api for flow
> > > classification
> > >
> > > This patch extends the flow classification library by adding run api.
> > > This function classifies the packets based on the flow rules stored
> > > in the classifier table.
> > > During lookup operation, the table entry is identified on lookup hit
> > > and based on meta-data stored at table entry, actions are performed
> > > on the current packet.
> > > The meta-information about the actions stored in the table entry is
> > > determined from the actions fields specified in flow rules.
> > >
> > > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > > ---
> > >  lib/librte_flow_classify/rte_flow_classify.c       | 56
> > > ++++++++++++++++++++++
> > >  lib/librte_flow_classify/rte_flow_classify.h       | 24 ++++++++++
> > >  .../rte_flow_classify_version.map                  |  1 +
> > >  3 files changed, 81 insertions(+)
> > >
> > > diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> > > b/lib/librte_flow_classify/rte_flow_classify.c
> > > index ff1bc86..5433bfe 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify.c
> > > +++ b/lib/librte_flow_classify/rte_flow_classify.c
> > > @@ -37,6 +37,9 @@
> > >  #include <rte_table_acl.h>
> > >  #include <stdbool.h>
> > >
> > > +#define RTE_PKT_METADATA_PTR(pkt, offset)         \
> > > +		(&((uint32_t *)(pkt))[offset])
> > > +
> > >  int librte_flow_classify_logtype;
> > >
> > >  static uint32_t unique_id = 1;
> > > @@ -674,6 +677,59 @@ action_apply(struct rte_flow_classifier *cls,
> > > }
> > >
> > >  int
> > > +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > > +	struct rte_mbuf **pkts,
> > > +	const uint16_t nb_pkts,
> > > +	uint32_t pkt_offset)
> > > +{
> > > +	struct rte_flow_action_mark *mark;
> > > +	struct classify_action *action;
> > > +	uint64_t pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> > > +	uint64_t action_mask;
> > > +	uint32_t *ptr, i, j;
> > > +	int ret = -EINVAL;
> > > +
> > > +	if (!cls || !pkts  || nb_pkts == 0)
> > > +		return ret;
> > > +
> > > +	for (i = 0; i < cls->num_tables; i++) {
> > > +		if (cls->table_mask & (1LU << i)) {
> > > +			struct rte_cls_table *table = &cls->tables[i];
> > > +			uint64_t lookup_hit_mask;
> > > +
> > > +			ret = table->ops.f_lookup(table->h_table,
> > > +				pkts, pkts_mask, &lookup_hit_mask,
> > > +				(void **)cls->entries);
> > > +			if (ret)
> > > +				return ret;
> > > +
> > > +			if (lookup_hit_mask) {
> > > +				for (j = 0; j < nb_pkts; j++) {
> > > +					uint64_t pkt_mask = 1LLU << j;
> > > +
> > > +					if ((lookup_hit_mask & pkt_mask) ==
> > > 0)
> > > +						continue;
> > > +					/* Meta-data */
> > > +					enum rte_flow_action_type act_type
> > > =
> > > +
> > > 	RTE_FLOW_ACTION_TYPE_MARK;
> > > +					action = &cls->entries[j]->action;
> > > +					action_mask = action->action_mask;
> > > +
> > > +					if (action_mask & (1LLU << act_type))
> > > {
> > > +						mark = &action->act.mark;
> > > +						ptr =
> > > RTE_PKT_METADATA_PTR(
> > > +							pkts[j], pkt_offset);
> > > +						*ptr = mark->id;
> > > +					}
> > > +				}
> > > +			}
> > > +		}
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +
> > > +int
> > >  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > >  		struct rte_mbuf **pkts,
> > >  		const uint16_t nb_pkts,
> > > diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> > > b/lib/librte_flow_classify/rte_flow_classify.h
> > > index b9b669f..b74bd11 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify.h
> > > +++ b/lib/librte_flow_classify/rte_flow_classify.h
> > > @@ -273,6 +273,30 @@ rte_flow_classify_table_entry_delete(struct
> > > rte_flow_classifier *cls,
> > >  		struct rte_flow_classify_rule *rule);
> > >
> > >  /**
> > > + * Flow classifier run.
> > > + *
> > > + * As a result of lookup operation, flow classifer idenfies the
> > > + * table entries that are hit and executes the actions on the packets.
> > > + *
> > > + * @param[in] cls
> > > + *   Flow classifier handle
> > > + * @param[in] pkts
> > > + *   Pointer to packets to process
> > > + * @param[in] nb_pkts
> > > + *   Number of packets to process
> > > + * @param[in] pkt_offset
> > > + *    Offset to store action metadata in the mbuf headroom
> > > + *
> > > + * @return
> > > + *   0 on success, error code otherwise.
> > > + */
> > > +int
> > > +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > > +		struct rte_mbuf **pkts,
> > > +		const uint16_t nb_pkts,
> > > +		uint32_t pkt_offset);
> > > +
> > > +/**
> > >   * Query flow classifier for given rule.
> > >   *
> > >   * @param[in] cls
> > > diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map
> > > b/lib/librte_flow_classify/rte_flow_classify_version.map
> > > index 49bc25c..b51cb1a 100644
> > > --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> > > +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> > > @@ -4,6 +4,7 @@ EXPERIMENTAL {
> > >  	rte_flow_classifier_create;
> > >  	rte_flow_classifier_free;
> > >  	rte_flow_classifier_query;
> > > +	rte_flow_classifier_run;
> > >  	rte_flow_classify_table_create;
> > >  	rte_flow_classify_table_entry_add;
> > >  	rte_flow_classify_table_entry_delete;
> > > --
> > > 2.9.3
> >
<snip>

Tests should be added to test_flow_classify.c for the rte_flow_classifier_run() API.
The flow_classify sample application should exercise the rte_flow_classifier_run() API.

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib
  2017-11-23 11:32 ` [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib Jasvinder Singh
  2017-12-06 12:04   ` Iremonger, Bernard
@ 2017-12-11 14:54   ` Mcnamara, John
  2017-12-11 15:53     ` Singh, Jasvinder
  1 sibling, 1 reply; 41+ messages in thread
From: Mcnamara, John @ 2017-12-11 14:54 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Iremonger, Bernard



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
> Sent: Thursday, November 23, 2017 11:32 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [dpdk-dev] [PATCH 3/3] doc: update documentation for flow
> classify lib
> 
> Updates the documentation for flow classification library and sample
> application.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>


>
> +370,24 @@ parses the Flow rule.
> 
>      struct rte_flow_classify {
>          uint32_t id;  /* unique ID of classify object */
> -        struct rte_flow_action action; /* action when match found */
> -	struct classify_rules rules; /* union of rules */
> +        enum rte_flow_classify_table_type tbl_type; /* rule table */
> +        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
> */
> +        struct rte_flow_classify_table_entry entry;  /* rule meta data */
> +       void *entry_ptr; /* handle to the table entry for rule meta data


The last line here is indented less than the others. Also there is a stray tab
a few lines above it (in the existing text). Can you replace that as well.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-06 12:34     ` Iremonger, Bernard
@ 2017-12-11 15:51       ` Singh, Jasvinder
  0 siblings, 0 replies; 41+ messages in thread
From: Singh, Jasvinder @ 2017-12-11 15:51 UTC (permalink / raw)
  To: Iremonger, Bernard, dev



> -----Original Message-----
> From: Iremonger, Bernard
> Sent: Wednesday, December 6, 2017 12:34 PM
> To: Iremonger, Bernard <bernard.iremonger@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: RE: [PATCH 1/3] lib/librte_flow_classify: remove table id parameter
> from apis
> 
> Hi Jasvinder,
> 
> > > > -----Original Message-----
> > > > From: Singh, Jasvinder
> > > > Sent: Thursday, November 23, 2017 11:32 AM
> > > > To: dev@dpdk.org
> > > > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > > > Subject: [PATCH 1/3] lib/librte_flow_classify: remove table id
> > > > parameter from apis
> > > >
> > > > This patch removes table id parameter from all the flow classify
> > > > apis to reduce the complexity and and does some cleanup of the code.
> > > >
> > > > The validate api has been exposed as public api to allows user to
> > > > validate the flow before adding it to the classifier.
> > > >
> > > > The sample app and unit tests have been updated to accomodate the
> > > > apis changes.
> > > >
> > > > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > > > ---
> > > >  examples/flow_classify/flow_classify.c             |  27 +-
> > > >  lib/librte_flow_classify/rte_flow_classify.c       | 320 +++++++++++--------
> --
> > > >  lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
> > > >  lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
> > > > lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
> > > >  .../rte_flow_classify_version.map                  |   1 +
> > > >  test/test/test_flow_classify.c                     |  86 +++---
> > > >  test/test/test_flow_classify.h                     |  10 +-
> > > >  8 files changed, 365 insertions(+), 287 deletions(-)
> > > >
> 
> It would be better to break this patch into three patches, a
> librte_flow_classify patch, a flow_classify sample app patch, and a
> test_flow_classify patch.

Ok, Will break this into multiple patches.

> flow_classify  test
> > > > diff --git a/examples/flow_classify/flow_classify.c
> > > > b/examples/flow_classify/flow_classify.c
> > > > index 766f1dd..37e6904 100644
> > > > --- a/examples/flow_classify/flow_classify.c
> > > > +++ b/examples/flow_classify/flow_classify.c


<snip>

> > > > +	if (!actions) {
> > > > +		rte_flow_error_set(error, EINVAL,
> > > > +				   RTE_FLOW_ERROR_TYPE_ACTION_NUM,
> > > > +				   NULL, "NULL action.");
> > > > +		return -EINVAL;
> > > > +	}
> > > > +
> > > > +	if (!error) {
> > > > +		rte_flow_error_set(error, EINVAL,
> > > > +				   RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> > > > +				   NULL, "NULL error.");
> > > > +		return -EINVAL;
> > > > +	}
> 
> The check on error, should be the first check and should not use
> rte_flow_error_set().

Will correct this.

> > > > +
> > > > +	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
> > > >
> > > >  	/* Get the non-void item number of pattern */
> > > >  	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { @@ -
> > > > 150,7 +195,7 @@ flow_classify_parse_flow(
> > > >  		return -EINVAL;
> > > >  	}
> > > >

<snip>

> > > >  	struct rte_flow_classify_rule *rule;
> > > >  	struct rte_flow_classify_table_entry *table_entry;
> > > > +	struct classify_action *action;
> > > > +	uint32_t i;
> > > >  	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 (key_found == NULL) {
> > > >  		rte_flow_error_set(error, EINVAL,
> > > >  				RTE_FLOW_ERROR_TYPE_UNSPECIFIED, @@
> -
> > 520,91 +536,95 @@
> > > > rte_flow_classify_table_entry_add(struct
> > > > rte_flow_classifier *cls,
> > > >  		return NULL;
> > > >  	}
> > > >
> 
> The check on error should be restored as the first check.

Ok.
 
> > > > -	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;
> > > > -	}

<snip>

> > > >  static struct rte_flow_action count_action_bad = { -1, 0};
> > > >
> > > >  static struct rte_flow_action end_action = {
> > > > RTE_FLOW_ACTION_TYPE_END, 0};
> > > > --
> > > > 2.9.3
> > >
> > > This patch fails to apply to the 18.02 master branch, a rebase may be
> needed.
> > >
> > > Regards,
> > >
> > > Bernard.
> >
> > False alarm, the patch applies ok on a fresh checkout.
> >
> > Regards,
> >
> > Bernard.

Thank you for the review, Bernard.

Jasvinder

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification
  2017-12-06 12:41       ` Iremonger, Bernard
@ 2017-12-11 15:52         ` Singh, Jasvinder
  0 siblings, 0 replies; 41+ messages in thread
From: Singh, Jasvinder @ 2017-12-11 15:52 UTC (permalink / raw)
  To: Iremonger, Bernard, dev



> -----Original Message-----
> From: Iremonger, Bernard
> Sent: Wednesday, December 6, 2017 12:41 PM
> To: Iremonger, Bernard <bernard.iremonger@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: RE: [PATCH 2/3] lib/librte_flow_classy: add run api for flow
> classification
> 
> Hi Jasvinder,
> 
> <snip>
> 
> > > > -----Original Message-----
> > > > From: Singh, Jasvinder
> > > > Sent: Thursday, November 23, 2017 11:32 AM
> > > > To: dev@dpdk.org
> > > > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > > > Subject: [PATCH 2/3] lib/librte_flow_classy: add run api for flow
> > > > classification
> > > >
> > > > This patch extends the flow classification library by adding run api.
> > > > This function classifies the packets based on the flow rules
> > > > stored in the classifier table.
> > > > During lookup operation, the table entry is identified on lookup
> > > > hit and based on meta-data stored at table entry, actions are
> > > > performed on the current packet.
> > > > The meta-information about the actions stored in the table entry
> > > > is determined from the actions fields specified in flow rules.
> > > >
> > > > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > > > ---
> > > >  lib/librte_flow_classify/rte_flow_classify.c       | 56
> > > > ++++++++++++++++++++++
> > > >  lib/librte_flow_classify/rte_flow_classify.h       | 24 ++++++++++
> > > >  .../rte_flow_classify_version.map                  |  1 +
> > > >  3 files changed, 81 insertions(+)
> > > >
> > > > diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> > > > b/lib/librte_flow_classify/rte_flow_classify.c
> > > > index ff1bc86..5433bfe 100644
> > > > --- a/lib/librte_flow_classify/rte_flow_classify.c
> > > > +++ b/lib/librte_flow_classify/rte_flow_classify.c
> > > > @@ -37,6 +37,9 @@
> > > >  #include <rte_table_acl.h>
> > > >  #include <stdbool.h>
> > > >
> > > > +#define RTE_PKT_METADATA_PTR(pkt, offset)         \
> > > > +		(&((uint32_t *)(pkt))[offset])
> > > > +
> > > >  int librte_flow_classify_logtype;
> > > >
> > > >  static uint32_t unique_id = 1;
> > > > @@ -674,6 +677,59 @@ action_apply(struct rte_flow_classifier *cls,
> > > > }
> > > >
> > > >  int
> > > > +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > > > +	struct rte_mbuf **pkts,
> > > > +	const uint16_t nb_pkts,
> > > > +	uint32_t pkt_offset)
> > > > +{
> > > > +	struct rte_flow_action_mark *mark;
> > > > +	struct classify_action *action;
> > > > +	uint64_t pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> > > > +	uint64_t action_mask;
> > > > +	uint32_t *ptr, i, j;
> > > > +	int ret = -EINVAL;
> > > > +
> > > > +	if (!cls || !pkts  || nb_pkts == 0)
> > > > +		return ret;
> > > > +
> > > > +	for (i = 0; i < cls->num_tables; i++) {
> > > > +		if (cls->table_mask & (1LU << i)) {
> > > > +			struct rte_cls_table *table = &cls->tables[i];
> > > > +			uint64_t lookup_hit_mask;
> > > > +
> > > > +			ret = table->ops.f_lookup(table->h_table,
> > > > +				pkts, pkts_mask, &lookup_hit_mask,
> > > > +				(void **)cls->entries);
> > > > +			if (ret)
> > > > +				return ret;
> > > > +
> > > > +			if (lookup_hit_mask) {
> > > > +				for (j = 0; j < nb_pkts; j++) {
> > > > +					uint64_t pkt_mask = 1LLU << j;
> > > > +
> > > > +					if ((lookup_hit_mask & pkt_mask) ==
> > > > 0)
> > > > +						continue;
> > > > +					/* Meta-data */
> > > > +					enum rte_flow_action_type act_type
> > > > =
> > > > +
> > > > 	RTE_FLOW_ACTION_TYPE_MARK;
> > > > +					action = &cls->entries[j]->action;
> > > > +					action_mask = action->action_mask;
> > > > +
> > > > +					if (action_mask & (1LLU << act_type))
> > > > {
> > > > +						mark = &action->act.mark;
> > > > +						ptr =
> > > > RTE_PKT_METADATA_PTR(
> > > > +							pkts[j], pkt_offset);
> > > > +						*ptr = mark->id;
> > > > +					}
> > > > +				}
> > > > +			}
> > > > +		}
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +int
> > > >  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> > > >  		struct rte_mbuf **pkts,
> > > >  		const uint16_t nb_pkts,
> > > > diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> > > > b/lib/librte_flow_classify/rte_flow_classify.h
> > > > index b9b669f..b74bd11 100644
> > > > --- a/lib/librte_flow_classify/rte_flow_classify.h
> > > > +++ b/lib/librte_flow_classify/rte_flow_classify.h
> > > > @@ -273,6 +273,30 @@ rte_flow_classify_table_entry_delete(struct
> > > > rte_flow_classifier *cls,
> > > >  		struct rte_flow_classify_rule *rule);
> > > >
> > > >  /**
> > > > + * Flow classifier run.
> > > > + *
> > > > + * As a result of lookup operation, flow classifer idenfies the
> > > > + * table entries that are hit and executes the actions on the packets.
> > > > + *
> > > > + * @param[in] cls
> > > > + *   Flow classifier handle
> > > > + * @param[in] pkts
> > > > + *   Pointer to packets to process
> > > > + * @param[in] nb_pkts
> > > > + *   Number of packets to process
> > > > + * @param[in] pkt_offset
> > > > + *    Offset to store action metadata in the mbuf headroom
> > > > + *
> > > > + * @return
> > > > + *   0 on success, error code otherwise.
> > > > + */
> > > > +int
> > > > +rte_flow_classifier_run(struct rte_flow_classifier *cls,
> > > > +		struct rte_mbuf **pkts,
> > > > +		const uint16_t nb_pkts,
> > > > +		uint32_t pkt_offset);
> > > > +
> > > > +/**
> > > >   * Query flow classifier for given rule.
> > > >   *
> > > >   * @param[in] cls
> > > > diff --git
> > > > a/lib/librte_flow_classify/rte_flow_classify_version.map
> > > > b/lib/librte_flow_classify/rte_flow_classify_version.map
> > > > index 49bc25c..b51cb1a 100644
> > > > --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> > > > +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> > > > @@ -4,6 +4,7 @@ EXPERIMENTAL {
> > > >  	rte_flow_classifier_create;
> > > >  	rte_flow_classifier_free;
> > > >  	rte_flow_classifier_query;
> > > > +	rte_flow_classifier_run;
> > > >  	rte_flow_classify_table_create;
> > > >  	rte_flow_classify_table_entry_add;
> > > >  	rte_flow_classify_table_entry_delete;
> > > > --
> > > > 2.9.3
> > >
> <snip>
> 
> Tests should be added to test_flow_classify.c for the
> rte_flow_classifier_run() API.
> The flow_classify sample application should exercise the
> rte_flow_classifier_run() API.

Ok, will do in v2.

Jasvinder

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib
  2017-12-11 14:54   ` Mcnamara, John
@ 2017-12-11 15:53     ` Singh, Jasvinder
  0 siblings, 0 replies; 41+ messages in thread
From: Singh, Jasvinder @ 2017-12-11 15:53 UTC (permalink / raw)
  To: Mcnamara, John, dev; +Cc: Iremonger, Bernard



> -----Original Message-----
> From: Mcnamara, John
> Sent: Monday, December 11, 2017 2:55 PM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: RE: [dpdk-dev] [PATCH 3/3] doc: update documentation for flow
> classify lib
> 
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
> > Sent: Thursday, November 23, 2017 11:32 AM
> > To: dev@dpdk.org
> > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > Subject: [dpdk-dev] [PATCH 3/3] doc: update documentation for flow
> > classify lib
> >
> > Updates the documentation for flow classification library and sample
> > application.
> >
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> 
> 
> >
> > +370,24 @@ parses the Flow rule.
> >
> >      struct rte_flow_classify {
> >          uint32_t id;  /* unique ID of classify object */
> > -        struct rte_flow_action action; /* action when match found */
> > -	struct classify_rules rules; /* union of rules */
> > +        enum rte_flow_classify_table_type tbl_type; /* rule table */
> > +        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
> > */
> > +        struct rte_flow_classify_table_entry entry;  /* rule meta data */
> > +       void *entry_ptr; /* handle to the table entry for rule meta
> > + data
> 
> 
> The last line here is indented less than the others. Also there is a stray tab a
> few lines above it (in the existing text). Can you replace that as well.
> 

Will fix this in the next version. Thank you.

Jasvinder

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2017-11-23 11:32 [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
                   ` (2 preceding siblings ...)
  2017-12-04 16:45 ` [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Iremonger, Bernard
@ 2017-12-11 16:26 ` Jasvinder Singh
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 2/4] test/test_flow_classify: update test to accomodate changes Jasvinder Singh
                     ` (3 more replies)
  3 siblings, 4 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-11 16:26 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, john.mcnamara

This patch removes table id parameter from all the flow
classify apis to reduce the complexity alongwith some code
cleanup.

The validate api is exposed as public api to allow user
to validate the flow before adding it to the classifier.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v2:
- break the patche into multiple
- fix the error checks

 lib/librte_flow_classify/rte_flow_classify.c       | 313 +++++++++++----------
 lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
 lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
 lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
 .../rte_flow_classify_version.map                  |   1 +
 5 files changed, 296 insertions(+), 226 deletions(-)

diff --git a/lib/librte_flow_classify/rte_flow_classify.c b/lib/librte_flow_classify/rte_flow_classify.c
index e6f4486..c2200df 100644
--- a/lib/librte_flow_classify/rte_flow_classify.c
+++ b/lib/librte_flow_classify/rte_flow_classify.c
@@ -39,16 +39,20 @@
 
 int librte_flow_classify_logtype;
 
-static struct rte_eth_ntuple_filter ntuple_filter;
 static uint32_t unique_id = 1;
 
+enum rte_flow_classify_table_type table_type
+	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
 
 struct rte_flow_classify_table_entry {
 	/* meta-data for classify rule */
 	uint32_t rule_id;
+
+	/* Flow action */
+	struct classify_action action;
 };
 
-struct rte_table {
+struct rte_cls_table {
 	/* Input parameters */
 	struct rte_table_ops ops;
 	uint32_t entry_size;
@@ -64,11 +68,16 @@ struct rte_flow_classifier {
 	/* Input parameters */
 	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
 	int socket_id;
-	enum rte_flow_classify_table_type type;
 
-	/* Internal tables */
-	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	/* Internal */
+	/* ntuple_fliter */
+	struct rte_eth_ntuple_filter ntuple_filter;
+
+	/* clasifier tables */
+	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	uint32_t table_mask;
 	uint32_t num_tables;
+
 	uint16_t nb_pkts;
 	struct rte_flow_classify_table_entry
 		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -97,18 +106,19 @@ struct classify_rules {
 
 struct rte_flow_classify_rule {
 	uint32_t id; /* unique ID of classify rule */
-	struct rte_flow_action action; /* action when match found */
+	enum rte_flow_classify_table_type tbl_type; /* rule table */
 	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 */
+	struct rte_flow_classify_table_entry entry;  /* rule meta data */
 	void *entry_ptr; /* handle to the table entry for rule meta data */
 };
 
-static int
-flow_classify_parse_flow(
+int
+rte_flow_classify_validate(
+		   struct rte_flow_classifier *cls,
 		   const struct rte_flow_attr *attr,
 		   const struct rte_flow_item pattern[],
 		   const struct rte_flow_action actions[],
@@ -120,7 +130,38 @@ flow_classify_parse_flow(
 	uint32_t i = 0;
 	int ret;
 
-	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
+	if (error == NULL)
+		return -EINVAL;
+
+	if (cls == NULL) {
+		RTE_FLOW_CLASSIFY_LOG(ERR,
+			"%s: rte_flow_classifier parameter is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (!attr) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ATTR,
+				   NULL, "NULL attribute.");
+		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;
+	}
+
+	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
 
 	/* Get the non-void item number of pattern */
 	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
@@ -150,7 +191,7 @@ flow_classify_parse_flow(
 		return -EINVAL;
 	}
 
-	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
+	ret = parse_filter(attr, items, actions, &cls->ntuple_filter, error);
 	free(items);
 	return ret;
 }
@@ -275,17 +316,14 @@ rte_flow_classifier_create(struct rte_flow_classifier_params *params)
 	/* 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;
+	cls->socket_id = params->socket_id;
 
 	return cls;
 }
 
 static void
-rte_flow_classify_table_free(struct rte_table *table)
+rte_flow_classify_table_free(struct rte_cls_table *table)
 {
 	if (table->ops.f_free != NULL)
 		table->ops.f_free(table->h_table);
@@ -306,7 +344,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 	/* Free tables */
 	for (i = 0; i < cls->num_tables; i++) {
-		struct rte_table *table = &cls->tables[i];
+		struct rte_cls_table *table = &cls->tables[i];
 
 		rte_flow_classify_table_free(table);
 	}
@@ -319,8 +357,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 static int
 rte_table_check_params(struct rte_flow_classifier *cls,
-		struct rte_flow_classify_table_params *params,
-		uint32_t *table_id)
+		struct rte_flow_classify_table_params *params)
 {
 	if (cls == NULL) {
 		RTE_FLOW_CLASSIFY_LOG(ERR,
@@ -333,11 +370,6 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 			__func__);
 		return -EINVAL;
 	}
-	if (table_id == NULL) {
-		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is NULL\n",
-			__func__);
-		return -EINVAL;
-	}
 
 	/* ops */
 	if (params->ops == NULL) {
@@ -371,22 +403,18 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 
 int
 rte_flow_classify_table_create(struct rte_flow_classifier *cls,
-	struct rte_flow_classify_table_params *params,
-	uint32_t *table_id)
+	struct rte_flow_classify_table_params *params)
 {
-	struct rte_table *table;
+	struct rte_cls_table *table;
 	void *h_table;
-	uint32_t entry_size, id;
+	uint32_t entry_size;
 	int ret;
 
 	/* Check input arguments */
-	ret = rte_table_check_params(cls, params, table_id);
+	ret = rte_table_check_params(cls, params);
 	if (ret != 0)
 		return ret;
 
-	id = cls->num_tables;
-	table = &cls->tables[id];
-
 	/* calculate table entry size */
 	entry_size = sizeof(struct rte_flow_classify_table_entry);
 
@@ -400,8 +428,9 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 	}
 
 	/* Commit current table to the classifier */
+	table = &cls->tables[cls->num_tables];
+	table->type = params->type;
 	cls->num_tables++;
-	*table_id = id;
 
 	/* Save input parameters */
 	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
@@ -414,7 +443,7 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 }
 
 static struct rte_flow_classify_rule *
-allocate_acl_ipv4_5tuple_rule(void)
+allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
 {
 	struct rte_flow_classify_rule *rule;
 	int log_level;
@@ -427,45 +456,44 @@ allocate_acl_ipv4_5tuple_rule(void)
 	rule->id = unique_id++;
 	rule->rules.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.priority = cls->ntuple_filter.priority;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
-			ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto_mask;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
-			ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto_mask = cls->ntuple_filter.proto_mask;
 
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.src_ip_mask;
+			cls->ntuple_filter.src_ip_mask;
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
-			ntuple_filter.src_ip;
-	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
-	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
+			cls->ntuple_filter.src_ip;
+	rule->rules.u.ipv4_5tuple.src_ip_mask = cls->ntuple_filter.src_ip_mask;
+	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
 
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.dst_ip_mask;
+			cls->ntuple_filter.dst_ip_mask;
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
-			ntuple_filter.dst_ip;
-	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
-	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
+			cls->ntuple_filter.dst_ip;
+	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls->ntuple_filter.dst_ip_mask;
+	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
 
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.src_port_mask;
+			cls->ntuple_filter.src_port_mask;
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
-			ntuple_filter.src_port;
-	rule->rules.u.ipv4_5tuple.src_port_mask = ntuple_filter.src_port_mask;
-	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
+			cls->ntuple_filter.src_port;
+	rule->rules.u.ipv4_5tuple.src_port_mask =
+			cls->ntuple_filter.src_port_mask;
+	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
 
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.dst_port_mask;
+			cls->ntuple_filter.dst_port_mask;
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
-			ntuple_filter.dst_port;
-	rule->rules.u.ipv4_5tuple.dst_port_mask = ntuple_filter.dst_port_mask;
-	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
+			cls->ntuple_filter.dst_port;
+	rule->rules.u.ipv4_5tuple.dst_port_mask =
+			cls->ntuple_filter.dst_port_mask;
+	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
 
 	log_level = rte_log_get_level(librte_flow_classify_logtype);
 
@@ -485,34 +513,21 @@ allocate_acl_ipv4_5tuple_rule(void)
 
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error)
 {
 	struct rte_flow_classify_rule *rule;
 	struct rte_flow_classify_table_entry *table_entry;
+	struct classify_action *action;
+	uint32_t i;
 	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 (key_found == NULL) {
 		rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -520,91 +535,95 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
 		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 = flow_classify_parse_flow(attr, pattern, actions, error);
+	ret = rte_flow_classify_validate(cls, attr, pattern, actions, error);
 	if (ret < 0)
 		return NULL;
 
-	switch (cls->type) {
-	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
-		rule = allocate_acl_ipv4_5tuple_rule();
+	switch (table_type) {
+	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
+		rule = allocate_acl_ipv4_5tuple_rule(cls);
 		if (!rule)
 			return NULL;
+		rule->tbl_type = table_type;
+		cls->table_mask |= table_type;
 		break;
 	default:
 		return NULL;
 	}
 
-	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
-	if (!rule->entry) {
-		free(rule);
-		return NULL;
-	}
-
-	table_entry = rule->entry;
+	action = classify_get_flow_action();
+	table_entry = &rule->entry;
 	table_entry->rule_id = rule->id;
+	table_entry->action.action_mask = action->action_mask;
 
-	if (cls->tables[table_id].ops.f_add != NULL) {
-		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);
-			return NULL;
+	/* Copy actions */
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
+		memcpy(&table_entry->action.act.counter, &action->act.counter,
+				sizeof(table_entry->action.act.counter));
+	}
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_MARK)) {
+		memcpy(&table_entry->action.act.mark, &action->act.mark,
+				sizeof(table_entry->action.act.mark));
+	}
+
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+		if (table->type == table_type) {
+			if (table->ops.f_add != NULL) {
+				ret = table->ops.f_add(
+					table->h_table,
+					&rule->u.key.key_add,
+					&rule->entry,
+					&rule->key_found,
+					&rule->entry_ptr);
+				if (ret) {
+					free(rule);
+					return NULL;
+				}
+
+			*key_found = rule->key_found;
+			}
+
+			return rule;
 		}
-		*key_found = rule->key_found;
 	}
-	return rule;
+	return NULL;
 }
 
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule)
 {
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || table_id >= cls->num_tables)
+	if (!cls || !rule)
 		return ret;
+	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
+
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
 
-	if (cls->tables[table_id].ops.f_delete != NULL)
-		ret = cls->tables[table_id].ops.f_delete(
-			cls->tables[table_id].h_table,
-			&rule->u.key.key_del,
-			&rule->key_found,
-			&rule->entry);
+		if (table->type == tbl_type) {
+			if (table->ops.f_delete != NULL) {
+				ret = table->ops.f_delete(table->h_table,
+						&rule->u.key.key_del,
+						&rule->key_found,
+						&rule->entry);
 
+				return ret;
+			}
+		}
+	}
+	free(rule);
 	return ret;
 }
 
 static int
 flow_classifier_lookup(struct rte_flow_classifier *cls,
-		uint32_t table_id,
+		struct rte_cls_table *table,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts)
 {
@@ -613,8 +632,7 @@ flow_classifier_lookup(struct rte_flow_classifier *cls,
 	uint64_t lookup_hit_mask;
 
 	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
-	ret = cls->tables[table_id].ops.f_lookup(
-		cls->tables[table_id].h_table,
+	ret = table->ops.f_lookup(table->h_table,
 		pkts, pkts_mask, &lookup_hit_mask,
 		(void **)cls->entries);
 
@@ -632,12 +650,12 @@ action_apply(struct rte_flow_classifier *cls,
 		struct rte_flow_classify_stats *stats)
 {
 	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
+	struct rte_flow_classify_table_entry *entry = &rule->entry;
 	uint64_t count = 0;
-	int i;
-	int ret = -EINVAL;
+	uint32_t action_mask = entry->action.action_mask;
+	int i, ret = -EINVAL;
 
-	switch (rule->action.type) {
-	case RTE_FLOW_ACTION_TYPE_COUNT:
+	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
 		for (i = 0; i < cls->nb_pkts; i++) {
 			if (rule->id == cls->entries[i]->rule_id)
 				count++;
@@ -650,32 +668,37 @@ action_apply(struct rte_flow_classifier *cls,
 			ntuple_stats->counter1 = count;
 			ntuple_stats->ipv4_5tuple = rule->rules.u.ipv4_5tuple;
 		}
-		break;
-	default:
-		ret = -ENOTSUP;
-		break;
 	}
-
 	return ret;
 }
 
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
 		struct rte_flow_classify_stats *stats)
 {
+	enum rte_flow_classify_table_type tbl_type;
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
-		table_id >= cls->num_tables)
+	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
 		return ret;
 
-	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
-	if (!ret)
-		ret = action_apply(cls, rule, stats);
+	tbl_type = rule->tbl_type;
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+			if (table->type == tbl_type) {
+				ret = flow_classifier_lookup(cls, table,
+						pkts, nb_pkts);
+				if (!ret) {
+					ret = action_apply(cls, rule, stats);
+					return ret;
+				}
+			}
+	}
 	return ret;
 }
 
diff --git a/lib/librte_flow_classify/rte_flow_classify.h b/lib/librte_flow_classify/rte_flow_classify.h
index 1211873..b9b669f 100644
--- a/lib/librte_flow_classify/rte_flow_classify.h
+++ b/lib/librte_flow_classify/rte_flow_classify.h
@@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
 rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
 	__func__, ## args)
 
+#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
+#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
+#endif
+
 /** Opaque data type for flow classifier */
 struct rte_flow_classifier;
 
@@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
 
 /** Flow classify table type */
 enum rte_flow_classify_table_type {
-	/** no type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
-	/** ACL type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
-};
+	/** No type */
+	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
+	/** ACL IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
+	/** ACL VLAN IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
+	/** ACL QinQ IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
 
-/**
- * Maximum number of tables allowed for any Flow Classifier instance.
- * The value of this parameter cannot be changed.
- */
-#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
+};
 
 /** Parameters for flow classifier creation */
 struct rte_flow_classifier_params {
@@ -122,9 +125,6 @@ struct rte_flow_classifier_params {
 	/** 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;
 };
 
 /** Parameters for table creation */
@@ -134,6 +134,9 @@ struct rte_flow_classify_table_params {
 
 	/** Opaque param to be passed to the table create operation */
 	void *arg_create;
+
+	/** Classifier table type */
+	enum rte_flow_classify_table_type type;
 };
 
 /** IPv4 5-tuple data */
@@ -197,32 +200,50 @@ rte_flow_classifier_free(struct rte_flow_classifier *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);
+		struct rte_flow_classify_table_params *params);
+
+/**
+ * Flow classify validate
+ *
+ * @param cls
+ *   Handle to flow classifier instance
+ * @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(struct rte_flow_classifier *cls,
+		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[out] key_found
- *  returns 1 if key present already, 0 otherwise.
  * @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] key_found
+ *  returns 1 if rule present already, 0 otherwise.
  * @param[out] error
  *   Perform verbose error reporting if not NULL. Structure
  *   initialised in case of error only.
@@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
  */
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error);
 
 /**
@@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  *
  * @param[in] cls
  *   Flow classifier handle
- * @param[in] table_id
- *   id of table
  * @param[in] rule
  *   Flow classify rule
  * @return
@@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule);
 
 /**
@@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  *
  * @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
@@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.c b/lib/librte_flow_classify/rte_flow_classify_parse.c
index dbfa111..9fb3e51 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.c
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
@@ -40,7 +40,7 @@ struct classify_valid_pattern {
 	parse_filter_t parse_filter;
 };
 
-static struct rte_flow_action action;
+static struct classify_action action;
 
 /* Pattern for IPv4 5-tuple UDP filter */
 static enum rte_flow_item_type pattern_ntuple_1[] = {
@@ -80,7 +80,7 @@ static struct classify_valid_pattern classify_supported_patterns[] = {
 	{ pattern_ntuple_3, classify_parse_ntuple_filter },
 };
 
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void)
 {
 	return &action;
@@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	const struct rte_flow_item_udp *udp_mask;
 	const struct rte_flow_item_sctp *sctp_spec;
 	const struct rte_flow_item_sctp *sctp_mask;
+	const struct rte_flow_action_count *count;
+	const struct rte_flow_action_mark *mark_spec;
 	uint32_t index;
 
-	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;
-	}
-
 	/* parse pattern */
 	index = 0;
 
@@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 		return -EINVAL;
 	}
 
-	/* parse action */
-	index = 0;
-
-	/**
-	 * n-tuple only supports count,
-	 * check if the first not void action is COUNT.
-	 */
-	memset(&action, 0, sizeof(action));
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			item, "Not supported action.");
-		return -EINVAL;
-	}
-	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
-
-	/* check if the next not void item is END */
-	index++;
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			act, "Not supported action.");
-		return -EINVAL;
-	}
+	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
 	/* parse attr */
 	/* must be input direction */
@@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
 		filter->priority = FLOW_RULE_MAX_PRIORITY;
 
+	/* parse action */
+	index = 0;
+
+	/**
+	 * n-tuple only supports count and Mark,
+	 * check if the first not void action is COUNT or MARK.
+	 */
+	memset(&action, 0, sizeof(action));
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is MARK or COUNT or END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	case RTE_FLOW_ACTION_TYPE_END:
+		return 0;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
 	return 0;
 }
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h b/lib/librte_flow_classify/rte_flow_classify_parse.h
index 1d4708a..9c1de72 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.h
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
@@ -43,6 +43,20 @@
 extern "C" {
 #endif
 
+extern enum rte_flow_classify_table_type table_type;
+
+struct classify_action {
+	/* Flow action mask */
+	uint64_t action_mask;
+
+	struct action {
+		/** Integer value to return with packets */
+		struct rte_flow_action_mark mark;
+		/** Flow rule counter */
+		struct rte_flow_query_count counter;
+	} act;
+};
+
 typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
 			      const struct rte_flow_item pattern[],
 			      const struct rte_flow_action actions[],
@@ -64,7 +78,7 @@ parse_filter_t
 classify_find_parse_filter_func(struct rte_flow_item *pattern);
 
 /* get action data */
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void);
 
 #ifdef __cplusplus
diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map b/lib/librte_flow_classify/rte_flow_classify_version.map
index f7695cb..49bc25c 100644
--- a/lib/librte_flow_classify/rte_flow_classify_version.map
+++ b/lib/librte_flow_classify/rte_flow_classify_version.map
@@ -7,6 +7,7 @@ EXPERIMENTAL {
 	rte_flow_classify_table_create;
 	rte_flow_classify_table_entry_add;
 	rte_flow_classify_table_entry_delete;
+	rte_flow_classify_validate;
 
 	local: *;
 };
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 2/4] test/test_flow_classify: update test to accomodate changes
  2017-12-11 16:26 ` [dpdk-dev] [PATCH v2 1/4] " Jasvinder Singh
@ 2017-12-11 16:26   ` Jasvinder Singh
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 3/4] examples/flow_classify: update sample application Jasvinder Singh
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-11 16:26 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, john.mcnamara

Test have ben modified to adapt the flow_classify api
changes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v2: 
- add validate API tests

 test/test/test_flow_classify.c | 178 +++++++++++++++++++++++++++++------------
 test/test/test_flow_classify.h |  10 ++-
 2 files changed, 135 insertions(+), 53 deletions(-)

diff --git a/test/test/test_flow_classify.c b/test/test/test_flow_classify.c
index 9f331cd..c8fd5ad 100644
--- a/test/test/test_flow_classify.c
+++ b/test/test/test_flow_classify.c
@@ -51,16 +51,10 @@
 
 
 #define FLOW_CLASSIFY_MAX_RULE_NUM 100
-struct flow_classifier *cls;
-
-struct flow_classifier {
-	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
-	uint32_t n_tables;
-};
+struct flow_classifier_acl *cls;
 
 struct flow_classifier_acl {
-	struct flow_classifier cls;
+	struct rte_flow_classifier *cls;
 } __rte_cache_aligned;
 
 /*
@@ -73,7 +67,15 @@ test_invalid_parameters(void)
 	struct rte_flow_classify_rule *rule;
 	int ret;
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	ret = rte_flow_classify_validate(NULL, NULL, NULL, NULL, NULL);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate",
+			__LINE__);
+		printf(" with NULL param should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 			NULL, NULL);
 	if (rule) {
 		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
@@ -81,7 +83,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -89,14 +91,14 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
 		return -1;
 	}
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 		NULL, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
@@ -104,7 +106,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -112,7 +114,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
@@ -129,7 +131,8 @@ test_valid_parameters(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -142,15 +145,24 @@ test_valid_parameters(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: rte_flow_classify_validate",
+			__LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
+
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -168,7 +180,8 @@ test_invalid_patterns(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -183,15 +196,24 @@ test_invalid_patterns(void)
 
 	pattern[0] = eth_item;
 	pattern[1] = ipv4_udp_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -202,15 +224,24 @@ test_invalid_patterns(void)
 	pattern[1] = ipv4_udp_item_1;
 	pattern[2] = udp_item_bad;
 	pattern[3] = end_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -228,7 +259,8 @@ test_invalid_actions(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -241,15 +273,23 @@ test_invalid_actions(void)
 	actions[0] = count_action_bad;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -260,15 +300,23 @@ test_invalid_actions(void)
 	actions[0] = count_action;
 	actions[1] = end_action_bad;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -449,7 +497,8 @@ test_query_udp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -462,15 +511,23 @@ test_query_udp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &udp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -478,7 +535,7 @@ test_query_udp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -507,7 +564,8 @@ test_query_tcp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -520,15 +578,23 @@ test_query_tcp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: flow_classifier_query", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &tcp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -536,7 +602,7 @@ test_query_tcp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -565,7 +631,8 @@ test_query_sctp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters rte_flow_classify_table_entry_add and
+	 * set up parameters rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -578,15 +645,23 @@ test_query_sctp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: flow_classifier_query", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &sctp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -594,7 +669,7 @@ test_query_sctp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -622,7 +697,6 @@ test_flow_classify(void)
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 	cls->cls = rte_flow_classifier_create(&cls_params);
 
 	/* initialise ACL table params */
@@ -632,11 +706,11 @@ test_flow_classify(void)
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
-			&cls->table_id[0]);
+	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
 	if (ret) {
 		printf("Line %i: f_create has failed!\n", __LINE__);
 		rte_flow_classifier_free(cls->cls);
diff --git a/test/test/test_flow_classify.h b/test/test/test_flow_classify.h
index 39535cf..af293ed 100644
--- a/test/test/test_flow_classify.h
+++ b/test/test/test_flow_classify.h
@@ -197,7 +197,15 @@ static struct rte_flow_item  sctp_item_1 = { RTE_FLOW_ITEM_TYPE_SCTP,
 /* test actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action count_action_bad = { -1, 0};
 
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 3/4] examples/flow_classify: update sample application
  2017-12-11 16:26 ` [dpdk-dev] [PATCH v2 1/4] " Jasvinder Singh
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 2/4] test/test_flow_classify: update test to accomodate changes Jasvinder Singh
@ 2017-12-11 16:26   ` Jasvinder Singh
  2017-12-14 14:42     ` Iremonger, Bernard
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 4/4] doc: update documentation for flow classify lib Jasvinder Singh
  2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
  3 siblings, 1 reply; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-11 16:26 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, john.mcnamara

Update the flow_classify sample app to adapt the changes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v2:
- use validate api to verify before adding flow rule

 examples/flow_classify/flow_classify.c | 36 +++++++++++++++++++++++-----------
 1 file changed, 25 insertions(+), 11 deletions(-)

diff --git a/examples/flow_classify/flow_classify.c b/examples/flow_classify/flow_classify.c
index 766f1dd..25b8fc6 100644
--- a/examples/flow_classify/flow_classify.c
+++ b/examples/flow_classify/flow_classify.c
@@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default = {
 
 struct flow_classifier {
 	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
 };
 
 struct flow_classifier_acl {
@@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = { RTE_FLOW_ITEM_TYPE_END,
 /* sample actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
 static struct rte_flow_action actions[2];
 
@@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
 	int i = 0;
 
 	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
-			cls_app->table_id[0], rules[7]);
+			rules[7]);
 	if (ret)
 		printf("table_entry_delete failed [7] %d\n\n", ret);
 	else
@@ -317,7 +324,6 @@ lcore_main(struct flow_classifier *cls_app)
 				if (rules[i]) {
 					ret = rte_flow_classifier_query(
 						cls_app->cls,
-						cls_app->table_id[0],
 						bufs, nb_rx, rules[i],
 						&classify_stats);
 					if (ret)
@@ -634,9 +640,18 @@ add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
 	actions[0] = count_action;
 	actions[1] = end_action;
 
+	/* Validate and add rule */
+	ret = rte_flow_classify_validate(cls_app->cls, &attr,
+			pattern_ipv4_5tuple, actions);
+	if (ret) {
+		printf("table entry validate failed ipv4_proto = %u\n",
+			ipv4_proto);
+		return ret;
+	}
+
 	rule = rte_flow_classify_table_entry_add(
-			cls_app->cls, cls_app->table_id[0], &key_found,
-			&attr, pattern_ipv4_5tuple, actions, &error);
+			cls_app->cls, &attr, pattern_ipv4_5tuple,
+			actions, &key_found, &error);
 	if (rule == NULL) {
 		printf("table entry add failed ipv4_proto = %u\n",
 			ipv4_proto);
@@ -809,7 +824,6 @@ main(int argc, char *argv[])
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
 	cls_app->cls = rte_flow_classifier_create(&cls_params);
 	if (cls_app->cls == NULL) {
@@ -824,11 +838,11 @@ main(int argc, char *argv[])
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-			&cls_app->table_id[0]);
+	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
 	if (ret) {
 		rte_flow_classifier_free(cls_app->cls);
 		rte_free(cls_app);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v2 4/4] doc: update documentation for flow classify lib
  2017-12-11 16:26 ` [dpdk-dev] [PATCH v2 1/4] " Jasvinder Singh
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 2/4] test/test_flow_classify: update test to accomodate changes Jasvinder Singh
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 3/4] examples/flow_classify: update sample application Jasvinder Singh
@ 2017-12-11 16:26   ` Jasvinder Singh
  2017-12-14 14:49     ` Iremonger, Bernard
  2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
  3 siblings, 1 reply; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-11 16:26 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, john.mcnamara

Updates the documentation for flow classification
library and sample application.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v2:
- replace parse flow function with validate API

 doc/guides/prog_guide/flow_classify_lib.rst | 59 ++++++++++++-----------------
 doc/guides/sample_app_ug/flow_classify.rst  |  8 +---
 2 files changed, 27 insertions(+), 40 deletions(-)

diff --git a/doc/guides/prog_guide/flow_classify_lib.rst b/doc/guides/prog_guide/flow_classify_lib.rst
index 820dc72..b0d3c1e 100644
--- a/doc/guides/prog_guide/flow_classify_lib.rst
+++ b/doc/guides/prog_guide/flow_classify_lib.rst
@@ -101,30 +101,26 @@ The library has the following API's
      *   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);
+           struct rte_flow_classify_table_params *params);
 
     /**
      * Add a flow classify rule to the flow_classifier 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] key_found
+     *   returns 1 if rule present already, 0 otherwise.
      * @param[out] error
      *   Perform verbose error reporting if not NULL. Structure
      *   initialised in case of error only.
@@ -133,10 +129,10 @@ The library has the following API's
      */
     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[],
+            int *key_found;
             struct rte_flow_error *error);
 
     /**
@@ -144,8 +140,6 @@ The library has the following API's
      *
      * @param[in] cls
      *   Flow classifier handle
-     * @param[in] table_id
-     *   id of table
      * @param[in] rule
      *   Flow classify rule
      * @return
@@ -153,7 +147,6 @@ The library has the following API's
      */
     int
     rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_flow_classify_rule *rule);
 
     /**
@@ -161,8 +154,6 @@ The library has the following API's
      *
      * @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
@@ -177,7 +168,6 @@ The library has the following API's
      */
     int
     rte_flow_classifier_query(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_mbuf **pkts,
             const uint16_t nb_pkts,
             struct rte_flow_classify_rule *rule,
@@ -200,16 +190,13 @@ application before calling the API.
         /** 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;
     };
 
 The ``Classifier`` has the following internal structures:
 
 .. code-block:: c
 
-    struct rte_table {
+    struct rte_cls_table {
         /* Input parameters */
         struct rte_table_ops ops;
         uint32_t entry_size;
@@ -225,11 +212,16 @@ The ``Classifier`` has the following internal structures:
         /* Input parameters */
         char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
         int socket_id;
-        enum rte_flow_classify_table_type type;
 
-        /* Internal tables */
-        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        /* Internal */
+        /* ntuple_fliter */
+        struct rte_eth_ntuple_filter ntuple_filter;
+
+        /* clasifier tables */
+        struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        uint32_t table_mask;
         uint32_t num_tables;
+
         uint16_t nb_pkts;
         struct rte_flow_classify_table_entry
             *entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -252,9 +244,8 @@ application before calling the API.
         /** 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;
+        /** Classifier table type */
+        enum rte_flow_classify_table_type type;
      };
 
 To create an ACL table the ``rte_table_acl_params`` structure must be
@@ -314,14 +305,14 @@ and SCTP.
         RTE_FLOW_ITEM_TYPE_END,
     };
 
-The internal function ``flow_classify_parse_flow`` parses the
+The API function ``rte_flow_classify_validate`` parses the
 IPv4 5-tuple pattern, attributes and actions and returns the 5-tuple data in the
 ``rte_eth_ntuple_filter`` structure.
 
 .. code-block:: c
 
     static int
-    flow_classify_parse_flow(
+    rte_flow_classify_validate(struct rte_flow_classifier *cls,
                    const struct rte_flow_attr *attr,
                    const struct rte_flow_item pattern[],
                    const struct rte_flow_action actions[],
@@ -333,7 +324,7 @@ Adding Flow Rules
 The ``rte_flow_classify_table_entry_add`` API creates an
 ``rte_flow_classify`` object which contains the flow_classify id and type, the
 action, a union of add and delete keys and a union of rules.
-It uses the ``flow_classify_parse_flow`` internal function for parsing the
+It uses the ``rte_flow_classify_validate`` api function for parsing the
 flow parameters.
 The 5-tuple ACL key data is obtained from the ``rte_eth_ntuple_filter``
 structure populated by the ``classify_parse_ntuple_filter`` function which
@@ -343,7 +334,7 @@ parses the Flow rule.
 
     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_table_acl_rule_delete_params key_del; /* delete key */
     };
 
     struct classify_rules {
@@ -355,24 +346,24 @@ parses the Flow rule.
 
     struct rte_flow_classify {
         uint32_t id;  /* unique ID of classify object */
-        struct rte_flow_action action; /* action when match found */
-	struct classify_rules rules; /* union of rules */
+        enum rte_flow_classify_table_type tbl_type; /* rule table */
+        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 */
+        struct rte_flow_classify_table_entry entry;  /* rule meta data */
         void *entry_ptr; /* handle to the table entry for rule meta data */
     };
 
-It then calls the ``table[table_id].ops.f_add`` API to add the rule to the ACL
+It then calls the ``table.ops.f_add`` API to add the rule to the ACL
 table.
 
 Deleting Flow Rules
 ~~~~~~~~~~~~~~~~~~~
 
 The ``rte_flow_classify_table_entry_delete`` API calls the
-``table[table_id].ops.f_delete`` API to delete a rule from the ACL table.
+``table.ops.f_delete`` API to delete a rule from the ACL table.
 
 Packet Matching
 ~~~~~~~~~~~~~~~
@@ -380,7 +371,7 @@ Packet Matching
 The ``rte_flow_classifier_query`` API is used to find packets which match a
 given flow Flow rule in the table.
 This API calls the flow_classify_run internal function which calls the
-``table[table_id].ops.f_lookup`` API to see if any packets in a burst match any
+``table.ops.f_lookup`` API to see if any packets in a burst match any
 of the Flow rules in the table.
 The meta data for the highest priority rule matched for each packet is returned
 in the entries array in the ``rte_flow_classify`` object.
diff --git a/doc/guides/sample_app_ug/flow_classify.rst b/doc/guides/sample_app_ug/flow_classify.rst
index bc12b87..427fded 100644
--- a/doc/guides/sample_app_ug/flow_classify.rst
+++ b/doc/guides/sample_app_ug/flow_classify.rst
@@ -228,7 +228,6 @@ table`` to the flow classifier.
 
     struct flow_classifier {
         struct rte_flow_classifier *cls;
-        uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
     };
 
     struct flow_classifier_acl {
@@ -243,7 +242,6 @@ table`` to the flow classifier.
 
     cls_params.name = "flow_classifier";
     cls_params.socket_id = socket_id;
-    cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
     cls_app->cls = rte_flow_classifier_create(&cls_params);
     if (cls_app->cls == NULL) {
@@ -260,10 +258,9 @@ table`` to the flow classifier.
     /* initialise table create params */
     cls_table_params.ops = &rte_table_acl_ops,
     cls_table_params.arg_create = &table_acl_params,
-    cls_table_params.table_metadata_size = 0;
+    cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-                  &cls->table_id[0]);
+    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
     if (ret) {
         rte_flow_classifier_free(cls_app->cls);
         rte_free(cls);
@@ -495,7 +492,6 @@ following:
                     if (rules[i]) {
                         ret = rte_flow_classifier_query(
                             cls_app->cls,
-                            cls_app->table_id[0],
                             bufs, nb_rx, rules[i],
                             &classify_stats);
                         if (ret)
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v2 3/4] examples/flow_classify: update sample application
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 3/4] examples/flow_classify: update sample application Jasvinder Singh
@ 2017-12-14 14:42     ` Iremonger, Bernard
  0 siblings, 0 replies; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-14 14:42 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Mcnamara, John

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Monday, December 11, 2017 4:27 PM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>; Mcnamara, John
> <john.mcnamara@intel.com>
> Subject: [PATCH v2 3/4] examples/flow_classify: update sample application
> 
> Update the flow_classify sample app to adapt the changes.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
> v2:
> - use validate api to verify before adding flow rule
> 
>  examples/flow_classify/flow_classify.c | 36 +++++++++++++++++++++++--------
> ---
>  1 file changed, 25 insertions(+), 11 deletions(-)
> 
> diff --git a/examples/flow_classify/flow_classify.c
> b/examples/flow_classify/flow_classify.c
> index 766f1dd..25b8fc6 100644
> --- a/examples/flow_classify/flow_classify.c
> +++ b/examples/flow_classify/flow_classify.c
> @@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default = {
> 
>  struct flow_classifier {
>  	struct rte_flow_classifier *cls;
> -	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
>  };
> 
>  struct flow_classifier_acl {
> @@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = {
> RTE_FLOW_ITEM_TYPE_END,
>  /* sample actions:
>   * "actions count / end"
>   */
> -static struct rte_flow_action count_action = {
> RTE_FLOW_ACTION_TYPE_COUNT, 0};
> +struct rte_flow_query_count count = {
> +	.reset = 1,
> +	.hits_set = 1,
> +	.bytes_set = 1,
> +	.hits = 0,
> +	.bytes = 0,
> +};
> +static struct rte_flow_action count_action = {
> RTE_FLOW_ACTION_TYPE_COUNT,
> +	&count};
>  static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
> static struct rte_flow_action actions[2];
> 
> @@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
>  	int i = 0;
> 
>  	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
> -			cls_app->table_id[0], rules[7]);
> +			rules[7]);
>  	if (ret)
>  		printf("table_entry_delete failed [7] %d\n\n", ret);
>  	else
> @@ -317,7 +324,6 @@ lcore_main(struct flow_classifier *cls_app)
>  				if (rules[i]) {
>  					ret = rte_flow_classifier_query(
>  						cls_app->cls,
> -						cls_app->table_id[0],
>  						bufs, nb_rx, rules[i],
>  						&classify_stats);
>  					if (ret)
> @@ -634,9 +640,18 @@ add_classify_rule(struct rte_eth_ntuple_filter
> *ntuple_filter,
>  	actions[0] = count_action;
>  	actions[1] = end_action;
> 
> +	/* Validate and add rule */
> +	ret = rte_flow_classify_validate(cls_app->cls, &attr,
> +			pattern_ipv4_5tuple, actions);

Parameter &error is missing from validate call, resulting in a compile error.

> +	if (ret) {
> +		printf("table entry validate failed ipv4_proto = %u\n",
> +			ipv4_proto);
> +		return ret;
> +	}
> +
>  	rule = rte_flow_classify_table_entry_add(
> -			cls_app->cls, cls_app->table_id[0], &key_found,
> -			&attr, pattern_ipv4_5tuple, actions, &error);
> +			cls_app->cls, &attr, pattern_ipv4_5tuple,
> +			actions, &key_found, &error);
>  	if (rule == NULL) {
>  		printf("table entry add failed ipv4_proto = %u\n",
>  			ipv4_proto);
> @@ -809,7 +824,6 @@ main(int argc, char *argv[])
> 
>  	cls_params.name = "flow_classifier";
>  	cls_params.socket_id = socket_id;
> -	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> 
>  	cls_app->cls = rte_flow_classifier_create(&cls_params);
>  	if (cls_app->cls == NULL) {
> @@ -824,11 +838,11 @@ main(int argc, char *argv[])
>  	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
> 
>  	/* initialise table create params */
> -	cls_table_params.ops = &rte_table_acl_ops,
> -	cls_table_params.arg_create = &table_acl_params,
> +	cls_table_params.ops = &rte_table_acl_ops;
> +	cls_table_params.arg_create = &table_acl_params;
> +	cls_table_params.type =
> RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> 
> -	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
> -			&cls_app->table_id[0]);
> +	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
>  	if (ret) {
>  		rte_flow_classifier_free(cls_app->cls);
>  		rte_free(cls_app);
> --
> 2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v2 4/4] doc: update documentation for flow classify lib
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 4/4] doc: update documentation for flow classify lib Jasvinder Singh
@ 2017-12-14 14:49     ` Iremonger, Bernard
  0 siblings, 0 replies; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-14 14:49 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Mcnamara, John

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Monday, December 11, 2017 4:27 PM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>; Mcnamara, John
> <john.mcnamara@intel.com>
> Subject: [PATCH v2 4/4] doc: update documentation for flow classify lib
> 
> Updates the documentation for flow classification library and sample
> application.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
> v2:
> - replace parse flow function with validate API
> 
>  doc/guides/prog_guide/flow_classify_lib.rst | 59 ++++++++++++-----------------
> doc/guides/sample_app_ug/flow_classify.rst  |  8 +---
>  2 files changed, 27 insertions(+), 40 deletions(-)
> 
> diff --git a/doc/guides/prog_guide/flow_classify_lib.rst
> b/doc/guides/prog_guide/flow_classify_lib.rst
> index 820dc72..b0d3c1e 100644
> --- a/doc/guides/prog_guide/flow_classify_lib.rst
> +++ b/doc/guides/prog_guide/flow_classify_lib.rst
> @@ -101,30 +101,26 @@ The library has the following API's
>       *   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);
> +           struct rte_flow_classify_table_params *params);
> 
>      /**
>       * Add a flow classify rule to the flow_classifier 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] key_found
> +     *   returns 1 if rule present already, 0 otherwise.
>       * @param[out] error
>       *   Perform verbose error reporting if not NULL. Structure
>       *   initialised in case of error only.
> @@ -133,10 +129,10 @@ The library has the following API's
>       */
>      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[],
> +            int *key_found;
>              struct rte_flow_error *error);
> 
>      /**
> @@ -144,8 +140,6 @@ The library has the following API's
>       *
>       * @param[in] cls
>       *   Flow classifier handle
> -     * @param[in] table_id
> -     *   id of table
>       * @param[in] rule
>       *   Flow classify rule
>       * @return
> @@ -153,7 +147,6 @@ The library has the following API's
>       */
>      int
>      rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> -            uint32_t table_id,
>              struct rte_flow_classify_rule *rule);
> 
>      /**
> @@ -161,8 +154,6 @@ The library has the following API's
>       *
>       * @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
> @@ -177,7 +168,6 @@ The library has the following API's
>       */
>      int
>      rte_flow_classifier_query(struct rte_flow_classifier *cls,
> -            uint32_t table_id,
>              struct rte_mbuf **pkts,
>              const uint16_t nb_pkts,
>              struct rte_flow_classify_rule *rule, @@ -200,16 +190,13 @@ application
> before calling the API.
>          /** 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;
>      };
> 

A description of the rte_flow_validate API should be added to the list of API's.

>  The ``Classifier`` has the following internal structures:
> 
>  .. code-block:: c
> 
> -    struct rte_table {
> +    struct rte_cls_table {
>          /* Input parameters */
>          struct rte_table_ops ops;
>          uint32_t entry_size;
> @@ -225,11 +212,16 @@ The ``Classifier`` has the following internal structures:
>          /* Input parameters */
>          char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
>          int socket_id;
> -        enum rte_flow_classify_table_type type;
> 
> -        /* Internal tables */
> -        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +        /* Internal */
> +        /* ntuple_fliter */
> +        struct rte_eth_ntuple_filter ntuple_filter;
> +
> +        /* clasifier tables */
> +        struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +        uint32_t table_mask;
>          uint32_t num_tables;
> +
>          uint16_t nb_pkts;
>          struct rte_flow_classify_table_entry
>              *entries[RTE_PORT_IN_BURST_SIZE_MAX];
> @@ -252,9 +244,8 @@ application before calling the API.
>          /** 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;
> +        /** Classifier table type */
> +        enum rte_flow_classify_table_type type;
>       };
> 
>  To create an ACL table the ``rte_table_acl_params`` structure must be @@ -
> 314,14 +305,14 @@ and SCTP.
>          RTE_FLOW_ITEM_TYPE_END,
>      };
> 
> -The internal function ``flow_classify_parse_flow`` parses the
> +The API function ``rte_flow_classify_validate`` parses the
>  IPv4 5-tuple pattern, attributes and actions and returns the 5-tuple data in the
> ``rte_eth_ntuple_filter`` structure.
> 
>  .. code-block:: c
> 
>      static int
> -    flow_classify_parse_flow(
> +    rte_flow_classify_validate(struct rte_flow_classifier *cls,
>                     const struct rte_flow_attr *attr,
>                     const struct rte_flow_item pattern[],
>                     const struct rte_flow_action actions[], @@ -333,7 +324,7 @@
> Adding Flow Rules  The ``rte_flow_classify_table_entry_add`` API creates an
> ``rte_flow_classify`` object which contains the flow_classify id and type, the
> action, a union of add and delete keys and a union of rules.
> -It uses the ``flow_classify_parse_flow`` internal function for parsing the
> +It uses the ``rte_flow_classify_validate`` api function for parsing the
>  flow parameters.
>  The 5-tuple ACL key data is obtained from the ``rte_eth_ntuple_filter``  structure
> populated by the ``classify_parse_ntuple_filter`` function which @@ -343,7
> +334,7 @@ parses the Flow rule.
> 
>      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_table_acl_rule_delete_params key_del; /* delete key
> + */
>      };
> 
>      struct classify_rules {
> @@ -355,24 +346,24 @@ parses the Flow rule.
> 
>      struct rte_flow_classify {
>          uint32_t id;  /* unique ID of classify object */
> -        struct rte_flow_action action; /* action when match found */
> -	struct classify_rules rules; /* union of rules */
> +        enum rte_flow_classify_table_type tbl_type; /* rule table */
> +        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 */
> +        struct rte_flow_classify_table_entry entry;  /* rule meta data
> + */
>          void *entry_ptr; /* handle to the table entry for rule meta data */
>      };
> 
> -It then calls the ``table[table_id].ops.f_add`` API to add the rule to the ACL
> +It then calls the ``table.ops.f_add`` API to add the rule to the ACL
>  table.
> 
>  Deleting Flow Rules
>  ~~~~~~~~~~~~~~~~~~~
> 
>  The ``rte_flow_classify_table_entry_delete`` API calls the -
> ``table[table_id].ops.f_delete`` API to delete a rule from the ACL table.
> +``table.ops.f_delete`` API to delete a rule from the ACL table.
> 
>  Packet Matching
>  ~~~~~~~~~~~~~~~
> @@ -380,7 +371,7 @@ Packet Matching
>  The ``rte_flow_classifier_query`` API is used to find packets which match a
> given flow Flow rule in the table.
>  This API calls the flow_classify_run internal function which calls the -
> ``table[table_id].ops.f_lookup`` API to see if any packets in a burst match any
> +``table.ops.f_lookup`` API to see if any packets in a burst match any
>  of the Flow rules in the table.
>  The meta data for the highest priority rule matched for each packet is returned
> in the entries array in the ``rte_flow_classify`` object.
> diff --git a/doc/guides/sample_app_ug/flow_classify.rst
> b/doc/guides/sample_app_ug/flow_classify.rst
> index bc12b87..427fded 100644
> --- a/doc/guides/sample_app_ug/flow_classify.rst
> +++ b/doc/guides/sample_app_ug/flow_classify.rst
> @@ -228,7 +228,6 @@ table`` to the flow classifier.
> 
>      struct flow_classifier {
>          struct rte_flow_classifier *cls;
> -        uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
>      };
> 
>      struct flow_classifier_acl {
> @@ -243,7 +242,6 @@ table`` to the flow classifier.
> 
>      cls_params.name = "flow_classifier";
>      cls_params.socket_id = socket_id;
> -    cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
> 
>      cls_app->cls = rte_flow_classifier_create(&cls_params);
>      if (cls_app->cls == NULL) {
> @@ -260,10 +258,9 @@ table`` to the flow classifier.
>      /* initialise table create params */
>      cls_table_params.ops = &rte_table_acl_ops,
>      cls_table_params.arg_create = &table_acl_params,
> -    cls_table_params.table_metadata_size = 0;
> +    cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> 
> -    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
> -                  &cls->table_id[0]);
> +    ret = rte_flow_classify_table_create(cls_app->cls,
> + &cls_table_params);
>      if (ret) {
>          rte_flow_classifier_free(cls_app->cls);
>          rte_free(cls);
> @@ -495,7 +492,6 @@ following:
>                      if (rules[i]) {
>                          ret = rte_flow_classifier_query(
>                              cls_app->cls,
> -                            cls_app->table_id[0],
>                              bufs, nb_rx, rules[i],
>                              &classify_stats);
>                          if (ret)
> --
> 2.9.3

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-11 16:26 ` [dpdk-dev] [PATCH v2 1/4] " Jasvinder Singh
                     ` (2 preceding siblings ...)
  2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 4/4] doc: update documentation for flow classify lib Jasvinder Singh
@ 2017-12-15 10:39   ` Jasvinder Singh
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
                       ` (4 more replies)
  3 siblings, 5 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-15 10:39 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger

This patch removes table id parameter from all the flow
classify apis to reduce the complexity alongwith some code
cleanup.

The validate api is exposed as public api to allow user
to validate the flow before adding it to the classifier.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v2:
- break the patche into multiple
- fix the error checks

 lib/librte_flow_classify/rte_flow_classify.c       | 313 +++++++++++----------
 lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
 lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
 lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
 .../rte_flow_classify_version.map                  |   1 +
 5 files changed, 296 insertions(+), 226 deletions(-)

diff --git a/lib/librte_flow_classify/rte_flow_classify.c b/lib/librte_flow_classify/rte_flow_classify.c
index e6f4486..c2200df 100644
--- a/lib/librte_flow_classify/rte_flow_classify.c
+++ b/lib/librte_flow_classify/rte_flow_classify.c
@@ -39,16 +39,20 @@
 
 int librte_flow_classify_logtype;
 
-static struct rte_eth_ntuple_filter ntuple_filter;
 static uint32_t unique_id = 1;
 
+enum rte_flow_classify_table_type table_type
+	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
 
 struct rte_flow_classify_table_entry {
 	/* meta-data for classify rule */
 	uint32_t rule_id;
+
+	/* Flow action */
+	struct classify_action action;
 };
 
-struct rte_table {
+struct rte_cls_table {
 	/* Input parameters */
 	struct rte_table_ops ops;
 	uint32_t entry_size;
@@ -64,11 +68,16 @@ struct rte_flow_classifier {
 	/* Input parameters */
 	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
 	int socket_id;
-	enum rte_flow_classify_table_type type;
 
-	/* Internal tables */
-	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	/* Internal */
+	/* ntuple_fliter */
+	struct rte_eth_ntuple_filter ntuple_filter;
+
+	/* clasifier tables */
+	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	uint32_t table_mask;
 	uint32_t num_tables;
+
 	uint16_t nb_pkts;
 	struct rte_flow_classify_table_entry
 		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -97,18 +106,19 @@ struct classify_rules {
 
 struct rte_flow_classify_rule {
 	uint32_t id; /* unique ID of classify rule */
-	struct rte_flow_action action; /* action when match found */
+	enum rte_flow_classify_table_type tbl_type; /* rule table */
 	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 */
+	struct rte_flow_classify_table_entry entry;  /* rule meta data */
 	void *entry_ptr; /* handle to the table entry for rule meta data */
 };
 
-static int
-flow_classify_parse_flow(
+int
+rte_flow_classify_validate(
+		   struct rte_flow_classifier *cls,
 		   const struct rte_flow_attr *attr,
 		   const struct rte_flow_item pattern[],
 		   const struct rte_flow_action actions[],
@@ -120,7 +130,38 @@ flow_classify_parse_flow(
 	uint32_t i = 0;
 	int ret;
 
-	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
+	if (error == NULL)
+		return -EINVAL;
+
+	if (cls == NULL) {
+		RTE_FLOW_CLASSIFY_LOG(ERR,
+			"%s: rte_flow_classifier parameter is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (!attr) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ATTR,
+				   NULL, "NULL attribute.");
+		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;
+	}
+
+	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
 
 	/* Get the non-void item number of pattern */
 	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
@@ -150,7 +191,7 @@ flow_classify_parse_flow(
 		return -EINVAL;
 	}
 
-	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
+	ret = parse_filter(attr, items, actions, &cls->ntuple_filter, error);
 	free(items);
 	return ret;
 }
@@ -275,17 +316,14 @@ rte_flow_classifier_create(struct rte_flow_classifier_params *params)
 	/* 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;
+	cls->socket_id = params->socket_id;
 
 	return cls;
 }
 
 static void
-rte_flow_classify_table_free(struct rte_table *table)
+rte_flow_classify_table_free(struct rte_cls_table *table)
 {
 	if (table->ops.f_free != NULL)
 		table->ops.f_free(table->h_table);
@@ -306,7 +344,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 	/* Free tables */
 	for (i = 0; i < cls->num_tables; i++) {
-		struct rte_table *table = &cls->tables[i];
+		struct rte_cls_table *table = &cls->tables[i];
 
 		rte_flow_classify_table_free(table);
 	}
@@ -319,8 +357,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 static int
 rte_table_check_params(struct rte_flow_classifier *cls,
-		struct rte_flow_classify_table_params *params,
-		uint32_t *table_id)
+		struct rte_flow_classify_table_params *params)
 {
 	if (cls == NULL) {
 		RTE_FLOW_CLASSIFY_LOG(ERR,
@@ -333,11 +370,6 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 			__func__);
 		return -EINVAL;
 	}
-	if (table_id == NULL) {
-		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is NULL\n",
-			__func__);
-		return -EINVAL;
-	}
 
 	/* ops */
 	if (params->ops == NULL) {
@@ -371,22 +403,18 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 
 int
 rte_flow_classify_table_create(struct rte_flow_classifier *cls,
-	struct rte_flow_classify_table_params *params,
-	uint32_t *table_id)
+	struct rte_flow_classify_table_params *params)
 {
-	struct rte_table *table;
+	struct rte_cls_table *table;
 	void *h_table;
-	uint32_t entry_size, id;
+	uint32_t entry_size;
 	int ret;
 
 	/* Check input arguments */
-	ret = rte_table_check_params(cls, params, table_id);
+	ret = rte_table_check_params(cls, params);
 	if (ret != 0)
 		return ret;
 
-	id = cls->num_tables;
-	table = &cls->tables[id];
-
 	/* calculate table entry size */
 	entry_size = sizeof(struct rte_flow_classify_table_entry);
 
@@ -400,8 +428,9 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 	}
 
 	/* Commit current table to the classifier */
+	table = &cls->tables[cls->num_tables];
+	table->type = params->type;
 	cls->num_tables++;
-	*table_id = id;
 
 	/* Save input parameters */
 	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
@@ -414,7 +443,7 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 }
 
 static struct rte_flow_classify_rule *
-allocate_acl_ipv4_5tuple_rule(void)
+allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
 {
 	struct rte_flow_classify_rule *rule;
 	int log_level;
@@ -427,45 +456,44 @@ allocate_acl_ipv4_5tuple_rule(void)
 	rule->id = unique_id++;
 	rule->rules.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.priority = cls->ntuple_filter.priority;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
-			ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto_mask;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
-			ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto_mask = cls->ntuple_filter.proto_mask;
 
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.src_ip_mask;
+			cls->ntuple_filter.src_ip_mask;
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
-			ntuple_filter.src_ip;
-	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
-	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
+			cls->ntuple_filter.src_ip;
+	rule->rules.u.ipv4_5tuple.src_ip_mask = cls->ntuple_filter.src_ip_mask;
+	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
 
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.dst_ip_mask;
+			cls->ntuple_filter.dst_ip_mask;
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
-			ntuple_filter.dst_ip;
-	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
-	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
+			cls->ntuple_filter.dst_ip;
+	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls->ntuple_filter.dst_ip_mask;
+	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
 
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.src_port_mask;
+			cls->ntuple_filter.src_port_mask;
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
-			ntuple_filter.src_port;
-	rule->rules.u.ipv4_5tuple.src_port_mask = ntuple_filter.src_port_mask;
-	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
+			cls->ntuple_filter.src_port;
+	rule->rules.u.ipv4_5tuple.src_port_mask =
+			cls->ntuple_filter.src_port_mask;
+	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
 
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.dst_port_mask;
+			cls->ntuple_filter.dst_port_mask;
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
-			ntuple_filter.dst_port;
-	rule->rules.u.ipv4_5tuple.dst_port_mask = ntuple_filter.dst_port_mask;
-	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
+			cls->ntuple_filter.dst_port;
+	rule->rules.u.ipv4_5tuple.dst_port_mask =
+			cls->ntuple_filter.dst_port_mask;
+	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
 
 	log_level = rte_log_get_level(librte_flow_classify_logtype);
 
@@ -485,34 +513,21 @@ allocate_acl_ipv4_5tuple_rule(void)
 
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error)
 {
 	struct rte_flow_classify_rule *rule;
 	struct rte_flow_classify_table_entry *table_entry;
+	struct classify_action *action;
+	uint32_t i;
 	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 (key_found == NULL) {
 		rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -520,91 +535,95 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
 		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 = flow_classify_parse_flow(attr, pattern, actions, error);
+	ret = rte_flow_classify_validate(cls, attr, pattern, actions, error);
 	if (ret < 0)
 		return NULL;
 
-	switch (cls->type) {
-	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
-		rule = allocate_acl_ipv4_5tuple_rule();
+	switch (table_type) {
+	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
+		rule = allocate_acl_ipv4_5tuple_rule(cls);
 		if (!rule)
 			return NULL;
+		rule->tbl_type = table_type;
+		cls->table_mask |= table_type;
 		break;
 	default:
 		return NULL;
 	}
 
-	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
-	if (!rule->entry) {
-		free(rule);
-		return NULL;
-	}
-
-	table_entry = rule->entry;
+	action = classify_get_flow_action();
+	table_entry = &rule->entry;
 	table_entry->rule_id = rule->id;
+	table_entry->action.action_mask = action->action_mask;
 
-	if (cls->tables[table_id].ops.f_add != NULL) {
-		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);
-			return NULL;
+	/* Copy actions */
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
+		memcpy(&table_entry->action.act.counter, &action->act.counter,
+				sizeof(table_entry->action.act.counter));
+	}
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_MARK)) {
+		memcpy(&table_entry->action.act.mark, &action->act.mark,
+				sizeof(table_entry->action.act.mark));
+	}
+
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+		if (table->type == table_type) {
+			if (table->ops.f_add != NULL) {
+				ret = table->ops.f_add(
+					table->h_table,
+					&rule->u.key.key_add,
+					&rule->entry,
+					&rule->key_found,
+					&rule->entry_ptr);
+				if (ret) {
+					free(rule);
+					return NULL;
+				}
+
+			*key_found = rule->key_found;
+			}
+
+			return rule;
 		}
-		*key_found = rule->key_found;
 	}
-	return rule;
+	return NULL;
 }
 
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule)
 {
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || table_id >= cls->num_tables)
+	if (!cls || !rule)
 		return ret;
+	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
+
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
 
-	if (cls->tables[table_id].ops.f_delete != NULL)
-		ret = cls->tables[table_id].ops.f_delete(
-			cls->tables[table_id].h_table,
-			&rule->u.key.key_del,
-			&rule->key_found,
-			&rule->entry);
+		if (table->type == tbl_type) {
+			if (table->ops.f_delete != NULL) {
+				ret = table->ops.f_delete(table->h_table,
+						&rule->u.key.key_del,
+						&rule->key_found,
+						&rule->entry);
 
+				return ret;
+			}
+		}
+	}
+	free(rule);
 	return ret;
 }
 
 static int
 flow_classifier_lookup(struct rte_flow_classifier *cls,
-		uint32_t table_id,
+		struct rte_cls_table *table,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts)
 {
@@ -613,8 +632,7 @@ flow_classifier_lookup(struct rte_flow_classifier *cls,
 	uint64_t lookup_hit_mask;
 
 	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
-	ret = cls->tables[table_id].ops.f_lookup(
-		cls->tables[table_id].h_table,
+	ret = table->ops.f_lookup(table->h_table,
 		pkts, pkts_mask, &lookup_hit_mask,
 		(void **)cls->entries);
 
@@ -632,12 +650,12 @@ action_apply(struct rte_flow_classifier *cls,
 		struct rte_flow_classify_stats *stats)
 {
 	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
+	struct rte_flow_classify_table_entry *entry = &rule->entry;
 	uint64_t count = 0;
-	int i;
-	int ret = -EINVAL;
+	uint32_t action_mask = entry->action.action_mask;
+	int i, ret = -EINVAL;
 
-	switch (rule->action.type) {
-	case RTE_FLOW_ACTION_TYPE_COUNT:
+	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
 		for (i = 0; i < cls->nb_pkts; i++) {
 			if (rule->id == cls->entries[i]->rule_id)
 				count++;
@@ -650,32 +668,37 @@ action_apply(struct rte_flow_classifier *cls,
 			ntuple_stats->counter1 = count;
 			ntuple_stats->ipv4_5tuple = rule->rules.u.ipv4_5tuple;
 		}
-		break;
-	default:
-		ret = -ENOTSUP;
-		break;
 	}
-
 	return ret;
 }
 
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
 		struct rte_flow_classify_stats *stats)
 {
+	enum rte_flow_classify_table_type tbl_type;
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
-		table_id >= cls->num_tables)
+	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
 		return ret;
 
-	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
-	if (!ret)
-		ret = action_apply(cls, rule, stats);
+	tbl_type = rule->tbl_type;
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+			if (table->type == tbl_type) {
+				ret = flow_classifier_lookup(cls, table,
+						pkts, nb_pkts);
+				if (!ret) {
+					ret = action_apply(cls, rule, stats);
+					return ret;
+				}
+			}
+	}
 	return ret;
 }
 
diff --git a/lib/librte_flow_classify/rte_flow_classify.h b/lib/librte_flow_classify/rte_flow_classify.h
index 1211873..b9b669f 100644
--- a/lib/librte_flow_classify/rte_flow_classify.h
+++ b/lib/librte_flow_classify/rte_flow_classify.h
@@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
 rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
 	__func__, ## args)
 
+#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
+#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
+#endif
+
 /** Opaque data type for flow classifier */
 struct rte_flow_classifier;
 
@@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
 
 /** Flow classify table type */
 enum rte_flow_classify_table_type {
-	/** no type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
-	/** ACL type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
-};
+	/** No type */
+	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
+	/** ACL IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
+	/** ACL VLAN IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
+	/** ACL QinQ IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
 
-/**
- * Maximum number of tables allowed for any Flow Classifier instance.
- * The value of this parameter cannot be changed.
- */
-#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
+};
 
 /** Parameters for flow classifier creation */
 struct rte_flow_classifier_params {
@@ -122,9 +125,6 @@ struct rte_flow_classifier_params {
 	/** 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;
 };
 
 /** Parameters for table creation */
@@ -134,6 +134,9 @@ struct rte_flow_classify_table_params {
 
 	/** Opaque param to be passed to the table create operation */
 	void *arg_create;
+
+	/** Classifier table type */
+	enum rte_flow_classify_table_type type;
 };
 
 /** IPv4 5-tuple data */
@@ -197,32 +200,50 @@ rte_flow_classifier_free(struct rte_flow_classifier *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);
+		struct rte_flow_classify_table_params *params);
+
+/**
+ * Flow classify validate
+ *
+ * @param cls
+ *   Handle to flow classifier instance
+ * @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(struct rte_flow_classifier *cls,
+		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[out] key_found
- *  returns 1 if key present already, 0 otherwise.
  * @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] key_found
+ *  returns 1 if rule present already, 0 otherwise.
  * @param[out] error
  *   Perform verbose error reporting if not NULL. Structure
  *   initialised in case of error only.
@@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
  */
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error);
 
 /**
@@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  *
  * @param[in] cls
  *   Flow classifier handle
- * @param[in] table_id
- *   id of table
  * @param[in] rule
  *   Flow classify rule
  * @return
@@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule);
 
 /**
@@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  *
  * @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
@@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.c b/lib/librte_flow_classify/rte_flow_classify_parse.c
index dbfa111..9fb3e51 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.c
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
@@ -40,7 +40,7 @@ struct classify_valid_pattern {
 	parse_filter_t parse_filter;
 };
 
-static struct rte_flow_action action;
+static struct classify_action action;
 
 /* Pattern for IPv4 5-tuple UDP filter */
 static enum rte_flow_item_type pattern_ntuple_1[] = {
@@ -80,7 +80,7 @@ static struct classify_valid_pattern classify_supported_patterns[] = {
 	{ pattern_ntuple_3, classify_parse_ntuple_filter },
 };
 
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void)
 {
 	return &action;
@@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	const struct rte_flow_item_udp *udp_mask;
 	const struct rte_flow_item_sctp *sctp_spec;
 	const struct rte_flow_item_sctp *sctp_mask;
+	const struct rte_flow_action_count *count;
+	const struct rte_flow_action_mark *mark_spec;
 	uint32_t index;
 
-	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;
-	}
-
 	/* parse pattern */
 	index = 0;
 
@@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 		return -EINVAL;
 	}
 
-	/* parse action */
-	index = 0;
-
-	/**
-	 * n-tuple only supports count,
-	 * check if the first not void action is COUNT.
-	 */
-	memset(&action, 0, sizeof(action));
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			item, "Not supported action.");
-		return -EINVAL;
-	}
-	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
-
-	/* check if the next not void item is END */
-	index++;
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			act, "Not supported action.");
-		return -EINVAL;
-	}
+	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
 	/* parse attr */
 	/* must be input direction */
@@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
 		filter->priority = FLOW_RULE_MAX_PRIORITY;
 
+	/* parse action */
+	index = 0;
+
+	/**
+	 * n-tuple only supports count and Mark,
+	 * check if the first not void action is COUNT or MARK.
+	 */
+	memset(&action, 0, sizeof(action));
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is MARK or COUNT or END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	case RTE_FLOW_ACTION_TYPE_END:
+		return 0;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
 	return 0;
 }
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h b/lib/librte_flow_classify/rte_flow_classify_parse.h
index 1d4708a..9c1de72 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.h
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
@@ -43,6 +43,20 @@
 extern "C" {
 #endif
 
+extern enum rte_flow_classify_table_type table_type;
+
+struct classify_action {
+	/* Flow action mask */
+	uint64_t action_mask;
+
+	struct action {
+		/** Integer value to return with packets */
+		struct rte_flow_action_mark mark;
+		/** Flow rule counter */
+		struct rte_flow_query_count counter;
+	} act;
+};
+
 typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
 			      const struct rte_flow_item pattern[],
 			      const struct rte_flow_action actions[],
@@ -64,7 +78,7 @@ parse_filter_t
 classify_find_parse_filter_func(struct rte_flow_item *pattern);
 
 /* get action data */
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void);
 
 #ifdef __cplusplus
diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map b/lib/librte_flow_classify/rte_flow_classify_version.map
index f7695cb..49bc25c 100644
--- a/lib/librte_flow_classify/rte_flow_classify_version.map
+++ b/lib/librte_flow_classify/rte_flow_classify_version.map
@@ -7,6 +7,7 @@ EXPERIMENTAL {
 	rte_flow_classify_table_create;
 	rte_flow_classify_table_entry_add;
 	rte_flow_classify_table_entry_delete;
+	rte_flow_classify_validate;
 
 	local: *;
 };
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 2/4] test/test_flow_classify: update test to accommodate changes
  2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
@ 2017-12-15 10:39     ` Jasvinder Singh
  2017-12-19 12:06       ` Iremonger, Bernard
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 3/4] examples/flow_classify: update sample application Jasvinder Singh
                       ` (3 subsequent siblings)
  4 siblings, 1 reply; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-15 10:39 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger

Test have ben modified to adapt the flow_classify api
changes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v2: 
- add validate API tests

 test/test/test_flow_classify.c | 178 +++++++++++++++++++++++++++++------------
 test/test/test_flow_classify.h |  10 ++-
 2 files changed, 135 insertions(+), 53 deletions(-)

diff --git a/test/test/test_flow_classify.c b/test/test/test_flow_classify.c
index 9f331cd..c8fd5ad 100644
--- a/test/test/test_flow_classify.c
+++ b/test/test/test_flow_classify.c
@@ -51,16 +51,10 @@
 
 
 #define FLOW_CLASSIFY_MAX_RULE_NUM 100
-struct flow_classifier *cls;
-
-struct flow_classifier {
-	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
-	uint32_t n_tables;
-};
+struct flow_classifier_acl *cls;
 
 struct flow_classifier_acl {
-	struct flow_classifier cls;
+	struct rte_flow_classifier *cls;
 } __rte_cache_aligned;
 
 /*
@@ -73,7 +67,15 @@ test_invalid_parameters(void)
 	struct rte_flow_classify_rule *rule;
 	int ret;
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	ret = rte_flow_classify_validate(NULL, NULL, NULL, NULL, NULL);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate",
+			__LINE__);
+		printf(" with NULL param should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 			NULL, NULL);
 	if (rule) {
 		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
@@ -81,7 +83,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -89,14 +91,14 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
 		return -1;
 	}
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 		NULL, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
@@ -104,7 +106,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -112,7 +114,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
@@ -129,7 +131,8 @@ test_valid_parameters(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -142,15 +145,24 @@ test_valid_parameters(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: rte_flow_classify_validate",
+			__LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
+
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -168,7 +180,8 @@ test_invalid_patterns(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -183,15 +196,24 @@ test_invalid_patterns(void)
 
 	pattern[0] = eth_item;
 	pattern[1] = ipv4_udp_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -202,15 +224,24 @@ test_invalid_patterns(void)
 	pattern[1] = ipv4_udp_item_1;
 	pattern[2] = udp_item_bad;
 	pattern[3] = end_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -228,7 +259,8 @@ test_invalid_actions(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -241,15 +273,23 @@ test_invalid_actions(void)
 	actions[0] = count_action_bad;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -260,15 +300,23 @@ test_invalid_actions(void)
 	actions[0] = count_action;
 	actions[1] = end_action_bad;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -449,7 +497,8 @@ test_query_udp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -462,15 +511,23 @@ test_query_udp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &udp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -478,7 +535,7 @@ test_query_udp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -507,7 +564,8 @@ test_query_tcp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -520,15 +578,23 @@ test_query_tcp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: flow_classifier_query", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &tcp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -536,7 +602,7 @@ test_query_tcp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -565,7 +631,8 @@ test_query_sctp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters rte_flow_classify_table_entry_add and
+	 * set up parameters rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -578,15 +645,23 @@ test_query_sctp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: flow_classifier_query", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &sctp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -594,7 +669,7 @@ test_query_sctp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -622,7 +697,6 @@ test_flow_classify(void)
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 	cls->cls = rte_flow_classifier_create(&cls_params);
 
 	/* initialise ACL table params */
@@ -632,11 +706,11 @@ test_flow_classify(void)
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
-			&cls->table_id[0]);
+	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
 	if (ret) {
 		printf("Line %i: f_create has failed!\n", __LINE__);
 		rte_flow_classifier_free(cls->cls);
diff --git a/test/test/test_flow_classify.h b/test/test/test_flow_classify.h
index 39535cf..af293ed 100644
--- a/test/test/test_flow_classify.h
+++ b/test/test/test_flow_classify.h
@@ -197,7 +197,15 @@ static struct rte_flow_item  sctp_item_1 = { RTE_FLOW_ITEM_TYPE_SCTP,
 /* test actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action count_action_bad = { -1, 0};
 
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 3/4] examples/flow_classify: update sample application
  2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
@ 2017-12-15 10:39     ` Jasvinder Singh
  2017-12-19 12:09       ` Iremonger, Bernard
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib Jasvinder Singh
                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-15 10:39 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger

Update the flow_classify sample app to adapt the APIs changes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v3:
- fix build error issue with validate API
v2:
- use validate api to verify before adding flow rule

 examples/flow_classify/flow_classify.c | 43 ++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/examples/flow_classify/flow_classify.c b/examples/flow_classify/flow_classify.c
index 766f1dd..af2e129 100644
--- a/examples/flow_classify/flow_classify.c
+++ b/examples/flow_classify/flow_classify.c
@@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default = {
 
 struct flow_classifier {
 	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
 };
 
 struct flow_classifier_acl {
@@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = { RTE_FLOW_ITEM_TYPE_END,
 /* sample actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
 static struct rte_flow_action actions[2];
 
@@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
 	int i = 0;
 
 	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
-			cls_app->table_id[0], rules[7]);
+			rules[7]);
 	if (ret)
 		printf("table_entry_delete failed [7] %d\n\n", ret);
 	else
@@ -292,11 +299,10 @@ lcore_main(struct flow_classifier *cls_app)
 			       port);
 			printf("to polling thread.\n");
 			printf("Performance will not be optimal.\n");
-
-			printf("\nCore %u forwarding packets. ",
-			       rte_lcore_id());
-			printf("[Ctrl+C to quit]\n");
 		}
+	printf("\nCore %u forwarding packets. ", rte_lcore_id());
+	printf("[Ctrl+C to quit]\n");
+
 	/* Run until the application is quit or killed. */
 	for (;;) {
 		/*
@@ -317,7 +323,6 @@ lcore_main(struct flow_classifier *cls_app)
 				if (rules[i]) {
 					ret = rte_flow_classifier_query(
 						cls_app->cls,
-						cls_app->table_id[0],
 						bufs, nb_rx, rules[i],
 						&classify_stats);
 					if (ret)
@@ -634,9 +639,18 @@ add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
 	actions[0] = count_action;
 	actions[1] = end_action;
 
+	/* Validate and add rule */
+	ret = rte_flow_classify_validate(cls_app->cls, &attr,
+			pattern_ipv4_5tuple, actions, &error);
+	if (ret) {
+		printf("table entry validate failed ipv4_proto = %u\n",
+			ipv4_proto);
+		return ret;
+	}
+
 	rule = rte_flow_classify_table_entry_add(
-			cls_app->cls, cls_app->table_id[0], &key_found,
-			&attr, pattern_ipv4_5tuple, actions, &error);
+			cls_app->cls, &attr, pattern_ipv4_5tuple,
+			actions, &key_found, &error);
 	if (rule == NULL) {
 		printf("table entry add failed ipv4_proto = %u\n",
 			ipv4_proto);
@@ -809,7 +823,6 @@ main(int argc, char *argv[])
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
 	cls_app->cls = rte_flow_classifier_create(&cls_params);
 	if (cls_app->cls == NULL) {
@@ -824,11 +837,11 @@ main(int argc, char *argv[])
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-			&cls_app->table_id[0]);
+	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
 	if (ret) {
 		rte_flow_classifier_free(cls_app->cls);
 		rte_free(cls_app);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib
  2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 3/4] examples/flow_classify: update sample application Jasvinder Singh
@ 2017-12-15 10:39     ` Jasvinder Singh
  2017-12-18 11:04       ` Kovacevic, Marko
  2017-12-19 12:03     ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Iremonger, Bernard
  2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
  4 siblings, 1 reply; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-15 10:39 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger

Updates the documentation for flow classification
library and sample application.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v3:
- add validate API desciption to programmers guide
v2:
- replace parse flow function with validate API

 doc/guides/prog_guide/flow_classify_lib.rst | 83 +++++++++++++++++------------
 doc/guides/sample_app_ug/flow_classify.rst  |  8 +--
 2 files changed, 51 insertions(+), 40 deletions(-)

diff --git a/doc/guides/prog_guide/flow_classify_lib.rst b/doc/guides/prog_guide/flow_classify_lib.rst
index 820dc72..6007e45 100644
--- a/doc/guides/prog_guide/flow_classify_lib.rst
+++ b/doc/guides/prog_guide/flow_classify_lib.rst
@@ -101,30 +101,50 @@ The library has the following API's
      *   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);
+           struct rte_flow_classify_table_params *params);
+
+    /**
+     * Validate the flow classify rule
+     *
+     * @param[in] cls
+     *   Handle to flow classifier instance
+     * @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(struct rte_flow_classifier *cls,
+            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_classifier 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] key_found
+     *   returns 1 if rule present already, 0 otherwise.
      * @param[out] error
      *   Perform verbose error reporting if not NULL. Structure
      *   initialised in case of error only.
@@ -133,10 +153,10 @@ The library has the following API's
      */
     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[],
+            int *key_found;
             struct rte_flow_error *error);
 
     /**
@@ -144,8 +164,6 @@ The library has the following API's
      *
      * @param[in] cls
      *   Flow classifier handle
-     * @param[in] table_id
-     *   id of table
      * @param[in] rule
      *   Flow classify rule
      * @return
@@ -153,7 +171,6 @@ The library has the following API's
      */
     int
     rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_flow_classify_rule *rule);
 
     /**
@@ -161,8 +178,6 @@ The library has the following API's
      *
      * @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
@@ -177,7 +192,6 @@ The library has the following API's
      */
     int
     rte_flow_classifier_query(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_mbuf **pkts,
             const uint16_t nb_pkts,
             struct rte_flow_classify_rule *rule,
@@ -200,16 +214,13 @@ application before calling the API.
         /** 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;
     };
 
 The ``Classifier`` has the following internal structures:
 
 .. code-block:: c
 
-    struct rte_table {
+    struct rte_cls_table {
         /* Input parameters */
         struct rte_table_ops ops;
         uint32_t entry_size;
@@ -225,11 +236,16 @@ The ``Classifier`` has the following internal structures:
         /* Input parameters */
         char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
         int socket_id;
-        enum rte_flow_classify_table_type type;
 
-        /* Internal tables */
-        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        /* Internal */
+        /* ntuple_fliter */
+        struct rte_eth_ntuple_filter ntuple_filter;
+
+        /* clasifier tables */
+        struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        uint32_t table_mask;
         uint32_t num_tables;
+
         uint16_t nb_pkts;
         struct rte_flow_classify_table_entry
             *entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -252,9 +268,8 @@ application before calling the API.
         /** 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;
+        /** Classifier table type */
+        enum rte_flow_classify_table_type type;
      };
 
 To create an ACL table the ``rte_table_acl_params`` structure must be
@@ -314,14 +329,14 @@ and SCTP.
         RTE_FLOW_ITEM_TYPE_END,
     };
 
-The internal function ``flow_classify_parse_flow`` parses the
+The API function ``rte_flow_classify_validate`` parses the
 IPv4 5-tuple pattern, attributes and actions and returns the 5-tuple data in the
 ``rte_eth_ntuple_filter`` structure.
 
 .. code-block:: c
 
     static int
-    flow_classify_parse_flow(
+    rte_flow_classify_validate(struct rte_flow_classifier *cls,
                    const struct rte_flow_attr *attr,
                    const struct rte_flow_item pattern[],
                    const struct rte_flow_action actions[],
@@ -333,7 +348,7 @@ Adding Flow Rules
 The ``rte_flow_classify_table_entry_add`` API creates an
 ``rte_flow_classify`` object which contains the flow_classify id and type, the
 action, a union of add and delete keys and a union of rules.
-It uses the ``flow_classify_parse_flow`` internal function for parsing the
+It uses the ``rte_flow_classify_validate`` api function for parsing the
 flow parameters.
 The 5-tuple ACL key data is obtained from the ``rte_eth_ntuple_filter``
 structure populated by the ``classify_parse_ntuple_filter`` function which
@@ -343,7 +358,7 @@ parses the Flow rule.
 
     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_table_acl_rule_delete_params key_del; /* delete key */
     };
 
     struct classify_rules {
@@ -355,24 +370,24 @@ parses the Flow rule.
 
     struct rte_flow_classify {
         uint32_t id;  /* unique ID of classify object */
-        struct rte_flow_action action; /* action when match found */
-	struct classify_rules rules; /* union of rules */
+        enum rte_flow_classify_table_type tbl_type; /* rule table */
+        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 */
+        struct rte_flow_classify_table_entry entry;  /* rule meta data */
         void *entry_ptr; /* handle to the table entry for rule meta data */
     };
 
-It then calls the ``table[table_id].ops.f_add`` API to add the rule to the ACL
+It then calls the ``table.ops.f_add`` API to add the rule to the ACL
 table.
 
 Deleting Flow Rules
 ~~~~~~~~~~~~~~~~~~~
 
 The ``rte_flow_classify_table_entry_delete`` API calls the
-``table[table_id].ops.f_delete`` API to delete a rule from the ACL table.
+``table.ops.f_delete`` API to delete a rule from the ACL table.
 
 Packet Matching
 ~~~~~~~~~~~~~~~
@@ -380,7 +395,7 @@ Packet Matching
 The ``rte_flow_classifier_query`` API is used to find packets which match a
 given flow Flow rule in the table.
 This API calls the flow_classify_run internal function which calls the
-``table[table_id].ops.f_lookup`` API to see if any packets in a burst match any
+``table.ops.f_lookup`` API to see if any packets in a burst match any
 of the Flow rules in the table.
 The meta data for the highest priority rule matched for each packet is returned
 in the entries array in the ``rte_flow_classify`` object.
diff --git a/doc/guides/sample_app_ug/flow_classify.rst b/doc/guides/sample_app_ug/flow_classify.rst
index bc12b87..427fded 100644
--- a/doc/guides/sample_app_ug/flow_classify.rst
+++ b/doc/guides/sample_app_ug/flow_classify.rst
@@ -228,7 +228,6 @@ table`` to the flow classifier.
 
     struct flow_classifier {
         struct rte_flow_classifier *cls;
-        uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
     };
 
     struct flow_classifier_acl {
@@ -243,7 +242,6 @@ table`` to the flow classifier.
 
     cls_params.name = "flow_classifier";
     cls_params.socket_id = socket_id;
-    cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
     cls_app->cls = rte_flow_classifier_create(&cls_params);
     if (cls_app->cls == NULL) {
@@ -260,10 +258,9 @@ table`` to the flow classifier.
     /* initialise table create params */
     cls_table_params.ops = &rte_table_acl_ops,
     cls_table_params.arg_create = &table_acl_params,
-    cls_table_params.table_metadata_size = 0;
+    cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-                  &cls->table_id[0]);
+    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
     if (ret) {
         rte_flow_classifier_free(cls_app->cls);
         rte_free(cls);
@@ -495,7 +492,6 @@ following:
                     if (rules[i]) {
                         ret = rte_flow_classifier_query(
                             cls_app->cls,
-                            cls_app->table_id[0],
                             bufs, nb_rx, rules[i],
                             &classify_stats);
                         if (ret)
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib Jasvinder Singh
@ 2017-12-18 11:04       ` Kovacevic, Marko
  2017-12-18 13:40         ` Singh, Jasvinder
  0 siblings, 1 reply; 41+ messages in thread
From: Kovacevic, Marko @ 2017-12-18 11:04 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Iremonger, Bernard



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
> Sent: Friday, December 15, 2017 10:39 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify
> lib
> 
> Updates the documentation for flow classification library and sample
> application.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>


> v3:
> - add validate API desciption to programmers guide

Small typo desciption/   description


> @@ -225,11 +236,16 @@ The ``Classifier`` has the following internal structures:
>          /* Input parameters */
>          char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
>          int socket_id;
> -        enum rte_flow_classify_table_type type;
> 
> -        /* Internal tables */
> -        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +        /* Internal */
> +        /* ntuple_fliter */

Small typo above.   Ntuple_fliter/  ntuple_filter.


> +        struct rte_eth_ntuple_filter ntuple_filter;
> +
> +        /* clasifier tables */

Same above clasifier /   classifier

 
>  To create an ACL table the ``rte_table_acl_params`` structure must be @@ -
> 314,14 +329,14 @@ and SCTP.
>          RTE_FLOW_ITEM_TYPE_END,
>      };
> 
> -The internal function ``flow_classify_parse_flow`` parses the
> +The API function ``rte_flow_classify_validate`` parses the
>  IPv4 5-tuple pattern, attributes and actions and returns the 5-tuple data in the
> ``rte_eth_ntuple_filter`` structure.
> 
>  .. code-block:: c
> 
>      static int
> -    flow_classify_parse_flow(
> +    rte_flow_classify_validate(struct rte_flow_classifier *cls,
>                     const struct rte_flow_attr *attr,
>                     const struct rte_flow_item pattern[],
>                     const struct rte_flow_action actions[], @@ -333,7 +348,7 @@
> Adding Flow Rules  The ``rte_flow_classify_table_entry_add`` API creates an
> ``rte_flow_classify`` object which contains the flow_classify id and type, the
> action, a union of add and delete keys and a union of rules.
> -It uses the ``flow_classify_parse_flow`` internal function for parsing the
> +It uses the ``rte_flow_classify_validate`` api function for parsing the

Above api/  API


Otherwise everything else seem ok

Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib
  2017-12-18 11:04       ` Kovacevic, Marko
@ 2017-12-18 13:40         ` Singh, Jasvinder
  2017-12-19 12:13           ` Iremonger, Bernard
  0 siblings, 1 reply; 41+ messages in thread
From: Singh, Jasvinder @ 2017-12-18 13:40 UTC (permalink / raw)
  To: Kovacevic, Marko, dev; +Cc: Iremonger, Bernard



> -----Original Message-----
> From: Kovacevic, Marko
> Sent: Monday, December 18, 2017 11:05 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow
> classify lib
> 
> 
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
> > Sent: Friday, December 15, 2017 10:39 AM
> > To: dev@dpdk.org
> > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > Subject: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow
> > classify lib
> >
> > Updates the documentation for flow classification library and sample
> > application.
> >
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> 
> 
> > v3:
> > - add validate API desciption to programmers guide
> 
> Small typo desciption/   description
> 
> 
> > @@ -225,11 +236,16 @@ The ``Classifier`` has the following internal
> structures:
> >          /* Input parameters */
> >          char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
> >          int socket_id;
> > -        enum rte_flow_classify_table_type type;
> >
> > -        /* Internal tables */
> > -        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > +        /* Internal */
> > +        /* ntuple_fliter */
> 
> Small typo above.   Ntuple_fliter/  ntuple_filter.
> 
> 
> > +        struct rte_eth_ntuple_filter ntuple_filter;
> > +
> > +        /* clasifier tables */
> 
> Same above clasifier /   classifier
> 
> 
> >  To create an ACL table the ``rte_table_acl_params`` structure must be
> > @@ -
> > 314,14 +329,14 @@ and SCTP.
> >          RTE_FLOW_ITEM_TYPE_END,
> >      };
> >
> > -The internal function ``flow_classify_parse_flow`` parses the
> > +The API function ``rte_flow_classify_validate`` parses the
> >  IPv4 5-tuple pattern, attributes and actions and returns the 5-tuple
> > data in the ``rte_eth_ntuple_filter`` structure.
> >
> >  .. code-block:: c
> >
> >      static int
> > -    flow_classify_parse_flow(
> > +    rte_flow_classify_validate(struct rte_flow_classifier *cls,
> >                     const struct rte_flow_attr *attr,
> >                     const struct rte_flow_item pattern[],
> >                     const struct rte_flow_action actions[], @@ -333,7
> > +348,7 @@ Adding Flow Rules  The ``rte_flow_classify_table_entry_add``
> > API creates an ``rte_flow_classify`` object which contains the
> > flow_classify id and type, the action, a union of add and delete keys and a
> union of rules.
> > -It uses the ``flow_classify_parse_flow`` internal function for
> > parsing the
> > +It uses the ``rte_flow_classify_validate`` api function for parsing
> > +the
> 
> Above api/  API
> 
> 
> Otherwise everything else seem ok
> 
> Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
> 

Thanks Marko for review. I will fix them in next version.

Jasvinder

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
                       ` (2 preceding siblings ...)
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib Jasvinder Singh
@ 2017-12-19 12:03     ` Iremonger, Bernard
  2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
  4 siblings, 0 replies; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-19 12:03 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Friday, December 15, 2017 10:39 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from
> apis
> 
> This patch removes table id parameter from all the flow classify apis to reduce
> the complexity alongwith some code cleanup.
> 
> The validate api is exposed as public api to allow user to validate the flow before
> adding it to the classifier.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
> v2:
> - break the patche into multiple
> - fix the error checks
> 
>  lib/librte_flow_classify/rte_flow_classify.c       | 313 +++++++++++----------
>  lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
>  lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
> lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
>  .../rte_flow_classify_version.map                  |   1 +
>  5 files changed, 296 insertions(+), 226 deletions(-)
> 
> diff --git a/lib/librte_flow_classify/rte_flow_classify.c
> b/lib/librte_flow_classify/rte_flow_classify.c
> index e6f4486..c2200df 100644
> --- a/lib/librte_flow_classify/rte_flow_classify.c
> +++ b/lib/librte_flow_classify/rte_flow_classify.c
> @@ -39,16 +39,20 @@
> 
>  int librte_flow_classify_logtype;
> 
> -static struct rte_eth_ntuple_filter ntuple_filter;  static uint32_t unique_id = 1;
> 
> +enum rte_flow_classify_table_type table_type
> +	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
> 
>  struct rte_flow_classify_table_entry {
>  	/* meta-data for classify rule */
>  	uint32_t rule_id;
> +
> +	/* Flow action */
> +	struct classify_action action;
>  };
> 
> -struct rte_table {
> +struct rte_cls_table {
>  	/* Input parameters */
>  	struct rte_table_ops ops;
>  	uint32_t entry_size;
> @@ -64,11 +68,16 @@ struct rte_flow_classifier {
>  	/* Input parameters */
>  	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
>  	int socket_id;
> -	enum rte_flow_classify_table_type type;
> 
> -	/* Internal tables */
> -	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +	/* Internal */
> +	/* ntuple_fliter */

Typo, fliter should be filter

> +	struct rte_eth_ntuple_filter ntuple_filter;
> +
> +	/* clasifier tables */

Typo, classifier should be classifier.

> +	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> +	uint32_t table_mask;
>  	uint32_t num_tables;
> +
>  	uint16_t nb_pkts;
>  	struct rte_flow_classify_table_entry
>  		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
> @@ -97,18 +106,19 @@ struct classify_rules {
> 
>  struct rte_flow_classify_rule {
>  	uint32_t id; /* unique ID of classify rule */
> -	struct rte_flow_action action; /* action when match found */
> +	enum rte_flow_classify_table_type tbl_type; /* rule table */
>  	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 */
> +	struct rte_flow_classify_table_entry entry;  /* rule meta data */
>  	void *entry_ptr; /* handle to the table entry for rule meta data */  };
> 
> -static int
> -flow_classify_parse_flow(
> +int
> +rte_flow_classify_validate(
> +		   struct rte_flow_classifier *cls,
>  		   const struct rte_flow_attr *attr,
>  		   const struct rte_flow_item pattern[],
>  		   const struct rte_flow_action actions[], @@ -120,7 +130,38
> @@ flow_classify_parse_flow(
>  	uint32_t i = 0;
>  	int ret;
> 
> -	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
> +	if (error == NULL)
> +		return -EINVAL;
> +
> +	if (cls == NULL) {
> +		RTE_FLOW_CLASSIFY_LOG(ERR,
> +			"%s: rte_flow_classifier parameter is NULL\n",
> +			__func__);
> +		return -EINVAL;
> +	}
> +
> +	if (!attr) {
> +		rte_flow_error_set(error, EINVAL,
> +				   RTE_FLOW_ERROR_TYPE_ATTR,
> +				   NULL, "NULL attribute.");
> +		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;
> +	}
> +
> +	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
> 
>  	/* Get the non-void item number of pattern */
>  	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) { @@ -150,7
> +191,7 @@ flow_classify_parse_flow(
>  		return -EINVAL;
>  	}
> 
> -	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
> +	ret = parse_filter(attr, items, actions, &cls->ntuple_filter, error);
>  	free(items);
>  	return ret;
>  }
> @@ -275,17 +316,14 @@ rte_flow_classifier_create(struct
> rte_flow_classifier_params *params)
>  	/* 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;
> +	cls->socket_id = params->socket_id;
> 
>  	return cls;
>  }
> 
>  static void
> -rte_flow_classify_table_free(struct rte_table *table)
> +rte_flow_classify_table_free(struct rte_cls_table *table)
>  {
>  	if (table->ops.f_free != NULL)
>  		table->ops.f_free(table->h_table);
> @@ -306,7 +344,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
> 
>  	/* Free tables */
>  	for (i = 0; i < cls->num_tables; i++) {
> -		struct rte_table *table = &cls->tables[i];
> +		struct rte_cls_table *table = &cls->tables[i];
> 
>  		rte_flow_classify_table_free(table);
>  	}
> @@ -319,8 +357,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
> 
>  static int
>  rte_table_check_params(struct rte_flow_classifier *cls,
> -		struct rte_flow_classify_table_params *params,
> -		uint32_t *table_id)
> +		struct rte_flow_classify_table_params *params)
>  {
>  	if (cls == NULL) {
>  		RTE_FLOW_CLASSIFY_LOG(ERR,
> @@ -333,11 +370,6 @@ rte_table_check_params(struct rte_flow_classifier
> *cls,
>  			__func__);
>  		return -EINVAL;
>  	}
> -	if (table_id == NULL) {
> -		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is
> NULL\n",
> -			__func__);
> -		return -EINVAL;
> -	}
> 
>  	/* ops */
>  	if (params->ops == NULL) {
> @@ -371,22 +403,18 @@ rte_table_check_params(struct rte_flow_classifier
> *cls,
> 
>  int
>  rte_flow_classify_table_create(struct rte_flow_classifier *cls,
> -	struct rte_flow_classify_table_params *params,
> -	uint32_t *table_id)
> +	struct rte_flow_classify_table_params *params)
>  {
> -	struct rte_table *table;
> +	struct rte_cls_table *table;
>  	void *h_table;
> -	uint32_t entry_size, id;
> +	uint32_t entry_size;
>  	int ret;
> 
>  	/* Check input arguments */
> -	ret = rte_table_check_params(cls, params, table_id);
> +	ret = rte_table_check_params(cls, params);
>  	if (ret != 0)
>  		return ret;
> 
> -	id = cls->num_tables;
> -	table = &cls->tables[id];
> -
>  	/* calculate table entry size */
>  	entry_size = sizeof(struct rte_flow_classify_table_entry);
> 
> @@ -400,8 +428,9 @@ rte_flow_classify_table_create(struct
> rte_flow_classifier *cls,
>  	}
> 
>  	/* Commit current table to the classifier */
> +	table = &cls->tables[cls->num_tables];
> +	table->type = params->type;
>  	cls->num_tables++;
> -	*table_id = id;
> 
>  	/* Save input parameters */
>  	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops)); @@ -
> 414,7 +443,7 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
> }
> 
>  static struct rte_flow_classify_rule *
> -allocate_acl_ipv4_5tuple_rule(void)
> +allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
>  {
>  	struct rte_flow_classify_rule *rule;
>  	int log_level;
> @@ -427,45 +456,44 @@ allocate_acl_ipv4_5tuple_rule(void)
>  	rule->id = unique_id++;
>  	rule->rules.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.priority = cls->ntuple_filter.priority;
>  	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
> -			ntuple_filter.proto_mask;
> +			cls->ntuple_filter.proto_mask;
>  	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
> -			ntuple_filter.proto;
> -	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
> -	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
> +			cls->ntuple_filter.proto;
> +	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
> +	rule->rules.u.ipv4_5tuple.proto_mask = cls->ntuple_filter.proto_mask;
> 
>  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32 =
> -			ntuple_filter.src_ip_mask;
> +			cls->ntuple_filter.src_ip_mask;
>  	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
> -			ntuple_filter.src_ip;
> -	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
> -	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
> +			cls->ntuple_filter.src_ip;
> +	rule->rules.u.ipv4_5tuple.src_ip_mask = cls->ntuple_filter.src_ip_mask;
> +	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
> 
>  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32 =
> -			ntuple_filter.dst_ip_mask;
> +			cls->ntuple_filter.dst_ip_mask;
>  	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
> -			ntuple_filter.dst_ip;
> -	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
> -	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
> +			cls->ntuple_filter.dst_ip;
> +	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls->ntuple_filter.dst_ip_mask;
> +	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
> 
>  	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
> -			ntuple_filter.src_port_mask;
> +			cls->ntuple_filter.src_port_mask;
>  	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
> -			ntuple_filter.src_port;
> -	rule->rules.u.ipv4_5tuple.src_port_mask = ntuple_filter.src_port_mask;
> -	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
> +			cls->ntuple_filter.src_port;
> +	rule->rules.u.ipv4_5tuple.src_port_mask =
> +			cls->ntuple_filter.src_port_mask;
> +	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
> 
>  	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
> -			ntuple_filter.dst_port_mask;
> +			cls->ntuple_filter.dst_port_mask;
>  	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
> -			ntuple_filter.dst_port;
> -	rule->rules.u.ipv4_5tuple.dst_port_mask = ntuple_filter.dst_port_mask;
> -	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
> +			cls->ntuple_filter.dst_port;
> +	rule->rules.u.ipv4_5tuple.dst_port_mask =
> +			cls->ntuple_filter.dst_port_mask;
> +	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
> 
>  	log_level = rte_log_get_level(librte_flow_classify_logtype);
> 
> @@ -485,34 +513,21 @@ allocate_acl_ipv4_5tuple_rule(void)
> 
>  struct rte_flow_classify_rule *
>  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
> -		int *key_found,
>  		const struct rte_flow_attr *attr,
>  		const struct rte_flow_item pattern[],
>  		const struct rte_flow_action actions[],
> +		int *key_found,
>  		struct rte_flow_error *error)
>  {
>  	struct rte_flow_classify_rule *rule;
>  	struct rte_flow_classify_table_entry *table_entry;
> +	struct classify_action *action;
> +	uint32_t i;
>  	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 (key_found == NULL) {
>  		rte_flow_error_set(error, EINVAL,
>  				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
> @@ -520,91 +535,95 @@ rte_flow_classify_table_entry_add(struct
> rte_flow_classifier *cls,
>  		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 = flow_classify_parse_flow(attr, pattern, actions, error);
> +	ret = rte_flow_classify_validate(cls, attr, pattern, actions, error);
>  	if (ret < 0)
>  		return NULL;
> 
> -	switch (cls->type) {
> -	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
> -		rule = allocate_acl_ipv4_5tuple_rule();
> +	switch (table_type) {
> +	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
> +		rule = allocate_acl_ipv4_5tuple_rule(cls);
>  		if (!rule)
>  			return NULL;
> +		rule->tbl_type = table_type;
> +		cls->table_mask |= table_type;
>  		break;
>  	default:
>  		return NULL;
>  	}
> 
> -	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
> -	if (!rule->entry) {
> -		free(rule);
> -		return NULL;
> -	}
> -
> -	table_entry = rule->entry;
> +	action = classify_get_flow_action();
> +	table_entry = &rule->entry;
>  	table_entry->rule_id = rule->id;
> +	table_entry->action.action_mask = action->action_mask;
> 
> -	if (cls->tables[table_id].ops.f_add != NULL) {
> -		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);
> -			return NULL;
> +	/* Copy actions */
> +	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT))
> {
> +		memcpy(&table_entry->action.act.counter, &action-
> >act.counter,
> +				sizeof(table_entry->action.act.counter));
> +	}
> +	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_MARK)) {
> +		memcpy(&table_entry->action.act.mark, &action->act.mark,
> +				sizeof(table_entry->action.act.mark));
> +	}
> +
> +	for (i = 0; i < cls->num_tables; i++) {
> +		struct rte_cls_table *table = &cls->tables[i];
> +
> +		if (table->type == table_type) {
> +			if (table->ops.f_add != NULL) {
> +				ret = table->ops.f_add(
> +					table->h_table,
> +					&rule->u.key.key_add,
> +					&rule->entry,
> +					&rule->key_found,
> +					&rule->entry_ptr);
> +				if (ret) {
> +					free(rule);
> +					return NULL;
> +				}
> +
> +			*key_found = rule->key_found;
> +			}
> +
> +			return rule;
>  		}
> -		*key_found = rule->key_found;
>  	}
> -	return rule;
> +	return NULL;
>  }
> 
>  int
>  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_flow_classify_rule *rule)
>  {
> +	uint32_t i;
>  	int ret = -EINVAL;
> 
> -	if (!cls || !rule || table_id >= cls->num_tables)
> +	if (!cls || !rule)
>  		return ret;
> +	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
> +
> +	for (i = 0; i < cls->num_tables; i++) {
> +		struct rte_cls_table *table = &cls->tables[i];
> 
> -	if (cls->tables[table_id].ops.f_delete != NULL)
> -		ret = cls->tables[table_id].ops.f_delete(
> -			cls->tables[table_id].h_table,
> -			&rule->u.key.key_del,
> -			&rule->key_found,
> -			&rule->entry);
> +		if (table->type == tbl_type) {
> +			if (table->ops.f_delete != NULL) {
> +				ret = table->ops.f_delete(table->h_table,
> +						&rule->u.key.key_del,
> +						&rule->key_found,
> +						&rule->entry);
> 
> +				return ret;
> +			}
> +		}
> +	}
> +	free(rule);
>  	return ret;
>  }
> 
>  static int
>  flow_classifier_lookup(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
> +		struct rte_cls_table *table,
>  		struct rte_mbuf **pkts,
>  		const uint16_t nb_pkts)
>  {
> @@ -613,8 +632,7 @@ flow_classifier_lookup(struct rte_flow_classifier *cls,
>  	uint64_t lookup_hit_mask;
> 
>  	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
> -	ret = cls->tables[table_id].ops.f_lookup(
> -		cls->tables[table_id].h_table,
> +	ret = table->ops.f_lookup(table->h_table,
>  		pkts, pkts_mask, &lookup_hit_mask,
>  		(void **)cls->entries);
> 
> @@ -632,12 +650,12 @@ action_apply(struct rte_flow_classifier *cls,
>  		struct rte_flow_classify_stats *stats)  {
>  	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
> +	struct rte_flow_classify_table_entry *entry = &rule->entry;
>  	uint64_t count = 0;
> -	int i;
> -	int ret = -EINVAL;
> +	uint32_t action_mask = entry->action.action_mask;
> +	int i, ret = -EINVAL;
> 
> -	switch (rule->action.type) {
> -	case RTE_FLOW_ACTION_TYPE_COUNT:
> +	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
>  		for (i = 0; i < cls->nb_pkts; i++) {
>  			if (rule->id == cls->entries[i]->rule_id)
>  				count++;
> @@ -650,32 +668,37 @@ action_apply(struct rte_flow_classifier *cls,
>  			ntuple_stats->counter1 = count;
>  			ntuple_stats->ipv4_5tuple = rule->rules.u.ipv4_5tuple;
>  		}
> -		break;
> -	default:
> -		ret = -ENOTSUP;
> -		break;
>  	}
> -
>  	return ret;
>  }
> 
>  int
>  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_mbuf **pkts,
>  		const uint16_t nb_pkts,
>  		struct rte_flow_classify_rule *rule,
>  		struct rte_flow_classify_stats *stats)  {
> +	enum rte_flow_classify_table_type tbl_type;
> +	uint32_t i;
>  	int ret = -EINVAL;
> 
> -	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
> -		table_id >= cls->num_tables)
> +	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
>  		return ret;
> 
> -	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
> -	if (!ret)
> -		ret = action_apply(cls, rule, stats);
> +	tbl_type = rule->tbl_type;
> +	for (i = 0; i < cls->num_tables; i++) {
> +		struct rte_cls_table *table = &cls->tables[i];
> +
> +			if (table->type == tbl_type) {
> +				ret = flow_classifier_lookup(cls, table,
> +						pkts, nb_pkts);
> +				if (!ret) {
> +					ret = action_apply(cls, rule, stats);
> +					return ret;
> +				}
> +			}
> +	}
>  	return ret;
>  }
> 
> diff --git a/lib/librte_flow_classify/rte_flow_classify.h
> b/lib/librte_flow_classify/rte_flow_classify.h
> index 1211873..b9b669f 100644
> --- a/lib/librte_flow_classify/rte_flow_classify.h
> +++ b/lib/librte_flow_classify/rte_flow_classify.h
> @@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
> rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
>  	__func__, ## args)
> 
> +#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
> +#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
> +#endif
> +
>  /** Opaque data type for flow classifier */  struct rte_flow_classifier;
> 
> @@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
> 
>  /** Flow classify table type */
>  enum rte_flow_classify_table_type {
> -	/** no type */
> -	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
> -	/** ACL type */
> -	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
> -};
> +	/** No type */
> +	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
> +	/** ACL IP4 5TUPLE */
> +	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
> +	/** ACL VLAN IP4 5TUPLE */
> +	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
> +	/** ACL QinQ IP4 5TUPLE */
> +	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
> 
> -/**
> - * Maximum number of tables allowed for any Flow Classifier instance.
> - * The value of this parameter cannot be changed.
> - */
> -#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
> +};
> 
>  /** Parameters for flow classifier creation */  struct rte_flow_classifier_params
> { @@ -122,9 +125,6 @@ struct rte_flow_classifier_params {
>  	/** 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;
>  };
> 
>  /** Parameters for table creation */
> @@ -134,6 +134,9 @@ struct rte_flow_classify_table_params {
> 
>  	/** Opaque param to be passed to the table create operation */
>  	void *arg_create;
> +
> +	/** Classifier table type */
> +	enum rte_flow_classify_table_type type;
>  };
> 
>  /** IPv4 5-tuple data */
> @@ -197,32 +200,50 @@ rte_flow_classifier_free(struct rte_flow_classifier
> *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);
> +		struct rte_flow_classify_table_params *params);
> +
> +/**
> + * Flow classify validate
> + *
> + * @param cls
> + *   Handle to flow classifier instance
> + * @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(struct rte_flow_classifier *cls,
> +		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[out] key_found
> - *  returns 1 if key present already, 0 otherwise.
>   * @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] key_found
> + *  returns 1 if rule present already, 0 otherwise.
>   * @param[out] error
>   *   Perform verbose error reporting if not NULL. Structure
>   *   initialised in case of error only.
> @@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct
> rte_flow_classifier *cls,
>   */
>  struct rte_flow_classify_rule *
>  rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
> -		int *key_found,
>  		const struct rte_flow_attr *attr,
>  		const struct rte_flow_item pattern[],
>  		const struct rte_flow_action actions[],
> +		int *key_found,
>  		struct rte_flow_error *error);
> 
>  /**
> @@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct
> rte_flow_classifier *cls,
>   *
>   * @param[in] cls
>   *   Flow classifier handle
> - * @param[in] table_id
> - *   id of table
>   * @param[in] rule
>   *   Flow classify rule
>   * @return
> @@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct
> rte_flow_classifier *cls,
>   */
>  int
>  rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_flow_classify_rule *rule);
> 
>  /**
> @@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct
> rte_flow_classifier *cls,
>   *
>   * @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
> @@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct
> rte_flow_classifier *cls,
>   */
>  int
>  rte_flow_classifier_query(struct rte_flow_classifier *cls,
> -		uint32_t table_id,
>  		struct rte_mbuf **pkts,
>  		const uint16_t nb_pkts,
>  		struct rte_flow_classify_rule *rule,
> diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.c
> b/lib/librte_flow_classify/rte_flow_classify_parse.c
> index dbfa111..9fb3e51 100644
> --- a/lib/librte_flow_classify/rte_flow_classify_parse.c
> +++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
> @@ -40,7 +40,7 @@ struct classify_valid_pattern {
>  	parse_filter_t parse_filter;
>  };
> 
> -static struct rte_flow_action action;
> +static struct classify_action action;
> 
>  /* Pattern for IPv4 5-tuple UDP filter */  static enum rte_flow_item_type
> pattern_ntuple_1[] = { @@ -80,7 +80,7 @@ static struct classify_valid_pattern
> classify_supported_patterns[] = {
>  	{ pattern_ntuple_3, classify_parse_ntuple_filter },  };
> 
> -struct rte_flow_action *
> +struct classify_action *
>  classify_get_flow_action(void)
>  {
>  	return &action;
> @@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct
> rte_flow_attr *attr,
>  	const struct rte_flow_item_udp *udp_mask;
>  	const struct rte_flow_item_sctp *sctp_spec;
>  	const struct rte_flow_item_sctp *sctp_mask;
> +	const struct rte_flow_action_count *count;
> +	const struct rte_flow_action_mark *mark_spec;
>  	uint32_t index;
> 
> -	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;
> -	}
> -
>  	/* parse pattern */
>  	index = 0;
> 
> @@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct rte_flow_attr
> *attr,
>  		return -EINVAL;
>  	}
> 
> -	/* parse action */
> -	index = 0;
> -
> -	/**
> -	 * n-tuple only supports count,
> -	 * check if the first not void action is COUNT.
> -	 */
> -	memset(&action, 0, sizeof(action));
> -	NEXT_ITEM_OF_ACTION(act, actions, index);
> -	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
> -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> -		rte_flow_error_set(error, EINVAL,
> -			RTE_FLOW_ERROR_TYPE_ACTION,
> -			item, "Not supported action.");
> -		return -EINVAL;
> -	}
> -	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
> -
> -	/* check if the next not void item is END */
> -	index++;
> -	NEXT_ITEM_OF_ACTION(act, actions, index);
> -	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> -		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> -		rte_flow_error_set(error, EINVAL,
> -			RTE_FLOW_ERROR_TYPE_ACTION,
> -			act, "Not supported action.");
> -		return -EINVAL;
> -	}
> +	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
> 
>  	/* parse attr */
>  	/* must be input direction */
> @@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct rte_flow_attr
> *attr,
>  	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
>  		filter->priority = FLOW_RULE_MAX_PRIORITY;
> 
> +	/* parse action */
> +	index = 0;
> +
> +	/**
> +	 * n-tuple only supports count and Mark,
> +	 * check if the first not void action is COUNT or MARK.
> +	 */
> +	memset(&action, 0, sizeof(action));
> +	NEXT_ITEM_OF_ACTION(act, actions, index);
> +	switch (act->type) {
> +	case RTE_FLOW_ACTION_TYPE_COUNT:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_COUNT;
> +		count = (const struct rte_flow_action_count *)act->conf;
> +		memcpy(&action.act.counter, count,
> sizeof(action.act.counter));
> +		break;
> +	case RTE_FLOW_ACTION_TYPE_MARK:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_MARK;
> +		mark_spec = (const struct rte_flow_action_mark *)act->conf;
> +		memcpy(&action.act.mark, mark_spec,
> sizeof(action.act.mark));
> +		break;
> +	default:
> +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> +		rte_flow_error_set(error, EINVAL,
> +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> +		   "Invalid action.");
> +		return -EINVAL;
> +	}
> +
> +	/* check if the next not void item is MARK or COUNT or END */
> +	index++;
> +	NEXT_ITEM_OF_ACTION(act, actions, index);
> +	switch (act->type) {
> +	case RTE_FLOW_ACTION_TYPE_COUNT:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_COUNT;
> +		count = (const struct rte_flow_action_count *)act->conf;
> +		memcpy(&action.act.counter, count,
> sizeof(action.act.counter));
> +		break;
> +	case RTE_FLOW_ACTION_TYPE_MARK:
> +		action.action_mask |= 1LLU <<
> RTE_FLOW_ACTION_TYPE_MARK;
> +		mark_spec = (const struct rte_flow_action_mark *)act->conf;
> +		memcpy(&action.act.mark, mark_spec,
> sizeof(action.act.mark));
> +		break;
> +	case RTE_FLOW_ACTION_TYPE_END:
> +		return 0;
> +	default:
> +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> +		rte_flow_error_set(error, EINVAL,
> +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> +		   "Invalid action.");
> +		return -EINVAL;
> +	}
> +
> +	/* check if the next not void item is END */
> +	index++;
> +	NEXT_ITEM_OF_ACTION(act, actions, index);
> +	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
> +		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
> +		rte_flow_error_set(error, EINVAL,
> +		   RTE_FLOW_ERROR_TYPE_ACTION, act,
> +		   "Invalid action.");
> +		return -EINVAL;
> +	}
> +
>  	return 0;
>  }
> diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h
> b/lib/librte_flow_classify/rte_flow_classify_parse.h
> index 1d4708a..9c1de72 100644
> --- a/lib/librte_flow_classify/rte_flow_classify_parse.h
> +++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
> @@ -43,6 +43,20 @@
>  extern "C" {
>  #endif
> 
> +extern enum rte_flow_classify_table_type table_type;
> +
> +struct classify_action {
> +	/* Flow action mask */
> +	uint64_t action_mask;
> +
> +	struct action {
> +		/** Integer value to return with packets */
> +		struct rte_flow_action_mark mark;
> +		/** Flow rule counter */
> +		struct rte_flow_query_count counter;
> +	} act;
> +};
> +
>  typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
>  			      const struct rte_flow_item pattern[],
>  			      const struct rte_flow_action actions[], @@ -64,7
> +78,7 @@ parse_filter_t  classify_find_parse_filter_func(struct rte_flow_item
> *pattern);
> 
>  /* get action data */
> -struct rte_flow_action *
> +struct classify_action *
>  classify_get_flow_action(void);
> 
>  #ifdef __cplusplus
> diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map
> b/lib/librte_flow_classify/rte_flow_classify_version.map
> index f7695cb..49bc25c 100644
> --- a/lib/librte_flow_classify/rte_flow_classify_version.map
> +++ b/lib/librte_flow_classify/rte_flow_classify_version.map
> @@ -7,6 +7,7 @@ EXPERIMENTAL {
>  	rte_flow_classify_table_create;
>  	rte_flow_classify_table_entry_add;
>  	rte_flow_classify_table_entry_delete;
> +	rte_flow_classify_validate;
> 
>  	local: *;
>  };
> --
> 2.9.3

Can you fix the typos in the the v4, other wise ack.
Acked-by: Bernard Iremonger<Bernard.iremonger@intel.com>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v3 2/4] test/test_flow_classify: update test to accommodate changes
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
@ 2017-12-19 12:06       ` Iremonger, Bernard
  0 siblings, 0 replies; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-19 12:06 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Friday, December 15, 2017 10:39 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [PATCH v3 2/4] test/test_flow_classify: update test to accommodate
> changes
> 
> Test have ben modified to adapt the flow_classify api changes.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>

Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v3 3/4] examples/flow_classify: update sample application
  2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 3/4] examples/flow_classify: update sample application Jasvinder Singh
@ 2017-12-19 12:09       ` Iremonger, Bernard
  0 siblings, 0 replies; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-19 12:09 UTC (permalink / raw)
  To: Singh, Jasvinder, dev

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Friday, December 15, 2017 10:39 AM
> To: dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: [PATCH v3 3/4] examples/flow_classify: update sample application
> 
> Update the flow_classify sample app to adapt the APIs changes.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>

Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib
  2017-12-18 13:40         ` Singh, Jasvinder
@ 2017-12-19 12:13           ` Iremonger, Bernard
  0 siblings, 0 replies; 41+ messages in thread
From: Iremonger, Bernard @ 2017-12-19 12:13 UTC (permalink / raw)
  To: Singh, Jasvinder, Kovacevic, Marko, dev

Hi Jasvinder,

> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Monday, December 18, 2017 1:41 PM
> To: Kovacevic, Marko <marko.kovacevic@intel.com>; dev@dpdk.org
> Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> Subject: RE: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow
> classify lib
> 
> 
> 
> > -----Original Message-----
> > From: Kovacevic, Marko
> > Sent: Monday, December 18, 2017 11:05 AM
> > To: Singh, Jasvinder <jasvinder.singh@intel.com>; dev@dpdk.org
> > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > Subject: RE: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for
> > flow classify lib
> >
> >
> >
> > > -----Original Message-----
> > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
> > > Sent: Friday, December 15, 2017 10:39 AM
> > > To: dev@dpdk.org
> > > Cc: Iremonger, Bernard <bernard.iremonger@intel.com>
> > > Subject: [dpdk-dev] [PATCH v3 4/4] doc: update documentation for
> > > flow classify lib
> > >
> > > Updates the documentation for flow classification library and sample
> > > application.
> > >
> > > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> >
> >
> > > v3:
> > > - add validate API desciption to programmers guide
> >
> > Small typo desciption/   description
> >
> >
> > > @@ -225,11 +236,16 @@ The ``Classifier`` has the following internal
> > structures:
> > >          /* Input parameters */
> > >          char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
> > >          int socket_id;
> > > -        enum rte_flow_classify_table_type type;
> > >
> > > -        /* Internal tables */
> > > -        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
> > > +        /* Internal */
> > > +        /* ntuple_fliter */
> >
> > Small typo above.   Ntuple_fliter/  ntuple_filter.
> >
> >
> > > +        struct rte_eth_ntuple_filter ntuple_filter;
> > > +
> > > +        /* clasifier tables */
> >
> > Same above clasifier /   classifier
> >
> >
> > >  To create an ACL table the ``rte_table_acl_params`` structure must
> > > be @@ -
> > > 314,14 +329,14 @@ and SCTP.
> > >          RTE_FLOW_ITEM_TYPE_END,
> > >      };
> > >
> > > -The internal function ``flow_classify_parse_flow`` parses the
> > > +The API function ``rte_flow_classify_validate`` parses the
> > >  IPv4 5-tuple pattern, attributes and actions and returns the
> > > 5-tuple data in the ``rte_eth_ntuple_filter`` structure.
> > >
> > >  .. code-block:: c
> > >
> > >      static int
> > > -    flow_classify_parse_flow(
> > > +    rte_flow_classify_validate(struct rte_flow_classifier *cls,
> > >                     const struct rte_flow_attr *attr,
> > >                     const struct rte_flow_item pattern[],
> > >                     const struct rte_flow_action actions[], @@
> > > -333,7
> > > +348,7 @@ Adding Flow Rules  The
> > > +``rte_flow_classify_table_entry_add``
> > > API creates an ``rte_flow_classify`` object which contains the
> > > flow_classify id and type, the action, a union of add and delete
> > > keys and a
> > union of rules.
> > > -It uses the ``flow_classify_parse_flow`` internal function for
> > > parsing the
> > > +It uses the ``rte_flow_classify_validate`` api function for parsing
> > > +the
> >
> > Above api/  API
> >
> >
> > Otherwise everything else seem ok
> >
> > Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
> >
> 
> Thanks Marko for review. I will fix them in next version.
> 
> Jasvinder

With above typo's fixed.

Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
                       ` (3 preceding siblings ...)
  2017-12-19 12:03     ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Iremonger, Bernard
@ 2017-12-19 14:29     ` Jasvinder Singh
  2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
                         ` (4 more replies)
  4 siblings, 5 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-19 14:29 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, marko.kovacevic

This patch removes table id parameter from all the flow
classify apis to reduce the complexity alongwith some code
cleanup.

The validate api is exposed as public api to allow user
to validate the flow before adding it to the classifier.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Bernard Iremonger<Bernard.iremonger@intel.com>
---
v4:
- fix typos in the description

v2:
- break the patche into multiple
- fix the error checks

 lib/librte_flow_classify/rte_flow_classify.c       | 313 +++++++++++----------
 lib/librte_flow_classify/rte_flow_classify.h       |  74 +++--
 lib/librte_flow_classify/rte_flow_classify_parse.c | 118 ++++----
 lib/librte_flow_classify/rte_flow_classify_parse.h |  16 +-
 .../rte_flow_classify_version.map                  |   1 +
 5 files changed, 296 insertions(+), 226 deletions(-)

diff --git a/lib/librte_flow_classify/rte_flow_classify.c b/lib/librte_flow_classify/rte_flow_classify.c
index e6f4486..689ad81 100644
--- a/lib/librte_flow_classify/rte_flow_classify.c
+++ b/lib/librte_flow_classify/rte_flow_classify.c
@@ -39,16 +39,20 @@
 
 int librte_flow_classify_logtype;
 
-static struct rte_eth_ntuple_filter ntuple_filter;
 static uint32_t unique_id = 1;
 
+enum rte_flow_classify_table_type table_type
+	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
 
 struct rte_flow_classify_table_entry {
 	/* meta-data for classify rule */
 	uint32_t rule_id;
+
+	/* Flow action */
+	struct classify_action action;
 };
 
-struct rte_table {
+struct rte_cls_table {
 	/* Input parameters */
 	struct rte_table_ops ops;
 	uint32_t entry_size;
@@ -64,11 +68,16 @@ struct rte_flow_classifier {
 	/* Input parameters */
 	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
 	int socket_id;
-	enum rte_flow_classify_table_type type;
 
-	/* Internal tables */
-	struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	/* Internal */
+	/* ntuple_filter */
+	struct rte_eth_ntuple_filter ntuple_filter;
+
+	/* classifier tables */
+	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+	uint32_t table_mask;
 	uint32_t num_tables;
+
 	uint16_t nb_pkts;
 	struct rte_flow_classify_table_entry
 		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -97,18 +106,19 @@ struct classify_rules {
 
 struct rte_flow_classify_rule {
 	uint32_t id; /* unique ID of classify rule */
-	struct rte_flow_action action; /* action when match found */
+	enum rte_flow_classify_table_type tbl_type; /* rule table */
 	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 */
+	struct rte_flow_classify_table_entry entry;  /* rule meta data */
 	void *entry_ptr; /* handle to the table entry for rule meta data */
 };
 
-static int
-flow_classify_parse_flow(
+int
+rte_flow_classify_validate(
+		   struct rte_flow_classifier *cls,
 		   const struct rte_flow_attr *attr,
 		   const struct rte_flow_item pattern[],
 		   const struct rte_flow_action actions[],
@@ -120,7 +130,38 @@ flow_classify_parse_flow(
 	uint32_t i = 0;
 	int ret;
 
-	memset(&ntuple_filter, 0, sizeof(ntuple_filter));
+	if (error == NULL)
+		return -EINVAL;
+
+	if (cls == NULL) {
+		RTE_FLOW_CLASSIFY_LOG(ERR,
+			"%s: rte_flow_classifier parameter is NULL\n",
+			__func__);
+		return -EINVAL;
+	}
+
+	if (!attr) {
+		rte_flow_error_set(error, EINVAL,
+				   RTE_FLOW_ERROR_TYPE_ATTR,
+				   NULL, "NULL attribute.");
+		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;
+	}
+
+	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
 
 	/* Get the non-void item number of pattern */
 	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
@@ -150,7 +191,7 @@ flow_classify_parse_flow(
 		return -EINVAL;
 	}
 
-	ret = parse_filter(attr, items, actions, &ntuple_filter, error);
+	ret = parse_filter(attr, items, actions, &cls->ntuple_filter, error);
 	free(items);
 	return ret;
 }
@@ -275,17 +316,14 @@ rte_flow_classifier_create(struct rte_flow_classifier_params *params)
 	/* 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;
+	cls->socket_id = params->socket_id;
 
 	return cls;
 }
 
 static void
-rte_flow_classify_table_free(struct rte_table *table)
+rte_flow_classify_table_free(struct rte_cls_table *table)
 {
 	if (table->ops.f_free != NULL)
 		table->ops.f_free(table->h_table);
@@ -306,7 +344,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 	/* Free tables */
 	for (i = 0; i < cls->num_tables; i++) {
-		struct rte_table *table = &cls->tables[i];
+		struct rte_cls_table *table = &cls->tables[i];
 
 		rte_flow_classify_table_free(table);
 	}
@@ -319,8 +357,7 @@ rte_flow_classifier_free(struct rte_flow_classifier *cls)
 
 static int
 rte_table_check_params(struct rte_flow_classifier *cls,
-		struct rte_flow_classify_table_params *params,
-		uint32_t *table_id)
+		struct rte_flow_classify_table_params *params)
 {
 	if (cls == NULL) {
 		RTE_FLOW_CLASSIFY_LOG(ERR,
@@ -333,11 +370,6 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 			__func__);
 		return -EINVAL;
 	}
-	if (table_id == NULL) {
-		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: table_id parameter is NULL\n",
-			__func__);
-		return -EINVAL;
-	}
 
 	/* ops */
 	if (params->ops == NULL) {
@@ -371,22 +403,18 @@ rte_table_check_params(struct rte_flow_classifier *cls,
 
 int
 rte_flow_classify_table_create(struct rte_flow_classifier *cls,
-	struct rte_flow_classify_table_params *params,
-	uint32_t *table_id)
+	struct rte_flow_classify_table_params *params)
 {
-	struct rte_table *table;
+	struct rte_cls_table *table;
 	void *h_table;
-	uint32_t entry_size, id;
+	uint32_t entry_size;
 	int ret;
 
 	/* Check input arguments */
-	ret = rte_table_check_params(cls, params, table_id);
+	ret = rte_table_check_params(cls, params);
 	if (ret != 0)
 		return ret;
 
-	id = cls->num_tables;
-	table = &cls->tables[id];
-
 	/* calculate table entry size */
 	entry_size = sizeof(struct rte_flow_classify_table_entry);
 
@@ -400,8 +428,9 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 	}
 
 	/* Commit current table to the classifier */
+	table = &cls->tables[cls->num_tables];
+	table->type = params->type;
 	cls->num_tables++;
-	*table_id = id;
 
 	/* Save input parameters */
 	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
@@ -414,7 +443,7 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
 }
 
 static struct rte_flow_classify_rule *
-allocate_acl_ipv4_5tuple_rule(void)
+allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
 {
 	struct rte_flow_classify_rule *rule;
 	int log_level;
@@ -427,45 +456,44 @@ allocate_acl_ipv4_5tuple_rule(void)
 	rule->id = unique_id++;
 	rule->rules.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.priority = cls->ntuple_filter.priority;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
-			ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto_mask;
 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
-			ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto = ntuple_filter.proto;
-	rule->rules.u.ipv4_5tuple.proto_mask = ntuple_filter.proto_mask;
+			cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
+	rule->rules.u.ipv4_5tuple.proto_mask = cls->ntuple_filter.proto_mask;
 
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.src_ip_mask;
+			cls->ntuple_filter.src_ip_mask;
 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
-			ntuple_filter.src_ip;
-	rule->rules.u.ipv4_5tuple.src_ip_mask = ntuple_filter.src_ip_mask;
-	rule->rules.u.ipv4_5tuple.src_ip = ntuple_filter.src_ip;
+			cls->ntuple_filter.src_ip;
+	rule->rules.u.ipv4_5tuple.src_ip_mask = cls->ntuple_filter.src_ip_mask;
+	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
 
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32 =
-			ntuple_filter.dst_ip_mask;
+			cls->ntuple_filter.dst_ip_mask;
 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
-			ntuple_filter.dst_ip;
-	rule->rules.u.ipv4_5tuple.dst_ip_mask = ntuple_filter.dst_ip_mask;
-	rule->rules.u.ipv4_5tuple.dst_ip = ntuple_filter.dst_ip;
+			cls->ntuple_filter.dst_ip;
+	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls->ntuple_filter.dst_ip_mask;
+	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
 
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.src_port_mask;
+			cls->ntuple_filter.src_port_mask;
 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
-			ntuple_filter.src_port;
-	rule->rules.u.ipv4_5tuple.src_port_mask = ntuple_filter.src_port_mask;
-	rule->rules.u.ipv4_5tuple.src_port = ntuple_filter.src_port;
+			cls->ntuple_filter.src_port;
+	rule->rules.u.ipv4_5tuple.src_port_mask =
+			cls->ntuple_filter.src_port_mask;
+	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
 
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
-			ntuple_filter.dst_port_mask;
+			cls->ntuple_filter.dst_port_mask;
 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
-			ntuple_filter.dst_port;
-	rule->rules.u.ipv4_5tuple.dst_port_mask = ntuple_filter.dst_port_mask;
-	rule->rules.u.ipv4_5tuple.dst_port = ntuple_filter.dst_port;
+			cls->ntuple_filter.dst_port;
+	rule->rules.u.ipv4_5tuple.dst_port_mask =
+			cls->ntuple_filter.dst_port_mask;
+	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
 
 	log_level = rte_log_get_level(librte_flow_classify_logtype);
 
@@ -485,34 +513,21 @@ allocate_acl_ipv4_5tuple_rule(void)
 
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error)
 {
 	struct rte_flow_classify_rule *rule;
 	struct rte_flow_classify_table_entry *table_entry;
+	struct classify_action *action;
+	uint32_t i;
 	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 (key_found == NULL) {
 		rte_flow_error_set(error, EINVAL,
 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
@@ -520,91 +535,95 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
 		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 = flow_classify_parse_flow(attr, pattern, actions, error);
+	ret = rte_flow_classify_validate(cls, attr, pattern, actions, error);
 	if (ret < 0)
 		return NULL;
 
-	switch (cls->type) {
-	case RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL:
-		rule = allocate_acl_ipv4_5tuple_rule();
+	switch (table_type) {
+	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
+		rule = allocate_acl_ipv4_5tuple_rule(cls);
 		if (!rule)
 			return NULL;
+		rule->tbl_type = table_type;
+		cls->table_mask |= table_type;
 		break;
 	default:
 		return NULL;
 	}
 
-	rule->entry = malloc(sizeof(struct rte_flow_classify_table_entry));
-	if (!rule->entry) {
-		free(rule);
-		return NULL;
-	}
-
-	table_entry = rule->entry;
+	action = classify_get_flow_action();
+	table_entry = &rule->entry;
 	table_entry->rule_id = rule->id;
+	table_entry->action.action_mask = action->action_mask;
 
-	if (cls->tables[table_id].ops.f_add != NULL) {
-		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);
-			return NULL;
+	/* Copy actions */
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
+		memcpy(&table_entry->action.act.counter, &action->act.counter,
+				sizeof(table_entry->action.act.counter));
+	}
+	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_MARK)) {
+		memcpy(&table_entry->action.act.mark, &action->act.mark,
+				sizeof(table_entry->action.act.mark));
+	}
+
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+		if (table->type == table_type) {
+			if (table->ops.f_add != NULL) {
+				ret = table->ops.f_add(
+					table->h_table,
+					&rule->u.key.key_add,
+					&rule->entry,
+					&rule->key_found,
+					&rule->entry_ptr);
+				if (ret) {
+					free(rule);
+					return NULL;
+				}
+
+			*key_found = rule->key_found;
+			}
+
+			return rule;
 		}
-		*key_found = rule->key_found;
 	}
-	return rule;
+	return NULL;
 }
 
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule)
 {
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || table_id >= cls->num_tables)
+	if (!cls || !rule)
 		return ret;
+	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
+
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
 
-	if (cls->tables[table_id].ops.f_delete != NULL)
-		ret = cls->tables[table_id].ops.f_delete(
-			cls->tables[table_id].h_table,
-			&rule->u.key.key_del,
-			&rule->key_found,
-			&rule->entry);
+		if (table->type == tbl_type) {
+			if (table->ops.f_delete != NULL) {
+				ret = table->ops.f_delete(table->h_table,
+						&rule->u.key.key_del,
+						&rule->key_found,
+						&rule->entry);
 
+				return ret;
+			}
+		}
+	}
+	free(rule);
 	return ret;
 }
 
 static int
 flow_classifier_lookup(struct rte_flow_classifier *cls,
-		uint32_t table_id,
+		struct rte_cls_table *table,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts)
 {
@@ -613,8 +632,7 @@ flow_classifier_lookup(struct rte_flow_classifier *cls,
 	uint64_t lookup_hit_mask;
 
 	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
-	ret = cls->tables[table_id].ops.f_lookup(
-		cls->tables[table_id].h_table,
+	ret = table->ops.f_lookup(table->h_table,
 		pkts, pkts_mask, &lookup_hit_mask,
 		(void **)cls->entries);
 
@@ -632,12 +650,12 @@ action_apply(struct rte_flow_classifier *cls,
 		struct rte_flow_classify_stats *stats)
 {
 	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
+	struct rte_flow_classify_table_entry *entry = &rule->entry;
 	uint64_t count = 0;
-	int i;
-	int ret = -EINVAL;
+	uint32_t action_mask = entry->action.action_mask;
+	int i, ret = -EINVAL;
 
-	switch (rule->action.type) {
-	case RTE_FLOW_ACTION_TYPE_COUNT:
+	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
 		for (i = 0; i < cls->nb_pkts; i++) {
 			if (rule->id == cls->entries[i]->rule_id)
 				count++;
@@ -650,32 +668,37 @@ action_apply(struct rte_flow_classifier *cls,
 			ntuple_stats->counter1 = count;
 			ntuple_stats->ipv4_5tuple = rule->rules.u.ipv4_5tuple;
 		}
-		break;
-	default:
-		ret = -ENOTSUP;
-		break;
 	}
-
 	return ret;
 }
 
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
 		struct rte_flow_classify_stats *stats)
 {
+	enum rte_flow_classify_table_type tbl_type;
+	uint32_t i;
 	int ret = -EINVAL;
 
-	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0 ||
-		table_id >= cls->num_tables)
+	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
 		return ret;
 
-	ret = flow_classifier_lookup(cls, table_id, pkts, nb_pkts);
-	if (!ret)
-		ret = action_apply(cls, rule, stats);
+	tbl_type = rule->tbl_type;
+	for (i = 0; i < cls->num_tables; i++) {
+		struct rte_cls_table *table = &cls->tables[i];
+
+			if (table->type == tbl_type) {
+				ret = flow_classifier_lookup(cls, table,
+						pkts, nb_pkts);
+				if (!ret) {
+					ret = action_apply(cls, rule, stats);
+					return ret;
+				}
+			}
+	}
 	return ret;
 }
 
diff --git a/lib/librte_flow_classify/rte_flow_classify.h b/lib/librte_flow_classify/rte_flow_classify.h
index 1211873..b9b669f 100644
--- a/lib/librte_flow_classify/rte_flow_classify.h
+++ b/lib/librte_flow_classify/rte_flow_classify.h
@@ -86,6 +86,10 @@ extern int librte_flow_classify_logtype;
 rte_log(RTE_LOG_ ## level, librte_flow_classify_logtype, "%s(): " fmt, \
 	__func__, ## args)
 
+#ifndef RTE_FLOW_CLASSIFY_TABLE_MAX
+#define RTE_FLOW_CLASSIFY_TABLE_MAX		32
+#endif
+
 /** Opaque data type for flow classifier */
 struct rte_flow_classifier;
 
@@ -102,17 +106,16 @@ enum rte_flow_classify_rule_type {
 
 /** Flow classify table type */
 enum rte_flow_classify_table_type {
-	/** no type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE,
-	/** ACL type */
-	RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL,
-};
+	/** No type */
+	RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE = 1 << 0,
+	/** ACL IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE = 1 << 1,
+	/** ACL VLAN IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_VLAN_IP4_5TUPLE = 1 << 2,
+	/** ACL QinQ IP4 5TUPLE */
+	RTE_FLOW_CLASSIFY_TABLE_ACL_QINQ_IP4_5TUPLE = 1 << 3,
 
-/**
- * Maximum number of tables allowed for any Flow Classifier instance.
- * The value of this parameter cannot be changed.
- */
-#define RTE_FLOW_CLASSIFY_TABLE_MAX  64
+};
 
 /** Parameters for flow classifier creation */
 struct rte_flow_classifier_params {
@@ -122,9 +125,6 @@ struct rte_flow_classifier_params {
 	/** 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;
 };
 
 /** Parameters for table creation */
@@ -134,6 +134,9 @@ struct rte_flow_classify_table_params {
 
 	/** Opaque param to be passed to the table create operation */
 	void *arg_create;
+
+	/** Classifier table type */
+	enum rte_flow_classify_table_type type;
 };
 
 /** IPv4 5-tuple data */
@@ -197,32 +200,50 @@ rte_flow_classifier_free(struct rte_flow_classifier *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);
+		struct rte_flow_classify_table_params *params);
+
+/**
+ * Flow classify validate
+ *
+ * @param cls
+ *   Handle to flow classifier instance
+ * @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(struct rte_flow_classifier *cls,
+		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[out] key_found
- *  returns 1 if key present already, 0 otherwise.
  * @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] key_found
+ *  returns 1 if rule present already, 0 otherwise.
  * @param[out] error
  *   Perform verbose error reporting if not NULL. Structure
  *   initialised in case of error only.
@@ -231,11 +252,10 @@ rte_flow_classify_table_create(struct rte_flow_classifier *cls,
  */
 struct rte_flow_classify_rule *
 rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
-		uint32_t table_id,
-		int *key_found,
 		const struct rte_flow_attr *attr,
 		const struct rte_flow_item pattern[],
 		const struct rte_flow_action actions[],
+		int *key_found,
 		struct rte_flow_error *error);
 
 /**
@@ -243,8 +263,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  *
  * @param[in] cls
  *   Flow classifier handle
- * @param[in] table_id
- *   id of table
  * @param[in] rule
  *   Flow classify rule
  * @return
@@ -252,7 +270,6 @@ rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_flow_classify_rule *rule);
 
 /**
@@ -260,8 +277,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  *
  * @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
@@ -276,7 +291,6 @@ rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
  */
 int
 rte_flow_classifier_query(struct rte_flow_classifier *cls,
-		uint32_t table_id,
 		struct rte_mbuf **pkts,
 		const uint16_t nb_pkts,
 		struct rte_flow_classify_rule *rule,
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.c b/lib/librte_flow_classify/rte_flow_classify_parse.c
index dbfa111..9fb3e51 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.c
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.c
@@ -40,7 +40,7 @@ struct classify_valid_pattern {
 	parse_filter_t parse_filter;
 };
 
-static struct rte_flow_action action;
+static struct classify_action action;
 
 /* Pattern for IPv4 5-tuple UDP filter */
 static enum rte_flow_item_type pattern_ntuple_1[] = {
@@ -80,7 +80,7 @@ static struct classify_valid_pattern classify_supported_patterns[] = {
 	{ pattern_ntuple_3, classify_parse_ntuple_filter },
 };
 
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void)
 {
 	return &action;
@@ -244,28 +244,10 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	const struct rte_flow_item_udp *udp_mask;
 	const struct rte_flow_item_sctp *sctp_spec;
 	const struct rte_flow_item_sctp *sctp_mask;
+	const struct rte_flow_action_count *count;
+	const struct rte_flow_action_mark *mark_spec;
 	uint32_t index;
 
-	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;
-	}
-
 	/* parse pattern */
 	index = 0;
 
@@ -483,34 +465,7 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 		return -EINVAL;
 	}
 
-	/* parse action */
-	index = 0;
-
-	/**
-	 * n-tuple only supports count,
-	 * check if the first not void action is COUNT.
-	 */
-	memset(&action, 0, sizeof(action));
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_COUNT) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			item, "Not supported action.");
-		return -EINVAL;
-	}
-	action.type = RTE_FLOW_ACTION_TYPE_COUNT;
-
-	/* check if the next not void item is END */
-	index++;
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
-		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			act, "Not supported action.");
-		return -EINVAL;
-	}
+	table_type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
 	/* parse attr */
 	/* must be input direction */
@@ -542,5 +497,68 @@ classify_parse_ntuple_filter(const struct rte_flow_attr *attr,
 	if (attr->priority >  FLOW_RULE_MIN_PRIORITY)
 		filter->priority = FLOW_RULE_MAX_PRIORITY;
 
+	/* parse action */
+	index = 0;
+
+	/**
+	 * n-tuple only supports count and Mark,
+	 * check if the first not void action is COUNT or MARK.
+	 */
+	memset(&action, 0, sizeof(action));
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is MARK or COUNT or END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	switch (act->type) {
+	case RTE_FLOW_ACTION_TYPE_COUNT:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_COUNT;
+		count = (const struct rte_flow_action_count *)act->conf;
+		memcpy(&action.act.counter, count, sizeof(action.act.counter));
+		break;
+	case RTE_FLOW_ACTION_TYPE_MARK:
+		action.action_mask |= 1LLU << RTE_FLOW_ACTION_TYPE_MARK;
+		mark_spec = (const struct rte_flow_action_mark *)act->conf;
+		memcpy(&action.act.mark, mark_spec, sizeof(action.act.mark));
+		break;
+	case RTE_FLOW_ACTION_TYPE_END:
+		return 0;
+	default:
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
+	/* check if the next not void item is END */
+	index++;
+	NEXT_ITEM_OF_ACTION(act, actions, index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+		memset(filter, 0, sizeof(struct rte_eth_ntuple_filter));
+		rte_flow_error_set(error, EINVAL,
+		   RTE_FLOW_ERROR_TYPE_ACTION, act,
+		   "Invalid action.");
+		return -EINVAL;
+	}
+
 	return 0;
 }
diff --git a/lib/librte_flow_classify/rte_flow_classify_parse.h b/lib/librte_flow_classify/rte_flow_classify_parse.h
index 1d4708a..9c1de72 100644
--- a/lib/librte_flow_classify/rte_flow_classify_parse.h
+++ b/lib/librte_flow_classify/rte_flow_classify_parse.h
@@ -43,6 +43,20 @@
 extern "C" {
 #endif
 
+extern enum rte_flow_classify_table_type table_type;
+
+struct classify_action {
+	/* Flow action mask */
+	uint64_t action_mask;
+
+	struct action {
+		/** Integer value to return with packets */
+		struct rte_flow_action_mark mark;
+		/** Flow rule counter */
+		struct rte_flow_query_count counter;
+	} act;
+};
+
 typedef int (*parse_filter_t)(const struct rte_flow_attr *attr,
 			      const struct rte_flow_item pattern[],
 			      const struct rte_flow_action actions[],
@@ -64,7 +78,7 @@ parse_filter_t
 classify_find_parse_filter_func(struct rte_flow_item *pattern);
 
 /* get action data */
-struct rte_flow_action *
+struct classify_action *
 classify_get_flow_action(void);
 
 #ifdef __cplusplus
diff --git a/lib/librte_flow_classify/rte_flow_classify_version.map b/lib/librte_flow_classify/rte_flow_classify_version.map
index f7695cb..49bc25c 100644
--- a/lib/librte_flow_classify/rte_flow_classify_version.map
+++ b/lib/librte_flow_classify/rte_flow_classify_version.map
@@ -7,6 +7,7 @@ EXPERIMENTAL {
 	rte_flow_classify_table_create;
 	rte_flow_classify_table_entry_add;
 	rte_flow_classify_table_entry_delete;
+	rte_flow_classify_validate;
 
 	local: *;
 };
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 2/4] test/test_flow_classify: update test to accommodate changes
  2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
@ 2017-12-19 14:29       ` Jasvinder Singh
  2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 3/4] examples/flow_classify: update sample application Jasvinder Singh
                         ` (3 subsequent siblings)
  4 siblings, 0 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-19 14:29 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, marko.kovacevic

Test have ben modified to adapt the flow_classify api
changes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>
---
v2: 
- add validate API tests

 test/test/test_flow_classify.c | 178 +++++++++++++++++++++++++++++------------
 test/test/test_flow_classify.h |  10 ++-
 2 files changed, 135 insertions(+), 53 deletions(-)

diff --git a/test/test/test_flow_classify.c b/test/test/test_flow_classify.c
index 9f331cd..c8fd5ad 100644
--- a/test/test/test_flow_classify.c
+++ b/test/test/test_flow_classify.c
@@ -51,16 +51,10 @@
 
 
 #define FLOW_CLASSIFY_MAX_RULE_NUM 100
-struct flow_classifier *cls;
-
-struct flow_classifier {
-	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
-	uint32_t n_tables;
-};
+struct flow_classifier_acl *cls;
 
 struct flow_classifier_acl {
-	struct flow_classifier cls;
+	struct rte_flow_classifier *cls;
 } __rte_cache_aligned;
 
 /*
@@ -73,7 +67,15 @@ test_invalid_parameters(void)
 	struct rte_flow_classify_rule *rule;
 	int ret;
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	ret = rte_flow_classify_validate(NULL, NULL, NULL, NULL, NULL);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate",
+			__LINE__);
+		printf(" with NULL param should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 			NULL, NULL);
 	if (rule) {
 		printf("Line %i: flow_classifier_table_entry_add", __LINE__);
@@ -81,7 +83,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -89,14 +91,14 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
 		return -1;
 	}
 
-	rule = rte_flow_classify_table_entry_add(NULL, 1, NULL, NULL, NULL,
+	rule = rte_flow_classify_table_entry_add(NULL, NULL, NULL, NULL,
 		NULL, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add ", __LINE__);
@@ -104,7 +106,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(NULL, 1, NULL);
+	ret = rte_flow_classify_table_entry_delete(NULL, NULL);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -112,7 +114,7 @@ test_invalid_parameters(void)
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(NULL, 1, NULL, 0, NULL, NULL);
+	ret = rte_flow_classifier_query(NULL, NULL, 0, NULL, NULL);
 	if (!ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
 		printf(" with NULL param should have failed!\n");
@@ -129,7 +131,8 @@ test_valid_parameters(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -142,15 +145,24 @@ test_valid_parameters(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: rte_flow_classify_validate",
+			__LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
+
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -168,7 +180,8 @@ test_invalid_patterns(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -183,15 +196,24 @@ test_invalid_patterns(void)
 
 	pattern[0] = eth_item;
 	pattern[1] = ipv4_udp_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -202,15 +224,24 @@ test_invalid_patterns(void)
 	pattern[1] = ipv4_udp_item_1;
 	pattern[2] = udp_item_bad;
 	pattern[3] = end_item_bad;
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -228,7 +259,8 @@ test_invalid_actions(void)
 	int key_found;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -241,15 +273,23 @@ test_invalid_actions(void)
 	actions[0] = count_action_bad;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -260,15 +300,23 @@ test_invalid_actions(void)
 	actions[0] = count_action;
 	actions[1] = end_action_bad;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (!ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (!ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -449,7 +497,8 @@ test_query_udp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -462,15 +511,23 @@ test_query_udp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: rte_flow_classify_validate", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &udp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -478,7 +535,7 @@ test_query_udp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -507,7 +564,8 @@ test_query_tcp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters for rte_flow_classify_table_entry_add and
+	 * set up parameters for rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -520,15 +578,23 @@ test_query_tcp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: flow_classifier_query", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &tcp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -536,7 +602,7 @@ test_query_tcp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -565,7 +631,8 @@ test_query_sctp(void)
 		bufs[i]->packet_type = RTE_PTYPE_L3_IPV4;
 
 	/*
-	 * set up parameters rte_flow_classify_table_entry_add and
+	 * set up parameters rte_flow_classify_validate,
+	 * rte_flow_classify_table_entry_add and
 	 * rte_flow_classify_table_entry_delete
 	 */
 
@@ -578,15 +645,23 @@ test_query_sctp(void)
 	actions[0] = count_action;
 	actions[1] = end_action;
 
-	rule = rte_flow_classify_table_entry_add(cls->cls, 0, &key_found,
-			&attr, pattern, actions, &error);
+	ret = rte_flow_classify_validate(cls->cls, &attr, pattern,
+			actions, &error);
+	if (ret) {
+		printf("Line %i: flow_classifier_query", __LINE__);
+		printf(" should not have failed!\n");
+		return -1;
+	}
+
+	rule = rte_flow_classify_table_entry_add(cls->cls, &attr, pattern,
+			actions, &key_found, &error);
 	if (!rule) {
 		printf("Line %i: flow_classify_table_entry_add", __LINE__);
 		printf(" should not have failed!\n");
 		return -1;
 	}
 
-	ret = rte_flow_classifier_query(cls->cls, 0, bufs, MAX_PKT_BURST,
+	ret = rte_flow_classifier_query(cls->cls, bufs, MAX_PKT_BURST,
 			rule, &sctp_classify_stats);
 	if (ret) {
 		printf("Line %i: flow_classifier_query", __LINE__);
@@ -594,7 +669,7 @@ test_query_sctp(void)
 		return -1;
 	}
 
-	ret = rte_flow_classify_table_entry_delete(cls->cls, 0, rule);
+	ret = rte_flow_classify_table_entry_delete(cls->cls, rule);
 	if (ret) {
 		printf("Line %i: rte_flow_classify_table_entry_delete",
 			__LINE__);
@@ -622,7 +697,6 @@ test_flow_classify(void)
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 	cls->cls = rte_flow_classifier_create(&cls_params);
 
 	/* initialise ACL table params */
@@ -632,11 +706,11 @@ test_flow_classify(void)
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params,
-			&cls->table_id[0]);
+	ret = rte_flow_classify_table_create(cls->cls, &cls_table_params);
 	if (ret) {
 		printf("Line %i: f_create has failed!\n", __LINE__);
 		rte_flow_classifier_free(cls->cls);
diff --git a/test/test/test_flow_classify.h b/test/test/test_flow_classify.h
index 39535cf..af293ed 100644
--- a/test/test/test_flow_classify.h
+++ b/test/test/test_flow_classify.h
@@ -197,7 +197,15 @@ static struct rte_flow_item  sctp_item_1 = { RTE_FLOW_ITEM_TYPE_SCTP,
 /* test actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action count_action_bad = { -1, 0};
 
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 3/4] examples/flow_classify: update sample application
  2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
  2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
@ 2017-12-19 14:29       ` Jasvinder Singh
  2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 4/4] doc: update documentation for flow classify lib Jasvinder Singh
                         ` (2 subsequent siblings)
  4 siblings, 0 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-19 14:29 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, marko.kovacevic

Update the flow_classify sample app to adapt the APIs changes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>
---
v3:
- fix build error issue with validate API
v2:
- use validate api to verify before adding flow rule

 examples/flow_classify/flow_classify.c | 43 ++++++++++++++++++++++------------
 1 file changed, 28 insertions(+), 15 deletions(-)

diff --git a/examples/flow_classify/flow_classify.c b/examples/flow_classify/flow_classify.c
index 766f1dd..af2e129 100644
--- a/examples/flow_classify/flow_classify.c
+++ b/examples/flow_classify/flow_classify.c
@@ -94,7 +94,6 @@ static const struct rte_eth_conf port_conf_default = {
 
 struct flow_classifier {
 	struct rte_flow_classifier *cls;
-	uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
 };
 
 struct flow_classifier_acl {
@@ -195,7 +194,15 @@ static struct rte_flow_item  end_item = { RTE_FLOW_ITEM_TYPE_END,
 /* sample actions:
  * "actions count / end"
  */
-static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT, 0};
+struct rte_flow_query_count count = {
+	.reset = 1,
+	.hits_set = 1,
+	.bytes_set = 1,
+	.hits = 0,
+	.bytes = 0,
+};
+static struct rte_flow_action count_action = { RTE_FLOW_ACTION_TYPE_COUNT,
+	&count};
 static struct rte_flow_action end_action = { RTE_FLOW_ACTION_TYPE_END, 0};
 static struct rte_flow_action actions[2];
 
@@ -274,7 +281,7 @@ lcore_main(struct flow_classifier *cls_app)
 	int i = 0;
 
 	ret = rte_flow_classify_table_entry_delete(cls_app->cls,
-			cls_app->table_id[0], rules[7]);
+			rules[7]);
 	if (ret)
 		printf("table_entry_delete failed [7] %d\n\n", ret);
 	else
@@ -292,11 +299,10 @@ lcore_main(struct flow_classifier *cls_app)
 			       port);
 			printf("to polling thread.\n");
 			printf("Performance will not be optimal.\n");
-
-			printf("\nCore %u forwarding packets. ",
-			       rte_lcore_id());
-			printf("[Ctrl+C to quit]\n");
 		}
+	printf("\nCore %u forwarding packets. ", rte_lcore_id());
+	printf("[Ctrl+C to quit]\n");
+
 	/* Run until the application is quit or killed. */
 	for (;;) {
 		/*
@@ -317,7 +323,6 @@ lcore_main(struct flow_classifier *cls_app)
 				if (rules[i]) {
 					ret = rte_flow_classifier_query(
 						cls_app->cls,
-						cls_app->table_id[0],
 						bufs, nb_rx, rules[i],
 						&classify_stats);
 					if (ret)
@@ -634,9 +639,18 @@ add_classify_rule(struct rte_eth_ntuple_filter *ntuple_filter,
 	actions[0] = count_action;
 	actions[1] = end_action;
 
+	/* Validate and add rule */
+	ret = rte_flow_classify_validate(cls_app->cls, &attr,
+			pattern_ipv4_5tuple, actions, &error);
+	if (ret) {
+		printf("table entry validate failed ipv4_proto = %u\n",
+			ipv4_proto);
+		return ret;
+	}
+
 	rule = rte_flow_classify_table_entry_add(
-			cls_app->cls, cls_app->table_id[0], &key_found,
-			&attr, pattern_ipv4_5tuple, actions, &error);
+			cls_app->cls, &attr, pattern_ipv4_5tuple,
+			actions, &key_found, &error);
 	if (rule == NULL) {
 		printf("table entry add failed ipv4_proto = %u\n",
 			ipv4_proto);
@@ -809,7 +823,6 @@ main(int argc, char *argv[])
 
 	cls_params.name = "flow_classifier";
 	cls_params.socket_id = socket_id;
-	cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
 	cls_app->cls = rte_flow_classifier_create(&cls_params);
 	if (cls_app->cls == NULL) {
@@ -824,11 +837,11 @@ main(int argc, char *argv[])
 	memcpy(table_acl_params.field_format, ipv4_defs, sizeof(ipv4_defs));
 
 	/* initialise table create params */
-	cls_table_params.ops = &rte_table_acl_ops,
-	cls_table_params.arg_create = &table_acl_params,
+	cls_table_params.ops = &rte_table_acl_ops;
+	cls_table_params.arg_create = &table_acl_params;
+	cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-			&cls_app->table_id[0]);
+	ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
 	if (ret) {
 		rte_flow_classifier_free(cls_app->cls);
 		rte_free(cls_app);
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* [dpdk-dev] [PATCH v4 4/4] doc: update documentation for flow classify lib
  2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
  2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
  2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 3/4] examples/flow_classify: update sample application Jasvinder Singh
@ 2017-12-19 14:29       ` Jasvinder Singh
  2018-01-10  0:19       ` [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis Thomas Monjalon
  2018-01-11 18:20       ` Thomas Monjalon
  4 siblings, 0 replies; 41+ messages in thread
From: Jasvinder Singh @ 2017-12-19 14:29 UTC (permalink / raw)
  To: dev; +Cc: bernard.iremonger, marko.kovacevic

Updates the documentation for flow classification
library and sample application.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Marko Kovacevic <marko.kovacevic@intel.com>
Acked-by: Bernard Iremonger <Bernard.iremonger@intel.com>
---
v4:
- fix typos in the description
v3:
- add validate API description to the programmers guide
v2:
- replace parse flow function with validate API

 doc/guides/prog_guide/flow_classify_lib.rst | 83 +++++++++++++++++------------
 doc/guides/sample_app_ug/flow_classify.rst  |  8 +--
 2 files changed, 51 insertions(+), 40 deletions(-)

diff --git a/doc/guides/prog_guide/flow_classify_lib.rst b/doc/guides/prog_guide/flow_classify_lib.rst
index 820dc72..3edb154 100644
--- a/doc/guides/prog_guide/flow_classify_lib.rst
+++ b/doc/guides/prog_guide/flow_classify_lib.rst
@@ -101,30 +101,50 @@ The library has the following API's
      *   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);
+           struct rte_flow_classify_table_params *params);
+
+    /**
+     * Validate the flow classify rule
+     *
+     * @param[in] cls
+     *   Handle to flow classifier instance
+     * @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(struct rte_flow_classifier *cls,
+            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_classifier 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] key_found
+     *   returns 1 if rule present already, 0 otherwise.
      * @param[out] error
      *   Perform verbose error reporting if not NULL. Structure
      *   initialised in case of error only.
@@ -133,10 +153,10 @@ The library has the following API's
      */
     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[],
+            int *key_found;
             struct rte_flow_error *error);
 
     /**
@@ -144,8 +164,6 @@ The library has the following API's
      *
      * @param[in] cls
      *   Flow classifier handle
-     * @param[in] table_id
-     *   id of table
      * @param[in] rule
      *   Flow classify rule
      * @return
@@ -153,7 +171,6 @@ The library has the following API's
      */
     int
     rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_flow_classify_rule *rule);
 
     /**
@@ -161,8 +178,6 @@ The library has the following API's
      *
      * @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
@@ -177,7 +192,6 @@ The library has the following API's
      */
     int
     rte_flow_classifier_query(struct rte_flow_classifier *cls,
-            uint32_t table_id,
             struct rte_mbuf **pkts,
             const uint16_t nb_pkts,
             struct rte_flow_classify_rule *rule,
@@ -200,16 +214,13 @@ application before calling the API.
         /** 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;
     };
 
 The ``Classifier`` has the following internal structures:
 
 .. code-block:: c
 
-    struct rte_table {
+    struct rte_cls_table {
         /* Input parameters */
         struct rte_table_ops ops;
         uint32_t entry_size;
@@ -225,11 +236,16 @@ The ``Classifier`` has the following internal structures:
         /* Input parameters */
         char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
         int socket_id;
-        enum rte_flow_classify_table_type type;
 
-        /* Internal tables */
-        struct rte_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        /* Internal */
+        /* ntuple_filter */
+        struct rte_eth_ntuple_filter ntuple_filter;
+
+        /* classifier tables */
+        struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
+        uint32_t table_mask;
         uint32_t num_tables;
+
         uint16_t nb_pkts;
         struct rte_flow_classify_table_entry
             *entries[RTE_PORT_IN_BURST_SIZE_MAX];
@@ -252,9 +268,8 @@ application before calling the API.
         /** 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;
+        /** Classifier table type */
+        enum rte_flow_classify_table_type type;
      };
 
 To create an ACL table the ``rte_table_acl_params`` structure must be
@@ -314,14 +329,14 @@ and SCTP.
         RTE_FLOW_ITEM_TYPE_END,
     };
 
-The internal function ``flow_classify_parse_flow`` parses the
+The API function ``rte_flow_classify_validate`` parses the
 IPv4 5-tuple pattern, attributes and actions and returns the 5-tuple data in the
 ``rte_eth_ntuple_filter`` structure.
 
 .. code-block:: c
 
     static int
-    flow_classify_parse_flow(
+    rte_flow_classify_validate(struct rte_flow_classifier *cls,
                    const struct rte_flow_attr *attr,
                    const struct rte_flow_item pattern[],
                    const struct rte_flow_action actions[],
@@ -333,7 +348,7 @@ Adding Flow Rules
 The ``rte_flow_classify_table_entry_add`` API creates an
 ``rte_flow_classify`` object which contains the flow_classify id and type, the
 action, a union of add and delete keys and a union of rules.
-It uses the ``flow_classify_parse_flow`` internal function for parsing the
+It uses the ``rte_flow_classify_validate`` API function for parsing the
 flow parameters.
 The 5-tuple ACL key data is obtained from the ``rte_eth_ntuple_filter``
 structure populated by the ``classify_parse_ntuple_filter`` function which
@@ -343,7 +358,7 @@ parses the Flow rule.
 
     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_table_acl_rule_delete_params key_del; /* delete key */
     };
 
     struct classify_rules {
@@ -355,24 +370,24 @@ parses the Flow rule.
 
     struct rte_flow_classify {
         uint32_t id;  /* unique ID of classify object */
-        struct rte_flow_action action; /* action when match found */
-	struct classify_rules rules; /* union of rules */
+        enum rte_flow_classify_table_type tbl_type; /* rule table */
+        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 */
+        struct rte_flow_classify_table_entry entry;  /* rule meta data */
         void *entry_ptr; /* handle to the table entry for rule meta data */
     };
 
-It then calls the ``table[table_id].ops.f_add`` API to add the rule to the ACL
+It then calls the ``table.ops.f_add`` API to add the rule to the ACL
 table.
 
 Deleting Flow Rules
 ~~~~~~~~~~~~~~~~~~~
 
 The ``rte_flow_classify_table_entry_delete`` API calls the
-``table[table_id].ops.f_delete`` API to delete a rule from the ACL table.
+``table.ops.f_delete`` API to delete a rule from the ACL table.
 
 Packet Matching
 ~~~~~~~~~~~~~~~
@@ -380,7 +395,7 @@ Packet Matching
 The ``rte_flow_classifier_query`` API is used to find packets which match a
 given flow Flow rule in the table.
 This API calls the flow_classify_run internal function which calls the
-``table[table_id].ops.f_lookup`` API to see if any packets in a burst match any
+``table.ops.f_lookup`` API to see if any packets in a burst match any
 of the Flow rules in the table.
 The meta data for the highest priority rule matched for each packet is returned
 in the entries array in the ``rte_flow_classify`` object.
diff --git a/doc/guides/sample_app_ug/flow_classify.rst b/doc/guides/sample_app_ug/flow_classify.rst
index bc12b87..427fded 100644
--- a/doc/guides/sample_app_ug/flow_classify.rst
+++ b/doc/guides/sample_app_ug/flow_classify.rst
@@ -228,7 +228,6 @@ table`` to the flow classifier.
 
     struct flow_classifier {
         struct rte_flow_classifier *cls;
-        uint32_t table_id[RTE_FLOW_CLASSIFY_TABLE_MAX];
     };
 
     struct flow_classifier_acl {
@@ -243,7 +242,6 @@ table`` to the flow classifier.
 
     cls_params.name = "flow_classifier";
     cls_params.socket_id = socket_id;
-    cls_params.type = RTE_FLOW_CLASSIFY_TABLE_TYPE_ACL;
 
     cls_app->cls = rte_flow_classifier_create(&cls_params);
     if (cls_app->cls == NULL) {
@@ -260,10 +258,9 @@ table`` to the flow classifier.
     /* initialise table create params */
     cls_table_params.ops = &rte_table_acl_ops,
     cls_table_params.arg_create = &table_acl_params,
-    cls_table_params.table_metadata_size = 0;
+    cls_table_params.type = RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE;
 
-    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params,
-                  &cls->table_id[0]);
+    ret = rte_flow_classify_table_create(cls_app->cls, &cls_table_params);
     if (ret) {
         rte_flow_classifier_free(cls_app->cls);
         rte_free(cls);
@@ -495,7 +492,6 @@ following:
                     if (rules[i]) {
                         ret = rte_flow_classifier_query(
                             cls_app->cls,
-                            cls_app->table_id[0],
                             bufs, nb_rx, rules[i],
                             &classify_stats);
                         if (ret)
-- 
2.9.3

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
                         ` (2 preceding siblings ...)
  2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 4/4] doc: update documentation for flow classify lib Jasvinder Singh
@ 2018-01-10  0:19       ` Thomas Monjalon
  2018-01-10  9:54         ` Singh, Jasvinder
  2018-01-11 18:20       ` Thomas Monjalon
  4 siblings, 1 reply; 41+ messages in thread
From: Thomas Monjalon @ 2018-01-10  0:19 UTC (permalink / raw)
  To: Jasvinder Singh; +Cc: dev, bernard.iremonger, marko.kovacevic

19/12/2017 15:29, Jasvinder Singh:
> This patch removes table id parameter from all the flow
> classify apis to reduce the complexity alongwith some code
> cleanup.
> 
> The validate api is exposed as public api to allow user
> to validate the flow before adding it to the classifier.

This patch does not compile alone.
Should we merge all patches together?

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2018-01-10  0:19       ` [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis Thomas Monjalon
@ 2018-01-10  9:54         ` Singh, Jasvinder
  2018-01-10 10:52           ` Thomas Monjalon
  0 siblings, 1 reply; 41+ messages in thread
From: Singh, Jasvinder @ 2018-01-10  9:54 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Iremonger, Bernard, Kovacevic, Marko


> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Wednesday, January 10, 2018 12:20 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>
> Cc: dev@dpdk.org; Iremonger, Bernard <bernard.iremonger@intel.com>;
> Kovacevic, Marko <marko.kovacevic@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table
> id parameter from apis
> 
> 19/12/2017 15:29, Jasvinder Singh:
> > This patch removes table id parameter from all the flow classify apis
> > to reduce the complexity alongwith some code cleanup.
> >
> > The validate api is exposed as public api to allow user to validate
> > the flow before adding it to the classifier.
> 
> This patch does not compile alone.
> Should we merge all patches together?

No, It should compile alone. On my system it doesn't show any error and compilation goes successfully. Could you send me error log, etc ?

Thank you,
Jasvinder

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2018-01-10  9:54         ` Singh, Jasvinder
@ 2018-01-10 10:52           ` Thomas Monjalon
  2018-01-10 10:59             ` Singh, Jasvinder
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Monjalon @ 2018-01-10 10:52 UTC (permalink / raw)
  To: Singh, Jasvinder; +Cc: dev, Iremonger, Bernard, Kovacevic, Marko

10/01/2018 10:54, Singh, Jasvinder:
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > 19/12/2017 15:29, Jasvinder Singh:
> > > This patch removes table id parameter from all the flow classify apis
> > > to reduce the complexity alongwith some code cleanup.
> > >
> > > The validate api is exposed as public api to allow user to validate
> > > the flow before adding it to the classifier.
> > 
> > This patch does not compile alone.
> > Should we merge all patches together?
> 
> No, It should compile alone. On my system it doesn't show any error and compilation goes successfully. Could you send me error log, etc ?

test/test/test_flow_classify.c:48:10: fatal error: too many arguments to
      function call, expected 6, have 7
                        NULL, NULL);
                              ^~~~

I guess it is expected that test and example does not compile after patch 1.
That's why I suggest to merge all 4 patches.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2018-01-10 10:52           ` Thomas Monjalon
@ 2018-01-10 10:59             ` Singh, Jasvinder
  2018-01-10 11:07               ` Thomas Monjalon
  0 siblings, 1 reply; 41+ messages in thread
From: Singh, Jasvinder @ 2018-01-10 10:59 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Iremonger, Bernard, Kovacevic, Marko



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Wednesday, January 10, 2018 10:53 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>
> Cc: dev@dpdk.org; Iremonger, Bernard <bernard.iremonger@intel.com>;
> Kovacevic, Marko <marko.kovacevic@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table
> id parameter from apis
> 
> 10/01/2018 10:54, Singh, Jasvinder:
> > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > > 19/12/2017 15:29, Jasvinder Singh:
> > > > This patch removes table id parameter from all the flow classify
> > > > apis to reduce the complexity alongwith some code cleanup.
> > > >
> > > > The validate api is exposed as public api to allow user to
> > > > validate the flow before adding it to the classifier.
> > >
> > > This patch does not compile alone.
> > > Should we merge all patches together?
> >
> > No, It should compile alone. On my system it doesn't show any error and
> compilation goes successfully. Could you send me error log, etc ?
> 
> test/test/test_flow_classify.c:48:10: fatal error: too many arguments to
>       function call, expected 6, have 7
>                         NULL, NULL);
>                               ^~~~
> 
> I guess it is expected that test and example does not compile after patch 1.
> That's why I suggest to merge all 4 patches.

Ok, I will send revised patch with all merged into one.

Thanks,
Jasvinder

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2018-01-10 10:59             ` Singh, Jasvinder
@ 2018-01-10 11:07               ` Thomas Monjalon
  2018-01-10 11:12                 ` Singh, Jasvinder
  0 siblings, 1 reply; 41+ messages in thread
From: Thomas Monjalon @ 2018-01-10 11:07 UTC (permalink / raw)
  To: Singh, Jasvinder; +Cc: dev, Iremonger, Bernard, Kovacevic, Marko

10/01/2018 11:59, Singh, Jasvinder:
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > 10/01/2018 10:54, Singh, Jasvinder:
> > > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > > > 19/12/2017 15:29, Jasvinder Singh:
> > > > > This patch removes table id parameter from all the flow classify
> > > > > apis to reduce the complexity alongwith some code cleanup.
> > > > >
> > > > > The validate api is exposed as public api to allow user to
> > > > > validate the flow before adding it to the classifier.
> > > >
> > > > This patch does not compile alone.
> > > > Should we merge all patches together?
> > >
> > > No, It should compile alone. On my system it doesn't show any error and
> > compilation goes successfully. Could you send me error log, etc ?
> > 
> > test/test/test_flow_classify.c:48:10: fatal error: too many arguments to
> >       function call, expected 6, have 7
> >                         NULL, NULL);
> >                               ^~~~
> > 
> > I guess it is expected that test and example does not compile after patch 1.
> > That's why I suggest to merge all 4 patches.
> 
> Ok, I will send revised patch with all merged into one.

I can merge them myself, it is fine.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2018-01-10 11:07               ` Thomas Monjalon
@ 2018-01-10 11:12                 ` Singh, Jasvinder
  0 siblings, 0 replies; 41+ messages in thread
From: Singh, Jasvinder @ 2018-01-10 11:12 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, Iremonger, Bernard, Kovacevic, Marko



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas@monjalon.net]
> Sent: Wednesday, January 10, 2018 11:07 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>
> Cc: dev@dpdk.org; Iremonger, Bernard <bernard.iremonger@intel.com>;
> Kovacevic, Marko <marko.kovacevic@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table
> id parameter from apis
> 
> 10/01/2018 11:59, Singh, Jasvinder:
> > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > > 10/01/2018 10:54, Singh, Jasvinder:
> > > > From: Thomas Monjalon [mailto:thomas@monjalon.net]
> > > > > 19/12/2017 15:29, Jasvinder Singh:
> > > > > > This patch removes table id parameter from all the flow
> > > > > > classify apis to reduce the complexity alongwith some code cleanup.
> > > > > >
> > > > > > The validate api is exposed as public api to allow user to
> > > > > > validate the flow before adding it to the classifier.
> > > > >
> > > > > This patch does not compile alone.
> > > > > Should we merge all patches together?
> > > >
> > > > No, It should compile alone. On my system it doesn't show any
> > > > error and
> > > compilation goes successfully. Could you send me error log, etc ?
> > >
> > > test/test/test_flow_classify.c:48:10: fatal error: too many arguments to
> > >       function call, expected 6, have 7
> > >                         NULL, NULL);
> > >                               ^~~~
> > >
> > > I guess it is expected that test and example does not compile after patch
> 1.
> > > That's why I suggest to merge all 4 patches.
> >
> > Ok, I will send revised patch with all merged into one.
> 
> I can merge them myself, it is fine.

Much Appreciated!  Thank you. 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis
  2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
                         ` (3 preceding siblings ...)
  2018-01-10  0:19       ` [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis Thomas Monjalon
@ 2018-01-11 18:20       ` Thomas Monjalon
  4 siblings, 0 replies; 41+ messages in thread
From: Thomas Monjalon @ 2018-01-11 18:20 UTC (permalink / raw)
  To: Jasvinder Singh; +Cc: dev, bernard.iremonger, marko.kovacevic

19/12/2017 15:29, Jasvinder Singh:
> This patch removes table id parameter from all the flow
> classify apis to reduce the complexity alongwith some code
> cleanup.
> 
> The validate api is exposed as public api to allow user
> to validate the flow before adding it to the classifier.
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> Acked-by: Bernard Iremonger<Bernard.iremonger@intel.com>

Patches merged into one and applied, thanks

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2018-01-11 18:21 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-23 11:32 [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
2017-11-23 11:32 ` [dpdk-dev] [PATCH 2/3] lib/librte_flow_classy: add run api for flow classification Jasvinder Singh
2017-12-04 16:46   ` Iremonger, Bernard
2017-12-05 11:01     ` Iremonger, Bernard
2017-12-06 12:41       ` Iremonger, Bernard
2017-12-11 15:52         ` Singh, Jasvinder
2017-11-23 11:32 ` [dpdk-dev] [PATCH 3/3] doc: update documentation for flow classify lib Jasvinder Singh
2017-12-06 12:04   ` Iremonger, Bernard
2017-12-11 14:54   ` Mcnamara, John
2017-12-11 15:53     ` Singh, Jasvinder
2017-12-04 16:45 ` [dpdk-dev] [PATCH 1/3] lib/librte_flow_classify: remove table id parameter from apis Iremonger, Bernard
2017-12-05 10:59   ` Iremonger, Bernard
2017-12-06 12:34     ` Iremonger, Bernard
2017-12-11 15:51       ` Singh, Jasvinder
2017-12-11 16:26 ` [dpdk-dev] [PATCH v2 1/4] " Jasvinder Singh
2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 2/4] test/test_flow_classify: update test to accomodate changes Jasvinder Singh
2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 3/4] examples/flow_classify: update sample application Jasvinder Singh
2017-12-14 14:42     ` Iremonger, Bernard
2017-12-11 16:26   ` [dpdk-dev] [PATCH v2 4/4] doc: update documentation for flow classify lib Jasvinder Singh
2017-12-14 14:49     ` Iremonger, Bernard
2017-12-15 10:39   ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Jasvinder Singh
2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
2017-12-19 12:06       ` Iremonger, Bernard
2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 3/4] examples/flow_classify: update sample application Jasvinder Singh
2017-12-19 12:09       ` Iremonger, Bernard
2017-12-15 10:39     ` [dpdk-dev] [PATCH v3 4/4] doc: update documentation for flow classify lib Jasvinder Singh
2017-12-18 11:04       ` Kovacevic, Marko
2017-12-18 13:40         ` Singh, Jasvinder
2017-12-19 12:13           ` Iremonger, Bernard
2017-12-19 12:03     ` [dpdk-dev] [PATCH v3 1/4] lib/librte_flow_classify: remove table id parameter from apis Iremonger, Bernard
2017-12-19 14:29     ` [dpdk-dev] [PATCH v4 " Jasvinder Singh
2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 2/4] test/test_flow_classify: update test to accommodate changes Jasvinder Singh
2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 3/4] examples/flow_classify: update sample application Jasvinder Singh
2017-12-19 14:29       ` [dpdk-dev] [PATCH v4 4/4] doc: update documentation for flow classify lib Jasvinder Singh
2018-01-10  0:19       ` [dpdk-dev] [PATCH v4 1/4] lib/librte_flow_classify: remove table id parameter from apis Thomas Monjalon
2018-01-10  9:54         ` Singh, Jasvinder
2018-01-10 10:52           ` Thomas Monjalon
2018-01-10 10:59             ` Singh, Jasvinder
2018-01-10 11:07               ` Thomas Monjalon
2018-01-10 11:12                 ` Singh, Jasvinder
2018-01-11 18:20       ` Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).