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