diff options
Diffstat (limited to 'drivers/net/qede/qede_fdir.c')
-rw-r--r-- | drivers/net/qede/qede_fdir.c | 470 |
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 = ð_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); -} |