From b0b2f05eb5b4308202463ca3f5fbc24e0e10dd3a Mon Sep 17 00:00:00 2001 From: Andrea Terzolo Date: Sun, 18 Sep 2022 22:51:18 +0000 Subject: [PATCH] new: configure syscall buffer dimension from Falco Signed-off-by: Andrea Terzolo --- falco.yaml | 55 +++++++++++++++ userspace/falco/CMakeLists.txt | 2 + .../compute_syscall_buffer_size.cpp | 68 +++++++++++++++++++ .../falco/app_actions/open_inspector.cpp | 6 +- .../falco/app_actions/print_page_size.cpp | 37 ++++++++++ userspace/falco/app_cmdline_options.cpp | 4 +- userspace/falco/app_cmdline_options.h | 1 + userspace/falco/application.cpp | 2 + userspace/falco/application.h | 6 ++ userspace/falco/configuration.cpp | 5 ++ userspace/falco/configuration.h | 3 + 11 files changed, 185 insertions(+), 4 deletions(-) create mode 100644 userspace/falco/app_actions/compute_syscall_buffer_size.cpp create mode 100644 userspace/falco/app_actions/print_page_size.cpp diff --git a/falco.yaml b/falco.yaml index 2ac2f400..e68b8c19 100644 --- a/falco.yaml +++ b/falco.yaml @@ -169,6 +169,61 @@ syscall_event_drops: syscall_event_timeouts: max_consecutives: 1000 +# --- [Description] +# +# This is an index that controls the dimension of the syscall buffers. +# The syscall buffer is the shared space between Falco and its drivers where all the syscall events +# are stored. +# Falco uses a syscall buffer for every online CPU, and all these buffers share the same dimension. +# So this parameter allows you to control the size of all the buffers! +# +# --- [Usage] +# +# You can choose between different indexes: from `1` to `10` (`0` is reserved for future uses). +# Every index corresponds to a dimension in bytes: +# +# [(*), 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 +# +# As you can see the `0` index is reserved, while the index `1` corresponds to +# `1 MB` and so on. +# +# These dimensions in bytes derive from the fact that the buffer size must be: +# (1) a power of 2. +# (2) a multiple of your system_page_dimension. +# (3) greater than `2 * (system_page_dimension)`. +# +# According to these constraints is possible that sometimes you cannot use all the indexes, let's consider an +# example to better understand it: +# If you have a `page_size` of 1 MB the first available buffer size is 4 MB because 2 MB is exactly +# `2 * (system_page_size)` -> `2 * 1 MB`, but this is not enough we need more than `2 * (system_page_size)`! +# So from this example is clear that if you have a page size of 1 MB the first index that you can use is `3`. +# +# Please note: this is a very extreme case just to let you understand the mechanism, usually the page size is something +# like 4 KB so you have no problem at all and you can use all the indexes (from `1` to `10`). +# +# To check your system page size use the Falco `--page-size` command line option. The output on a system with a page +# size of 4096 Bytes (4 KB) should be the following: +# +# "Your system page size is: 4096 bytes." +# +# --- [Suggestions] +# +# Before the introduction of this param the buffer size was fixed to 8 MB (so index `4`, as you can see +# in the default value below). +# Unless you are sure about what you are doing please keep this value as it is, Falco should work as +# well as it always has with this value! +# You can try to increase the buffer size when you face a lot of syscalls drops, but remember that this has +# a price, larger buffers could slow down the entire machine. Moreover, consider 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 the process virtual memory. +# On the other side you can try to reduce the buffer size to speed up the system, but this could +# increase the number of syscall drops! +# So just to conclude, change this index only if you have the necessity otherwise leave it as it is! + +syscall_buffer_index: 4 + # Falco continuously monitors outputs performance. When an output channel does not allow # to deliver an alert within a given deadline, an error is reported indicating # which output is blocking notifications. diff --git a/userspace/falco/CMakeLists.txt b/userspace/falco/CMakeLists.txt index 9338dfa5..8407f676 100644 --- a/userspace/falco/CMakeLists.txt +++ b/userspace/falco/CMakeLists.txt @@ -37,6 +37,8 @@ set( app_actions/print_support.cpp app_actions/print_syscall_events.cpp app_actions/print_version.cpp + app_actions/print_page_size.cpp + app_actions/compute_syscall_buffer_size.cpp app_actions/select_event_sources.cpp app_actions/start_grpc_server.cpp app_actions/start_webserver.cpp diff --git a/userspace/falco/app_actions/compute_syscall_buffer_size.cpp b/userspace/falco/app_actions/compute_syscall_buffer_size.cpp new file mode 100644 index 00000000..371952a9 --- /dev/null +++ b/userspace/falco/app_actions/compute_syscall_buffer_size.cpp @@ -0,0 +1,68 @@ +/* +Copyright (C) 2022 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. +*/ + +#include "application.h" + +using namespace falco::app; + +/* These indexes could change over the Falco releases. */ +#define MIN_INDEX 1 +#define MAX_INDEX 10 + +application::run_result application::configure_syscall_buffer_size() +{ + /* 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(is_capture_mode() || m_state->enabled_sources.find(falco_common::syscall_source) == m_state->enabled_sources.end()) + { + return run_result::ok(); + } + + uint16_t index = m_state->config->m_syscall_buffer_index; + if(index < MIN_INDEX || index > MAX_INDEX) + { + return run_result::fatal("The index 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! */ + std::vector vect{0, 1 << 20, 1 << 21, 1 << 22, 1 << 23, 1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29}; + + uint64_t chosen_size = vect[index]; + + /* If the page size is not valid we return here. */ + long page_size = getpagesize(); + if(page_size <= 0) + { + return run_result::fatal("\nUnable to get the system page size through 'getpagesize()'\n"); + } + + /* Check if the chosen size is a multiple of the page size. */ + if(chosen_size % page_size != 0) + { + return run_result::fatal("The chosen size '" + std::to_string(chosen_size) + "' is not a multiple of your system page '" + std::to_string(page_size) + "'. Please choose a greater index.\n"); + } + + /* Check if the chosen size is greater than `2 * page_size`. */ + if((chosen_size / page_size) <= 2) + { + return run_result::fatal("The chosen size '" + std::to_string(chosen_size) + "' is not greater than '2 * " + std::to_string(page_size) + "'. Please choose a greater index.\n"); + } + + m_state->syscall_buffer_bytes_size = chosen_size; + falco_logger::log(LOG_INFO, "The chosen syscall buffer dimension is: " + std::to_string(chosen_size) + " bytes.\n"); + return run_result::ok(); +} diff --git a/userspace/falco/app_actions/open_inspector.cpp b/userspace/falco/app_actions/open_inspector.cpp index 43e4878e..7ba5d5fc 100644 --- a/userspace/falco/app_actions/open_inspector.cpp +++ b/userspace/falco/app_actions/open_inspector.cpp @@ -91,14 +91,14 @@ application::run_result application::open_live_inspector( bpf_probe_path = full_path; } falco_logger::log(LOG_INFO, "Starting capture with BPF probe. BPF probe path: " + std::string(bpf_probe_path)); - inspector->open_bpf(bpf_probe_path, DEFAULT_DRIVER_BUFFER_BYTES_DIM, m_state->ppm_sc_of_interest, m_state->tp_of_interest); + inspector->open_bpf(bpf_probe_path, m_state->syscall_buffer_bytes_size, m_state->ppm_sc_of_interest, m_state->tp_of_interest); } else /* Kernel module (default). */ { try { falco_logger::log(LOG_INFO, "Starting capture with Kernel module."); - inspector->open_kmod(DEFAULT_DRIVER_BUFFER_BYTES_DIM, m_state->ppm_sc_of_interest, m_state->tp_of_interest); + inspector->open_kmod(m_state->syscall_buffer_bytes_size, m_state->ppm_sc_of_interest, m_state->tp_of_interest); } catch(sinsp_exception &e) { @@ -108,7 +108,7 @@ application::run_result application::open_live_inspector( { falco_logger::log(LOG_ERR, "Unable to load the driver.\n"); } - inspector->open_kmod(DEFAULT_DRIVER_BUFFER_BYTES_DIM, m_state->ppm_sc_of_interest, m_state->tp_of_interest); + inspector->open_kmod(m_state->syscall_buffer_bytes_size, m_state->ppm_sc_of_interest, m_state->tp_of_interest); } } } diff --git a/userspace/falco/app_actions/print_page_size.cpp b/userspace/falco/app_actions/print_page_size.cpp new file mode 100644 index 00000000..aa455d14 --- /dev/null +++ b/userspace/falco/app_actions/print_page_size.cpp @@ -0,0 +1,37 @@ +/* +Copyright (C) 2022 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. +*/ + +#include "application.h" + +using namespace falco::app; + +application::run_result application::print_page_size() +{ + if(m_options.print_page_size) + { + long page_size = getpagesize(); + if(page_size <= 0) + { + return run_result::fatal("\nUnable to get the system page size through 'getpagesize()'\n"); + } + else + { + falco_logger::log(LOG_INFO, "Your system page size is: " + std::to_string(page_size) + " bytes.\n"); + } + return run_result::exit(); + } + return run_result::ok(); +} diff --git a/userspace/falco/app_cmdline_options.cpp b/userspace/falco/app_cmdline_options.cpp index 663b85a9..d55eb0ad 100644 --- a/userspace/falco/app_cmdline_options.cpp +++ b/userspace/falco/app_cmdline_options.cpp @@ -203,7 +203,9 @@ void cmdline_options::define() ("u,userspace", "Parse events from userspace. To be used in conjunction with the ptrace(2) based driver (pdig)", cxxopts::value(userspace)->default_value("false")) ("V,validate", "Read the contents of the specified rules(s) file and exit. Can be specified multiple times to validate multiple files.", cxxopts::value(validate_rules_filenames), "") ("v", "Verbose output.", cxxopts::value(verbose)->default_value("false")) - ("version", "Print version number.", cxxopts::value(print_version_info)->default_value("false")); + ("version", "Print version number.", cxxopts::value(print_version_info)->default_value("false")) + ("page-size", "Print the system page size used to choose the syscall buffer size.", cxxopts::value(print_page_size)->default_value("false")); + m_cmdline_opts.set_width(140); } diff --git a/userspace/falco/app_cmdline_options.h b/userspace/falco/app_cmdline_options.h index 6543194b..0af763bc 100644 --- a/userspace/falco/app_cmdline_options.h +++ b/userspace/falco/app_cmdline_options.h @@ -78,6 +78,7 @@ public: std::vector validate_rules_filenames; bool verbose; bool print_version_info; + bool print_page_size; bool parse(int argc, char **argv, std::string &errstr); diff --git a/userspace/falco/application.cpp b/userspace/falco/application.cpp index e8f957c5..c58a42ca 100644 --- a/userspace/falco/application.cpp +++ b/userspace/falco/application.cpp @@ -131,6 +131,7 @@ bool application::run(std::string &errstr, bool &restart) std::list> run_steps = { std::bind(&application::print_help, this), std::bind(&application::print_version, this), + std::bind(&application::print_page_size, this), std::bind(&application::print_generated_gvisor_config, this), std::bind(&application::print_ignored_events, this), std::bind(&application::print_syscall_events, this), @@ -151,6 +152,7 @@ bool application::run(std::string &errstr, bool &restart) std::bind(&application::daemonize, this), std::bind(&application::init_outputs, this), std::bind(&application::init_clients, this), + std::bind(&application::configure_syscall_buffer_size, this), #ifndef MINIMAL_BUILD std::bind(&application::start_grpc_server, this), std::bind(&application::start_webserver, this), diff --git a/userspace/falco/application.h b/userspace/falco/application.h index aee0565d..2c6206d3 100644 --- a/userspace/falco/application.h +++ b/userspace/falco/application.h @@ -116,6 +116,9 @@ private: // Set of tracepoints we want the driver to capture std::unordered_set tp_of_interest; + // Dimension of the syscall buffer in bytes. + uint64_t syscall_buffer_bytes_size; + #ifndef MINIMAL_BUILD falco::grpc::server grpc_server; std::thread grpc_server_thread; @@ -247,9 +250,11 @@ private: run_result print_support(); run_result print_syscall_events(); run_result print_version(); + run_result print_page_size(); run_result process_events(); run_result select_event_sources(); void configure_interesting_sets(); + application::run_result configure_syscall_buffer_size(); #ifndef MINIMAL_BUILD run_result start_grpc_server(); run_result start_webserver(); @@ -289,6 +294,7 @@ private: std::string source, // an empty source represents capture mode run_result* res) noexcept; + /* Returns true if we are in capture mode. */ inline bool is_capture_mode() const { return !m_options.trace_filename.empty(); diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index b8bbe062..0e8886d8 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -285,6 +285,11 @@ void falco_configuration::init(string conf_filename, const vector &cmdli throw logic_error("Error reading config file(" + m_config_file + "): metadata download watch frequency seconds 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. + */ + m_syscall_buffer_index = m_config->get_scalar("syscall_buffer_index", 4); + std::set load_plugins; bool load_plugins_node_defined = m_config->is_defined("load_plugins"); diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index e3b1c79a..0c61b116 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -269,6 +269,9 @@ public: uint32_t m_metadata_download_chunk_wait_us; uint32_t m_metadata_download_watch_freq_sec; + // Index corresponding to the syscall buffer dimension. + uint64_t m_syscall_buffer_index; + std::vector m_plugins; private: