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" 2359513c3eSOphir Munk #include "mlx5_common_utils.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 3659513c3eSOphir Munk 3759513c3eSOphir Munk /** Parameters of VLAN devices created by driver. */ 3859513c3eSOphir Munk #define MLX5_VMWA_VLAN_DEVICE_PFX "evmlx" 3959513c3eSOphir Munk /* 4059513c3eSOphir Munk * Define NDA_RTA as defined in iproute2 sources. 4159513c3eSOphir Munk * 4259513c3eSOphir Munk * see in iproute2 sources file include/libnetlink.h 4359513c3eSOphir Munk */ 4459513c3eSOphir Munk #ifndef MLX5_NDA_RTA 4559513c3eSOphir Munk #define MLX5_NDA_RTA(r) \ 4659513c3eSOphir Munk ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) 4759513c3eSOphir Munk #endif 4859513c3eSOphir Munk /* 4959513c3eSOphir Munk * Define NLMSG_TAIL as defined in iproute2 sources. 5059513c3eSOphir Munk * 5159513c3eSOphir Munk * see in iproute2 sources file include/libnetlink.h 5259513c3eSOphir Munk */ 5359513c3eSOphir Munk #ifndef NLMSG_TAIL 5459513c3eSOphir Munk #define NLMSG_TAIL(nmsg) \ 5559513c3eSOphir Munk ((struct rtattr *)(((char *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 5659513c3eSOphir Munk #endif 5759513c3eSOphir Munk /* 5859513c3eSOphir Munk * The following definitions are normally found in rdma/rdma_netlink.h, 5959513c3eSOphir Munk * however they are so recent that most systems do not expose them yet. 6059513c3eSOphir Munk */ 6159513c3eSOphir Munk #ifndef HAVE_RDMA_NL_NLDEV 6259513c3eSOphir Munk #define RDMA_NL_NLDEV 5 6359513c3eSOphir Munk #endif 6459513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_CMD_GET 6559513c3eSOphir Munk #define RDMA_NLDEV_CMD_GET 1 6659513c3eSOphir Munk #endif 6759513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_CMD_PORT_GET 6859513c3eSOphir Munk #define RDMA_NLDEV_CMD_PORT_GET 5 6959513c3eSOphir Munk #endif 7059513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_INDEX 7159513c3eSOphir Munk #define RDMA_NLDEV_ATTR_DEV_INDEX 1 7259513c3eSOphir Munk #endif 7359513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_DEV_NAME 7459513c3eSOphir Munk #define RDMA_NLDEV_ATTR_DEV_NAME 2 7559513c3eSOphir Munk #endif 7659513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_PORT_INDEX 7759513c3eSOphir Munk #define RDMA_NLDEV_ATTR_PORT_INDEX 3 7859513c3eSOphir Munk #endif 7959513c3eSOphir Munk #ifndef HAVE_RDMA_NLDEV_ATTR_NDEV_INDEX 8059513c3eSOphir Munk #define RDMA_NLDEV_ATTR_NDEV_INDEX 50 8159513c3eSOphir Munk #endif 8259513c3eSOphir Munk 8359513c3eSOphir Munk /* These are normally found in linux/if_link.h. */ 8459513c3eSOphir Munk #ifndef HAVE_IFLA_NUM_VF 8559513c3eSOphir Munk #define IFLA_NUM_VF 21 8659513c3eSOphir Munk #endif 8759513c3eSOphir Munk #ifndef HAVE_IFLA_EXT_MASK 8859513c3eSOphir Munk #define IFLA_EXT_MASK 29 8959513c3eSOphir Munk #endif 9059513c3eSOphir Munk #ifndef HAVE_IFLA_PHYS_SWITCH_ID 9159513c3eSOphir Munk #define IFLA_PHYS_SWITCH_ID 36 9259513c3eSOphir Munk #endif 9359513c3eSOphir Munk #ifndef HAVE_IFLA_PHYS_PORT_NAME 9459513c3eSOphir Munk #define IFLA_PHYS_PORT_NAME 38 9559513c3eSOphir Munk #endif 9659513c3eSOphir Munk 9759513c3eSOphir Munk /* 9859513c3eSOphir Munk * Some Devlink defines may be missed in old kernel versions, 9959513c3eSOphir Munk * adjust used defines. 10059513c3eSOphir Munk */ 10159513c3eSOphir Munk #ifndef DEVLINK_GENL_NAME 10259513c3eSOphir Munk #define DEVLINK_GENL_NAME "devlink" 10359513c3eSOphir Munk #endif 10459513c3eSOphir Munk #ifndef DEVLINK_GENL_VERSION 10559513c3eSOphir Munk #define DEVLINK_GENL_VERSION 1 10659513c3eSOphir Munk #endif 10759513c3eSOphir Munk #ifndef DEVLINK_ATTR_BUS_NAME 10859513c3eSOphir Munk #define DEVLINK_ATTR_BUS_NAME 1 10959513c3eSOphir Munk #endif 11059513c3eSOphir Munk #ifndef DEVLINK_ATTR_DEV_NAME 11159513c3eSOphir Munk #define DEVLINK_ATTR_DEV_NAME 2 11259513c3eSOphir Munk #endif 11359513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM 11459513c3eSOphir Munk #define DEVLINK_ATTR_PARAM 80 11559513c3eSOphir Munk #endif 11659513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_NAME 11759513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_NAME 81 11859513c3eSOphir Munk #endif 11959513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_TYPE 12059513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_TYPE 83 12159513c3eSOphir Munk #endif 12259513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUES_LIST 12359513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUES_LIST 84 12459513c3eSOphir Munk #endif 12559513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUE 12659513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUE 85 12759513c3eSOphir Munk #endif 12859513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUE_DATA 12959513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUE_DATA 86 13059513c3eSOphir Munk #endif 13159513c3eSOphir Munk #ifndef DEVLINK_ATTR_PARAM_VALUE_CMODE 13259513c3eSOphir Munk #define DEVLINK_ATTR_PARAM_VALUE_CMODE 87 13359513c3eSOphir Munk #endif 13459513c3eSOphir Munk #ifndef DEVLINK_PARAM_CMODE_DRIVERINIT 13559513c3eSOphir Munk #define DEVLINK_PARAM_CMODE_DRIVERINIT 1 13659513c3eSOphir Munk #endif 13759513c3eSOphir Munk #ifndef DEVLINK_CMD_RELOAD 13859513c3eSOphir Munk #define DEVLINK_CMD_RELOAD 37 13959513c3eSOphir Munk #endif 14059513c3eSOphir Munk #ifndef DEVLINK_CMD_PARAM_GET 14159513c3eSOphir Munk #define DEVLINK_CMD_PARAM_GET 38 14259513c3eSOphir Munk #endif 14359513c3eSOphir Munk #ifndef DEVLINK_CMD_PARAM_SET 14459513c3eSOphir Munk #define DEVLINK_CMD_PARAM_SET 39 14559513c3eSOphir Munk #endif 14659513c3eSOphir Munk #ifndef NLA_FLAG 14759513c3eSOphir Munk #define NLA_FLAG 6 14859513c3eSOphir Munk #endif 14959513c3eSOphir Munk 15059513c3eSOphir Munk /* Add/remove MAC address through Netlink */ 15159513c3eSOphir Munk struct mlx5_nl_mac_addr { 15259513c3eSOphir Munk struct rte_ether_addr (*mac)[]; 15359513c3eSOphir Munk /**< MAC address handled by the device. */ 15459513c3eSOphir Munk int mac_n; /**< Number of addresses in the array. */ 15559513c3eSOphir Munk }; 15659513c3eSOphir Munk 15759513c3eSOphir Munk #define MLX5_NL_CMD_GET_IB_NAME (1 << 0) 15859513c3eSOphir Munk #define MLX5_NL_CMD_GET_IB_INDEX (1 << 1) 15959513c3eSOphir Munk #define MLX5_NL_CMD_GET_NET_INDEX (1 << 2) 16059513c3eSOphir Munk #define MLX5_NL_CMD_GET_PORT_INDEX (1 << 3) 16159513c3eSOphir Munk 16259513c3eSOphir Munk /** Data structure used by mlx5_nl_cmdget_cb(). */ 16359513c3eSOphir Munk struct mlx5_nl_ifindex_data { 16459513c3eSOphir Munk const char *name; /**< IB device name (in). */ 16559513c3eSOphir Munk uint32_t flags; /**< found attribute flags (out). */ 16659513c3eSOphir Munk uint32_t ibindex; /**< IB device index (out). */ 16759513c3eSOphir Munk uint32_t ifindex; /**< Network interface index (out). */ 16859513c3eSOphir Munk uint32_t portnum; /**< IB device max port number (out). */ 16959513c3eSOphir Munk }; 17059513c3eSOphir Munk 171*10a5fa20SAlexander Kozyrev uint32_t atomic_sn; 17259513c3eSOphir Munk 17359513c3eSOphir Munk /* Generate Netlink sequence number. */ 174*10a5fa20SAlexander Kozyrev #define MLX5_NL_SN_GENERATE __atomic_add_fetch(&atomic_sn, 1, __ATOMIC_RELAXED) 17559513c3eSOphir Munk 17659513c3eSOphir Munk /** 17759513c3eSOphir Munk * Opens a Netlink socket. 17859513c3eSOphir Munk * 17959513c3eSOphir Munk * @param protocol 18059513c3eSOphir Munk * Netlink protocol (e.g. NETLINK_ROUTE, NETLINK_RDMA). 18159513c3eSOphir Munk * 18259513c3eSOphir Munk * @return 18359513c3eSOphir Munk * A file descriptor on success, a negative errno value otherwise and 18459513c3eSOphir Munk * rte_errno is set. 18559513c3eSOphir Munk */ 18659513c3eSOphir Munk int 18759513c3eSOphir Munk mlx5_nl_init(int protocol) 18859513c3eSOphir Munk { 18959513c3eSOphir Munk int fd; 19059513c3eSOphir Munk int sndbuf_size = MLX5_SEND_BUF_SIZE; 19159513c3eSOphir Munk int rcvbuf_size = MLX5_RECV_BUF_SIZE; 19259513c3eSOphir Munk struct sockaddr_nl local = { 19359513c3eSOphir Munk .nl_family = AF_NETLINK, 19459513c3eSOphir Munk }; 19559513c3eSOphir Munk int ret; 19659513c3eSOphir Munk 19759513c3eSOphir Munk fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, protocol); 19859513c3eSOphir Munk if (fd == -1) { 19959513c3eSOphir Munk rte_errno = errno; 20059513c3eSOphir Munk return -rte_errno; 20159513c3eSOphir Munk } 20259513c3eSOphir Munk ret = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, sizeof(int)); 20359513c3eSOphir Munk if (ret == -1) { 20459513c3eSOphir Munk rte_errno = errno; 20559513c3eSOphir Munk goto error; 20659513c3eSOphir Munk } 20759513c3eSOphir Munk ret = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, sizeof(int)); 20859513c3eSOphir Munk if (ret == -1) { 20959513c3eSOphir Munk rte_errno = errno; 21059513c3eSOphir Munk goto error; 21159513c3eSOphir Munk } 21259513c3eSOphir Munk ret = bind(fd, (struct sockaddr *)&local, sizeof(local)); 21359513c3eSOphir Munk if (ret == -1) { 21459513c3eSOphir Munk rte_errno = errno; 21559513c3eSOphir Munk goto error; 21659513c3eSOphir Munk } 21759513c3eSOphir Munk return fd; 21859513c3eSOphir Munk error: 21959513c3eSOphir Munk close(fd); 22059513c3eSOphir Munk return -rte_errno; 22159513c3eSOphir Munk } 22259513c3eSOphir Munk 22359513c3eSOphir Munk /** 22459513c3eSOphir Munk * Send a request message to the kernel on the Netlink socket. 22559513c3eSOphir Munk * 22659513c3eSOphir Munk * @param[in] nlsk_fd 22759513c3eSOphir Munk * Netlink socket file descriptor. 22859513c3eSOphir Munk * @param[in] nh 22959513c3eSOphir Munk * The Netlink message send to the kernel. 23059513c3eSOphir Munk * @param[in] ssn 23159513c3eSOphir Munk * Sequence number. 23259513c3eSOphir Munk * @param[in] req 23359513c3eSOphir Munk * Pointer to the request structure. 23459513c3eSOphir Munk * @param[in] len 23559513c3eSOphir Munk * Length of the request in bytes. 23659513c3eSOphir Munk * 23759513c3eSOphir Munk * @return 23859513c3eSOphir Munk * The number of sent bytes on success, a negative errno value otherwise and 23959513c3eSOphir Munk * rte_errno is set. 24059513c3eSOphir Munk */ 24159513c3eSOphir Munk static int 24259513c3eSOphir Munk mlx5_nl_request(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn, void *req, 24359513c3eSOphir Munk int len) 24459513c3eSOphir Munk { 24559513c3eSOphir Munk struct sockaddr_nl sa = { 24659513c3eSOphir Munk .nl_family = AF_NETLINK, 24759513c3eSOphir Munk }; 24859513c3eSOphir Munk struct iovec iov[2] = { 24959513c3eSOphir Munk { .iov_base = nh, .iov_len = sizeof(*nh), }, 25059513c3eSOphir Munk { .iov_base = req, .iov_len = len, }, 25159513c3eSOphir Munk }; 25259513c3eSOphir Munk struct msghdr msg = { 25359513c3eSOphir Munk .msg_name = &sa, 25459513c3eSOphir Munk .msg_namelen = sizeof(sa), 25559513c3eSOphir Munk .msg_iov = iov, 25659513c3eSOphir Munk .msg_iovlen = 2, 25759513c3eSOphir Munk }; 25859513c3eSOphir Munk int send_bytes; 25959513c3eSOphir Munk 26059513c3eSOphir Munk nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */ 26159513c3eSOphir Munk nh->nlmsg_seq = sn; 26259513c3eSOphir Munk send_bytes = sendmsg(nlsk_fd, &msg, 0); 26359513c3eSOphir Munk if (send_bytes < 0) { 26459513c3eSOphir Munk rte_errno = errno; 26559513c3eSOphir Munk return -rte_errno; 26659513c3eSOphir Munk } 26759513c3eSOphir Munk return send_bytes; 26859513c3eSOphir Munk } 26959513c3eSOphir Munk 27059513c3eSOphir Munk /** 27159513c3eSOphir Munk * Send a message to the kernel on the Netlink socket. 27259513c3eSOphir Munk * 27359513c3eSOphir Munk * @param[in] nlsk_fd 27459513c3eSOphir Munk * The Netlink socket file descriptor used for communication. 27559513c3eSOphir Munk * @param[in] nh 27659513c3eSOphir Munk * The Netlink message send to the kernel. 27759513c3eSOphir Munk * @param[in] sn 27859513c3eSOphir Munk * Sequence number. 27959513c3eSOphir Munk * 28059513c3eSOphir Munk * @return 28159513c3eSOphir Munk * The number of sent bytes on success, a negative errno value otherwise and 28259513c3eSOphir Munk * rte_errno is set. 28359513c3eSOphir Munk */ 28459513c3eSOphir Munk static int 28559513c3eSOphir Munk mlx5_nl_send(int nlsk_fd, struct nlmsghdr *nh, uint32_t sn) 28659513c3eSOphir Munk { 28759513c3eSOphir Munk struct sockaddr_nl sa = { 28859513c3eSOphir Munk .nl_family = AF_NETLINK, 28959513c3eSOphir Munk }; 29059513c3eSOphir Munk struct iovec iov = { 29159513c3eSOphir Munk .iov_base = nh, 29259513c3eSOphir Munk .iov_len = nh->nlmsg_len, 29359513c3eSOphir Munk }; 29459513c3eSOphir Munk struct msghdr msg = { 29559513c3eSOphir Munk .msg_name = &sa, 29659513c3eSOphir Munk .msg_namelen = sizeof(sa), 29759513c3eSOphir Munk .msg_iov = &iov, 29859513c3eSOphir Munk .msg_iovlen = 1, 29959513c3eSOphir Munk }; 30059513c3eSOphir Munk int send_bytes; 30159513c3eSOphir Munk 30259513c3eSOphir Munk nh->nlmsg_pid = 0; /* communication with the kernel uses pid 0 */ 30359513c3eSOphir Munk nh->nlmsg_seq = sn; 30459513c3eSOphir Munk send_bytes = sendmsg(nlsk_fd, &msg, 0); 30559513c3eSOphir Munk if (send_bytes < 0) { 30659513c3eSOphir Munk rte_errno = errno; 30759513c3eSOphir Munk return -rte_errno; 30859513c3eSOphir Munk } 30959513c3eSOphir Munk return send_bytes; 31059513c3eSOphir Munk } 31159513c3eSOphir Munk 31259513c3eSOphir Munk /** 31359513c3eSOphir Munk * Receive a message from the kernel on the Netlink socket, following 31459513c3eSOphir Munk * mlx5_nl_send(). 31559513c3eSOphir Munk * 31659513c3eSOphir Munk * @param[in] nlsk_fd 31759513c3eSOphir Munk * The Netlink socket file descriptor used for communication. 31859513c3eSOphir Munk * @param[in] sn 31959513c3eSOphir Munk * Sequence number. 32059513c3eSOphir Munk * @param[in] cb 32159513c3eSOphir Munk * The callback function to call for each Netlink message received. 32259513c3eSOphir Munk * @param[in, out] arg 32359513c3eSOphir Munk * Custom arguments for the callback. 32459513c3eSOphir Munk * 32559513c3eSOphir Munk * @return 32659513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 32759513c3eSOphir Munk */ 32859513c3eSOphir Munk static int 32959513c3eSOphir Munk mlx5_nl_recv(int nlsk_fd, uint32_t sn, int (*cb)(struct nlmsghdr *, void *arg), 33059513c3eSOphir Munk void *arg) 33159513c3eSOphir Munk { 33259513c3eSOphir Munk struct sockaddr_nl sa; 33366914d19SSuanming Mou void *buf = mlx5_malloc(0, MLX5_RECV_BUF_SIZE, 0, SOCKET_ID_ANY); 33459513c3eSOphir Munk struct iovec iov = { 33559513c3eSOphir Munk .iov_base = buf, 33659513c3eSOphir Munk .iov_len = MLX5_RECV_BUF_SIZE, 33759513c3eSOphir Munk }; 33859513c3eSOphir Munk struct msghdr msg = { 33959513c3eSOphir Munk .msg_name = &sa, 34059513c3eSOphir Munk .msg_namelen = sizeof(sa), 34159513c3eSOphir Munk .msg_iov = &iov, 34259513c3eSOphir Munk /* One message at a time */ 34359513c3eSOphir Munk .msg_iovlen = 1, 34459513c3eSOphir Munk }; 34559513c3eSOphir Munk int multipart = 0; 34659513c3eSOphir Munk int ret = 0; 34759513c3eSOphir Munk 34859513c3eSOphir Munk if (!buf) { 34959513c3eSOphir Munk rte_errno = ENOMEM; 35059513c3eSOphir Munk return -rte_errno; 35159513c3eSOphir Munk } 35259513c3eSOphir Munk do { 35359513c3eSOphir Munk struct nlmsghdr *nh; 35459513c3eSOphir Munk int recv_bytes = 0; 35559513c3eSOphir Munk 35659513c3eSOphir Munk do { 35759513c3eSOphir Munk recv_bytes = recvmsg(nlsk_fd, &msg, 0); 35859513c3eSOphir Munk if (recv_bytes == -1) { 35959513c3eSOphir Munk rte_errno = errno; 36059513c3eSOphir Munk ret = -rte_errno; 36159513c3eSOphir Munk goto exit; 36259513c3eSOphir Munk } 36359513c3eSOphir Munk nh = (struct nlmsghdr *)buf; 36459513c3eSOphir Munk } while (nh->nlmsg_seq != sn); 36559513c3eSOphir Munk for (; 36659513c3eSOphir Munk NLMSG_OK(nh, (unsigned int)recv_bytes); 36759513c3eSOphir Munk nh = NLMSG_NEXT(nh, recv_bytes)) { 36859513c3eSOphir Munk if (nh->nlmsg_type == NLMSG_ERROR) { 36959513c3eSOphir Munk struct nlmsgerr *err_data = NLMSG_DATA(nh); 37059513c3eSOphir Munk 37159513c3eSOphir Munk if (err_data->error < 0) { 37259513c3eSOphir Munk rte_errno = -err_data->error; 37359513c3eSOphir Munk ret = -rte_errno; 37459513c3eSOphir Munk goto exit; 37559513c3eSOphir Munk } 37659513c3eSOphir Munk /* Ack message. */ 37759513c3eSOphir Munk ret = 0; 37859513c3eSOphir Munk goto exit; 37959513c3eSOphir Munk } 38059513c3eSOphir Munk /* Multi-part msgs and their trailing DONE message. */ 38159513c3eSOphir Munk if (nh->nlmsg_flags & NLM_F_MULTI) { 38259513c3eSOphir Munk if (nh->nlmsg_type == NLMSG_DONE) { 38359513c3eSOphir Munk ret = 0; 38459513c3eSOphir Munk goto exit; 38559513c3eSOphir Munk } 38659513c3eSOphir Munk multipart = 1; 38759513c3eSOphir Munk } 38859513c3eSOphir Munk if (cb) { 38959513c3eSOphir Munk ret = cb(nh, arg); 39059513c3eSOphir Munk if (ret < 0) 39159513c3eSOphir Munk goto exit; 39259513c3eSOphir Munk } 39359513c3eSOphir Munk } 39459513c3eSOphir Munk } while (multipart); 39559513c3eSOphir Munk exit: 39666914d19SSuanming Mou mlx5_free(buf); 39759513c3eSOphir Munk return ret; 39859513c3eSOphir Munk } 39959513c3eSOphir Munk 40059513c3eSOphir Munk /** 40159513c3eSOphir Munk * Parse Netlink message to retrieve the bridge MAC address. 40259513c3eSOphir Munk * 40359513c3eSOphir Munk * @param nh 40459513c3eSOphir Munk * Pointer to Netlink Message Header. 40559513c3eSOphir Munk * @param arg 40659513c3eSOphir Munk * PMD data register with this callback. 40759513c3eSOphir Munk * 40859513c3eSOphir Munk * @return 40959513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 41059513c3eSOphir Munk */ 41159513c3eSOphir Munk static int 41259513c3eSOphir Munk mlx5_nl_mac_addr_cb(struct nlmsghdr *nh, void *arg) 41359513c3eSOphir Munk { 41459513c3eSOphir Munk struct mlx5_nl_mac_addr *data = arg; 41559513c3eSOphir Munk struct ndmsg *r = NLMSG_DATA(nh); 41659513c3eSOphir Munk struct rtattr *attribute; 41759513c3eSOphir Munk int len; 41859513c3eSOphir Munk 41959513c3eSOphir Munk len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*r)); 42059513c3eSOphir Munk for (attribute = MLX5_NDA_RTA(r); 42159513c3eSOphir Munk RTA_OK(attribute, len); 42259513c3eSOphir Munk attribute = RTA_NEXT(attribute, len)) { 42359513c3eSOphir Munk if (attribute->rta_type == NDA_LLADDR) { 42459513c3eSOphir Munk if (data->mac_n == MLX5_MAX_MAC_ADDRESSES) { 42559513c3eSOphir Munk DRV_LOG(WARNING, 42659513c3eSOphir Munk "not enough room to finalize the" 42759513c3eSOphir Munk " request"); 42859513c3eSOphir Munk rte_errno = ENOMEM; 42959513c3eSOphir Munk return -rte_errno; 43059513c3eSOphir Munk } 43159513c3eSOphir Munk #ifdef RTE_LIBRTE_MLX5_DEBUG 43259513c3eSOphir Munk char m[RTE_ETHER_ADDR_FMT_SIZE]; 43359513c3eSOphir Munk 43459513c3eSOphir Munk rte_ether_format_addr(m, RTE_ETHER_ADDR_FMT_SIZE, 43559513c3eSOphir Munk RTA_DATA(attribute)); 43659513c3eSOphir Munk DRV_LOG(DEBUG, "bridge MAC address %s", m); 43759513c3eSOphir Munk #endif 43859513c3eSOphir Munk memcpy(&(*data->mac)[data->mac_n++], 43959513c3eSOphir Munk RTA_DATA(attribute), RTE_ETHER_ADDR_LEN); 44059513c3eSOphir Munk } 44159513c3eSOphir Munk } 44259513c3eSOphir Munk return 0; 44359513c3eSOphir Munk } 44459513c3eSOphir Munk 44559513c3eSOphir Munk /** 44659513c3eSOphir Munk * Get bridge MAC addresses. 44759513c3eSOphir Munk * 44859513c3eSOphir Munk * @param[in] nlsk_fd 44959513c3eSOphir Munk * Netlink socket file descriptor. 45059513c3eSOphir Munk * @param[in] iface_idx 45159513c3eSOphir Munk * Net device interface index. 45259513c3eSOphir Munk * @param mac[out] 45359513c3eSOphir Munk * Pointer to the array table of MAC addresses to fill. 45459513c3eSOphir Munk * Its size should be of MLX5_MAX_MAC_ADDRESSES. 45559513c3eSOphir Munk * @param mac_n[out] 45659513c3eSOphir Munk * Number of entries filled in MAC array. 45759513c3eSOphir Munk * 45859513c3eSOphir Munk * @return 45959513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 46059513c3eSOphir Munk */ 46159513c3eSOphir Munk static int 46259513c3eSOphir Munk mlx5_nl_mac_addr_list(int nlsk_fd, unsigned int iface_idx, 46359513c3eSOphir Munk struct rte_ether_addr (*mac)[], int *mac_n) 46459513c3eSOphir Munk { 46559513c3eSOphir Munk struct { 46659513c3eSOphir Munk struct nlmsghdr hdr; 46759513c3eSOphir Munk struct ifinfomsg ifm; 46859513c3eSOphir Munk } req = { 46959513c3eSOphir Munk .hdr = { 47059513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), 47159513c3eSOphir Munk .nlmsg_type = RTM_GETNEIGH, 47259513c3eSOphir Munk .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, 47359513c3eSOphir Munk }, 47459513c3eSOphir Munk .ifm = { 47559513c3eSOphir Munk .ifi_family = PF_BRIDGE, 47659513c3eSOphir Munk .ifi_index = iface_idx, 47759513c3eSOphir Munk }, 47859513c3eSOphir Munk }; 47959513c3eSOphir Munk struct mlx5_nl_mac_addr data = { 48059513c3eSOphir Munk .mac = mac, 48159513c3eSOphir Munk .mac_n = 0, 48259513c3eSOphir Munk }; 48359513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 48459513c3eSOphir Munk int ret; 48559513c3eSOphir Munk 48659513c3eSOphir Munk if (nlsk_fd == -1) 48759513c3eSOphir Munk return 0; 48859513c3eSOphir Munk ret = mlx5_nl_request(nlsk_fd, &req.hdr, sn, &req.ifm, 48959513c3eSOphir Munk sizeof(struct ifinfomsg)); 49059513c3eSOphir Munk if (ret < 0) 49159513c3eSOphir Munk goto error; 49259513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_mac_addr_cb, &data); 49359513c3eSOphir Munk if (ret < 0) 49459513c3eSOphir Munk goto error; 49559513c3eSOphir Munk *mac_n = data.mac_n; 49659513c3eSOphir Munk return 0; 49759513c3eSOphir Munk error: 49859513c3eSOphir Munk DRV_LOG(DEBUG, "Interface %u cannot retrieve MAC address list %s", 49959513c3eSOphir Munk iface_idx, strerror(rte_errno)); 50059513c3eSOphir Munk return -rte_errno; 50159513c3eSOphir Munk } 50259513c3eSOphir Munk 50359513c3eSOphir Munk /** 50459513c3eSOphir Munk * Modify the MAC address neighbour table with Netlink. 50559513c3eSOphir Munk * 50659513c3eSOphir Munk * @param[in] nlsk_fd 50759513c3eSOphir Munk * Netlink socket file descriptor. 50859513c3eSOphir Munk * @param[in] iface_idx 50959513c3eSOphir Munk * Net device interface index. 51059513c3eSOphir Munk * @param mac 51159513c3eSOphir Munk * MAC address to consider. 51259513c3eSOphir Munk * @param add 51359513c3eSOphir Munk * 1 to add the MAC address, 0 to remove the MAC address. 51459513c3eSOphir Munk * 51559513c3eSOphir Munk * @return 51659513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 51759513c3eSOphir Munk */ 51859513c3eSOphir Munk static int 51959513c3eSOphir Munk mlx5_nl_mac_addr_modify(int nlsk_fd, unsigned int iface_idx, 52059513c3eSOphir Munk struct rte_ether_addr *mac, int add) 52159513c3eSOphir Munk { 52259513c3eSOphir Munk struct { 52359513c3eSOphir Munk struct nlmsghdr hdr; 52459513c3eSOphir Munk struct ndmsg ndm; 52559513c3eSOphir Munk struct rtattr rta; 52659513c3eSOphir Munk uint8_t buffer[RTE_ETHER_ADDR_LEN]; 52759513c3eSOphir Munk } req = { 52859513c3eSOphir Munk .hdr = { 52959513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)), 53059513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | 53159513c3eSOphir Munk NLM_F_EXCL | NLM_F_ACK, 53259513c3eSOphir Munk .nlmsg_type = add ? RTM_NEWNEIGH : RTM_DELNEIGH, 53359513c3eSOphir Munk }, 53459513c3eSOphir Munk .ndm = { 53559513c3eSOphir Munk .ndm_family = PF_BRIDGE, 53659513c3eSOphir Munk .ndm_state = NUD_NOARP | NUD_PERMANENT, 53759513c3eSOphir Munk .ndm_ifindex = iface_idx, 53859513c3eSOphir Munk .ndm_flags = NTF_SELF, 53959513c3eSOphir Munk }, 54059513c3eSOphir Munk .rta = { 54159513c3eSOphir Munk .rta_type = NDA_LLADDR, 54259513c3eSOphir Munk .rta_len = RTA_LENGTH(RTE_ETHER_ADDR_LEN), 54359513c3eSOphir Munk }, 54459513c3eSOphir Munk }; 54559513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 54659513c3eSOphir Munk int ret; 54759513c3eSOphir Munk 54859513c3eSOphir Munk if (nlsk_fd == -1) 54959513c3eSOphir Munk return 0; 55059513c3eSOphir Munk memcpy(RTA_DATA(&req.rta), mac, RTE_ETHER_ADDR_LEN); 55159513c3eSOphir Munk req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + 55259513c3eSOphir Munk RTA_ALIGN(req.rta.rta_len); 55359513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn); 55459513c3eSOphir Munk if (ret < 0) 55559513c3eSOphir Munk goto error; 55659513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL); 55759513c3eSOphir Munk if (ret < 0) 55859513c3eSOphir Munk goto error; 55959513c3eSOphir Munk return 0; 56059513c3eSOphir Munk error: 56159513c3eSOphir Munk #ifdef RTE_LIBRTE_MLX5_DEBUG 56259513c3eSOphir Munk { 56359513c3eSOphir Munk char m[RTE_ETHER_ADDR_FMT_SIZE]; 56459513c3eSOphir Munk 56559513c3eSOphir Munk rte_ether_format_addr(m, RTE_ETHER_ADDR_FMT_SIZE, mac); 56659513c3eSOphir Munk DRV_LOG(DEBUG, 56759513c3eSOphir Munk "Interface %u cannot %s MAC address %s %s", 56859513c3eSOphir Munk iface_idx, 56959513c3eSOphir Munk add ? "add" : "remove", m, strerror(rte_errno)); 57059513c3eSOphir Munk } 57159513c3eSOphir Munk #endif 57259513c3eSOphir Munk return -rte_errno; 57359513c3eSOphir Munk } 57459513c3eSOphir Munk 57559513c3eSOphir Munk /** 57659513c3eSOphir Munk * Modify the VF MAC address neighbour table with Netlink. 57759513c3eSOphir Munk * 57859513c3eSOphir Munk * @param[in] nlsk_fd 57959513c3eSOphir Munk * Netlink socket file descriptor. 58059513c3eSOphir Munk * @param[in] iface_idx 58159513c3eSOphir Munk * Net device interface index. 58259513c3eSOphir Munk * @param mac 58359513c3eSOphir Munk * MAC address to consider. 58459513c3eSOphir Munk * @param vf_index 58559513c3eSOphir Munk * VF index. 58659513c3eSOphir Munk * 58759513c3eSOphir Munk * @return 58859513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 58959513c3eSOphir Munk */ 59059513c3eSOphir Munk int 59159513c3eSOphir Munk mlx5_nl_vf_mac_addr_modify(int nlsk_fd, unsigned int iface_idx, 59259513c3eSOphir Munk struct rte_ether_addr *mac, int vf_index) 59359513c3eSOphir Munk { 59459513c3eSOphir Munk int ret; 59559513c3eSOphir Munk struct { 59659513c3eSOphir Munk struct nlmsghdr hdr; 59759513c3eSOphir Munk struct ifinfomsg ifm; 59859513c3eSOphir Munk struct rtattr vf_list_rta; 59959513c3eSOphir Munk struct rtattr vf_info_rta; 60059513c3eSOphir Munk struct rtattr vf_mac_rta; 60159513c3eSOphir Munk struct ifla_vf_mac ivm; 60259513c3eSOphir Munk } req = { 60359513c3eSOphir Munk .hdr = { 60459513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), 60559513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 60659513c3eSOphir Munk .nlmsg_type = RTM_BASE, 60759513c3eSOphir Munk }, 60859513c3eSOphir Munk .ifm = { 60959513c3eSOphir Munk .ifi_index = iface_idx, 61059513c3eSOphir Munk }, 61159513c3eSOphir Munk .vf_list_rta = { 61259513c3eSOphir Munk .rta_type = IFLA_VFINFO_LIST, 61359513c3eSOphir Munk .rta_len = RTA_ALIGN(RTA_LENGTH(0)), 61459513c3eSOphir Munk }, 61559513c3eSOphir Munk .vf_info_rta = { 61659513c3eSOphir Munk .rta_type = IFLA_VF_INFO, 61759513c3eSOphir Munk .rta_len = RTA_ALIGN(RTA_LENGTH(0)), 61859513c3eSOphir Munk }, 61959513c3eSOphir Munk .vf_mac_rta = { 62059513c3eSOphir Munk .rta_type = IFLA_VF_MAC, 62159513c3eSOphir Munk }, 62259513c3eSOphir Munk }; 62359513c3eSOphir Munk struct ifla_vf_mac ivm = { 62459513c3eSOphir Munk .vf = vf_index, 62559513c3eSOphir Munk }; 62659513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 62759513c3eSOphir Munk 62859513c3eSOphir Munk memcpy(&ivm.mac, mac, RTE_ETHER_ADDR_LEN); 62959513c3eSOphir Munk memcpy(RTA_DATA(&req.vf_mac_rta), &ivm, sizeof(ivm)); 63059513c3eSOphir Munk 63159513c3eSOphir Munk req.vf_mac_rta.rta_len = RTA_LENGTH(sizeof(ivm)); 63259513c3eSOphir Munk req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + 63359513c3eSOphir Munk RTA_ALIGN(req.vf_list_rta.rta_len) + 63459513c3eSOphir Munk RTA_ALIGN(req.vf_info_rta.rta_len) + 63559513c3eSOphir Munk RTA_ALIGN(req.vf_mac_rta.rta_len); 63659513c3eSOphir Munk req.vf_list_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr), 63759513c3eSOphir Munk &req.vf_list_rta); 63859513c3eSOphir Munk req.vf_info_rta.rta_len = RTE_PTR_DIFF(NLMSG_TAIL(&req.hdr), 63959513c3eSOphir Munk &req.vf_info_rta); 64059513c3eSOphir Munk 64159513c3eSOphir Munk if (nlsk_fd < 0) 64259513c3eSOphir Munk return -1; 64359513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn); 64459513c3eSOphir Munk if (ret < 0) 64559513c3eSOphir Munk goto error; 64659513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL); 64759513c3eSOphir Munk if (ret < 0) 64859513c3eSOphir Munk goto error; 64959513c3eSOphir Munk return 0; 65059513c3eSOphir Munk error: 65159513c3eSOphir Munk DRV_LOG(ERR, 65259513c3eSOphir Munk "representor %u cannot set VF MAC address " 65359513c3eSOphir Munk "%02X:%02X:%02X:%02X:%02X:%02X : %s", 65459513c3eSOphir Munk vf_index, 65559513c3eSOphir Munk mac->addr_bytes[0], mac->addr_bytes[1], 65659513c3eSOphir Munk mac->addr_bytes[2], mac->addr_bytes[3], 65759513c3eSOphir Munk mac->addr_bytes[4], mac->addr_bytes[5], 65859513c3eSOphir Munk strerror(rte_errno)); 65959513c3eSOphir Munk return -rte_errno; 66059513c3eSOphir Munk } 66159513c3eSOphir Munk 66259513c3eSOphir Munk /** 66359513c3eSOphir Munk * Add a MAC address. 66459513c3eSOphir Munk * 66559513c3eSOphir Munk * @param[in] nlsk_fd 66659513c3eSOphir Munk * Netlink socket file descriptor. 66759513c3eSOphir Munk * @param[in] iface_idx 66859513c3eSOphir Munk * Net device interface index. 66959513c3eSOphir Munk * @param mac_own 67059513c3eSOphir Munk * BITFIELD_DECLARE array to store the mac. 67159513c3eSOphir Munk * @param mac 67259513c3eSOphir Munk * MAC address to register. 67359513c3eSOphir Munk * @param index 67459513c3eSOphir Munk * MAC address index. 67559513c3eSOphir Munk * 67659513c3eSOphir Munk * @return 67759513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 67859513c3eSOphir Munk */ 67959513c3eSOphir Munk int 68059513c3eSOphir Munk mlx5_nl_mac_addr_add(int nlsk_fd, unsigned int iface_idx, 68159513c3eSOphir Munk uint64_t *mac_own, struct rte_ether_addr *mac, 68259513c3eSOphir Munk uint32_t index) 68359513c3eSOphir Munk { 68459513c3eSOphir Munk int ret; 68559513c3eSOphir Munk 68659513c3eSOphir Munk ret = mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 1); 68759513c3eSOphir Munk if (!ret) { 68859513c3eSOphir Munk MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES); 68959513c3eSOphir Munk if (index >= MLX5_MAX_MAC_ADDRESSES) 69059513c3eSOphir Munk return -EINVAL; 69159513c3eSOphir Munk 69259513c3eSOphir Munk BITFIELD_SET(mac_own, index); 69359513c3eSOphir Munk } 69459513c3eSOphir Munk if (ret == -EEXIST) 69559513c3eSOphir Munk return 0; 69659513c3eSOphir Munk return ret; 69759513c3eSOphir Munk } 69859513c3eSOphir Munk 69959513c3eSOphir Munk /** 70059513c3eSOphir Munk * Remove a MAC address. 70159513c3eSOphir Munk * 70259513c3eSOphir Munk * @param[in] nlsk_fd 70359513c3eSOphir Munk * Netlink socket file descriptor. 70459513c3eSOphir Munk * @param[in] iface_idx 70559513c3eSOphir Munk * Net device interface index. 70659513c3eSOphir Munk * @param mac_own 70759513c3eSOphir Munk * BITFIELD_DECLARE array to store the mac. 70859513c3eSOphir Munk * @param mac 70959513c3eSOphir Munk * MAC address to remove. 71059513c3eSOphir Munk * @param index 71159513c3eSOphir Munk * MAC address index. 71259513c3eSOphir Munk * 71359513c3eSOphir Munk * @return 71459513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 71559513c3eSOphir Munk */ 71659513c3eSOphir Munk int 71759513c3eSOphir Munk mlx5_nl_mac_addr_remove(int nlsk_fd, unsigned int iface_idx, uint64_t *mac_own, 71859513c3eSOphir Munk struct rte_ether_addr *mac, uint32_t index) 71959513c3eSOphir Munk { 72059513c3eSOphir Munk MLX5_ASSERT(index < MLX5_MAX_MAC_ADDRESSES); 72159513c3eSOphir Munk if (index >= MLX5_MAX_MAC_ADDRESSES) 72259513c3eSOphir Munk return -EINVAL; 72359513c3eSOphir Munk 72459513c3eSOphir Munk BITFIELD_RESET(mac_own, index); 72559513c3eSOphir Munk return mlx5_nl_mac_addr_modify(nlsk_fd, iface_idx, mac, 0); 72659513c3eSOphir Munk } 72759513c3eSOphir Munk 72859513c3eSOphir Munk /** 72959513c3eSOphir Munk * Synchronize Netlink bridge table to the internal table. 73059513c3eSOphir Munk * 73159513c3eSOphir Munk * @param[in] nlsk_fd 73259513c3eSOphir Munk * Netlink socket file descriptor. 73359513c3eSOphir Munk * @param[in] iface_idx 73459513c3eSOphir Munk * Net device interface index. 73559513c3eSOphir Munk * @param mac_addrs 73659513c3eSOphir Munk * Mac addresses array to sync. 73759513c3eSOphir Munk * @param n 73859513c3eSOphir Munk * @p mac_addrs array size. 73959513c3eSOphir Munk */ 74059513c3eSOphir Munk void 74159513c3eSOphir Munk mlx5_nl_mac_addr_sync(int nlsk_fd, unsigned int iface_idx, 74259513c3eSOphir Munk struct rte_ether_addr *mac_addrs, int n) 74359513c3eSOphir Munk { 74459513c3eSOphir Munk struct rte_ether_addr macs[n]; 74559513c3eSOphir Munk int macs_n = 0; 74659513c3eSOphir Munk int i; 74759513c3eSOphir Munk int ret; 74859513c3eSOphir Munk 74959513c3eSOphir Munk ret = mlx5_nl_mac_addr_list(nlsk_fd, iface_idx, &macs, &macs_n); 75059513c3eSOphir Munk if (ret) 75159513c3eSOphir Munk return; 75259513c3eSOphir Munk for (i = 0; i != macs_n; ++i) { 75359513c3eSOphir Munk int j; 75459513c3eSOphir Munk 75559513c3eSOphir Munk /* Verify the address is not in the array yet. */ 75659513c3eSOphir Munk for (j = 0; j != n; ++j) 75759513c3eSOphir Munk if (rte_is_same_ether_addr(&macs[i], &mac_addrs[j])) 75859513c3eSOphir Munk break; 75959513c3eSOphir Munk if (j != n) 76059513c3eSOphir Munk continue; 76159513c3eSOphir Munk /* Find the first entry available. */ 76259513c3eSOphir Munk for (j = 0; j != n; ++j) { 76359513c3eSOphir Munk if (rte_is_zero_ether_addr(&mac_addrs[j])) { 76459513c3eSOphir Munk mac_addrs[j] = macs[i]; 76559513c3eSOphir Munk break; 76659513c3eSOphir Munk } 76759513c3eSOphir Munk } 76859513c3eSOphir Munk } 76959513c3eSOphir Munk } 77059513c3eSOphir Munk 77159513c3eSOphir Munk /** 77259513c3eSOphir Munk * Flush all added MAC addresses. 77359513c3eSOphir Munk * 77459513c3eSOphir Munk * @param[in] nlsk_fd 77559513c3eSOphir Munk * Netlink socket file descriptor. 77659513c3eSOphir Munk * @param[in] iface_idx 77759513c3eSOphir Munk * Net device interface index. 77859513c3eSOphir Munk * @param[in] mac_addrs 77959513c3eSOphir Munk * Mac addresses array to flush. 78059513c3eSOphir Munk * @param n 78159513c3eSOphir Munk * @p mac_addrs array size. 78259513c3eSOphir Munk * @param mac_own 78359513c3eSOphir Munk * BITFIELD_DECLARE array to store the mac. 78459513c3eSOphir Munk */ 78559513c3eSOphir Munk void 78659513c3eSOphir Munk mlx5_nl_mac_addr_flush(int nlsk_fd, unsigned int iface_idx, 78759513c3eSOphir Munk struct rte_ether_addr *mac_addrs, int n, 78859513c3eSOphir Munk uint64_t *mac_own) 78959513c3eSOphir Munk { 79059513c3eSOphir Munk int i; 79159513c3eSOphir Munk 7924a01fa04SShiri Kuzin if (n <= 0 || n > MLX5_MAX_MAC_ADDRESSES) 79359513c3eSOphir Munk return; 79459513c3eSOphir Munk 79559513c3eSOphir Munk for (i = n - 1; i >= 0; --i) { 79659513c3eSOphir Munk struct rte_ether_addr *m = &mac_addrs[i]; 79759513c3eSOphir Munk 79859513c3eSOphir Munk if (BITFIELD_ISSET(mac_own, i)) 79959513c3eSOphir Munk mlx5_nl_mac_addr_remove(nlsk_fd, iface_idx, mac_own, m, 80059513c3eSOphir Munk i); 80159513c3eSOphir Munk } 80259513c3eSOphir Munk } 80359513c3eSOphir Munk 80459513c3eSOphir Munk /** 80559513c3eSOphir Munk * Enable promiscuous / all multicast mode through Netlink. 80659513c3eSOphir Munk * 80759513c3eSOphir Munk * @param[in] nlsk_fd 80859513c3eSOphir Munk * Netlink socket file descriptor. 80959513c3eSOphir Munk * @param[in] iface_idx 81059513c3eSOphir Munk * Net device interface index. 81159513c3eSOphir Munk * @param flags 81259513c3eSOphir Munk * IFF_PROMISC for promiscuous, IFF_ALLMULTI for allmulti. 81359513c3eSOphir Munk * @param enable 81459513c3eSOphir Munk * Nonzero to enable, disable otherwise. 81559513c3eSOphir Munk * 81659513c3eSOphir Munk * @return 81759513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 81859513c3eSOphir Munk */ 81959513c3eSOphir Munk static int 82059513c3eSOphir Munk mlx5_nl_device_flags(int nlsk_fd, unsigned int iface_idx, uint32_t flags, 82159513c3eSOphir Munk int enable) 82259513c3eSOphir Munk { 82359513c3eSOphir Munk struct { 82459513c3eSOphir Munk struct nlmsghdr hdr; 82559513c3eSOphir Munk struct ifinfomsg ifi; 82659513c3eSOphir Munk } req = { 82759513c3eSOphir Munk .hdr = { 82859513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), 82959513c3eSOphir Munk .nlmsg_type = RTM_NEWLINK, 83059513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST, 83159513c3eSOphir Munk }, 83259513c3eSOphir Munk .ifi = { 83359513c3eSOphir Munk .ifi_flags = enable ? flags : 0, 83459513c3eSOphir Munk .ifi_change = flags, 83559513c3eSOphir Munk .ifi_index = iface_idx, 83659513c3eSOphir Munk }, 83759513c3eSOphir Munk }; 83859513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 83959513c3eSOphir Munk int ret; 84059513c3eSOphir Munk 84159513c3eSOphir Munk MLX5_ASSERT(!(flags & ~(IFF_PROMISC | IFF_ALLMULTI))); 84259513c3eSOphir Munk if (nlsk_fd < 0) 84359513c3eSOphir Munk return 0; 84459513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, &req.hdr, sn); 84559513c3eSOphir Munk if (ret < 0) 84659513c3eSOphir Munk return ret; 84759513c3eSOphir Munk return 0; 84859513c3eSOphir Munk } 84959513c3eSOphir Munk 85059513c3eSOphir Munk /** 85159513c3eSOphir Munk * Enable promiscuous mode through Netlink. 85259513c3eSOphir Munk * 85359513c3eSOphir Munk * @param[in] nlsk_fd 85459513c3eSOphir Munk * Netlink socket file descriptor. 85559513c3eSOphir Munk * @param[in] iface_idx 85659513c3eSOphir Munk * Net device interface index. 85759513c3eSOphir Munk * @param enable 85859513c3eSOphir Munk * Nonzero to enable, disable otherwise. 85959513c3eSOphir Munk * 86059513c3eSOphir Munk * @return 86159513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 86259513c3eSOphir Munk */ 86359513c3eSOphir Munk int 86459513c3eSOphir Munk mlx5_nl_promisc(int nlsk_fd, unsigned int iface_idx, int enable) 86559513c3eSOphir Munk { 86659513c3eSOphir Munk int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_PROMISC, enable); 86759513c3eSOphir Munk 86859513c3eSOphir Munk if (ret) 86959513c3eSOphir Munk DRV_LOG(DEBUG, 87059513c3eSOphir Munk "Interface %u cannot %s promisc mode: Netlink error %s", 87159513c3eSOphir Munk iface_idx, enable ? "enable" : "disable", 87259513c3eSOphir Munk strerror(rte_errno)); 87359513c3eSOphir Munk return ret; 87459513c3eSOphir Munk } 87559513c3eSOphir Munk 87659513c3eSOphir Munk /** 87759513c3eSOphir Munk * Enable all multicast mode through Netlink. 87859513c3eSOphir Munk * 87959513c3eSOphir Munk * @param[in] nlsk_fd 88059513c3eSOphir Munk * Netlink socket file descriptor. 88159513c3eSOphir Munk * @param[in] iface_idx 88259513c3eSOphir Munk * Net device interface index. 88359513c3eSOphir Munk * @param enable 88459513c3eSOphir Munk * Nonzero to enable, disable otherwise. 88559513c3eSOphir Munk * 88659513c3eSOphir Munk * @return 88759513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 88859513c3eSOphir Munk */ 88959513c3eSOphir Munk int 89059513c3eSOphir Munk mlx5_nl_allmulti(int nlsk_fd, unsigned int iface_idx, int enable) 89159513c3eSOphir Munk { 89259513c3eSOphir Munk int ret = mlx5_nl_device_flags(nlsk_fd, iface_idx, IFF_ALLMULTI, 89359513c3eSOphir Munk enable); 89459513c3eSOphir Munk 89559513c3eSOphir Munk if (ret) 89659513c3eSOphir Munk DRV_LOG(DEBUG, 89759513c3eSOphir Munk "Interface %u cannot %s allmulti : Netlink error %s", 89859513c3eSOphir Munk iface_idx, enable ? "enable" : "disable", 89959513c3eSOphir Munk strerror(rte_errno)); 90059513c3eSOphir Munk return ret; 90159513c3eSOphir Munk } 90259513c3eSOphir Munk 90359513c3eSOphir Munk /** 90459513c3eSOphir Munk * Process network interface information from Netlink message. 90559513c3eSOphir Munk * 90659513c3eSOphir Munk * @param nh 90759513c3eSOphir Munk * Pointer to Netlink message header. 90859513c3eSOphir Munk * @param arg 90959513c3eSOphir Munk * Opaque data pointer for this callback. 91059513c3eSOphir Munk * 91159513c3eSOphir Munk * @return 91259513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 91359513c3eSOphir Munk */ 91459513c3eSOphir Munk static int 91559513c3eSOphir Munk mlx5_nl_cmdget_cb(struct nlmsghdr *nh, void *arg) 91659513c3eSOphir Munk { 91759513c3eSOphir Munk struct mlx5_nl_ifindex_data *data = arg; 91859513c3eSOphir Munk struct mlx5_nl_ifindex_data local = { 91959513c3eSOphir Munk .flags = 0, 92059513c3eSOphir Munk }; 92159513c3eSOphir Munk size_t off = NLMSG_HDRLEN; 92259513c3eSOphir Munk 92359513c3eSOphir Munk if (nh->nlmsg_type != 92459513c3eSOphir Munk RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_GET) && 92559513c3eSOphir Munk nh->nlmsg_type != 92659513c3eSOphir Munk RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, RDMA_NLDEV_CMD_PORT_GET)) 92759513c3eSOphir Munk goto error; 92859513c3eSOphir Munk while (off < nh->nlmsg_len) { 92959513c3eSOphir Munk struct nlattr *na = (void *)((uintptr_t)nh + off); 93059513c3eSOphir Munk void *payload = (void *)((uintptr_t)na + NLA_HDRLEN); 93159513c3eSOphir Munk 93259513c3eSOphir Munk if (na->nla_len > nh->nlmsg_len - off) 93359513c3eSOphir Munk goto error; 93459513c3eSOphir Munk switch (na->nla_type) { 93559513c3eSOphir Munk case RDMA_NLDEV_ATTR_DEV_INDEX: 93659513c3eSOphir Munk local.ibindex = *(uint32_t *)payload; 93759513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_IB_INDEX; 93859513c3eSOphir Munk break; 93959513c3eSOphir Munk case RDMA_NLDEV_ATTR_DEV_NAME: 94059513c3eSOphir Munk if (!strcmp(payload, data->name)) 94159513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_IB_NAME; 94259513c3eSOphir Munk break; 94359513c3eSOphir Munk case RDMA_NLDEV_ATTR_NDEV_INDEX: 94459513c3eSOphir Munk local.ifindex = *(uint32_t *)payload; 94559513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_NET_INDEX; 94659513c3eSOphir Munk break; 94759513c3eSOphir Munk case RDMA_NLDEV_ATTR_PORT_INDEX: 94859513c3eSOphir Munk local.portnum = *(uint32_t *)payload; 94959513c3eSOphir Munk local.flags |= MLX5_NL_CMD_GET_PORT_INDEX; 95059513c3eSOphir Munk break; 95159513c3eSOphir Munk default: 95259513c3eSOphir Munk break; 95359513c3eSOphir Munk } 95459513c3eSOphir Munk off += NLA_ALIGN(na->nla_len); 95559513c3eSOphir Munk } 95659513c3eSOphir Munk /* 95759513c3eSOphir Munk * It is possible to have multiple messages for all 95859513c3eSOphir Munk * Infiniband devices in the system with appropriate name. 95959513c3eSOphir Munk * So we should gather parameters locally and copy to 96059513c3eSOphir Munk * query context only in case of coinciding device name. 96159513c3eSOphir Munk */ 96259513c3eSOphir Munk if (local.flags & MLX5_NL_CMD_GET_IB_NAME) { 96359513c3eSOphir Munk data->flags = local.flags; 96459513c3eSOphir Munk data->ibindex = local.ibindex; 96559513c3eSOphir Munk data->ifindex = local.ifindex; 96659513c3eSOphir Munk data->portnum = local.portnum; 96759513c3eSOphir Munk } 96859513c3eSOphir Munk return 0; 96959513c3eSOphir Munk error: 97059513c3eSOphir Munk rte_errno = EINVAL; 97159513c3eSOphir Munk return -rte_errno; 97259513c3eSOphir Munk } 97359513c3eSOphir Munk 97459513c3eSOphir Munk /** 97559513c3eSOphir Munk * Get index of network interface associated with some IB device. 97659513c3eSOphir Munk * 97759513c3eSOphir Munk * This is the only somewhat safe method to avoid resorting to heuristics 97859513c3eSOphir Munk * when faced with port representors. Unfortunately it requires at least 97959513c3eSOphir Munk * Linux 4.17. 98059513c3eSOphir Munk * 98159513c3eSOphir Munk * @param nl 98259513c3eSOphir Munk * Netlink socket of the RDMA kind (NETLINK_RDMA). 98359513c3eSOphir Munk * @param[in] name 98459513c3eSOphir Munk * IB device name. 98559513c3eSOphir Munk * @param[in] pindex 98659513c3eSOphir Munk * IB device port index, starting from 1 98759513c3eSOphir Munk * @return 98859513c3eSOphir Munk * A valid (nonzero) interface index on success, 0 otherwise and rte_errno 98959513c3eSOphir Munk * is set. 99059513c3eSOphir Munk */ 99159513c3eSOphir Munk unsigned int 99259513c3eSOphir Munk mlx5_nl_ifindex(int nl, const char *name, uint32_t pindex) 99359513c3eSOphir Munk { 99459513c3eSOphir Munk struct mlx5_nl_ifindex_data data = { 99559513c3eSOphir Munk .name = name, 99659513c3eSOphir Munk .flags = 0, 99759513c3eSOphir Munk .ibindex = 0, /* Determined during first pass. */ 99859513c3eSOphir Munk .ifindex = 0, /* Determined during second pass. */ 99959513c3eSOphir Munk }; 100059513c3eSOphir Munk union { 100159513c3eSOphir Munk struct nlmsghdr nh; 100259513c3eSOphir Munk uint8_t buf[NLMSG_HDRLEN + 100359513c3eSOphir Munk NLA_HDRLEN + NLA_ALIGN(sizeof(data.ibindex)) + 100459513c3eSOphir Munk NLA_HDRLEN + NLA_ALIGN(sizeof(pindex))]; 100559513c3eSOphir Munk } req = { 100659513c3eSOphir Munk .nh = { 100759513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(0), 100859513c3eSOphir Munk .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 100959513c3eSOphir Munk RDMA_NLDEV_CMD_GET), 101059513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, 101159513c3eSOphir Munk }, 101259513c3eSOphir Munk }; 101359513c3eSOphir Munk struct nlattr *na; 101459513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 101559513c3eSOphir Munk int ret; 101659513c3eSOphir Munk 101759513c3eSOphir Munk ret = mlx5_nl_send(nl, &req.nh, sn); 101859513c3eSOphir Munk if (ret < 0) 101959513c3eSOphir Munk return 0; 102059513c3eSOphir Munk ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data); 102159513c3eSOphir Munk if (ret < 0) 102259513c3eSOphir Munk return 0; 102359513c3eSOphir Munk if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) || 102459513c3eSOphir Munk !(data.flags & MLX5_NL_CMD_GET_IB_INDEX)) 102559513c3eSOphir Munk goto error; 102659513c3eSOphir Munk data.flags = 0; 102759513c3eSOphir Munk sn = MLX5_NL_SN_GENERATE; 102859513c3eSOphir Munk req.nh.nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 102959513c3eSOphir Munk RDMA_NLDEV_CMD_PORT_GET); 103059513c3eSOphir Munk req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 103159513c3eSOphir Munk req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.buf) - NLMSG_HDRLEN); 103259513c3eSOphir Munk na = (void *)((uintptr_t)req.buf + NLMSG_HDRLEN); 103359513c3eSOphir Munk na->nla_len = NLA_HDRLEN + sizeof(data.ibindex); 103459513c3eSOphir Munk na->nla_type = RDMA_NLDEV_ATTR_DEV_INDEX; 103559513c3eSOphir Munk memcpy((void *)((uintptr_t)na + NLA_HDRLEN), 103659513c3eSOphir Munk &data.ibindex, sizeof(data.ibindex)); 103759513c3eSOphir Munk na = (void *)((uintptr_t)na + NLA_ALIGN(na->nla_len)); 103859513c3eSOphir Munk na->nla_len = NLA_HDRLEN + sizeof(pindex); 103959513c3eSOphir Munk na->nla_type = RDMA_NLDEV_ATTR_PORT_INDEX; 104059513c3eSOphir Munk memcpy((void *)((uintptr_t)na + NLA_HDRLEN), 104159513c3eSOphir Munk &pindex, sizeof(pindex)); 104259513c3eSOphir Munk ret = mlx5_nl_send(nl, &req.nh, sn); 104359513c3eSOphir Munk if (ret < 0) 104459513c3eSOphir Munk return 0; 104559513c3eSOphir Munk ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data); 104659513c3eSOphir Munk if (ret < 0) 104759513c3eSOphir Munk return 0; 104859513c3eSOphir Munk if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) || 104959513c3eSOphir Munk !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) || 105059513c3eSOphir Munk !(data.flags & MLX5_NL_CMD_GET_NET_INDEX) || 105159513c3eSOphir Munk !data.ifindex) 105259513c3eSOphir Munk goto error; 105359513c3eSOphir Munk return data.ifindex; 105459513c3eSOphir Munk error: 105559513c3eSOphir Munk rte_errno = ENODEV; 105659513c3eSOphir Munk return 0; 105759513c3eSOphir Munk } 105859513c3eSOphir Munk 105959513c3eSOphir Munk /** 106059513c3eSOphir Munk * Get the number of physical ports of given IB device. 106159513c3eSOphir Munk * 106259513c3eSOphir Munk * @param nl 106359513c3eSOphir Munk * Netlink socket of the RDMA kind (NETLINK_RDMA). 106459513c3eSOphir Munk * @param[in] name 106559513c3eSOphir Munk * IB device name. 106659513c3eSOphir Munk * 106759513c3eSOphir Munk * @return 106859513c3eSOphir Munk * A valid (nonzero) number of ports on success, 0 otherwise 106959513c3eSOphir Munk * and rte_errno is set. 107059513c3eSOphir Munk */ 107159513c3eSOphir Munk unsigned int 107259513c3eSOphir Munk mlx5_nl_portnum(int nl, const char *name) 107359513c3eSOphir Munk { 107459513c3eSOphir Munk struct mlx5_nl_ifindex_data data = { 107559513c3eSOphir Munk .flags = 0, 107659513c3eSOphir Munk .name = name, 107759513c3eSOphir Munk .ifindex = 0, 107859513c3eSOphir Munk .portnum = 0, 107959513c3eSOphir Munk }; 108059513c3eSOphir Munk struct nlmsghdr req = { 108159513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(0), 108259513c3eSOphir Munk .nlmsg_type = RDMA_NL_GET_TYPE(RDMA_NL_NLDEV, 108359513c3eSOphir Munk RDMA_NLDEV_CMD_GET), 108459513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, 108559513c3eSOphir Munk }; 108659513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 108759513c3eSOphir Munk int ret; 108859513c3eSOphir Munk 108959513c3eSOphir Munk ret = mlx5_nl_send(nl, &req, sn); 109059513c3eSOphir Munk if (ret < 0) 109159513c3eSOphir Munk return 0; 109259513c3eSOphir Munk ret = mlx5_nl_recv(nl, sn, mlx5_nl_cmdget_cb, &data); 109359513c3eSOphir Munk if (ret < 0) 109459513c3eSOphir Munk return 0; 109559513c3eSOphir Munk if (!(data.flags & MLX5_NL_CMD_GET_IB_NAME) || 109659513c3eSOphir Munk !(data.flags & MLX5_NL_CMD_GET_IB_INDEX) || 109759513c3eSOphir Munk !(data.flags & MLX5_NL_CMD_GET_PORT_INDEX)) { 109859513c3eSOphir Munk rte_errno = ENODEV; 109959513c3eSOphir Munk return 0; 110059513c3eSOphir Munk } 110159513c3eSOphir Munk if (!data.portnum) 110259513c3eSOphir Munk rte_errno = EINVAL; 110359513c3eSOphir Munk return data.portnum; 110459513c3eSOphir Munk } 110559513c3eSOphir Munk 110659513c3eSOphir Munk /** 110759513c3eSOphir Munk * Analyze gathered port parameters via Netlink to recognize master 110859513c3eSOphir Munk * and representor devices for E-Switch configuration. 110959513c3eSOphir Munk * 111059513c3eSOphir Munk * @param[in] num_vf_set 111159513c3eSOphir Munk * flag of presence of number of VFs port attribute. 111259513c3eSOphir Munk * @param[inout] switch_info 111359513c3eSOphir Munk * Port information, including port name as a number and port name 111459513c3eSOphir Munk * type if recognized 111559513c3eSOphir Munk * 111659513c3eSOphir Munk * @return 111759513c3eSOphir Munk * master and representor flags are set in switch_info according to 111859513c3eSOphir Munk * recognized parameters (if any). 111959513c3eSOphir Munk */ 112059513c3eSOphir Munk static void 112159513c3eSOphir Munk mlx5_nl_check_switch_info(bool num_vf_set, 112259513c3eSOphir Munk struct mlx5_switch_info *switch_info) 112359513c3eSOphir Munk { 112459513c3eSOphir Munk switch (switch_info->name_type) { 112559513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_UNKNOWN: 112659513c3eSOphir Munk /* 112759513c3eSOphir Munk * Name is not recognized, assume the master, 112859513c3eSOphir Munk * check the number of VFs key presence. 112959513c3eSOphir Munk */ 113059513c3eSOphir Munk switch_info->master = num_vf_set; 113159513c3eSOphir Munk break; 113259513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_NOTSET: 113359513c3eSOphir Munk /* 113459513c3eSOphir Munk * Name is not set, this assumes the legacy naming 113559513c3eSOphir Munk * schema for master, just check if there is a 113659513c3eSOphir Munk * number of VFs key. 113759513c3eSOphir Munk */ 113859513c3eSOphir Munk switch_info->master = num_vf_set; 113959513c3eSOphir Munk break; 114059513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_UPLINK: 114159513c3eSOphir Munk /* New uplink naming schema recognized. */ 114259513c3eSOphir Munk switch_info->master = 1; 114359513c3eSOphir Munk break; 114459513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_LEGACY: 114559513c3eSOphir Munk /* Legacy representors naming schema. */ 114659513c3eSOphir Munk switch_info->representor = !num_vf_set; 114759513c3eSOphir Munk break; 1148420bbdaeSViacheslav Ovsiienko case MLX5_PHYS_PORT_NAME_TYPE_PFHPF: 1149420bbdaeSViacheslav Ovsiienko /* Fallthrough */ 115059513c3eSOphir Munk case MLX5_PHYS_PORT_NAME_TYPE_PFVF: 115159513c3eSOphir Munk /* New representors naming schema. */ 115259513c3eSOphir Munk switch_info->representor = 1; 115359513c3eSOphir Munk break; 115459513c3eSOphir Munk } 115559513c3eSOphir Munk } 115659513c3eSOphir Munk 115759513c3eSOphir Munk /** 115859513c3eSOphir Munk * Process switch information from Netlink message. 115959513c3eSOphir Munk * 116059513c3eSOphir Munk * @param nh 116159513c3eSOphir Munk * Pointer to Netlink message header. 116259513c3eSOphir Munk * @param arg 116359513c3eSOphir Munk * Opaque data pointer for this callback. 116459513c3eSOphir Munk * 116559513c3eSOphir Munk * @return 116659513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 116759513c3eSOphir Munk */ 116859513c3eSOphir Munk static int 116959513c3eSOphir Munk mlx5_nl_switch_info_cb(struct nlmsghdr *nh, void *arg) 117059513c3eSOphir Munk { 117159513c3eSOphir Munk struct mlx5_switch_info info = { 117259513c3eSOphir Munk .master = 0, 117359513c3eSOphir Munk .representor = 0, 117459513c3eSOphir Munk .name_type = MLX5_PHYS_PORT_NAME_TYPE_NOTSET, 117559513c3eSOphir Munk .port_name = 0, 117659513c3eSOphir Munk .switch_id = 0, 117759513c3eSOphir Munk }; 117859513c3eSOphir Munk size_t off = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 117959513c3eSOphir Munk bool switch_id_set = false; 118059513c3eSOphir Munk bool num_vf_set = false; 118159513c3eSOphir Munk 118259513c3eSOphir Munk if (nh->nlmsg_type != RTM_NEWLINK) 118359513c3eSOphir Munk goto error; 118459513c3eSOphir Munk while (off < nh->nlmsg_len) { 118559513c3eSOphir Munk struct rtattr *ra = (void *)((uintptr_t)nh + off); 118659513c3eSOphir Munk void *payload = RTA_DATA(ra); 118759513c3eSOphir Munk unsigned int i; 118859513c3eSOphir Munk 118959513c3eSOphir Munk if (ra->rta_len > nh->nlmsg_len - off) 119059513c3eSOphir Munk goto error; 119159513c3eSOphir Munk switch (ra->rta_type) { 119259513c3eSOphir Munk case IFLA_NUM_VF: 119359513c3eSOphir Munk num_vf_set = true; 119459513c3eSOphir Munk break; 119559513c3eSOphir Munk case IFLA_PHYS_PORT_NAME: 119659513c3eSOphir Munk mlx5_translate_port_name((char *)payload, &info); 119759513c3eSOphir Munk break; 119859513c3eSOphir Munk case IFLA_PHYS_SWITCH_ID: 119959513c3eSOphir Munk info.switch_id = 0; 120059513c3eSOphir Munk for (i = 0; i < RTA_PAYLOAD(ra); ++i) { 120159513c3eSOphir Munk info.switch_id <<= 8; 120259513c3eSOphir Munk info.switch_id |= ((uint8_t *)payload)[i]; 120359513c3eSOphir Munk } 120459513c3eSOphir Munk switch_id_set = true; 120559513c3eSOphir Munk break; 120659513c3eSOphir Munk } 120759513c3eSOphir Munk off += RTA_ALIGN(ra->rta_len); 120859513c3eSOphir Munk } 120959513c3eSOphir Munk if (switch_id_set) { 121059513c3eSOphir Munk /* We have some E-Switch configuration. */ 121159513c3eSOphir Munk mlx5_nl_check_switch_info(num_vf_set, &info); 121259513c3eSOphir Munk } 121359513c3eSOphir Munk MLX5_ASSERT(!(info.master && info.representor)); 121459513c3eSOphir Munk memcpy(arg, &info, sizeof(info)); 121559513c3eSOphir Munk return 0; 121659513c3eSOphir Munk error: 121759513c3eSOphir Munk rte_errno = EINVAL; 121859513c3eSOphir Munk return -rte_errno; 121959513c3eSOphir Munk } 122059513c3eSOphir Munk 122159513c3eSOphir Munk /** 122259513c3eSOphir Munk * Get switch information associated with network interface. 122359513c3eSOphir Munk * 122459513c3eSOphir Munk * @param nl 122559513c3eSOphir Munk * Netlink socket of the ROUTE kind (NETLINK_ROUTE). 122659513c3eSOphir Munk * @param ifindex 122759513c3eSOphir Munk * Network interface index. 122859513c3eSOphir Munk * @param[out] info 122959513c3eSOphir Munk * Switch information object, populated in case of success. 123059513c3eSOphir Munk * 123159513c3eSOphir Munk * @return 123259513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 123359513c3eSOphir Munk */ 123459513c3eSOphir Munk int 123559513c3eSOphir Munk mlx5_nl_switch_info(int nl, unsigned int ifindex, 123659513c3eSOphir Munk struct mlx5_switch_info *info) 123759513c3eSOphir Munk { 123859513c3eSOphir Munk struct { 123959513c3eSOphir Munk struct nlmsghdr nh; 124059513c3eSOphir Munk struct ifinfomsg info; 124159513c3eSOphir Munk struct rtattr rta; 124259513c3eSOphir Munk uint32_t extmask; 124359513c3eSOphir Munk } req = { 124459513c3eSOphir Munk .nh = { 124559513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH 124659513c3eSOphir Munk (sizeof(req.info) + 124759513c3eSOphir Munk RTA_LENGTH(sizeof(uint32_t))), 124859513c3eSOphir Munk .nlmsg_type = RTM_GETLINK, 124959513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 125059513c3eSOphir Munk }, 125159513c3eSOphir Munk .info = { 125259513c3eSOphir Munk .ifi_family = AF_UNSPEC, 125359513c3eSOphir Munk .ifi_index = ifindex, 125459513c3eSOphir Munk }, 125559513c3eSOphir Munk .rta = { 125659513c3eSOphir Munk .rta_type = IFLA_EXT_MASK, 125759513c3eSOphir Munk .rta_len = RTA_LENGTH(sizeof(int32_t)), 125859513c3eSOphir Munk }, 125959513c3eSOphir Munk .extmask = RTE_LE32(1), 126059513c3eSOphir Munk }; 126159513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 126259513c3eSOphir Munk int ret; 126359513c3eSOphir Munk 126459513c3eSOphir Munk ret = mlx5_nl_send(nl, &req.nh, sn); 126559513c3eSOphir Munk if (ret >= 0) 126659513c3eSOphir Munk ret = mlx5_nl_recv(nl, sn, mlx5_nl_switch_info_cb, info); 126759513c3eSOphir Munk if (info->master && info->representor) { 126859513c3eSOphir Munk DRV_LOG(ERR, "ifindex %u device is recognized as master" 126959513c3eSOphir Munk " and as representor", ifindex); 127059513c3eSOphir Munk rte_errno = ENODEV; 127159513c3eSOphir Munk ret = -rte_errno; 127259513c3eSOphir Munk } 127359513c3eSOphir Munk return ret; 127459513c3eSOphir Munk } 127559513c3eSOphir Munk 127659513c3eSOphir Munk /* 127759513c3eSOphir Munk * Delete VLAN network device by ifindex. 127859513c3eSOphir Munk * 127959513c3eSOphir Munk * @param[in] tcf 128059513c3eSOphir Munk * Context object initialized by mlx5_nl_vlan_vmwa_init(). 128159513c3eSOphir Munk * @param[in] ifindex 128259513c3eSOphir Munk * Interface index of network device to delete. 128359513c3eSOphir Munk */ 128459513c3eSOphir Munk void 128559513c3eSOphir Munk mlx5_nl_vlan_vmwa_delete(struct mlx5_nl_vlan_vmwa_context *vmwa, 128659513c3eSOphir Munk uint32_t ifindex) 128759513c3eSOphir Munk { 128859513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 128959513c3eSOphir Munk int ret; 129059513c3eSOphir Munk struct { 129159513c3eSOphir Munk struct nlmsghdr nh; 129259513c3eSOphir Munk struct ifinfomsg info; 129359513c3eSOphir Munk } req = { 129459513c3eSOphir Munk .nh = { 129559513c3eSOphir Munk .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), 129659513c3eSOphir Munk .nlmsg_type = RTM_DELLINK, 129759513c3eSOphir Munk .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 129859513c3eSOphir Munk }, 129959513c3eSOphir Munk .info = { 130059513c3eSOphir Munk .ifi_family = AF_UNSPEC, 130159513c3eSOphir Munk .ifi_index = ifindex, 130259513c3eSOphir Munk }, 130359513c3eSOphir Munk }; 130459513c3eSOphir Munk 130559513c3eSOphir Munk if (ifindex) { 130659513c3eSOphir Munk ret = mlx5_nl_send(vmwa->nl_socket, &req.nh, sn); 130759513c3eSOphir Munk if (ret >= 0) 130859513c3eSOphir Munk ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL); 130959513c3eSOphir Munk if (ret < 0) 131059513c3eSOphir Munk DRV_LOG(WARNING, "netlink: error deleting VLAN WA" 131159513c3eSOphir Munk " ifindex %u, %d", ifindex, ret); 131259513c3eSOphir Munk } 131359513c3eSOphir Munk } 131459513c3eSOphir Munk 131559513c3eSOphir Munk /* Set of subroutines to build Netlink message. */ 131659513c3eSOphir Munk static struct nlattr * 131759513c3eSOphir Munk nl_msg_tail(struct nlmsghdr *nlh) 131859513c3eSOphir Munk { 131959513c3eSOphir Munk return (struct nlattr *) 132059513c3eSOphir Munk (((uint8_t *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len)); 132159513c3eSOphir Munk } 132259513c3eSOphir Munk 132359513c3eSOphir Munk static void 132459513c3eSOphir Munk nl_attr_put(struct nlmsghdr *nlh, int type, const void *data, int alen) 132559513c3eSOphir Munk { 132659513c3eSOphir Munk struct nlattr *nla = nl_msg_tail(nlh); 132759513c3eSOphir Munk 132859513c3eSOphir Munk nla->nla_type = type; 132959513c3eSOphir Munk nla->nla_len = NLMSG_ALIGN(sizeof(struct nlattr)) + alen; 133059513c3eSOphir Munk nlh->nlmsg_len += NLMSG_ALIGN(nla->nla_len); 133159513c3eSOphir Munk 133259513c3eSOphir Munk if (alen) 133359513c3eSOphir Munk memcpy((uint8_t *)nla + sizeof(struct nlattr), data, alen); 133459513c3eSOphir Munk } 133559513c3eSOphir Munk 133659513c3eSOphir Munk static struct nlattr * 133759513c3eSOphir Munk nl_attr_nest_start(struct nlmsghdr *nlh, int type) 133859513c3eSOphir Munk { 133959513c3eSOphir Munk struct nlattr *nest = (struct nlattr *)nl_msg_tail(nlh); 134059513c3eSOphir Munk 134159513c3eSOphir Munk nl_attr_put(nlh, type, NULL, 0); 134259513c3eSOphir Munk return nest; 134359513c3eSOphir Munk } 134459513c3eSOphir Munk 134559513c3eSOphir Munk static void 134659513c3eSOphir Munk nl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *nest) 134759513c3eSOphir Munk { 134859513c3eSOphir Munk nest->nla_len = (uint8_t *)nl_msg_tail(nlh) - (uint8_t *)nest; 134959513c3eSOphir Munk } 135059513c3eSOphir Munk 135159513c3eSOphir Munk /* 135259513c3eSOphir Munk * Create network VLAN device with specified VLAN tag. 135359513c3eSOphir Munk * 135459513c3eSOphir Munk * @param[in] tcf 135559513c3eSOphir Munk * Context object initialized by mlx5_nl_vlan_vmwa_init(). 135659513c3eSOphir Munk * @param[in] ifindex 135759513c3eSOphir Munk * Base network interface index. 135859513c3eSOphir Munk * @param[in] tag 135959513c3eSOphir Munk * VLAN tag for VLAN network device to create. 136059513c3eSOphir Munk */ 136159513c3eSOphir Munk uint32_t 136259513c3eSOphir Munk mlx5_nl_vlan_vmwa_create(struct mlx5_nl_vlan_vmwa_context *vmwa, 136359513c3eSOphir Munk uint32_t ifindex, uint16_t tag) 136459513c3eSOphir Munk { 136559513c3eSOphir Munk struct nlmsghdr *nlh; 136659513c3eSOphir Munk struct ifinfomsg *ifm; 136759513c3eSOphir Munk char name[sizeof(MLX5_VMWA_VLAN_DEVICE_PFX) + 32]; 136859513c3eSOphir Munk 136959513c3eSOphir Munk __rte_cache_aligned 137059513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 137159513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct ifinfomsg)) + 137259513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 8 + 137359513c3eSOphir Munk NLMSG_ALIGN(sizeof(uint32_t)) + 137459513c3eSOphir Munk NLMSG_ALIGN(sizeof(name)) + 137559513c3eSOphir Munk NLMSG_ALIGN(sizeof("vlan")) + 137659513c3eSOphir Munk NLMSG_ALIGN(sizeof(uint32_t)) + 137759513c3eSOphir Munk NLMSG_ALIGN(sizeof(uint16_t)) + 16]; 137859513c3eSOphir Munk struct nlattr *na_info; 137959513c3eSOphir Munk struct nlattr *na_vlan; 138059513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 138159513c3eSOphir Munk int ret; 138259513c3eSOphir Munk 138359513c3eSOphir Munk memset(buf, 0, sizeof(buf)); 138459513c3eSOphir Munk nlh = (struct nlmsghdr *)buf; 138559513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr); 138659513c3eSOphir Munk nlh->nlmsg_type = RTM_NEWLINK; 138759513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | 138859513c3eSOphir Munk NLM_F_EXCL | NLM_F_ACK; 138959513c3eSOphir Munk ifm = (struct ifinfomsg *)nl_msg_tail(nlh); 139059513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct ifinfomsg); 139159513c3eSOphir Munk ifm->ifi_family = AF_UNSPEC; 139259513c3eSOphir Munk ifm->ifi_type = 0; 139359513c3eSOphir Munk ifm->ifi_index = 0; 139459513c3eSOphir Munk ifm->ifi_flags = IFF_UP; 139559513c3eSOphir Munk ifm->ifi_change = 0xffffffff; 139659513c3eSOphir Munk nl_attr_put(nlh, IFLA_LINK, &ifindex, sizeof(ifindex)); 139759513c3eSOphir Munk ret = snprintf(name, sizeof(name), "%s.%u.%u", 139859513c3eSOphir Munk MLX5_VMWA_VLAN_DEVICE_PFX, ifindex, tag); 139959513c3eSOphir Munk nl_attr_put(nlh, IFLA_IFNAME, name, ret + 1); 140059513c3eSOphir Munk na_info = nl_attr_nest_start(nlh, IFLA_LINKINFO); 140159513c3eSOphir Munk nl_attr_put(nlh, IFLA_INFO_KIND, "vlan", sizeof("vlan")); 140259513c3eSOphir Munk na_vlan = nl_attr_nest_start(nlh, IFLA_INFO_DATA); 140359513c3eSOphir Munk nl_attr_put(nlh, IFLA_VLAN_ID, &tag, sizeof(tag)); 140459513c3eSOphir Munk nl_attr_nest_end(nlh, na_vlan); 140559513c3eSOphir Munk nl_attr_nest_end(nlh, na_info); 140659513c3eSOphir Munk MLX5_ASSERT(sizeof(buf) >= nlh->nlmsg_len); 140759513c3eSOphir Munk ret = mlx5_nl_send(vmwa->nl_socket, nlh, sn); 140859513c3eSOphir Munk if (ret >= 0) 140959513c3eSOphir Munk ret = mlx5_nl_recv(vmwa->nl_socket, sn, NULL, NULL); 141059513c3eSOphir Munk if (ret < 0) { 141159513c3eSOphir Munk DRV_LOG(WARNING, "netlink: VLAN %s create failure (%d)", name, 141259513c3eSOphir Munk ret); 141359513c3eSOphir Munk } 141459513c3eSOphir Munk /* Try to get ifindex of created or pre-existing device. */ 141559513c3eSOphir Munk ret = if_nametoindex(name); 141659513c3eSOphir Munk if (!ret) { 141759513c3eSOphir Munk DRV_LOG(WARNING, "VLAN %s failed to get index (%d)", name, 141859513c3eSOphir Munk errno); 141959513c3eSOphir Munk return 0; 142059513c3eSOphir Munk } 142159513c3eSOphir Munk return ret; 142259513c3eSOphir Munk } 142359513c3eSOphir Munk 142459513c3eSOphir Munk /** 142559513c3eSOphir Munk * Parse Netlink message to retrieve the general family ID. 142659513c3eSOphir Munk * 142759513c3eSOphir Munk * @param nh 142859513c3eSOphir Munk * Pointer to Netlink Message Header. 142959513c3eSOphir Munk * @param arg 143059513c3eSOphir Munk * PMD data register with this callback. 143159513c3eSOphir Munk * 143259513c3eSOphir Munk * @return 143359513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 143459513c3eSOphir Munk */ 143559513c3eSOphir Munk static int 143659513c3eSOphir Munk mlx5_nl_family_id_cb(struct nlmsghdr *nh, void *arg) 143759513c3eSOphir Munk { 143859513c3eSOphir Munk 143959513c3eSOphir Munk struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len); 144059513c3eSOphir Munk struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) + 144159513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr))); 144259513c3eSOphir Munk 144359513c3eSOphir Munk for (; nla->nla_len && nla < tail; 144459513c3eSOphir Munk nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len))) { 144559513c3eSOphir Munk if (nla->nla_type == CTRL_ATTR_FAMILY_ID) { 144659513c3eSOphir Munk *(uint16_t *)arg = *(uint16_t *)(nla + 1); 144759513c3eSOphir Munk return 0; 144859513c3eSOphir Munk } 144959513c3eSOphir Munk } 145059513c3eSOphir Munk return -EINVAL; 145159513c3eSOphir Munk } 145259513c3eSOphir Munk 145359513c3eSOphir Munk #define MLX5_NL_MAX_ATTR_SIZE 100 145459513c3eSOphir Munk /** 145559513c3eSOphir Munk * Get generic netlink family ID. 145659513c3eSOphir Munk * 145759513c3eSOphir Munk * @param[in] nlsk_fd 145859513c3eSOphir Munk * Netlink socket file descriptor. 145959513c3eSOphir Munk * @param[in] name 146059513c3eSOphir Munk * The family name. 146159513c3eSOphir Munk * 146259513c3eSOphir Munk * @return 146359513c3eSOphir Munk * ID >= 0 on success and @p enable is updated, a negative errno value 146459513c3eSOphir Munk * otherwise and rte_errno is set. 146559513c3eSOphir Munk */ 146659513c3eSOphir Munk static int 146759513c3eSOphir Munk mlx5_nl_generic_family_id_get(int nlsk_fd, const char *name) 146859513c3eSOphir Munk { 146959513c3eSOphir Munk struct nlmsghdr *nlh; 147059513c3eSOphir Munk struct genlmsghdr *genl; 147159513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 147259513c3eSOphir Munk int name_size = strlen(name) + 1; 147359513c3eSOphir Munk int ret; 147459513c3eSOphir Munk uint16_t id = -1; 147559513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 147659513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 147759513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) + 147859513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE)]; 147959513c3eSOphir Munk 148059513c3eSOphir Munk memset(buf, 0, sizeof(buf)); 148159513c3eSOphir Munk nlh = (struct nlmsghdr *)buf; 148259513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr); 148359513c3eSOphir Munk nlh->nlmsg_type = GENL_ID_CTRL; 148459513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 148559513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh); 148659513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr); 148759513c3eSOphir Munk genl->cmd = CTRL_CMD_GETFAMILY; 148859513c3eSOphir Munk genl->version = 1; 148959513c3eSOphir Munk nl_attr_put(nlh, CTRL_ATTR_FAMILY_NAME, name, name_size); 149059513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn); 149159513c3eSOphir Munk if (ret >= 0) 149259513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_family_id_cb, &id); 149359513c3eSOphir Munk if (ret < 0) { 149459513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to get Netlink %s family ID: %d.", name, 149559513c3eSOphir Munk ret); 149659513c3eSOphir Munk return ret; 149759513c3eSOphir Munk } 149859513c3eSOphir Munk DRV_LOG(DEBUG, "Netlink \"%s\" family ID is %u.", name, id); 149959513c3eSOphir Munk return (int)id; 150059513c3eSOphir Munk } 150159513c3eSOphir Munk 150259513c3eSOphir Munk /** 150359513c3eSOphir Munk * Get Devlink family ID. 150459513c3eSOphir Munk * 150559513c3eSOphir Munk * @param[in] nlsk_fd 150659513c3eSOphir Munk * Netlink socket file descriptor. 150759513c3eSOphir Munk * 150859513c3eSOphir Munk * @return 150959513c3eSOphir Munk * ID >= 0 on success and @p enable is updated, a negative errno value 151059513c3eSOphir Munk * otherwise and rte_errno is set. 151159513c3eSOphir Munk */ 151259513c3eSOphir Munk 151359513c3eSOphir Munk int 151459513c3eSOphir Munk mlx5_nl_devlink_family_id_get(int nlsk_fd) 151559513c3eSOphir Munk { 151659513c3eSOphir Munk return mlx5_nl_generic_family_id_get(nlsk_fd, DEVLINK_GENL_NAME); 151759513c3eSOphir Munk } 151859513c3eSOphir Munk 151959513c3eSOphir Munk /** 152059513c3eSOphir Munk * Parse Netlink message to retrieve the ROCE enable status. 152159513c3eSOphir Munk * 152259513c3eSOphir Munk * @param nh 152359513c3eSOphir Munk * Pointer to Netlink Message Header. 152459513c3eSOphir Munk * @param arg 152559513c3eSOphir Munk * PMD data register with this callback. 152659513c3eSOphir Munk * 152759513c3eSOphir Munk * @return 152859513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 152959513c3eSOphir Munk */ 153059513c3eSOphir Munk static int 153159513c3eSOphir Munk mlx5_nl_roce_cb(struct nlmsghdr *nh, void *arg) 153259513c3eSOphir Munk { 153359513c3eSOphir Munk 153459513c3eSOphir Munk int ret = -EINVAL; 153559513c3eSOphir Munk int *enable = arg; 153659513c3eSOphir Munk struct nlattr *tail = RTE_PTR_ADD(nh, nh->nlmsg_len); 153759513c3eSOphir Munk struct nlattr *nla = RTE_PTR_ADD(nh, NLMSG_ALIGN(sizeof(*nh)) + 153859513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr))); 153959513c3eSOphir Munk 154059513c3eSOphir Munk while (nla->nla_len && nla < tail) { 154159513c3eSOphir Munk switch (nla->nla_type) { 154259513c3eSOphir Munk /* Expected nested attributes case. */ 154359513c3eSOphir Munk case DEVLINK_ATTR_PARAM: 154459513c3eSOphir Munk case DEVLINK_ATTR_PARAM_VALUES_LIST: 154559513c3eSOphir Munk case DEVLINK_ATTR_PARAM_VALUE: 154659513c3eSOphir Munk ret = 0; 154759513c3eSOphir Munk nla += 1; 154859513c3eSOphir Munk break; 154959513c3eSOphir Munk case DEVLINK_ATTR_PARAM_VALUE_DATA: 155059513c3eSOphir Munk *enable = 1; 155159513c3eSOphir Munk return 0; 155259513c3eSOphir Munk default: 155359513c3eSOphir Munk nla = RTE_PTR_ADD(nla, NLMSG_ALIGN(nla->nla_len)); 155459513c3eSOphir Munk } 155559513c3eSOphir Munk } 155659513c3eSOphir Munk *enable = 0; 155759513c3eSOphir Munk return ret; 155859513c3eSOphir Munk } 155959513c3eSOphir Munk 156059513c3eSOphir Munk /** 156159513c3eSOphir Munk * Get ROCE enable status through Netlink. 156259513c3eSOphir Munk * 156359513c3eSOphir Munk * @param[in] nlsk_fd 156459513c3eSOphir Munk * Netlink socket file descriptor. 156559513c3eSOphir Munk * @param[in] family_id 156659513c3eSOphir Munk * the Devlink family ID. 156759513c3eSOphir Munk * @param pci_addr 156859513c3eSOphir Munk * The device PCI address. 156959513c3eSOphir Munk * @param[out] enable 157059513c3eSOphir Munk * Where to store the enable status. 157159513c3eSOphir Munk * 157259513c3eSOphir Munk * @return 157359513c3eSOphir Munk * 0 on success and @p enable is updated, a negative errno value otherwise 157459513c3eSOphir Munk * and rte_errno is set. 157559513c3eSOphir Munk */ 157659513c3eSOphir Munk int 157759513c3eSOphir Munk mlx5_nl_enable_roce_get(int nlsk_fd, int family_id, const char *pci_addr, 157859513c3eSOphir Munk int *enable) 157959513c3eSOphir Munk { 158059513c3eSOphir Munk struct nlmsghdr *nlh; 158159513c3eSOphir Munk struct genlmsghdr *genl; 158259513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 158359513c3eSOphir Munk int ret; 158459513c3eSOphir Munk int cur_en = 0; 158559513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 158659513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 158759513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 4 + 158859513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 4]; 158959513c3eSOphir Munk 159059513c3eSOphir Munk memset(buf, 0, sizeof(buf)); 159159513c3eSOphir Munk nlh = (struct nlmsghdr *)buf; 159259513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr); 159359513c3eSOphir Munk nlh->nlmsg_type = family_id; 159459513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 159559513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh); 159659513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr); 159759513c3eSOphir Munk genl->cmd = DEVLINK_CMD_PARAM_GET; 159859513c3eSOphir Munk genl->version = DEVLINK_GENL_VERSION; 159959513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4); 160059513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1); 160159513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12); 160259513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn); 160359513c3eSOphir Munk if (ret >= 0) 160459513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, mlx5_nl_roce_cb, &cur_en); 160559513c3eSOphir Munk if (ret < 0) { 160659513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to get ROCE enable on device %s: %d.", 160759513c3eSOphir Munk pci_addr, ret); 160859513c3eSOphir Munk return ret; 160959513c3eSOphir Munk } 161059513c3eSOphir Munk *enable = cur_en; 161159513c3eSOphir Munk DRV_LOG(DEBUG, "ROCE is %sabled for device \"%s\".", 161259513c3eSOphir Munk cur_en ? "en" : "dis", pci_addr); 161359513c3eSOphir Munk return ret; 161459513c3eSOphir Munk } 161559513c3eSOphir Munk 161659513c3eSOphir Munk /** 161759513c3eSOphir Munk * Reload mlx5 device kernel driver through Netlink. 161859513c3eSOphir Munk * 161959513c3eSOphir Munk * @param[in] nlsk_fd 162059513c3eSOphir Munk * Netlink socket file descriptor. 162159513c3eSOphir Munk * @param[in] family_id 162259513c3eSOphir Munk * the Devlink family ID. 162359513c3eSOphir Munk * @param pci_addr 162459513c3eSOphir Munk * The device PCI address. 162559513c3eSOphir Munk * @param[out] enable 162659513c3eSOphir Munk * The enable status to set. 162759513c3eSOphir Munk * 162859513c3eSOphir Munk * @return 162959513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 163059513c3eSOphir Munk */ 163159513c3eSOphir Munk int 163259513c3eSOphir Munk mlx5_nl_driver_reload(int nlsk_fd, int family_id, const char *pci_addr) 163359513c3eSOphir Munk { 163459513c3eSOphir Munk struct nlmsghdr *nlh; 163559513c3eSOphir Munk struct genlmsghdr *genl; 163659513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 163759513c3eSOphir Munk int ret; 163859513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 163959513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 164059513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 2 + 164159513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 2]; 164259513c3eSOphir Munk 164359513c3eSOphir Munk memset(buf, 0, sizeof(buf)); 164459513c3eSOphir Munk nlh = (struct nlmsghdr *)buf; 164559513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr); 164659513c3eSOphir Munk nlh->nlmsg_type = family_id; 164759513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 164859513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh); 164959513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr); 165059513c3eSOphir Munk genl->cmd = DEVLINK_CMD_RELOAD; 165159513c3eSOphir Munk genl->version = DEVLINK_GENL_VERSION; 165259513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4); 165359513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1); 165459513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn); 165559513c3eSOphir Munk if (ret >= 0) 165659513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL); 165759513c3eSOphir Munk if (ret < 0) { 165859513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to reload %s device by Netlink - %d", 165959513c3eSOphir Munk pci_addr, ret); 166059513c3eSOphir Munk return ret; 166159513c3eSOphir Munk } 166259513c3eSOphir Munk DRV_LOG(DEBUG, "Device \"%s\" was reloaded by Netlink successfully.", 166359513c3eSOphir Munk pci_addr); 166459513c3eSOphir Munk return 0; 166559513c3eSOphir Munk } 166659513c3eSOphir Munk 166759513c3eSOphir Munk /** 166859513c3eSOphir Munk * Set ROCE enable status through Netlink. 166959513c3eSOphir Munk * 167059513c3eSOphir Munk * @param[in] nlsk_fd 167159513c3eSOphir Munk * Netlink socket file descriptor. 167259513c3eSOphir Munk * @param[in] family_id 167359513c3eSOphir Munk * the Devlink family ID. 167459513c3eSOphir Munk * @param pci_addr 167559513c3eSOphir Munk * The device PCI address. 167659513c3eSOphir Munk * @param[out] enable 167759513c3eSOphir Munk * The enable status to set. 167859513c3eSOphir Munk * 167959513c3eSOphir Munk * @return 168059513c3eSOphir Munk * 0 on success, a negative errno value otherwise and rte_errno is set. 168159513c3eSOphir Munk */ 168259513c3eSOphir Munk int 168359513c3eSOphir Munk mlx5_nl_enable_roce_set(int nlsk_fd, int family_id, const char *pci_addr, 168459513c3eSOphir Munk int enable) 168559513c3eSOphir Munk { 168659513c3eSOphir Munk struct nlmsghdr *nlh; 168759513c3eSOphir Munk struct genlmsghdr *genl; 168859513c3eSOphir Munk uint32_t sn = MLX5_NL_SN_GENERATE; 168959513c3eSOphir Munk int ret; 169059513c3eSOphir Munk uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + 169159513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct genlmsghdr)) + 169259513c3eSOphir Munk NLMSG_ALIGN(sizeof(struct nlattr)) * 6 + 169359513c3eSOphir Munk NLMSG_ALIGN(MLX5_NL_MAX_ATTR_SIZE) * 6]; 169459513c3eSOphir Munk uint8_t cmode = DEVLINK_PARAM_CMODE_DRIVERINIT; 169559513c3eSOphir Munk uint8_t ptype = NLA_FLAG; 169659513c3eSOphir Munk ; 169759513c3eSOphir Munk 169859513c3eSOphir Munk memset(buf, 0, sizeof(buf)); 169959513c3eSOphir Munk nlh = (struct nlmsghdr *)buf; 170059513c3eSOphir Munk nlh->nlmsg_len = sizeof(struct nlmsghdr); 170159513c3eSOphir Munk nlh->nlmsg_type = family_id; 170259513c3eSOphir Munk nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 170359513c3eSOphir Munk genl = (struct genlmsghdr *)nl_msg_tail(nlh); 170459513c3eSOphir Munk nlh->nlmsg_len += sizeof(struct genlmsghdr); 170559513c3eSOphir Munk genl->cmd = DEVLINK_CMD_PARAM_SET; 170659513c3eSOphir Munk genl->version = DEVLINK_GENL_VERSION; 170759513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_BUS_NAME, "pci", 4); 170859513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_DEV_NAME, pci_addr, strlen(pci_addr) + 1); 170959513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_NAME, "enable_roce", 12); 171059513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE, &cmode, sizeof(cmode)); 171159513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_TYPE, &ptype, sizeof(ptype)); 171259513c3eSOphir Munk if (enable) 171359513c3eSOphir Munk nl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, NULL, 0); 171459513c3eSOphir Munk ret = mlx5_nl_send(nlsk_fd, nlh, sn); 171559513c3eSOphir Munk if (ret >= 0) 171659513c3eSOphir Munk ret = mlx5_nl_recv(nlsk_fd, sn, NULL, NULL); 171759513c3eSOphir Munk if (ret < 0) { 171859513c3eSOphir Munk DRV_LOG(DEBUG, "Failed to %sable ROCE for device %s by Netlink:" 171959513c3eSOphir Munk " %d.", enable ? "en" : "dis", pci_addr, ret); 172059513c3eSOphir Munk return ret; 172159513c3eSOphir Munk } 172259513c3eSOphir Munk DRV_LOG(DEBUG, "Device %s ROCE was %sabled by Netlink successfully.", 172359513c3eSOphir Munk pci_addr, enable ? "en" : "dis"); 172459513c3eSOphir Munk /* Now, need to reload the driver. */ 172559513c3eSOphir Munk return mlx5_nl_driver_reload(nlsk_fd, family_id, pci_addr); 172659513c3eSOphir Munk } 1727