common/mlx5: replace alignas keyword
[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((size_t)(index) < sizeof(mac_own) * CHAR_BIT);
675                 BITFIELD_SET(mac_own, index);
676         }
677         if (ret == -EEXIST)
678                 return 0;
679         return ret;
680 }
681
682 /**
683  * Remove a MAC address.
684  *
685  * @param[in] nlsk_fd
686  *   Netlink socket file descriptor.
687  * @param[in] iface_idx
688  *   Net device interface index.
689  * @param mac_own
690  *   BITFIELD_DECLARE array to store the mac.
691  * @param mac
692  *   MAC address to remove.
693  * @param index
694  *   MAC address index.
695  *
696  * @return
697  *   0 on success, a negative errno value otherwise and rte_errno is set.
698  */
699 int
700 mlx5_nl_mac_addr_remove(int nlsk_fd, unsigned int iface_idx, uint64_t *mac_own,
701                         struct rte_ether_addr *mac, uint32_t index)
702 {
703         MLX5_ASSERT((size_t)(index) < sizeof(mac_own) * CHAR_BIT);
704         BITFIELD_RESET(mac_own, index);
705         return mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 0);
706 }
707
708 /**
709  * Synchronize Netlink bridge table to the internal table.
710  *
711  * @param[in] nlsk_fd
712  *   Netlink socket file descriptor.
713  * @param[in] iface_idx
714  *   Net device interface index.
715  * @param mac_addrs
716  *   Mac addresses array to sync.
717  * @param n
718  *   @p mac_addrs array size.
719  */
720 void
721 mlx5_nl_mac_addr_sync(int nlsk_fd, unsigned int iface_idx,
722                       struct rte_ether_addr *mac_addrs, int n)
723 {
724         struct rte_ether_addr macs[n];
725         int macs_n = 0;
726         int i;
727         int ret;
728
729         ret = mlx5_nl_mac_addr_list(nlsk_fd, iface_idx, &macs, &macs_n);
730         if (ret)
731                 return;
732         for (i = 0; i != macs_n; ++i) {
733                 int j;
734
735                 /* Verify the address is not in the array yet. */
736                 for (j = 0; j != n; ++j)
737                         if (rte_is_same_ether_addr(&macs[i], &mac_addrs[j]))
738                                 break;
739                 if (j != n)
740                         continue;
741                 /* Find the first entry available. */
742                 for (j = 0; j != n; ++j) {
743                         if (rte_is_zero_ether_addr(&mac_addrs[j])) {
744                                 mac_addrs[j] = macs[i];
745                                 break;
746                         }
747                 }
748         }
749 }
750
751 /**
752  * Flush all added MAC addresses.
753  *
754  * @param[in] nlsk_fd
755  *   Netlink socket file descriptor.
756  * @param[in] iface_idx
757  *   Net device interface index.
758  * @param[in] mac_addrs
759  *   Mac addresses array to flush.
760  * @param n
761  *   @p mac_addrs array size.
762  * @param mac_own
763  *   BITFIELD_DECLARE array to store the mac.
764  */
765 void
766 mlx5_nl_mac_addr_flush(int nlsk_fd, unsigned int iface_idx,
767                        struct rte_ether_addr *mac_addrs, int n,
768                        uint64_t *mac_own)
769 {
770         int i;
771
772         for (i = n - 1; i >= 0; --i) {
773                 struct rte_ether_addr *m = &mac_addrs[i];
774
775                 MLX5_ASSERT((size_t)(i) < sizeof(mac_own) * CHAR_BIT);
776                 if (BITFIELD_ISSET(mac_own, i))
777                         mlx5_nl_mac_addr_remove(nlsk_fd, iface_idx, mac_own, m,
778                                                 i);
779         }
780 }
781
782 /**
783  * Enable promiscuous / all multicast mode through Netlink.
784  *
785  * @param[in] nlsk_fd
786  *   Netlink socket file descriptor.
787  * @param[in] iface_idx
788  *   Net device interface index.
789  * @param flags
790  *   IFF_PROMISC for promiscuous, IFF_ALLMULTI for allmulti.
791  * @param enable
792  *   Nonzero to enable, disable otherwise.
793  *
794  * @return
795  *   0 on success, a negative errno value otherwise and rte_errno is set.
796  */
797 static int
798 mlx5_nl_device_flags(int nlsk_fd, unsigned int iface_idx, uint32_t flags,
799                      int enable)
800 {
801         struct {
802                 struct nlmsghdr hdr;
803                 struct ifinfomsg ifi;
804         } req = {
805                 .hdr = {
806                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
807                         .nlmsg_type = RTM_NEWLINK,
808                         .nlmsg_flags = NLM_F_REQUEST,
809                 },
810                 .ifi = {
811                         .ifi_flags = enable ? flags : 0,
812                         .ifi_change = flags,
813                         .ifi_index = iface_idx,
814                 },
815         };
816         uint32_t sn = MLX5_NL_SN_GENERATE;
817         int ret;
818
819         MLX5_ASSERT(!(flags & ~(IFF_PROMISC | IFF_ALLMULTI)));
820         if (nlsk_fd < 0)
821                 return 0;
822         ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
823         if (ret < 0)
824                 return ret;
825         return 0;
826 }
827
828 /**
829  * Enable promiscuous mode through Netlink.
830  *
831  * @param[in] nlsk_fd
832  *   Netlink socket file descriptor.
833  * @param[in] iface_idx
834  *   Net device interface index.
835  * @param enable
836  *   Nonzero to enable, disable otherwise.
837  *
838  * @return
839  *   0 on success, a negative errno value otherwise and rte_errno is set.
840  */
841 int
842 mlx5_nl_promisc(int nlsk_fd, unsigned int iface_idx, int enable)
843 {
844         int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_PROMISC, enable);
845
846         if (ret)
847                 DRV_LOG(DEBUG,
848                         "Interface %u cannot %s promisc mode: Netlink error %s",
849                         iface_idx, enable ? "enable" : "disable",
850                         strerror(rte_errno));
851         return ret;
852 }
853
854 /**
855  * Enable all multicast mode through Netlink.
856  *
857  * @param[in] nlsk_fd
858  *   Netlink socket file descriptor.
859  * @param[in] iface_idx
860  *   Net device interface index.
861  * @param enable
862  *   Nonzero to enable, disable otherwise.
863  *
864  * @return
865  *   0 on success, a negative errno value otherwise and rte_errno is set.
866  */
867 int
868 mlx5_nl_allmulti(int nlsk_fd, unsigned int iface_idx, int enable)
869 {
870         int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_ALLMULTI,
871                                        enable);
872
873         if (ret)
874                 DRV_LOG(DEBUG,
875                         "Interface %u cannot %s allmulti : Netlink error %s",
876                         iface_idx, enable ? "enable" : "disable",
877                         strerror(rte_errno));
878         return ret;
879 }
880
881 /**
882  * Process network interface information from Netlink message.
883  *
884  * @param nh
885  *   Pointer to Netlink message header.
886  * @param arg
887  *   Opaque data pointer for this callback.
888  *
889  * @return
890  *   0 on success, a negative errno value otherwise and rte_errno is set.
891  */
892 static int
893 mlx5_nl_cmdget_cb(struct nlmsghdr *nh, void *arg)
894 {
895         struct mlx5_nl_ifindex_data *data = arg;
896         struct mlx5_nl_ifindex_data local = {
897                 .flags = 0,
898         };
899         size_t off = NLMSG_HDRLEN;
900
901         if (nh->nlmsg_type !=
902             RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET) &&
903             nh->nlmsg_type !=
904             RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_PORT_GET))
905                 goto error;
906         while (off < nh->nlmsg_len) {
907                 struct nlattr *na = (void *)((uintptr_t)nh + off);
908                 void *payload = (void *)((uintptr_t)na + NLA_HDRLEN);
909
910                 if (na->nla_len > nh->nlmsg_len - off)
911                         goto error;
912                 switch (na->nla_type) {
913                 case RDMA_NLDEV_ATTR_DEV_INDEX:
914                         local.ibindex = *(uint32_t *)payload;
915                         local.flags |= MLX5_NL_CMD_GET_IB_INDEX;
916                         break;
917                 case RDMA_NLDEV_ATTR_DEV_NAME:
918                         if (!strcmp(payload, data->name))
919                                 local.flags |= MLX5_NL_CMD_GET_IB_NAME;
920                         break;
921                 case RDMA_NLDEV_ATTR_NDEV_INDEX:
922                         local.ifindex = *(uint32_t *)payload;
923                         local.flags |= MLX5_NL_CMD_GET_NET_INDEX;
924                         break;
925                 case RDMA_NLDEV_ATTR_PORT_INDEX:
926                         local.portnum = *(uint32_t *)payload;
927                         local.flags |= MLX5_NL_CMD_GET_PORT_INDEX;
928                         break;
929                 default:
930                         break;
931                 }
932                 off += NLA_ALIGN(na->nla_len);
933         }
934         /*
935          * It is possible to have multiple messages for all
936          * Infiniband devices in the system with appropriate name.
937          * So we should gather parameters locally and copy to
938          * query context only in case of coinciding device name.
939          */
940         if (local.flags & MLX5_NL_CMD_GET_IB_NAME) {
941                 data->flags = local.flags;
942                 data->ibindex = local.ibindex;
943                 data->ifindex = local.ifindex;
944                 data->portnum = local.portnum;
945         }
946         return 0;
947 error:
948         rte_errno = EINVAL;
949         return -rte_errno;
950 }
951
952 /**
953  * Get index of network interface associated with some IB device.
954  *
955  * This is the only somewhat safe method to avoid resorting to heuristics
956  * when faced with port representors. Unfortunately it requires at least
957  * Linux 4.17.
958  *
959  * @param nl
960  *   Netlink socket of the RDMA kind (NETLINK_RDMA).
961  * @param[in] name
962  *   IB device name.
963  * @param[in] pindex
964  *   IB device port index, starting from 1
965  * @return
966  *   A valid (nonzero) interface index on success, 0 otherwise and rte_errno
967  *   is set.
968  */
969 unsigned int
970 mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex)
971 {
972         struct mlx5_nl_ifindex_data data = {
973                 .name = name,
974                 .flags = 0,
975                 .ibindex = 0, /* Determined during first pass. */
976                 .ifindex = 0, /* Determined during second pass. */
977         };
978         union {
979                 struct nlmsghdr nh;
980                 uint8_t buf[NLMSG_HDRLEN +
981                             NLA_HDRLEN + NLA_ALIGN(sizeof(data.ibindex)) +
982                             NLA_HDRLEN + NLA_ALIGN(sizeof(pindex))];
983         } req = {
984                 .nh = {
985                         .nlmsg_len = NLMSG_LENGTH(0),
986                         .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
987                                                        RDMA_NLDEV_CMD_GET),
988                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
989                 },
990         };
991         struct nlattr *na;
992         uint32_t sn = MLX5_NL_SN_GENERATE;
993         int ret;
994
995         ret = mlx5_nl_send(nl, &req.nh, sn);
996         if (ret < 0)
997                 return 0;
998         ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
999         if (ret < 0)
1000                 return 0;
1001         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
1002             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX))
1003                 goto error;
1004         data.flags = 0;
1005         sn = MLX5_NL_SN_GENERATE;
1006         req.nh.nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1007                                              RDMA_NLDEV_CMD_PORT_GET);
1008         req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1009         req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.buf) - NLMSG_HDRLEN);
1010         na = (void *)((uintptr_t)req.buf + NLMSG_HDRLEN);
1011         na->nla_len = NLA_HDRLEN + sizeof(data.ibindex);
1012         na->nla_type = RDMA_NLDEV_ATTR_DEV_INDEX;
1013         memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1014                &data.ibindex, sizeof(data.ibindex));
1015         na = (void *)((uintptr_t)na + NLA_ALIGN(na->nla_len));
1016         na->nla_len = NLA_HDRLEN + sizeof(pindex);
1017         na->nla_type = RDMA_NLDEV_ATTR_PORT_INDEX;
1018         memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1019                &pindex, sizeof(pindex));
1020         ret = mlx5_nl_send(nl, &req.nh, sn);
1021         if (ret < 0)
1022                 return 0;
1023         ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
1024         if (ret < 0)
1025                 return 0;
1026         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
1027             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
1028             !(data.flags & MLX5_NL_CMD_GET_NET_INDEX) ||
1029             !data.ifindex)
1030                 goto error;
1031         return data.ifindex;
1032 error:
1033         rte_errno = ENODEV;
1034         return 0;
1035 }
1036
1037 /**
1038  * Get the number of physical ports of given IB device.
1039  *
1040  * @param nl
1041  *   Netlink socket of the RDMA kind (NETLINK_RDMA).
1042  * @param[in] name
1043  *   IB device name.
1044  *
1045  * @return
1046  *   A valid (nonzero) number of ports on success, 0 otherwise
1047  *   and rte_errno is set.
1048  */
1049 unsigned int
1050 mlx5_nl_portnum(int nl, const char *name)
1051 {
1052         struct mlx5_nl_ifindex_data data = {
1053                 .flags = 0,
1054                 .name = name,
1055                 .ifindex = 0,
1056                 .portnum = 0,
1057         };
1058         struct nlmsghdr req = {
1059                 .nlmsg_len = NLMSG_LENGTH(0),
1060                 .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1061                                                RDMA_NLDEV_CMD_GET),
1062                 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
1063         };
1064         uint32_t sn = MLX5_NL_SN_GENERATE;
1065         int ret;
1066
1067         ret = mlx5_nl_send(nl, &req, sn);
1068         if (ret < 0)
1069                 return 0;
1070         ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
1071         if (ret < 0)
1072                 return 0;
1073         if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
1074             !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
1075             !(data.flags & MLX5_NL_CMD_GET_PORT_INDEX)) {
1076                 rte_errno = ENODEV;
1077                 return 0;
1078         }
1079         if (!data.portnum)
1080                 rte_errno = EINVAL;
1081         return data.portnum;
1082 }
1083
1084 /**
1085  * Analyze gathered port parameters via Netlink to recognize master
1086  * and representor devices for E-Switch configuration.
1087  *
1088  * @param[in] num_vf_set
1089  *   flag of presence of number of VFs port attribute.
1090  * @param[inout] switch_info
1091  *   Port information, including port name as a number and port name
1092  *   type if recognized
1093  *
1094  * @return
1095  *   master and representor flags are set in switch_info according to
1096  *   recognized parameters (if any).
1097  */
1098 static void
1099 mlx5_nl_check_switch_info(bool num_vf_set,
1100                           struct mlx5_switch_info *switch_info)
1101 {
1102         switch (switch_info->name_type) {
1103         case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
1104                 /*
1105                  * Name is not recognized, assume the master,
1106                  * check the number of VFs key presence.
1107                  */
1108                 switch_info->master = num_vf_set;
1109                 break;
1110         case MLX5_PHYS_PORT_NAME_TYPE_NOTSET:
1111                 /*
1112                  * Name is not set, this assumes the legacy naming
1113                  * schema for master, just check if there is a
1114                  * number of VFs key.
1115                  */
1116                 switch_info->master = num_vf_set;
1117                 break;
1118         case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
1119                 /* New uplink naming schema recognized. */
1120                 switch_info->master = 1;
1121                 break;
1122         case MLX5_PHYS_PORT_NAME_TYPE_LEGACY:
1123                 /* Legacy representors naming schema. */
1124                 switch_info->representor = !num_vf_set;
1125                 break;
1126         case MLX5_PHYS_PORT_NAME_TYPE_PFVF:
1127                 /* New representors naming schema. */
1128                 switch_info->representor = 1;
1129                 break;
1130         }
1131 }
1132
1133 /**
1134  * Process switch information from Netlink message.
1135  *
1136  * @param nh
1137  *   Pointer to Netlink message header.
1138  * @param arg
1139  *   Opaque data pointer for this callback.
1140  *
1141  * @return
1142  *   0 on success, a negative errno value otherwise and rte_errno is set.
1143  */
1144 static int
1145 mlx5_nl_switch_info_cb(struct nlmsghdr *nh, void *arg)
1146 {
1147         struct mlx5_switch_info info = {
1148                 .master = 0,
1149                 .representor = 0,
1150                 .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
1151                 .port_name = 0,
1152                 .switch_id = 0,
1153         };
1154         size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
1155         bool switch_id_set = false;
1156         bool num_vf_set = false;
1157
1158         if (nh->nlmsg_type != RTM_NEWLINK)
1159                 goto error;
1160         while (off < nh->nlmsg_len) {
1161                 struct rtattr *ra = (void *)((uintptr_t)nh + off);
1162                 void *payload = RTA_DATA(ra);
1163                 unsigned int i;
1164
1165                 if (ra->rta_len > nh->nlmsg_len - off)
1166                         goto error;
1167                 switch (ra->rta_type) {
1168                 case IFLA_NUM_VF:
1169                         num_vf_set = true;
1170                         break;
1171                 case IFLA_PHYS_PORT_NAME:
1172                         mlx5_translate_port_name((char *)payload, &info);
1173                         break;
1174                 case IFLA_PHYS_SWITCH_ID:
1175                         info.switch_id = 0;
1176                         for (i = 0; i < RTA_PAYLOAD(ra); ++i) {
1177                                 info.switch_id <<= 8;
1178                                 info.switch_id |= ((uint8_t *)payload)[i];
1179                         }
1180                         switch_id_set = true;
1181                         break;
1182                 }
1183                 off += RTA_ALIGN(ra->rta_len);
1184         }
1185         if (switch_id_set) {
1186                 /* We have some E-Switch configuration. */
1187                 mlx5_nl_check_switch_info(num_vf_set, &info);
1188         }
1189         MLX5_ASSERT(!(info.master && info.representor));
1190         memcpy(arg, &info, sizeof(info));
1191         return 0;
1192 error:
1193         rte_errno = EINVAL;
1194         return -rte_errno;
1195 }
1196
1197 /**
1198  * Get switch information associated with network interface.
1199  *
1200  * @param nl
1201  *   Netlink socket of the ROUTE kind (NETLINK_ROUTE).
1202  * @param ifindex
1203  *   Network interface index.
1204  * @param[out] info
1205  *   Switch information object, populated in case of success.
1206  *
1207  * @return
1208  *   0 on success, a negative errno value otherwise and rte_errno is set.
1209  */
1210 int
1211 mlx5_nl_switch_info(int nl, unsigned int ifindex,
1212                     struct mlx5_switch_info *info)
1213 {
1214         struct {
1215                 struct nlmsghdr nh;
1216                 struct ifinfomsg info;
1217                 struct rtattr rta;
1218                 uint32_t extmask;
1219         } req = {
1220                 .nh = {
1221                         .nlmsg_len = NLMSG_LENGTH
1222                                         (sizeof(req.info) +
1223                                          RTA_LENGTH(sizeof(uint32_t))),
1224                         .nlmsg_type = RTM_GETLINK,
1225                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
1226                 },
1227                 .info = {
1228                         .ifi_family = AF_UNSPEC,
1229                         .ifi_index = ifindex,
1230                 },
1231                 .rta = {
1232                         .rta_type = IFLA_EXT_MASK,
1233                         .rta_len = RTA_LENGTH(sizeof(int32_t)),
1234                 },
1235                 .extmask = RTE_LE32(1),
1236         };
1237         uint32_t sn = MLX5_NL_SN_GENERATE;
1238         int ret;
1239
1240         ret = mlx5_nl_send(nl, &req.nh, sn);
1241         if (ret >= 0)
1242                 ret = mlx5_nl_recv(nl, sn, mlx5_nl_switch_info_cb, info);
1243         if (info->master && info->representor) {
1244                 DRV_LOG(ERR, "ifindex %u device is recognized as master"
1245                              " and as representor", ifindex);
1246                 rte_errno = ENODEV;
1247                 ret = -rte_errno;
1248         }
1249         return ret;
1250 }
1251
1252 /*
1253  * Delete VLAN network device by ifindex.
1254  *
1255  * @param[in] tcf
1256  *   Context object initialized by mlx5_nl_vlan_vmwa_init().
1257  * @param[in] ifindex
1258  *   Interface index of network device to delete.
1259  */
1260 void
1261 mlx5_nl_vlan_vmwa_delete(struct mlx5_nl_vlan_vmwa_context *vmwa,
1262                       uint32_t ifindex)
1263 {
1264         uint32_t sn = MLX5_NL_SN_GENERATE;
1265         int ret;
1266         struct {
1267                 struct nlmsghdr nh;
1268                 struct ifinfomsg info;
1269         } req = {
1270                 .nh = {
1271                         .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
1272                         .nlmsg_type = RTM_DELLINK,
1273                         .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
1274                 },
1275                 .info = {
1276                         .ifi_family = AF_UNSPEC,
1277                         .ifi_index = ifindex,
1278                 },
1279         };
1280
1281         if (ifindex) {
1282                 ret = mlx5_nl_send(vmwa->nl_socket, &req.nh, sn);
1283                 if (ret >= 0)
1284                         ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
1285                 if (ret < 0)
1286                         DRV_LOG(WARNING, "netlink: error deleting VLAN WA"
1287                                 " ifindex %u, %d", ifindex, ret);
1288         }
1289 }
1290
1291 /* Set of subroutines to build Netlink message. */
1292 static struct nlattr *
1293 nl_msg_tail(struct nlmsghdr *nlh)
1294 {
1295         return (struct nlattr *)
1296                 (((uint8_t *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1297 }
1298
1299 static void
1300 nl_attr_put(struct nlmsghdr *nlh, int type, const void *data, int alen)
1301 {
1302         struct nlattr *nla = nl_msg_tail(nlh);
1303
1304         nla->nla_type = type;
1305         nla->nla_len = NLMSG_ALIGN(sizeof(struct nlattr)) + alen;
1306         nlh->nlmsg_len += NLMSG_ALIGN(nla->nla_len);
1307
1308         if (alen)
1309                 memcpy((uint8_t *)nla + sizeof(struct nlattr), data, alen);
1310 }
1311
1312 static struct nlattr *
1313 nl_attr_nest_start(struct nlmsghdr *nlh, int type)
1314 {
1315         struct nlattr *nest = (struct nlattr *)nl_msg_tail(nlh);
1316
1317         nl_attr_put(nlh, type, NULL, 0);
1318         return nest;
1319 }
1320
1321 static void
1322 nl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *nest)
1323 {
1324         nest->nla_len = (uint8_t *)nl_msg_tail(nlh) - (uint8_t *)nest;
1325 }
1326
1327 /*
1328  * Create network VLAN device with specified VLAN tag.
1329  *
1330  * @param[in] tcf
1331  *   Context object initialized by mlx5_nl_vlan_vmwa_init().
1332  * @param[in] ifindex
1333  *   Base network interface index.
1334  * @param[in] tag
1335  *   VLAN tag for VLAN network device to create.
1336  */
1337 uint32_t
1338 mlx5_nl_vlan_vmwa_create(struct mlx5_nl_vlan_vmwa_context *vmwa,
1339                          uint32_t ifindex, uint16_t tag)
1340 {
1341         struct nlmsghdr *nlh;
1342         struct ifinfomsg *ifm;
1343         char name[sizeof(MLX5_VMWA_VLAN_DEVICE_PFX) + 32];
1344
1345         __rte_cache_aligned
1346         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1347                     NLMSG_ALIGN(sizeof(struct ifinfomsg)) +
1348                     NLMSG_ALIGN(sizeof(struct nlattr)) * 8 +
1349                     NLMSG_ALIGN(sizeof(uint32_t)) +
1350                     NLMSG_ALIGN(sizeof(name)) +
1351                     NLMSG_ALIGN(sizeof("vlan")) +
1352                     NLMSG_ALIGN(sizeof(uint32_t)) +
1353                     NLMSG_ALIGN(sizeof(uint16_t)) + 16];
1354         struct nlattr *na_info;
1355         struct nlattr *na_vlan;
1356         uint32_t sn = MLX5_NL_SN_GENERATE;
1357         int ret;
1358
1359         memset(buf, 0, sizeof(buf));
1360         nlh = (struct nlmsghdr *)buf;
1361         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1362         nlh->nlmsg_type = RTM_NEWLINK;
1363         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
1364                            NLM_F_EXCL | NLM_F_ACK;
1365         ifm = (struct ifinfomsg *)nl_msg_tail(nlh);
1366         nlh->nlmsg_len += sizeof(struct ifinfomsg);
1367         ifm->ifi_family = AF_UNSPEC;
1368         ifm->ifi_type = 0;
1369         ifm->ifi_index = 0;
1370         ifm->ifi_flags = IFF_UP;
1371         ifm->ifi_change = 0xffffffff;
1372         nl_attr_put(nlh, IFLA_LINK, &ifindex, sizeof(ifindex));
1373         ret = snprintf(name, sizeof(name), "%s.%u.%u",
1374                        MLX5_VMWA_VLAN_DEVICE_PFX, ifindex, tag);
1375         nl_attr_put(nlh, IFLA_IFNAME, name, ret + 1);
1376         na_info = nl_attr_nest_start(nlh, IFLA_LINKINFO);
1377         nl_attr_put(nlh, IFLA_INFO_KIND, "vlan", sizeof("vlan"));
1378         na_vlan = nl_attr_nest_start(nlh, IFLA_INFO_DATA);
1379         nl_attr_put(nlh, IFLA_VLAN_ID, &tag, sizeof(tag));
1380         nl_attr_nest_end(nlh, na_vlan);
1381         nl_attr_nest_end(nlh, na_info);
1382         MLX5_ASSERT(sizeof(buf) >= nlh->nlmsg_len);
1383         ret = mlx5_nl_send(vmwa->nl_socket, nlh, sn);
1384         if (ret >= 0)
1385                 ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
1386         if (ret < 0) {
1387                 DRV_LOG(WARNING, "netlink: VLAN %s create failure (%d)", name,
1388                         ret);
1389         }
1390         // Try to get ifindex of created or pre-existing device.
1391         ret = if_nametoindex(name);
1392         if (!ret) {
1393                 DRV_LOG(WARNING, "VLAN %s failed to get index (%d)", name,
1394                         errno);
1395                 return 0;
1396         }
1397         return ret;
1398 }
1399
1400 /**
1401  * Parse Netlink message to retrieve the general family ID.
1402  *
1403  * @param nh
1404  *   Pointer to Netlink Message Header.
1405  * @param arg
1406  *   PMD data register with this callback.
1407  *
1408  * @return
1409  *   0 on success, a negative errno value otherwise and rte_errno is set.
1410  */
1411 static int
1412 mlx5_nl_family_id_cb(struct nlmsghdr *nh, void *arg)
1413 {
1414
1415         struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
1416         struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
1417                                         NLMSG_ALIGN(sizeof(struct genlmsghdr)));
1418
1419         for (; nla->nla_len && nla < tail;
1420              nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len))) {
1421                 if (nla->nla_type == CTRL_ATTR_FAMILY_ID) {
1422                         *(uint16_t *)arg = *(uint16_t *)(nla + 1);
1423                         return 0;
1424                 }
1425         }
1426         return -EINVAL;
1427 }
1428
1429 #define MLX5_NL_MAX_ATTR_SIZE 100
1430 /**
1431  * Get generic netlink family ID.
1432  *
1433  * @param[in] nlsk_fd
1434  *   Netlink socket file descriptor.
1435  * @param[in] name
1436  *   The family name.
1437  *
1438  * @return
1439  *   ID >= 0 on success and @p enable is updated, a negative errno value
1440  *   otherwise and rte_errno is set.
1441  */
1442 static int
1443 mlx5_nl_generic_family_id_get(int nlsk_fd, const char *name)
1444 {
1445         struct nlmsghdr *nlh;
1446         struct genlmsghdr *genl;
1447         uint32_t sn = MLX5_NL_SN_GENERATE;
1448         int name_size = strlen(name) + 1;
1449         int ret;
1450         uint16_t id = -1;
1451         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1452                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1453                     NLMSG_ALIGN(sizeof(struct nlattr)) +
1454                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE)];
1455
1456         memset(buf, 0, sizeof(buf));
1457         nlh = (struct nlmsghdr *)buf;
1458         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1459         nlh->nlmsg_type = GENL_ID_CTRL;
1460         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1461         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1462         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1463         genl->cmd = CTRL_CMD_GETFAMILY;
1464         genl->version = 1;
1465         nl_attr_put(nlh, CTRL_ATTR_FAMILY_NAME, name, name_size);
1466         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1467         if (ret >= 0)
1468                 ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_family_id_cb, &id);
1469         if (ret < 0) {
1470                 DRV_LOG(DEBUG, "Failed to get Netlink %s family ID: %d.", name,
1471                         ret);
1472                 return ret;
1473         }
1474         DRV_LOG(DEBUG, "Netlink \"%s\" family ID is %u.", name, id);
1475         return (int)id;
1476 }
1477
1478 /**
1479  * Get Devlink family ID.
1480  *
1481  * @param[in] nlsk_fd
1482  *   Netlink socket file descriptor.
1483  *
1484  * @return
1485  *   ID >= 0 on success and @p enable is updated, a negative errno value
1486  *   otherwise and rte_errno is set.
1487  */
1488
1489 int
1490 mlx5_nl_devlink_family_id_get(int nlsk_fd)
1491 {
1492         return mlx5_nl_generic_family_id_get(nlsk_fd, DEVLINK_GENL_NAME);
1493 }
1494
1495 /**
1496  * Parse Netlink message to retrieve the ROCE enable status.
1497  *
1498  * @param nh
1499  *   Pointer to Netlink Message Header.
1500  * @param arg
1501  *   PMD data register with this callback.
1502  *
1503  * @return
1504  *   0 on success, a negative errno value otherwise and rte_errno is set.
1505  */
1506 static int
1507 mlx5_nl_roce_cb(struct nlmsghdr *nh, void *arg)
1508 {
1509
1510         int ret = -EINVAL;
1511         int *enable = arg;
1512         struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
1513         struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
1514                                         NLMSG_ALIGN(sizeof(struct genlmsghdr)));
1515
1516         while (nla->nla_len && nla < tail) {
1517                 switch (nla->nla_type) {
1518                 /* Expected nested attributes case. */
1519                 case DEVLINK_ATTR_PARAM:
1520                 case DEVLINK_ATTR_PARAM_VALUES_LIST:
1521                 case DEVLINK_ATTR_PARAM_VALUE:
1522                         ret = 0;
1523                         nla += 1;
1524                         break;
1525                 case DEVLINK_ATTR_PARAM_VALUE_DATA:
1526                         *enable = 1;
1527                         return 0;
1528                 default:
1529                         nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len));
1530                 }
1531         }
1532         *enable = 0;
1533         return ret;
1534 }
1535
1536 /**
1537  * Get ROCE enable status through Netlink.
1538  *
1539  * @param[in] nlsk_fd
1540  *   Netlink socket file descriptor.
1541  * @param[in] family_id
1542  *   the Devlink family ID.
1543  * @param pci_addr
1544  *   The device PCI address.
1545  * @param[out] enable
1546  *   Where to store the enable status.
1547  *
1548  * @return
1549  *   0 on success and @p enable is updated, a negative errno value otherwise
1550  *   and rte_errno is set.
1551  */
1552 int
1553 mlx5_nl_enable_roce_get(int nlsk_fd, int family_id, const char *pci_addr,
1554                         int *enable)
1555 {
1556         struct nlmsghdr *nlh;
1557         struct genlmsghdr *genl;
1558         uint32_t sn = MLX5_NL_SN_GENERATE;
1559         int ret;
1560         int cur_en;
1561         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1562                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1563                     NLMSG_ALIGN(sizeof(struct nlattr)) * 4 +
1564                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4];
1565
1566         memset(buf, 0, sizeof(buf));
1567         nlh = (struct nlmsghdr *)buf;
1568         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1569         nlh->nlmsg_type = family_id;
1570         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1571         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1572         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1573         genl->cmd = DEVLINK_CMD_PARAM_GET;
1574         genl->version = DEVLINK_GENL_VERSION;
1575         nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1576         nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1577         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
1578         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1579         if (ret >= 0)
1580                 ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_roce_cb, &cur_en);
1581         if (ret < 0) {
1582                 DRV_LOG(DEBUG, "Failed to get ROCE enable on device %s: %d.",
1583                         pci_addr, ret);
1584                 return ret;
1585         }
1586         *enable = cur_en;
1587         DRV_LOG(DEBUG, "ROCE is %sabled for device \"%s\".",
1588                 cur_en ? "en" : "dis", pci_addr);
1589         return ret;
1590 }
1591
1592 /**
1593  * Reload mlx5 device kernel driver through Netlink.
1594  *
1595  * @param[in] nlsk_fd
1596  *   Netlink socket file descriptor.
1597  * @param[in] family_id
1598  *   the Devlink family ID.
1599  * @param pci_addr
1600  *   The device PCI address.
1601  * @param[out] enable
1602  *   The enable status to set.
1603  *
1604  * @return
1605  *   0 on success, a negative errno value otherwise and rte_errno is set.
1606  */
1607 int
1608 mlx5_nl_driver_reload(int nlsk_fd, int family_id, const char *pci_addr)
1609 {
1610         struct nlmsghdr *nlh;
1611         struct genlmsghdr *genl;
1612         uint32_t sn = MLX5_NL_SN_GENERATE;
1613         int ret;
1614         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1615                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1616                     NLMSG_ALIGN(sizeof(struct nlattr)) * 2 +
1617                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 2];
1618
1619         memset(buf, 0, sizeof(buf));
1620         nlh = (struct nlmsghdr *)buf;
1621         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1622         nlh->nlmsg_type = family_id;
1623         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1624         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1625         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1626         genl->cmd = DEVLINK_CMD_RELOAD;
1627         genl->version = DEVLINK_GENL_VERSION;
1628         nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1629         nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1630         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1631         if (ret >= 0)
1632                 ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
1633         if (ret < 0) {
1634                 DRV_LOG(DEBUG, "Failed to reload %s device by Netlink - %d",
1635                         pci_addr, ret);
1636                 return ret;
1637         }
1638         DRV_LOG(DEBUG, "Device \"%s\" was reloaded by Netlink successfully.",
1639                 pci_addr);
1640         return 0;
1641 }
1642
1643 /**
1644  * Set ROCE enable status through Netlink.
1645  *
1646  * @param[in] nlsk_fd
1647  *   Netlink socket file descriptor.
1648  * @param[in] family_id
1649  *   the Devlink family ID.
1650  * @param pci_addr
1651  *   The device PCI address.
1652  * @param[out] enable
1653  *   The enable status to set.
1654  *
1655  * @return
1656  *   0 on success, a negative errno value otherwise and rte_errno is set.
1657  */
1658 int
1659 mlx5_nl_enable_roce_set(int nlsk_fd, int family_id, const char *pci_addr,
1660                         int enable)
1661 {
1662         struct nlmsghdr *nlh;
1663         struct genlmsghdr *genl;
1664         uint32_t sn = MLX5_NL_SN_GENERATE;
1665         int ret;
1666         uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1667                     NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1668                     NLMSG_ALIGN(sizeof(struct nlattr)) * 6 +
1669                     NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 6];
1670         uint8_t cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
1671         uint8_t ptype = NLA_FLAG;
1672 ;
1673
1674         memset(buf, 0, sizeof(buf));
1675         nlh = (struct nlmsghdr *)buf;
1676         nlh->nlmsg_len = sizeof(struct nlmsghdr);
1677         nlh->nlmsg_type = family_id;
1678         nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1679         genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1680         nlh->nlmsg_len += sizeof(struct genlmsghdr);
1681         genl->cmd = DEVLINK_CMD_PARAM_SET;
1682         genl->version = DEVLINK_GENL_VERSION;
1683         nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1684         nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1685         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
1686         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, &cmode, sizeof(cmode));
1687         nl_attr_put(nlh, DEVLINK_ATTR_PARAM_TYPE, &ptype, sizeof(ptype));
1688         if (enable)
1689                 nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, NULL, 0);
1690         ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1691         if (ret >= 0)
1692                 ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
1693         if (ret < 0) {
1694                 DRV_LOG(DEBUG, "Failed to %sable ROCE for device %s by Netlink:"
1695                         " %d.", enable ? "en" : "dis", pci_addr, ret);
1696                 return ret;
1697         }
1698         DRV_LOG(DEBUG, "Device %s ROCE was %sabled by Netlink successfully.",
1699                 pci_addr, enable ? "en" : "dis");
1700         /* Now, need to reload the driver. */
1701         return mlx5_nl_driver_reload(nlsk_fd, family_id, pci_addr);
1702 }