New upstream version 17.11.5
[deb_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 #define QEDE_FDIR_IPV6_DEFAULT_VTC_FLOW         (0x60000000)
22
23 /* Sum of length of header types of L2, L3, L4.
24  * L2 : ether_hdr + vlan_hdr + vxlan_hdr
25  * L3 : ipv6_hdr
26  * L4 : tcp_hdr
27  */
28 #define QEDE_MAX_FDIR_PKT_LEN                   (86)
29
30 #ifndef IPV6_ADDR_LEN
31 #define IPV6_ADDR_LEN                           (16)
32 #endif
33
34 #define QEDE_VALID_FLOW(flow_type) \
35         ((flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_TCP   || \
36         (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV4_UDP    || \
37         (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_TCP    || \
38         (flow_type) == RTE_ETH_FLOW_NONFRAG_IPV6_UDP)
39
40 /* Note: Flowdir support is only partial.
41  * For ex: drop_queue, FDIR masks, flex_conf are not supported.
42  * Parameters like pballoc/status fields are irrelevant here.
43  */
44 int qede_check_fdir_support(struct rte_eth_dev *eth_dev)
45 {
46         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
47         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
48         struct rte_fdir_conf *fdir = &eth_dev->data->dev_conf.fdir_conf;
49
50         /* check FDIR modes */
51         switch (fdir->mode) {
52         case RTE_FDIR_MODE_NONE:
53                 qdev->fdir_info.arfs.arfs_enable = false;
54                 DP_INFO(edev, "flowdir is disabled\n");
55         break;
56         case RTE_FDIR_MODE_PERFECT:
57                 if (ECORE_IS_CMT(edev)) {
58                         DP_ERR(edev, "flowdir is not supported in 100G mode\n");
59                         qdev->fdir_info.arfs.arfs_enable = false;
60                         return -ENOTSUP;
61                 }
62                 qdev->fdir_info.arfs.arfs_enable = true;
63                 DP_INFO(edev, "flowdir is enabled\n");
64         break;
65         case RTE_FDIR_MODE_PERFECT_TUNNEL:
66         case RTE_FDIR_MODE_SIGNATURE:
67         case RTE_FDIR_MODE_PERFECT_MAC_VLAN:
68                 DP_ERR(edev, "Unsupported flowdir mode %d\n", fdir->mode);
69                 return -ENOTSUP;
70         }
71
72         return 0;
73 }
74
75 void qede_fdir_dealloc_resc(struct rte_eth_dev *eth_dev)
76 {
77         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
78         struct qede_fdir_entry *tmp = NULL;
79
80         SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
81                 if (tmp) {
82                         if (tmp->mz)
83                                 rte_memzone_free(tmp->mz);
84                         SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
85                                      qede_fdir_entry, list);
86                         rte_free(tmp);
87                 }
88         }
89 }
90
91 static int
92 qede_config_cmn_fdir_filter(struct rte_eth_dev *eth_dev,
93                             struct rte_eth_fdir_filter *fdir_filter,
94                             bool add)
95 {
96         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
97         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
98         char mz_name[RTE_MEMZONE_NAMESIZE] = {0};
99         struct qede_fdir_entry *tmp = NULL;
100         struct qede_fdir_entry *fdir = NULL;
101         const struct rte_memzone *mz;
102         struct ecore_hwfn *p_hwfn;
103         enum _ecore_status_t rc;
104         uint16_t pkt_len;
105         void *pkt;
106
107         if (add) {
108                 if (qdev->fdir_info.filter_count == QEDE_RFS_MAX_FLTR - 1) {
109                         DP_ERR(edev, "Reached max flowdir filter limit\n");
110                         return -EINVAL;
111                 }
112                 fdir = rte_malloc(NULL, sizeof(struct qede_fdir_entry),
113                                   RTE_CACHE_LINE_SIZE);
114                 if (!fdir) {
115                         DP_ERR(edev, "Did not allocate memory for fdir\n");
116                         return -ENOMEM;
117                 }
118         }
119         /* soft_id could have been used as memzone string, but soft_id is
120          * not currently used so it has no significance.
121          */
122         snprintf(mz_name, sizeof(mz_name) - 1, "%lx",
123                  (unsigned long)rte_get_timer_cycles());
124         mz = rte_memzone_reserve_aligned(mz_name, QEDE_MAX_FDIR_PKT_LEN,
125                                          SOCKET_ID_ANY, 0, RTE_CACHE_LINE_SIZE);
126         if (!mz) {
127                 DP_ERR(edev, "Failed to allocate memzone for fdir, err = %s\n",
128                        rte_strerror(rte_errno));
129                 rc = -rte_errno;
130                 goto err1;
131         }
132
133         pkt = mz->addr;
134         memset(pkt, 0, QEDE_MAX_FDIR_PKT_LEN);
135         pkt_len = qede_fdir_construct_pkt(eth_dev, fdir_filter, pkt,
136                                           &qdev->fdir_info.arfs);
137         if (pkt_len == 0) {
138                 rc = -EINVAL;
139                 goto err2;
140         }
141         DP_INFO(edev, "pkt_len = %u memzone = %s\n", pkt_len, mz_name);
142         if (add) {
143                 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
144                         if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0) {
145                                 DP_INFO(edev, "flowdir filter exist\n");
146                                 rc = 0;
147                                 goto err2;
148                         }
149                 }
150         } else {
151                 SLIST_FOREACH(tmp, &qdev->fdir_info.fdir_list_head, list) {
152                         if (memcmp(tmp->mz->addr, pkt, pkt_len) == 0)
153                                 break;
154                 }
155                 if (!tmp) {
156                         DP_ERR(edev, "flowdir filter does not exist\n");
157                         rc = -EEXIST;
158                         goto err2;
159                 }
160         }
161         p_hwfn = ECORE_LEADING_HWFN(edev);
162         if (add) {
163                 if (!qdev->fdir_info.arfs.arfs_enable) {
164                         /* Force update */
165                         eth_dev->data->dev_conf.fdir_conf.mode =
166                                                 RTE_FDIR_MODE_PERFECT;
167                         qdev->fdir_info.arfs.arfs_enable = true;
168                         DP_INFO(edev, "Force enable flowdir in perfect mode\n");
169                 }
170                 /* Enable ARFS searcher with updated flow_types */
171                 ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
172                                           &qdev->fdir_info.arfs);
173         }
174         /* configure filter with ECORE_SPQ_MODE_EBLOCK */
175         rc = ecore_configure_rfs_ntuple_filter(p_hwfn, NULL,
176                                                (dma_addr_t)mz->iova,
177                                                pkt_len,
178                                                fdir_filter->action.rx_queue,
179                                                0, add);
180         if (rc == ECORE_SUCCESS) {
181                 if (add) {
182                         fdir->rx_queue = fdir_filter->action.rx_queue;
183                         fdir->pkt_len = pkt_len;
184                         fdir->mz = mz;
185                         SLIST_INSERT_HEAD(&qdev->fdir_info.fdir_list_head,
186                                           fdir, list);
187                         qdev->fdir_info.filter_count++;
188                         DP_INFO(edev, "flowdir filter added, count = %d\n",
189                                 qdev->fdir_info.filter_count);
190                 } else {
191                         rte_memzone_free(tmp->mz);
192                         SLIST_REMOVE(&qdev->fdir_info.fdir_list_head, tmp,
193                                      qede_fdir_entry, list);
194                         rte_free(tmp); /* the node deleted */
195                         rte_memzone_free(mz); /* temp node allocated */
196                         qdev->fdir_info.filter_count--;
197                         DP_INFO(edev, "Fdir filter deleted, count = %d\n",
198                                 qdev->fdir_info.filter_count);
199                 }
200         } else {
201                 DP_ERR(edev, "flowdir filter failed, rc=%d filter_count=%d\n",
202                        rc, qdev->fdir_info.filter_count);
203         }
204
205         /* Disable ARFS searcher if there are no more filters */
206         if (qdev->fdir_info.filter_count == 0) {
207                 memset(&qdev->fdir_info.arfs, 0,
208                        sizeof(struct ecore_arfs_config_params));
209                 DP_INFO(edev, "Disabling flowdir\n");
210                 qdev->fdir_info.arfs.arfs_enable = false;
211                 ecore_arfs_mode_configure(p_hwfn, p_hwfn->p_arfs_ptt,
212                                           &qdev->fdir_info.arfs);
213         }
214         return 0;
215
216 err2:
217         rte_memzone_free(mz);
218 err1:
219         if (add)
220                 rte_free(fdir);
221         return rc;
222 }
223
224 static int
225 qede_fdir_filter_add(struct rte_eth_dev *eth_dev,
226                      struct rte_eth_fdir_filter *fdir,
227                      bool add)
228 {
229         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
230         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
231
232         if (!QEDE_VALID_FLOW(fdir->input.flow_type)) {
233                 DP_ERR(edev, "invalid flow_type input\n");
234                 return -EINVAL;
235         }
236
237         if (fdir->action.rx_queue >= QEDE_RSS_COUNT(qdev)) {
238                 DP_ERR(edev, "invalid queue number %u\n",
239                        fdir->action.rx_queue);
240                 return -EINVAL;
241         }
242
243         if (fdir->input.flow_ext.is_vf) {
244                 DP_ERR(edev, "flowdir is not supported over VF\n");
245                 return -EINVAL;
246         }
247
248         return qede_config_cmn_fdir_filter(eth_dev, fdir, add);
249 }
250
251 /* Fills the L3/L4 headers and returns the actual length  of flowdir packet */
252 uint16_t
253 qede_fdir_construct_pkt(struct rte_eth_dev *eth_dev,
254                         struct rte_eth_fdir_filter *fdir,
255                         void *buff,
256                         struct ecore_arfs_config_params *params)
257
258 {
259         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
260         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
261         uint16_t *ether_type;
262         uint8_t *raw_pkt;
263         struct rte_eth_fdir_input *input;
264         static uint8_t vlan_frame[] = {0x81, 0, 0, 0};
265         struct ipv4_hdr *ip;
266         struct ipv6_hdr *ip6;
267         struct udp_hdr *udp;
268         struct tcp_hdr *tcp;
269         uint16_t len;
270         static const uint8_t next_proto[] = {
271                 [RTE_ETH_FLOW_NONFRAG_IPV4_TCP] = IPPROTO_TCP,
272                 [RTE_ETH_FLOW_NONFRAG_IPV4_UDP] = IPPROTO_UDP,
273                 [RTE_ETH_FLOW_NONFRAG_IPV6_TCP] = IPPROTO_TCP,
274                 [RTE_ETH_FLOW_NONFRAG_IPV6_UDP] = IPPROTO_UDP,
275         };
276         raw_pkt = (uint8_t *)buff;
277         input = &fdir->input;
278         DP_INFO(edev, "flow_type %d\n", input->flow_type);
279
280         len =  2 * sizeof(struct ether_addr);
281         raw_pkt += 2 * sizeof(struct ether_addr);
282         if (input->flow_ext.vlan_tci) {
283                 DP_INFO(edev, "adding VLAN header\n");
284                 rte_memcpy(raw_pkt, vlan_frame, sizeof(vlan_frame));
285                 rte_memcpy(raw_pkt + sizeof(uint16_t),
286                            &input->flow_ext.vlan_tci,
287                            sizeof(uint16_t));
288                 raw_pkt += sizeof(vlan_frame);
289                 len += sizeof(vlan_frame);
290         }
291         ether_type = (uint16_t *)raw_pkt;
292         raw_pkt += sizeof(uint16_t);
293         len += sizeof(uint16_t);
294
295         switch (input->flow_type) {
296         case RTE_ETH_FLOW_NONFRAG_IPV4_TCP:
297         case RTE_ETH_FLOW_NONFRAG_IPV4_UDP:
298                 /* fill the common ip header */
299                 ip = (struct ipv4_hdr *)raw_pkt;
300                 *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
301                 ip->version_ihl = QEDE_FDIR_IP_DEFAULT_VERSION_IHL;
302                 ip->total_length = sizeof(struct ipv4_hdr);
303                 ip->next_proto_id = input->flow.ip4_flow.proto ?
304                                     input->flow.ip4_flow.proto :
305                                     next_proto[input->flow_type];
306                 ip->time_to_live = input->flow.ip4_flow.ttl ?
307                                    input->flow.ip4_flow.ttl :
308                                    QEDE_FDIR_IPV4_DEF_TTL;
309                 ip->type_of_service = input->flow.ip4_flow.tos;
310                 ip->dst_addr = input->flow.ip4_flow.dst_ip;
311                 ip->src_addr = input->flow.ip4_flow.src_ip;
312                 len += sizeof(struct ipv4_hdr);
313                 params->ipv4 = true;
314
315                 raw_pkt = (uint8_t *)buff;
316                 /* UDP */
317                 if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV4_UDP) {
318                         udp = (struct udp_hdr *)(raw_pkt + len);
319                         udp->dst_port = input->flow.udp4_flow.dst_port;
320                         udp->src_port = input->flow.udp4_flow.src_port;
321                         udp->dgram_len = sizeof(struct udp_hdr);
322                         len += sizeof(struct udp_hdr);
323                         /* adjust ip total_length */
324                         ip->total_length += sizeof(struct udp_hdr);
325                         params->udp = true;
326                 } else { /* TCP */
327                         tcp = (struct tcp_hdr *)(raw_pkt + len);
328                         tcp->src_port = input->flow.tcp4_flow.src_port;
329                         tcp->dst_port = input->flow.tcp4_flow.dst_port;
330                         tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
331                         len += sizeof(struct tcp_hdr);
332                         /* adjust ip total_length */
333                         ip->total_length += sizeof(struct tcp_hdr);
334                         params->tcp = true;
335                 }
336                 break;
337         case RTE_ETH_FLOW_NONFRAG_IPV6_TCP:
338         case RTE_ETH_FLOW_NONFRAG_IPV6_UDP:
339                 ip6 = (struct ipv6_hdr *)raw_pkt;
340                 *ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv6);
341                 ip6->proto = input->flow.ipv6_flow.proto ?
342                                         input->flow.ipv6_flow.proto :
343                                         next_proto[input->flow_type];
344                 ip6->vtc_flow =
345                         rte_cpu_to_be_32(QEDE_FDIR_IPV6_DEFAULT_VTC_FLOW);
346                 rte_memcpy(&ip6->src_addr, &input->flow.ipv6_flow.src_ip,
347                            IPV6_ADDR_LEN);
348                 rte_memcpy(&ip6->dst_addr, &input->flow.ipv6_flow.dst_ip,
349                            IPV6_ADDR_LEN);
350                 len += sizeof(struct ipv6_hdr);
351                 params->ipv6 = true;
352
353                 raw_pkt = (uint8_t *)buff;
354                 /* UDP */
355                 if (input->flow_type == RTE_ETH_FLOW_NONFRAG_IPV6_UDP) {
356                         udp = (struct udp_hdr *)(raw_pkt + len);
357                         udp->src_port = input->flow.udp6_flow.src_port;
358                         udp->dst_port = input->flow.udp6_flow.dst_port;
359                         len += sizeof(struct udp_hdr);
360                         params->udp = true;
361                 } else { /* TCP */
362                         tcp = (struct tcp_hdr *)(raw_pkt + len);
363                         tcp->src_port = input->flow.tcp4_flow.src_port;
364                         tcp->dst_port = input->flow.tcp4_flow.dst_port;
365                         tcp->data_off = QEDE_FDIR_TCP_DEFAULT_DATAOFF;
366                         len += sizeof(struct tcp_hdr);
367                         params->tcp = true;
368                 }
369                 break;
370         default:
371                 DP_ERR(edev, "Unsupported flow_type %u\n",
372                        input->flow_type);
373                 return 0;
374         }
375
376         return len;
377 }
378
379 int
380 qede_fdir_filter_conf(struct rte_eth_dev *eth_dev,
381                       enum rte_filter_op filter_op,
382                       void *arg)
383 {
384         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
385         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
386         struct rte_eth_fdir_filter *fdir;
387         int ret;
388
389         fdir = (struct rte_eth_fdir_filter *)arg;
390         switch (filter_op) {
391         case RTE_ETH_FILTER_NOP:
392                 /* Typically used to query flowdir support */
393                 if (ECORE_IS_CMT(edev)) {
394                         DP_ERR(edev, "flowdir is not supported in 100G mode\n");
395                         return -ENOTSUP;
396                 }
397                 return 0; /* means supported */
398         case RTE_ETH_FILTER_ADD:
399                 ret = qede_fdir_filter_add(eth_dev, fdir, 1);
400         break;
401         case RTE_ETH_FILTER_DELETE:
402                 ret = qede_fdir_filter_add(eth_dev, fdir, 0);
403         break;
404         case RTE_ETH_FILTER_FLUSH:
405         case RTE_ETH_FILTER_UPDATE:
406         case RTE_ETH_FILTER_INFO:
407                 return -ENOTSUP;
408         break;
409         default:
410                 DP_ERR(edev, "unknown operation %u", filter_op);
411                 ret = -EINVAL;
412         }
413
414         return ret;
415 }
416
417 int qede_ntuple_filter_conf(struct rte_eth_dev *eth_dev,
418                             enum rte_filter_op filter_op,
419                             void *arg)
420 {
421         struct qede_dev *qdev = QEDE_INIT_QDEV(eth_dev);
422         struct ecore_dev *edev = QEDE_INIT_EDEV(qdev);
423         struct rte_eth_ntuple_filter *ntuple;
424         struct rte_eth_fdir_filter fdir_entry;
425         struct rte_eth_tcpv4_flow *tcpv4_flow;
426         struct rte_eth_udpv4_flow *udpv4_flow;
427         bool add = false;
428
429         switch (filter_op) {
430         case RTE_ETH_FILTER_NOP:
431                 /* Typically used to query fdir support */
432                 if (ECORE_IS_CMT(edev)) {
433                         DP_ERR(edev, "flowdir is not supported in 100G mode\n");
434                         return -ENOTSUP;
435                 }
436                 return 0; /* means supported */
437         case RTE_ETH_FILTER_ADD:
438                 add = true;
439         break;
440         case RTE_ETH_FILTER_DELETE:
441         break;
442         case RTE_ETH_FILTER_INFO:
443         case RTE_ETH_FILTER_GET:
444         case RTE_ETH_FILTER_UPDATE:
445         case RTE_ETH_FILTER_FLUSH:
446         case RTE_ETH_FILTER_SET:
447         case RTE_ETH_FILTER_STATS:
448         case RTE_ETH_FILTER_OP_MAX:
449                 DP_ERR(edev, "Unsupported filter_op %d\n", filter_op);
450                 return -ENOTSUP;
451         }
452         ntuple = (struct rte_eth_ntuple_filter *)arg;
453         /* Internally convert ntuple to fdir entry */
454         memset(&fdir_entry, 0, sizeof(fdir_entry));
455         if (ntuple->proto == IPPROTO_TCP) {
456                 fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_TCP;
457                 tcpv4_flow = &fdir_entry.input.flow.tcp4_flow;
458                 tcpv4_flow->ip.src_ip = ntuple->src_ip;
459                 tcpv4_flow->ip.dst_ip = ntuple->dst_ip;
460                 tcpv4_flow->ip.proto = IPPROTO_TCP;
461                 tcpv4_flow->src_port = ntuple->src_port;
462                 tcpv4_flow->dst_port = ntuple->dst_port;
463         } else {
464                 fdir_entry.input.flow_type = RTE_ETH_FLOW_NONFRAG_IPV4_UDP;
465                 udpv4_flow = &fdir_entry.input.flow.udp4_flow;
466                 udpv4_flow->ip.src_ip = ntuple->src_ip;
467                 udpv4_flow->ip.dst_ip = ntuple->dst_ip;
468                 udpv4_flow->ip.proto = IPPROTO_TCP;
469                 udpv4_flow->src_port = ntuple->src_port;
470                 udpv4_flow->dst_port = ntuple->dst_port;
471         }
472
473         fdir_entry.action.rx_queue = ntuple->queue;
474
475         return qede_config_cmn_fdir_filter(eth_dev, &fdir_entry, add);
476 }