mlx5: refactor special flows handling
[dpdk.git] / drivers / net / mlx5 / mlx5_rxmode.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright 2015 6WIND S.A.
5  *   Copyright 2015 Mellanox.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of 6WIND S.A. nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stddef.h>
35 #include <errno.h>
36 #include <string.h>
37
38 /* Verbs header. */
39 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
40 #ifdef PEDANTIC
41 #pragma GCC diagnostic ignored "-pedantic"
42 #endif
43 #include <infiniband/verbs.h>
44 #ifdef PEDANTIC
45 #pragma GCC diagnostic error "-pedantic"
46 #endif
47
48 /* DPDK headers don't like -pedantic. */
49 #ifdef PEDANTIC
50 #pragma GCC diagnostic ignored "-pedantic"
51 #endif
52 #include <rte_ethdev.h>
53 #ifdef PEDANTIC
54 #pragma GCC diagnostic error "-pedantic"
55 #endif
56
57 #include "mlx5.h"
58 #include "mlx5_rxtx.h"
59 #include "mlx5_utils.h"
60
61 /* Initialization data for special flows. */
62 static const struct special_flow_init special_flow_init[] = {
63         [HASH_RXQ_FLOW_TYPE_PROMISC] = {
64                 .dst_mac_val = "\x00\x00\x00\x00\x00\x00",
65                 .dst_mac_mask = "\x00\x00\x00\x00\x00\x00",
66                 .hash_types =
67                         1 << HASH_RXQ_TCPV4 |
68                         1 << HASH_RXQ_UDPV4 |
69                         1 << HASH_RXQ_IPV4 |
70 #ifdef HAVE_FLOW_SPEC_IPV6
71                         1 << HASH_RXQ_TCPV6 |
72                         1 << HASH_RXQ_UDPV6 |
73                         1 << HASH_RXQ_IPV6 |
74 #endif /* HAVE_FLOW_SPEC_IPV6 */
75                         1 << HASH_RXQ_ETH |
76                         0,
77         },
78         [HASH_RXQ_FLOW_TYPE_ALLMULTI] = {
79                 .dst_mac_val = "\x01\x00\x00\x00\x00\x00",
80                 .dst_mac_mask = "\x01\x00\x00\x00\x00\x00",
81                 .hash_types =
82                         1 << HASH_RXQ_UDPV4 |
83                         1 << HASH_RXQ_IPV4 |
84 #ifdef HAVE_FLOW_SPEC_IPV6
85                         1 << HASH_RXQ_UDPV6 |
86                         1 << HASH_RXQ_IPV6 |
87 #endif /* HAVE_FLOW_SPEC_IPV6 */
88                         1 << HASH_RXQ_ETH |
89                         0,
90         },
91 };
92
93 /**
94  * Enable a special flow in a hash RX queue.
95  *
96  * @param hash_rxq
97  *   Pointer to hash RX queue structure.
98  * @param flow_type
99  *   Special flow type.
100  *
101  * @return
102  *   0 on success, errno value on failure.
103  */
104 static int
105 hash_rxq_special_flow_enable(struct hash_rxq *hash_rxq,
106                              enum hash_rxq_flow_type flow_type)
107 {
108         struct ibv_exp_flow *flow;
109         FLOW_ATTR_SPEC_ETH(data, hash_rxq_flow_attr(hash_rxq, NULL, 0));
110         struct ibv_exp_flow_attr *attr = &data->attr;
111         struct ibv_exp_flow_spec_eth *spec = &data->spec;
112         const uint8_t *mac;
113         const uint8_t *mask;
114
115         /* Check if flow is relevant for this hash_rxq. */
116         if (!(special_flow_init[flow_type].hash_types & (1 << hash_rxq->type)))
117                 return 0;
118         /* Check if flow already exists. */
119         if (hash_rxq->special_flow[flow_type] != NULL)
120                 return 0;
121
122         /*
123          * No padding must be inserted by the compiler between attr and spec.
124          * This layout is expected by libibverbs.
125          */
126         assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec);
127         hash_rxq_flow_attr(hash_rxq, attr, sizeof(data));
128         /* The first specification must be Ethernet. */
129         assert(spec->type == IBV_EXP_FLOW_SPEC_ETH);
130         assert(spec->size == sizeof(*spec));
131
132         mac = special_flow_init[flow_type].dst_mac_val;
133         mask = special_flow_init[flow_type].dst_mac_mask;
134         *spec = (struct ibv_exp_flow_spec_eth){
135                 .type = IBV_EXP_FLOW_SPEC_ETH,
136                 .size = sizeof(*spec),
137                 .val = {
138                         .dst_mac = {
139                                 mac[0], mac[1], mac[2],
140                                 mac[3], mac[4], mac[5],
141                         },
142                 },
143                 .mask = {
144                         .dst_mac = {
145                                 mask[0], mask[1], mask[2],
146                                 mask[3], mask[4], mask[5],
147                         },
148                 },
149         };
150
151         errno = 0;
152         flow = ibv_exp_create_flow(hash_rxq->qp, attr);
153         if (flow == NULL) {
154                 /* It's not clear whether errno is always set in this case. */
155                 ERROR("%p: flow configuration failed, errno=%d: %s",
156                       (void *)hash_rxq, errno,
157                       (errno ? strerror(errno) : "Unknown error"));
158                 if (errno)
159                         return errno;
160                 return EINVAL;
161         }
162         hash_rxq->special_flow[flow_type] = flow;
163         DEBUG("%p: enabling special flow %s (%d)",
164               (void *)hash_rxq, hash_rxq_flow_type_str(flow_type), flow_type);
165         return 0;
166 }
167
168 /**
169  * Disable a special flow in a hash RX queue.
170  *
171  * @param hash_rxq
172  *   Pointer to hash RX queue structure.
173  * @param flow_type
174  *   Special flow type.
175  */
176 static void
177 hash_rxq_special_flow_disable(struct hash_rxq *hash_rxq,
178                               enum hash_rxq_flow_type flow_type)
179 {
180         if (hash_rxq->special_flow[flow_type] == NULL)
181                 return;
182         DEBUG("%p: disabling special flow %s (%d)",
183               (void *)hash_rxq, hash_rxq_flow_type_str(flow_type), flow_type);
184         claim_zero(ibv_exp_destroy_flow(hash_rxq->special_flow[flow_type]));
185         hash_rxq->special_flow[flow_type] = NULL;
186         DEBUG("%p: special flow %s (%d) disabled",
187               (void *)hash_rxq, hash_rxq_flow_type_str(flow_type), flow_type);
188 }
189
190 /**
191  * Enable a special flow in all hash RX queues.
192  *
193  * @param priv
194  *   Private structure.
195  * @param flow_type
196  *   Special flow type.
197  *
198  * @return
199  *   0 on success, errno value on failure.
200  */
201 int
202 priv_special_flow_enable(struct priv *priv, enum hash_rxq_flow_type flow_type)
203 {
204         unsigned int i;
205
206         if (!priv_allow_flow_type(priv, flow_type))
207                 return 0;
208         for (i = 0; (i != priv->hash_rxqs_n); ++i) {
209                 struct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i];
210                 int ret;
211
212                 ret = hash_rxq_special_flow_enable(hash_rxq, flow_type);
213                 if (!ret)
214                         continue;
215                 /* Failure, rollback. */
216                 while (i != 0) {
217                         hash_rxq = &(*priv->hash_rxqs)[--i];
218                         hash_rxq_special_flow_disable(hash_rxq, flow_type);
219                 }
220                 return ret;
221         }
222         return 0;
223 }
224
225 /**
226  * Disable a special flow in all hash RX queues.
227  *
228  * @param priv
229  *   Private structure.
230  * @param flow_type
231  *   Special flow type.
232  */
233 void
234 priv_special_flow_disable(struct priv *priv, enum hash_rxq_flow_type flow_type)
235 {
236         unsigned int i;
237
238         for (i = 0; (i != priv->hash_rxqs_n); ++i) {
239                 struct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i];
240
241                 hash_rxq_special_flow_disable(hash_rxq, flow_type);
242         }
243 }
244
245 /**
246  * DPDK callback to enable promiscuous mode.
247  *
248  * @param dev
249  *   Pointer to Ethernet device structure.
250  */
251 void
252 mlx5_promiscuous_enable(struct rte_eth_dev *dev)
253 {
254         struct priv *priv = dev->data->dev_private;
255         int ret;
256
257         priv_lock(priv);
258         priv->promisc_req = 1;
259         ret = priv_rehash_flows(priv);
260         if (ret)
261                 ERROR("error while enabling promiscuous mode: %s",
262                       strerror(ret));
263         priv_unlock(priv);
264 }
265
266 /**
267  * DPDK callback to disable promiscuous mode.
268  *
269  * @param dev
270  *   Pointer to Ethernet device structure.
271  */
272 void
273 mlx5_promiscuous_disable(struct rte_eth_dev *dev)
274 {
275         struct priv *priv = dev->data->dev_private;
276         int ret;
277
278         priv_lock(priv);
279         priv->promisc_req = 0;
280         ret = priv_rehash_flows(priv);
281         if (ret)
282                 ERROR("error while disabling promiscuous mode: %s",
283                       strerror(ret));
284         priv_unlock(priv);
285 }
286
287 /**
288  * DPDK callback to enable allmulti mode.
289  *
290  * @param dev
291  *   Pointer to Ethernet device structure.
292  */
293 void
294 mlx5_allmulticast_enable(struct rte_eth_dev *dev)
295 {
296         struct priv *priv = dev->data->dev_private;
297         int ret;
298
299         priv_lock(priv);
300         priv->allmulti_req = 1;
301         ret = priv_rehash_flows(priv);
302         if (ret)
303                 ERROR("error while enabling allmulticast mode: %s",
304                       strerror(ret));
305         priv_unlock(priv);
306 }
307
308 /**
309  * DPDK callback to disable allmulti mode.
310  *
311  * @param dev
312  *   Pointer to Ethernet device structure.
313  */
314 void
315 mlx5_allmulticast_disable(struct rte_eth_dev *dev)
316 {
317         struct priv *priv = dev->data->dev_private;
318         int ret;
319
320         priv_lock(priv);
321         priv->allmulti_req = 0;
322         ret = priv_rehash_flows(priv);
323         if (ret)
324                 ERROR("error while disabling allmulticast mode: %s",
325                       strerror(ret));
326         priv_unlock(priv);
327 }