Branch data Line data Source code
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 <eal_export.h>
21 : : #include <rte_errno.h>
22 : :
23 : : #include "mlx5_nl.h"
24 : : #include "../mlx5_common_log.h"
25 : : #include "mlx5_malloc.h"
26 : : #ifdef HAVE_DEVLINK
27 : : #include <linux/devlink.h>
28 : : #endif
29 : :
30 : :
31 : : /* Size of the buffer to receive kernel messages */
32 : : #define MLX5_NL_BUF_SIZE (32 * 1024)
33 : : /* Send buffer size for the Netlink socket */
34 : : #define MLX5_SEND_BUF_SIZE 32768
35 : : /* Receive buffer size for the Netlink socket */
36 : : #define MLX5_RECV_BUF_SIZE 32768
37 : : /* Maximal physical port name length. */
38 : : #define MLX5_PHYS_PORT_NAME_MAX 128
39 : :
40 : : /** Parameters of VLAN devices created by driver. */
41 : : #define MLX5_VMWA_VLAN_DEVICE_PFX "evmlx"
42 : : /*
43 : : * Define NDA_RTA as defined in iproute2 sources.
44 : : *
45 : : * see in iproute2 sources file include/libnetlink.h
46 : : */
47 : : #ifndef MLX5_NDA_RTA
48 : : #define MLX5_NDA_RTA(r) \
49 : : ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
50 : : #endif
51 : : /*
52 : : * Define NLMSG_TAIL as defined in iproute2 sources.
53 : : *
54 : : * see in iproute2 sources file include/libnetlink.h
55 : : */
56 : : #ifndef NLMSG_TAIL
57 : : #define NLMSG_TAIL(nmsg) \
58 : : ((struct rtattr *)(((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
59 : : #endif
60 : : /*
61 : : * The following definitions are normally found in rdma/rdma_netlink.h,
62 : : * however they are so recent that most systems do not expose them yet.
63 : : */
64 : : #ifndef HAVE_RDMA_NL_NLDEV
65 : : #define RDMA_NL_NLDEV 5
66 : : #endif
67 : : #ifndef HAVE_RDMA_NLDEV_CMD_GET
68 : : #define RDMA_NLDEV_CMD_GET 1
69 : : #endif
70 : : #ifndef HAVE_RDMA_NLDEV_CMD_PORT_GET
71 : : #define RDMA_NLDEV_CMD_PORT_GET 5
72 : : #endif
73 : : #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_INDEX
74 : : #define RDMA_NLDEV_ATTR_DEV_INDEX 1
75 : : #endif
76 : : #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_NAME
77 : : #define RDMA_NLDEV_ATTR_DEV_NAME 2
78 : : #endif
79 : : #ifndef HAVE_RDMA_NLDEV_ATTR_PORT_INDEX
80 : : #define RDMA_NLDEV_ATTR_PORT_INDEX 3
81 : : #endif
82 : : #ifndef HAVE_RDMA_NLDEV_ATTR_PORT_STATE
83 : : #define RDMA_NLDEV_ATTR_PORT_STATE 12
84 : : #endif
85 : : #ifndef HAVE_RDMA_NLDEV_ATTR_NDEV_INDEX
86 : : #define RDMA_NLDEV_ATTR_NDEV_INDEX 50
87 : : #endif
88 : : #ifndef HAVE_RDMA_NLDEV_ATTR_EVENT_TYPE
89 : : #define RDMA_NLDEV_ATTR_EVENT_TYPE 102
90 : : #define RDMA_NETDEV_ATTACH_EVENT 2
91 : : #define RDMA_NETDEV_DETACH_EVENT 3
92 : : #endif
93 : : #ifndef HAVE_RDMA_NLDEV_SYS_ATTR_MONITOR_MODE
94 : : #define RDMA_NLDEV_SYS_ATTR_MONITOR_MODE 103
95 : : #endif
96 : : #ifndef HAVE_RDMA_NLDEV_CMD_MONITOR
97 : : #define RDMA_NLDEV_CMD_MONITOR 28
98 : : #endif
99 : : #ifndef HAVE_RDMA_NLDEV_CMD_SYS_GET
100 : : #define RDMA_NLDEV_CMD_SYS_GET 6
101 : : #endif
102 : : #ifndef HAVE_RDMA_NL_GROUP_NOTIFY
103 : : #define RDMA_NL_GROUP_NOTIFY 4
104 : : #endif
105 : : #define RDMA_NL_GROUP_NOTIFICATION (1 << (RDMA_NL_GROUP_NOTIFY - 1))
106 : :
107 : : /* These are normally found in linux/if_link.h. */
108 : : #ifndef HAVE_IFLA_NUM_VF
109 : : #define IFLA_NUM_VF 21
110 : : #endif
111 : : #ifndef HAVE_IFLA_EXT_MASK
112 : : #define IFLA_EXT_MASK 29
113 : : #endif
114 : : #ifndef HAVE_IFLA_PHYS_SWITCH_ID
115 : : #define IFLA_PHYS_SWITCH_ID 36
116 : : #endif
117 : : #ifndef HAVE_IFLA_PHYS_PORT_NAME
118 : : #define IFLA_PHYS_PORT_NAME 38
119 : : #endif
120 : :
121 : : /*
122 : : * Some Devlink defines may be missed in old kernel versions,
123 : : * adjust used defines.
124 : : */
125 : : #ifndef DEVLINK_GENL_NAME
126 : : #define DEVLINK_GENL_NAME "devlink"
127 : : #endif
128 : : #ifndef DEVLINK_GENL_VERSION
129 : : #define DEVLINK_GENL_VERSION 1
130 : : #endif
131 : : #ifndef DEVLINK_ATTR_BUS_NAME
132 : : #define DEVLINK_ATTR_BUS_NAME 1
133 : : #endif
134 : : #ifndef DEVLINK_ATTR_DEV_NAME
135 : : #define DEVLINK_ATTR_DEV_NAME 2
136 : : #endif
137 : : #ifndef DEVLINK_ATTR_PARAM
138 : : #define DEVLINK_ATTR_PARAM 80
139 : : #endif
140 : : #ifndef DEVLINK_ATTR_PARAM_NAME
141 : : #define DEVLINK_ATTR_PARAM_NAME 81
142 : : #endif
143 : : #ifndef DEVLINK_ATTR_PARAM_TYPE
144 : : #define DEVLINK_ATTR_PARAM_TYPE 83
145 : : #endif
146 : : #ifndef DEVLINK_ATTR_PARAM_VALUES_LIST
147 : : #define DEVLINK_ATTR_PARAM_VALUES_LIST 84
148 : : #endif
149 : : #ifndef DEVLINK_ATTR_PARAM_VALUE
150 : : #define DEVLINK_ATTR_PARAM_VALUE 85
151 : : #endif
152 : : #ifndef DEVLINK_ATTR_PARAM_VALUE_DATA
153 : : #define DEVLINK_ATTR_PARAM_VALUE_DATA 86
154 : : #endif
155 : : #ifndef DEVLINK_ATTR_PARAM_VALUE_CMODE
156 : : #define DEVLINK_ATTR_PARAM_VALUE_CMODE 87
157 : : #endif
158 : : #ifndef DEVLINK_PARAM_CMODE_DRIVERINIT
159 : : #define DEVLINK_PARAM_CMODE_DRIVERINIT 1
160 : : #endif
161 : : #ifndef DEVLINK_CMD_RELOAD
162 : : #define DEVLINK_CMD_RELOAD 37
163 : : #endif
164 : : #ifndef DEVLINK_CMD_PARAM_GET
165 : : #define DEVLINK_CMD_PARAM_GET 38
166 : : #endif
167 : : #ifndef DEVLINK_CMD_PARAM_SET
168 : : #define DEVLINK_CMD_PARAM_SET 39
169 : : #endif
170 : : #ifndef NLA_FLAG
171 : : #define NLA_FLAG 6
172 : : #endif
173 : :
174 : : /* Add/remove MAC address through Netlink */
175 : : struct mlx5_nl_mac_addr {
176 : : struct rte_ether_addr (*mac)[];
177 : : /**< MAC address handled by the device. */
178 : : int mac_n; /**< Number of addresses in the array. */
179 : : };
180 : :
181 : : RTE_ATOMIC(uint32_t) atomic_sn;
182 : :
183 : : /* Generate Netlink sequence number. */
184 : : #define MLX5_NL_SN_GENERATE (rte_atomic_fetch_add_explicit(&atomic_sn, 1, \
185 : : rte_memory_order_relaxed) + 1)
186 : :
187 : : /**
188 : : * Opens a Netlink socket.
189 : : *
190 : : * @param protocol
191 : : * Netlink protocol (e.g. NETLINK_ROUTE, NETLINK_RDMA).
192 : : * @param groups
193 : : * Groups to listen (e.g. RTMGRP_LINK), can be 0.
194 : : *
195 : : * @return
196 : : * A file descriptor on success, a negative errno value otherwise and
197 : : * rte_errno is set.
198 : : */
199 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_init)
200 : : int
201 : 0 : mlx5_nl_init(int protocol, int groups)
202 : : {
203 : : int fd;
204 : : int buf_size;
205 : : socklen_t opt_size;
206 : 0 : struct sockaddr_nl local = {
207 : : .nl_family = AF_NETLINK,
208 : : .nl_groups = groups,
209 : : };
210 : : int ret;
211 : :
212 : 0 : fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
213 [ # # ]: 0 : if (fd == -1) {
214 : 0 : rte_errno = errno;
215 : 0 : return -rte_errno;
216 : : }
217 : 0 : opt_size = sizeof(buf_size);
218 : 0 : ret = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, &opt_size);
219 [ # # ]: 0 : if (ret == -1) {
220 : 0 : rte_errno = errno;
221 : 0 : goto error;
222 : : }
223 : 0 : DRV_LOG(DEBUG, "Netlink socket send buffer: %d", buf_size);
224 [ # # ]: 0 : if (buf_size < MLX5_SEND_BUF_SIZE) {
225 : 0 : ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
226 : : &buf_size, sizeof(buf_size));
227 [ # # ]: 0 : if (ret == -1) {
228 : 0 : rte_errno = errno;
229 : 0 : goto error;
230 : : }
231 : : }
232 : 0 : opt_size = sizeof(buf_size);
233 : 0 : ret = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, &opt_size);
234 [ # # ]: 0 : if (ret == -1) {
235 : 0 : rte_errno = errno;
236 : 0 : goto error;
237 : : }
238 : 0 : DRV_LOG(DEBUG, "Netlink socket recv buffer: %d", buf_size);
239 [ # # ]: 0 : if (buf_size < MLX5_RECV_BUF_SIZE) {
240 : 0 : ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
241 : : &buf_size, sizeof(buf_size));
242 [ # # ]: 0 : if (ret == -1) {
243 : 0 : rte_errno = errno;
244 : 0 : goto error;
245 : : }
246 : : }
247 : 0 : ret = bind(fd, (struct sockaddr *)&local, sizeof(local));
248 [ # # ]: 0 : if (ret == -1) {
249 : 0 : rte_errno = errno;
250 : 0 : goto error;
251 : : }
252 : : return fd;
253 : 0 : error:
254 : 0 : close(fd);
255 : 0 : return -rte_errno;
256 : : }
257 : :
258 : : /**
259 : : * Send a request message to the kernel on the Netlink socket.
260 : : *
261 : : * @param[in] nlsk_fd
262 : : * Netlink socket file descriptor.
263 : : * @param[in] nh
264 : : * The Netlink message send to the kernel.
265 : : * @param[in] ssn
266 : : * Sequence number.
267 : : * @param[in] req
268 : : * Pointer to the request structure.
269 : : * @param[in] len
270 : : * Length of the request in bytes.
271 : : *
272 : : * @return
273 : : * The number of sent bytes on success, a negative errno value otherwise and
274 : : * rte_errno is set.
275 : : */
276 : : static int
277 : 0 : mlx5_nl_request(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn, void *req,
278 : : int len)
279 : : {
280 : 0 : struct sockaddr_nl sa = {
281 : : .nl_family = AF_NETLINK,
282 : : };
283 : 0 : struct iovec iov[2] = {
284 : : { .iov_base = nh, .iov_len = sizeof(*nh), },
285 : : { .iov_base = req, .iov_len = len, },
286 : : };
287 : 0 : struct msghdr msg = {
288 : : .msg_name = &sa,
289 : : .msg_namelen = sizeof(sa),
290 : : .msg_iov = iov,
291 : : .msg_iovlen = 2,
292 : : };
293 : : int send_bytes;
294 : :
295 : 0 : nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
296 : 0 : nh->nlmsg_seq = sn;
297 : 0 : send_bytes = sendmsg(nlsk_fd, &msg, 0);
298 [ # # ]: 0 : if (send_bytes < 0) {
299 : 0 : rte_errno = errno;
300 : 0 : return -rte_errno;
301 : : }
302 : : return send_bytes;
303 : : }
304 : :
305 : : /**
306 : : * Send a message to the kernel on the Netlink socket.
307 : : *
308 : : * @param[in] nlsk_fd
309 : : * The Netlink socket file descriptor used for communication.
310 : : * @param[in] nh
311 : : * The Netlink message send to the kernel.
312 : : * @param[in] sn
313 : : * Sequence number.
314 : : *
315 : : * @return
316 : : * The number of sent bytes on success, a negative errno value otherwise and
317 : : * rte_errno is set.
318 : : */
319 : : static int
320 : 0 : mlx5_nl_send(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn)
321 : : {
322 : 0 : struct sockaddr_nl sa = {
323 : : .nl_family = AF_NETLINK,
324 : : };
325 : 0 : struct iovec iov = {
326 : : .iov_base = nh,
327 : 0 : .iov_len = nh->nlmsg_len,
328 : : };
329 : 0 : struct msghdr msg = {
330 : : .msg_name = &sa,
331 : : .msg_namelen = sizeof(sa),
332 : : .msg_iov = &iov,
333 : : .msg_iovlen = 1,
334 : : };
335 : : int send_bytes;
336 : :
337 : 0 : nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
338 : 0 : nh->nlmsg_seq = sn;
339 : 0 : send_bytes = sendmsg(nlsk_fd, &msg, 0);
340 [ # # ]: 0 : if (send_bytes < 0) {
341 : 0 : rte_errno = errno;
342 : 0 : return -rte_errno;
343 : : }
344 : : return send_bytes;
345 : : }
346 : :
347 : : /**
348 : : * Receive a message from the kernel on the Netlink socket, following
349 : : * mlx5_nl_send().
350 : : *
351 : : * @param[in] nlsk_fd
352 : : * The Netlink socket file descriptor used for communication.
353 : : * @param[in] sn
354 : : * Sequence number.
355 : : * @param[in] cb
356 : : * The callback function to call for each Netlink message received.
357 : : * @param[in, out] arg
358 : : * Custom arguments for the callback.
359 : : *
360 : : * @return
361 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
362 : : */
363 : : static int
364 : 0 : mlx5_nl_recv(int nlsk_fd, uint32_t sn, int (*cb)(struct nlmsghdr *, void *arg),
365 : : void *arg)
366 : : {
367 : : struct sockaddr_nl sa;
368 : : struct iovec iov;
369 : 0 : struct msghdr msg = {
370 : : .msg_name = &sa,
371 : : .msg_namelen = sizeof(sa),
372 : : .msg_iov = &iov,
373 : : /* One message at a time */
374 : : .msg_iovlen = 1,
375 : : };
376 : : void *buf = NULL;
377 : : int multipart = 0;
378 : : int ret = 0;
379 : :
380 : : do {
381 : : struct nlmsghdr *nh;
382 : : int recv_bytes;
383 : :
384 : : do {
385 : : /* Query length of incoming message. */
386 : 0 : iov.iov_base = NULL;
387 : 0 : iov.iov_len = 0;
388 : 0 : recv_bytes = recvmsg(nlsk_fd, &msg,
389 : : MSG_PEEK | MSG_TRUNC);
390 [ # # ]: 0 : if (recv_bytes < 0) {
391 : 0 : rte_errno = errno;
392 : 0 : ret = -rte_errno;
393 : 0 : goto exit;
394 : : }
395 [ # # ]: 0 : if (recv_bytes == 0) {
396 : 0 : rte_errno = ENODATA;
397 : : ret = -rte_errno;
398 : 0 : goto exit;
399 : : }
400 : : /* Allocate buffer to fetch the message. */
401 : : if (recv_bytes < MLX5_RECV_BUF_SIZE)
402 : : recv_bytes = MLX5_RECV_BUF_SIZE;
403 : 0 : mlx5_free(buf);
404 : 0 : buf = mlx5_malloc(0, recv_bytes, 0, SOCKET_ID_ANY);
405 [ # # ]: 0 : if (!buf) {
406 : 0 : rte_errno = ENOMEM;
407 : : ret = -rte_errno;
408 : 0 : goto exit;
409 : : }
410 : : /* Fetch the message. */
411 : 0 : iov.iov_base = buf;
412 : 0 : iov.iov_len = recv_bytes;
413 : 0 : recv_bytes = recvmsg(nlsk_fd, &msg, 0);
414 [ # # ]: 0 : if (recv_bytes == -1) {
415 : 0 : rte_errno = errno;
416 : 0 : ret = -rte_errno;
417 : 0 : goto exit;
418 : : }
419 : : nh = (struct nlmsghdr *)buf;
420 [ # # ]: 0 : } while (nh->nlmsg_seq != sn);
421 : : for (;
422 [ # # # # : 0 : NLMSG_OK(nh, (unsigned int)recv_bytes);
# # ]
423 : 0 : nh = NLMSG_NEXT(nh, recv_bytes)) {
424 [ # # ]: 0 : if (nh->nlmsg_type == NLMSG_ERROR) {
425 : : struct nlmsgerr *err_data = NLMSG_DATA(nh);
426 : :
427 [ # # ]: 0 : if (err_data->error < 0) {
428 : 0 : rte_errno = -err_data->error;
429 : : ret = -rte_errno;
430 : 0 : goto exit;
431 : : }
432 : : /* Ack message. */
433 : : ret = 0;
434 : 0 : goto exit;
435 : : }
436 : : /* Multi-part msgs and their trailing DONE message. */
437 [ # # ]: 0 : if (nh->nlmsg_flags & NLM_F_MULTI) {
438 [ # # ]: 0 : if (nh->nlmsg_type == NLMSG_DONE) {
439 : : ret = 0;
440 : 0 : goto exit;
441 : : }
442 : : multipart = 1;
443 : : }
444 [ # # ]: 0 : if (cb) {
445 : 0 : ret = cb(nh, arg);
446 [ # # ]: 0 : if (ret < 0)
447 : 0 : goto exit;
448 : : }
449 : : }
450 [ # # ]: 0 : } while (multipart);
451 : 0 : exit:
452 : 0 : mlx5_free(buf);
453 : 0 : return ret;
454 : : }
455 : :
456 : : /**
457 : : * Parse Netlink message to retrieve the bridge MAC address.
458 : : *
459 : : * @param nh
460 : : * Pointer to Netlink Message Header.
461 : : * @param arg
462 : : * PMD data register with this callback.
463 : : *
464 : : * @return
465 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
466 : : */
467 : : static int
468 : 0 : mlx5_nl_mac_addr_cb(struct nlmsghdr *nh, void *arg)
469 : : {
470 : : struct mlx5_nl_mac_addr *data = arg;
471 : : struct ndmsg *r = NLMSG_DATA(nh);
472 : : struct rtattr *attribute;
473 : : int len;
474 : :
475 : 0 : len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
476 : 0 : for (attribute = MLX5_NDA_RTA(r);
477 [ # # # # : 0 : RTA_OK(attribute, len);
# # ]
478 : 0 : attribute = RTA_NEXT(attribute, len)) {
479 [ # # ]: 0 : if (attribute->rta_type == NDA_LLADDR) {
480 [ # # ]: 0 : if (data->mac_n == MLX5_MAX_MAC_ADDRESSES) {
481 : 0 : DRV_LOG(WARNING,
482 : : "not enough room to finalize the"
483 : : " request");
484 : 0 : rte_errno = ENOMEM;
485 : 0 : return -rte_errno;
486 : : }
487 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
488 : : char m[RTE_ETHER_ADDR_FMT_SIZE];
489 : :
490 : : rte_ether_format_addr(m, RTE_ETHER_ADDR_FMT_SIZE,
491 : : RTA_DATA(attribute));
492 : : DRV_LOG(DEBUG, "bridge MAC address %s", m);
493 : : #endif
494 : 0 : memcpy(&(*data->mac)[data->mac_n++],
495 : : RTA_DATA(attribute), RTE_ETHER_ADDR_LEN);
496 : : }
497 : : }
498 : : return 0;
499 : : }
500 : :
501 : : /**
502 : : * Get bridge MAC addresses.
503 : : *
504 : : * @param[in] nlsk_fd
505 : : * Netlink socket file descriptor.
506 : : * @param[in] iface_idx
507 : : * Net device interface index.
508 : : * @param mac[out]
509 : : * Pointer to the array table of MAC addresses to fill.
510 : : * Its size should be of MLX5_MAX_MAC_ADDRESSES.
511 : : * @param mac_n[out]
512 : : * Number of entries filled in MAC array.
513 : : *
514 : : * @return
515 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
516 : : */
517 : : static int
518 : 0 : mlx5_nl_mac_addr_list(int nlsk_fd, unsigned int iface_idx,
519 : : struct rte_ether_addr (*mac)[], int *mac_n)
520 : : {
521 : : struct {
522 : : struct nlmsghdr hdr;
523 : : struct ifinfomsg ifm;
524 : 0 : } req = {
525 : : .hdr = {
526 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
527 : : .nlmsg_type = RTM_GETNEIGH,
528 : : .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
529 : : },
530 : : .ifm = {
531 : : .ifi_family = PF_BRIDGE,
532 : : .ifi_index = iface_idx,
533 : : },
534 : : };
535 : 0 : struct mlx5_nl_mac_addr data = {
536 : : .mac = mac,
537 : : .mac_n = 0,
538 : : };
539 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
540 : : int ret;
541 : :
542 [ # # ]: 0 : if (nlsk_fd == -1)
543 : : return 0;
544 : 0 : ret = mlx5_nl_request(nlsk_fd, &req.hdr, sn, &req.ifm,
545 : : sizeof(struct ifinfomsg));
546 [ # # ]: 0 : if (ret < 0)
547 : 0 : goto error;
548 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_mac_addr_cb, &data);
549 [ # # ]: 0 : if (ret < 0)
550 : 0 : goto error;
551 : 0 : *mac_n = data.mac_n;
552 : 0 : return 0;
553 : 0 : error:
554 : 0 : DRV_LOG(DEBUG, "Interface %u cannot retrieve MAC address list %s",
555 : : iface_idx, strerror(rte_errno));
556 : 0 : return -rte_errno;
557 : : }
558 : :
559 : : /**
560 : : * Modify the MAC address neighbour table with Netlink.
561 : : *
562 : : * @param[in] nlsk_fd
563 : : * Netlink socket file descriptor.
564 : : * @param[in] iface_idx
565 : : * Net device interface index.
566 : : * @param mac
567 : : * MAC address to consider.
568 : : * @param add
569 : : * 1 to add the MAC address, 0 to remove the MAC address.
570 : : *
571 : : * @return
572 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
573 : : */
574 : : static int
575 : 0 : mlx5_nl_mac_addr_modify(int nlsk_fd, unsigned int iface_idx,
576 : : struct rte_ether_addr *mac, int add)
577 : : {
578 : : struct {
579 : : struct nlmsghdr hdr;
580 : : struct ndmsg ndm;
581 : : struct rtattr rta;
582 : : uint8_t buffer[RTE_ETHER_ADDR_LEN];
583 [ # # ]: 0 : } req = {
584 : : .hdr = {
585 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
586 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
587 : : NLM_F_EXCL | NLM_F_ACK,
588 : : .nlmsg_type = add ? RTM_NEWNEIGH : RTM_DELNEIGH,
589 : : },
590 : : .ndm = {
591 : : .ndm_family = PF_BRIDGE,
592 : : .ndm_state = NUD_NOARP | NUD_PERMANENT,
593 : : .ndm_ifindex = iface_idx,
594 : : .ndm_flags = NTF_SELF,
595 : : },
596 : : .rta = {
597 : : .rta_type = NDA_LLADDR,
598 : : .rta_len = RTA_LENGTH(RTE_ETHER_ADDR_LEN),
599 : : },
600 : : };
601 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
602 : : int ret;
603 : :
604 [ # # ]: 0 : if (nlsk_fd == -1)
605 : : return 0;
606 : : memcpy(RTA_DATA(&req.rta), mac, RTE_ETHER_ADDR_LEN);
607 : 0 : req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
608 : 0 : RTA_ALIGN(req.rta.rta_len);
609 : 0 : ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
610 [ # # ]: 0 : if (ret < 0)
611 : 0 : goto error;
612 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
613 [ # # ]: 0 : if (ret < 0)
614 : 0 : goto error;
615 : : return 0;
616 : 0 : error:
617 : : #ifdef RTE_LIBRTE_MLX5_DEBUG
618 : : {
619 : : char m[RTE_ETHER_ADDR_FMT_SIZE];
620 : :
621 : : rte_ether_format_addr(m, RTE_ETHER_ADDR_FMT_SIZE, mac);
622 : : DRV_LOG(DEBUG,
623 : : "Interface %u cannot %s MAC address %s %s",
624 : : iface_idx,
625 : : add ? "add" : "remove", m, strerror(rte_errno));
626 : : }
627 : : #endif
628 : 0 : return -rte_errno;
629 : : }
630 : :
631 : : /**
632 : : * Modify the VF MAC address neighbour table with Netlink.
633 : : *
634 : : * @param[in] nlsk_fd
635 : : * Netlink socket file descriptor.
636 : : * @param[in] iface_idx
637 : : * Net device interface index.
638 : : * @param mac
639 : : * MAC address to consider.
640 : : * @param vf_index
641 : : * VF index.
642 : : *
643 : : * @return
644 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
645 : : */
646 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_vf_mac_addr_modify)
647 : : int
648 : 0 : mlx5_nl_vf_mac_addr_modify(int nlsk_fd, unsigned int iface_idx,
649 : : struct rte_ether_addr *mac, int vf_index)
650 : : {
651 : : int ret;
652 : : struct {
653 : : struct nlmsghdr hdr;
654 : : struct ifinfomsg ifm;
655 : : struct rtattr vf_list_rta;
656 : : struct rtattr vf_info_rta;
657 : : struct rtattr vf_mac_rta;
658 : : struct ifla_vf_mac ivm;
659 : 0 : } req = {
660 : : .hdr = {
661 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
662 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
663 : : .nlmsg_type = RTM_BASE,
664 : : },
665 : : .ifm = {
666 : : .ifi_index = iface_idx,
667 : : },
668 : : .vf_list_rta = {
669 : : .rta_type = IFLA_VFINFO_LIST,
670 : : .rta_len = RTA_ALIGN(RTA_LENGTH(0)),
671 : : },
672 : : .vf_info_rta = {
673 : : .rta_type = IFLA_VF_INFO,
674 : : .rta_len = RTA_ALIGN(RTA_LENGTH(0)),
675 : : },
676 : : .vf_mac_rta = {
677 : : .rta_type = IFLA_VF_MAC,
678 : : },
679 : : };
680 : 0 : struct ifla_vf_mac ivm = {
681 : : .vf = vf_index,
682 : : };
683 [ # # ]: 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
684 : :
685 : : memcpy(&ivm.mac, mac, RTE_ETHER_ADDR_LEN);
686 : : memcpy(RTA_DATA(&req.vf_mac_rta), &ivm, sizeof(ivm));
687 : :
688 : 0 : req.vf_mac_rta.rta_len = RTA_LENGTH(sizeof(ivm));
689 : 0 : req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
690 : 0 : RTA_ALIGN(req.vf_list_rta.rta_len) +
691 : 0 : RTA_ALIGN(req.vf_info_rta.rta_len) +
692 : : RTA_ALIGN(req.vf_mac_rta.rta_len);
693 : 0 : req.vf_list_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr),
694 : : &req.vf_list_rta);
695 : 0 : req.vf_info_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr),
696 : : &req.vf_info_rta);
697 : :
698 [ # # ]: 0 : if (nlsk_fd < 0)
699 : : return -1;
700 : 0 : ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
701 [ # # ]: 0 : if (ret < 0)
702 : 0 : goto error;
703 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
704 [ # # ]: 0 : if (ret < 0)
705 : 0 : goto error;
706 : : return 0;
707 : 0 : error:
708 : 0 : DRV_LOG(ERR,
709 : : "representor %u cannot set VF MAC address "
710 : : RTE_ETHER_ADDR_PRT_FMT " : %s",
711 : : vf_index,
712 : : RTE_ETHER_ADDR_BYTES(mac),
713 : : strerror(rte_errno));
714 : 0 : return -rte_errno;
715 : : }
716 : :
717 : : /**
718 : : * Add a MAC address.
719 : : *
720 : : * @param[in] nlsk_fd
721 : : * Netlink socket file descriptor.
722 : : * @param[in] iface_idx
723 : : * Net device interface index.
724 : : * @param mac_own
725 : : * BITFIELD_DECLARE array to store the mac.
726 : : * @param mac
727 : : * MAC address to register.
728 : : * @param index
729 : : * MAC address index.
730 : : *
731 : : * @return
732 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
733 : : */
734 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_mac_addr_add)
735 : : int
736 : 0 : mlx5_nl_mac_addr_add(int nlsk_fd, unsigned int iface_idx,
737 : : uint64_t *mac_own, struct rte_ether_addr *mac,
738 : : uint32_t index)
739 : : {
740 : : int ret;
741 : :
742 : 0 : ret = mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 1);
743 [ # # ]: 0 : if (!ret) {
744 : : MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
745 [ # # ]: 0 : if (index >= MLX5_MAX_MAC_ADDRESSES)
746 : : return -EINVAL;
747 : :
748 : 0 : BITFIELD_SET(mac_own, index);
749 : : }
750 [ # # ]: 0 : if (ret == -EEXIST)
751 : 0 : return 0;
752 : : return ret;
753 : : }
754 : :
755 : : /**
756 : : * Remove a MAC address.
757 : : *
758 : : * @param[in] nlsk_fd
759 : : * Netlink socket file descriptor.
760 : : * @param[in] iface_idx
761 : : * Net device interface index.
762 : : * @param mac_own
763 : : * BITFIELD_DECLARE array to store the mac.
764 : : * @param mac
765 : : * MAC address to remove.
766 : : * @param index
767 : : * MAC address index.
768 : : *
769 : : * @return
770 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
771 : : */
772 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_mac_addr_remove)
773 : : int
774 : 0 : mlx5_nl_mac_addr_remove(int nlsk_fd, unsigned int iface_idx, uint64_t *mac_own,
775 : : struct rte_ether_addr *mac, uint32_t index)
776 : : {
777 : : MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
778 [ # # ]: 0 : if (index >= MLX5_MAX_MAC_ADDRESSES)
779 : : return -EINVAL;
780 : :
781 : 0 : BITFIELD_RESET(mac_own, index);
782 : 0 : return mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 0);
783 : : }
784 : :
785 : : /**
786 : : * Synchronize Netlink bridge table to the internal table.
787 : : *
788 : : * @param[in] nlsk_fd
789 : : * Netlink socket file descriptor.
790 : : * @param[in] iface_idx
791 : : * Net device interface index.
792 : : * @param mac_addrs
793 : : * Mac addresses array to sync.
794 : : * @param n
795 : : * @p mac_addrs array size.
796 : : */
797 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_mac_addr_sync)
798 : : void
799 : 0 : mlx5_nl_mac_addr_sync(int nlsk_fd, unsigned int iface_idx,
800 : : struct rte_ether_addr *mac_addrs, int n)
801 : 0 : {
802 : 0 : struct rte_ether_addr macs[n];
803 : 0 : int macs_n = 0;
804 : : int i;
805 : : int ret;
806 : :
807 : : memset(macs, 0, n * sizeof(macs[0]));
808 : 0 : ret = mlx5_nl_mac_addr_list(nlsk_fd, iface_idx, &macs, &macs_n);
809 [ # # ]: 0 : if (ret)
810 : 0 : return;
811 [ # # ]: 0 : for (i = 0; i != macs_n; ++i) {
812 : : int j;
813 : :
814 : : /* Verify the address is not in the array yet. */
815 [ # # ]: 0 : for (j = 0; j != n; ++j)
816 [ # # ]: 0 : if (rte_is_same_ether_addr(&macs[i], &mac_addrs[j]))
817 : : break;
818 [ # # ]: 0 : if (j != n)
819 : 0 : continue;
820 [ # # ]: 0 : if (rte_is_multicast_ether_addr(&macs[i])) {
821 : : /* Find the first entry available. */
822 [ # # ]: 0 : for (j = MLX5_MAX_UC_MAC_ADDRESSES; j != n; ++j) {
823 [ # # ]: 0 : if (rte_is_zero_ether_addr(&mac_addrs[j])) {
824 : 0 : mac_addrs[j] = macs[i];
825 : 0 : break;
826 : : }
827 : : }
828 : : } else {
829 : : /* Find the first entry available. */
830 [ # # ]: 0 : for (j = 0; j != MLX5_MAX_UC_MAC_ADDRESSES; ++j) {
831 [ # # ]: 0 : if (rte_is_zero_ether_addr(&mac_addrs[j])) {
832 : 0 : mac_addrs[j] = macs[i];
833 : 0 : break;
834 : : }
835 : : }
836 : : }
837 : : }
838 : : }
839 : :
840 : : /**
841 : : * Flush all added MAC addresses.
842 : : *
843 : : * @param[in] nlsk_fd
844 : : * Netlink socket file descriptor.
845 : : * @param[in] iface_idx
846 : : * Net device interface index.
847 : : * @param[in] mac_addrs
848 : : * Mac addresses array to flush.
849 : : * @param n
850 : : * @p mac_addrs array size.
851 : : * @param mac_own
852 : : * BITFIELD_DECLARE array to store the mac.
853 : : */
854 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_mac_addr_flush)
855 : : void
856 : 0 : mlx5_nl_mac_addr_flush(int nlsk_fd, unsigned int iface_idx,
857 : : struct rte_ether_addr *mac_addrs, int n,
858 : : uint64_t *mac_own)
859 : : {
860 : : int i;
861 : :
862 [ # # ]: 0 : if (n <= 0 || n > MLX5_MAX_MAC_ADDRESSES)
863 : : return;
864 : :
865 [ # # ]: 0 : for (i = n - 1; i >= 0; --i) {
866 : 0 : struct rte_ether_addr *m = &mac_addrs[i];
867 : :
868 [ # # ]: 0 : if (BITFIELD_ISSET(mac_own, i))
869 : 0 : mlx5_nl_mac_addr_remove(nlsk_fd, iface_idx, mac_own, m,
870 : : i);
871 : : }
872 : : }
873 : :
874 : : /**
875 : : * Enable promiscuous / all multicast mode through Netlink.
876 : : *
877 : : * @param[in] nlsk_fd
878 : : * Netlink socket file descriptor.
879 : : * @param[in] iface_idx
880 : : * Net device interface index.
881 : : * @param flags
882 : : * IFF_PROMISC for promiscuous, IFF_ALLMULTI for allmulti.
883 : : * @param enable
884 : : * Nonzero to enable, disable otherwise.
885 : : *
886 : : * @return
887 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
888 : : */
889 : : static int
890 : 0 : mlx5_nl_device_flags(int nlsk_fd, unsigned int iface_idx, uint32_t flags,
891 : : int enable)
892 : : {
893 : : struct {
894 : : struct nlmsghdr hdr;
895 : : struct ifinfomsg ifi;
896 : 0 : } req = {
897 : : .hdr = {
898 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
899 : : .nlmsg_type = RTM_NEWLINK,
900 : : .nlmsg_flags = NLM_F_REQUEST,
901 : : },
902 : : .ifi = {
903 [ # # ]: 0 : .ifi_flags = enable ? flags : 0,
904 : : .ifi_change = flags,
905 : : .ifi_index = iface_idx,
906 : : },
907 : : };
908 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
909 : : int ret;
910 : :
911 : : MLX5_ASSERT(!(flags & ~(IFF_PROMISC | IFF_ALLMULTI)));
912 [ # # ]: 0 : if (nlsk_fd < 0)
913 : : return 0;
914 : 0 : ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
915 : : if (ret < 0)
916 : : return ret;
917 : : return 0;
918 : : }
919 : :
920 : : /**
921 : : * Enable promiscuous mode through Netlink.
922 : : *
923 : : * @param[in] nlsk_fd
924 : : * Netlink socket file descriptor.
925 : : * @param[in] iface_idx
926 : : * Net device interface index.
927 : : * @param enable
928 : : * Nonzero to enable, disable otherwise.
929 : : *
930 : : * @return
931 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
932 : : */
933 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_promisc)
934 : : int
935 : 0 : mlx5_nl_promisc(int nlsk_fd, unsigned int iface_idx, int enable)
936 : : {
937 : 0 : int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_PROMISC, enable);
938 : :
939 [ # # ]: 0 : if (ret)
940 [ # # ]: 0 : DRV_LOG(DEBUG,
941 : : "Interface %u cannot %s promisc mode: Netlink error %s",
942 : : iface_idx, enable ? "enable" : "disable",
943 : : strerror(rte_errno));
944 : 0 : return ret;
945 : : }
946 : :
947 : : /**
948 : : * Enable all multicast mode through Netlink.
949 : : *
950 : : * @param[in] nlsk_fd
951 : : * Netlink socket file descriptor.
952 : : * @param[in] iface_idx
953 : : * Net device interface index.
954 : : * @param enable
955 : : * Nonzero to enable, disable otherwise.
956 : : *
957 : : * @return
958 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
959 : : */
960 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_allmulti)
961 : : int
962 : 0 : mlx5_nl_allmulti(int nlsk_fd, unsigned int iface_idx, int enable)
963 : : {
964 : 0 : int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_ALLMULTI,
965 : : enable);
966 : :
967 [ # # ]: 0 : if (ret)
968 [ # # ]: 0 : DRV_LOG(DEBUG,
969 : : "Interface %u cannot %s allmulti : Netlink error %s",
970 : : iface_idx, enable ? "enable" : "disable",
971 : : strerror(rte_errno));
972 : 0 : return ret;
973 : : }
974 : :
975 : : /**
976 : : * Process network interface information from Netlink message.
977 : : *
978 : : * @param nh
979 : : * Pointer to Netlink message header.
980 : : * @param arg
981 : : * Opaque data pointer for this callback.
982 : : *
983 : : * @return
984 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
985 : : */
986 : : static int
987 : 0 : mlx5_nl_cmdget_cb(struct nlmsghdr *nh, void *arg)
988 : : {
989 : : struct mlx5_nl_port_info *data = arg;
990 : : struct mlx5_nl_port_info local = {
991 : : .flags = 0,
992 : : };
993 : : size_t off = NLMSG_HDRLEN;
994 : :
995 : 0 : if (nh->nlmsg_type !=
996 [ # # ]: 0 : RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET) &&
997 : : nh->nlmsg_type !=
998 : : RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_PORT_GET))
999 : 0 : goto error;
1000 [ # # ]: 0 : while (off < nh->nlmsg_len) {
1001 : 0 : struct nlattr *na = (void *)((uintptr_t)nh + off);
1002 : 0 : void *payload = (void *)((uintptr_t)na + NLA_HDRLEN);
1003 : :
1004 [ # # ]: 0 : if (na->nla_len > nh->nlmsg_len - off)
1005 : 0 : goto error;
1006 [ # # # # : 0 : switch (na->nla_type) {
# # ]
1007 : 0 : case RDMA_NLDEV_ATTR_DEV_INDEX:
1008 : 0 : local.ibindex = *(uint32_t *)payload;
1009 : 0 : local.flags |= MLX5_NL_CMD_GET_IB_INDEX;
1010 : 0 : break;
1011 : 0 : case RDMA_NLDEV_ATTR_DEV_NAME:
1012 [ # # ]: 0 : if (!strcmp(payload, data->name))
1013 : 0 : local.flags |= MLX5_NL_CMD_GET_IB_NAME;
1014 : : break;
1015 : 0 : case RDMA_NLDEV_ATTR_NDEV_INDEX:
1016 : 0 : local.ifindex = *(uint32_t *)payload;
1017 : 0 : local.flags |= MLX5_NL_CMD_GET_NET_INDEX;
1018 : 0 : break;
1019 : 0 : case RDMA_NLDEV_ATTR_PORT_INDEX:
1020 : 0 : local.portnum = *(uint32_t *)payload;
1021 : 0 : local.flags |= MLX5_NL_CMD_GET_PORT_INDEX;
1022 : 0 : break;
1023 : 0 : case RDMA_NLDEV_ATTR_PORT_STATE:
1024 : 0 : local.state = *(uint8_t *)payload;
1025 : 0 : local.flags |= MLX5_NL_CMD_GET_PORT_STATE;
1026 : 0 : break;
1027 : : default:
1028 : : break;
1029 : : }
1030 : 0 : off += NLA_ALIGN(na->nla_len);
1031 : : }
1032 : : /*
1033 : : * It is possible to have multiple messages for all
1034 : : * Infiniband devices in the system with appropriate name.
1035 : : * So we should gather parameters locally and copy to
1036 : : * query context only in case of coinciding device name.
1037 : : */
1038 [ # # ]: 0 : if (local.flags & MLX5_NL_CMD_GET_IB_NAME) {
1039 : 0 : data->flags = local.flags;
1040 : 0 : data->ibindex = local.ibindex;
1041 : 0 : data->ifindex = local.ifindex;
1042 : 0 : data->portnum = local.portnum;
1043 : 0 : data->state = local.state;
1044 : : }
1045 : : return 0;
1046 : 0 : error:
1047 : 0 : rte_errno = EINVAL;
1048 : 0 : return -rte_errno;
1049 : : }
1050 : :
1051 : : /**
1052 : : * Get port info of network interface associated with some IB device.
1053 : : *
1054 : : * This is the only somewhat safe method to avoid resorting to heuristics
1055 : : * when faced with port representors. Unfortunately it requires at least
1056 : : * Linux 4.17.
1057 : : *
1058 : : * @param nl
1059 : : * Netlink socket of the RDMA kind (NETLINK_RDMA).
1060 : : * @param[in] pindex
1061 : : * IB device port index, starting from 1
1062 : : * @param[out] data
1063 : : * Pointer to port info.
1064 : : * @return
1065 : : * 0 on success, negative on error and rte_errno is set.
1066 : : */
1067 : : static int
1068 : 0 : mlx5_nl_port_info(int nl, uint32_t pindex, struct mlx5_nl_port_info *data)
1069 : : {
1070 : : union {
1071 : : struct nlmsghdr nh;
1072 : : uint8_t buf[NLMSG_HDRLEN +
1073 : : NLA_HDRLEN + NLA_ALIGN(sizeof(data->ibindex)) +
1074 : : NLA_HDRLEN + NLA_ALIGN(sizeof(pindex))];
1075 : 0 : } req = {
1076 : : .nh = {
1077 : : .nlmsg_len = NLMSG_LENGTH(0),
1078 : : .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1079 : : RDMA_NLDEV_CMD_GET),
1080 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
1081 : : },
1082 : : };
1083 : : struct nlattr *na;
1084 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1085 : : int ret;
1086 : :
1087 [ # # ]: 0 : if (data->ibindex == UINT32_MAX) {
1088 : 0 : ret = mlx5_nl_send(nl, &req.nh, sn);
1089 [ # # ]: 0 : if (ret < 0)
1090 : : return ret;
1091 : 0 : ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, data);
1092 [ # # ]: 0 : if (ret < 0)
1093 : : return ret;
1094 [ # # ]: 0 : if (!(data->flags & MLX5_NL_CMD_GET_IB_NAME) ||
1095 : : !(data->flags & MLX5_NL_CMD_GET_IB_INDEX))
1096 : 0 : goto error;
1097 : 0 : data->flags = 0;
1098 : : }
1099 : 0 : sn = MLX5_NL_SN_GENERATE;
1100 : 0 : req.nh.nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1101 : : RDMA_NLDEV_CMD_PORT_GET);
1102 : 0 : req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1103 : 0 : req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.buf) - NLMSG_HDRLEN);
1104 : 0 : na = (void *)((uintptr_t)req.buf + NLMSG_HDRLEN);
1105 : 0 : na->nla_len = NLA_HDRLEN + sizeof(data->ibindex);
1106 : 0 : na->nla_type = RDMA_NLDEV_ATTR_DEV_INDEX;
1107 : 0 : memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1108 : 0 : &data->ibindex, sizeof(data->ibindex));
1109 : 0 : na = (void *)((uintptr_t)na + NLA_ALIGN(na->nla_len));
1110 : 0 : na->nla_len = NLA_HDRLEN + sizeof(pindex);
1111 : 0 : na->nla_type = RDMA_NLDEV_ATTR_PORT_INDEX;
1112 : 0 : memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1113 : : &pindex, sizeof(pindex));
1114 : 0 : ret = mlx5_nl_send(nl, &req.nh, sn);
1115 [ # # ]: 0 : if (ret < 0)
1116 : : return ret;
1117 : 0 : ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, data);
1118 [ # # ]: 0 : if (ret < 0)
1119 : : return ret;
1120 : 0 : if (!(data->flags & MLX5_NL_CMD_GET_IB_NAME) ||
1121 [ # # ]: 0 : !(data->flags & MLX5_NL_CMD_GET_IB_INDEX) ||
1122 : 0 : !(data->flags & MLX5_NL_CMD_GET_NET_INDEX) ||
1123 [ # # ]: 0 : !data->ifindex)
1124 : 0 : goto error;
1125 : : return 0;
1126 : 0 : error:
1127 : 0 : rte_errno = ENODEV;
1128 : 0 : return -rte_errno;
1129 : : }
1130 : :
1131 : : /**
1132 : : * Get index of network interface associated with some IB device.
1133 : : *
1134 : : * This is the only somewhat safe method to avoid resorting to heuristics
1135 : : * when faced with port representors. Unfortunately it requires at least
1136 : : * Linux 4.17.
1137 : : *
1138 : : * @param nl
1139 : : * Netlink socket of the RDMA kind (NETLINK_RDMA).
1140 : : * @param[in] name
1141 : : * IB device name.
1142 : : * @param[in] pindex
1143 : : * IB device port index, starting from 1
1144 : : * @param[in] dev_info
1145 : : * Cached mlx5 device information.
1146 : : * @return
1147 : : * A valid (nonzero) interface index on success, 0 otherwise and rte_errno
1148 : : * is set.
1149 : : */
1150 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_ifindex)
1151 : : unsigned int
1152 : 0 : mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex, struct mlx5_dev_info *dev_info)
1153 : : {
1154 : : int ret;
1155 : :
1156 : 0 : struct mlx5_nl_port_info data = {
1157 : : .ifindex = 0,
1158 : : .name = name,
1159 : : .ibindex = UINT32_MAX,
1160 : : .flags = 0,
1161 : : };
1162 : :
1163 [ # # # # ]: 0 : if (dev_info->probe_opt && !strcmp(name, dev_info->ibname)) {
1164 [ # # # # ]: 0 : if (dev_info->port_info && pindex <= dev_info->port_num &&
1165 [ # # ]: 0 : dev_info->port_info[pindex].valid) {
1166 [ # # ]: 0 : if (!dev_info->port_info[pindex].ifindex)
1167 : 0 : rte_errno = ENODEV;
1168 : 0 : return dev_info->port_info[pindex].ifindex;
1169 : : }
1170 [ # # ]: 0 : if (dev_info->port_num)
1171 : 0 : data.ibindex = dev_info->ibindex;
1172 : : }
1173 : :
1174 : : /* Update should be done via monitor thread to avoid race condition */
1175 [ # # ]: 0 : if (dev_info->async_mon_ready) {
1176 : 0 : rte_errno = ENODEV;
1177 : 0 : return 0;
1178 : : }
1179 : 0 : ret = mlx5_nl_port_info(nl, pindex, &data);
1180 [ # # # # ]: 0 : if (dev_info->probe_opt && !strcmp(dev_info->ibname, name)) {
1181 [ # # # # ]: 0 : if ((!ret || ret == -ENODEV) && dev_info->port_info &&
1182 [ # # ]: 0 : pindex <= dev_info->port_num) {
1183 [ # # ]: 0 : if (!ret)
1184 : 0 : dev_info->port_info[pindex].ifindex = data.ifindex;
1185 : : /* -ENODEV means the pindex is unused but still valid case */
1186 : 0 : dev_info->port_info[pindex].valid = 1;
1187 : : }
1188 : : }
1189 [ # # ]: 0 : return ret ? 0 : data.ifindex;
1190 : : }
1191 : :
1192 : : /**
1193 : : * Get IB device port state.
1194 : : *
1195 : : * This is the only somewhat safe method to get info for port number >= 255.
1196 : : * Unfortunately it requires at least Linux 4.17.
1197 : : *
1198 : : * @param nl
1199 : : * Netlink socket of the RDMA kind (NETLINK_RDMA).
1200 : : * @param[in] name
1201 : : * IB device name.
1202 : : * @param[in] pindex
1203 : : * IB device port index, starting from 1
1204 : : * @param[in] dev_info
1205 : : * Cached mlx5 device information.
1206 : : * @return
1207 : : * Port state (ibv_port_state) on success, negative on error
1208 : : * and rte_errno is set.
1209 : : */
1210 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_port_state)
1211 : : int
1212 : 0 : mlx5_nl_port_state(int nl, const char *name, uint32_t pindex, struct mlx5_dev_info *dev_info)
1213 : : {
1214 : 0 : struct mlx5_nl_port_info data = {
1215 : : .state = 0,
1216 : : .name = name,
1217 : : .ibindex = UINT32_MAX,
1218 : : };
1219 : :
1220 [ # # # # ]: 0 : if (dev_info && dev_info->probe_opt &&
1221 [ # # # # ]: 0 : !strcmp(name, dev_info->ibname) && dev_info->port_num)
1222 : 0 : data.ibindex = dev_info->ibindex;
1223 [ # # ]: 0 : if (mlx5_nl_port_info(nl, pindex, &data) < 0)
1224 : 0 : return -rte_errno;
1225 [ # # ]: 0 : if ((data.flags & MLX5_NL_CMD_GET_PORT_STATE) == 0) {
1226 : 0 : rte_errno = ENOTSUP;
1227 : 0 : return -rte_errno;
1228 : : }
1229 : 0 : return (int)data.state;
1230 : : }
1231 : :
1232 : : /**
1233 : : * Get the number of physical ports of given IB device.
1234 : : *
1235 : : * @param nl
1236 : : * Netlink socket of the RDMA kind (NETLINK_RDMA).
1237 : : * @param[in] name
1238 : : * IB device name.
1239 : : * @param[in] dev_info
1240 : : * Cached mlx5 device info.
1241 : : *
1242 : : * @return
1243 : : * A valid (nonzero) number of ports on success, 0 otherwise
1244 : : * and rte_errno is set.
1245 : : */
1246 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_portnum)
1247 : : unsigned int
1248 : 0 : mlx5_nl_portnum(int nl, const char *name, struct mlx5_dev_info *dev_info)
1249 : : {
1250 : 0 : struct mlx5_nl_port_info data = {
1251 : : .flags = 0,
1252 : : .name = name,
1253 : : .ifindex = 0,
1254 : : .portnum = 0,
1255 : : };
1256 : 0 : struct nlmsghdr req = {
1257 : : .nlmsg_len = NLMSG_LENGTH(0),
1258 : : .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1259 : : RDMA_NLDEV_CMD_GET),
1260 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
1261 : : };
1262 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1263 : : int ret, size;
1264 : :
1265 [ # # # # ]: 0 : if (dev_info->probe_opt && dev_info->port_num &&
1266 [ # # ]: 0 : !strcmp(name, dev_info->ibname))
1267 : : return dev_info->port_num;
1268 : :
1269 : 0 : ret = mlx5_nl_send(nl, &req, sn);
1270 [ # # ]: 0 : if (ret < 0)
1271 : : return 0;
1272 : 0 : ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
1273 [ # # ]: 0 : if (ret < 0)
1274 : : return 0;
1275 : 0 : if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
1276 [ # # ]: 0 : !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
1277 : : !(data.flags & MLX5_NL_CMD_GET_PORT_INDEX)) {
1278 : 0 : rte_errno = ENODEV;
1279 : 0 : return 0;
1280 : : }
1281 [ # # ]: 0 : if (!data.portnum) {
1282 : 0 : rte_errno = EINVAL;
1283 : 0 : return 0;
1284 : : }
1285 [ # # ]: 0 : if (!dev_info->probe_opt)
1286 : : return data.portnum;
1287 : : MLX5_ASSERT(!strlen(dev_info->ibname));
1288 : 0 : dev_info->port_num = data.portnum;
1289 : 0 : dev_info->ibindex = data.ibindex;
1290 [ # # ]: 0 : snprintf(dev_info->ibname, MLX5_FS_NAME_MAX, "%s", name);
1291 [ # # ]: 0 : if (data.portnum > 1) {
1292 : 0 : size = (data.portnum + 1) * sizeof(struct mlx5_port_nl_info);
1293 : 0 : dev_info->port_info = mlx5_malloc(MLX5_MEM_ZERO | MLX5_MEM_RTE, size,
1294 : : RTE_CACHE_LINE_SIZE,
1295 : : SOCKET_ID_ANY);
1296 [ # # ]: 0 : if (dev_info->port_info == NULL) {
1297 : : memset(dev_info, 0, sizeof(*dev_info));
1298 : 0 : rte_errno = ENOMEM;
1299 : 0 : return 0;
1300 : : }
1301 : : }
1302 : 0 : return data.portnum;
1303 : : }
1304 : :
1305 : : /**
1306 : : * Analyze gathered port parameters via Netlink to recognize master
1307 : : * and representor devices for E-Switch configuration.
1308 : : *
1309 : : * @param[in] num_vf_set
1310 : : * flag of presence of number of VFs port attribute.
1311 : : * @param[inout] switch_info
1312 : : * Port information, including port name as a number and port name
1313 : : * type if recognized
1314 : : *
1315 : : * @return
1316 : : * master and representor flags are set in switch_info according to
1317 : : * recognized parameters (if any).
1318 : : */
1319 : : static void
1320 : : mlx5_nl_check_switch_info(bool num_vf_set,
1321 : : struct mlx5_switch_info *switch_info)
1322 : : {
1323 [ # # # # : 0 : switch (switch_info->name_type) {
# # ]
1324 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
1325 : : /*
1326 : : * Name is not recognized, assume the master,
1327 : : * check the number of VFs key presence.
1328 : : */
1329 : 0 : switch_info->master = num_vf_set;
1330 : 0 : break;
1331 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_NOTSET:
1332 : : /*
1333 : : * Name is not set, this assumes the legacy naming
1334 : : * schema for master, just check if there is a
1335 : : * number of VFs key.
1336 : : */
1337 : 0 : switch_info->master = num_vf_set;
1338 : 0 : break;
1339 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
1340 : : /* New uplink naming schema recognized. */
1341 : 0 : switch_info->master = 1;
1342 : 0 : break;
1343 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_LEGACY:
1344 : : /* Legacy representors naming schema. */
1345 : 0 : switch_info->representor = !num_vf_set;
1346 : 0 : break;
1347 : 0 : case MLX5_PHYS_PORT_NAME_TYPE_PFHPF:
1348 : : /* Fallthrough */
1349 : : case MLX5_PHYS_PORT_NAME_TYPE_PFVF:
1350 : : /* Fallthrough */
1351 : : case MLX5_PHYS_PORT_NAME_TYPE_PFSF:
1352 : : /* New representors naming schema. */
1353 : 0 : switch_info->representor = 1;
1354 : 0 : break;
1355 : : }
1356 : : }
1357 : :
1358 : : /**
1359 : : * Process switch information from Netlink message.
1360 : : *
1361 : : * @param nh
1362 : : * Pointer to Netlink message header.
1363 : : * @param arg
1364 : : * Opaque data pointer for this callback.
1365 : : *
1366 : : * @return
1367 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1368 : : */
1369 : : static int
1370 : 0 : mlx5_nl_switch_info_cb(struct nlmsghdr *nh, void *arg)
1371 : : {
1372 : 0 : struct mlx5_switch_info info = {
1373 : : .master = 0,
1374 : : .representor = 0,
1375 : : .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
1376 : : .port_name = 0,
1377 : : .switch_id = 0,
1378 : : };
1379 : : size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
1380 : : bool switch_id_set = false;
1381 : : bool num_vf_set = false;
1382 : : int len;
1383 : :
1384 [ # # ]: 0 : if (nh->nlmsg_type != RTM_NEWLINK)
1385 : 0 : goto error;
1386 [ # # ]: 0 : while (off < nh->nlmsg_len) {
1387 : 0 : struct rtattr *ra = (void *)((uintptr_t)nh + off);
1388 : 0 : void *payload = RTA_DATA(ra);
1389 : : unsigned int i;
1390 : :
1391 [ # # ]: 0 : if (ra->rta_len > nh->nlmsg_len - off)
1392 : 0 : goto error;
1393 [ # # # # ]: 0 : switch (ra->rta_type) {
1394 : 0 : case IFLA_NUM_VF:
1395 : : num_vf_set = true;
1396 : 0 : break;
1397 : 0 : case IFLA_PHYS_PORT_NAME:
1398 : 0 : len = RTA_PAYLOAD(ra);
1399 : : /* Some kernels do not pad attributes with zero. */
1400 [ # # ]: 0 : if (len > 0 && len < MLX5_PHYS_PORT_NAME_MAX) {
1401 : : char name[MLX5_PHYS_PORT_NAME_MAX];
1402 : :
1403 : : /*
1404 : : * We can't just patch the message with padding
1405 : : * zero - it might corrupt the following items
1406 : : * in the message, we have to copy the string
1407 : : * by attribute length and pad the copied one.
1408 : : */
1409 : 0 : memcpy(name, payload, len);
1410 : 0 : name[len] = 0;
1411 : 0 : mlx5_translate_port_name(name, &info);
1412 : : } else {
1413 : 0 : info.name_type =
1414 : : MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN;
1415 : : }
1416 : : break;
1417 : 0 : case IFLA_PHYS_SWITCH_ID:
1418 : 0 : info.switch_id = 0;
1419 [ # # ]: 0 : for (i = 0; i < RTA_PAYLOAD(ra); ++i) {
1420 : 0 : info.switch_id <<= 8;
1421 : 0 : info.switch_id |= ((uint8_t *)payload)[i];
1422 : : }
1423 : : switch_id_set = true;
1424 : : break;
1425 : : }
1426 : 0 : off += RTA_ALIGN(ra->rta_len);
1427 : : }
1428 [ # # ]: 0 : if (switch_id_set) {
1429 : : /* We have some E-Switch configuration. */
1430 : : mlx5_nl_check_switch_info(num_vf_set, &info);
1431 : : }
1432 : : MLX5_ASSERT(!(info.master && info.representor));
1433 : : memcpy(arg, &info, sizeof(info));
1434 : 0 : return 0;
1435 : 0 : error:
1436 : 0 : rte_errno = EINVAL;
1437 : 0 : return -rte_errno;
1438 : : }
1439 : :
1440 : : /**
1441 : : * Get switch information associated with network interface.
1442 : : *
1443 : : * @param nl
1444 : : * Netlink socket of the ROUTE kind (NETLINK_ROUTE).
1445 : : * @param ifindex
1446 : : * Network interface index.
1447 : : * @param[out] info
1448 : : * Switch information object, populated in case of success.
1449 : : *
1450 : : * @return
1451 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1452 : : */
1453 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_switch_info)
1454 : : int
1455 : 0 : mlx5_nl_switch_info(int nl, unsigned int ifindex,
1456 : : struct mlx5_switch_info *info)
1457 : : {
1458 : : struct {
1459 : : struct nlmsghdr nh;
1460 : : struct ifinfomsg info;
1461 : : struct rtattr rta;
1462 : : uint32_t extmask;
1463 : 0 : } req = {
1464 : : .nh = {
1465 : : .nlmsg_len = NLMSG_LENGTH
1466 : : (sizeof(req.info) +
1467 : : RTA_LENGTH(sizeof(uint32_t))),
1468 : : .nlmsg_type = RTM_GETLINK,
1469 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
1470 : : },
1471 : : .info = {
1472 : : .ifi_family = AF_UNSPEC,
1473 : : .ifi_index = ifindex,
1474 : : },
1475 : : .rta = {
1476 : : .rta_type = IFLA_EXT_MASK,
1477 : : .rta_len = RTA_LENGTH(sizeof(int32_t)),
1478 : : },
1479 : : .extmask = RTE_LE32(1),
1480 : : };
1481 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1482 : : int ret;
1483 : :
1484 : 0 : ret = mlx5_nl_send(nl, &req.nh, sn);
1485 [ # # ]: 0 : if (ret >= 0)
1486 : 0 : ret = mlx5_nl_recv(nl, sn, mlx5_nl_switch_info_cb, info);
1487 [ # # ]: 0 : if (info->master && info->representor) {
1488 : 0 : DRV_LOG(ERR, "ifindex %u device is recognized as master"
1489 : : " and as representor", ifindex);
1490 : 0 : rte_errno = ENODEV;
1491 : : ret = -rte_errno;
1492 : : }
1493 : 0 : return ret;
1494 : : }
1495 : :
1496 : : /*
1497 : : * Delete VLAN network device by ifindex.
1498 : : *
1499 : : * @param[in] tcf
1500 : : * Context object initialized by mlx5_nl_vlan_vmwa_init().
1501 : : * @param[in] ifindex
1502 : : * Interface index of network device to delete.
1503 : : */
1504 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_vlan_vmwa_delete)
1505 : : void
1506 : 0 : mlx5_nl_vlan_vmwa_delete(struct mlx5_nl_vlan_vmwa_context *vmwa,
1507 : : uint32_t ifindex)
1508 : : {
1509 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1510 : : int ret;
1511 : : struct {
1512 : : struct nlmsghdr nh;
1513 : : struct ifinfomsg info;
1514 : 0 : } req = {
1515 : : .nh = {
1516 : : .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
1517 : : .nlmsg_type = RTM_DELLINK,
1518 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
1519 : : },
1520 : : .info = {
1521 : : .ifi_family = AF_UNSPEC,
1522 : : .ifi_index = ifindex,
1523 : : },
1524 : : };
1525 : :
1526 [ # # ]: 0 : if (ifindex) {
1527 : 0 : ret = mlx5_nl_send(vmwa->nl_socket, &req.nh, sn);
1528 [ # # ]: 0 : if (ret >= 0)
1529 : 0 : ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
1530 [ # # ]: 0 : if (ret < 0)
1531 : 0 : DRV_LOG(WARNING, "netlink: error deleting VLAN WA"
1532 : : " ifindex %u, %d", ifindex, ret);
1533 : : }
1534 : 0 : }
1535 : :
1536 : : /* Set of subroutines to build Netlink message. */
1537 : : static struct nlattr *
1538 : : nl_msg_tail(struct nlmsghdr *nlh)
1539 : : {
1540 : 0 : return (struct nlattr *)
1541 : 0 : (((uint8_t *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
1542 : : }
1543 : :
1544 : : static void
1545 : 0 : nl_attr_put(struct nlmsghdr *nlh, int type, const void *data, int alen)
1546 : : {
1547 : : struct nlattr *nla = nl_msg_tail(nlh);
1548 : :
1549 : 0 : nla->nla_type = type;
1550 : 0 : nla->nla_len = NLMSG_ALIGN(sizeof(struct nlattr)) + alen;
1551 : 0 : nlh->nlmsg_len += NLMSG_ALIGN(nla->nla_len);
1552 : :
1553 [ # # ]: 0 : if (alen)
1554 : 0 : memcpy((uint8_t *)nla + sizeof(struct nlattr), data, alen);
1555 : 0 : }
1556 : :
1557 : : static struct nlattr *
1558 : : nl_attr_nest_start(struct nlmsghdr *nlh, int type)
1559 : : {
1560 : : struct nlattr *nest = (struct nlattr *)nl_msg_tail(nlh);
1561 : :
1562 : : nl_attr_put(nlh, type, NULL, 0);
1563 : : return nest;
1564 : : }
1565 : :
1566 : : static void
1567 : : nl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *nest)
1568 : : {
1569 : 0 : nest->nla_len = (uint8_t *)nl_msg_tail(nlh) - (uint8_t *)nest;
1570 : : }
1571 : :
1572 : : /*
1573 : : * Create network VLAN device with specified VLAN tag.
1574 : : *
1575 : : * @param[in] tcf
1576 : : * Context object initialized by mlx5_nl_vlan_vmwa_init().
1577 : : * @param[in] ifindex
1578 : : * Base network interface index.
1579 : : * @param[in] tag
1580 : : * VLAN tag for VLAN network device to create.
1581 : : */
1582 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_vlan_vmwa_create)
1583 : : uint32_t
1584 : 0 : mlx5_nl_vlan_vmwa_create(struct mlx5_nl_vlan_vmwa_context *vmwa,
1585 : : uint32_t ifindex, uint16_t tag)
1586 : : {
1587 : : struct nlmsghdr *nlh;
1588 : : struct ifinfomsg *ifm;
1589 : : char name[sizeof(MLX5_VMWA_VLAN_DEVICE_PFX) + 32];
1590 : :
1591 : : alignas(RTE_CACHE_LINE_SIZE)
1592 : : uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1593 : : NLMSG_ALIGN(sizeof(struct ifinfomsg)) +
1594 : : NLMSG_ALIGN(sizeof(struct nlattr)) * 8 +
1595 : : NLMSG_ALIGN(sizeof(uint32_t)) +
1596 : : NLMSG_ALIGN(sizeof(name)) +
1597 : : NLMSG_ALIGN(sizeof("vlan")) +
1598 : : NLMSG_ALIGN(sizeof(uint32_t)) +
1599 : : NLMSG_ALIGN(sizeof(uint16_t)) + 16];
1600 : : struct nlattr *na_info;
1601 : : struct nlattr *na_vlan;
1602 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1603 : : int ret;
1604 : :
1605 : : memset(buf, 0, sizeof(buf));
1606 : : nlh = (struct nlmsghdr *)buf;
1607 : : nlh->nlmsg_len = sizeof(struct nlmsghdr);
1608 : 0 : nlh->nlmsg_type = RTM_NEWLINK;
1609 : 0 : nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
1610 : : NLM_F_EXCL | NLM_F_ACK;
1611 : : ifm = (struct ifinfomsg *)nl_msg_tail(nlh);
1612 : 0 : nlh->nlmsg_len += sizeof(struct ifinfomsg);
1613 : : ifm->ifi_family = AF_UNSPEC;
1614 : : ifm->ifi_type = 0;
1615 : : ifm->ifi_index = 0;
1616 : 0 : ifm->ifi_flags = IFF_UP;
1617 : 0 : ifm->ifi_change = 0xffffffff;
1618 : 0 : nl_attr_put(nlh, IFLA_LINK, &ifindex, sizeof(ifindex));
1619 : 0 : ret = snprintf(name, sizeof(name), "%s.%u.%u",
1620 : : MLX5_VMWA_VLAN_DEVICE_PFX, ifindex, tag);
1621 : 0 : nl_attr_put(nlh, IFLA_IFNAME, name, ret + 1);
1622 : : na_info = nl_attr_nest_start(nlh, IFLA_LINKINFO);
1623 : 0 : nl_attr_put(nlh, IFLA_INFO_KIND, "vlan", sizeof("vlan"));
1624 : : na_vlan = nl_attr_nest_start(nlh, IFLA_INFO_DATA);
1625 : 0 : nl_attr_put(nlh, IFLA_VLAN_ID, &tag, sizeof(tag));
1626 : : nl_attr_nest_end(nlh, na_vlan);
1627 : : nl_attr_nest_end(nlh, na_info);
1628 : : MLX5_ASSERT(sizeof(buf) >= nlh->nlmsg_len);
1629 : 0 : ret = mlx5_nl_send(vmwa->nl_socket, nlh, sn);
1630 [ # # ]: 0 : if (ret >= 0)
1631 : 0 : ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
1632 [ # # ]: 0 : if (ret < 0) {
1633 : 0 : DRV_LOG(WARNING, "netlink: VLAN %s create failure (%d)", name,
1634 : : ret);
1635 : : }
1636 : : /* Try to get ifindex of created or pre-existing device. */
1637 : 0 : ret = if_nametoindex(name);
1638 [ # # ]: 0 : if (!ret) {
1639 : 0 : DRV_LOG(WARNING, "VLAN %s failed to get index (%d)", name,
1640 : : errno);
1641 : 0 : return 0;
1642 : : }
1643 : : return ret;
1644 : : }
1645 : :
1646 : : /**
1647 : : * Parse Netlink message to retrieve the general family ID.
1648 : : *
1649 : : * @param nh
1650 : : * Pointer to Netlink Message Header.
1651 : : * @param arg
1652 : : * PMD data register with this callback.
1653 : : *
1654 : : * @return
1655 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1656 : : */
1657 : : static int
1658 : 0 : mlx5_nl_family_id_cb(struct nlmsghdr *nh, void *arg)
1659 : : {
1660 : :
1661 : 0 : struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
1662 : 0 : struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
1663 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)));
1664 : :
1665 [ # # # # ]: 0 : for (; nla->nla_len && nla < tail;
1666 : 0 : nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len))) {
1667 [ # # ]: 0 : if (nla->nla_type == CTRL_ATTR_FAMILY_ID) {
1668 : 0 : *(uint16_t *)arg = *(uint16_t *)(nla + 1);
1669 : 0 : return 0;
1670 : : }
1671 : : }
1672 : : return -EINVAL;
1673 : : }
1674 : :
1675 : : #define MLX5_NL_MAX_ATTR_SIZE 100
1676 : : /**
1677 : : * Get generic netlink family ID.
1678 : : *
1679 : : * @param[in] nlsk_fd
1680 : : * Netlink socket file descriptor.
1681 : : * @param[in] name
1682 : : * The family name.
1683 : : *
1684 : : * @return
1685 : : * ID >= 0 on success and @p enable is updated, a negative errno value
1686 : : * otherwise and rte_errno is set.
1687 : : */
1688 : : static int
1689 : 0 : mlx5_nl_generic_family_id_get(int nlsk_fd, const char *name)
1690 : : {
1691 : : struct nlmsghdr *nlh;
1692 : : struct genlmsghdr *genl;
1693 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1694 : 0 : int name_size = strlen(name) + 1;
1695 : : int ret;
1696 : 0 : uint16_t id = -1;
1697 : : uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1698 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1699 : : NLMSG_ALIGN(sizeof(struct nlattr)) +
1700 : : NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE)];
1701 : :
1702 : : memset(buf, 0, sizeof(buf));
1703 : : nlh = (struct nlmsghdr *)buf;
1704 : : nlh->nlmsg_len = sizeof(struct nlmsghdr);
1705 : 0 : nlh->nlmsg_type = GENL_ID_CTRL;
1706 : 0 : nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1707 : : genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1708 : 0 : nlh->nlmsg_len += sizeof(struct genlmsghdr);
1709 : 0 : genl->cmd = CTRL_CMD_GETFAMILY;
1710 : 0 : genl->version = 1;
1711 : 0 : nl_attr_put(nlh, CTRL_ATTR_FAMILY_NAME, name, name_size);
1712 : 0 : ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1713 [ # # ]: 0 : if (ret >= 0)
1714 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_family_id_cb, &id);
1715 [ # # ]: 0 : if (ret < 0) {
1716 : 0 : DRV_LOG(DEBUG, "Failed to get Netlink %s family ID: %d.", name,
1717 : : ret);
1718 : 0 : return ret;
1719 : : }
1720 : 0 : DRV_LOG(DEBUG, "Netlink \"%s\" family ID is %u.", name, id);
1721 : 0 : return (int)id;
1722 : : }
1723 : :
1724 : : /**
1725 : : * Get Devlink family ID.
1726 : : *
1727 : : * @param[in] nlsk_fd
1728 : : * Netlink socket file descriptor.
1729 : : *
1730 : : * @return
1731 : : * ID >= 0 on success and @p enable is updated, a negative errno value
1732 : : * otherwise and rte_errno is set.
1733 : : */
1734 : :
1735 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_devlink_family_id_get)
1736 : : int
1737 : 0 : mlx5_nl_devlink_family_id_get(int nlsk_fd)
1738 : : {
1739 : 0 : return mlx5_nl_generic_family_id_get(nlsk_fd, DEVLINK_GENL_NAME);
1740 : : }
1741 : :
1742 : : /**
1743 : : * Parse Netlink message to retrieve the ROCE enable status.
1744 : : *
1745 : : * @param nh
1746 : : * Pointer to Netlink Message Header.
1747 : : * @param arg
1748 : : * PMD data register with this callback.
1749 : : *
1750 : : * @return
1751 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1752 : : */
1753 : : static int
1754 : 0 : mlx5_nl_roce_cb(struct nlmsghdr *nh, void *arg)
1755 : : {
1756 : :
1757 : : int ret = -EINVAL;
1758 : : int *enable = arg;
1759 : 0 : struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
1760 : 0 : struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
1761 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)));
1762 : :
1763 [ # # # # ]: 0 : while (nla->nla_len && nla < tail) {
1764 [ # # # ]: 0 : switch (nla->nla_type) {
1765 : : /* Expected nested attributes case. */
1766 : 0 : case DEVLINK_ATTR_PARAM:
1767 : : case DEVLINK_ATTR_PARAM_VALUES_LIST:
1768 : : case DEVLINK_ATTR_PARAM_VALUE:
1769 : : ret = 0;
1770 : 0 : nla += 1;
1771 : 0 : break;
1772 : 0 : case DEVLINK_ATTR_PARAM_VALUE_DATA:
1773 : 0 : *enable = 1;
1774 : 0 : return 0;
1775 : 0 : default:
1776 : 0 : nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len));
1777 : : }
1778 : : }
1779 : 0 : *enable = 0;
1780 : 0 : return ret;
1781 : : }
1782 : :
1783 : : /**
1784 : : * Get ROCE enable status through Netlink.
1785 : : *
1786 : : * @param[in] nlsk_fd
1787 : : * Netlink socket file descriptor.
1788 : : * @param[in] family_id
1789 : : * the Devlink family ID.
1790 : : * @param pci_addr
1791 : : * The device PCI address.
1792 : : * @param[out] enable
1793 : : * Where to store the enable status.
1794 : : *
1795 : : * @return
1796 : : * 0 on success and @p enable is updated, a negative errno value otherwise
1797 : : * and rte_errno is set.
1798 : : */
1799 : : int
1800 : 0 : mlx5_nl_enable_roce_get(int nlsk_fd, int family_id, const char *pci_addr,
1801 : : int *enable)
1802 : : {
1803 : : struct nlmsghdr *nlh;
1804 : : struct genlmsghdr *genl;
1805 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1806 : : int ret;
1807 : 0 : int cur_en = 0;
1808 : : uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1809 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1810 : : NLMSG_ALIGN(sizeof(struct nlattr)) * 4 +
1811 : : NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4];
1812 : :
1813 : : memset(buf, 0, sizeof(buf));
1814 : : nlh = (struct nlmsghdr *)buf;
1815 : : nlh->nlmsg_len = sizeof(struct nlmsghdr);
1816 : 0 : nlh->nlmsg_type = family_id;
1817 : 0 : nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1818 : : genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1819 : 0 : nlh->nlmsg_len += sizeof(struct genlmsghdr);
1820 : 0 : genl->cmd = DEVLINK_CMD_PARAM_GET;
1821 : 0 : genl->version = DEVLINK_GENL_VERSION;
1822 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1823 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1824 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
1825 : 0 : ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1826 [ # # ]: 0 : if (ret >= 0)
1827 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_roce_cb, &cur_en);
1828 [ # # ]: 0 : if (ret < 0) {
1829 : 0 : DRV_LOG(DEBUG, "Failed to get ROCE enable on device %s: %d.",
1830 : : pci_addr, ret);
1831 : 0 : return ret;
1832 : : }
1833 : 0 : *enable = cur_en;
1834 [ # # ]: 0 : DRV_LOG(DEBUG, "ROCE is %sabled for device \"%s\".",
1835 : : cur_en ? "en" : "dis", pci_addr);
1836 : 0 : return ret;
1837 : : }
1838 : :
1839 : : /**
1840 : : * Reload mlx5 device kernel driver through Netlink.
1841 : : *
1842 : : * @param[in] nlsk_fd
1843 : : * Netlink socket file descriptor.
1844 : : * @param[in] family_id
1845 : : * the Devlink family ID.
1846 : : * @param pci_addr
1847 : : * The device PCI address.
1848 : : * @param[out] enable
1849 : : * The enable status to set.
1850 : : *
1851 : : * @return
1852 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1853 : : */
1854 : : static int
1855 : 0 : mlx5_nl_driver_reload(int nlsk_fd, int family_id, const char *pci_addr)
1856 : : {
1857 : : struct nlmsghdr *nlh;
1858 : : struct genlmsghdr *genl;
1859 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1860 : : int ret;
1861 : : uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1862 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1863 : : NLMSG_ALIGN(sizeof(struct nlattr)) * 2 +
1864 : : NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 2];
1865 : :
1866 : : memset(buf, 0, sizeof(buf));
1867 : : nlh = (struct nlmsghdr *)buf;
1868 : : nlh->nlmsg_len = sizeof(struct nlmsghdr);
1869 : 0 : nlh->nlmsg_type = family_id;
1870 : 0 : nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1871 : : genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1872 : 0 : nlh->nlmsg_len += sizeof(struct genlmsghdr);
1873 : 0 : genl->cmd = DEVLINK_CMD_RELOAD;
1874 : 0 : genl->version = DEVLINK_GENL_VERSION;
1875 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1876 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1877 : 0 : ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1878 [ # # ]: 0 : if (ret >= 0)
1879 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
1880 [ # # ]: 0 : if (ret < 0) {
1881 : 0 : DRV_LOG(DEBUG, "Failed to reload %s device by Netlink - %d",
1882 : : pci_addr, ret);
1883 : 0 : return ret;
1884 : : }
1885 : 0 : DRV_LOG(DEBUG, "Device \"%s\" was reloaded by Netlink successfully.",
1886 : : pci_addr);
1887 : 0 : return 0;
1888 : : }
1889 : :
1890 : : /**
1891 : : * Set ROCE enable status through Netlink.
1892 : : *
1893 : : * @param[in] nlsk_fd
1894 : : * Netlink socket file descriptor.
1895 : : * @param[in] family_id
1896 : : * the Devlink family ID.
1897 : : * @param pci_addr
1898 : : * The device PCI address.
1899 : : * @param[out] enable
1900 : : * The enable status to set.
1901 : : *
1902 : : * @return
1903 : : * 0 on success, a negative errno value otherwise and rte_errno is set.
1904 : : */
1905 : : int
1906 : 0 : mlx5_nl_enable_roce_set(int nlsk_fd, int family_id, const char *pci_addr,
1907 : : int enable)
1908 : : {
1909 : : struct nlmsghdr *nlh;
1910 : : struct genlmsghdr *genl;
1911 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
1912 : : int ret;
1913 : : uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
1914 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
1915 : : NLMSG_ALIGN(sizeof(struct nlattr)) * 6 +
1916 : : NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 6];
1917 : 0 : uint8_t cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
1918 : 0 : uint8_t ptype = NLA_FLAG;
1919 : : ;
1920 : :
1921 : : memset(buf, 0, sizeof(buf));
1922 : : nlh = (struct nlmsghdr *)buf;
1923 : : nlh->nlmsg_len = sizeof(struct nlmsghdr);
1924 : 0 : nlh->nlmsg_type = family_id;
1925 : 0 : nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1926 : : genl = (struct genlmsghdr *)nl_msg_tail(nlh);
1927 : 0 : nlh->nlmsg_len += sizeof(struct genlmsghdr);
1928 : 0 : genl->cmd = DEVLINK_CMD_PARAM_SET;
1929 : 0 : genl->version = DEVLINK_GENL_VERSION;
1930 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
1931 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
1932 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
1933 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, &cmode, sizeof(cmode));
1934 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_PARAM_TYPE, &ptype, sizeof(ptype));
1935 [ # # ]: 0 : if (enable)
1936 : : nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, NULL, 0);
1937 : 0 : ret = mlx5_nl_send(nlsk_fd, nlh, sn);
1938 [ # # ]: 0 : if (ret >= 0)
1939 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
1940 [ # # ]: 0 : if (ret < 0) {
1941 [ # # ]: 0 : DRV_LOG(DEBUG, "Failed to %sable ROCE for device %s by Netlink:"
1942 : : " %d.", enable ? "en" : "dis", pci_addr, ret);
1943 : 0 : return ret;
1944 : : }
1945 [ # # ]: 0 : DRV_LOG(DEBUG, "Device %s ROCE was %sabled by Netlink successfully.",
1946 : : pci_addr, enable ? "en" : "dis");
1947 : : /* Now, need to reload the driver. */
1948 : 0 : return mlx5_nl_driver_reload(nlsk_fd, family_id, pci_addr);
1949 : : }
1950 : :
1951 : : /**
1952 : : * Try to parse a Netlink message as a link status update.
1953 : : *
1954 : : * @param hdr
1955 : : * Netlink message header.
1956 : : * @param[out] ifindex
1957 : : * Index of the updated interface.
1958 : : *
1959 : : * @return
1960 : : * 0 on success, negative on failure.
1961 : : */
1962 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_parse_link_status_update)
1963 : : int
1964 : 0 : mlx5_nl_parse_link_status_update(struct nlmsghdr *hdr, uint32_t *ifindex)
1965 : : {
1966 : : struct ifinfomsg *info;
1967 : :
1968 [ # # ]: 0 : switch (hdr->nlmsg_type) {
1969 : 0 : case RTM_NEWLINK:
1970 : : case RTM_DELLINK:
1971 : : case RTM_GETLINK:
1972 : : case RTM_SETLINK:
1973 : : info = NLMSG_DATA(hdr);
1974 : 0 : *ifindex = info->ifi_index;
1975 : 0 : return 0;
1976 : : }
1977 : : return -1;
1978 : : }
1979 : :
1980 : : /**
1981 : : * Read pending events from a Netlink socket.
1982 : : *
1983 : : * @param nlsk_fd
1984 : : * Netlink socket.
1985 : : * @param cb
1986 : : * Callback invoked for each of the events.
1987 : : * @param cb_arg
1988 : : * User data for the callback.
1989 : : *
1990 : : * @return
1991 : : * 0 on success, including the case when there are no events.
1992 : : * Negative on failure and rte_errno is set.
1993 : : */
1994 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_read_events)
1995 : : int
1996 : 0 : mlx5_nl_read_events(int nlsk_fd, mlx5_nl_event_cb *cb, void *cb_arg)
1997 : : {
1998 : : char buf[8192];
1999 : : struct sockaddr_nl addr;
2000 : 0 : struct iovec iov = {
2001 : : .iov_base = buf,
2002 : : .iov_len = sizeof(buf),
2003 : : };
2004 : 0 : struct msghdr msg = {
2005 : : .msg_name = &addr,
2006 : : .msg_namelen = sizeof(addr),
2007 : : .msg_iov = &iov,
2008 : : .msg_iovlen = 1,
2009 : : };
2010 : : struct nlmsghdr *hdr;
2011 : : ssize_t size;
2012 : :
2013 : : while (1) {
2014 : 0 : size = recvmsg(nlsk_fd, &msg, MSG_DONTWAIT);
2015 [ # # ]: 0 : if (size < 0) {
2016 [ # # ]: 0 : if (errno == EAGAIN)
2017 : : return 0;
2018 [ # # ]: 0 : if (errno == EINTR)
2019 : 0 : continue;
2020 : 0 : DRV_LOG(DEBUG, "Failed to receive netlink message: %s",
2021 : : strerror(errno));
2022 : 0 : rte_errno = errno;
2023 : 0 : return -rte_errno;
2024 : : }
2025 : : hdr = (struct nlmsghdr *)buf;
2026 [ # # ]: 0 : while (size >= (ssize_t)sizeof(*hdr)) {
2027 : 0 : ssize_t msg_len = hdr->nlmsg_len;
2028 : 0 : ssize_t data_len = msg_len - sizeof(*hdr);
2029 : : ssize_t aligned_len;
2030 : :
2031 [ # # ]: 0 : if (data_len < 0) {
2032 : 0 : DRV_LOG(DEBUG, "Netlink message too short");
2033 : 0 : rte_errno = EINVAL;
2034 : 0 : return -rte_errno;
2035 : : }
2036 : 0 : aligned_len = NLMSG_ALIGN(msg_len);
2037 [ # # ]: 0 : if (aligned_len > size) {
2038 : 0 : DRV_LOG(DEBUG, "Netlink message too long");
2039 : 0 : rte_errno = EINVAL;
2040 : 0 : return -rte_errno;
2041 : : }
2042 : 0 : cb(hdr, cb_arg);
2043 : 0 : hdr = RTE_PTR_ADD(hdr, aligned_len);
2044 : 0 : size -= aligned_len;
2045 : : }
2046 : : }
2047 : : return 0;
2048 : : }
2049 : :
2050 : : static int
2051 : 0 : mlx5_nl_esw_multiport_cb(struct nlmsghdr *nh, void *arg)
2052 : : {
2053 : :
2054 : : int ret = -EINVAL;
2055 : : int *enable = arg;
2056 : 0 : struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
2057 : 0 : struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
2058 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)));
2059 : :
2060 [ # # # # ]: 0 : while (nla->nla_len && nla < tail) {
2061 [ # # # ]: 0 : switch (nla->nla_type) {
2062 : : /* Expected nested attributes case. */
2063 : 0 : case DEVLINK_ATTR_PARAM:
2064 : : case DEVLINK_ATTR_PARAM_VALUES_LIST:
2065 : : case DEVLINK_ATTR_PARAM_VALUE:
2066 : : ret = 0;
2067 : 0 : nla += 1;
2068 : 0 : break;
2069 : 0 : case DEVLINK_ATTR_PARAM_VALUE_DATA:
2070 : 0 : *enable = 1;
2071 : 0 : return 0;
2072 : 0 : default:
2073 : 0 : nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len));
2074 : : }
2075 : : }
2076 : 0 : *enable = 0;
2077 : 0 : return ret;
2078 : : }
2079 : :
2080 : : #define NL_ESW_MULTIPORT_PARAM "esw_multiport"
2081 : :
2082 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_devlink_esw_multiport_get)
2083 : : int
2084 : 0 : mlx5_nl_devlink_esw_multiport_get(int nlsk_fd, int family_id, const char *pci_addr, int *enable)
2085 : : {
2086 : : struct nlmsghdr *nlh;
2087 : : struct genlmsghdr *genl;
2088 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
2089 : : int ret;
2090 : : uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
2091 : : NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
2092 : : NLMSG_ALIGN(sizeof(struct nlattr)) * 4 +
2093 : : NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4];
2094 : :
2095 : : memset(buf, 0, sizeof(buf));
2096 : : nlh = (struct nlmsghdr *)buf;
2097 : : nlh->nlmsg_len = sizeof(struct nlmsghdr);
2098 : 0 : nlh->nlmsg_type = family_id;
2099 : 0 : nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
2100 : : genl = (struct genlmsghdr *)nl_msg_tail(nlh);
2101 : 0 : nlh->nlmsg_len += sizeof(struct genlmsghdr);
2102 : 0 : genl->cmd = DEVLINK_CMD_PARAM_GET;
2103 : 0 : genl->version = DEVLINK_GENL_VERSION;
2104 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
2105 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
2106 : 0 : nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME,
2107 : : NL_ESW_MULTIPORT_PARAM, sizeof(NL_ESW_MULTIPORT_PARAM));
2108 : 0 : ret = mlx5_nl_send(nlsk_fd, nlh, sn);
2109 [ # # ]: 0 : if (ret >= 0)
2110 : 0 : ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_esw_multiport_cb, enable);
2111 [ # # ]: 0 : if (ret < 0) {
2112 : 0 : DRV_LOG(DEBUG, "Failed to get Multiport E-Switch enable on device %s: %d.",
2113 : : pci_addr, ret);
2114 : 0 : return ret;
2115 : : }
2116 [ # # ]: 0 : DRV_LOG(DEBUG, "Multiport E-Switch is %sabled for device \"%s\".",
2117 : : *enable ? "en" : "dis", pci_addr);
2118 : 0 : return ret;
2119 : : }
2120 : :
2121 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_rdma_monitor_init)
2122 : : int
2123 : 0 : mlx5_nl_rdma_monitor_init(void)
2124 : : {
2125 : 0 : return mlx5_nl_init(NETLINK_RDMA, RDMA_NL_GROUP_NOTIFICATION);
2126 : : }
2127 : :
2128 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_rdma_monitor_info_get)
2129 : : void
2130 : 0 : mlx5_nl_rdma_monitor_info_get(struct nlmsghdr *hdr, struct mlx5_nl_port_info *data)
2131 : : {
2132 : : size_t off = NLMSG_HDRLEN;
2133 : : uint8_t event_type = 0;
2134 : :
2135 [ # # ]: 0 : if (hdr->nlmsg_type != RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_MONITOR))
2136 : 0 : goto error;
2137 : :
2138 [ # # ]: 0 : while (off < hdr->nlmsg_len) {
2139 : 0 : struct nlattr *na = (void *)((uintptr_t)hdr + off);
2140 : 0 : void *payload = (void *)((uintptr_t)na + NLA_HDRLEN);
2141 : :
2142 [ # # ]: 0 : if (na->nla_len > hdr->nlmsg_len - off)
2143 : 0 : goto error;
2144 [ # # # # : 0 : switch (na->nla_type) {
# ]
2145 : 0 : case RDMA_NLDEV_ATTR_EVENT_TYPE:
2146 : 0 : event_type = *(uint8_t *)payload;
2147 [ # # ]: 0 : if (event_type == RDMA_NETDEV_ATTACH_EVENT) {
2148 : 0 : data->flags |= MLX5_NL_CMD_GET_EVENT_TYPE;
2149 : 0 : data->event_type = MLX5_NL_RDMA_NETDEV_ATTACH_EVENT;
2150 [ # # ]: 0 : } else if (event_type == RDMA_NETDEV_DETACH_EVENT) {
2151 : 0 : data->flags |= MLX5_NL_CMD_GET_EVENT_TYPE;
2152 : 0 : data->event_type = MLX5_NL_RDMA_NETDEV_DETACH_EVENT;
2153 : : }
2154 : : break;
2155 : 0 : case RDMA_NLDEV_ATTR_DEV_INDEX:
2156 : 0 : data->ibindex = *(uint32_t *)payload;
2157 : 0 : data->flags |= MLX5_NL_CMD_GET_IB_INDEX;
2158 : 0 : break;
2159 : 0 : case RDMA_NLDEV_ATTR_PORT_INDEX:
2160 : 0 : data->portnum = *(uint32_t *)payload;
2161 : 0 : data->flags |= MLX5_NL_CMD_GET_PORT_INDEX;
2162 : 0 : break;
2163 : 0 : case RDMA_NLDEV_ATTR_NDEV_INDEX:
2164 : 0 : data->ifindex = *(uint32_t *)payload;
2165 : 0 : data->flags |= MLX5_NL_CMD_GET_NET_INDEX;
2166 : 0 : break;
2167 : 0 : default:
2168 : 0 : DRV_LOG(DEBUG, "Unknown attribute[%d] found", na->nla_type);
2169 : 0 : break;
2170 : : }
2171 : 0 : off += NLA_ALIGN(na->nla_len);
2172 : : }
2173 : :
2174 : : return;
2175 : :
2176 : 0 : error:
2177 : 0 : rte_errno = EINVAL;
2178 : : }
2179 : :
2180 : : static int
2181 : 0 : mlx5_nl_rdma_monitor_cap_get_cb(struct nlmsghdr *hdr, void *arg)
2182 : : {
2183 : : size_t off = NLMSG_HDRLEN;
2184 : : uint8_t *cap = arg;
2185 : :
2186 [ # # ]: 0 : if (hdr->nlmsg_type != RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_SYS_GET))
2187 : 0 : goto error;
2188 : :
2189 : 0 : *cap = 0;
2190 [ # # ]: 0 : while (off < hdr->nlmsg_len) {
2191 : 0 : struct nlattr *na = (void *)((uintptr_t)hdr + off);
2192 : 0 : void *payload = (void *)((uintptr_t)na + NLA_HDRLEN);
2193 : :
2194 [ # # ]: 0 : if (na->nla_len > hdr->nlmsg_len - off)
2195 : 0 : goto error;
2196 [ # # ]: 0 : switch (na->nla_type) {
2197 : 0 : case RDMA_NLDEV_SYS_ATTR_MONITOR_MODE:
2198 : 0 : *cap = *(uint8_t *)payload;
2199 : 0 : return 0;
2200 : : default:
2201 : : break;
2202 : : }
2203 : 0 : off += NLA_ALIGN(na->nla_len);
2204 : : }
2205 : :
2206 : : return 0;
2207 : :
2208 : : error:
2209 : : return -EINVAL;
2210 : : }
2211 : :
2212 : : /**
2213 : : * Get RDMA monitor support in driver.
2214 : : *
2215 : : *
2216 : : * @param nl
2217 : : * Netlink socket of the RDMA kind (NETLINK_RDMA).
2218 : : * @param[out] cap
2219 : : * Pointer to port info.
2220 : : * @return
2221 : : * 0 on success, negative on error and rte_errno is set.
2222 : : */
2223 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_rdma_monitor_cap_get)
2224 : : int
2225 : 0 : mlx5_nl_rdma_monitor_cap_get(int nl, uint8_t *cap)
2226 : : {
2227 : : union {
2228 : : struct nlmsghdr nh;
2229 : : uint8_t buf[NLMSG_HDRLEN];
2230 : 0 : } req = {
2231 : : .nh = {
2232 : : .nlmsg_len = NLMSG_LENGTH(0),
2233 : : .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
2234 : : RDMA_NLDEV_CMD_SYS_GET),
2235 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
2236 : : },
2237 : : };
2238 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
2239 : : int ret;
2240 : :
2241 : 0 : ret = mlx5_nl_send(nl, &req.nh, sn);
2242 [ # # ]: 0 : if (ret < 0) {
2243 : 0 : rte_errno = -ret;
2244 : 0 : return ret;
2245 : : }
2246 : 0 : ret = mlx5_nl_recv(nl, sn, mlx5_nl_rdma_monitor_cap_get_cb, cap);
2247 [ # # ]: 0 : if (ret < 0) {
2248 : 0 : rte_errno = -ret;
2249 : 0 : return ret;
2250 : : }
2251 : : return 0;
2252 : : }
2253 : :
2254 : : struct mlx5_mtu {
2255 : : uint32_t min_mtu;
2256 : : bool min_mtu_set;
2257 : : uint32_t max_mtu;
2258 : : bool max_mtu_set;
2259 : : };
2260 : :
2261 : : static int
2262 : 0 : mlx5_nl_get_mtu_bounds_cb(struct nlmsghdr *nh, void *arg)
2263 : : {
2264 : : size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
2265 : : struct mlx5_mtu *out = arg;
2266 : :
2267 [ # # ]: 0 : while (off < nh->nlmsg_len) {
2268 : 0 : struct rtattr *ra = RTE_PTR_ADD(nh, off);
2269 : : uint32_t *payload;
2270 : :
2271 [ # # # ]: 0 : switch (ra->rta_type) {
2272 : 0 : case IFLA_MIN_MTU:
2273 : : payload = RTA_DATA(ra);
2274 : 0 : out->min_mtu = *payload;
2275 : 0 : out->min_mtu_set = true;
2276 : 0 : break;
2277 : 0 : case IFLA_MAX_MTU:
2278 : : payload = RTA_DATA(ra);
2279 : 0 : out->max_mtu = *payload;
2280 : 0 : out->max_mtu_set = true;
2281 : 0 : break;
2282 : : default:
2283 : : /* Nothing to do for other attributes. */
2284 : : break;
2285 : : }
2286 : 0 : off += RTA_ALIGN(ra->rta_len);
2287 : : }
2288 : :
2289 : 0 : return 0;
2290 : : }
2291 : :
2292 : : /**
2293 : : * Query minimum and maximum allowed MTU values for given Linux network interface.
2294 : : *
2295 : : * This function queries the following interface attributes exposed in netlink since Linux 4.18:
2296 : : *
2297 : : * - IFLA_MIN_MTU - minimum allowed MTU
2298 : : * - IFLA_MAX_MTU - maximum allowed MTU
2299 : : *
2300 : : * @param[in] nl
2301 : : * Netlink socket of the ROUTE kind (NETLINK_ROUTE).
2302 : : * @param[in] ifindex
2303 : : * Linux network device index.
2304 : : * @param[out] min_mtu
2305 : : * Pointer to minimum allowed MTU. Populated only if both minimum and maximum MTU was queried.
2306 : : * @param[out] max_mtu
2307 : : * Pointer to maximum allowed MTU. Populated only if both minimum and maximum MTU was queried.
2308 : : *
2309 : : * @return
2310 : : * 0 on success, negative on error and rte_errno is set.
2311 : : *
2312 : : * Known errors:
2313 : : *
2314 : : * - (-EINVAL) - either @p min_mtu or @p max_mtu is NULL.
2315 : : * - (-ENOENT) - either minimum or maximum allowed MTU was not found in interface attributes.
2316 : : */
2317 : : RTE_EXPORT_INTERNAL_SYMBOL(mlx5_nl_get_mtu_bounds)
2318 : : int
2319 : 0 : mlx5_nl_get_mtu_bounds(int nl, unsigned int ifindex, uint16_t *min_mtu, uint16_t *max_mtu)
2320 : : {
2321 : 0 : struct mlx5_mtu out = { 0 };
2322 : : struct {
2323 : : struct nlmsghdr nh;
2324 : : struct ifinfomsg info;
2325 : 0 : } req = {
2326 : : .nh = {
2327 : : .nlmsg_len = NLMSG_LENGTH(sizeof(req.info)),
2328 : : .nlmsg_type = RTM_GETLINK,
2329 : : .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
2330 : : },
2331 : : .info = {
2332 : : .ifi_family = AF_UNSPEC,
2333 : : .ifi_index = ifindex,
2334 : : },
2335 : : };
2336 : 0 : uint32_t sn = MLX5_NL_SN_GENERATE;
2337 : : int ret;
2338 : :
2339 [ # # ]: 0 : if (min_mtu == NULL || max_mtu == NULL) {
2340 : 0 : rte_errno = EINVAL;
2341 : 0 : return -rte_errno;
2342 : : }
2343 : :
2344 : 0 : ret = mlx5_nl_send(nl, &req.nh, sn);
2345 [ # # ]: 0 : if (ret < 0)
2346 : : return ret;
2347 : :
2348 : 0 : ret = mlx5_nl_recv(nl, sn, mlx5_nl_get_mtu_bounds_cb, &out);
2349 [ # # ]: 0 : if (ret < 0)
2350 : : return ret;
2351 : :
2352 [ # # # # ]: 0 : if (!out.min_mtu_set || !out.max_mtu_set) {
2353 : 0 : rte_errno = ENOENT;
2354 : 0 : return -rte_errno;
2355 : : }
2356 : :
2357 : 0 : *min_mtu = out.min_mtu;
2358 : 0 : *max_mtu = out.max_mtu;
2359 : :
2360 : 0 : return ret;
2361 : : }
|