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