Skip to content

Commit 750a096

Browse files
committed
FDS input: initial version of FDS File reader
1 parent b0b3a00 commit 750a096

File tree

12 files changed

+1719
-2
lines changed

12 files changed

+1719
-2
lines changed

src/plugins/input/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# List of input plugins to build and install
22
add_subdirectory(dummy)
3-
add_subdirectory(ipfix)
43
add_subdirectory(tcp)
5-
add_subdirectory(udp)
4+
add_subdirectory(udp)
5+
add_subdirectory(ipfix)
6+
add_subdirectory(fds)

src/plugins/input/fds/Builder.cpp

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/**
2+
* \file src/plugins/input/fds/Builder.cpp
3+
* \author Lukas Hutak <[email protected]>
4+
* \brief IPFIX Message builder (implementation)
5+
* \date May 2020
6+
*/
7+
8+
#include <arpa/inet.h>
9+
#include <cstdlib>
10+
11+
#include "Builder.hpp"
12+
#include "Exception.hpp"
13+
14+
15+
Builder::Builder(uint16_t size)
16+
{
17+
struct fds_ipfix_msg_hdr *hdr_ptr;
18+
19+
if (size < FDS_IPFIX_MSG_HDR_LEN) {
20+
throw FDS_exception("[internal] Invalid size of a message to generate!");
21+
}
22+
23+
m_msg.reset((uint8_t *) malloc(size));
24+
if (!m_msg) {
25+
throw FDS_exception("Memory allocation error " + std::string(__PRETTY_FUNCTION__));
26+
}
27+
28+
// Fill the message header (size will be filled on release)
29+
hdr_ptr = reinterpret_cast<fds_ipfix_msg_hdr *>(m_msg.get());
30+
hdr_ptr->version = htons(FDS_IPFIX_VERSION);
31+
hdr_ptr->odid = 0;
32+
hdr_ptr->seq_num = 0;
33+
hdr_ptr->export_time = 0;
34+
35+
// Positions
36+
m_msg_alloc = size;
37+
m_msg_valid = FDS_IPFIX_MSG_HDR_LEN;
38+
m_set_offset = 0;
39+
m_set_id = 0; // invalid
40+
}
41+
42+
void
43+
Builder::resize(uint16_t size)
44+
{
45+
uint8_t *new_ptr = (uint8_t *) realloc(m_msg.get(), size);
46+
if (!new_ptr) {
47+
throw FDS_exception("Memory allocation error " + std::string(__PRETTY_FUNCTION__));
48+
}
49+
50+
m_msg.release(); // To avoid calling free()
51+
m_msg.reset(new_ptr);
52+
m_msg_alloc = size;
53+
54+
if (m_msg_valid > m_msg_alloc) {
55+
// The message has been trimmed!
56+
m_msg_valid = m_msg_alloc;
57+
}
58+
59+
if (m_set_offset + FDS_IPFIX_SET_HDR_LEN > m_msg_alloc) {
60+
// The current offset is out of range
61+
m_set_offset = 0;
62+
m_set_id = 0;
63+
}
64+
}
65+
66+
bool
67+
Builder::empty()
68+
{
69+
return (!m_msg || m_msg_valid == FDS_IPFIX_MSG_HDR_LEN);
70+
}
71+
72+
uint8_t *
73+
Builder::release()
74+
{
75+
// Close the current set (if any)
76+
fset_close();
77+
78+
// Update IPFIX Message header (size)
79+
struct fds_ipfix_msg_hdr *hdr_ptr;
80+
hdr_ptr = reinterpret_cast<fds_ipfix_msg_hdr *>(m_msg.get());
81+
hdr_ptr->length = htons(m_msg_valid);
82+
83+
m_msg_alloc = 0;
84+
m_msg_valid = 0;
85+
return m_msg.release();
86+
}
87+
88+
/**
89+
* @brief Create a new Set
90+
*
91+
* The previous Set is always closed even if the ID is the same.
92+
* @param[in] sid Set ID
93+
* @throw FDS_exception if the Message is full and the Set cannot be created
94+
*/
95+
void
96+
Builder::fset_new(uint16_t sid)
97+
{
98+
// Close the previous set (if any)
99+
fset_close();
100+
101+
// Initialize a new IPFIX Set
102+
if (FDS_IPFIX_SET_HDR_LEN > m_msg_alloc - m_msg_valid) {
103+
throw FDS_exception("[internal] Insufficient space for Set in an IPFIX Message");
104+
}
105+
106+
m_set_offset = m_msg_valid;
107+
auto *set_ptr = reinterpret_cast<struct fds_ipfix_set_hdr *>(&m_msg.get()[m_set_offset]);
108+
set_ptr->flowset_id = htons(sid);
109+
m_msg_valid += FDS_IPFIX_SET_HDR_LEN;
110+
m_set_size = FDS_IPFIX_SET_HDR_LEN;
111+
m_set_id = sid;
112+
}
113+
114+
/**
115+
* @brief Close the current Set (if any)
116+
*/
117+
void
118+
Builder::fset_close()
119+
{
120+
if (m_set_offset == 0) {
121+
return;
122+
}
123+
124+
auto *set_ptr = reinterpret_cast<struct fds_ipfix_set_hdr *>(&m_msg.get()[m_set_offset]);
125+
set_ptr->length = htons(m_set_size);
126+
m_set_offset = 0;
127+
m_set_id = 0;
128+
}
129+
130+
void
131+
Builder::set_etime(uint32_t time)
132+
{
133+
if (!m_msg) {
134+
throw FDS_exception("[internal] IPFIX Message is not allocated!");
135+
}
136+
137+
// Update IPFIX Message header (export time)
138+
struct fds_ipfix_msg_hdr *hdr_ptr;
139+
hdr_ptr = reinterpret_cast<fds_ipfix_msg_hdr *>(m_msg.get());
140+
hdr_ptr->export_time = htonl(time);
141+
}
142+
143+
void
144+
Builder::set_odid(uint32_t odid)
145+
{
146+
if (!m_msg) {
147+
throw FDS_exception("[internal] IPFIX Message is not allocated!");
148+
}
149+
150+
// Update IPFIX Message header (export time)
151+
struct fds_ipfix_msg_hdr *hdr_ptr;
152+
hdr_ptr = reinterpret_cast<fds_ipfix_msg_hdr *>(m_msg.get());
153+
hdr_ptr->odid = htonl(odid);
154+
}
155+
156+
void
157+
Builder::set_seqnum(uint32_t seq_num)
158+
{
159+
if (!m_msg) {
160+
throw FDS_exception("[internal] IPFIX Message is not allocated!");
161+
}
162+
163+
// Update IPFIX Message header (export time)
164+
struct fds_ipfix_msg_hdr *hdr_ptr;
165+
hdr_ptr = reinterpret_cast<fds_ipfix_msg_hdr *>(m_msg.get());
166+
hdr_ptr->seq_num = htonl(seq_num);
167+
}
168+
169+
bool
170+
Builder::add_template(const struct fds_template *tmplt)
171+
{
172+
uint16_t tmplt_len = tmplt->raw.length;
173+
uint16_t size_req = tmplt_len;
174+
uint16_t set_id;
175+
176+
switch (tmplt->type) {
177+
case FDS_TYPE_TEMPLATE:
178+
set_id = FDS_IPFIX_SET_TMPLT;
179+
break;
180+
case FDS_TYPE_TEMPLATE_OPTS:
181+
set_id = FDS_IPFIX_SET_OPTS_TMPLT;
182+
break;
183+
default:
184+
throw FDS_exception("[internal] Unexpected Template type cannot be used!");
185+
}
186+
187+
if (m_set_offset == 0 || set_id != m_set_id) {
188+
// New (Options) Template Set must be created
189+
fset_close();
190+
size_req += FDS_IPFIX_SET_HDR_LEN;
191+
}
192+
193+
if (size_req > m_msg_alloc - m_msg_valid) {
194+
// Unable to add
195+
return false;
196+
}
197+
198+
if (m_set_offset == 0) {
199+
fset_new(set_id);
200+
}
201+
202+
memcpy(&m_msg.get()[m_msg_valid], tmplt->raw.data, tmplt_len);
203+
m_msg_valid += tmplt_len;
204+
m_set_size += tmplt_len;
205+
return true;
206+
}
207+
208+
209+
bool
210+
Builder::add_record(const struct fds_drec *rec)
211+
{
212+
uint16_t size_req = rec->size;
213+
if (m_set_offset == 0 || rec->tmplt->id != m_set_id) {
214+
// New Data Set must be created
215+
fset_close();
216+
size_req += FDS_IPFIX_SET_HDR_LEN;
217+
}
218+
219+
if (size_req > m_msg_alloc - m_msg_valid) {
220+
// Unable to add
221+
return false;
222+
}
223+
224+
if (m_set_offset == 0) {
225+
fset_new(rec->tmplt->id);
226+
}
227+
228+
memcpy(&m_msg.get()[m_msg_valid], rec->data, rec->size);
229+
m_msg_valid += rec->size;
230+
m_set_size += rec->size;
231+
return true;
232+
}
233+
234+
bool
235+
Builder::add_withdrawals()
236+
{
237+
struct fds_ipfix_trec *rec_ptr = nullptr;
238+
uint16_t size_req = 2U * FDS_IPFIX_WDRL_ALLSET_LEN;
239+
240+
if (size_req > m_msg_alloc - m_msg_valid) {
241+
return false;
242+
}
243+
244+
// All Templates Withdrawal
245+
fset_new(FDS_IPFIX_SET_TMPLT);
246+
rec_ptr = reinterpret_cast<struct fds_ipfix_trec *>(&m_msg.get()[m_msg_valid]);
247+
rec_ptr->template_id = htons(FDS_IPFIX_SET_TMPLT);
248+
rec_ptr->count = htons(0);
249+
m_msg_valid += 4U; // Only 4 bytes as specified in RFC 7011, 8.1
250+
m_set_size += 4U;
251+
fset_close();
252+
253+
// All Options Template Withdrawal
254+
fset_new(FDS_IPFIX_SET_OPTS_TMPLT);
255+
rec_ptr = reinterpret_cast<struct fds_ipfix_trec *>(&m_msg.get()[m_msg_valid]);
256+
rec_ptr->template_id = htons(FDS_IPFIX_SET_OPTS_TMPLT);
257+
rec_ptr->count = htons(0);
258+
m_msg_valid += 4U; // Only 4 bytes as specified in RFC 7011, 8.1
259+
m_set_size += 4U;
260+
fset_close();
261+
262+
return true;
263+
}

src/plugins/input/fds/Builder.hpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/**
2+
* \file src/plugins/input/fds/Builder.hpp
3+
* \author Lukas Hutak <[email protected]>
4+
* \brief IPFIX Message builder
5+
* \date May 2020
6+
*/
7+
8+
#ifndef FDS_BUILDER_HPP
9+
#define FDS_BUILDER_HPP
10+
11+
#include <memory>
12+
#include <libfds.h>
13+
14+
/// IPFIX Message builder
15+
class Builder {
16+
private:
17+
/// Memory of IPFIX Message to generate (can be nullptr)
18+
std::unique_ptr<uint8_t, decltype(&free)> m_msg = {nullptr, &free};
19+
/// Allocated size (bytes)
20+
uint16_t m_msg_alloc;
21+
/// Filled size (bytes)
22+
uint16_t m_msg_valid;
23+
24+
/// Currently edited Flow Set (zero == invalid)
25+
uint16_t m_set_offset;
26+
/// Set ID of the current Flow Set
27+
uint16_t m_set_id;
28+
/// Size of the current IPFIX Set
29+
uint16_t m_set_size;
30+
31+
void
32+
fset_new(uint16_t sid);
33+
void
34+
fset_close();
35+
36+
public:
37+
/**
38+
* @brief Create an IPFIX Message generator
39+
*
40+
* By default, ODID, Sequence Number, and Export Time are set to zeros.
41+
* @param[in] size Maximal size of the message (allocation size)
42+
*/
43+
Builder(uint16_t size);
44+
~Builder() = default;
45+
Builder(Builder &&other) = default;
46+
47+
/**
48+
* @brief Change maximal size of the message
49+
*
50+
* If the size is less than the size of the currently built message, the
51+
* message is trimmed!
52+
* @param[in] size Maximal size (i.e. allocation size)
53+
*/
54+
void
55+
resize(uint16_t size);
56+
/**
57+
* @brief Test if the builder contains an IPFIX Message without content
58+
*
59+
* @note The builder is also considered as empty after release().
60+
* @return True/false
61+
*/
62+
bool
63+
empty();
64+
/**
65+
* @brief Release the generated IPFIX Message
66+
* @warning After releasing, the class functions MUST NOT be used anymore!
67+
* @return Pointer to the message (real size is part of the Message)
68+
*/
69+
uint8_t *
70+
release();
71+
72+
/**
73+
* @brief Set Export Time of the IPFIX Message
74+
* @param[in] time Export Time
75+
*/
76+
void
77+
set_etime(uint32_t time);
78+
/**
79+
* @brief Set Observation Domain ID (ODID) of the IPFIX Message
80+
* @param[in] odid ODID
81+
*/
82+
void
83+
set_odid(uint32_t odid);
84+
/**
85+
* @brief Set Sequence Number of the IPFIX Message
86+
* @param[in] seq_num Sequence Number
87+
*/
88+
void
89+
set_seqnum(uint32_t seq_num);
90+
91+
/**
92+
* @brief Add an (Options) Template Record
93+
* @param[in] tmplt IPFIX (Options) Template
94+
* @return True, if the Template has been successfully added
95+
* @return False, if the Message is already full
96+
*/
97+
bool
98+
add_template(const struct fds_template *tmplt);
99+
/**
100+
* @brief Add a Data Record
101+
* @param[in] rec IPFIX Data Record
102+
* @return True, if the Record has been successfully added
103+
* @return False, if the Message is already full
104+
*/
105+
bool
106+
add_record(const struct fds_drec *rec);
107+
/**
108+
* @brief Add an All (Options) Template Withdrawals (only TCP, SCTP, and File sessions)
109+
* @note
110+
* After calling the function, all previous (Options) Templates are considered to
111+
* be invalid.
112+
* @return True, if the Withdrawals has been successfully added
113+
* @return False, if the Message is already full
114+
*/
115+
bool
116+
add_withdrawals();
117+
};
118+
119+
#endif // FDS_BUILDER_HPP

0 commit comments

Comments
 (0)