mirror of
https://github.com/falcosecurity/falco.git
synced 2025-06-25 22:32:07 +00:00
perf: change falco_engine::process_event to lookup sources by index
falco_engine::process_event gets called for every inspector event. Profiling showed that std::map::find takes about 10% of falco_engine::process_event, and that can easily improved by accessing the source by index. Signed-off-by: Angelo Puglisi <angelopuglisi86@gmail.com>
This commit is contained in:
parent
cb4cec6f57
commit
e8cb96a57b
@ -208,7 +208,7 @@ void falco_engine::enable_rule(const string &substring, bool enabled, const stri
|
||||
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
it.second->enable(substring, match_exact, enabled, ruleset_id);
|
||||
it.ruleset->enable(substring, match_exact, enabled, ruleset_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +219,7 @@ void falco_engine::enable_rule_exact(const string &rule_name, bool enabled, cons
|
||||
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
it.second->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||
it.ruleset->enable(rule_name, match_exact, enabled, ruleset_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -229,7 +229,7 @@ void falco_engine::enable_rule_by_tag(const set<string> &tags, bool enabled, con
|
||||
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
it.second->enable_tags(tags, enabled, ruleset_id);
|
||||
it.ruleset->enable_tags(tags, enabled, ruleset_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +259,7 @@ uint64_t falco_engine::num_rules_for_ruleset(const std::string &ruleset)
|
||||
uint64_t ret = 0;
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
ret += it.second->num_rules_for_ruleset(ruleset_id);
|
||||
ret += it.ruleset->num_rules_for_ruleset(ruleset_id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -269,14 +269,14 @@ void falco_engine::evttypes_for_ruleset(std::string &source, std::set<uint16_t>
|
||||
{
|
||||
uint16_t ruleset_id = find_ruleset_id(ruleset);
|
||||
|
||||
auto it = m_rulesets.find(source);
|
||||
auto it = find_ruleset(source);
|
||||
if(it == m_rulesets.end())
|
||||
{
|
||||
string err = "Unknown event source " + source;
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
it->second->evttypes_for_ruleset(evttypes, ruleset_id);
|
||||
it->ruleset->evttypes_for_ruleset(evttypes, ruleset_id);
|
||||
|
||||
}
|
||||
|
||||
@ -294,47 +294,51 @@ std::shared_ptr<gen_event_formatter> falco_engine::create_formatter(const std::s
|
||||
return it->second->create_formatter(output);
|
||||
}
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::string &source, gen_event *ev, uint16_t ruleset_id)
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id)
|
||||
{
|
||||
if(should_drop_evt())
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
|
||||
auto it = m_rulesets.find(source);
|
||||
if(it == m_rulesets.end())
|
||||
try
|
||||
{
|
||||
string err = "Unknown event source " + source;
|
||||
auto &r = m_rulesets.at(source_idx);
|
||||
if(!r.ruleset->run(ev, ruleset_id))
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
|
||||
unique_ptr<struct rule_result> res(new rule_result());
|
||||
res->source = r.source;
|
||||
|
||||
populate_rule_result(res, ev);
|
||||
|
||||
return res;
|
||||
}
|
||||
catch(std::out_of_range const &exc)
|
||||
{
|
||||
std::string err = "Unknown event source index " + std::to_string(source_idx);
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
if (!it->second->run(ev, ruleset_id))
|
||||
{
|
||||
return unique_ptr<struct rule_result>();
|
||||
}
|
||||
|
||||
unique_ptr<struct rule_result> res(new rule_result());
|
||||
res->source = source;
|
||||
|
||||
populate_rule_result(res, ev);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::string &source, gen_event *ev)
|
||||
unique_ptr<falco_engine::rule_result> falco_engine::process_event(std::size_t source_idx, gen_event *ev)
|
||||
{
|
||||
return process_event(source, ev, m_default_ruleset_id);
|
||||
return process_event(source_idx, ev, m_default_ruleset_id);
|
||||
}
|
||||
|
||||
void falco_engine::add_source(const std::string &source,
|
||||
std::shared_ptr<gen_event_filter_factory> filter_factory,
|
||||
std::shared_ptr<gen_event_formatter_factory> formatter_factory)
|
||||
std::size_t falco_engine::add_source(const std::string &source,
|
||||
std::shared_ptr<gen_event_filter_factory> filter_factory,
|
||||
std::shared_ptr<gen_event_formatter_factory> formatter_factory)
|
||||
{
|
||||
m_filter_factories[source] = filter_factory;
|
||||
m_format_factories[source] = formatter_factory;
|
||||
|
||||
std::shared_ptr<falco_ruleset> ruleset(new falco_ruleset());
|
||||
m_rulesets[source] = ruleset;
|
||||
auto idx = m_rulesets.size();
|
||||
m_rulesets.emplace_back(source, new falco_ruleset);
|
||||
// here we just trust the caller they won't add the same source more than once
|
||||
return idx;
|
||||
}
|
||||
|
||||
void falco_engine::populate_rule_result(unique_ptr<struct rule_result> &res, gen_event *ev)
|
||||
@ -418,19 +422,19 @@ void falco_engine::add_filter(std::shared_ptr<gen_event_filter> filter,
|
||||
std::string &source,
|
||||
std::set<std::string> &tags)
|
||||
{
|
||||
auto it = m_rulesets.find(source);
|
||||
auto it = find_ruleset(source);
|
||||
if(it == m_rulesets.end())
|
||||
{
|
||||
string err = "Unknown event source " + source;
|
||||
throw falco_exception(err);
|
||||
}
|
||||
|
||||
it->second->add(source, rule, tags, filter);
|
||||
it->ruleset->add(source, rule, tags, filter);
|
||||
}
|
||||
|
||||
bool falco_engine::is_source_valid(const std::string &source)
|
||||
{
|
||||
return (m_rulesets.find(source) != m_rulesets.end());
|
||||
return (find_ruleset(source) != m_rulesets.end());
|
||||
}
|
||||
|
||||
bool falco_engine::is_plugin_compatible(const std::string &name,
|
||||
@ -465,12 +469,9 @@ bool falco_engine::is_plugin_compatible(const std::string &name,
|
||||
|
||||
void falco_engine::clear_filters()
|
||||
{
|
||||
m_rulesets.clear();
|
||||
|
||||
for(auto &it : m_filter_factories)
|
||||
for(auto &it : m_rulesets)
|
||||
{
|
||||
std::shared_ptr<falco_ruleset> ruleset(new falco_ruleset());
|
||||
m_rulesets[it.first] = ruleset;
|
||||
it.ruleset.reset(new falco_ruleset);
|
||||
}
|
||||
|
||||
m_required_plugin_versions.clear();
|
||||
@ -507,3 +508,17 @@ inline bool falco_engine::should_drop_evt()
|
||||
double coin = (random() * (1.0/RAND_MAX));
|
||||
return (coin >= (1.0/(m_sampling_multiplier * m_sampling_ratio)));
|
||||
}
|
||||
|
||||
inline std::vector<falco_engine::ruleset_node>::iterator falco_engine::find_ruleset(const std::string &source)
|
||||
{
|
||||
return std::find_if(
|
||||
m_rulesets.begin(), m_rulesets.end(),
|
||||
[&source](const ruleset_node &r) { return r.source == source; });
|
||||
}
|
||||
|
||||
inline std::vector<falco_engine::ruleset_node>::const_iterator falco_engine::find_ruleset(const std::string &source) const
|
||||
{
|
||||
return std::find_if(
|
||||
m_rulesets.cbegin(), m_rulesets.cend(),
|
||||
[&source](const ruleset_node &r) { return r.source == source; });
|
||||
}
|
||||
|
@ -163,20 +163,21 @@ public:
|
||||
// with a ruleset string.
|
||||
//
|
||||
// the returned rule_result is allocated and must be delete()d.
|
||||
std::unique_ptr<rule_result> process_event(std::string &source, gen_event *ev, uint16_t ruleset_id);
|
||||
std::unique_ptr<rule_result> process_event(std::size_t source_idx, gen_event *ev, uint16_t ruleset_id);
|
||||
|
||||
//
|
||||
// Wrapper assuming the default ruleset
|
||||
//
|
||||
std::unique_ptr<rule_result> process_event(std::string &source, gen_event *ev);
|
||||
std::unique_ptr<rule_result> process_event(std::size_t source_idx, gen_event *ev);
|
||||
|
||||
//
|
||||
// Configure the engine to support events with the provided
|
||||
// source, with the provided filter factory and formatter factory.
|
||||
// Return source index for fast lookup.
|
||||
//
|
||||
void add_source(const std::string &source,
|
||||
std::shared_ptr<gen_event_filter_factory> filter_factory,
|
||||
std::shared_ptr<gen_event_formatter_factory> formatter_factory);
|
||||
std::size_t add_source(const std::string &source,
|
||||
std::shared_ptr<gen_event_filter_factory> filter_factory,
|
||||
std::shared_ptr<gen_event_formatter_factory> formatter_factory);
|
||||
|
||||
// Return whether or not there is a valid filter/formatter
|
||||
// factory for this source.
|
||||
@ -213,6 +214,14 @@ public:
|
||||
bool is_plugin_compatible(const std::string &name, const std::string &version, std::string &required_version);
|
||||
|
||||
private:
|
||||
struct ruleset_node
|
||||
{
|
||||
ruleset_node(const std::string &n, falco_ruleset *p):
|
||||
source(n), ruleset(p) {}
|
||||
|
||||
std::string source;
|
||||
mutable std::shared_ptr<falco_ruleset> ruleset;
|
||||
};
|
||||
|
||||
//
|
||||
// Determine whether the given event should be matched at all
|
||||
@ -221,6 +230,9 @@ private:
|
||||
//
|
||||
inline bool should_drop_evt();
|
||||
|
||||
inline std::vector<ruleset_node>::iterator find_ruleset(const std::string &source);
|
||||
inline std::vector<ruleset_node>::const_iterator find_ruleset(const std::string &source) const;
|
||||
|
||||
// Maps from event source to object that can generate filters from rules
|
||||
std::map<std::string, std::shared_ptr<gen_event_filter_factory>> m_filter_factories;
|
||||
|
||||
@ -228,7 +240,7 @@ private:
|
||||
std::map<std::string, std::shared_ptr<gen_event_formatter_factory>> m_format_factories;
|
||||
|
||||
// Maps from event source to the set of rules for that event source
|
||||
std::map<std::string, std::shared_ptr<falco_ruleset>> m_rulesets;
|
||||
std::vector<ruleset_node> m_rulesets;
|
||||
|
||||
std::unique_ptr<falco_rules> m_rules;
|
||||
uint16_t m_next_ruleset_id;
|
||||
|
@ -62,7 +62,9 @@ bool g_restart = false;
|
||||
bool g_daemonized = false;
|
||||
|
||||
static std::string syscall_source = "syscall";
|
||||
static std::size_t syscall_source_idx;
|
||||
static std::string k8s_audit_source = "k8s_audit";
|
||||
static std::size_t k8s_audit_source_idx;
|
||||
|
||||
//
|
||||
// Helper functions
|
||||
@ -118,7 +120,7 @@ void read_k8s_audit_trace_file(falco_engine *engine,
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!k8s_audit_handler::accept_data(engine, outputs, line, errstr))
|
||||
if(!k8s_audit_handler::accept_data(engine, outputs, k8s_audit_source_idx, line, errstr))
|
||||
{
|
||||
falco_logger::log(LOG_ERR, "Could not read k8s audit event line #" + to_string(line_num) + ", \"" + line + "\": " + errstr + ", stopping");
|
||||
return;
|
||||
@ -140,16 +142,16 @@ static std::string read_file(std::string filename)
|
||||
// Event processing loop
|
||||
//
|
||||
uint64_t do_inspect(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
sinsp* inspector,
|
||||
std::string &event_source,
|
||||
falco_configuration &config,
|
||||
syscall_evt_drop_mgr &sdropmgr,
|
||||
uint64_t duration_to_tot_ns,
|
||||
string &stats_filename,
|
||||
uint64_t stats_interval,
|
||||
bool all_events,
|
||||
int &result)
|
||||
falco_outputs *outputs,
|
||||
sinsp *inspector,
|
||||
std::size_t event_source_idx,
|
||||
falco_configuration &config,
|
||||
syscall_evt_drop_mgr &sdropmgr,
|
||||
uint64_t duration_to_tot_ns,
|
||||
string &stats_filename,
|
||||
uint64_t stats_interval,
|
||||
bool all_events,
|
||||
int &result)
|
||||
{
|
||||
uint64_t num_evts = 0;
|
||||
int32_t rc;
|
||||
@ -207,7 +209,7 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
if(unlikely(ev == nullptr))
|
||||
{
|
||||
timeouts_since_last_success_or_msg++;
|
||||
if(event_source == syscall_source &&
|
||||
if(event_source_idx == syscall_source_idx &&
|
||||
(timeouts_since_last_success_or_msg > config.m_syscall_evt_timeout_max_consecutives))
|
||||
{
|
||||
std::string rule = "Falco internal: timeouts notification";
|
||||
@ -272,7 +274,7 @@ uint64_t do_inspect(falco_engine *engine,
|
||||
// engine, which will match the event against the set
|
||||
// of rules. If a match is found, pass the event to
|
||||
// the outputs.
|
||||
unique_ptr<falco_engine::rule_result> res = engine->process_event(event_source, ev);
|
||||
unique_ptr<falco_engine::rule_result> res = engine->process_event(event_source_idx, ev);
|
||||
if(res)
|
||||
{
|
||||
outputs->handle_event(res->evt, res->rule, res->source, res->priority_num, res->format, res->tags);
|
||||
@ -517,8 +519,8 @@ int falco_init(int argc, char **argv)
|
||||
std::shared_ptr<gen_event_formatter_factory> syscall_formatter_factory(new sinsp_evt_formatter_factory(inspector));
|
||||
std::shared_ptr<gen_event_formatter_factory> k8s_audit_formatter_factory(new json_event_formatter_factory(k8s_audit_filter_factory));
|
||||
|
||||
engine->add_source(syscall_source, syscall_filter_factory, syscall_formatter_factory);
|
||||
engine->add_source(k8s_audit_source, k8s_audit_filter_factory, k8s_audit_formatter_factory);
|
||||
syscall_source_idx = engine->add_source(syscall_source, syscall_filter_factory, syscall_formatter_factory);
|
||||
k8s_audit_source_idx = engine->add_source(k8s_audit_source, k8s_audit_filter_factory, k8s_audit_formatter_factory);
|
||||
|
||||
for(const auto &src : app.options().disable_sources)
|
||||
{
|
||||
@ -581,6 +583,7 @@ int falco_init(int argc, char **argv)
|
||||
// plugin was found, the source is the source of that
|
||||
// plugin.
|
||||
std::string event_source = syscall_source;
|
||||
std::size_t event_source_idx = syscall_source_idx;
|
||||
|
||||
// All filterchecks created by plugins go in this
|
||||
// list. If we ever support multiple event sources at
|
||||
@ -628,7 +631,7 @@ int falco_init(int argc, char **argv)
|
||||
inspector->set_input_plugin_open_params(p.m_open_params.c_str());
|
||||
}
|
||||
|
||||
engine->add_source(event_source, plugin_filter_factory, plugin_formatter_factory);
|
||||
event_source_idx = engine->add_source(event_source, plugin_filter_factory, plugin_formatter_factory);
|
||||
|
||||
} else {
|
||||
extractor_plugins.push_back(plugin);
|
||||
@ -1151,7 +1154,7 @@ int falco_init(int argc, char **argv)
|
||||
{
|
||||
std::string ssl_option = (config.m_webserver_ssl_enabled ? " (SSL)" : "");
|
||||
falco_logger::log(LOG_INFO, "Starting internal webserver, listening on port " + to_string(config.m_webserver_listen_port) + ssl_option + "\n");
|
||||
webserver.init(&config, engine, outputs);
|
||||
webserver.init(&config, engine, outputs, k8s_audit_source_idx);
|
||||
webserver.start();
|
||||
}
|
||||
|
||||
@ -1190,7 +1193,7 @@ int falco_init(int argc, char **argv)
|
||||
num_evts = do_inspect(engine,
|
||||
outputs,
|
||||
inspector,
|
||||
event_source,
|
||||
event_source_idx,
|
||||
config,
|
||||
sdropmgr,
|
||||
uint64_t(app.options().duration_to_tot*ONE_SECOND_IN_NS),
|
||||
|
@ -25,10 +25,8 @@ limitations under the License.
|
||||
using json = nlohmann::json;
|
||||
using namespace std;
|
||||
|
||||
string k8s_audit_handler::m_k8s_audit_event_source = "k8s_audit";
|
||||
|
||||
k8s_audit_handler::k8s_audit_handler(falco_engine *engine, falco_outputs *outputs):
|
||||
m_engine(engine), m_outputs(outputs)
|
||||
k8s_audit_handler::k8s_audit_handler(falco_engine *engine, falco_outputs *outputs, std::size_t k8s_audit_event_source_idx):
|
||||
m_engine(engine), m_outputs(outputs), m_k8s_audit_event_source_idx(k8s_audit_event_source_idx)
|
||||
{
|
||||
}
|
||||
|
||||
@ -47,6 +45,7 @@ bool k8s_healthz_handler::handleGet(CivetServer *server, struct mg_connection *c
|
||||
|
||||
bool k8s_audit_handler::accept_data(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
std::size_t k8s_audit_event_source_idx,
|
||||
std::string &data,
|
||||
std::string &errstr)
|
||||
{
|
||||
@ -89,7 +88,7 @@ bool k8s_audit_handler::accept_data(falco_engine *engine,
|
||||
|
||||
try
|
||||
{
|
||||
res = engine->process_event(m_k8s_audit_event_source, &jev);
|
||||
res = engine->process_event(k8s_audit_event_source_idx, &jev);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
@ -120,7 +119,7 @@ bool k8s_audit_handler::accept_data(falco_engine *engine,
|
||||
|
||||
bool k8s_audit_handler::accept_uploaded_data(std::string &post_data, std::string &errstr)
|
||||
{
|
||||
return k8s_audit_handler::accept_data(m_engine, m_outputs, post_data, errstr);
|
||||
return k8s_audit_handler::accept_data(m_engine, m_outputs, m_k8s_audit_event_source_idx, post_data, errstr);
|
||||
}
|
||||
|
||||
bool k8s_audit_handler::handleGet(CivetServer *server, struct mg_connection *conn)
|
||||
@ -189,11 +188,13 @@ falco_webserver::~falco_webserver()
|
||||
|
||||
void falco_webserver::init(falco_configuration *config,
|
||||
falco_engine *engine,
|
||||
falco_outputs *outputs)
|
||||
falco_outputs *outputs,
|
||||
std::size_t k8s_audit_event_source_idx)
|
||||
{
|
||||
m_config = config;
|
||||
m_engine = engine;
|
||||
m_outputs = outputs;
|
||||
m_k8s_audit_event_source_idx = k8s_audit_event_source_idx;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
@ -253,7 +254,7 @@ void falco_webserver::start()
|
||||
throw falco_exception("Could not create embedded webserver");
|
||||
}
|
||||
|
||||
m_k8s_audit_handler = make_unique<k8s_audit_handler>(m_engine, m_outputs);
|
||||
m_k8s_audit_handler = make_unique<k8s_audit_handler>(m_engine, m_outputs, m_k8s_audit_event_source_idx);
|
||||
m_server->addHandler(m_config->m_webserver_k8s_audit_endpoint, *m_k8s_audit_handler);
|
||||
m_k8s_healthz_handler = make_unique<k8s_healthz_handler>();
|
||||
m_server->addHandler(m_config->m_webserver_k8s_healthz_endpoint, *m_k8s_healthz_handler);
|
||||
|
@ -25,7 +25,7 @@ limitations under the License.
|
||||
class k8s_audit_handler : public CivetHandler
|
||||
{
|
||||
public:
|
||||
k8s_audit_handler(falco_engine *engine, falco_outputs *outputs);
|
||||
k8s_audit_handler(falco_engine *engine, falco_outputs *outputs, std::size_t k8s_audit_event_source_idx);
|
||||
virtual ~k8s_audit_handler();
|
||||
|
||||
bool handleGet(CivetServer *server, struct mg_connection *conn);
|
||||
@ -33,13 +33,13 @@ public:
|
||||
|
||||
static bool accept_data(falco_engine *engine,
|
||||
falco_outputs *outputs,
|
||||
std::size_t k8s_audit_event_source_idx,
|
||||
std::string &post_data, std::string &errstr);
|
||||
|
||||
static std::string m_k8s_audit_event_source;
|
||||
|
||||
private:
|
||||
falco_engine *m_engine;
|
||||
falco_outputs *m_outputs;
|
||||
std::size_t m_k8s_audit_event_source_idx;
|
||||
bool accept_uploaded_data(std::string &post_data, std::string &errstr);
|
||||
};
|
||||
|
||||
@ -65,7 +65,8 @@ public:
|
||||
|
||||
void init(falco_configuration *config,
|
||||
falco_engine *engine,
|
||||
falco_outputs *outputs);
|
||||
falco_outputs *outputs,
|
||||
std::size_t k8s_audit_event_source_idx);
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
@ -74,6 +75,7 @@ private:
|
||||
falco_engine *m_engine;
|
||||
falco_configuration *m_config;
|
||||
falco_outputs *m_outputs;
|
||||
std::size_t m_k8s_audit_event_source_idx;
|
||||
unique_ptr<CivetServer> m_server;
|
||||
unique_ptr<k8s_audit_handler> m_k8s_audit_handler;
|
||||
unique_ptr<k8s_healthz_handler> m_k8s_healthz_handler;
|
||||
|
Loading…
Reference in New Issue
Block a user