mlx5: support IPv6 RSS using experimental flows
[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 static void hash_rxq_promiscuous_disable(struct hash_rxq *);
62 static void hash_rxq_allmulticast_disable(struct hash_rxq *);
63
64 /**
65  * Enable promiscuous mode in a hash RX queue.
66  *
67  * @param hash_rxq
68  *   Pointer to hash RX queue structure.
69  *
70  * @return
71  *   0 on success, errno value on failure.
72  */
73 static int
74 hash_rxq_promiscuous_enable(struct hash_rxq *hash_rxq)
75 {
76         struct ibv_exp_flow *flow;
77         FLOW_ATTR_SPEC_ETH(data, hash_rxq_flow_attr(hash_rxq, NULL, 0));
78         struct ibv_exp_flow_attr *attr = &data->attr;
79
80         if (hash_rxq->promisc_flow != NULL)
81                 return 0;
82         DEBUG("%p: enabling promiscuous mode", (void *)hash_rxq);
83         /* Promiscuous flows only differ from normal flows by not filtering
84          * on specific MAC addresses. */
85         hash_rxq_flow_attr(hash_rxq, attr, sizeof(data));
86         errno = 0;
87         flow = ibv_exp_create_flow(hash_rxq->qp, attr);
88         if (flow == NULL) {
89                 /* It's not clear whether errno is always set in this case. */
90                 ERROR("%p: flow configuration failed, errno=%d: %s",
91                       (void *)hash_rxq, errno,
92                       (errno ? strerror(errno) : "Unknown error"));
93                 if (errno)
94                         return errno;
95                 return EINVAL;
96         }
97         hash_rxq->promisc_flow = flow;
98         DEBUG("%p: promiscuous mode enabled", (void *)hash_rxq);
99         return 0;
100 }
101
102 /**
103  * Enable promiscuous mode in all hash RX queues.
104  *
105  * @param priv
106  *   Private structure.
107  *
108  * @return
109  *   0 on success, errno value on failure.
110  */
111 int
112 priv_promiscuous_enable(struct priv *priv)
113 {
114         unsigned int i;
115
116         if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_PROMISC))
117                 return 0;
118         for (i = 0; (i != priv->hash_rxqs_n); ++i) {
119                 struct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i];
120                 int ret;
121
122                 ret = hash_rxq_promiscuous_enable(hash_rxq);
123                 if (!ret)
124                         continue;
125                 /* Failure, rollback. */
126                 while (i != 0) {
127                         hash_rxq = &(*priv->hash_rxqs)[--i];
128                         hash_rxq_promiscuous_disable(hash_rxq);
129                 }
130                 return ret;
131         }
132         return 0;
133 }
134
135 /**
136  * DPDK callback to enable promiscuous mode.
137  *
138  * @param dev
139  *   Pointer to Ethernet device structure.
140  */
141 void
142 mlx5_promiscuous_enable(struct rte_eth_dev *dev)
143 {
144         struct priv *priv = dev->data->dev_private;
145         int ret;
146
147         priv_lock(priv);
148         priv->promisc_req = 1;
149         ret = priv_promiscuous_enable(priv);
150         if (ret)
151                 ERROR("cannot enable promiscuous mode: %s", strerror(ret));
152         else {
153                 priv_mac_addrs_disable(priv);
154                 priv_allmulticast_disable(priv);
155         }
156         priv_unlock(priv);
157 }
158
159 /**
160  * Disable promiscuous mode in a hash RX queue.
161  *
162  * @param hash_rxq
163  *   Pointer to hash RX queue structure.
164  */
165 static void
166 hash_rxq_promiscuous_disable(struct hash_rxq *hash_rxq)
167 {
168         if (hash_rxq->promisc_flow == NULL)
169                 return;
170         DEBUG("%p: disabling promiscuous mode", (void *)hash_rxq);
171         claim_zero(ibv_exp_destroy_flow(hash_rxq->promisc_flow));
172         hash_rxq->promisc_flow = NULL;
173         DEBUG("%p: promiscuous mode disabled", (void *)hash_rxq);
174 }
175
176 /**
177  * Disable promiscuous mode in all hash RX queues.
178  *
179  * @param priv
180  *   Private structure.
181  */
182 void
183 priv_promiscuous_disable(struct priv *priv)
184 {
185         unsigned int i;
186
187         for (i = 0; (i != priv->hash_rxqs_n); ++i)
188                 hash_rxq_promiscuous_disable(&(*priv->hash_rxqs)[i]);
189 }
190
191 /**
192  * DPDK callback to disable promiscuous mode.
193  *
194  * @param dev
195  *   Pointer to Ethernet device structure.
196  */
197 void
198 mlx5_promiscuous_disable(struct rte_eth_dev *dev)
199 {
200         struct priv *priv = dev->data->dev_private;
201
202         priv_lock(priv);
203         priv->promisc_req = 0;
204         priv_promiscuous_disable(priv);
205         priv_mac_addrs_enable(priv);
206         priv_allmulticast_enable(priv);
207         priv_unlock(priv);
208 }
209
210 /**
211  * Enable allmulti mode in a hash RX queue.
212  *
213  * @param hash_rxq
214  *   Pointer to hash RX queue structure.
215  *
216  * @return
217  *   0 on success, errno value on failure.
218  */
219 static int
220 hash_rxq_allmulticast_enable(struct hash_rxq *hash_rxq)
221 {
222         struct ibv_exp_flow *flow;
223         FLOW_ATTR_SPEC_ETH(data, hash_rxq_flow_attr(hash_rxq, NULL, 0));
224         struct ibv_exp_flow_attr *attr = &data->attr;
225         struct ibv_exp_flow_spec_eth *spec = &data->spec;
226
227         if (hash_rxq->allmulti_flow != NULL)
228                 return 0;
229         DEBUG("%p: enabling allmulticast mode", (void *)hash_rxq);
230         /*
231          * No padding must be inserted by the compiler between attr and spec.
232          * This layout is expected by libibverbs.
233          */
234         assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec);
235         hash_rxq_flow_attr(hash_rxq, attr, sizeof(data));
236         *spec = (struct ibv_exp_flow_spec_eth){
237                 .type = IBV_EXP_FLOW_SPEC_ETH,
238                 .size = sizeof(*spec),
239                 .val = {
240                         .dst_mac = "\x01\x00\x00\x00\x00\x00",
241                 },
242                 .mask = {
243                         .dst_mac = "\x01\x00\x00\x00\x00\x00",
244                 },
245         };
246         errno = 0;
247         flow = ibv_exp_create_flow(hash_rxq->qp, attr);
248         if (flow == NULL) {
249                 /* It's not clear whether errno is always set in this case. */
250                 ERROR("%p: flow configuration failed, errno=%d: %s",
251                       (void *)hash_rxq, errno,
252                       (errno ? strerror(errno) : "Unknown error"));
253                 if (errno)
254                         return errno;
255                 return EINVAL;
256         }
257         hash_rxq->allmulti_flow = flow;
258         DEBUG("%p: allmulticast mode enabled", (void *)hash_rxq);
259         return 0;
260 }
261
262 /**
263  * Enable allmulti mode in most hash RX queues.
264  * TCP queues are exempted to save resources.
265  *
266  * @param priv
267  *   Private structure.
268  *
269  * @return
270  *   0 on success, errno value on failure.
271  */
272 int
273 priv_allmulticast_enable(struct priv *priv)
274 {
275         unsigned int i;
276
277         if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_ALLMULTI))
278                 return 0;
279         for (i = 0; (i != priv->hash_rxqs_n); ++i) {
280                 struct hash_rxq *hash_rxq = &(*priv->hash_rxqs)[i];
281                 int ret;
282
283                 /* allmulticast not relevant for TCP. */
284                 if (hash_rxq->type == HASH_RXQ_TCPV4)
285                         continue;
286                 ret = hash_rxq_allmulticast_enable(hash_rxq);
287                 if (!ret)
288                         continue;
289                 /* Failure, rollback. */
290                 while (i != 0) {
291                         hash_rxq = &(*priv->hash_rxqs)[--i];
292                         hash_rxq_allmulticast_disable(hash_rxq);
293                 }
294                 return ret;
295         }
296         return 0;
297 }
298
299 /**
300  * DPDK callback to enable allmulti mode.
301  *
302  * @param dev
303  *   Pointer to Ethernet device structure.
304  */
305 void
306 mlx5_allmulticast_enable(struct rte_eth_dev *dev)
307 {
308         struct priv *priv = dev->data->dev_private;
309         int ret;
310
311         priv_lock(priv);
312         priv->allmulti_req = 1;
313         ret = priv_allmulticast_enable(priv);
314         if (ret)
315                 ERROR("cannot enable allmulticast mode: %s", strerror(ret));
316         priv_unlock(priv);
317 }
318
319 /**
320  * Disable allmulti mode in a hash RX queue.
321  *
322  * @param hash_rxq
323  *   Pointer to hash RX queue structure.
324  */
325 static void
326 hash_rxq_allmulticast_disable(struct hash_rxq *hash_rxq)
327 {
328         if (hash_rxq->allmulti_flow == NULL)
329                 return;
330         DEBUG("%p: disabling allmulticast mode", (void *)hash_rxq);
331         claim_zero(ibv_exp_destroy_flow(hash_rxq->allmulti_flow));
332         hash_rxq->allmulti_flow = NULL;
333         DEBUG("%p: allmulticast mode disabled", (void *)hash_rxq);
334 }
335
336 /**
337  * Disable allmulti mode in all hash RX queues.
338  *
339  * @param priv
340  *   Private structure.
341  */
342 void
343 priv_allmulticast_disable(struct priv *priv)
344 {
345         unsigned int i;
346
347         for (i = 0; (i != priv->hash_rxqs_n); ++i)
348                 hash_rxq_allmulticast_disable(&(*priv->hash_rxqs)[i]);
349 }
350
351 /**
352  * DPDK callback to disable allmulti mode.
353  *
354  * @param dev
355  *   Pointer to Ethernet device structure.
356  */
357 void
358 mlx5_allmulticast_disable(struct rte_eth_dev *dev)
359 {
360         struct priv *priv = dev->data->dev_private;
361
362         priv_lock(priv);
363         priv->allmulti_req = 0;
364         priv_allmulticast_disable(priv);
365         priv_unlock(priv);
366 }