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