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
mlx5_pmd_socket_handle(void * cb __rte_unused)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
mlx5_pmd_socket_init(void)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
mlx5_pmd_socket_uninit(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