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