1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdint.h> 7 #include <stdarg.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <errno.h> 11 #include <regex.h> 12 #include <fnmatch.h> 13 #include <sys/queue.h> 14 15 #include <rte_log.h> 16 #include <rte_os_shim.h> 17 #include <rte_per_lcore.h> 18 19 #include "eal_log.h" 20 #include "eal_private.h" 21 22 struct rte_log_dynamic_type { 23 const char *name; 24 uint32_t loglevel; 25 }; 26 27 /** The rte_log structure. */ 28 static struct rte_logs { 29 uint32_t type; /**< Bitfield with enabled logs. */ 30 uint32_t level; /**< Log level. */ 31 FILE *file; /**< Output file set by rte_openlog_stream, or NULL. */ 32 size_t dynamic_types_len; 33 struct rte_log_dynamic_type *dynamic_types; 34 } rte_logs = { 35 .type = UINT32_MAX, 36 .level = RTE_LOG_DEBUG, 37 }; 38 39 struct rte_eal_opt_loglevel { 40 /** Next list entry */ 41 TAILQ_ENTRY(rte_eal_opt_loglevel) next; 42 /** Compiled regular expression obtained from the option */ 43 regex_t re_match; 44 /** Globbing pattern option */ 45 char *pattern; 46 /** Log level value obtained from the option */ 47 uint32_t level; 48 }; 49 50 TAILQ_HEAD(rte_eal_opt_loglevel_list, rte_eal_opt_loglevel); 51 52 /** List of valid EAL log level options */ 53 static struct rte_eal_opt_loglevel_list opt_loglevel_list = 54 TAILQ_HEAD_INITIALIZER(opt_loglevel_list); 55 56 /* Stream to use for logging if rte_logs.file is NULL */ 57 static FILE *default_log_stream; 58 59 /** 60 * This global structure stores some information about the message 61 * that is currently being processed by one lcore 62 */ 63 struct log_cur_msg { 64 uint32_t loglevel; /**< log level - see rte_log.h */ 65 uint32_t logtype; /**< log type - see rte_log.h */ 66 }; 67 68 /* per core log */ 69 static RTE_DEFINE_PER_LCORE(struct log_cur_msg, log_cur_msg); 70 71 /* default logs */ 72 73 /* Change the stream that will be used by logging system */ 74 int 75 rte_openlog_stream(FILE *f) 76 { 77 rte_logs.file = f; 78 return 0; 79 } 80 81 FILE * 82 rte_log_get_stream(void) 83 { 84 FILE *f = rte_logs.file; 85 86 if (f == NULL) { 87 /* 88 * Grab the current value of stderr here, rather than 89 * just initializing default_log_stream to stderr. This 90 * ensures that we will always use the current value 91 * of stderr, even if the application closes and 92 * reopens it. 93 */ 94 return default_log_stream ? : stderr; 95 } 96 return f; 97 } 98 99 /* Set global log level */ 100 void 101 rte_log_set_global_level(uint32_t level) 102 { 103 rte_logs.level = (uint32_t)level; 104 } 105 106 /* Get global log level */ 107 uint32_t 108 rte_log_get_global_level(void) 109 { 110 return rte_logs.level; 111 } 112 113 int 114 rte_log_get_level(uint32_t type) 115 { 116 if (type >= rte_logs.dynamic_types_len) 117 return -1; 118 119 return rte_logs.dynamic_types[type].loglevel; 120 } 121 122 bool 123 rte_log_can_log(uint32_t logtype, uint32_t level) 124 { 125 int log_level; 126 127 if (level > rte_log_get_global_level()) 128 return false; 129 130 log_level = rte_log_get_level(logtype); 131 if (log_level < 0) 132 return false; 133 134 if (level > (uint32_t)log_level) 135 return false; 136 137 return true; 138 } 139 140 static void 141 logtype_set_level(uint32_t type, uint32_t level) 142 { 143 uint32_t current = rte_logs.dynamic_types[type].loglevel; 144 145 if (current != level) { 146 rte_logs.dynamic_types[type].loglevel = level; 147 RTE_LOG(DEBUG, EAL, "%s log level changed from %s to %s\n", 148 rte_logs.dynamic_types[type].name == NULL ? 149 "" : rte_logs.dynamic_types[type].name, 150 eal_log_level2str(current), 151 eal_log_level2str(level)); 152 } 153 } 154 155 int 156 rte_log_set_level(uint32_t type, uint32_t level) 157 { 158 if (type >= rte_logs.dynamic_types_len) 159 return -1; 160 if (level > RTE_LOG_MAX) 161 return -1; 162 163 logtype_set_level(type, level); 164 165 return 0; 166 } 167 168 /* set log level by regular expression */ 169 int 170 rte_log_set_level_regexp(const char *regex, uint32_t level) 171 { 172 regex_t r; 173 size_t i; 174 175 if (level > RTE_LOG_MAX) 176 return -1; 177 178 if (regcomp(&r, regex, 0) != 0) 179 return -1; 180 181 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 182 if (rte_logs.dynamic_types[i].name == NULL) 183 continue; 184 if (regexec(&r, rte_logs.dynamic_types[i].name, 0, 185 NULL, 0) == 0) 186 logtype_set_level(i, level); 187 } 188 189 regfree(&r); 190 191 return 0; 192 } 193 194 /* 195 * Save the type string and the loglevel for later dynamic 196 * logtypes which may register later. 197 */ 198 static int 199 log_save_level(uint32_t priority, const char *regex, const char *pattern) 200 { 201 struct rte_eal_opt_loglevel *opt_ll = NULL; 202 203 opt_ll = malloc(sizeof(*opt_ll)); 204 if (opt_ll == NULL) 205 goto fail; 206 207 opt_ll->level = priority; 208 209 if (regex) { 210 opt_ll->pattern = NULL; 211 if (regcomp(&opt_ll->re_match, regex, 0) != 0) 212 goto fail; 213 } else if (pattern) { 214 opt_ll->pattern = strdup(pattern); 215 if (opt_ll->pattern == NULL) 216 goto fail; 217 } else 218 goto fail; 219 220 TAILQ_INSERT_HEAD(&opt_loglevel_list, opt_ll, next); 221 return 0; 222 fail: 223 free(opt_ll); 224 return -1; 225 } 226 227 int 228 eal_log_save_regexp(const char *regex, uint32_t level) 229 { 230 return log_save_level(level, regex, NULL); 231 } 232 233 /* set log level based on globbing pattern */ 234 int 235 rte_log_set_level_pattern(const char *pattern, uint32_t level) 236 { 237 size_t i; 238 239 if (level > RTE_LOG_MAX) 240 return -1; 241 242 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 243 if (rte_logs.dynamic_types[i].name == NULL) 244 continue; 245 246 if (fnmatch(pattern, rte_logs.dynamic_types[i].name, 0) == 0) 247 logtype_set_level(i, level); 248 } 249 250 return 0; 251 } 252 253 int 254 eal_log_save_pattern(const char *pattern, uint32_t level) 255 { 256 return log_save_level(level, NULL, pattern); 257 } 258 259 /* get the current loglevel for the message being processed */ 260 int rte_log_cur_msg_loglevel(void) 261 { 262 return RTE_PER_LCORE(log_cur_msg).loglevel; 263 } 264 265 /* get the current logtype for the message being processed */ 266 int rte_log_cur_msg_logtype(void) 267 { 268 return RTE_PER_LCORE(log_cur_msg).logtype; 269 } 270 271 static int 272 log_lookup(const char *name) 273 { 274 size_t i; 275 276 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 277 if (rte_logs.dynamic_types[i].name == NULL) 278 continue; 279 if (strcmp(name, rte_logs.dynamic_types[i].name) == 0) 280 return i; 281 } 282 283 return -1; 284 } 285 286 static int 287 log_register(const char *name, uint32_t level) 288 { 289 struct rte_log_dynamic_type *new_dynamic_types; 290 int id; 291 292 id = log_lookup(name); 293 if (id >= 0) 294 return id; 295 296 new_dynamic_types = realloc(rte_logs.dynamic_types, 297 sizeof(struct rte_log_dynamic_type) * 298 (rte_logs.dynamic_types_len + 1)); 299 if (new_dynamic_types == NULL) 300 return -ENOMEM; 301 rte_logs.dynamic_types = new_dynamic_types; 302 303 id = rte_logs.dynamic_types_len; 304 memset(&rte_logs.dynamic_types[id], 0, 305 sizeof(rte_logs.dynamic_types[id])); 306 rte_logs.dynamic_types[id].name = strdup(name); 307 if (rte_logs.dynamic_types[id].name == NULL) 308 return -ENOMEM; 309 logtype_set_level(id, level); 310 311 rte_logs.dynamic_types_len++; 312 313 return id; 314 } 315 316 /* register an extended log type */ 317 int 318 rte_log_register(const char *name) 319 { 320 return log_register(name, RTE_LOG_INFO); 321 } 322 323 /* Register an extended log type and try to pick its level from EAL options */ 324 int 325 rte_log_register_type_and_pick_level(const char *name, uint32_t level_def) 326 { 327 struct rte_eal_opt_loglevel *opt_ll; 328 uint32_t level = level_def; 329 330 TAILQ_FOREACH(opt_ll, &opt_loglevel_list, next) { 331 if (opt_ll->level > RTE_LOG_MAX) 332 continue; 333 334 if (opt_ll->pattern) { 335 if (fnmatch(opt_ll->pattern, name, 0) == 0) 336 level = opt_ll->level; 337 } else { 338 if (regexec(&opt_ll->re_match, name, 0, NULL, 0) == 0) 339 level = opt_ll->level; 340 } 341 } 342 343 return log_register(name, level); 344 } 345 346 struct logtype { 347 uint32_t log_id; 348 const char *logtype; 349 }; 350 351 static const struct logtype logtype_strings[] = { 352 {RTE_LOGTYPE_EAL, "lib.eal"}, 353 {RTE_LOGTYPE_MALLOC, "lib.malloc"}, 354 {RTE_LOGTYPE_RING, "lib.ring"}, 355 {RTE_LOGTYPE_MEMPOOL, "lib.mempool"}, 356 {RTE_LOGTYPE_TIMER, "lib.timer"}, 357 {RTE_LOGTYPE_PMD, "pmd"}, 358 {RTE_LOGTYPE_HASH, "lib.hash"}, 359 {RTE_LOGTYPE_LPM, "lib.lpm"}, 360 {RTE_LOGTYPE_KNI, "lib.kni"}, 361 {RTE_LOGTYPE_ACL, "lib.acl"}, 362 {RTE_LOGTYPE_POWER, "lib.power"}, 363 {RTE_LOGTYPE_METER, "lib.meter"}, 364 {RTE_LOGTYPE_SCHED, "lib.sched"}, 365 {RTE_LOGTYPE_PORT, "lib.port"}, 366 {RTE_LOGTYPE_TABLE, "lib.table"}, 367 {RTE_LOGTYPE_PIPELINE, "lib.pipeline"}, 368 {RTE_LOGTYPE_MBUF, "lib.mbuf"}, 369 {RTE_LOGTYPE_CRYPTODEV, "lib.cryptodev"}, 370 {RTE_LOGTYPE_EFD, "lib.efd"}, 371 {RTE_LOGTYPE_EVENTDEV, "lib.eventdev"}, 372 {RTE_LOGTYPE_GSO, "lib.gso"}, 373 {RTE_LOGTYPE_USER1, "user1"}, 374 {RTE_LOGTYPE_USER2, "user2"}, 375 {RTE_LOGTYPE_USER3, "user3"}, 376 {RTE_LOGTYPE_USER4, "user4"}, 377 {RTE_LOGTYPE_USER5, "user5"}, 378 {RTE_LOGTYPE_USER6, "user6"}, 379 {RTE_LOGTYPE_USER7, "user7"}, 380 {RTE_LOGTYPE_USER8, "user8"} 381 }; 382 383 /* Logging should be first initializer (before drivers and bus) */ 384 RTE_INIT_PRIO(log_init, LOG) 385 { 386 uint32_t i; 387 388 rte_log_set_global_level(RTE_LOG_DEBUG); 389 390 rte_logs.dynamic_types = calloc(RTE_LOGTYPE_FIRST_EXT_ID, 391 sizeof(struct rte_log_dynamic_type)); 392 if (rte_logs.dynamic_types == NULL) 393 return; 394 395 /* register legacy log types */ 396 for (i = 0; i < RTE_DIM(logtype_strings); i++) { 397 rte_logs.dynamic_types[logtype_strings[i].log_id].name = 398 strdup(logtype_strings[i].logtype); 399 logtype_set_level(logtype_strings[i].log_id, RTE_LOG_INFO); 400 } 401 402 rte_logs.dynamic_types_len = RTE_LOGTYPE_FIRST_EXT_ID; 403 } 404 405 const char * 406 eal_log_level2str(uint32_t level) 407 { 408 switch (level) { 409 case 0: return "disabled"; 410 case RTE_LOG_EMERG: return "emergency"; 411 case RTE_LOG_ALERT: return "alert"; 412 case RTE_LOG_CRIT: return "critical"; 413 case RTE_LOG_ERR: return "error"; 414 case RTE_LOG_WARNING: return "warning"; 415 case RTE_LOG_NOTICE: return "notice"; 416 case RTE_LOG_INFO: return "info"; 417 case RTE_LOG_DEBUG: return "debug"; 418 default: return "unknown"; 419 } 420 } 421 422 static int 423 log_type_compare(const void *a, const void *b) 424 { 425 const struct rte_log_dynamic_type *type_a = a; 426 const struct rte_log_dynamic_type *type_b = b; 427 428 if (type_a->name == NULL && type_b->name == NULL) 429 return 0; 430 if (type_a->name == NULL) 431 return -1; 432 if (type_b->name == NULL) 433 return 1; 434 return strcmp(type_a->name, type_b->name); 435 } 436 437 /* Dump name of each logtype, one per line. */ 438 void 439 rte_log_list_types(FILE *out, const char *prefix) 440 { 441 struct rte_log_dynamic_type *sorted_types; 442 const size_t type_size = sizeof(rte_logs.dynamic_types[0]); 443 const size_t type_count = rte_logs.dynamic_types_len; 444 const size_t total_size = type_size * type_count; 445 size_t type; 446 447 sorted_types = malloc(total_size); 448 if (sorted_types == NULL) { 449 /* no sorting - unlikely */ 450 sorted_types = rte_logs.dynamic_types; 451 } else { 452 memcpy(sorted_types, rte_logs.dynamic_types, total_size); 453 qsort(sorted_types, type_count, type_size, log_type_compare); 454 } 455 456 for (type = 0; type < type_count; ++type) { 457 if (sorted_types[type].name == NULL) 458 continue; 459 fprintf(out, "%s%s\n", prefix, sorted_types[type].name); 460 } 461 462 if (sorted_types != rte_logs.dynamic_types) 463 free(sorted_types); 464 } 465 466 /* dump global level and registered log types */ 467 void 468 rte_log_dump(FILE *f) 469 { 470 size_t i; 471 472 fprintf(f, "global log level is %s\n", 473 eal_log_level2str(rte_log_get_global_level())); 474 475 for (i = 0; i < rte_logs.dynamic_types_len; i++) { 476 if (rte_logs.dynamic_types[i].name == NULL) 477 continue; 478 fprintf(f, "id %zu: %s, level is %s\n", 479 i, rte_logs.dynamic_types[i].name, 480 eal_log_level2str(rte_logs.dynamic_types[i].loglevel)); 481 } 482 } 483 484 /* 485 * Generates a log message The message will be sent in the stream 486 * defined by the previous call to rte_openlog_stream(). 487 */ 488 int 489 rte_vlog(uint32_t level, uint32_t logtype, const char *format, va_list ap) 490 { 491 FILE *f = rte_log_get_stream(); 492 int ret; 493 494 if (logtype >= rte_logs.dynamic_types_len) 495 return -1; 496 if (!rte_log_can_log(logtype, level)) 497 return 0; 498 499 /* save loglevel and logtype in a global per-lcore variable */ 500 RTE_PER_LCORE(log_cur_msg).loglevel = level; 501 RTE_PER_LCORE(log_cur_msg).logtype = logtype; 502 503 ret = vfprintf(f, format, ap); 504 fflush(f); 505 return ret; 506 } 507 508 /* 509 * Generates a log message The message will be sent in the stream 510 * defined by the previous call to rte_openlog_stream(). 511 * No need to check level here, done by rte_vlog(). 512 */ 513 int 514 rte_log(uint32_t level, uint32_t logtype, const char *format, ...) 515 { 516 va_list ap; 517 int ret; 518 519 va_start(ap, format); 520 ret = rte_vlog(level, logtype, format, ap); 521 va_end(ap); 522 return ret; 523 } 524 525 /* 526 * Called by environment-specific initialization functions. 527 */ 528 void 529 eal_log_set_default(FILE *default_log) 530 { 531 default_log_stream = default_log; 532 533 #if RTE_LOG_DP_LEVEL >= RTE_LOG_DEBUG 534 RTE_LOG(NOTICE, EAL, 535 "Debug dataplane logs available - lower performance\n"); 536 #endif 537 } 538 539 /* 540 * Called by eal_cleanup 541 */ 542 void 543 rte_eal_log_cleanup(void) 544 { 545 if (default_log_stream) { 546 fclose(default_log_stream); 547 default_log_stream = NULL; 548 } 549 } 550