45d23e437bf0db411418b0f53313e7ad5a7a512c
[dpdk.git] / drivers / net / mlx5 / mlx5_mac.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 <assert.h>
36 #include <stdint.h>
37 #include <string.h>
38 #include <inttypes.h>
39 #include <errno.h>
40 #include <netinet/in.h>
41 #include <sys/ioctl.h>
42 #include <arpa/inet.h>
43
44 /* Verbs header. */
45 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
46 #ifdef PEDANTIC
47 #pragma GCC diagnostic ignored "-Wpedantic"
48 #endif
49 #include <infiniband/verbs.h>
50 #ifdef PEDANTIC
51 #pragma GCC diagnostic error "-Wpedantic"
52 #endif
53
54 #include <rte_ether.h>
55 #include <rte_ethdev.h>
56 #include <rte_common.h>
57
58 #include "mlx5.h"
59 #include "mlx5_utils.h"
60 #include "mlx5_rxtx.h"
61 #include "mlx5_defs.h"
62
63 /**
64  * Get MAC address by querying netdevice.
65  *
66  * @param[in] priv
67  *   struct priv for the requested device.
68  * @param[out] mac
69  *   MAC address output buffer.
70  *
71  * @return
72  *   0 on success, -1 on failure and errno is set.
73  */
74 int
75 priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN])
76 {
77         struct ifreq request;
78
79         if (priv_ifreq(priv, SIOCGIFHWADDR, &request))
80                 return -1;
81         memcpy(mac, request.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
82         return 0;
83 }
84
85 /**
86  * Delete MAC flow steering rule.
87  *
88  * @param hash_rxq
89  *   Pointer to hash RX queue structure.
90  * @param mac_index
91  *   MAC address index.
92  * @param vlan_index
93  *   VLAN index to use.
94  */
95 static void
96 hash_rxq_del_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index,
97                       unsigned int vlan_index)
98 {
99 #ifndef NDEBUG
100         const uint8_t (*mac)[ETHER_ADDR_LEN] =
101                 (const uint8_t (*)[ETHER_ADDR_LEN])
102                 hash_rxq->priv->mac[mac_index].addr_bytes;
103 #endif
104
105         assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
106         assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index]));
107         if (hash_rxq->mac_flow[mac_index][vlan_index] == NULL)
108                 return;
109         DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u"
110               " VLAN index %u",
111               (void *)hash_rxq,
112               (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],
113               mac_index,
114               vlan_index);
115         claim_zero(ibv_exp_destroy_flow(hash_rxq->mac_flow
116                                         [mac_index][vlan_index]));
117         hash_rxq->mac_flow[mac_index][vlan_index] = NULL;
118 }
119
120 /**
121  * Unregister a MAC address from a hash RX queue.
122  *
123  * @param hash_rxq
124  *   Pointer to hash RX queue structure.
125  * @param mac_index
126  *   MAC address index.
127  */
128 static void
129 hash_rxq_mac_addr_del(struct hash_rxq *hash_rxq, unsigned int mac_index)
130 {
131         unsigned int i;
132
133         assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
134         for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow[mac_index])); ++i)
135                 hash_rxq_del_mac_flow(hash_rxq, mac_index, i);
136 }
137
138 /**
139  * Unregister all MAC addresses from a hash RX queue.
140  *
141  * @param hash_rxq
142  *   Pointer to hash RX queue structure.
143  */
144 void
145 hash_rxq_mac_addrs_del(struct hash_rxq *hash_rxq)
146 {
147         unsigned int i;
148
149         for (i = 0; (i != RTE_DIM(hash_rxq->mac_flow)); ++i)
150                 hash_rxq_mac_addr_del(hash_rxq, i);
151 }
152
153 /**
154  * Unregister a MAC address.
155  *
156  * This is done for each hash RX queue.
157  *
158  * @param priv
159  *   Pointer to private structure.
160  * @param mac_index
161  *   MAC address index.
162  */
163 static void
164 priv_mac_addr_del(struct priv *priv, unsigned int mac_index)
165 {
166         unsigned int i;
167
168         assert(mac_index < RTE_DIM(priv->mac));
169         if (!BITFIELD_ISSET(priv->mac_configured, mac_index))
170                 return;
171         for (i = 0; (i != priv->hash_rxqs_n); ++i)
172                 hash_rxq_mac_addr_del(&(*priv->hash_rxqs)[i], mac_index);
173         BITFIELD_RESET(priv->mac_configured, mac_index);
174 }
175
176 /**
177  * Unregister all MAC addresses from all hash RX queues.
178  *
179  * @param priv
180  *   Pointer to private structure.
181  */
182 void
183 priv_mac_addrs_disable(struct priv *priv)
184 {
185         unsigned int i;
186
187         for (i = 0; (i != priv->hash_rxqs_n); ++i)
188                 hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[i]);
189 }
190
191 /**
192  * DPDK callback to remove a MAC address.
193  *
194  * @param dev
195  *   Pointer to Ethernet device structure.
196  * @param index
197  *   MAC address index.
198  */
199 void
200 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
201 {
202         struct priv *priv = dev->data->dev_private;
203
204         if (mlx5_is_secondary())
205                 return;
206
207         priv_lock(priv);
208         DEBUG("%p: removing MAC address from index %" PRIu32,
209               (void *)dev, index);
210         if (index >= RTE_DIM(priv->mac))
211                 goto end;
212         priv_mac_addr_del(priv, index);
213 end:
214         priv_unlock(priv);
215 }
216
217 /**
218  * Add MAC flow steering rule.
219  *
220  * @param hash_rxq
221  *   Pointer to hash RX queue structure.
222  * @param mac_index
223  *   MAC address index to register.
224  * @param vlan_index
225  *   VLAN index to use.
226  *
227  * @return
228  *   0 on success, errno value on failure.
229  */
230 static int
231 hash_rxq_add_mac_flow(struct hash_rxq *hash_rxq, unsigned int mac_index,
232                       unsigned int vlan_index)
233 {
234         struct ibv_exp_flow *flow;
235         struct priv *priv = hash_rxq->priv;
236         const uint8_t (*mac)[ETHER_ADDR_LEN] =
237                         (const uint8_t (*)[ETHER_ADDR_LEN])
238                         priv->mac[mac_index].addr_bytes;
239         FLOW_ATTR_SPEC_ETH(data, priv_flow_attr(priv, NULL, 0, hash_rxq->type));
240         struct ibv_exp_flow_attr *attr = &data->attr;
241         struct ibv_exp_flow_spec_eth *spec = &data->spec;
242         unsigned int vlan_enabled = !!priv->vlan_filter_n;
243         unsigned int vlan_id = priv->vlan_filter[vlan_index];
244
245         assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
246         assert(vlan_index < RTE_DIM(hash_rxq->mac_flow[mac_index]));
247         if (hash_rxq->mac_flow[mac_index][vlan_index] != NULL)
248                 return 0;
249         /*
250          * No padding must be inserted by the compiler between attr and spec.
251          * This layout is expected by libibverbs.
252          */
253         assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec);
254         priv_flow_attr(priv, attr, sizeof(data), hash_rxq->type);
255         /* The first specification must be Ethernet. */
256         assert(spec->type == IBV_EXP_FLOW_SPEC_ETH);
257         assert(spec->size == sizeof(*spec));
258         *spec = (struct ibv_exp_flow_spec_eth){
259                 .type = IBV_EXP_FLOW_SPEC_ETH,
260                 .size = sizeof(*spec),
261                 .val = {
262                         .dst_mac = {
263                                 (*mac)[0], (*mac)[1], (*mac)[2],
264                                 (*mac)[3], (*mac)[4], (*mac)[5]
265                         },
266                         .vlan_tag = (vlan_enabled ? htons(vlan_id) : 0),
267                 },
268                 .mask = {
269                         .dst_mac = "\xff\xff\xff\xff\xff\xff",
270                         .vlan_tag = (vlan_enabled ? htons(0xfff) : 0),
271                 },
272         };
273         DEBUG("%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u"
274               " VLAN index %u filtering %s, ID %u",
275               (void *)hash_rxq,
276               (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],
277               mac_index,
278               vlan_index,
279               (vlan_enabled ? "enabled" : "disabled"),
280               vlan_id);
281         /* Create related flow. */
282         errno = 0;
283         flow = ibv_exp_create_flow(hash_rxq->qp, attr);
284         if (flow == NULL) {
285                 /* It's not clear whether errno is always set in this case. */
286                 ERROR("%p: flow configuration failed, errno=%d: %s",
287                       (void *)hash_rxq, errno,
288                       (errno ? strerror(errno) : "Unknown error"));
289                 if (errno)
290                         return errno;
291                 return EINVAL;
292         }
293         hash_rxq->mac_flow[mac_index][vlan_index] = flow;
294         return 0;
295 }
296
297 /**
298  * Register a MAC address in a hash RX queue.
299  *
300  * @param hash_rxq
301  *   Pointer to hash RX queue structure.
302  * @param mac_index
303  *   MAC address index to register.
304  *
305  * @return
306  *   0 on success, errno value on failure.
307  */
308 static int
309 hash_rxq_mac_addr_add(struct hash_rxq *hash_rxq, unsigned int mac_index)
310 {
311         struct priv *priv = hash_rxq->priv;
312         unsigned int i = 0;
313         int ret;
314
315         assert(mac_index < RTE_DIM(hash_rxq->mac_flow));
316         assert(RTE_DIM(hash_rxq->mac_flow[mac_index]) ==
317                RTE_DIM(priv->vlan_filter));
318         /* Add a MAC address for each VLAN filter, or at least once. */
319         do {
320                 ret = hash_rxq_add_mac_flow(hash_rxq, mac_index, i);
321                 if (ret) {
322                         /* Failure, rollback. */
323                         while (i != 0)
324                                 hash_rxq_del_mac_flow(hash_rxq, mac_index,
325                                                       --i);
326                         return ret;
327                 }
328         } while (++i < priv->vlan_filter_n);
329         return 0;
330 }
331
332 /**
333  * Register all MAC addresses in a hash RX queue.
334  *
335  * @param hash_rxq
336  *   Pointer to hash RX queue structure.
337  *
338  * @return
339  *   0 on success, errno value on failure.
340  */
341 int
342 hash_rxq_mac_addrs_add(struct hash_rxq *hash_rxq)
343 {
344         struct priv *priv = hash_rxq->priv;
345         unsigned int i;
346         int ret;
347
348         assert(RTE_DIM(priv->mac) == RTE_DIM(hash_rxq->mac_flow));
349         for (i = 0; (i != RTE_DIM(priv->mac)); ++i) {
350                 if (!BITFIELD_ISSET(priv->mac_configured, i))
351                         continue;
352                 ret = hash_rxq_mac_addr_add(hash_rxq, i);
353                 if (!ret)
354                         continue;
355                 /* Failure, rollback. */
356                 while (i != 0)
357                         hash_rxq_mac_addr_del(hash_rxq, --i);
358                 assert(ret > 0);
359                 return ret;
360         }
361         return 0;
362 }
363
364 /**
365  * Register a MAC address.
366  *
367  * This is done for each hash RX queue.
368  *
369  * @param priv
370  *   Pointer to private structure.
371  * @param mac_index
372  *   MAC address index to use.
373  * @param mac
374  *   MAC address to register.
375  *
376  * @return
377  *   0 on success, errno value on failure.
378  */
379 int
380 priv_mac_addr_add(struct priv *priv, unsigned int mac_index,
381                   const uint8_t (*mac)[ETHER_ADDR_LEN])
382 {
383         unsigned int i;
384         int ret;
385
386         assert(mac_index < RTE_DIM(priv->mac));
387         /* First, make sure this address isn't already configured. */
388         for (i = 0; (i != RTE_DIM(priv->mac)); ++i) {
389                 /* Skip this index, it's going to be reconfigured. */
390                 if (i == mac_index)
391                         continue;
392                 if (!BITFIELD_ISSET(priv->mac_configured, i))
393                         continue;
394                 if (memcmp(priv->mac[i].addr_bytes, *mac, sizeof(*mac)))
395                         continue;
396                 /* Address already configured elsewhere, return with error. */
397                 return EADDRINUSE;
398         }
399         if (BITFIELD_ISSET(priv->mac_configured, mac_index))
400                 priv_mac_addr_del(priv, mac_index);
401         priv->mac[mac_index] = (struct ether_addr){
402                 {
403                         (*mac)[0], (*mac)[1], (*mac)[2],
404                         (*mac)[3], (*mac)[4], (*mac)[5]
405                 }
406         };
407         if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))
408                 goto end;
409         for (i = 0; (i != priv->hash_rxqs_n); ++i) {
410                 ret = hash_rxq_mac_addr_add(&(*priv->hash_rxqs)[i], mac_index);
411                 if (!ret)
412                         continue;
413                 /* Failure, rollback. */
414                 while (i != 0)
415                         hash_rxq_mac_addr_del(&(*priv->hash_rxqs)[--i],
416                                               mac_index);
417                 return ret;
418         }
419 end:
420         BITFIELD_SET(priv->mac_configured, mac_index);
421         return 0;
422 }
423
424 /**
425  * Register all MAC addresses in all hash RX queues.
426  *
427  * @param priv
428  *   Pointer to private structure.
429  *
430  * @return
431  *   0 on success, errno value on failure.
432  */
433 int
434 priv_mac_addrs_enable(struct priv *priv)
435 {
436         unsigned int i;
437         int ret;
438
439         if (priv->isolated)
440                 return 0;
441         if (!priv_allow_flow_type(priv, HASH_RXQ_FLOW_TYPE_MAC))
442                 return 0;
443         for (i = 0; (i != priv->hash_rxqs_n); ++i) {
444                 ret = hash_rxq_mac_addrs_add(&(*priv->hash_rxqs)[i]);
445                 if (!ret)
446                         continue;
447                 /* Failure, rollback. */
448                 while (i != 0)
449                         hash_rxq_mac_addrs_del(&(*priv->hash_rxqs)[--i]);
450                 assert(ret > 0);
451                 return ret;
452         }
453         return 0;
454 }
455
456 /**
457  * DPDK callback to add a MAC address.
458  *
459  * @param dev
460  *   Pointer to Ethernet device structure.
461  * @param mac_addr
462  *   MAC address to register.
463  * @param index
464  *   MAC address index.
465  * @param vmdq
466  *   VMDq pool index to associate address with (ignored).
467  */
468 int
469 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
470                   uint32_t index, uint32_t vmdq)
471 {
472         struct priv *priv = dev->data->dev_private;
473         int re;
474
475         if (mlx5_is_secondary())
476                 return -ENOTSUP;
477
478         (void)vmdq;
479         priv_lock(priv);
480         DEBUG("%p: adding MAC address at index %" PRIu32,
481               (void *)dev, index);
482         if (index >= RTE_DIM(priv->mac)) {
483                 re = EINVAL;
484                 goto end;
485         }
486         re = priv_mac_addr_add(priv, index,
487                                (const uint8_t (*)[ETHER_ADDR_LEN])
488                                mac_addr->addr_bytes);
489 end:
490         priv_unlock(priv);
491         return -re;
492 }
493
494 /**
495  * DPDK callback to set primary MAC address.
496  *
497  * @param dev
498  *   Pointer to Ethernet device structure.
499  * @param mac_addr
500  *   MAC address to register.
501  */
502 void
503 mlx5_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr)
504 {
505         DEBUG("%p: setting primary MAC address", (void *)dev);
506         mlx5_mac_addr_remove(dev, 0);
507         mlx5_mac_addr_add(dev, mac_addr, 0, 0);
508 }