Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new: configure syscall buffer dimension from Falco #2214

Merged
merged 5 commits into from
Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions falco.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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).
# You can increase the buffer size when you face syscall drops. A size of 16 MB (so index `5`) can reduce
# syscall drops in production-heavy systems without noticeable impact. Very large buffers however could
# slow down the entire machine.
# 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!
# As a final remark 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.
# Please pay attention when you use this parameter and change it only if the default size doesn't fit your use case.

syscall_buf_size_preset: 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.
Expand Down
2 changes: 2 additions & 0 deletions userspace/falco/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
71 changes: 71 additions & 0 deletions userspace/falco/app_actions/compute_syscall_buffer_size.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
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
#define DEFAULT_BYTE_SIZE 1 << 23

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_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");
}

/* 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, DEFAULT_BYTE_SIZE, 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)
{
m_state->syscall_buffer_bytes_size = DEFAULT_BYTE_SIZE;
falco_logger::log(LOG_WARNING, "Unable to get the system page size through 'getpagesize()'. Try to use the default syscall buffer dimension: " + std::to_string(DEFAULT_BYTE_SIZE) + " bytes.\n");
return run_result::ok();
}

/* 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");
}

/* 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");
}

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();
}
6 changes: 3 additions & 3 deletions userspace/falco/app_actions/open_inspector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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);
}
}
}
Expand Down
37 changes: 37 additions & 0 deletions userspace/falco/app_actions/print_page_size.cpp
Original file line number Diff line number Diff line change
@@ -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();
}
4 changes: 3 additions & 1 deletion userspace/falco/app_cmdline_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 (may help you to choose the right syscall buffer size).", cxxopts::value(print_page_size)->default_value("false"));


m_cmdline_opts.set_width(140);
}
Expand Down
1 change: 1 addition & 0 deletions userspace/falco/app_cmdline_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class cmdline_options {
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);

Expand Down
2 changes: 2 additions & 0 deletions userspace/falco/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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),
Expand Down
6 changes: 6 additions & 0 deletions userspace/falco/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ class application {
// 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;
Expand Down Expand Up @@ -247,9 +250,11 @@ class application {
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();
Expand Down Expand Up @@ -289,6 +294,7 @@ class application {
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();
Expand Down
5 changes: 5 additions & 0 deletions userspace/falco/configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_buf_size_preset = m_config->get_scalar<uint16_t>("syscall_buf_size_preset", 4);

std::set<std::string> load_plugins;

bool load_plugins_node_defined = m_config->is_defined("load_plugins");
Expand Down
3 changes: 3 additions & 0 deletions userspace/falco/configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ class falco_configuration
uint32_t m_metadata_download_chunk_wait_us;
uint32_t m_metadata_download_watch_freq_sec;

// Index corresponding to the syscall buffer dimension.
uint16_t m_syscall_buf_size_preset;

std::vector<plugin_config> m_plugins;

private:
Expand Down