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