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_TMTY logtype
60 : : #define TMTY_LOG_LINE(l, ...) RTE_LOG_LINE(l, TMTY, "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 : close(s);
382 : 4 : return NULL;
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 : close(s);
408 : 1 : rte_atomic_fetch_sub_explicit(&v2_clients, 1, rte_memory_order_relaxed);
409 : 1 : return NULL;
410 : : }
411 : :
412 : : static void *
413 : 278 : socket_listener(void *socket)
414 : : {
415 : : while (1) {
416 : : pthread_t th;
417 : : int rc;
418 : : struct socket *s = (struct socket *)socket;
419 : 287 : int s_accepted = accept(s->sock, NULL, NULL);
420 [ - + ]: 9 : if (s_accepted < 0) {
421 : 0 : TMTY_LOG_LINE(ERR, "Error with accept, telemetry thread quitting");
422 : 0 : return NULL;
423 : : }
424 [ + + ]: 9 : if (s->num_clients != NULL) {
425 : 5 : uint16_t conns = rte_atomic_load_explicit(s->num_clients,
426 : : rte_memory_order_relaxed);
427 [ - + ]: 5 : if (conns >= MAX_CONNECTIONS) {
428 : 0 : close(s_accepted);
429 : 0 : continue;
430 : : }
431 : 5 : rte_atomic_fetch_add_explicit(s->num_clients, 1,
432 : : rte_memory_order_relaxed);
433 : : }
434 : 9 : rc = pthread_create(&th, NULL, s->fn,
435 : 9 : (void *)(uintptr_t)s_accepted);
436 [ - + ]: 9 : if (rc != 0) {
437 : 0 : TMTY_LOG_LINE(ERR, "Error with create client thread: %s",
438 : : strerror(rc));
439 : 0 : close(s_accepted);
440 [ # # ]: 0 : if (s->num_clients != NULL)
441 : 0 : rte_atomic_fetch_sub_explicit(s->num_clients, 1,
442 : : rte_memory_order_relaxed);
443 : 0 : continue;
444 : : }
445 : 9 : pthread_detach(th);
446 : : }
447 : : return NULL;
448 : : }
449 : :
450 : : static inline char *
451 : : get_socket_path(const char *runtime_dir, const int version)
452 : : {
453 : : static char path[PATH_MAX];
454 : 144 : snprintf(path, sizeof(path), "%s/dpdk_telemetry.v%d",
455 : 144 : strlen(runtime_dir) ? runtime_dir : "/tmp", version);
456 : : return path;
457 : : }
458 : :
459 : : static void
460 : 144 : unlink_sockets(void)
461 : : {
462 [ + - ]: 144 : if (v2_socket.path[0])
463 : 144 : unlink(v2_socket.path);
464 [ + + ]: 144 : if (v1_socket.path[0])
465 : 140 : unlink(v1_socket.path);
466 : 144 : }
467 : :
468 : : static int
469 : 292 : create_socket(char *path)
470 : : {
471 : 292 : int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
472 [ - + ]: 292 : if (sock < 0) {
473 : 0 : TMTY_LOG_LINE(ERR, "Error with socket creation, %s", strerror(errno));
474 : 0 : return -1;
475 : : }
476 : :
477 : 292 : struct sockaddr_un sun = {.sun_family = AF_UNIX};
478 : : strlcpy(sun.sun_path, path, sizeof(sun.sun_path));
479 : 292 : TMTY_LOG_LINE(DEBUG, "Attempting socket bind to path '%s'", path);
480 : :
481 [ + + ]: 292 : if (bind(sock, (void *) &sun, sizeof(sun)) < 0) {
482 : : struct stat st;
483 : :
484 : 8 : TMTY_LOG_LINE(DEBUG, "Initial bind to socket '%s' failed.", path);
485 : :
486 : : /* first check if we have a runtime dir */
487 [ + - - + ]: 8 : if (stat(socket_dir, &st) < 0 || !S_ISDIR(st.st_mode)) {
488 : 0 : TMTY_LOG_LINE(ERR, "Cannot access DPDK runtime directory: %s", socket_dir);
489 : 0 : close(sock);
490 : 8 : return -ENOENT;
491 : : }
492 : :
493 : : /* check if current socket is active */
494 [ + - ]: 8 : if (connect(sock, (void *)&sun, sizeof(sun)) == 0) {
495 : 8 : close(sock);
496 : 8 : return -EADDRINUSE;
497 : : }
498 : :
499 : : /* socket is not active, delete and attempt rebind */
500 : 0 : TMTY_LOG_LINE(DEBUG, "Attempting unlink and retrying bind");
501 : 0 : unlink(sun.sun_path);
502 [ # # ]: 0 : if (bind(sock, (void *) &sun, sizeof(sun)) < 0) {
503 : 0 : TMTY_LOG_LINE(ERR, "Error binding socket: %s", strerror(errno));
504 : 0 : close(sock);
505 : 0 : return -errno; /* if unlink failed, this will be -EADDRINUSE as above */
506 : : }
507 : : }
508 : :
509 [ - + ]: 284 : if (listen(sock, 1) < 0) {
510 : 0 : TMTY_LOG_LINE(ERR, "Error calling listen for socket: %s", strerror(errno));
511 : 0 : unlink(sun.sun_path);
512 : 0 : close(sock);
513 : 0 : return -errno;
514 : : }
515 : 284 : TMTY_LOG_LINE(DEBUG, "Socket creation and binding ok");
516 : :
517 : 284 : return sock;
518 : : }
519 : :
520 : : static void
521 : : set_thread_name(pthread_t id __rte_unused, const char *name __rte_unused)
522 : : {
523 : : #if defined RTE_EXEC_ENV_LINUX && defined __GLIBC__ && defined __GLIBC_PREREQ
524 : : #if __GLIBC_PREREQ(2, 12)
525 : 284 : pthread_setname_np(id, name);
526 : : #endif
527 : : #elif defined RTE_EXEC_ENV_FREEBSD
528 : : pthread_set_name_np(id, name);
529 : : #endif
530 : : }
531 : :
532 : : static int
533 : 144 : telemetry_legacy_init(void)
534 : : {
535 : : pthread_t t_old;
536 : : int rc;
537 : :
538 [ - + ]: 144 : if (num_legacy_callbacks == 1) {
539 : 0 : TMTY_LOG_LINE(WARNING, "No legacy callbacks, legacy socket not created");
540 : 0 : return -1;
541 : : }
542 : :
543 : 144 : v1_socket.fn = legacy_client_handler;
544 [ - + ]: 144 : if ((size_t) snprintf(v1_socket.path, sizeof(v1_socket.path),
545 : : "%s/telemetry", socket_dir) >= sizeof(v1_socket.path)) {
546 : 0 : TMTY_LOG_LINE(ERR, "Error with socket binding, path too long");
547 : 0 : return -1;
548 : : }
549 : 144 : v1_socket.sock = create_socket(v1_socket.path);
550 [ + + ]: 144 : if (v1_socket.sock < 0) {
551 : 4 : v1_socket.path[0] = '\0';
552 : 4 : return -1;
553 : : }
554 : 140 : rc = pthread_create(&t_old, NULL, socket_listener, &v1_socket);
555 [ - + ]: 140 : if (rc != 0) {
556 : 0 : TMTY_LOG_LINE(ERR, "Error with create legacy socket thread: %s",
557 : : strerror(rc));
558 : 0 : close(v1_socket.sock);
559 : 0 : v1_socket.sock = -1;
560 : 0 : unlink(v1_socket.path);
561 : 0 : v1_socket.path[0] = '\0';
562 : 0 : return -1;
563 : : }
564 : 140 : pthread_setaffinity_np(t_old, sizeof(*thread_cpuset), thread_cpuset);
565 : 140 : set_thread_name(t_old, "dpdk-telemet-v1");
566 : 140 : TMTY_LOG_LINE(DEBUG, "Legacy telemetry socket initialized ok");
567 : 140 : pthread_detach(t_old);
568 : 140 : return 0;
569 : : }
570 : :
571 : : static int
572 : 144 : telemetry_v2_init(void)
573 : : {
574 : : char spath[sizeof(v2_socket.path)];
575 : : pthread_t t_new;
576 : : short suffix = 0;
577 : : int rc;
578 : :
579 : 144 : v2_socket.num_clients = &v2_clients;
580 : 144 : rte_telemetry_register_cmd("/", list_commands,
581 : : "Returns list of available commands, Takes no parameters");
582 : 144 : rte_telemetry_register_cmd("/info", json_info,
583 : : "Returns DPDK Telemetry information. Takes no parameters");
584 : 144 : rte_telemetry_register_cmd("/help", command_help,
585 : : "Returns help text for a command. Parameters: string command");
586 : 144 : v2_socket.fn = client_handler;
587 [ - + - + ]: 144 : if (strlcpy(spath, get_socket_path(socket_dir, 2), sizeof(spath)) >= sizeof(spath)) {
588 : 0 : TMTY_LOG_LINE(ERR, "Error with socket binding, path too long");
589 : 0 : return -1;
590 : : }
591 : : memcpy(v2_socket.path, spath, sizeof(v2_socket.path));
592 : :
593 : 144 : v2_socket.sock = create_socket(v2_socket.path);
594 [ + + ]: 148 : while (v2_socket.sock < 0) {
595 : : /* bail out on unexpected error, or suffix wrap-around */
596 [ + - - + ]: 4 : if (v2_socket.sock != -EADDRINUSE || suffix < 0) {
597 : 0 : v2_socket.path[0] = '\0'; /* clear socket path */
598 : 0 : return -1;
599 : : }
600 : : /* add a suffix to the path if the basic version fails */
601 : 4 : if (snprintf(v2_socket.path, sizeof(v2_socket.path), "%s:%d",
602 [ - + ]: 4 : spath, ++suffix) >= (int)sizeof(v2_socket.path)) {
603 : 0 : TMTY_LOG_LINE(ERR, "Error with socket binding, path too long");
604 : 0 : return -1;
605 : : }
606 : 4 : v2_socket.sock = create_socket(v2_socket.path);
607 : : }
608 : 144 : rc = pthread_create(&t_new, NULL, socket_listener, &v2_socket);
609 [ - + ]: 144 : if (rc != 0) {
610 : 0 : TMTY_LOG_LINE(ERR, "Error with create socket thread: %s",
611 : : strerror(rc));
612 : 0 : close(v2_socket.sock);
613 : 0 : v2_socket.sock = -1;
614 : 0 : unlink(v2_socket.path);
615 : 0 : v2_socket.path[0] = '\0';
616 : 0 : return -1;
617 : : }
618 : 144 : pthread_setaffinity_np(t_new, sizeof(*thread_cpuset), thread_cpuset);
619 : 144 : set_thread_name(t_new, "dpdk-telemet-v2");
620 : 144 : pthread_detach(t_new);
621 : 144 : atexit(unlink_sockets);
622 : :
623 : 144 : return 0;
624 : : }
625 : :
626 : : #endif /* !RTE_EXEC_ENV_WINDOWS */
627 : :
628 : : int32_t
629 : 144 : rte_telemetry_init(const char *runtime_dir, const char *rte_version, rte_cpuset_t *cpuset)
630 : : {
631 : 144 : telemetry_version = rte_version;
632 : 144 : socket_dir = runtime_dir;
633 : 144 : thread_cpuset = cpuset;
634 : :
635 : : #ifndef RTE_EXEC_ENV_WINDOWS
636 [ + - ]: 144 : if (telemetry_v2_init() != 0)
637 : : return -1;
638 : 144 : TMTY_LOG_LINE(DEBUG, "Telemetry initialized ok");
639 : 144 : telemetry_legacy_init();
640 : : #endif /* RTE_EXEC_ENV_WINDOWS */
641 : :
642 : 144 : return 0;
643 : : }
|