new: configure syscall buffer dimension from Falco

Signed-off-by: Andrea Terzolo <andrea.terzolo@polito.it>
This commit is contained in:
Andrea Terzolo 2022-09-18 22:51:18 +00:00 committed by poiana
parent 8aea0935c9
commit b0b2f05eb5
11 changed files with 185 additions and 4 deletions

View File

@ -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.

View File

@ -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

View File

@ -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<uint32_t> 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();
}

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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), "<rules_file>")
("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);
}

View File

@ -78,6 +78,7 @@ public:
std::vector<std::string> validate_rules_filenames;
bool verbose;
bool print_version_info;
bool print_page_size;
bool parse(int argc, char **argv, std::string &errstr);

View File

@ -131,6 +131,7 @@ bool application::run(std::string &errstr, bool &restart)
std::list<std::function<run_result()>> 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),

View File

@ -116,6 +116,9 @@ private:
// Set of tracepoints we want the driver to capture
std::unordered_set<uint32_t> 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();

View File

@ -285,6 +285,11 @@ void falco_configuration::init(string conf_filename, const vector<string> &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<uint64_t>("syscall_buffer_index", 4);
std::set<std::string> load_plugins;
bool load_plugins_node_defined = m_config->is_defined("load_plugins");

View File

@ -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<plugin_config> m_plugins;
private: