11/* *
22 * \file src/plugins/output/fds/src/Storage.cpp
33 * \author Lukas Hutak <[email protected] > 4+ * \author Michal Sedlak <[email protected] > 45 * \brief FDS file storage (source file)
56 * \date June 2019
67 *
1314#include < cstdio>
1415#include < cstring>
1516#include < sys/stat.h>
17+ #include < netinet/in.h>
1618#include < ipfixcol2.h>
1719#include < libgen.h>
1820#include " Storage.hpp"
1921
2022const std::string TMP_SUFFIX = " .tmp" ;
2123
22- Storage::Storage (ipx_ctx_t *ctx, const Config &cfg) : m_ctx(ctx), m_path(cfg.m_path)
24+ static void
25+ buf_write (std::vector<uint8_t > &buffer, const uint8_t *data, std::size_t data_len)
26+ {
27+ if (data_len == 0 ) {
28+ return ;
29+ }
30+ std::size_t idx = buffer.size ();
31+ buffer.resize (idx + data_len);
32+ std::memcpy (&buffer[idx], data, data_len);
33+ }
34+
35+ template <typename T>
36+ static void
37+ buf_write (std::vector<uint8_t > &buffer, T &&value)
38+ {
39+ buf_write (buffer, reinterpret_cast <const uint8_t *>(&value), sizeof (value));
40+ }
41+
42+ static bool
43+ contains_element (const std::vector<Config::element> &elements, const fds_tfield &field)
44+ {
45+ auto it = std::find_if (elements.begin (), elements.end (),
46+ [&](const Config::element &elem) { return elem.id == field.id && elem.pen == field.en ; });
47+ return it != elements.end ();
48+ }
49+
50+ void
51+ create_modified_template (const fds_template *tmplt,
52+ const std::vector<Config::element> &selected_elements,
53+ std::vector<uint8_t > &out_buffer)
54+ {
55+ out_buffer.clear ();
56+
57+ // Collect the fields we want in the resulting template
58+ std::vector<const fds_tfield *> fields;
59+ for (uint16_t i = 0 ; i < tmplt->fields_cnt_total ; i++) {
60+ const fds_tfield &field = tmplt->fields [i];
61+ if (contains_element (selected_elements, field)) {
62+ fields.push_back (&field);
63+ }
64+ }
65+
66+
67+ /* *
68+ * Build the template definition...
69+ *
70+ * Template:
71+ * [Template Record Header]
72+ * [Field Specifier]
73+ * [Field Specifier]
74+ * ...
75+ * [Field Specifier]
76+ *
77+ * Template Record Header:
78+ * [Template ID : 16 bit] [Field Count : 16 bit]
79+ *
80+ * Example:
81+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
82+ * | Template ID = 256 | Field Count = N |
83+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
84+ * |1| Information Element id. 1.1 | Field Length 1.1 |
85+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
86+ * | Enterprise Number 1.1 |
87+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
88+ * |0| Information Element id. 1.2 | Field Length 1.2 |
89+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
90+ * | ... | ... |
91+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
92+ * |1| Information Element id. 1.N | Field Length 1.N |
93+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
94+ * | Enterprise Number 1.N |
95+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
96+ * | Template ID = 257 | Field Count = M |
97+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
98+ * |0| Information Element id. 2.1 | Field Length 2.1 |
99+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
100+ * |1| Information Element id. 2.2 | Field Length 2.2 |
101+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
102+ * | Enterprise Number 2.2 |
103+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104+ * | ... | ... |
105+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106+ * |1| Information Element id. 2.M | Field Length 2.M |
107+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108+ * | Enterprise Number 2.M |
109+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
110+ * | Padding (opt) |
111+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
112+ */
113+
114+ // Write the header
115+ buf_write (out_buffer, htons (tmplt->id ));
116+ buf_write (out_buffer, htons (fields.size ()));
117+
118+ // Write the template fields
119+ for (const fds_tfield *field : fields) {
120+ if (field->en == 0 ) {
121+ buf_write (out_buffer, htons (field->id ));
122+ buf_write (out_buffer, htons (field->length ));
123+ } else {
124+ // If PEN is specified, MSB of element ID is set to 1
125+ buf_write (out_buffer, htons (field->id | 0x8000 ));
126+ buf_write (out_buffer, htons (field->length ));
127+ buf_write (out_buffer, htonl (field->en ));
128+ }
129+ }
130+ }
131+
132+ static void
133+ create_modified_data_record (fds_drec &drec,
134+ const std::vector<Config::element> &selected_elements,
135+ std::vector<uint8_t > &out_buffer)
136+ {
137+ out_buffer.clear ();
138+
139+ /* *
140+ * Data record consists of a sequence of field values.
141+ *
142+ * Data Record:
143+ * +--------------------------------------------------+
144+ * | Field Value |
145+ * +--------------------------------------------------+
146+ * | Field Value |
147+ * +--------------------------------------------------+
148+ * ...
149+ * +--------------------------------------------------+
150+ * | Field Value |
151+ * +--------------------------------------------------+
152+ */
153+
154+ fds_drec_iter iter;
155+ fds_drec_iter_init (&iter, &drec, 0 );
156+ while (fds_drec_iter_next (&iter) != FDS_EOC) {
157+ if (contains_element (selected_elements, *iter.field .info )) {
158+ if (iter.field .info ->length == FDS_IPFIX_VAR_IE_LEN) {
159+ /* *
160+ * Variable length fields are specified with 65535 in their
161+ * template field length. In this case, the first octet of the
162+ * field value in the data record specifies its length (of the
163+ * data only, the extra octet is not included in this length).
164+ *
165+ * If the data were to be longer than 254, the octet is 255 and the
166+ * next 2 octets are uint16 of the length.
167+ */
168+ if (iter.field .size < 255 ) {
169+ buf_write (out_buffer, uint8_t (iter.field .size ));
170+ } else {
171+ buf_write (out_buffer, uint8_t (255 ));
172+ buf_write (out_buffer, htons (uint16_t (iter.field .size )));
173+ }
174+ buf_write (out_buffer, iter.field .data , iter.field .size );
175+ } else {
176+ buf_write (out_buffer, iter.field .data , iter.field .size );
177+ }
178+ }
179+ }
180+ }
181+
182+ Storage::Storage (ipx_ctx_t *ctx, const Config &cfg) :
183+ m_ctx(ctx),
184+ m_path(cfg.m_path),
185+ m_selection_used(cfg.m_selection_used),
186+ m_selection(cfg.m_selection)
23187{
24188 // Check if the directory exists
25189 struct stat file_info;
@@ -142,6 +306,16 @@ Storage::process_msg(ipx_msg_ipfix_t *msg)
142306 uint16_t rec_size = rec_ptr->rec .size ;
143307 uint16_t tmplt_id = rec_ptr->rec .tmplt ->id ;
144308
309+ if (m_selection_used) {
310+ create_modified_data_record (rec_ptr->rec , m_selection, m_buffer);
311+ rec_data = m_buffer.data ();
312+ rec_size = m_buffer.size ();
313+ if (rec_size == 0 ) {
314+ // No record fields were selected -> the record is empty, skip
315+ continue ;
316+ }
317+ }
318+
145319 if (fds_file_write_rec (m_file.get (), tmplt_id, rec_data, rec_size) != FDS_OK) {
146320 const char *err_msg = fds_file_error (m_file.get ());
147321 throw FDS_exception (" Failed to add a Data Record: " + std::string (err_msg));
@@ -160,6 +334,12 @@ struct tmplt_update_data {
160334 fds_file_t *file;
161335 // / Set of processed Templates in the snapshot
162336 std::set<uint16_t > ids;
337+ // / Whether selection is used
338+ bool selection_used;
339+ // / The selection
340+ std::vector<Config::element> *selection;
341+ // / Buffer for building modified templates
342+ std::vector<uint8_t > *buffer;
163343};
164344
165345/* *
@@ -175,21 +355,40 @@ struct tmplt_update_data {
175355static bool
176356tmplt_update_cb (const struct fds_template *tmplt, void *data)
177357{
178- // Template type, raw data and size
179- enum fds_template_type t_type;
180- const uint8_t *t_data;
181- uint16_t t_size;
182-
183358 auto info = reinterpret_cast <tmplt_update_data *>(data);
184359
185360 // No exceptions can be thrown in the C callback!
186361 try {
187- uint16_t t_id = tmplt->id ;
188- info->ids .emplace (t_id);
362+ if (info->selection_used && tmplt->type != FDS_TYPE_TEMPLATE) {
363+ // Skip Option Templates in case field selection is used
364+ return info->is_ok ;
365+ }
366+
367+ // Get definition of the template we want to store
368+ fds_template_type new_t_type = tmplt->type ;
369+ const uint8_t *new_t_data = tmplt->raw .data ;
370+ uint16_t new_t_size = tmplt->raw .length ;
371+
372+ if (info->selection_used ) {
373+ create_modified_template (tmplt, *info->selection , *info->buffer );
374+ new_t_data = info->buffer ->data ();
375+ new_t_size = info->buffer ->size ();
376+
377+ if (new_t_size == 0 ) {
378+ // None of the template fields have been selected -> skip this template
379+ return info->is_ok ;
380+ }
381+ }
382+
383+ // Only now store the template ID as we're now sure that this is an active template
384+ info->ids .emplace (tmplt->id );
189385
190386 // Get definition of the Template specified in the file
191- int res = fds_file_write_tmplt_get (info->file , t_id, &t_type, &t_data, &t_size);
387+ fds_template_type old_t_type;
388+ const uint8_t *old_t_data;
389+ uint16_t old_t_size;
192390
391+ int res = fds_file_write_tmplt_get (info->file , tmplt->id , &old_t_type, &old_t_data, &old_t_size);
193392 if (res != FDS_OK && res != FDS_ERR_NOTFOUND) {
194393 // Something bad happened
195394 const char *err_msg = fds_file_error (info->file );
@@ -198,21 +397,17 @@ tmplt_update_cb(const struct fds_template *tmplt, void *data)
198397
199398 // Should we add/redefine the definition of the Template
200399 if (res == FDS_OK
201- && tmplt-> type == t_type
202- && tmplt-> raw . length == t_size
203- && memcmp (tmplt-> raw . data , t_data, t_size ) == 0 ) {
400+ && old_t_type == new_t_type
401+ && old_t_size == new_t_size
402+ && memcmp (old_t_data, new_t_data, new_t_size ) == 0 ) {
204403 // The same -> nothing to do
205404 return info->is_ok ;
206405 }
207406
208407 // Add the definition (i.e. templates are different or the template hasn't been defined)
209- IPX_CTX_DEBUG (info->ctx , " Adding/updating definition of Template ID %" PRIu16, t_id );
408+ IPX_CTX_DEBUG (info->ctx , " Adding/updating definition of Template ID %" PRIu16, tmplt-> id );
210409
211- t_type = tmplt->type ;
212- t_data = tmplt->raw .data ;
213- t_size = tmplt->raw .length ;
214-
215- if (fds_file_write_tmplt_add (info->file , t_type, t_data, t_size) != FDS_OK) {
410+ if (fds_file_write_tmplt_add (info->file , new_t_type, new_t_data, new_t_size) != FDS_OK) {
216411 const char *err_msg = fds_file_error (info->file );
217412 throw FDS_exception (" fds_file_write_tmplt_add() failed: " + std::string (err_msg));
218413 }
@@ -258,6 +453,9 @@ Storage::tmplts_update(struct snap_info &info, const fds_tsnapshot_t *snap)
258453 data.ctx = m_ctx;
259454 data.file = m_file.get ();
260455 data.ids .clear ();
456+ data.selection_used = m_selection_used;
457+ data.selection = &m_selection;
458+ data.buffer = &m_buffer;
261459
262460 // Update templates
263461 fds_tsnapshot_for (snap, &tmplt_update_cb, &data);
@@ -436,4 +634,3 @@ Storage::session_ipx2fds(const struct ipx_session *ipx_desc, struct fds_file_ses
436634 memcpy (&fds_desc->ip_dst , &net_desc->addr_dst .ipv6 , sizeof fds_desc->ip_dst );
437635 }
438636}
439-
0 commit comments