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