18fb8d68c5d36135eb63604375b69eb42d6bc24e
[dpdk.git] / drivers / net / qede / qede_fdir.c
1 /*
2  * Copyright (c) 2017 QLogic Corporation.
3  * All rights reserved.
4  * www.qlogic.com
5  *
6  * See LICENSE.qede_pmd for copyright and licensing details.
7  */
8
9 #include <rte_udp.h>
10 #include <rte_tcp.h>
11 #include <rte_sctp.h>
12 #include <rte_errno.h>
13
14 #include "qede_ethdev.h"
15
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)
21
22 /* Sum of length of header types of L2, L3, L4.
23  * L2 : ether_hdr + vlan_hdr + vxlan_hdr
24  * L3 : ipv6_hdr
25  * L4 : tcp_hdr
26  */
27 #define QEDE_MAX_FDIR_PKT_LEN                   (86)
28
29 #ifndef IPV6_ADDR_LEN
30 #define IPV6_ADDR_LEN                           (16)
31 #endif
32
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)
38
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.
42  */
43 int qede_check_fdir_support(struct rte_eth_dev *eth_dev)
44 {
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 = &eth_dev->data->dev_conf.fdir_conf;
48
49         /* check FDIR modes */
50         switch (fdir->mode) {
51         case RTE_FDIR_MODE_NONE:
52                 qdev->fdir_info.arfs.arfs_enable = false;
53                 DP_INFO(edev, "flowdir is disabled\n");
54         break;
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;
59                         return -ENOTSUP;
60                 }
61                 qdev->fdir_info.arfs.arfs_enable = true;
62                 DP_INFO(edev, "flowdir is enabled\n");
63         break;
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);
68                 return -ENOTSUP;
69         }
70
71         return 0;
72 }
73
74 void qede_fdir_dealloc_resc(struct rte_eth_dev *eth_dev)
75 {
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;
80
81         SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
82                 if (tmp) {
83                         if (tmp->mz)
84                                 rte_memzone_free(tmp->mz);
85                         SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
86                                      qede_fdir_entry, list);
87                         rte_free(tmp);
88                 }
89         }
90 }
91
92 static int
93 qede_config_cmn_fdir_filter(struct rte_eth_dev *eth_dev,
94                             struct rte_eth_fdir_filter *fdir_filter,
95                             bool add)
96 {
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;
105         uint16_t pkt_len;
106         uint16_t len;
107         void *pkt;
108
109         if (add) {
110                 if (qdev->fdir_info.filter_count == QEDE_RFS_MAX_FLTR - 1) {
111                         DP_ERR(edev, "Reached max flowdir filter limit\n");
112                         return -EINVAL;
113                 }
114                 fdir = rte_malloc(NULL, sizeof(struct qede_fdir_entry),
115                                   RTE_CACHE_LINE_SIZE);
116                 if (!fdir) {
117                         DP_ERR(edev, "Did not allocate memory for fdir\n");
118                         return -ENOMEM;
119                 }
120         }
121         /* soft_id could have been used as memzone string, but soft_id is
122          * not currently used so it has no significance.
123          */
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);
128         if (!mz) {
129                 DP_ERR(edev, "Failed to allocate memzone for fdir, err = %s\n",
130                        rte_strerror(rte_errno));
131                 rc = -rte_errno;
132                 goto err1;
133         }
134
135         pkt = mz->addr;
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);
139         if (pkt_len == 0) {
140                 rc = -EINVAL;
141                 goto err2;
142         }
143         DP_INFO(edev, "pkt_len = %u memzone = %s\n", pkt_len, mz_name);
144         if (add) {
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");
148                                 rc = -EEXIST;
149                                 goto err2;
150                         }
151                 }
152         } else {
153                 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
154                         if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0)
155                                 break;
156                 }
157                 if (!tmp) {
158                         DP_ERR(edev, "flowdir filter does not exist\n");
159                         rc = -EEXIST;
160                         goto err2;
161                 }
162         }
163         p_hwfn = ECORE_LEADING_HWFN(edev);
164         if (add) {
165                 if (!qdev->fdir_info.arfs.arfs_enable) {
166                         /* Force update */
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");
171                 }
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);
175         }
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,
179                                                pkt_len,
180                                                fdir_filter->action.rx_queue,
181                                                0, add);
182         if (rc == ECORE_SUCCESS) {
183                 if (add) {
184                         fdir->rx_queue = fdir_filter->action.rx_queue;
185                         fdir->pkt_len = pkt_len;
186                         fdir->mz = mz;
187                         SLIST_INSERT_HEAD(&qdev->fdir_info.fdir_list_head,
188                                           fdir, list);
189                         qdev->fdir_info.filter_count++;
190                         DP_INFO(edev, "flowdir filter added, count = %d\n",
191                                 qdev->fdir_info.filter_count);
192                 } else {
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);
201                 }
202         } else {
203                 DP_ERR(edev, "flowdir filter failed, rc=%d filter_count=%d\n",
204                        rc, qdev->fdir_info.filter_count);
205         }
206
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);
215         }
216         return 0;
217
218 err2:
219         rte_memzone_free(mz);
220 err1:
221         if (add)
222                 rte_free(fdir);
223         return rc;
224 }
225
226 static int
227 qede_fdir_filter_add(struct rte_eth_dev *eth_dev,
228                      struct rte_eth_fdir_filter *fdir,
229                      bool add)
230 {
231         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
232         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
233
234         if (!QEDE_VALID_FLOW(fdir->input.flow_type)) {
235                 DP_ERR(edev, "invalid flow_type input\n");
236                 return -EINVAL;
237         }
238
239         if (fdir->action.rx_queue >= QEDE_RSS_COUNT(qdev)) {
240                 DP_ERR(edev, "invalid queue number %u\n",
241                        fdir->action.rx_queue);
242                 return -EINVAL;
243         }
244
245         if (fdir->input.flow_ext.is_vf) {
246                 DP_ERR(edev, "flowdir is not supported over VF\n");
247                 return -EINVAL;
248         }
249
250         return qede_config_cmn_fdir_filter(eth_dev, fdir, add);
251 }
252
253 /* Fills the L3/L4 headers and returns the actual length  of flowdir packet */
254 static uint16_t
255 qede_fdir_construct_pkt(struct rte_eth_dev *eth_dev,
256                         struct rte_eth_fdir_filter *fdir,
257                         void *buff,
258                         struct ecore_arfs_config_params *params)
259
260 {
261         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
262         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
263         uint16_t *ether_type;
264         uint8_t *raw_pkt;
265         struct rte_eth_fdir_input *input;
266         static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
267         struct ipv4_hdr *ip;
268         struct ipv6_hdr *ip6;
269         struct udp_hdr *udp;
270         struct tcp_hdr *tcp;
271         struct sctp_hdr *sctp;
272         uint8_t size, dst = 0;
273         uint16_t len;
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,
279         };
280         raw_pkt = (uint8_t *)buff;
281         input = &fdir->input;
282         DP_INFO(edev, "flow_type %d\n", input->flow_type);
283
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,
291                            sizeof(uint16_t));
292                 raw_pkt += sizeof(vlan_frame);
293                 len += sizeof(vlan_frame);
294         }
295         ether_type = (uint16_t *)raw_pkt;
296         raw_pkt += sizeof(uint16_t);
297         len += sizeof(uint16_t);
298
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);
317                 params->ipv4 = true;
318
319                 raw_pkt = (uint8_t *)buff;
320                 /* UDP */
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);
329                         params->udp = true;
330                 } else { /* TCP */
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);
338                         params->tcp = true;
339                 }
340                 break;
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,
349                            IPV6_ADDR_LEN);
350                 rte_memcpy(&ip6->dst_addr, &input->flow.ipv6_flow.src_ip,
351                            IPV6_ADDR_LEN);
352                 len += sizeof(struct ipv6_hdr);
353
354                 raw_pkt = (uint8_t *)buff;
355                 /* UDP */
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);
361                         params->udp = true;
362                 } else { /* TCP */
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);
368                         params->tcp = true;
369                 }
370                 break;
371         default:
372                 DP_ERR(edev, "Unsupported flow_type %u\n",
373                        input->flow_type);
374                 return 0;
375         }
376
377         return len;
378 }
379
380 int
381 qede_fdir_filter_conf(struct rte_eth_dev *eth_dev,
382                       enum rte_filter_op filter_op,
383                       void *arg)
384 {
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;
388         int ret;
389
390         fdir = (struct rte_eth_fdir_filter *)arg;
391         switch (filter_op) {
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");
396                         return -ENOTSUP;
397                 }
398                 return 0; /* means supported */
399         case RTE_ETH_FILTER_ADD:
400                 ret = qede_fdir_filter_add(eth_dev, fdir, 1);
401         break;
402         case RTE_ETH_FILTER_DELETE:
403                 ret = qede_fdir_filter_add(eth_dev, fdir, 0);
404         break;
405         case RTE_ETH_FILTER_FLUSH:
406         case RTE_ETH_FILTER_UPDATE:
407         case RTE_ETH_FILTER_INFO:
408                 return -ENOTSUP;
409         break;
410         default:
411                 DP_ERR(edev, "unknown operation %u", filter_op);
412                 ret = -EINVAL;
413         }
414
415         return ret;
416 }
417
418 int qede_ntuple_filter_conf(struct rte_eth_dev *eth_dev,
419                             enum rte_filter_op filter_op,
420                             void *arg)
421 {
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;
429         bool add;
430
431         switch (filter_op) {
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");
436                         return -ENOTSUP;
437                 }
438                 return 0; /* means supported */
439         case RTE_ETH_FILTER_ADD:
440                 add = true;
441         break;
442         case RTE_ETH_FILTER_DELETE:
443                 add = false;
444         break;
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);
453                 return -ENOTSUP;
454         }
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;
466         } else {
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;
474         }
475         return qede_config_cmn_fdir_filter(eth_dev, &fdir_entry, add);
476 }