159513c3eSOphir Munk /* SPDX-License-Identifier: BSD-3-Clause
259513c3eSOphir Munk * Copyright 2018 6WIND S.A.
359513c3eSOphir Munk * Copyright 2018 Mellanox Technologies, Ltd
459513c3eSOphir Munk */
559513c3eSOphir Munk
659513c3eSOphir Munk #include <errno.h>
759513c3eSOphir Munk #include <linux/if_link.h>
859513c3eSOphir Munk #include <linux/rtnetlink.h>
959513c3eSOphir Munk #include <linux/genetlink.h>
1059513c3eSOphir Munk #include <net/if.h>
1159513c3eSOphir Munk #include <rdma/rdma_netlink.h>
1259513c3eSOphir Munk #include <stdbool.h>
1359513c3eSOphir Munk #include <stdint.h>
1459513c3eSOphir Munk #include <stdlib.h>
1559513c3eSOphir Munk #include <stdalign.h>
1659513c3eSOphir Munk #include <string.h>
1759513c3eSOphir Munk #include <sys/socket.h>
1859513c3eSOphir Munk #include <unistd.h>
1959513c3eSOphir Munk
2059513c3eSOphir Munk #include <rte_errno.h>
2159513c3eSOphir Munk
2259513c3eSOphir Munk #include "mlx5_nl.h"
2325245d5dSShiri Kuzin #include "../mlx5_common_log.h"
2466914d19SSuanming Mou #include "mlx5_malloc.h"
2559513c3eSOphir Munk #ifdef HAVE_DEVLINK
2659513c3eSOphir Munk #include <linux/devlink.h>
2759513c3eSOphir Munk #endif
2859513c3eSOphir Munk
2959513c3eSOphir Munk
3059513c3eSOphir Munk /* Size of the buffer to receive kernel messages */
3159513c3eSOphir Munk #define MLX5_NL_BUF_SIZE (32 * 1024)
3259513c3eSOphir Munk /* Send buffer size for the Netlink socket */
3359513c3eSOphir Munk #define MLX5_SEND_BUF_SIZE 32768
3459513c3eSOphir Munk /* Receive buffer size for the Netlink socket */
3559513c3eSOphir Munk #define MLX5_RECV_BUF_SIZE 32768
36568d97c0SViacheslav Ovsiienko /* Maximal physical port name length. */
37568d97c0SViacheslav Ovsiienko #define MLX5_PHYS_PORT_NAME_MAX 128
3859513c3eSOphir Munk
3959513c3eSOphir Munk /** Parameters of VLAN devices created by driver. */
4059513c3eSOphir Munk #define MLX5_VMWA_VLAN_DEVICE_PFX "evmlx"
4159513c3eSOphir Munk /*
4259513c3eSOphir Munk * Define NDA_RTA as defined in iproute2 sources.
4359513c3eSOphir Munk *
4459513c3eSOphir Munk * see in iproute2 sources file include/libnetlink.h
4559513c3eSOphir Munk */
4659513c3eSOphir Munk #ifndef MLX5_NDA_RTA
4759513c3eSOphir Munk #define MLX5_NDA_RTA(r) \
4859513c3eSOphir Munk ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
4959513c3eSOphir Munk #endif
5059513c3eSOphir Munk /*
5159513c3eSOphir Munk * Define NLMSG_TAIL as defined in iproute2 sources.
5259513c3eSOphir Munk *
5359513c3eSOphir Munk * see in iproute2 sources file include/libnetlink.h
5459513c3eSOphir Munk */
5559513c3eSOphir Munk #ifndef NLMSG_TAIL
5659513c3eSOphir Munk #define NLMSG_TAIL(nmsg) \
5759513c3eSOphir Munk ((struct rtattr *)(((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
5859513c3eSOphir Munk #endif
5959513c3eSOphir Munk /*
6059513c3eSOphir Munk * The following definitions are normally found in rdma/rdma_netlink.h,
6159513c3eSOphir Munk * however they are so recent that most systems do not expose them yet.
6259513c3eSOphir Munk */
6359513c3eSOphir Munk #ifndef HAVE_RDMA_NL_NLDEV
6459513c3eSOphir Munk #define RDMA_NL_NLDEV 5
6559513c3eSOphir Munk #endif
6659513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_CMD_GET
6759513c3eSOphir Munk #define RDMA_NLDEV_CMD_GET 1
6859513c3eSOphir Munk #endif
6959513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_CMD_PORT_GET
7059513c3eSOphir Munk #define RDMA_NLDEV_CMD_PORT_GET 5
7159513c3eSOphir Munk #endif
7259513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_INDEX
7359513c3eSOphir Munk #define RDMA_NLDEV_ATTR_DEV_INDEX 1
7459513c3eSOphir Munk #endif
7559513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_NAME
7659513c3eSOphir Munk #define RDMA_NLDEV_ATTR_DEV_NAME 2
7759513c3eSOphir Munk #endif
7859513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_PORT_INDEX
7959513c3eSOphir Munk #define RDMA_NLDEV_ATTR_PORT_INDEX 3
8059513c3eSOphir Munk #endif
81227813f2SXueming Li #ifndef HAVE_RDMA_NLDEV_ATTR_PORT_STATE
82227813f2SXueming Li #define RDMA_NLDEV_ATTR_PORT_STATE 12
83227813f2SXueming Li #endif
8459513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_NDEV_INDEX
8559513c3eSOphir Munk #define RDMA_NLDEV_ATTR_NDEV_INDEX 50
8659513c3eSOphir Munk #endif
8759513c3eSOphir Munk
8859513c3eSOphir Munk /* These are normally found in linux/if_link.h. */
8959513c3eSOphir Munk #ifndef HAVE_IFLA_NUM_VF
9059513c3eSOphir Munk #define IFLA_NUM_VF 21
9159513c3eSOphir Munk #endif
9259513c3eSOphir Munk #ifndef HAVE_IFLA_EXT_MASK
9359513c3eSOphir Munk #define IFLA_EXT_MASK 29
9459513c3eSOphir Munk #endif
9559513c3eSOphir Munk #ifndef HAVE_IFLA_PHYS_SWITCH_ID
9659513c3eSOphir Munk #define IFLA_PHYS_SWITCH_ID 36
9759513c3eSOphir Munk #endif
9859513c3eSOphir Munk #ifndef HAVE_IFLA_PHYS_PORT_NAME
9959513c3eSOphir Munk #define IFLA_PHYS_PORT_NAME 38
10059513c3eSOphir Munk #endif
10159513c3eSOphir Munk
10259513c3eSOphir Munk /*
10359513c3eSOphir Munk * Some Devlink defines may be missed in old kernel versions,
10459513c3eSOphir Munk * adjust used defines.
10559513c3eSOphir Munk */
10659513c3eSOphir Munk #ifndef DEVLINK_GENL_NAME
10759513c3eSOphir Munk #define DEVLINK_GENL_NAME "devlink"
10859513c3eSOphir Munk #endif
10959513c3eSOphir Munk #ifndef DEVLINK_GENL_VERSION
11059513c3eSOphir Munk #define DEVLINK_GENL_VERSION 1
11159513c3eSOphir Munk #endif
11259513c3eSOphir Munk #ifndef DEVLINK_ATTR_BUS_NAME
11359513c3eSOphir Munk #define DEVLINK_ATTR_BUS_NAME 1
11459513c3eSOphir Munk #endif
11559513c3eSOphir Munk #ifndef DEVLINK_ATTR_DEV_NAME
11659513c3eSOphir Munk #define DEVLINK_ATTR_DEV_NAME 2
11759513c3eSOphir Munk #endif
11859513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM
11959513c3eSOphir Munk #define DEVLINK_ATTR_PARAM 80
12059513c3eSOphir Munk #endif
12159513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_NAME
12259513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_NAME 81
12359513c3eSOphir Munk #endif
12459513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_TYPE
12559513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_TYPE 83
12659513c3eSOphir Munk #endif
12759513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUES_LIST
12859513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUES_LIST 84
12959513c3eSOphir Munk #endif
13059513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUE
13159513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUE 85
13259513c3eSOphir Munk #endif
13359513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUE_DATA
13459513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUE_DATA 86
13559513c3eSOphir Munk #endif
13659513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUE_CMODE
13759513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUE_CMODE 87
13859513c3eSOphir Munk #endif
13959513c3eSOphir Munk #ifndef DEVLINK_PARAM_CMODE_DRIVERINIT
14059513c3eSOphir Munk #define DEVLINK_PARAM_CMODE_DRIVERINIT 1
14159513c3eSOphir Munk #endif
14259513c3eSOphir Munk #ifndef DEVLINK_CMD_RELOAD
14359513c3eSOphir Munk #define DEVLINK_CMD_RELOAD 37
14459513c3eSOphir Munk #endif
14559513c3eSOphir Munk #ifndef DEVLINK_CMD_PARAM_GET
14659513c3eSOphir Munk #define DEVLINK_CMD_PARAM_GET 38
14759513c3eSOphir Munk #endif
14859513c3eSOphir Munk #ifndef DEVLINK_CMD_PARAM_SET
14959513c3eSOphir Munk #define DEVLINK_CMD_PARAM_SET 39
15059513c3eSOphir Munk #endif
15159513c3eSOphir Munk #ifndef NLA_FLAG
15259513c3eSOphir Munk #define NLA_FLAG 6
15359513c3eSOphir Munk #endif
15459513c3eSOphir Munk
15559513c3eSOphir Munk /* Add/remove MAC address through Netlink */
15659513c3eSOphir Munk struct mlx5_nl_mac_addr {
15759513c3eSOphir Munk struct rte_ether_addr (*mac)[];
15859513c3eSOphir Munk /**< MAC address handled by the device. */
15959513c3eSOphir Munk int mac_n; /**< Number of addresses in the array. */
16059513c3eSOphir Munk };
16159513c3eSOphir Munk
16259513c3eSOphir Munk #define MLX5_NL_CMD_GET_IB_NAME (1 << 0)
16359513c3eSOphir Munk #define MLX5_NL_CMD_GET_IB_INDEX (1 << 1)
16459513c3eSOphir Munk #define MLX5_NL_CMD_GET_NET_INDEX (1 << 2)
16559513c3eSOphir Munk #define MLX5_NL_CMD_GET_PORT_INDEX (1 << 3)
166227813f2SXueming Li #define MLX5_NL_CMD_GET_PORT_STATE (1 << 4)
16759513c3eSOphir Munk
16859513c3eSOphir Munk /** Data structure used by mlx5_nl_cmdget_cb(). */
169227813f2SXueming Li struct mlx5_nl_port_info {
17059513c3eSOphir Munk const char *name; /**< IB device name (in). */
17159513c3eSOphir Munk uint32_t flags; /**< found attribute flags (out). */
17259513c3eSOphir Munk uint32_t ibindex; /**< IB device index (out). */
17359513c3eSOphir Munk uint32_t ifindex; /**< Network interface index (out). */
17459513c3eSOphir Munk uint32_t portnum; /**< IB device max port number (out). */
175227813f2SXueming Li uint16_t state; /**< IB device port state (out). */
17659513c3eSOphir Munk };
17759513c3eSOphir Munk
178*e12a0166STyler Retzlaff RTE_ATOMIC(uint32_t) atomic_sn;
17959513c3eSOphir Munk
18059513c3eSOphir Munk /* Generate Netlink sequence number. */
181*e12a0166STyler Retzlaff #define MLX5_NL_SN_GENERATE (rte_atomic_fetch_add_explicit(&atomic_sn, 1, \
182*e12a0166STyler Retzlaff rte_memory_order_relaxed) + 1)
18359513c3eSOphir Munk
18459513c3eSOphir Munk /**
18559513c3eSOphir Munk * Opens a Netlink socket.
18659513c3eSOphir Munk *
18759513c3eSOphir Munk * @param protocol
18859513c3eSOphir Munk * Netlink protocol (e.g. NETLINK_ROUTE, NETLINK_RDMA).
189be66461cSDmitry Kozlyuk * @param groups
190be66461cSDmitry Kozlyuk * Groups to listen (e.g. RTMGRP_LINK), can be 0.
19159513c3eSOphir Munk *
19259513c3eSOphir Munk * @return
19359513c3eSOphir Munk * A file descriptor on success, a negative errno value otherwise and
19459513c3eSOphir Munk * rte_errno is set.
19559513c3eSOphir Munk */
19659513c3eSOphir Munk int
mlx5_nl_init(int protocol,int groups)197be66461cSDmitry Kozlyuk mlx5_nl_init(int protocol, int groups)
19859513c3eSOphir Munk {
19959513c3eSOphir Munk int fd;
20032d1e4dbSViacheslav Ovsiienko int buf_size;
20132d1e4dbSViacheslav Ovsiienko socklen_t opt_size;
20259513c3eSOphir Munk struct sockaddr_nl local = {
20359513c3eSOphir Munk .nl_family = AF_NETLINK,
204be66461cSDmitry Kozlyuk .nl_groups = groups,
20559513c3eSOphir Munk };
20659513c3eSOphir Munk int ret;
20759513c3eSOphir Munk
20859513c3eSOphir Munk fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol);
20959513c3eSOphir Munk if (fd == -1) {
21059513c3eSOphir Munk rte_errno = errno;
21159513c3eSOphir Munk return -rte_errno;
21259513c3eSOphir Munk }
21332d1e4dbSViacheslav Ovsiienko opt_size = sizeof(buf_size);
21432d1e4dbSViacheslav Ovsiienko ret = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_size, &opt_size);
21559513c3eSOphir Munk if (ret == -1) {
21659513c3eSOphir Munk rte_errno = errno;
21759513c3eSOphir Munk goto error;
21859513c3eSOphir Munk }
21932d1e4dbSViacheslav Ovsiienko DRV_LOG(DEBUG, "Netlink socket send buffer: %d", buf_size);
22032d1e4dbSViacheslav Ovsiienko if (buf_size < MLX5_SEND_BUF_SIZE) {
22132d1e4dbSViacheslav Ovsiienko ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
22232d1e4dbSViacheslav Ovsiienko &buf_size, sizeof(buf_size));
22359513c3eSOphir Munk if (ret == -1) {
22459513c3eSOphir Munk rte_errno = errno;
22559513c3eSOphir Munk goto error;
22659513c3eSOphir Munk }
22732d1e4dbSViacheslav Ovsiienko }
22832d1e4dbSViacheslav Ovsiienko opt_size = sizeof(buf_size);
22932d1e4dbSViacheslav Ovsiienko ret = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buf_size, &opt_size);
23032d1e4dbSViacheslav Ovsiienko if (ret == -1) {
23132d1e4dbSViacheslav Ovsiienko rte_errno = errno;
23232d1e4dbSViacheslav Ovsiienko goto error;
23332d1e4dbSViacheslav Ovsiienko }
23432d1e4dbSViacheslav Ovsiienko DRV_LOG(DEBUG, "Netlink socket recv buffer: %d", buf_size);
23532d1e4dbSViacheslav Ovsiienko if (buf_size < MLX5_RECV_BUF_SIZE) {
23632d1e4dbSViacheslav Ovsiienko ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
23732d1e4dbSViacheslav Ovsiienko &buf_size, sizeof(buf_size));
23832d1e4dbSViacheslav Ovsiienko if (ret == -1) {
23932d1e4dbSViacheslav Ovsiienko rte_errno = errno;
24032d1e4dbSViacheslav Ovsiienko goto error;
24132d1e4dbSViacheslav Ovsiienko }
24232d1e4dbSViacheslav Ovsiienko }
24359513c3eSOphir Munk ret = bind(fd, (struct sockaddr *)&local, sizeof(local));
24459513c3eSOphir Munk if (ret == -1) {
24559513c3eSOphir Munk rte_errno = errno;
24659513c3eSOphir Munk goto error;
24759513c3eSOphir Munk }
24859513c3eSOphir Munk return fd;
24959513c3eSOphir Munk error:
25059513c3eSOphir Munk close(fd);
25159513c3eSOphir Munk return -rte_errno;
25259513c3eSOphir Munk }
25359513c3eSOphir Munk
25459513c3eSOphir Munk /**
25559513c3eSOphir Munk * Send a request message to the kernel on the Netlink socket.
25659513c3eSOphir Munk *
25759513c3eSOphir Munk * @param[in] nlsk_fd
25859513c3eSOphir Munk * Netlink socket file descriptor.
25959513c3eSOphir Munk * @param[in] nh
26059513c3eSOphir Munk * The Netlink message send to the kernel.
26159513c3eSOphir Munk * @param[in] ssn
26259513c3eSOphir Munk * Sequence number.
26359513c3eSOphir Munk * @param[in] req
26459513c3eSOphir Munk * Pointer to the request structure.
26559513c3eSOphir Munk * @param[in] len
26659513c3eSOphir Munk * Length of the request in bytes.
26759513c3eSOphir Munk *
26859513c3eSOphir Munk * @return
26959513c3eSOphir Munk * The number of sent bytes on success, a negative errno value otherwise and
27059513c3eSOphir Munk * rte_errno is set.
27159513c3eSOphir Munk */
27259513c3eSOphir Munk static int
mlx5_nl_request(int nlsk_fd,struct nlmsghdr * nh,uint32_t sn,void * req,int len)27359513c3eSOphir Munk mlx5_nl_request(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn, void *req,
27459513c3eSOphir Munk int len)
27559513c3eSOphir Munk {
27659513c3eSOphir Munk struct sockaddr_nl sa = {
27759513c3eSOphir Munk .nl_family = AF_NETLINK,
27859513c3eSOphir Munk };
27959513c3eSOphir Munk struct iovec iov[2] = {
28059513c3eSOphir Munk { .iov_base = nh, .iov_len = sizeof(*nh), },
28159513c3eSOphir Munk { .iov_base = req, .iov_len = len, },
28259513c3eSOphir Munk };
28359513c3eSOphir Munk struct msghdr msg = {
28459513c3eSOphir Munk .msg_name = &sa,
28559513c3eSOphir Munk .msg_namelen = sizeof(sa),
28659513c3eSOphir Munk .msg_iov = iov,
28759513c3eSOphir Munk .msg_iovlen = 2,
28859513c3eSOphir Munk };
28959513c3eSOphir Munk int send_bytes;
29059513c3eSOphir Munk
29159513c3eSOphir Munk nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
29259513c3eSOphir Munk nh->nlmsg_seq = sn;
29359513c3eSOphir Munk send_bytes = sendmsg(nlsk_fd, &msg, 0);
29459513c3eSOphir Munk if (send_bytes < 0) {
29559513c3eSOphir Munk rte_errno = errno;
29659513c3eSOphir Munk return -rte_errno;
29759513c3eSOphir Munk }
29859513c3eSOphir Munk return send_bytes;
29959513c3eSOphir Munk }
30059513c3eSOphir Munk
30159513c3eSOphir Munk /**
30259513c3eSOphir Munk * Send a message to the kernel on the Netlink socket.
30359513c3eSOphir Munk *
30459513c3eSOphir Munk * @param[in] nlsk_fd
30559513c3eSOphir Munk * The Netlink socket file descriptor used for communication.
30659513c3eSOphir Munk * @param[in] nh
30759513c3eSOphir Munk * The Netlink message send to the kernel.
30859513c3eSOphir Munk * @param[in] sn
30959513c3eSOphir Munk * Sequence number.
31059513c3eSOphir Munk *
31159513c3eSOphir Munk * @return
31259513c3eSOphir Munk * The number of sent bytes on success, a negative errno value otherwise and
31359513c3eSOphir Munk * rte_errno is set.
31459513c3eSOphir Munk */
31559513c3eSOphir Munk static int
mlx5_nl_send(int nlsk_fd,struct nlmsghdr * nh,uint32_t sn)31659513c3eSOphir Munk mlx5_nl_send(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn)
31759513c3eSOphir Munk {
31859513c3eSOphir Munk struct sockaddr_nl sa = {
31959513c3eSOphir Munk .nl_family = AF_NETLINK,
32059513c3eSOphir Munk };
32159513c3eSOphir Munk struct iovec iov = {
32259513c3eSOphir Munk .iov_base = nh,
32359513c3eSOphir Munk .iov_len = nh->nlmsg_len,
32459513c3eSOphir Munk };
32559513c3eSOphir Munk struct msghdr msg = {
32659513c3eSOphir Munk .msg_name = &sa,
32759513c3eSOphir Munk .msg_namelen = sizeof(sa),
32859513c3eSOphir Munk .msg_iov = &iov,
32959513c3eSOphir Munk .msg_iovlen = 1,
33059513c3eSOphir Munk };
33159513c3eSOphir Munk int send_bytes;
33259513c3eSOphir Munk
33359513c3eSOphir Munk nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */
33459513c3eSOphir Munk nh->nlmsg_seq = sn;
33559513c3eSOphir Munk send_bytes = sendmsg(nlsk_fd, &msg, 0);
33659513c3eSOphir Munk if (send_bytes < 0) {
33759513c3eSOphir Munk rte_errno = errno;
33859513c3eSOphir Munk return -rte_errno;
33959513c3eSOphir Munk }
34059513c3eSOphir Munk return send_bytes;
34159513c3eSOphir Munk }
34259513c3eSOphir Munk
34359513c3eSOphir Munk /**
34459513c3eSOphir Munk * Receive a message from the kernel on the Netlink socket, following
34559513c3eSOphir Munk * mlx5_nl_send().
34659513c3eSOphir Munk *
34759513c3eSOphir Munk * @param[in] nlsk_fd
34859513c3eSOphir Munk * The Netlink socket file descriptor used for communication.
34959513c3eSOphir Munk * @param[in] sn
35059513c3eSOphir Munk * Sequence number.
35159513c3eSOphir Munk * @param[in] cb
35259513c3eSOphir Munk * The callback function to call for each Netlink message received.
35359513c3eSOphir Munk * @param[in, out] arg
35459513c3eSOphir Munk * Custom arguments for the callback.
35559513c3eSOphir Munk *
35659513c3eSOphir Munk * @return
35759513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
35859513c3eSOphir Munk */
35959513c3eSOphir Munk static int
mlx5_nl_recv(int nlsk_fd,uint32_t sn,int (* cb)(struct nlmsghdr *,void * arg),void * arg)36059513c3eSOphir Munk mlx5_nl_recv(int nlsk_fd, uint32_t sn, int (*cb)(struct nlmsghdr *, void *arg),
36159513c3eSOphir Munk void *arg)
36259513c3eSOphir Munk {
36359513c3eSOphir Munk struct sockaddr_nl sa;
36432d1e4dbSViacheslav Ovsiienko struct iovec iov;
36559513c3eSOphir Munk struct msghdr msg = {
36659513c3eSOphir Munk .msg_name = &sa,
36759513c3eSOphir Munk .msg_namelen = sizeof(sa),
36859513c3eSOphir Munk .msg_iov = &iov,
36959513c3eSOphir Munk /* One message at a time */
37059513c3eSOphir Munk .msg_iovlen = 1,
37159513c3eSOphir Munk };
37232d1e4dbSViacheslav Ovsiienko void *buf = NULL;
37359513c3eSOphir Munk int multipart = 0;
37459513c3eSOphir Munk int ret = 0;
37559513c3eSOphir Munk
37659513c3eSOphir Munk do {
37759513c3eSOphir Munk struct nlmsghdr *nh;
37832d1e4dbSViacheslav Ovsiienko int recv_bytes;
37959513c3eSOphir Munk
38059513c3eSOphir Munk do {
38132d1e4dbSViacheslav Ovsiienko /* Query length of incoming message. */
38232d1e4dbSViacheslav Ovsiienko iov.iov_base = NULL;
38332d1e4dbSViacheslav Ovsiienko iov.iov_len = 0;
38432d1e4dbSViacheslav Ovsiienko recv_bytes = recvmsg(nlsk_fd, &msg,
38532d1e4dbSViacheslav Ovsiienko MSG_PEEK | MSG_TRUNC);
38632d1e4dbSViacheslav Ovsiienko if (recv_bytes < 0) {
38732d1e4dbSViacheslav Ovsiienko rte_errno = errno;
38832d1e4dbSViacheslav Ovsiienko ret = -rte_errno;
38932d1e4dbSViacheslav Ovsiienko goto exit;
39032d1e4dbSViacheslav Ovsiienko }
39132d1e4dbSViacheslav Ovsiienko if (recv_bytes == 0) {
39232d1e4dbSViacheslav Ovsiienko rte_errno = ENODATA;
39332d1e4dbSViacheslav Ovsiienko ret = -rte_errno;
39432d1e4dbSViacheslav Ovsiienko goto exit;
39532d1e4dbSViacheslav Ovsiienko }
39632d1e4dbSViacheslav Ovsiienko /* Allocate buffer to fetch the message. */
39732d1e4dbSViacheslav Ovsiienko if (recv_bytes < MLX5_RECV_BUF_SIZE)
39832d1e4dbSViacheslav Ovsiienko recv_bytes = MLX5_RECV_BUF_SIZE;
39932d1e4dbSViacheslav Ovsiienko mlx5_free(buf);
40032d1e4dbSViacheslav Ovsiienko buf = mlx5_malloc(0, recv_bytes, 0, SOCKET_ID_ANY);
40132d1e4dbSViacheslav Ovsiienko if (!buf) {
40232d1e4dbSViacheslav Ovsiienko rte_errno = ENOMEM;
40332d1e4dbSViacheslav Ovsiienko ret = -rte_errno;
40432d1e4dbSViacheslav Ovsiienko goto exit;
40532d1e4dbSViacheslav Ovsiienko }
40632d1e4dbSViacheslav Ovsiienko /* Fetch the message. */
40732d1e4dbSViacheslav Ovsiienko iov.iov_base = buf;
40832d1e4dbSViacheslav Ovsiienko iov.iov_len = recv_bytes;
40959513c3eSOphir Munk recv_bytes = recvmsg(nlsk_fd, &msg, 0);
41059513c3eSOphir Munk if (recv_bytes == -1) {
41159513c3eSOphir Munk rte_errno = errno;
41259513c3eSOphir Munk ret = -rte_errno;
41359513c3eSOphir Munk goto exit;
41459513c3eSOphir Munk }
41559513c3eSOphir Munk nh = (struct nlmsghdr *)buf;
41659513c3eSOphir Munk } while (nh->nlmsg_seq != sn);
41759513c3eSOphir Munk for (;
41859513c3eSOphir Munk NLMSG_OK(nh, (unsigned int)recv_bytes);
41959513c3eSOphir Munk nh = NLMSG_NEXT(nh, recv_bytes)) {
42059513c3eSOphir Munk if (nh->nlmsg_type == NLMSG_ERROR) {
42159513c3eSOphir Munk struct nlmsgerr *err_data = NLMSG_DATA(nh);
42259513c3eSOphir Munk
42359513c3eSOphir Munk if (err_data->error < 0) {
42459513c3eSOphir Munk rte_errno = -err_data->error;
42559513c3eSOphir Munk ret = -rte_errno;
42659513c3eSOphir Munk goto exit;
42759513c3eSOphir Munk }
42859513c3eSOphir Munk /* Ack message. */
42959513c3eSOphir Munk ret = 0;
43059513c3eSOphir Munk goto exit;
43159513c3eSOphir Munk }
43259513c3eSOphir Munk /* Multi-part msgs and their trailing DONE message. */
43359513c3eSOphir Munk if (nh->nlmsg_flags & NLM_F_MULTI) {
43459513c3eSOphir Munk if (nh->nlmsg_type == NLMSG_DONE) {
43559513c3eSOphir Munk ret = 0;
43659513c3eSOphir Munk goto exit;
43759513c3eSOphir Munk }
43859513c3eSOphir Munk multipart = 1;
43959513c3eSOphir Munk }
44059513c3eSOphir Munk if (cb) {
44159513c3eSOphir Munk ret = cb(nh, arg);
44259513c3eSOphir Munk if (ret < 0)
44359513c3eSOphir Munk goto exit;
44459513c3eSOphir Munk }
44559513c3eSOphir Munk }
44659513c3eSOphir Munk } while (multipart);
44759513c3eSOphir Munk exit:
44866914d19SSuanming Mou mlx5_free(buf);
44959513c3eSOphir Munk return ret;
45059513c3eSOphir Munk }
45159513c3eSOphir Munk
45259513c3eSOphir Munk /**
45359513c3eSOphir Munk * Parse Netlink message to retrieve the bridge MAC address.
45459513c3eSOphir Munk *
45559513c3eSOphir Munk * @param nh
45659513c3eSOphir Munk * Pointer to Netlink Message Header.
45759513c3eSOphir Munk * @param arg
45859513c3eSOphir Munk * PMD data register with this callback.
45959513c3eSOphir Munk *
46059513c3eSOphir Munk * @return
46159513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
46259513c3eSOphir Munk */
46359513c3eSOphir Munk static int
mlx5_nl_mac_addr_cb(struct nlmsghdr * nh,void * arg)46459513c3eSOphir Munk mlx5_nl_mac_addr_cb(struct nlmsghdr *nh, void *arg)
46559513c3eSOphir Munk {
46659513c3eSOphir Munk struct mlx5_nl_mac_addr *data = arg;
46759513c3eSOphir Munk struct ndmsg *r = NLMSG_DATA(nh);
46859513c3eSOphir Munk struct rtattr *attribute;
46959513c3eSOphir Munk int len;
47059513c3eSOphir Munk
47159513c3eSOphir Munk len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r));
47259513c3eSOphir Munk for (attribute = MLX5_NDA_RTA(r);
47359513c3eSOphir Munk RTA_OK(attribute, len);
47459513c3eSOphir Munk attribute = RTA_NEXT(attribute, len)) {
47559513c3eSOphir Munk if (attribute->rta_type == NDA_LLADDR) {
47659513c3eSOphir Munk if (data->mac_n == MLX5_MAX_MAC_ADDRESSES) {
47759513c3eSOphir Munk DRV_LOG(WARNING,
47859513c3eSOphir Munk "not enough room to finalize the"
47959513c3eSOphir Munk " request");
48059513c3eSOphir Munk rte_errno = ENOMEM;
48159513c3eSOphir Munk return -rte_errno;
48259513c3eSOphir Munk }
48359513c3eSOphir Munk #ifdef RTE_LIBRTE_MLX5_DEBUG
48459513c3eSOphir Munk char m[RTE_ETHER_ADDR_FMT_SIZE];
48559513c3eSOphir Munk
48659513c3eSOphir Munk rte_ether_format_addr(m, RTE_ETHER_ADDR_FMT_SIZE,
48759513c3eSOphir Munk RTA_DATA(attribute));
48859513c3eSOphir Munk DRV_LOG(DEBUG, "bridge MAC address %s", m);
48959513c3eSOphir Munk #endif
49059513c3eSOphir Munk memcpy(&(*data->mac)[data->mac_n++],
49159513c3eSOphir Munk RTA_DATA(attribute), RTE_ETHER_ADDR_LEN);
49259513c3eSOphir Munk }
49359513c3eSOphir Munk }
49459513c3eSOphir Munk return 0;
49559513c3eSOphir Munk }
49659513c3eSOphir Munk
49759513c3eSOphir Munk /**
49859513c3eSOphir Munk * Get bridge MAC addresses.
49959513c3eSOphir Munk *
50059513c3eSOphir Munk * @param[in] nlsk_fd
50159513c3eSOphir Munk * Netlink socket file descriptor.
50259513c3eSOphir Munk * @param[in] iface_idx
50359513c3eSOphir Munk * Net device interface index.
50459513c3eSOphir Munk * @param mac[out]
50559513c3eSOphir Munk * Pointer to the array table of MAC addresses to fill.
50659513c3eSOphir Munk * Its size should be of MLX5_MAX_MAC_ADDRESSES.
50759513c3eSOphir Munk * @param mac_n[out]
50859513c3eSOphir Munk * Number of entries filled in MAC array.
50959513c3eSOphir Munk *
51059513c3eSOphir Munk * @return
51159513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
51259513c3eSOphir Munk */
51359513c3eSOphir Munk static int
mlx5_nl_mac_addr_list(int nlsk_fd,unsigned int iface_idx,struct rte_ether_addr (* mac)[],int * mac_n)51459513c3eSOphir Munk mlx5_nl_mac_addr_list(int nlsk_fd, unsigned int iface_idx,
51559513c3eSOphir Munk struct rte_ether_addr (*mac)[], int *mac_n)
51659513c3eSOphir Munk {
51759513c3eSOphir Munk struct {
51859513c3eSOphir Munk struct nlmsghdr hdr;
51959513c3eSOphir Munk struct ifinfomsg ifm;
52059513c3eSOphir Munk } req = {
52159513c3eSOphir Munk .hdr = {
52259513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
52359513c3eSOphir Munk .nlmsg_type = RTM_GETNEIGH,
52459513c3eSOphir Munk .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST,
52559513c3eSOphir Munk },
52659513c3eSOphir Munk .ifm = {
52759513c3eSOphir Munk .ifi_family = PF_BRIDGE,
52859513c3eSOphir Munk .ifi_index = iface_idx,
52959513c3eSOphir Munk },
53059513c3eSOphir Munk };
53159513c3eSOphir Munk struct mlx5_nl_mac_addr data = {
53259513c3eSOphir Munk .mac = mac,
53359513c3eSOphir Munk .mac_n = 0,
53459513c3eSOphir Munk };
53559513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
53659513c3eSOphir Munk int ret;
53759513c3eSOphir Munk
53859513c3eSOphir Munk if (nlsk_fd == -1)
53959513c3eSOphir Munk return 0;
54059513c3eSOphir Munk ret = mlx5_nl_request(nlsk_fd, &req.hdr, sn, &req.ifm,
54159513c3eSOphir Munk sizeof(struct ifinfomsg));
54259513c3eSOphir Munk if (ret < 0)
54359513c3eSOphir Munk goto error;
54459513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_mac_addr_cb, &data);
54559513c3eSOphir Munk if (ret < 0)
54659513c3eSOphir Munk goto error;
54759513c3eSOphir Munk *mac_n = data.mac_n;
54859513c3eSOphir Munk return 0;
54959513c3eSOphir Munk error:
55059513c3eSOphir Munk DRV_LOG(DEBUG, "Interface %u cannot retrieve MAC address list %s",
55159513c3eSOphir Munk iface_idx, strerror(rte_errno));
55259513c3eSOphir Munk return -rte_errno;
55359513c3eSOphir Munk }
55459513c3eSOphir Munk
55559513c3eSOphir Munk /**
55659513c3eSOphir Munk * Modify the MAC address neighbour table with Netlink.
55759513c3eSOphir Munk *
55859513c3eSOphir Munk * @param[in] nlsk_fd
55959513c3eSOphir Munk * Netlink socket file descriptor.
56059513c3eSOphir Munk * @param[in] iface_idx
56159513c3eSOphir Munk * Net device interface index.
56259513c3eSOphir Munk * @param mac
56359513c3eSOphir Munk * MAC address to consider.
56459513c3eSOphir Munk * @param add
56559513c3eSOphir Munk * 1 to add the MAC address, 0 to remove the MAC address.
56659513c3eSOphir Munk *
56759513c3eSOphir Munk * @return
56859513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
56959513c3eSOphir Munk */
57059513c3eSOphir Munk static int
mlx5_nl_mac_addr_modify(int nlsk_fd,unsigned int iface_idx,struct rte_ether_addr * mac,int add)57159513c3eSOphir Munk mlx5_nl_mac_addr_modify(int nlsk_fd, unsigned int iface_idx,
57259513c3eSOphir Munk struct rte_ether_addr *mac, int add)
57359513c3eSOphir Munk {
57459513c3eSOphir Munk struct {
57559513c3eSOphir Munk struct nlmsghdr hdr;
57659513c3eSOphir Munk struct ndmsg ndm;
57759513c3eSOphir Munk struct rtattr rta;
57859513c3eSOphir Munk uint8_t buffer[RTE_ETHER_ADDR_LEN];
57959513c3eSOphir Munk } req = {
58059513c3eSOphir Munk .hdr = {
58159513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)),
58259513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
58359513c3eSOphir Munk NLM_F_EXCL | NLM_F_ACK,
58459513c3eSOphir Munk .nlmsg_type = add ? RTM_NEWNEIGH : RTM_DELNEIGH,
58559513c3eSOphir Munk },
58659513c3eSOphir Munk .ndm = {
58759513c3eSOphir Munk .ndm_family = PF_BRIDGE,
58859513c3eSOphir Munk .ndm_state = NUD_NOARP | NUD_PERMANENT,
58959513c3eSOphir Munk .ndm_ifindex = iface_idx,
59059513c3eSOphir Munk .ndm_flags = NTF_SELF,
59159513c3eSOphir Munk },
59259513c3eSOphir Munk .rta = {
59359513c3eSOphir Munk .rta_type = NDA_LLADDR,
59459513c3eSOphir Munk .rta_len = RTA_LENGTH(RTE_ETHER_ADDR_LEN),
59559513c3eSOphir Munk },
59659513c3eSOphir Munk };
59759513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
59859513c3eSOphir Munk int ret;
59959513c3eSOphir Munk
60059513c3eSOphir Munk if (nlsk_fd == -1)
60159513c3eSOphir Munk return 0;
60259513c3eSOphir Munk memcpy(RTA_DATA(&req.rta), mac, RTE_ETHER_ADDR_LEN);
60359513c3eSOphir Munk req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
60459513c3eSOphir Munk RTA_ALIGN(req.rta.rta_len);
60559513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
60659513c3eSOphir Munk if (ret < 0)
60759513c3eSOphir Munk goto error;
60859513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
60959513c3eSOphir Munk if (ret < 0)
61059513c3eSOphir Munk goto error;
61159513c3eSOphir Munk return 0;
61259513c3eSOphir Munk error:
61359513c3eSOphir Munk #ifdef RTE_LIBRTE_MLX5_DEBUG
61459513c3eSOphir Munk {
61559513c3eSOphir Munk char m[RTE_ETHER_ADDR_FMT_SIZE];
61659513c3eSOphir Munk
61759513c3eSOphir Munk rte_ether_format_addr(m, RTE_ETHER_ADDR_FMT_SIZE, mac);
61859513c3eSOphir Munk DRV_LOG(DEBUG,
61959513c3eSOphir Munk "Interface %u cannot %s MAC address %s %s",
62059513c3eSOphir Munk iface_idx,
62159513c3eSOphir Munk add ? "add" : "remove", m, strerror(rte_errno));
62259513c3eSOphir Munk }
62359513c3eSOphir Munk #endif
62459513c3eSOphir Munk return -rte_errno;
62559513c3eSOphir Munk }
62659513c3eSOphir Munk
62759513c3eSOphir Munk /**
62859513c3eSOphir Munk * Modify the VF MAC address neighbour table with Netlink.
62959513c3eSOphir Munk *
63059513c3eSOphir Munk * @param[in] nlsk_fd
63159513c3eSOphir Munk * Netlink socket file descriptor.
63259513c3eSOphir Munk * @param[in] iface_idx
63359513c3eSOphir Munk * Net device interface index.
63459513c3eSOphir Munk * @param mac
63559513c3eSOphir Munk * MAC address to consider.
63659513c3eSOphir Munk * @param vf_index
63759513c3eSOphir Munk * VF index.
63859513c3eSOphir Munk *
63959513c3eSOphir Munk * @return
64059513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
64159513c3eSOphir Munk */
64259513c3eSOphir Munk int
mlx5_nl_vf_mac_addr_modify(int nlsk_fd,unsigned int iface_idx,struct rte_ether_addr * mac,int vf_index)64359513c3eSOphir Munk mlx5_nl_vf_mac_addr_modify(int nlsk_fd, unsigned int iface_idx,
64459513c3eSOphir Munk struct rte_ether_addr *mac, int vf_index)
64559513c3eSOphir Munk {
64659513c3eSOphir Munk int ret;
64759513c3eSOphir Munk struct {
64859513c3eSOphir Munk struct nlmsghdr hdr;
64959513c3eSOphir Munk struct ifinfomsg ifm;
65059513c3eSOphir Munk struct rtattr vf_list_rta;
65159513c3eSOphir Munk struct rtattr vf_info_rta;
65259513c3eSOphir Munk struct rtattr vf_mac_rta;
65359513c3eSOphir Munk struct ifla_vf_mac ivm;
65459513c3eSOphir Munk } req = {
65559513c3eSOphir Munk .hdr = {
65659513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
65759513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
65859513c3eSOphir Munk .nlmsg_type = RTM_BASE,
65959513c3eSOphir Munk },
66059513c3eSOphir Munk .ifm = {
66159513c3eSOphir Munk .ifi_index = iface_idx,
66259513c3eSOphir Munk },
66359513c3eSOphir Munk .vf_list_rta = {
66459513c3eSOphir Munk .rta_type = IFLA_VFINFO_LIST,
66559513c3eSOphir Munk .rta_len = RTA_ALIGN(RTA_LENGTH(0)),
66659513c3eSOphir Munk },
66759513c3eSOphir Munk .vf_info_rta = {
66859513c3eSOphir Munk .rta_type = IFLA_VF_INFO,
66959513c3eSOphir Munk .rta_len = RTA_ALIGN(RTA_LENGTH(0)),
67059513c3eSOphir Munk },
67159513c3eSOphir Munk .vf_mac_rta = {
67259513c3eSOphir Munk .rta_type = IFLA_VF_MAC,
67359513c3eSOphir Munk },
67459513c3eSOphir Munk };
67559513c3eSOphir Munk struct ifla_vf_mac ivm = {
67659513c3eSOphir Munk .vf = vf_index,
67759513c3eSOphir Munk };
67859513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
67959513c3eSOphir Munk
68059513c3eSOphir Munk memcpy(&ivm.mac, mac, RTE_ETHER_ADDR_LEN);
68159513c3eSOphir Munk memcpy(RTA_DATA(&req.vf_mac_rta), &ivm, sizeof(ivm));
68259513c3eSOphir Munk
68359513c3eSOphir Munk req.vf_mac_rta.rta_len = RTA_LENGTH(sizeof(ivm));
68459513c3eSOphir Munk req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
68559513c3eSOphir Munk RTA_ALIGN(req.vf_list_rta.rta_len) +
68659513c3eSOphir Munk RTA_ALIGN(req.vf_info_rta.rta_len) +
68759513c3eSOphir Munk RTA_ALIGN(req.vf_mac_rta.rta_len);
68859513c3eSOphir Munk req.vf_list_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr),
68959513c3eSOphir Munk &req.vf_list_rta);
69059513c3eSOphir Munk req.vf_info_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr),
69159513c3eSOphir Munk &req.vf_info_rta);
69259513c3eSOphir Munk
69359513c3eSOphir Munk if (nlsk_fd < 0)
69459513c3eSOphir Munk return -1;
69559513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
69659513c3eSOphir Munk if (ret < 0)
69759513c3eSOphir Munk goto error;
69859513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
69959513c3eSOphir Munk if (ret < 0)
70059513c3eSOphir Munk goto error;
70159513c3eSOphir Munk return 0;
70259513c3eSOphir Munk error:
70359513c3eSOphir Munk DRV_LOG(ERR,
70459513c3eSOphir Munk "representor %u cannot set VF MAC address "
705c2c4f87bSAman Deep Singh RTE_ETHER_ADDR_PRT_FMT " : %s",
70659513c3eSOphir Munk vf_index,
707a7db3afcSAman Deep Singh RTE_ETHER_ADDR_BYTES(mac),
70859513c3eSOphir Munk strerror(rte_errno));
70959513c3eSOphir Munk return -rte_errno;
71059513c3eSOphir Munk }
71159513c3eSOphir Munk
71259513c3eSOphir Munk /**
71359513c3eSOphir Munk * Add a MAC address.
71459513c3eSOphir Munk *
71559513c3eSOphir Munk * @param[in] nlsk_fd
71659513c3eSOphir Munk * Netlink socket file descriptor.
71759513c3eSOphir Munk * @param[in] iface_idx
71859513c3eSOphir Munk * Net device interface index.
71959513c3eSOphir Munk * @param mac_own
72059513c3eSOphir Munk * BITFIELD_DECLARE array to store the mac.
72159513c3eSOphir Munk * @param mac
72259513c3eSOphir Munk * MAC address to register.
72359513c3eSOphir Munk * @param index
72459513c3eSOphir Munk * MAC address index.
72559513c3eSOphir Munk *
72659513c3eSOphir Munk * @return
72759513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
72859513c3eSOphir Munk */
72959513c3eSOphir Munk int
mlx5_nl_mac_addr_add(int nlsk_fd,unsigned int iface_idx,uint64_t * mac_own,struct rte_ether_addr * mac,uint32_t index)73059513c3eSOphir Munk mlx5_nl_mac_addr_add(int nlsk_fd, unsigned int iface_idx,
73159513c3eSOphir Munk uint64_t *mac_own, struct rte_ether_addr *mac,
73259513c3eSOphir Munk uint32_t index)
73359513c3eSOphir Munk {
73459513c3eSOphir Munk int ret;
73559513c3eSOphir Munk
73659513c3eSOphir Munk ret = mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 1);
73759513c3eSOphir Munk if (!ret) {
73859513c3eSOphir Munk MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
73959513c3eSOphir Munk if (index >= MLX5_MAX_MAC_ADDRESSES)
74059513c3eSOphir Munk return -EINVAL;
74159513c3eSOphir Munk
74259513c3eSOphir Munk BITFIELD_SET(mac_own, index);
74359513c3eSOphir Munk }
74459513c3eSOphir Munk if (ret == -EEXIST)
74559513c3eSOphir Munk return 0;
74659513c3eSOphir Munk return ret;
74759513c3eSOphir Munk }
74859513c3eSOphir Munk
74959513c3eSOphir Munk /**
75059513c3eSOphir Munk * Remove a MAC address.
75159513c3eSOphir Munk *
75259513c3eSOphir Munk * @param[in] nlsk_fd
75359513c3eSOphir Munk * Netlink socket file descriptor.
75459513c3eSOphir Munk * @param[in] iface_idx
75559513c3eSOphir Munk * Net device interface index.
75659513c3eSOphir Munk * @param mac_own
75759513c3eSOphir Munk * BITFIELD_DECLARE array to store the mac.
75859513c3eSOphir Munk * @param mac
75959513c3eSOphir Munk * MAC address to remove.
76059513c3eSOphir Munk * @param index
76159513c3eSOphir Munk * MAC address index.
76259513c3eSOphir Munk *
76359513c3eSOphir Munk * @return
76459513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
76559513c3eSOphir Munk */
76659513c3eSOphir Munk int
mlx5_nl_mac_addr_remove(int nlsk_fd,unsigned int iface_idx,uint64_t * mac_own,struct rte_ether_addr * mac,uint32_t index)76759513c3eSOphir Munk mlx5_nl_mac_addr_remove(int nlsk_fd, unsigned int iface_idx, uint64_t *mac_own,
76859513c3eSOphir Munk struct rte_ether_addr *mac, uint32_t index)
76959513c3eSOphir Munk {
77059513c3eSOphir Munk MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES);
77159513c3eSOphir Munk if (index >= MLX5_MAX_MAC_ADDRESSES)
77259513c3eSOphir Munk return -EINVAL;
77359513c3eSOphir Munk
77459513c3eSOphir Munk BITFIELD_RESET(mac_own, index);
77559513c3eSOphir Munk return mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 0);
77659513c3eSOphir Munk }
77759513c3eSOphir Munk
77859513c3eSOphir Munk /**
77959513c3eSOphir Munk * Synchronize Netlink bridge table to the internal table.
78059513c3eSOphir Munk *
78159513c3eSOphir Munk * @param[in] nlsk_fd
78259513c3eSOphir Munk * Netlink socket file descriptor.
78359513c3eSOphir Munk * @param[in] iface_idx
78459513c3eSOphir Munk * Net device interface index.
78559513c3eSOphir Munk * @param mac_addrs
78659513c3eSOphir Munk * Mac addresses array to sync.
78759513c3eSOphir Munk * @param n
78859513c3eSOphir Munk * @p mac_addrs array size.
78959513c3eSOphir Munk */
79059513c3eSOphir Munk void
mlx5_nl_mac_addr_sync(int nlsk_fd,unsigned int iface_idx,struct rte_ether_addr * mac_addrs,int n)79159513c3eSOphir Munk mlx5_nl_mac_addr_sync(int nlsk_fd, unsigned int iface_idx,
79259513c3eSOphir Munk struct rte_ether_addr *mac_addrs, int n)
79359513c3eSOphir Munk {
79459513c3eSOphir Munk struct rte_ether_addr macs[n];
79559513c3eSOphir Munk int macs_n = 0;
79659513c3eSOphir Munk int i;
79759513c3eSOphir Munk int ret;
79859513c3eSOphir Munk
79959df97f1SXueming Li memset(macs, 0, n * sizeof(macs[0]));
80059513c3eSOphir Munk ret = mlx5_nl_mac_addr_list(nlsk_fd, iface_idx, &macs, &macs_n);
80159513c3eSOphir Munk if (ret)
80259513c3eSOphir Munk return;
80359513c3eSOphir Munk for (i = 0; i != macs_n; ++i) {
80459513c3eSOphir Munk int j;
80559513c3eSOphir Munk
80659513c3eSOphir Munk /* Verify the address is not in the array yet. */
80759513c3eSOphir Munk for (j = 0; j != n; ++j)
80859513c3eSOphir Munk if (rte_is_same_ether_addr(&macs[i], &mac_addrs[j]))
80959513c3eSOphir Munk break;
81059513c3eSOphir Munk if (j != n)
81159513c3eSOphir Munk continue;
812493f0bb5SSouvik Dey if (rte_is_multicast_ether_addr(&macs[i])) {
81359513c3eSOphir Munk /* Find the first entry available. */
814493f0bb5SSouvik Dey for (j = MLX5_MAX_UC_MAC_ADDRESSES; j != n; ++j) {
81559513c3eSOphir Munk if (rte_is_zero_ether_addr(&mac_addrs[j])) {
81659513c3eSOphir Munk mac_addrs[j] = macs[i];
81759513c3eSOphir Munk break;
81859513c3eSOphir Munk }
81959513c3eSOphir Munk }
820493f0bb5SSouvik Dey } else {
821493f0bb5SSouvik Dey /* Find the first entry available. */
822493f0bb5SSouvik Dey for (j = 0; j != MLX5_MAX_UC_MAC_ADDRESSES; ++j) {
823493f0bb5SSouvik Dey if (rte_is_zero_ether_addr(&mac_addrs[j])) {
824493f0bb5SSouvik Dey mac_addrs[j] = macs[i];
825493f0bb5SSouvik Dey break;
826493f0bb5SSouvik Dey }
827493f0bb5SSouvik Dey }
828493f0bb5SSouvik Dey }
82959513c3eSOphir Munk }
83059513c3eSOphir Munk }
83159513c3eSOphir Munk
83259513c3eSOphir Munk /**
83359513c3eSOphir Munk * Flush all added MAC addresses.
83459513c3eSOphir Munk *
83559513c3eSOphir Munk * @param[in] nlsk_fd
83659513c3eSOphir Munk * Netlink socket file descriptor.
83759513c3eSOphir Munk * @param[in] iface_idx
83859513c3eSOphir Munk * Net device interface index.
83959513c3eSOphir Munk * @param[in] mac_addrs
84059513c3eSOphir Munk * Mac addresses array to flush.
84159513c3eSOphir Munk * @param n
84259513c3eSOphir Munk * @p mac_addrs array size.
84359513c3eSOphir Munk * @param mac_own
84459513c3eSOphir Munk * BITFIELD_DECLARE array to store the mac.
84559513c3eSOphir Munk */
84659513c3eSOphir Munk void
mlx5_nl_mac_addr_flush(int nlsk_fd,unsigned int iface_idx,struct rte_ether_addr * mac_addrs,int n,uint64_t * mac_own)84759513c3eSOphir Munk mlx5_nl_mac_addr_flush(int nlsk_fd, unsigned int iface_idx,
84859513c3eSOphir Munk struct rte_ether_addr *mac_addrs, int n,
84959513c3eSOphir Munk uint64_t *mac_own)
85059513c3eSOphir Munk {
85159513c3eSOphir Munk int i;
85259513c3eSOphir Munk
8534a01fa04SShiri Kuzin if (n <= 0 || n > MLX5_MAX_MAC_ADDRESSES)
85459513c3eSOphir Munk return;
85559513c3eSOphir Munk
85659513c3eSOphir Munk for (i = n - 1; i >= 0; --i) {
85759513c3eSOphir Munk struct rte_ether_addr *m = &mac_addrs[i];
85859513c3eSOphir Munk
85959513c3eSOphir Munk if (BITFIELD_ISSET(mac_own, i))
86059513c3eSOphir Munk mlx5_nl_mac_addr_remove(nlsk_fd, iface_idx, mac_own, m,
86159513c3eSOphir Munk i);
86259513c3eSOphir Munk }
86359513c3eSOphir Munk }
86459513c3eSOphir Munk
86559513c3eSOphir Munk /**
86659513c3eSOphir Munk * Enable promiscuous / all multicast mode through Netlink.
86759513c3eSOphir Munk *
86859513c3eSOphir Munk * @param[in] nlsk_fd
86959513c3eSOphir Munk * Netlink socket file descriptor.
87059513c3eSOphir Munk * @param[in] iface_idx
87159513c3eSOphir Munk * Net device interface index.
87259513c3eSOphir Munk * @param flags
87359513c3eSOphir Munk * IFF_PROMISC for promiscuous, IFF_ALLMULTI for allmulti.
87459513c3eSOphir Munk * @param enable
87559513c3eSOphir Munk * Nonzero to enable, disable otherwise.
87659513c3eSOphir Munk *
87759513c3eSOphir Munk * @return
87859513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
87959513c3eSOphir Munk */
88059513c3eSOphir Munk static int
mlx5_nl_device_flags(int nlsk_fd,unsigned int iface_idx,uint32_t flags,int enable)88159513c3eSOphir Munk mlx5_nl_device_flags(int nlsk_fd, unsigned int iface_idx, uint32_t flags,
88259513c3eSOphir Munk int enable)
88359513c3eSOphir Munk {
88459513c3eSOphir Munk struct {
88559513c3eSOphir Munk struct nlmsghdr hdr;
88659513c3eSOphir Munk struct ifinfomsg ifi;
88759513c3eSOphir Munk } req = {
88859513c3eSOphir Munk .hdr = {
88959513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
89059513c3eSOphir Munk .nlmsg_type = RTM_NEWLINK,
89159513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST,
89259513c3eSOphir Munk },
89359513c3eSOphir Munk .ifi = {
89459513c3eSOphir Munk .ifi_flags = enable ? flags : 0,
89559513c3eSOphir Munk .ifi_change = flags,
89659513c3eSOphir Munk .ifi_index = iface_idx,
89759513c3eSOphir Munk },
89859513c3eSOphir Munk };
89959513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
90059513c3eSOphir Munk int ret;
90159513c3eSOphir Munk
90259513c3eSOphir Munk MLX5_ASSERT(!(flags & ~(IFF_PROMISC | IFF_ALLMULTI)));
90359513c3eSOphir Munk if (nlsk_fd < 0)
90459513c3eSOphir Munk return 0;
90559513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn);
90659513c3eSOphir Munk if (ret < 0)
90759513c3eSOphir Munk return ret;
90859513c3eSOphir Munk return 0;
90959513c3eSOphir Munk }
91059513c3eSOphir Munk
91159513c3eSOphir Munk /**
91259513c3eSOphir Munk * Enable promiscuous mode through Netlink.
91359513c3eSOphir Munk *
91459513c3eSOphir Munk * @param[in] nlsk_fd
91559513c3eSOphir Munk * Netlink socket file descriptor.
91659513c3eSOphir Munk * @param[in] iface_idx
91759513c3eSOphir Munk * Net device interface index.
91859513c3eSOphir Munk * @param enable
91959513c3eSOphir Munk * Nonzero to enable, disable otherwise.
92059513c3eSOphir Munk *
92159513c3eSOphir Munk * @return
92259513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
92359513c3eSOphir Munk */
92459513c3eSOphir Munk int
mlx5_nl_promisc(int nlsk_fd,unsigned int iface_idx,int enable)92559513c3eSOphir Munk mlx5_nl_promisc(int nlsk_fd, unsigned int iface_idx, int enable)
92659513c3eSOphir Munk {
92759513c3eSOphir Munk int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_PROMISC, enable);
92859513c3eSOphir Munk
92959513c3eSOphir Munk if (ret)
93059513c3eSOphir Munk DRV_LOG(DEBUG,
93159513c3eSOphir Munk "Interface %u cannot %s promisc mode: Netlink error %s",
93259513c3eSOphir Munk iface_idx, enable ? "enable" : "disable",
93359513c3eSOphir Munk strerror(rte_errno));
93459513c3eSOphir Munk return ret;
93559513c3eSOphir Munk }
93659513c3eSOphir Munk
93759513c3eSOphir Munk /**
93859513c3eSOphir Munk * Enable all multicast mode through Netlink.
93959513c3eSOphir Munk *
94059513c3eSOphir Munk * @param[in] nlsk_fd
94159513c3eSOphir Munk * Netlink socket file descriptor.
94259513c3eSOphir Munk * @param[in] iface_idx
94359513c3eSOphir Munk * Net device interface index.
94459513c3eSOphir Munk * @param enable
94559513c3eSOphir Munk * Nonzero to enable, disable otherwise.
94659513c3eSOphir Munk *
94759513c3eSOphir Munk * @return
94859513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
94959513c3eSOphir Munk */
95059513c3eSOphir Munk int
mlx5_nl_allmulti(int nlsk_fd,unsigned int iface_idx,int enable)95159513c3eSOphir Munk mlx5_nl_allmulti(int nlsk_fd, unsigned int iface_idx, int enable)
95259513c3eSOphir Munk {
95359513c3eSOphir Munk int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_ALLMULTI,
95459513c3eSOphir Munk enable);
95559513c3eSOphir Munk
95659513c3eSOphir Munk if (ret)
95759513c3eSOphir Munk DRV_LOG(DEBUG,
95859513c3eSOphir Munk "Interface %u cannot %s allmulti : Netlink error %s",
95959513c3eSOphir Munk iface_idx, enable ? "enable" : "disable",
96059513c3eSOphir Munk strerror(rte_errno));
96159513c3eSOphir Munk return ret;
96259513c3eSOphir Munk }
96359513c3eSOphir Munk
96459513c3eSOphir Munk /**
96559513c3eSOphir Munk * Process network interface information from Netlink message.
96659513c3eSOphir Munk *
96759513c3eSOphir Munk * @param nh
96859513c3eSOphir Munk * Pointer to Netlink message header.
96959513c3eSOphir Munk * @param arg
97059513c3eSOphir Munk * Opaque data pointer for this callback.
97159513c3eSOphir Munk *
97259513c3eSOphir Munk * @return
97359513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
97459513c3eSOphir Munk */
97559513c3eSOphir Munk static int
mlx5_nl_cmdget_cb(struct nlmsghdr * nh,void * arg)97659513c3eSOphir Munk mlx5_nl_cmdget_cb(struct nlmsghdr *nh, void *arg)
97759513c3eSOphir Munk {
978227813f2SXueming Li struct mlx5_nl_port_info *data = arg;
979227813f2SXueming Li struct mlx5_nl_port_info local = {
98059513c3eSOphir Munk .flags = 0,
98159513c3eSOphir Munk };
98259513c3eSOphir Munk size_t off = NLMSG_HDRLEN;
98359513c3eSOphir Munk
98459513c3eSOphir Munk if (nh->nlmsg_type !=
98559513c3eSOphir Munk RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET) &&
98659513c3eSOphir Munk nh->nlmsg_type !=
98759513c3eSOphir Munk RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_PORT_GET))
98859513c3eSOphir Munk goto error;
98959513c3eSOphir Munk while (off < nh->nlmsg_len) {
99059513c3eSOphir Munk struct nlattr *na = (void *)((uintptr_t)nh + off);
99159513c3eSOphir Munk void *payload = (void *)((uintptr_t)na + NLA_HDRLEN);
99259513c3eSOphir Munk
99359513c3eSOphir Munk if (na->nla_len > nh->nlmsg_len - off)
99459513c3eSOphir Munk goto error;
99559513c3eSOphir Munk switch (na->nla_type) {
99659513c3eSOphir Munk case RDMA_NLDEV_ATTR_DEV_INDEX:
99759513c3eSOphir Munk local.ibindex = *(uint32_t *)payload;
99859513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_IB_INDEX;
99959513c3eSOphir Munk break;
100059513c3eSOphir Munk case RDMA_NLDEV_ATTR_DEV_NAME:
100159513c3eSOphir Munk if (!strcmp(payload, data->name))
100259513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_IB_NAME;
100359513c3eSOphir Munk break;
100459513c3eSOphir Munk case RDMA_NLDEV_ATTR_NDEV_INDEX:
100559513c3eSOphir Munk local.ifindex = *(uint32_t *)payload;
100659513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_NET_INDEX;
100759513c3eSOphir Munk break;
100859513c3eSOphir Munk case RDMA_NLDEV_ATTR_PORT_INDEX:
100959513c3eSOphir Munk local.portnum = *(uint32_t *)payload;
101059513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_PORT_INDEX;
101159513c3eSOphir Munk break;
1012227813f2SXueming Li case RDMA_NLDEV_ATTR_PORT_STATE:
1013227813f2SXueming Li local.state = *(uint8_t *)payload;
1014227813f2SXueming Li local.flags |= MLX5_NL_CMD_GET_PORT_STATE;
1015227813f2SXueming Li break;
101659513c3eSOphir Munk default:
101759513c3eSOphir Munk break;
101859513c3eSOphir Munk }
101959513c3eSOphir Munk off += NLA_ALIGN(na->nla_len);
102059513c3eSOphir Munk }
102159513c3eSOphir Munk /*
102259513c3eSOphir Munk * It is possible to have multiple messages for all
102359513c3eSOphir Munk * Infiniband devices in the system with appropriate name.
102459513c3eSOphir Munk * So we should gather parameters locally and copy to
102559513c3eSOphir Munk * query context only in case of coinciding device name.
102659513c3eSOphir Munk */
102759513c3eSOphir Munk if (local.flags & MLX5_NL_CMD_GET_IB_NAME) {
102859513c3eSOphir Munk data->flags = local.flags;
102959513c3eSOphir Munk data->ibindex = local.ibindex;
103059513c3eSOphir Munk data->ifindex = local.ifindex;
103159513c3eSOphir Munk data->portnum = local.portnum;
1032227813f2SXueming Li data->state = local.state;
103359513c3eSOphir Munk }
103459513c3eSOphir Munk return 0;
103559513c3eSOphir Munk error:
103659513c3eSOphir Munk rte_errno = EINVAL;
103759513c3eSOphir Munk return -rte_errno;
103859513c3eSOphir Munk }
103959513c3eSOphir Munk
104059513c3eSOphir Munk /**
1041227813f2SXueming Li * Get port info of network interface associated with some IB device.
1042227813f2SXueming Li *
1043227813f2SXueming Li * This is the only somewhat safe method to avoid resorting to heuristics
1044227813f2SXueming Li * when faced with port representors. Unfortunately it requires at least
1045227813f2SXueming Li * Linux 4.17.
1046227813f2SXueming Li *
1047227813f2SXueming Li * @param nl
1048227813f2SXueming Li * Netlink socket of the RDMA kind (NETLINK_RDMA).
1049227813f2SXueming Li * @param[in] pindex
1050227813f2SXueming Li * IB device port index, starting from 1
1051227813f2SXueming Li * @param[out] data
1052227813f2SXueming Li * Pointer to port info.
1053227813f2SXueming Li * @return
1054227813f2SXueming Li * 0 on success, negative on error and rte_errno is set.
1055227813f2SXueming Li */
1056227813f2SXueming Li static int
mlx5_nl_port_info(int nl,uint32_t pindex,struct mlx5_nl_port_info * data)1057227813f2SXueming Li mlx5_nl_port_info(int nl, uint32_t pindex, struct mlx5_nl_port_info *data)
1058227813f2SXueming Li {
1059227813f2SXueming Li union {
1060227813f2SXueming Li struct nlmsghdr nh;
1061227813f2SXueming Li uint8_t buf[NLMSG_HDRLEN +
1062227813f2SXueming Li NLA_HDRLEN + NLA_ALIGN(sizeof(data->ibindex)) +
1063227813f2SXueming Li NLA_HDRLEN + NLA_ALIGN(sizeof(pindex))];
1064227813f2SXueming Li } req = {
1065227813f2SXueming Li .nh = {
1066227813f2SXueming Li .nlmsg_len = NLMSG_LENGTH(0),
1067227813f2SXueming Li .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1068227813f2SXueming Li RDMA_NLDEV_CMD_GET),
1069227813f2SXueming Li .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
1070227813f2SXueming Li },
1071227813f2SXueming Li };
1072227813f2SXueming Li struct nlattr *na;
1073227813f2SXueming Li uint32_t sn = MLX5_NL_SN_GENERATE;
1074227813f2SXueming Li int ret;
1075227813f2SXueming Li
1076227813f2SXueming Li ret = mlx5_nl_send(nl, &req.nh, sn);
1077227813f2SXueming Li if (ret < 0)
1078227813f2SXueming Li return ret;
1079227813f2SXueming Li ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, data);
1080227813f2SXueming Li if (ret < 0)
1081227813f2SXueming Li return ret;
1082227813f2SXueming Li if (!(data->flags & MLX5_NL_CMD_GET_IB_NAME) ||
1083227813f2SXueming Li !(data->flags & MLX5_NL_CMD_GET_IB_INDEX))
1084227813f2SXueming Li goto error;
1085227813f2SXueming Li data->flags = 0;
1086227813f2SXueming Li sn = MLX5_NL_SN_GENERATE;
1087227813f2SXueming Li req.nh.nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
1088227813f2SXueming Li RDMA_NLDEV_CMD_PORT_GET);
1089227813f2SXueming Li req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
1090227813f2SXueming Li req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.buf) - NLMSG_HDRLEN);
1091227813f2SXueming Li na = (void *)((uintptr_t)req.buf + NLMSG_HDRLEN);
1092227813f2SXueming Li na->nla_len = NLA_HDRLEN + sizeof(data->ibindex);
1093227813f2SXueming Li na->nla_type = RDMA_NLDEV_ATTR_DEV_INDEX;
1094227813f2SXueming Li memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1095227813f2SXueming Li &data->ibindex, sizeof(data->ibindex));
1096227813f2SXueming Li na = (void *)((uintptr_t)na + NLA_ALIGN(na->nla_len));
1097227813f2SXueming Li na->nla_len = NLA_HDRLEN + sizeof(pindex);
1098227813f2SXueming Li na->nla_type = RDMA_NLDEV_ATTR_PORT_INDEX;
1099227813f2SXueming Li memcpy((void *)((uintptr_t)na + NLA_HDRLEN),
1100227813f2SXueming Li &pindex, sizeof(pindex));
1101227813f2SXueming Li ret = mlx5_nl_send(nl, &req.nh, sn);
1102227813f2SXueming Li if (ret < 0)
1103227813f2SXueming Li return ret;
1104227813f2SXueming Li ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, data);
1105227813f2SXueming Li if (ret < 0)
1106227813f2SXueming Li return ret;
1107227813f2SXueming Li if (!(data->flags & MLX5_NL_CMD_GET_IB_NAME) ||
1108227813f2SXueming Li !(data->flags & MLX5_NL_CMD_GET_IB_INDEX) ||
1109227813f2SXueming Li !(data->flags & MLX5_NL_CMD_GET_NET_INDEX) ||
1110227813f2SXueming Li !data->ifindex)
1111227813f2SXueming Li goto error;
1112227813f2SXueming Li return 1;
1113227813f2SXueming Li error:
1114227813f2SXueming Li rte_errno = ENODEV;
1115227813f2SXueming Li return -rte_errno;
1116227813f2SXueming Li }
1117227813f2SXueming Li
1118227813f2SXueming Li /**
111959513c3eSOphir Munk * Get index of network interface associated with some IB device.
112059513c3eSOphir Munk *
112159513c3eSOphir Munk * This is the only somewhat safe method to avoid resorting to heuristics
112259513c3eSOphir Munk * when faced with port representors. Unfortunately it requires at least
112359513c3eSOphir Munk * Linux 4.17.
112459513c3eSOphir Munk *
112559513c3eSOphir Munk * @param nl
112659513c3eSOphir Munk * Netlink socket of the RDMA kind (NETLINK_RDMA).
112759513c3eSOphir Munk * @param[in] name
112859513c3eSOphir Munk * IB device name.
112959513c3eSOphir Munk * @param[in] pindex
113059513c3eSOphir Munk * IB device port index, starting from 1
113159513c3eSOphir Munk * @return
113259513c3eSOphir Munk * A valid (nonzero) interface index on success, 0 otherwise and rte_errno
113359513c3eSOphir Munk * is set.
113459513c3eSOphir Munk */
113559513c3eSOphir Munk unsigned int
mlx5_nl_ifindex(int nl,const char * name,uint32_t pindex)113659513c3eSOphir Munk mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex)
113759513c3eSOphir Munk {
1138227813f2SXueming Li struct mlx5_nl_port_info data = {
1139227813f2SXueming Li .ifindex = 0,
114059513c3eSOphir Munk .name = name,
114159513c3eSOphir Munk };
114259513c3eSOphir Munk
1143227813f2SXueming Li if (mlx5_nl_port_info(nl, pindex, &data) < 0)
114459513c3eSOphir Munk return 0;
114559513c3eSOphir Munk return data.ifindex;
1146227813f2SXueming Li }
1147227813f2SXueming Li
1148227813f2SXueming Li /**
1149227813f2SXueming Li * Get IB device port state.
1150227813f2SXueming Li *
1151227813f2SXueming Li * This is the only somewhat safe method to get info for port number >= 255.
1152227813f2SXueming Li * Unfortunately it requires at least Linux 4.17.
1153227813f2SXueming Li *
1154227813f2SXueming Li * @param nl
1155227813f2SXueming Li * Netlink socket of the RDMA kind (NETLINK_RDMA).
1156227813f2SXueming Li * @param[in] name
1157227813f2SXueming Li * IB device name.
1158227813f2SXueming Li * @param[in] pindex
1159227813f2SXueming Li * IB device port index, starting from 1
1160227813f2SXueming Li * @return
1161227813f2SXueming Li * Port state (ibv_port_state) on success, negative on error
1162227813f2SXueming Li * and rte_errno is set.
1163227813f2SXueming Li */
1164227813f2SXueming Li int
mlx5_nl_port_state(int nl,const char * name,uint32_t pindex)1165227813f2SXueming Li mlx5_nl_port_state(int nl, const char *name, uint32_t pindex)
1166227813f2SXueming Li {
1167227813f2SXueming Li struct mlx5_nl_port_info data = {
1168227813f2SXueming Li .state = 0,
1169227813f2SXueming Li .name = name,
1170227813f2SXueming Li };
1171227813f2SXueming Li
1172227813f2SXueming Li if (mlx5_nl_port_info(nl, pindex, &data) < 0)
1173227813f2SXueming Li return -rte_errno;
1174227813f2SXueming Li if ((data.flags & MLX5_NL_CMD_GET_PORT_STATE) == 0) {
1175227813f2SXueming Li rte_errno = ENOTSUP;
1176227813f2SXueming Li return -rte_errno;
1177227813f2SXueming Li }
1178227813f2SXueming Li return (int)data.state;
117959513c3eSOphir Munk }
118059513c3eSOphir Munk
118159513c3eSOphir Munk /**
118259513c3eSOphir Munk * Get the number of physical ports of given IB device.
118359513c3eSOphir Munk *
118459513c3eSOphir Munk * @param nl
118559513c3eSOphir Munk * Netlink socket of the RDMA kind (NETLINK_RDMA).
118659513c3eSOphir Munk * @param[in] name
118759513c3eSOphir Munk * IB device name.
118859513c3eSOphir Munk *
118959513c3eSOphir Munk * @return
119059513c3eSOphir Munk * A valid (nonzero) number of ports on success, 0 otherwise
119159513c3eSOphir Munk * and rte_errno is set.
119259513c3eSOphir Munk */
119359513c3eSOphir Munk unsigned int
mlx5_nl_portnum(int nl,const char * name)119459513c3eSOphir Munk mlx5_nl_portnum(int nl, const char *name)
119559513c3eSOphir Munk {
1196227813f2SXueming Li struct mlx5_nl_port_info data = {
119759513c3eSOphir Munk .flags = 0,
119859513c3eSOphir Munk .name = name,
119959513c3eSOphir Munk .ifindex = 0,
120059513c3eSOphir Munk .portnum = 0,
120159513c3eSOphir Munk };
120259513c3eSOphir Munk struct nlmsghdr req = {
120359513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(0),
120459513c3eSOphir Munk .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV,
120559513c3eSOphir Munk RDMA_NLDEV_CMD_GET),
120659513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP,
120759513c3eSOphir Munk };
120859513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
120959513c3eSOphir Munk int ret;
121059513c3eSOphir Munk
121159513c3eSOphir Munk ret = mlx5_nl_send(nl, &req, sn);
121259513c3eSOphir Munk if (ret < 0)
121359513c3eSOphir Munk return 0;
121459513c3eSOphir Munk ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data);
121559513c3eSOphir Munk if (ret < 0)
121659513c3eSOphir Munk return 0;
121759513c3eSOphir Munk if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) ||
121859513c3eSOphir Munk !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) ||
121959513c3eSOphir Munk !(data.flags & MLX5_NL_CMD_GET_PORT_INDEX)) {
122059513c3eSOphir Munk rte_errno = ENODEV;
122159513c3eSOphir Munk return 0;
122259513c3eSOphir Munk }
122359513c3eSOphir Munk if (!data.portnum)
122459513c3eSOphir Munk rte_errno = EINVAL;
122559513c3eSOphir Munk return data.portnum;
122659513c3eSOphir Munk }
122759513c3eSOphir Munk
122859513c3eSOphir Munk /**
122959513c3eSOphir Munk * Analyze gathered port parameters via Netlink to recognize master
123059513c3eSOphir Munk * and representor devices for E-Switch configuration.
123159513c3eSOphir Munk *
123259513c3eSOphir Munk * @param[in] num_vf_set
123359513c3eSOphir Munk * flag of presence of number of VFs port attribute.
123459513c3eSOphir Munk * @param[inout] switch_info
123559513c3eSOphir Munk * Port information, including port name as a number and port name
123659513c3eSOphir Munk * type if recognized
123759513c3eSOphir Munk *
123859513c3eSOphir Munk * @return
123959513c3eSOphir Munk * master and representor flags are set in switch_info according to
124059513c3eSOphir Munk * recognized parameters (if any).
124159513c3eSOphir Munk */
124259513c3eSOphir Munk static void
mlx5_nl_check_switch_info(bool num_vf_set,struct mlx5_switch_info * switch_info)124359513c3eSOphir Munk mlx5_nl_check_switch_info(bool num_vf_set,
124459513c3eSOphir Munk struct mlx5_switch_info *switch_info)
124559513c3eSOphir Munk {
124659513c3eSOphir Munk switch (switch_info->name_type) {
124759513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN:
124859513c3eSOphir Munk /*
124959513c3eSOphir Munk * Name is not recognized, assume the master,
125059513c3eSOphir Munk * check the number of VFs key presence.
125159513c3eSOphir Munk */
125259513c3eSOphir Munk switch_info->master = num_vf_set;
125359513c3eSOphir Munk break;
125459513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_NOTSET:
125559513c3eSOphir Munk /*
125659513c3eSOphir Munk * Name is not set, this assumes the legacy naming
125759513c3eSOphir Munk * schema for master, just check if there is a
125859513c3eSOphir Munk * number of VFs key.
125959513c3eSOphir Munk */
126059513c3eSOphir Munk switch_info->master = num_vf_set;
126159513c3eSOphir Munk break;
126259513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_UPLINK:
126359513c3eSOphir Munk /* New uplink naming schema recognized. */
126459513c3eSOphir Munk switch_info->master = 1;
126559513c3eSOphir Munk break;
126659513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_LEGACY:
126759513c3eSOphir Munk /* Legacy representors naming schema. */
126859513c3eSOphir Munk switch_info->representor = !num_vf_set;
126959513c3eSOphir Munk break;
1270420bbdaeSViacheslav Ovsiienko case MLX5_PHYS_PORT_NAME_TYPE_PFHPF:
1271420bbdaeSViacheslav Ovsiienko /* Fallthrough */
127259513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_PFVF:
127359df97f1SXueming Li /* Fallthrough */
127459df97f1SXueming Li case MLX5_PHYS_PORT_NAME_TYPE_PFSF:
127559513c3eSOphir Munk /* New representors naming schema. */
127659513c3eSOphir Munk switch_info->representor = 1;
127759513c3eSOphir Munk break;
127859513c3eSOphir Munk }
127959513c3eSOphir Munk }
128059513c3eSOphir Munk
128159513c3eSOphir Munk /**
128259513c3eSOphir Munk * Process switch information from Netlink message.
128359513c3eSOphir Munk *
128459513c3eSOphir Munk * @param nh
128559513c3eSOphir Munk * Pointer to Netlink message header.
128659513c3eSOphir Munk * @param arg
128759513c3eSOphir Munk * Opaque data pointer for this callback.
128859513c3eSOphir Munk *
128959513c3eSOphir Munk * @return
129059513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
129159513c3eSOphir Munk */
129259513c3eSOphir Munk static int
mlx5_nl_switch_info_cb(struct nlmsghdr * nh,void * arg)129359513c3eSOphir Munk mlx5_nl_switch_info_cb(struct nlmsghdr *nh, void *arg)
129459513c3eSOphir Munk {
129559513c3eSOphir Munk struct mlx5_switch_info info = {
129659513c3eSOphir Munk .master = 0,
129759513c3eSOphir Munk .representor = 0,
129859513c3eSOphir Munk .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET,
129959513c3eSOphir Munk .port_name = 0,
130059513c3eSOphir Munk .switch_id = 0,
130159513c3eSOphir Munk };
130259513c3eSOphir Munk size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg));
130359513c3eSOphir Munk bool switch_id_set = false;
130459513c3eSOphir Munk bool num_vf_set = false;
1305568d97c0SViacheslav Ovsiienko int len;
130659513c3eSOphir Munk
130759513c3eSOphir Munk if (nh->nlmsg_type != RTM_NEWLINK)
130859513c3eSOphir Munk goto error;
130959513c3eSOphir Munk while (off < nh->nlmsg_len) {
131059513c3eSOphir Munk struct rtattr *ra = (void *)((uintptr_t)nh + off);
131159513c3eSOphir Munk void *payload = RTA_DATA(ra);
131259513c3eSOphir Munk unsigned int i;
131359513c3eSOphir Munk
131459513c3eSOphir Munk if (ra->rta_len > nh->nlmsg_len - off)
131559513c3eSOphir Munk goto error;
131659513c3eSOphir Munk switch (ra->rta_type) {
131759513c3eSOphir Munk case IFLA_NUM_VF:
131859513c3eSOphir Munk num_vf_set = true;
131959513c3eSOphir Munk break;
132059513c3eSOphir Munk case IFLA_PHYS_PORT_NAME:
1321568d97c0SViacheslav Ovsiienko len = RTA_PAYLOAD(ra);
1322568d97c0SViacheslav Ovsiienko /* Some kernels do not pad attributes with zero. */
1323568d97c0SViacheslav Ovsiienko if (len > 0 && len < MLX5_PHYS_PORT_NAME_MAX) {
1324568d97c0SViacheslav Ovsiienko char name[MLX5_PHYS_PORT_NAME_MAX];
1325568d97c0SViacheslav Ovsiienko
1326568d97c0SViacheslav Ovsiienko /*
1327568d97c0SViacheslav Ovsiienko * We can't just patch the message with padding
1328568d97c0SViacheslav Ovsiienko * zero - it might corrupt the following items
1329568d97c0SViacheslav Ovsiienko * in the message, we have to copy the string
1330568d97c0SViacheslav Ovsiienko * by attribute length and pad the copied one.
1331568d97c0SViacheslav Ovsiienko */
1332568d97c0SViacheslav Ovsiienko memcpy(name, payload, len);
1333568d97c0SViacheslav Ovsiienko name[len] = 0;
1334568d97c0SViacheslav Ovsiienko mlx5_translate_port_name(name, &info);
1335568d97c0SViacheslav Ovsiienko } else {
1336568d97c0SViacheslav Ovsiienko info.name_type =
1337568d97c0SViacheslav Ovsiienko MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN;
1338568d97c0SViacheslav Ovsiienko }
133959513c3eSOphir Munk break;
134059513c3eSOphir Munk case IFLA_PHYS_SWITCH_ID:
134159513c3eSOphir Munk info.switch_id = 0;
134259513c3eSOphir Munk for (i = 0; i < RTA_PAYLOAD(ra); ++i) {
134359513c3eSOphir Munk info.switch_id <<= 8;
134459513c3eSOphir Munk info.switch_id |= ((uint8_t *)payload)[i];
134559513c3eSOphir Munk }
134659513c3eSOphir Munk switch_id_set = true;
134759513c3eSOphir Munk break;
134859513c3eSOphir Munk }
134959513c3eSOphir Munk off += RTA_ALIGN(ra->rta_len);
135059513c3eSOphir Munk }
135159513c3eSOphir Munk if (switch_id_set) {
135259513c3eSOphir Munk /* We have some E-Switch configuration. */
135359513c3eSOphir Munk mlx5_nl_check_switch_info(num_vf_set, &info);
135459513c3eSOphir Munk }
135559513c3eSOphir Munk MLX5_ASSERT(!(info.master && info.representor));
135659513c3eSOphir Munk memcpy(arg, &info, sizeof(info));
135759513c3eSOphir Munk return 0;
135859513c3eSOphir Munk error:
135959513c3eSOphir Munk rte_errno = EINVAL;
136059513c3eSOphir Munk return -rte_errno;
136159513c3eSOphir Munk }
136259513c3eSOphir Munk
136359513c3eSOphir Munk /**
136459513c3eSOphir Munk * Get switch information associated with network interface.
136559513c3eSOphir Munk *
136659513c3eSOphir Munk * @param nl
136759513c3eSOphir Munk * Netlink socket of the ROUTE kind (NETLINK_ROUTE).
136859513c3eSOphir Munk * @param ifindex
136959513c3eSOphir Munk * Network interface index.
137059513c3eSOphir Munk * @param[out] info
137159513c3eSOphir Munk * Switch information object, populated in case of success.
137259513c3eSOphir Munk *
137359513c3eSOphir Munk * @return
137459513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
137559513c3eSOphir Munk */
137659513c3eSOphir Munk int
mlx5_nl_switch_info(int nl,unsigned int ifindex,struct mlx5_switch_info * info)137759513c3eSOphir Munk mlx5_nl_switch_info(int nl, unsigned int ifindex,
137859513c3eSOphir Munk struct mlx5_switch_info *info)
137959513c3eSOphir Munk {
138059513c3eSOphir Munk struct {
138159513c3eSOphir Munk struct nlmsghdr nh;
138259513c3eSOphir Munk struct ifinfomsg info;
138359513c3eSOphir Munk struct rtattr rta;
138459513c3eSOphir Munk uint32_t extmask;
138559513c3eSOphir Munk } req = {
138659513c3eSOphir Munk .nh = {
138759513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH
138859513c3eSOphir Munk (sizeof(req.info) +
138959513c3eSOphir Munk RTA_LENGTH(sizeof(uint32_t))),
139059513c3eSOphir Munk .nlmsg_type = RTM_GETLINK,
139159513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
139259513c3eSOphir Munk },
139359513c3eSOphir Munk .info = {
139459513c3eSOphir Munk .ifi_family = AF_UNSPEC,
139559513c3eSOphir Munk .ifi_index = ifindex,
139659513c3eSOphir Munk },
139759513c3eSOphir Munk .rta = {
139859513c3eSOphir Munk .rta_type = IFLA_EXT_MASK,
139959513c3eSOphir Munk .rta_len = RTA_LENGTH(sizeof(int32_t)),
140059513c3eSOphir Munk },
140159513c3eSOphir Munk .extmask = RTE_LE32(1),
140259513c3eSOphir Munk };
140359513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
140459513c3eSOphir Munk int ret;
140559513c3eSOphir Munk
140659513c3eSOphir Munk ret = mlx5_nl_send(nl, &req.nh, sn);
140759513c3eSOphir Munk if (ret >= 0)
140859513c3eSOphir Munk ret = mlx5_nl_recv(nl, sn, mlx5_nl_switch_info_cb, info);
140959513c3eSOphir Munk if (info->master && info->representor) {
141059513c3eSOphir Munk DRV_LOG(ERR, "ifindex %u device is recognized as master"
141159513c3eSOphir Munk " and as representor", ifindex);
141259513c3eSOphir Munk rte_errno = ENODEV;
141359513c3eSOphir Munk ret = -rte_errno;
141459513c3eSOphir Munk }
141559513c3eSOphir Munk return ret;
141659513c3eSOphir Munk }
141759513c3eSOphir Munk
141859513c3eSOphir Munk /*
141959513c3eSOphir Munk * Delete VLAN network device by ifindex.
142059513c3eSOphir Munk *
142159513c3eSOphir Munk * @param[in] tcf
142259513c3eSOphir Munk * Context object initialized by mlx5_nl_vlan_vmwa_init().
142359513c3eSOphir Munk * @param[in] ifindex
142459513c3eSOphir Munk * Interface index of network device to delete.
142559513c3eSOphir Munk */
142659513c3eSOphir Munk void
mlx5_nl_vlan_vmwa_delete(struct mlx5_nl_vlan_vmwa_context * vmwa,uint32_t ifindex)142759513c3eSOphir Munk mlx5_nl_vlan_vmwa_delete(struct mlx5_nl_vlan_vmwa_context *vmwa,
142859513c3eSOphir Munk uint32_t ifindex)
142959513c3eSOphir Munk {
143059513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
143159513c3eSOphir Munk int ret;
143259513c3eSOphir Munk struct {
143359513c3eSOphir Munk struct nlmsghdr nh;
143459513c3eSOphir Munk struct ifinfomsg info;
143559513c3eSOphir Munk } req = {
143659513c3eSOphir Munk .nh = {
143759513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
143859513c3eSOphir Munk .nlmsg_type = RTM_DELLINK,
143959513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
144059513c3eSOphir Munk },
144159513c3eSOphir Munk .info = {
144259513c3eSOphir Munk .ifi_family = AF_UNSPEC,
144359513c3eSOphir Munk .ifi_index = ifindex,
144459513c3eSOphir Munk },
144559513c3eSOphir Munk };
144659513c3eSOphir Munk
144759513c3eSOphir Munk if (ifindex) {
144859513c3eSOphir Munk ret = mlx5_nl_send(vmwa->nl_socket, &req.nh, sn);
144959513c3eSOphir Munk if (ret >= 0)
145059513c3eSOphir Munk ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
145159513c3eSOphir Munk if (ret < 0)
145259513c3eSOphir Munk DRV_LOG(WARNING, "netlink: error deleting VLAN WA"
145359513c3eSOphir Munk " ifindex %u, %d", ifindex, ret);
145459513c3eSOphir Munk }
145559513c3eSOphir Munk }
145659513c3eSOphir Munk
145759513c3eSOphir Munk /* Set of subroutines to build Netlink message. */
145859513c3eSOphir Munk static struct nlattr *
nl_msg_tail(struct nlmsghdr * nlh)145959513c3eSOphir Munk nl_msg_tail(struct nlmsghdr *nlh)
146059513c3eSOphir Munk {
146159513c3eSOphir Munk return (struct nlattr *)
146259513c3eSOphir Munk (((uint8_t *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len));
146359513c3eSOphir Munk }
146459513c3eSOphir Munk
146559513c3eSOphir Munk static void
nl_attr_put(struct nlmsghdr * nlh,int type,const void * data,int alen)146659513c3eSOphir Munk nl_attr_put(struct nlmsghdr *nlh, int type, const void *data, int alen)
146759513c3eSOphir Munk {
146859513c3eSOphir Munk struct nlattr *nla = nl_msg_tail(nlh);
146959513c3eSOphir Munk
147059513c3eSOphir Munk nla->nla_type = type;
147159513c3eSOphir Munk nla->nla_len = NLMSG_ALIGN(sizeof(struct nlattr)) + alen;
147259513c3eSOphir Munk nlh->nlmsg_len += NLMSG_ALIGN(nla->nla_len);
147359513c3eSOphir Munk
147459513c3eSOphir Munk if (alen)
147559513c3eSOphir Munk memcpy((uint8_t *)nla + sizeof(struct nlattr), data, alen);
147659513c3eSOphir Munk }
147759513c3eSOphir Munk
147859513c3eSOphir Munk static struct nlattr *
nl_attr_nest_start(struct nlmsghdr * nlh,int type)147959513c3eSOphir Munk nl_attr_nest_start(struct nlmsghdr *nlh, int type)
148059513c3eSOphir Munk {
148159513c3eSOphir Munk struct nlattr *nest = (struct nlattr *)nl_msg_tail(nlh);
148259513c3eSOphir Munk
148359513c3eSOphir Munk nl_attr_put(nlh, type, NULL, 0);
148459513c3eSOphir Munk return nest;
148559513c3eSOphir Munk }
148659513c3eSOphir Munk
148759513c3eSOphir Munk static void
nl_attr_nest_end(struct nlmsghdr * nlh,struct nlattr * nest)148859513c3eSOphir Munk nl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *nest)
148959513c3eSOphir Munk {
149059513c3eSOphir Munk nest->nla_len = (uint8_t *)nl_msg_tail(nlh) - (uint8_t *)nest;
149159513c3eSOphir Munk }
149259513c3eSOphir Munk
149359513c3eSOphir Munk /*
149459513c3eSOphir Munk * Create network VLAN device with specified VLAN tag.
149559513c3eSOphir Munk *
149659513c3eSOphir Munk * @param[in] tcf
149759513c3eSOphir Munk * Context object initialized by mlx5_nl_vlan_vmwa_init().
149859513c3eSOphir Munk * @param[in] ifindex
149959513c3eSOphir Munk * Base network interface index.
150059513c3eSOphir Munk * @param[in] tag
150159513c3eSOphir Munk * VLAN tag for VLAN network device to create.
150259513c3eSOphir Munk */
150359513c3eSOphir Munk uint32_t
mlx5_nl_vlan_vmwa_create(struct mlx5_nl_vlan_vmwa_context * vmwa,uint32_t ifindex,uint16_t tag)150459513c3eSOphir Munk mlx5_nl_vlan_vmwa_create(struct mlx5_nl_vlan_vmwa_context *vmwa,
150559513c3eSOphir Munk uint32_t ifindex, uint16_t tag)
150659513c3eSOphir Munk {
150759513c3eSOphir Munk struct nlmsghdr *nlh;
150859513c3eSOphir Munk struct ifinfomsg *ifm;
150959513c3eSOphir Munk char name[sizeof(MLX5_VMWA_VLAN_DEVICE_PFX) + 32];
151059513c3eSOphir Munk
151127595cd8STyler Retzlaff alignas(RTE_CACHE_LINE_SIZE)
151259513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
151359513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct ifinfomsg)) +
151459513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 8 +
151559513c3eSOphir Munk NLMSG_ALIGN(sizeof(uint32_t)) +
151659513c3eSOphir Munk NLMSG_ALIGN(sizeof(name)) +
151759513c3eSOphir Munk NLMSG_ALIGN(sizeof("vlan")) +
151859513c3eSOphir Munk NLMSG_ALIGN(sizeof(uint32_t)) +
151959513c3eSOphir Munk NLMSG_ALIGN(sizeof(uint16_t)) + 16];
152059513c3eSOphir Munk struct nlattr *na_info;
152159513c3eSOphir Munk struct nlattr *na_vlan;
152259513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
152359513c3eSOphir Munk int ret;
152459513c3eSOphir Munk
152559513c3eSOphir Munk memset(buf, 0, sizeof(buf));
152659513c3eSOphir Munk nlh = (struct nlmsghdr *)buf;
152759513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr);
152859513c3eSOphir Munk nlh->nlmsg_type = RTM_NEWLINK;
152959513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE |
153059513c3eSOphir Munk NLM_F_EXCL | NLM_F_ACK;
153159513c3eSOphir Munk ifm = (struct ifinfomsg *)nl_msg_tail(nlh);
153259513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct ifinfomsg);
153359513c3eSOphir Munk ifm->ifi_family = AF_UNSPEC;
153459513c3eSOphir Munk ifm->ifi_type = 0;
153559513c3eSOphir Munk ifm->ifi_index = 0;
153659513c3eSOphir Munk ifm->ifi_flags = IFF_UP;
153759513c3eSOphir Munk ifm->ifi_change = 0xffffffff;
153859513c3eSOphir Munk nl_attr_put(nlh, IFLA_LINK, &ifindex, sizeof(ifindex));
153959513c3eSOphir Munk ret = snprintf(name, sizeof(name), "%s.%u.%u",
154059513c3eSOphir Munk MLX5_VMWA_VLAN_DEVICE_PFX, ifindex, tag);
154159513c3eSOphir Munk nl_attr_put(nlh, IFLA_IFNAME, name, ret + 1);
154259513c3eSOphir Munk na_info = nl_attr_nest_start(nlh, IFLA_LINKINFO);
154359513c3eSOphir Munk nl_attr_put(nlh, IFLA_INFO_KIND, "vlan", sizeof("vlan"));
154459513c3eSOphir Munk na_vlan = nl_attr_nest_start(nlh, IFLA_INFO_DATA);
154559513c3eSOphir Munk nl_attr_put(nlh, IFLA_VLAN_ID, &tag, sizeof(tag));
154659513c3eSOphir Munk nl_attr_nest_end(nlh, na_vlan);
154759513c3eSOphir Munk nl_attr_nest_end(nlh, na_info);
154859513c3eSOphir Munk MLX5_ASSERT(sizeof(buf) >= nlh->nlmsg_len);
154959513c3eSOphir Munk ret = mlx5_nl_send(vmwa->nl_socket, nlh, sn);
155059513c3eSOphir Munk if (ret >= 0)
155159513c3eSOphir Munk ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL);
155259513c3eSOphir Munk if (ret < 0) {
155359513c3eSOphir Munk DRV_LOG(WARNING, "netlink: VLAN %s create failure (%d)", name,
155459513c3eSOphir Munk ret);
155559513c3eSOphir Munk }
155659513c3eSOphir Munk /* Try to get ifindex of created or pre-existing device. */
155759513c3eSOphir Munk ret = if_nametoindex(name);
155859513c3eSOphir Munk if (!ret) {
155959513c3eSOphir Munk DRV_LOG(WARNING, "VLAN %s failed to get index (%d)", name,
156059513c3eSOphir Munk errno);
156159513c3eSOphir Munk return 0;
156259513c3eSOphir Munk }
156359513c3eSOphir Munk return ret;
156459513c3eSOphir Munk }
156559513c3eSOphir Munk
156659513c3eSOphir Munk /**
156759513c3eSOphir Munk * Parse Netlink message to retrieve the general family ID.
156859513c3eSOphir Munk *
156959513c3eSOphir Munk * @param nh
157059513c3eSOphir Munk * Pointer to Netlink Message Header.
157159513c3eSOphir Munk * @param arg
157259513c3eSOphir Munk * PMD data register with this callback.
157359513c3eSOphir Munk *
157459513c3eSOphir Munk * @return
157559513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
157659513c3eSOphir Munk */
157759513c3eSOphir Munk static int
mlx5_nl_family_id_cb(struct nlmsghdr * nh,void * arg)157859513c3eSOphir Munk mlx5_nl_family_id_cb(struct nlmsghdr *nh, void *arg)
157959513c3eSOphir Munk {
158059513c3eSOphir Munk
158159513c3eSOphir Munk struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
158259513c3eSOphir Munk struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
158359513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)));
158459513c3eSOphir Munk
158559513c3eSOphir Munk for (; nla->nla_len && nla < tail;
158659513c3eSOphir Munk nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len))) {
158759513c3eSOphir Munk if (nla->nla_type == CTRL_ATTR_FAMILY_ID) {
158859513c3eSOphir Munk *(uint16_t *)arg = *(uint16_t *)(nla + 1);
158959513c3eSOphir Munk return 0;
159059513c3eSOphir Munk }
159159513c3eSOphir Munk }
159259513c3eSOphir Munk return -EINVAL;
159359513c3eSOphir Munk }
159459513c3eSOphir Munk
159559513c3eSOphir Munk #define MLX5_NL_MAX_ATTR_SIZE 100
159659513c3eSOphir Munk /**
159759513c3eSOphir Munk * Get generic netlink family ID.
159859513c3eSOphir Munk *
159959513c3eSOphir Munk * @param[in] nlsk_fd
160059513c3eSOphir Munk * Netlink socket file descriptor.
160159513c3eSOphir Munk * @param[in] name
160259513c3eSOphir Munk * The family name.
160359513c3eSOphir Munk *
160459513c3eSOphir Munk * @return
160559513c3eSOphir Munk * ID >= 0 on success and @p enable is updated, a negative errno value
160659513c3eSOphir Munk * otherwise and rte_errno is set.
160759513c3eSOphir Munk */
160859513c3eSOphir Munk static int
mlx5_nl_generic_family_id_get(int nlsk_fd,const char * name)160959513c3eSOphir Munk mlx5_nl_generic_family_id_get(int nlsk_fd, const char *name)
161059513c3eSOphir Munk {
161159513c3eSOphir Munk struct nlmsghdr *nlh;
161259513c3eSOphir Munk struct genlmsghdr *genl;
161359513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
161459513c3eSOphir Munk int name_size = strlen(name) + 1;
161559513c3eSOphir Munk int ret;
161659513c3eSOphir Munk uint16_t id = -1;
161759513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
161859513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
161959513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) +
162059513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE)];
162159513c3eSOphir Munk
162259513c3eSOphir Munk memset(buf, 0, sizeof(buf));
162359513c3eSOphir Munk nlh = (struct nlmsghdr *)buf;
162459513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr);
162559513c3eSOphir Munk nlh->nlmsg_type = GENL_ID_CTRL;
162659513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
162759513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh);
162859513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr);
162959513c3eSOphir Munk genl->cmd = CTRL_CMD_GETFAMILY;
163059513c3eSOphir Munk genl->version = 1;
163159513c3eSOphir Munk nl_attr_put(nlh, CTRL_ATTR_FAMILY_NAME, name, name_size);
163259513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn);
163359513c3eSOphir Munk if (ret >= 0)
163459513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_family_id_cb, &id);
163559513c3eSOphir Munk if (ret < 0) {
163659513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to get Netlink %s family ID: %d.", name,
163759513c3eSOphir Munk ret);
163859513c3eSOphir Munk return ret;
163959513c3eSOphir Munk }
164059513c3eSOphir Munk DRV_LOG(DEBUG, "Netlink \"%s\" family ID is %u.", name, id);
164159513c3eSOphir Munk return (int)id;
164259513c3eSOphir Munk }
164359513c3eSOphir Munk
164459513c3eSOphir Munk /**
164559513c3eSOphir Munk * Get Devlink family ID.
164659513c3eSOphir Munk *
164759513c3eSOphir Munk * @param[in] nlsk_fd
164859513c3eSOphir Munk * Netlink socket file descriptor.
164959513c3eSOphir Munk *
165059513c3eSOphir Munk * @return
165159513c3eSOphir Munk * ID >= 0 on success and @p enable is updated, a negative errno value
165259513c3eSOphir Munk * otherwise and rte_errno is set.
165359513c3eSOphir Munk */
165459513c3eSOphir Munk
165559513c3eSOphir Munk int
mlx5_nl_devlink_family_id_get(int nlsk_fd)165659513c3eSOphir Munk mlx5_nl_devlink_family_id_get(int nlsk_fd)
165759513c3eSOphir Munk {
165859513c3eSOphir Munk return mlx5_nl_generic_family_id_get(nlsk_fd, DEVLINK_GENL_NAME);
165959513c3eSOphir Munk }
166059513c3eSOphir Munk
166159513c3eSOphir Munk /**
166259513c3eSOphir Munk * Parse Netlink message to retrieve the ROCE enable status.
166359513c3eSOphir Munk *
166459513c3eSOphir Munk * @param nh
166559513c3eSOphir Munk * Pointer to Netlink Message Header.
166659513c3eSOphir Munk * @param arg
166759513c3eSOphir Munk * PMD data register with this callback.
166859513c3eSOphir Munk *
166959513c3eSOphir Munk * @return
167059513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
167159513c3eSOphir Munk */
167259513c3eSOphir Munk static int
mlx5_nl_roce_cb(struct nlmsghdr * nh,void * arg)167359513c3eSOphir Munk mlx5_nl_roce_cb(struct nlmsghdr *nh, void *arg)
167459513c3eSOphir Munk {
167559513c3eSOphir Munk
167659513c3eSOphir Munk int ret = -EINVAL;
167759513c3eSOphir Munk int *enable = arg;
167859513c3eSOphir Munk struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
167959513c3eSOphir Munk struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
168059513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)));
168159513c3eSOphir Munk
168259513c3eSOphir Munk while (nla->nla_len && nla < tail) {
168359513c3eSOphir Munk switch (nla->nla_type) {
168459513c3eSOphir Munk /* Expected nested attributes case. */
168559513c3eSOphir Munk case DEVLINK_ATTR_PARAM:
168659513c3eSOphir Munk case DEVLINK_ATTR_PARAM_VALUES_LIST:
168759513c3eSOphir Munk case DEVLINK_ATTR_PARAM_VALUE:
168859513c3eSOphir Munk ret = 0;
168959513c3eSOphir Munk nla += 1;
169059513c3eSOphir Munk break;
169159513c3eSOphir Munk case DEVLINK_ATTR_PARAM_VALUE_DATA:
169259513c3eSOphir Munk *enable = 1;
169359513c3eSOphir Munk return 0;
169459513c3eSOphir Munk default:
169559513c3eSOphir Munk nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len));
169659513c3eSOphir Munk }
169759513c3eSOphir Munk }
169859513c3eSOphir Munk *enable = 0;
169959513c3eSOphir Munk return ret;
170059513c3eSOphir Munk }
170159513c3eSOphir Munk
170259513c3eSOphir Munk /**
170359513c3eSOphir Munk * Get ROCE enable status through Netlink.
170459513c3eSOphir Munk *
170559513c3eSOphir Munk * @param[in] nlsk_fd
170659513c3eSOphir Munk * Netlink socket file descriptor.
170759513c3eSOphir Munk * @param[in] family_id
170859513c3eSOphir Munk * the Devlink family ID.
170959513c3eSOphir Munk * @param pci_addr
171059513c3eSOphir Munk * The device PCI address.
171159513c3eSOphir Munk * @param[out] enable
171259513c3eSOphir Munk * Where to store the enable status.
171359513c3eSOphir Munk *
171459513c3eSOphir Munk * @return
171559513c3eSOphir Munk * 0 on success and @p enable is updated, a negative errno value otherwise
171659513c3eSOphir Munk * and rte_errno is set.
171759513c3eSOphir Munk */
171859513c3eSOphir Munk int
mlx5_nl_enable_roce_get(int nlsk_fd,int family_id,const char * pci_addr,int * enable)171959513c3eSOphir Munk mlx5_nl_enable_roce_get(int nlsk_fd, int family_id, const char *pci_addr,
172059513c3eSOphir Munk int *enable)
172159513c3eSOphir Munk {
172259513c3eSOphir Munk struct nlmsghdr *nlh;
172359513c3eSOphir Munk struct genlmsghdr *genl;
172459513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
172559513c3eSOphir Munk int ret;
172659513c3eSOphir Munk int cur_en = 0;
172759513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
172859513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
172959513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 4 +
173059513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4];
173159513c3eSOphir Munk
173259513c3eSOphir Munk memset(buf, 0, sizeof(buf));
173359513c3eSOphir Munk nlh = (struct nlmsghdr *)buf;
173459513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr);
173559513c3eSOphir Munk nlh->nlmsg_type = family_id;
173659513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
173759513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh);
173859513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr);
173959513c3eSOphir Munk genl->cmd = DEVLINK_CMD_PARAM_GET;
174059513c3eSOphir Munk genl->version = DEVLINK_GENL_VERSION;
174159513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
174259513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
174359513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
174459513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn);
174559513c3eSOphir Munk if (ret >= 0)
174659513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_roce_cb, &cur_en);
174759513c3eSOphir Munk if (ret < 0) {
174859513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to get ROCE enable on device %s: %d.",
174959513c3eSOphir Munk pci_addr, ret);
175059513c3eSOphir Munk return ret;
175159513c3eSOphir Munk }
175259513c3eSOphir Munk *enable = cur_en;
175359513c3eSOphir Munk DRV_LOG(DEBUG, "ROCE is %sabled for device \"%s\".",
175459513c3eSOphir Munk cur_en ? "en" : "dis", pci_addr);
175559513c3eSOphir Munk return ret;
175659513c3eSOphir Munk }
175759513c3eSOphir Munk
175859513c3eSOphir Munk /**
175959513c3eSOphir Munk * Reload mlx5 device kernel driver through Netlink.
176059513c3eSOphir Munk *
176159513c3eSOphir Munk * @param[in] nlsk_fd
176259513c3eSOphir Munk * Netlink socket file descriptor.
176359513c3eSOphir Munk * @param[in] family_id
176459513c3eSOphir Munk * the Devlink family ID.
176559513c3eSOphir Munk * @param pci_addr
176659513c3eSOphir Munk * The device PCI address.
176759513c3eSOphir Munk * @param[out] enable
176859513c3eSOphir Munk * The enable status to set.
176959513c3eSOphir Munk *
177059513c3eSOphir Munk * @return
177159513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
177259513c3eSOphir Munk */
1773662d0dc6SMichael Baum static int
mlx5_nl_driver_reload(int nlsk_fd,int family_id,const char * pci_addr)177459513c3eSOphir Munk mlx5_nl_driver_reload(int nlsk_fd, int family_id, const char *pci_addr)
177559513c3eSOphir Munk {
177659513c3eSOphir Munk struct nlmsghdr *nlh;
177759513c3eSOphir Munk struct genlmsghdr *genl;
177859513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
177959513c3eSOphir Munk int ret;
178059513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
178159513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
178259513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 2 +
178359513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 2];
178459513c3eSOphir Munk
178559513c3eSOphir Munk memset(buf, 0, sizeof(buf));
178659513c3eSOphir Munk nlh = (struct nlmsghdr *)buf;
178759513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr);
178859513c3eSOphir Munk nlh->nlmsg_type = family_id;
178959513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
179059513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh);
179159513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr);
179259513c3eSOphir Munk genl->cmd = DEVLINK_CMD_RELOAD;
179359513c3eSOphir Munk genl->version = DEVLINK_GENL_VERSION;
179459513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
179559513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
179659513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn);
179759513c3eSOphir Munk if (ret >= 0)
179859513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
179959513c3eSOphir Munk if (ret < 0) {
180059513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to reload %s device by Netlink - %d",
180159513c3eSOphir Munk pci_addr, ret);
180259513c3eSOphir Munk return ret;
180359513c3eSOphir Munk }
180459513c3eSOphir Munk DRV_LOG(DEBUG, "Device \"%s\" was reloaded by Netlink successfully.",
180559513c3eSOphir Munk pci_addr);
180659513c3eSOphir Munk return 0;
180759513c3eSOphir Munk }
180859513c3eSOphir Munk
180959513c3eSOphir Munk /**
181059513c3eSOphir Munk * Set ROCE enable status through Netlink.
181159513c3eSOphir Munk *
181259513c3eSOphir Munk * @param[in] nlsk_fd
181359513c3eSOphir Munk * Netlink socket file descriptor.
181459513c3eSOphir Munk * @param[in] family_id
181559513c3eSOphir Munk * the Devlink family ID.
181659513c3eSOphir Munk * @param pci_addr
181759513c3eSOphir Munk * The device PCI address.
181859513c3eSOphir Munk * @param[out] enable
181959513c3eSOphir Munk * The enable status to set.
182059513c3eSOphir Munk *
182159513c3eSOphir Munk * @return
182259513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set.
182359513c3eSOphir Munk */
182459513c3eSOphir Munk int
mlx5_nl_enable_roce_set(int nlsk_fd,int family_id,const char * pci_addr,int enable)182559513c3eSOphir Munk mlx5_nl_enable_roce_set(int nlsk_fd, int family_id, const char *pci_addr,
182659513c3eSOphir Munk int enable)
182759513c3eSOphir Munk {
182859513c3eSOphir Munk struct nlmsghdr *nlh;
182959513c3eSOphir Munk struct genlmsghdr *genl;
183059513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE;
183159513c3eSOphir Munk int ret;
183259513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
183359513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
183459513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 6 +
183559513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 6];
183659513c3eSOphir Munk uint8_t cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
183759513c3eSOphir Munk uint8_t ptype = NLA_FLAG;
183859513c3eSOphir Munk ;
183959513c3eSOphir Munk
184059513c3eSOphir Munk memset(buf, 0, sizeof(buf));
184159513c3eSOphir Munk nlh = (struct nlmsghdr *)buf;
184259513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr);
184359513c3eSOphir Munk nlh->nlmsg_type = family_id;
184459513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
184559513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh);
184659513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr);
184759513c3eSOphir Munk genl->cmd = DEVLINK_CMD_PARAM_SET;
184859513c3eSOphir Munk genl->version = DEVLINK_GENL_VERSION;
184959513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
185059513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
185159513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12);
185259513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, &cmode, sizeof(cmode));
185359513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_TYPE, &ptype, sizeof(ptype));
185459513c3eSOphir Munk if (enable)
185559513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, NULL, 0);
185659513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn);
185759513c3eSOphir Munk if (ret >= 0)
185859513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL);
185959513c3eSOphir Munk if (ret < 0) {
186059513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to %sable ROCE for device %s by Netlink:"
186159513c3eSOphir Munk " %d.", enable ? "en" : "dis", pci_addr, ret);
186259513c3eSOphir Munk return ret;
186359513c3eSOphir Munk }
186459513c3eSOphir Munk DRV_LOG(DEBUG, "Device %s ROCE was %sabled by Netlink successfully.",
186559513c3eSOphir Munk pci_addr, enable ? "en" : "dis");
186659513c3eSOphir Munk /* Now, need to reload the driver. */
186759513c3eSOphir Munk return mlx5_nl_driver_reload(nlsk_fd, family_id, pci_addr);
186859513c3eSOphir Munk }
1869be66461cSDmitry Kozlyuk
1870be66461cSDmitry Kozlyuk /**
1871be66461cSDmitry Kozlyuk * Try to parse a Netlink message as a link status update.
1872be66461cSDmitry Kozlyuk *
1873be66461cSDmitry Kozlyuk * @param hdr
1874be66461cSDmitry Kozlyuk * Netlink message header.
1875be66461cSDmitry Kozlyuk * @param[out] ifindex
1876be66461cSDmitry Kozlyuk * Index of the updated interface.
1877be66461cSDmitry Kozlyuk *
1878be66461cSDmitry Kozlyuk * @return
1879be66461cSDmitry Kozlyuk * 0 on success, negative on failure.
1880be66461cSDmitry Kozlyuk */
1881be66461cSDmitry Kozlyuk int
mlx5_nl_parse_link_status_update(struct nlmsghdr * hdr,uint32_t * ifindex)1882be66461cSDmitry Kozlyuk mlx5_nl_parse_link_status_update(struct nlmsghdr *hdr, uint32_t *ifindex)
1883be66461cSDmitry Kozlyuk {
1884be66461cSDmitry Kozlyuk struct ifinfomsg *info;
1885be66461cSDmitry Kozlyuk
1886be66461cSDmitry Kozlyuk switch (hdr->nlmsg_type) {
1887be66461cSDmitry Kozlyuk case RTM_NEWLINK:
1888be66461cSDmitry Kozlyuk case RTM_DELLINK:
1889be66461cSDmitry Kozlyuk case RTM_GETLINK:
1890be66461cSDmitry Kozlyuk case RTM_SETLINK:
1891be66461cSDmitry Kozlyuk info = NLMSG_DATA(hdr);
1892be66461cSDmitry Kozlyuk *ifindex = info->ifi_index;
1893be66461cSDmitry Kozlyuk return 0;
1894be66461cSDmitry Kozlyuk }
1895be66461cSDmitry Kozlyuk return -1;
1896be66461cSDmitry Kozlyuk }
1897be66461cSDmitry Kozlyuk
1898be66461cSDmitry Kozlyuk /**
1899be66461cSDmitry Kozlyuk * Read pending events from a Netlink socket.
1900be66461cSDmitry Kozlyuk *
1901be66461cSDmitry Kozlyuk * @param nlsk_fd
1902be66461cSDmitry Kozlyuk * Netlink socket.
1903be66461cSDmitry Kozlyuk * @param cb
1904be66461cSDmitry Kozlyuk * Callback invoked for each of the events.
1905be66461cSDmitry Kozlyuk * @param cb_arg
1906be66461cSDmitry Kozlyuk * User data for the callback.
1907be66461cSDmitry Kozlyuk *
1908be66461cSDmitry Kozlyuk * @return
1909be66461cSDmitry Kozlyuk * 0 on success, including the case when there are no events.
1910be66461cSDmitry Kozlyuk * Negative on failure and rte_errno is set.
1911be66461cSDmitry Kozlyuk */
1912be66461cSDmitry Kozlyuk int
mlx5_nl_read_events(int nlsk_fd,mlx5_nl_event_cb * cb,void * cb_arg)1913be66461cSDmitry Kozlyuk mlx5_nl_read_events(int nlsk_fd, mlx5_nl_event_cb *cb, void *cb_arg)
1914be66461cSDmitry Kozlyuk {
1915be66461cSDmitry Kozlyuk char buf[8192];
1916be66461cSDmitry Kozlyuk struct sockaddr_nl addr;
1917be66461cSDmitry Kozlyuk struct iovec iov = {
1918be66461cSDmitry Kozlyuk .iov_base = buf,
1919be66461cSDmitry Kozlyuk .iov_len = sizeof(buf),
1920be66461cSDmitry Kozlyuk };
1921be66461cSDmitry Kozlyuk struct msghdr msg = {
1922be66461cSDmitry Kozlyuk .msg_name = &addr,
1923be66461cSDmitry Kozlyuk .msg_namelen = sizeof(addr),
1924be66461cSDmitry Kozlyuk .msg_iov = &iov,
1925be66461cSDmitry Kozlyuk .msg_iovlen = 1,
1926be66461cSDmitry Kozlyuk };
1927be66461cSDmitry Kozlyuk struct nlmsghdr *hdr;
1928be66461cSDmitry Kozlyuk ssize_t size;
1929be66461cSDmitry Kozlyuk
1930be66461cSDmitry Kozlyuk while (1) {
1931be66461cSDmitry Kozlyuk size = recvmsg(nlsk_fd, &msg, MSG_DONTWAIT);
1932be66461cSDmitry Kozlyuk if (size < 0) {
1933be66461cSDmitry Kozlyuk if (errno == EAGAIN)
1934be66461cSDmitry Kozlyuk return 0;
1935be66461cSDmitry Kozlyuk if (errno == EINTR)
1936be66461cSDmitry Kozlyuk continue;
1937be66461cSDmitry Kozlyuk DRV_LOG(DEBUG, "Failed to receive netlink message: %s",
1938be66461cSDmitry Kozlyuk strerror(errno));
1939be66461cSDmitry Kozlyuk rte_errno = errno;
1940be66461cSDmitry Kozlyuk return -rte_errno;
1941be66461cSDmitry Kozlyuk }
1942be66461cSDmitry Kozlyuk hdr = (struct nlmsghdr *)buf;
1943be66461cSDmitry Kozlyuk while (size >= (ssize_t)sizeof(*hdr)) {
1944be66461cSDmitry Kozlyuk ssize_t msg_len = hdr->nlmsg_len;
1945be66461cSDmitry Kozlyuk ssize_t data_len = msg_len - sizeof(*hdr);
1946be66461cSDmitry Kozlyuk ssize_t aligned_len;
1947be66461cSDmitry Kozlyuk
1948be66461cSDmitry Kozlyuk if (data_len < 0) {
1949be66461cSDmitry Kozlyuk DRV_LOG(DEBUG, "Netlink message too short");
1950be66461cSDmitry Kozlyuk rte_errno = EINVAL;
1951be66461cSDmitry Kozlyuk return -rte_errno;
1952be66461cSDmitry Kozlyuk }
1953be66461cSDmitry Kozlyuk aligned_len = NLMSG_ALIGN(msg_len);
1954be66461cSDmitry Kozlyuk if (aligned_len > size) {
1955be66461cSDmitry Kozlyuk DRV_LOG(DEBUG, "Netlink message too long");
1956be66461cSDmitry Kozlyuk rte_errno = EINVAL;
1957be66461cSDmitry Kozlyuk return -rte_errno;
1958be66461cSDmitry Kozlyuk }
1959be66461cSDmitry Kozlyuk cb(hdr, cb_arg);
1960be66461cSDmitry Kozlyuk hdr = RTE_PTR_ADD(hdr, aligned_len);
1961be66461cSDmitry Kozlyuk size -= aligned_len;
1962be66461cSDmitry Kozlyuk }
1963be66461cSDmitry Kozlyuk }
1964be66461cSDmitry Kozlyuk return 0;
1965be66461cSDmitry Kozlyuk }
196654245a29SDariusz Sosnowski
196754245a29SDariusz Sosnowski static int
mlx5_nl_esw_multiport_cb(struct nlmsghdr * nh,void * arg)196854245a29SDariusz Sosnowski mlx5_nl_esw_multiport_cb(struct nlmsghdr *nh, void *arg)
196954245a29SDariusz Sosnowski {
197054245a29SDariusz Sosnowski
197154245a29SDariusz Sosnowski int ret = -EINVAL;
197254245a29SDariusz Sosnowski int *enable = arg;
197354245a29SDariusz Sosnowski struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len);
197454245a29SDariusz Sosnowski struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) +
197554245a29SDariusz Sosnowski NLMSG_ALIGN(sizeof(struct genlmsghdr)));
197654245a29SDariusz Sosnowski
197754245a29SDariusz Sosnowski while (nla->nla_len && nla < tail) {
197854245a29SDariusz Sosnowski switch (nla->nla_type) {
197954245a29SDariusz Sosnowski /* Expected nested attributes case. */
198054245a29SDariusz Sosnowski case DEVLINK_ATTR_PARAM:
198154245a29SDariusz Sosnowski case DEVLINK_ATTR_PARAM_VALUES_LIST:
198254245a29SDariusz Sosnowski case DEVLINK_ATTR_PARAM_VALUE:
198354245a29SDariusz Sosnowski ret = 0;
198454245a29SDariusz Sosnowski nla += 1;
198554245a29SDariusz Sosnowski break;
198654245a29SDariusz Sosnowski case DEVLINK_ATTR_PARAM_VALUE_DATA:
198754245a29SDariusz Sosnowski *enable = 1;
198854245a29SDariusz Sosnowski return 0;
198954245a29SDariusz Sosnowski default:
199054245a29SDariusz Sosnowski nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len));
199154245a29SDariusz Sosnowski }
199254245a29SDariusz Sosnowski }
199354245a29SDariusz Sosnowski *enable = 0;
199454245a29SDariusz Sosnowski return ret;
199554245a29SDariusz Sosnowski }
199654245a29SDariusz Sosnowski
199754245a29SDariusz Sosnowski #define NL_ESW_MULTIPORT_PARAM "esw_multiport"
199854245a29SDariusz Sosnowski
199954245a29SDariusz Sosnowski int
mlx5_nl_devlink_esw_multiport_get(int nlsk_fd,int family_id,const char * pci_addr,int * enable)200054245a29SDariusz Sosnowski mlx5_nl_devlink_esw_multiport_get(int nlsk_fd, int family_id, const char *pci_addr, int *enable)
200154245a29SDariusz Sosnowski {
200254245a29SDariusz Sosnowski struct nlmsghdr *nlh;
200354245a29SDariusz Sosnowski struct genlmsghdr *genl;
200454245a29SDariusz Sosnowski uint32_t sn = MLX5_NL_SN_GENERATE;
200554245a29SDariusz Sosnowski int ret;
200654245a29SDariusz Sosnowski uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
200754245a29SDariusz Sosnowski NLMSG_ALIGN(sizeof(struct genlmsghdr)) +
200854245a29SDariusz Sosnowski NLMSG_ALIGN(sizeof(struct nlattr)) * 4 +
200954245a29SDariusz Sosnowski NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4];
201054245a29SDariusz Sosnowski
201154245a29SDariusz Sosnowski memset(buf, 0, sizeof(buf));
201254245a29SDariusz Sosnowski nlh = (struct nlmsghdr *)buf;
201354245a29SDariusz Sosnowski nlh->nlmsg_len = sizeof(struct nlmsghdr);
201454245a29SDariusz Sosnowski nlh->nlmsg_type = family_id;
201554245a29SDariusz Sosnowski nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
201654245a29SDariusz Sosnowski genl = (struct genlmsghdr *)nl_msg_tail(nlh);
201754245a29SDariusz Sosnowski nlh->nlmsg_len += sizeof(struct genlmsghdr);
201854245a29SDariusz Sosnowski genl->cmd = DEVLINK_CMD_PARAM_GET;
201954245a29SDariusz Sosnowski genl->version = DEVLINK_GENL_VERSION;
202054245a29SDariusz Sosnowski nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4);
202154245a29SDariusz Sosnowski nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1);
202254245a29SDariusz Sosnowski nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME,
202354245a29SDariusz Sosnowski NL_ESW_MULTIPORT_PARAM, sizeof(NL_ESW_MULTIPORT_PARAM));
202454245a29SDariusz Sosnowski ret = mlx5_nl_send(nlsk_fd, nlh, sn);
202554245a29SDariusz Sosnowski if (ret >= 0)
202654245a29SDariusz Sosnowski ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_esw_multiport_cb, enable);
202754245a29SDariusz Sosnowski if (ret < 0) {
202854245a29SDariusz Sosnowski DRV_LOG(DEBUG, "Failed to get Multiport E-Switch enable on device %s: %d.",
202954245a29SDariusz Sosnowski pci_addr, ret);
203054245a29SDariusz Sosnowski return ret;
203154245a29SDariusz Sosnowski }
203254245a29SDariusz Sosnowski DRV_LOG(DEBUG, "Multiport E-Switch is %sabled for device \"%s\".",
203354245a29SDariusz Sosnowski *enable ? "en" : "dis", pci_addr);
203454245a29SDariusz Sosnowski return ret;
203554245a29SDariusz Sosnowski }
2036