From 0548d46ebf0bc72a8fcc7e2d4ba4b6c3c97908d9 Mon Sep 17 00:00:00 2001 From: Roberto Scolaro Date: Mon, 6 Feb 2023 16:29:55 +0000 Subject: [PATCH 01/29] wip: driver selection in falco.yaml Signed-off-by: Roberto Scolaro --- userspace/falco/configuration.cpp | 20 ++++++++++++++++++++ userspace/falco/configuration.h | 11 ++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 4fa0fb662df..9ac5aa5ec76 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -41,6 +41,7 @@ namespace fs = std::filesystem; static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))"); falco_configuration::falco_configuration(): + m_driver_mode(driver_mode_type::KMOD), m_json_output(false), m_json_include_output_property(true), m_json_include_tags_property(true), @@ -105,8 +106,27 @@ void falco_configuration::init(const std::string& conf_filename, const std::vect load_yaml(conf_filename, config); } +static driver_mode_type get_driver_mode(const std::string& input){ + // Set driver mode if not already set. + if( input == "bpf" ) + { + return driver_mode_type::BPF; + } + else if( input == "modern_bpf" ) + { + return driver_mode_type::MODERN_BPF; + } + else if( input == "custom" ) + { + return driver_mode_type::CUSTOM; + } + return driver_mode_type::KMOD; +} + void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) { + m_driver_mode = get_driver_mode(config.get_scalar("driver_mode", "")); + std::list rules_files; config.get_sequence>(rules_files, std::string("rules_file")); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index ce6fb459c39..07b22a4b224 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -37,6 +37,15 @@ limitations under the License. #include "event_drops.h" #include "falco_outputs.h" +enum class driver_mode_type : uint8_t +{ + INVALID = 0, + KMOD, + BPF, + MODERN_BPF, + CUSTOM +}; + class falco_configuration { public: @@ -63,7 +72,7 @@ class falco_configuration std::list m_loaded_rules_filenames; // List of loaded rule folders std::list m_loaded_rules_folders; - + driver_mode_type m_driver_mode; bool m_json_output; bool m_json_include_output_property; bool m_json_include_tags_property; From 1f3a1ce7bbad5ed7b9ad2e91b83335625e285b5e Mon Sep 17 00:00:00 2001 From: Roberto Scolaro Date: Mon, 6 Nov 2023 12:07:01 +0000 Subject: [PATCH 02/29] refacotr(configuration): enhance readability of get_driver_mode Signed-off-by: Roberto Scolaro --- userspace/falco/configuration.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 9ac5aa5ec76..eb56ee99c38 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -108,24 +108,23 @@ void falco_configuration::init(const std::string& conf_filename, const std::vect static driver_mode_type get_driver_mode(const std::string& input){ // Set driver mode if not already set. - if( input == "bpf" ) - { - return driver_mode_type::BPF; - } - else if( input == "modern_bpf" ) - { - return driver_mode_type::MODERN_BPF; - } - else if( input == "custom" ) - { - return driver_mode_type::CUSTOM; + const std::unordered_map driver_mode_lut = { + {"kmod",driver_mode_type::KMOD}, + {"bpf",driver_mode_type::BPF}, + {"modern_bpf",driver_mode_type::MODERN_BPF}, + {"custom",driver_mode_type::CUSTOM}, + }; + + if(driver_mode_lut.find(input) != driver_mode_lut.end()) { + return driver_mode_lut.at(input); + } else { + return driver_mode_type::KMOD; } - return driver_mode_type::KMOD; } void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) { - m_driver_mode = get_driver_mode(config.get_scalar("driver_mode", "")); + m_driver_mode = get_driver_mode(config.get_scalar("driver_mode", "")); std::list rules_files; From d1989bd2bc46df842a1dd010b619c80f145ac747 Mon Sep 17 00:00:00 2001 From: Roberto Scolaro Date: Mon, 6 Nov 2023 14:45:52 +0000 Subject: [PATCH 03/29] new(falco.yaml): added driver selection section Signed-off-by: Roberto Scolaro --- falco.yaml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/falco.yaml b/falco.yaml index 15d4dc28d06..50340135c5a 100644 --- a/falco.yaml +++ b/falco.yaml @@ -62,6 +62,8 @@ # syscall_event_timeouts # syscall_event_drops # metrics +# Falco driver selection +# driver_mode # Falco performance tuning (advanced) # syscall_buf_size_preset # syscall_drop_failed_exit @@ -769,6 +771,39 @@ metrics: convert_memory_to_mb: true include_empty_values: false + ############################################### +# Falco driver selection # +############################################### + +# [Stable] `driver_mode` +# +# --- [Description] +# +# Falco supports different driver modes for capturing syscall events. The choice +# of driver mode can significantly impact the performance and compatibility of +# Falco with your system. Choose the appropriate driver mode based on your +# system's configuration and requirements. +# +# Available driver modes: +# - `kmod`: Kernel Module (Kernel Module) +# - `bpf`: eBPF (Extended Berkeley Packet Filter) +# - `modern_bpf`: Modern eBPF (Modern Extended Berkeley Packet Filter) +# - `nodriver`: No Driver (No driver, just for testing) +# - `gvisor`: gVisor (gVisor sandbox) +# - `custom`: Custom Driver (Specify a custom driver module) + +# Example usage: +# driver_mode: kmod + +# Select the appropriate driver mode by uncommenting the corresponding line. +# Make sure to specify only one driver mode at a time. + +driver_mode: kmod +# driver_mode: bpf +# driver_mode: modern_bpf +# driver_mode: nodriver +# driver_mode: gvisor +# driver_mode: custom ####################################### # Falco performance tuning (advanced) # From 4fbd740d4d1100b447741feac05b111ad6894d00 Mon Sep 17 00:00:00 2001 From: Roberto Scolaro Date: Mon, 6 Nov 2023 14:46:14 +0000 Subject: [PATCH 04/29] new(userspace/falco): select driver from config Signed-off-by: Roberto Scolaro --- .../falco/app/actions/helpers_inspector.cpp | 16 ++++++++++++---- userspace/falco/app/options.cpp | 7 ++++++- userspace/falco/configuration.cpp | 2 ++ userspace/falco/configuration.h | 2 ++ 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 28df58d221d..5be80abccdc 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -20,6 +20,7 @@ limitations under the License. #include #include +#include #include "helpers.h" @@ -52,6 +53,13 @@ falco::app::run_result falco::app::actions::open_live_inspector( std::shared_ptr inspector, const std::string& source) { + + bool is_driver_mode_from_cmdline = (s.options.nodriver || + s.is_gvisor_enabled() || + s.options.modern_bpf || + getenv(FALCO_BPF_ENV_VARIABLE) != NULL + ); + try { if (source != falco_common::syscall_source) /* Plugin engine */ @@ -71,7 +79,7 @@ falco::app::run_result falco::app::actions::open_live_inspector( } return run_result::fatal("Can't find plugin for event source: " + source); } - else if (s.options.nodriver) /* nodriver engine. */ + else if (s.options.nodriver || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::NODRIVER)) /* nodriver engine. */ { // when opening a capture with no driver, Falco will first check // if a plugin is capable of generating raw events from the libscap @@ -90,18 +98,18 @@ falco::app::run_result falco::app::actions::open_live_inspector( falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with no driver\n"); inspector->open_nodriver(); } - else if(s.is_gvisor_enabled()) /* gvisor engine. */ + else if(s.is_gvisor_enabled() || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::GVISOR)) /* gvisor engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.options.gvisor_config); inspector->open_gvisor(s.options.gvisor_config, s.options.gvisor_root); } - else if(s.options.modern_bpf) /* modern BPF engine. */ + else if(s.options.modern_bpf || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::MODERN_BPF)) /* modern BPF engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs."); inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); } - else if(getenv(FALCO_BPF_ENV_VARIABLE) != NULL) /* BPF engine. */ + else if(getenv(FALCO_BPF_ENV_VARIABLE) != NULL || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::BPF)) /* BPF engine. */ { const char *bpf_probe_path = std::getenv(FALCO_BPF_ENV_VARIABLE); char full_path[PATH_MAX]; diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index 7268b46ad15..70ce72af813 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -22,6 +22,7 @@ limitations under the License. #include #include +#include namespace falco { namespace app { @@ -149,7 +150,11 @@ bool options::parse(int argc, char **argv, std::string &errstr) open_modes += !trace_filename.empty(); open_modes += !gvisor_config.empty(); open_modes += modern_bpf; - open_modes += getenv("FALCO_BPF_PROBE") != NULL; + if(getenv("FALCO_BPF_PROBE") != NULL) + { + falco_logger::log(LOG_WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable will be soon deprecated!\n"); + open_modes += 1; + } open_modes += nodriver; if (open_modes > 1) { diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index eb56ee99c38..1cb33cbd7a2 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -112,6 +112,8 @@ static driver_mode_type get_driver_mode(const std::string& input){ {"kmod",driver_mode_type::KMOD}, {"bpf",driver_mode_type::BPF}, {"modern_bpf",driver_mode_type::MODERN_BPF}, + {"gvisor",driver_mode_type::GVISOR}, + {"nodriver",driver_mode_type::NODRIVER}, {"custom",driver_mode_type::CUSTOM}, }; diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 07b22a4b224..547c54729ab 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -43,6 +43,8 @@ enum class driver_mode_type : uint8_t KMOD, BPF, MODERN_BPF, + GVISOR, + NODRIVER, CUSTOM }; From f72de02ba1c32cb9ca29fa4484a47750c79ce676 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Tue, 14 Nov 2023 11:59:03 +0100 Subject: [PATCH 05/29] chore(userspace,falco.yaml): rename new config key to `driver.kind`. Moreover, renamed driver kinds to use better naming, and move driver's related config keys under `driver.$kind`. Added DEPRECTATION notices on CLI options, and in falco.yaml. DEPRECATED options (both CLI and config ones) will have priority over the new ones, to retain compatibility with existing configs. DEPRECATED options will be dropped in Falco 0.38. Signed-off-by: Federico Di Pierro Co-authored-by: Andrea Terzolo --- falco.yaml | 68 ++++++++++------ .../test_configure_syscall_buffer_num.cpp | 8 +- .../app/actions/test_select_event_sources.cpp | 2 +- .../actions/configure_syscall_buffer_num.cpp | 6 +- .../actions/configure_syscall_buffer_size.cpp | 12 +-- .../falco/app/actions/helpers_inspector.cpp | 34 +++----- .../falco/app/actions/init_inspectors.cpp | 2 +- userspace/falco/app/actions/load_config.cpp | 41 ++++++++-- userspace/falco/app/options.cpp | 44 ++++++---- userspace/falco/app/state.h | 46 ++++++++++- userspace/falco/configuration.cpp | 81 ++++++++++++++----- userspace/falco/configuration.h | 55 ++++++++++--- 12 files changed, 278 insertions(+), 121 deletions(-) diff --git a/falco.yaml b/falco.yaml index 50340135c5a..93eecf29c53 100644 --- a/falco.yaml +++ b/falco.yaml @@ -62,8 +62,8 @@ # syscall_event_timeouts # syscall_event_drops # metrics -# Falco driver selection -# driver_mode +# Falco driver +# driver # Falco performance tuning (advanced) # syscall_buf_size_preset # syscall_drop_failed_exit @@ -96,7 +96,7 @@ # - "HOST_ROOT": Specifies the prefix to the underlying host `/proc` filesystem # when deploying Falco over a container with read-only host mounts instead of # directly on the host. Defaults to "/host". -# - "FALCO_BPF_PROBE": Specify a custom path to the BPF object code file (`bpf` +# - "FALCO_BPF_PROBE": DEPRECATED. Specify a custom path to the BPF object code file (`bpf` # driver). This is not needed for the modern_bpf driver. # - "FALCO_HOSTNAME": Customize the hostname output field logged by Falco by # setting the "FALCO_HOSTNAME" environment variable. @@ -771,11 +771,11 @@ metrics: convert_memory_to_mb: true include_empty_values: false - ############################################### -# Falco driver selection # -############################################### +################ +# Falco driver # +################ -# [Stable] `driver_mode` +# [Stable] `driver` # # --- [Description] # @@ -784,32 +784,45 @@ metrics: # Falco with your system. Choose the appropriate driver mode based on your # system's configuration and requirements. # -# Available driver modes: +# Available driver kinds: # - `kmod`: Kernel Module (Kernel Module) -# - `bpf`: eBPF (Extended Berkeley Packet Filter) -# - `modern_bpf`: Modern eBPF (Modern Extended Berkeley Packet Filter) -# - `nodriver`: No Driver (No driver, just for testing) +# - `ebpf`: eBPF (Extended Berkeley Packet Filter) +# - `modern-ebpf`: Modern eBPF (Modern Extended Berkeley Packet Filter), available only for recent kernels +# - `none`: No Driver (No driver loaded, useful to run `syscall` source plugin or just plugins without loading any driver) # - `gvisor`: gVisor (gVisor sandbox) -# - `custom`: Custom Driver (Specify a custom driver module) - -# Example usage: -# driver_mode: kmod +# - `replay`: Replay a scap file # Select the appropriate driver mode by uncommenting the corresponding line. # Make sure to specify only one driver mode at a time. - -driver_mode: kmod -# driver_mode: bpf -# driver_mode: modern_bpf -# driver_mode: nodriver -# driver_mode: gvisor -# driver_mode: custom +# Moreover, for each driver multiple options might be available and are grouped +# under the `driver.$kind` configuration key. + +driver: + kind: kmod + kmod: + buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset + drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit + ebpf: + probe: /path/to/probe.o + buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset + drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit + modern-ebpf: + cpus_for_each_syscall_buffer: 2 # Overridden by deprecated cpus_for_each_syscall_buffer + buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset + drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit + replay: + scap_file: /path/to/file.scap + gvisor: + config: /path/to/gvisor.yaml + root: /gvisor/root ####################################### # Falco performance tuning (advanced) # ####################################### -# [Stable] `syscall_buf_size_preset` +# [DEPRECATED] `syscall_buf_size_preset` +# +# Deprecated in favor of driver.{kmod,ebpf,modern-ebpf}.buf_size_preset # # --- [Description] # @@ -861,10 +874,11 @@ driver_mode: kmod # if the default size is not suitable for your use case. syscall_buf_size_preset: 4 -# [Experimental] `syscall_drop_failed_exit` +# [DEPRECATED] `syscall_drop_failed_exit` +# Deprecated in favor of driver.{kmod,ebpf,modern-ebpf}.drop_failed_exit # # Enabling this option in Falco allows it to drop failed system call exit events -# in the kernel driver before pushing them onto the ring buffer. This +# in the kernel drivers before pushing them onto the ring buffer. This # optimization can result in lower CPU usage and more efficient utilization of # the ring buffer, potentially reducing the number of event losses. However, it # is important to note that enabling this option also means sacrificing some @@ -986,7 +1000,9 @@ base_syscalls: custom_set: [] repair: false -# [Stable] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only +# [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only +# +# Deprecated in favor of driver.modern-ebpf.cpus_for_each_syscall_buffer # # --- [Description] # diff --git a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp index 5f15e6d31a8..be70373212e 100644 --- a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp +++ b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp @@ -39,9 +39,9 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) { falco::app::state s; s.options.modern_bpf = true; - s.config->m_cpus_for_each_syscall_buffer = online_cpus + 1; + s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus + 1; EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus); + EXPECT_EQ(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, online_cpus); } // modern bpf engine, with an valid number of CPUs @@ -49,8 +49,8 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) { falco::app::state s; s.options.modern_bpf = true; - s.config->m_cpus_for_each_syscall_buffer = online_cpus - 1; + s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus - 1; EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, online_cpus - 1); + EXPECT_EQ(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, online_cpus - 1); } } diff --git a/unit_tests/falco/app/actions/test_select_event_sources.cpp b/unit_tests/falco/app/actions/test_select_event_sources.cpp index 8ae4b58eda1..d4cccdfadab 100644 --- a/unit_tests/falco/app/actions/test_select_event_sources.cpp +++ b/unit_tests/falco/app/actions/test_select_event_sources.cpp @@ -30,7 +30,7 @@ TEST(ActionSelectEventSources, pre_post_conditions) // ignore source selection in capture mode { falco::app::state s; - s.options.trace_filename = "some_capture_file.scap"; + s.config->m_driver_mode = driver_mode_type::REPLAY; EXPECT_TRUE(s.is_capture_mode()); EXPECT_ACTION_OK(action(s)); } diff --git a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp index 6bc896e443f..d618cb0760b 100644 --- a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp +++ b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp @@ -34,10 +34,10 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco:: return run_result::fatal("cannot get the number of online CPUs from the system\n"); } - if(s.config->m_cpus_for_each_syscall_buffer > online_cpus) + if(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer > online_cpus) { - falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); - s.config->m_cpus_for_each_syscall_buffer = online_cpus; + falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); + s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus; } #endif return run_result::ok(); diff --git a/userspace/falco/app/actions/configure_syscall_buffer_size.cpp b/userspace/falco/app/actions/configure_syscall_buffer_size.cpp index 7af78380101..7e6c2a82c9d 100644 --- a/userspace/falco/app/actions/configure_syscall_buffer_size.cpp +++ b/userspace/falco/app/actions/configure_syscall_buffer_size.cpp @@ -28,18 +28,12 @@ using namespace falco::app::actions; falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco::app::state& s) { #ifdef __linux__ - /* We don't need to compute the syscall buffer dimension if we are in capture mode or if the - * the syscall source is not enabled. - */ - if(s.is_capture_mode() - || !s.is_source_enabled(falco_common::syscall_source) - || s.is_gvisor_enabled() - || s.options.nodriver) + auto index = s.driver_buf_size_preset(); + if (index == -1) { + // Chosen driver kind does not support this option. return run_result::ok(); } - - uint16_t index = s.config->m_syscall_buf_size_preset; if(index < MIN_INDEX || index > MAX_INDEX) { return run_result::fatal("The 'syscall_buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n"); diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 5be80abccdc..9c084f1a3ec 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -28,9 +28,6 @@ limitations under the License. #define PATH_MAX 260 #endif -/* DEPRECATED: we will remove it in Falco 0.34. */ -#define FALCO_BPF_ENV_VARIABLE "FALCO_BPF_PROBE" - using namespace falco::app; using namespace falco::app::actions; @@ -38,13 +35,13 @@ falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::s { try { - s.offline_inspector->open_savefile(s.options.trace_filename); - falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.options.trace_filename + "\n"); + s.offline_inspector->open_savefile(s.config->m_replay.m_scap_file); + falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.config->m_replay.m_scap_file + "\n"); return run_result::ok(); } catch (sinsp_exception &e) { - return run_result::fatal("Could not open trace filename " + s.options.trace_filename + " for reading: " + e.what()); + return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_scap_file + " for reading: " + e.what()); } } @@ -53,13 +50,6 @@ falco::app::run_result falco::app::actions::open_live_inspector( std::shared_ptr inspector, const std::string& source) { - - bool is_driver_mode_from_cmdline = (s.options.nodriver || - s.is_gvisor_enabled() || - s.options.modern_bpf || - getenv(FALCO_BPF_ENV_VARIABLE) != NULL - ); - try { if (source != falco_common::syscall_source) /* Plugin engine */ @@ -79,7 +69,7 @@ falco::app::run_result falco::app::actions::open_live_inspector( } return run_result::fatal("Can't find plugin for event source: " + source); } - else if (s.options.nodriver || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::NODRIVER)) /* nodriver engine. */ + else if (s.config->m_driver_mode == driver_mode_type::NONE) /* nodriver engine. */ { // when opening a capture with no driver, Falco will first check // if a plugin is capable of generating raw events from the libscap @@ -98,20 +88,20 @@ falco::app::run_result falco::app::actions::open_live_inspector( falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with no driver\n"); inspector->open_nodriver(); } - else if(s.is_gvisor_enabled() || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::GVISOR)) /* gvisor engine. */ + else if(s.is_gvisor_enabled()) /* gvisor engine. */ { - falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.options.gvisor_config); - inspector->open_gvisor(s.options.gvisor_config, s.options.gvisor_root); + falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.config->m_gvisor.m_config); + inspector->open_gvisor(s.config->m_gvisor.m_config, s.config->m_gvisor.m_root); } - else if(s.options.modern_bpf || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::MODERN_BPF)) /* modern BPF engine. */ + else if(s.config->m_driver_mode == driver_mode_type::MODERN_EBPF) /* modern BPF engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); - falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_cpus_for_each_syscall_buffer) + "' CPUs."); - inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); + falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer) + "' CPUs."); + inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); } - else if(getenv(FALCO_BPF_ENV_VARIABLE) != NULL || (!is_driver_mode_from_cmdline && s.config->m_driver_mode == driver_mode_type::BPF)) /* BPF engine. */ + else if(s.config->m_driver_mode == driver_mode_type::EBPF) /* BPF engine. */ { - const char *bpf_probe_path = std::getenv(FALCO_BPF_ENV_VARIABLE); + const char *bpf_probe_path = s.config->m_bpf.m_probe_path.c_str(); char full_path[PATH_MAX]; /* If the path is empty try to load the probe from the default path. */ if(strncmp(bpf_probe_path, "", 1) == 0) diff --git a/userspace/falco/app/actions/init_inspectors.cpp b/userspace/falco/app/actions/init_inspectors.cpp index 79a9685ad68..110c0db7a0e 100644 --- a/userspace/falco/app/actions/init_inspectors.cpp +++ b/userspace/falco/app/actions/init_inspectors.cpp @@ -49,7 +49,7 @@ static void init_syscall_inspector(falco::app::state& s, std::shared_ptr inspector->set_snaplen(s.options.snaplen); } - if (s.config->m_syscall_drop_failed_exit) + if (s.is_driver_drop_failed_exit_enabled()) { falco_logger::log(falco_logger::level::INFO, "Failed syscall exit events are dropped in the kernel driver\n"); inspector->set_dropfailed(true); diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 30b60ff562d..296d250dff6 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -18,15 +18,42 @@ limitations under the License. #include "actions.h" #include "falco_utils.h" +/* DEPRECATED: we will remove it in Falco 0.38. */ +#define FALCO_BPF_ENV_VARIABLE "FALCO_BPF_PROBE" + using namespace falco::app; using namespace falco::app::actions; -// applies legacy/in-deprecation options to the current config -static void apply_deprecated_options( - const falco::app::options& opts, - const std::shared_ptr& cfg) +// applies legacy/in-deprecation options to the current state +static falco::app::run_result apply_deprecated_options(falco::app::state& s) { - // Keep for future use cases. + // If overridden from CLI options (soon to be removed), + // use the requested driver. + if (getenv(FALCO_BPF_ENV_VARIABLE)) + { + s.config->m_driver_mode = driver_mode_type::EBPF; + s.config->m_bpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE); + } + else if (s.options.modern_bpf) + { + s.config->m_driver_mode = driver_mode_type::MODERN_EBPF; + } + if (!s.options.gvisor_config.empty()) + { + s.config->m_driver_mode = driver_mode_type::GVISOR; + s.config->m_gvisor.m_config = s.options.gvisor_config; + s.config->m_gvisor.m_root = s.options.gvisor_root; + } + if (s.options.nodriver) + { + s.config->m_driver_mode = driver_mode_type::NONE; + } + if (!s.options.trace_filename.empty()) + { + s.config->m_driver_mode = driver_mode_type::REPLAY; + s.config->m_replay.m_scap_file = s.options.trace_filename; + } + return run_result::ok(); } falco::app::run_result falco::app::actions::load_config(falco::app::state& s) @@ -61,9 +88,7 @@ falco::app::run_result falco::app::actions::load_config(falco::app::state& s) s.config->m_buffered_outputs = !s.options.unbuffered_outputs; - apply_deprecated_options(s.options, s.config); - - return run_result::ok(); + return apply_deprecated_options(s); } falco::app::run_result falco::app::actions::require_config_file(falco::app::state& s) diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index 70ce72af813..e6d07c4ffc3 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -22,7 +22,6 @@ limitations under the License. #include #include -#include namespace falco { namespace app { @@ -138,24 +137,41 @@ bool options::parse(int argc, char **argv, std::string &errstr) // You can't both disable and enable rules if((disabled_rule_substrings.size() + disabled_rule_tags.size() > 0) && - enabled_rule_tags.size() > 0) + !enabled_rule_tags.empty()) { errstr = std::string("You can not specify both disabled (-D/-T) and enabled (-t) rules"); return false; } - list_fields = m_cmdline_parsed.count("list") > 0 ? true : false; + list_fields = m_cmdline_parsed.count("list") > 0; + // TODO: remove for Falco 0.38 since these CLI options are deprecated. int open_modes = 0; - open_modes += !trace_filename.empty(); - open_modes += !gvisor_config.empty(); - open_modes += modern_bpf; + if (!trace_filename.empty()) + { + open_modes++; + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-e' cmdline option is deprecated and will be removed in Falco 0.38!\n"); + } + if (!gvisor_config.empty()) + { + open_modes++; + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-g,--gvisor-config' cmdline option is deprecated and will be removed in Falco 0.38!\n"); + } if(getenv("FALCO_BPF_PROBE") != NULL) { - falco_logger::log(LOG_WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable will be soon deprecated!\n"); - open_modes += 1; + open_modes++; + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable is deprecated and will be removed in Falco 0.38!\n"); + } + if (modern_bpf) + { + open_modes++; + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--modern-bpf' cmdline option is deprecated and will be removed in Falco 0.38!\n"); + } + if (nodriver) + { + open_modes++; + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--nodriver' cmdline option is deprecated and will be removed in Falco 0.38!\n"); } - open_modes += nodriver; if (open_modes > 1) { errstr = std::string("You can not specify more than one of -e, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var"); @@ -188,15 +204,15 @@ void options::define(cxxopts::Options& opts) ("disable-source", "Turn off a specific . By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "") ("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false")) ("D", "Turn off any rules with names having the substring . This option can be passed multiple times. It cannot be mixed with -t.", cxxopts::value(disabled_rule_substrings), "") - ("e", "Reproduce the events by reading from the given instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(trace_filename), "") + ("e", "DEPRECATED. Reproduce the events by reading from the given instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(trace_filename), "") ("enable-source", "Enable a specific . By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. When using this option, only the event sources specified by it will be enabled. This option can not be mixed with --disable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(enable_sources), "") #ifdef HAS_GVISOR - ("g,gvisor-config", "Collect 'syscall' events from gVisor using the specified file. A Falco-compatible configuration file can be generated with --gvisor-generate-config and utilized for both runsc and Falco.", cxxopts::value(gvisor_config), "") + ("g,gvisor-config", "DEPRECATED. Collect 'syscall' events from gVisor using the specified file. A Falco-compatible configuration file can be generated with --gvisor-generate-config and utilized for both runsc and Falco.", cxxopts::value(gvisor_config), "") ("gvisor-generate-config", "Generate a configuration file that can be used for gVisor and exit. See --gvisor-config for more details.", cxxopts::value(gvisor_generate_config_with_socket)->implicit_value("/run/falco/gvisor.sock"), "") - ("gvisor-root", "Set gVisor root directory for storage of container state when used in conjunction with --gvisor-config. The to be passed is the one usually passed to runsc --root flag.", cxxopts::value(gvisor_root), "") + ("gvisor-root", "DEPRECATED. Set gVisor root directory for storage of container state when used in conjunction with --gvisor-config. The to be passed is the one usually passed to runsc --root flag.", cxxopts::value(gvisor_root), "") #endif #ifdef HAS_MODERN_BPF - ("modern-bpf", "Use the BPF modern probe driver to instrument the kernel and observe 'syscall' events.", cxxopts::value(modern_bpf)->default_value("false")) + ("modern-bpf", "DEPRECATED. Use the BPF modern probe driver to instrument the kernel and observe 'syscall' events.", cxxopts::value(modern_bpf)->default_value("false")) #endif ("i", "Print those events that are ignored by default for performance reasons and exit. See -A for more details.", cxxopts::value(print_ignored_events)->default_value("false")) ("L", "Show the name and description of all rules and exit. If json_output is set to true, it prints details about all rules, macros, and lists in JSON format.", cxxopts::value(describe_all_rules)->default_value("false")) @@ -207,7 +223,7 @@ void options::define(cxxopts::Options& opts) ("M", "Stop Falco execution after are passed.", cxxopts::value(duration_to_tot)->default_value("0"), "") ("markdown", "Print output in Markdown format when used in conjunction with --list or --list-events options. It has no effect when used with other options.", cxxopts::value(markdown)) ("N", "Only print field names when used in conjunction with the --list option. It has no effect when used with other options.", cxxopts::value(names_only)->default_value("false")) - ("nodriver", "Do not use a driver to instrument the kernel. If a loaded plugin has event-sourcing capability and can produce system events, it will be used for event collection. Otherwise, no event will be collected.", cxxopts::value(nodriver)->default_value("false")) + ("nodriver", "DEPRECATED. Do not use a driver to instrument the kernel. If a loaded plugin has event-sourcing capability and can produce system events, it will be used for event collection. Otherwise, no event will be collected.", cxxopts::value(nodriver)->default_value("false")) ("o,option", "Set the value of option to . Overrides values in the configuration file. can be identified using its location in the configuration file using dot notation. Elements of list entries can be accessed via square brackets [].\n E.g. base.id = val\n base.subvalue.subvalue2 = val\n base.list[1]=val", cxxopts::value(cmdline_config_options), "=") ("plugin-info", "Print info for the plugin specified by and exit.\nThis includes all descriptive information like name and author, along with the\nschema format for the init configuration and a list of suggested open parameters.\n can be the plugin's name or its configured 'library_path'.", cxxopts::value(print_plugin_info), "") ("p,print", "Print (or replace) additional information in the rule's output.\nUse -pc or -pcontainer to append container details.\nUse -pk or -pkubernetes to add both container and Kubernetes details.\nIf using gVisor, choose -pcg or -pkg variants (or -pcontainer-gvisor and -pkubernetes-gvisor, respectively).\nIf a rule's output contains %container.info, it will be replaced with the corresponding details. Otherwise, these details will be directly appended to the rule's output.\nAlternatively, use -p for a custom format. In this case, the given will be appended to the rule's output without any replacement.", cxxopts::value(print_additional), "") diff --git a/userspace/falco/app/state.h b/userspace/falco/app/state.h index dd74c1fd89e..702c7c693b8 100644 --- a/userspace/falco/app/state.h +++ b/userspace/falco/app/state.h @@ -147,18 +147,60 @@ struct state inline bool is_capture_mode() const { - return !options.trace_filename.empty(); + return config->m_driver_mode == driver_mode_type::REPLAY; } inline bool is_gvisor_enabled() const { - return !options.gvisor_config.empty(); + return config->m_driver_mode == driver_mode_type::GVISOR; } inline bool is_source_enabled(const std::string& src) const { return enabled_sources.find(falco_common::syscall_source) != enabled_sources.end(); } + + inline bool is_driver_drop_failed_exit_enabled() const + { + bool drop_failed; + switch (config->m_driver_mode) + { + case driver_mode_type::KMOD: + drop_failed = config->m_kmod.m_drop_failed_exit; + break; + case driver_mode_type::EBPF: + drop_failed = config->m_bpf.m_drop_failed_exit; + break; + case driver_mode_type::MODERN_EBPF: + drop_failed = config->m_modern_bpf.m_drop_failed_exit; + break; + default: + drop_failed = false; + break; + } + return drop_failed; + } + + inline int16_t driver_buf_size_preset() const + { + int16_t index; + switch (config->m_driver_mode) { + case driver_mode_type::KMOD: + index = config->m_kmod.m_buf_size_preset; + break; + case driver_mode_type::EBPF: + index = config->m_bpf.m_buf_size_preset; + break; + case driver_mode_type::MODERN_EBPF: + index = config->m_modern_bpf.m_buf_size_preset; + break; + default: + // unsupported + index = - 1; + break; + } + return index; + } }; }; // namespace app diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 1cb33cbd7a2..774acc716e6 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -64,9 +64,6 @@ falco_configuration::falco_configuration(): m_syscall_evt_drop_max_burst(1), m_syscall_evt_simulate_drops(false), m_syscall_evt_timeout_max_consecutives(1000), - m_syscall_buf_size_preset(4), - m_cpus_for_each_syscall_buffer(2), - m_syscall_drop_failed_exit(false), m_base_syscalls_repair(false), m_metrics_enabled(false), m_metrics_interval_str("5000"), @@ -106,27 +103,72 @@ void falco_configuration::init(const std::string& conf_filename, const std::vect load_yaml(conf_filename, config); } -static driver_mode_type get_driver_mode(const std::string& input){ +void falco_configuration::load_driver_config(const std::string& config_name, const yaml_helper& config) +{ // Set driver mode if not already set. const std::unordered_map driver_mode_lut = { {"kmod",driver_mode_type::KMOD}, - {"bpf",driver_mode_type::BPF}, - {"modern_bpf",driver_mode_type::MODERN_BPF}, + {"ebpf",driver_mode_type::EBPF}, + {"modern-ebpf",driver_mode_type::MODERN_EBPF}, + {"replay",driver_mode_type::REPLAY}, {"gvisor",driver_mode_type::GVISOR}, - {"nodriver",driver_mode_type::NODRIVER}, - {"custom",driver_mode_type::CUSTOM}, + {"none",driver_mode_type::NONE}, }; - if(driver_mode_lut.find(input) != driver_mode_lut.end()) { - return driver_mode_lut.at(input); - } else { - return driver_mode_type::KMOD; + auto driver_mode_str = config.get_scalar("driver.kind", "kmod"); + if (driver_mode_lut.find(driver_mode_str) != driver_mode_lut.end()) + { + m_driver_mode = driver_mode_lut.at(driver_mode_str); + } + else + { + throw std::logic_error("Error reading config file (" + config_name + "): wrong driver.kind specified."); + } + + switch (m_driver_mode) + { + case driver_mode_type::KMOD: + m_kmod.m_buf_size_preset = config.get_scalar("driver.kmod.buf_size_preset", 4); + m_kmod.m_drop_failed_exit = config.get_scalar("driver.kmod.drop_failed", false); + break; + case driver_mode_type::EBPF: + // TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH, + // to be done once we drop the CLI option otherwise we would need to make the check twice, + // once here, and once when we merge the CLI options in the config file. + m_bpf.m_probe_path = config.get_scalar("driver.ebpf.probe", ""); + m_bpf.m_buf_size_preset = config.get_scalar("driver.ebpf.buf_size_preset", 4); + m_bpf.m_drop_failed_exit = config.get_scalar("driver.ebpf.drop_failed", false); + break; + case driver_mode_type::MODERN_EBPF: + m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar("driver.modern-ebpf.cpus_for_each_syscall_buffer", 2); + m_modern_bpf.m_buf_size_preset = config.get_scalar("driver.modern-ebpf.buf_size_preset", 4); + m_modern_bpf.m_drop_failed_exit = config.get_scalar("driver.modern-ebpf.drop_failed", false); + break; + case driver_mode_type::REPLAY: + m_replay.m_scap_file = config.get_scalar("driver.replay.scap_file", ""); + if (m_replay.m_scap_file.empty()) + { + throw std::logic_error("Error reading config file (" + config_name + "): driver.kind is 'replay' but no driver.replay.scap_file specified."); + } + break; + case driver_mode_type::GVISOR: + m_gvisor.m_config = config.get_scalar("driver.gvisor.config", ""); + if (m_gvisor.m_config.empty()) + { + throw std::logic_error("Error reading config file (" + config_name + "): driver.kind is 'gvisor' but no driver.gvisor.config specified."); + } + m_gvisor.m_root = config.get_scalar("driver.gvisor.root", ""); + break; + case driver_mode_type::NONE: + default: + break; } } void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) { - m_driver_mode = get_driver_mode(config.get_scalar("driver_mode", "")); + load_driver_config(config_name, config); + m_log_level = config.get_scalar("log_level", "info"); std::list rules_files; @@ -385,11 +427,14 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h /* We put this value in the configuration file because in this way we can change the dimension at every reload. * The default value is `4` -> 8 MB. */ - m_syscall_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); - - m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", 2); - - m_syscall_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); + // TODO: remove in Falco 0.38 since they are deprecated. + m_kmod.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); + m_bpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); + m_modern_bpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); + m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", 2); + m_kmod.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); + m_bpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); + m_modern_bpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); m_base_syscalls_custom_set.clear(); config.get_sequence>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set")); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 547c54729ab..63531d2d29f 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -39,13 +39,12 @@ limitations under the License. enum class driver_mode_type : uint8_t { - INVALID = 0, KMOD, - BPF, - MODERN_BPF, + EBPF, + MODERN_EBPF, + REPLAY, GVISOR, - NODRIVER, - CUSTOM + NONE }; class falco_configuration @@ -60,6 +59,37 @@ class falco_configuration std::string m_open_params; } plugin_config; + typedef struct { + public: + int16_t m_buf_size_preset; + bool m_drop_failed_exit; + } kmod_config; + + typedef struct { + public: + std::string m_probe_path; + int16_t m_buf_size_preset; + bool m_drop_failed_exit; + } bpf_config; + + typedef struct { + public: + uint16_t m_cpus_for_each_syscall_buffer; + int16_t m_buf_size_preset; + bool m_drop_failed_exit; + } modern_bpf_config; + + typedef struct { + public: + std::string m_scap_file; + } replay_config; + + typedef struct { + public: + std::string m_config; + std::string m_root; + } gvisor_config; + falco_configuration(); virtual ~falco_configuration() = default; @@ -114,14 +144,6 @@ class falco_configuration uint32_t m_syscall_evt_timeout_max_consecutives; - // Index corresponding to the syscall buffer dimension. - uint16_t m_syscall_buf_size_preset; - - // Number of CPUs associated with a single ring buffer. - uint16_t m_cpus_for_each_syscall_buffer; - - bool m_syscall_drop_failed_exit; - // User supplied base_syscalls, overrides any Falco state engine enforcement. std::unordered_set m_base_syscalls_custom_set; bool m_base_syscalls_repair; @@ -138,11 +160,18 @@ class falco_configuration bool m_metrics_convert_memory_to_mb; bool m_metrics_include_empty_values; + kmod_config m_kmod; + bpf_config m_bpf; + modern_bpf_config m_modern_bpf; + replay_config m_replay; + gvisor_config m_gvisor; std::vector m_plugins; private: void load_yaml(const std::string& config_name, const yaml_helper& config); + void load_driver_config(const std::string& config_name, const yaml_helper& config); + void init_cmdline_options(yaml_helper& config, const std::vector& cmdline_options); /** From 49b8d7a110c2173d50b17d4f9df02e433daa44b9 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Fri, 17 Nov 2023 09:41:22 +0100 Subject: [PATCH 06/29] chore(userspace): renamed `driver.` config to `engine.`; renamed `engine.replay.scap_file` to `engine.replay.trace_file`. Signed-off-by: Federico Di Pierro --- falco.yaml | 32 ++++----- .../app/actions/test_select_event_sources.cpp | 2 +- .../falco/app/actions/helpers_inspector.cpp | 12 ++-- userspace/falco/app/actions/load_config.cpp | 12 ++-- userspace/falco/app/state.h | 20 +++--- userspace/falco/configuration.cpp | 70 +++++++++---------- userspace/falco/configuration.h | 8 +-- 7 files changed, 77 insertions(+), 79 deletions(-) diff --git a/falco.yaml b/falco.yaml index 93eecf29c53..645d1801453 100644 --- a/falco.yaml +++ b/falco.yaml @@ -775,29 +775,27 @@ metrics: # Falco driver # ################ -# [Stable] `driver` +# [Stable] `engine` # # --- [Description] # -# Falco supports different driver modes for capturing syscall events. The choice -# of driver mode can significantly impact the performance and compatibility of -# Falco with your system. Choose the appropriate driver mode based on your -# system's configuration and requirements. +# Falco supports different engines to generate events. +# Choose the appropriate engine kind based on your system's configuration and requirements. # -# Available driver kinds: +# Available engines: # - `kmod`: Kernel Module (Kernel Module) # - `ebpf`: eBPF (Extended Berkeley Packet Filter) # - `modern-ebpf`: Modern eBPF (Modern Extended Berkeley Packet Filter), available only for recent kernels -# - `none`: No Driver (No driver loaded, useful to run `syscall` source plugin or just plugins without loading any driver) # - `gvisor`: gVisor (gVisor sandbox) -# - `replay`: Replay a scap file +# - `replay`: Replay a scap trace file +# - `none`: No engine loaded, useful to run `syscall` source plugin or just plugins without loading any other event producer. -# Select the appropriate driver mode by uncommenting the corresponding line. -# Make sure to specify only one driver mode at a time. -# Moreover, for each driver multiple options might be available and are grouped -# under the `driver.$kind` configuration key. +# Select the appropriate engine kind by uncommenting the corresponding line. +# Make sure to specify only one engine kind at a time. +# Moreover, for each engine multiple options might be available, +# grouped under the `engine.$kind` configuration key. -driver: +engine: kind: kmod kmod: buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset @@ -811,7 +809,7 @@ driver: buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit replay: - scap_file: /path/to/file.scap + trace_file: /path/to/file.scap gvisor: config: /path/to/gvisor.yaml root: /gvisor/root @@ -822,7 +820,7 @@ driver: # [DEPRECATED] `syscall_buf_size_preset` # -# Deprecated in favor of driver.{kmod,ebpf,modern-ebpf}.buf_size_preset +# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.buf_size_preset # # --- [Description] # @@ -875,7 +873,7 @@ driver: syscall_buf_size_preset: 4 # [DEPRECATED] `syscall_drop_failed_exit` -# Deprecated in favor of driver.{kmod,ebpf,modern-ebpf}.drop_failed_exit +# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.drop_failed_exit # # Enabling this option in Falco allows it to drop failed system call exit events # in the kernel drivers before pushing them onto the ring buffer. This @@ -1002,7 +1000,7 @@ base_syscalls: # [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only # -# Deprecated in favor of driver.modern-ebpf.cpus_for_each_syscall_buffer +# Deprecated in favor of engine.modern-ebpf.cpus_for_each_syscall_buffer # # --- [Description] # diff --git a/unit_tests/falco/app/actions/test_select_event_sources.cpp b/unit_tests/falco/app/actions/test_select_event_sources.cpp index d4cccdfadab..74fe73a257a 100644 --- a/unit_tests/falco/app/actions/test_select_event_sources.cpp +++ b/unit_tests/falco/app/actions/test_select_event_sources.cpp @@ -30,7 +30,7 @@ TEST(ActionSelectEventSources, pre_post_conditions) // ignore source selection in capture mode { falco::app::state s; - s.config->m_driver_mode = driver_mode_type::REPLAY; + s.config->m_engine_mode = engine_kind_t::REPLAY; EXPECT_TRUE(s.is_capture_mode()); EXPECT_ACTION_OK(action(s)); } diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 9c084f1a3ec..e065e7a85b7 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -35,13 +35,13 @@ falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::s { try { - s.offline_inspector->open_savefile(s.config->m_replay.m_scap_file); - falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.config->m_replay.m_scap_file + "\n"); + s.offline_inspector->open_savefile(s.config->m_replay.m_trace_file); + falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.config->m_replay.m_trace_file + "\n"); return run_result::ok(); } catch (sinsp_exception &e) { - return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_scap_file + " for reading: " + e.what()); + return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_trace_file + " for reading: " + e.what()); } } @@ -69,7 +69,7 @@ falco::app::run_result falco::app::actions::open_live_inspector( } return run_result::fatal("Can't find plugin for event source: " + source); } - else if (s.config->m_driver_mode == driver_mode_type::NONE) /* nodriver engine. */ + else if (s.config->m_engine_mode == engine_kind_t::NONE) /* nodriver engine. */ { // when opening a capture with no driver, Falco will first check // if a plugin is capable of generating raw events from the libscap @@ -93,13 +93,13 @@ falco::app::run_result falco::app::actions::open_live_inspector( falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.config->m_gvisor.m_config); inspector->open_gvisor(s.config->m_gvisor.m_config, s.config->m_gvisor.m_root); } - else if(s.config->m_driver_mode == driver_mode_type::MODERN_EBPF) /* modern BPF engine. */ + else if(s.config->m_engine_mode == engine_kind_t::MODERN_EBPF) /* modern BPF engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer) + "' CPUs."); inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); } - else if(s.config->m_driver_mode == driver_mode_type::EBPF) /* BPF engine. */ + else if(s.config->m_engine_mode == engine_kind_t::EBPF) /* BPF engine. */ { const char *bpf_probe_path = s.config->m_bpf.m_probe_path.c_str(); char full_path[PATH_MAX]; diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 296d250dff6..e626645afb0 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -31,27 +31,27 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) // use the requested driver. if (getenv(FALCO_BPF_ENV_VARIABLE)) { - s.config->m_driver_mode = driver_mode_type::EBPF; + s.config->m_engine_mode = engine_kind_t::EBPF; s.config->m_bpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE); } else if (s.options.modern_bpf) { - s.config->m_driver_mode = driver_mode_type::MODERN_EBPF; + s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; } if (!s.options.gvisor_config.empty()) { - s.config->m_driver_mode = driver_mode_type::GVISOR; + s.config->m_engine_mode = engine_kind_t::GVISOR; s.config->m_gvisor.m_config = s.options.gvisor_config; s.config->m_gvisor.m_root = s.options.gvisor_root; } if (s.options.nodriver) { - s.config->m_driver_mode = driver_mode_type::NONE; + s.config->m_engine_mode = engine_kind_t::NONE; } if (!s.options.trace_filename.empty()) { - s.config->m_driver_mode = driver_mode_type::REPLAY; - s.config->m_replay.m_scap_file = s.options.trace_filename; + s.config->m_engine_mode = engine_kind_t::REPLAY; + s.config->m_replay.m_trace_file = s.options.trace_filename; } return run_result::ok(); } diff --git a/userspace/falco/app/state.h b/userspace/falco/app/state.h index 702c7c693b8..c260742905f 100644 --- a/userspace/falco/app/state.h +++ b/userspace/falco/app/state.h @@ -147,12 +147,12 @@ struct state inline bool is_capture_mode() const { - return config->m_driver_mode == driver_mode_type::REPLAY; + return config->m_engine_mode == engine_kind_t::REPLAY; } inline bool is_gvisor_enabled() const { - return config->m_driver_mode == driver_mode_type::GVISOR; + return config->m_engine_mode == engine_kind_t::GVISOR; } inline bool is_source_enabled(const std::string& src) const @@ -163,15 +163,15 @@ struct state inline bool is_driver_drop_failed_exit_enabled() const { bool drop_failed; - switch (config->m_driver_mode) + switch (config->m_engine_mode) { - case driver_mode_type::KMOD: + case engine_kind_t::KMOD: drop_failed = config->m_kmod.m_drop_failed_exit; break; - case driver_mode_type::EBPF: + case engine_kind_t::EBPF: drop_failed = config->m_bpf.m_drop_failed_exit; break; - case driver_mode_type::MODERN_EBPF: + case engine_kind_t::MODERN_EBPF: drop_failed = config->m_modern_bpf.m_drop_failed_exit; break; default: @@ -184,14 +184,14 @@ struct state inline int16_t driver_buf_size_preset() const { int16_t index; - switch (config->m_driver_mode) { - case driver_mode_type::KMOD: + switch (config->m_engine_mode) { + case engine_kind_t::KMOD: index = config->m_kmod.m_buf_size_preset; break; - case driver_mode_type::EBPF: + case engine_kind_t::EBPF: index = config->m_bpf.m_buf_size_preset; break; - case driver_mode_type::MODERN_EBPF: + case engine_kind_t::MODERN_EBPF: index = config->m_modern_bpf.m_buf_size_preset; break; default: diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 774acc716e6..3d00c0bda6f 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -41,7 +41,7 @@ namespace fs = std::filesystem; static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))"); falco_configuration::falco_configuration(): - m_driver_mode(driver_mode_type::KMOD), + m_engine_mode(engine_kind_t::KMOD), m_json_output(false), m_json_include_output_property(true), m_json_include_tags_property(true), @@ -103,63 +103,63 @@ void falco_configuration::init(const std::string& conf_filename, const std::vect load_yaml(conf_filename, config); } -void falco_configuration::load_driver_config(const std::string& config_name, const yaml_helper& config) +void falco_configuration::load_engine_config(const std::string& config_name, const yaml_helper& config) { // Set driver mode if not already set. - const std::unordered_map driver_mode_lut = { - {"kmod",driver_mode_type::KMOD}, - {"ebpf",driver_mode_type::EBPF}, - {"modern-ebpf",driver_mode_type::MODERN_EBPF}, - {"replay",driver_mode_type::REPLAY}, - {"gvisor",driver_mode_type::GVISOR}, - {"none",driver_mode_type::NONE}, + const std::unordered_map engine_mode_lut = { + {"kmod",engine_kind_t::KMOD}, + {"ebpf",engine_kind_t::EBPF}, + {"modern-ebpf",engine_kind_t::MODERN_EBPF}, + {"replay",engine_kind_t::REPLAY}, + {"gvisor",engine_kind_t::GVISOR}, + {"none",engine_kind_t::NONE}, }; - auto driver_mode_str = config.get_scalar("driver.kind", "kmod"); - if (driver_mode_lut.find(driver_mode_str) != driver_mode_lut.end()) + auto driver_mode_str = config.get_scalar("engine.kind", "kmod"); + if (engine_mode_lut.find(driver_mode_str) != engine_mode_lut.end()) { - m_driver_mode = driver_mode_lut.at(driver_mode_str); + m_engine_mode = engine_mode_lut.at(driver_mode_str); } else { - throw std::logic_error("Error reading config file (" + config_name + "): wrong driver.kind specified."); + throw std::logic_error("Error reading config file (" + config_name + "): wrong engine.kind specified."); } - switch (m_driver_mode) + switch (m_engine_mode) { - case driver_mode_type::KMOD: - m_kmod.m_buf_size_preset = config.get_scalar("driver.kmod.buf_size_preset", 4); - m_kmod.m_drop_failed_exit = config.get_scalar("driver.kmod.drop_failed", false); + case engine_kind_t::KMOD: + m_kmod.m_buf_size_preset = config.get_scalar("engine.kmod.buf_size_preset", 4); + m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed", false); break; - case driver_mode_type::EBPF: + case engine_kind_t::EBPF: // TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH, // to be done once we drop the CLI option otherwise we would need to make the check twice, // once here, and once when we merge the CLI options in the config file. - m_bpf.m_probe_path = config.get_scalar("driver.ebpf.probe", ""); - m_bpf.m_buf_size_preset = config.get_scalar("driver.ebpf.buf_size_preset", 4); - m_bpf.m_drop_failed_exit = config.get_scalar("driver.ebpf.drop_failed", false); + m_bpf.m_probe_path = config.get_scalar("engine.ebpf.probe", ""); + m_bpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", 4); + m_bpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed", false); break; - case driver_mode_type::MODERN_EBPF: - m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar("driver.modern-ebpf.cpus_for_each_syscall_buffer", 2); - m_modern_bpf.m_buf_size_preset = config.get_scalar("driver.modern-ebpf.buf_size_preset", 4); - m_modern_bpf.m_drop_failed_exit = config.get_scalar("driver.modern-ebpf.drop_failed", false); + case engine_kind_t::MODERN_EBPF: + m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_syscall_buffer", 2); + m_modern_bpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", 4); + m_modern_bpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed", false); break; - case driver_mode_type::REPLAY: - m_replay.m_scap_file = config.get_scalar("driver.replay.scap_file", ""); - if (m_replay.m_scap_file.empty()) + case engine_kind_t::REPLAY: + m_replay.m_trace_file = config.get_scalar("engine.replay.trace_file", ""); + if (m_replay.m_trace_file.empty()) { - throw std::logic_error("Error reading config file (" + config_name + "): driver.kind is 'replay' but no driver.replay.scap_file specified."); + throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'replay' but no engine.replay.trace_file specified."); } break; - case driver_mode_type::GVISOR: - m_gvisor.m_config = config.get_scalar("driver.gvisor.config", ""); + case engine_kind_t::GVISOR: + m_gvisor.m_config = config.get_scalar("engine.gvisor.config", ""); if (m_gvisor.m_config.empty()) { - throw std::logic_error("Error reading config file (" + config_name + "): driver.kind is 'gvisor' but no driver.gvisor.config specified."); + throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'gvisor' but no engine.gvisor.config specified."); } - m_gvisor.m_root = config.get_scalar("driver.gvisor.root", ""); + m_gvisor.m_root = config.get_scalar("engine.gvisor.root", ""); break; - case driver_mode_type::NONE: + case engine_kind_t::NONE: default: break; } @@ -167,7 +167,7 @@ void falco_configuration::load_driver_config(const std::string& config_name, con void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) { - load_driver_config(config_name, config); + load_engine_config(config_name, config); m_log_level = config.get_scalar("log_level", "info"); std::list rules_files; diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 63531d2d29f..19d6652e088 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -37,7 +37,7 @@ limitations under the License. #include "event_drops.h" #include "falco_outputs.h" -enum class driver_mode_type : uint8_t +enum class engine_kind_t : uint8_t { KMOD, EBPF, @@ -81,7 +81,7 @@ class falco_configuration typedef struct { public: - std::string m_scap_file; + std::string m_trace_file; } replay_config; typedef struct { @@ -104,7 +104,7 @@ class falco_configuration std::list m_loaded_rules_filenames; // List of loaded rule folders std::list m_loaded_rules_folders; - driver_mode_type m_driver_mode; + engine_kind_t m_engine_mode; bool m_json_output; bool m_json_include_output_property; bool m_json_include_tags_property; @@ -170,7 +170,7 @@ class falco_configuration private: void load_yaml(const std::string& config_name, const yaml_helper& config); - void load_driver_config(const std::string& config_name, const yaml_helper& config); + void load_engine_config(const std::string& config_name, const yaml_helper& config); void init_cmdline_options(yaml_helper& config, const std::vector& cmdline_options); From ffcbe37953ff682eaef7c99bb75c5d33fe853c54 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 17 Nov 2023 11:47:15 +0100 Subject: [PATCH 07/29] cleanup: some renaming from `bpf` to `ebpf` the idea is to use only the word `ebpf` in Falco Signed-off-by: Andrea Terzolo --- falco.yaml | 8 +++---- .../test_configure_syscall_buffer_num.cpp | 14 ++++++------ .../actions/configure_syscall_buffer_num.cpp | 6 ++--- .../falco/app/actions/helpers_inspector.cpp | 6 ++--- userspace/falco/app/actions/load_config.cpp | 2 +- userspace/falco/app/state.h | 8 +++---- userspace/falco/configuration.cpp | 22 +++++++++---------- userspace/falco/configuration.h | 11 +++++----- 8 files changed, 39 insertions(+), 38 deletions(-) diff --git a/falco.yaml b/falco.yaml index 645d1801453..069d1cda229 100644 --- a/falco.yaml +++ b/falco.yaml @@ -62,8 +62,8 @@ # syscall_event_timeouts # syscall_event_drops # metrics -# Falco driver -# driver +# Falco engine +# engine # Falco performance tuning (advanced) # syscall_buf_size_preset # syscall_drop_failed_exit @@ -772,7 +772,7 @@ metrics: include_empty_values: false ################ -# Falco driver # +# Falco engine # ################ # [Stable] `engine` @@ -793,7 +793,7 @@ metrics: # Select the appropriate engine kind by uncommenting the corresponding line. # Make sure to specify only one engine kind at a time. # Moreover, for each engine multiple options might be available, -# grouped under the `engine.$kind` configuration key. +# grouped under the `engine.kind` configuration key. engine: kind: kmod diff --git a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp index be70373212e..13288faf328 100644 --- a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp +++ b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp @@ -27,30 +27,30 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) FAIL() << "cannot get the number of online CPUs from the system\n"; } - // not modern bpf engine, we do nothing + // not modern ebpf engine, we do nothing { falco::app::state s; s.options.modern_bpf = false; EXPECT_ACTION_OK(action(s)); } - // modern bpf engine, with an invalid number of CPUs + // modern ebpf engine, with an invalid number of CPUs // default `m_cpus_for_each_syscall_buffer` to online CPU number { falco::app::state s; s.options.modern_bpf = true; - s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus + 1; + s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus + 1; EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, online_cpus); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, online_cpus); } - // modern bpf engine, with an valid number of CPUs + // modern ebpf engine, with a valid number of CPUs // we don't modify `m_cpus_for_each_syscall_buffer` { falco::app::state s; s.options.modern_bpf = true; - s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus - 1; + s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus - 1; EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, online_cpus - 1); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, online_cpus - 1); } } diff --git a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp index d618cb0760b..6df84d8f860 100644 --- a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp +++ b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp @@ -34,10 +34,10 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco:: return run_result::fatal("cannot get the number of online CPUs from the system\n"); } - if(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer > online_cpus) + if(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer > online_cpus) { - falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); - s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer = online_cpus; + falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); + s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus; } #endif return run_result::ok(); diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index e065e7a85b7..d918e9b4ca3 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -96,12 +96,12 @@ falco::app::run_result falco::app::actions::open_live_inspector( else if(s.config->m_engine_mode == engine_kind_t::MODERN_EBPF) /* modern BPF engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); - falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer) + "' CPUs."); - inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_bpf.m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); + falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer) + "' CPUs."); + inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); } else if(s.config->m_engine_mode == engine_kind_t::EBPF) /* BPF engine. */ { - const char *bpf_probe_path = s.config->m_bpf.m_probe_path.c_str(); + const char *bpf_probe_path = s.config->m_ebpf.m_probe_path.c_str(); char full_path[PATH_MAX]; /* If the path is empty try to load the probe from the default path. */ if(strncmp(bpf_probe_path, "", 1) == 0) diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index e626645afb0..ebfb203f123 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -32,7 +32,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) if (getenv(FALCO_BPF_ENV_VARIABLE)) { s.config->m_engine_mode = engine_kind_t::EBPF; - s.config->m_bpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE); + s.config->m_ebpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE); } else if (s.options.modern_bpf) { diff --git a/userspace/falco/app/state.h b/userspace/falco/app/state.h index c260742905f..226772c8bc4 100644 --- a/userspace/falco/app/state.h +++ b/userspace/falco/app/state.h @@ -169,10 +169,10 @@ struct state drop_failed = config->m_kmod.m_drop_failed_exit; break; case engine_kind_t::EBPF: - drop_failed = config->m_bpf.m_drop_failed_exit; + drop_failed = config->m_ebpf.m_drop_failed_exit; break; case engine_kind_t::MODERN_EBPF: - drop_failed = config->m_modern_bpf.m_drop_failed_exit; + drop_failed = config->m_modern_ebpf.m_drop_failed_exit; break; default: drop_failed = false; @@ -189,10 +189,10 @@ struct state index = config->m_kmod.m_buf_size_preset; break; case engine_kind_t::EBPF: - index = config->m_bpf.m_buf_size_preset; + index = config->m_ebpf.m_buf_size_preset; break; case engine_kind_t::MODERN_EBPF: - index = config->m_modern_bpf.m_buf_size_preset; + index = config->m_modern_ebpf.m_buf_size_preset; break; default: // unsupported diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 3d00c0bda6f..fe3b7dee0ac 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -135,14 +135,14 @@ void falco_configuration::load_engine_config(const std::string& config_name, con // TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH, // to be done once we drop the CLI option otherwise we would need to make the check twice, // once here, and once when we merge the CLI options in the config file. - m_bpf.m_probe_path = config.get_scalar("engine.ebpf.probe", ""); - m_bpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", 4); - m_bpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed", false); + m_ebpf.m_probe_path = config.get_scalar("engine.ebpf.probe", ""); + m_ebpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", 4); + m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed", false); break; case engine_kind_t::MODERN_EBPF: - m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_syscall_buffer", 2); - m_modern_bpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", 4); - m_modern_bpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed", false); + m_modern_ebpf.m_cpus_for_each_syscall_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_syscall_buffer", 2); + m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", 4); + m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed", false); break; case engine_kind_t::REPLAY: m_replay.m_trace_file = config.get_scalar("engine.replay.trace_file", ""); @@ -429,12 +429,12 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h */ // TODO: remove in Falco 0.38 since they are deprecated. m_kmod.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); - m_bpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); - m_modern_bpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); - m_modern_bpf.m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", 2); + m_ebpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); + m_modern_ebpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); + m_modern_ebpf.m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", 2); m_kmod.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); - m_bpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); - m_modern_bpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); + m_ebpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); + m_modern_ebpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); m_base_syscalls_custom_set.clear(); config.get_sequence>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set")); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 19d6652e088..3af44e50f56 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -70,14 +70,14 @@ class falco_configuration std::string m_probe_path; int16_t m_buf_size_preset; bool m_drop_failed_exit; - } bpf_config; + } ebpf_config; typedef struct { public: uint16_t m_cpus_for_each_syscall_buffer; int16_t m_buf_size_preset; bool m_drop_failed_exit; - } modern_bpf_config; + } modern_ebpf_config; typedef struct { public: @@ -104,7 +104,6 @@ class falco_configuration std::list m_loaded_rules_filenames; // List of loaded rule folders std::list m_loaded_rules_folders; - engine_kind_t m_engine_mode; bool m_json_output; bool m_json_include_output_property; bool m_json_include_tags_property; @@ -160,9 +159,11 @@ class falco_configuration bool m_metrics_convert_memory_to_mb; bool m_metrics_include_empty_values; + // Falco engine + engine_kind_t m_engine_mode; kmod_config m_kmod; - bpf_config m_bpf; - modern_bpf_config m_modern_bpf; + ebpf_config m_ebpf; + modern_ebpf_config m_modern_ebpf; replay_config m_replay; gvisor_config m_gvisor; std::vector m_plugins; From 8a8fdca33c99dc2b591f872a3dd33f9350d33fd8 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 17 Nov 2023 13:04:46 +0100 Subject: [PATCH 08/29] fix: use only new config instead of old command line options Signed-off-by: Andrea Terzolo --- .../app/actions/test_configure_syscall_buffer_num.cpp | 6 +++--- .../falco/app/actions/configure_syscall_buffer_num.cpp | 2 +- userspace/falco/app/actions/create_requested_paths.cpp | 8 ++++---- userspace/falco/app/actions/helpers_generic.cpp | 5 ++--- userspace/falco/app/actions/load_config.cpp | 4 ++++ userspace/falco/app/options.cpp | 3 ++- userspace/falco/app/state.h | 10 ++++++++++ userspace/falco/configuration.cpp | 2 +- 8 files changed, 27 insertions(+), 13 deletions(-) diff --git a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp index 13288faf328..ddbea31de12 100644 --- a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp +++ b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp @@ -30,7 +30,7 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) // not modern ebpf engine, we do nothing { falco::app::state s; - s.options.modern_bpf = false; + s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; EXPECT_ACTION_OK(action(s)); } @@ -38,7 +38,7 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) // default `m_cpus_for_each_syscall_buffer` to online CPU number { falco::app::state s; - s.options.modern_bpf = true; + s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus + 1; EXPECT_ACTION_OK(action(s)); EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, online_cpus); @@ -48,7 +48,7 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) // we don't modify `m_cpus_for_each_syscall_buffer` { falco::app::state s; - s.options.modern_bpf = true; + s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus - 1; EXPECT_ACTION_OK(action(s)); EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, online_cpus - 1); diff --git a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp index 6df84d8f860..aed2534c98f 100644 --- a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp +++ b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp @@ -23,7 +23,7 @@ using namespace falco::app::actions; falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco::app::state& s) { #ifdef __linux__ - if(!s.options.modern_bpf) + if(!s.is_modern_ebpf()) { return run_result::ok(); } diff --git a/userspace/falco/app/actions/create_requested_paths.cpp b/userspace/falco/app/actions/create_requested_paths.cpp index eae3815421e..5eba04ac895 100644 --- a/userspace/falco/app/actions/create_requested_paths.cpp +++ b/userspace/falco/app/actions/create_requested_paths.cpp @@ -39,10 +39,10 @@ falco::app::run_result falco::app::actions::create_requested_paths(falco::app::s { // This is bad: parsing gvisor config to get endpoint // to be able to auto-create the path to the file for the user. - std::ifstream reader(s.options.gvisor_config); + std::ifstream reader(s.config->m_gvisor.m_config); if (reader.fail()) { - return run_result::fatal(s.options.gvisor_config + ": cannot open file"); + return run_result::fatal(s.config->m_gvisor.m_config + ": cannot open file"); } nlohmann::json parsed_json; @@ -53,7 +53,7 @@ falco::app::run_result falco::app::actions::create_requested_paths(falco::app::s } catch (const std::exception &e) { - return run_result::fatal(s.options.gvisor_config + ": cannot parse JSON: " + e.what()); + return run_result::fatal(s.config->m_gvisor.m_config + ": cannot parse JSON: " + e.what()); } try @@ -62,7 +62,7 @@ falco::app::run_result falco::app::actions::create_requested_paths(falco::app::s } catch (const std::exception &e) { - return run_result::fatal(s.options.gvisor_config + ": failed to fetch config.endpoint: " + e.what()); + return run_result::fatal(s.config->m_gvisor.m_config + ": failed to fetch config.endpoint: " + e.what()); } int ret = create_dir(gvisor_socket); diff --git a/userspace/falco/app/actions/helpers_generic.cpp b/userspace/falco/app/actions/helpers_generic.cpp index 44e205edf94..2a199158a1a 100644 --- a/userspace/falco/app/actions/helpers_generic.cpp +++ b/userspace/falco/app/actions/helpers_generic.cpp @@ -75,7 +75,7 @@ void falco::app::actions::print_enabled_event_sources(falco::app::state& s) } else { - if (src != falco_common::syscall_source || s.options.nodriver) + if (src != falco_common::syscall_source || s.is_nodriver()) { falco_logger::log(falco_logger::level::WARNING, "Enabled event source '" + src + "' can be opened with multiple loaded plugins, will use only '" @@ -84,7 +84,7 @@ void falco::app::actions::print_enabled_event_sources(falco::app::state& s) } } } - if (!first_plugin && s.options.nodriver) + if (!first_plugin && s.is_nodriver()) { falco_logger::log(falco_logger::level::WARNING, "Enabled event source '" + src + "' will be opened with no driver, no event will be produced"); @@ -126,4 +126,3 @@ void falco::app::actions::format_plugin_info(std::shared_ptr p, st os << " - Async Events" << std::endl; } } - diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index ebfb203f123..fb140e938ac 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -27,6 +27,10 @@ using namespace falco::app::actions; // applies legacy/in-deprecation options to the current state static falco::app::run_result apply_deprecated_options(falco::app::state& s) { + // Please note: is not possible to mix command line options and configs to obtain a configuration + // we need to use only one method. For example, is not possible to set the gvisor-config through + // the command line and the gvisor-root through the config file. + // // If overridden from CLI options (soon to be removed), // use the requested driver. if (getenv(FALCO_BPF_ENV_VARIABLE)) diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index e6d07c4ffc3..32ea07ecfce 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -39,7 +39,8 @@ options::options() markdown(false), modern_bpf(false), dry_run(false), - nodriver(false) + nodriver(false), + trace_filename("") { } diff --git a/userspace/falco/app/state.h b/userspace/falco/app/state.h index 226772c8bc4..ba6caee5961 100644 --- a/userspace/falco/app/state.h +++ b/userspace/falco/app/state.h @@ -155,6 +155,16 @@ struct state return config->m_engine_mode == engine_kind_t::GVISOR; } + inline bool is_modern_ebpf() const + { + return config->m_engine_mode == engine_kind_t::MODERN_EBPF; + } + + inline bool is_nodriver() const + { + return config->m_engine_mode == engine_kind_t::NONE; + } + inline bool is_source_enabled(const std::string& src) const { return enabled_sources.find(falco_common::syscall_source) != enabled_sources.end(); diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index fe3b7dee0ac..750519a71ad 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -122,7 +122,7 @@ void falco_configuration::load_engine_config(const std::string& config_name, con } else { - throw std::logic_error("Error reading config file (" + config_name + "): wrong engine.kind specified."); + throw std::logic_error("Error reading config file (" + config_name + "): engine.kind '"+ driver_mode_str + "' is not a valid kind."); } switch (m_engine_mode) From 9e7f948bd4aae10086822ef927e85a849bd769ec Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 17 Nov 2023 14:44:40 +0100 Subject: [PATCH 09/29] cleanup: move some initializations and add helpers Signed-off-by: Andrea Terzolo --- .../falco/app/actions/create_requested_paths.cpp | 2 +- userspace/falco/app/actions/helpers_inspector.cpp | 8 ++++---- userspace/falco/app/actions/process_events.cpp | 2 +- userspace/falco/app/options.cpp | 6 +----- userspace/falco/app/options.h | 13 ++++++++----- userspace/falco/app/state.h | 9 +++++++-- userspace/falco/configuration.cpp | 1 - userspace/falco/configuration.h | 2 +- 8 files changed, 23 insertions(+), 20 deletions(-) diff --git a/userspace/falco/app/actions/create_requested_paths.cpp b/userspace/falco/app/actions/create_requested_paths.cpp index 5eba04ac895..401e15ed055 100644 --- a/userspace/falco/app/actions/create_requested_paths.cpp +++ b/userspace/falco/app/actions/create_requested_paths.cpp @@ -35,7 +35,7 @@ static int create_dir(const std::string &path); falco::app::run_result falco::app::actions::create_requested_paths(falco::app::state& s) { - if(s.is_gvisor_enabled()) + if(s.is_gvisor()) { // This is bad: parsing gvisor config to get endpoint // to be able to auto-create the path to the file for the user. diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index d918e9b4ca3..92e5f34b271 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -69,7 +69,7 @@ falco::app::run_result falco::app::actions::open_live_inspector( } return run_result::fatal("Can't find plugin for event source: " + source); } - else if (s.config->m_engine_mode == engine_kind_t::NONE) /* nodriver engine. */ + else if (s.is_nodriver()) /* nodriver engine. */ { // when opening a capture with no driver, Falco will first check // if a plugin is capable of generating raw events from the libscap @@ -88,18 +88,18 @@ falco::app::run_result falco::app::actions::open_live_inspector( falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with no driver\n"); inspector->open_nodriver(); } - else if(s.is_gvisor_enabled()) /* gvisor engine. */ + else if(s.is_gvisor()) /* gvisor engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with gVisor. Configuration path: " + s.config->m_gvisor.m_config); inspector->open_gvisor(s.config->m_gvisor.m_config, s.config->m_gvisor.m_root); } - else if(s.config->m_engine_mode == engine_kind_t::MODERN_EBPF) /* modern BPF engine. */ + else if(s.is_modern_ebpf()) /* modern BPF engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer) + "' CPUs."); inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); } - else if(s.config->m_engine_mode == engine_kind_t::EBPF) /* BPF engine. */ + else if(s.is_ebpf()) /* BPF engine. */ { const char *bpf_probe_path = s.config->m_ebpf.m_probe_path.c_str(); char full_path[PATH_MAX]; diff --git a/userspace/falco/app/actions/process_events.cpp b/userspace/falco/app/actions/process_events.cpp index 120e702ff9d..72f916a2d24 100644 --- a/userspace/falco/app/actions/process_events.cpp +++ b/userspace/falco/app/actions/process_events.cpp @@ -348,7 +348,7 @@ static void process_inspector_events( syscall_evt_drop_mgr sdropmgr; bool is_capture_mode = source.empty(); bool check_drops_timeouts = is_capture_mode - || (source == falco_common::syscall_source && !s.is_gvisor_enabled()); + || (source == falco_common::syscall_source && !s.is_gvisor()); duration = ((double)clock()) / CLOCKS_PER_SEC; diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index 32ea07ecfce..9416b09b593 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -32,15 +32,11 @@ namespace app { // initialize their linked variables. options::options() : event_buffer_format(sinsp_evt::PF_NORMAL), - gvisor_config(""), list_fields(false), list_plugins(false), list_syscall_events(false), markdown(false), - modern_bpf(false), - dry_run(false), - nodriver(false), - trace_filename("") + dry_run(false) { } diff --git a/userspace/falco/app/options.h b/userspace/falco/app/options.h index 8ff2a1c69c3..cf19f15d406 100644 --- a/userspace/falco/app/options.h +++ b/userspace/falco/app/options.h @@ -47,10 +47,7 @@ class options { std::vector disable_sources; std::vector disabled_rule_substrings; std::vector enable_sources; - std::string trace_filename; - std::string gvisor_config; std::string gvisor_generate_config_with_socket; - std::string gvisor_root; bool describe_all_rules; std::string describe_rule; bool print_ignored_events; @@ -76,9 +73,15 @@ class options { bool verbose; bool print_version_info; bool print_page_size; - bool modern_bpf; bool dry_run; - bool nodriver; + + // todo!: remove them in Falco 0.38.0 since they are deprecated + std::string trace_filename = ""; + std::string gvisor_config = ""; + std::string gvisor_root = ""; + bool modern_bpf = false; + bool nodriver = false; + bool parse(int argc, char **argv, std::string &errstr); diff --git a/userspace/falco/app/state.h b/userspace/falco/app/state.h index ba6caee5961..ff927c86ccd 100644 --- a/userspace/falco/app/state.h +++ b/userspace/falco/app/state.h @@ -150,11 +150,16 @@ struct state return config->m_engine_mode == engine_kind_t::REPLAY; } - inline bool is_gvisor_enabled() const + inline bool is_gvisor() const { return config->m_engine_mode == engine_kind_t::GVISOR; } - + + inline bool is_ebpf() const + { + return config->m_engine_mode == engine_kind_t::EBPF; + } + inline bool is_modern_ebpf() const { return config->m_engine_mode == engine_kind_t::MODERN_EBPF; diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 750519a71ad..af0e45f84d1 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -41,7 +41,6 @@ namespace fs = std::filesystem; static re2::RE2 ip_address_re("((^\\s*((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))\\s*$)|(^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$))"); falco_configuration::falco_configuration(): - m_engine_mode(engine_kind_t::KMOD), m_json_output(false), m_json_include_output_property(true), m_json_include_tags_property(true), diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 3af44e50f56..b42c41d6e0d 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -160,7 +160,7 @@ class falco_configuration bool m_metrics_include_empty_values; // Falco engine - engine_kind_t m_engine_mode; + engine_kind_t m_engine_mode = engine_kind_t::KMOD; kmod_config m_kmod; ebpf_config m_ebpf; modern_ebpf_config m_modern_ebpf; From 5441cee05347dd153bb7d174586fd698f938f5f8 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Fri, 17 Nov 2023 16:37:10 +0100 Subject: [PATCH 10/29] chore(userspace): properly let old config keys override new ones when set to a non-default value. Signed-off-by: Federico Di Pierro Co-authored-by: Andrea Terzolo --- falco.yaml | 89 +++++++++++++++---------------- userspace/falco/configuration.cpp | 53 +++++++++++------- 2 files changed, 77 insertions(+), 65 deletions(-) diff --git a/falco.yaml b/falco.yaml index 069d1cda229..cde3bbe4abd 100644 --- a/falco.yaml +++ b/falco.yaml @@ -27,6 +27,8 @@ # (Falco environment variables) # Falco rules files # rules_file +# Falco engine +# engine # Falco plugins # load_plugins # plugins @@ -62,8 +64,6 @@ # syscall_event_timeouts # syscall_event_drops # metrics -# Falco engine -# engine # Falco performance tuning (advanced) # syscall_buf_size_preset # syscall_drop_failed_exit @@ -147,6 +147,48 @@ rules_file: - /etc/falco/falco_rules.local.yaml - /etc/falco/rules.d +################ +# Falco engine # +################ + +# [Stable] `engine` +# +# --- [Description] +# +# Falco supports different engines to generate events. +# Choose the appropriate engine kind based on your system's configuration and requirements. +# +# Available engines: +# - `kmod`: Kernel Module (Kernel Module) +# - `ebpf`: eBPF (Extended Berkeley Packet Filter) +# - `modern-ebpf`: Modern eBPF (Modern Extended Berkeley Packet Filter), available only for recent kernels +# - `gvisor`: gVisor (gVisor sandbox) +# - `replay`: Replay a scap trace file +# - `none`: No engine loaded, useful to run `syscall` source plugin or just plugins without loading any other event producer. + +# Select the appropriate engine kind by uncommenting the corresponding line. +# Make sure to specify only one engine kind at a time. +# Moreover, for each engine multiple options might be available, +# grouped under engine specific configuration keys. +engine: + kind: kmod + kmod: + buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset if set + drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit if set + ebpf: + probe: /path/to/probe.o + buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset if set + drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit if set + modern-ebpf: + cpus_for_each_syscall_buffer: 2 # Overridden by deprecated cpus_for_each_syscall_buffer if set + buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset if set + drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit if set + replay: + trace_file: /path/to/file.scap + gvisor: + config: /path/to/gvisor.yaml + root: /gvisor/root + ################# # Falco plugins # ################# @@ -771,49 +813,6 @@ metrics: convert_memory_to_mb: true include_empty_values: false -################ -# Falco engine # -################ - -# [Stable] `engine` -# -# --- [Description] -# -# Falco supports different engines to generate events. -# Choose the appropriate engine kind based on your system's configuration and requirements. -# -# Available engines: -# - `kmod`: Kernel Module (Kernel Module) -# - `ebpf`: eBPF (Extended Berkeley Packet Filter) -# - `modern-ebpf`: Modern eBPF (Modern Extended Berkeley Packet Filter), available only for recent kernels -# - `gvisor`: gVisor (gVisor sandbox) -# - `replay`: Replay a scap trace file -# - `none`: No engine loaded, useful to run `syscall` source plugin or just plugins without loading any other event producer. - -# Select the appropriate engine kind by uncommenting the corresponding line. -# Make sure to specify only one engine kind at a time. -# Moreover, for each engine multiple options might be available, -# grouped under the `engine.kind` configuration key. - -engine: - kind: kmod - kmod: - buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset - drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit - ebpf: - probe: /path/to/probe.o - buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset - drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit - modern-ebpf: - cpus_for_each_syscall_buffer: 2 # Overridden by deprecated cpus_for_each_syscall_buffer - buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset - drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit - replay: - trace_file: /path/to/file.scap - gvisor: - config: /path/to/gvisor.yaml - root: /gvisor/root - ####################################### # Falco performance tuning (advanced) # ####################################### diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index af0e45f84d1..f728f7c39ea 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -114,6 +114,10 @@ void falco_configuration::load_engine_config(const std::string& config_name, con {"none",engine_kind_t::NONE}, }; + constexpr int default_buf_size_preset = 4; + constexpr int default_cpus_for_each_syscall_buffer = 2; + constexpr bool default_drop_failed = false; + auto driver_mode_str = config.get_scalar("engine.kind", "kmod"); if (engine_mode_lut.find(driver_mode_str) != engine_mode_lut.end()) { @@ -127,21 +131,21 @@ void falco_configuration::load_engine_config(const std::string& config_name, con switch (m_engine_mode) { case engine_kind_t::KMOD: - m_kmod.m_buf_size_preset = config.get_scalar("engine.kmod.buf_size_preset", 4); - m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed", false); + m_kmod.m_buf_size_preset = config.get_scalar("engine.kmod.buf_size_preset", default_buf_size_preset); + m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed", default_drop_failed); break; case engine_kind_t::EBPF: // TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH, // to be done once we drop the CLI option otherwise we would need to make the check twice, // once here, and once when we merge the CLI options in the config file. m_ebpf.m_probe_path = config.get_scalar("engine.ebpf.probe", ""); - m_ebpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", 4); - m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed", false); + m_ebpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", default_buf_size_preset); + m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed", default_drop_failed); break; case engine_kind_t::MODERN_EBPF: - m_modern_ebpf.m_cpus_for_each_syscall_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_syscall_buffer", 2); - m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", 4); - m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed", false); + m_modern_ebpf.m_cpus_for_each_syscall_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_syscall_buffer", default_cpus_for_each_syscall_buffer); + m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", default_buf_size_preset); + m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed", default_drop_failed); break; case engine_kind_t::REPLAY: m_replay.m_trace_file = config.get_scalar("engine.replay.trace_file", ""); @@ -162,6 +166,28 @@ void falco_configuration::load_engine_config(const std::string& config_name, con default: break; } + + // TODO: remove in Falco 0.38 since they are deprecated. + // old config keys always have priority over new ones, when set to a non-default value + auto buf_size_preset = config.get_scalar("syscall_buf_size_preset", default_buf_size_preset); + if (buf_size_preset != default_buf_size_preset) + { + m_kmod.m_buf_size_preset = buf_size_preset; + m_ebpf.m_buf_size_preset = buf_size_preset; + m_modern_ebpf.m_buf_size_preset = buf_size_preset; + } + auto cpus_for_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", default_cpus_for_each_syscall_buffer); + if (cpus_for_syscall_buffer != default_cpus_for_each_syscall_buffer) + { + m_modern_ebpf.m_cpus_for_each_syscall_buffer = cpus_for_syscall_buffer; + } + auto drop_failed = config.get_scalar("syscall_drop_failed_exit", default_drop_failed); + if (drop_failed) + { + m_kmod.m_drop_failed_exit = drop_failed; + m_ebpf.m_drop_failed_exit = drop_failed; + m_modern_ebpf.m_drop_failed_exit = drop_failed; + } } void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) @@ -423,18 +449,6 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h throw std::logic_error("Error reading config file(" + config_name + "): the maximum consecutive timeouts without an event must be an unsigned integer > 0"); } - /* We put this value in the configuration file because in this way we can change the dimension at every reload. - * The default value is `4` -> 8 MB. - */ - // TODO: remove in Falco 0.38 since they are deprecated. - m_kmod.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); - m_ebpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); - m_modern_ebpf.m_buf_size_preset = config.get_scalar("syscall_buf_size_preset", 4); - m_modern_ebpf.m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", 2); - m_kmod.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); - m_ebpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); - m_modern_ebpf.m_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", false); - m_base_syscalls_custom_set.clear(); config.get_sequence>(m_base_syscalls_custom_set, std::string("base_syscalls.custom_set")); m_base_syscalls_repair = config.get_scalar("base_syscalls.repair", false); @@ -453,7 +467,6 @@ void falco_configuration::load_yaml(const std::string& config_name, const yaml_h std::vector load_plugins; bool load_plugins_node_defined = config.is_defined("load_plugins"); - config.get_sequence>(load_plugins, "load_plugins"); std::list plugins; From f9bfcf387b755c3a1676fa1417250615dbaa8ae8 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 17 Nov 2023 17:49:02 +0100 Subject: [PATCH 11/29] fix: always initialize the engine configs Signed-off-by: Andrea Terzolo --- userspace/falco/configuration.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index b42c41d6e0d..13da566d5d2 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -158,15 +158,15 @@ class falco_configuration bool m_metrics_libbpf_stats_enabled; bool m_metrics_convert_memory_to_mb; bool m_metrics_include_empty_values; + std::vector m_plugins; // Falco engine engine_kind_t m_engine_mode = engine_kind_t::KMOD; - kmod_config m_kmod; - ebpf_config m_ebpf; - modern_ebpf_config m_modern_ebpf; - replay_config m_replay; - gvisor_config m_gvisor; - std::vector m_plugins; + kmod_config m_kmod = {}; + ebpf_config m_ebpf = {}; + modern_ebpf_config m_modern_ebpf = {}; + replay_config m_replay = {}; + gvisor_config m_gvisor = {}; private: void load_yaml(const std::string& config_name, const yaml_helper& config); From fc50b663f27a3d2fcb0af5c9ffe00657ded77b80 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 17 Nov 2023 17:49:32 +0100 Subject: [PATCH 12/29] tests: add a basic test to check config precedence Signed-off-by: Andrea Terzolo --- unit_tests/CMakeLists.txt | 9 ++++ .../falco/app/actions/test_load_config.cpp | 34 +++++++++++++ .../test_engine_selection_precedence.yaml | 51 +++++++++++++++++++ unit_tests/falco_test_var.h.in | 3 ++ 4 files changed, 97 insertions(+) create mode 100644 unit_tests/falco/app/actions/test_load_config.cpp create mode 100644 unit_tests/falco/test_configs/test_engine_selection_precedence.yaml create mode 100644 unit_tests/falco_test_var.h.in diff --git a/unit_tests/CMakeLists.txt b/unit_tests/CMakeLists.txt index 69a568530a4..e93ebabbeca 100644 --- a/unit_tests/CMakeLists.txt +++ b/unit_tests/CMakeLists.txt @@ -27,10 +27,18 @@ FetchContent_MakeAvailable(googletest) file(GLOB_RECURSE ENGINE_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/engine/*.cpp) file(GLOB_RECURSE FALCO_TESTS ${CMAKE_CURRENT_SOURCE_DIR}/falco/*.cpp) +# Create a libscap_test_var.h file with some variables used by our tests +# for example the kmod path or the bpf path. +configure_file ( + "${CMAKE_CURRENT_SOURCE_DIR}/falco_test_var.h.in" + "${CMAKE_CURRENT_BINARY_DIR}/falco_test_var.h" +) + set(FALCO_UNIT_TESTS_SOURCES "${ENGINE_TESTS}" falco/test_configuration.cpp falco/app/actions/test_select_event_sources.cpp + falco/app/actions/test_load_config.cpp ) if (CMAKE_SYSTEM_NAME MATCHES "Linux") @@ -45,6 +53,7 @@ set(FALCO_UNIT_TESTS_INCLUDES ${CMAKE_SOURCE_DIR}/userspace ${CMAKE_BINARY_DIR}/userspace/falco # we need it to include indirectly `config_falco.h` file ${CMAKE_SOURCE_DIR}/userspace/engine # we need it to include indirectly `falco_common.h` file + "${CMAKE_CURRENT_BINARY_DIR}" # we need it to include `falco_test_var.h` ) set(FALCO_UNIT_TESTS_DEPENDENCIES diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp new file mode 100644 index 00000000000..3821a936ddb --- /dev/null +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +/* +Copyright (C) 2023 The Falco Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless ASSERTd by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "app_action_helpers.h" +#include "falco_test_var.h" + +TEST(ActionLoadConfig, check_depracated_falco_038_configs) +{ + auto action = falco::app::actions::load_config; + + // todo!: remove in 0.38.0 since we don't have anymore any precedence + { + falco::app::state s; + s.options.conf_filename = ENGINE_SELECTION_TEST_CONFIG; + EXPECT_ACTION_OK(action(s)); + EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 5); + EXPECT_TRUE(s.config->m_modern_ebpf.m_drop_failed_exit); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 3); + } +} diff --git a/unit_tests/falco/test_configs/test_engine_selection_precedence.yaml b/unit_tests/falco/test_configs/test_engine_selection_precedence.yaml new file mode 100644 index 00000000000..994697de7e1 --- /dev/null +++ b/unit_tests/falco/test_configs/test_engine_selection_precedence.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2023 The Falco Authors. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +################ +# Falco engine # +################ + +engine: + kind: modern-ebpf + kmod: + buf_size_preset: 4 + drop_failed_exit: false + ebpf: + probe: /path/to/probe.o + buf_size_preset: 4 + drop_failed_exit: false + modern-ebpf: + cpus_for_each_syscall_buffer: 1 + buf_size_preset: 5 # This should win over the other config + drop_failed_exit: false + replay: + trace_file: /path/to/file.scap + gvisor: + config: /path/to/gvisor.yaml + root: /gvisor/root + +####################################### +# Falco performance tuning (advanced) # +####################################### + +syscall_buf_size_preset: 4 + +syscall_drop_failed_exit: true # This should win over the other config + +modern_bpf: + cpus_for_each_syscall_buffer: 3 # Should win this 3 over the 1 in the other config diff --git a/unit_tests/falco_test_var.h.in b/unit_tests/falco_test_var.h.in new file mode 100644 index 00000000000..208fb67b985 --- /dev/null +++ b/unit_tests/falco_test_var.h.in @@ -0,0 +1,3 @@ +#pragma once + +#define ENGINE_SELECTION_TEST_CONFIG "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/test_engine_selection_precedence.yaml" From 86497331bdb238fcaee0a6fe9a10fe8387516d7c Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 18 Nov 2023 11:24:47 +0100 Subject: [PATCH 13/29] fix: use `drop_failed_exit` instead of just `drop_failed` Signed-off-by: Andrea Terzolo --- userspace/falco/configuration.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index f728f7c39ea..053ee1fd03f 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -114,9 +114,9 @@ void falco_configuration::load_engine_config(const std::string& config_name, con {"none",engine_kind_t::NONE}, }; - constexpr int default_buf_size_preset = 4; - constexpr int default_cpus_for_each_syscall_buffer = 2; - constexpr bool default_drop_failed = false; + constexpr int16_t default_buf_size_preset = 4; + constexpr int16_t default_cpus_for_each_syscall_buffer = 2; + constexpr bool default_drop_failed_exit = false; auto driver_mode_str = config.get_scalar("engine.kind", "kmod"); if (engine_mode_lut.find(driver_mode_str) != engine_mode_lut.end()) @@ -132,7 +132,7 @@ void falco_configuration::load_engine_config(const std::string& config_name, con { case engine_kind_t::KMOD: m_kmod.m_buf_size_preset = config.get_scalar("engine.kmod.buf_size_preset", default_buf_size_preset); - m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed", default_drop_failed); + m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed_exit", default_drop_failed_exit); break; case engine_kind_t::EBPF: // TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH, @@ -140,12 +140,12 @@ void falco_configuration::load_engine_config(const std::string& config_name, con // once here, and once when we merge the CLI options in the config file. m_ebpf.m_probe_path = config.get_scalar("engine.ebpf.probe", ""); m_ebpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", default_buf_size_preset); - m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed", default_drop_failed); + m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed_exit", default_drop_failed_exit); break; case engine_kind_t::MODERN_EBPF: m_modern_ebpf.m_cpus_for_each_syscall_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_syscall_buffer", default_cpus_for_each_syscall_buffer); m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", default_buf_size_preset); - m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed", default_drop_failed); + m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed_exit", default_drop_failed_exit); break; case engine_kind_t::REPLAY: m_replay.m_trace_file = config.get_scalar("engine.replay.trace_file", ""); @@ -181,7 +181,7 @@ void falco_configuration::load_engine_config(const std::string& config_name, con { m_modern_ebpf.m_cpus_for_each_syscall_buffer = cpus_for_syscall_buffer; } - auto drop_failed = config.get_scalar("syscall_drop_failed_exit", default_drop_failed); + auto drop_failed = config.get_scalar("syscall_drop_failed_exit", default_drop_failed_exit); if (drop_failed) { m_kmod.m_drop_failed_exit = drop_failed; From 2b3922b765f6b72549376e188c002ef808b7c9bd Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 18 Nov 2023 11:56:50 +0100 Subject: [PATCH 14/29] new: allow to use only one between the config and the command line Signed-off-by: Andrea Terzolo --- userspace/falco/app/actions/load_config.cpp | 20 +++++++++- userspace/falco/configuration.cpp | 41 ++++++++++----------- userspace/falco/configuration.h | 9 +++++ 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index fb140e938ac..6022eb7030d 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -29,18 +29,34 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) { // Please note: is not possible to mix command line options and configs to obtain a configuration // we need to use only one method. For example, is not possible to set the gvisor-config through - // the command line and the gvisor-root through the config file. - // + // the command line and the gvisor-root through the config file. For this reason, if we detect + // at least one change in the default config we don't allow to use the command line options. + if(s.config->m_changes_in_engine_config) + { + return run_result::ok(); + } + + // Replace the kmod default values in case the engine was open with the kmod. + // We don't have a command line option to open the kmod so we have to always enforce the + // default values. + s.config->m_kmod.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; + s.config->m_kmod.m_buf_size_preset = s.config->m_syscall_buf_size_preset; + // If overridden from CLI options (soon to be removed), // use the requested driver. if (getenv(FALCO_BPF_ENV_VARIABLE)) { s.config->m_engine_mode = engine_kind_t::EBPF; s.config->m_ebpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE); + s.config->m_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; + s.config->m_ebpf.m_buf_size_preset = s.config->m_syscall_buf_size_preset; } else if (s.options.modern_bpf) { s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; + s.config->m_modern_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; + s.config->m_modern_ebpf.m_buf_size_preset = s.config->m_syscall_buf_size_preset; + s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = s.config->m_cpus_for_each_syscall_buffer; } if (!s.options.gvisor_config.empty()) { diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 053ee1fd03f..f84360ab76c 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -133,6 +133,22 @@ void falco_configuration::load_engine_config(const std::string& config_name, con case engine_kind_t::KMOD: m_kmod.m_buf_size_preset = config.get_scalar("engine.kmod.buf_size_preset", default_buf_size_preset); m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed_exit", default_drop_failed_exit); + + if(m_kmod.m_buf_size_preset == default_buf_size_preset && m_kmod.m_drop_failed_exit==default_drop_failed_exit) + { + // This could happen in 2 cases: + // 1. The user doesn't use the new config (it could also have commented it) + // 2. The user uses the new config unchanged. + // In these 2 cases the users are allowed to use the command line arguments to open an engine + m_changes_in_engine_config = false; + + // Catch deprecated values from the config, to use them with the command line if needed + m_syscall_buf_size_preset = config.get_scalar("syscall_buf_size_preset", default_buf_size_preset); + m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", default_cpus_for_each_syscall_buffer); + m_syscall_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", default_drop_failed_exit); + return; + } + break; case engine_kind_t::EBPF: // TODO: default value for `probe` should be $HOME/FALCO_PROBE_BPF_FILEPATH, @@ -166,28 +182,9 @@ void falco_configuration::load_engine_config(const std::string& config_name, con default: break; } - - // TODO: remove in Falco 0.38 since they are deprecated. - // old config keys always have priority over new ones, when set to a non-default value - auto buf_size_preset = config.get_scalar("syscall_buf_size_preset", default_buf_size_preset); - if (buf_size_preset != default_buf_size_preset) - { - m_kmod.m_buf_size_preset = buf_size_preset; - m_ebpf.m_buf_size_preset = buf_size_preset; - m_modern_ebpf.m_buf_size_preset = buf_size_preset; - } - auto cpus_for_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", default_cpus_for_each_syscall_buffer); - if (cpus_for_syscall_buffer != default_cpus_for_each_syscall_buffer) - { - m_modern_ebpf.m_cpus_for_each_syscall_buffer = cpus_for_syscall_buffer; - } - auto drop_failed = config.get_scalar("syscall_drop_failed_exit", default_drop_failed_exit); - if (drop_failed) - { - m_kmod.m_drop_failed_exit = drop_failed; - m_ebpf.m_drop_failed_exit = drop_failed; - m_modern_ebpf.m_drop_failed_exit = drop_failed; - } + + // If we arrive here it means we have at least one change in the `engine` config. + m_changes_in_engine_config = true; } void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 13da566d5d2..82e222fc693 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -168,6 +168,15 @@ class falco_configuration replay_config m_replay = {}; gvisor_config m_gvisor = {}; + // todo!: to remove in Falco 0.38.0 + // used to keep track if the `engine` config is used. + bool m_changes_in_engine_config = false; + // Index corresponding to the syscall buffer dimension. + uint16_t m_syscall_buf_size_preset = 4; + // Number of CPUs associated with a single ring buffer. + uint16_t m_cpus_for_each_syscall_buffer = 2; + bool m_syscall_drop_failed_exit = false; + private: void load_yaml(const std::string& config_name, const yaml_helper& config); From 6cad918b9a61c1401e1da379884806fb1c67b826 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 18 Nov 2023 15:24:57 +0100 Subject: [PATCH 15/29] fix: take into consideration that `load_yaml` is called more than once Signed-off-by: Andrea Terzolo --- .../falco/app/actions/test_load_config.cpp | 189 ++++++++++++++++-- ...ce.yaml => new_engine_config_changed.yaml} | 21 +- .../new_engine_config_unchanged.yaml | 53 +++++ unit_tests/falco_test_var.h.in | 3 +- userspace/falco/configuration.cpp | 5 + userspace/falco/configuration.h | 4 +- 6 files changed, 250 insertions(+), 25 deletions(-) rename unit_tests/falco/test_configs/{test_engine_selection_precedence.yaml => new_engine_config_changed.yaml} (73%) create mode 100644 unit_tests/falco/test_configs/new_engine_config_unchanged.yaml diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index 3821a936ddb..fabcb5f4a6c 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -18,17 +18,182 @@ limitations under the License. #include "app_action_helpers.h" #include "falco_test_var.h" -TEST(ActionLoadConfig, check_depracated_falco_038_configs) +auto action = falco::app::actions::load_config; + +TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed) +{ + falco::app::state s = {}; + s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED; + // TODO: understand why load_yaml is called more times + EXPECT_ACTION_OK(action(s)); + + // Check that the engine is the kmod + EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD); + + // Check that kmod params are the ones specified in the config + EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 2); + EXPECT_FALSE(s.config->m_kmod.m_drop_failed_exit); + + // Check that all other engine params are empty + EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty()); + EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); + + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); + + EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + + EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); + EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); + + // Check that deprecated configs are not populated since we are using + // the new config. + EXPECT_EQ(s.config->m_syscall_buf_size_preset, 0); + EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 0); + EXPECT_FALSE(s.config->m_syscall_drop_failed_exit); +} + +// Equal to the one above but checks that the command line options are not parsed +TEST(ActionLoadConfig, check_command_line_options_are_not_used) +{ + falco::app::state s; + s.options.modern_bpf = true; + s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED; + EXPECT_ACTION_OK(action(s)); + + // Check that the engine is the kmod + EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD); + + // Check that kmod params are the ones specified in the config + EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 2); + EXPECT_FALSE(s.config->m_kmod.m_drop_failed_exit); + + // Check that all other engine params are empty + EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty()); + EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); + + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); + + EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + + EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); + EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); + + // Check that deprecated configs are not populated since we are using + // the new config. + EXPECT_EQ(s.config->m_syscall_buf_size_preset, 0); + EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 0); + EXPECT_FALSE(s.config->m_syscall_drop_failed_exit); +} + +TEST(ActionLoadConfig, check_kmod_with_syscall_configs) { - auto action = falco::app::actions::load_config; - - // todo!: remove in 0.38.0 since we don't have anymore any precedence - { - falco::app::state s; - s.options.conf_filename = ENGINE_SELECTION_TEST_CONFIG; - EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 5); - EXPECT_TRUE(s.config->m_modern_ebpf.m_drop_failed_exit); - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 3); - } + falco::app::state s; + s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; + EXPECT_ACTION_OK(action(s)); + + // Check that the engine is the kmod + EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD); + + // Kmod params should be populated with the syscall configs + // since the `engine` block is untouched. + EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6); + EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit); + + // Check that all other engine params are empty + EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty()); + EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); + + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); + + EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + + EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); + EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); + + // Check that deprecated configs are populated + EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6); + EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3); + EXPECT_TRUE(s.config->m_syscall_drop_failed_exit); +} + +TEST(ActionLoadConfig, check_override_command_line_modern) +{ + falco::app::state s; + // The comman line options should be correctly applied since the + // config is unchanged + s.options.modern_bpf = true; + s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; + EXPECT_ACTION_OK(action(s)); + + // Check that the engine is the kmod + EXPECT_TRUE(s.is_modern_ebpf()); + + // Check that the modern ebpf engine uses the default syscall configs + // and not the ones in the `engine` block + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 3); + EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 6); + EXPECT_TRUE(s.config->m_modern_ebpf.m_drop_failed_exit); + + // Kmod params should be always populated since the kmod is the default + EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6); + EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit); + + // Check that all other engine params are empty + EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty()); + EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); + + EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + + EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); + EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); + + // Check that deprecated configs are populated + EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6); + EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3); + EXPECT_TRUE(s.config->m_syscall_drop_failed_exit); +} + +TEST(ActionLoadConfig, check_override_command_line_gvisor) +{ + falco::app::state s; + // The comman line options should be correctly applied since the + // config is unchanged + s.options.gvisor_config = "config"; + s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; + EXPECT_ACTION_OK(action(s)); + + // Check that the engine is the kmod + EXPECT_TRUE(s.is_gvisor()); + EXPECT_EQ(s.config->m_gvisor.m_config, "config"); + EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); + + // Kmod params should be always populated since the kmod is the default + EXPECT_EQ(s.config->m_kmod.m_buf_size_preset, 6); + EXPECT_TRUE(s.config->m_kmod.m_drop_failed_exit); + + // Check that all other engine params are empty + EXPECT_TRUE(s.config->m_ebpf.m_probe_path.empty()); + EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); + + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); + EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); + + EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + + // Check that deprecated configs are populated + EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6); + EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3); + EXPECT_TRUE(s.config->m_syscall_drop_failed_exit); } diff --git a/unit_tests/falco/test_configs/test_engine_selection_precedence.yaml b/unit_tests/falco/test_configs/new_engine_config_changed.yaml similarity index 73% rename from unit_tests/falco/test_configs/test_engine_selection_precedence.yaml rename to unit_tests/falco/test_configs/new_engine_config_changed.yaml index 994697de7e1..bed9898fd28 100644 --- a/unit_tests/falco/test_configs/test_engine_selection_precedence.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_changed.yaml @@ -21,31 +21,32 @@ ################ engine: - kind: modern-ebpf + kind: kmod kmod: - buf_size_preset: 4 + buf_size_preset: 2 # changed default value drop_failed_exit: false ebpf: probe: /path/to/probe.o - buf_size_preset: 4 + buf_size_preset: 4 drop_failed_exit: false modern-ebpf: - cpus_for_each_syscall_buffer: 1 - buf_size_preset: 5 # This should win over the other config + cpus_for_each_syscall_buffer: 2 + buf_size_preset: 4 drop_failed_exit: false replay: trace_file: /path/to/file.scap gvisor: - config: /path/to/gvisor.yaml - root: /gvisor/root + config: /path/to/gvisor_config.yaml + root: "" ####################################### # Falco performance tuning (advanced) # ####################################### -syscall_buf_size_preset: 4 +# These configs should be ignored since we have changed the `engine` config +syscall_buf_size_preset: 6 -syscall_drop_failed_exit: true # This should win over the other config +syscall_drop_failed_exit: true modern_bpf: - cpus_for_each_syscall_buffer: 3 # Should win this 3 over the 1 in the other config + cpus_for_each_syscall_buffer: 7 diff --git a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml new file mode 100644 index 00000000000..70998a06f67 --- /dev/null +++ b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml @@ -0,0 +1,53 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (C) 2023 The Falco Authors. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +################ +# Falco engine # +################ + +# Unchanged +engine: + kind: kmod + kmod: + buf_size_preset: 4 + drop_failed_exit: false + ebpf: + probe: /path/to/probe.o + buf_size_preset: 4 + drop_failed_exit: false + modern-ebpf: + cpus_for_each_syscall_buffer: 2 + buf_size_preset: 4 + drop_failed_exit: false + replay: + trace_file: /path/to/file.scap + gvisor: + config: /path/to/gvisor_config.yaml + root: "" + +####################################### +# Falco performance tuning (advanced) # +####################################### + +# The `engine` config is unchanged so these configs are used +syscall_buf_size_preset: 6 + +syscall_drop_failed_exit: true + +modern_bpf: + cpus_for_each_syscall_buffer: 3 diff --git a/unit_tests/falco_test_var.h.in b/unit_tests/falco_test_var.h.in index 208fb67b985..f8cfcab8321 100644 --- a/unit_tests/falco_test_var.h.in +++ b/unit_tests/falco_test_var.h.in @@ -1,3 +1,4 @@ #pragma once -#define ENGINE_SELECTION_TEST_CONFIG "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/test_engine_selection_precedence.yaml" +#define NEW_ENGINE_CONFIG_CHANGED "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/new_engine_config_changed.yaml" +#define NEW_ENGINE_CONFIG_UNCHANGED "${CMAKE_SOURCE_DIR}/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml" diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index f84360ab76c..d4b8ac42d2f 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -184,7 +184,12 @@ void falco_configuration::load_engine_config(const std::string& config_name, con } // If we arrive here it means we have at least one change in the `engine` config. + // Please note that `load_config` is called more than one time during initialization + // so the last time wins m_changes_in_engine_config = true; + m_syscall_buf_size_preset = 0; + m_cpus_for_each_syscall_buffer = 0; + m_syscall_drop_failed_exit = false; } void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 82e222fc693..24f808bb7b4 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -172,9 +172,9 @@ class falco_configuration // used to keep track if the `engine` config is used. bool m_changes_in_engine_config = false; // Index corresponding to the syscall buffer dimension. - uint16_t m_syscall_buf_size_preset = 4; + uint16_t m_syscall_buf_size_preset = 0; // Number of CPUs associated with a single ring buffer. - uint16_t m_cpus_for_each_syscall_buffer = 2; + uint16_t m_cpus_for_each_syscall_buffer = 0; bool m_syscall_drop_failed_exit = false; private: From a7e3cb653201d3171059b3d9c69b4dcb7ce1d098 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 18 Nov 2023 15:51:21 +0100 Subject: [PATCH 16/29] cleanup: rename `cpus_for_each_syscall_buffer` Signed-off-by: Andrea Terzolo --- falco.yaml | 25 ++++++++++++------- .../test_configure_syscall_buffer_num.cpp | 8 +++--- .../falco/app/actions/test_load_config.cpp | 10 ++++---- .../new_engine_config_changed.yaml | 4 +-- .../new_engine_config_unchanged.yaml | 4 +-- .../actions/configure_syscall_buffer_num.cpp | 6 ++--- .../falco/app/actions/helpers_inspector.cpp | 4 +-- userspace/falco/app/actions/load_config.cpp | 2 +- userspace/falco/configuration.cpp | 2 +- userspace/falco/configuration.h | 2 +- 10 files changed, 37 insertions(+), 30 deletions(-) diff --git a/falco.yaml b/falco.yaml index cde3bbe4abd..b115b9f9b01 100644 --- a/falco.yaml +++ b/falco.yaml @@ -173,21 +173,28 @@ rules_file: engine: kind: kmod kmod: - buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset if set - drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit if set + buf_size_preset: 4 + drop_failed_exit: false ebpf: + # path to the elf file to load. probe: /path/to/probe.o - buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset if set - drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit if set + buf_size_preset: 4 + drop_failed_exit: false modern-ebpf: - cpus_for_each_syscall_buffer: 2 # Overridden by deprecated cpus_for_each_syscall_buffer if set - buf_size_preset: 4 # Overridden by deprecated syscall_buf_size_preset if set - drop_failed_exit: false # Overridden by deprecated syscall_drop_failed_exit if set + cpus_for_each_buffer: 2 ## todo! rename it without syscall + buf_size_preset: 4 + drop_failed_exit: false replay: + # path to the trace file to replay. trace_file: /path/to/file.scap gvisor: - config: /path/to/gvisor.yaml - root: /gvisor/root + # A Falco-compatible configuration file can be generated with + # '--gvisor-generate-config' and utilized for both runsc and Falco. + config: /path/to/gvisor_config.yaml + # Set gVisor root directory for storage of container state when used + # in conjunction with 'gvisor.config'. The 'gvisor.root' to be passed + # is the one usually passed to 'runsc --root' flag. + root: "" ################# # Falco plugins # diff --git a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp index ddbea31de12..0b1c65fb732 100644 --- a/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp +++ b/unit_tests/falco/app/actions/test_configure_syscall_buffer_num.cpp @@ -39,9 +39,9 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) { falco::app::state s; s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; - s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus + 1; + s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus + 1; EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, online_cpus); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, online_cpus); } // modern ebpf engine, with a valid number of CPUs @@ -49,8 +49,8 @@ TEST(ActionConfigureSyscallBufferNum, variable_number_of_CPUs) { falco::app::state s; s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; - s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus - 1; + s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus - 1; EXPECT_ACTION_OK(action(s)); - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, online_cpus - 1); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, online_cpus - 1); } } diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index fabcb5f4a6c..f1a1c22ac7b 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -39,7 +39,7 @@ TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed) EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0); EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); @@ -75,7 +75,7 @@ TEST(ActionLoadConfig, check_command_line_options_are_not_used) EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0); EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); @@ -110,7 +110,7 @@ TEST(ActionLoadConfig, check_kmod_with_syscall_configs) EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0); EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); @@ -139,7 +139,7 @@ TEST(ActionLoadConfig, check_override_command_line_modern) // Check that the modern ebpf engine uses the default syscall configs // and not the ones in the `engine` block - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 3); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 3); EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 6); EXPECT_TRUE(s.config->m_modern_ebpf.m_drop_failed_exit); @@ -186,7 +186,7 @@ TEST(ActionLoadConfig, check_override_command_line_gvisor) EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); - EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, 0); + EXPECT_EQ(s.config->m_modern_ebpf.m_cpus_for_each_buffer, 0); EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); diff --git a/unit_tests/falco/test_configs/new_engine_config_changed.yaml b/unit_tests/falco/test_configs/new_engine_config_changed.yaml index bed9898fd28..e0db0d74b3b 100644 --- a/unit_tests/falco/test_configs/new_engine_config_changed.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_changed.yaml @@ -30,7 +30,7 @@ engine: buf_size_preset: 4 drop_failed_exit: false modern-ebpf: - cpus_for_each_syscall_buffer: 2 + cpus_for_each_buffer: 2 buf_size_preset: 4 drop_failed_exit: false replay: @@ -49,4 +49,4 @@ syscall_buf_size_preset: 6 syscall_drop_failed_exit: true modern_bpf: - cpus_for_each_syscall_buffer: 7 + cpus_for_each_buffer: 7 diff --git a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml index 70998a06f67..bb21b2e5c44 100644 --- a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml @@ -31,7 +31,7 @@ engine: buf_size_preset: 4 drop_failed_exit: false modern-ebpf: - cpus_for_each_syscall_buffer: 2 + cpus_for_each_buffer: 2 buf_size_preset: 4 drop_failed_exit: false replay: @@ -50,4 +50,4 @@ syscall_buf_size_preset: 6 syscall_drop_failed_exit: true modern_bpf: - cpus_for_each_syscall_buffer: 3 + cpus_for_each_buffer: 3 diff --git a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp index aed2534c98f..b44984226c5 100644 --- a/userspace/falco/app/actions/configure_syscall_buffer_num.cpp +++ b/userspace/falco/app/actions/configure_syscall_buffer_num.cpp @@ -34,10 +34,10 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_num(falco:: return run_result::fatal("cannot get the number of online CPUs from the system\n"); } - if(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer > online_cpus) + if(s.config->m_modern_ebpf.m_cpus_for_each_buffer > online_cpus) { - falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); - s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = online_cpus; + falco_logger::log(falco_logger::level::WARNING, "you required a buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + "' CPUs but there are only '" + std::to_string(online_cpus) + "' online CPUs. Falco changed the config to: one buffer every '" + std::to_string(online_cpus) + "' CPUs\n"); + s.config->m_modern_ebpf.m_cpus_for_each_buffer = online_cpus; } #endif return run_result::ok(); diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 92e5f34b271..80c4113d4e0 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -96,8 +96,8 @@ falco::app::run_result falco::app::actions::open_live_inspector( else if(s.is_modern_ebpf()) /* modern BPF engine. */ { falco_logger::log(falco_logger::level::INFO, "Opening '" + source + "' source with modern BPF probe."); - falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer) + "' CPUs."); - inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer, true, s.selected_sc_set); + falco_logger::log(falco_logger::level::INFO, "One ring buffer every '" + std::to_string(s.config->m_modern_ebpf.m_cpus_for_each_buffer) + "' CPUs."); + inspector->open_modern_bpf(s.syscall_buffer_bytes_size, s.config->m_modern_ebpf.m_cpus_for_each_buffer, true, s.selected_sc_set); } else if(s.is_ebpf()) /* BPF engine. */ { diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 6022eb7030d..1fe2da64b20 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -56,7 +56,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; s.config->m_modern_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; s.config->m_modern_ebpf.m_buf_size_preset = s.config->m_syscall_buf_size_preset; - s.config->m_modern_ebpf.m_cpus_for_each_syscall_buffer = s.config->m_cpus_for_each_syscall_buffer; + s.config->m_modern_ebpf.m_cpus_for_each_buffer = s.config->m_cpus_for_each_syscall_buffer; } if (!s.options.gvisor_config.empty()) { diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index d4b8ac42d2f..813d0817add 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -159,7 +159,7 @@ void falco_configuration::load_engine_config(const std::string& config_name, con m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed_exit", default_drop_failed_exit); break; case engine_kind_t::MODERN_EBPF: - m_modern_ebpf.m_cpus_for_each_syscall_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_syscall_buffer", default_cpus_for_each_syscall_buffer); + m_modern_ebpf.m_cpus_for_each_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_buffer", default_cpus_for_each_syscall_buffer); m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", default_buf_size_preset); m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed_exit", default_drop_failed_exit); break; diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 24f808bb7b4..c72a07bf11f 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -74,7 +74,7 @@ class falco_configuration typedef struct { public: - uint16_t m_cpus_for_each_syscall_buffer; + uint16_t m_cpus_for_each_buffer; int16_t m_buf_size_preset; bool m_drop_failed_exit; } modern_ebpf_config; From 6e07a86397b1012dbdbe2cfb883ef089a6cbd3a3 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 18 Nov 2023 15:52:00 +0100 Subject: [PATCH 17/29] docs: add some descriptions in falco.yaml Signed-off-by: Andrea Terzolo --- falco.yaml | 176 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 162 insertions(+), 14 deletions(-) diff --git a/falco.yaml b/falco.yaml index b115b9f9b01..601f528d393 100644 --- a/falco.yaml +++ b/falco.yaml @@ -65,10 +65,10 @@ # syscall_event_drops # metrics # Falco performance tuning (advanced) -# syscall_buf_size_preset -# syscall_drop_failed_exit +# syscall_buf_size_preset [DEPRECATED] +# syscall_drop_failed_exit [DEPRECATED] # base_syscalls -# modern_bpf.cpus_for_each_syscall_buffer +# modern_bpf.cpus_for_each_syscall_buffer [DEPRECATED] ################################ @@ -160,16 +160,157 @@ rules_file: # # Available engines: # - `kmod`: Kernel Module (Kernel Module) -# - `ebpf`: eBPF (Extended Berkeley Packet Filter) -# - `modern-ebpf`: Modern eBPF (Modern Extended Berkeley Packet Filter), available only for recent kernels +# - `ebpf`: eBPF (eBPF probe) +# - `modern-ebpf`: Modern eBPF (CO-RE eBPF probe) # - `gvisor`: gVisor (gVisor sandbox) # - `replay`: Replay a scap trace file -# - `none`: No engine loaded, useful to run `syscall` source plugin or just plugins without loading any other event producer. - -# Select the appropriate engine kind by uncommenting the corresponding line. -# Make sure to specify only one engine kind at a time. +# - `none`: No event producer loaded, useful to run with plugins. +# +# Only one engine can be specified in the `kind` key. # Moreover, for each engine multiple options might be available, -# grouped under engine specific configuration keys. +# grouped under engine-specific configuration keys. +# Some of them deserve an in-depth description: +# +################### `buf_size_preset` +# +# --- [Description] +# +# The syscall buffer index determines the size of the shared space between Falco +# and its drivers. This shared space serves as a temporary storage for syscall +# events, allowing them to be transferred from the kernel to the userspace +# efficiently. The buffer size for each online CPU is determined by the buffer +# index, and each CPU has its own dedicated buffer. Adjusting this index allows +# you to control the overall size of the syscall buffers. +# +# --- [Usage] +# +# The index 0 is reserved, and each subsequent index corresponds to an +# increasing size in bytes. For example, index 1 corresponds to a size of 1 MB, +# index 2 corresponds to 2 MB, and so on: +# +# [(*), 1 MB, 2 MB, 4 MB, 8 MB, 16 MB, 32 MB, 64 MB, 128 MB, 256 MB, 512 MB] +# ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ +# | | | | | | | | | | | +# 0 1 2 3 4 5 6 7 8 9 10 +# +# +# The buffer dimensions in bytes are determined by the following requirements: +# (1) a power of 2. +# (2) a multiple of your system_page_dimension. +# (3) greater than `2 * (system_page_dimension). +# +# The buffer size constraints may limit the usability of certain indexes. Let's +# consider an example to illustrate this: +# +# If your system has a page size of 1 MB, the first available buffer size would +# be 4 MB because 2 MB is exactly equal to 2 * (system_page_size), which is not +# sufficient as we require more than 2 * (system_page_size). In this example, it +# is evident that if the page size is 1 MB, the first index that can be used is 3. +# +# However, in most cases, these constraints do not pose a limitation, and all +# indexes from 1 to 10 can be used. You can check your system's page size using +# the Falco `--page-size` command-line option. +# +# --- [Suggestions] +# +# The buffer size was previously fixed at 8 MB (index 4). You now have the +# option to adjust the size based on your needs. Increasing the size, such as to +# 16 MB (index 5), can reduce syscall drops in heavy production systems, but may +# impact performance. Decreasing the size can speed up the system but may +# increase syscall drops. It's important to note that the buffer size is mapped +# twice in the process' virtual memory, so a buffer of 8 MB will result in a 16 +# MB area in virtual memory. Use this parameter with caution and only modify it +# if the default size is not suitable for your use case. +# +################### `drop_failed_exit` +# +# --- [Description] +# +# Enabling this option in Falco allows it to drop failed system call exit events +# in the kernel drivers before pushing them onto the ring buffer. This +# optimization can result in lower CPU usage and more efficient utilization of +# the ring buffer, potentially reducing the number of event losses. However, it +# is important to note that enabling this option also means sacrificing some +# visibility into the system. +# +################### `cpus_for_each_buffer` (modern-ebpf only) +# +# --- [Description] +# +# The modern_bpf driver in Falco utilizes the new BPF ring buffer, which has a +# different memory footprint compared to the current BPF driver that uses the +# perf buffer. The Falco core maintainers have discussed the differences and +# their implications, particularly in Kubernetes environments where limits need +# to be carefully set to avoid interference with the Falco daemonset deployment +# from the OOM killer. Based on guidance received from the kernel mailing list, +# it is recommended to assign multiple CPUs to one buffer instead of allocating +# a buffer for each CPU individually. This helps optimize resource allocation +# and prevent potential issues related to memory usage. +# +# This is an index that controls how many CPUs you want to assign to a single +# syscall buffer (ring buffer). By default, for modern_bpf every syscall buffer +# is associated to 2 CPUs, so the mapping is 1:2. The modern BPF probe allows +# you to choose different mappings, for example, changing the value to `1` +# results in a 1:1 mapping and would mean one syscall buffer for each CPU (this +# is the default for the `bpf` driver). +# +# --- [Usage] +# +# You can choose an index from 0 to MAX_NUMBER_ONLINE_CPUs to set the dimension +# of the syscall buffers. The value 0 represents a single buffer shared among +# all online CPUs. It serves as a flexible option when the exact number of +# online CPUs is unknown. Here's an example to illustrate this: +# +# Consider a system with 7 online CPUs: +# +# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) +# +# - `1` means a syscall buffer for each CPU so 7 buffers +# +# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) +# | | | | | | | +# BUFFERs 0 1 2 3 4 5 6 +# +# - `2` (Default value) means a syscall buffer for each CPU pair, so 4 buffers +# +# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) +# | | | | | | | +# BUFFERs 0 0 1 1 2 2 3 +# +# Please note that in this example, there are 4 buffers in total. Three of the +# buffers are associated with pairs of CPUs, while the last buffer is mapped to +# a single CPU. This arrangement is necessary because we have an odd number of +# CPUs. +# +# - `0` or `MAX_NUMBER_ONLINE_CPUs` mean a syscall buffer shared between all +# CPUs, so 1 buffer +# +# CPUs 0 X 2 3 X X 6 7 8 9 (X means offline CPU) +# | | | | | | | +# BUFFERs 0 0 0 0 0 0 0 +# +# Moreover, you have the option to combine this parameter with +# `syscall_buf_size_preset` index. For instance, you can create a large shared +# syscall buffer of 512 MB (using syscall_buf_size_preset=10) that is +# allocated among all the online CPUs. +# +# --- [Suggestions] +# +# The default choice of index 2 (one syscall buffer for each CPU pair) was made +# because the modern bpf probe utilizes a different memory allocation strategy +# compared to the other two drivers (bpf and kernel module). However, you have +# the flexibility to experiment and find the optimal configuration for your +# system. +# +# When considering a fixed syscall_buf_size_preset and a fixed buffer dimension: +# - Increasing this configs value results in lower number of buffers and you can +# speed up your system and reduce memory usage +# - However, using too few buffers may increase contention in the kernel, +# leading to a slowdown. +# +# If you have low event throughputs and minimal drops, reducing the number of +# buffers (higher `cpus_for_each_buffer`) can lower the memory footprint. +# engine: kind: kmod kmod: @@ -181,7 +322,7 @@ engine: buf_size_preset: 4 drop_failed_exit: false modern-ebpf: - cpus_for_each_buffer: 2 ## todo! rename it without syscall + cpus_for_each_buffer: 2 buf_size_preset: 4 drop_failed_exit: false replay: @@ -826,7 +967,9 @@ metrics: # [DEPRECATED] `syscall_buf_size_preset` # -# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.buf_size_preset +# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.buf_size_preset. +# This config is evaluated only if the default `engine` config block is not changed, +# otherwise it is ignored. # # --- [Description] # @@ -879,7 +1022,10 @@ metrics: syscall_buf_size_preset: 4 # [DEPRECATED] `syscall_drop_failed_exit` -# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.drop_failed_exit +# +# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.drop_failed_exit. +# This config is evaluated only if the default `engine` config block is not changed, +# otherwise it is ignored. # # Enabling this option in Falco allows it to drop failed system call exit events # in the kernel drivers before pushing them onto the ring buffer. This @@ -1006,7 +1152,9 @@ base_syscalls: # [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only # -# Deprecated in favor of engine.modern-ebpf.cpus_for_each_syscall_buffer +# Deprecated in favor of engine.modern-ebpf.cpus_for_each_buffer. +# This config is evaluated only if the default `engine` config block is not changed, +# otherwise it is ignored. # # --- [Description] # From 38927692299d891cd4efc19918010ced37355b8e Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 18 Nov 2023 23:45:58 +0100 Subject: [PATCH 18/29] tests: call the callback `action` only once moreover this commit corrects `cpus_for_each_syscall_buffer` into test configs Signed-off-by: Andrea Terzolo --- unit_tests/falco/app/actions/app_action_helpers.h | 4 ++-- unit_tests/falco/app/actions/test_load_config.cpp | 12 +++++------- .../test_configs/new_engine_config_changed.yaml | 2 +- .../test_configs/new_engine_config_unchanged.yaml | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/unit_tests/falco/app/actions/app_action_helpers.h b/unit_tests/falco/app/actions/app_action_helpers.h index 7467efee433..cd79ffd0c8d 100644 --- a/unit_tests/falco/app/actions/app_action_helpers.h +++ b/unit_tests/falco/app/actions/app_action_helpers.h @@ -19,5 +19,5 @@ limitations under the License. #include #include -#define EXPECT_ACTION_OK(r) { EXPECT_TRUE(r.success); EXPECT_TRUE(r.proceed); EXPECT_EQ(r.errstr, ""); } -#define EXPECT_ACTION_FAIL(r) { EXPECT_FALSE(r.success); EXPECT_FALSE(r.proceed); EXPECT_NE(r.errstr, ""); } +#define EXPECT_ACTION_OK(r) { auto result = r; EXPECT_TRUE(result.success); EXPECT_TRUE(result.proceed); EXPECT_EQ(result.errstr, ""); } +#define EXPECT_ACTION_FAIL(r) { auto result = r; EXPECT_FALSE(result.success); EXPECT_FALSE(result.proceed); EXPECT_NE(result.errstr, ""); } diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index f1a1c22ac7b..30e3b92e12c 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -18,14 +18,12 @@ limitations under the License. #include "app_action_helpers.h" #include "falco_test_var.h" -auto action = falco::app::actions::load_config; TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed) { falco::app::state s = {}; s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED; - // TODO: understand why load_yaml is called more times - EXPECT_ACTION_OK(action(s)); + EXPECT_ACTION_OK(falco::app::actions::load_config(s)); // Check that the engine is the kmod EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD); @@ -61,7 +59,7 @@ TEST(ActionLoadConfig, check_command_line_options_are_not_used) falco::app::state s; s.options.modern_bpf = true; s.options.conf_filename = NEW_ENGINE_CONFIG_CHANGED; - EXPECT_ACTION_OK(action(s)); + EXPECT_ACTION_OK(falco::app::actions::load_config(s)); // Check that the engine is the kmod EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD); @@ -95,7 +93,7 @@ TEST(ActionLoadConfig, check_kmod_with_syscall_configs) { falco::app::state s; s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; - EXPECT_ACTION_OK(action(s)); + EXPECT_ACTION_OK(falco::app::actions::load_config(s)); // Check that the engine is the kmod EXPECT_TRUE(s.config->m_engine_mode == engine_kind_t::KMOD); @@ -132,7 +130,7 @@ TEST(ActionLoadConfig, check_override_command_line_modern) // config is unchanged s.options.modern_bpf = true; s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; - EXPECT_ACTION_OK(action(s)); + EXPECT_ACTION_OK(falco::app::actions::load_config(s)); // Check that the engine is the kmod EXPECT_TRUE(s.is_modern_ebpf()); @@ -170,7 +168,7 @@ TEST(ActionLoadConfig, check_override_command_line_gvisor) // config is unchanged s.options.gvisor_config = "config"; s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; - EXPECT_ACTION_OK(action(s)); + EXPECT_ACTION_OK(falco::app::actions::load_config(s)); // Check that the engine is the kmod EXPECT_TRUE(s.is_gvisor()); diff --git a/unit_tests/falco/test_configs/new_engine_config_changed.yaml b/unit_tests/falco/test_configs/new_engine_config_changed.yaml index e0db0d74b3b..a22875738a8 100644 --- a/unit_tests/falco/test_configs/new_engine_config_changed.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_changed.yaml @@ -49,4 +49,4 @@ syscall_buf_size_preset: 6 syscall_drop_failed_exit: true modern_bpf: - cpus_for_each_buffer: 7 + cpus_for_each_syscall_buffer: 7 diff --git a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml index bb21b2e5c44..f262f6031bb 100644 --- a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml @@ -50,4 +50,4 @@ syscall_buf_size_preset: 6 syscall_drop_failed_exit: true modern_bpf: - cpus_for_each_buffer: 3 + cpus_for_each_syscall_buffer: 3 From 1eb6375b80289c33b0f5a8a71f802e3a536c029e Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sat, 18 Nov 2023 23:46:52 +0100 Subject: [PATCH 19/29] docs: fix some docs Signed-off-by: Andrea Terzolo --- falco.yaml | 6 +++--- .../falco/app/actions/configure_syscall_buffer_size.cpp | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/falco.yaml b/falco.yaml index 601f528d393..8c71bc3c80f 100644 --- a/falco.yaml +++ b/falco.yaml @@ -290,8 +290,8 @@ rules_file: # BUFFERs 0 0 0 0 0 0 0 # # Moreover, you have the option to combine this parameter with -# `syscall_buf_size_preset` index. For instance, you can create a large shared -# syscall buffer of 512 MB (using syscall_buf_size_preset=10) that is +# `buf_size_preset` index. For instance, you can create a large shared +# syscall buffer of 512 MB (using buf_size_preset=10) that is # allocated among all the online CPUs. # # --- [Suggestions] @@ -302,7 +302,7 @@ rules_file: # the flexibility to experiment and find the optimal configuration for your # system. # -# When considering a fixed syscall_buf_size_preset and a fixed buffer dimension: +# When considering a fixed buf_size_preset and a fixed buffer dimension: # - Increasing this configs value results in lower number of buffers and you can # speed up your system and reduce memory usage # - However, using too few buffers may increase contention in the kernel, diff --git a/userspace/falco/app/actions/configure_syscall_buffer_size.cpp b/userspace/falco/app/actions/configure_syscall_buffer_size.cpp index 7e6c2a82c9d..ca1cdae70ee 100644 --- a/userspace/falco/app/actions/configure_syscall_buffer_size.cpp +++ b/userspace/falco/app/actions/configure_syscall_buffer_size.cpp @@ -36,7 +36,7 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco: } if(index < MIN_INDEX || index > MAX_INDEX) { - return run_result::fatal("The 'syscall_buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n"); + return run_result::fatal("The 'buf_size_preset' value must be between '" + std::to_string(MIN_INDEX) + "' and '" + std::to_string(MAX_INDEX) + "'\n"); } /* Sizes from `1 MB` to `512 MB`. The index `0` is reserved, users cannot use it! */ @@ -56,13 +56,13 @@ falco::app::run_result falco::app::actions::configure_syscall_buffer_size(falco: /* Check if the chosen size is a multiple of the page size. */ if(chosen_size % page_size != 0) { - return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not a multiple of your system page size '" + std::to_string(page_size) + "'. Please configure a greater 'syscall_buf_size_preset' value in the Falco configuration file\n"); + return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not a multiple of your system page size '" + std::to_string(page_size) + "'. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n"); } /* Check if the chosen size is greater than `2 * page_size`. */ if((chosen_size / page_size) <= 2) { - return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "' where '" + std::to_string(page_size) + "' is your system page size. Please configure a greater 'syscall_buf_size_preset' value in the Falco configuration file\n"); + return run_result::fatal("The chosen syscall buffer size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "' where '" + std::to_string(page_size) + "' is your system page size. Please configure a greater 'buf_size_preset' value in the Falco configuration file\n"); } s.syscall_buffer_bytes_size = chosen_size; From edb6e7cad8f5197f886fa30ff316baa7d638a3c0 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sun, 19 Nov 2023 00:17:25 +0100 Subject: [PATCH 20/29] docs: add a comment on missing config files Signed-off-by: Andrea Terzolo --- userspace/falco/app/actions/load_config.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 1fe2da64b20..464cbaa0084 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -86,6 +86,9 @@ falco::app::run_result falco::app::actions::load_config(falco::app::state& s) } else { + // Is possible to have an empty config file when we want to use some command line + // options like `--help`, `--version`, ... + // The configs used in `load_yaml` will be initialized to the default values. s.config->init(s.options.cmdline_config_options); } } From dd9a1dd5eaf1aaa9478b1e4d2bc63631f8435dee Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sun, 19 Nov 2023 11:48:14 +0100 Subject: [PATCH 21/29] docs: fix codespell Signed-off-by: Andrea Terzolo --- unit_tests/falco/app/actions/test_load_config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index 30e3b92e12c..b9591e3aa5f 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -126,7 +126,7 @@ TEST(ActionLoadConfig, check_kmod_with_syscall_configs) TEST(ActionLoadConfig, check_override_command_line_modern) { falco::app::state s; - // The comman line options should be correctly applied since the + // The command line options should be correctly applied since the // config is unchanged s.options.modern_bpf = true; s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; @@ -164,7 +164,7 @@ TEST(ActionLoadConfig, check_override_command_line_modern) TEST(ActionLoadConfig, check_override_command_line_gvisor) { falco::app::state s; - // The comman line options should be correctly applied since the + // The command line options should be correctly applied since the // config is unchanged s.options.gvisor_config = "config"; s.options.conf_filename = NEW_ENGINE_CONFIG_UNCHANGED; From e04b910d63d765f80ef0a38ed5ea1768bf89fb2e Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Tue, 21 Nov 2023 10:42:42 +0100 Subject: [PATCH 22/29] test: don't test load config if we are under wasm Signed-off-by: Andrea Terzolo --- unit_tests/falco/app/actions/test_load_config.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index b9591e3aa5f..0a0e78f3d24 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -18,7 +18,7 @@ limitations under the License. #include "app_action_helpers.h" #include "falco_test_var.h" - +#ifndef __EMSCRIPTEN__ TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed) { falco::app::state s = {}; @@ -195,3 +195,4 @@ TEST(ActionLoadConfig, check_override_command_line_gvisor) EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 3); EXPECT_TRUE(s.config->m_syscall_drop_failed_exit); } +#endif From 7b39c8e82ed178be5f54d7ca2a6f9fc1eb9c904c Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Wed, 22 Nov 2023 11:37:30 +0100 Subject: [PATCH 23/29] chore(userspace,unit_tests): renamed `engine.replay.trace_file` to `engine.replay.capture_file`. Signed-off-by: Federico Di Pierro --- falco.yaml | 4 +-- .../falco/app/actions/test_load_config.cpp | 10 +++--- .../new_engine_config_changed.yaml | 2 +- .../new_engine_config_unchanged.yaml | 2 +- .../falco/app/actions/helpers_inspector.cpp | 6 ++-- userspace/falco/app/actions/load_config.cpp | 9 ++++-- userspace/falco/app/options.cpp | 32 ++++--------------- userspace/falco/app/options.h | 2 +- userspace/falco/configuration.cpp | 6 ++-- userspace/falco/configuration.h | 2 +- 10 files changed, 30 insertions(+), 45 deletions(-) diff --git a/falco.yaml b/falco.yaml index 8c71bc3c80f..43d1cdcdbd6 100644 --- a/falco.yaml +++ b/falco.yaml @@ -326,8 +326,8 @@ engine: buf_size_preset: 4 drop_failed_exit: false replay: - # path to the trace file to replay. - trace_file: /path/to/file.scap + # path to the capture file to replay. + capture_file: /path/to/file.scap gvisor: # A Falco-compatible configuration file can be generated with # '--gvisor-generate-config' and utilized for both runsc and Falco. diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index 0a0e78f3d24..51181e7f531 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -41,7 +41,7 @@ TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed) EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); - EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + EXPECT_TRUE(s.config->m_replay.m_capture_file.empty()); EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); @@ -77,7 +77,7 @@ TEST(ActionLoadConfig, check_command_line_options_are_not_used) EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); - EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + EXPECT_TRUE(s.config->m_replay.m_capture_file.empty()); EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); @@ -112,7 +112,7 @@ TEST(ActionLoadConfig, check_kmod_with_syscall_configs) EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); - EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + EXPECT_TRUE(s.config->m_replay.m_capture_file.empty()); EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); @@ -150,7 +150,7 @@ TEST(ActionLoadConfig, check_override_command_line_modern) EXPECT_EQ(s.config->m_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_ebpf.m_drop_failed_exit); - EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + EXPECT_TRUE(s.config->m_replay.m_capture_file.empty()); EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); @@ -188,7 +188,7 @@ TEST(ActionLoadConfig, check_override_command_line_gvisor) EXPECT_EQ(s.config->m_modern_ebpf.m_buf_size_preset, 0); EXPECT_FALSE(s.config->m_modern_ebpf.m_drop_failed_exit); - EXPECT_TRUE(s.config->m_replay.m_trace_file.empty()); + EXPECT_TRUE(s.config->m_replay.m_capture_file.empty()); // Check that deprecated configs are populated EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6); diff --git a/unit_tests/falco/test_configs/new_engine_config_changed.yaml b/unit_tests/falco/test_configs/new_engine_config_changed.yaml index a22875738a8..db10a982e36 100644 --- a/unit_tests/falco/test_configs/new_engine_config_changed.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_changed.yaml @@ -34,7 +34,7 @@ engine: buf_size_preset: 4 drop_failed_exit: false replay: - trace_file: /path/to/file.scap + capture_file: /path/to/file.scap gvisor: config: /path/to/gvisor_config.yaml root: "" diff --git a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml index f262f6031bb..f5db54c8870 100644 --- a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml @@ -35,7 +35,7 @@ engine: buf_size_preset: 4 drop_failed_exit: false replay: - trace_file: /path/to/file.scap + capture_file: /path/to/file.scap gvisor: config: /path/to/gvisor_config.yaml root: "" diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 80c4113d4e0..66cf62d065f 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -35,13 +35,13 @@ falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::s { try { - s.offline_inspector->open_savefile(s.config->m_replay.m_trace_file); - falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.config->m_replay.m_trace_file + "\n"); + s.offline_inspector->open_savefile(s.config->m_replay.m_capture_file); + falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.config->m_replay.m_capture_file + "\n"); return run_result::ok(); } catch (sinsp_exception &e) { - return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_trace_file + " for reading: " + e.what()); + return run_result::fatal("Could not open trace filename " + s.config->m_replay.m_capture_file + " for reading: " + e.what()); } } diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 464cbaa0084..f76bda8f5ab 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -46,6 +46,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) // use the requested driver. if (getenv(FALCO_BPF_ENV_VARIABLE)) { + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::EBPF; s.config->m_ebpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE); s.config->m_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; @@ -53,6 +54,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) } else if (s.options.modern_bpf) { + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--modern-bpf' cmdline option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; s.config->m_modern_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; s.config->m_modern_ebpf.m_buf_size_preset = s.config->m_syscall_buf_size_preset; @@ -60,18 +62,21 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) } if (!s.options.gvisor_config.empty()) { + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-g,--gvisor-config' cmdline option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::GVISOR; s.config->m_gvisor.m_config = s.options.gvisor_config; s.config->m_gvisor.m_root = s.options.gvisor_root; } if (s.options.nodriver) { + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--nodriver' cmdline option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::NONE; } - if (!s.options.trace_filename.empty()) + if (!s.options.capture_file.empty()) { + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-e' cmdline option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::REPLAY; - s.config->m_replay.m_trace_file = s.options.trace_filename; + s.config->m_replay.m_capture_file = s.options.capture_file; } return run_result::ok(); } diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index 9416b09b593..3159fb45691 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -144,31 +144,11 @@ bool options::parse(int argc, char **argv, std::string &errstr) // TODO: remove for Falco 0.38 since these CLI options are deprecated. int open_modes = 0; - if (!trace_filename.empty()) - { - open_modes++; - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-e' cmdline option is deprecated and will be removed in Falco 0.38!\n"); - } - if (!gvisor_config.empty()) - { - open_modes++; - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-g,--gvisor-config' cmdline option is deprecated and will be removed in Falco 0.38!\n"); - } - if(getenv("FALCO_BPF_PROBE") != NULL) - { - open_modes++; - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable is deprecated and will be removed in Falco 0.38!\n"); - } - if (modern_bpf) - { - open_modes++; - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--modern-bpf' cmdline option is deprecated and will be removed in Falco 0.38!\n"); - } - if (nodriver) - { - open_modes++; - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--nodriver' cmdline option is deprecated and will be removed in Falco 0.38!\n"); - } + open_modes += !capture_file.empty(); + open_modes += !gvisor_config.empty(); + open_modes += modern_bpf; + open_modes += getenv("FALCO_BPF_PROBE") != NULL; + open_modes += nodriver; if (open_modes > 1) { errstr = std::string("You can not specify more than one of -e, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var"); @@ -201,7 +181,7 @@ void options::define(cxxopts::Options& opts) ("disable-source", "Turn off a specific . By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times, but turning off all event sources simultaneously is not permitted. This option can not be mixed with --enable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(disable_sources), "") ("dry-run", "Run Falco without processing events. It can help check that the configuration and rules do not have any errors.", cxxopts::value(dry_run)->default_value("false")) ("D", "Turn off any rules with names having the substring . This option can be passed multiple times. It cannot be mixed with -t.", cxxopts::value(disabled_rule_substrings), "") - ("e", "DEPRECATED. Reproduce the events by reading from the given instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(trace_filename), "") + ("e", "DEPRECATED. Reproduce the events by reading from the given instead of opening a live session. Only capture files in .scap format are supported.", cxxopts::value(capture_file), "") ("enable-source", "Enable a specific . By default, all loaded sources get enabled. Available sources are 'syscall' plus all sources defined by loaded plugins supporting the event sourcing capability. This option can be passed multiple times. When using this option, only the event sources specified by it will be enabled. This option can not be mixed with --disable-source. This option has no effect when reproducing events from a capture file.", cxxopts::value(enable_sources), "") #ifdef HAS_GVISOR ("g,gvisor-config", "DEPRECATED. Collect 'syscall' events from gVisor using the specified file. A Falco-compatible configuration file can be generated with --gvisor-generate-config and utilized for both runsc and Falco.", cxxopts::value(gvisor_config), "") diff --git a/userspace/falco/app/options.h b/userspace/falco/app/options.h index cf19f15d406..4a568e3d801 100644 --- a/userspace/falco/app/options.h +++ b/userspace/falco/app/options.h @@ -76,7 +76,7 @@ class options { bool dry_run; // todo!: remove them in Falco 0.38.0 since they are deprecated - std::string trace_filename = ""; + std::string capture_file = ""; std::string gvisor_config = ""; std::string gvisor_root = ""; bool modern_bpf = false; diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 813d0817add..e2af000d5e4 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -164,10 +164,10 @@ void falco_configuration::load_engine_config(const std::string& config_name, con m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed_exit", default_drop_failed_exit); break; case engine_kind_t::REPLAY: - m_replay.m_trace_file = config.get_scalar("engine.replay.trace_file", ""); - if (m_replay.m_trace_file.empty()) + m_replay.m_capture_file = config.get_scalar("engine.replay.capture_file", ""); + if (m_replay.m_capture_file.empty()) { - throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'replay' but no engine.replay.trace_file specified."); + throw std::logic_error("Error reading config file (" + config_name + "): engine.kind is 'replay' but no engine.replay.capture_file specified."); } break; case engine_kind_t::GVISOR: diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index c72a07bf11f..e5fa270155e 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -81,7 +81,7 @@ class falco_configuration typedef struct { public: - std::string m_trace_file; + std::string m_capture_file; } replay_config; typedef struct { From 8f3edccf63e12b50c817f8efe524b8f842f4ab09 Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Thu, 23 Nov 2023 15:56:38 +0100 Subject: [PATCH 24/29] chore(userspace): small round of review-induced fixes. Also, properly warn the user that deprecated CLI options will be ignored when the new `engine` configuration key is in use. Signed-off-by: Federico Di Pierro --- falco.yaml | 8 ++++---- userspace/falco/app/actions/helpers_inspector.cpp | 2 +- userspace/falco/app/actions/load_config.cpp | 11 +++++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/falco.yaml b/falco.yaml index 43d1cdcdbd6..ec7cfa46a16 100644 --- a/falco.yaml +++ b/falco.yaml @@ -318,7 +318,7 @@ engine: drop_failed_exit: false ebpf: # path to the elf file to load. - probe: /path/to/probe.o + probe: /root/.falco/falco-bpf.o buf_size_preset: 4 drop_failed_exit: false modern-ebpf: @@ -326,12 +326,12 @@ engine: buf_size_preset: 4 drop_failed_exit: false replay: - # path to the capture file to replay. - capture_file: /path/to/file.scap + # path to the capture file to replay (eg: /path/to/file.scap) + capture_file: "" gvisor: # A Falco-compatible configuration file can be generated with # '--gvisor-generate-config' and utilized for both runsc and Falco. - config: /path/to/gvisor_config.yaml + config: "" # Set gVisor root directory for storage of container state when used # in conjunction with 'gvisor.config'. The 'gvisor.root' to be passed # is the one usually passed to 'runsc --root' flag. diff --git a/userspace/falco/app/actions/helpers_inspector.cpp b/userspace/falco/app/actions/helpers_inspector.cpp index 66cf62d065f..5d1471d4631 100644 --- a/userspace/falco/app/actions/helpers_inspector.cpp +++ b/userspace/falco/app/actions/helpers_inspector.cpp @@ -36,7 +36,7 @@ falco::app::run_result falco::app::actions::open_offline_inspector(falco::app::s try { s.offline_inspector->open_savefile(s.config->m_replay.m_capture_file); - falco_logger::log(falco_logger::level::INFO, "Reading system call events from file: " + s.config->m_replay.m_capture_file + "\n"); + falco_logger::log(falco_logger::level::INFO, "Replaying events from the capture file: " + s.config->m_replay.m_capture_file + "\n"); return run_result::ok(); } catch (sinsp_exception &e) diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index f76bda8f5ab..a8a32dfb79f 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -33,6 +33,9 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) // at least one change in the default config we don't allow to use the command line options. if(s.config->m_changes_in_engine_config) { + falco_logger::log(falco_logger::level::WARNING, + "Since the new 'engine' config key is being used, deprecated CLI options " + "[-e,-g,--gvisor-config,--nodriver,--modern-bpf] and FALCO_BPF_PROBE environment variable will be ignored.\n"); return run_result::ok(); } @@ -54,7 +57,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) } else if (s.options.modern_bpf) { - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--modern-bpf' cmdline option is deprecated and will be removed in Falco 0.38!\n"); + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--modern-bpf' command line option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::MODERN_EBPF; s.config->m_modern_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; s.config->m_modern_ebpf.m_buf_size_preset = s.config->m_syscall_buf_size_preset; @@ -62,19 +65,19 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) } if (!s.options.gvisor_config.empty()) { - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-g,--gvisor-config' cmdline option is deprecated and will be removed in Falco 0.38!\n"); + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-g,--gvisor-config' command line option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::GVISOR; s.config->m_gvisor.m_config = s.options.gvisor_config; s.config->m_gvisor.m_root = s.options.gvisor_root; } if (s.options.nodriver) { - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--nodriver' cmdline option is deprecated and will be removed in Falco 0.38!\n"); + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '--nodriver' command line option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::NONE; } if (!s.options.capture_file.empty()) { - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-e' cmdline option is deprecated and will be removed in Falco 0.38!\n"); + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the '-e' command line option is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::REPLAY; s.config->m_replay.m_capture_file = s.options.capture_file; } From 231e13492af6886eeef5d2c33a21cedfdbf2ee75 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Thu, 23 Nov 2023 18:50:22 +0100 Subject: [PATCH 25/29] cleanup: move some macros inside a shared file These macros will be used by other files so we need to share them Signed-off-by: Andrea Terzolo --- userspace/falco/app/actions/load_config.cpp | 2 ++ userspace/falco/configuration.cpp | 37 +++++++++------------ userspace/falco/configuration.h | 11 ++++-- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index a8a32dfb79f..9860c06ac13 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -17,6 +17,8 @@ limitations under the License. #include "actions.h" #include "falco_utils.h" +// USED just to include some shared macros, remove this include in Falco 0.38.0 +#include "configuration.h" /* DEPRECATED: we will remove it in Falco 0.38. */ #define FALCO_BPF_ENV_VARIABLE "FALCO_BPF_PROBE" diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index e2af000d5e4..9f39747ff9d 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -114,10 +114,6 @@ void falco_configuration::load_engine_config(const std::string& config_name, con {"none",engine_kind_t::NONE}, }; - constexpr int16_t default_buf_size_preset = 4; - constexpr int16_t default_cpus_for_each_syscall_buffer = 2; - constexpr bool default_drop_failed_exit = false; - auto driver_mode_str = config.get_scalar("engine.kind", "kmod"); if (engine_mode_lut.find(driver_mode_str) != engine_mode_lut.end()) { @@ -131,21 +127,16 @@ void falco_configuration::load_engine_config(const std::string& config_name, con switch (m_engine_mode) { case engine_kind_t::KMOD: - m_kmod.m_buf_size_preset = config.get_scalar("engine.kmod.buf_size_preset", default_buf_size_preset); - m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed_exit", default_drop_failed_exit); + m_kmod.m_buf_size_preset = config.get_scalar("engine.kmod.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); + m_kmod.m_drop_failed_exit = config.get_scalar("engine.kmod.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); - if(m_kmod.m_buf_size_preset == default_buf_size_preset && m_kmod.m_drop_failed_exit==default_drop_failed_exit) + if(m_kmod.m_buf_size_preset == DEFAULT_BUF_SIZE_PRESET && m_kmod.m_drop_failed_exit==DEFAULT_DROP_FAILED_EXIT) { // This could happen in 2 cases: // 1. The user doesn't use the new config (it could also have commented it) // 2. The user uses the new config unchanged. // In these 2 cases the users are allowed to use the command line arguments to open an engine m_changes_in_engine_config = false; - - // Catch deprecated values from the config, to use them with the command line if needed - m_syscall_buf_size_preset = config.get_scalar("syscall_buf_size_preset", default_buf_size_preset); - m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", default_cpus_for_each_syscall_buffer); - m_syscall_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", default_drop_failed_exit); return; } @@ -155,13 +146,13 @@ void falco_configuration::load_engine_config(const std::string& config_name, con // to be done once we drop the CLI option otherwise we would need to make the check twice, // once here, and once when we merge the CLI options in the config file. m_ebpf.m_probe_path = config.get_scalar("engine.ebpf.probe", ""); - m_ebpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", default_buf_size_preset); - m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed_exit", default_drop_failed_exit); + m_ebpf.m_buf_size_preset = config.get_scalar("engine.ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); + m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); break; case engine_kind_t::MODERN_EBPF: - m_modern_ebpf.m_cpus_for_each_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_buffer", default_cpus_for_each_syscall_buffer); - m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", default_buf_size_preset); - m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed_exit", default_drop_failed_exit); + m_modern_ebpf.m_cpus_for_each_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); + m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); + m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); break; case engine_kind_t::REPLAY: m_replay.m_capture_file = config.get_scalar("engine.replay.capture_file", ""); @@ -184,12 +175,14 @@ void falco_configuration::load_engine_config(const std::string& config_name, con } // If we arrive here it means we have at least one change in the `engine` config. - // Please note that `load_config` is called more than one time during initialization - // so the last time wins + // Please note that `load_config` could be called more than one time during initialization + // so the last time wins, the load config phase should be idempotent m_changes_in_engine_config = true; - m_syscall_buf_size_preset = 0; - m_cpus_for_each_syscall_buffer = 0; - m_syscall_drop_failed_exit = false; + + // Catch deprecated values from the config, to use them with the command line if needed + m_syscall_buf_size_preset = config.get_scalar("syscall_buf_size_preset", DEFAULT_BUF_SIZE_PRESET); + m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); + m_syscall_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); } void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index e5fa270155e..85f06e2d1e7 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -37,6 +37,11 @@ limitations under the License. #include "event_drops.h" #include "falco_outputs.h" +// todo!: remove them in Falco 0.38.0 +#define DEFAULT_BUF_SIZE_PRESET 4 +#define DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER 2 +#define DEFAULT_DROP_FAILED_EXIT false + enum class engine_kind_t : uint8_t { KMOD, @@ -172,10 +177,10 @@ class falco_configuration // used to keep track if the `engine` config is used. bool m_changes_in_engine_config = false; // Index corresponding to the syscall buffer dimension. - uint16_t m_syscall_buf_size_preset = 0; + uint16_t m_syscall_buf_size_preset = DEFAULT_BUF_SIZE_PRESET; // Number of CPUs associated with a single ring buffer. - uint16_t m_cpus_for_each_syscall_buffer = 0; - bool m_syscall_drop_failed_exit = false; + uint16_t m_cpus_for_each_syscall_buffer = DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER; + bool m_syscall_drop_failed_exit = DEFAULT_DROP_FAILED_EXIT; private: void load_yaml(const std::string& config_name, const yaml_helper& config); From 4b083bb5aabadce2bb4678438edd28983e1a8612 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Thu, 23 Nov 2023 19:14:24 +0100 Subject: [PATCH 26/29] new: add some deprecation warnings Signed-off-by: Andrea Terzolo --- userspace/falco/app/actions/load_config.cpp | 53 ++++++++++++++++++++- userspace/falco/app/options.cpp | 13 ----- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 9860c06ac13..2b604967378 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -29,18 +29,69 @@ using namespace falco::app::actions; // applies legacy/in-deprecation options to the current state static falco::app::run_result apply_deprecated_options(falco::app::state& s) { + // Check that at most one command line option is provided + int open_modes = 0; + open_modes += !s.options.capture_file.empty(); + open_modes += !s.options.gvisor_config.empty(); + open_modes += s.options.modern_bpf; + open_modes += getenv(FALCO_BPF_ENV_VARIABLE) != NULL; + open_modes += s.options.nodriver; + if(open_modes > 1) + { + return run_result::fatal("You can not specify more than one of -e, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var"); + } + // Please note: is not possible to mix command line options and configs to obtain a configuration // we need to use only one method. For example, is not possible to set the gvisor-config through // the command line and the gvisor-root through the config file. For this reason, if we detect // at least one change in the default config we don't allow to use the command line options. if(s.config->m_changes_in_engine_config) { - falco_logger::log(falco_logger::level::WARNING, + // If a command line option is specified, print a warning because it will be ignored + if(open_modes == 1) + { + falco_logger::log(falco_logger::level::WARNING, "Since the new 'engine' config key is being used, deprecated CLI options " "[-e,-g,--gvisor-config,--nodriver,--modern-bpf] and FALCO_BPF_PROBE environment variable will be ignored.\n"); + } + + // If these configs are specified, print a warning because they will be ignored + if(s.config->m_syscall_drop_failed_exit != DEFAULT_DROP_FAILED_EXIT) + { + falco_logger::log(falco_logger::level::WARNING, + "Since the new 'engine' config key is being used, deprecated config 'syscall_drop_failed_exit' will be ignored.\n"); + } + if(s.config->m_syscall_buf_size_preset != DEFAULT_BUF_SIZE_PRESET) + { + falco_logger::log(falco_logger::level::WARNING, + "Since the new 'engine' config key is being used, deprecated config 'syscall_buf_size_preset' will be ignored.\n"); + } + if(s.config->m_cpus_for_each_syscall_buffer != DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER) + { + falco_logger::log(falco_logger::level::WARNING, + "Since the new 'engine' config key is being used, deprecated config 'modern_bpf.cpus_for_each_syscall_buffer' will be ignored.\n"); + } return run_result::ok(); } + // These warnings are similar to the ones above, but in this case, the configs are not ignored + // they are just deprecated + if(s.config->m_syscall_drop_failed_exit != DEFAULT_DROP_FAILED_EXIT) + { + falco_logger::log(falco_logger::level::WARNING, + "DEPRECATION NOTICE: 'syscall_drop_failed_exit' config is deprecated and will be removed in Falco 0.38! Use `engine..drop_failed_exit' config instead\n"); + } + if(s.config->m_syscall_buf_size_preset != DEFAULT_BUF_SIZE_PRESET) + { + falco_logger::log(falco_logger::level::WARNING, + "DEPRECATION NOTICE: 'syscall_buf_size_preset' config is deprecated and will be removed in Falco 0.38! Use `engine..buf_size_preset' config instead\n"); + } + if(s.config->m_cpus_for_each_syscall_buffer != DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER) + { + falco_logger::log(falco_logger::level::WARNING, + "DEPRECATION NOTICE: 'modern_bpf.cpus_for_each_syscall_buffer' config is deprecated and will be removed in Falco 0.38! Use `engine.modern-ebpf.cpus_for_each_buffer' config instead\n"); + } + // Replace the kmod default values in case the engine was open with the kmod. // We don't have a command line option to open the kmod so we have to always enforce the // default values. diff --git a/userspace/falco/app/options.cpp b/userspace/falco/app/options.cpp index 3159fb45691..f3d8a714af9 100644 --- a/userspace/falco/app/options.cpp +++ b/userspace/falco/app/options.cpp @@ -142,19 +142,6 @@ bool options::parse(int argc, char **argv, std::string &errstr) list_fields = m_cmdline_parsed.count("list") > 0; - // TODO: remove for Falco 0.38 since these CLI options are deprecated. - int open_modes = 0; - open_modes += !capture_file.empty(); - open_modes += !gvisor_config.empty(); - open_modes += modern_bpf; - open_modes += getenv("FALCO_BPF_PROBE") != NULL; - open_modes += nodriver; - if (open_modes > 1) - { - errstr = std::string("You can not specify more than one of -e, -g (--gvisor-config), --modern-bpf, --nodriver, and the FALCO_BPF_PROBE env var"); - return false; - } - return true; } From 0c2f8c09d2226f1141dd6e66c55cc86cb10b1576 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Thu, 23 Nov 2023 19:43:08 +0100 Subject: [PATCH 27/29] fix: fix some broken tests Signed-off-by: Andrea Terzolo --- .../falco/app/actions/test_load_config.cpp | 18 ++++++++---------- userspace/falco/configuration.cpp | 10 +++++----- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/unit_tests/falco/app/actions/test_load_config.cpp b/unit_tests/falco/app/actions/test_load_config.cpp index 51181e7f531..78b55022abd 100644 --- a/unit_tests/falco/app/actions/test_load_config.cpp +++ b/unit_tests/falco/app/actions/test_load_config.cpp @@ -46,11 +46,10 @@ TEST(ActionLoadConfig, check_engine_config_is_correctly_parsed) EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); - // Check that deprecated configs are not populated since we are using - // the new config. - EXPECT_EQ(s.config->m_syscall_buf_size_preset, 0); - EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 0); - EXPECT_FALSE(s.config->m_syscall_drop_failed_exit); + // Check that deprecated configs are always set since + EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6); + EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 7); + EXPECT_TRUE(s.config->m_syscall_drop_failed_exit); } // Equal to the one above but checks that the command line options are not parsed @@ -82,11 +81,10 @@ TEST(ActionLoadConfig, check_command_line_options_are_not_used) EXPECT_TRUE(s.config->m_gvisor.m_config.empty()); EXPECT_TRUE(s.config->m_gvisor.m_root.empty()); - // Check that deprecated configs are not populated since we are using - // the new config. - EXPECT_EQ(s.config->m_syscall_buf_size_preset, 0); - EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 0); - EXPECT_FALSE(s.config->m_syscall_drop_failed_exit); + // Check that deprecated configs are always set since + EXPECT_EQ(s.config->m_syscall_buf_size_preset, 6); + EXPECT_EQ(s.config->m_cpus_for_each_syscall_buffer, 7); + EXPECT_TRUE(s.config->m_syscall_drop_failed_exit); } TEST(ActionLoadConfig, check_kmod_with_syscall_configs) diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 9f39747ff9d..c89f8c6b307 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -124,6 +124,11 @@ void falco_configuration::load_engine_config(const std::string& config_name, con throw std::logic_error("Error reading config file (" + config_name + "): engine.kind '"+ driver_mode_str + "' is not a valid kind."); } + // Catch deprecated values from the config, to use them with the command line if needed + m_syscall_buf_size_preset = config.get_scalar("syscall_buf_size_preset", DEFAULT_BUF_SIZE_PRESET); + m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); + m_syscall_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); + switch (m_engine_mode) { case engine_kind_t::KMOD: @@ -178,11 +183,6 @@ void falco_configuration::load_engine_config(const std::string& config_name, con // Please note that `load_config` could be called more than one time during initialization // so the last time wins, the load config phase should be idempotent m_changes_in_engine_config = true; - - // Catch deprecated values from the config, to use them with the command line if needed - m_syscall_buf_size_preset = config.get_scalar("syscall_buf_size_preset", DEFAULT_BUF_SIZE_PRESET); - m_cpus_for_each_syscall_buffer = config.get_scalar("modern_bpf.cpus_for_each_syscall_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); - m_syscall_drop_failed_exit = config.get_scalar("syscall_drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); } void falco_configuration::load_yaml(const std::string& config_name, const yaml_helper& config) From 3dc8dadc1a872a74782129772e45c95a6b19a5ea Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Thu, 23 Nov 2023 19:50:03 +0100 Subject: [PATCH 28/29] docs: improve a log Signed-off-by: Andrea Terzolo --- userspace/falco/app/actions/load_config.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 2b604967378..2efce5f7d4e 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -52,7 +52,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) { falco_logger::log(falco_logger::level::WARNING, "Since the new 'engine' config key is being used, deprecated CLI options " - "[-e,-g,--gvisor-config,--nodriver,--modern-bpf] and FALCO_BPF_PROBE environment variable will be ignored.\n"); + "[-e,-g,--gvisor-config,--nodriver,--modern-bpf] and 'FALCO_BPF_PROBE' environment variable will be ignored.\n"); } // If these configs are specified, print a warning because they will be ignored @@ -102,7 +102,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) // use the requested driver. if (getenv(FALCO_BPF_ENV_VARIABLE)) { - falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the FALCO_BPF_PROBE environment variable is deprecated and will be removed in Falco 0.38!\n"); + falco_logger::log(falco_logger::level::WARNING, "DEPRECATION NOTICE: the 'FALCO_BPF_PROBE' environment variable is deprecated and will be removed in Falco 0.38!\n"); s.config->m_engine_mode = engine_kind_t::EBPF; s.config->m_ebpf.m_probe_path = getenv(FALCO_BPF_ENV_VARIABLE); s.config->m_ebpf.m_drop_failed_exit = s.config->m_syscall_drop_failed_exit; From 5ea13592df031b6d111ce4edd57b0bb1e85c3c11 Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Fri, 24 Nov 2023 10:35:06 +0100 Subject: [PATCH 29/29] cleanup: rename `modern-ebpf` into `modern_ebpf` Signed-off-by: Andrea Terzolo --- falco.yaml | 12 ++++++------ .../test_configs/new_engine_config_changed.yaml | 2 +- .../test_configs/new_engine_config_unchanged.yaml | 2 +- userspace/falco/app/actions/load_config.cpp | 2 +- userspace/falco/configuration.cpp | 8 ++++---- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/falco.yaml b/falco.yaml index ec7cfa46a16..a89608ccedd 100644 --- a/falco.yaml +++ b/falco.yaml @@ -161,7 +161,7 @@ rules_file: # Available engines: # - `kmod`: Kernel Module (Kernel Module) # - `ebpf`: eBPF (eBPF probe) -# - `modern-ebpf`: Modern eBPF (CO-RE eBPF probe) +# - `modern_ebpf`: Modern eBPF (CO-RE eBPF probe) # - `gvisor`: gVisor (gVisor sandbox) # - `replay`: Replay a scap trace file # - `none`: No event producer loaded, useful to run with plugins. @@ -233,7 +233,7 @@ rules_file: # is important to note that enabling this option also means sacrificing some # visibility into the system. # -################### `cpus_for_each_buffer` (modern-ebpf only) +################### `cpus_for_each_buffer` (modern_ebpf only) # # --- [Description] # @@ -321,7 +321,7 @@ engine: probe: /root/.falco/falco-bpf.o buf_size_preset: 4 drop_failed_exit: false - modern-ebpf: + modern_ebpf: cpus_for_each_buffer: 2 buf_size_preset: 4 drop_failed_exit: false @@ -967,7 +967,7 @@ metrics: # [DEPRECATED] `syscall_buf_size_preset` # -# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.buf_size_preset. +# Deprecated in favor of engine.{kmod,ebpf,modern_ebpf}.buf_size_preset. # This config is evaluated only if the default `engine` config block is not changed, # otherwise it is ignored. # @@ -1023,7 +1023,7 @@ syscall_buf_size_preset: 4 # [DEPRECATED] `syscall_drop_failed_exit` # -# Deprecated in favor of engine.{kmod,ebpf,modern-ebpf}.drop_failed_exit. +# Deprecated in favor of engine.{kmod,ebpf,modern_ebpf}.drop_failed_exit. # This config is evaluated only if the default `engine` config block is not changed, # otherwise it is ignored. # @@ -1152,7 +1152,7 @@ base_syscalls: # [DEPRECATED] `modern_bpf.cpus_for_each_syscall_buffer`, modern_bpf only # -# Deprecated in favor of engine.modern-ebpf.cpus_for_each_buffer. +# Deprecated in favor of engine.modern_ebpf.cpus_for_each_buffer. # This config is evaluated only if the default `engine` config block is not changed, # otherwise it is ignored. # diff --git a/unit_tests/falco/test_configs/new_engine_config_changed.yaml b/unit_tests/falco/test_configs/new_engine_config_changed.yaml index db10a982e36..99962545a60 100644 --- a/unit_tests/falco/test_configs/new_engine_config_changed.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_changed.yaml @@ -29,7 +29,7 @@ engine: probe: /path/to/probe.o buf_size_preset: 4 drop_failed_exit: false - modern-ebpf: + modern_ebpf: cpus_for_each_buffer: 2 buf_size_preset: 4 drop_failed_exit: false diff --git a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml index f5db54c8870..7d0fb870540 100644 --- a/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml +++ b/unit_tests/falco/test_configs/new_engine_config_unchanged.yaml @@ -30,7 +30,7 @@ engine: probe: /path/to/probe.o buf_size_preset: 4 drop_failed_exit: false - modern-ebpf: + modern_ebpf: cpus_for_each_buffer: 2 buf_size_preset: 4 drop_failed_exit: false diff --git a/userspace/falco/app/actions/load_config.cpp b/userspace/falco/app/actions/load_config.cpp index 2efce5f7d4e..60f804d4377 100644 --- a/userspace/falco/app/actions/load_config.cpp +++ b/userspace/falco/app/actions/load_config.cpp @@ -89,7 +89,7 @@ static falco::app::run_result apply_deprecated_options(falco::app::state& s) if(s.config->m_cpus_for_each_syscall_buffer != DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER) { falco_logger::log(falco_logger::level::WARNING, - "DEPRECATION NOTICE: 'modern_bpf.cpus_for_each_syscall_buffer' config is deprecated and will be removed in Falco 0.38! Use `engine.modern-ebpf.cpus_for_each_buffer' config instead\n"); + "DEPRECATION NOTICE: 'modern_bpf.cpus_for_each_syscall_buffer' config is deprecated and will be removed in Falco 0.38! Use `engine.modern_ebpf.cpus_for_each_buffer' config instead\n"); } // Replace the kmod default values in case the engine was open with the kmod. diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index c89f8c6b307..eac6f27e5c1 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -108,7 +108,7 @@ void falco_configuration::load_engine_config(const std::string& config_name, con const std::unordered_map engine_mode_lut = { {"kmod",engine_kind_t::KMOD}, {"ebpf",engine_kind_t::EBPF}, - {"modern-ebpf",engine_kind_t::MODERN_EBPF}, + {"modern_ebpf",engine_kind_t::MODERN_EBPF}, {"replay",engine_kind_t::REPLAY}, {"gvisor",engine_kind_t::GVISOR}, {"none",engine_kind_t::NONE}, @@ -155,9 +155,9 @@ void falco_configuration::load_engine_config(const std::string& config_name, con m_ebpf.m_drop_failed_exit = config.get_scalar("engine.ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); break; case engine_kind_t::MODERN_EBPF: - m_modern_ebpf.m_cpus_for_each_buffer = config.get_scalar("engine.modern-ebpf.cpus_for_each_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); - m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern-ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); - m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern-ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); + m_modern_ebpf.m_cpus_for_each_buffer = config.get_scalar("engine.modern_ebpf.cpus_for_each_buffer", DEFAULT_CPUS_FOR_EACH_SYSCALL_BUFFER); + m_modern_ebpf.m_buf_size_preset = config.get_scalar("engine.modern_ebpf.buf_size_preset", DEFAULT_BUF_SIZE_PRESET); + m_modern_ebpf.m_drop_failed_exit = config.get_scalar("engine.modern_ebpf.drop_failed_exit", DEFAULT_DROP_FAILED_EXIT); break; case engine_kind_t::REPLAY: m_replay.m_capture_file = config.get_scalar("engine.replay.capture_file", "");