diff --git a/userspace/falco/app_actions/init_inspector.cpp b/userspace/falco/app_actions/init_inspector.cpp index 6695b153..5b1faa1d 100644 --- a/userspace/falco/app_actions/init_inspector.cpp +++ b/userspace/falco/app_actions/init_inspector.cpp @@ -15,44 +15,187 @@ limitations under the License. */ #include "application.h" +#include +#include using namespace falco::app; -application::run_result application::init_inspector() +static void init_syscall_inspector( + std::shared_ptr 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 inspector, + const std::string& source, + filter_check_list& filterchecks, + std::unordered_set& used_plugins, + std::string& err) +{ + std::vector 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 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(); + + // 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 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(); }