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