mlx5: add MAC handling
[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 <linux/if.h>
42 #include <sys/ioctl.h>
43 #include <arpa/inet.h>
44
45 /* Verbs header. */
46 /* ISO C doesn't support unnamed structs/unions, disabling -pedantic. */
47 #ifdef PEDANTIC
48 #pragma GCC diagnostic ignored "-pedantic"
49 #endif
50 #include <infiniband/verbs.h>
51 #ifdef PEDANTIC
52 #pragma GCC diagnostic error "-pedantic"
53 #endif
54
55 /* DPDK headers don't like -pedantic. */
56 #ifdef PEDANTIC
57 #pragma GCC diagnostic ignored "-pedantic"
58 #endif
59 #include <rte_ether.h>
60 #include <rte_ethdev.h>
61 #include <rte_common.h>
62 #ifdef PEDANTIC
63 #pragma GCC diagnostic error "-pedantic"
64 #endif
65
66 #include "mlx5.h"
67 #include "mlx5_utils.h"
68 #include "mlx5_rxtx.h"
69 #include "mlx5_defs.h"
70
71 /**
72  * Get MAC address by querying netdevice.
73  *
74  * @param[in] priv
75  *   struct priv for the requested device.
76  * @param[out] mac
77  *   MAC address output buffer.
78  *
79  * @return
80  *   0 on success, -1 on failure and errno is set.
81  */
82 int
83 priv_get_mac(struct priv *priv, uint8_t (*mac)[ETHER_ADDR_LEN])
84 {
85         struct ifreq request;
86
87         if (priv_ifreq(priv, SIOCGIFHWADDR, &request))
88                 return -1;
89         memcpy(mac, request.ifr_hwaddr.sa_data, ETHER_ADDR_LEN);
90         return 0;
91 }
92
93 /**
94  * Delete MAC flow steering rule.
95  *
96  * @param rxq
97  *   Pointer to RX queue structure.
98  * @param mac_index
99  *   MAC address index.
100  */
101 static void
102 rxq_del_mac_flow(struct rxq *rxq, unsigned int mac_index)
103 {
104 #ifndef NDEBUG
105         const uint8_t (*mac)[ETHER_ADDR_LEN] =
106                 (const uint8_t (*)[ETHER_ADDR_LEN])
107                 rxq->priv->mac[mac_index].addr_bytes;
108 #endif
109
110         assert(mac_index < RTE_DIM(rxq->mac_flow));
111         if (rxq->mac_flow[mac_index] == NULL)
112                 return;
113         DEBUG("%p: removing MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u",
114               (void *)rxq,
115               (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],
116               mac_index);
117         claim_zero(ibv_destroy_flow(rxq->mac_flow[mac_index]));
118         rxq->mac_flow[mac_index] = NULL;
119 }
120
121 /**
122  * Unregister a MAC address from a RX queue.
123  *
124  * @param rxq
125  *   Pointer to RX queue structure.
126  * @param mac_index
127  *   MAC address index.
128  */
129 static void
130 rxq_mac_addr_del(struct rxq *rxq, unsigned int mac_index)
131 {
132         assert(mac_index < RTE_DIM(rxq->mac_flow));
133         rxq_del_mac_flow(rxq, mac_index);
134 }
135
136 /**
137  * Unregister all MAC addresses from a RX queue.
138  *
139  * @param rxq
140  *   Pointer to RX queue structure.
141  */
142 void
143 rxq_mac_addrs_del(struct rxq *rxq)
144 {
145         unsigned int i;
146
147         for (i = 0; (i != RTE_DIM(rxq->mac_flow)); ++i)
148                 rxq_mac_addr_del(rxq, i);
149 }
150
151 /**
152  * Unregister a MAC address.
153  *
154  * In RSS mode, the MAC address is unregistered from the parent queue,
155  * otherwise it is unregistered from each queue directly.
156  *
157  * @param priv
158  *   Pointer to private structure.
159  * @param mac_index
160  *   MAC address index.
161  */
162 static void
163 priv_mac_addr_del(struct priv *priv, unsigned int mac_index)
164 {
165         unsigned int i;
166
167         assert(mac_index < RTE_DIM(priv->mac));
168         if (!BITFIELD_ISSET(priv->mac_configured, mac_index))
169                 return;
170         if (priv->rss) {
171                 rxq_mac_addr_del(&priv->rxq_parent, mac_index);
172                 goto end;
173         }
174         for (i = 0; (i != priv->dev->data->nb_rx_queues); ++i)
175                 rxq_mac_addr_del((*priv->rxqs)[i], mac_index);
176 end:
177         BITFIELD_RESET(priv->mac_configured, mac_index);
178 }
179
180 /**
181  * DPDK callback to remove a MAC address.
182  *
183  * @param dev
184  *   Pointer to Ethernet device structure.
185  * @param index
186  *   MAC address index.
187  */
188 void
189 mlx5_mac_addr_remove(struct rte_eth_dev *dev, uint32_t index)
190 {
191         struct priv *priv = dev->data->dev_private;
192
193         priv_lock(priv);
194         DEBUG("%p: removing MAC address from index %" PRIu32,
195               (void *)dev, index);
196         /* Last array entry is reserved for broadcast. */
197         if (index >= (RTE_DIM(priv->mac) - 1))
198                 goto end;
199         priv_mac_addr_del(priv, index);
200 end:
201         priv_unlock(priv);
202 }
203
204 /**
205  * Add MAC flow steering rule.
206  *
207  * @param rxq
208  *   Pointer to RX queue structure.
209  * @param mac_index
210  *   MAC address index to register.
211  *
212  * @return
213  *   0 on success, errno value on failure.
214  */
215 static int
216 rxq_add_mac_flow(struct rxq *rxq, unsigned int mac_index)
217 {
218         struct ibv_flow *flow;
219         struct priv *priv = rxq->priv;
220         const uint8_t (*mac)[ETHER_ADDR_LEN] =
221                         (const uint8_t (*)[ETHER_ADDR_LEN])
222                         priv->mac[mac_index].addr_bytes;
223         struct __attribute__((packed)) {
224                 struct ibv_flow_attr attr;
225                 struct ibv_flow_spec_eth spec;
226         } data;
227         struct ibv_flow_attr *attr = &data.attr;
228         struct ibv_flow_spec_eth *spec = &data.spec;
229
230         assert(mac_index < RTE_DIM(rxq->mac_flow));
231         if (rxq->mac_flow[mac_index] != NULL)
232                 return 0;
233         /*
234          * No padding must be inserted by the compiler between attr and spec.
235          * This layout is expected by libibverbs.
236          */
237         assert(((uint8_t *)attr + sizeof(*attr)) == (uint8_t *)spec);
238         *attr = (struct ibv_flow_attr){
239                 .type = IBV_FLOW_ATTR_NORMAL,
240                 .num_of_specs = 1,
241                 .port = priv->port,
242                 .flags = 0
243         };
244         *spec = (struct ibv_flow_spec_eth){
245                 .type = IBV_FLOW_SPEC_ETH,
246                 .size = sizeof(*spec),
247                 .val = {
248                         .dst_mac = {
249                                 (*mac)[0], (*mac)[1], (*mac)[2],
250                                 (*mac)[3], (*mac)[4], (*mac)[5]
251                         },
252                 },
253                 .mask = {
254                         .dst_mac = "\xff\xff\xff\xff\xff\xff",
255                 },
256         };
257         DEBUG("%p: adding MAC address %02x:%02x:%02x:%02x:%02x:%02x index %u",
258               (void *)rxq,
259               (*mac)[0], (*mac)[1], (*mac)[2], (*mac)[3], (*mac)[4], (*mac)[5],
260               mac_index);
261         /* Create related flow. */
262         errno = 0;
263         flow = ibv_create_flow(rxq->qp, attr);
264         if (flow == NULL) {
265                 /* It's not clear whether errno is always set in this case. */
266                 ERROR("%p: flow configuration failed, errno=%d: %s",
267                       (void *)rxq, errno,
268                       (errno ? strerror(errno) : "Unknown error"));
269                 if (errno)
270                         return errno;
271                 return EINVAL;
272         }
273         rxq->mac_flow[mac_index] = flow;
274         return 0;
275 }
276
277 /**
278  * Register a MAC address in a RX queue.
279  *
280  * @param rxq
281  *   Pointer to RX queue structure.
282  * @param mac_index
283  *   MAC address index to register.
284  *
285  * @return
286  *   0 on success, errno value on failure.
287  */
288 static int
289 rxq_mac_addr_add(struct rxq *rxq, unsigned int mac_index)
290 {
291         int ret;
292
293         assert(mac_index < RTE_DIM(rxq->mac_flow));
294         ret = rxq_add_mac_flow(rxq, mac_index);
295         if (ret)
296                 return ret;
297         return 0;
298 }
299
300 /**
301  * Register all MAC addresses in a RX queue.
302  *
303  * @param rxq
304  *   Pointer to RX queue structure.
305  *
306  * @return
307  *   0 on success, errno value on failure.
308  */
309 int
310 rxq_mac_addrs_add(struct rxq *rxq)
311 {
312         struct priv *priv = rxq->priv;
313         unsigned int i;
314         int ret;
315
316         assert(RTE_DIM(priv->mac) == RTE_DIM(rxq->mac_flow));
317         for (i = 0; (i != RTE_DIM(priv->mac)); ++i) {
318                 if (!BITFIELD_ISSET(priv->mac_configured, i))
319                         continue;
320                 ret = rxq_mac_addr_add(rxq, i);
321                 if (!ret)
322                         continue;
323                 /* Failure, rollback. */
324                 while (i != 0)
325                         rxq_mac_addr_del(rxq, --i);
326                 assert(ret > 0);
327                 return ret;
328         }
329         return 0;
330 }
331
332 /**
333  * Register a MAC address.
334  *
335  * In RSS mode, the MAC address is registered in the parent queue,
336  * otherwise it is registered in each queue directly.
337  *
338  * @param priv
339  *   Pointer to private structure.
340  * @param mac_index
341  *   MAC address index to use.
342  * @param mac
343  *   MAC address to register.
344  *
345  * @return
346  *   0 on success, errno value on failure.
347  */
348 int
349 priv_mac_addr_add(struct priv *priv, unsigned int mac_index,
350                   const uint8_t (*mac)[ETHER_ADDR_LEN])
351 {
352         unsigned int i;
353         int ret;
354
355         assert(mac_index < RTE_DIM(priv->mac));
356         /* First, make sure this address isn't already configured. */
357         for (i = 0; (i != RTE_DIM(priv->mac)); ++i) {
358                 /* Skip this index, it's going to be reconfigured. */
359                 if (i == mac_index)
360                         continue;
361                 if (!BITFIELD_ISSET(priv->mac_configured, i))
362                         continue;
363                 if (memcmp(priv->mac[i].addr_bytes, *mac, sizeof(*mac)))
364                         continue;
365                 /* Address already configured elsewhere, return with error. */
366                 return EADDRINUSE;
367         }
368         if (BITFIELD_ISSET(priv->mac_configured, mac_index))
369                 priv_mac_addr_del(priv, mac_index);
370         priv->mac[mac_index] = (struct ether_addr){
371                 {
372                         (*mac)[0], (*mac)[1], (*mac)[2],
373                         (*mac)[3], (*mac)[4], (*mac)[5]
374                 }
375         };
376         /* If device isn't started, this is all we need to do. */
377         if (!priv->started)
378                 goto end;
379         if (priv->rss) {
380                 ret = rxq_mac_addr_add(&priv->rxq_parent, mac_index);
381                 if (ret)
382                         return ret;
383                 goto end;
384         }
385         for (i = 0; (i != priv->rxqs_n); ++i) {
386                 if ((*priv->rxqs)[i] == NULL)
387                         continue;
388                 ret = rxq_mac_addr_add((*priv->rxqs)[i], mac_index);
389                 if (!ret)
390                         continue;
391                 /* Failure, rollback. */
392                 while (i != 0)
393                         if ((*priv->rxqs)[--i] != NULL)
394                                 rxq_mac_addr_del((*priv->rxqs)[i], mac_index);
395                 return ret;
396         }
397 end:
398         BITFIELD_SET(priv->mac_configured, mac_index);
399         return 0;
400 }
401
402 /**
403  * DPDK callback to add a MAC address.
404  *
405  * @param dev
406  *   Pointer to Ethernet device structure.
407  * @param mac_addr
408  *   MAC address to register.
409  * @param index
410  *   MAC address index.
411  * @param vmdq
412  *   VMDq pool index to associate address with (ignored).
413  */
414 void
415 mlx5_mac_addr_add(struct rte_eth_dev *dev, struct ether_addr *mac_addr,
416                   uint32_t index, uint32_t vmdq)
417 {
418         struct priv *priv = dev->data->dev_private;
419
420         (void)vmdq;
421         priv_lock(priv);
422         DEBUG("%p: adding MAC address at index %" PRIu32,
423               (void *)dev, index);
424         /* Last array entry is reserved for broadcast. */
425         if (index >= (RTE_DIM(priv->mac) - 1))
426                 goto end;
427         priv_mac_addr_add(priv, index,
428                           (const uint8_t (*)[ETHER_ADDR_LEN])
429                           mac_addr->addr_bytes);
430 end:
431         priv_unlock(priv);
432 }