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