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