1f484ffa1SOphir Munk /* SPDX-License-Identifier: BSD-3-Clause 2f484ffa1SOphir Munk * Copyright 2019 Mellanox Technologies, Ltd 3f484ffa1SOphir Munk */ 4f484ffa1SOphir Munk 5bd0a9315SHaifei Luo #ifndef _GNU_SOURCE 6bd0a9315SHaifei Luo #define _GNU_SOURCE 7bd0a9315SHaifei Luo #endif 8bd0a9315SHaifei Luo 9f484ffa1SOphir Munk #include <sys/types.h> 10f484ffa1SOphir Munk #include <sys/socket.h> 11f484ffa1SOphir Munk #include <sys/un.h> 12f484ffa1SOphir Munk #include <fcntl.h> 13f484ffa1SOphir Munk #include <stdio.h> 14f484ffa1SOphir Munk #include <unistd.h> 15f484ffa1SOphir Munk #include <sys/stat.h> 16f484ffa1SOphir Munk 17f484ffa1SOphir Munk #include "rte_eal.h" 18f484ffa1SOphir Munk #include "mlx5_utils.h" 19f484ffa1SOphir Munk #include "mlx5.h" 20f484ffa1SOphir Munk 21f484ffa1SOphir Munk /* PMD socket service for tools. */ 22f484ffa1SOphir Munk 23733bbf51SXueming Li #define MLX5_SOCKET_PATH "/var/tmp/dpdk_net_mlx5_%d" 24733bbf51SXueming Li 25f484ffa1SOphir Munk int server_socket; /* Unix socket for primary process. */ 26*d61138d4SHarman Kalra struct rte_intr_handle *server_intr_handle; /* Interrupt handler. */ 27f484ffa1SOphir Munk 28f484ffa1SOphir Munk /** 29f484ffa1SOphir Munk * Handle server pmd socket interrupts. 30f484ffa1SOphir Munk */ 31f484ffa1SOphir Munk static void 32f484ffa1SOphir Munk mlx5_pmd_socket_handle(void *cb __rte_unused) 33f484ffa1SOphir Munk { 34f484ffa1SOphir Munk int conn_sock; 35f484ffa1SOphir Munk int ret; 36f484ffa1SOphir Munk struct cmsghdr *cmsg = NULL; 37bd0a9315SHaifei Luo uint32_t data[MLX5_SENDMSG_MAX / sizeof(uint32_t)]; 38bd0a9315SHaifei Luo uint64_t flow_ptr = 0; 39bd0a9315SHaifei Luo uint8_t buf[CMSG_SPACE(sizeof(int))] = { 0 }; 40f484ffa1SOphir Munk struct iovec io = { 41bd0a9315SHaifei Luo .iov_base = data, 42f484ffa1SOphir Munk .iov_len = sizeof(data), 43f484ffa1SOphir Munk }; 44f484ffa1SOphir Munk struct msghdr msg = { 45f484ffa1SOphir Munk .msg_iov = &io, 46f484ffa1SOphir Munk .msg_iovlen = 1, 47f484ffa1SOphir Munk .msg_control = buf, 48f484ffa1SOphir Munk .msg_controllen = sizeof(buf), 49f484ffa1SOphir Munk }; 50bd0a9315SHaifei Luo 51bd0a9315SHaifei Luo uint32_t port_id; 52f484ffa1SOphir Munk int fd; 53f484ffa1SOphir Munk FILE *file = NULL; 54f484ffa1SOphir Munk struct rte_eth_dev *dev; 55bd0a9315SHaifei Luo struct rte_flow_error err; 56bd0a9315SHaifei Luo struct mlx5_flow_dump_req *dump_req; 57bd0a9315SHaifei Luo struct mlx5_flow_dump_ack *dump_ack; 58f484ffa1SOphir Munk 59bd0a9315SHaifei Luo memset(data, 0, sizeof(data)); 60f484ffa1SOphir Munk /* Accept the connection from the client. */ 61f484ffa1SOphir Munk conn_sock = accept(server_socket, NULL, NULL); 62f484ffa1SOphir Munk if (conn_sock < 0) { 63f484ffa1SOphir Munk DRV_LOG(WARNING, "connection failed: %s", strerror(errno)); 64f484ffa1SOphir Munk return; 65f484ffa1SOphir Munk } 66f484ffa1SOphir Munk ret = recvmsg(conn_sock, &msg, MSG_WAITALL); 67bd0a9315SHaifei Luo if (ret != sizeof(struct mlx5_flow_dump_req)) { 68f484ffa1SOphir Munk DRV_LOG(WARNING, "wrong message received: %s", 69f484ffa1SOphir Munk strerror(errno)); 70f484ffa1SOphir Munk goto error; 71f484ffa1SOphir Munk } 72bd0a9315SHaifei Luo 73f484ffa1SOphir Munk /* Receive file descriptor. */ 74f484ffa1SOphir Munk cmsg = CMSG_FIRSTHDR(&msg); 75f484ffa1SOphir Munk if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS || 76f484ffa1SOphir Munk cmsg->cmsg_len < sizeof(int)) { 77f484ffa1SOphir Munk DRV_LOG(WARNING, "invalid file descriptor message"); 78f484ffa1SOphir Munk goto error; 79f484ffa1SOphir Munk } 80f484ffa1SOphir Munk memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); 81f484ffa1SOphir Munk file = fdopen(fd, "w"); 82f484ffa1SOphir Munk if (!file) { 83f484ffa1SOphir Munk DRV_LOG(WARNING, "Failed to open file"); 84f484ffa1SOphir Munk goto error; 85f484ffa1SOphir Munk } 86f484ffa1SOphir Munk /* Receive port number. */ 87f484ffa1SOphir Munk if (msg.msg_iovlen != 1 || msg.msg_iov->iov_len < sizeof(uint16_t)) { 88f484ffa1SOphir Munk DRV_LOG(WARNING, "wrong port number message"); 89f484ffa1SOphir Munk goto error; 90f484ffa1SOphir Munk } 91bd0a9315SHaifei Luo 92bd0a9315SHaifei Luo dump_req = (struct mlx5_flow_dump_req *)msg.msg_iov->iov_base; 93bd0a9315SHaifei Luo if (dump_req) { 94bd0a9315SHaifei Luo port_id = dump_req->port_id; 95bd0a9315SHaifei Luo flow_ptr = dump_req->flow_id; 96bd0a9315SHaifei Luo } else { 97bd0a9315SHaifei Luo DRV_LOG(WARNING, "Invalid message"); 98bd0a9315SHaifei Luo goto error; 99bd0a9315SHaifei Luo } 100bd0a9315SHaifei Luo 101f484ffa1SOphir Munk if (!rte_eth_dev_is_valid_port(port_id)) { 102f484ffa1SOphir Munk DRV_LOG(WARNING, "Invalid port %u", port_id); 103f484ffa1SOphir Munk goto error; 104f484ffa1SOphir Munk } 105bd0a9315SHaifei Luo 106f484ffa1SOphir Munk /* Dump flow. */ 107f484ffa1SOphir Munk dev = &rte_eth_devices[port_id]; 108bd0a9315SHaifei Luo if (flow_ptr == 0) 10950c38379SHaifei Luo ret = mlx5_flow_dev_dump(dev, NULL, file, NULL); 110bd0a9315SHaifei Luo else 111bd0a9315SHaifei Luo ret = mlx5_flow_dev_dump(dev, 112bd0a9315SHaifei Luo (struct rte_flow *)((uintptr_t)flow_ptr), file, &err); 113bd0a9315SHaifei Luo 114f484ffa1SOphir Munk /* Set-up the ancillary data and reply. */ 115f484ffa1SOphir Munk msg.msg_controllen = 0; 116f484ffa1SOphir Munk msg.msg_control = NULL; 117f484ffa1SOphir Munk msg.msg_iovlen = 1; 118f484ffa1SOphir Munk msg.msg_iov = &io; 119bd0a9315SHaifei Luo dump_ack = (struct mlx5_flow_dump_ack *)data; 120bd0a9315SHaifei Luo dump_ack->rc = -ret; 121bd0a9315SHaifei Luo io.iov_len = sizeof(struct mlx5_flow_dump_ack); 122bd0a9315SHaifei Luo io.iov_base = dump_ack; 123f484ffa1SOphir Munk do { 124f484ffa1SOphir Munk ret = sendmsg(conn_sock, &msg, 0); 125f484ffa1SOphir Munk } while (ret < 0 && errno == EINTR); 126f484ffa1SOphir Munk if (ret < 0) 127f484ffa1SOphir Munk DRV_LOG(WARNING, "failed to send response %s", 128f484ffa1SOphir Munk strerror(errno)); 129f484ffa1SOphir Munk error: 130f484ffa1SOphir Munk if (conn_sock >= 0) 131f484ffa1SOphir Munk close(conn_sock); 132f484ffa1SOphir Munk if (file) 133f484ffa1SOphir Munk fclose(file); 134f484ffa1SOphir Munk } 135f484ffa1SOphir Munk 136f484ffa1SOphir Munk /** 137f484ffa1SOphir Munk * Install interrupt handler. 138f484ffa1SOphir Munk * 139f484ffa1SOphir Munk * @param dev 140f484ffa1SOphir Munk * Pointer to Ethernet device. 141f484ffa1SOphir Munk * @return 142f484ffa1SOphir Munk * 0 on success, a negative errno value otherwise. 143f484ffa1SOphir Munk */ 144f484ffa1SOphir Munk static int 145f484ffa1SOphir Munk mlx5_pmd_interrupt_handler_install(void) 146f484ffa1SOphir Munk { 147f484ffa1SOphir Munk MLX5_ASSERT(server_socket); 148*d61138d4SHarman Kalra server_intr_handle = 149*d61138d4SHarman Kalra rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE); 150*d61138d4SHarman Kalra if (server_intr_handle == NULL) { 151*d61138d4SHarman Kalra DRV_LOG(ERR, "Fail to allocate intr_handle"); 152*d61138d4SHarman Kalra return -ENOMEM; 153*d61138d4SHarman Kalra } 154*d61138d4SHarman Kalra if (rte_intr_fd_set(server_intr_handle, server_socket)) 155*d61138d4SHarman Kalra return -rte_errno; 156*d61138d4SHarman Kalra 157*d61138d4SHarman Kalra if (rte_intr_type_set(server_intr_handle, RTE_INTR_HANDLE_EXT)) 158*d61138d4SHarman Kalra return -rte_errno; 159*d61138d4SHarman Kalra 160*d61138d4SHarman Kalra return rte_intr_callback_register(server_intr_handle, 161f484ffa1SOphir Munk mlx5_pmd_socket_handle, NULL); 162f484ffa1SOphir Munk } 163f484ffa1SOphir Munk 164f484ffa1SOphir Munk /** 165f484ffa1SOphir Munk * Uninstall interrupt handler. 166f484ffa1SOphir Munk */ 167f484ffa1SOphir Munk static void 168f484ffa1SOphir Munk mlx5_pmd_interrupt_handler_uninstall(void) 169f484ffa1SOphir Munk { 170f484ffa1SOphir Munk if (server_socket) { 171*d61138d4SHarman Kalra mlx5_intr_callback_unregister(server_intr_handle, 172f484ffa1SOphir Munk mlx5_pmd_socket_handle, 173f484ffa1SOphir Munk NULL); 174f484ffa1SOphir Munk } 175*d61138d4SHarman Kalra rte_intr_fd_set(server_intr_handle, 0); 176*d61138d4SHarman Kalra rte_intr_type_set(server_intr_handle, RTE_INTR_HANDLE_UNKNOWN); 177*d61138d4SHarman Kalra rte_intr_instance_free(server_intr_handle); 178f484ffa1SOphir Munk } 179f484ffa1SOphir Munk 180f484ffa1SOphir Munk /** 181ea823b2cSDmitry Kozlyuk * Initialise the socket to communicate with external tools. 182f484ffa1SOphir Munk * 183f484ffa1SOphir Munk * @return 184f484ffa1SOphir Munk * 0 on success, a negative value otherwise. 185f484ffa1SOphir Munk */ 186f484ffa1SOphir Munk int 187f484ffa1SOphir Munk mlx5_pmd_socket_init(void) 188f484ffa1SOphir Munk { 189f484ffa1SOphir Munk struct sockaddr_un sun = { 190f484ffa1SOphir Munk .sun_family = AF_UNIX, 191f484ffa1SOphir Munk }; 192f484ffa1SOphir Munk int ret; 193f484ffa1SOphir Munk int flags; 194f484ffa1SOphir Munk 195f484ffa1SOphir Munk MLX5_ASSERT(rte_eal_process_type() == RTE_PROC_PRIMARY); 196f484ffa1SOphir Munk if (server_socket) 197f484ffa1SOphir Munk return 0; 198f484ffa1SOphir Munk ret = socket(AF_UNIX, SOCK_STREAM, 0); 199f484ffa1SOphir Munk if (ret < 0) { 200f484ffa1SOphir Munk DRV_LOG(WARNING, "Failed to open mlx5 socket: %s", 201f484ffa1SOphir Munk strerror(errno)); 202f484ffa1SOphir Munk goto error; 203f484ffa1SOphir Munk } 204f484ffa1SOphir Munk server_socket = ret; 205f484ffa1SOphir Munk flags = fcntl(server_socket, F_GETFL, 0); 206f484ffa1SOphir Munk if (flags == -1) 207f484ffa1SOphir Munk goto error; 208f484ffa1SOphir Munk ret = fcntl(server_socket, F_SETFL, flags | O_NONBLOCK); 209f484ffa1SOphir Munk if (ret < 0) 210f484ffa1SOphir Munk goto error; 211733bbf51SXueming Li snprintf(sun.sun_path, sizeof(sun.sun_path), MLX5_SOCKET_PATH, 212733bbf51SXueming Li getpid()); 213f484ffa1SOphir Munk remove(sun.sun_path); 214f484ffa1SOphir Munk ret = bind(server_socket, (const struct sockaddr *)&sun, sizeof(sun)); 215f484ffa1SOphir Munk if (ret < 0) { 216f484ffa1SOphir Munk DRV_LOG(WARNING, 217f484ffa1SOphir Munk "cannot bind mlx5 socket: %s", strerror(errno)); 218f484ffa1SOphir Munk goto close; 219f484ffa1SOphir Munk } 220f484ffa1SOphir Munk ret = listen(server_socket, 0); 221f484ffa1SOphir Munk if (ret < 0) { 222f484ffa1SOphir Munk DRV_LOG(WARNING, "cannot listen on mlx5 socket: %s", 223f484ffa1SOphir Munk strerror(errno)); 224f484ffa1SOphir Munk goto close; 225f484ffa1SOphir Munk } 226f484ffa1SOphir Munk if (mlx5_pmd_interrupt_handler_install()) { 227f484ffa1SOphir Munk DRV_LOG(WARNING, "cannot register interrupt handler for mlx5 socket: %s", 228f484ffa1SOphir Munk strerror(errno)); 229f484ffa1SOphir Munk goto close; 230f484ffa1SOphir Munk } 231f484ffa1SOphir Munk return 0; 232f484ffa1SOphir Munk close: 233f484ffa1SOphir Munk remove(sun.sun_path); 234f484ffa1SOphir Munk error: 235f484ffa1SOphir Munk claim_zero(close(server_socket)); 236f484ffa1SOphir Munk server_socket = 0; 237f484ffa1SOphir Munk DRV_LOG(ERR, "Cannot initialize socket: %s", strerror(errno)); 238f484ffa1SOphir Munk return -errno; 239f484ffa1SOphir Munk } 240f484ffa1SOphir Munk 241f484ffa1SOphir Munk /** 242f484ffa1SOphir Munk * Un-Initialize the pmd socket 243f484ffa1SOphir Munk */ 244ea823b2cSDmitry Kozlyuk void 245ea823b2cSDmitry Kozlyuk mlx5_pmd_socket_uninit(void) 246f484ffa1SOphir Munk { 247f484ffa1SOphir Munk if (!server_socket) 248f484ffa1SOphir Munk return; 249f484ffa1SOphir Munk mlx5_pmd_interrupt_handler_uninstall(); 250f484ffa1SOphir Munk claim_zero(close(server_socket)); 251f484ffa1SOphir Munk server_socket = 0; 252733bbf51SXueming Li MKSTR(path, MLX5_SOCKET_PATH, getpid()); 253f484ffa1SOphir Munk claim_zero(remove(path)); 254f484ffa1SOphir Munk } 255