1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * in kernel monitor support: allows rv to control in-kernel monitors. 4 * 5 * Copyright (C) 2022 Red Hat Inc, Daniel Bristot de Oliveira <bristot@kernel.org> 6 */ 7 #include <getopt.h> 8 #include <stdlib.h> 9 #include <stdio.h> 10 #include <string.h> 11 #include <errno.h> 12 #include <unistd.h> 13 #include <dirent.h> 14 15 #include <trace.h> 16 #include <utils.h> 17 #include <rv.h> 18 19 static int config_has_id; 20 static int config_is_container; 21 static int config_my_pid; 22 static int config_trace; 23 24 static char *config_initial_reactor; 25 static char *config_reactor; 26 27 /* 28 * __ikm_read_enable - reads monitor's enable status 29 * 30 * __does not log errors. 31 * 32 * Returns the current status, or -1 if the monitor does not exist, 33 * __hence not logging errors. 34 */ 35 static int __ikm_read_enable(char *monitor_name) 36 { 37 char path[MAX_PATH]; 38 long long enabled; 39 int retval; 40 41 snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name); 42 43 retval = tracefs_instance_file_read_number(NULL, path, &enabled); 44 if (retval < 0) 45 return -1; 46 47 return enabled; 48 } 49 50 /* 51 * __ikm_find_monitor - find the full name of a possibly nested module 52 * 53 * __does not log errors. 54 * 55 * Returns 1 if we found the monitor, -1 on error and 0 if it does not exist. 56 * The string out_name is populated with the full name, which can be 57 * equal to monitor_name or container/monitor_name if nested 58 */ 59 static int __ikm_find_monitor_name(char *monitor_name, char *out_name) 60 { 61 char *available_monitors, container[MAX_DA_NAME_LEN+1], *cursor, *end; 62 int retval = 1; 63 64 available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 65 if (!available_monitors) 66 return -1; 67 68 cursor = strstr(available_monitors, monitor_name); 69 if (!cursor) { 70 retval = 0; 71 goto out_free; 72 } 73 74 for (; cursor > available_monitors; cursor--) 75 if (*(cursor-1) == '\n') 76 break; 77 end = strstr(cursor, "\n"); 78 memcpy(out_name, cursor, end-cursor); 79 out_name[end-cursor] = '\0'; 80 81 cursor = strstr(out_name, ":"); 82 if (cursor) 83 *cursor = '/'; 84 else { 85 sprintf(container, "%s:", monitor_name); 86 if (strstr(available_monitors, container)) 87 config_is_container = 1; 88 } 89 90 out_free: 91 free(available_monitors); 92 return retval; 93 } 94 95 /* 96 * ikm_read_enable - reads monitor's enable status 97 * 98 * Returns the current status, or -1 on error. 99 */ 100 static int ikm_read_enable(char *monitor_name) 101 { 102 int enabled; 103 104 enabled = __ikm_read_enable(monitor_name); 105 if (enabled < 0) { 106 err_msg("ikm: fail read enabled: %d\n", enabled); 107 return -1; 108 } 109 110 debug_msg("ikm: read enabled: %d\n", enabled); 111 112 return enabled; 113 } 114 115 /* 116 * ikm_write_enable - write to the monitor's enable file 117 * 118 * Return the number of bytes written, -1 on error. 119 */ 120 static int ikm_write_enable(char *monitor_name, char *enable_disable) 121 { 122 char path[MAX_PATH]; 123 int retval; 124 125 debug_msg("ikm: writing enabled: %s\n", enable_disable); 126 127 snprintf(path, MAX_PATH, "rv/monitors/%s/enable", monitor_name); 128 retval = tracefs_instance_file_write(NULL, path, enable_disable); 129 if (retval < strlen(enable_disable)) { 130 err_msg("ikm: writing enabled: %s\n", enable_disable); 131 return -1; 132 } 133 134 return retval; 135 } 136 137 /* 138 * ikm_enable - enable a monitor 139 * 140 * Returns -1 on failure. Success otherwise. 141 */ 142 static int ikm_enable(char *monitor_name) 143 { 144 return ikm_write_enable(monitor_name, "1"); 145 } 146 147 /* 148 * ikm_disable - disable a monitor 149 * 150 * Returns -1 on failure. Success otherwise. 151 */ 152 static int ikm_disable(char *monitor_name) 153 { 154 return ikm_write_enable(monitor_name, "0"); 155 } 156 157 /* 158 * ikm_read_desc - read monitors' description 159 * 160 * Return a dynamically allocated string with the monitor's 161 * description, NULL otherwise. 162 */ 163 static char *ikm_read_desc(char *monitor_name) 164 { 165 char path[MAX_PATH]; 166 char *desc; 167 168 snprintf(path, MAX_PATH, "rv/monitors/%s/desc", monitor_name); 169 desc = tracefs_instance_file_read(NULL, path, NULL); 170 if (!desc) { 171 err_msg("ikm: error reading monitor %s desc\n", monitor_name); 172 return NULL; 173 } 174 175 *strstr(desc, "\n") = '\0'; 176 177 return desc; 178 } 179 180 /* 181 * ikm_fill_monitor_definition - fill monitor's definition 182 * 183 * Returns -1 on error, 0 otherwise. 184 */ 185 static int ikm_fill_monitor_definition(char *name, struct monitor *ikm) 186 { 187 int enabled; 188 char *desc, *nested_name; 189 190 nested_name = strstr(name, ":"); 191 if (nested_name) { 192 *nested_name = '/'; 193 ++nested_name; 194 ikm->nested = 1; 195 } else { 196 nested_name = name; 197 ikm->nested = 0; 198 } 199 200 enabled = ikm_read_enable(name); 201 if (enabled < 0) { 202 err_msg("ikm: monitor %s fail to read enable file, bug?\n", name); 203 return -1; 204 } 205 206 desc = ikm_read_desc(name); 207 if (!desc) { 208 err_msg("ikm: monitor %s does not have desc file, bug?\n", name); 209 return -1; 210 } 211 212 strncpy(ikm->name, nested_name, MAX_DA_NAME_LEN); 213 ikm->enabled = enabled; 214 strncpy(ikm->desc, desc, MAX_DESCRIPTION); 215 216 free(desc); 217 218 return 0; 219 } 220 221 /* 222 * ikm_write_reactor - switch the reactor to *reactor 223 * 224 * Return the number or characters written, -1 on error. 225 */ 226 static int ikm_write_reactor(char *monitor_name, char *reactor) 227 { 228 char path[MAX_PATH]; 229 int retval; 230 231 snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name); 232 retval = tracefs_instance_file_write(NULL, path, reactor); 233 debug_msg("ikm: write \"%s\" reactors: %d\n", reactor, retval); 234 235 return retval; 236 } 237 238 /* 239 * ikm_read_reactor - read the reactors file 240 * 241 * Returns a dynamically allocated string with monitor's 242 * available reactors, or NULL on error. 243 */ 244 static char *ikm_read_reactor(char *monitor_name) 245 { 246 char path[MAX_PATH]; 247 char *reactors; 248 249 snprintf(path, MAX_PATH, "rv/monitors/%s/reactors", monitor_name); 250 reactors = tracefs_instance_file_read(NULL, path, NULL); 251 if (!reactors) { 252 err_msg("ikm: fail reading monitor's %s reactors file\n", monitor_name); 253 return NULL; 254 } 255 256 return reactors; 257 } 258 259 /* 260 * ikm_get_current_reactor - get the current enabled reactor 261 * 262 * Reads the reactors file and find the currently enabled 263 * [reactor]. 264 * 265 * Returns a dynamically allocated memory with the current 266 * reactor. NULL otherwise. 267 */ 268 static char *ikm_get_current_reactor(char *monitor_name) 269 { 270 char *reactors = ikm_read_reactor(monitor_name); 271 char *curr_reactor = NULL; 272 char *start; 273 char *end; 274 275 if (!reactors) 276 return NULL; 277 278 start = strstr(reactors, "["); 279 if (!start) 280 goto out_free; 281 282 start++; 283 284 end = strstr(start, "]"); 285 if (!end) 286 goto out_free; 287 288 *end = '\0'; 289 290 curr_reactor = calloc(strlen(start) + 1, sizeof(char)); 291 if (!curr_reactor) 292 goto out_free; 293 294 strncpy(curr_reactor, start, strlen(start)); 295 debug_msg("ikm: read current reactor %s\n", curr_reactor); 296 297 out_free: 298 free(reactors); 299 300 return curr_reactor; 301 } 302 303 static int ikm_has_id(char *monitor_name) 304 { 305 char path[MAX_PATH]; 306 char *format; 307 int has_id; 308 309 snprintf(path, MAX_PATH, "events/rv/event_%s/format", monitor_name); 310 format = tracefs_instance_file_read(NULL, path, NULL); 311 if (!format) { 312 err_msg("ikm: fail reading monitor's %s format event file\n", monitor_name); 313 return -1; 314 } 315 316 /* print fmt: "%d: %s x %s -> %s %s", REC->id, ... */ 317 has_id = !!strstr(format, "REC->id"); 318 319 debug_msg("ikm: monitor %s has id: %s\n", monitor_name, has_id ? "yes" : "no"); 320 321 free(format); 322 323 return has_id; 324 } 325 326 /** 327 * ikm_list_monitors - list all available monitors 328 * 329 * Returns 0 on success, -1 otherwise. 330 */ 331 int ikm_list_monitors(void) 332 { 333 char *available_monitors; 334 struct monitor ikm = {0}; 335 char *curr, *next; 336 int retval; 337 338 available_monitors = tracefs_instance_file_read(NULL, "rv/available_monitors", NULL); 339 340 if (!available_monitors) { 341 err_msg("ikm: available monitors is not available, is CONFIG_RV enabled?\n"); 342 return -1; 343 } 344 345 curr = available_monitors; 346 do { 347 next = strstr(curr, "\n"); 348 *next = '\0'; 349 350 retval = ikm_fill_monitor_definition(curr, &ikm); 351 if (retval) 352 err_msg("ikm: error reading %d in kernel monitor, skipping\n", curr); 353 354 printf("%s%-*s %s %s\n", ikm.nested ? " - " : "", 355 ikm.nested ? MAX_DA_NAME_LEN - 3 : MAX_DA_NAME_LEN, 356 ikm.name, ikm.desc, ikm.enabled ? "[ON]" : "[OFF]"); 357 curr = ++next; 358 359 } while (strlen(curr)); 360 361 free(available_monitors); 362 363 return 0; 364 } 365 366 static void ikm_print_header(struct trace_seq *s) 367 { 368 trace_seq_printf(s, "%16s-%-8s %5s %5s ", "<TASK>", "PID", "[CPU]", "TYPE"); 369 if (config_has_id) 370 trace_seq_printf(s, "%8s ", "ID"); 371 372 trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n", 373 "STATE", 374 "EVENT", 375 "NEXT_STATE", 376 "FINAL"); 377 378 trace_seq_printf(s, "%16s %-8s %5s %5s ", " | ", " | ", " | ", " | "); 379 380 if (config_has_id) 381 trace_seq_printf(s, "%8s ", " | "); 382 383 trace_seq_printf(s, "%24s %-24s %-24s %s\n", 384 " | ", 385 " | ", 386 " | ", 387 "|"); 388 389 } 390 391 /* 392 * ikm_event_handler - callback to handle event events 393 * 394 * Called any time a rv:"monitor"_event events is generated. 395 * It parses and prints event. 396 */ 397 static int 398 ikm_event_handler(struct trace_seq *s, struct tep_record *record, 399 struct tep_event *trace_event, void *context) 400 { 401 /* if needed: struct trace_instance *inst = context; */ 402 char *state, *event, *next_state; 403 unsigned long long final_state; 404 unsigned long long pid; 405 unsigned long long id; 406 int val; 407 bool missing_id; 408 409 if (config_has_id) 410 missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 411 412 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 413 414 if (config_has_id && (config_my_pid == id)) 415 return 0; 416 else if (config_my_pid && (config_my_pid == pid)) 417 return 0; 418 419 tep_print_event(trace_event->tep, s, record, "%16s-%-8d [%.3d] ", 420 TEP_PRINT_COMM, TEP_PRINT_PID, TEP_PRINT_CPU); 421 422 if (config_is_container) 423 tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 424 else 425 trace_seq_printf(s, "event "); 426 427 if (config_has_id) { 428 if (missing_id) 429 /* placeholder if we are dealing with a mixed-type container*/ 430 trace_seq_printf(s, " "); 431 else 432 trace_seq_printf(s, "%8llu ", id); 433 } 434 435 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 436 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); 437 next_state = tep_get_field_raw(s, trace_event, "next_state", record, &val, 0); 438 tep_get_field_val(s, trace_event, "final_state", record, &final_state, 1); 439 440 trace_seq_printf(s, "%24s x %-24s -> %-24s %s\n", 441 state, 442 event, 443 next_state, 444 final_state ? "Y" : "N"); 445 446 trace_seq_do_printf(s); 447 trace_seq_reset(s); 448 449 return 0; 450 } 451 452 /* 453 * ikm_error_handler - callback to handle error events 454 * 455 * Called any time a rv:"monitor"_errors events is generated. 456 * It parses and prints event. 457 */ 458 static int 459 ikm_error_handler(struct trace_seq *s, struct tep_record *record, 460 struct tep_event *trace_event, void *context) 461 { 462 unsigned long long pid, id; 463 int cpu = record->cpu; 464 char *state, *event; 465 int val; 466 bool missing_id; 467 468 if (config_has_id) 469 missing_id = tep_get_field_val(s, trace_event, "id", record, &id, 1); 470 471 tep_get_common_field_val(s, trace_event, "common_pid", record, &pid, 1); 472 473 if (config_has_id && config_my_pid == id) 474 return 0; 475 else if (config_my_pid == pid) 476 return 0; 477 478 trace_seq_printf(s, "%8lld [%03d] ", pid, cpu); 479 480 if (config_is_container) 481 tep_print_event(trace_event->tep, s, record, "%s ", TEP_PRINT_NAME); 482 else 483 trace_seq_printf(s, "error "); 484 485 if (config_has_id) { 486 if (missing_id) 487 /* placeholder if we are dealing with a mixed-type container*/ 488 trace_seq_printf(s, " "); 489 else 490 trace_seq_printf(s, "%8llu ", id); 491 } 492 493 state = tep_get_field_raw(s, trace_event, "state", record, &val, 0); 494 event = tep_get_field_raw(s, trace_event, "event", record, &val, 0); 495 496 trace_seq_printf(s, "%24s x %s\n", state, event); 497 498 trace_seq_do_printf(s); 499 trace_seq_reset(s); 500 501 return 0; 502 } 503 504 static int ikm_enable_trace_events(char *monitor_name, struct trace_instance *inst) 505 { 506 char event[MAX_DA_NAME_LEN + 7]; /* max(error_,event_) + '0' = 7 */ 507 int retval; 508 509 snprintf(event, sizeof(event), "event_%s", monitor_name); 510 retval = tracefs_event_enable(inst->inst, "rv", event); 511 if (retval) 512 return -1; 513 514 tep_register_event_handler(inst->tep, -1, "rv", event, 515 ikm_event_handler, NULL); 516 517 snprintf(event, sizeof(event), "error_%s", monitor_name); 518 retval = tracefs_event_enable(inst->inst, "rv", event); 519 if (retval) 520 return -1; 521 522 tep_register_event_handler(inst->tep, -1, "rv", event, 523 ikm_error_handler, NULL); 524 525 /* set if at least 1 monitor has id in case of a container */ 526 config_has_id = ikm_has_id(monitor_name); 527 if (config_has_id < 0) 528 return -1; 529 530 531 return 0; 532 } 533 534 static int ikm_enable_trace_container(char *monitor_name, 535 struct trace_instance *inst) 536 { 537 DIR *dp; 538 char *abs_path, rv_path[MAX_PATH]; 539 struct dirent *ep; 540 int retval = 0; 541 542 snprintf(rv_path, MAX_PATH, "rv/monitors/%s", monitor_name); 543 abs_path = tracefs_instance_get_file(NULL, rv_path); 544 if (!abs_path) 545 return -1; 546 dp = opendir(abs_path); 547 if (!dp) 548 goto out_free; 549 550 while (!retval && (ep = readdir(dp))) { 551 if (ep->d_type != DT_DIR || ep->d_name[0] == '.') 552 continue; 553 retval = ikm_enable_trace_events(ep->d_name, inst); 554 } 555 556 closedir(dp); 557 out_free: 558 free(abs_path); 559 return retval; 560 } 561 562 /* 563 * ikm_setup_trace_instance - set up a tracing instance to collect data 564 * 565 * Create a trace instance, enable rv: events and enable the trace. 566 * 567 * Returns the trace_instance * with all set, NULL otherwise. 568 */ 569 static struct trace_instance *ikm_setup_trace_instance(char *monitor_name) 570 { 571 struct trace_instance *inst; 572 int retval; 573 574 if (!config_trace) 575 return NULL; 576 577 /* alloc data */ 578 inst = calloc(1, sizeof(*inst)); 579 if (!inst) { 580 err_msg("ikm: failed to allocate trace instance"); 581 goto out_err; 582 } 583 584 retval = trace_instance_init(inst, monitor_name); 585 if (retval) 586 goto out_free; 587 588 if (config_is_container) 589 retval = ikm_enable_trace_container(monitor_name, inst); 590 else 591 retval = ikm_enable_trace_events(monitor_name, inst); 592 if (retval) 593 goto out_inst; 594 595 /* ready to enable */ 596 tracefs_trace_on(inst->inst); 597 598 return inst; 599 600 out_inst: 601 trace_instance_destroy(inst); 602 out_free: 603 free(inst); 604 out_err: 605 return NULL; 606 } 607 608 /** 609 * ikm_destroy_trace_instance - destroy a previously created instance 610 */ 611 static void ikm_destroy_trace_instance(struct trace_instance *inst) 612 { 613 if (!inst) 614 return; 615 616 trace_instance_destroy(inst); 617 free(inst); 618 } 619 620 /* 621 * ikm_usage_print_reactors - print all available reactors, one per line. 622 */ 623 static void ikm_usage_print_reactors(void) 624 { 625 char *reactors = tracefs_instance_file_read(NULL, "rv/available_reactors", NULL); 626 char *start, *end; 627 628 if (!reactors) 629 return; 630 631 fprintf(stderr, " available reactors:"); 632 633 start = reactors; 634 end = strstr(start, "\n"); 635 636 while (end) { 637 *end = '\0'; 638 639 fprintf(stderr, " %s", start); 640 641 start = ++end; 642 end = strstr(start, "\n"); 643 } 644 645 fprintf(stderr, "\n"); 646 } 647 /* 648 * ikm_usage - print usage 649 */ 650 static void ikm_usage(int exit_val, char *monitor_name, const char *fmt, ...) 651 { 652 653 char message[1024]; 654 va_list ap; 655 int i; 656 657 static const char *const usage[] = { 658 "", 659 " -h/--help: print this menu and the reactor list", 660 " -r/--reactor 'reactor': enables the 'reactor'", 661 " -s/--self: when tracing (-t), also trace rv command", 662 " -t/--trace: trace monitor's event", 663 " -v/--verbose: print debug messages", 664 "", 665 NULL, 666 }; 667 668 va_start(ap, fmt); 669 vsnprintf(message, sizeof(message), fmt, ap); 670 va_end(ap); 671 672 fprintf(stderr, " %s\n", message); 673 674 fprintf(stderr, "\n usage: rv mon %s [-h] [-q] [-r reactor] [-s] [-v]", monitor_name); 675 676 for (i = 0; usage[i]; i++) 677 fprintf(stderr, "%s\n", usage[i]); 678 679 ikm_usage_print_reactors(); 680 exit(exit_val); 681 } 682 683 /* 684 * parse_arguments - parse arguments and set config 685 */ 686 static int parse_arguments(char *monitor_name, int argc, char **argv) 687 { 688 int c, retval; 689 690 config_my_pid = getpid(); 691 692 while (1) { 693 static struct option long_options[] = { 694 {"help", no_argument, 0, 'h'}, 695 {"reactor", required_argument, 0, 'r'}, 696 {"self", no_argument, 0, 's'}, 697 {"trace", no_argument, 0, 't'}, 698 {"verbose", no_argument, 0, 'v'}, 699 {0, 0, 0, 0} 700 }; 701 702 /* getopt_long stores the option index here. */ 703 int option_index = 0; 704 705 c = getopt_long(argc, argv, "hr:stv", long_options, &option_index); 706 707 /* detect the end of the options. */ 708 if (c == -1) 709 break; 710 711 switch (c) { 712 case 'h': 713 ikm_usage(0, monitor_name, "help:"); 714 break; 715 case 'r': 716 config_reactor = optarg; 717 break; 718 case 's': 719 config_my_pid = 0; 720 break; 721 case 't': 722 config_trace = 1; 723 break; 724 case 'v': 725 config_debug = 1; 726 break; 727 } 728 } 729 730 if (config_reactor) { 731 config_initial_reactor = ikm_get_current_reactor(monitor_name); 732 if (!config_initial_reactor) 733 ikm_usage(1, monitor_name, 734 "ikm: failed to read current reactor, are reactors enabled?"); 735 736 retval = ikm_write_reactor(monitor_name, config_reactor); 737 if (retval <= 0) 738 ikm_usage(1, monitor_name, 739 "ikm: failed to set %s reactor, is it available?", 740 config_reactor); 741 } 742 743 debug_msg("ikm: my pid is %d\n", config_my_pid); 744 745 return 0; 746 } 747 748 /** 749 * ikm_run_monitor - apply configs and run the monitor 750 * 751 * Returns 1 if a monitor was found an executed, 0 if no 752 * monitors were found, or -1 on error. 753 */ 754 int ikm_run_monitor(char *monitor_name, int argc, char **argv) 755 { 756 struct trace_instance *inst = NULL; 757 char *nested_name, full_name[2*MAX_DA_NAME_LEN]; 758 int retval; 759 760 nested_name = strstr(monitor_name, ":"); 761 if (nested_name) 762 ++nested_name; 763 else 764 nested_name = monitor_name; 765 766 retval = __ikm_find_monitor_name(monitor_name, full_name); 767 if (!retval) 768 return 0; 769 if (retval < 0) { 770 err_msg("ikm: error finding monitor %s\n", nested_name); 771 return -1; 772 } 773 774 retval = __ikm_read_enable(full_name); 775 if (retval) { 776 err_msg("ikm: monitor %s (in-kernel) is already enabled\n", nested_name); 777 return -1; 778 } 779 780 /* we should be good to go */ 781 retval = parse_arguments(full_name, argc, argv); 782 if (retval) 783 ikm_usage(1, nested_name, "ikm: failed parsing arguments"); 784 785 if (config_trace) { 786 inst = ikm_setup_trace_instance(nested_name); 787 if (!inst) 788 return -1; 789 } 790 791 retval = ikm_enable(full_name); 792 if (retval < 0) 793 goto out_free_instance; 794 795 if (config_trace) 796 ikm_print_header(inst->seq); 797 798 while (!should_stop()) { 799 if (config_trace) { 800 retval = tracefs_iterate_raw_events(inst->tep, 801 inst->inst, 802 NULL, 803 0, 804 collect_registered_events, 805 inst); 806 if (retval) { 807 err_msg("ikm: error reading trace buffer\n"); 808 break; 809 } 810 } 811 812 sleep(1); 813 } 814 815 ikm_disable(full_name); 816 ikm_destroy_trace_instance(inst); 817 818 if (config_reactor && config_initial_reactor) 819 ikm_write_reactor(full_name, config_initial_reactor); 820 821 return 1; 822 823 out_free_instance: 824 ikm_destroy_trace_instance(inst); 825 if (config_reactor && config_initial_reactor) 826 ikm_write_reactor(full_name, config_initial_reactor); 827 return -1; 828 } 829