common/mlx5: fix MAC addresses assert
[dpdk.git] / drivers / common / 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/rtnetlink.h>
9 #include <linux/genetlink.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_atomic.h>
22
23 #include "mlx5_nl.h"
24 #include "mlx5_common_utils.h"
25 #ifdef HAVE_DEVLINK
26 #include <linux/devlink.h>
27 #endif
28
29
30 /* Size of the buffer to receive kernel messages */
31 #define MLX5_NL_BUF_SIZE (32 * 1024)
32 /* Send buffer size for the Netlink socket */
33 #define MLX5_SEND_BUF_SIZE 32768
34 /* Receive buffer size for the Netlink socket */
35 #define MLX5_RECV_BUF_SIZE 32768
36
37 /** Parameters of VLAN devices created by driver. */
38 #define MLX5_VMWA_VLAN_DEVICE_PFX "evmlx"
39 /*
40  * Define NDA_RTA as defined in iproute2 sources.
41  *
42  * see in iproute2 sources file include/libnetlink.h
43  */
44 #ifndef MLX5_NDA_RTA
45 #define MLX5_NDA_RTA(r) \
46         ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
47 #endif
48 /*
49  * Define NLMSG_TAIL as defined in iproute2 sources.
50  *
51  * see in iproute2 sources file include/libnetlink.h
52  */
53 #ifndef NLMSG_TAIL
54 #define NLMSG_TAIL(nmsg) \
55         ((struct rtattr *)(((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
56 #endif
57 /*
58  * The following definitions are normally found in rdma/rdma_netlink.h,
59  * however they are so recent that most systems do not expose them yet.
60  */
61 #ifndef HAVE_RDMA_NL_NLDEV
62 #define RDMA_NL_NLDEV 5
63 #endif
64 #ifndef HAVE_RDMA_NLDEV_CMD_GET
65 #define RDMA_NLDEV_CMD_GET 1
66 #endif
67 #ifndef HAVE_RDMA_NLDEV_CMD_PORT_GET
68 #define RDMA_NLDEV_CMD_PORT_GET 5
69 #endif
70 #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_INDEX
71 #define RDMA_NLDEV_ATTR_DEV_INDEX 1
72 #endif
73 #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_NAME
74 #define RDMA_NLDEV_ATTR_DEV_NAME 2
75 #endif
76 #ifndef HAVE_RDMA_NLDEV_ATTR_PORT_INDEX
77 #define RDMA_NLDEV_ATTR_PORT_INDEX 3
78 #endif
79 #ifndef HAVE_RDMA_NLDEV_ATTR_NDEV_INDEX
80 #define RDMA_NLDEV_ATTR_NDEV_INDEX 50
81 #endif
82
83 /* These are normally found in linux/if_link.h. */
84 #ifndef HAVE_IFLA_NUM_VF
85 #define IFLA_NUM_VF 21
86 #endif
87 #ifndef HAVE_IFLA_EXT_MASK
88 #define IFLA_EXT_MASK 29
89 #endif
90 #ifndef HAVE_IFLA_PHYS_SWITCH_ID
91 #define IFLA_PHYS_SWITCH_ID 36
92 #endif
93 #ifndef HAVE_IFLA_PHYS_PORT_NAME
94 #define IFLA_PHYS_PORT_NAME 38
95 #endif
96
97 /*
98  * Some Devlink defines may be missed in old kernel versions,
99  * adjust used defines.
100  */
101 #ifndef DEVLINK_GENL_NAME
102 #define DEVLINK_GENL_NAME "devlink"
103 #endif
104 #ifndef DEVLINK_GENL_VERSION
105 #define DEVLINK_GENL_VERSION 1
106 #endif
107 #ifndef DEVLINK_ATTR_BUS_NAME
108 #define DEVLINK_ATTR_BUS_NAME 1
109 #endif
110 #ifndef DEVLINK_ATTR_DEV_NAME
111 #define DEVLINK_ATTR_DEV_NAME 2
112 #endif
113 #ifndef DEVLINK_ATTR_PARAM
114 #define DEVLINK_ATTR_PARAM 80
115 #endif
116 #ifndef DEVLINK_ATTR_PARAM_NAME
117 #define DEVLINK_ATTR_PARAM_NAME 81
118 #endif
119 #ifndef DEVLINK_ATTR_PARAM_TYPE
120 #define DEVLINK_ATTR_PARAM_TYPE 83
121 #endif
122 #ifndef DEVLINK_ATTR_PARAM_VALUES_LIST
123 #define DEVLINK_ATTR_PARAM_VALUES_LIST 84
124 #endif
125 #ifndef DEVLINK_ATTR_PARAM_VALUE
126 #define DEVLINK_ATTR_PARAM_VALUE 85
127 #endif
128 #ifndef DEVLINK_ATTR_PARAM_VALUE_DATA
129 #define DEVLINK_ATTR_PARAM_VALUE_DATA 86
130 #endif
131 #ifndef DEVLINK_ATTR_PARAM_VALUE_CMODE
132 #define DEVLINK_ATTR_PARAM_VALUE_CMODE 87
133 #endif
134 #ifndef DEVLINK_PARAM_CMODE_DRIVERINIT
135 #define DEVLINK_PARAM_CMODE_DRIVERINIT 1
136 #endif
137 #ifndef DEVLINK_CMD_RELOAD
138 #define DEVLINK_CMD_RELOAD 37
139 #endif
140 #ifndef DEVLINK_CMD_PARAM_GET
141 #define DEVLINK_CMD_PARAM_GET 38
142 #endif
143 #ifndef DEVLINK_CMD_PARAM_SET
144 #define DEVLINK_CMD_PARAM_SET 39
145 #endif
146 #ifndef NLA_FLAG
147 #define NLA_FLAG 6
148 #endif
149
150 /* Add/remove MAC address through Netlink */
151 struct mlx5_nl_mac_addr {
152         struct rte_ether_addr (*mac)[];
153         /**< MAC address handled by the device. */
154         int mac_n; /**< Number of addresses in the array. */
155 };
156
157 #define MLX5_NL_CMD_GET_IB_NAME (1 << 0)
158 #define MLX5_NL_CMD_GET_IB_INDEX (1 << 1)
159 #define MLX5_NL_CMD_GET_NET_INDEX (1 << 2)
160 #define MLX5_NL_CMD_GET_PORT_INDEX (1 << 3)
161
162 /** Data structure used by mlx5_nl_cmdget_cb(). */
163 struct mlx5_nl_ifindex_data {
164         const char *name; /**< IB device name (in). */
165         uint32_t flags; /**< found attribute flags (out). */
166         uint32_t ibindex; /**< IB device index (out). */
167         uint32_t ifindex; /**< Network interface index (out). */
168         uint32_t portnum; /**< IB device max port number (out). */
169 };
170
171 rte_atomic32_t atomic_sn = RTE_ATOMIC32_INIT(0);
172
173 /* Generate Netlink sequence number. */
174 #define MLX5_NL_SN_GENERATE ((uint32_t)rte_atomic32_add_return(&atomic_sn, 1))
175
176 /**
177  * Opens a Netlink socket.
178  *
179  * @param protocol
180  *   Netlink protocol (e.g. NETLINK_ROUTE, NETLINK_RDMA).
181  *
182  * @return
183  *   A file descriptor on success, a negative errno value otherwise and
184  *   rte_errno is set.
185  */
186 int
187 mlx5_nl_init(int protocol)
188 {
189         int fd;
190         int sndbuf_size = MLX5_SEND_BUF_SIZE;
191         int rcvbuf_size = MLX5_RECV_BUF_SIZE;
192         struct sockaddr_nl local = {
193                 .nl_family = AF_NETLINK,
194         };
195         int ret;
196
197         fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
198         if (fd == -1) {
199                 rte_errno = errno;
200                 return -rte_errno;
201         }
202         ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(int));
203         if (ret == -1) {
204                 rte_errno = errno;
205                 goto error;
206         }
207         ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, sizeof(int));
208         if (ret == -1) {
209                 rte_errno = errno;
210                 goto error;
211         }
212         ret = bind(fd, (struct sockaddr *)&local, sizeof(local));
213         if (ret == -1) {
214                 rte_errno = errno;
215                 goto error;
216         }
217         return fd;
218 error:
219         close(fd);
220         return -rte_errno;
221 }
222
223 /**
224  * Send a request message to the kernel on the Netlink socket.
225  *
226  * @param[in] nlsk_fd
227  *   Netlink socket file descriptor.
228  * @param[in] nh
229  *   The Netlink message send to the kernel.
230  * @param[in] ssn
231  *   Sequence number.
232  * @param[in] req
233  *   Pointer to the request structure.
234  * @param[in] len
235  *   Length of the request in bytes.
236  *
237  * @return
238  *   The number of sent bytes on success, a negative errno value otherwise and
239  *   rte_errno is set.
240  */
241 static int
242 mlx5_nl_request(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn, void *req,
243                 int len)
244 {
245         struct sockaddr_nl sa = {
246                 .nl_family = AF_NETLINK,
247         };
248         struct iovec iov[2] = {
249                 { .iov_base = nh, .iov_len = sizeof(*nh), },
250                 { .iov_base = req, .iov_len = len, },
251         };
252         struct msghdr msg = {
253                 .msg_name = &sa,
254                 .msg_namelen = sizeof(sa),
255                 .msg_iov = iov,
256                 .msg_iovlen = 2,
257         };
258         int send_bytes;
259
260         nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
261         nh->nlmsg_seq = sn;
262         send_bytes = sendmsg(nlsk_fd, &msg, 0);
263         if (send_bytes < 0) {
264                 rte_errno = errno;
265                 return -rte_errno;
266         }
267         return send_bytes;
268 }
269
270 /**
271  * Send a message to the kernel on the Netlink socket.
272  *
273  * @param[in] nlsk_fd
274  *   The Netlink socket file descriptor used for communication.
275  * @param[in] nh
276  *   The Netlink message send to the kernel.
277  * @param[in] sn
278  *   Sequence number.
279  *
280  * @return
281  *   The number of sent bytes on success, a negative errno value otherwise and
282  *   rte_errno is set.
283  */
284 static int
285 mlx5_nl_send(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn)
286 {
287         struct sockaddr_nl sa = {
288                 .nl_family = AF_NETLINK,
289         };
290         struct iovec iov = {
291                 .iov_base = nh,
292                 .iov_len = nh->nlmsg_len,
293         };
294         struct msghdr msg = {
295                 .msg_name = &sa,
296                 .msg_namelen = sizeof(sa),
297                 .msg_iov = &iov,
298                 .msg_iovlen = 1,
299         };
300         int send_bytes;
301
302         nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
303         nh->nlmsg_seq = sn;
304         send_bytes = sendmsg(nlsk_fd, &msg, 0);
305         if (send_bytes < 0) {
306                 rte_errno = errno;
307                 return -rte_errno;
308         }
309         return send_bytes;
310 }
311
312 /**
313  * Receive a message from the kernel on the Netlink socket, following
314  * mlx5_nl_send().
315  *
316  * @param[in] nlsk_fd
317  *   The Netlink socket file descriptor used for communication.
318  * @param[in] sn
319  *   Sequence number.
320  * @param[in] cb
321  *   The callback function to call for each Netlink message received.
322  * @param[in, out] arg
323  *   Custom arguments for the callback.
324  *
325  * @return
326  *   0 on success, a negative errno value otherwise and rte_errno is set.
327  */
328 static int
329 mlx5_nl_recv(int nlsk_fd, uint32_t sn, int (*cb)(struct nlmsghdr *, void *arg),
330              void *arg)
331 {
332         struct sockaddr_nl sa;
333         char buf[MLX5_RECV_BUF_SIZE];
334         struct iovec iov = {
335                 .iov_base = buf,
336                 .iov_len = sizeof(buf),
337         };
338         struct msghdr msg = {
339                 .msg_name = &sa,
340                 .msg_namelen = sizeof(sa),
341                 .msg_iov = &iov,
342                 /* One message at a time */
343                 .msg_iovlen = 1,
344         };
345         int multipart = 0;
346         int ret = 0;
347
348         do {
349                 struct nlmsghdr *nh;
350                 int recv_bytes = 0;
351
352                 do {
353                         recv_bytes = recvmsg(nlsk_fd, &msg, 0);
354                         if (recv_bytes == -1) {
355                                 rte_errno = errno;
356                                 return -rte_errno;
357                         }
358                         nh = (struct nlmsghdr *)buf;
359                 } while (nh->nlmsg_seq != sn);
360                 for (;
361                      NLMSG_OK(nh, (unsigned int)recv_bytes);
362                      nh = NLMSG_NEXT(nh, recv_bytes)) {
363                         if (nh->nlmsg_type == NLMSG_ERROR) {
364                                 struct nlmsgerr *err_data = NLMSG_DATA(nh);
365
366                                 if (err_data->error < 0) {
367                                         rte_errno = -err_data->error;
368                                         return -rte_errno;
369                                 }
370                                 /* Ack message. */
371                                 return 0;
372                         }
373                         /* Multi-part msgs and their trailing DONE message. */
374                         if (nh->nlmsg_flags & NLM_F_MULTI) {
375                                 if (nh->nlmsg_type == NLMSG_DONE)
376                                         return 0;
377                                 multipart = 1;
378                         }
379                         if (cb) {
380                                 ret = cb(nh, arg);
381                                 if (ret < 0)
382                                         return ret;
383                         }
384                 }
385         } while (multipart);
386         return ret;
387 }
388
389 /**
390  * Parse Netlink message to retrieve the bridge MAC address.
391  *
392  * @param nh
393  *   Pointer to Netlink Message Header.
394  * @param arg
395  *   PMD data register with this callback.
396  *
397  * @return
398  *   0 on success, a negative errno value otherwise and rte_errno is set.
399  */
400 static int
401 mlx5_nl_mac_addr_cb(struct nlmsghdr *nh, void *arg)
402 {
403         struct mlx5_nl_mac_addr *data = arg;
404         struct ndmsg *r = NLMSG_DATA(nh);
405         struct rtattr *attribute;
406         int len;
407
408         len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
409         for (attribute = MLX5_NDA_RTA(r);
410              RTA_OK(attribute, len);
411              attribute = RTA_NEXT(attribute, len)) {
412                 if (attribute->rta_type == NDA_LLADDR) {
413                         if (data->mac_n == MLX5_MAX_MAC_ADDRESSES) {
414                                 DRV_LOG(WARNING,
415                                         "not enough room to finalize the"
416                                         " request");
417                                 rte_errno = ENOMEM;
418                                 return -rte_errno;
419                         }
420 #ifdef RTE_LIBRTE_MLX5_DEBUG
421                         char m[18];
422
423                         rte_ether_format_addr(m, 18, RTA_DATA(attribute));
424                         DRV_LOG(DEBUG, "bridge MAC address %s", m);
425 #endif
426                         memcpy(&(*data->mac)[data->mac_n++],
427                                RTA_DATA(attribute), RTE_ETHER_ADDR_LEN);
428                 }
429         }
430         return 0;
431 }
432
433 /**
434  * Get bridge MAC addresses.
435  *
436  * @param[in] nlsk_fd
437  *   Netlink socket file descriptor.
438  * @param[in] iface_idx
439  *   Net device interface index.
440  * @param mac[out]
441  *   Pointer to the array table of MAC addresses to fill.
442  *   Its size should be of MLX5_MAX_MAC_ADDRESSES.
443  * @param mac_n[out]
444  *   Number of entries filled in MAC array.
445  *
446  * @return
447  *   0 on success, a negative errno value otherwise and rte_errno is set.
448  */
449 static int
450 mlx5_nl_mac_addr_list(int nlsk_fd, unsigned int iface_idx,
451                       struct rte_ether_addr (*mac)[], int *mac_n)
452 {
453         struct {
454                 struct nlmsghdr hdr;
455                 struct ifinfomsg ifm;
456         } req = {
457                 .hdr = {
458                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
459                         .nlmsg_type = RTM_GETNEIGH,
460                         .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
461                 },
462                 .ifm = {
463                         .ifi_family = PF_BRIDGE,
464                         .ifi_index = iface_idx,
465                 },
466         };
467         struct mlx5_nl_mac_addr data = {
468                 .mac = mac,
469                 .mac_n = 0,
470         };
471         uint32_t sn = MLX5_NL_SN_GENERATE;
472         int ret;
473
474         if (nlsk_fd == -1)
475                 return 0;
476         ret = mlx5_nl_request(nlsk_fd, &req.hdr, sn, &req.ifm,
477                               sizeof(struct ifinfomsg));
478         if (ret < 0)
479                 goto error;
480         ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_mac_addr_cb, &data);
481         if (ret < 0)
482                 goto error;
483         *mac_n = data.mac_n;
484         return 0;
485 error:
486         DRV_LOG(DEBUG, "Interface %u cannot retrieve MAC address list %s",
487                 iface_idx, strerror(rte_errno));
488         return -rte_errno;
489 }
490
491 /**
492  * Modify the MAC address neighbour table with Netlink.
493  *
494  * @param[in] nlsk_fd
495  *   Netlink socket file descriptor.
496  * @param[in] iface_idx
497  *   Net device interface index.
498  * @param mac
499  *   MAC address to consider.
500  * @param add
501  *   1 to add the MAC address, 0 to remove the MAC address.
502  *
503  * @return
504  *   0 on success, a negative errno value otherwise and rte_errno is set.
505  */
506 static int
507 mlx5_nl_mac_addr_modify(int nlsk_fd, unsigned int iface_idx,
508                         struct rte_ether_addr *mac, int add)
509 {
510         struct {
511                 struct nlmsghdr hdr;
512                 struct ndmsg ndm;
513                 struct rtattr rta;
514                 uint8_t buffer[RTE_ETHER_ADDR_LEN];
515         } req = {
516                 .hdr = {
517                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
518                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
519                                 NLM_F_EXCL | NLM_F_ACK,
520                         .nlmsg_type = add ? RTM_NEWNEIGH : RTM_DELNEIGH,
521                 },
522                 .ndm = {
523                         .ndm_family = PF_BRIDGE,
524                         .ndm_state = NUD_NOARP | NUD_PERMANENT,
525                         .ndm_ifindex = iface_idx,
526                         .ndm_flags = NTF_SELF,
527                 },
528                 .rta = {
529                         .rta_type = NDA_LLADDR,
530                         .rta_len = RTA_LENGTH(RTE_ETHER_ADDR_LEN),
531                 },
532         };
533         uint32_t sn = MLX5_NL_SN_GENERATE;
534         int ret;
535
536         if (nlsk_fd == -1)
537                 return 0;
538         memcpy(RTA_DATA(&req.rta), mac, RTE_ETHER_ADDR_LEN);
539         req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
540                 RTA_ALIGN(req.rta.rta_len);
541         ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
542         if (ret < 0)
543                 goto error;
544         ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
545         if (ret < 0)
546                 goto error;
547         return 0;
548 error:
549         DRV_LOG(DEBUG,
550                 "Interface %u cannot %s MAC address"
551                 " %02X:%02X:%02X:%02X:%02X:%02X %s",
552                 iface_idx,
553                 add ? "add" : "remove",
554                 mac->addr_bytes[0], mac->addr_bytes[1],
555                 mac->addr_bytes[2], mac->addr_bytes[3],
556                 mac->addr_bytes[4], mac->addr_bytes[5],
557                 strerror(rte_errno));
558         return -rte_errno;
559 }
560
561 /**
562  * Modify the VF MAC address neighbour table with Netlink.
563  *
564  * @param[in] nlsk_fd
565  *   Netlink socket file descriptor.
566  * @param[in] iface_idx
567  *   Net device interface index.
568  * @param mac
569  *    MAC address to consider.
570  * @param vf_index
571  *    VF index.
572  *
573  * @return
574  *    0 on success, a negative errno value otherwise and rte_errno is set.
575  */
576 int
577 mlx5_nl_vf_mac_addr_modify(int nlsk_fd, unsigned int iface_idx,
578                            struct rte_ether_addr *mac, int vf_index)
579 {
580         int ret;
581         struct {
582                 struct nlmsghdr hdr;
583                 struct ifinfomsg ifm;
584                 struct rtattr vf_list_rta;
585                 struct rtattr vf_info_rta;
586                 struct rtattr vf_mac_rta;
587                 struct ifla_vf_mac ivm;
588         } req = {
589                 .hdr = {
590                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
591                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
592                         .nlmsg_type = RTM_BASE,
593                 },
594                 .ifm = {
595                         .ifi_index = iface_idx,
596                 },
597                 .vf_list_rta = {
598                         .rta_type = IFLA_VFINFO_LIST,
599                         .rta_len = RTA_ALIGN(RTA_LENGTH(0)),
600                 },
601                 .vf_info_rta = {
602                         .rta_type = IFLA_VF_INFO,
603                         .rta_len = RTA_ALIGN(RTA_LENGTH(0)),
604                 },
605                 .vf_mac_rta = {
606                         .rta_type = IFLA_VF_MAC,
607                 },
608         };
609         struct ifla_vf_mac ivm = {
610                 .vf = vf_index,
611         };
612         uint32_t sn = MLX5_NL_SN_GENERATE;
613
614         memcpy(&ivm.mac, mac, RTE_ETHER_ADDR_LEN);
615         memcpy(RTA_DATA(&req.vf_mac_rta), &ivm, sizeof(ivm));
616
617         req.vf_mac_rta.rta_len = RTA_LENGTH(sizeof(ivm));
618         req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
619                 RTA_ALIGN(req.vf_list_rta.rta_len) +
620                 RTA_ALIGN(req.vf_info_rta.rta_len) +
621                 RTA_ALIGN(req.vf_mac_rta.rta_len);
622         req.vf_list_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr),
623                                                &req.vf_list_rta);
624         req.vf_info_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr),
625                                                &req.vf_info_rta);
626
627         if (nlsk_fd < 0)
628                 return -1;
629         ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
630         if (ret < 0)
631                 goto error;
632         ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
633         if (ret < 0)
634                 goto error;
635         return 0;
636 error:
637         DRV_LOG(ERR,
638                 "representor %u cannot set VF MAC address "
639                 "%02X:%02X:%02X:%02X:%02X:%02X : %s",
640                 vf_index,
641                 mac->addr_bytes[0], mac->addr_bytes[1],
642                 mac->addr_bytes[2], mac->addr_bytes[3],
643                 mac->addr_bytes[4], mac->addr_bytes[5],
644                 strerror(rte_errno));
645         return -rte_errno;
646 }
647
648 /**
649  * Add a MAC address.
650  *
651  * @param[in] nlsk_fd
652  *   Netlink socket file descriptor.
653  * @param[in] iface_idx
654  *   Net device interface index.
655  * @param mac_own
656  *   BITFIELD_DECLARE array to store the mac.
657  * @param mac
658  *   MAC address to register.
659  * @param index
660  *   MAC address index.
661  *
662  * @return
663  *   0 on success, a negative errno value otherwise and rte_errno is set.
664  */
665 int
666 mlx5_nl_mac_addr_add(int nlsk_fd, unsigned int iface_idx,
667                      uint64_t *mac_own, struct rte_ether_addr *mac,
668                      uint32_t index)
669 {
670         int ret;
671
672         ret = mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 1);
673         if (!ret) {
674                 MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
675                 if (index >= MLX5_MAX_MAC_ADDRESSES)
676                         return -EINVAL;
677
678                 BITFIELD_SET(mac_own, index);
679         }
680         if (ret == -EEXIST)
681                 return 0;
682         return ret;
683 }
684
685 /**
686  * Remove a MAC address.
687  *
688  * @param[in] nlsk_fd
689  *   Netlink socket file descriptor.
690  * @param[in] iface_idx
691  *   Net device interface index.
692  * @param mac_own
693  *   BITFIELD_DECLARE array to store the mac.
694  * @param mac
695  *   MAC address to remove.
696  * @param index
697  *   MAC address index.
698  *
699  * @return
700  *   0 on success, a negative errno value otherwise and rte_errno is set.
701  */
702 int
703 mlx5_nl_mac_addr_remove(int nlsk_fd, unsigned int iface_idx, uint64_t *mac_own,
704                         struct rte_ether_addr *mac, uint32_t index)
705 {
706         MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
707         if (index >= MLX5_MAX_MAC_ADDRESSES)
708                 return -EINVAL;
709
710         BITFIELD_RESET(mac_own, index);
711         return mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 0);
712 }
713
714 /**
715  * Synchronize Netlink bridge table to the internal table.
716  *
717  * @param[in] nlsk_fd
718  *   Netlink socket file descriptor.
719  * @param[in] iface_idx
720  *   Net device interface index.
721  * @param mac_addrs
722  *   Mac addresses array to sync.
723  * @param n
724  *   @p mac_addrs array size.
725  */
726 void
727 mlx5_nl_mac_addr_sync(int nlsk_fd, unsigned int iface_idx,
728                       struct rte_ether_addr *mac_addrs, int n)
729 {
730         struct rte_ether_addr macs[n];
731         int macs_n = 0;
732         int i;
733         int ret;
734
735         ret = mlx5_nl_mac_addr_list(nlsk_fd, iface_idx, &macs, &macs_n);
736         if (ret)
737                 return;
738         for (i = 0; i != macs_n; ++i) {
739                 int j;
740
741                 /* Verify the address is not in the array yet. */
742                 for (j = 0; j != n; ++j)
743                         if (rte_is_same_ether_addr(&macs[i], &mac_addrs[j]))
744                                 break;
745                 if (j != n)
746                         continue;
747                 /* Find the first entry available. */
748                 for (j = 0; j != n; ++j) {
749                         if (rte_is_zero_ether_addr(&mac_addrs[j])) {
750                                 mac_addrs[j] = macs[i];
751                                 break;
752                         }
753                 }
754         }
755 }
756
757 /**
758  * Flush all added MAC addresses.
759  *
760  * @param[in] nlsk_fd
761  *   Netlink socket file descriptor.
762  * @param[in] iface_idx
763  *   Net device interface index.
764  * @param[in] mac_addrs
765  *   Mac addresses array to flush.
766  * @param n
767  *   @p mac_addrs array size.
768  * @param mac_own
769  *   BITFIELD_DECLARE array to store the mac.
770  */
771 void
772 mlx5_nl_mac_addr_flush(int nlsk_fd, unsigned int iface_idx,
773                        struct rte_ether_addr *mac_addrs, int n,
774                        uint64_t *mac_own)
775 {
776         int i;
777
778         if (n <= 0 || n >= MLX5_MAX_MAC_ADDRESSES)
779                 return;
780
781         for (i = n - 1; i >= 0; --i) {
782                 struct rte_ether_addr *m = &mac_addrs[i];
783
784                 if (BITFIELD_ISSET(mac_own, i))
785                         mlx5_nl_mac_addr_remove(nlsk_fd, iface_idx, mac_own, m,
786                                                 i);
787         }
788 }
789
790 /**
791  * Enable promiscuous / all multicast mode through Netlink.
792  *
793  * @param[in] nlsk_fd
794  *   Netlink socket file descriptor.
795  * @param[in] iface_idx
796  *   Net device interface index.
797  * @param flags
798  *   IFF_PROMISC for promiscuous, IFF_ALLMULTI for allmulti.
799  * @param enable
800  *   Nonzero to enable, disable otherwise.
801  *
802  * @return
803  *   0 on success, a negative errno value otherwise and rte_errno is set.
804  */
805 static int
806 mlx5_nl_device_flags(int nlsk_fd, unsigned int iface_idx, uint32_t flags,
807                      int enable)
808 {
809         struct {
810                 struct nlmsghdr hdr;
811                 struct ifinfomsg ifi;
812         } req = {
813                 .hdr = {
814                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
815                         .nlmsg_type = RTM_NEWLINK,
816                         .nlmsg_flags = NLM_F_REQUEST,
817                 },
818                 .ifi = {
819                         .ifi_flags = enable ? flags : 0,
820                         .ifi_change = flags,
821                         .ifi_index = iface_idx,
822                 },
823         };
824         uint32_t sn = MLX5_NL_SN_GENERATE;
825         int ret;
826
827         MLX5_ASSERT(!(flags & ~(IFF_PROMISC | IFF_ALLMULTI)));
828         if (nlsk_fd < 0)
829                 return 0;
830         ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
831         if (ret < 0)
832                 return ret;
833         return 0;
834 }
835
836 /**
837  * Enable promiscuous mode through Netlink.
838  *
839  * @param[in] nlsk_fd
840  *   Netlink socket file descriptor.
841  * @param[in] iface_idx
842  *   Net device interface index.
843  * @param enable
844  *   Nonzero to enable, disable otherwise.
845  *
846  * @return
847  *   0 on success, a negative errno value otherwise and rte_errno is set.
848  */
849 int
850 mlx5_nl_promisc(int nlsk_fd, unsigned int iface_idx, int enable)
851 {
852         int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_PROMISC, enable);
853
854         if (ret)
855                 DRV_LOG(DEBUG,
856                         "Interface %u cannot %s promisc mode: Netlink error %s",
857                         iface_idx, enable ? "enable" : "disable",
858                         strerror(rte_errno));
859         return ret;
860 }
861
862 /**
863  * Enable all multicast mode through Netlink.
864  *
865  * @param[in] nlsk_fd
866  *   Netlink socket file descriptor.
867  * @param[in] iface_idx
868  *   Net device interface index.
869  * @param enable
870  *   Nonzero to enable, disable otherwise.
871  *
872  * @return
873  *   0 on success, a negative errno value otherwise and rte_errno is set.
874  */
875 int
876 mlx5_nl_allmulti(int nlsk_fd, unsigned int iface_idx, int enable)
877 {
878         int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_ALLMULTI,
879                                        enable);
880
881         if (ret)
882                 DRV_LOG(DEBUG,
883                         "Interface %u cannot %s allmulti : Netlink error %s",
884                         iface_idx, enable ? "enable" : "disable",
885                         strerror(rte_errno));
886         return ret;
887 }
888
889 /**
890  * Process network interface information from Netlink message.
891  *
892  * @param nh
893  *   Pointer to Netlink message header.
894  * @param arg
895  *   Opaque data pointer for this callback.
896  *
897  * @return
898  *   0 on success, a negative errno value otherwise and rte_errno is set.
899  */
900 static int
901 mlx5_nl_cmdget_cb(struct nlmsghdr *nh, void *arg)
902 {
903         struct mlx5_nl_ifindex_data *data = arg;
904         struct mlx5_nl_ifindex_data local = {
905                 .flags = 0,
906         };
907         size_t off = NLMSG_HDRLEN;
908
909         if (nh->nlmsg_type !=
910             RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET) &&
911             nh->nlmsg_type !=
912             RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_PORT_GET))
913                 goto error;
914         while (off < nh->nlmsg_len) {
915                 struct nlattr *na = (void *)((uintptr_t)nh + off);
916                 void *payload = (void *)((uintptr_t)na + NLA_HDRLEN);
917
918                 if (na->nla_len > nh->nlmsg_len - off)
919                         goto error;
920                 switch (na->nla_type) {
921                 case RDMA_NLDEV_ATTR_DEV_INDEX:
922                         local.ibindex = *(uint32_t *)payload;
923                         local.flags |= MLX5_NL_CMD_GET_IB_INDEX;
924                         break;
925                 case RDMA_NLDEV_ATTR_DEV_NAME:
926                         if (!strcmp(payload, data->name))
927                                 local.flags |= MLX5_NL_CMD_GET_IB_NAME;
928                         break;
929                 case RDMA_NLDEV_ATTR_NDEV_INDEX:
930                         local.ifindex = *(uint32_t *)payload;
931                         local.flags |= MLX5_NL_CMD_GET_NET_INDEX;
932                         break;
933                 case RDMA_NLDEV_ATTR_PORT_INDEX:
934                         local.portnum = *(uint32_t *)payload;
935                         local.flags |= MLX5_NL_CMD_GET_PORT_INDEX;
936                         break;
937                 default:
938                         break;
939                 }
940                 off += NLA_ALIGN(na->nla_len);
941         }
942         /*
943          * It is possible to have multiple messages for all
944          * Infiniband devices in the system with appropriate name.
945          * So we should gather parameters locally and copy to
946          * query context only in case of coinciding device name.
947          */
948         if (local.flags & MLX5_NL_CMD_GET_IB_NAME) {
949                 data->flags = local.flags;
950                 data->ibindex = local.ibindex;
951                 data->ifindex = local.ifindex;
952                 data->portnum = local.portnum;
953         }
954         return 0;
955 error:
956         rte_errno = EINVAL;
957         return -rte_errno;
958 }
959
960 /**
961  * Get index of network interface associated with some IB device.
962  *
963  * This is the only somewhat safe method to avoid resorting to heuristics
964  * when faced with port representors. Unfortunately it requires at least
965  * Linux 4.17.
966  *
967  * @param nl
968  *   Netlink socket of the RDMA kind (NETLINK_RDMA).
969  * @param[in] name
970  *   IB device name.
971  * @param[in] pindex
972  *   IB device port index, starting from 1
973  * @return
974  *   A valid (nonzero) interface index on success, 0 otherwise and rte_errno
975  *   is set.
976  */
977 unsigned int
978 mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex)
979 {
980         struct mlx5_nl_ifindex_data data = {
981                 .name = name,
982                 .flags = 0,
983                 .ibindex = 0, /* Determined during first pass. */
984                 .ifindex = 0, /* Determined during second pass. */
985         };
986         union {
987                 struct nlmsghdr nh;
988                 uint8_t buf[NLMSG_HDRLEN +
989                             NLA_HDRLEN + NLA_ALIGN(sizeof(data.ibindex)) +
990                             NLA_HDRLEN + NLA_ALIGN(sizeof(pindex))];
991         } req = {
992                 .nh = {
993                         .nlmsg_len = NLMSG_LENGTH(0),
994                         .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
995                                                        RDMA_NLDEV_CMD_GET),
996                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
997                 },
998         };
999         struct nlattr *na;
1000         uint32_t sn = MLX5_NL_SN_GENERATE;
1001         int ret;
1002
1003         ret = mlx5_nl_send(nl, &req.nh, sn);
1004         if (ret < 0)
1005                 return 0;
1006         ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
1007         if (ret < 0)
1008                 return 0;
1009         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
1010             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX))
1011                 goto error;
1012         data.flags = 0;
1013         sn = MLX5_NL_SN_GENERATE;
1014         req.nh.nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1015                                              RDMA_NLDEV_CMD_PORT_GET);
1016         req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1017         req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.buf) - NLMSG_HDRLEN);
1018         na = (void *)((uintptr_t)req.buf + NLMSG_HDRLEN);
1019         na->nla_len = NLA_HDRLEN + sizeof(data.ibindex);
1020         na->nla_type = RDMA_NLDEV_ATTR_DEV_INDEX;
1021         memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1022                &data.ibindex, sizeof(data.ibindex));
1023         na = (void *)((uintptr_t)na + NLA_ALIGN(na->nla_len));
1024         na->nla_len = NLA_HDRLEN + sizeof(pindex);
1025         na->nla_type = RDMA_NLDEV_ATTR_PORT_INDEX;
1026         memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1027                &pindex, sizeof(pindex));
1028         ret = mlx5_nl_send(nl, &req.nh, sn);
1029         if (ret < 0)
1030                 return 0;
1031         ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
1032         if (ret < 0)
1033                 return 0;
1034         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
1035             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
1036             !(data.flags & MLX5_NL_CMD_GET_NET_INDEX) ||
1037             !data.ifindex)
1038                 goto error;
1039         return data.ifindex;
1040 error:
1041         rte_errno = ENODEV;
1042         return 0;
1043 }
1044
1045 /**
1046  * Get the number of physical ports of given IB device.
1047  *
1048  * @param nl
1049  *   Netlink socket of the RDMA kind (NETLINK_RDMA).
1050  * @param[in] name
1051  *   IB device name.
1052  *
1053  * @return
1054  *   A valid (nonzero) number of ports on success, 0 otherwise
1055  *   and rte_errno is set.
1056  */
1057 unsigned int
1058 mlx5_nl_portnum(int nl, const char *name)
1059 {
1060         struct mlx5_nl_ifindex_data data = {
1061                 .flags = 0,
1062                 .name = name,
1063                 .ifindex = 0,
1064                 .portnum = 0,
1065         };
1066         struct nlmsghdr req = {
1067                 .nlmsg_len = NLMSG_LENGTH(0),
1068                 .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1069                                                RDMA_NLDEV_CMD_GET),
1070                 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
1071         };
1072         uint32_t sn = MLX5_NL_SN_GENERATE;
1073         int ret;
1074
1075         ret = mlx5_nl_send(nl, &req, sn);
1076         if (ret < 0)
1077                 return 0;
1078         ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
1079         if (ret < 0)
1080                 return 0;
1081         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
1082             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
1083             !(data.flags & MLX5_NL_CMD_GET_PORT_INDEX)) {
1084                 rte_errno = ENODEV;
1085                 return 0;
1086         }
1087         if (!data.portnum)
1088                 rte_errno = EINVAL;
1089         return data.portnum;
1090 }
1091
1092 /**
1093  * Analyze gathered port parameters via Netlink to recognize master
1094  * and representor devices for E-Switch configuration.
1095  *
1096  * @param[in] num_vf_set
1097  *   flag of presence of number of VFs port attribute.
1098  * @param[inout] switch_info
1099  *   Port information, including port name as a number and port name
1100  *   type if recognized
1101  *
1102  * @return
1103  *   master and representor flags are set in switch_info according to
1104  *   recognized parameters (if any).
1105  */
1106 static void
1107 mlx5_nl_check_switch_info(bool num_vf_set,
1108                           struct mlx5_switch_info *switch_info)
1109 {
1110         switch (switch_info->name_type) {
1111         case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
1112                 /*
1113                  * Name is not recognized, assume the master,
1114                  * check the number of VFs key presence.
1115                  */
1116                 switch_info->master = num_vf_set;
1117                 break;
1118         case MLX5_PHYS_PORT_NAME_TYPE_NOTSET:
1119                 /*
1120                  * Name is not set, this assumes the legacy naming
1121                  * schema for master, just check if there is a
1122                  * number of VFs key.
1123                  */
1124                 switch_info->master = num_vf_set;
1125                 break;
1126         case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
1127                 /* New uplink naming schema recognized. */
1128                 switch_info->master = 1;
1129                 break;
1130         case MLX5_PHYS_PORT_NAME_TYPE_LEGACY:
1131                 /* Legacy representors naming schema. */
1132                 switch_info->representor = !num_vf_set;
1133                 break;
1134         case MLX5_PHYS_PORT_NAME_TYPE_PFVF:
1135                 /* New representors naming schema. */
1136                 switch_info->representor = 1;
1137                 break;
1138         }
1139 }
1140
1141 /**
1142  * Process switch information from Netlink message.
1143  *
1144  * @param nh
1145  *   Pointer to Netlink message header.
1146  * @param arg
1147  *   Opaque data pointer for this callback.
1148  *
1149  * @return
1150  *   0 on success, a negative errno value otherwise and rte_errno is set.
1151  */
1152 static int
1153 mlx5_nl_switch_info_cb(struct nlmsghdr *nh, void *arg)
1154 {
1155         struct mlx5_switch_info info = {
1156                 .master = 0,
1157                 .representor = 0,
1158                 .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
1159                 .port_name = 0,
1160                 .switch_id = 0,
1161         };
1162         size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
1163         bool switch_id_set = false;
1164         bool num_vf_set = false;
1165
1166         if (nh->nlmsg_type != RTM_NEWLINK)
1167                 goto error;
1168         while (off < nh->nlmsg_len) {
1169                 struct rtattr *ra = (void *)((uintptr_t)nh + off);
1170                 void *payload = RTA_DATA(ra);
1171                 unsigned int i;
1172
1173                 if (ra->rta_len > nh->nlmsg_len - off)
1174                         goto error;
1175                 switch (ra->rta_type) {
1176                 case IFLA_NUM_VF:
1177                         num_vf_set = true;
1178                         break;
1179                 case IFLA_PHYS_PORT_NAME:
1180                         mlx5_translate_port_name((char *)payload, &info);
1181                         break;
1182                 case IFLA_PHYS_SWITCH_ID:
1183                         info.switch_id = 0;
1184                         for (i = 0; i < RTA_PAYLOAD(ra); ++i) {
1185                                 info.switch_id <<= 8;
1186                                 info.switch_id |= ((uint8_t *)payload)[i];
1187                         }
1188                         switch_id_set = true;
1189                         break;
1190                 }
1191                 off += RTA_ALIGN(ra->rta_len);
1192         }
1193         if (switch_id_set) {
1194                 /* We have some E-Switch configuration. */
1195                 mlx5_nl_check_switch_info(num_vf_set, &info);
1196         }
1197         MLX5_ASSERT(!(info.master && info.representor));
1198         memcpy(arg, &info, sizeof(info));
1199         return 0;
1200 error:
1201         rte_errno = EINVAL;
1202         return -rte_errno;
1203 }
1204
1205 /**
1206  * Get switch information associated with network interface.
1207  *
1208  * @param nl
1209  *   Netlink socket of the ROUTE kind (NETLINK_ROUTE).
1210  * @param ifindex
1211  *   Network interface index.
1212  * @param[out] info
1213  *   Switch information object, populated in case of success.
1214  *
1215  * @return
1216  *   0 on success, a negative errno value otherwise and rte_errno is set.
1217  */
1218 int
1219 mlx5_nl_switch_info(int nl, unsigned int ifindex,
1220                     struct mlx5_switch_info *info)
1221 {
1222         struct {
1223                 struct nlmsghdr nh;
1224                 struct ifinfomsg info;
1225                 struct rtattr rta;
1226                 uint32_t extmask;
1227         } req = {
1228                 .nh = {
1229                         .nlmsg_len = NLMSG_LENGTH
1230                                         (sizeof(req.info) +
1231                                          RTA_LENGTH(sizeof(uint32_t))),
1232                         .nlmsg_type = RTM_GETLINK,
1233                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
1234                 },
1235                 .info = {
1236                         .ifi_family = AF_UNSPEC,
1237                         .ifi_index = ifindex,
1238                 },
1239                 .rta = {
1240                         .rta_type = IFLA_EXT_MASK,
1241                         .rta_len = RTA_LENGTH(sizeof(int32_t)),
1242                 },
1243                 .extmask = RTE_LE32(1),
1244         };
1245         uint32_t sn = MLX5_NL_SN_GENERATE;
1246         int ret;
1247
1248         ret = mlx5_nl_send(nl, &req.nh, sn);
1249         if (ret >= 0)
1250                 ret = mlx5_nl_recv(nl, sn, mlx5_nl_switch_info_cb, info);
1251         if (info->master && info->representor) {
1252                 DRV_LOG(ERR, "ifindex %u device is recognized as master"
1253                              " and as representor", ifindex);
1254                 rte_errno = ENODEV;
1255                 ret = -rte_errno;
1256         }
1257         return ret;
1258 }
1259
1260 /*
1261  * Delete VLAN network device by ifindex.
1262  *
1263  * @param[in] tcf
1264  *   Context object initialized by mlx5_nl_vlan_vmwa_init().
1265  * @param[in] ifindex
1266  *   Interface index of network device to delete.
1267  */
1268 void
1269 mlx5_nl_vlan_vmwa_delete(struct mlx5_nl_vlan_vmwa_context *vmwa,
1270                       uint32_t ifindex)
1271 {
1272         uint32_t sn = MLX5_NL_SN_GENERATE;
1273         int ret;
1274         struct {
1275                 struct nlmsghdr nh;
1276                 struct ifinfomsg info;
1277         } req = {
1278                 .nh = {
1279                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
1280                         .nlmsg_type = RTM_DELLINK,
1281                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
1282                 },
1283                 .info = {
1284                         .ifi_family = AF_UNSPEC,
1285                         .ifi_index = ifindex,
1286                 },
1287         };
1288
1289         if (ifindex) {
1290                 ret = mlx5_nl_send(vmwa->nl_socket, &req.nh, sn);
1291                 if (ret >= 0)
1292                         ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
1293                 if (ret < 0)
1294                         DRV_LOG(WARNING, "netlink: error deleting VLAN WA"
1295                                 " ifindex %u, %d", ifindex, ret);
1296         }
1297 }
1298
1299 /* Set of subroutines to build Netlink message. */
1300 static struct nlattr *
1301 nl_msg_tail(struct nlmsghdr *nlh)
1302 {
1303         return (struct nlattr *)
1304                 (((uint8_t *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1305 }
1306
1307 static void
1308 nl_attr_put(struct nlmsghdr *nlh, int type, const void *data, int alen)
1309 {
1310         struct nlattr *nla = nl_msg_tail(nlh);
1311
1312         nla->nla_type = type;
1313         nla->nla_len = NLMSG_ALIGN(sizeof(struct nlattr)) + alen;
1314         nlh->nlmsg_len += NLMSG_ALIGN(nla->nla_len);
1315
1316         if (alen)
1317                 memcpy((uint8_t *)nla + sizeof(struct nlattr), data, alen);
1318 }
1319
1320 static struct nlattr *
1321 nl_attr_nest_start(struct nlmsghdr *nlh, int type)
1322 {
1323         struct nlattr *nest = (struct nlattr *)nl_msg_tail(nlh);
1324
1325         nl_attr_put(nlh, type, NULL, 0);
1326         return nest;
1327 }
1328
1329 static void
1330 nl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *nest)
1331 {
1332         nest->nla_len = (uint8_t *)nl_msg_tail(nlh) - (uint8_t *)nest;
1333 }
1334
1335 /*
1336  * Create network VLAN device with specified VLAN tag.
1337  *
1338  * @param[in] tcf
1339  *   Context object initialized by mlx5_nl_vlan_vmwa_init().
1340  * @param[in] ifindex
1341  *   Base network interface index.
1342  * @param[in] tag
1343  *   VLAN tag for VLAN network device to create.
1344  */
1345 uint32_t
1346 mlx5_nl_vlan_vmwa_create(struct mlx5_nl_vlan_vmwa_context *vmwa,
1347                          uint32_t ifindex, uint16_t tag)
1348 {
1349         struct nlmsghdr *nlh;
1350         struct ifinfomsg *ifm;
1351         char name[sizeof(MLX5_VMWA_VLAN_DEVICE_PFX) + 32];
1352
1353         __rte_cache_aligned
1354         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1355                     NLMSG_ALIGN(sizeof(struct ifinfomsg)) +
1356                     NLMSG_ALIGN(sizeof(struct nlattr)) * 8 +
1357                     NLMSG_ALIGN(sizeof(uint32_t)) +
1358                     NLMSG_ALIGN(sizeof(name)) +
1359                     NLMSG_ALIGN(sizeof("vlan")) +
1360                     NLMSG_ALIGN(sizeof(uint32_t)) +
1361                     NLMSG_ALIGN(sizeof(uint16_t)) + 16];
1362         struct nlattr *na_info;
1363         struct nlattr *na_vlan;
1364         uint32_t sn = MLX5_NL_SN_GENERATE;
1365         int ret;
1366
1367         memset(buf, 0, sizeof(buf));
1368         nlh = (struct nlmsghdr *)buf;
1369         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1370         nlh->nlmsg_type = RTM_NEWLINK;
1371         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
1372                            NLM_F_EXCL | NLM_F_ACK;
1373         ifm = (struct ifinfomsg *)nl_msg_tail(nlh);
1374         nlh->nlmsg_len += sizeof(struct ifinfomsg);
1375         ifm->ifi_family = AF_UNSPEC;
1376         ifm->ifi_type = 0;
1377         ifm->ifi_index = 0;
1378         ifm->ifi_flags = IFF_UP;
1379         ifm->ifi_change = 0xffffffff;
1380         nl_attr_put(nlh, IFLA_LINK, &ifindex, sizeof(ifindex));
1381         ret = snprintf(name, sizeof(name), "%s.%u.%u",
1382                        MLX5_VMWA_VLAN_DEVICE_PFX, ifindex, tag);
1383         nl_attr_put(nlh, IFLA_IFNAME, name, ret + 1);
1384         na_info = nl_attr_nest_start(nlh, IFLA_LINKINFO);
1385         nl_attr_put(nlh, IFLA_INFO_KIND, "vlan", sizeof("vlan"));
1386         na_vlan = nl_attr_nest_start(nlh, IFLA_INFO_DATA);
1387         nl_attr_put(nlh, IFLA_VLAN_ID, &tag, sizeof(tag));
1388         nl_attr_nest_end(nlh, na_vlan);
1389         nl_attr_nest_end(nlh, na_info);
1390         MLX5_ASSERT(sizeof(buf) >= nlh->nlmsg_len);
1391         ret = mlx5_nl_send(vmwa->nl_socket, nlh, sn);
1392         if (ret >= 0)
1393                 ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
1394         if (ret < 0) {
1395                 DRV_LOG(WARNING, "netlink: VLAN %s create failure (%d)", name,
1396                         ret);
1397         }
1398         // Try to get ifindex of created or pre-existing device.
1399         ret = if_nametoindex(name);
1400         if (!ret) {
1401                 DRV_LOG(WARNING, "VLAN %s failed to get index (%d)", name,
1402                         errno);
1403                 return 0;
1404         }
1405         return ret;
1406 }
1407
1408 /**
1409  * Parse Netlink message to retrieve the general family ID.
1410  *
1411  * @param nh
1412  *   Pointer to Netlink Message Header.
1413  * @param arg
1414  *   PMD data register with this callback.
1415  *
1416  * @return
1417  *   0 on success, a negative errno value otherwise and rte_errno is set.
1418  */
1419 static int
1420 mlx5_nl_family_id_cb(struct nlmsghdr *nh, void *arg)
1421 {
1422
1423         struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
1424         struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
1425                                         NLMSG_ALIGN(sizeof(struct genlmsghdr)));
1426
1427         for (; nla->nla_len && nla < tail;
1428              nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len))) {
1429                 if (nla->nla_type == CTRL_ATTR_FAMILY_ID) {
1430                         *(uint16_t *)arg = *(uint16_t *)(nla + 1);
1431                         return 0;
1432                 }
1433         }
1434         return -EINVAL;
1435 }
1436
1437 #define MLX5_NL_MAX_ATTR_SIZE 100
1438 /**
1439  * Get generic netlink family ID.
1440  *
1441  * @param[in] nlsk_fd
1442  *   Netlink socket file descriptor.
1443  * @param[in] name
1444  *   The family name.
1445  *
1446  * @return
1447  *   ID >= 0 on success and @p enable is updated, a negative errno value
1448  *   otherwise and rte_errno is set.
1449  */
1450 static int
1451 mlx5_nl_generic_family_id_get(int nlsk_fd, const char *name)
1452 {
1453         struct nlmsghdr *nlh;
1454         struct genlmsghdr *genl;
1455         uint32_t sn = MLX5_NL_SN_GENERATE;
1456         int name_size = strlen(name) + 1;
1457         int ret;
1458         uint16_t id = -1;
1459         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1460                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1461                     NLMSG_ALIGN(sizeof(struct nlattr)) +
1462                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE)];
1463
1464         memset(buf, 0, sizeof(buf));
1465         nlh = (struct nlmsghdr *)buf;
1466         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1467         nlh->nlmsg_type = GENL_ID_CTRL;
1468         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1469         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1470         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1471         genl->cmd = CTRL_CMD_GETFAMILY;
1472         genl->version = 1;
1473         nl_attr_put(nlh, CTRL_ATTR_FAMILY_NAME, name, name_size);
1474         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1475         if (ret >= 0)
1476                 ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_family_id_cb, &id);
1477         if (ret < 0) {
1478                 DRV_LOG(DEBUG, "Failed to get Netlink %s family ID: %d.", name,
1479                         ret);
1480                 return ret;
1481         }
1482         DRV_LOG(DEBUG, "Netlink \"%s\" family ID is %u.", name, id);
1483         return (int)id;
1484 }
1485
1486 /**
1487  * Get Devlink family ID.
1488  *
1489  * @param[in] nlsk_fd
1490  *   Netlink socket file descriptor.
1491  *
1492  * @return
1493  *   ID >= 0 on success and @p enable is updated, a negative errno value
1494  *   otherwise and rte_errno is set.
1495  */
1496
1497 int
1498 mlx5_nl_devlink_family_id_get(int nlsk_fd)
1499 {
1500         return mlx5_nl_generic_family_id_get(nlsk_fd, DEVLINK_GENL_NAME);
1501 }
1502
1503 /**
1504  * Parse Netlink message to retrieve the ROCE enable status.
1505  *
1506  * @param nh
1507  *   Pointer to Netlink Message Header.
1508  * @param arg
1509  *   PMD data register with this callback.
1510  *
1511  * @return
1512  *   0 on success, a negative errno value otherwise and rte_errno is set.
1513  */
1514 static int
1515 mlx5_nl_roce_cb(struct nlmsghdr *nh, void *arg)
1516 {
1517
1518         int ret = -EINVAL;
1519         int *enable = arg;
1520         struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
1521         struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
1522                                         NLMSG_ALIGN(sizeof(struct genlmsghdr)));
1523
1524         while (nla->nla_len && nla < tail) {
1525                 switch (nla->nla_type) {
1526                 /* Expected nested attributes case. */
1527                 case DEVLINK_ATTR_PARAM:
1528                 case DEVLINK_ATTR_PARAM_VALUES_LIST:
1529                 case DEVLINK_ATTR_PARAM_VALUE:
1530                         ret = 0;
1531                         nla += 1;
1532                         break;
1533                 case DEVLINK_ATTR_PARAM_VALUE_DATA:
1534                         *enable = 1;
1535                         return 0;
1536                 default:
1537                         nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len));
1538                 }
1539         }
1540         *enable = 0;
1541         return ret;
1542 }
1543
1544 /**
1545  * Get ROCE enable status through Netlink.
1546  *
1547  * @param[in] nlsk_fd
1548  *   Netlink socket file descriptor.
1549  * @param[in] family_id
1550  *   the Devlink family ID.
1551  * @param pci_addr
1552  *   The device PCI address.
1553  * @param[out] enable
1554  *   Where to store the enable status.
1555  *
1556  * @return
1557  *   0 on success and @p enable is updated, a negative errno value otherwise
1558  *   and rte_errno is set.
1559  */
1560 int
1561 mlx5_nl_enable_roce_get(int nlsk_fd, int family_id, const char *pci_addr,
1562                         int *enable)
1563 {
1564         struct nlmsghdr *nlh;
1565         struct genlmsghdr *genl;
1566         uint32_t sn = MLX5_NL_SN_GENERATE;
1567         int ret;
1568         int cur_en = 0;
1569         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1570                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1571                     NLMSG_ALIGN(sizeof(struct nlattr)) * 4 +
1572                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4];
1573
1574         memset(buf, 0, sizeof(buf));
1575         nlh = (struct nlmsghdr *)buf;
1576         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1577         nlh->nlmsg_type = family_id;
1578         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1579         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1580         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1581         genl->cmd = DEVLINK_CMD_PARAM_GET;
1582         genl->version = DEVLINK_GENL_VERSION;
1583         nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1584         nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1585         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
1586         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1587         if (ret >= 0)
1588                 ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_roce_cb, &cur_en);
1589         if (ret < 0) {
1590                 DRV_LOG(DEBUG, "Failed to get ROCE enable on device %s: %d.",
1591                         pci_addr, ret);
1592                 return ret;
1593         }
1594         *enable = cur_en;
1595         DRV_LOG(DEBUG, "ROCE is %sabled for device \"%s\".",
1596                 cur_en ? "en" : "dis", pci_addr);
1597         return ret;
1598 }
1599
1600 /**
1601  * Reload mlx5 device kernel driver through Netlink.
1602  *
1603  * @param[in] nlsk_fd
1604  *   Netlink socket file descriptor.
1605  * @param[in] family_id
1606  *   the Devlink family ID.
1607  * @param pci_addr
1608  *   The device PCI address.
1609  * @param[out] enable
1610  *   The enable status to set.
1611  *
1612  * @return
1613  *   0 on success, a negative errno value otherwise and rte_errno is set.
1614  */
1615 int
1616 mlx5_nl_driver_reload(int nlsk_fd, int family_id, const char *pci_addr)
1617 {
1618         struct nlmsghdr *nlh;
1619         struct genlmsghdr *genl;
1620         uint32_t sn = MLX5_NL_SN_GENERATE;
1621         int ret;
1622         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1623                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1624                     NLMSG_ALIGN(sizeof(struct nlattr)) * 2 +
1625                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 2];
1626
1627         memset(buf, 0, sizeof(buf));
1628         nlh = (struct nlmsghdr *)buf;
1629         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1630         nlh->nlmsg_type = family_id;
1631         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1632         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1633         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1634         genl->cmd = DEVLINK_CMD_RELOAD;
1635         genl->version = DEVLINK_GENL_VERSION;
1636         nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1637         nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1638         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1639         if (ret >= 0)
1640                 ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
1641         if (ret < 0) {
1642                 DRV_LOG(DEBUG, "Failed to reload %s device by Netlink - %d",
1643                         pci_addr, ret);
1644                 return ret;
1645         }
1646         DRV_LOG(DEBUG, "Device \"%s\" was reloaded by Netlink successfully.",
1647                 pci_addr);
1648         return 0;
1649 }
1650
1651 /**
1652  * Set ROCE enable status through Netlink.
1653  *
1654  * @param[in] nlsk_fd
1655  *   Netlink socket file descriptor.
1656  * @param[in] family_id
1657  *   the Devlink family ID.
1658  * @param pci_addr
1659  *   The device PCI address.
1660  * @param[out] enable
1661  *   The enable status to set.
1662  *
1663  * @return
1664  *   0 on success, a negative errno value otherwise and rte_errno is set.
1665  */
1666 int
1667 mlx5_nl_enable_roce_set(int nlsk_fd, int family_id, const char *pci_addr,
1668                         int enable)
1669 {
1670         struct nlmsghdr *nlh;
1671         struct genlmsghdr *genl;
1672         uint32_t sn = MLX5_NL_SN_GENERATE;
1673         int ret;
1674         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1675                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1676                     NLMSG_ALIGN(sizeof(struct nlattr)) * 6 +
1677                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 6];
1678         uint8_t cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
1679         uint8_t ptype = NLA_FLAG;
1680 ;
1681
1682         memset(buf, 0, sizeof(buf));
1683         nlh = (struct nlmsghdr *)buf;
1684         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1685         nlh->nlmsg_type = family_id;
1686         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1687         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1688         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1689         genl->cmd = DEVLINK_CMD_PARAM_SET;
1690         genl->version = DEVLINK_GENL_VERSION;
1691         nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1692         nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1693         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
1694         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, &cmode, sizeof(cmode));
1695         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_TYPE, &ptype, sizeof(ptype));
1696         if (enable)
1697                 nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, NULL, 0);
1698         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1699         if (ret >= 0)
1700                 ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
1701         if (ret < 0) {
1702                 DRV_LOG(DEBUG, "Failed to %sable ROCE for device %s by Netlink:"
1703                         " %d.", enable ? "en" : "dis", pci_addr, ret);
1704                 return ret;
1705         }
1706         DRV_LOG(DEBUG, "Device %s ROCE was %sabled by Netlink successfully.",
1707                 pci_addr, enable ? "en" : "dis");
1708         /* Now, need to reload the driver. */
1709         return mlx5_nl_driver_reload(nlsk_fd, family_id, pci_addr);
1710 }