1*99a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 2*99a2dd95SBruce Richardson * Copyright(c) 2020 Intel Corporation 3*99a2dd95SBruce Richardson */ 4*99a2dd95SBruce Richardson 5*99a2dd95SBruce Richardson #ifndef RTE_EXEC_ENV_WINDOWS 6*99a2dd95SBruce Richardson #include <unistd.h> 7*99a2dd95SBruce Richardson #include <pthread.h> 8*99a2dd95SBruce Richardson #include <sys/socket.h> 9*99a2dd95SBruce Richardson #include <sys/un.h> 10*99a2dd95SBruce Richardson #include <dlfcn.h> 11*99a2dd95SBruce Richardson #endif /* !RTE_EXEC_ENV_WINDOWS */ 12*99a2dd95SBruce Richardson 13*99a2dd95SBruce Richardson /* we won't link against libbsd, so just always use DPDKs-specific strlcpy */ 14*99a2dd95SBruce Richardson #undef RTE_USE_LIBBSD 15*99a2dd95SBruce Richardson #include <rte_string_fns.h> 16*99a2dd95SBruce Richardson #include <rte_common.h> 17*99a2dd95SBruce Richardson #include <rte_spinlock.h> 18*99a2dd95SBruce Richardson #include <rte_log.h> 19*99a2dd95SBruce Richardson 20*99a2dd95SBruce Richardson #include "rte_telemetry.h" 21*99a2dd95SBruce Richardson #include "telemetry_json.h" 22*99a2dd95SBruce Richardson #include "telemetry_data.h" 23*99a2dd95SBruce Richardson #include "telemetry_internal.h" 24*99a2dd95SBruce Richardson 25*99a2dd95SBruce Richardson #define MAX_CMD_LEN 56 26*99a2dd95SBruce Richardson #define MAX_HELP_LEN 64 27*99a2dd95SBruce Richardson #define MAX_OUTPUT_LEN (1024 * 16) 28*99a2dd95SBruce Richardson #define MAX_CONNECTIONS 10 29*99a2dd95SBruce Richardson 30*99a2dd95SBruce Richardson #ifndef RTE_EXEC_ENV_WINDOWS 31*99a2dd95SBruce Richardson static void * 32*99a2dd95SBruce Richardson client_handler(void *socket); 33*99a2dd95SBruce Richardson #endif /* !RTE_EXEC_ENV_WINDOWS */ 34*99a2dd95SBruce Richardson 35*99a2dd95SBruce Richardson struct cmd_callback { 36*99a2dd95SBruce Richardson char cmd[MAX_CMD_LEN]; 37*99a2dd95SBruce Richardson telemetry_cb fn; 38*99a2dd95SBruce Richardson char help[MAX_HELP_LEN]; 39*99a2dd95SBruce Richardson }; 40*99a2dd95SBruce Richardson 41*99a2dd95SBruce Richardson #ifndef RTE_EXEC_ENV_WINDOWS 42*99a2dd95SBruce Richardson struct socket { 43*99a2dd95SBruce Richardson int sock; 44*99a2dd95SBruce Richardson char path[sizeof(((struct sockaddr_un *)0)->sun_path)]; 45*99a2dd95SBruce Richardson handler fn; 46*99a2dd95SBruce Richardson uint16_t *num_clients; 47*99a2dd95SBruce Richardson }; 48*99a2dd95SBruce Richardson static struct socket v2_socket; /* socket for v2 telemetry */ 49*99a2dd95SBruce Richardson static struct socket v1_socket; /* socket for v1 telemetry */ 50*99a2dd95SBruce Richardson #endif /* !RTE_EXEC_ENV_WINDOWS */ 51*99a2dd95SBruce Richardson 52*99a2dd95SBruce Richardson static const char *telemetry_version; /* save rte_version */ 53*99a2dd95SBruce Richardson static const char *socket_dir; /* runtime directory */ 54*99a2dd95SBruce Richardson static rte_cpuset_t *thread_cpuset; 55*99a2dd95SBruce Richardson static rte_log_fn rte_log_ptr; 56*99a2dd95SBruce Richardson static uint32_t logtype; 57*99a2dd95SBruce Richardson 58*99a2dd95SBruce Richardson #define TMTY_LOG(l, ...) \ 59*99a2dd95SBruce Richardson rte_log_ptr(RTE_LOG_ ## l, logtype, "TELEMETRY: " __VA_ARGS__) 60*99a2dd95SBruce Richardson 61*99a2dd95SBruce Richardson /* list of command callbacks, with one command registered by default */ 62*99a2dd95SBruce Richardson static struct cmd_callback callbacks[TELEMETRY_MAX_CALLBACKS]; 63*99a2dd95SBruce Richardson static int num_callbacks; /* How many commands are registered */ 64*99a2dd95SBruce Richardson /* Used when accessing or modifying list of command callbacks */ 65*99a2dd95SBruce Richardson static rte_spinlock_t callback_sl = RTE_SPINLOCK_INITIALIZER; 66*99a2dd95SBruce Richardson #ifndef RTE_EXEC_ENV_WINDOWS 67*99a2dd95SBruce Richardson static uint16_t v2_clients; 68*99a2dd95SBruce Richardson #endif /* !RTE_EXEC_ENV_WINDOWS */ 69*99a2dd95SBruce Richardson 70*99a2dd95SBruce Richardson int 71*99a2dd95SBruce Richardson rte_telemetry_register_cmd(const char *cmd, telemetry_cb fn, const char *help) 72*99a2dd95SBruce Richardson { 73*99a2dd95SBruce Richardson int i = 0; 74*99a2dd95SBruce Richardson 75*99a2dd95SBruce Richardson if (strlen(cmd) >= MAX_CMD_LEN || fn == NULL || cmd[0] != '/' 76*99a2dd95SBruce Richardson || strlen(help) >= MAX_HELP_LEN) 77*99a2dd95SBruce Richardson return -EINVAL; 78*99a2dd95SBruce Richardson if (num_callbacks >= TELEMETRY_MAX_CALLBACKS) 79*99a2dd95SBruce Richardson return -ENOENT; 80*99a2dd95SBruce Richardson 81*99a2dd95SBruce Richardson rte_spinlock_lock(&callback_sl); 82*99a2dd95SBruce Richardson while (i < num_callbacks && strcmp(cmd, callbacks[i].cmd) > 0) 83*99a2dd95SBruce Richardson i++; 84*99a2dd95SBruce Richardson if (i != num_callbacks) 85*99a2dd95SBruce Richardson /* Move elements to keep the list alphabetical */ 86*99a2dd95SBruce Richardson memmove(callbacks + i + 1, callbacks + i, 87*99a2dd95SBruce Richardson sizeof(struct cmd_callback) * (num_callbacks - i)); 88*99a2dd95SBruce Richardson 89*99a2dd95SBruce Richardson strlcpy(callbacks[i].cmd, cmd, MAX_CMD_LEN); 90*99a2dd95SBruce Richardson callbacks[i].fn = fn; 91*99a2dd95SBruce Richardson strlcpy(callbacks[i].help, help, MAX_HELP_LEN); 92*99a2dd95SBruce Richardson num_callbacks++; 93*99a2dd95SBruce Richardson rte_spinlock_unlock(&callback_sl); 94*99a2dd95SBruce Richardson 95*99a2dd95SBruce Richardson return 0; 96*99a2dd95SBruce Richardson } 97*99a2dd95SBruce Richardson 98*99a2dd95SBruce Richardson #ifndef RTE_EXEC_ENV_WINDOWS 99*99a2dd95SBruce Richardson 100*99a2dd95SBruce Richardson static int 101*99a2dd95SBruce Richardson list_commands(const char *cmd __rte_unused, const char *params __rte_unused, 102*99a2dd95SBruce Richardson struct rte_tel_data *d) 103*99a2dd95SBruce Richardson { 104*99a2dd95SBruce Richardson int i; 105*99a2dd95SBruce Richardson 106*99a2dd95SBruce Richardson rte_tel_data_start_array(d, RTE_TEL_STRING_VAL); 107*99a2dd95SBruce Richardson for (i = 0; i < num_callbacks; i++) 108*99a2dd95SBruce Richardson rte_tel_data_add_array_string(d, callbacks[i].cmd); 109*99a2dd95SBruce Richardson return 0; 110*99a2dd95SBruce Richardson } 111*99a2dd95SBruce Richardson 112*99a2dd95SBruce Richardson static int 113*99a2dd95SBruce Richardson json_info(const char *cmd __rte_unused, const char *params __rte_unused, 114*99a2dd95SBruce Richardson struct rte_tel_data *d) 115*99a2dd95SBruce Richardson { 116*99a2dd95SBruce Richardson rte_tel_data_start_dict(d); 117*99a2dd95SBruce Richardson rte_tel_data_add_dict_string(d, "version", telemetry_version); 118*99a2dd95SBruce Richardson rte_tel_data_add_dict_int(d, "pid", getpid()); 119*99a2dd95SBruce Richardson rte_tel_data_add_dict_int(d, "max_output_len", MAX_OUTPUT_LEN); 120*99a2dd95SBruce Richardson return 0; 121*99a2dd95SBruce Richardson } 122*99a2dd95SBruce Richardson 123*99a2dd95SBruce Richardson static int 124*99a2dd95SBruce Richardson command_help(const char *cmd __rte_unused, const char *params, 125*99a2dd95SBruce Richardson struct rte_tel_data *d) 126*99a2dd95SBruce Richardson { 127*99a2dd95SBruce Richardson int i; 128*99a2dd95SBruce Richardson 129*99a2dd95SBruce Richardson if (!params) 130*99a2dd95SBruce Richardson return -1; 131*99a2dd95SBruce Richardson rte_tel_data_start_dict(d); 132*99a2dd95SBruce Richardson rte_spinlock_lock(&callback_sl); 133*99a2dd95SBruce Richardson for (i = 0; i < num_callbacks; i++) 134*99a2dd95SBruce Richardson if (strcmp(params, callbacks[i].cmd) == 0) { 135*99a2dd95SBruce Richardson rte_tel_data_add_dict_string(d, params, 136*99a2dd95SBruce Richardson callbacks[i].help); 137*99a2dd95SBruce Richardson break; 138*99a2dd95SBruce Richardson } 139*99a2dd95SBruce Richardson rte_spinlock_unlock(&callback_sl); 140*99a2dd95SBruce Richardson if (i == num_callbacks) 141*99a2dd95SBruce Richardson return -1; 142*99a2dd95SBruce Richardson return 0; 143*99a2dd95SBruce Richardson } 144*99a2dd95SBruce Richardson 145*99a2dd95SBruce Richardson static int 146*99a2dd95SBruce Richardson container_to_json(const struct rte_tel_data *d, char *out_buf, size_t buf_len) 147*99a2dd95SBruce Richardson { 148*99a2dd95SBruce Richardson size_t used = 0; 149*99a2dd95SBruce Richardson unsigned int i; 150*99a2dd95SBruce Richardson 151*99a2dd95SBruce Richardson if (d->type != RTE_TEL_ARRAY_U64 && d->type != RTE_TEL_ARRAY_INT 152*99a2dd95SBruce Richardson && d->type != RTE_TEL_ARRAY_STRING) 153*99a2dd95SBruce Richardson return snprintf(out_buf, buf_len, "null"); 154*99a2dd95SBruce Richardson 155*99a2dd95SBruce Richardson used = rte_tel_json_empty_array(out_buf, buf_len, 0); 156*99a2dd95SBruce Richardson if (d->type == RTE_TEL_ARRAY_U64) 157*99a2dd95SBruce Richardson for (i = 0; i < d->data_len; i++) 158*99a2dd95SBruce Richardson used = rte_tel_json_add_array_u64(out_buf, 159*99a2dd95SBruce Richardson buf_len, used, 160*99a2dd95SBruce Richardson d->data.array[i].u64val); 161*99a2dd95SBruce Richardson if (d->type == RTE_TEL_ARRAY_INT) 162*99a2dd95SBruce Richardson for (i = 0; i < d->data_len; i++) 163*99a2dd95SBruce Richardson used = rte_tel_json_add_array_int(out_buf, 164*99a2dd95SBruce Richardson buf_len, used, 165*99a2dd95SBruce Richardson d->data.array[i].ival); 166*99a2dd95SBruce Richardson if (d->type == RTE_TEL_ARRAY_STRING) 167*99a2dd95SBruce Richardson for (i = 0; i < d->data_len; i++) 168*99a2dd95SBruce Richardson used = rte_tel_json_add_array_string(out_buf, 169*99a2dd95SBruce Richardson buf_len, used, 170*99a2dd95SBruce Richardson d->data.array[i].sval); 171*99a2dd95SBruce Richardson return used; 172*99a2dd95SBruce Richardson } 173*99a2dd95SBruce Richardson 174*99a2dd95SBruce Richardson static void 175*99a2dd95SBruce Richardson output_json(const char *cmd, const struct rte_tel_data *d, int s) 176*99a2dd95SBruce Richardson { 177*99a2dd95SBruce Richardson char out_buf[MAX_OUTPUT_LEN]; 178*99a2dd95SBruce Richardson 179*99a2dd95SBruce Richardson char *cb_data_buf; 180*99a2dd95SBruce Richardson size_t buf_len, prefix_used, used = 0; 181*99a2dd95SBruce Richardson unsigned int i; 182*99a2dd95SBruce Richardson 183*99a2dd95SBruce Richardson RTE_BUILD_BUG_ON(sizeof(out_buf) < MAX_CMD_LEN + 184*99a2dd95SBruce Richardson RTE_TEL_MAX_SINGLE_STRING_LEN + 10); 185*99a2dd95SBruce Richardson switch (d->type) { 186*99a2dd95SBruce Richardson case RTE_TEL_NULL: 187*99a2dd95SBruce Richardson used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":null}", 188*99a2dd95SBruce Richardson MAX_CMD_LEN, cmd ? cmd : "none"); 189*99a2dd95SBruce Richardson break; 190*99a2dd95SBruce Richardson case RTE_TEL_STRING: 191*99a2dd95SBruce Richardson used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":\"%.*s\"}", 192*99a2dd95SBruce Richardson MAX_CMD_LEN, cmd, 193*99a2dd95SBruce Richardson RTE_TEL_MAX_SINGLE_STRING_LEN, d->data.str); 194*99a2dd95SBruce Richardson break; 195*99a2dd95SBruce Richardson case RTE_TEL_DICT: 196*99a2dd95SBruce Richardson prefix_used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":", 197*99a2dd95SBruce Richardson MAX_CMD_LEN, cmd); 198*99a2dd95SBruce Richardson cb_data_buf = &out_buf[prefix_used]; 199*99a2dd95SBruce Richardson buf_len = sizeof(out_buf) - prefix_used - 1; /* space for '}' */ 200*99a2dd95SBruce Richardson 201*99a2dd95SBruce Richardson used = rte_tel_json_empty_obj(cb_data_buf, buf_len, 0); 202*99a2dd95SBruce Richardson for (i = 0; i < d->data_len; i++) { 203*99a2dd95SBruce Richardson const struct tel_dict_entry *v = &d->data.dict[i]; 204*99a2dd95SBruce Richardson switch (v->type) { 205*99a2dd95SBruce Richardson case RTE_TEL_STRING_VAL: 206*99a2dd95SBruce Richardson used = rte_tel_json_add_obj_str(cb_data_buf, 207*99a2dd95SBruce Richardson buf_len, used, 208*99a2dd95SBruce Richardson v->name, v->value.sval); 209*99a2dd95SBruce Richardson break; 210*99a2dd95SBruce Richardson case RTE_TEL_INT_VAL: 211*99a2dd95SBruce Richardson used = rte_tel_json_add_obj_int(cb_data_buf, 212*99a2dd95SBruce Richardson buf_len, used, 213*99a2dd95SBruce Richardson v->name, v->value.ival); 214*99a2dd95SBruce Richardson break; 215*99a2dd95SBruce Richardson case RTE_TEL_U64_VAL: 216*99a2dd95SBruce Richardson used = rte_tel_json_add_obj_u64(cb_data_buf, 217*99a2dd95SBruce Richardson buf_len, used, 218*99a2dd95SBruce Richardson v->name, v->value.u64val); 219*99a2dd95SBruce Richardson break; 220*99a2dd95SBruce Richardson case RTE_TEL_CONTAINER: 221*99a2dd95SBruce Richardson { 222*99a2dd95SBruce Richardson char temp[buf_len]; 223*99a2dd95SBruce Richardson const struct container *cont = 224*99a2dd95SBruce Richardson &v->value.container; 225*99a2dd95SBruce Richardson if (container_to_json(cont->data, 226*99a2dd95SBruce Richardson temp, buf_len) != 0) 227*99a2dd95SBruce Richardson used = rte_tel_json_add_obj_json( 228*99a2dd95SBruce Richardson cb_data_buf, 229*99a2dd95SBruce Richardson buf_len, used, 230*99a2dd95SBruce Richardson v->name, temp); 231*99a2dd95SBruce Richardson if (!cont->keep) 232*99a2dd95SBruce Richardson rte_tel_data_free(cont->data); 233*99a2dd95SBruce Richardson } 234*99a2dd95SBruce Richardson } 235*99a2dd95SBruce Richardson } 236*99a2dd95SBruce Richardson used += prefix_used; 237*99a2dd95SBruce Richardson used += strlcat(out_buf + used, "}", sizeof(out_buf) - used); 238*99a2dd95SBruce Richardson break; 239*99a2dd95SBruce Richardson case RTE_TEL_ARRAY_STRING: 240*99a2dd95SBruce Richardson case RTE_TEL_ARRAY_INT: 241*99a2dd95SBruce Richardson case RTE_TEL_ARRAY_U64: 242*99a2dd95SBruce Richardson case RTE_TEL_ARRAY_CONTAINER: 243*99a2dd95SBruce Richardson prefix_used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":", 244*99a2dd95SBruce Richardson MAX_CMD_LEN, cmd); 245*99a2dd95SBruce Richardson cb_data_buf = &out_buf[prefix_used]; 246*99a2dd95SBruce Richardson buf_len = sizeof(out_buf) - prefix_used - 1; /* space for '}' */ 247*99a2dd95SBruce Richardson 248*99a2dd95SBruce Richardson used = rte_tel_json_empty_array(cb_data_buf, buf_len, 0); 249*99a2dd95SBruce Richardson for (i = 0; i < d->data_len; i++) 250*99a2dd95SBruce Richardson if (d->type == RTE_TEL_ARRAY_STRING) 251*99a2dd95SBruce Richardson used = rte_tel_json_add_array_string( 252*99a2dd95SBruce Richardson cb_data_buf, 253*99a2dd95SBruce Richardson buf_len, used, 254*99a2dd95SBruce Richardson d->data.array[i].sval); 255*99a2dd95SBruce Richardson else if (d->type == RTE_TEL_ARRAY_INT) 256*99a2dd95SBruce Richardson used = rte_tel_json_add_array_int(cb_data_buf, 257*99a2dd95SBruce Richardson buf_len, used, 258*99a2dd95SBruce Richardson d->data.array[i].ival); 259*99a2dd95SBruce Richardson else if (d->type == RTE_TEL_ARRAY_U64) 260*99a2dd95SBruce Richardson used = rte_tel_json_add_array_u64(cb_data_buf, 261*99a2dd95SBruce Richardson buf_len, used, 262*99a2dd95SBruce Richardson d->data.array[i].u64val); 263*99a2dd95SBruce Richardson else if (d->type == RTE_TEL_ARRAY_CONTAINER) { 264*99a2dd95SBruce Richardson char temp[buf_len]; 265*99a2dd95SBruce Richardson const struct container *rec_data = 266*99a2dd95SBruce Richardson &d->data.array[i].container; 267*99a2dd95SBruce Richardson if (container_to_json(rec_data->data, 268*99a2dd95SBruce Richardson temp, buf_len) != 0) 269*99a2dd95SBruce Richardson used = rte_tel_json_add_array_json( 270*99a2dd95SBruce Richardson cb_data_buf, 271*99a2dd95SBruce Richardson buf_len, used, temp); 272*99a2dd95SBruce Richardson if (!rec_data->keep) 273*99a2dd95SBruce Richardson rte_tel_data_free(rec_data->data); 274*99a2dd95SBruce Richardson } 275*99a2dd95SBruce Richardson used += prefix_used; 276*99a2dd95SBruce Richardson used += strlcat(out_buf + used, "}", sizeof(out_buf) - used); 277*99a2dd95SBruce Richardson break; 278*99a2dd95SBruce Richardson } 279*99a2dd95SBruce Richardson if (write(s, out_buf, used) < 0) 280*99a2dd95SBruce Richardson perror("Error writing to socket"); 281*99a2dd95SBruce Richardson } 282*99a2dd95SBruce Richardson 283*99a2dd95SBruce Richardson static void 284*99a2dd95SBruce Richardson perform_command(telemetry_cb fn, const char *cmd, const char *param, int s) 285*99a2dd95SBruce Richardson { 286*99a2dd95SBruce Richardson struct rte_tel_data data; 287*99a2dd95SBruce Richardson 288*99a2dd95SBruce Richardson int ret = fn(cmd, param, &data); 289*99a2dd95SBruce Richardson if (ret < 0) { 290*99a2dd95SBruce Richardson char out_buf[MAX_CMD_LEN + 10]; 291*99a2dd95SBruce Richardson int used = snprintf(out_buf, sizeof(out_buf), "{\"%.*s\":null}", 292*99a2dd95SBruce Richardson MAX_CMD_LEN, cmd ? cmd : "none"); 293*99a2dd95SBruce Richardson if (write(s, out_buf, used) < 0) 294*99a2dd95SBruce Richardson perror("Error writing to socket"); 295*99a2dd95SBruce Richardson return; 296*99a2dd95SBruce Richardson } 297*99a2dd95SBruce Richardson output_json(cmd, &data, s); 298*99a2dd95SBruce Richardson } 299*99a2dd95SBruce Richardson 300*99a2dd95SBruce Richardson static int 301*99a2dd95SBruce Richardson unknown_command(const char *cmd __rte_unused, const char *params __rte_unused, 302*99a2dd95SBruce Richardson struct rte_tel_data *d) 303*99a2dd95SBruce Richardson { 304*99a2dd95SBruce Richardson return d->type = RTE_TEL_NULL; 305*99a2dd95SBruce Richardson } 306*99a2dd95SBruce Richardson 307*99a2dd95SBruce Richardson static void * 308*99a2dd95SBruce Richardson client_handler(void *sock_id) 309*99a2dd95SBruce Richardson { 310*99a2dd95SBruce Richardson int s = (int)(uintptr_t)sock_id; 311*99a2dd95SBruce Richardson char buffer[1024]; 312*99a2dd95SBruce Richardson char info_str[1024]; 313*99a2dd95SBruce Richardson snprintf(info_str, sizeof(info_str), 314*99a2dd95SBruce Richardson "{\"version\":\"%s\",\"pid\":%d,\"max_output_len\":%d}", 315*99a2dd95SBruce Richardson telemetry_version, getpid(), MAX_OUTPUT_LEN); 316*99a2dd95SBruce Richardson if (write(s, info_str, strlen(info_str)) < 0) { 317*99a2dd95SBruce Richardson close(s); 318*99a2dd95SBruce Richardson return NULL; 319*99a2dd95SBruce Richardson } 320*99a2dd95SBruce Richardson 321*99a2dd95SBruce Richardson /* receive data is not null terminated */ 322*99a2dd95SBruce Richardson int bytes = read(s, buffer, sizeof(buffer) - 1); 323*99a2dd95SBruce Richardson while (bytes > 0) { 324*99a2dd95SBruce Richardson buffer[bytes] = 0; 325*99a2dd95SBruce Richardson const char *cmd = strtok(buffer, ","); 326*99a2dd95SBruce Richardson const char *param = strtok(NULL, "\0"); 327*99a2dd95SBruce Richardson telemetry_cb fn = unknown_command; 328*99a2dd95SBruce Richardson int i; 329*99a2dd95SBruce Richardson 330*99a2dd95SBruce Richardson if (cmd && strlen(cmd) < MAX_CMD_LEN) { 331*99a2dd95SBruce Richardson rte_spinlock_lock(&callback_sl); 332*99a2dd95SBruce Richardson for (i = 0; i < num_callbacks; i++) 333*99a2dd95SBruce Richardson if (strcmp(cmd, callbacks[i].cmd) == 0) { 334*99a2dd95SBruce Richardson fn = callbacks[i].fn; 335*99a2dd95SBruce Richardson break; 336*99a2dd95SBruce Richardson } 337*99a2dd95SBruce Richardson rte_spinlock_unlock(&callback_sl); 338*99a2dd95SBruce Richardson } 339*99a2dd95SBruce Richardson perform_command(fn, cmd, param, s); 340*99a2dd95SBruce Richardson 341*99a2dd95SBruce Richardson bytes = read(s, buffer, sizeof(buffer) - 1); 342*99a2dd95SBruce Richardson } 343*99a2dd95SBruce Richardson close(s); 344*99a2dd95SBruce Richardson __atomic_sub_fetch(&v2_clients, 1, __ATOMIC_RELAXED); 345*99a2dd95SBruce Richardson return NULL; 346*99a2dd95SBruce Richardson } 347*99a2dd95SBruce Richardson 348*99a2dd95SBruce Richardson static void * 349*99a2dd95SBruce Richardson socket_listener(void *socket) 350*99a2dd95SBruce Richardson { 351*99a2dd95SBruce Richardson while (1) { 352*99a2dd95SBruce Richardson pthread_t th; 353*99a2dd95SBruce Richardson struct socket *s = (struct socket *)socket; 354*99a2dd95SBruce Richardson int s_accepted = accept(s->sock, NULL, NULL); 355*99a2dd95SBruce Richardson if (s_accepted < 0) { 356*99a2dd95SBruce Richardson TMTY_LOG(ERR, "Error with accept, telemetry thread quitting\n"); 357*99a2dd95SBruce Richardson return NULL; 358*99a2dd95SBruce Richardson } 359*99a2dd95SBruce Richardson if (s->num_clients != NULL) { 360*99a2dd95SBruce Richardson uint16_t conns = __atomic_load_n(s->num_clients, 361*99a2dd95SBruce Richardson __ATOMIC_RELAXED); 362*99a2dd95SBruce Richardson if (conns >= MAX_CONNECTIONS) { 363*99a2dd95SBruce Richardson close(s_accepted); 364*99a2dd95SBruce Richardson continue; 365*99a2dd95SBruce Richardson } 366*99a2dd95SBruce Richardson __atomic_add_fetch(s->num_clients, 1, 367*99a2dd95SBruce Richardson __ATOMIC_RELAXED); 368*99a2dd95SBruce Richardson } 369*99a2dd95SBruce Richardson pthread_create(&th, NULL, s->fn, (void *)(uintptr_t)s_accepted); 370*99a2dd95SBruce Richardson pthread_detach(th); 371*99a2dd95SBruce Richardson } 372*99a2dd95SBruce Richardson return NULL; 373*99a2dd95SBruce Richardson } 374*99a2dd95SBruce Richardson 375*99a2dd95SBruce Richardson static inline char * 376*99a2dd95SBruce Richardson get_socket_path(const char *runtime_dir, const int version) 377*99a2dd95SBruce Richardson { 378*99a2dd95SBruce Richardson static char path[PATH_MAX]; 379*99a2dd95SBruce Richardson snprintf(path, sizeof(path), "%s/dpdk_telemetry.v%d", 380*99a2dd95SBruce Richardson strlen(runtime_dir) ? runtime_dir : "/tmp", version); 381*99a2dd95SBruce Richardson return path; 382*99a2dd95SBruce Richardson } 383*99a2dd95SBruce Richardson 384*99a2dd95SBruce Richardson static void 385*99a2dd95SBruce Richardson unlink_sockets(void) 386*99a2dd95SBruce Richardson { 387*99a2dd95SBruce Richardson if (v2_socket.path[0]) 388*99a2dd95SBruce Richardson unlink(v2_socket.path); 389*99a2dd95SBruce Richardson if (v1_socket.path[0]) 390*99a2dd95SBruce Richardson unlink(v1_socket.path); 391*99a2dd95SBruce Richardson } 392*99a2dd95SBruce Richardson 393*99a2dd95SBruce Richardson static int 394*99a2dd95SBruce Richardson create_socket(char *path) 395*99a2dd95SBruce Richardson { 396*99a2dd95SBruce Richardson int sock = socket(AF_UNIX, SOCK_SEQPACKET, 0); 397*99a2dd95SBruce Richardson if (sock < 0) { 398*99a2dd95SBruce Richardson TMTY_LOG(ERR, "Error with socket creation, %s\n", strerror(errno)); 399*99a2dd95SBruce Richardson return -1; 400*99a2dd95SBruce Richardson } 401*99a2dd95SBruce Richardson 402*99a2dd95SBruce Richardson struct sockaddr_un sun = {.sun_family = AF_UNIX}; 403*99a2dd95SBruce Richardson strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); 404*99a2dd95SBruce Richardson unlink(sun.sun_path); 405*99a2dd95SBruce Richardson if (bind(sock, (void *) &sun, sizeof(sun)) < 0) { 406*99a2dd95SBruce Richardson TMTY_LOG(ERR, "Error binding socket: %s\n", strerror(errno)); 407*99a2dd95SBruce Richardson sun.sun_path[0] = 0; 408*99a2dd95SBruce Richardson goto error; 409*99a2dd95SBruce Richardson } 410*99a2dd95SBruce Richardson 411*99a2dd95SBruce Richardson if (listen(sock, 1) < 0) { 412*99a2dd95SBruce Richardson TMTY_LOG(ERR, "Error calling listen for socket: %s\n", strerror(errno)); 413*99a2dd95SBruce Richardson goto error; 414*99a2dd95SBruce Richardson } 415*99a2dd95SBruce Richardson 416*99a2dd95SBruce Richardson return sock; 417*99a2dd95SBruce Richardson 418*99a2dd95SBruce Richardson error: 419*99a2dd95SBruce Richardson close(sock); 420*99a2dd95SBruce Richardson unlink_sockets(); 421*99a2dd95SBruce Richardson return -1; 422*99a2dd95SBruce Richardson } 423*99a2dd95SBruce Richardson 424*99a2dd95SBruce Richardson static int 425*99a2dd95SBruce Richardson telemetry_legacy_init(void) 426*99a2dd95SBruce Richardson { 427*99a2dd95SBruce Richardson pthread_t t_old; 428*99a2dd95SBruce Richardson 429*99a2dd95SBruce Richardson if (num_legacy_callbacks == 1) { 430*99a2dd95SBruce Richardson TMTY_LOG(WARNING, "No legacy callbacks, legacy socket not created\n"); 431*99a2dd95SBruce Richardson return -1; 432*99a2dd95SBruce Richardson } 433*99a2dd95SBruce Richardson 434*99a2dd95SBruce Richardson v1_socket.fn = legacy_client_handler; 435*99a2dd95SBruce Richardson if ((size_t) snprintf(v1_socket.path, sizeof(v1_socket.path), 436*99a2dd95SBruce Richardson "%s/telemetry", socket_dir) >= sizeof(v1_socket.path)) { 437*99a2dd95SBruce Richardson TMTY_LOG(ERR, "Error with socket binding, path too long\n"); 438*99a2dd95SBruce Richardson return -1; 439*99a2dd95SBruce Richardson } 440*99a2dd95SBruce Richardson v1_socket.sock = create_socket(v1_socket.path); 441*99a2dd95SBruce Richardson if (v1_socket.sock < 0) 442*99a2dd95SBruce Richardson return -1; 443*99a2dd95SBruce Richardson pthread_create(&t_old, NULL, socket_listener, &v1_socket); 444*99a2dd95SBruce Richardson pthread_setaffinity_np(t_old, sizeof(*thread_cpuset), thread_cpuset); 445*99a2dd95SBruce Richardson 446*99a2dd95SBruce Richardson TMTY_LOG(DEBUG, "Legacy telemetry socket initialized ok\n"); 447*99a2dd95SBruce Richardson return 0; 448*99a2dd95SBruce Richardson } 449*99a2dd95SBruce Richardson 450*99a2dd95SBruce Richardson static int 451*99a2dd95SBruce Richardson telemetry_v2_init(void) 452*99a2dd95SBruce Richardson { 453*99a2dd95SBruce Richardson pthread_t t_new; 454*99a2dd95SBruce Richardson 455*99a2dd95SBruce Richardson v2_socket.num_clients = &v2_clients; 456*99a2dd95SBruce Richardson rte_telemetry_register_cmd("/", list_commands, 457*99a2dd95SBruce Richardson "Returns list of available commands, Takes no parameters"); 458*99a2dd95SBruce Richardson rte_telemetry_register_cmd("/info", json_info, 459*99a2dd95SBruce Richardson "Returns DPDK Telemetry information. Takes no parameters"); 460*99a2dd95SBruce Richardson rte_telemetry_register_cmd("/help", command_help, 461*99a2dd95SBruce Richardson "Returns help text for a command. Parameters: string command"); 462*99a2dd95SBruce Richardson v2_socket.fn = client_handler; 463*99a2dd95SBruce Richardson if (strlcpy(v2_socket.path, get_socket_path(socket_dir, 2), 464*99a2dd95SBruce Richardson sizeof(v2_socket.path)) >= sizeof(v2_socket.path)) { 465*99a2dd95SBruce Richardson TMTY_LOG(ERR, "Error with socket binding, path too long\n"); 466*99a2dd95SBruce Richardson return -1; 467*99a2dd95SBruce Richardson } 468*99a2dd95SBruce Richardson 469*99a2dd95SBruce Richardson v2_socket.sock = create_socket(v2_socket.path); 470*99a2dd95SBruce Richardson if (v2_socket.sock < 0) 471*99a2dd95SBruce Richardson return -1; 472*99a2dd95SBruce Richardson pthread_create(&t_new, NULL, socket_listener, &v2_socket); 473*99a2dd95SBruce Richardson pthread_setaffinity_np(t_new, sizeof(*thread_cpuset), thread_cpuset); 474*99a2dd95SBruce Richardson atexit(unlink_sockets); 475*99a2dd95SBruce Richardson 476*99a2dd95SBruce Richardson return 0; 477*99a2dd95SBruce Richardson } 478*99a2dd95SBruce Richardson 479*99a2dd95SBruce Richardson #endif /* !RTE_EXEC_ENV_WINDOWS */ 480*99a2dd95SBruce Richardson 481*99a2dd95SBruce Richardson int32_t 482*99a2dd95SBruce Richardson rte_telemetry_init(const char *runtime_dir, const char *rte_version, rte_cpuset_t *cpuset, 483*99a2dd95SBruce Richardson rte_log_fn log_fn, uint32_t registered_logtype) 484*99a2dd95SBruce Richardson { 485*99a2dd95SBruce Richardson telemetry_version = rte_version; 486*99a2dd95SBruce Richardson socket_dir = runtime_dir; 487*99a2dd95SBruce Richardson thread_cpuset = cpuset; 488*99a2dd95SBruce Richardson rte_log_ptr = log_fn; 489*99a2dd95SBruce Richardson logtype = registered_logtype; 490*99a2dd95SBruce Richardson 491*99a2dd95SBruce Richardson #ifndef RTE_EXEC_ENV_WINDOWS 492*99a2dd95SBruce Richardson if (telemetry_v2_init() != 0) 493*99a2dd95SBruce Richardson return -1; 494*99a2dd95SBruce Richardson TMTY_LOG(DEBUG, "Telemetry initialized ok\n"); 495*99a2dd95SBruce Richardson telemetry_legacy_init(); 496*99a2dd95SBruce Richardson #endif /* RTE_EXEC_ENV_WINDOWS */ 497*99a2dd95SBruce Richardson 498*99a2dd95SBruce Richardson return 0; 499*99a2dd95SBruce Richardson } 500