1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606  * Copyright(c) 2017 Intel Corporation
32bfe3f2eSlogwang  */
42bfe3f2eSlogwang 
54418919fSjohnjiang #include <rte_string_fns.h>
6d30ea906Sjfb8856606 #include <rte_compat.h>
72bfe3f2eSlogwang #include <rte_flow_classify.h>
82bfe3f2eSlogwang #include "rte_flow_classify_parse.h"
92bfe3f2eSlogwang #include <rte_flow_driver.h>
102bfe3f2eSlogwang #include <rte_table_acl.h>
112bfe3f2eSlogwang #include <stdbool.h>
122bfe3f2eSlogwang 
132bfe3f2eSlogwang static uint32_t unique_id = 1;
142bfe3f2eSlogwang 
15d30ea906Sjfb8856606 enum rte_flow_classify_table_type table_type
16d30ea906Sjfb8856606 	= RTE_FLOW_CLASSIFY_TABLE_TYPE_NONE;
172bfe3f2eSlogwang 
182bfe3f2eSlogwang struct rte_flow_classify_table_entry {
192bfe3f2eSlogwang 	/* meta-data for classify rule */
202bfe3f2eSlogwang 	uint32_t rule_id;
21d30ea906Sjfb8856606 
22d30ea906Sjfb8856606 	/* Flow action */
23d30ea906Sjfb8856606 	struct classify_action action;
242bfe3f2eSlogwang };
252bfe3f2eSlogwang 
26d30ea906Sjfb8856606 struct rte_cls_table {
272bfe3f2eSlogwang 	/* Input parameters */
282bfe3f2eSlogwang 	struct rte_table_ops ops;
292bfe3f2eSlogwang 	uint32_t entry_size;
302bfe3f2eSlogwang 	enum rte_flow_classify_table_type type;
312bfe3f2eSlogwang 
322bfe3f2eSlogwang 	/* Handle to the low-level table object */
332bfe3f2eSlogwang 	void *h_table;
342bfe3f2eSlogwang };
352bfe3f2eSlogwang 
362bfe3f2eSlogwang #define RTE_FLOW_CLASSIFIER_MAX_NAME_SZ 256
372bfe3f2eSlogwang 
382bfe3f2eSlogwang struct rte_flow_classifier {
392bfe3f2eSlogwang 	/* Input parameters */
402bfe3f2eSlogwang 	char name[RTE_FLOW_CLASSIFIER_MAX_NAME_SZ];
412bfe3f2eSlogwang 	int socket_id;
422bfe3f2eSlogwang 
43d30ea906Sjfb8856606 	/* Internal */
44d30ea906Sjfb8856606 	/* ntuple_filter */
45d30ea906Sjfb8856606 	struct rte_eth_ntuple_filter ntuple_filter;
46d30ea906Sjfb8856606 
47d30ea906Sjfb8856606 	/* classifier tables */
48d30ea906Sjfb8856606 	struct rte_cls_table tables[RTE_FLOW_CLASSIFY_TABLE_MAX];
49d30ea906Sjfb8856606 	uint32_t table_mask;
502bfe3f2eSlogwang 	uint32_t num_tables;
51d30ea906Sjfb8856606 
522bfe3f2eSlogwang 	uint16_t nb_pkts;
532bfe3f2eSlogwang 	struct rte_flow_classify_table_entry
542bfe3f2eSlogwang 		*entries[RTE_PORT_IN_BURST_SIZE_MAX];
552bfe3f2eSlogwang } __rte_cache_aligned;
562bfe3f2eSlogwang 
572bfe3f2eSlogwang enum {
582bfe3f2eSlogwang 	PROTO_FIELD_IPV4,
592bfe3f2eSlogwang 	SRC_FIELD_IPV4,
602bfe3f2eSlogwang 	DST_FIELD_IPV4,
612bfe3f2eSlogwang 	SRCP_FIELD_IPV4,
622bfe3f2eSlogwang 	DSTP_FIELD_IPV4,
632bfe3f2eSlogwang 	NUM_FIELDS_IPV4
642bfe3f2eSlogwang };
652bfe3f2eSlogwang 
662bfe3f2eSlogwang struct acl_keys {
672bfe3f2eSlogwang 	struct rte_table_acl_rule_add_params key_add; /* add key */
682bfe3f2eSlogwang 	struct rte_table_acl_rule_delete_params	key_del; /* delete key */
692bfe3f2eSlogwang };
702bfe3f2eSlogwang 
712bfe3f2eSlogwang struct classify_rules {
722bfe3f2eSlogwang 	enum rte_flow_classify_rule_type type;
732bfe3f2eSlogwang 	union {
742bfe3f2eSlogwang 		struct rte_flow_classify_ipv4_5tuple ipv4_5tuple;
752bfe3f2eSlogwang 	} u;
762bfe3f2eSlogwang };
772bfe3f2eSlogwang 
782bfe3f2eSlogwang struct rte_flow_classify_rule {
792bfe3f2eSlogwang 	uint32_t id; /* unique ID of classify rule */
80d30ea906Sjfb8856606 	enum rte_flow_classify_table_type tbl_type; /* rule table */
812bfe3f2eSlogwang 	struct classify_rules rules; /* union of rules */
822bfe3f2eSlogwang 	union {
832bfe3f2eSlogwang 		struct acl_keys key;
842bfe3f2eSlogwang 	} u;
852bfe3f2eSlogwang 	int key_found;   /* rule key found in table */
86d30ea906Sjfb8856606 	struct rte_flow_classify_table_entry entry;  /* rule meta data */
872bfe3f2eSlogwang 	void *entry_ptr; /* handle to the table entry for rule meta data */
882bfe3f2eSlogwang };
892bfe3f2eSlogwang 
904418919fSjohnjiang 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)91d30ea906Sjfb8856606 rte_flow_classify_validate(
92d30ea906Sjfb8856606 		   struct rte_flow_classifier *cls,
932bfe3f2eSlogwang 		   const struct rte_flow_attr *attr,
942bfe3f2eSlogwang 		   const struct rte_flow_item pattern[],
952bfe3f2eSlogwang 		   const struct rte_flow_action actions[],
962bfe3f2eSlogwang 		   struct rte_flow_error *error)
972bfe3f2eSlogwang {
982bfe3f2eSlogwang 	struct rte_flow_item *items;
992bfe3f2eSlogwang 	parse_filter_t parse_filter;
1002bfe3f2eSlogwang 	uint32_t item_num = 0;
1012bfe3f2eSlogwang 	uint32_t i = 0;
1022bfe3f2eSlogwang 	int ret;
1032bfe3f2eSlogwang 
104d30ea906Sjfb8856606 	if (error == NULL)
105d30ea906Sjfb8856606 		return -EINVAL;
106d30ea906Sjfb8856606 
107d30ea906Sjfb8856606 	if (cls == NULL) {
108d30ea906Sjfb8856606 		RTE_FLOW_CLASSIFY_LOG(ERR,
109d30ea906Sjfb8856606 			"%s: rte_flow_classifier parameter is NULL\n",
110d30ea906Sjfb8856606 			__func__);
111d30ea906Sjfb8856606 		return -EINVAL;
112d30ea906Sjfb8856606 	}
113d30ea906Sjfb8856606 
114d30ea906Sjfb8856606 	if (!attr) {
115d30ea906Sjfb8856606 		rte_flow_error_set(error, EINVAL,
116d30ea906Sjfb8856606 				   RTE_FLOW_ERROR_TYPE_ATTR,
117d30ea906Sjfb8856606 				   NULL, "NULL attribute.");
118d30ea906Sjfb8856606 		return -EINVAL;
119d30ea906Sjfb8856606 	}
120d30ea906Sjfb8856606 
121d30ea906Sjfb8856606 	if (!pattern) {
122d30ea906Sjfb8856606 		rte_flow_error_set(error,
123d30ea906Sjfb8856606 			EINVAL, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
124d30ea906Sjfb8856606 			NULL, "NULL pattern.");
125d30ea906Sjfb8856606 		return -EINVAL;
126d30ea906Sjfb8856606 	}
127d30ea906Sjfb8856606 
128d30ea906Sjfb8856606 	if (!actions) {
129d30ea906Sjfb8856606 		rte_flow_error_set(error, EINVAL,
130d30ea906Sjfb8856606 				   RTE_FLOW_ERROR_TYPE_ACTION_NUM,
131d30ea906Sjfb8856606 				   NULL, "NULL action.");
132d30ea906Sjfb8856606 		return -EINVAL;
133d30ea906Sjfb8856606 	}
134d30ea906Sjfb8856606 
135d30ea906Sjfb8856606 	memset(&cls->ntuple_filter, 0, sizeof(cls->ntuple_filter));
1362bfe3f2eSlogwang 
1372bfe3f2eSlogwang 	/* Get the non-void item number of pattern */
1382bfe3f2eSlogwang 	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
1392bfe3f2eSlogwang 		if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID)
1402bfe3f2eSlogwang 			item_num++;
1412bfe3f2eSlogwang 		i++;
1422bfe3f2eSlogwang 	}
1432bfe3f2eSlogwang 	item_num++;
1442bfe3f2eSlogwang 
1452bfe3f2eSlogwang 	items = malloc(item_num * sizeof(struct rte_flow_item));
1462bfe3f2eSlogwang 	if (!items) {
1472bfe3f2eSlogwang 		rte_flow_error_set(error, ENOMEM,
1482bfe3f2eSlogwang 				RTE_FLOW_ERROR_TYPE_ITEM_NUM,
1492bfe3f2eSlogwang 				NULL, "No memory for pattern items.");
1502bfe3f2eSlogwang 		return -ENOMEM;
1512bfe3f2eSlogwang 	}
1522bfe3f2eSlogwang 
1532bfe3f2eSlogwang 	memset(items, 0, item_num * sizeof(struct rte_flow_item));
1542bfe3f2eSlogwang 	classify_pattern_skip_void_item(items, pattern);
1552bfe3f2eSlogwang 
1562bfe3f2eSlogwang 	parse_filter = classify_find_parse_filter_func(items);
1572bfe3f2eSlogwang 	if (!parse_filter) {
1582bfe3f2eSlogwang 		rte_flow_error_set(error, EINVAL,
1592bfe3f2eSlogwang 				RTE_FLOW_ERROR_TYPE_ITEM,
1602bfe3f2eSlogwang 				pattern, "Unsupported pattern");
1612bfe3f2eSlogwang 		free(items);
1622bfe3f2eSlogwang 		return -EINVAL;
1632bfe3f2eSlogwang 	}
1642bfe3f2eSlogwang 
165d30ea906Sjfb8856606 	ret = parse_filter(attr, items, actions, &cls->ntuple_filter, error);
1662bfe3f2eSlogwang 	free(items);
1672bfe3f2eSlogwang 	return ret;
1682bfe3f2eSlogwang }
1692bfe3f2eSlogwang 
1702bfe3f2eSlogwang 
1712bfe3f2eSlogwang #define uint32_t_to_char(ip, a, b, c, d) do {\
1722bfe3f2eSlogwang 		*a = (unsigned char)(ip >> 24 & 0xff);\
1732bfe3f2eSlogwang 		*b = (unsigned char)(ip >> 16 & 0xff);\
1742bfe3f2eSlogwang 		*c = (unsigned char)(ip >> 8 & 0xff);\
1752bfe3f2eSlogwang 		*d = (unsigned char)(ip & 0xff);\
1762bfe3f2eSlogwang 	} while (0)
1772bfe3f2eSlogwang 
1782bfe3f2eSlogwang static inline void
print_acl_ipv4_key_add(struct rte_table_acl_rule_add_params * key)1792bfe3f2eSlogwang print_acl_ipv4_key_add(struct rte_table_acl_rule_add_params *key)
1802bfe3f2eSlogwang {
1812bfe3f2eSlogwang 	unsigned char a, b, c, d;
1822bfe3f2eSlogwang 
1832bfe3f2eSlogwang 	printf("%s:    0x%02hhx/0x%hhx ", __func__,
1842bfe3f2eSlogwang 		key->field_value[PROTO_FIELD_IPV4].value.u8,
1852bfe3f2eSlogwang 		key->field_value[PROTO_FIELD_IPV4].mask_range.u8);
1862bfe3f2eSlogwang 
1872bfe3f2eSlogwang 	uint32_t_to_char(key->field_value[SRC_FIELD_IPV4].value.u32,
1882bfe3f2eSlogwang 			&a, &b, &c, &d);
1892bfe3f2eSlogwang 	printf(" %hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
1902bfe3f2eSlogwang 			key->field_value[SRC_FIELD_IPV4].mask_range.u32);
1912bfe3f2eSlogwang 
1922bfe3f2eSlogwang 	uint32_t_to_char(key->field_value[DST_FIELD_IPV4].value.u32,
1932bfe3f2eSlogwang 			&a, &b, &c, &d);
1942bfe3f2eSlogwang 	printf("%hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
1952bfe3f2eSlogwang 			key->field_value[DST_FIELD_IPV4].mask_range.u32);
1962bfe3f2eSlogwang 
1972bfe3f2eSlogwang 	printf("%hu : 0x%x %hu : 0x%x",
1982bfe3f2eSlogwang 		key->field_value[SRCP_FIELD_IPV4].value.u16,
1992bfe3f2eSlogwang 		key->field_value[SRCP_FIELD_IPV4].mask_range.u16,
2002bfe3f2eSlogwang 		key->field_value[DSTP_FIELD_IPV4].value.u16,
2012bfe3f2eSlogwang 		key->field_value[DSTP_FIELD_IPV4].mask_range.u16);
2022bfe3f2eSlogwang 
2032bfe3f2eSlogwang 	printf(" priority: 0x%x\n", key->priority);
2042bfe3f2eSlogwang }
2052bfe3f2eSlogwang 
2062bfe3f2eSlogwang static inline void
print_acl_ipv4_key_delete(struct rte_table_acl_rule_delete_params * key)2072bfe3f2eSlogwang print_acl_ipv4_key_delete(struct rte_table_acl_rule_delete_params *key)
2082bfe3f2eSlogwang {
2092bfe3f2eSlogwang 	unsigned char a, b, c, d;
2102bfe3f2eSlogwang 
2112bfe3f2eSlogwang 	printf("%s: 0x%02hhx/0x%hhx ", __func__,
2122bfe3f2eSlogwang 		key->field_value[PROTO_FIELD_IPV4].value.u8,
2132bfe3f2eSlogwang 		key->field_value[PROTO_FIELD_IPV4].mask_range.u8);
2142bfe3f2eSlogwang 
2152bfe3f2eSlogwang 	uint32_t_to_char(key->field_value[SRC_FIELD_IPV4].value.u32,
2162bfe3f2eSlogwang 			&a, &b, &c, &d);
2172bfe3f2eSlogwang 	printf(" %hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
2182bfe3f2eSlogwang 			key->field_value[SRC_FIELD_IPV4].mask_range.u32);
2192bfe3f2eSlogwang 
2202bfe3f2eSlogwang 	uint32_t_to_char(key->field_value[DST_FIELD_IPV4].value.u32,
2212bfe3f2eSlogwang 			&a, &b, &c, &d);
2222bfe3f2eSlogwang 	printf("%hhu.%hhu.%hhu.%hhu/0x%x ", a, b, c, d,
2232bfe3f2eSlogwang 			key->field_value[DST_FIELD_IPV4].mask_range.u32);
2242bfe3f2eSlogwang 
2252bfe3f2eSlogwang 	printf("%hu : 0x%x %hu : 0x%x\n",
2262bfe3f2eSlogwang 		key->field_value[SRCP_FIELD_IPV4].value.u16,
2272bfe3f2eSlogwang 		key->field_value[SRCP_FIELD_IPV4].mask_range.u16,
2282bfe3f2eSlogwang 		key->field_value[DSTP_FIELD_IPV4].value.u16,
2292bfe3f2eSlogwang 		key->field_value[DSTP_FIELD_IPV4].mask_range.u16);
2302bfe3f2eSlogwang }
2312bfe3f2eSlogwang 
2322bfe3f2eSlogwang static int
rte_flow_classifier_check_params(struct rte_flow_classifier_params * params)2332bfe3f2eSlogwang rte_flow_classifier_check_params(struct rte_flow_classifier_params *params)
2342bfe3f2eSlogwang {
2352bfe3f2eSlogwang 	if (params == NULL) {
2362bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
2372bfe3f2eSlogwang 			"%s: Incorrect value for parameter params\n", __func__);
2382bfe3f2eSlogwang 		return -EINVAL;
2392bfe3f2eSlogwang 	}
2402bfe3f2eSlogwang 
2412bfe3f2eSlogwang 	/* name */
2422bfe3f2eSlogwang 	if (params->name == NULL) {
2432bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
2442bfe3f2eSlogwang 			"%s: Incorrect value for parameter name\n", __func__);
2452bfe3f2eSlogwang 		return -EINVAL;
2462bfe3f2eSlogwang 	}
2472bfe3f2eSlogwang 
2482bfe3f2eSlogwang 	/* socket */
249d30ea906Sjfb8856606 	if (params->socket_id < 0) {
2502bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
2512bfe3f2eSlogwang 			"%s: Incorrect value for parameter socket_id\n",
2522bfe3f2eSlogwang 			__func__);
2532bfe3f2eSlogwang 		return -EINVAL;
2542bfe3f2eSlogwang 	}
2552bfe3f2eSlogwang 
2562bfe3f2eSlogwang 	return 0;
2572bfe3f2eSlogwang }
2582bfe3f2eSlogwang 
2594418919fSjohnjiang struct rte_flow_classifier *
rte_flow_classifier_create(struct rte_flow_classifier_params * params)2602bfe3f2eSlogwang rte_flow_classifier_create(struct rte_flow_classifier_params *params)
2612bfe3f2eSlogwang {
2622bfe3f2eSlogwang 	struct rte_flow_classifier *cls;
2632bfe3f2eSlogwang 	int ret;
2642bfe3f2eSlogwang 
2652bfe3f2eSlogwang 	/* Check input parameters */
2662bfe3f2eSlogwang 	ret = rte_flow_classifier_check_params(params);
2672bfe3f2eSlogwang 	if (ret != 0) {
2682bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
2692bfe3f2eSlogwang 			"%s: flow classifier params check failed (%d)\n",
2702bfe3f2eSlogwang 			__func__, ret);
2712bfe3f2eSlogwang 		return NULL;
2722bfe3f2eSlogwang 	}
2732bfe3f2eSlogwang 
2742bfe3f2eSlogwang 	/* Allocate memory for the flow classifier */
2752bfe3f2eSlogwang 	cls = rte_zmalloc_socket("FLOW_CLASSIFIER",
2762bfe3f2eSlogwang 			sizeof(struct rte_flow_classifier),
2772bfe3f2eSlogwang 			RTE_CACHE_LINE_SIZE, params->socket_id);
2782bfe3f2eSlogwang 
2792bfe3f2eSlogwang 	if (cls == NULL) {
2802bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
2812bfe3f2eSlogwang 			"%s: flow classifier memory allocation failed\n",
2822bfe3f2eSlogwang 			__func__);
2832bfe3f2eSlogwang 		return NULL;
2842bfe3f2eSlogwang 	}
2852bfe3f2eSlogwang 
2862bfe3f2eSlogwang 	/* Save input parameters */
2874418919fSjohnjiang 	strlcpy(cls->name, params->name, RTE_FLOW_CLASSIFIER_MAX_NAME_SZ);
2885af785ecSfengbojiang(姜凤波) 
289d30ea906Sjfb8856606 	cls->socket_id = params->socket_id;
2902bfe3f2eSlogwang 
2912bfe3f2eSlogwang 	return cls;
2922bfe3f2eSlogwang }
2932bfe3f2eSlogwang 
2942bfe3f2eSlogwang static void
rte_flow_classify_table_free(struct rte_cls_table * table)295d30ea906Sjfb8856606 rte_flow_classify_table_free(struct rte_cls_table *table)
2962bfe3f2eSlogwang {
2972bfe3f2eSlogwang 	if (table->ops.f_free != NULL)
2982bfe3f2eSlogwang 		table->ops.f_free(table->h_table);
2992bfe3f2eSlogwang }
3002bfe3f2eSlogwang 
3014418919fSjohnjiang int
rte_flow_classifier_free(struct rte_flow_classifier * cls)3022bfe3f2eSlogwang rte_flow_classifier_free(struct rte_flow_classifier *cls)
3032bfe3f2eSlogwang {
3042bfe3f2eSlogwang 	uint32_t i;
3052bfe3f2eSlogwang 
3062bfe3f2eSlogwang 	/* Check input parameters */
3072bfe3f2eSlogwang 	if (cls == NULL) {
3082bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
3092bfe3f2eSlogwang 			"%s: rte_flow_classifier parameter is NULL\n",
3102bfe3f2eSlogwang 			__func__);
3112bfe3f2eSlogwang 		return -EINVAL;
3122bfe3f2eSlogwang 	}
3132bfe3f2eSlogwang 
3142bfe3f2eSlogwang 	/* Free tables */
3152bfe3f2eSlogwang 	for (i = 0; i < cls->num_tables; i++) {
316d30ea906Sjfb8856606 		struct rte_cls_table *table = &cls->tables[i];
3172bfe3f2eSlogwang 
3182bfe3f2eSlogwang 		rte_flow_classify_table_free(table);
3192bfe3f2eSlogwang 	}
3202bfe3f2eSlogwang 
3212bfe3f2eSlogwang 	/* Free flow classifier memory */
3222bfe3f2eSlogwang 	rte_free(cls);
3232bfe3f2eSlogwang 
3242bfe3f2eSlogwang 	return 0;
3252bfe3f2eSlogwang }
3262bfe3f2eSlogwang 
3272bfe3f2eSlogwang static int
rte_table_check_params(struct rte_flow_classifier * cls,struct rte_flow_classify_table_params * params)3282bfe3f2eSlogwang rte_table_check_params(struct rte_flow_classifier *cls,
329d30ea906Sjfb8856606 		struct rte_flow_classify_table_params *params)
3302bfe3f2eSlogwang {
3312bfe3f2eSlogwang 	if (cls == NULL) {
3322bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
3332bfe3f2eSlogwang 			"%s: flow classifier parameter is NULL\n",
3342bfe3f2eSlogwang 			__func__);
3352bfe3f2eSlogwang 		return -EINVAL;
3362bfe3f2eSlogwang 	}
3372bfe3f2eSlogwang 	if (params == NULL) {
3382bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: params parameter is NULL\n",
3392bfe3f2eSlogwang 			__func__);
3402bfe3f2eSlogwang 		return -EINVAL;
3412bfe3f2eSlogwang 	}
3422bfe3f2eSlogwang 
3432bfe3f2eSlogwang 	/* ops */
3442bfe3f2eSlogwang 	if (params->ops == NULL) {
3452bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: params->ops is NULL\n",
3462bfe3f2eSlogwang 			__func__);
3472bfe3f2eSlogwang 		return -EINVAL;
3482bfe3f2eSlogwang 	}
3492bfe3f2eSlogwang 
3502bfe3f2eSlogwang 	if (params->ops->f_create == NULL) {
3512bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
3522bfe3f2eSlogwang 			"%s: f_create function pointer is NULL\n", __func__);
3532bfe3f2eSlogwang 		return -EINVAL;
3542bfe3f2eSlogwang 	}
3552bfe3f2eSlogwang 
3562bfe3f2eSlogwang 	if (params->ops->f_lookup == NULL) {
3572bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
3582bfe3f2eSlogwang 			"%s: f_lookup function pointer is NULL\n", __func__);
3592bfe3f2eSlogwang 		return -EINVAL;
3602bfe3f2eSlogwang 	}
3612bfe3f2eSlogwang 
3622bfe3f2eSlogwang 	/* De we have room for one more table? */
3632bfe3f2eSlogwang 	if (cls->num_tables == RTE_FLOW_CLASSIFY_TABLE_MAX) {
3642bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR,
3652bfe3f2eSlogwang 			"%s: Incorrect value for num_tables parameter\n",
3662bfe3f2eSlogwang 			__func__);
3672bfe3f2eSlogwang 		return -EINVAL;
3682bfe3f2eSlogwang 	}
3692bfe3f2eSlogwang 
3702bfe3f2eSlogwang 	return 0;
3712bfe3f2eSlogwang }
3722bfe3f2eSlogwang 
3734418919fSjohnjiang int
rte_flow_classify_table_create(struct rte_flow_classifier * cls,struct rte_flow_classify_table_params * params)3742bfe3f2eSlogwang rte_flow_classify_table_create(struct rte_flow_classifier *cls,
375d30ea906Sjfb8856606 	struct rte_flow_classify_table_params *params)
3762bfe3f2eSlogwang {
377d30ea906Sjfb8856606 	struct rte_cls_table *table;
3782bfe3f2eSlogwang 	void *h_table;
379d30ea906Sjfb8856606 	uint32_t entry_size;
3802bfe3f2eSlogwang 	int ret;
3812bfe3f2eSlogwang 
3822bfe3f2eSlogwang 	/* Check input arguments */
383d30ea906Sjfb8856606 	ret = rte_table_check_params(cls, params);
3842bfe3f2eSlogwang 	if (ret != 0)
3852bfe3f2eSlogwang 		return ret;
3862bfe3f2eSlogwang 
3872bfe3f2eSlogwang 	/* calculate table entry size */
3882bfe3f2eSlogwang 	entry_size = sizeof(struct rte_flow_classify_table_entry);
3892bfe3f2eSlogwang 
3902bfe3f2eSlogwang 	/* Create the table */
3912bfe3f2eSlogwang 	h_table = params->ops->f_create(params->arg_create, cls->socket_id,
3922bfe3f2eSlogwang 		entry_size);
3932bfe3f2eSlogwang 	if (h_table == NULL) {
3942bfe3f2eSlogwang 		RTE_FLOW_CLASSIFY_LOG(ERR, "%s: Table creation failed\n",
3952bfe3f2eSlogwang 			__func__);
3962bfe3f2eSlogwang 		return -EINVAL;
3972bfe3f2eSlogwang 	}
3982bfe3f2eSlogwang 
3992bfe3f2eSlogwang 	/* Commit current table to the classifier */
400d30ea906Sjfb8856606 	table = &cls->tables[cls->num_tables];
401d30ea906Sjfb8856606 	table->type = params->type;
4022bfe3f2eSlogwang 	cls->num_tables++;
4032bfe3f2eSlogwang 
4042bfe3f2eSlogwang 	/* Save input parameters */
4052bfe3f2eSlogwang 	memcpy(&table->ops, params->ops, sizeof(struct rte_table_ops));
4062bfe3f2eSlogwang 
4072bfe3f2eSlogwang 	/* Initialize table internal data structure */
4082bfe3f2eSlogwang 	table->entry_size = entry_size;
4092bfe3f2eSlogwang 	table->h_table = h_table;
4102bfe3f2eSlogwang 
4112bfe3f2eSlogwang 	return 0;
4122bfe3f2eSlogwang }
4132bfe3f2eSlogwang 
4142bfe3f2eSlogwang static struct rte_flow_classify_rule *
allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier * cls)415d30ea906Sjfb8856606 allocate_acl_ipv4_5tuple_rule(struct rte_flow_classifier *cls)
4162bfe3f2eSlogwang {
4172bfe3f2eSlogwang 	struct rte_flow_classify_rule *rule;
4182bfe3f2eSlogwang 
4192bfe3f2eSlogwang 	rule = malloc(sizeof(struct rte_flow_classify_rule));
4202bfe3f2eSlogwang 	if (!rule)
4212bfe3f2eSlogwang 		return rule;
4222bfe3f2eSlogwang 
4232bfe3f2eSlogwang 	memset(rule, 0, sizeof(struct rte_flow_classify_rule));
4242bfe3f2eSlogwang 	rule->id = unique_id++;
4252bfe3f2eSlogwang 	rule->rules.type = RTE_FLOW_CLASSIFY_RULE_TYPE_IPV4_5TUPLE;
4262bfe3f2eSlogwang 
4272bfe3f2eSlogwang 	/* key add values */
428d30ea906Sjfb8856606 	rule->u.key.key_add.priority = cls->ntuple_filter.priority;
4292bfe3f2eSlogwang 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].mask_range.u8 =
430d30ea906Sjfb8856606 			cls->ntuple_filter.proto_mask;
4312bfe3f2eSlogwang 	rule->u.key.key_add.field_value[PROTO_FIELD_IPV4].value.u8 =
432d30ea906Sjfb8856606 			cls->ntuple_filter.proto;
433d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.proto = cls->ntuple_filter.proto;
434d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.proto_mask = cls->ntuple_filter.proto_mask;
4352bfe3f2eSlogwang 
4362bfe3f2eSlogwang 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].mask_range.u32 =
437d30ea906Sjfb8856606 			cls->ntuple_filter.src_ip_mask;
4382bfe3f2eSlogwang 	rule->u.key.key_add.field_value[SRC_FIELD_IPV4].value.u32 =
439d30ea906Sjfb8856606 			cls->ntuple_filter.src_ip;
440d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.src_ip_mask = cls->ntuple_filter.src_ip_mask;
441d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.src_ip = cls->ntuple_filter.src_ip;
4422bfe3f2eSlogwang 
4432bfe3f2eSlogwang 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].mask_range.u32 =
444d30ea906Sjfb8856606 			cls->ntuple_filter.dst_ip_mask;
4452bfe3f2eSlogwang 	rule->u.key.key_add.field_value[DST_FIELD_IPV4].value.u32 =
446d30ea906Sjfb8856606 			cls->ntuple_filter.dst_ip;
447d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.dst_ip_mask = cls->ntuple_filter.dst_ip_mask;
448d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.dst_ip = cls->ntuple_filter.dst_ip;
4492bfe3f2eSlogwang 
4502bfe3f2eSlogwang 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].mask_range.u16 =
451d30ea906Sjfb8856606 			cls->ntuple_filter.src_port_mask;
4522bfe3f2eSlogwang 	rule->u.key.key_add.field_value[SRCP_FIELD_IPV4].value.u16 =
453d30ea906Sjfb8856606 			cls->ntuple_filter.src_port;
454d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.src_port_mask =
455d30ea906Sjfb8856606 			cls->ntuple_filter.src_port_mask;
456d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.src_port = cls->ntuple_filter.src_port;
4572bfe3f2eSlogwang 
4582bfe3f2eSlogwang 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].mask_range.u16 =
459d30ea906Sjfb8856606 			cls->ntuple_filter.dst_port_mask;
4602bfe3f2eSlogwang 	rule->u.key.key_add.field_value[DSTP_FIELD_IPV4].value.u16 =
461d30ea906Sjfb8856606 			cls->ntuple_filter.dst_port;
462d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.dst_port_mask =
463d30ea906Sjfb8856606 			cls->ntuple_filter.dst_port_mask;
464d30ea906Sjfb8856606 	rule->rules.u.ipv4_5tuple.dst_port = cls->ntuple_filter.dst_port;
4652bfe3f2eSlogwang 
466*2d9fd380Sjfb8856606 	if (rte_log_can_log(librte_flow_classify_logtype, RTE_LOG_DEBUG))
4672bfe3f2eSlogwang 		print_acl_ipv4_key_add(&rule->u.key.key_add);
4682bfe3f2eSlogwang 
4692bfe3f2eSlogwang 	/* key delete values */
4702bfe3f2eSlogwang 	memcpy(&rule->u.key.key_del.field_value[PROTO_FIELD_IPV4],
4712bfe3f2eSlogwang 	       &rule->u.key.key_add.field_value[PROTO_FIELD_IPV4],
4722bfe3f2eSlogwang 	       NUM_FIELDS_IPV4 * sizeof(struct rte_acl_field));
4732bfe3f2eSlogwang 
474*2d9fd380Sjfb8856606 	if (rte_log_can_log(librte_flow_classify_logtype, RTE_LOG_DEBUG))
4752bfe3f2eSlogwang 		print_acl_ipv4_key_delete(&rule->u.key.key_del);
4762bfe3f2eSlogwang 
4772bfe3f2eSlogwang 	return rule;
4782bfe3f2eSlogwang }
4792bfe3f2eSlogwang 
4804418919fSjohnjiang struct rte_flow_classify_rule *
rte_flow_classify_table_entry_add(struct rte_flow_classifier * cls,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)4812bfe3f2eSlogwang rte_flow_classify_table_entry_add(struct rte_flow_classifier *cls,
4822bfe3f2eSlogwang 		const struct rte_flow_attr *attr,
4832bfe3f2eSlogwang 		const struct rte_flow_item pattern[],
4842bfe3f2eSlogwang 		const struct rte_flow_action actions[],
485d30ea906Sjfb8856606 		int *key_found,
4862bfe3f2eSlogwang 		struct rte_flow_error *error)
4872bfe3f2eSlogwang {
4882bfe3f2eSlogwang 	struct rte_flow_classify_rule *rule;
4892bfe3f2eSlogwang 	struct rte_flow_classify_table_entry *table_entry;
490d30ea906Sjfb8856606 	struct classify_action *action;
491d30ea906Sjfb8856606 	uint32_t i;
4922bfe3f2eSlogwang 	int ret;
4932bfe3f2eSlogwang 
4942bfe3f2eSlogwang 	if (!error)
4952bfe3f2eSlogwang 		return NULL;
4962bfe3f2eSlogwang 
4972bfe3f2eSlogwang 	if (key_found == NULL) {
4982bfe3f2eSlogwang 		rte_flow_error_set(error, EINVAL,
4992bfe3f2eSlogwang 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
5002bfe3f2eSlogwang 				NULL, "NULL key_found.");
5012bfe3f2eSlogwang 		return NULL;
5022bfe3f2eSlogwang 	}
5032bfe3f2eSlogwang 
5042bfe3f2eSlogwang 	/* parse attr, pattern and actions */
505d30ea906Sjfb8856606 	ret = rte_flow_classify_validate(cls, attr, pattern, actions, error);
5062bfe3f2eSlogwang 	if (ret < 0)
5072bfe3f2eSlogwang 		return NULL;
5082bfe3f2eSlogwang 
509d30ea906Sjfb8856606 	switch (table_type) {
510d30ea906Sjfb8856606 	case RTE_FLOW_CLASSIFY_TABLE_ACL_IP4_5TUPLE:
511d30ea906Sjfb8856606 		rule = allocate_acl_ipv4_5tuple_rule(cls);
5122bfe3f2eSlogwang 		if (!rule)
5132bfe3f2eSlogwang 			return NULL;
514d30ea906Sjfb8856606 		rule->tbl_type = table_type;
515d30ea906Sjfb8856606 		cls->table_mask |= table_type;
5162bfe3f2eSlogwang 		break;
5172bfe3f2eSlogwang 	default:
5182bfe3f2eSlogwang 		return NULL;
5192bfe3f2eSlogwang 	}
5202bfe3f2eSlogwang 
521d30ea906Sjfb8856606 	action = classify_get_flow_action();
522d30ea906Sjfb8856606 	table_entry = &rule->entry;
523d30ea906Sjfb8856606 	table_entry->rule_id = rule->id;
524d30ea906Sjfb8856606 	table_entry->action.action_mask = action->action_mask;
525d30ea906Sjfb8856606 
526d30ea906Sjfb8856606 	/* Copy actions */
527d30ea906Sjfb8856606 	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
528d30ea906Sjfb8856606 		memcpy(&table_entry->action.act.counter, &action->act.counter,
529d30ea906Sjfb8856606 				sizeof(table_entry->action.act.counter));
530d30ea906Sjfb8856606 	}
531d30ea906Sjfb8856606 	if (action->action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_MARK)) {
532d30ea906Sjfb8856606 		memcpy(&table_entry->action.act.mark, &action->act.mark,
533d30ea906Sjfb8856606 				sizeof(table_entry->action.act.mark));
5345af785ecSfengbojiang(姜凤波) 	}
5355af785ecSfengbojiang(姜凤波) 
536d30ea906Sjfb8856606 	for (i = 0; i < cls->num_tables; i++) {
537d30ea906Sjfb8856606 		struct rte_cls_table *table = &cls->tables[i];
53828440c50Sjfb8856606 
539d30ea906Sjfb8856606 		if (table->type == table_type) {
540d30ea906Sjfb8856606 			if (table->ops.f_add != NULL) {
541d30ea906Sjfb8856606 				ret = table->ops.f_add(
542d30ea906Sjfb8856606 					table->h_table,
5432bfe3f2eSlogwang 					&rule->u.key.key_add,
544d30ea906Sjfb8856606 					&rule->entry,
5452bfe3f2eSlogwang 					&rule->key_found,
5462bfe3f2eSlogwang 					&rule->entry_ptr);
5472bfe3f2eSlogwang 				if (ret) {
5482bfe3f2eSlogwang 					free(rule);
5492bfe3f2eSlogwang 					return NULL;
5502bfe3f2eSlogwang 				}
551d30ea906Sjfb8856606 
5522bfe3f2eSlogwang 			*key_found = rule->key_found;
5532bfe3f2eSlogwang 			}
554d30ea906Sjfb8856606 
5552bfe3f2eSlogwang 			return rule;
5562bfe3f2eSlogwang 		}
557d30ea906Sjfb8856606 	}
558d30ea906Sjfb8856606 	free(rule);
559d30ea906Sjfb8856606 	return NULL;
560d30ea906Sjfb8856606 }
5612bfe3f2eSlogwang 
5624418919fSjohnjiang int
rte_flow_classify_table_entry_delete(struct rte_flow_classifier * cls,struct rte_flow_classify_rule * rule)5632bfe3f2eSlogwang rte_flow_classify_table_entry_delete(struct rte_flow_classifier *cls,
5642bfe3f2eSlogwang 		struct rte_flow_classify_rule *rule)
5652bfe3f2eSlogwang {
566d30ea906Sjfb8856606 	uint32_t i;
5672bfe3f2eSlogwang 	int ret = -EINVAL;
5682bfe3f2eSlogwang 
569d30ea906Sjfb8856606 	if (!cls || !rule)
5702bfe3f2eSlogwang 		return ret;
571d30ea906Sjfb8856606 	enum rte_flow_classify_table_type tbl_type = rule->tbl_type;
5722bfe3f2eSlogwang 
573d30ea906Sjfb8856606 	for (i = 0; i < cls->num_tables; i++) {
574d30ea906Sjfb8856606 		struct rte_cls_table *table = &cls->tables[i];
575d30ea906Sjfb8856606 
576d30ea906Sjfb8856606 		if (table->type == tbl_type) {
577d30ea906Sjfb8856606 			if (table->ops.f_delete != NULL) {
578d30ea906Sjfb8856606 				ret = table->ops.f_delete(table->h_table,
5792bfe3f2eSlogwang 						&rule->u.key.key_del,
5802bfe3f2eSlogwang 						&rule->key_found,
5812bfe3f2eSlogwang 						&rule->entry);
5822bfe3f2eSlogwang 
5832bfe3f2eSlogwang 				return ret;
5842bfe3f2eSlogwang 			}
585d30ea906Sjfb8856606 		}
586d30ea906Sjfb8856606 	}
587d30ea906Sjfb8856606 	free(rule);
588d30ea906Sjfb8856606 	return ret;
589d30ea906Sjfb8856606 }
5902bfe3f2eSlogwang 
5912bfe3f2eSlogwang static int
flow_classifier_lookup(struct rte_flow_classifier * cls,struct rte_cls_table * table,struct rte_mbuf ** pkts,const uint16_t nb_pkts)5922bfe3f2eSlogwang flow_classifier_lookup(struct rte_flow_classifier *cls,
593d30ea906Sjfb8856606 		struct rte_cls_table *table,
5942bfe3f2eSlogwang 		struct rte_mbuf **pkts,
5952bfe3f2eSlogwang 		const uint16_t nb_pkts)
5962bfe3f2eSlogwang {
5972bfe3f2eSlogwang 	int ret = -EINVAL;
5982bfe3f2eSlogwang 	uint64_t pkts_mask;
5992bfe3f2eSlogwang 	uint64_t lookup_hit_mask;
6002bfe3f2eSlogwang 
6012bfe3f2eSlogwang 	pkts_mask = RTE_LEN2MASK(nb_pkts, uint64_t);
602d30ea906Sjfb8856606 	ret = table->ops.f_lookup(table->h_table,
6032bfe3f2eSlogwang 		pkts, pkts_mask, &lookup_hit_mask,
6042bfe3f2eSlogwang 		(void **)cls->entries);
6052bfe3f2eSlogwang 
6062bfe3f2eSlogwang 	if (!ret && lookup_hit_mask)
6072bfe3f2eSlogwang 		cls->nb_pkts = nb_pkts;
6082bfe3f2eSlogwang 	else
6092bfe3f2eSlogwang 		cls->nb_pkts = 0;
6102bfe3f2eSlogwang 
6112bfe3f2eSlogwang 	return ret;
6122bfe3f2eSlogwang }
6132bfe3f2eSlogwang 
6142bfe3f2eSlogwang static int
action_apply(struct rte_flow_classifier * cls,struct rte_flow_classify_rule * rule,struct rte_flow_classify_stats * stats)6152bfe3f2eSlogwang action_apply(struct rte_flow_classifier *cls,
6162bfe3f2eSlogwang 		struct rte_flow_classify_rule *rule,
6172bfe3f2eSlogwang 		struct rte_flow_classify_stats *stats)
6182bfe3f2eSlogwang {
6192bfe3f2eSlogwang 	struct rte_flow_classify_ipv4_5tuple_stats *ntuple_stats;
620d30ea906Sjfb8856606 	struct rte_flow_classify_table_entry *entry = &rule->entry;
6212bfe3f2eSlogwang 	uint64_t count = 0;
622d30ea906Sjfb8856606 	uint32_t action_mask = entry->action.action_mask;
623d30ea906Sjfb8856606 	int i, ret = -EINVAL;
6242bfe3f2eSlogwang 
625d30ea906Sjfb8856606 	if (action_mask & (1LLU << RTE_FLOW_ACTION_TYPE_COUNT)) {
6262bfe3f2eSlogwang 		for (i = 0; i < cls->nb_pkts; i++) {
6272bfe3f2eSlogwang 			if (rule->id == cls->entries[i]->rule_id)
6282bfe3f2eSlogwang 				count++;
6292bfe3f2eSlogwang 		}
6302bfe3f2eSlogwang 		if (count) {
6312bfe3f2eSlogwang 			ret = 0;
632d30ea906Sjfb8856606 			ntuple_stats = stats->stats;
6332bfe3f2eSlogwang 			ntuple_stats->counter1 = count;
6342bfe3f2eSlogwang 			ntuple_stats->ipv4_5tuple = rule->rules.u.ipv4_5tuple;
6352bfe3f2eSlogwang 		}
6362bfe3f2eSlogwang 	}
6372bfe3f2eSlogwang 	return ret;
6382bfe3f2eSlogwang }
6392bfe3f2eSlogwang 
6404418919fSjohnjiang int
rte_flow_classifier_query(struct rte_flow_classifier * cls,struct rte_mbuf ** pkts,const uint16_t nb_pkts,struct rte_flow_classify_rule * rule,struct rte_flow_classify_stats * stats)6412bfe3f2eSlogwang rte_flow_classifier_query(struct rte_flow_classifier *cls,
6422bfe3f2eSlogwang 		struct rte_mbuf **pkts,
6432bfe3f2eSlogwang 		const uint16_t nb_pkts,
6442bfe3f2eSlogwang 		struct rte_flow_classify_rule *rule,
6452bfe3f2eSlogwang 		struct rte_flow_classify_stats *stats)
6462bfe3f2eSlogwang {
647d30ea906Sjfb8856606 	enum rte_flow_classify_table_type tbl_type;
648d30ea906Sjfb8856606 	uint32_t i;
6492bfe3f2eSlogwang 	int ret = -EINVAL;
6502bfe3f2eSlogwang 
651d30ea906Sjfb8856606 	if (!cls || !rule || !stats || !pkts  || nb_pkts == 0)
6522bfe3f2eSlogwang 		return ret;
6532bfe3f2eSlogwang 
654d30ea906Sjfb8856606 	tbl_type = rule->tbl_type;
655d30ea906Sjfb8856606 	for (i = 0; i < cls->num_tables; i++) {
656d30ea906Sjfb8856606 		struct rte_cls_table *table = &cls->tables[i];
657d30ea906Sjfb8856606 
658d30ea906Sjfb8856606 			if (table->type == tbl_type) {
659d30ea906Sjfb8856606 				ret = flow_classifier_lookup(cls, table,
660d30ea906Sjfb8856606 						pkts, nb_pkts);
661d30ea906Sjfb8856606 				if (!ret) {
6622bfe3f2eSlogwang 					ret = action_apply(cls, rule, stats);
6632bfe3f2eSlogwang 					return ret;
6642bfe3f2eSlogwang 				}
665d30ea906Sjfb8856606 			}
666d30ea906Sjfb8856606 	}
667d30ea906Sjfb8856606 	return ret;
668d30ea906Sjfb8856606 }
6692bfe3f2eSlogwang 
670*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(librte_flow_classify_logtype, lib.flow_classify, INFO);
671