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