Skip to content

Commit 1e9ee27

Browse files
Lukas HutakLukas955
authored andcommitted
fdsdump: flowProvider: define component
1 parent 6777334 commit 1e9ee27

File tree

2 files changed

+300
-0
lines changed

2 files changed

+300
-0
lines changed
Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
2+
#include <new>
3+
#include <stdexcept>
4+
#include <iostream>
5+
6+
#include "fieldView.hpp"
7+
#include "flowProvider.hpp"
8+
9+
FlowProvider::FlowProvider(const shared_iemgr &iemgr)
10+
: m_iemgr(iemgr)
11+
{
12+
int ret;
13+
14+
m_file.reset(fds_file_init());
15+
if (!m_file) {
16+
throw std::runtime_error("fds_file_init() has failed");
17+
}
18+
19+
ret = fds_file_set_iemgr(m_file.get(), m_iemgr.get());
20+
if (ret != FDS_OK) {
21+
throw std::runtime_error("fds_file_set_iemgr() has failed: " + std::to_string(ret));
22+
}
23+
}
24+
25+
void
26+
FlowProvider::add_file(const std::string &file)
27+
{
28+
m_remains.push_back(file);
29+
}
30+
31+
void
32+
FlowProvider::set_filter(const std::string &expr)
33+
{
34+
fds_ipfix_filter_t *filter;
35+
int ret;
36+
37+
ret = fds_ipfix_filter_create(&filter, m_iemgr.get(), expr.c_str());
38+
m_filter.reset(filter);
39+
40+
if (ret != FDS_OK) {
41+
const std::string err_msg = fds_ipfix_filter_get_error(filter);
42+
throw std::runtime_error("fds_ipfix_filter_create() has failed: " + err_msg);
43+
}
44+
}
45+
46+
void
47+
FlowProvider::set_biflow_autoignore(bool enable)
48+
{
49+
m_biflow_autoignore = enable;
50+
}
51+
52+
bool
53+
FlowProvider::prepare_next_file()
54+
{
55+
while (true) {
56+
const std::string *next_file;
57+
int ret;
58+
59+
// Check if there are more files to read...
60+
if (m_remains.empty()) {
61+
return false;
62+
}
63+
64+
next_file = &m_remains.front();
65+
66+
// Try to open it
67+
ret = fds_file_open(m_file.get(), next_file->c_str(), FDS_FILE_READ);
68+
if (ret != FDS_OK) {
69+
const std::string err_msg = fds_file_error(m_file.get());
70+
71+
std::cerr << "fds_file_open('" << *next_file << "') failed: " << err_msg << std::endl;
72+
m_remains.pop_front();
73+
continue;
74+
}
75+
76+
m_remains.pop_front();
77+
return true;
78+
}
79+
}
80+
81+
bool
82+
FlowProvider::prepare_next_record()
83+
{
84+
int ret;
85+
86+
ret = fds_file_read_rec(m_file.get(), &m_flow.rec, NULL);
87+
switch (ret) {
88+
case FDS_OK:
89+
return true;
90+
case FDS_EOC:
91+
return false;
92+
default:
93+
throw std::runtime_error("fds_file_read_rec() has failed: " + std::to_string(ret));
94+
}
95+
}
96+
97+
enum Direction
98+
FlowProvider::filter_record(struct fds_drec *rec)
99+
{
100+
const fds_template_flag_t tflags = rec->tmplt->flags;
101+
const bool is_biflow = (tflags & FDS_TEMPLATE_BIFLOW) != 0;
102+
103+
if (!m_filter) {
104+
// No filter defined, match it
105+
return is_biflow ? DIRECTION_BOTH : DIRECTION_FWD;
106+
}
107+
108+
if (is_biflow) {
109+
switch (fds_ipfix_filter_eval_biflow(m_filter.get(), rec)) {
110+
case FDS_IPFIX_FILTER_NO_MATCH:
111+
return DIRECTION_NONE;
112+
case FDS_IPFIX_FILTER_MATCH_FWD:
113+
return DIRECTION_FWD;
114+
case FDS_IPFIX_FILTER_MATCH_REV:
115+
return DIRECTION_REV;
116+
case FDS_IPFIX_FILTER_MATCH_BOTH:
117+
return DIRECTION_BOTH;
118+
}
119+
120+
return DIRECTION_NONE;
121+
} else {
122+
return (fds_ipfix_filter_eval(m_filter.get(), rec))
123+
? DIRECTION_FWD
124+
: DIRECTION_NONE;
125+
}
126+
}
127+
128+
bool
129+
FlowProvider::field_has_only_zero_value(struct fds_drec *rec, uint16_t id, bool reverse)
130+
{
131+
const uint16_t flags = reverse ? FDS_DREC_BIFLOW_REV : FDS_DREC_BIFLOW_FWD;
132+
struct fds_drec_iter iter;
133+
int found = false;
134+
135+
fds_drec_iter_init(&iter, rec, flags);
136+
137+
while (fds_drec_iter_find(&iter, 0, id) != FDS_EOC) {
138+
FieldView field(iter.field);
139+
140+
found = true;
141+
142+
if (field.as_uint() != 0) {
143+
return false;
144+
}
145+
}
146+
147+
return found;
148+
}
149+
150+
bool
151+
FlowProvider::direction_is_empty(struct fds_drec *rec, bool reverse)
152+
{
153+
const uint16_t IPFIX_OCTET_DELTA = 1;
154+
const uint16_t IPFIX_PACKET_DELTA = 2;
155+
156+
if (!field_has_only_zero_value(rec, IPFIX_OCTET_DELTA, reverse)) {
157+
return false;
158+
}
159+
160+
if (!field_has_only_zero_value(rec, IPFIX_PACKET_DELTA, reverse)) {
161+
return false;
162+
}
163+
164+
return true;
165+
}
166+
167+
enum Direction
168+
FlowProvider::biflow_autoignore(struct fds_drec *rec)
169+
{
170+
const fds_template_flag_t tflags = rec->tmplt->flags;
171+
const bool is_biflow = (tflags & FDS_TEMPLATE_BIFLOW) != 0;
172+
int result = 0;
173+
174+
if (!m_biflow_autoignore) {
175+
// Disabled
176+
return is_biflow ? DIRECTION_BOTH : DIRECTION_FWD;
177+
}
178+
179+
if (!is_biflow) {
180+
return DIRECTION_FWD;
181+
}
182+
183+
if (!direction_is_empty(rec, false)) {
184+
result |= DIRECTION_FWD;
185+
}
186+
187+
if (!direction_is_empty(rec, true)) {
188+
result |= DIRECTION_REV;
189+
}
190+
191+
return static_cast<enum Direction>(result);
192+
}
193+
194+
Flow *
195+
FlowProvider::next_record()
196+
{
197+
int dir;
198+
199+
while (true) {
200+
if (!m_file_ready) {
201+
if (!prepare_next_file()) {
202+
// No more file, no more records
203+
return nullptr;
204+
}
205+
206+
m_file_ready = true;
207+
}
208+
209+
if (!prepare_next_record()) {
210+
m_file_ready = false;
211+
continue;
212+
}
213+
214+
dir = filter_record(&m_flow.rec);
215+
if (dir == DIRECTION_NONE) {
216+
continue;
217+
}
218+
219+
dir &= biflow_autoignore(&m_flow.rec);
220+
if (dir == DIRECTION_NONE) {
221+
continue;
222+
}
223+
224+
m_flow.dir = static_cast<enum Direction>(dir);
225+
return &m_flow;
226+
}
227+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
2+
#pragma once
3+
4+
#include <memory>
5+
#include <string>
6+
#include <list>
7+
8+
#include <libfds.h>
9+
10+
#include "common.hpp" // unique_file, unique_iemgr
11+
#include "flow.hpp"
12+
13+
class FlowProvider {
14+
public:
15+
FlowProvider(const shared_iemgr &iemgr);
16+
~FlowProvider() = default;
17+
18+
FlowProvider(const FlowProvider &) = delete;
19+
FlowProvider &operator=(const FlowProvider &) = delete;
20+
21+
/**
22+
* @brief Add a new file to process
23+
* @param[in] file Path to the file
24+
*/
25+
void
26+
add_file(const std::string &file);
27+
28+
/**
29+
* @brief Set a flow filter.
30+
* @param[in] expr Filtration expression.
31+
*/
32+
void
33+
set_filter(const std::string &expr);
34+
35+
/**
36+
* @brief Enable heuristic that automatically hides specific direction of
37+
* biflow record that seems to be empty.
38+
*
39+
* Some expoters migth send uniflow records as biflow records but we usually
40+
* don't want to show these values to a user. If enabled, the <em>match</em>
41+
* variable of Record is modified to hide direction that seems to be empty
42+
* even if it matches the filter.
43+
* @param[in] enable True/false
44+
*/
45+
void
46+
set_biflow_autoignore(bool enable);
47+
48+
/**
49+
* @brief Get the next flow record
50+
* @return Pointer or NULL (no more records to process)
51+
*/
52+
Flow *
53+
next_record();
54+
55+
private:
56+
bool prepare_next_file();
57+
bool prepare_next_record();
58+
enum Direction filter_record(struct fds_drec *rec);
59+
enum Direction biflow_autoignore(struct fds_drec *rec);
60+
61+
bool field_has_only_zero_value(struct fds_drec *rec, uint16_t id, bool reverse);
62+
bool direction_is_empty(struct fds_drec *rec, bool reverse);
63+
64+
std::list<std::string> m_remains;
65+
66+
shared_iemgr m_iemgr;
67+
unique_filter m_filter {nullptr, &fds_ipfix_filter_destroy};
68+
unique_file m_file {nullptr, &fds_file_close};
69+
bool m_file_ready = false;
70+
bool m_biflow_autoignore = false;
71+
72+
Flow m_flow;
73+
};

0 commit comments

Comments
 (0)