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 #define MLX5_ALL_PORT_IDS 0xffff 25 26 int server_socket = -1; /* Unix socket for primary process. */ 27 struct rte_intr_handle *server_intr_handle; /* Interrupt handler. */ 28 29 /** 30 * Handle server pmd socket interrupts. 31 */ 32 static void 33 mlx5_pmd_socket_handle(void *cb __rte_unused) 34 { 35 int conn_sock; 36 int ret; 37 struct cmsghdr *cmsg = NULL; 38 uint32_t data[MLX5_SENDMSG_MAX / sizeof(uint32_t)]; 39 struct rte_flow *flow_ptr = NULL; 40 uint8_t buf[CMSG_SPACE(sizeof(int))] = { 0 }; 41 struct iovec io = { 42 .iov_base = data, 43 .iov_len = sizeof(data), 44 }; 45 struct msghdr msg = { 46 .msg_iov = &io, 47 .msg_iovlen = 1, 48 .msg_control = buf, 49 .msg_controllen = sizeof(buf), 50 }; 51 52 uint32_t port_id; 53 int fd; 54 FILE *file = NULL; 55 struct rte_eth_dev *dev; 56 struct rte_flow_error err; 57 struct mlx5_flow_dump_req *dump_req; 58 struct mlx5_flow_dump_ack *dump_ack; 59 60 memset(data, 0, sizeof(data)); 61 /* Accept the connection from the client. */ 62 conn_sock = accept(server_socket, NULL, NULL); 63 if (conn_sock < 0) { 64 DRV_LOG(WARNING, "connection failed: %s", strerror(errno)); 65 return; 66 } 67 ret = recvmsg(conn_sock, &msg, MSG_WAITALL); 68 if (ret != sizeof(struct mlx5_flow_dump_req)) { 69 DRV_LOG(WARNING, "wrong message received: %s", 70 strerror(errno)); 71 goto error; 72 } 73 74 /* Receive file descriptor. */ 75 cmsg = CMSG_FIRSTHDR(&msg); 76 if (cmsg == NULL || cmsg->cmsg_type != SCM_RIGHTS || 77 cmsg->cmsg_len < sizeof(int)) { 78 DRV_LOG(WARNING, "invalid file descriptor message"); 79 goto error; 80 } 81 memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); 82 file = fdopen(fd, "w"); 83 if (!file) { 84 DRV_LOG(WARNING, "Failed to open file"); 85 goto error; 86 } 87 /* Receive port number. */ 88 if (msg.msg_iovlen != 1 || msg.msg_iov->iov_len < sizeof(uint16_t)) { 89 DRV_LOG(WARNING, "wrong port number message"); 90 goto error; 91 } 92 93 dump_req = (struct mlx5_flow_dump_req *)msg.msg_iov->iov_base; 94 if (dump_req) { 95 port_id = dump_req->port_id; 96 flow_ptr = (struct rte_flow *)((uintptr_t)dump_req->flow_id); 97 } else { 98 DRV_LOG(WARNING, "Invalid message"); 99 goto error; 100 } 101 102 if (port_id == MLX5_ALL_PORT_IDS) { 103 /* Dump all port ids */ 104 if (flow_ptr) { 105 DRV_LOG(WARNING, "Flow ptr unsupported with given port id"); 106 goto error; 107 } 108 109 MLX5_ETH_FOREACH_DEV(port_id, NULL) { 110 dev = &rte_eth_devices[port_id]; 111 ret = mlx5_flow_dev_dump(dev, NULL, file, &err); 112 if (ret) 113 break; 114 } 115 } else { 116 /* Dump single port id */ 117 if (!rte_eth_dev_is_valid_port(port_id)) { 118 DRV_LOG(WARNING, "Invalid port %u", port_id); 119 goto error; 120 } 121 122 /* Dump flow */ 123 dev = &rte_eth_devices[port_id]; 124 ret = mlx5_flow_dev_dump(dev, flow_ptr, file, &err); 125 } 126 127 /* Set-up the ancillary data and reply. */ 128 msg.msg_controllen = 0; 129 msg.msg_control = NULL; 130 msg.msg_iovlen = 1; 131 msg.msg_iov = &io; 132 dump_ack = (struct mlx5_flow_dump_ack *)data; 133 dump_ack->rc = -ret; 134 io.iov_len = sizeof(struct mlx5_flow_dump_ack); 135 io.iov_base = dump_ack; 136 do { 137 ret = sendmsg(conn_sock, &msg, 0); 138 } while (ret < 0 && errno == EINTR); 139 if (ret < 0) 140 DRV_LOG(WARNING, "failed to send response %s", 141 strerror(errno)); 142 error: 143 if (conn_sock >= 0) 144 close(conn_sock); 145 if (file) 146 fclose(file); 147 } 148 149 /** 150 * Initialise the socket to communicate with external tools. 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 != -1) 166 return 0; 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 close; 177 ret = fcntl(server_socket, F_SETFL, flags | O_NONBLOCK); 178 if (ret < 0) 179 goto close; 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 remove; 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 remove; 194 } 195 server_intr_handle = mlx5_os_interrupt_handler_create 196 (RTE_INTR_INSTANCE_F_PRIVATE, false, 197 server_socket, mlx5_pmd_socket_handle, NULL); 198 if (server_intr_handle == NULL) { 199 DRV_LOG(WARNING, "cannot register interrupt handler for mlx5 socket: %s", 200 strerror(errno)); 201 goto remove; 202 } 203 return 0; 204 remove: 205 remove(sun.sun_path); 206 close: 207 claim_zero(close(server_socket)); 208 server_socket = -1; 209 error: 210 DRV_LOG(ERR, "Cannot initialize socket: %s", strerror(errno)); 211 return -errno; 212 } 213 214 /** 215 * Un-Initialize the pmd socket 216 */ 217 void 218 mlx5_pmd_socket_uninit(void) 219 { 220 if (server_socket == -1) 221 return; 222 mlx5_os_interrupt_handler_destroy(server_intr_handle, 223 mlx5_pmd_socket_handle, NULL); 224 claim_zero(close(server_socket)); 225 server_socket = -1; 226 MKSTR(path, MLX5_SOCKET_PATH, getpid()); 227 claim_zero(remove(path)); 228 } 229