refactor(userspace/falco): generalize responsibilities of init_inspector action

Now, the action takes care of inizializing all app inspectors
(just one in capture mode, one for each evt source in live mode), and of
registering and initializing all loaded plugins in the right inspector as needed.
The plugin initialization logic, which also involves the filtercheck list
population and checks, was moved and refactored from the previous
implementation of the load_plugins action.

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
Jason Dellaluce 2022-08-30 12:49:36 +00:00 committed by poiana
parent ed025f1a86
commit f9a152b24c

View File

@ -15,44 +15,187 @@ limitations under the License.
*/
#include "application.h"
#include <unordered_set>
#include <plugin_manager.h>
using namespace falco::app;
application::run_result application::init_inspector()
static void init_syscall_inspector(
std::shared_ptr<sinsp> inspector,
const falco::app::cmdline_options& opts)
{
m_state->inspector->set_buffer_format(m_options.event_buffer_format);
inspector->set_buffer_format(opts.event_buffer_format);
// If required, set the CRI paths
for (auto &p : m_options.cri_socket_paths)
for (auto &p : opts.cri_socket_paths)
{
if (!p.empty())
{
m_state->inspector->add_cri_socket_path(p);
inspector->add_cri_socket_path(p);
}
}
// Decide whether to do sync or async for CRI metadata fetch
m_state->inspector->set_cri_async(!m_options.disable_cri_async);
inspector->set_cri_async(!opts.disable_cri_async);
//
// If required, set the snaplen
//
if(m_options.snaplen != 0)
if(opts.snaplen != 0)
{
m_state->inspector->set_snaplen(m_options.snaplen);
inspector->set_snaplen(opts.snaplen);
}
if(!m_options.all_events)
if(!opts.all_events)
{
// Drop EF_DROP_SIMPLE_CONS kernel side
m_state->inspector->set_simple_consumer();
inspector->set_simple_consumer();
// Eventually, drop any EF_DROP_SIMPLE_CONS event
// that reached userspace (there are some events that are not syscall-based
// like signaldeliver, that have the EF_DROP_SIMPLE_CONS flag)
m_state->inspector->set_drop_event_flags(EF_DROP_SIMPLE_CONS);
inspector->set_drop_event_flags(EF_DROP_SIMPLE_CONS);
}
m_state->inspector->set_hostname_and_port_resolution_mode(false);
inspector->set_hostname_and_port_resolution_mode(false);
}
static bool populate_filterchecks(
std::shared_ptr<sinsp> inspector,
const std::string& source,
filter_check_list& filterchecks,
std::unordered_set<std::string>& used_plugins,
std::string& err)
{
std::vector<const filter_check_info*> info;
for(const auto& p : inspector->get_plugin_manager()->plugins())
{
if (!(p->caps() & CAP_EXTRACTION))
{
continue;
}
// check if some fields are overlapping on this event sources
info.clear();
filterchecks.get_all_fields(info);
for (auto &info : info)
{
for (int32_t i = 0; i < info->m_nfields; i++)
{
// check if one of the fields extractable by the plugin
// is already provided by another filtercheck for this source
std::string fname = info->m_fields[i].m_name;
for (auto &f : p->fields())
{
if (std::string(f.m_name) == fname)
{
err = "Plugin '" + p->name()
+ "' supports extraction of field '" + fname
+ "' that is overlapping for source '" + source + "'";
return false;
}
}
}
}
// add plugin filterchecks to the event source
filterchecks.add_filter_check(sinsp_plugin::new_filtercheck(p));
used_plugins.insert(p->name());
}
return true;
}
// todo(XXX): rename this to init_inspectors()
application::run_result application::init_inspector()
{
std::string err;
std::unordered_set<std::string> used_plugins;
const auto& all_plugins = m_state->offline_inspector->get_plugin_manager()->plugins();
for (const auto &src : m_state->loaded_sources)
{
auto src_info = m_state->sources.at(src);
// in capture mode, every event source uses the offline inspector.
// in live mode, we create a new inspector for each event source
src_info->inspector = is_capture_mode()
? m_state->offline_inspector
: std::make_shared<sinsp>();
// handle syscall and plugin sources differently
// todo(jasondellaluce): change this once we support extracting plugin fields from syscalls too
if (src == falco_common::syscall_source)
{
init_syscall_inspector(src_info->inspector, m_options);
continue;
}
// load and init all plugins compatible with this event source
// (if in capture mode, all plugins will be inited on the same inspector)
for (const auto& p : all_plugins)
{
std::shared_ptr<sinsp_plugin> plugin = nullptr;
auto config = m_state->plugin_configs.at(p->name());
auto is_input = p->caps() & CAP_SOURCING && p->event_source() == src;
if (is_capture_mode())
{
// in capture mode, every plugin is already registered
// in the offline inspector by the load_plugins action
plugin = p;
}
else
{
// in live mode, for the inspector assigned to the given
// event source, we must register the plugin supporting
// that event source and also plugins with field extraction
// capability that are compatible with that event source
if (is_input || (p->caps() & CAP_EXTRACTION && p->is_source_compatible(src)))
{
plugin = src_info->inspector->register_plugin(config->m_library_path);
}
}
// init the plugin, if we registered it into an inspector
// (in capture mode, this is true for every plugin)
if (plugin)
{
if (!plugin->init(config->m_init_config, err))
{
return run_result::fatal(err);
}
if (is_input)
{
auto gen_check = src_info->inspector->new_generic_filtercheck();
src_info->filterchecks.add_filter_check(gen_check);
}
used_plugins.insert(plugin->name());
}
}
// populate filtercheck list for this inspector
if (!populate_filterchecks(
src_info->inspector,
src,
src_info->filterchecks,
used_plugins,
err))
{
return run_result::fatal(err);
}
}
// check if some plugin with field extraction capability remains unused
for (const auto& p : all_plugins)
{
if(used_plugins.find(p->name()) == used_plugins.end()
&& p->caps() & CAP_EXTRACTION
&& !(p->caps() & CAP_SOURCING && p->is_source_compatible(p->event_source())))
{
return run_result::fatal("Plugin '" + p->name()
+ "' has field extraction capability but is not compatible with any known event source");
}
}
return run_result::ok();
}