Skip to content

Commit 38cf038

Browse files
author
Damir Zainullin
committed
++
1 parent 2529c7f commit 38cf038

File tree

14 files changed

+520
-87
lines changed

14 files changed

+520
-87
lines changed

new-process-api/directionalField.hpp

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,44 @@
22

33
#include <cstdint>
44

5-
enum Direction : std::size_t { Forward = 0, Reverse = 1 };
5+
class Direction {
6+
private:
7+
enum class Value : std::size_t {};
8+
public:
9+
constexpr static Value Forward = static_cast<Value>(0);
10+
constexpr static Value Reverse = static_cast<Value>(1);
11+
12+
constexpr Direction(const Value value) noexcept
13+
: m_value(value) {}
14+
15+
constexpr Direction(const bool value) noexcept
16+
: m_value(static_cast<Value>(value)) {}
17+
18+
constexpr operator Value() const noexcept
19+
{
20+
return m_value;
21+
}
22+
23+
constexpr Direction operator!() const noexcept
24+
{
25+
return m_value == Direction::Forward ? Direction::Reverse : Direction::Forward;
26+
}
27+
private:
28+
Value m_value;
29+
};
30+
631

732
template<typename T>
833
struct DirectionalField {
934
T values[2]{};
1035

11-
constexpr T& operator[](Direction d) { return values[static_cast<std::size_t>(d)]; }
12-
constexpr const T& operator[](Direction d) const { return values[static_cast<std::size_t>(d)]; }
36+
constexpr T& operator[](Direction d)
37+
{
38+
return d == Direction::Forward ? values[0] : values[1];
39+
}
40+
41+
constexpr const T& operator[](Direction d) const
42+
{
43+
return d == Direction::Forward ? values[0] : values[1];
44+
}
1345
};

new-process-api/fieldGroup.hpp

Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
/**
2+
* @file
3+
* @author Pavel Siska <[email protected]>
4+
* @brief Provides the FieldGroup class for registering scalar, vector, directional, and biflow
5+
* fields.
6+
*
7+
* FieldGroup is responsible for managing field metadata within a specific group.
8+
* It allows adding scalar and vector fields, as well as pairs of fields that
9+
* represent either directional or biflow traffic. The class interfaces with
10+
* FieldManager to register fields and maintain consistency in FlowRecords.
11+
*
12+
* The template methods enable flexible accessor functions for fields, supporting:
13+
* - Scalar values
14+
* - Vector values (std::span)
15+
* - Directional field pairs (forward/reverse)
16+
* - Biflow field pairs (A/B)
17+
*
18+
* @note FieldGroup instances are constructed by FieldManager and are tied to
19+
* a specific field group.
20+
*
21+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
22+
*/
23+
24+
#pragma once
25+
26+
#include "fieldGroupTypeTraits.hpp"
27+
#include "fieldHandler.hpp"
28+
#include "fieldManager.hpp"
29+
30+
#include <cstdint>
31+
#include <string_view>
32+
#include <type_traits>
33+
#include <utility>
34+
35+
namespace ipxp {
36+
37+
/**
38+
* @class FieldGroup
39+
* @brief Manages registration of scalar, vector, directional, and biflow fields.
40+
*
41+
* FieldGroup acts as a bridge between user-provided accessor functions and the FieldManager,
42+
* ensuring type consistency and correct registration of fields.
43+
*
44+
* It supports the following types of fields:
45+
* - Scalar values
46+
* - Vector values (`std::span`)
47+
* - Directional field pairs (forward/reverse)
48+
* - Biflow field pairs (A/B)
49+
*
50+
* ### Directional Pairs
51+
*
52+
* DirectionalPair is used for fields that have a forward and a reverse component.
53+
* Typical example: `packets` (forward) and `packets_rev` (reverse).
54+
*
55+
* Behavior depends on flow orientation:
56+
*
57+
* | Flow Type | Forward Field | Reverse Field |
58+
* |------------------|---------------------|---------------------|
59+
* | Forward Uniflow | exported | ignored |
60+
* | Reverse Uniflow | ignored | exported as forward |
61+
* | Biflow | exported | exported |
62+
* | Reverse Biflow | exported as reverse | exported as forward |
63+
*
64+
* This ensures consistent handling of directional metrics across different flow representations.
65+
*
66+
* ### Biflow Pairs
67+
*
68+
* BiflowPair is used for fields that conceptually belong to two sides of a bidirectional flow.
69+
* Typical example: `src_port` (A) and `dst_port` (B).
70+
* Behavior depends on flow orientation:
71+
*
72+
* | Flow Type | A Field | B Field |
73+
* |------------------|-----------------|-----------------|
74+
* | Forward Uniflow | exported | exported |
75+
* | Reverse Uniflow | exported as B | exported as A |
76+
* | Biflow | exported | exported |
77+
* | Reverse Biflow | exported as B | exported as A |
78+
*
79+
*
80+
* ## Example: Adding a scalar field
81+
* @code
82+
* FieldGroup group = fieldManager.createFieldGroup("my_group");
83+
*
84+
* group.addScalarField("packet_count", [](const void* rec) {
85+
* return reinterpret_cast<const MyRecord*>(rec)->pktCount;
86+
* });
87+
* @endcode
88+
*
89+
* ## Example: Adding a vector field
90+
* @code
91+
* group.addVectorField("payload", [](const void* rec) {
92+
* auto r = reinterpret_cast<const MyRecord*>(rec);
93+
* return std::span<const uint8_t>(r->payload, r->payloadLength);
94+
* });
95+
* @endcode
96+
*
97+
* ## Example: Adding a directional pair of scalar fields
98+
* @code
99+
* group.addScalarDirectionalFields(
100+
* "fwd_packets", "rev_packets",
101+
* [](const void* rec) { return reinterpret_cast<const MyRecord*>(rec)->fwdCount; },
102+
* [](const void* rec) { return reinterpret_cast<const MyRecord*>(rec)->revCount; }
103+
* );
104+
* @endcode
105+
*/
106+
class FieldGroup {
107+
public:
108+
/**
109+
* @brief Registers a scalar field.
110+
*
111+
* @tparam AccessorFunction Callable returning the field value.
112+
* @param fieldName Name of the field.
113+
* @param accessorFunction Function that retrieves the field value.
114+
* @return FieldHandler Handle to the registered field.
115+
*/
116+
template<typename AccessorFunction>
117+
[[nodiscard]] FieldHandler
118+
addScalarField(std::string_view fieldName, AccessorFunction&& accessorFunction)
119+
{
120+
return addFieldGeneric<ScalarAccessor>(
121+
fieldName,
122+
std::forward<AccessorFunction>(accessorFunction));
123+
}
124+
125+
/**
126+
* @brief Registers a vector field.
127+
*
128+
* @tparam AccessorFunction Callable returning a `std::span` of values.
129+
* @param fieldName Name of the field.
130+
* @param accessorFunction Function that retrieves the field values.
131+
* @return FieldHandler Handle to the registered field.
132+
*/
133+
template<typename AccessorFunction>
134+
[[nodiscard]] FieldHandler
135+
addVectorField(std::string_view fieldName, AccessorFunction&& accessorFunction)
136+
{
137+
return addFieldGeneric<VectorAccessor>(
138+
fieldName,
139+
std::forward<AccessorFunction>(accessorFunction));
140+
}
141+
142+
/**
143+
* @brief Registers a pair of scalar fields representing directional traffic.
144+
*
145+
* @note This registers a **DirectionalPair**, see class documentation for behavior.
146+
*
147+
* @tparam ForwardAccessorFunction Accessor for the forward direction.
148+
* @tparam ReverseAccessorFunction Accessor for the reverse direction.
149+
* @param forwardFieldName Name of the forward field.
150+
* @param reverseFieldName Name of the reverse field.
151+
* @param forwardAccessorFunction Getter for the forward value.
152+
* @param reverseAccessorFunction Getter for the reverse value.
153+
* @return Pair of FieldHandler objects for forward and reverse fields.
154+
*/
155+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
156+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addScalarDirectionalFields(
157+
std::string_view forwardFieldName,
158+
std::string_view reverseFieldName,
159+
ForwardAccessorFunction&& forwardAccessorFunction,
160+
ReverseAccessorFunction&& reverseAccessorFunction)
161+
{
162+
return addPairFieldsGeneric<ScalarAccessor>(
163+
forwardFieldName,
164+
reverseFieldName,
165+
std::forward<ForwardAccessorFunction>(forwardAccessorFunction),
166+
std::forward<ReverseAccessorFunction>(reverseAccessorFunction),
167+
PairType::Directional);
168+
}
169+
170+
/**
171+
* @brief Registers a pair of vector fields representing directional traffic.
172+
*
173+
* @note This registers a **DirectionalPair**, see class documentation for behavior.
174+
*
175+
* @tparam ForwardAccessorFunction Accessor for the forward direction.
176+
* @tparam ReverseAccessorFunction Accessor for the reverse direction.
177+
* @param forwardFieldName Name of the forward field.
178+
* @param reverseFieldName Name of the reverse field.
179+
* @param forwardAccessorFunction Getter for the forward value.
180+
* @param reverseAccessorFunction Getter for the reverse value.
181+
* @return Pair of FieldHandler objects for forward and reverse fields.
182+
*/
183+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
184+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addVectorDirectionalFields(
185+
std::string_view forwardFieldName,
186+
std::string_view reverseFieldName,
187+
ForwardAccessorFunction&& forwardAccessorFunction,
188+
ReverseAccessorFunction&& reverseAccessorFunction)
189+
{
190+
return addPairFieldsGeneric<VectorAccessor>(
191+
forwardFieldName,
192+
reverseFieldName,
193+
std::forward<ForwardAccessorFunction>(forwardAccessorFunction),
194+
std::forward<ReverseAccessorFunction>(reverseAccessorFunction),
195+
PairType::Directional);
196+
}
197+
198+
/**
199+
* @brief Registers a pair of scalar fields representing biflow traffic.
200+
*
201+
* @note This registers a **BiflowPair**, see class documentation for behavior.
202+
*
203+
* @param aFieldName Name of the "A" field.
204+
* @param bFieldName Name of the "B" field.
205+
* @param aGetter Getter for the "A" value.
206+
* @param bGetter Getter for the "B" value.
207+
*/
208+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
209+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addScalarBiflowFields(
210+
std::string_view aFieldName,
211+
std::string_view bFieldName,
212+
ForwardAccessorFunction&& aGetter,
213+
ReverseAccessorFunction&& bGetter)
214+
{
215+
return addPairFieldsGeneric<ScalarAccessor>(
216+
aFieldName,
217+
bFieldName,
218+
std::forward<ForwardAccessorFunction>(aGetter),
219+
std::forward<ReverseAccessorFunction>(bGetter),
220+
PairType::Biflow);
221+
}
222+
223+
/**
224+
* @brief Registers a pair of vector fields representing biflow traffic.
225+
*
226+
* @note This registers a **BiflowPair**, see class documentation for behavior.
227+
*
228+
* @param aFieldName Name of the "A" field.
229+
* @param bFieldName Name of the "B" field.
230+
* @param aGetter Getter for the "A" value.
231+
* @param bGetter Getter for the "B" value.
232+
*/
233+
template<typename ForwardAccessorFunction, typename ReverseAccessorFunction>
234+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addVectorBiflowFields(
235+
std::string_view aFieldName,
236+
std::string_view bFieldName,
237+
ForwardAccessorFunction&& aGetter,
238+
ReverseAccessorFunction&& bGetter)
239+
{
240+
return addPairFieldsGeneric<VectorAccessor>(
241+
aFieldName,
242+
bFieldName,
243+
std::forward<ForwardAccessorFunction>(aGetter),
244+
std::forward<ReverseAccessorFunction>(bGetter),
245+
PairType::Biflow);
246+
}
247+
248+
private:
249+
template<typename AccessorFunction>
250+
using FieldType = std::invoke_result_t<AccessorFunction, const void*>;
251+
252+
template<typename AccessorFunction>
253+
using ElementType = typename span_element_type<FieldType<AccessorFunction>>::type;
254+
255+
enum class PairType : uint8_t {
256+
Directional,
257+
Biflow,
258+
};
259+
260+
// Can be constructed only by FieldManager
261+
friend class FieldManager;
262+
263+
FieldGroup(std::string_view groupName, FieldManager& manager)
264+
: m_groupName(std::string(groupName))
265+
, m_fieldManager(manager)
266+
{
267+
}
268+
269+
template<template<typename> class Accessor, typename AccessorFunction>
270+
[[nodiscard]] FieldHandler
271+
addFieldGeneric(std::string_view fieldName, AccessorFunction&& accessorFunction)
272+
{
273+
using T = FieldType<AccessorFunction>;
274+
return m_fieldManager.registerField(
275+
m_groupName,
276+
fieldName,
277+
Accessor<T> {std::forward<AccessorFunction>(accessorFunction)});
278+
}
279+
280+
// T
281+
template<
282+
template<typename> class Accessor,
283+
typename ForwardAccessorFunction,
284+
typename ReverseAccessorFunction>
285+
[[nodiscard]] std::pair<FieldHandler, FieldHandler> addPairFieldsGeneric(
286+
std::string_view fieldNameA,
287+
std::string_view fieldNameB,
288+
ForwardAccessorFunction&& forwardAccessorFunction,
289+
ReverseAccessorFunction&& reverseAccessorFunctionB,
290+
PairType pairType)
291+
{
292+
using TaRaw = FieldType<ForwardAccessorFunction>;
293+
using TbRaw = FieldType<ReverseAccessorFunction>;
294+
295+
static_assert(
296+
std::is_same_v<TaRaw, TbRaw>,
297+
"Accessor functions for pair fields must return the same type");
298+
299+
using Ta = std::conditional_t<
300+
is_scalar_accessor<Accessor, FieldType<ForwardAccessorFunction>>::value,
301+
TaRaw,
302+
ElementType<ForwardAccessorFunction>>;
303+
304+
using Tb = std::conditional_t<
305+
is_scalar_accessor<Accessor, FieldType<ReverseAccessorFunction>>::value,
306+
TbRaw,
307+
ElementType<ReverseAccessorFunction>>;
308+
309+
const Accessor<Ta> accessorA {
310+
std::forward<ForwardAccessorFunction>(forwardAccessorFunction)};
311+
const Accessor<Tb> accessorB {
312+
std::forward<ReverseAccessorFunction>(reverseAccessorFunctionB)};
313+
314+
switch (pairType) {
315+
case PairType::Biflow:
316+
return m_fieldManager.registerBiflowPairFields(
317+
m_groupName,
318+
fieldNameA,
319+
fieldNameB,
320+
std::move(accessorA),
321+
std::move(accessorB));
322+
case PairType::Directional:
323+
return m_fieldManager.registerDirectionalPairFields(
324+
m_groupName,
325+
fieldNameA,
326+
fieldNameB,
327+
std::move(accessorA),
328+
std::move(accessorB));
329+
}
330+
331+
__builtin_unreachable();
332+
}
333+
334+
std::string m_groupName;
335+
FieldManager& m_fieldManager;
336+
};
337+
338+
} // namespace ipxp

new-process-api/fieldSupportedTypes.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ using NumericFieldTypes = std::
4444
*
4545
* Contains specialized types like Timestamp, IP and MAC addresses.
4646
*/
47-
using CustomFieldTypes = std::tuple<Timestamp, IPAddress, MacAddress>;
47+
using CustomFieldTypes = std::tuple<Timestamp, IPAddress, MACAddress>;
4848

4949
/**
5050
* @brief Helper alias for compile-time concatenation of multiple `std::tuple` type lists.

0 commit comments

Comments
 (0)