Skip to content

Commit 9b23fd8

Browse files
committed
FDS output: improved detection of Template modifications
Detection is newly based on detection of snapshot changes. If a template snapshot of a Data Record is different (compared to a previous Data Record from the same source and ODID), all Templates in the new snapshot are compared to Templates already added to the file. New or redefined Templates are added and Templates that not defined in the new snapshot are removed.
1 parent 8002be6 commit 9b23fd8

File tree

2 files changed

+188
-31
lines changed

2 files changed

+188
-31
lines changed

src/plugins/output/fds/src/Storage.cpp

Lines changed: 169 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
* SPDX-License-Identifier: BSD-3-Clause
99
*/
1010

11+
#include <algorithm>
12+
#include <cinttypes>
1113
#include <cstdio>
1214
#include <cstring>
1315
#include <sys/stat.h>
@@ -69,9 +71,9 @@ Storage::window_new(time_t ts)
6971
}
7072

7173
if (fds_file_open(m_file.get(), new_file.c_str(), m_flags) != FDS_OK) {
74+
std::string err_msg = fds_file_error(m_file.get());
7275
m_file.reset();
73-
const char *err_msg = "something"; //fds_file_error(m_file.get());
74-
throw FDS_exception("Failed to create file '" + new_file + "': " + err_msg);
76+
throw FDS_exception("Failed to create/append file '" + new_file + "': " + err_msg);
7577
}
7678
}
7779

@@ -100,51 +102,188 @@ Storage::process_msg(ipx_msg_ipfix_t *msg)
100102

101103
if (fds_file_write_ctx(m_file.get(), file_ctx.id, msg_ctx->odid, exp_time) != FDS_OK) {
102104
const char *err_msg = fds_file_error(m_file.get());
103-
throw FDS_exception("Failed to configure file writer: " + std::string(err_msg));
105+
throw FDS_exception("Failed to configure the writer: " + std::string(err_msg));
104106
}
105107

108+
// Get info about the last seen Template snapshot
109+
struct snap_info &snap_last = file_ctx.odid2snap[msg_ctx->odid];
110+
106111
// For each Data Record in the file
107112
const uint32_t rec_cnt = ipx_msg_ipfix_get_drec_cnt(msg);
108113
for (uint32_t i = 0; i < rec_cnt; ++i) {
109114
ipx_ipfix_record *rec_ptr = ipx_msg_ipfix_get_drec(msg, i);
110115

111-
// Insert the record // TODO: improve me!
112-
const struct fds_template *rec_tmplt = rec_ptr->rec.tmplt;
113-
uint16_t tmplt_id = rec_tmplt->id;
114-
enum fds_template_type t_type;
115-
const uint8_t *t_data;
116-
uint16_t t_size;
116+
// Check if the templates has been changed (detected by change of template snapshots)
117+
if (rec_ptr->rec.snap != snap_last.ptr) {
118+
const char *session_name = msg_ctx->session->ident;
119+
uint32_t session_odid = msg_ctx->odid;
120+
IPX_CTX_DEBUG(m_ctx, "Template snapshot of '%s' [ODID %" PRIu32 "] has been changed. "
121+
"Updating template definitions...", session_name, session_odid);
117122

118-
int rc = fds_file_write_tmplt_get(m_file.get(), tmplt_id, &t_type, &t_data, &t_size);
119-
if (rc != FDS_OK && rc != FDS_ERR_NOTFOUND) {
120-
// Something bad happened
123+
tmplts_update(snap_last, rec_ptr->rec.snap);
124+
}
125+
126+
// Write the Data Record
127+
const uint8_t *rec_data = rec_ptr->rec.data;
128+
uint16_t rec_size = rec_ptr->rec.size;
129+
uint16_t tmplt_id = rec_ptr->rec.tmplt->id;
130+
131+
if (fds_file_write_rec(m_file.get(), tmplt_id, rec_data, rec_size) != FDS_OK) {
121132
const char *err_msg = fds_file_error(m_file.get());
133+
throw FDS_exception("Failed to add a Data Record: " + std::string(err_msg));
134+
}
135+
}
136+
}
137+
138+
/// Auxiliary data structure used in the snapshot iterator
139+
struct tmplt_update_data {
140+
/// Status of template processing
141+
bool is_ok;
142+
/// Plugin context (only for log!)
143+
ipx_ctx_t *ctx;
144+
145+
/// FDS file with specified context
146+
fds_file_t *file;
147+
/// Set of processed Templates in the snapshot
148+
std::set<uint16_t> ids;
149+
};
150+
151+
/**
152+
* @brief Callback function for updating definition of an IPFIX (Options) Template
153+
*
154+
* The function checks if the same Template is already defined in the current context of the file.
155+
* If the Template is not present or it's different, the new Template definition is added to the
156+
* file.
157+
* @param[in] tmplt Template to process
158+
* @param[in] data Auxiliary data structure \ref tmplt_update_data
159+
* @return On success returns true. Otherwise returns false.
160+
*/
161+
static bool
162+
tmplt_update_cb(const struct fds_template *tmplt, void *data)
163+
{
164+
// Template type, raw data and size
165+
enum fds_template_type t_type;
166+
const uint8_t *t_data;
167+
uint16_t t_size;
168+
169+
auto info = reinterpret_cast<tmplt_update_data *>(data);
170+
171+
// No exceptions can be thrown in the C callback!
172+
try {
173+
uint16_t t_id = tmplt->id;
174+
info->ids.emplace(t_id);
175+
176+
// Get definition of the Template specified in the file
177+
int res = fds_file_write_tmplt_get(info->file, t_id, &t_type, &t_data, &t_size);
178+
179+
if (res != FDS_OK && res != FDS_ERR_NOTFOUND) {
180+
// Something bad happened
181+
const char *err_msg = fds_file_error(info->file);
122182
throw FDS_exception("fds_file_write_tmplt_get() failed: " + std::string(err_msg));
123183
}
124184

125-
if (rc == FDS_ERR_NOTFOUND || t_type != rec_tmplt->type || t_size != rec_tmplt->raw.length
126-
|| memcmp(t_data, rec_tmplt->raw.data, rec_tmplt->raw.length) != 0) {
127-
// Template not defined or the template are different
128-
t_type = rec_tmplt->type;
129-
t_data = rec_tmplt->raw.data;
130-
t_size = rec_tmplt->raw.length;
131-
132-
if (fds_file_write_tmplt_add(m_file.get(), t_type, t_data, t_size) != FDS_OK) {
133-
const char *err_msg = fds_file_error(m_file.get());
134-
throw FDS_exception("Failed to add a template: " + std::string(err_msg));
135-
}
185+
// Should we add/redefine the definition of the Template
186+
if (res == FDS_OK
187+
&& tmplt->type == t_type
188+
&& tmplt->raw.length == t_size
189+
&& memcmp(tmplt->raw.data, t_data, t_size) == 0) {
190+
// The same -> nothing to do
191+
return info->is_ok;
136192
}
137193

138-
// FIXME: check subTemplateList & subTemplateMultiList templates
194+
// Add the definition (i.e. templates are different or the template hasn't been defined)
195+
IPX_CTX_DEBUG(info->ctx, "Adding/updating definition of Template ID %" PRIu16, t_id);
139196

140-
// Write the Data record
141-
const uint8_t *rec_data = rec_ptr->rec.data;
142-
const uint16_t rec_size = rec_ptr->rec.size;
143-
if (fds_file_write_rec(m_file.get(), tmplt_id, rec_data, rec_size) != FDS_OK) {
144-
const char *err_msg = fds_file_error(m_file.get());
145-
throw FDS_exception("Failed to add a Data Record: " + std::string(err_msg));
197+
t_type = tmplt->type;
198+
t_data = tmplt->raw.data;
199+
t_size = tmplt->raw.length;
200+
201+
if (fds_file_write_tmplt_add(info->file, t_type, t_data, t_size) != FDS_OK) {
202+
const char *err_msg = fds_file_error(info->file);
203+
throw FDS_exception("fds_file_write_tmplt_add() failed: " + std::string(err_msg));
204+
}
205+
206+
} catch (std::exception &ex) {
207+
// Exceptions
208+
IPX_CTX_ERROR(info->ctx, "Failure during update of Template ID %" PRIu16 ": %s", tmplt->id,
209+
ex.what());
210+
info->is_ok = false;
211+
} catch (...) {
212+
// Other exceptions
213+
IPX_CTX_ERROR(info->ctx, "Unknown exception thrown during template definition update", '\0');
214+
info->is_ok = false;
215+
}
216+
217+
return info->is_ok;
218+
}
219+
220+
/**
221+
* @brief Update Template definitions for the current Transport Session and ODID
222+
*
223+
* The function compares Templates in the \p snap with Template definitions previously defined
224+
* for the currently selected combination of Transport Session and ODID. For each different or
225+
* previously undefined Template, its definition is added or updated. Definitions of Templates
226+
* that were available in the previous snapshot but not available in the new one are removed.
227+
*
228+
* Finally, information (pointer, IDs) in \p info are updated to reflect the performed update.
229+
* @warning
230+
* Template definitions are always unique for a combination of Transport Session and ODID,
231+
* therefore, appropriate file writer context MUST already set using fds_file_writer_ctx().
232+
* Parameters \p info and \p snap MUST also belong the same unique combination.
233+
* @param[in] info Information about the last update of Templates (old snapshot ref. + list of IDs)
234+
* @param[in] snap New Template snapshot with all valid Template definitions
235+
*/
236+
void
237+
Storage::tmplts_update(struct snap_info &info, const fds_tsnapshot_t *snap)
238+
{
239+
assert(info.ptr != snap && "Snapshots should be different");
240+
241+
// Prepare data for the callback function
242+
struct tmplt_update_data data;
243+
data.is_ok = true;
244+
data.ctx = m_ctx;
245+
data.file = m_file.get();
246+
data.ids.clear();
247+
248+
// Update templates
249+
fds_tsnapshot_for(snap, &tmplt_update_cb, &data);
250+
251+
// Check if the update failed
252+
if (!data.is_ok) {
253+
throw FDS_exception("Failed to update Template definitions");
254+
}
255+
256+
// Check if there are any Template IDs that have been removed
257+
std::set<uint16_t> &ids_old = info.tmplt_ids;
258+
std::set<uint16_t> &ids_new = data.ids;
259+
std::set<uint16_t> ids2remove;
260+
// Old Template IDs - New Templates IDs = Template IDs to remove
261+
std::set_difference(ids_old.begin(), ids_old.end(), ids_new.begin(), ids_new.end(),
262+
std::inserter(ids2remove, ids2remove.begin()));
263+
264+
// Remove old templates that are not available in the new snapshot
265+
for (uint16_t tid : ids2remove) {
266+
IPX_CTX_DEBUG(m_ctx, "Removing definition of Template ID %" PRIu16, tid);
267+
268+
int rc = fds_file_write_tmplt_remove(m_file.get(), tid);
269+
if (rc == FDS_OK) {
270+
continue;
271+
}
272+
273+
// Something bad happened
274+
if (rc != FDS_ERR_NOTFOUND) {
275+
std::string err_msg = fds_file_error(m_file.get());
276+
throw FDS_exception("fds_file_write_tmplt_remove() failed: " + err_msg);
146277
}
278+
279+
// Weird, but not critical
280+
IPX_CTX_WARNING(m_ctx, "Failed to remove undefined Template ID %" PRIu16 ". "
281+
"Weird, this should not happen.", tid);
147282
}
283+
284+
// Update information about the last update of Templates
285+
info.ptr = snap;
286+
std::swap(info.tmplt_ids, data.ids);
148287
}
149288

150289
/**

src/plugins/output/fds/src/Storage.hpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <ipfixcol2.h>
1515
#include <map>
1616
#include <memory>
17+
#include <set>
1718
#include <string>
1819
#include <libfds.h>
1920

@@ -74,10 +75,25 @@ class Storage {
7475
process_msg(ipx_msg_ipfix_t *msg);
7576

7677
private:
78+
/// Information about Templates in a snapshot
79+
struct snap_info {
80+
/// Last seen snapshot (might be already freed, do NOT dereference!)
81+
const fds_tsnapshot_t *ptr;
82+
/// Set of Template IDs in the snapshot
83+
std::set<uint16_t> tmplt_ids;
84+
85+
snap_info() {
86+
ptr = nullptr;
87+
tmplt_ids.clear();
88+
}
89+
};
90+
7791
/// Description parameters of a Transport Session
7892
struct session_ctx {
79-
/// FDS file ID
93+
/// Session ID used in the FDS file
8094
fds_file_sid_t id;
95+
/// Last seen snapshot for a specific ODID of the Transport Session
96+
std::map<uint32_t, struct snap_info> odid2snap;
8197
};
8298

8399
/// Plugin context only for logging!
@@ -100,6 +116,8 @@ class Storage {
100116
session_get(const struct ipx_session *sptr);
101117
void
102118
session_ipx2fds(const struct ipx_session *ipx_desc, struct fds_file_session *fds_desc);
119+
void
120+
tmplts_update(struct snap_info &info, const fds_tsnapshot_t *snap);
103121
};
104122

105123

0 commit comments

Comments
 (0)