From 50bda4f1fc8a3a62176f3ecd23d47a863727f61d Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Sat, 21 Oct 2023 23:00:04 +0000 Subject: [PATCH 1/5] update(userspace/falco): add libsinsp state metrics option Signed-off-by: Melissa Kilby --- falco.yaml | 24 ++++-- userspace/falco/configuration.cpp | 2 + userspace/falco/configuration.h | 1 + userspace/falco/stats_writer.cpp | 130 ++++++++++++++++++------------ 4 files changed, 100 insertions(+), 57 deletions(-) diff --git a/falco.yaml b/falco.yaml index 15d4dc28d06..e7ca72f9303 100644 --- a/falco.yaml +++ b/falco.yaml @@ -725,13 +725,22 @@ syscall_event_drops: # number of CPUs to determine overall usage. Memory metrics are provided in raw # units (`kb` for `RSS`, `PSS` and `VSZ` or `bytes` for `container_memory_used`) # and can be uniformly converted to megabytes (MB) using the -# `convert_memory_to_mb` functionality. In environments such as Kubernetes, it -# is crucial to track Falco's container memory usage. To customize the path of -# the memory metric file, you can create an environment variable named -# `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By default, Falco -# uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to monitor -# container memory usage, which aligns with Kubernetes' -# `container_memory_working_set_bytes` metric. +# `convert_memory_to_mb` functionality. In environments such as Kubernetes when +# deployed as daemonset, it is crucial to track Falco's container memory usage. +# To customize the path of the memory metric file, you can create an environment +# variable named `FALCO_CGROUP_MEM_PATH` and set it to the desired file path. By +# default, Falco uses the file `/sys/fs/cgroup/memory/memory.usage_in_bytes` to +# monitor container memory usage, which aligns with Kubernetes' +# `container_memory_working_set_bytes` metric. Finally, we emit the overall host +# CPU and memory usages, along with the total number of processes and open file +# descriptors (fds) on the host, obtained from the proc file system unrelated to +# Falco's monitoring. These metrics help assess Falco's usage in relation to the +# server's workload intensity. +# +# `state_counters_enabled`: Emit counters related to Falco's state engine, including +# added, removed threads or file descriptors (fds), and failed lookup, store, or +# retrieve actions in relation to Falco's underlying process cache table (threadtable). +# We also log the number of currently cached containers if applicable. # # `kernel_event_counters_enabled`: Emit kernel side event and drop counters, as # an alternative to `syscall_event_drops`, but with some differences. These @@ -764,6 +773,7 @@ metrics: output_rule: true # output_file: /tmp/falco_stats.jsonl resource_utilization_enabled: true + state_counters_enabled: true kernel_event_counters_enabled: true libbpf_stats_enabled: true convert_memory_to_mb: true diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index e36fe3be735..f49d45f84b1 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -73,6 +73,7 @@ falco_configuration::falco_configuration(): m_metrics_stats_rule_enabled(false), m_metrics_output_file(""), m_metrics_resource_utilization_enabled(true), + m_metrics_state_counters_enabled(true), m_metrics_kernel_event_counters_enabled(true), m_metrics_libbpf_stats_enabled(true), m_metrics_convert_memory_to_mb(true), @@ -381,6 +382,7 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h m_metrics_stats_rule_enabled = config.get_scalar("metrics.output_rule", false); m_metrics_output_file = config.get_scalar("metrics.output_file", ""); m_metrics_resource_utilization_enabled = config.get_scalar("metrics.resource_utilization_enabled", true); + m_metrics_state_counters_enabled = config.get_scalar("metrics.state_counters_enabled", true); m_metrics_kernel_event_counters_enabled = config.get_scalar("metrics.kernel_event_counters_enabled", true); m_metrics_libbpf_stats_enabled = config.get_scalar("metrics.libbpf_stats_enabled", true); m_metrics_convert_memory_to_mb = config.get_scalar("metrics.convert_memory_to_mb", true); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index ce6fb459c39..ed1a6dee1d8 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -122,6 +122,7 @@ class falco_configuration bool m_metrics_stats_rule_enabled; std::string m_metrics_output_file; bool m_metrics_resource_utilization_enabled; + bool m_metrics_state_counters_enabled; bool m_metrics_kernel_event_counters_enabled; bool m_metrics_libbpf_stats_enabled; bool m_metrics_convert_memory_to_mb; diff --git a/userspace/falco/stats_writer.cpp b/userspace/falco/stats_writer.cpp index 450d3def403..80678713dcc 100644 --- a/userspace/falco/stats_writer.cpp +++ b/userspace/falco/stats_writer.cpp @@ -358,60 +358,86 @@ void stats_writer::collector::get_metrics_output_fields_additional( const scap_agent_info* agent_info = inspector->get_agent_info(); #if !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) - /* Resource utilization, CPU and memory usage etc. */ uint32_t nstats = 0; int32_t rc = 0; + uint32_t flags = 0; + if (m_writer->m_config->m_metrics_resource_utilization_enabled) { - const scap_stats_v2* utilization; - auto buffer = inspector->get_sinsp_stats_v2_buffer(); - utilization = libsinsp::resource_utilization::get_resource_utilization(agent_info, buffer, &nstats, &rc); - if (utilization && rc == 0 && nstats > 0) + /* Resource utilization, CPU and memory usage etc. */ + flags |= PPM_SCAP_STATS_RESOURCE_UTILIZATION; + } + + if (m_writer->m_config->m_metrics_state_counters_enabled) + { + /* Counters related to sinsp state (threadtable including fds per thread as well as container cache) */ + flags |= PPM_SCAP_STATS_STATE_COUNTERS; + } + + auto buffer = inspector->get_sinsp_stats_v2_buffer(); + sinsp_stats_v2 sinsp_stats_v2 = inspector->get_sinsp_stats_v2(); + sinsp_thread_manager* thread_manager = inspector->m_thread_manager; + const scap_stats_v2* sinsp_stats_v2_snapshot = libsinsp::stats::get_sinsp_stats_v2(flags, agent_info, thread_manager, sinsp_stats_v2, buffer, &nstats, &rc); + + if (sinsp_stats_v2_snapshot && rc == 0 && nstats > 0) + { + for(uint32_t stat = 0; stat < nstats; stat++) { - for(uint32_t stat = 0; stat < nstats; stat++) + if (sinsp_stats_v2_snapshot[stat].name[0] == '\0') + { + break; + } + char metric_name[STATS_NAME_MAX] = "falco."; + strlcat(metric_name, sinsp_stats_v2_snapshot[stat].name, sizeof(metric_name)); + switch(sinsp_stats_v2_snapshot[stat].type) { - char metric_name[STATS_NAME_MAX] = "falco."; - strlcat(metric_name, utilization[stat].name, sizeof(metric_name)); - switch(utilization[stat].type) + case STATS_VALUE_TYPE_U64: + if (sinsp_stats_v2_snapshot[stat].value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) { - case STATS_VALUE_TYPE_U64: - if (utilization[stat].value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { - break; - } - if (m_writer->m_config->m_metrics_convert_memory_to_mb && strncmp(utilization[stat].name, "container_memory_used", 22) == 0) // exact str match - { - output_fields[metric_name] = (uint64_t)(utilization[stat].value.u64 / (double)1024 / (double)1024); - } - else - { - output_fields[metric_name] = utilization[stat].value.u64; - } break; - case STATS_VALUE_TYPE_U32: - if (utilization[stat].value.u32 == 0 && !m_writer->m_config->m_metrics_include_empty_values) - { - break; - } - if (m_writer->m_config->m_metrics_convert_memory_to_mb && strncmp(utilization[stat].name, "memory_", 7) == 0) // prefix match + } + if (m_writer->m_config->m_metrics_convert_memory_to_mb) + { + if (strncmp(sinsp_stats_v2_snapshot[stat].name, "container_memory_used", 22) == 0) // exact str match { - output_fields[metric_name] = (uint32_t)(utilization[stat].value.u32 / (double)1024); - } - else + output_fields[metric_name] = (uint64_t)(sinsp_stats_v2_snapshot[stat].value.u64 / (double)1024 / (double)1024); + + } else if (strncmp(sinsp_stats_v2_snapshot[stat].name, "memory_", 7) == 0) // prefix match { - output_fields[metric_name] = utilization[stat].value.u32; - } - break; - case STATS_VALUE_TYPE_D: - if (utilization[stat].value.d == 0 && !m_writer->m_config->m_metrics_include_empty_values) + output_fields[metric_name] = (uint64_t)(sinsp_stats_v2_snapshot[stat].value.u64 / (double)1024); + } else { - break; + output_fields[metric_name] = sinsp_stats_v2_snapshot[stat].value.u64; } - output_fields[metric_name] = utilization[stat].value.d; + } + else + { + output_fields[metric_name] = sinsp_stats_v2_snapshot[stat].value.u64; + } + break; + case STATS_VALUE_TYPE_U32: + if (sinsp_stats_v2_snapshot[stat].value.u32 == 0 && !m_writer->m_config->m_metrics_include_empty_values) + { break; - default: + } + if (m_writer->m_config->m_metrics_convert_memory_to_mb && strncmp(sinsp_stats_v2_snapshot[stat].name, "memory_", 7) == 0) // prefix match + { + output_fields[metric_name] = (uint32_t)(sinsp_stats_v2_snapshot[stat].value.u32 / (double)1024); + } + else + { + output_fields[metric_name] = sinsp_stats_v2_snapshot[stat].value.u32; + } + break; + case STATS_VALUE_TYPE_D: + if (sinsp_stats_v2_snapshot[stat].value.d == 0 && !m_writer->m_config->m_metrics_include_empty_values) + { break; } + output_fields[metric_name] = sinsp_stats_v2_snapshot[stat].value.d; + break; + default: + break; } } } @@ -424,7 +450,7 @@ void stats_writer::collector::get_metrics_output_fields_additional( /* Kernel side stats counters and libbpf stats if applicable. */ nstats = 0; rc = 0; - uint32_t flags = 0; + flags = 0; if (m_writer->m_config->m_metrics_kernel_event_counters_enabled) { @@ -434,8 +460,8 @@ void stats_writer::collector::get_metrics_output_fields_additional( { flags |= PPM_SCAP_STATS_LIBBPF_STATS; } - const scap_stats_v2* stats_v2 = inspector->get_capture_stats_v2(flags, &nstats, &rc); - if (stats_v2 && nstats > 0 && rc == 0) + const scap_stats_v2* stats_v2_snapshot = inspector->get_capture_stats_v2(flags, &nstats, &rc); + if (stats_v2_snapshot && nstats > 0 && rc == 0) { /* Cache n_evts and n_drops to derive n_drops_perc. */ uint64_t n_evts = 0; @@ -444,17 +470,21 @@ void stats_writer::collector::get_metrics_output_fields_additional( uint64_t n_drops_delta = 0; for(uint32_t stat = 0; stat < nstats; stat++) { + if (stats_v2_snapshot[stat].name[0] == '\0') + { + break; + } // todo: as we expand scap_stats_v2 prefix may be pushed to scap or we may need to expand // functionality here for example if we add userspace syscall counters that should be prefixed w/ `falco.` char metric_name[STATS_NAME_MAX] = "scap."; - strlcat(metric_name, stats_v2[stat].name, sizeof(metric_name)); - switch(stats_v2[stat].type) + strlcat(metric_name, stats_v2_snapshot[stat].name, sizeof(metric_name)); + switch(stats_v2_snapshot[stat].type) { case STATS_VALUE_TYPE_U64: /* Always send high level n_evts related fields, even if zero. */ - if (strncmp(stats_v2[stat].name, "n_evts", 7) == 0) // exact not prefix match here + if (strncmp(stats_v2_snapshot[stat].name, "n_evts", 7) == 0) // exact not prefix match here { - n_evts = stats_v2[stat].value.u64; + n_evts = stats_v2_snapshot[stat].value.u64; output_fields[metric_name] = n_evts; output_fields["scap.n_evts_prev"] = m_last_n_evts; n_evts_delta = n_evts - m_last_n_evts; @@ -470,9 +500,9 @@ void stats_writer::collector::get_metrics_output_fields_additional( m_last_n_evts = n_evts; } /* Always send high level n_drops related fields, even if zero. */ - else if (strncmp(stats_v2[stat].name, "n_drops", 8) == 0) // exact not prefix match here + else if (strncmp(stats_v2_snapshot[stat].name, "n_drops", 8) == 0) // exact not prefix match here { - n_drops = stats_v2[stat].value.u64; + n_drops = stats_v2_snapshot[stat].value.u64; output_fields[metric_name] = n_drops; output_fields["scap.n_drops_prev"] = m_last_n_drops; n_drops_delta = n_drops - m_last_n_drops; @@ -487,11 +517,11 @@ void stats_writer::collector::get_metrics_output_fields_additional( } m_last_n_drops = n_drops; } - if (stats_v2[stat].value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) + if (stats_v2_snapshot[stat].value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } - output_fields[metric_name] = stats_v2[stat].value.u64; + output_fields[metric_name] = stats_v2_snapshot[stat].value.u64; break; default: break; From 4d200499a009de484539342eb4022d29bf4a2f84 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Mon, 23 Oct 2023 16:22:21 +0000 Subject: [PATCH 2/5] cleanup(libsinsp): simplify metrics flags config handling Signed-off-by: Melissa Kilby --- userspace/falco/configuration.cpp | 32 ++++++-- userspace/falco/configuration.h | 5 +- userspace/falco/stats_writer.cpp | 127 ++++++------------------------ 3 files changed, 51 insertions(+), 113 deletions(-) diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index f49d45f84b1..54412e94237 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -72,10 +72,7 @@ falco_configuration::falco_configuration(): m_metrics_interval(5000), m_metrics_stats_rule_enabled(false), m_metrics_output_file(""), - m_metrics_resource_utilization_enabled(true), - m_metrics_state_counters_enabled(true), - m_metrics_kernel_event_counters_enabled(true), - m_metrics_libbpf_stats_enabled(true), + m_metrics_flags((PPM_SCAP_STATS_KERNEL_COUNTERS | PPM_SCAP_STATS_LIBBPF_STATS | PPM_SCAP_STATS_RESOURCE_UTILIZATION | PPM_SCAP_STATS_STATE_COUNTERS)), m_metrics_convert_memory_to_mb(true), m_metrics_include_empty_values(false) { @@ -381,10 +378,29 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h m_metrics_interval = falco::utils::parse_prometheus_interval(m_metrics_interval_str); m_metrics_stats_rule_enabled = config.get_scalar("metrics.output_rule", false); m_metrics_output_file = config.get_scalar("metrics.output_file", ""); - m_metrics_resource_utilization_enabled = config.get_scalar("metrics.resource_utilization_enabled", true); - m_metrics_state_counters_enabled = config.get_scalar("metrics.state_counters_enabled", true); - m_metrics_kernel_event_counters_enabled = config.get_scalar("metrics.kernel_event_counters_enabled", true); - m_metrics_libbpf_stats_enabled = config.get_scalar("metrics.libbpf_stats_enabled", true); + + m_metrics_flags = 0; + if (config.get_scalar("metrics.resource_utilization_enabled", true)) + { + m_metrics_flags |= PPM_SCAP_STATS_RESOURCE_UTILIZATION; + + } + if (config.get_scalar("metrics.state_counters_enabled", true)) + { + m_metrics_flags |= PPM_SCAP_STATS_STATE_COUNTERS; + + } + if (config.get_scalar("metrics.kernel_event_counters_enabled", true)) + { + m_metrics_flags |= PPM_SCAP_STATS_KERNEL_COUNTERS; + + } + if (config.get_scalar("metrics.libbpf_stats_enabled", true)) + { + m_metrics_flags |= PPM_SCAP_STATS_LIBBPF_STATS; + + } + m_metrics_convert_memory_to_mb = config.get_scalar("metrics.convert_memory_to_mb", true); m_metrics_include_empty_values = config.get_scalar("metrics.include_empty_values", false); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index ed1a6dee1d8..34ee0a6a62a 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -121,10 +121,7 @@ class falco_configuration uint64_t m_metrics_interval; bool m_metrics_stats_rule_enabled; std::string m_metrics_output_file; - bool m_metrics_resource_utilization_enabled; - bool m_metrics_state_counters_enabled; - bool m_metrics_kernel_event_counters_enabled; - bool m_metrics_libbpf_stats_enabled; + uint32_t m_metrics_flags; bool m_metrics_convert_memory_to_mb; bool m_metrics_include_empty_values; diff --git a/userspace/falco/stats_writer.cpp b/userspace/falco/stats_writer.cpp index 80678713dcc..2be9f1bab88 100644 --- a/userspace/falco/stats_writer.cpp +++ b/userspace/falco/stats_writer.cpp @@ -15,9 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -#ifndef _WIN32 #include -#endif #include #include #include @@ -35,11 +33,7 @@ limitations under the License. // overflows here. Threads calling stats_writer::handle() will just // check that this value changed since their last observation. static std::atomic s_timer((stats_writer::ticker_t) 0); -#if !defined(__APPLE__) && !defined(_WIN32) static timer_t s_timerid; -#else -static uint16_t s_timerid; -#endif // note: Workaround for older GLIBC versions (< 2.35), where calling timer_delete() // with an invalid timer ID not returned by timer_create() causes a segfault because of // a bug in GLIBC (https://sourceware.org/bugzilla/show_bug.cgi?id=28257). @@ -52,65 +46,6 @@ static void timer_handler(int signum) s_timer.fetch_add(1, std::memory_order_relaxed); } -#if defined(_WIN32) -bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) -{ - return true; -} -#endif - -#if defined(__APPLE__) -bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) -{ - struct sigaction handler = {}; - - memset (&handler, 0, sizeof(handler)); - handler.sa_handler = &timer_handler; - if (sigaction(SIGALRM, &handler, NULL) == -1) - { - err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); - return false; - } - - struct sigevent sev = {}; - /* Create the timer */ - sev.sigev_notify = SIGEV_SIGNAL; - sev.sigev_signo = SIGALRM; - sev.sigev_value.sival_ptr = &s_timerid; - - return true; -} -#endif - -#if defined(EMSCRIPTEN) -bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) -{ - struct itimerspec timer = {}; - struct sigaction handler = {}; - - memset (&handler, 0, sizeof(handler)); - handler.sa_handler = &timer_handler; - if (sigaction(SIGALRM, &handler, NULL) == -1) - { - err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); - return false; - } - - struct sigevent sev = {}; - /* Create the timer */ - sev.sigev_notify = SIGEV_SIGNAL; - sev.sigev_signo = SIGALRM; - sev.sigev_value.sival_ptr = &s_timerid; - - timer.it_value.tv_sec = interval_msec / 1000; - timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000; - timer.it_interval = timer.it_value; - - return true; -} -#endif - -#if defined(__linux__) bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) { struct itimerspec timer = {}; @@ -123,12 +58,13 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); return false; } - + struct sigevent sev = {}; /* Create the timer */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; sev.sigev_value.sival_ptr = &s_timerid; +#ifndef __EMSCRIPTEN__ // delete any previously set timer if (s_timerid_exists) { @@ -147,19 +83,20 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) } s_timerid_exists = true; +#endif timer.it_value.tv_sec = interval_msec / 1000; timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000; timer.it_interval = timer.it_value; +#ifndef __EMSCRIPTEN__ if (timer_settime(s_timerid, 0, &timer, NULL) == -1) { err = std::string("Could not set up periodic timer: ") + strerror(errno); return false; } - +#endif return true; } -#endif stats_writer::ticker_t stats_writer::get_ticker() { @@ -214,7 +151,7 @@ stats_writer::~stats_writer() m_file_output.close(); } // delete timerID and reset timer -#ifdef __linux__ +#ifndef __EMSCRIPTEN__ if (s_timerid_exists) { timer_delete(s_timerid); @@ -295,7 +232,7 @@ void stats_writer::worker() noexcept } catch(const std::exception &e) { - falco_logger::log(falco_logger::level::ERR, "stats_writer (worker): " + std::string(e.what()) + "\n"); + falco_logger::log(LOG_ERR, "stats_writer (worker): " + std::string(e.what()) + "\n"); } } } @@ -356,26 +293,15 @@ void stats_writer::collector::get_metrics_output_fields_additional( double stats_snapshot_time_delta_sec, const std::string& src) { const scap_agent_info* agent_info = inspector->get_agent_info(); + const scap_machine_info* machine_info = inspector->get_machine_info(); #if !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) uint32_t nstats = 0; int32_t rc = 0; - uint32_t flags = 0; - - if (m_writer->m_config->m_metrics_resource_utilization_enabled) - { - /* Resource utilization, CPU and memory usage etc. */ - flags |= PPM_SCAP_STATS_RESOURCE_UTILIZATION; - } - - if (m_writer->m_config->m_metrics_state_counters_enabled) - { - /* Counters related to sinsp state (threadtable including fds per thread as well as container cache) */ - flags |= PPM_SCAP_STATS_STATE_COUNTERS; - } + uint32_t flags = m_writer->m_config->m_metrics_flags; auto buffer = inspector->get_sinsp_stats_v2_buffer(); - sinsp_stats_v2 sinsp_stats_v2 = inspector->get_sinsp_stats_v2(); + auto sinsp_stats_v2 = inspector->get_sinsp_stats_v2(); sinsp_thread_manager* thread_manager = inspector->m_thread_manager; const scap_stats_v2* sinsp_stats_v2_snapshot = libsinsp::stats::get_sinsp_stats_v2(flags, agent_info, thread_manager, sinsp_stats_v2, buffer, &nstats, &rc); @@ -450,18 +376,17 @@ void stats_writer::collector::get_metrics_output_fields_additional( /* Kernel side stats counters and libbpf stats if applicable. */ nstats = 0; rc = 0; - flags = 0; - - if (m_writer->m_config->m_metrics_kernel_event_counters_enabled) + if (!(inspector->check_current_engine(BPF_ENGINE) || inspector->check_current_engine(MODERN_BPF_ENGINE))) { - flags |= PPM_SCAP_STATS_KERNEL_COUNTERS; + flags &= ~PPM_SCAP_STATS_LIBBPF_STATS; } - if (m_writer->m_config->m_metrics_libbpf_stats_enabled && (inspector->check_current_engine(BPF_ENGINE) || inspector->check_current_engine(MODERN_BPF_ENGINE))) + if (!(machine_info->flags & PPM_BPF_STATS_ENABLED)) { - flags |= PPM_SCAP_STATS_LIBBPF_STATS; + flags &= ~PPM_SCAP_STATS_LIBBPF_STATS; } - const scap_stats_v2* stats_v2_snapshot = inspector->get_capture_stats_v2(flags, &nstats, &rc); - if (stats_v2_snapshot && nstats > 0 && rc == 0) + + const scap_stats_v2* scap_stats_v2_snapshot = inspector->get_capture_stats_v2(flags, &nstats, &rc); + if (scap_stats_v2_snapshot && nstats > 0 && rc == 0) { /* Cache n_evts and n_drops to derive n_drops_perc. */ uint64_t n_evts = 0; @@ -470,21 +395,21 @@ void stats_writer::collector::get_metrics_output_fields_additional( uint64_t n_drops_delta = 0; for(uint32_t stat = 0; stat < nstats; stat++) { - if (stats_v2_snapshot[stat].name[0] == '\0') + if (scap_stats_v2_snapshot[stat].name[0] == '\0') { break; } // todo: as we expand scap_stats_v2 prefix may be pushed to scap or we may need to expand // functionality here for example if we add userspace syscall counters that should be prefixed w/ `falco.` char metric_name[STATS_NAME_MAX] = "scap."; - strlcat(metric_name, stats_v2_snapshot[stat].name, sizeof(metric_name)); - switch(stats_v2_snapshot[stat].type) + strlcat(metric_name, scap_stats_v2_snapshot[stat].name, sizeof(metric_name)); + switch(scap_stats_v2_snapshot[stat].type) { case STATS_VALUE_TYPE_U64: /* Always send high level n_evts related fields, even if zero. */ - if (strncmp(stats_v2_snapshot[stat].name, "n_evts", 7) == 0) // exact not prefix match here + if (strncmp(scap_stats_v2_snapshot[stat].name, "n_evts", 7) == 0) // exact not prefix match here { - n_evts = stats_v2_snapshot[stat].value.u64; + n_evts = scap_stats_v2_snapshot[stat].value.u64; output_fields[metric_name] = n_evts; output_fields["scap.n_evts_prev"] = m_last_n_evts; n_evts_delta = n_evts - m_last_n_evts; @@ -500,9 +425,9 @@ void stats_writer::collector::get_metrics_output_fields_additional( m_last_n_evts = n_evts; } /* Always send high level n_drops related fields, even if zero. */ - else if (strncmp(stats_v2_snapshot[stat].name, "n_drops", 8) == 0) // exact not prefix match here + else if (strncmp(scap_stats_v2_snapshot[stat].name, "n_drops", 8) == 0) // exact not prefix match here { - n_drops = stats_v2_snapshot[stat].value.u64; + n_drops = scap_stats_v2_snapshot[stat].value.u64; output_fields[metric_name] = n_drops; output_fields["scap.n_drops_prev"] = m_last_n_drops; n_drops_delta = n_drops - m_last_n_drops; @@ -517,11 +442,11 @@ void stats_writer::collector::get_metrics_output_fields_additional( } m_last_n_drops = n_drops; } - if (stats_v2_snapshot[stat].value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) + if (scap_stats_v2_snapshot[stat].value.u64 == 0 && !m_writer->m_config->m_metrics_include_empty_values) { break; } - output_fields[metric_name] = stats_v2_snapshot[stat].value.u64; + output_fields[metric_name] = scap_stats_v2_snapshot[stat].value.u64; break; default: break; From 70a14e36763d5bab152292eb14dd16c7d3cca262 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Sun, 29 Oct 2023 04:53:49 +0000 Subject: [PATCH 3/5] cleanup(userspace/falco): enable sinsp_stats_v2 Signed-off-by: Melissa Kilby --- userspace/falco/app/actions/helpers_inspector.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 28df58d221d..3fd606b884a 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -54,6 +54,11 @@ falco::app::run_result falco::app::actions::open_live_inspector( { try { + if((s.config->m_metrics_flags & PPM_SCAP_STATS_STATE_COUNTERS)) + { + inspector->set_sinsp_stats_v2_enabled(); + } + if (source != falco_common::syscall_source) /* Plugin engine */ { for (const auto& p: inspector->get_plugin_manager()->plugins()) From ada5f21f5a56990596a046d4757d31894813b691 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Sat, 18 Nov 2023 04:57:05 +0000 Subject: [PATCH 4/5] cleanup(userspace/falco): minor adjustments to stats writer and rebase correction Signed-off-by: Melissa Kilby --- userspace/falco/stats_writer.cpp | 91 ++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 15 deletions(-) diff --git a/userspace/falco/stats_writer.cpp b/userspace/falco/stats_writer.cpp index 2be9f1bab88..1a414e2abed 100644 --- a/userspace/falco/stats_writer.cpp +++ b/userspace/falco/stats_writer.cpp @@ -15,7 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +#ifndef _WIN32 #include +#endif #include #include #include @@ -33,7 +35,11 @@ limitations under the License. // overflows here. Threads calling stats_writer::handle() will just // check that this value changed since their last observation. static std::atomic s_timer((stats_writer::ticker_t) 0); +#if !defined(__APPLE__) && !defined(_WIN32) static timer_t s_timerid; +#else +static uint16_t s_timerid; +#endif // note: Workaround for older GLIBC versions (< 2.35), where calling timer_delete() // with an invalid timer ID not returned by timer_create() causes a segfault because of // a bug in GLIBC (https://sourceware.org/bugzilla/show_bug.cgi?id=28257). @@ -46,6 +52,37 @@ static void timer_handler(int signum) s_timer.fetch_add(1, std::memory_order_relaxed); } +#if defined(_WIN32) +bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) +{ + return true; +} +#endif + +#if defined(__APPLE__) +bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) +{ + struct sigaction handler = {}; + + memset (&handler, 0, sizeof(handler)); + handler.sa_handler = &timer_handler; + if (sigaction(SIGALRM, &handler, NULL) == -1) + { + err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); + return false; + } + + struct sigevent sev = {}; + /* Create the timer */ + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = SIGALRM; + sev.sigev_value.sival_ptr = &s_timerid; + + return true; +} +#endif + +#if defined(EMSCRIPTEN) bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) { struct itimerspec timer = {}; @@ -58,13 +95,40 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); return false; } - + + struct sigevent sev = {}; + /* Create the timer */ + sev.sigev_notify = SIGEV_SIGNAL; + sev.sigev_signo = SIGALRM; + sev.sigev_value.sival_ptr = &s_timerid; + + timer.it_value.tv_sec = interval_msec / 1000; + timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000; + timer.it_interval = timer.it_value; + + return true; +} +#endif + +#if defined(__linux__) +bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) +{ + struct itimerspec timer = {}; + struct sigaction handler = {}; + + memset (&handler, 0, sizeof(handler)); + handler.sa_handler = &timer_handler; + if (sigaction(SIGALRM, &handler, NULL) == -1) + { + err = std::string("Could not set up signal handler for periodic timer: ") + strerror(errno); + return false; + } + struct sigevent sev = {}; /* Create the timer */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGALRM; sev.sigev_value.sival_ptr = &s_timerid; -#ifndef __EMSCRIPTEN__ // delete any previously set timer if (s_timerid_exists) { @@ -83,20 +147,19 @@ bool stats_writer::init_ticker(uint32_t interval_msec, std::string &err) } s_timerid_exists = true; -#endif timer.it_value.tv_sec = interval_msec / 1000; timer.it_value.tv_nsec = (interval_msec % 1000) * 1000 * 1000; timer.it_interval = timer.it_value; -#ifndef __EMSCRIPTEN__ if (timer_settime(s_timerid, 0, &timer, NULL) == -1) { err = std::string("Could not set up periodic timer: ") + strerror(errno); return false; } -#endif + return true; } +#endif stats_writer::ticker_t stats_writer::get_ticker() { @@ -151,7 +214,7 @@ stats_writer::~stats_writer() m_file_output.close(); } // delete timerID and reset timer -#ifndef __EMSCRIPTEN__ +#ifdef __linux__ if (s_timerid_exists) { timer_delete(s_timerid); @@ -232,7 +295,7 @@ void stats_writer::worker() noexcept } catch(const std::exception &e) { - falco_logger::log(LOG_ERR, "stats_writer (worker): " + std::string(e.what()) + "\n"); + falco_logger::log(falco_logger::level::ERR, "stats_writer (worker): " + std::string(e.what()) + "\n"); } } } @@ -280,7 +343,7 @@ void stats_writer::collector::get_metrics_output_fields_wrapper( if (m_last_num_evts != 0 && stats_snapshot_time_delta_sec > 0) { /* Successfully processed userspace event rate. */ - output_fields["falco.evts_rate_sec"] = (double)((num_evts - m_last_num_evts) / (double)stats_snapshot_time_delta_sec); + output_fields["falco.evts_rate_sec"] = std::round((double)((num_evts - m_last_num_evts) / (double)stats_snapshot_time_delta_sec) * 10.0) / 10.0; // round to 1 decimal } output_fields["falco.num_evts"] = num_evts; output_fields["falco.num_evts_prev"] = m_last_num_evts; @@ -293,7 +356,6 @@ void stats_writer::collector::get_metrics_output_fields_additional( double stats_snapshot_time_delta_sec, const std::string& src) { const scap_agent_info* agent_info = inspector->get_agent_info(); - const scap_machine_info* machine_info = inspector->get_machine_info(); #if !defined(MINIMAL_BUILD) and !defined(__EMSCRIPTEN__) uint32_t nstats = 0; @@ -380,10 +442,9 @@ void stats_writer::collector::get_metrics_output_fields_additional( { flags &= ~PPM_SCAP_STATS_LIBBPF_STATS; } - if (!(machine_info->flags & PPM_BPF_STATS_ENABLED)) - { - flags &= ~PPM_SCAP_STATS_LIBBPF_STATS; - } + + // Note: ENGINE_FLAG_BPF_STATS_ENABLED check has been moved to libs, that is, when libbpf stats is not enabled + // in the kernel settings we won't collect them even if the end user enabled the libbpf stats option const scap_stats_v2* scap_stats_v2_snapshot = inspector->get_capture_stats_v2(flags, &nstats, &rc); if (scap_stats_v2_snapshot && nstats > 0 && rc == 0) @@ -416,7 +477,7 @@ void stats_writer::collector::get_metrics_output_fields_additional( if (n_evts_delta != 0 && stats_snapshot_time_delta_sec > 0) { /* n_evts is total number of kernel side events. */ - output_fields["scap.evts_rate_sec"] = (double)(n_evts_delta / stats_snapshot_time_delta_sec); + output_fields["scap.evts_rate_sec"] = std::round((double)(n_evts_delta / stats_snapshot_time_delta_sec) * 10.0) / 10.0; // round to 1 decimal } else { @@ -434,7 +495,7 @@ void stats_writer::collector::get_metrics_output_fields_additional( if (n_drops_delta != 0 && stats_snapshot_time_delta_sec > 0) { /* n_drops is total number of kernel side event drops. */ - output_fields["scap.evts_drop_rate_sec"] = (double)(n_drops_delta / stats_snapshot_time_delta_sec); + output_fields["scap.evts_drop_rate_sec"] = std::round((double)(n_drops_delta / stats_snapshot_time_delta_sec) * 10.0) / 10.0; // round to 1 decimal } else { From 6b05bcfe0a6899db817867674c6b8e17afb337a5 Mon Sep 17 00:00:00 2001 From: Melissa Kilby Date: Mon, 27 Nov 2023 04:58:16 +0000 Subject: [PATCH 5/5] update(cmake): bump libs and driver to c2fd308 plus bump falco engine version Signed-off-by: Melissa Kilby --- cmake/modules/driver.cmake | 4 ++-- cmake/modules/falcosecurity-libs.cmake | 4 ++-- userspace/engine/falco_engine_version.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cmake/modules/driver.cmake b/cmake/modules/driver.cmake index f92b1d2e3f3..1bc0ed11297 100644 --- a/cmake/modules/driver.cmake +++ b/cmake/modules/driver.cmake @@ -34,8 +34,8 @@ else() # In case you want to test against another driver version (or branch, or commit) just pass the variable - # ie., `cmake -DDRIVER_VERSION=dev ..` if(NOT DRIVER_VERSION) - set(DRIVER_VERSION "7cbc03a535ead9d530f7b77ffd68766d5e22da74") - set(DRIVER_CHECKSUM "SHA256=94d110ad1738cce2635fd15d41701bea5e061fd9a5a4be3f2ee8ec7a28fe50cc") + set(DRIVER_VERSION "c2fd3086ff1bd0fce20a24a6da9f03c47332d68a") + set(DRIVER_CHECKSUM "SHA256=b25de5174b9f7199ecaedeb84bdbb9b075871478547de4e724e625bc43322aa9") endif() # cd /path/to/build && cmake /path/to/source diff --git a/cmake/modules/falcosecurity-libs.cmake b/cmake/modules/falcosecurity-libs.cmake index ae1537c04f5..4656e97921f 100644 --- a/cmake/modules/falcosecurity-libs.cmake +++ b/cmake/modules/falcosecurity-libs.cmake @@ -35,8 +35,8 @@ else() # In case you want to test against another falcosecurity/libs version (or branch, or commit) just pass the variable - # ie., `cmake -DFALCOSECURITY_LIBS_VERSION=dev ..` if(NOT FALCOSECURITY_LIBS_VERSION) - set(FALCOSECURITY_LIBS_VERSION "7cbc03a535ead9d530f7b77ffd68766d5e22da74") - set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=94d110ad1738cce2635fd15d41701bea5e061fd9a5a4be3f2ee8ec7a28fe50cc") + set(FALCOSECURITY_LIBS_VERSION "c2fd3086ff1bd0fce20a24a6da9f03c47332d68a") + set(FALCOSECURITY_LIBS_CHECKSUM "SHA256=b25de5174b9f7199ecaedeb84bdbb9b075871478547de4e724e625bc43322aa9") endif() # cd /path/to/build && cmake /path/to/source diff --git a/userspace/engine/falco_engine_version.h b/userspace/engine/falco_engine_version.h index 66aa664b4f6..69cde5d5c1a 100644 --- a/userspace/engine/falco_engine_version.h +++ b/userspace/engine/falco_engine_version.h @@ -20,7 +20,7 @@ limitations under the License. // The version of this Falco engine #define FALCO_ENGINE_VERSION_MAJOR 0 -#define FALCO_ENGINE_VERSION_MINOR 27 +#define FALCO_ENGINE_VERSION_MINOR 28 #define FALCO_ENGINE_VERSION_PATCH 0 #define FALCO_ENGINE_VERSION \ @@ -34,4 +34,4 @@ limitations under the License. // It represents the fields supported by this version of Falco, // the event types, and the underlying driverevent schema. It's used to // detetect changes in engine version in our CI jobs. -#define FALCO_ENGINE_CHECKSUM "dbc34e88ab420320994d85f155dee6baff2dd018aacc00e249f897edc8b1e0f4" +#define FALCO_ENGINE_CHECKSUM "5d488b68856d70300ae37453295383821822d8423af170eb28e1bef52042f0b3"