app/testpmd: disable packet type parsing by default
[dpdk.git] / drivers / net / mlx5 / mlx5_nl.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2018 6WIND S.A.
3  * Copyright 2018 Mellanox Technologies, Ltd
4  */
5
6 #include <errno.h>
7 #include <linux/if_link.h>
8 #include <linux/netlink.h>
9 #include <linux/rtnetlink.h>
10 #include <net/if.h>
11 #include <rdma/rdma_netlink.h>
12 #include <stdbool.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <stdalign.h>
16 #include <string.h>
17 #include <sys/socket.h>
18 #include <unistd.h>
19
20 #include <rte_errno.h>
21 #include <rte_malloc.h>
22 #include <rte_hypervisor.h>
23
24 #include "mlx5.h"
25 #include "mlx5_utils.h"
26
27 /* Size of the buffer to receive kernel messages */
28 #define MLX5_NL_BUF_SIZE (32 * 1024)
29 /* Send buffer size for the Netlink socket */
30 #define MLX5_SEND_BUF_SIZE 32768
31 /* Receive buffer size for the Netlink socket */
32 #define MLX5_RECV_BUF_SIZE 32768
33
34 /** Parameters of VLAN devices created by driver. */
35 #define MLX5_VMWA_VLAN_DEVICE_PFX "evmlx"
36 /*
37  * Define NDA_RTA as defined in iproute2 sources.
38  *
39  * see in iproute2 sources file include/libnetlink.h
40  */
41 #ifndef MLX5_NDA_RTA
42 #define MLX5_NDA_RTA(r) \
43         ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
44 #endif
45
46 /*
47  * The following definitions are normally found in rdma/rdma_netlink.h,
48  * however they are so recent that most systems do not expose them yet.
49  */
50 #ifndef HAVE_RDMA_NL_NLDEV
51 #define RDMA_NL_NLDEV 5
52 #endif
53 #ifndef HAVE_RDMA_NLDEV_CMD_GET
54 #define RDMA_NLDEV_CMD_GET 1
55 #endif
56 #ifndef HAVE_RDMA_NLDEV_CMD_PORT_GET
57 #define RDMA_NLDEV_CMD_PORT_GET 5
58 #endif
59 #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_INDEX
60 #define RDMA_NLDEV_ATTR_DEV_INDEX 1
61 #endif
62 #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_NAME
63 #define RDMA_NLDEV_ATTR_DEV_NAME 2
64 #endif
65 #ifndef HAVE_RDMA_NLDEV_ATTR_PORT_INDEX
66 #define RDMA_NLDEV_ATTR_PORT_INDEX 3
67 #endif
68 #ifndef HAVE_RDMA_NLDEV_ATTR_NDEV_INDEX
69 #define RDMA_NLDEV_ATTR_NDEV_INDEX 50
70 #endif
71
72 /* These are normally found in linux/if_link.h. */
73 #ifndef HAVE_IFLA_NUM_VF
74 #define IFLA_NUM_VF 21
75 #endif
76 #ifndef HAVE_IFLA_EXT_MASK
77 #define IFLA_EXT_MASK 29
78 #endif
79 #ifndef HAVE_IFLA_PHYS_SWITCH_ID
80 #define IFLA_PHYS_SWITCH_ID 36
81 #endif
82 #ifndef HAVE_IFLA_PHYS_PORT_NAME
83 #define IFLA_PHYS_PORT_NAME 38
84 #endif
85
86 /* Add/remove MAC address through Netlink */
87 struct mlx5_nl_mac_addr {
88         struct rte_ether_addr (*mac)[];
89         /**< MAC address handled by the device. */
90         int mac_n; /**< Number of addresses in the array. */
91 };
92
93 #define MLX5_NL_CMD_GET_IB_NAME (1 << 0)
94 #define MLX5_NL_CMD_GET_IB_INDEX (1 << 1)
95 #define MLX5_NL_CMD_GET_NET_INDEX (1 << 2)
96 #define MLX5_NL_CMD_GET_PORT_INDEX (1 << 3)
97
98 /** Data structure used by mlx5_nl_cmdget_cb(). */
99 struct mlx5_nl_ifindex_data {
100         const char *name; /**< IB device name (in). */
101         uint32_t flags; /**< found attribute flags (out). */
102         uint32_t ibindex; /**< IB device index (out). */
103         uint32_t ifindex; /**< Network interface index (out). */
104         uint32_t portnum; /**< IB device max port number (out). */
105 };
106
107 /**
108  * Opens a Netlink socket.
109  *
110  * @param protocol
111  *   Netlink protocol (e.g. NETLINK_ROUTE, NETLINK_RDMA).
112  *
113  * @return
114  *   A file descriptor on success, a negative errno value otherwise and
115  *   rte_errno is set.
116  */
117 int
118 mlx5_nl_init(int protocol)
119 {
120         int fd;
121         int sndbuf_size = MLX5_SEND_BUF_SIZE;
122         int rcvbuf_size = MLX5_RECV_BUF_SIZE;
123         struct sockaddr_nl local = {
124                 .nl_family = AF_NETLINK,
125         };
126         int ret;
127
128         fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
129         if (fd == -1) {
130                 rte_errno = errno;
131                 return -rte_errno;
132         }
133         ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(int));
134         if (ret == -1) {
135                 rte_errno = errno;
136                 goto error;
137         }
138         ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, sizeof(int));
139         if (ret == -1) {
140                 rte_errno = errno;
141                 goto error;
142         }
143         ret = bind(fd, (struct sockaddr *)&local, sizeof(local));
144         if (ret == -1) {
145                 rte_errno = errno;
146                 goto error;
147         }
148         return fd;
149 error:
150         close(fd);
151         return -rte_errno;
152 }
153
154 /**
155  * Send a request message to the kernel on the Netlink socket.
156  *
157  * @param[in] nlsk_fd
158  *   Netlink socket file descriptor.
159  * @param[in] nh
160  *   The Netlink message send to the kernel.
161  * @param[in] ssn
162  *   Sequence number.
163  * @param[in] req
164  *   Pointer to the request structure.
165  * @param[in] len
166  *   Length of the request in bytes.
167  *
168  * @return
169  *   The number of sent bytes on success, a negative errno value otherwise and
170  *   rte_errno is set.
171  */
172 static int
173 mlx5_nl_request(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn, void *req,
174                 int len)
175 {
176         struct sockaddr_nl sa = {
177                 .nl_family = AF_NETLINK,
178         };
179         struct iovec iov[2] = {
180                 { .iov_base = nh, .iov_len = sizeof(*nh), },
181                 { .iov_base = req, .iov_len = len, },
182         };
183         struct msghdr msg = {
184                 .msg_name = &sa,
185                 .msg_namelen = sizeof(sa),
186                 .msg_iov = iov,
187                 .msg_iovlen = 2,
188         };
189         int send_bytes;
190
191         nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
192         nh->nlmsg_seq = sn;
193         send_bytes = sendmsg(nlsk_fd, &msg, 0);
194         if (send_bytes < 0) {
195                 rte_errno = errno;
196                 return -rte_errno;
197         }
198         return send_bytes;
199 }
200
201 /**
202  * Send a message to the kernel on the Netlink socket.
203  *
204  * @param[in] nlsk_fd
205  *   The Netlink socket file descriptor used for communication.
206  * @param[in] nh
207  *   The Netlink message send to the kernel.
208  * @param[in] sn
209  *   Sequence number.
210  *
211  * @return
212  *   The number of sent bytes on success, a negative errno value otherwise and
213  *   rte_errno is set.
214  */
215 static int
216 mlx5_nl_send(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn)
217 {
218         struct sockaddr_nl sa = {
219                 .nl_family = AF_NETLINK,
220         };
221         struct iovec iov = {
222                 .iov_base = nh,
223                 .iov_len = nh->nlmsg_len,
224         };
225         struct msghdr msg = {
226                 .msg_name = &sa,
227                 .msg_namelen = sizeof(sa),
228                 .msg_iov = &iov,
229                 .msg_iovlen = 1,
230         };
231         int send_bytes;
232
233         nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
234         nh->nlmsg_seq = sn;
235         send_bytes = sendmsg(nlsk_fd, &msg, 0);
236         if (send_bytes < 0) {
237                 rte_errno = errno;
238                 return -rte_errno;
239         }
240         return send_bytes;
241 }
242
243 /**
244  * Receive a message from the kernel on the Netlink socket, following
245  * mlx5_nl_send().
246  *
247  * @param[in] nlsk_fd
248  *   The Netlink socket file descriptor used for communication.
249  * @param[in] sn
250  *   Sequence number.
251  * @param[in] cb
252  *   The callback function to call for each Netlink message received.
253  * @param[in, out] arg
254  *   Custom arguments for the callback.
255  *
256  * @return
257  *   0 on success, a negative errno value otherwise and rte_errno is set.
258  */
259 static int
260 mlx5_nl_recv(int nlsk_fd, uint32_t sn, int (*cb)(struct nlmsghdr *, void *arg),
261              void *arg)
262 {
263         struct sockaddr_nl sa;
264         char buf[MLX5_RECV_BUF_SIZE];
265         struct iovec iov = {
266                 .iov_base = buf,
267                 .iov_len = sizeof(buf),
268         };
269         struct msghdr msg = {
270                 .msg_name = &sa,
271                 .msg_namelen = sizeof(sa),
272                 .msg_iov = &iov,
273                 /* One message at a time */
274                 .msg_iovlen = 1,
275         };
276         int multipart = 0;
277         int ret = 0;
278
279         do {
280                 struct nlmsghdr *nh;
281                 int recv_bytes = 0;
282
283                 do {
284                         recv_bytes = recvmsg(nlsk_fd, &msg, 0);
285                         if (recv_bytes == -1) {
286                                 rte_errno = errno;
287                                 return -rte_errno;
288                         }
289                         nh = (struct nlmsghdr *)buf;
290                 } while (nh->nlmsg_seq != sn);
291                 for (;
292                      NLMSG_OK(nh, (unsigned int)recv_bytes);
293                      nh = NLMSG_NEXT(nh, recv_bytes)) {
294                         if (nh->nlmsg_type == NLMSG_ERROR) {
295                                 struct nlmsgerr *err_data = NLMSG_DATA(nh);
296
297                                 if (err_data->error < 0) {
298                                         rte_errno = -err_data->error;
299                                         return -rte_errno;
300                                 }
301                                 /* Ack message. */
302                                 return 0;
303                         }
304                         /* Multi-part msgs and their trailing DONE message. */
305                         if (nh->nlmsg_flags & NLM_F_MULTI) {
306                                 if (nh->nlmsg_type == NLMSG_DONE)
307                                         return 0;
308                                 multipart = 1;
309                         }
310                         if (cb) {
311                                 ret = cb(nh, arg);
312                                 if (ret < 0)
313                                         return ret;
314                         }
315                 }
316         } while (multipart);
317         return ret;
318 }
319
320 /**
321  * Parse Netlink message to retrieve the bridge MAC address.
322  *
323  * @param nh
324  *   Pointer to Netlink Message Header.
325  * @param arg
326  *   PMD data register with this callback.
327  *
328  * @return
329  *   0 on success, a negative errno value otherwise and rte_errno is set.
330  */
331 static int
332 mlx5_nl_mac_addr_cb(struct nlmsghdr *nh, void *arg)
333 {
334         struct mlx5_nl_mac_addr *data = arg;
335         struct ndmsg *r = NLMSG_DATA(nh);
336         struct rtattr *attribute;
337         int len;
338
339         len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
340         for (attribute = MLX5_NDA_RTA(r);
341              RTA_OK(attribute, len);
342              attribute = RTA_NEXT(attribute, len)) {
343                 if (attribute->rta_type == NDA_LLADDR) {
344                         if (data->mac_n == MLX5_MAX_MAC_ADDRESSES) {
345                                 DRV_LOG(WARNING,
346                                         "not enough room to finalize the"
347                                         " request");
348                                 rte_errno = ENOMEM;
349                                 return -rte_errno;
350                         }
351 #ifndef NDEBUG
352                         char m[18];
353
354                         rte_ether_format_addr(m, 18, RTA_DATA(attribute));
355                         DRV_LOG(DEBUG, "bridge MAC address %s", m);
356 #endif
357                         memcpy(&(*data->mac)[data->mac_n++],
358                                RTA_DATA(attribute), RTE_ETHER_ADDR_LEN);
359                 }
360         }
361         return 0;
362 }
363
364 /**
365  * Get bridge MAC addresses.
366  *
367  * @param dev
368  *   Pointer to Ethernet device.
369  * @param mac[out]
370  *   Pointer to the array table of MAC addresses to fill.
371  *   Its size should be of MLX5_MAX_MAC_ADDRESSES.
372  * @param mac_n[out]
373  *   Number of entries filled in MAC array.
374  *
375  * @return
376  *   0 on success, a negative errno value otherwise and rte_errno is set.
377  */
378 static int
379 mlx5_nl_mac_addr_list(struct rte_eth_dev *dev, struct rte_ether_addr (*mac)[],
380                       int *mac_n)
381 {
382         struct mlx5_priv *priv = dev->data->dev_private;
383         unsigned int iface_idx = mlx5_ifindex(dev);
384         struct {
385                 struct nlmsghdr hdr;
386                 struct ifinfomsg ifm;
387         } req = {
388                 .hdr = {
389                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
390                         .nlmsg_type = RTM_GETNEIGH,
391                         .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
392                 },
393                 .ifm = {
394                         .ifi_family = PF_BRIDGE,
395                         .ifi_index = iface_idx,
396                 },
397         };
398         struct mlx5_nl_mac_addr data = {
399                 .mac = mac,
400                 .mac_n = 0,
401         };
402         int fd;
403         int ret;
404         uint32_t sn = priv->nl_sn++;
405
406         if (priv->nl_socket_route == -1)
407                 return 0;
408         fd = priv->nl_socket_route;
409         ret = mlx5_nl_request(fd, &req.hdr, sn, &req.ifm,
410                               sizeof(struct ifinfomsg));
411         if (ret < 0)
412                 goto error;
413         ret = mlx5_nl_recv(fd, sn, mlx5_nl_mac_addr_cb, &data);
414         if (ret < 0)
415                 goto error;
416         *mac_n = data.mac_n;
417         return 0;
418 error:
419         DRV_LOG(DEBUG, "port %u cannot retrieve MAC address list %s",
420                 dev->data->port_id, strerror(rte_errno));
421         return -rte_errno;
422 }
423
424 /**
425  * Modify the MAC address neighbour table with Netlink.
426  *
427  * @param dev
428  *   Pointer to Ethernet device.
429  * @param mac
430  *   MAC address to consider.
431  * @param add
432  *   1 to add the MAC address, 0 to remove the MAC address.
433  *
434  * @return
435  *   0 on success, a negative errno value otherwise and rte_errno is set.
436  */
437 static int
438 mlx5_nl_mac_addr_modify(struct rte_eth_dev *dev, struct rte_ether_addr *mac,
439                         int add)
440 {
441         struct mlx5_priv *priv = dev->data->dev_private;
442         unsigned int iface_idx = mlx5_ifindex(dev);
443         struct {
444                 struct nlmsghdr hdr;
445                 struct ndmsg ndm;
446                 struct rtattr rta;
447                 uint8_t buffer[RTE_ETHER_ADDR_LEN];
448         } req = {
449                 .hdr = {
450                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
451                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
452                                 NLM_F_EXCL | NLM_F_ACK,
453                         .nlmsg_type = add ? RTM_NEWNEIGH : RTM_DELNEIGH,
454                 },
455                 .ndm = {
456                         .ndm_family = PF_BRIDGE,
457                         .ndm_state = NUD_NOARP | NUD_PERMANENT,
458                         .ndm_ifindex = iface_idx,
459                         .ndm_flags = NTF_SELF,
460                 },
461                 .rta = {
462                         .rta_type = NDA_LLADDR,
463                         .rta_len = RTA_LENGTH(RTE_ETHER_ADDR_LEN),
464                 },
465         };
466         int fd;
467         int ret;
468         uint32_t sn = priv->nl_sn++;
469
470         if (priv->nl_socket_route == -1)
471                 return 0;
472         fd = priv->nl_socket_route;
473         memcpy(RTA_DATA(&req.rta), mac, RTE_ETHER_ADDR_LEN);
474         req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
475                 RTA_ALIGN(req.rta.rta_len);
476         ret = mlx5_nl_send(fd, &req.hdr, sn);
477         if (ret < 0)
478                 goto error;
479         ret = mlx5_nl_recv(fd, sn, NULL, NULL);
480         if (ret < 0)
481                 goto error;
482         return 0;
483 error:
484         DRV_LOG(DEBUG,
485                 "port %u cannot %s MAC address %02X:%02X:%02X:%02X:%02X:%02X"
486                 " %s",
487                 dev->data->port_id,
488                 add ? "add" : "remove",
489                 mac->addr_bytes[0], mac->addr_bytes[1],
490                 mac->addr_bytes[2], mac->addr_bytes[3],
491                 mac->addr_bytes[4], mac->addr_bytes[5],
492                 strerror(rte_errno));
493         return -rte_errno;
494 }
495
496 /**
497  * Add a MAC address.
498  *
499  * @param dev
500  *   Pointer to Ethernet device.
501  * @param mac
502  *   MAC address to register.
503  * @param index
504  *   MAC address index.
505  *
506  * @return
507  *   0 on success, a negative errno value otherwise and rte_errno is set.
508  */
509 int
510 mlx5_nl_mac_addr_add(struct rte_eth_dev *dev, struct rte_ether_addr *mac,
511                      uint32_t index)
512 {
513         struct mlx5_priv *priv = dev->data->dev_private;
514         int ret;
515
516         ret = mlx5_nl_mac_addr_modify(dev, mac, 1);
517         if (!ret)
518                 BITFIELD_SET(priv->mac_own, index);
519         if (ret == -EEXIST)
520                 return 0;
521         return ret;
522 }
523
524 /**
525  * Remove a MAC address.
526  *
527  * @param dev
528  *   Pointer to Ethernet device.
529  * @param mac
530  *   MAC address to remove.
531  * @param index
532  *   MAC address index.
533  *
534  * @return
535  *   0 on success, a negative errno value otherwise and rte_errno is set.
536  */
537 int
538 mlx5_nl_mac_addr_remove(struct rte_eth_dev *dev, struct rte_ether_addr *mac,
539                         uint32_t index)
540 {
541         struct mlx5_priv *priv = dev->data->dev_private;
542
543         BITFIELD_RESET(priv->mac_own, index);
544         return mlx5_nl_mac_addr_modify(dev, mac, 0);
545 }
546
547 /**
548  * Synchronize Netlink bridge table to the internal table.
549  *
550  * @param dev
551  *   Pointer to Ethernet device.
552  */
553 void
554 mlx5_nl_mac_addr_sync(struct rte_eth_dev *dev)
555 {
556         struct rte_ether_addr macs[MLX5_MAX_MAC_ADDRESSES];
557         int macs_n = 0;
558         int i;
559         int ret;
560
561         ret = mlx5_nl_mac_addr_list(dev, &macs, &macs_n);
562         if (ret)
563                 return;
564         for (i = 0; i != macs_n; ++i) {
565                 int j;
566
567                 /* Verify the address is not in the array yet. */
568                 for (j = 0; j != MLX5_MAX_MAC_ADDRESSES; ++j)
569                         if (rte_is_same_ether_addr(&macs[i],
570                                                &dev->data->mac_addrs[j]))
571                                 break;
572                 if (j != MLX5_MAX_MAC_ADDRESSES)
573                         continue;
574                 /* Find the first entry available. */
575                 for (j = 0; j != MLX5_MAX_MAC_ADDRESSES; ++j) {
576                         if (rte_is_zero_ether_addr(&dev->data->mac_addrs[j])) {
577                                 dev->data->mac_addrs[j] = macs[i];
578                                 break;
579                         }
580                 }
581         }
582 }
583
584 /**
585  * Flush all added MAC addresses.
586  *
587  * @param dev
588  *   Pointer to Ethernet device.
589  */
590 void
591 mlx5_nl_mac_addr_flush(struct rte_eth_dev *dev)
592 {
593         struct mlx5_priv *priv = dev->data->dev_private;
594         int i;
595
596         for (i = MLX5_MAX_MAC_ADDRESSES - 1; i >= 0; --i) {
597                 struct rte_ether_addr *m = &dev->data->mac_addrs[i];
598
599                 if (BITFIELD_ISSET(priv->mac_own, i))
600                         mlx5_nl_mac_addr_remove(dev, m, i);
601         }
602 }
603
604 /**
605  * Enable promiscuous / all multicast mode through Netlink.
606  *
607  * @param dev
608  *   Pointer to Ethernet device structure.
609  * @param flags
610  *   IFF_PROMISC for promiscuous, IFF_ALLMULTI for allmulti.
611  * @param enable
612  *   Nonzero to enable, disable otherwise.
613  *
614  * @return
615  *   0 on success, a negative errno value otherwise and rte_errno is set.
616  */
617 static int
618 mlx5_nl_device_flags(struct rte_eth_dev *dev, uint32_t flags, int enable)
619 {
620         struct mlx5_priv *priv = dev->data->dev_private;
621         unsigned int iface_idx = mlx5_ifindex(dev);
622         struct {
623                 struct nlmsghdr hdr;
624                 struct ifinfomsg ifi;
625         } req = {
626                 .hdr = {
627                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
628                         .nlmsg_type = RTM_NEWLINK,
629                         .nlmsg_flags = NLM_F_REQUEST,
630                 },
631                 .ifi = {
632                         .ifi_flags = enable ? flags : 0,
633                         .ifi_change = flags,
634                         .ifi_index = iface_idx,
635                 },
636         };
637         int fd;
638         int ret;
639
640         assert(!(flags & ~(IFF_PROMISC | IFF_ALLMULTI)));
641         if (priv->nl_socket_route < 0)
642                 return 0;
643         fd = priv->nl_socket_route;
644         ret = mlx5_nl_send(fd, &req.hdr, priv->nl_sn++);
645         if (ret < 0)
646                 return ret;
647         return 0;
648 }
649
650 /**
651  * Enable promiscuous mode through Netlink.
652  *
653  * @param dev
654  *   Pointer to Ethernet device structure.
655  * @param enable
656  *   Nonzero to enable, disable otherwise.
657  *
658  * @return
659  *   0 on success, a negative errno value otherwise and rte_errno is set.
660  */
661 int
662 mlx5_nl_promisc(struct rte_eth_dev *dev, int enable)
663 {
664         int ret = mlx5_nl_device_flags(dev, IFF_PROMISC, enable);
665
666         if (ret)
667                 DRV_LOG(DEBUG,
668                         "port %u cannot %s promisc mode: Netlink error %s",
669                         dev->data->port_id, enable ? "enable" : "disable",
670                         strerror(rte_errno));
671         return ret;
672 }
673
674 /**
675  * Enable all multicast mode through Netlink.
676  *
677  * @param dev
678  *   Pointer to Ethernet device structure.
679  * @param enable
680  *   Nonzero to enable, disable otherwise.
681  *
682  * @return
683  *   0 on success, a negative errno value otherwise and rte_errno is set.
684  */
685 int
686 mlx5_nl_allmulti(struct rte_eth_dev *dev, int enable)
687 {
688         int ret = mlx5_nl_device_flags(dev, IFF_ALLMULTI, enable);
689
690         if (ret)
691                 DRV_LOG(DEBUG,
692                         "port %u cannot %s allmulti mode: Netlink error %s",
693                         dev->data->port_id, enable ? "enable" : "disable",
694                         strerror(rte_errno));
695         return ret;
696 }
697
698 /**
699  * Process network interface information from Netlink message.
700  *
701  * @param nh
702  *   Pointer to Netlink message header.
703  * @param arg
704  *   Opaque data pointer for this callback.
705  *
706  * @return
707  *   0 on success, a negative errno value otherwise and rte_errno is set.
708  */
709 static int
710 mlx5_nl_cmdget_cb(struct nlmsghdr *nh, void *arg)
711 {
712         struct mlx5_nl_ifindex_data *data = arg;
713         struct mlx5_nl_ifindex_data local = {
714                 .flags = 0,
715         };
716         size_t off = NLMSG_HDRLEN;
717
718         if (nh->nlmsg_type !=
719             RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET) &&
720             nh->nlmsg_type !=
721             RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_PORT_GET))
722                 goto error;
723         while (off < nh->nlmsg_len) {
724                 struct nlattr *na = (void *)((uintptr_t)nh + off);
725                 void *payload = (void *)((uintptr_t)na + NLA_HDRLEN);
726
727                 if (na->nla_len > nh->nlmsg_len - off)
728                         goto error;
729                 switch (na->nla_type) {
730                 case RDMA_NLDEV_ATTR_DEV_INDEX:
731                         local.ibindex = *(uint32_t *)payload;
732                         local.flags |= MLX5_NL_CMD_GET_IB_INDEX;
733                         break;
734                 case RDMA_NLDEV_ATTR_DEV_NAME:
735                         if (!strcmp(payload, data->name))
736                                 local.flags |= MLX5_NL_CMD_GET_IB_NAME;
737                         break;
738                 case RDMA_NLDEV_ATTR_NDEV_INDEX:
739                         local.ifindex = *(uint32_t *)payload;
740                         local.flags |= MLX5_NL_CMD_GET_NET_INDEX;
741                         break;
742                 case RDMA_NLDEV_ATTR_PORT_INDEX:
743                         local.portnum = *(uint32_t *)payload;
744                         local.flags |= MLX5_NL_CMD_GET_PORT_INDEX;
745                         break;
746                 default:
747                         break;
748                 }
749                 off += NLA_ALIGN(na->nla_len);
750         }
751         /*
752          * It is possible to have multiple messages for all
753          * Infiniband devices in the system with appropriate name.
754          * So we should gather parameters locally and copy to
755          * query context only in case of coinciding device name.
756          */
757         if (local.flags & MLX5_NL_CMD_GET_IB_NAME) {
758                 data->flags = local.flags;
759                 data->ibindex = local.ibindex;
760                 data->ifindex = local.ifindex;
761                 data->portnum = local.portnum;
762         }
763         return 0;
764 error:
765         rte_errno = EINVAL;
766         return -rte_errno;
767 }
768
769 /**
770  * Get index of network interface associated with some IB device.
771  *
772  * This is the only somewhat safe method to avoid resorting to heuristics
773  * when faced with port representors. Unfortunately it requires at least
774  * Linux 4.17.
775  *
776  * @param nl
777  *   Netlink socket of the RDMA kind (NETLINK_RDMA).
778  * @param[in] name
779  *   IB device name.
780  * @param[in] pindex
781  *   IB device port index, starting from 1
782  * @return
783  *   A valid (nonzero) interface index on success, 0 otherwise and rte_errno
784  *   is set.
785  */
786 unsigned int
787 mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex)
788 {
789         uint32_t seq = random();
790         struct mlx5_nl_ifindex_data data = {
791                 .name = name,
792                 .flags = 0,
793                 .ibindex = 0, /* Determined during first pass. */
794                 .ifindex = 0, /* Determined during second pass. */
795         };
796         union {
797                 struct nlmsghdr nh;
798                 uint8_t buf[NLMSG_HDRLEN +
799                             NLA_HDRLEN + NLA_ALIGN(sizeof(data.ibindex)) +
800                             NLA_HDRLEN + NLA_ALIGN(sizeof(pindex))];
801         } req = {
802                 .nh = {
803                         .nlmsg_len = NLMSG_LENGTH(0),
804                         .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
805                                                        RDMA_NLDEV_CMD_GET),
806                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
807                 },
808         };
809         struct nlattr *na;
810         int ret;
811
812         ret = mlx5_nl_send(nl, &req.nh, seq);
813         if (ret < 0)
814                 return 0;
815         ret = mlx5_nl_recv(nl, seq, mlx5_nl_cmdget_cb, &data);
816         if (ret < 0)
817                 return 0;
818         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
819             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX))
820                 goto error;
821         data.flags = 0;
822         ++seq;
823         req.nh.nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
824                                              RDMA_NLDEV_CMD_PORT_GET);
825         req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
826         req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.buf) - NLMSG_HDRLEN);
827         na = (void *)((uintptr_t)req.buf + NLMSG_HDRLEN);
828         na->nla_len = NLA_HDRLEN + sizeof(data.ibindex);
829         na->nla_type = RDMA_NLDEV_ATTR_DEV_INDEX;
830         memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
831                &data.ibindex, sizeof(data.ibindex));
832         na = (void *)((uintptr_t)na + NLA_ALIGN(na->nla_len));
833         na->nla_len = NLA_HDRLEN + sizeof(pindex);
834         na->nla_type = RDMA_NLDEV_ATTR_PORT_INDEX;
835         memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
836                &pindex, sizeof(pindex));
837         ret = mlx5_nl_send(nl, &req.nh, seq);
838         if (ret < 0)
839                 return 0;
840         ret = mlx5_nl_recv(nl, seq, mlx5_nl_cmdget_cb, &data);
841         if (ret < 0)
842                 return 0;
843         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
844             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
845             !(data.flags & MLX5_NL_CMD_GET_NET_INDEX) ||
846             !data.ifindex)
847                 goto error;
848         return data.ifindex;
849 error:
850         rte_errno = ENODEV;
851         return 0;
852 }
853
854 /**
855  * Get the number of physical ports of given IB device.
856  *
857  * @param nl
858  *   Netlink socket of the RDMA kind (NETLINK_RDMA).
859  * @param[in] name
860  *   IB device name.
861  *
862  * @return
863  *   A valid (nonzero) number of ports on success, 0 otherwise
864  *   and rte_errno is set.
865  */
866 unsigned int
867 mlx5_nl_portnum(int nl, const char *name)
868 {
869         uint32_t seq = random();
870         struct mlx5_nl_ifindex_data data = {
871                 .flags = 0,
872                 .name = name,
873                 .ifindex = 0,
874                 .portnum = 0,
875         };
876         struct nlmsghdr req = {
877                 .nlmsg_len = NLMSG_LENGTH(0),
878                 .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
879                                                RDMA_NLDEV_CMD_GET),
880                 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
881         };
882         int ret;
883
884         ret = mlx5_nl_send(nl, &req, seq);
885         if (ret < 0)
886                 return 0;
887         ret = mlx5_nl_recv(nl, seq, mlx5_nl_cmdget_cb, &data);
888         if (ret < 0)
889                 return 0;
890         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
891             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
892             !(data.flags & MLX5_NL_CMD_GET_PORT_INDEX)) {
893                 rte_errno = ENODEV;
894                 return 0;
895         }
896         if (!data.portnum)
897                 rte_errno = EINVAL;
898         return data.portnum;
899 }
900
901 /**
902  * Process switch information from Netlink message.
903  *
904  * @param nh
905  *   Pointer to Netlink message header.
906  * @param arg
907  *   Opaque data pointer for this callback.
908  *
909  * @return
910  *   0 on success, a negative errno value otherwise and rte_errno is set.
911  */
912 static int
913 mlx5_nl_switch_info_cb(struct nlmsghdr *nh, void *arg)
914 {
915         struct mlx5_switch_info info = {
916                 .master = 0,
917                 .representor = 0,
918                 .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
919                 .port_name = 0,
920                 .switch_id = 0,
921         };
922         size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
923         bool switch_id_set = false;
924         bool num_vf_set = false;
925
926         if (nh->nlmsg_type != RTM_NEWLINK)
927                 goto error;
928         while (off < nh->nlmsg_len) {
929                 struct rtattr *ra = (void *)((uintptr_t)nh + off);
930                 void *payload = RTA_DATA(ra);
931                 unsigned int i;
932
933                 if (ra->rta_len > nh->nlmsg_len - off)
934                         goto error;
935                 switch (ra->rta_type) {
936                 case IFLA_NUM_VF:
937                         num_vf_set = true;
938                         break;
939                 case IFLA_PHYS_PORT_NAME:
940                         mlx5_translate_port_name((char *)payload, &info);
941                         break;
942                 case IFLA_PHYS_SWITCH_ID:
943                         info.switch_id = 0;
944                         for (i = 0; i < RTA_PAYLOAD(ra); ++i) {
945                                 info.switch_id <<= 8;
946                                 info.switch_id |= ((uint8_t *)payload)[i];
947                         }
948                         switch_id_set = true;
949                         break;
950                 }
951                 off += RTA_ALIGN(ra->rta_len);
952         }
953         if (switch_id_set) {
954                 /* We have some E-Switch configuration. */
955                 mlx5_nl_check_switch_info(num_vf_set, &info);
956         }
957         assert(!(info.master && info.representor));
958         memcpy(arg, &info, sizeof(info));
959         return 0;
960 error:
961         rte_errno = EINVAL;
962         return -rte_errno;
963 }
964
965 /**
966  * Get switch information associated with network interface.
967  *
968  * @param nl
969  *   Netlink socket of the ROUTE kind (NETLINK_ROUTE).
970  * @param ifindex
971  *   Network interface index.
972  * @param[out] info
973  *   Switch information object, populated in case of success.
974  *
975  * @return
976  *   0 on success, a negative errno value otherwise and rte_errno is set.
977  */
978 int
979 mlx5_nl_switch_info(int nl, unsigned int ifindex, struct mlx5_switch_info *info)
980 {
981         uint32_t seq = random();
982         struct {
983                 struct nlmsghdr nh;
984                 struct ifinfomsg info;
985                 struct rtattr rta;
986                 uint32_t extmask;
987         } req = {
988                 .nh = {
989                         .nlmsg_len = NLMSG_LENGTH
990                                         (sizeof(req.info) +
991                                          RTA_LENGTH(sizeof(uint32_t))),
992                         .nlmsg_type = RTM_GETLINK,
993                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
994                 },
995                 .info = {
996                         .ifi_family = AF_UNSPEC,
997                         .ifi_index = ifindex,
998                 },
999                 .rta = {
1000                         .rta_type = IFLA_EXT_MASK,
1001                         .rta_len = RTA_LENGTH(sizeof(int32_t)),
1002                 },
1003                 .extmask = RTE_LE32(1),
1004         };
1005         int ret;
1006
1007         ret = mlx5_nl_send(nl, &req.nh, seq);
1008         if (ret >= 0)
1009                 ret = mlx5_nl_recv(nl, seq, mlx5_nl_switch_info_cb, info);
1010         if (info->master && info->representor) {
1011                 DRV_LOG(ERR, "ifindex %u device is recognized as master"
1012                              " and as representor", ifindex);
1013                 rte_errno = ENODEV;
1014                 ret = -rte_errno;
1015         }
1016         return ret;
1017 }
1018
1019 /*
1020  * Delete VLAN network device by ifindex.
1021  *
1022  * @param[in] tcf
1023  *   Context object initialized by mlx5_vlan_vmwa_init().
1024  * @param[in] ifindex
1025  *   Interface index of network device to delete.
1026  */
1027 static void
1028 mlx5_vlan_vmwa_delete(struct mlx5_vlan_vmwa_context *vmwa,
1029                       uint32_t ifindex)
1030 {
1031         int ret;
1032         struct {
1033                 struct nlmsghdr nh;
1034                 struct ifinfomsg info;
1035         } req = {
1036                 .nh = {
1037                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
1038                         .nlmsg_type = RTM_DELLINK,
1039                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
1040                 },
1041                 .info = {
1042                         .ifi_family = AF_UNSPEC,
1043                         .ifi_index = ifindex,
1044                 },
1045         };
1046
1047         if (ifindex) {
1048                 ++vmwa->nl_sn;
1049                 if (!vmwa->nl_sn)
1050                         ++vmwa->nl_sn;
1051                 ret = mlx5_nl_send(vmwa->nl_socket, &req.nh, vmwa->nl_sn);
1052                 if (ret >= 0)
1053                         ret = mlx5_nl_recv(vmwa->nl_socket,
1054                                            vmwa->nl_sn,
1055                                            NULL, NULL);
1056                 if (ret < 0)
1057                         DRV_LOG(WARNING, "netlink: error deleting"
1058                                          " VLAN WA ifindex %u, %d",
1059                                          ifindex, ret);
1060         }
1061 }
1062
1063 /* Set of subroutines to build Netlink message. */
1064 static struct nlattr *
1065 nl_msg_tail(struct nlmsghdr *nlh)
1066 {
1067         return (struct nlattr *)
1068                 (((uint8_t *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1069 }
1070
1071 static void
1072 nl_attr_put(struct nlmsghdr *nlh, int type, const void *data, int alen)
1073 {
1074         struct nlattr *nla = nl_msg_tail(nlh);
1075
1076         nla->nla_type = type;
1077         nla->nla_len = NLMSG_ALIGN(sizeof(struct nlattr) + alen);
1078         nlh->nlmsg_len = NLMSG_ALIGN(nlh->nlmsg_len) + nla->nla_len;
1079
1080         if (alen)
1081                 memcpy((uint8_t *)nla + sizeof(struct nlattr), data, alen);
1082 }
1083
1084 static struct nlattr *
1085 nl_attr_nest_start(struct nlmsghdr *nlh, int type)
1086 {
1087         struct nlattr *nest = (struct nlattr *)nl_msg_tail(nlh);
1088
1089         nl_attr_put(nlh, type, NULL, 0);
1090         return nest;
1091 }
1092
1093 static void
1094 nl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *nest)
1095 {
1096         nest->nla_len = (uint8_t *)nl_msg_tail(nlh) - (uint8_t *)nest;
1097 }
1098
1099 /*
1100  * Create network VLAN device with specified VLAN tag.
1101  *
1102  * @param[in] tcf
1103  *   Context object initialized by mlx5_vlan_vmwa_init().
1104  * @param[in] ifindex
1105  *   Base network interface index.
1106  * @param[in] tag
1107  *   VLAN tag for VLAN network device to create.
1108  */
1109 static uint32_t
1110 mlx5_vlan_vmwa_create(struct mlx5_vlan_vmwa_context *vmwa,
1111                       uint32_t ifindex,
1112                       uint16_t tag)
1113 {
1114         struct nlmsghdr *nlh;
1115         struct ifinfomsg *ifm;
1116         char name[sizeof(MLX5_VMWA_VLAN_DEVICE_PFX) + 32];
1117
1118         alignas(RTE_CACHE_LINE_SIZE)
1119         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1120                     NLMSG_ALIGN(sizeof(struct ifinfomsg)) +
1121                     NLMSG_ALIGN(sizeof(struct nlattr)) * 8 +
1122                     NLMSG_ALIGN(sizeof(uint32_t)) +
1123                     NLMSG_ALIGN(sizeof(name)) +
1124                     NLMSG_ALIGN(sizeof("vlan")) +
1125                     NLMSG_ALIGN(sizeof(uint32_t)) +
1126                     NLMSG_ALIGN(sizeof(uint16_t)) + 16];
1127         struct nlattr *na_info;
1128         struct nlattr *na_vlan;
1129         int ret;
1130
1131         memset(buf, 0, sizeof(buf));
1132         ++vmwa->nl_sn;
1133         if (!vmwa->nl_sn)
1134                 ++vmwa->nl_sn;
1135         nlh = (struct nlmsghdr *)buf;
1136         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1137         nlh->nlmsg_type = RTM_NEWLINK;
1138         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
1139                            NLM_F_EXCL | NLM_F_ACK;
1140         ifm = (struct ifinfomsg *)nl_msg_tail(nlh);
1141         nlh->nlmsg_len += sizeof(struct ifinfomsg);
1142         ifm->ifi_family = AF_UNSPEC;
1143         ifm->ifi_type = 0;
1144         ifm->ifi_index = 0;
1145         ifm->ifi_flags = IFF_UP;
1146         ifm->ifi_change = 0xffffffff;
1147         nl_attr_put(nlh, IFLA_LINK, &ifindex, sizeof(ifindex));
1148         ret = snprintf(name, sizeof(name), "%s.%u.%u",
1149                        MLX5_VMWA_VLAN_DEVICE_PFX, ifindex, tag);
1150         nl_attr_put(nlh, IFLA_IFNAME, name, ret + 1);
1151         na_info = nl_attr_nest_start(nlh, IFLA_LINKINFO);
1152         nl_attr_put(nlh, IFLA_INFO_KIND, "vlan", sizeof("vlan"));
1153         na_vlan = nl_attr_nest_start(nlh, IFLA_INFO_DATA);
1154         nl_attr_put(nlh, IFLA_VLAN_ID, &tag, sizeof(tag));
1155         nl_attr_nest_end(nlh, na_vlan);
1156         nl_attr_nest_end(nlh, na_info);
1157         assert(sizeof(buf) >= nlh->nlmsg_len);
1158         ret = mlx5_nl_send(vmwa->nl_socket, nlh, vmwa->nl_sn);
1159         if (ret >= 0)
1160                 ret = mlx5_nl_recv(vmwa->nl_socket, vmwa->nl_sn, NULL, NULL);
1161         if (ret < 0) {
1162                 DRV_LOG(WARNING,
1163                         "netlink: VLAN %s create failure (%d)",
1164                         name, ret);
1165         }
1166         // Try to get ifindex of created or pre-existing device.
1167         ret = if_nametoindex(name);
1168         if (!ret) {
1169                 DRV_LOG(WARNING,
1170                         "VLAN %s failed to get index (%d)",
1171                         name, errno);
1172                 return 0;
1173         }
1174         return ret;
1175 }
1176
1177 /*
1178  * Release VLAN network device, created for VM workaround.
1179  *
1180  * @param[in] dev
1181  *   Ethernet device object, Netlink context provider.
1182  * @param[in] vlan
1183  *   Object representing the network device to release.
1184  */
1185 void mlx5_vlan_vmwa_release(struct rte_eth_dev *dev,
1186                             struct mlx5_vf_vlan *vlan)
1187 {
1188         struct mlx5_priv *priv = dev->data->dev_private;
1189         struct mlx5_vlan_vmwa_context *vmwa = priv->vmwa_context;
1190         struct mlx5_vlan_dev *vlan_dev = &vmwa->vlan_dev[0];
1191
1192         assert(vlan->created);
1193         assert(priv->vmwa_context);
1194         if (!vlan->created || !vmwa)
1195                 return;
1196         vlan->created = 0;
1197         assert(vlan_dev[vlan->tag].refcnt);
1198         if (--vlan_dev[vlan->tag].refcnt == 0 &&
1199             vlan_dev[vlan->tag].ifindex) {
1200                 mlx5_vlan_vmwa_delete(vmwa, vlan_dev[vlan->tag].ifindex);
1201                 vlan_dev[vlan->tag].ifindex = 0;
1202         }
1203 }
1204
1205 /**
1206  * Acquire VLAN interface with specified tag for VM workaround.
1207  *
1208  * @param[in] dev
1209  *   Ethernet device object, Netlink context provider.
1210  * @param[in] vlan
1211  *   Object representing the network device to acquire.
1212  */
1213 void mlx5_vlan_vmwa_acquire(struct rte_eth_dev *dev,
1214                             struct mlx5_vf_vlan *vlan)
1215 {
1216         struct mlx5_priv *priv = dev->data->dev_private;
1217         struct mlx5_vlan_vmwa_context *vmwa = priv->vmwa_context;
1218         struct mlx5_vlan_dev *vlan_dev = &vmwa->vlan_dev[0];
1219
1220         assert(!vlan->created);
1221         assert(priv->vmwa_context);
1222         if (vlan->created || !vmwa)
1223                 return;
1224         if (vlan_dev[vlan->tag].refcnt == 0) {
1225                 assert(!vlan_dev[vlan->tag].ifindex);
1226                 vlan_dev[vlan->tag].ifindex =
1227                         mlx5_vlan_vmwa_create(vmwa,
1228                                               vmwa->vf_ifindex,
1229                                               vlan->tag);
1230         }
1231         if (vlan_dev[vlan->tag].ifindex) {
1232                 vlan_dev[vlan->tag].refcnt++;
1233                 vlan->created = 1;
1234         }
1235 }
1236
1237 /*
1238  * Create per ethernet device VLAN VM workaround context
1239  */
1240 struct mlx5_vlan_vmwa_context *
1241 mlx5_vlan_vmwa_init(struct rte_eth_dev *dev,
1242                     uint32_t ifindex)
1243 {
1244         struct mlx5_priv *priv = dev->data->dev_private;
1245         struct mlx5_dev_config *config = &priv->config;
1246         struct mlx5_vlan_vmwa_context *vmwa;
1247         enum rte_hypervisor hv_type;
1248
1249         /* Do not engage workaround over PF. */
1250         if (!config->vf)
1251                 return NULL;
1252         /* Check whether there is desired virtual environment */
1253         hv_type = rte_hypervisor_get();
1254         switch (hv_type) {
1255         case RTE_HYPERVISOR_UNKNOWN:
1256         case RTE_HYPERVISOR_VMWARE:
1257                 /*
1258                  * The "white list" of configurations
1259                  * to engage the workaround.
1260                  */
1261                 break;
1262         default:
1263                 /*
1264                  * The configuration is not found in the "white list".
1265                  * We should not engage the VLAN workaround.
1266                  */
1267                 return NULL;
1268         }
1269         vmwa = rte_zmalloc(__func__, sizeof(*vmwa), sizeof(uint32_t));
1270         if (!vmwa) {
1271                 DRV_LOG(WARNING,
1272                         "Can not allocate memory"
1273                         " for VLAN workaround context");
1274                 return NULL;
1275         }
1276         vmwa->nl_socket = mlx5_nl_init(NETLINK_ROUTE);
1277         if (vmwa->nl_socket < 0) {
1278                 DRV_LOG(WARNING,
1279                         "Can not create Netlink socket"
1280                         " for VLAN workaround context");
1281                 rte_free(vmwa);
1282                 return NULL;
1283         }
1284         vmwa->nl_sn = random();
1285         vmwa->vf_ifindex = ifindex;
1286         vmwa->dev = dev;
1287         /* Cleanup for existing VLAN devices. */
1288         return vmwa;
1289 }
1290
1291 /*
1292  * Destroy per ethernet device VLAN VM workaround context
1293  */
1294 void mlx5_vlan_vmwa_exit(struct mlx5_vlan_vmwa_context *vmwa)
1295 {
1296         unsigned int i;
1297
1298         /* Delete all remaining VLAN devices. */
1299         for (i = 0; i < RTE_DIM(vmwa->vlan_dev); i++) {
1300                 if (vmwa->vlan_dev[i].ifindex)
1301                         mlx5_vlan_vmwa_delete(vmwa, vmwa->vlan_dev[i].ifindex);
1302         }
1303         if (vmwa->nl_socket >= 0)
1304                 close(vmwa->nl_socket);
1305         rte_free(vmwa);
1306 }