Skip to content

Commit cac1caa

Browse files
committed
fdsdump: add an abstract/base field class
1 parent 01379fe commit cac1caa

File tree

2 files changed

+392
-0
lines changed

2 files changed

+392
-0
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
/**
2+
* @file
3+
* @author Michal Sedlak <[email protected]>
4+
* @brief Field base
5+
*
6+
* Copyright: (C) 2024 CESNET, z.s.p.o.
7+
* SPDX-License-Identifier: BSD-3-Clause
8+
*/
9+
10+
#include <aggregator/field.hpp>
11+
12+
#include <libfds.h>
13+
14+
#include <stdexcept>
15+
16+
namespace fdsdump {
17+
namespace aggregator {
18+
19+
void
20+
Field::set_data_type(DataType data_type)
21+
{
22+
m_data_type = data_type;
23+
24+
switch (data_type) {
25+
case DataType::IPv4Address:
26+
m_size = sizeof(Value::ipv4);
27+
break;
28+
case DataType::IPv6Address:
29+
m_size = sizeof(Value::ipv6);
30+
break;
31+
case DataType::IPAddress:
32+
m_size = sizeof(Value::ip);
33+
break;
34+
case DataType::MacAddress:
35+
m_size = sizeof(Value::mac);
36+
break;
37+
case DataType::Signed8:
38+
m_size = sizeof(Value::i8);
39+
break;
40+
case DataType::Signed16:
41+
m_size = sizeof(Value::i16);
42+
break;
43+
case DataType::Signed32:
44+
m_size = sizeof(Value::i32);
45+
break;
46+
case DataType::Signed64:
47+
m_size = sizeof(Value::i64);
48+
break;
49+
case DataType::Unsigned8:
50+
m_size = sizeof(Value::u8);
51+
break;
52+
case DataType::Unsigned16:
53+
m_size = sizeof(Value::u16);
54+
break;
55+
case DataType::Unsigned32:
56+
m_size = sizeof(Value::u32);
57+
break;
58+
case DataType::Unsigned64:
59+
m_size = sizeof(Value::u64);
60+
break;
61+
case DataType::DateTime:
62+
m_size = sizeof(Value::ts_millisecs);
63+
break;
64+
case DataType::String128B:
65+
m_size = sizeof(Value::str);
66+
break;
67+
case DataType::Octets128B:
68+
m_size = sizeof(Value::str);
69+
break;
70+
case DataType::Unassigned:
71+
throw std::logic_error("unexpected field data type");
72+
}
73+
}
74+
75+
void
76+
Field::set_offset(size_t offset)
77+
{
78+
m_offset = offset;
79+
}
80+
81+
void
82+
Field::set_name(std::string name)
83+
{
84+
m_name = name;
85+
}
86+
87+
bool
88+
Field::load(FlowContext &ctx, Value &value) const
89+
{
90+
(void) ctx;
91+
(void) value;
92+
throw std::logic_error("unimplemented load for field " + name());
93+
}
94+
95+
void
96+
Field::init(Value &value) const
97+
{
98+
(void) value;
99+
throw std::logic_error("unimplemented init for field " + name());
100+
}
101+
102+
bool
103+
Field::aggregate(FlowContext &ctx, Value &aggregated_value) const
104+
{
105+
(void) ctx;
106+
(void) aggregated_value;
107+
throw std::logic_error("unimplemented aggregate for field " + name());
108+
}
109+
110+
void
111+
Field::merge(Value &value, const Value &other) const
112+
{
113+
(void) value;
114+
(void) other;
115+
throw std::logic_error("unimplemented merge for field " + name());
116+
}
117+
118+
template <typename T>
119+
static CmpResult
120+
cmp(T a, T b)
121+
{
122+
if (a < b) {
123+
return CmpResult::Lt;
124+
} else if (a > b) {
125+
return CmpResult::Gt;
126+
} else {
127+
return CmpResult::Eq;
128+
}
129+
}
130+
131+
static CmpResult
132+
cmp(const uint8_t *a, const uint8_t *b, size_t count)
133+
{
134+
int result = std::memcmp(a, b, count);
135+
if (result < 0) {
136+
return CmpResult::Lt;
137+
} else if (result > 0) {
138+
return CmpResult::Gt;
139+
} else {
140+
return CmpResult::Eq;
141+
}
142+
}
143+
144+
CmpResult
145+
Field::compare(const Value &a, const Value &b) const
146+
{
147+
switch (data_type()) {
148+
case DataType::Unsigned8:
149+
return cmp(a.u8, b.u8);
150+
case DataType::Signed8:
151+
return cmp(a.i8, b.i8);
152+
case DataType::Unsigned16:
153+
return cmp(a.u16, b.u16);
154+
case DataType::Signed16:
155+
return cmp(a.i16, b.i16);
156+
case DataType::Unsigned32:
157+
return cmp(a.u32, b.u32);
158+
case DataType::Signed32:
159+
return cmp(a.i32, b.i32);
160+
case DataType::Unsigned64:
161+
return cmp(a.u64, b.u64);
162+
case DataType::Signed64:
163+
return cmp(a.i64, b.i64);
164+
case DataType::DateTime:
165+
return cmp(a.ts_millisecs, b.ts_millisecs);
166+
case DataType::IPv4Address:
167+
return cmp(a.ipv4, b.ipv4, sizeof(a.ipv4));
168+
case DataType::IPv6Address:
169+
return cmp(a.ipv6, b.ipv6, sizeof(a.ipv6));
170+
case DataType::IPAddress:
171+
return cmp(a.ip, b.ip);
172+
case DataType::MacAddress:
173+
return cmp(a.mac, b.mac, sizeof(a.mac));
174+
case DataType::String128B:
175+
case DataType::Octets128B:
176+
return cmp(reinterpret_cast<const uint8_t *>(a.str), reinterpret_cast<const uint8_t *>(b.str), sizeof(a.str));
177+
case DataType::Unassigned:
178+
throw std::logic_error("cannot compare fields with unassigned data type");
179+
}
180+
181+
__builtin_unreachable();
182+
}
183+
184+
bool
185+
Field::operator==(const std::unique_ptr<Field> &other) const
186+
{
187+
return *this == *other.get();
188+
}
189+
190+
bool
191+
Field::operator!=(const Field &other) const
192+
{
193+
return !(*this == other);
194+
}
195+
196+
bool
197+
Field::is_number() const
198+
{
199+
switch (data_type()) {
200+
case DataType::Unsigned8:
201+
case DataType::Unsigned16:
202+
case DataType::Unsigned32:
203+
case DataType::Unsigned64:
204+
case DataType::Signed8:
205+
case DataType::Signed16:
206+
case DataType::Signed32:
207+
case DataType::Signed64:
208+
return true;
209+
default:
210+
return false;
211+
}
212+
}
213+
214+
} // aggregator
215+
} // fdsdump
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/**
2+
* @file
3+
* @author Michal Sedlak <[email protected]>
4+
* @brief Field base
5+
*
6+
* Copyright: (C) 2024 CESNET, z.s.p.o.
7+
* SPDX-License-Identifier: BSD-3-Clause
8+
*/
9+
10+
#pragma once
11+
12+
#include <aggregator/flowContext.hpp>
13+
#include <aggregator/value.hpp>
14+
15+
#include <libfds.h>
16+
17+
#include <cstddef>
18+
#include <string>
19+
#include <memory>
20+
#include <typeinfo>
21+
22+
namespace fdsdump {
23+
namespace aggregator {
24+
25+
/**
26+
* @brief Result of a comparison
27+
*/
28+
enum class CmpResult {
29+
Lt,
30+
Eq,
31+
Gt
32+
};
33+
34+
/**
35+
* @brief The base class for all aggregator fields
36+
*/
37+
class Field {
38+
39+
public:
40+
/**
41+
* @brief Get the size of the field in bytes
42+
*/
43+
size_t size() const { return m_size; }
44+
45+
/**
46+
* @brief Get the offset of the field from the beginning of the aggregation record
47+
*/
48+
size_t offset() const { return m_offset; }
49+
50+
/**
51+
* @brief Get the name of the field
52+
*/
53+
const std::string &name() const { return m_name; }
54+
55+
/**
56+
* @brief Get the data type of the field
57+
*/
58+
DataType data_type() const { return m_data_type; }
59+
60+
/**
61+
* @brief Load the value of the field flow record
62+
*
63+
* @param[in] ctx The flow record
64+
* @param[out] value The value
65+
*/
66+
virtual bool
67+
load(FlowContext &ctx, Value &value) const;
68+
69+
/**
70+
* @brief Initialize the value with the default value
71+
*
72+
* @param The value
73+
*/
74+
virtual void
75+
init(Value &value) const;
76+
77+
/**
78+
* @brief Aggregate the value retrieved from the provided flow record into the provided
79+
* aggregated value
80+
*
81+
* @param ctx The flow record to retrieve the value that will be aggregated from
82+
* @param aggregated_value The currently accumulated value that the retrieved value will be
83+
* aggregated towards
84+
*
85+
* @return true if the field was found in the flow record and the aggregated value was updated,
86+
* false otherwise
87+
*/
88+
virtual bool
89+
aggregate(FlowContext &ctx, Value &aggregated_value) const;
90+
91+
/**
92+
* @brief Merge one value with another
93+
*
94+
* @param value The value that will be updated with the result of the merge
95+
* @param other The value to merge onto the first value
96+
*/
97+
virtual void
98+
merge(Value &value, const Value &other) const;
99+
100+
/**
101+
* @brief Compare two values
102+
*
103+
* @param a The first value
104+
* @param b The second value
105+
*
106+
* @return the result of the comparison
107+
*/
108+
CmpResult
109+
compare(const Value &a, const Value &b) const;
110+
111+
/**
112+
* @brief Get a string representation of the field
113+
*/
114+
virtual std::string
115+
repr() const = 0;
116+
117+
/**
118+
* @brief Check if the fields are equal
119+
*/
120+
virtual bool
121+
operator==(const Field &other) const = 0;
122+
123+
/**
124+
* @brief Check if the fields are equal
125+
*/
126+
bool
127+
operator==(const std::unique_ptr<Field> &other) const;
128+
129+
/**
130+
* @brief Check if the fields are not equal
131+
*/
132+
bool
133+
operator!=(const Field &other) const;
134+
135+
/**
136+
* @brief Check if the field is of the provided type
137+
*/
138+
template <typename T>
139+
bool
140+
is_of_type() const
141+
{
142+
return typeid(T) == typeid(*this);
143+
}
144+
145+
/**
146+
* @brief Check if the field is a number
147+
*/
148+
bool
149+
is_number() const;
150+
151+
protected:
152+
size_t m_size = 0;
153+
size_t m_offset = 0;
154+
std::string m_name;
155+
DataType m_data_type = DataType::Unassigned;
156+
157+
/**
158+
* @brief Set the data type of the field
159+
*/
160+
void
161+
set_data_type(DataType data_type);
162+
163+
/**
164+
* @brief Set the offset of the field
165+
*/
166+
void
167+
set_offset(size_t offset);
168+
169+
/**
170+
* @brief Set the name of the field
171+
*/
172+
void
173+
set_name(std::string name);
174+
};
175+
176+
} // aggregator
177+
} // fdsdump

0 commit comments

Comments
 (0)