2 * Copyright (c) 2017 QLogic Corporation.
6 * See LICENSE.qede_pmd for copyright and licensing details.
12 #include <rte_errno.h>
14 #include "qede_ethdev.h"
16 #define IP_VERSION (0x40)
17 #define IP_HDRLEN (0x5)
18 #define QEDE_FDIR_IP_DEFAULT_VERSION_IHL (IP_VERSION | IP_HDRLEN)
19 #define QEDE_FDIR_TCP_DEFAULT_DATAOFF (0x50)
20 #define QEDE_FDIR_IPV4_DEF_TTL (64)
22 /* Sum of length of header types of L2, L3, L4.
23 * L2 : ether_hdr + vlan_hdr + vxlan_hdr
27 #define QEDE_MAX_FDIR_PKT_LEN (86)
30 #define IPV6_ADDR_LEN (16)
33 #define QEDE_VALID_FLOW(flow_type) \
34 ((flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP || \
35 (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_UDP || \
36 (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_TCP || \
37 (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_UDP)
39 /* Note: Flowdir support is only partial.
40 * For ex: drop_queue, FDIR masks, flex_conf are not supported.
41 * Parameters like pballoc/status fields are irrelevant here.
43 int qede_check_fdir_support(struct rte_eth_dev *eth_dev)
45 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
46 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
47 struct rte_fdir_conf *fdir = ð_dev->data->dev_conf.fdir_conf;
49 /* check FDIR modes */
51 case RTE_FDIR_MODE_NONE:
52 qdev->fdir_info.arfs.arfs_enable = false;
53 DP_INFO(edev, "flowdir is disabled\n");
55 case RTE_FDIR_MODE_PERFECT:
56 if (edev->num_hwfns > 1) {
57 DP_ERR(edev, "flowdir is not supported in 100G mode\n");
58 qdev->fdir_info.arfs.arfs_enable = false;
61 qdev->fdir_info.arfs.arfs_enable = true;
62 DP_INFO(edev, "flowdir is enabled\n");
64 case RTE_FDIR_MODE_PERFECT_TUNNEL:
65 case RTE_FDIR_MODE_SIGNATURE:
66 case RTE_FDIR_MODE_PERFECT_MAC_VLAN:
67 DP_ERR(edev, "Unsupported flowdir mode %d\n", fdir->mode);
74 void qede_fdir_dealloc_resc(struct rte_eth_dev *eth_dev)
76 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
77 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
78 struct qede_fdir_entry *tmp = NULL;
79 struct qede_fdir_entry *fdir;
81 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
84 rte_memzone_free(tmp->mz);
85 SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
86 qede_fdir_entry, list);
93 qede_config_cmn_fdir_filter(struct rte_eth_dev *eth_dev,
94 struct rte_eth_fdir_filter *fdir_filter,
97 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
98 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
99 char mz_name[RTE_MEMZONE_NAMESIZE] = {0};
100 struct qede_fdir_entry *tmp = NULL;
101 struct qede_fdir_entry *fdir;
102 const struct rte_memzone *mz;
103 struct ecore_hwfn *p_hwfn;
104 enum _ecore_status_t rc;
110 if (qdev->fdir_info.filter_count == QEDE_RFS_MAX_FLTR - 1) {
111 DP_ERR(edev, "Reached max flowdir filter limit\n");
114 fdir = rte_malloc(NULL, sizeof(struct qede_fdir_entry),
115 RTE_CACHE_LINE_SIZE);
117 DP_ERR(edev, "Did not allocate memory for fdir\n");
121 /* soft_id could have been used as memzone string, but soft_id is
122 * not currently used so it has no significance.
124 snprintf(mz_name, sizeof(mz_name) - 1, "%lx",
125 (unsigned long)rte_get_timer_cycles());
126 mz = rte_memzone_reserve_aligned(mz_name, QEDE_MAX_FDIR_PKT_LEN,
127 SOCKET_ID_ANY, 0, RTE_CACHE_LINE_SIZE);
129 DP_ERR(edev, "Failed to allocate memzone for fdir, err = %s\n",
130 rte_strerror(rte_errno));
136 memset(pkt, 0, QEDE_MAX_FDIR_PKT_LEN);
137 pkt_len = qede_fdir_construct_pkt(eth_dev, fdir_filter, pkt,
138 &qdev->fdir_info.arfs);
143 DP_INFO(edev, "pkt_len = %u memzone = %s\n", pkt_len, mz_name);
145 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
146 if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0) {
147 DP_ERR(edev, "flowdir filter exist\n");
153 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
154 if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0)
158 DP_ERR(edev, "flowdir filter does not exist\n");
163 p_hwfn = ECORE_LEADING_HWFN(edev);
165 if (!qdev->fdir_info.arfs.arfs_enable) {
167 eth_dev->data->dev_conf.fdir_conf.mode =
168 RTE_FDIR_MODE_PERFECT;
169 qdev->fdir_info.arfs.arfs_enable = true;
170 DP_INFO(edev, "Force enable flowdir in perfect mode\n");
172 /* Enable ARFS searcher with updated flow_types */
173 ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
174 &qdev->fdir_info.arfs);
176 /* configure filter with ECORE_SPQ_MODE_EBLOCK */
177 rc = ecore_configure_rfs_ntuple_filter(p_hwfn, p_hwfn->p_arfs_ptt, NULL,
178 (dma_addr_t)mz->phys_addr,
180 fdir_filter->action.rx_queue,
182 if (rc == ECORE_SUCCESS) {
184 fdir->rx_queue = fdir_filter->action.rx_queue;
185 fdir->pkt_len = pkt_len;
187 SLIST_INSERT_HEAD(&qdev->fdir_info.fdir_list_head,
189 qdev->fdir_info.filter_count++;
190 DP_INFO(edev, "flowdir filter added, count = %d\n",
191 qdev->fdir_info.filter_count);
193 rte_memzone_free(tmp->mz);
194 SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
195 qede_fdir_entry, list);
196 rte_free(tmp); /* the node deleted */
197 rte_memzone_free(mz); /* temp node allocated */
198 qdev->fdir_info.filter_count--;
199 DP_INFO(edev, "Fdir filter deleted, count = %d\n",
200 qdev->fdir_info.filter_count);
203 DP_ERR(edev, "flowdir filter failed, rc=%d filter_count=%d\n",
204 rc, qdev->fdir_info.filter_count);
207 /* Disable ARFS searcher if there are no more filters */
208 if (qdev->fdir_info.filter_count == 0) {
209 memset(&qdev->fdir_info.arfs, 0,
210 sizeof(struct ecore_arfs_config_params));
211 DP_INFO(edev, "Disabling flowdir\n");
212 qdev->fdir_info.arfs.arfs_enable = false;
213 ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
214 &qdev->fdir_info.arfs);
219 rte_memzone_free(mz);
227 qede_fdir_filter_add(struct rte_eth_dev *eth_dev,
228 struct rte_eth_fdir_filter *fdir,
231 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
232 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
234 if (!QEDE_VALID_FLOW(fdir->input.flow_type)) {
235 DP_ERR(edev, "invalid flow_type input\n");
239 if (fdir->action.rx_queue >= QEDE_RSS_COUNT(qdev)) {
240 DP_ERR(edev, "invalid queue number %u\n",
241 fdir->action.rx_queue);
245 if (fdir->input.flow_ext.is_vf) {
246 DP_ERR(edev, "flowdir is not supported over VF\n");
250 return qede_config_cmn_fdir_filter(eth_dev, fdir, add);
253 /* Fills the L3/L4 headers and returns the actual length of flowdir packet */
255 qede_fdir_construct_pkt(struct rte_eth_dev *eth_dev,
256 struct rte_eth_fdir_filter *fdir,
258 struct ecore_arfs_config_params *params)
261 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
262 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
263 uint16_t *ether_type;
265 struct rte_eth_fdir_input *input;
266 static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
268 struct ipv6_hdr *ip6;
271 struct sctp_hdr *sctp;
272 uint8_t size, dst = 0;
274 static const uint8_t next_proto[] = {
275 [RTE_ETH_FLOW_NONFRAG_IPV4_TCP] = IPPROTO_TCP,
276 [RTE_ETH_FLOW_NONFRAG_IPV4_UDP] = IPPROTO_UDP,
277 [RTE_ETH_FLOW_NONFRAG_IPV6_TCP] = IPPROTO_TCP,
278 [RTE_ETH_FLOW_NONFRAG_IPV6_UDP] = IPPROTO_UDP,
280 raw_pkt = (uint8_t *)buff;
281 input = &fdir->input;
282 DP_INFO(edev, "flow_type %d\n", input->flow_type);
284 len = 2 * sizeof(struct ether_addr);
285 raw_pkt += 2 * sizeof(struct ether_addr);
286 if (input->flow_ext.vlan_tci) {
287 DP_INFO(edev, "adding VLAN header\n");
288 rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame));
289 rte_memcpy(raw_pkt + sizeof(uint16_t),
290 &input->flow_ext.vlan_tci,
292 raw_pkt += sizeof(vlan_frame);
293 len += sizeof(vlan_frame);
295 ether_type = (uint16_t *)raw_pkt;
296 raw_pkt += sizeof(uint16_t);
297 len += sizeof(uint16_t);
299 switch (input->flow_type) {
300 case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
301 case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
302 /* fill the common ip header */
303 ip = (struct ipv4_hdr *)raw_pkt;
304 *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
305 ip->version_ihl = QEDE_FDIR_IP_DEFAULT_VERSION_IHL;
306 ip->total_length = sizeof(struct ipv4_hdr);
307 ip->next_proto_id = input->flow.ip4_flow.proto ?
308 input->flow.ip4_flow.proto :
309 next_proto[input->flow_type];
310 ip->time_to_live = input->flow.ip4_flow.ttl ?
311 input->flow.ip4_flow.ttl :
312 QEDE_FDIR_IPV4_DEF_TTL;
313 ip->type_of_service = input->flow.ip4_flow.tos;
314 ip->dst_addr = input->flow.ip4_flow.dst_ip;
315 ip->src_addr = input->flow.ip4_flow.src_ip;
316 len += sizeof(struct ipv4_hdr);
319 raw_pkt = (uint8_t *)buff;
321 if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_UDP) {
322 udp = (struct udp_hdr *)(raw_pkt + len);
323 udp->dst_port = input->flow.udp4_flow.dst_port;
324 udp->src_port = input->flow.udp4_flow.src_port;
325 udp->dgram_len = sizeof(struct udp_hdr);
326 len += sizeof(struct udp_hdr);
327 /* adjust ip total_length */
328 ip->total_length += sizeof(struct udp_hdr);
331 tcp = (struct tcp_hdr *)(raw_pkt + len);
332 tcp->src_port = input->flow.tcp4_flow.src_port;
333 tcp->dst_port = input->flow.tcp4_flow.dst_port;
334 tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
335 len += sizeof(struct tcp_hdr);
336 /* adjust ip total_length */
337 ip->total_length += sizeof(struct tcp_hdr);
341 case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
342 case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
343 ip6 = (struct ipv6_hdr *)raw_pkt;
344 *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
345 ip6->proto = input->flow.ipv6_flow.proto ?
346 input->flow.ipv6_flow.proto :
347 next_proto[input->flow_type];
348 rte_memcpy(&ip6->src_addr, &input->flow.ipv6_flow.dst_ip,
350 rte_memcpy(&ip6->dst_addr, &input->flow.ipv6_flow.src_ip,
352 len += sizeof(struct ipv6_hdr);
354 raw_pkt = (uint8_t *)buff;
356 if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_UDP) {
357 udp = (struct udp_hdr *)(raw_pkt + len);
358 udp->src_port = input->flow.udp6_flow.dst_port;
359 udp->dst_port = input->flow.udp6_flow.src_port;
360 len += sizeof(struct udp_hdr);
363 tcp = (struct tcp_hdr *)(raw_pkt + len);
364 tcp->src_port = input->flow.tcp4_flow.src_port;
365 tcp->dst_port = input->flow.tcp4_flow.dst_port;
366 tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
367 len += sizeof(struct tcp_hdr);
372 DP_ERR(edev, "Unsupported flow_type %u\n",
381 qede_fdir_filter_conf(struct rte_eth_dev *eth_dev,
382 enum rte_filter_op filter_op,
385 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
386 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
387 struct rte_eth_fdir_filter *fdir;
390 fdir = (struct rte_eth_fdir_filter *)arg;
392 case RTE_ETH_FILTER_NOP:
393 /* Typically used to query flowdir support */
394 if (edev->num_hwfns > 1) {
395 DP_ERR(edev, "flowdir is not supported in 100G mode\n");
398 return 0; /* means supported */
399 case RTE_ETH_FILTER_ADD:
400 ret = qede_fdir_filter_add(eth_dev, fdir, 1);
402 case RTE_ETH_FILTER_DELETE:
403 ret = qede_fdir_filter_add(eth_dev, fdir, 0);
405 case RTE_ETH_FILTER_FLUSH:
406 case RTE_ETH_FILTER_UPDATE:
407 case RTE_ETH_FILTER_INFO:
411 DP_ERR(edev, "unknown operation %u", filter_op);
418 int qede_ntuple_filter_conf(struct rte_eth_dev *eth_dev,
419 enum rte_filter_op filter_op,
422 struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
423 struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
424 struct rte_eth_ntuple_filter *ntuple;
425 struct rte_eth_fdir_filter fdir_entry;
426 struct rte_eth_tcpv4_flow *tcpv4_flow;
427 struct rte_eth_udpv4_flow *udpv4_flow;
428 struct ecore_hwfn *p_hwfn;
432 case RTE_ETH_FILTER_NOP:
433 /* Typically used to query fdir support */
434 if (edev->num_hwfns > 1) {
435 DP_ERR(edev, "flowdir is not supported in 100G mode\n");
438 return 0; /* means supported */
439 case RTE_ETH_FILTER_ADD:
442 case RTE_ETH_FILTER_DELETE:
445 case RTE_ETH_FILTER_INFO:
446 case RTE_ETH_FILTER_GET:
447 case RTE_ETH_FILTER_UPDATE:
448 case RTE_ETH_FILTER_FLUSH:
449 case RTE_ETH_FILTER_SET:
450 case RTE_ETH_FILTER_STATS:
451 case RTE_ETH_FILTER_OP_MAX:
452 DP_ERR(edev, "Unsupported filter_op %d\n", filter_op);
455 ntuple = (struct rte_eth_ntuple_filter *)arg;
456 /* Internally convert ntuple to fdir entry */
457 memset(&fdir_entry, 0, sizeof(fdir_entry));
458 if (ntuple->proto == IPPROTO_TCP) {
459 fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
460 tcpv4_flow = &fdir_entry.input.flow.tcp4_flow;
461 tcpv4_flow->ip.src_ip = ntuple->src_ip;
462 tcpv4_flow->ip.dst_ip = ntuple->dst_ip;
463 tcpv4_flow->ip.proto = IPPROTO_TCP;
464 tcpv4_flow->src_port = ntuple->src_port;
465 tcpv4_flow->dst_port = ntuple->dst_port;
467 fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_UDP;
468 udpv4_flow = &fdir_entry.input.flow.udp4_flow;
469 udpv4_flow->ip.src_ip = ntuple->src_ip;
470 udpv4_flow->ip.dst_ip = ntuple->dst_ip;
471 udpv4_flow->ip.proto = IPPROTO_TCP;
472 udpv4_flow->src_port = ntuple->src_port;
473 udpv4_flow->dst_port = ntuple->dst_port;
475 return qede_config_cmn_fdir_filter(eth_dev, &fdir_entry, add);