xref: /dpdk/drivers/net/nfp/nfp_net_flow.c (revision b6de43530dfa30cbf6b70857e3835099701063d4)
18153bc6fSChaoyong He /* SPDX-License-Identifier: BSD-3-Clause
28153bc6fSChaoyong He  * Copyright (c) 2023 Corigine, Inc.
38153bc6fSChaoyong He  * All rights reserved.
48153bc6fSChaoyong He  */
58153bc6fSChaoyong He 
68153bc6fSChaoyong He #include "nfp_net_flow.h"
78153bc6fSChaoyong He 
88153bc6fSChaoyong He #include <rte_flow_driver.h>
98153bc6fSChaoyong He #include <rte_hash.h>
108153bc6fSChaoyong He #include <rte_jhash.h>
118153bc6fSChaoyong He #include <rte_malloc.h>
128153bc6fSChaoyong He 
138153bc6fSChaoyong He #include "nfp_logs.h"
140b9079d2SChaoyong He #include "nfp_net_cmsg.h"
158153bc6fSChaoyong He 
16c91c6512SChaoyong He /* Static initializer for a list of subsequent item types */
17c91c6512SChaoyong He #define NEXT_ITEM(...) \
18c91c6512SChaoyong He 	((const enum rte_flow_item_type []){ \
19c91c6512SChaoyong He 		__VA_ARGS__, RTE_FLOW_ITEM_TYPE_END, \
20c91c6512SChaoyong He 	})
21c91c6512SChaoyong He 
22c91c6512SChaoyong He /* Process structure associated with a flow item */
23c91c6512SChaoyong He struct nfp_net_flow_item_proc {
24c91c6512SChaoyong He 	/* Bit-mask for fields supported by this PMD. */
25c91c6512SChaoyong He 	const void *mask_support;
26c91c6512SChaoyong He 	/* Bit-mask to use when @p item->mask is not provided. */
27c91c6512SChaoyong He 	const void *mask_default;
28c91c6512SChaoyong He 	/* Size in bytes for @p mask_support and @p mask_default. */
29c91c6512SChaoyong He 	const uint32_t mask_sz;
30c91c6512SChaoyong He 	/* Merge a pattern item into a flow rule handle. */
31c91c6512SChaoyong He 	int (*merge)(struct rte_flow *nfp_flow,
32c91c6512SChaoyong He 			const struct rte_flow_item *item,
33c91c6512SChaoyong He 			const struct nfp_net_flow_item_proc *proc);
34c91c6512SChaoyong He 	/* List of possible subsequent items. */
35c91c6512SChaoyong He 	const enum rte_flow_item_type *const next_item;
36c91c6512SChaoyong He };
37c91c6512SChaoyong He 
380b9079d2SChaoyong He static int
398153bc6fSChaoyong He nfp_net_flow_table_add(struct nfp_net_priv *priv,
408153bc6fSChaoyong He 		struct rte_flow *nfp_flow)
418153bc6fSChaoyong He {
428153bc6fSChaoyong He 	int ret;
438153bc6fSChaoyong He 
448153bc6fSChaoyong He 	ret = rte_hash_add_key_data(priv->flow_table, &nfp_flow->hash_key, nfp_flow);
458153bc6fSChaoyong He 	if (ret != 0) {
468153bc6fSChaoyong He 		PMD_DRV_LOG(ERR, "Add to flow table failed.");
478153bc6fSChaoyong He 		return ret;
488153bc6fSChaoyong He 	}
498153bc6fSChaoyong He 
508153bc6fSChaoyong He 	return 0;
518153bc6fSChaoyong He }
528153bc6fSChaoyong He 
530b9079d2SChaoyong He static int
548153bc6fSChaoyong He nfp_net_flow_table_delete(struct nfp_net_priv *priv,
558153bc6fSChaoyong He 		struct rte_flow *nfp_flow)
568153bc6fSChaoyong He {
578153bc6fSChaoyong He 	int ret;
588153bc6fSChaoyong He 
598153bc6fSChaoyong He 	ret = rte_hash_del_key(priv->flow_table, &nfp_flow->hash_key);
608153bc6fSChaoyong He 	if (ret < 0) {
618153bc6fSChaoyong He 		PMD_DRV_LOG(ERR, "Delete from flow table failed.");
628153bc6fSChaoyong He 		return ret;
638153bc6fSChaoyong He 	}
648153bc6fSChaoyong He 
658153bc6fSChaoyong He 	return 0;
668153bc6fSChaoyong He }
678153bc6fSChaoyong He 
680b9079d2SChaoyong He static struct rte_flow *
698153bc6fSChaoyong He nfp_net_flow_table_search(struct nfp_net_priv *priv,
708153bc6fSChaoyong He 		struct rte_flow *nfp_flow)
718153bc6fSChaoyong He {
728153bc6fSChaoyong He 	int index;
738153bc6fSChaoyong He 	struct rte_flow *flow_find;
748153bc6fSChaoyong He 
758153bc6fSChaoyong He 	index = rte_hash_lookup_data(priv->flow_table, &nfp_flow->hash_key,
768153bc6fSChaoyong He 			(void **)&flow_find);
778153bc6fSChaoyong He 	if (index < 0) {
788153bc6fSChaoyong He 		PMD_DRV_LOG(DEBUG, "Data NOT found in the flow table.");
798153bc6fSChaoyong He 		return NULL;
808153bc6fSChaoyong He 	}
818153bc6fSChaoyong He 
828153bc6fSChaoyong He 	return flow_find;
838153bc6fSChaoyong He }
848153bc6fSChaoyong He 
850b9079d2SChaoyong He static int
860b9079d2SChaoyong He nfp_net_flow_position_acquire(struct nfp_net_priv *priv,
870b9079d2SChaoyong He 		uint32_t priority,
880b9079d2SChaoyong He 		struct rte_flow *nfp_flow)
890b9079d2SChaoyong He {
900b9079d2SChaoyong He 	uint32_t i;
9166df893fSChaoyong He 	uint32_t limit;
9266df893fSChaoyong He 
9366df893fSChaoyong He 	limit = priv->flow_limit;
940b9079d2SChaoyong He 
950b9079d2SChaoyong He 	if (priority != 0) {
9666df893fSChaoyong He 		i = limit - priority - 1;
970b9079d2SChaoyong He 
980b9079d2SChaoyong He 		if (priv->flow_position[i]) {
990b9079d2SChaoyong He 			PMD_DRV_LOG(ERR, "There is already a flow rule in this place.");
1000b9079d2SChaoyong He 			return -EAGAIN;
1010b9079d2SChaoyong He 		}
1020b9079d2SChaoyong He 
1030b9079d2SChaoyong He 		priv->flow_position[i] = true;
1040b9079d2SChaoyong He 		nfp_flow->position = priority;
1050b9079d2SChaoyong He 		return 0;
1060b9079d2SChaoyong He 	}
1070b9079d2SChaoyong He 
10866df893fSChaoyong He 	for (i = 0; i < limit; i++) {
1090b9079d2SChaoyong He 		if (!priv->flow_position[i]) {
1100b9079d2SChaoyong He 			priv->flow_position[i] = true;
1110b9079d2SChaoyong He 			break;
1120b9079d2SChaoyong He 		}
1130b9079d2SChaoyong He 	}
1140b9079d2SChaoyong He 
11566df893fSChaoyong He 	if (i == limit) {
1160b9079d2SChaoyong He 		PMD_DRV_LOG(ERR, "The limited flow number is reach.");
1170b9079d2SChaoyong He 		return -ERANGE;
1180b9079d2SChaoyong He 	}
1190b9079d2SChaoyong He 
12066df893fSChaoyong He 	nfp_flow->position = limit - i - 1;
1210b9079d2SChaoyong He 
1220b9079d2SChaoyong He 	return 0;
1230b9079d2SChaoyong He }
1240b9079d2SChaoyong He 
1250b9079d2SChaoyong He static void
1260b9079d2SChaoyong He nfp_net_flow_position_free(struct nfp_net_priv *priv,
1270b9079d2SChaoyong He 		struct rte_flow *nfp_flow)
1280b9079d2SChaoyong He {
129fd38c08fSLong Wu 	uint32_t index;
130fd38c08fSLong Wu 
131fd38c08fSLong Wu 	index = NFP_NET_FLOW_LIMIT - 1 - nfp_flow->position;
132fd38c08fSLong Wu 
133fd38c08fSLong Wu 	priv->flow_position[index] = false;
1340b9079d2SChaoyong He }
1350b9079d2SChaoyong He 
1360b9079d2SChaoyong He static struct rte_flow *
1370b9079d2SChaoyong He nfp_net_flow_alloc(struct nfp_net_priv *priv,
1380b9079d2SChaoyong He 		uint32_t priority,
1390b9079d2SChaoyong He 		uint32_t match_len,
1408153bc6fSChaoyong He 		uint32_t action_len,
1418153bc6fSChaoyong He 		uint32_t port_id)
1428153bc6fSChaoyong He {
1430b9079d2SChaoyong He 	int ret;
1448153bc6fSChaoyong He 	char *data;
1458153bc6fSChaoyong He 	struct rte_flow *nfp_flow;
1468153bc6fSChaoyong He 	struct nfp_net_flow_payload *payload;
1478153bc6fSChaoyong He 
1488153bc6fSChaoyong He 	nfp_flow = rte_zmalloc("nfp_flow", sizeof(struct rte_flow), 0);
1498153bc6fSChaoyong He 	if (nfp_flow == NULL)
1508153bc6fSChaoyong He 		return NULL;
1518153bc6fSChaoyong He 
1528153bc6fSChaoyong He 	data = rte_zmalloc("nfp_flow_payload", match_len + action_len, 0);
1538153bc6fSChaoyong He 	if (data == NULL)
1548153bc6fSChaoyong He 		goto free_flow;
1558153bc6fSChaoyong He 
1560b9079d2SChaoyong He 	ret = nfp_net_flow_position_acquire(priv, priority, nfp_flow);
1570b9079d2SChaoyong He 	if (ret != 0)
1580b9079d2SChaoyong He 		goto free_payload;
1590b9079d2SChaoyong He 
1608153bc6fSChaoyong He 	nfp_flow->port_id      = port_id;
1618153bc6fSChaoyong He 	payload                = &nfp_flow->payload;
1628153bc6fSChaoyong He 	payload->match_len     = match_len;
1638153bc6fSChaoyong He 	payload->action_len    = action_len;
1648153bc6fSChaoyong He 	payload->match_data    = data;
1658153bc6fSChaoyong He 	payload->action_data   = data + match_len;
1668153bc6fSChaoyong He 
1678153bc6fSChaoyong He 	return nfp_flow;
1688153bc6fSChaoyong He 
1690b9079d2SChaoyong He free_payload:
1700b9079d2SChaoyong He 	rte_free(data);
1718153bc6fSChaoyong He free_flow:
1728153bc6fSChaoyong He 	rte_free(nfp_flow);
1738153bc6fSChaoyong He 
1748153bc6fSChaoyong He 	return NULL;
1758153bc6fSChaoyong He }
1768153bc6fSChaoyong He 
1770b9079d2SChaoyong He static void
1780b9079d2SChaoyong He nfp_net_flow_free(struct nfp_net_priv *priv,
1790b9079d2SChaoyong He 		struct rte_flow *nfp_flow)
1808153bc6fSChaoyong He {
1810b9079d2SChaoyong He 	nfp_net_flow_position_free(priv, nfp_flow);
1828153bc6fSChaoyong He 	rte_free(nfp_flow->payload.match_data);
1838153bc6fSChaoyong He 	rte_free(nfp_flow);
1848153bc6fSChaoyong He }
1858153bc6fSChaoyong He 
1860b9079d2SChaoyong He static int
1870b9079d2SChaoyong He nfp_net_flow_calculate_items(const struct rte_flow_item items[],
188849a9ffbSLong Wu 		uint32_t *match_len,
189849a9ffbSLong Wu 		uint32_t *item_type)
1900b9079d2SChaoyong He {
191ec2822a0SChaoyong He 	int ret = -EINVAL;
1920b9079d2SChaoyong He 	const struct rte_flow_item *item;
1930b9079d2SChaoyong He 
1940b9079d2SChaoyong He 	for (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {
1950b9079d2SChaoyong He 		switch (item->type) {
196c91c6512SChaoyong He 		case RTE_FLOW_ITEM_TYPE_ETH:
197*b6de4353SZerun Fu 			PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_ETH detected.");
198c91c6512SChaoyong He 			*match_len = sizeof(struct nfp_net_cmsg_match_eth);
199849a9ffbSLong Wu 			*item_type = RTE_FLOW_ITEM_TYPE_ETH;
200ec2822a0SChaoyong He 			ret = 0;
201ec2822a0SChaoyong He 			break;
20242eabda0SChaoyong He 		case RTE_FLOW_ITEM_TYPE_IPV4:
203*b6de4353SZerun Fu 			PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_IPV4 detected.");
20442eabda0SChaoyong He 			*match_len = sizeof(struct nfp_net_cmsg_match_v4);
205849a9ffbSLong Wu 			*item_type = RTE_FLOW_ITEM_TYPE_IPV4;
20642eabda0SChaoyong He 			return 0;
2079f27cb88SChaoyong He 		case RTE_FLOW_ITEM_TYPE_IPV6:
208*b6de4353SZerun Fu 			PMD_DRV_LOG(DEBUG, "RTE_FLOW_ITEM_TYPE_IPV6 detected.");
2099f27cb88SChaoyong He 			*match_len = sizeof(struct nfp_net_cmsg_match_v6);
210849a9ffbSLong Wu 			*item_type = RTE_FLOW_ITEM_TYPE_IPV6;
2119f27cb88SChaoyong He 			return 0;
2120b9079d2SChaoyong He 		default:
213*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Can not calculate match length.");
2140b9079d2SChaoyong He 			*match_len = 0;
2150b9079d2SChaoyong He 			return -ENOTSUP;
2160b9079d2SChaoyong He 		}
2170b9079d2SChaoyong He 	}
2180b9079d2SChaoyong He 
219ec2822a0SChaoyong He 	return ret;
2200b9079d2SChaoyong He }
2210b9079d2SChaoyong He 
222c91c6512SChaoyong He static int
223c91c6512SChaoyong He nfp_net_flow_merge_eth(__rte_unused struct rte_flow *nfp_flow,
224c91c6512SChaoyong He 		const struct rte_flow_item *item,
225c91c6512SChaoyong He 		__rte_unused const struct nfp_net_flow_item_proc *proc)
226c91c6512SChaoyong He {
227c91c6512SChaoyong He 	struct nfp_net_cmsg_match_eth *eth;
228c91c6512SChaoyong He 	const struct rte_flow_item_eth *spec;
229c91c6512SChaoyong He 
230c91c6512SChaoyong He 	spec = item->spec;
231c91c6512SChaoyong He 	if (spec == NULL) {
232c91c6512SChaoyong He 		PMD_DRV_LOG(ERR, "NFP flow merge eth: no item->spec!");
233c91c6512SChaoyong He 		return -EINVAL;
234c91c6512SChaoyong He 	}
235c91c6512SChaoyong He 
236c91c6512SChaoyong He 	nfp_flow->payload.cmsg_type = NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE;
237c91c6512SChaoyong He 
238c91c6512SChaoyong He 	eth = (struct nfp_net_cmsg_match_eth *)nfp_flow->payload.match_data;
239c91c6512SChaoyong He 	eth->ether_type = rte_be_to_cpu_16(spec->type);
240c91c6512SChaoyong He 
241c91c6512SChaoyong He 	return 0;
242c91c6512SChaoyong He }
243c91c6512SChaoyong He 
24442eabda0SChaoyong He static int
24542eabda0SChaoyong He nfp_net_flow_merge_ipv4(struct rte_flow *nfp_flow,
24642eabda0SChaoyong He 		const struct rte_flow_item *item,
24742eabda0SChaoyong He 		const struct nfp_net_flow_item_proc *proc)
24842eabda0SChaoyong He {
24942eabda0SChaoyong He 	struct nfp_net_cmsg_match_v4 *ipv4;
25042eabda0SChaoyong He 	const struct rte_flow_item_ipv4 *mask;
25142eabda0SChaoyong He 	const struct rte_flow_item_ipv4 *spec;
25242eabda0SChaoyong He 
253328ac087SLong Wu 	nfp_flow->payload.cmsg_type = NFP_NET_CFG_MBOX_CMD_FS_ADD_V4;
254328ac087SLong Wu 
25542eabda0SChaoyong He 	spec = item->spec;
25642eabda0SChaoyong He 	if (spec == NULL) {
25742eabda0SChaoyong He 		PMD_DRV_LOG(DEBUG, "NFP flow merge ipv4: no item->spec!");
25842eabda0SChaoyong He 		return 0;
25942eabda0SChaoyong He 	}
26042eabda0SChaoyong He 
26142eabda0SChaoyong He 	mask = (item->mask != NULL) ? item->mask : proc->mask_default;
26242eabda0SChaoyong He 
26342eabda0SChaoyong He 	ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
26442eabda0SChaoyong He 
26542eabda0SChaoyong He 	ipv4->l4_protocol_mask = mask->hdr.next_proto_id;
26642eabda0SChaoyong He 	ipv4->src_ipv4_mask    = rte_be_to_cpu_32(mask->hdr.src_addr);
26742eabda0SChaoyong He 	ipv4->dst_ipv4_mask    = rte_be_to_cpu_32(mask->hdr.dst_addr);
26842eabda0SChaoyong He 
26942eabda0SChaoyong He 	ipv4->l4_protocol  = spec->hdr.next_proto_id;
27042eabda0SChaoyong He 	ipv4->src_ipv4     = rte_be_to_cpu_32(spec->hdr.src_addr);
27142eabda0SChaoyong He 	ipv4->dst_ipv4     = rte_be_to_cpu_32(spec->hdr.dst_addr);
27242eabda0SChaoyong He 
27342eabda0SChaoyong He 	return 0;
27442eabda0SChaoyong He }
27542eabda0SChaoyong He 
2769f27cb88SChaoyong He static int
2779f27cb88SChaoyong He nfp_net_flow_merge_ipv6(struct rte_flow *nfp_flow,
2789f27cb88SChaoyong He 		const struct rte_flow_item *item,
2799f27cb88SChaoyong He 		const struct nfp_net_flow_item_proc *proc)
2809f27cb88SChaoyong He {
2819f27cb88SChaoyong He 	uint32_t i;
2829f27cb88SChaoyong He 	struct nfp_net_cmsg_match_v6 *ipv6;
2839f27cb88SChaoyong He 	const struct rte_flow_item_ipv6 *mask;
2849f27cb88SChaoyong He 	const struct rte_flow_item_ipv6 *spec;
2859f27cb88SChaoyong He 
286328ac087SLong Wu 	nfp_flow->payload.cmsg_type = NFP_NET_CFG_MBOX_CMD_FS_ADD_V6;
287328ac087SLong Wu 
2889f27cb88SChaoyong He 	spec = item->spec;
2899f27cb88SChaoyong He 	if (spec == NULL) {
2909f27cb88SChaoyong He 		PMD_DRV_LOG(DEBUG, "NFP flow merge ipv6: no item->spec!");
2919f27cb88SChaoyong He 		return 0;
2929f27cb88SChaoyong He 	}
2939f27cb88SChaoyong He 
2949f27cb88SChaoyong He 	mask = (item->mask != NULL) ? item->mask : proc->mask_default;
2959f27cb88SChaoyong He 
2969f27cb88SChaoyong He 	ipv6 = (struct nfp_net_cmsg_match_v6 *)nfp_flow->payload.match_data;
2979f27cb88SChaoyong He 
2989f27cb88SChaoyong He 	ipv6->l4_protocol_mask = mask->hdr.proto;
2999f27cb88SChaoyong He 	for (i = 0; i < sizeof(ipv6->src_ipv6); i += 4) {
30089b5642dSRobin Jarry 		ipv6->src_ipv6_mask[i] = mask->hdr.src_addr.a[i + 3];
30189b5642dSRobin Jarry 		ipv6->src_ipv6_mask[i + 1] = mask->hdr.src_addr.a[i + 2];
30289b5642dSRobin Jarry 		ipv6->src_ipv6_mask[i + 2] = mask->hdr.src_addr.a[i + 1];
30389b5642dSRobin Jarry 		ipv6->src_ipv6_mask[i + 3] = mask->hdr.src_addr.a[i];
3049f27cb88SChaoyong He 
30589b5642dSRobin Jarry 		ipv6->dst_ipv6_mask[i] = mask->hdr.dst_addr.a[i + 3];
30689b5642dSRobin Jarry 		ipv6->dst_ipv6_mask[i + 1] = mask->hdr.dst_addr.a[i + 2];
30789b5642dSRobin Jarry 		ipv6->dst_ipv6_mask[i + 2] = mask->hdr.dst_addr.a[i + 1];
30889b5642dSRobin Jarry 		ipv6->dst_ipv6_mask[i + 3] = mask->hdr.dst_addr.a[i];
3099f27cb88SChaoyong He 	}
3109f27cb88SChaoyong He 
3119f27cb88SChaoyong He 	ipv6->l4_protocol = spec->hdr.proto;
3129f27cb88SChaoyong He 	for (i = 0; i < sizeof(ipv6->src_ipv6); i += 4) {
31389b5642dSRobin Jarry 		ipv6->src_ipv6[i] = spec->hdr.src_addr.a[i + 3];
31489b5642dSRobin Jarry 		ipv6->src_ipv6[i + 1] = spec->hdr.src_addr.a[i + 2];
31589b5642dSRobin Jarry 		ipv6->src_ipv6[i + 2] = spec->hdr.src_addr.a[i + 1];
31689b5642dSRobin Jarry 		ipv6->src_ipv6[i + 3] = spec->hdr.src_addr.a[i];
3179f27cb88SChaoyong He 
31889b5642dSRobin Jarry 		ipv6->dst_ipv6[i] = spec->hdr.dst_addr.a[i + 3];
31989b5642dSRobin Jarry 		ipv6->dst_ipv6[i + 1] = spec->hdr.dst_addr.a[i + 2];
32089b5642dSRobin Jarry 		ipv6->dst_ipv6[i + 2] = spec->hdr.dst_addr.a[i + 1];
32189b5642dSRobin Jarry 		ipv6->dst_ipv6[i + 3] = spec->hdr.dst_addr.a[i];
3229f27cb88SChaoyong He 	}
3239f27cb88SChaoyong He 
3249f27cb88SChaoyong He 	return 0;
3259f27cb88SChaoyong He }
3269f27cb88SChaoyong He 
32794438b09SChaoyong He static int
32894438b09SChaoyong He nfp_flow_merge_l4(struct rte_flow *nfp_flow,
32994438b09SChaoyong He 		const struct rte_flow_item *item,
33094438b09SChaoyong He 		const struct nfp_net_flow_item_proc *proc)
33194438b09SChaoyong He {
33294438b09SChaoyong He 	const struct rte_flow_item_tcp *mask;
33394438b09SChaoyong He 	const struct rte_flow_item_tcp *spec;
33494438b09SChaoyong He 	struct nfp_net_cmsg_match_v4 *ipv4 = NULL;
33594438b09SChaoyong He 	struct nfp_net_cmsg_match_v6 *ipv6 = NULL;
33694438b09SChaoyong He 
33794438b09SChaoyong He 	spec = item->spec;
33894438b09SChaoyong He 	if (spec == NULL) {
33994438b09SChaoyong He 		PMD_DRV_LOG(ERR, "NFP flow merge tcp: no item->spec!");
34094438b09SChaoyong He 		return -EINVAL;
34194438b09SChaoyong He 	}
34294438b09SChaoyong He 
34394438b09SChaoyong He 	mask = (item->mask != NULL) ? item->mask : proc->mask_default;
34494438b09SChaoyong He 
34594438b09SChaoyong He 	switch (nfp_flow->payload.cmsg_type) {
34694438b09SChaoyong He 	case NFP_NET_CFG_MBOX_CMD_FS_ADD_V4:
34794438b09SChaoyong He 		ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
34894438b09SChaoyong He 		break;
34994438b09SChaoyong He 	case NFP_NET_CFG_MBOX_CMD_FS_ADD_V6:
35094438b09SChaoyong He 		ipv6 = (struct nfp_net_cmsg_match_v6 *)nfp_flow->payload.match_data;
35194438b09SChaoyong He 		break;
35294438b09SChaoyong He 	default:
35394438b09SChaoyong He 		PMD_DRV_LOG(ERR, "L3 layer neither IPv4 nor IPv6.");
35494438b09SChaoyong He 		return -EINVAL;
35594438b09SChaoyong He 	}
35694438b09SChaoyong He 
35794438b09SChaoyong He 	if (ipv4 != NULL) {
35894438b09SChaoyong He 		ipv4->src_port_mask = rte_be_to_cpu_16(mask->hdr.src_port);
35994438b09SChaoyong He 		ipv4->dst_port_mask = rte_be_to_cpu_16(mask->hdr.dst_port);
36094438b09SChaoyong He 
36194438b09SChaoyong He 		ipv4->src_port = rte_be_to_cpu_16(spec->hdr.src_port);
36294438b09SChaoyong He 		ipv4->dst_port = rte_be_to_cpu_16(spec->hdr.dst_port);
3630b92659dSChaoyong He 	} else if (ipv6 != NULL) {
36494438b09SChaoyong He 		ipv6->src_port_mask = rte_be_to_cpu_16(mask->hdr.src_port);
36594438b09SChaoyong He 		ipv6->dst_port_mask = rte_be_to_cpu_16(mask->hdr.dst_port);
36694438b09SChaoyong He 
36794438b09SChaoyong He 		ipv6->src_port = rte_be_to_cpu_16(spec->hdr.src_port);
36894438b09SChaoyong He 		ipv6->dst_port = rte_be_to_cpu_16(spec->hdr.dst_port);
3690b92659dSChaoyong He 	} else {
3700b92659dSChaoyong He 		PMD_DRV_LOG(ERR, "No valid L3 layer pointer.");
3710b92659dSChaoyong He 		return -EINVAL;
37294438b09SChaoyong He 	}
37394438b09SChaoyong He 
37494438b09SChaoyong He 	return 0;
37594438b09SChaoyong He }
37694438b09SChaoyong He 
377c91c6512SChaoyong He /* Graph of supported items and associated process function */
378c91c6512SChaoyong He static const struct nfp_net_flow_item_proc nfp_net_flow_item_proc_list[] = {
379c91c6512SChaoyong He 	[RTE_FLOW_ITEM_TYPE_END] = {
38042eabda0SChaoyong He 		.next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_ETH,
3819f27cb88SChaoyong He 				RTE_FLOW_ITEM_TYPE_IPV4,
3829f27cb88SChaoyong He 				RTE_FLOW_ITEM_TYPE_IPV6),
383c91c6512SChaoyong He 	},
384c91c6512SChaoyong He 	[RTE_FLOW_ITEM_TYPE_ETH] = {
385c91c6512SChaoyong He 		.merge = nfp_net_flow_merge_eth,
386c91c6512SChaoyong He 	},
38742eabda0SChaoyong He 	[RTE_FLOW_ITEM_TYPE_IPV4] = {
38894438b09SChaoyong He 		.next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_TCP,
38994438b09SChaoyong He 				RTE_FLOW_ITEM_TYPE_UDP,
39094438b09SChaoyong He 				RTE_FLOW_ITEM_TYPE_SCTP),
39142eabda0SChaoyong He 		.mask_support = &(const struct rte_flow_item_ipv4){
39242eabda0SChaoyong He 			.hdr = {
39342eabda0SChaoyong He 				.next_proto_id = 0xff,
39442eabda0SChaoyong He 				.src_addr      = RTE_BE32(0xffffffff),
39542eabda0SChaoyong He 				.dst_addr      = RTE_BE32(0xffffffff),
39642eabda0SChaoyong He 			},
39742eabda0SChaoyong He 		},
39842eabda0SChaoyong He 		.mask_default = &rte_flow_item_ipv4_mask,
39942eabda0SChaoyong He 		.mask_sz = sizeof(struct rte_flow_item_ipv4),
40042eabda0SChaoyong He 		.merge = nfp_net_flow_merge_ipv4,
40142eabda0SChaoyong He 	},
4029f27cb88SChaoyong He 	[RTE_FLOW_ITEM_TYPE_IPV6] = {
40394438b09SChaoyong He 		.next_item = NEXT_ITEM(RTE_FLOW_ITEM_TYPE_TCP,
40494438b09SChaoyong He 				RTE_FLOW_ITEM_TYPE_UDP,
40594438b09SChaoyong He 				RTE_FLOW_ITEM_TYPE_SCTP),
4069f27cb88SChaoyong He 		.mask_support = &(const struct rte_flow_item_ipv6){
4079f27cb88SChaoyong He 			.hdr = {
4089f27cb88SChaoyong He 				.proto    = 0xff,
40989b5642dSRobin Jarry 				.src_addr = RTE_IPV6_MASK_FULL,
41089b5642dSRobin Jarry 				.dst_addr = RTE_IPV6_MASK_FULL,
4119f27cb88SChaoyong He 			},
4129f27cb88SChaoyong He 		},
4139f27cb88SChaoyong He 		.mask_default = &rte_flow_item_ipv6_mask,
4149f27cb88SChaoyong He 		.mask_sz = sizeof(struct rte_flow_item_ipv6),
4159f27cb88SChaoyong He 		.merge = nfp_net_flow_merge_ipv6,
4169f27cb88SChaoyong He 	},
41794438b09SChaoyong He 	[RTE_FLOW_ITEM_TYPE_TCP] = {
41894438b09SChaoyong He 		.mask_support = &(const struct rte_flow_item_tcp){
41994438b09SChaoyong He 			.hdr = {
42094438b09SChaoyong He 				.src_port  = RTE_BE16(0xffff),
42194438b09SChaoyong He 				.dst_port  = RTE_BE16(0xffff),
42294438b09SChaoyong He 			},
42394438b09SChaoyong He 		},
42494438b09SChaoyong He 		.mask_default = &rte_flow_item_tcp_mask,
42594438b09SChaoyong He 		.mask_sz = sizeof(struct rte_flow_item_tcp),
42694438b09SChaoyong He 		.merge = nfp_flow_merge_l4,
42794438b09SChaoyong He 	},
42894438b09SChaoyong He 	[RTE_FLOW_ITEM_TYPE_UDP] = {
42994438b09SChaoyong He 		.mask_support = &(const struct rte_flow_item_udp){
43094438b09SChaoyong He 			.hdr = {
43194438b09SChaoyong He 				.src_port = RTE_BE16(0xffff),
43294438b09SChaoyong He 				.dst_port = RTE_BE16(0xffff),
43394438b09SChaoyong He 			},
43494438b09SChaoyong He 		},
43594438b09SChaoyong He 		.mask_default = &rte_flow_item_udp_mask,
43694438b09SChaoyong He 		.mask_sz = sizeof(struct rte_flow_item_udp),
43794438b09SChaoyong He 		.merge = nfp_flow_merge_l4,
43894438b09SChaoyong He 	},
43994438b09SChaoyong He 	[RTE_FLOW_ITEM_TYPE_SCTP] = {
44094438b09SChaoyong He 		.mask_support = &(const struct rte_flow_item_sctp){
44194438b09SChaoyong He 			.hdr = {
44294438b09SChaoyong He 				.src_port  = RTE_BE16(0xffff),
44394438b09SChaoyong He 				.dst_port  = RTE_BE16(0xffff),
44494438b09SChaoyong He 			},
44594438b09SChaoyong He 		},
44694438b09SChaoyong He 		.mask_default = &rte_flow_item_sctp_mask,
44794438b09SChaoyong He 		.mask_sz = sizeof(struct rte_flow_item_sctp),
44894438b09SChaoyong He 		.merge = nfp_flow_merge_l4,
44994438b09SChaoyong He 	},
450c91c6512SChaoyong He };
451c91c6512SChaoyong He 
452c91c6512SChaoyong He static int
453c91c6512SChaoyong He nfp_net_flow_item_check(const struct rte_flow_item *item,
454c91c6512SChaoyong He 		const struct nfp_net_flow_item_proc *proc)
455c91c6512SChaoyong He {
456c91c6512SChaoyong He 	uint32_t i;
457c91c6512SChaoyong He 	int ret = 0;
458c91c6512SChaoyong He 	const uint8_t *mask;
459c91c6512SChaoyong He 
460c91c6512SChaoyong He 	/* item->last and item->mask cannot exist without item->spec. */
461c91c6512SChaoyong He 	if (item->spec == NULL) {
462c91c6512SChaoyong He 		if (item->mask || item->last) {
463f6272c7aSZerun Fu 			PMD_DRV_LOG(ERR, "The 'mask' or 'last' field provided"
464c91c6512SChaoyong He 					" without a corresponding 'spec'.");
465c91c6512SChaoyong He 			return -EINVAL;
466c91c6512SChaoyong He 		}
467c91c6512SChaoyong He 
468c91c6512SChaoyong He 		/* No spec, no mask, no problem. */
469c91c6512SChaoyong He 		return 0;
470c91c6512SChaoyong He 	}
471c91c6512SChaoyong He 
472c91c6512SChaoyong He 	mask = (item->mask != NULL) ? item->mask : proc->mask_default;
473c91c6512SChaoyong He 
474c91c6512SChaoyong He 	/*
475c91c6512SChaoyong He 	 * Single-pass check to make sure that:
476c91c6512SChaoyong He 	 * - Mask is supported, no bits are set outside proc->mask_support.
477c91c6512SChaoyong He 	 * - Both item->spec and item->last are included in mask.
478c91c6512SChaoyong He 	 */
479c91c6512SChaoyong He 	for (i = 0; i != proc->mask_sz; ++i) {
480c91c6512SChaoyong He 		if (mask[i] == 0)
481c91c6512SChaoyong He 			continue;
482c91c6512SChaoyong He 
483c91c6512SChaoyong He 		if ((mask[i] | ((const uint8_t *)proc->mask_support)[i]) !=
484c91c6512SChaoyong He 				((const uint8_t *)proc->mask_support)[i]) {
485c91c6512SChaoyong He 			PMD_DRV_LOG(ERR, "Unsupported field found in 'mask'.");
486c91c6512SChaoyong He 			ret = -EINVAL;
487c91c6512SChaoyong He 			break;
488c91c6512SChaoyong He 		}
489c91c6512SChaoyong He 
490c91c6512SChaoyong He 		if (item->last != NULL &&
491c91c6512SChaoyong He 				(((const uint8_t *)item->spec)[i] & mask[i]) !=
492c91c6512SChaoyong He 				(((const uint8_t *)item->last)[i] & mask[i])) {
493c91c6512SChaoyong He 			PMD_DRV_LOG(ERR, "Range between 'spec' and 'last'"
494c91c6512SChaoyong He 					" is larger than 'mask'.");
495c91c6512SChaoyong He 			ret = -ERANGE;
496c91c6512SChaoyong He 			break;
497c91c6512SChaoyong He 		}
498c91c6512SChaoyong He 	}
499c91c6512SChaoyong He 
500c91c6512SChaoyong He 	return ret;
501c91c6512SChaoyong He }
502c91c6512SChaoyong He 
503c91c6512SChaoyong He static int
504c91c6512SChaoyong He nfp_net_flow_compile_items(const struct rte_flow_item items[],
505c91c6512SChaoyong He 		struct rte_flow *nfp_flow)
506c91c6512SChaoyong He {
507c91c6512SChaoyong He 	uint32_t i;
508c91c6512SChaoyong He 	int ret = 0;
509c91c6512SChaoyong He 	const struct rte_flow_item *item;
510c91c6512SChaoyong He 	const struct nfp_net_flow_item_proc *proc_list;
511c91c6512SChaoyong He 
512c91c6512SChaoyong He 	proc_list = nfp_net_flow_item_proc_list;
513c91c6512SChaoyong He 
514c91c6512SChaoyong He 	for (item = items; item->type != RTE_FLOW_ITEM_TYPE_END; ++item) {
515c91c6512SChaoyong He 		const struct nfp_net_flow_item_proc *proc = NULL;
516c91c6512SChaoyong He 
517c91c6512SChaoyong He 		for (i = 0; (proc_list->next_item != NULL) &&
518c91c6512SChaoyong He 				(proc_list->next_item[i] != RTE_FLOW_ITEM_TYPE_END); ++i) {
519c91c6512SChaoyong He 			if (proc_list->next_item[i] == item->type) {
520c91c6512SChaoyong He 				proc = &nfp_net_flow_item_proc_list[item->type];
521c91c6512SChaoyong He 				break;
522c91c6512SChaoyong He 			}
523c91c6512SChaoyong He 		}
524c91c6512SChaoyong He 
525c91c6512SChaoyong He 		if (proc == NULL) {
526*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "No next item provided for %d.", item->type);
527c91c6512SChaoyong He 			ret = -ENOTSUP;
528c91c6512SChaoyong He 			break;
529c91c6512SChaoyong He 		}
530c91c6512SChaoyong He 
531c91c6512SChaoyong He 		/* Perform basic sanity checks */
532c91c6512SChaoyong He 		ret = nfp_net_flow_item_check(item, proc);
533c91c6512SChaoyong He 		if (ret != 0) {
534*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "NFP flow item %d check failed.", item->type);
535c91c6512SChaoyong He 			ret = -EINVAL;
536c91c6512SChaoyong He 			break;
537c91c6512SChaoyong He 		}
538c91c6512SChaoyong He 
539c91c6512SChaoyong He 		if (proc->merge == NULL) {
540*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "NFP flow item %d no proc function.", item->type);
541c91c6512SChaoyong He 			ret = -ENOTSUP;
542c91c6512SChaoyong He 			break;
543c91c6512SChaoyong He 		}
544c91c6512SChaoyong He 
545c91c6512SChaoyong He 		ret = proc->merge(nfp_flow, item, proc);
546c91c6512SChaoyong He 		if (ret != 0) {
547*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "NFP flow item %d exact merge failed.", item->type);
548c91c6512SChaoyong He 			break;
549c91c6512SChaoyong He 		}
550c91c6512SChaoyong He 
551c91c6512SChaoyong He 		proc_list = proc;
552c91c6512SChaoyong He 	}
553c91c6512SChaoyong He 
554c91c6512SChaoyong He 	return ret;
555c91c6512SChaoyong He }
556c91c6512SChaoyong He 
5570b9079d2SChaoyong He static void
558bc94750aSChaoyong He nfp_net_flow_action_drop(struct rte_flow *nfp_flow)
559bc94750aSChaoyong He {
560bc94750aSChaoyong He 	struct nfp_net_cmsg_action *action_data;
561bc94750aSChaoyong He 
562bc94750aSChaoyong He 	action_data = (struct nfp_net_cmsg_action *)nfp_flow->payload.action_data;
563bc94750aSChaoyong He 
564bc94750aSChaoyong He 	action_data->action = NFP_NET_CMSG_ACTION_DROP;
565bc94750aSChaoyong He }
566bc94750aSChaoyong He 
5679c5cfc10SChaoyong He static void
5689c5cfc10SChaoyong He nfp_net_flow_action_mark(struct rte_flow *nfp_flow,
5699c5cfc10SChaoyong He 		const struct rte_flow_action *action)
5709c5cfc10SChaoyong He {
5719c5cfc10SChaoyong He 	struct nfp_net_cmsg_action *action_data;
5729c5cfc10SChaoyong He 	const struct rte_flow_action_mark *mark;
5739c5cfc10SChaoyong He 
5749c5cfc10SChaoyong He 	action_data = (struct nfp_net_cmsg_action *)nfp_flow->payload.action_data;
5759c5cfc10SChaoyong He 	mark = action->conf;
5769c5cfc10SChaoyong He 
5779c5cfc10SChaoyong He 	action_data->action |= NFP_NET_CMSG_ACTION_MARK;
5789c5cfc10SChaoyong He 	action_data->mark_id = mark->id;
5799c5cfc10SChaoyong He }
5809c5cfc10SChaoyong He 
5810eb77bbdSLong Wu static int
5820eb77bbdSLong Wu nfp_net_flow_action_queue(struct rte_eth_dev *dev,
5830eb77bbdSLong Wu 		struct rte_flow *nfp_flow,
5847493f8a5SChaoyong He 		const struct rte_flow_action *action)
5857493f8a5SChaoyong He {
5867493f8a5SChaoyong He 	struct nfp_net_cmsg_action *action_data;
5877493f8a5SChaoyong He 	const struct rte_flow_action_queue *queue;
5887493f8a5SChaoyong He 
5897493f8a5SChaoyong He 	action_data = (struct nfp_net_cmsg_action *)nfp_flow->payload.action_data;
5907493f8a5SChaoyong He 	queue = action->conf;
5910eb77bbdSLong Wu 	if (queue->index >= dev->data->nb_rx_queues ||
5920eb77bbdSLong Wu 			dev->data->rx_queues[queue->index] == NULL) {
593*b6de4353SZerun Fu 		PMD_DRV_LOG(ERR, "Queue index is illegal.");
5940eb77bbdSLong Wu 		return -EINVAL;
5950eb77bbdSLong Wu 	}
5967493f8a5SChaoyong He 
5977493f8a5SChaoyong He 	action_data->action |= NFP_NET_CMSG_ACTION_QUEUE;
5987493f8a5SChaoyong He 	action_data->queue = queue->index;
5990eb77bbdSLong Wu 
6000eb77bbdSLong Wu 	return 0;
6017493f8a5SChaoyong He }
6027493f8a5SChaoyong He 
603bc94750aSChaoyong He static int
6040eb77bbdSLong Wu nfp_net_flow_compile_actions(struct rte_eth_dev *dev,
6050eb77bbdSLong Wu 		const struct rte_flow_action actions[],
606bc94750aSChaoyong He 		struct rte_flow *nfp_flow)
607bc94750aSChaoyong He {
6080eb77bbdSLong Wu 	int ret = 0;
609bc94750aSChaoyong He 	const struct rte_flow_action *action;
610bc94750aSChaoyong He 
611bc94750aSChaoyong He 	for (action = actions; action->type != RTE_FLOW_ACTION_TYPE_END; ++action) {
612bc94750aSChaoyong He 		switch (action->type) {
613bc94750aSChaoyong He 		case RTE_FLOW_ACTION_TYPE_DROP:
614*b6de4353SZerun Fu 			PMD_DRV_LOG(DEBUG, "Process RTE_FLOW_ACTION_TYPE_DROP.");
615bc94750aSChaoyong He 			nfp_net_flow_action_drop(nfp_flow);
616bc94750aSChaoyong He 			return 0;
6179c5cfc10SChaoyong He 		case RTE_FLOW_ACTION_TYPE_MARK:
618*b6de4353SZerun Fu 			PMD_DRV_LOG(DEBUG, "Process RTE_FLOW_ACTION_TYPE_MARK.");
6199c5cfc10SChaoyong He 			nfp_net_flow_action_mark(nfp_flow, action);
6209c5cfc10SChaoyong He 			break;
6217493f8a5SChaoyong He 		case RTE_FLOW_ACTION_TYPE_QUEUE:
622*b6de4353SZerun Fu 			PMD_DRV_LOG(DEBUG, "Process RTE_FLOW_ACTION_TYPE_QUEUE.");
6230eb77bbdSLong Wu 			ret = nfp_net_flow_action_queue(dev, nfp_flow, action);
6247493f8a5SChaoyong He 			break;
625bc94750aSChaoyong He 		default:
626*b6de4353SZerun Fu 			PMD_DRV_LOG(ERR, "Unsupported action type: %d.", action->type);
627bc94750aSChaoyong He 			return -ENOTSUP;
628bc94750aSChaoyong He 		}
629bc94750aSChaoyong He 	}
630bc94750aSChaoyong He 
6310eb77bbdSLong Wu 	return ret;
632bc94750aSChaoyong He }
633bc94750aSChaoyong He 
634bc94750aSChaoyong He static void
63542eabda0SChaoyong He nfp_net_flow_process_priority(struct rte_flow *nfp_flow,
6360b9079d2SChaoyong He 		uint32_t match_len)
6370b9079d2SChaoyong He {
63842eabda0SChaoyong He 	struct nfp_net_cmsg_match_v4 *ipv4;
6399f27cb88SChaoyong He 	struct nfp_net_cmsg_match_v6 *ipv6;
64042eabda0SChaoyong He 
6410b9079d2SChaoyong He 	switch (match_len) {
64242eabda0SChaoyong He 	case sizeof(struct nfp_net_cmsg_match_v4):
64342eabda0SChaoyong He 		ipv4 = (struct nfp_net_cmsg_match_v4 *)nfp_flow->payload.match_data;
64442eabda0SChaoyong He 		ipv4->position = nfp_flow->position;
64542eabda0SChaoyong He 		break;
6469f27cb88SChaoyong He 	case sizeof(struct nfp_net_cmsg_match_v6):
6479f27cb88SChaoyong He 		ipv6 = (struct nfp_net_cmsg_match_v6 *)nfp_flow->payload.match_data;
6489f27cb88SChaoyong He 		ipv6->position = nfp_flow->position;
6499f27cb88SChaoyong He 		break;
6500b9079d2SChaoyong He 	default:
6510b9079d2SChaoyong He 		break;
6520b9079d2SChaoyong He 	}
6530b9079d2SChaoyong He }
6540b9079d2SChaoyong He 
655849a9ffbSLong Wu static int
656849a9ffbSLong Wu nfp_net_flow_check_count(struct nfp_net_flow_count *flow_count,
657849a9ffbSLong Wu 		uint32_t item_type)
658849a9ffbSLong Wu {
659849a9ffbSLong Wu 	int ret = 0;
660849a9ffbSLong Wu 
661849a9ffbSLong Wu 	switch (item_type) {
662849a9ffbSLong Wu 	case RTE_FLOW_ITEM_TYPE_ETH:
663849a9ffbSLong Wu 		if (flow_count->eth_count >= NFP_NET_ETH_FLOW_LIMIT)
664849a9ffbSLong Wu 			ret = -ENOSPC;
665849a9ffbSLong Wu 		break;
666849a9ffbSLong Wu 	case RTE_FLOW_ITEM_TYPE_IPV4:
667849a9ffbSLong Wu 		if (flow_count->ipv4_count >= NFP_NET_IPV4_FLOW_LIMIT)
668849a9ffbSLong Wu 			ret = -ENOSPC;
669849a9ffbSLong Wu 		break;
670849a9ffbSLong Wu 	case RTE_FLOW_ITEM_TYPE_IPV6:
671849a9ffbSLong Wu 		if (flow_count->ipv6_count >= NFP_NET_IPV6_FLOW_LIMIT)
672849a9ffbSLong Wu 			ret = -ENOSPC;
673849a9ffbSLong Wu 		break;
674849a9ffbSLong Wu 	default:
675849a9ffbSLong Wu 		ret = -ENOTSUP;
676849a9ffbSLong Wu 		break;
677849a9ffbSLong Wu 	}
678849a9ffbSLong Wu 
679849a9ffbSLong Wu 	return ret;
680849a9ffbSLong Wu }
681849a9ffbSLong Wu 
682849a9ffbSLong Wu static int
683849a9ffbSLong Wu nfp_net_flow_calculate_count(struct rte_flow *nfp_flow,
684849a9ffbSLong Wu 		struct nfp_net_flow_count *flow_count,
685849a9ffbSLong Wu 		bool delete_flag)
686849a9ffbSLong Wu {
687849a9ffbSLong Wu 	uint16_t *count;
688849a9ffbSLong Wu 
689849a9ffbSLong Wu 	switch (nfp_flow->payload.cmsg_type) {
690849a9ffbSLong Wu 	case NFP_NET_CFG_MBOX_CMD_FS_ADD_V4:
691849a9ffbSLong Wu 	case NFP_NET_CFG_MBOX_CMD_FS_DEL_V4:
692849a9ffbSLong Wu 		count = &flow_count->ipv4_count;
693849a9ffbSLong Wu 		break;
694849a9ffbSLong Wu 	case NFP_NET_CFG_MBOX_CMD_FS_ADD_V6:
695849a9ffbSLong Wu 	case NFP_NET_CFG_MBOX_CMD_FS_DEL_V6:
696849a9ffbSLong Wu 		count = &flow_count->ipv6_count;
697849a9ffbSLong Wu 		break;
698849a9ffbSLong Wu 	case NFP_NET_CFG_MBOX_CMD_FS_ADD_ETHTYPE:
699849a9ffbSLong Wu 	case NFP_NET_CFG_MBOX_CMD_FS_DEL_ETHTYPE:
700849a9ffbSLong Wu 		count = &flow_count->eth_count;
701849a9ffbSLong Wu 		break;
702849a9ffbSLong Wu 	default:
703849a9ffbSLong Wu 		PMD_DRV_LOG(ERR, "Flow count calculate failed.");
704849a9ffbSLong Wu 		return -EINVAL;
705849a9ffbSLong Wu 	}
706849a9ffbSLong Wu 
707849a9ffbSLong Wu 	if (delete_flag)
708849a9ffbSLong Wu 		(*count)--;
709849a9ffbSLong Wu 	else
710849a9ffbSLong Wu 		(*count)++;
711849a9ffbSLong Wu 
712849a9ffbSLong Wu 	return 0;
713849a9ffbSLong Wu }
714849a9ffbSLong Wu 
7150b9079d2SChaoyong He static struct rte_flow *
7160b9079d2SChaoyong He nfp_net_flow_setup(struct rte_eth_dev *dev,
7170b9079d2SChaoyong He 		const struct rte_flow_attr *attr,
7180b9079d2SChaoyong He 		const struct rte_flow_item items[],
719bc94750aSChaoyong He 		const struct rte_flow_action actions[])
7200b9079d2SChaoyong He {
7210b9079d2SChaoyong He 	int ret;
7220b9079d2SChaoyong He 	char *hash_data;
7230b9079d2SChaoyong He 	uint32_t port_id;
724849a9ffbSLong Wu 	uint32_t item_type;
7250b9079d2SChaoyong He 	uint32_t action_len;
7260b9079d2SChaoyong He 	struct nfp_net_hw *hw;
7270b9079d2SChaoyong He 	uint32_t match_len = 0;
7280b9079d2SChaoyong He 	struct nfp_net_priv *priv;
7290b9079d2SChaoyong He 	struct rte_flow *nfp_flow;
7300b9079d2SChaoyong He 	struct rte_flow *flow_find;
731ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
7320b9079d2SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
7330b9079d2SChaoyong He 
7340b9079d2SChaoyong He 	hw = dev->data->dev_private;
735ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
736ff9f5a56SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw_priv->pf_dev->app_fw_priv);
7370b9079d2SChaoyong He 	priv = app_fw_nic->ports[hw->idx]->priv;
7380b9079d2SChaoyong He 
739849a9ffbSLong Wu 	ret = nfp_net_flow_calculate_items(items, &match_len, &item_type);
7400b9079d2SChaoyong He 	if (ret != 0) {
7410b9079d2SChaoyong He 		PMD_DRV_LOG(ERR, "Key layers calculate failed.");
7420b9079d2SChaoyong He 		return NULL;
7430b9079d2SChaoyong He 	}
7440b9079d2SChaoyong He 
745849a9ffbSLong Wu 	ret = nfp_net_flow_check_count(&priv->flow_count, item_type);
746849a9ffbSLong Wu 	if (ret != 0) {
747849a9ffbSLong Wu 		PMD_DRV_LOG(ERR, "Flow count check failed.");
748849a9ffbSLong Wu 		return NULL;
749849a9ffbSLong Wu 	}
750849a9ffbSLong Wu 
7510b9079d2SChaoyong He 	action_len = sizeof(struct nfp_net_cmsg_action);
7520b9079d2SChaoyong He 	port_id = ((struct nfp_net_hw *)dev->data->dev_private)->nfp_idx;
7530b9079d2SChaoyong He 
7540b9079d2SChaoyong He 	nfp_flow = nfp_net_flow_alloc(priv, attr->priority, match_len, action_len, port_id);
7550b9079d2SChaoyong He 	if (nfp_flow == NULL) {
7560b9079d2SChaoyong He 		PMD_DRV_LOG(ERR, "Alloc nfp flow failed.");
7570b9079d2SChaoyong He 		return NULL;
7580b9079d2SChaoyong He 	}
7590b9079d2SChaoyong He 
760c91c6512SChaoyong He 	ret = nfp_net_flow_compile_items(items, nfp_flow);
761c91c6512SChaoyong He 	if (ret != 0) {
762c91c6512SChaoyong He 		PMD_DRV_LOG(ERR, "NFP flow item process failed.");
763c91c6512SChaoyong He 		goto free_flow;
764c91c6512SChaoyong He 	}
765c91c6512SChaoyong He 
7660eb77bbdSLong Wu 	ret = nfp_net_flow_compile_actions(dev, actions, nfp_flow);
767bc94750aSChaoyong He 	if (ret != 0) {
768bc94750aSChaoyong He 		PMD_DRV_LOG(ERR, "NFP flow action process failed.");
769bc94750aSChaoyong He 		goto free_flow;
770bc94750aSChaoyong He 	}
771bc94750aSChaoyong He 
7720b9079d2SChaoyong He 	/* Calculate and store the hash_key for later use */
7730b9079d2SChaoyong He 	hash_data = nfp_flow->payload.match_data;
7740b9079d2SChaoyong He 	nfp_flow->hash_key = rte_jhash(hash_data, match_len + action_len,
7750b9079d2SChaoyong He 			priv->hash_seed);
7760b9079d2SChaoyong He 
7770b9079d2SChaoyong He 	/* Find the flow in hash table */
7780b9079d2SChaoyong He 	flow_find = nfp_net_flow_table_search(priv, nfp_flow);
7790b9079d2SChaoyong He 	if (flow_find != NULL) {
7800b9079d2SChaoyong He 		PMD_DRV_LOG(ERR, "This flow is already exist.");
7810b9079d2SChaoyong He 		goto free_flow;
7820b9079d2SChaoyong He 	}
7830b9079d2SChaoyong He 
784849a9ffbSLong Wu 	ret = nfp_net_flow_calculate_count(nfp_flow, &priv->flow_count, false);
785849a9ffbSLong Wu 	if (ret != 0) {
786849a9ffbSLong Wu 		PMD_DRV_LOG(ERR, "NFP flow calculate count failed.");
787849a9ffbSLong Wu 		goto free_flow;
788849a9ffbSLong Wu 	}
7890b9079d2SChaoyong He 
7900b9079d2SChaoyong He 	nfp_net_flow_process_priority(nfp_flow, match_len);
7910b9079d2SChaoyong He 
7920b9079d2SChaoyong He 	return nfp_flow;
7930b9079d2SChaoyong He 
7940b9079d2SChaoyong He free_flow:
7950b9079d2SChaoyong He 	nfp_net_flow_free(priv, nfp_flow);
7960b9079d2SChaoyong He 
7970b9079d2SChaoyong He 	return NULL;
7980b9079d2SChaoyong He }
7990b9079d2SChaoyong He 
8000b9079d2SChaoyong He static int
8010b9079d2SChaoyong He nfp_net_flow_teardown(struct nfp_net_priv *priv,
802849a9ffbSLong Wu 		struct rte_flow *nfp_flow)
8030b9079d2SChaoyong He {
804849a9ffbSLong Wu 	return nfp_net_flow_calculate_count(nfp_flow, &priv->flow_count, true);
8050b9079d2SChaoyong He }
8060b9079d2SChaoyong He 
8070b9079d2SChaoyong He static int
8080b9079d2SChaoyong He nfp_net_flow_offload(struct nfp_net_hw *hw,
8090b9079d2SChaoyong He 		struct rte_flow *flow,
8100b9079d2SChaoyong He 		bool delete_flag)
8110b9079d2SChaoyong He {
8120b9079d2SChaoyong He 	int ret;
8130b9079d2SChaoyong He 	char *tmp;
8140b9079d2SChaoyong He 	uint32_t msg_size;
8150b9079d2SChaoyong He 	struct nfp_net_cmsg *cmsg;
8160b9079d2SChaoyong He 
8170b9079d2SChaoyong He 	msg_size = sizeof(uint32_t) + flow->payload.match_len +
8180b9079d2SChaoyong He 			flow->payload.action_len;
8190b9079d2SChaoyong He 	cmsg = nfp_net_cmsg_alloc(msg_size);
8200b9079d2SChaoyong He 	if (cmsg == NULL) {
8210b9079d2SChaoyong He 		PMD_DRV_LOG(ERR, "Alloc cmsg failed.");
8220b9079d2SChaoyong He 		return -ENOMEM;
8230b9079d2SChaoyong He 	}
8240b9079d2SChaoyong He 
8250b9079d2SChaoyong He 	cmsg->cmd = flow->payload.cmsg_type;
8260b9079d2SChaoyong He 	if (delete_flag)
8270b9079d2SChaoyong He 		cmsg->cmd++;
8280b9079d2SChaoyong He 
8290b9079d2SChaoyong He 	tmp = (char *)cmsg->data;
8300b9079d2SChaoyong He 	rte_memcpy(tmp, flow->payload.match_data, flow->payload.match_len);
8310b9079d2SChaoyong He 	tmp += flow->payload.match_len;
8320b9079d2SChaoyong He 	rte_memcpy(tmp, flow->payload.action_data, flow->payload.action_len);
8330b9079d2SChaoyong He 
8340b9079d2SChaoyong He 	ret = nfp_net_cmsg_xmit(hw, cmsg, msg_size);
8350b9079d2SChaoyong He 	if (ret != 0) {
8360b9079d2SChaoyong He 		PMD_DRV_LOG(ERR, "Send cmsg failed.");
8370b9079d2SChaoyong He 		ret = -EINVAL;
8380b9079d2SChaoyong He 		goto free_cmsg;
8390b9079d2SChaoyong He 	}
8400b9079d2SChaoyong He 
8410b9079d2SChaoyong He free_cmsg:
8420b9079d2SChaoyong He 	nfp_net_cmsg_free(cmsg);
8430b9079d2SChaoyong He 
8440b9079d2SChaoyong He 	return ret;
8450b9079d2SChaoyong He }
8460b9079d2SChaoyong He 
8470b9079d2SChaoyong He static int
8480b9079d2SChaoyong He nfp_net_flow_validate(struct rte_eth_dev *dev,
8490b9079d2SChaoyong He 		const struct rte_flow_attr *attr,
8500b9079d2SChaoyong He 		const struct rte_flow_item items[],
8510b9079d2SChaoyong He 		const struct rte_flow_action actions[],
8520b9079d2SChaoyong He 		struct rte_flow_error *error)
8530b9079d2SChaoyong He {
8540b9079d2SChaoyong He 	int ret;
8550b9079d2SChaoyong He 	struct nfp_net_hw *hw;
8560b9079d2SChaoyong He 	struct rte_flow *nfp_flow;
8570b9079d2SChaoyong He 	struct nfp_net_priv *priv;
858ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
8590b9079d2SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
8600b9079d2SChaoyong He 
8610b9079d2SChaoyong He 	hw = dev->data->dev_private;
862ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
863ff9f5a56SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw_priv->pf_dev->app_fw_priv);
8640b9079d2SChaoyong He 	priv = app_fw_nic->ports[hw->idx]->priv;
8650b9079d2SChaoyong He 
8660b9079d2SChaoyong He 	nfp_flow = nfp_net_flow_setup(dev, attr, items, actions);
8670b9079d2SChaoyong He 	if (nfp_flow == NULL) {
8680b9079d2SChaoyong He 		return rte_flow_error_set(error, ENOTSUP,
8690b9079d2SChaoyong He 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
8700b9079d2SChaoyong He 				NULL, "This flow can not be offloaded.");
8710b9079d2SChaoyong He 	}
8720b9079d2SChaoyong He 
8730b9079d2SChaoyong He 	ret = nfp_net_flow_teardown(priv, nfp_flow);
8740b9079d2SChaoyong He 	if (ret != 0) {
8750b9079d2SChaoyong He 		return rte_flow_error_set(error, EINVAL,
8760b9079d2SChaoyong He 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
8770b9079d2SChaoyong He 				NULL, "Flow resource free failed.");
8780b9079d2SChaoyong He 	}
8790b9079d2SChaoyong He 
8800b9079d2SChaoyong He 	nfp_net_flow_free(priv, nfp_flow);
8810b9079d2SChaoyong He 
8820b9079d2SChaoyong He 	return 0;
8830b9079d2SChaoyong He }
8840b9079d2SChaoyong He 
8850b9079d2SChaoyong He static struct rte_flow *
8860b9079d2SChaoyong He nfp_net_flow_create(struct rte_eth_dev *dev,
8870b9079d2SChaoyong He 		const struct rte_flow_attr *attr,
8880b9079d2SChaoyong He 		const struct rte_flow_item items[],
8890b9079d2SChaoyong He 		const struct rte_flow_action actions[],
8900b9079d2SChaoyong He 		struct rte_flow_error *error)
8910b9079d2SChaoyong He {
8920b9079d2SChaoyong He 	int ret;
8930b9079d2SChaoyong He 	struct nfp_net_hw *hw;
8940b9079d2SChaoyong He 	struct rte_flow *nfp_flow;
8950b9079d2SChaoyong He 	struct nfp_net_priv *priv;
896ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
8970b9079d2SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
8980b9079d2SChaoyong He 
8990b9079d2SChaoyong He 	hw = dev->data->dev_private;
900ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
901ff9f5a56SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw_priv->pf_dev->app_fw_priv);
9020b9079d2SChaoyong He 	priv = app_fw_nic->ports[hw->idx]->priv;
9030b9079d2SChaoyong He 
9040b9079d2SChaoyong He 	nfp_flow = nfp_net_flow_setup(dev, attr, items, actions);
9050b9079d2SChaoyong He 	if (nfp_flow == NULL) {
9060b9079d2SChaoyong He 		rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9070b9079d2SChaoyong He 				NULL, "This flow can not be offloaded.");
9080b9079d2SChaoyong He 		return NULL;
9090b9079d2SChaoyong He 	}
9100b9079d2SChaoyong He 
9110b9079d2SChaoyong He 	/* Add the flow to flow hash table */
9120b9079d2SChaoyong He 	ret = nfp_net_flow_table_add(priv, nfp_flow);
9130b9079d2SChaoyong He 	if (ret != 0) {
9140b9079d2SChaoyong He 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9150b9079d2SChaoyong He 				NULL, "Add flow to the flow table failed.");
9160b9079d2SChaoyong He 		goto flow_teardown;
9170b9079d2SChaoyong He 	}
9180b9079d2SChaoyong He 
9190b9079d2SChaoyong He 	/* Add the flow to hardware */
9200b9079d2SChaoyong He 	ret = nfp_net_flow_offload(hw, nfp_flow, false);
9210b9079d2SChaoyong He 	if (ret != 0) {
9220b9079d2SChaoyong He 		rte_flow_error_set(error, EINVAL,
9230b9079d2SChaoyong He 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9240b9079d2SChaoyong He 				NULL, "Add flow to firmware failed.");
9250b9079d2SChaoyong He 		goto table_delete;
9260b9079d2SChaoyong He 	}
9270b9079d2SChaoyong He 
9280b9079d2SChaoyong He 	return nfp_flow;
9290b9079d2SChaoyong He 
9300b9079d2SChaoyong He table_delete:
9310b9079d2SChaoyong He 	nfp_net_flow_table_delete(priv, nfp_flow);
9320b9079d2SChaoyong He flow_teardown:
9330b9079d2SChaoyong He 	nfp_net_flow_teardown(priv, nfp_flow);
9340b9079d2SChaoyong He 	nfp_net_flow_free(priv, nfp_flow);
9350b9079d2SChaoyong He 
9360b9079d2SChaoyong He 	return NULL;
9370b9079d2SChaoyong He }
9380b9079d2SChaoyong He 
9390b9079d2SChaoyong He static int
9400b9079d2SChaoyong He nfp_net_flow_destroy(struct rte_eth_dev *dev,
9410b9079d2SChaoyong He 		struct rte_flow *nfp_flow,
9420b9079d2SChaoyong He 		struct rte_flow_error *error)
9430b9079d2SChaoyong He {
9440b9079d2SChaoyong He 	int ret;
9450b9079d2SChaoyong He 	struct nfp_net_hw *hw;
9460b9079d2SChaoyong He 	struct nfp_net_priv *priv;
9470b9079d2SChaoyong He 	struct rte_flow *flow_find;
948ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
9490b9079d2SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
9500b9079d2SChaoyong He 
9510b9079d2SChaoyong He 	hw = dev->data->dev_private;
952ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
953ff9f5a56SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw_priv->pf_dev->app_fw_priv);
9540b9079d2SChaoyong He 	priv = app_fw_nic->ports[hw->idx]->priv;
9550b9079d2SChaoyong He 
9560b9079d2SChaoyong He 	/* Find the flow in flow hash table */
9570b9079d2SChaoyong He 	flow_find = nfp_net_flow_table_search(priv, nfp_flow);
9580b9079d2SChaoyong He 	if (flow_find == NULL) {
9590b9079d2SChaoyong He 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9600b9079d2SChaoyong He 				NULL, "Flow does not exist.");
9610b9079d2SChaoyong He 		ret = -EINVAL;
9620b9079d2SChaoyong He 		goto exit;
9630b9079d2SChaoyong He 	}
9640b9079d2SChaoyong He 
9650b9079d2SChaoyong He 	/* Delete the flow from hardware */
9660b9079d2SChaoyong He 	ret = nfp_net_flow_offload(hw, nfp_flow, true);
9670b9079d2SChaoyong He 	if (ret != 0) {
9680b9079d2SChaoyong He 		rte_flow_error_set(error, EINVAL,
9690b9079d2SChaoyong He 				RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9700b9079d2SChaoyong He 				NULL, "Delete flow from firmware failed.");
9710b9079d2SChaoyong He 		ret = -EINVAL;
9720b9079d2SChaoyong He 		goto exit;
9730b9079d2SChaoyong He 	}
9740b9079d2SChaoyong He 
9750b9079d2SChaoyong He 	/* Delete the flow from flow hash table */
9760b9079d2SChaoyong He 	ret = nfp_net_flow_table_delete(priv, nfp_flow);
9770b9079d2SChaoyong He 	if (ret != 0) {
9780b9079d2SChaoyong He 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9790b9079d2SChaoyong He 				NULL, "Delete flow from the flow table failed.");
9800b9079d2SChaoyong He 		ret = -EINVAL;
9810b9079d2SChaoyong He 		goto exit;
9820b9079d2SChaoyong He 	}
9830b9079d2SChaoyong He 
9840b9079d2SChaoyong He 	ret = nfp_net_flow_teardown(priv, nfp_flow);
9850b9079d2SChaoyong He 	if (ret != 0) {
9860b9079d2SChaoyong He 		rte_flow_error_set(error, EINVAL, RTE_FLOW_ERROR_TYPE_UNSPECIFIED,
9870b9079d2SChaoyong He 				NULL, "Flow teardown failed.");
9880b9079d2SChaoyong He 		ret = -EINVAL;
9890b9079d2SChaoyong He 		goto exit;
9900b9079d2SChaoyong He 	}
9910b9079d2SChaoyong He 
9920b9079d2SChaoyong He exit:
9930b9079d2SChaoyong He 	nfp_net_flow_free(priv, nfp_flow);
9940b9079d2SChaoyong He 
9950b9079d2SChaoyong He 	return ret;
9960b9079d2SChaoyong He }
9970b9079d2SChaoyong He 
9980b9079d2SChaoyong He static int
9990b9079d2SChaoyong He nfp_net_flow_flush(struct rte_eth_dev *dev,
10000b9079d2SChaoyong He 		struct rte_flow_error *error)
10010b9079d2SChaoyong He {
10020b9079d2SChaoyong He 	int ret = 0;
10030b9079d2SChaoyong He 	void *next_data;
10040b9079d2SChaoyong He 	uint32_t iter = 0;
10050b9079d2SChaoyong He 	const void *next_key;
10060b9079d2SChaoyong He 	struct nfp_net_hw *hw;
10070b9079d2SChaoyong He 	struct rte_flow *nfp_flow;
10080b9079d2SChaoyong He 	struct rte_hash *flow_table;
1009ff9f5a56SChaoyong He 	struct nfp_net_hw_priv *hw_priv;
10100b9079d2SChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
10110b9079d2SChaoyong He 
10120b9079d2SChaoyong He 	hw = dev->data->dev_private;
1013ff9f5a56SChaoyong He 	hw_priv = dev->process_private;
1014ff9f5a56SChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(hw_priv->pf_dev->app_fw_priv);
10150b9079d2SChaoyong He 	flow_table = app_fw_nic->ports[hw->idx]->priv->flow_table;
10160b9079d2SChaoyong He 
10170b9079d2SChaoyong He 	while (rte_hash_iterate(flow_table, &next_key, &next_data, &iter) >= 0) {
10180b9079d2SChaoyong He 		nfp_flow = next_data;
10190b9079d2SChaoyong He 		ret = nfp_net_flow_destroy(dev, nfp_flow, error);
10200b9079d2SChaoyong He 		if (ret != 0)
10210b9079d2SChaoyong He 			break;
10220b9079d2SChaoyong He 	}
10230b9079d2SChaoyong He 
10240b9079d2SChaoyong He 	return ret;
10250b9079d2SChaoyong He }
10260b9079d2SChaoyong He 
10270b9079d2SChaoyong He static const struct rte_flow_ops nfp_net_flow_ops = {
10280b9079d2SChaoyong He 	.validate                = nfp_net_flow_validate,
10290b9079d2SChaoyong He 	.create                  = nfp_net_flow_create,
10300b9079d2SChaoyong He 	.destroy                 = nfp_net_flow_destroy,
10310b9079d2SChaoyong He 	.flush                   = nfp_net_flow_flush,
10320b9079d2SChaoyong He };
10330b9079d2SChaoyong He 
10340b9079d2SChaoyong He int
10350b9079d2SChaoyong He nfp_net_flow_ops_get(struct rte_eth_dev *dev,
10360b9079d2SChaoyong He 		const struct rte_flow_ops **ops)
10370b9079d2SChaoyong He {
10380b9079d2SChaoyong He 	struct nfp_net_hw *hw;
10390b9079d2SChaoyong He 
1040c99e1db8SLong Wu 	if (rte_eth_dev_is_repr(dev)) {
10410b9079d2SChaoyong He 		*ops = NULL;
10420b9079d2SChaoyong He 		PMD_DRV_LOG(ERR, "Port is a representor.");
10430b9079d2SChaoyong He 		return -EINVAL;
10440b9079d2SChaoyong He 	}
10450b9079d2SChaoyong He 
10460b9079d2SChaoyong He 	hw = dev->data->dev_private;
10470b9079d2SChaoyong He 	if ((hw->super.ctrl_ext & NFP_NET_CFG_CTRL_FLOW_STEER) == 0) {
10480b9079d2SChaoyong He 		*ops = NULL;
10490b9079d2SChaoyong He 		return 0;
10500b9079d2SChaoyong He 	}
10510b9079d2SChaoyong He 
10520b9079d2SChaoyong He 	*ops = &nfp_net_flow_ops;
10530b9079d2SChaoyong He 
10540b9079d2SChaoyong He 	return 0;
10550b9079d2SChaoyong He }
10560b9079d2SChaoyong He 
105766df893fSChaoyong He static uint32_t
105866df893fSChaoyong He nfp_net_fs_max_entry_get(struct nfp_hw *hw)
105966df893fSChaoyong He {
106066df893fSChaoyong He 	uint32_t cnt;
106166df893fSChaoyong He 
106266df893fSChaoyong He 	cnt = nn_cfg_readl(hw, NFP_NET_CFG_MAX_FS_CAP);
106366df893fSChaoyong He 	if (cnt != 0)
106466df893fSChaoyong He 		return cnt;
106566df893fSChaoyong He 
106666df893fSChaoyong He 	return NFP_NET_FLOW_LIMIT;
106766df893fSChaoyong He }
106866df893fSChaoyong He 
10698153bc6fSChaoyong He int
10708153bc6fSChaoyong He nfp_net_flow_priv_init(struct nfp_pf_dev *pf_dev,
10718153bc6fSChaoyong He 		uint16_t port)
10728153bc6fSChaoyong He {
10738153bc6fSChaoyong He 	int ret = 0;
107466df893fSChaoyong He 	struct nfp_hw *hw;
10758153bc6fSChaoyong He 	struct nfp_net_priv *priv;
10768153bc6fSChaoyong He 	char flow_name[RTE_HASH_NAMESIZE];
10778153bc6fSChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
10788153bc6fSChaoyong He 	const char *pci_name = strchr(pf_dev->pci_dev->name, ':') + 1;
10798153bc6fSChaoyong He 
10808153bc6fSChaoyong He 	snprintf(flow_name, sizeof(flow_name), "%s_fl_%u", pci_name, port);
10818153bc6fSChaoyong He 
10828153bc6fSChaoyong He 	struct rte_hash_parameters flow_hash_params = {
10838153bc6fSChaoyong He 		.name       = flow_name,
10848153bc6fSChaoyong He 		.hash_func  = rte_jhash,
10858153bc6fSChaoyong He 		.socket_id  = rte_socket_id(),
10868153bc6fSChaoyong He 		.key_len    = sizeof(uint32_t),
10878153bc6fSChaoyong He 		.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY,
10888153bc6fSChaoyong He 	};
10898153bc6fSChaoyong He 
10908153bc6fSChaoyong He 	priv = rte_zmalloc("nfp_app_nic_priv", sizeof(struct nfp_net_priv), 0);
10918153bc6fSChaoyong He 	if (priv == NULL) {
1092*b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "NFP app nic priv creation failed.");
10938153bc6fSChaoyong He 		ret = -ENOMEM;
10948153bc6fSChaoyong He 		goto exit;
10958153bc6fSChaoyong He 	}
10968153bc6fSChaoyong He 
10978153bc6fSChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
10988153bc6fSChaoyong He 	app_fw_nic->ports[port]->priv = priv;
10998153bc6fSChaoyong He 	priv->hash_seed = (uint32_t)rte_rand();
11008153bc6fSChaoyong He 
110166df893fSChaoyong He 	/* Flow limit */
110266df893fSChaoyong He 	hw = &app_fw_nic->ports[port]->super;
110366df893fSChaoyong He 	priv->flow_limit = nfp_net_fs_max_entry_get(hw);
110466df893fSChaoyong He 	if (priv->flow_limit == 0) {
110566df893fSChaoyong He 		PMD_INIT_LOG(ERR, "NFP app nic flow limit not right.");
110666df893fSChaoyong He 		ret = -EINVAL;
110766df893fSChaoyong He 		goto free_priv;
110866df893fSChaoyong He 	}
110966df893fSChaoyong He 
111066df893fSChaoyong He 	/* Flow position array */
111166df893fSChaoyong He 	priv->flow_position = rte_zmalloc(NULL, sizeof(bool) * priv->flow_limit, 0);
111266df893fSChaoyong He 	if (priv->flow_position == NULL) {
111366df893fSChaoyong He 		PMD_INIT_LOG(ERR, "NFP app nic flow position creation failed.");
11148153bc6fSChaoyong He 		ret = -ENOMEM;
11158153bc6fSChaoyong He 		goto free_priv;
11168153bc6fSChaoyong He 	}
11178153bc6fSChaoyong He 
111866df893fSChaoyong He 	/* Flow table */
111966df893fSChaoyong He 	flow_hash_params.hash_func_init_val = priv->hash_seed;
112066df893fSChaoyong He 	flow_hash_params.entries = priv->flow_limit * NFP_NET_HASH_REDUNDANCE;
112166df893fSChaoyong He 	priv->flow_table = rte_hash_create(&flow_hash_params);
112266df893fSChaoyong He 	if (priv->flow_table == NULL) {
1123*b6de4353SZerun Fu 		PMD_INIT_LOG(ERR, "Flow hash table creation failed.");
112466df893fSChaoyong He 		ret = -ENOMEM;
112566df893fSChaoyong He 		goto free_flow_position;
112666df893fSChaoyong He 	}
112766df893fSChaoyong He 
11288153bc6fSChaoyong He 	return 0;
11298153bc6fSChaoyong He 
113066df893fSChaoyong He free_flow_position:
113166df893fSChaoyong He 	rte_free(priv->flow_position);
11328153bc6fSChaoyong He free_priv:
11338153bc6fSChaoyong He 	rte_free(priv);
11348153bc6fSChaoyong He exit:
11358153bc6fSChaoyong He 	return ret;
11368153bc6fSChaoyong He }
11378153bc6fSChaoyong He 
11388153bc6fSChaoyong He void
11398153bc6fSChaoyong He nfp_net_flow_priv_uninit(struct nfp_pf_dev *pf_dev,
11408153bc6fSChaoyong He 		uint16_t port)
11418153bc6fSChaoyong He {
11428153bc6fSChaoyong He 	struct nfp_net_priv *priv;
11438153bc6fSChaoyong He 	struct nfp_app_fw_nic *app_fw_nic;
11448153bc6fSChaoyong He 
11458153bc6fSChaoyong He 	if (pf_dev == NULL)
11468153bc6fSChaoyong He 		return;
11478153bc6fSChaoyong He 
11488153bc6fSChaoyong He 	app_fw_nic = NFP_PRIV_TO_APP_FW_NIC(pf_dev->app_fw_priv);
11498153bc6fSChaoyong He 	priv = app_fw_nic->ports[port]->priv;
115066df893fSChaoyong He 	if (priv != NULL) {
11518153bc6fSChaoyong He 		rte_hash_free(priv->flow_table);
115266df893fSChaoyong He 		rte_free(priv->flow_position);
115366df893fSChaoyong He 	}
11548153bc6fSChaoyong He 
11558153bc6fSChaoyong He 	rte_free(priv);
11568153bc6fSChaoyong He }
1157