eal: introduce ymm type for AVX 256-bit
[dpdk.git] / lib / librte_pmd_enic / enic_clsf.c
1 /*
2  * Copyright 2008-2014 Cisco Systems, Inc.  All rights reserved.
3  * Copyright 2007 Nuova Systems, Inc.  All rights reserved.
4  *
5  * Copyright (c) 2014, Cisco Systems, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  */
34 #ident "$Id$"
35
36 #include <libgen.h>
37
38 #include <rte_ethdev.h>
39 #include <rte_malloc.h>
40 #include <rte_hash.h>
41 #include <rte_byteorder.h>
42
43 #include "enic_compat.h"
44 #include "enic.h"
45 #include "wq_enet_desc.h"
46 #include "rq_enet_desc.h"
47 #include "cq_enet_desc.h"
48 #include "vnic_enet.h"
49 #include "vnic_dev.h"
50 #include "vnic_wq.h"
51 #include "vnic_rq.h"
52 #include "vnic_cq.h"
53 #include "vnic_intr.h"
54 #include "vnic_nic.h"
55
56 #ifdef RTE_MACHINE_CPUFLAG_SSE4_2
57 #include <rte_hash_crc.h>
58 #define DEFAULT_HASH_FUNC       rte_hash_crc
59 #else
60 #include <rte_jhash.h>
61 #define DEFAULT_HASH_FUNC       rte_jhash
62 #endif
63
64 #define SOCKET_0                0
65 #define ENICPMD_CLSF_HASH_ENTRIES       ENICPMD_FDIR_MAX
66 #define ENICPMD_CLSF_BUCKET_ENTRIES     4
67
68 int enic_fdir_del_fltr(struct enic *enic, struct rte_fdir_filter *params)
69 {
70         int32_t pos;
71         struct enic_fdir_node *key;
72         /* See if the key is in the table */
73         pos = rte_hash_del_key(enic->fdir.hash, params);
74         switch (pos) {
75         case -EINVAL:
76         case -ENOENT:
77                 enic->fdir.stats.f_remove++;
78                 return -EINVAL;
79         default:
80                 /* The entry is present in the table */
81                 key = enic->fdir.nodes[pos];
82
83                 /* Delete the filter */
84                 vnic_dev_classifier(enic->vdev, CLSF_DEL,
85                         &key->fltr_id, NULL);
86                 rte_free(key);
87                 enic->fdir.nodes[pos] = NULL;
88                 enic->fdir.stats.free++;
89                 enic->fdir.stats.remove++;
90                 break;
91         }
92         return 0;
93 }
94
95 int enic_fdir_add_fltr(struct enic *enic, struct rte_fdir_filter *params,
96         u16 queue, u8 drop)
97 {
98         struct enic_fdir_node *key;
99         struct filter fltr = {.type = 0};
100         int32_t pos;
101         u8 do_free = 0;
102         u16 old_fltr_id = 0;
103
104         if (!enic->fdir.hash || params->vlan_id || !params->l4type ||
105                 (RTE_FDIR_IPTYPE_IPV6 == params->iptype) ||
106                 (RTE_FDIR_L4TYPE_SCTP == params->l4type) ||
107                 params->flex_bytes || drop) {
108                 enic->fdir.stats.f_add++;
109                 return -ENOTSUP;
110         }
111
112         /* See if the key is already there in the table */
113         pos = rte_hash_del_key(enic->fdir.hash, params);
114         switch (pos) {
115         case -EINVAL:
116                 enic->fdir.stats.f_add++;
117                 return -EINVAL;
118         case -ENOENT:
119                 /* Add a new classifier entry */
120                 if (!enic->fdir.stats.free) {
121                         enic->fdir.stats.f_add++;
122                         return -ENOSPC;
123                 }
124                 key = (struct enic_fdir_node *)rte_zmalloc(
125                         "enic_fdir_node",
126                         sizeof(struct enic_fdir_node), 0);
127                 if (!key) {
128                         enic->fdir.stats.f_add++;
129                         return -ENOMEM;
130                 }
131                 break;
132         default:
133                 /* The entry is already present in the table.
134                  * Check if there is a change in queue
135                  */
136                 key = enic->fdir.nodes[pos];
137                 enic->fdir.nodes[pos] = NULL;
138                 if (unlikely(key->rq_index == queue)) {
139                         /* Nothing to be done */
140                         pos = rte_hash_add_key(enic->fdir.hash, params);
141                         enic->fdir.nodes[pos] = key;
142                         enic->fdir.stats.f_add++;
143                         dev_warning(enic,
144                                 "FDIR rule is already present\n");
145                         return 0;
146                 }
147
148                 if (likely(enic->fdir.stats.free)) {
149                         /* Add the filter and then delete the old one.
150                          * This is to avoid packets from going into the
151                          * default queue during the window between
152                          * delete and add
153                          */
154                         do_free = 1;
155                         old_fltr_id = key->fltr_id;
156                 } else {
157                         /* No free slots in the classifier.
158                          * Delete the filter and add the modified one later
159                          */
160                         vnic_dev_classifier(enic->vdev, CLSF_DEL,
161                                 &key->fltr_id, NULL);
162                         enic->fdir.stats.free++;
163                 }
164
165                 break;
166         }
167
168         key->filter = *params;
169         key->rq_index = queue;
170
171         fltr.type = FILTER_IPV4_5TUPLE;
172         fltr.u.ipv4.src_addr = rte_be_to_cpu_32(params->ip_src.ipv4_addr);
173         fltr.u.ipv4.dst_addr = rte_be_to_cpu_32(params->ip_dst.ipv4_addr);
174         fltr.u.ipv4.src_port = rte_be_to_cpu_16(params->port_src);
175         fltr.u.ipv4.dst_port = rte_be_to_cpu_16(params->port_dst);
176
177         if (RTE_FDIR_L4TYPE_TCP == params->l4type)
178                 fltr.u.ipv4.protocol = PROTO_TCP;
179         else
180                 fltr.u.ipv4.protocol = PROTO_UDP;
181
182         fltr.u.ipv4.flags = FILTER_FIELDS_IPV4_5TUPLE;
183
184         if (!vnic_dev_classifier(enic->vdev, CLSF_ADD, &queue, &fltr)) {
185                 key->fltr_id = queue;
186         } else {
187                 dev_err(enic, "Add classifier entry failed\n");
188                 enic->fdir.stats.f_add++;
189                 rte_free(key);
190                 return -1;
191         }
192
193         if (do_free)
194                 vnic_dev_classifier(enic->vdev, CLSF_DEL, &old_fltr_id, NULL);
195         else{
196                 enic->fdir.stats.free--;
197                 enic->fdir.stats.add++;
198         }
199
200         pos = rte_hash_add_key(enic->fdir.hash, (void *)key);
201         enic->fdir.nodes[pos] = key;
202         return 0;
203 }
204
205 void enic_clsf_destroy(struct enic *enic)
206 {
207         u32 index;
208         struct enic_fdir_node *key;
209         /* delete classifier entries */
210         for (index = 0; index < ENICPMD_FDIR_MAX; index++) {
211                 key = enic->fdir.nodes[index];
212                 if (key) {
213                         vnic_dev_classifier(enic->vdev, CLSF_DEL,
214                                 &key->fltr_id, NULL);
215                         rte_free(key);
216                 }
217         }
218
219         if (enic->fdir.hash) {
220                 rte_hash_free(enic->fdir.hash);
221                 enic->fdir.hash = NULL;
222         }
223 }
224
225 int enic_clsf_init(struct enic *enic)
226 {
227         struct rte_hash_parameters hash_params = {
228                 .name = "enicpmd_clsf_hash",
229                 .entries = ENICPMD_CLSF_HASH_ENTRIES,
230                 .bucket_entries = ENICPMD_CLSF_BUCKET_ENTRIES,
231                 .key_len = sizeof(struct rte_fdir_filter),
232                 .hash_func = DEFAULT_HASH_FUNC,
233                 .hash_func_init_val = 0,
234                 .socket_id = SOCKET_0,
235         };
236
237         enic->fdir.hash = rte_hash_create(&hash_params);
238         memset(&enic->fdir.stats, 0, sizeof(enic->fdir.stats));
239         enic->fdir.stats.free = ENICPMD_FDIR_MAX;
240         return (NULL == enic->fdir.hash);
241 }