Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2020 Intel Corporation
3 : : */
4 : :
5 : : #include <ctype.h>
6 : : #include <errno.h>
7 : : #include <stdlib.h>
8 : : #ifndef RTE_EXEC_ENV_WINDOWS
9 : : #include <unistd.h>
10 : : #include <pthread.h>
11 : : #include <sys/socket.h>
12 : : #include <sys/un.h>
13 : : #include <sys/stat.h>
14 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
15 : :
16 : : /* we won't link against libbsd, so just always use DPDKs-specific strlcpy */
17 : : #undef RTE_USE_LIBBSD
18 : : #include <eal_export.h>
19 : : #include <rte_string_fns.h>
20 : : #include <rte_common.h>
21 : : #include <rte_spinlock.h>
22 : : #include <rte_log.h>
23 : :
24 : : #include "rte_telemetry.h"
25 : : #include "telemetry_json.h"
26 : : #include "telemetry_data.h"
27 : : #include "telemetry_internal.h"
28 : :
29 : : #define MAX_CMD_LEN 56
30 : : #define MAX_OUTPUT_LEN (1024 * 16)
31 : : #define MAX_CONNECTIONS 10
32 : :
33 : : #ifndef RTE_EXEC_ENV_WINDOWS
34 : : static void *
35 : : client_handler(void *socket);
36 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
37 : :
38 : : struct cmd_callback {
39 : : char cmd[MAX_CMD_LEN];
40 : : telemetry_cb fn;
41 : : telemetry_arg_cb fn_arg;
42 : : void *arg;
43 : : char help[RTE_TEL_MAX_STRING_LEN];
44 : : };
45 : :
46 : : #ifndef RTE_EXEC_ENV_WINDOWS
47 : : struct socket {
48 : : int sock;
49 : : char path[sizeof(((struct sockaddr_un *)0)->sun_path)];
50 : : handler fn;
51 : : RTE_ATOMIC(uint16_t) *num_clients;
52 : : };
53 : : static struct socket v2_socket; /* socket for v2 telemetry */
54 : : static struct socket v1_socket; /* socket for v1 telemetry */
55 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
56 : :
57 : : static const char *telemetry_version; /* save rte_version */
58 : : static const char *socket_dir; /* runtime directory */
59 : : static rte_cpuset_t *thread_cpuset;
60 : :
61 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(logtype, WARNING);
62 : : #define RTE_LOGTYPE_TELEMETRY logtype
63 : : #define TMTY_LOG_LINE(l, ...) RTE_LOG_LINE(l, TELEMETRY, "" __VA_ARGS__)
64 : :
65 : : /* list of command callbacks, with one command registered by default */
66 : : static struct cmd_callback *callbacks;
67 : : static int num_callbacks; /* How many commands are registered */
68 : : /* Used when accessing or modifying list of command callbacks */
69 : : static rte_spinlock_t callback_sl = RTE_SPINLOCK_INITIALIZER;
70 : : #ifndef RTE_EXEC_ENV_WINDOWS
71 : : static RTE_ATOMIC(uint16_t) v2_clients;
72 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
73 : :
74 : : static int
75 : 23392 : register_cmd(const char *cmd, const char *help,
76 : : telemetry_cb fn, telemetry_arg_cb fn_arg, void *arg)
77 : : {
78 : : struct cmd_callback *new_callbacks;
79 : : const char *cmdp = cmd;
80 : : int i = 0;
81 : :
82 [ + - + - : 23392 : if (strlen(cmd) >= MAX_CMD_LEN || (fn == NULL && fn_arg == NULL) || cmd[0] != '/'
+ - ]
83 [ + - ]: 23392 : || strlen(help) >= RTE_TEL_MAX_STRING_LEN)
84 : : return -EINVAL;
85 : :
86 [ + + ]: 416380 : while (*cmdp != '\0') {
87 [ + + + + : 392988 : if (!isalnum(*cmdp) && *cmdp != '_' && *cmdp != '/')
+ - ]
88 : : return -EINVAL;
89 : 392988 : cmdp++;
90 : : }
91 : :
92 : : rte_spinlock_lock(&callback_sl);
93 : 23392 : new_callbacks = realloc(callbacks, sizeof(callbacks[0]) * (num_callbacks + 1));
94 [ - + ]: 23392 : if (new_callbacks == NULL) {
95 : : rte_spinlock_unlock(&callback_sl);
96 : 0 : return -ENOMEM;
97 : : }
98 : 23392 : callbacks = new_callbacks;
99 : :
100 [ + + + + ]: 242580 : while (i < num_callbacks && strcmp(cmd, callbacks[i].cmd) > 0)
101 : 219188 : i++;
102 [ + + ]: 23392 : if (i != num_callbacks)
103 : : /* Move elements to keep the list alphabetical */
104 : 22383 : memmove(callbacks + i + 1, callbacks + i,
105 : 22383 : sizeof(struct cmd_callback) * (num_callbacks - i));
106 : :
107 : 23392 : strlcpy(callbacks[i].cmd, cmd, MAX_CMD_LEN);
108 : 23392 : callbacks[i].fn = fn;
109 : 23392 : callbacks[i].fn_arg = fn_arg;
110 : 23392 : callbacks[i].arg = arg;
111 : 23392 : strlcpy(callbacks[i].help, help, RTE_TEL_MAX_STRING_LEN);
112 : 23392 : num_callbacks++;
113 : : rte_spinlock_unlock(&callback_sl);
114 : :
115 : 23392 : return 0;
116 : : }
117 : :
118 : : RTE_EXPORT_SYMBOL(rte_telemetry_register_cmd)
119 : : int
120 : 18856 : rte_telemetry_register_cmd(const char *cmd, telemetry_cb fn, const char *help)
121 : : {
122 : 18856 : return register_cmd(cmd, help, fn, NULL, NULL);
123 : : }
124 : :
125 : : RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_telemetry_register_cmd_arg, 24.11)
126 : : int
127 : 4536 : rte_telemetry_register_cmd_arg(const char *cmd, telemetry_arg_cb fn, void *arg, const char *help)
128 : : {
129 : 4536 : return register_cmd(cmd, help, NULL, fn, arg);
130 : : }
131 : :
132 : : #ifndef RTE_EXEC_ENV_WINDOWS
133 : :
134 : : static int
135 : 0 : list_commands(const char *cmd __rte_unused, const char *params __rte_unused,
136 : : struct rte_tel_data *d)
137 : : {
138 : : int i;
139 : :
140 : 0 : rte_tel_data_start_array(d, RTE_TEL_STRING_VAL);
141 : : rte_spinlock_lock(&callback_sl);
142 [ # # ]: 0 : for (i = 0; i < num_callbacks; i++)
143 : 0 : rte_tel_data_add_array_string(d, callbacks[i].cmd);
144 : : rte_spinlock_unlock(&callback_sl);
145 : 0 : return 0;
146 : : }
147 : :
148 : : static int
149 : 0 : json_info(const char *cmd __rte_unused, const char *params __rte_unused,
150 : : struct rte_tel_data *d)
151 : : {
152 : 0 : rte_tel_data_start_dict(d);
153 : 0 : rte_tel_data_add_dict_string(d, "version", telemetry_version);
154 : 0 : rte_tel_data_add_dict_int(d, "pid", getpid());
155 : 0 : rte_tel_data_add_dict_int(d, "max_output_len", MAX_OUTPUT_LEN);
156 : 0 : return 0;
157 : : }
158 : :
159 : : static int
160 : 0 : command_help(const char *cmd __rte_unused, const char *params,
161 : : struct rte_tel_data *d)
162 : : {
163 : : int i;
164 : : /* if no parameters return our own help text */
165 [ # # ]: 0 : const char *to_lookup = (params == NULL ? cmd : params);
166 : :
167 : 0 : rte_tel_data_start_dict(d);
168 : : rte_spinlock_lock(&callback_sl);
169 [ # # ]: 0 : for (i = 0; i < num_callbacks; i++)
170 [ # # ]: 0 : if (strcmp(to_lookup, callbacks[i].cmd) == 0) {
171 [ # # ]: 0 : if (params == NULL)
172 : 0 : rte_tel_data_string(d, callbacks[i].help);
173 : : else
174 : 0 : rte_tel_data_add_dict_string(d, params, callbacks[i].help);
175 : : break;
176 : : }
177 : : rte_spinlock_unlock(&callback_sl);
178 [ # # ]: 0 : if (i == num_callbacks)
179 : 0 : return -1;
180 : : return 0;
181 : : }
182 : :
183 : : static int
184 : 23 : container_to_json(const struct rte_tel_data *d, char *out_buf, size_t buf_len)
185 : : {
186 : : size_t used = 0;
187 : : unsigned int i;
188 : :
189 [ + + + + ]: 23 : if (d->type != TEL_DICT && d->type != TEL_ARRAY_UINT &&
190 [ - + ]: 14 : d->type != TEL_ARRAY_INT && d->type != TEL_ARRAY_STRING)
191 : 0 : return snprintf(out_buf, buf_len, "null");
192 : :
193 [ + + ]: 23 : if (d->type == TEL_DICT)
194 : 1 : used = rte_tel_json_empty_obj(out_buf, buf_len, 0);
195 : : else
196 : 22 : used = rte_tel_json_empty_array(out_buf, buf_len, 0);
197 : :
198 [ + + ]: 23 : if (d->type == TEL_ARRAY_UINT)
199 [ + + ]: 34 : for (i = 0; i < d->data_len; i++)
200 : 30 : used = rte_tel_json_add_array_uint(out_buf,
201 : : buf_len, used,
202 : 30 : d->data.array[i].uval);
203 [ + + ]: 23 : if (d->type == TEL_ARRAY_INT)
204 [ + + ]: 24 : for (i = 0; i < d->data_len; i++)
205 : 20 : used = rte_tel_json_add_array_int(out_buf,
206 : : buf_len, used,
207 : 20 : d->data.array[i].ival);
208 [ + + ]: 23 : if (d->type == TEL_ARRAY_STRING)
209 [ + + ]: 28 : for (i = 0; i < d->data_len; i++)
210 : 14 : used = rte_tel_json_add_array_string(out_buf,
211 : : buf_len, used,
212 : 14 : d->data.array[i].sval);
213 [ + + ]: 23 : if (d->type == TEL_DICT)
214 [ + + ]: 3 : for (i = 0; i < d->data_len; i++) {
215 : : const struct tel_dict_entry *v = &d->data.dict[i];
216 [ - - - + : 2 : switch (v->type) {
- ]
217 : 0 : case RTE_TEL_STRING_VAL:
218 : 0 : used = rte_tel_json_add_obj_str(out_buf,
219 : : buf_len, used,
220 : 0 : v->name, v->value.sval);
221 : 0 : break;
222 : 0 : case RTE_TEL_INT_VAL:
223 : 0 : used = rte_tel_json_add_obj_int(out_buf,
224 : : buf_len, used,
225 : 0 : v->name, v->value.ival);
226 : 0 : break;
227 : 0 : case RTE_TEL_UINT_VAL:
228 : 0 : used = rte_tel_json_add_obj_uint(out_buf,
229 : : buf_len, used,
230 : 0 : v->name, v->value.uval);
231 : 0 : break;
232 : 2 : case RTE_TEL_CONTAINER:
233 : : {
234 : 2 : char *temp = malloc(buf_len);
235 [ + - ]: 2 : if (temp == NULL)
236 : : break;
237 : 2 : *temp = '\0'; /* ensure valid string */
238 : :
239 : : const struct container *cont =
240 : : &v->value.container;
241 [ + - ]: 2 : if (container_to_json(cont->data,
242 : : temp, buf_len) != 0)
243 : 2 : used = rte_tel_json_add_obj_json(
244 : : out_buf,
245 : : buf_len, used,
246 : 2 : v->name, temp);
247 [ + - ]: 2 : if (!cont->keep)
248 : 2 : rte_tel_data_free(cont->data);
249 : 2 : free(temp);
250 : 2 : break;
251 : : }
252 : : }
253 : : }
254 : :
255 : 23 : return used;
256 : : }
257 : :
258 : : static void
259 [ + + + + : 26 : output_json(const char *cmd, const struct rte_tel_data *d, int s)
- ]
260 : : {
261 : : char out_buf[MAX_OUTPUT_LEN];
262 : :
263 : : char *cb_data_buf;
264 : : size_t buf_len, prefix_used, used = 0;
265 : : unsigned int i;
266 : :
267 : : RTE_BUILD_BUG_ON(sizeof(out_buf) < MAX_CMD_LEN +
268 : : RTE_TEL_MAX_SINGLE_STRING_LEN + 10);
269 : :
270 : 26 : prefix_used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":",
271 : : MAX_CMD_LEN, cmd);
272 : 26 : cb_data_buf = &out_buf[prefix_used];
273 : 26 : buf_len = sizeof(out_buf) - prefix_used - 1; /* space for '}' */
274 : :
275 [ + + + + : 26 : switch (d->type) {
- ]
276 : : case TEL_NULL:
277 : : used = strlcpy(cb_data_buf, "null", buf_len);
278 : 1 : break;
279 : :
280 : 2 : case TEL_STRING:
281 : 2 : used = rte_tel_json_str(cb_data_buf, buf_len, 0, d->data.str);
282 : 2 : break;
283 : :
284 : 12 : case TEL_DICT:
285 : 12 : used = rte_tel_json_empty_obj(cb_data_buf, buf_len, 0);
286 [ + + ]: 46 : for (i = 0; i < d->data_len; i++) {
287 : : const struct tel_dict_entry *v = &d->data.dict[i];
288 [ + + + + : 34 : switch (v->type) {
- ]
289 : 13 : case RTE_TEL_STRING_VAL:
290 : 26 : used = rte_tel_json_add_obj_str(cb_data_buf,
291 : : buf_len, used,
292 : 13 : v->name, v->value.sval);
293 : 13 : break;
294 : 5 : case RTE_TEL_INT_VAL:
295 : 10 : used = rte_tel_json_add_obj_int(cb_data_buf,
296 : : buf_len, used,
297 : 5 : v->name, v->value.ival);
298 : 5 : break;
299 : 5 : case RTE_TEL_UINT_VAL:
300 : 10 : used = rte_tel_json_add_obj_uint(cb_data_buf,
301 : : buf_len, used,
302 : 5 : v->name, v->value.uval);
303 : 5 : break;
304 : 11 : case RTE_TEL_CONTAINER:
305 : : {
306 : 11 : char *temp = malloc(buf_len);
307 [ + - ]: 11 : if (temp == NULL)
308 : : break;
309 : 11 : *temp = '\0'; /* ensure valid string */
310 : :
311 : : const struct container *cont =
312 : : &v->value.container;
313 [ + - ]: 11 : if (container_to_json(cont->data,
314 : : temp, buf_len) != 0)
315 : 11 : used = rte_tel_json_add_obj_json(
316 : : cb_data_buf,
317 : : buf_len, used,
318 : 11 : v->name, temp);
319 [ + - ]: 11 : if (!cont->keep)
320 : 11 : rte_tel_data_free(cont->data);
321 : 11 : free(temp);
322 : : }
323 : : }
324 : : }
325 : : break;
326 : :
327 : 11 : case TEL_ARRAY_STRING:
328 : : case TEL_ARRAY_INT:
329 : : case TEL_ARRAY_UINT:
330 : : case TEL_ARRAY_CONTAINER:
331 : 11 : used = rte_tel_json_empty_array(cb_data_buf, buf_len, 0);
332 [ + + ]: 46 : for (i = 0; i < d->data_len; i++)
333 [ + + ]: 35 : if (d->type == TEL_ARRAY_STRING)
334 : 15 : used = rte_tel_json_add_array_string(
335 : : cb_data_buf,
336 : : buf_len, used,
337 : 15 : d->data.array[i].sval);
338 [ + + ]: 20 : else if (d->type == TEL_ARRAY_INT)
339 : 5 : used = rte_tel_json_add_array_int(cb_data_buf,
340 : : buf_len, used,
341 : 5 : d->data.array[i].ival);
342 [ + + ]: 15 : else if (d->type == TEL_ARRAY_UINT)
343 : 5 : used = rte_tel_json_add_array_uint(cb_data_buf,
344 : : buf_len, used,
345 : 5 : d->data.array[i].uval);
346 [ + - ]: 10 : else if (d->type == TEL_ARRAY_CONTAINER) {
347 : 10 : char *temp = malloc(buf_len);
348 [ + - ]: 10 : if (temp == NULL)
349 : : break;
350 : 10 : *temp = '\0'; /* ensure valid string */
351 : :
352 : : const struct container *rec_data =
353 : : &d->data.array[i].container;
354 [ + - ]: 10 : if (container_to_json(rec_data->data,
355 : : temp, buf_len) != 0)
356 : 10 : used = rte_tel_json_add_array_json(
357 : : cb_data_buf,
358 : : buf_len, used, temp);
359 [ + - ]: 10 : if (!rec_data->keep)
360 : 10 : rte_tel_data_free(rec_data->data);
361 : 10 : free(temp);
362 : : }
363 : : break;
364 : : }
365 : 26 : used += prefix_used;
366 : 26 : used += strlcat(out_buf + used, "}", sizeof(out_buf) - used);
367 [ - + ]: 26 : if (write(s, out_buf, used) < 0)
368 : 0 : perror("Error writing to socket");
369 : 26 : }
370 : :
371 : : static void
372 : 26 : perform_command(const struct cmd_callback *cb, const char *cmd, const char *param, int s)
373 : : {
374 : 26 : struct rte_tel_data data = {0};
375 : : int ret;
376 : :
377 [ - + ]: 26 : if (cb->fn_arg != NULL)
378 : 0 : ret = cb->fn_arg(cmd, param, cb->arg, &data);
379 : : else
380 : 26 : ret = cb->fn(cmd, param, &data);
381 : :
382 [ - + ]: 26 : if (ret < 0) {
383 : : char out_buf[MAX_CMD_LEN + 10];
384 [ # # ]: 0 : int used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":null}",
385 : : MAX_CMD_LEN, cmd ? cmd : "none");
386 [ # # ]: 0 : if (write(s, out_buf, used) < 0)
387 : 0 : perror("Error writing to socket");
388 : : return;
389 : : }
390 : 26 : output_json(cmd, &data, s);
391 : : }
392 : :
393 : : static int
394 : 0 : unknown_command(const char *cmd __rte_unused, const char *params __rte_unused,
395 : : struct rte_tel_data *d)
396 : : {
397 : 0 : return d->type = TEL_NULL;
398 : : }
399 : :
400 : : static void *
401 : 5 : client_handler(void *sock_id)
402 : : {
403 : 5 : int s = (int)(uintptr_t)sock_id;
404 : : char buffer[1024];
405 : : char info_str[1024];
406 : 5 : snprintf(info_str, sizeof(info_str),
407 : : "{\"version\":\"%s\",\"pid\":%d,\"max_output_len\":%d}",
408 : : telemetry_version, getpid(), MAX_OUTPUT_LEN);
409 [ + + ]: 5 : if (write(s, info_str, strlen(info_str)) < 0) {
410 : 4 : TMTY_LOG_LINE(DEBUG, "Socket write base info to client failed");
411 : 4 : goto exit;
412 : : }
413 : :
414 : : /* receive data is not null terminated */
415 : 1 : int bytes = read(s, buffer, sizeof(buffer) - 1);
416 [ + + ]: 27 : while (bytes > 0) {
417 : 26 : buffer[bytes] = 0;
418 : 26 : const char *cmd = strtok(buffer, ",");
419 : 26 : const char *param = strtok(NULL, "\0");
420 : 26 : struct cmd_callback cb = {.fn = unknown_command};
421 : : int i;
422 : :
423 [ + - + - ]: 26 : if (cmd && strlen(cmd) < MAX_CMD_LEN) {
424 : : rte_spinlock_lock(&callback_sl);
425 [ + - ]: 2470 : for (i = 0; i < num_callbacks; i++)
426 [ + + ]: 2470 : if (strcmp(cmd, callbacks[i].cmd) == 0) {
427 : 26 : cb = callbacks[i];
428 : 26 : break;
429 : : }
430 : : rte_spinlock_unlock(&callback_sl);
431 : : }
432 : 26 : perform_command(&cb, cmd, param, s);
433 : :
434 : 26 : bytes = read(s, buffer, sizeof(buffer) - 1);
435 : : }
436 : 1 : exit:
437 : 5 : close(s);
438 : 5 : rte_atomic_fetch_sub_explicit(&v2_clients, 1, rte_memory_order_relaxed);
439 : 5 : return NULL;
440 : : }
441 : :
442 : : static void *
443 : 268 : socket_listener(void *socket)
444 : : {
445 : : while (1) {
446 : : pthread_t th;
447 : : int rc;
448 : : struct socket *s = (struct socket *)socket;
449 : 277 : int s_accepted = accept(s->sock, NULL, NULL);
450 [ - + ]: 9 : if (s_accepted < 0) {
451 : 0 : TMTY_LOG_LINE(ERR, "Error with accept, telemetry thread quitting");
452 : 0 : return NULL;
453 : : }
454 [ + + ]: 9 : if (s->num_clients != NULL) {
455 : 5 : uint16_t conns = rte_atomic_load_explicit(s->num_clients,
456 : : rte_memory_order_relaxed);
457 [ - + ]: 5 : if (conns >= MAX_CONNECTIONS) {
458 : 0 : close(s_accepted);
459 : 0 : continue;
460 : : }
461 : 5 : rte_atomic_fetch_add_explicit(s->num_clients, 1,
462 : : rte_memory_order_relaxed);
463 : : }
464 : 9 : rc = pthread_create(&th, NULL, s->fn,
465 : 9 : (void *)(uintptr_t)s_accepted);
466 [ - + ]: 9 : if (rc != 0) {
467 : 0 : TMTY_LOG_LINE(ERR, "Error with create client thread: %s",
468 : : strerror(rc));
469 : 0 : close(s_accepted);
470 [ # # ]: 0 : if (s->num_clients != NULL)
471 : 0 : rte_atomic_fetch_sub_explicit(s->num_clients, 1,
472 : : rte_memory_order_relaxed);
473 : 0 : continue;
474 : : }
475 : 9 : pthread_detach(th);
476 : : }
477 : : return NULL;
478 : : }
479 : :
480 : : static inline char *
481 : : get_socket_path(const char *runtime_dir, const int version)
482 : : {
483 : : static char path[PATH_MAX];
484 : 155 : snprintf(path, sizeof(path), "%s/dpdk_telemetry.v%d",
485 : 155 : strlen(runtime_dir) ? runtime_dir : "/tmp", version);
486 : : return path;
487 : : }
488 : :
489 : : static void
490 : 155 : unlink_sockets(void)
491 : : {
492 [ + - ]: 155 : if (v2_socket.path[0])
493 : 155 : unlink(v2_socket.path);
494 [ + + ]: 155 : if (v1_socket.path[0])
495 : 151 : unlink(v1_socket.path);
496 : 155 : }
497 : :
498 : : static int
499 : 314 : create_socket(char *path)
500 : : {
501 : 314 : int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
502 [ - + ]: 314 : if (sock < 0) {
503 : 0 : TMTY_LOG_LINE(ERR, "Error with socket creation, %s", strerror(errno));
504 : 0 : return -1;
505 : : }
506 : :
507 : 314 : struct sockaddr_un sun = {.sun_family = AF_UNIX};
508 : : strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
509 : 314 : TMTY_LOG_LINE(DEBUG, "Attempting socket bind to path '%s'", path);
510 : :
511 [ + + ]: 314 : if (bind(sock, (void *) &sun, sizeof(sun)) < 0) {
512 : : struct stat st;
513 : :
514 : 8 : TMTY_LOG_LINE(DEBUG, "Initial bind to socket '%s' failed.", path);
515 : :
516 : : /* first check if we have a runtime dir */
517 [ + - - + ]: 8 : if (stat(socket_dir, &st) < 0 || !S_ISDIR(st.st_mode)) {
518 : 0 : TMTY_LOG_LINE(ERR, "Cannot access DPDK runtime directory: %s", socket_dir);
519 : 0 : close(sock);
520 : 8 : return -ENOENT;
521 : : }
522 : :
523 : : /* check if current socket is active */
524 [ + - ]: 8 : if (connect(sock, (void *)&sun, sizeof(sun)) == 0) {
525 : 8 : close(sock);
526 : 8 : return -EADDRINUSE;
527 : : }
528 : :
529 : : /* socket is not active, delete and attempt rebind */
530 : 0 : TMTY_LOG_LINE(DEBUG, "Attempting unlink and retrying bind");
531 : 0 : unlink(sun.sun_path);
532 [ # # ]: 0 : if (bind(sock, (void *) &sun, sizeof(sun)) < 0) {
533 : 0 : TMTY_LOG_LINE(ERR, "Error binding socket: %s", strerror(errno));
534 : 0 : close(sock);
535 : 0 : return -errno; /* if unlink failed, this will be -EADDRINUSE as above */
536 : : }
537 : : }
538 : :
539 [ - + ]: 306 : if (listen(sock, 1) < 0) {
540 : 0 : TMTY_LOG_LINE(ERR, "Error calling listen for socket: %s", strerror(errno));
541 : 0 : unlink(sun.sun_path);
542 : 0 : close(sock);
543 : 0 : return -errno;
544 : : }
545 : 306 : TMTY_LOG_LINE(DEBUG, "Socket creation and binding ok");
546 : :
547 : 306 : return sock;
548 : : }
549 : :
550 : : static void
551 : : set_thread_name(pthread_t id __rte_unused, const char *name __rte_unused)
552 : : {
553 : : #if defined RTE_EXEC_ENV_LINUX && defined __GLIBC__ && defined __GLIBC_PREREQ
554 : : #if __GLIBC_PREREQ(2, 12)
555 : 306 : pthread_setname_np(id, name);
556 : : #endif
557 : : #elif defined RTE_EXEC_ENV_FREEBSD
558 : : pthread_set_name_np(id, name);
559 : : #endif
560 : : }
561 : :
562 : : static int
563 : 155 : telemetry_legacy_init(void)
564 : : {
565 : : pthread_t t_old;
566 : : int rc;
567 : :
568 [ - + ]: 155 : if (num_legacy_callbacks == 1) {
569 : 0 : TMTY_LOG_LINE(DEBUG, "No legacy callbacks, legacy socket not created");
570 : 0 : return -1;
571 : : }
572 : :
573 : 155 : v1_socket.fn = legacy_client_handler;
574 [ - + ]: 155 : if ((size_t) snprintf(v1_socket.path, sizeof(v1_socket.path),
575 : : "%s/telemetry", socket_dir) >= sizeof(v1_socket.path)) {
576 : 0 : TMTY_LOG_LINE(ERR, "Error with socket binding, path too long");
577 : 0 : return -1;
578 : : }
579 : 155 : v1_socket.sock = create_socket(v1_socket.path);
580 [ + + ]: 155 : if (v1_socket.sock < 0) {
581 : 4 : v1_socket.path[0] = '\0';
582 : 4 : return -1;
583 : : }
584 : 151 : rc = pthread_create(&t_old, NULL, socket_listener, &v1_socket);
585 [ - + ]: 151 : if (rc != 0) {
586 : 0 : TMTY_LOG_LINE(ERR, "Error with create legacy socket thread: %s",
587 : : strerror(rc));
588 : 0 : close(v1_socket.sock);
589 : 0 : v1_socket.sock = -1;
590 : 0 : unlink(v1_socket.path);
591 : 0 : v1_socket.path[0] = '\0';
592 : 0 : return -1;
593 : : }
594 : 151 : pthread_setaffinity_np(t_old, sizeof(*thread_cpuset), thread_cpuset);
595 : 151 : set_thread_name(t_old, "dpdk-telemet-v1");
596 : 151 : TMTY_LOG_LINE(DEBUG, "Legacy telemetry socket initialized ok");
597 : 151 : pthread_detach(t_old);
598 : 151 : return 0;
599 : : }
600 : :
601 : : static int
602 : 155 : telemetry_v2_init(void)
603 : : {
604 : : char spath[sizeof(v2_socket.path)];
605 : : pthread_t t_new;
606 : : short suffix = 0;
607 : : int rc;
608 : :
609 : 155 : v2_socket.num_clients = &v2_clients;
610 : 155 : rte_telemetry_register_cmd("/", list_commands,
611 : : "Returns list of available commands, Takes no parameters");
612 : 155 : rte_telemetry_register_cmd("/info", json_info,
613 : : "Returns DPDK Telemetry information. Takes no parameters");
614 : 155 : rte_telemetry_register_cmd("/help", command_help,
615 : : "Returns help text for a command. Parameters: string command");
616 : 155 : v2_socket.fn = client_handler;
617 [ - + - + ]: 155 : if (strlcpy(spath, get_socket_path(socket_dir, 2), sizeof(spath)) >= sizeof(spath)) {
618 : 0 : TMTY_LOG_LINE(ERR, "Error with socket binding, path too long");
619 : 0 : return -1;
620 : : }
621 : : memcpy(v2_socket.path, spath, sizeof(v2_socket.path));
622 : :
623 : 155 : v2_socket.sock = create_socket(v2_socket.path);
624 [ + + ]: 159 : while (v2_socket.sock < 0) {
625 : : /* bail out on unexpected error, or suffix wrap-around */
626 [ + - - + ]: 4 : if (v2_socket.sock != -EADDRINUSE || suffix < 0) {
627 : 0 : v2_socket.path[0] = '\0'; /* clear socket path */
628 : 0 : return -1;
629 : : }
630 : : /* add a suffix to the path if the basic version fails */
631 : 4 : if (snprintf(v2_socket.path, sizeof(v2_socket.path), "%s:%d",
632 [ - + ]: 4 : spath, ++suffix) >= (int)sizeof(v2_socket.path)) {
633 : 0 : TMTY_LOG_LINE(ERR, "Error with socket binding, path too long");
634 : 0 : return -1;
635 : : }
636 : 4 : v2_socket.sock = create_socket(v2_socket.path);
637 : : }
638 : 155 : rc = pthread_create(&t_new, NULL, socket_listener, &v2_socket);
639 [ - + ]: 155 : if (rc != 0) {
640 : 0 : TMTY_LOG_LINE(ERR, "Error with create socket thread: %s",
641 : : strerror(rc));
642 : 0 : close(v2_socket.sock);
643 : 0 : v2_socket.sock = -1;
644 : 0 : unlink(v2_socket.path);
645 : 0 : v2_socket.path[0] = '\0';
646 : 0 : return -1;
647 : : }
648 : 155 : pthread_setaffinity_np(t_new, sizeof(*thread_cpuset), thread_cpuset);
649 : 155 : set_thread_name(t_new, "dpdk-telemet-v2");
650 : 155 : pthread_detach(t_new);
651 : 155 : atexit(unlink_sockets);
652 : :
653 : 155 : return 0;
654 : : }
655 : :
656 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
657 : :
658 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_telemetry_init)
659 : : int32_t
660 : 155 : rte_telemetry_init(const char *runtime_dir, const char *rte_version, rte_cpuset_t *cpuset)
661 : : {
662 : 155 : telemetry_version = rte_version;
663 : 155 : socket_dir = runtime_dir;
664 : 155 : thread_cpuset = cpuset;
665 : :
666 : : #ifndef RTE_EXEC_ENV_WINDOWS
667 [ + - ]: 155 : if (telemetry_v2_init() != 0)
668 : : return -1;
669 : 155 : TMTY_LOG_LINE(DEBUG, "Telemetry initialized ok");
670 : 155 : telemetry_legacy_init();
671 : : #endif /* RTE_EXEC_ENV_WINDOWS */
672 : :
673 : 155 : return 0;
674 : : }
|