aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qede/qede_fdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/qede/qede_fdir.c')
-rw-r--r--drivers/net/qede/qede_fdir.c470
1 files changed, 0 insertions, 470 deletions
diff --git a/drivers/net/qede/qede_fdir.c b/drivers/net/qede/qede_fdir.c
deleted file mode 100644
index 83580d04..00000000
--- a/drivers/net/qede/qede_fdir.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright (c) 2017 Cavium Inc.
- * All rights reserved.
- * www.cavium.com
- */
-
-#include <rte_udp.h>
-#include <rte_tcp.h>
-#include <rte_sctp.h>
-#include <rte_errno.h>
-
-#include "qede_ethdev.h"
-
-#define IP_VERSION (0x40)
-#define IP_HDRLEN (0x5)
-#define QEDE_FDIR_IP_DEFAULT_VERSION_IHL (IP_VERSION | IP_HDRLEN)
-#define QEDE_FDIR_TCP_DEFAULT_DATAOFF (0x50)
-#define QEDE_FDIR_IPV4_DEF_TTL (64)
-
-/* Sum of length of header types of L2, L3, L4.
- * L2 : ether_hdr + vlan_hdr + vxlan_hdr
- * L3 : ipv6_hdr
- * L4 : tcp_hdr
- */
-#define QEDE_MAX_FDIR_PKT_LEN (86)
-
-#ifndef IPV6_ADDR_LEN
-#define IPV6_ADDR_LEN (16)
-#endif
-
-#define QEDE_VALID_FLOW(flow_type) \
- ((flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP || \
- (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_UDP || \
- (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_TCP || \
- (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_UDP)
-
-/* Note: Flowdir support is only partial.
- * For ex: drop_queue, FDIR masks, flex_conf are not supported.
- * Parameters like pballoc/status fields are irrelevant here.
- */
-int qede_check_fdir_support(struct rte_eth_dev *eth_dev)
-{
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
- struct rte_fdir_conf *fdir = &eth_dev->data->dev_conf.fdir_conf;
-
- /* check FDIR modes */
- switch (fdir->mode) {
- case RTE_FDIR_MODE_NONE:
- qdev->fdir_info.arfs.arfs_enable = false;
- DP_INFO(edev, "flowdir is disabled\n");
- break;
- case RTE_FDIR_MODE_PERFECT:
- if (ECORE_IS_CMT(edev)) {
- DP_ERR(edev, "flowdir is not supported in 100G mode\n");
- qdev->fdir_info.arfs.arfs_enable = false;
- return -ENOTSUP;
- }
- qdev->fdir_info.arfs.arfs_enable = true;
- DP_INFO(edev, "flowdir is enabled\n");
- break;
- case RTE_FDIR_MODE_PERFECT_TUNNEL:
- case RTE_FDIR_MODE_SIGNATURE:
- case RTE_FDIR_MODE_PERFECT_MAC_VLAN:
- DP_ERR(edev, "Unsupported flowdir mode %d\n", fdir->mode);
- return -ENOTSUP;
- }
-
- return 0;
-}
-
-void qede_fdir_dealloc_resc(struct rte_eth_dev *eth_dev)
-{
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct qede_fdir_entry *tmp = NULL;
-
- SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
- if (tmp) {
- if (tmp->mz)
- rte_memzone_free(tmp->mz);
- SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
- qede_fdir_entry, list);
- rte_free(tmp);
- }
- }
-}
-
-static int
-qede_config_cmn_fdir_filter(struct rte_eth_dev *eth_dev,
- struct rte_eth_fdir_filter *fdir_filter,
- bool add)
-{
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
- char mz_name[RTE_MEMZONE_NAMESIZE] = {0};
- struct qede_fdir_entry *tmp = NULL;
- struct qede_fdir_entry *fdir = NULL;
- const struct rte_memzone *mz;
- struct ecore_hwfn *p_hwfn;
- enum _ecore_status_t rc;
- uint16_t pkt_len;
- void *pkt;
-
- if (add) {
- if (qdev->fdir_info.filter_count == QEDE_RFS_MAX_FLTR - 1) {
- DP_ERR(edev, "Reached max flowdir filter limit\n");
- return -EINVAL;
- }
- fdir = rte_malloc(NULL, sizeof(struct qede_fdir_entry),
- RTE_CACHE_LINE_SIZE);
- if (!fdir) {
- DP_ERR(edev, "Did not allocate memory for fdir\n");
- return -ENOMEM;
- }
- }
- /* soft_id could have been used as memzone string, but soft_id is
- * not currently used so it has no significance.
- */
- snprintf(mz_name, sizeof(mz_name) - 1, "%lx",
- (unsigned long)rte_get_timer_cycles());
- mz = rte_memzone_reserve_aligned(mz_name, QEDE_MAX_FDIR_PKT_LEN,
- SOCKET_ID_ANY, 0, RTE_CACHE_LINE_SIZE);
- if (!mz) {
- DP_ERR(edev, "Failed to allocate memzone for fdir, err = %s\n",
- rte_strerror(rte_errno));
- rc = -rte_errno;
- goto err1;
- }
-
- pkt = mz->addr;
- memset(pkt, 0, QEDE_MAX_FDIR_PKT_LEN);
- pkt_len = qede_fdir_construct_pkt(eth_dev, fdir_filter, pkt,
- &qdev->fdir_info.arfs);
- if (pkt_len == 0) {
- rc = -EINVAL;
- goto err2;
- }
- DP_INFO(edev, "pkt_len = %u memzone = %s\n", pkt_len, mz_name);
- if (add) {
- SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
- if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0) {
- DP_INFO(edev, "flowdir filter exist\n");
- rc = 0;
- goto err2;
- }
- }
- } else {
- SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
- if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0)
- break;
- }
- if (!tmp) {
- DP_ERR(edev, "flowdir filter does not exist\n");
- rc = -EEXIST;
- goto err2;
- }
- }
- p_hwfn = ECORE_LEADING_HWFN(edev);
- if (add) {
- if (!qdev->fdir_info.arfs.arfs_enable) {
- /* Force update */
- eth_dev->data->dev_conf.fdir_conf.mode =
- RTE_FDIR_MODE_PERFECT;
- qdev->fdir_info.arfs.arfs_enable = true;
- DP_INFO(edev, "Force enable flowdir in perfect mode\n");
- }
- /* Enable ARFS searcher with updated flow_types */
- ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
- &qdev->fdir_info.arfs);
- }
- /* configure filter with ECORE_SPQ_MODE_EBLOCK */
- rc = ecore_configure_rfs_ntuple_filter(p_hwfn, NULL,
- (dma_addr_t)mz->iova,
- pkt_len,
- fdir_filter->action.rx_queue,
- 0, add);
- if (rc == ECORE_SUCCESS) {
- if (add) {
- fdir->rx_queue = fdir_filter->action.rx_queue;
- fdir->pkt_len = pkt_len;
- fdir->mz = mz;
- SLIST_INSERT_HEAD(&qdev->fdir_info.fdir_list_head,
- fdir, list);
- qdev->fdir_info.filter_count++;
- DP_INFO(edev, "flowdir filter added, count = %d\n",
- qdev->fdir_info.filter_count);
- } else {
- rte_memzone_free(tmp->mz);
- SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
- qede_fdir_entry, list);
- rte_free(tmp); /* the node deleted */
- rte_memzone_free(mz); /* temp node allocated */
- qdev->fdir_info.filter_count--;
- DP_INFO(edev, "Fdir filter deleted, count = %d\n",
- qdev->fdir_info.filter_count);
- }
- } else {
- DP_ERR(edev, "flowdir filter failed, rc=%d filter_count=%d\n",
- rc, qdev->fdir_info.filter_count);
- }
-
- /* Disable ARFS searcher if there are no more filters */
- if (qdev->fdir_info.filter_count == 0) {
- memset(&qdev->fdir_info.arfs, 0,
- sizeof(struct ecore_arfs_config_params));
- DP_INFO(edev, "Disabling flowdir\n");
- qdev->fdir_info.arfs.arfs_enable = false;
- ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
- &qdev->fdir_info.arfs);
- }
- return 0;
-
-err2:
- rte_memzone_free(mz);
-err1:
- if (add)
- rte_free(fdir);
- return rc;
-}
-
-static int
-qede_fdir_filter_add(struct rte_eth_dev *eth_dev,
- struct rte_eth_fdir_filter *fdir,
- bool add)
-{
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
-
- if (!QEDE_VALID_FLOW(fdir->input.flow_type)) {
- DP_ERR(edev, "invalid flow_type input\n");
- return -EINVAL;
- }
-
- if (fdir->action.rx_queue >= QEDE_RSS_COUNT(qdev)) {
- DP_ERR(edev, "invalid queue number %u\n",
- fdir->action.rx_queue);
- return -EINVAL;
- }
-
- if (fdir->input.flow_ext.is_vf) {
- DP_ERR(edev, "flowdir is not supported over VF\n");
- return -EINVAL;
- }
-
- return qede_config_cmn_fdir_filter(eth_dev, fdir, add);
-}
-
-/* Fills the L3/L4 headers and returns the actual length of flowdir packet */
-uint16_t
-qede_fdir_construct_pkt(struct rte_eth_dev *eth_dev,
- struct rte_eth_fdir_filter *fdir,
- void *buff,
- struct ecore_arfs_config_params *params)
-
-{
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
- uint16_t *ether_type;
- uint8_t *raw_pkt;
- struct rte_eth_fdir_input *input;
- static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
- struct ipv4_hdr *ip;
- struct ipv6_hdr *ip6;
- struct udp_hdr *udp;
- struct tcp_hdr *tcp;
- uint16_t len;
- static const uint8_t next_proto[] = {
- [RTE_ETH_FLOW_NONFRAG_IPV4_TCP] = IPPROTO_TCP,
- [RTE_ETH_FLOW_NONFRAG_IPV4_UDP] = IPPROTO_UDP,
- [RTE_ETH_FLOW_NONFRAG_IPV6_TCP] = IPPROTO_TCP,
- [RTE_ETH_FLOW_NONFRAG_IPV6_UDP] = IPPROTO_UDP,
- };
- raw_pkt = (uint8_t *)buff;
- input = &fdir->input;
- DP_INFO(edev, "flow_type %d\n", input->flow_type);
-
- len = 2 * sizeof(struct ether_addr);
- raw_pkt += 2 * sizeof(struct ether_addr);
- if (input->flow_ext.vlan_tci) {
- DP_INFO(edev, "adding VLAN header\n");
- rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame));
- rte_memcpy(raw_pkt + sizeof(uint16_t),
- &input->flow_ext.vlan_tci,
- sizeof(uint16_t));
- raw_pkt += sizeof(vlan_frame);
- len += sizeof(vlan_frame);
- }
- ether_type = (uint16_t *)raw_pkt;
- raw_pkt += sizeof(uint16_t);
- len += sizeof(uint16_t);
-
- switch (input->flow_type) {
- case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
- case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
- /* fill the common ip header */
- ip = (struct ipv4_hdr *)raw_pkt;
- *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
- ip->version_ihl = QEDE_FDIR_IP_DEFAULT_VERSION_IHL;
- ip->total_length = sizeof(struct ipv4_hdr);
- ip->next_proto_id = input->flow.ip4_flow.proto ?
- input->flow.ip4_flow.proto :
- next_proto[input->flow_type];
- ip->time_to_live = input->flow.ip4_flow.ttl ?
- input->flow.ip4_flow.ttl :
- QEDE_FDIR_IPV4_DEF_TTL;
- ip->type_of_service = input->flow.ip4_flow.tos;
- ip->dst_addr = input->flow.ip4_flow.dst_ip;
- ip->src_addr = input->flow.ip4_flow.src_ip;
- len += sizeof(struct ipv4_hdr);
- params->ipv4 = true;
-
- raw_pkt = (uint8_t *)buff;
- /* UDP */
- if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_UDP) {
- udp = (struct udp_hdr *)(raw_pkt + len);
- udp->dst_port = input->flow.udp4_flow.dst_port;
- udp->src_port = input->flow.udp4_flow.src_port;
- udp->dgram_len = sizeof(struct udp_hdr);
- len += sizeof(struct udp_hdr);
- /* adjust ip total_length */
- ip->total_length += sizeof(struct udp_hdr);
- params->udp = true;
- } else { /* TCP */
- tcp = (struct tcp_hdr *)(raw_pkt + len);
- tcp->src_port = input->flow.tcp4_flow.src_port;
- tcp->dst_port = input->flow.tcp4_flow.dst_port;
- tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
- len += sizeof(struct tcp_hdr);
- /* adjust ip total_length */
- ip->total_length += sizeof(struct tcp_hdr);
- params->tcp = true;
- }
- break;
- case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
- case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
- ip6 = (struct ipv6_hdr *)raw_pkt;
- *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
- ip6->proto = input->flow.ipv6_flow.proto ?
- input->flow.ipv6_flow.proto :
- next_proto[input->flow_type];
- rte_memcpy(&ip6->src_addr, &input->flow.ipv6_flow.dst_ip,
- IPV6_ADDR_LEN);
- rte_memcpy(&ip6->dst_addr, &input->flow.ipv6_flow.src_ip,
- IPV6_ADDR_LEN);
- len += sizeof(struct ipv6_hdr);
-
- raw_pkt = (uint8_t *)buff;
- /* UDP */
- if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_UDP) {
- udp = (struct udp_hdr *)(raw_pkt + len);
- udp->src_port = input->flow.udp6_flow.dst_port;
- udp->dst_port = input->flow.udp6_flow.src_port;
- len += sizeof(struct udp_hdr);
- params->udp = true;
- } else { /* TCP */
- tcp = (struct tcp_hdr *)(raw_pkt + len);
- tcp->src_port = input->flow.tcp4_flow.src_port;
- tcp->dst_port = input->flow.tcp4_flow.dst_port;
- tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
- len += sizeof(struct tcp_hdr);
- params->tcp = true;
- }
- break;
- default:
- DP_ERR(edev, "Unsupported flow_type %u\n",
- input->flow_type);
- return 0;
- }
-
- return len;
-}
-
-int
-qede_fdir_filter_conf(struct rte_eth_dev *eth_dev,
- enum rte_filter_op filter_op,
- void *arg)
-{
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
- struct rte_eth_fdir_filter *fdir;
- int ret;
-
- fdir = (struct rte_eth_fdir_filter *)arg;
- switch (filter_op) {
- case RTE_ETH_FILTER_NOP:
- /* Typically used to query flowdir support */
- if (ECORE_IS_CMT(edev)) {
- DP_ERR(edev, "flowdir is not supported in 100G mode\n");
- return -ENOTSUP;
- }
- return 0; /* means supported */
- case RTE_ETH_FILTER_ADD:
- ret = qede_fdir_filter_add(eth_dev, fdir, 1);
- break;
- case RTE_ETH_FILTER_DELETE:
- ret = qede_fdir_filter_add(eth_dev, fdir, 0);
- break;
- case RTE_ETH_FILTER_FLUSH:
- case RTE_ETH_FILTER_UPDATE:
- case RTE_ETH_FILTER_INFO:
- return -ENOTSUP;
- break;
- default:
- DP_ERR(edev, "unknown operation %u", filter_op);
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-int qede_ntuple_filter_conf(struct rte_eth_dev *eth_dev,
- enum rte_filter_op filter_op,
- void *arg)
-{
- struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
- struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
- struct rte_eth_ntuple_filter *ntuple;
- struct rte_eth_fdir_filter fdir_entry;
- struct rte_eth_tcpv4_flow *tcpv4_flow;
- struct rte_eth_udpv4_flow *udpv4_flow;
- bool add = false;
-
- switch (filter_op) {
- case RTE_ETH_FILTER_NOP:
- /* Typically used to query fdir support */
- if (ECORE_IS_CMT(edev)) {
- DP_ERR(edev, "flowdir is not supported in 100G mode\n");
- return -ENOTSUP;
- }
- return 0; /* means supported */
- case RTE_ETH_FILTER_ADD:
- add = true;
- break;
- case RTE_ETH_FILTER_DELETE:
- break;
- case RTE_ETH_FILTER_INFO:
- case RTE_ETH_FILTER_GET:
- case RTE_ETH_FILTER_UPDATE:
- case RTE_ETH_FILTER_FLUSH:
- case RTE_ETH_FILTER_SET:
- case RTE_ETH_FILTER_STATS:
- case RTE_ETH_FILTER_OP_MAX:
- DP_ERR(edev, "Unsupported filter_op %d\n", filter_op);
- return -ENOTSUP;
- }
- ntuple = (struct rte_eth_ntuple_filter *)arg;
- /* Internally convert ntuple to fdir entry */
- memset(&fdir_entry, 0, sizeof(fdir_entry));
- if (ntuple->proto == IPPROTO_TCP) {
- fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
- tcpv4_flow = &fdir_entry.input.flow.tcp4_flow;
- tcpv4_flow->ip.src_ip = ntuple->src_ip;
- tcpv4_flow->ip.dst_ip = ntuple->dst_ip;
- tcpv4_flow->ip.proto = IPPROTO_TCP;
- tcpv4_flow->src_port = ntuple->src_port;
- tcpv4_flow->dst_port = ntuple->dst_port;
- } else {
- fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_UDP;
- udpv4_flow = &fdir_entry.input.flow.udp4_flow;
- udpv4_flow->ip.src_ip = ntuple->src_ip;
- udpv4_flow->ip.dst_ip = ntuple->dst_ip;
- udpv4_flow->ip.proto = IPPROTO_TCP;
- udpv4_flow->src_port = ntuple->src_port;
- udpv4_flow->dst_port = ntuple->dst_port;
- }
-
- fdir_entry.action.rx_queue = ntuple->queue;
-
- return qede_config_cmn_fdir_filter(eth_dev, &fdir_entry, add);
-}