Skip to content

Commit 5965c54

Browse files
Zainullin DamirZainullin Damir
authored andcommitted
Process plugins - Introduce VLAN process plugin
1 parent 2718759 commit 5965c54

File tree

7 files changed

+227
-92
lines changed

7 files changed

+227
-92
lines changed

src/plugins/process/vlan/CMakeLists.txt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,20 @@ project(ipfixprobe-process-vlan VERSION 1.0.0 DESCRIPTION "ipfixprobe-process-vl
33
add_library(ipfixprobe-process-vlan MODULE
44
src/vlan.cpp
55
src/vlan.hpp
6+
src/vlanContext.hpp
7+
src/vlanFields.hpp
68
)
79

810
set_target_properties(ipfixprobe-process-vlan PROPERTIES
911
CXX_VISIBILITY_PRESET hidden
1012
VISIBILITY_INLINES_HIDDEN YES
1113
)
1214

13-
target_include_directories(ipfixprobe-process-vlan PRIVATE
15+
target_include_directories(ipfixprobe-process-vlan PRIVATE
1416
${CMAKE_SOURCE_DIR}/include/
17+
${CMAKE_SOURCE_DIR}/include/ipfixprobe/processPlugin
18+
${CMAKE_SOURCE_DIR}/include/ipfixprobe/pluginFactory
19+
${adaptmon_SOURCE_DIR}/lib/include/public/
1520
)
1621

1722
if(ENABLE_NEMEA)

src/plugins/process/vlan/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# VLAN Plugin
2+
3+
The **VLAN Plugin** parses VLAN tags and exports extracted values.
4+
5+
## Features
6+
7+
- Extracts and exports VLAN ID.
8+
9+
## Output Fields
10+
11+
| Field Name | Data Type | Description |
12+
| ---------- | ---------- | ---------------------------------- |
13+
| `VLAN_ID` | `uint16_t` | VLAN ID extracted from the packet. |
14+
15+
## Usage
16+
17+
### YAML Configuration
18+
19+
Add the plugin to your ipfixprobe YAML configuration:
20+
21+
```yaml
22+
process_plugins:
23+
- vlan
24+
```
25+
26+
### CLI Usage
27+
28+
You can also enable the plugin directly from the command line:
29+
30+
`ipfixprobe -p vlan ...`

src/plugins/process/vlan/src/vlan.cpp

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,33 @@
33
* @brief Plugin for parsing basicplus traffic.
44
* @author Jakub Antonín Štigler xstigl00@[email protected]
55
* @author Pavel Siska <[email protected]>
6+
* @author Damir Zainullin <[email protected]>
67
* @date 2025
78
*
8-
* Copyright (c) 2025 CESNET
9+
* Provides a plugin that parses VLAN traffic,
10+
* stores it in per-flow plugin data, and exposes that field via FieldManager.
911
*
10-
* SPDX-License-Identifier: BSD-3-Clause
12+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
1113
*/
1214

1315
#include "vlan.hpp"
1416

17+
#include "vlanContext.hpp"
18+
#include "vlanGetters.hpp"
19+
1520
#include <iostream>
1621

17-
#include <ipfixprobe/pluginFactory/pluginManifest.hpp>
18-
#include <ipfixprobe/pluginFactory/pluginRegistrar.hpp>
22+
#include <amon/layers/VLAN.hpp>
23+
#include <fieldGroup.hpp>
24+
#include <fieldManager.hpp>
25+
#include <flowRecord.hpp>
26+
#include <ipfixprobe/options.hpp>
27+
#include <pluginFactory.hpp>
28+
#include <pluginManifest.hpp>
29+
#include <pluginRegistrar.hpp>
30+
#include <utils.hpp>
1931

20-
namespace ipxp {
32+
namespace ipxp::process::vlan {
2133

2234
static const PluginManifest vlanPluginManifest = {
2335
.name = "vlan",
@@ -31,25 +43,56 @@ static const PluginManifest vlanPluginManifest = {
3143
},
3244
};
3345

34-
VLANPlugin::VLANPlugin(const std::string& params, int pluginID)
35-
: ProcessPlugin(pluginID)
46+
static FieldGroup
47+
createVLANSchema(FieldManager& fieldManager, FieldHandlers<VLANFields>& handlers) noexcept
48+
{
49+
FieldGroup schema = fieldManager.createFieldGroup("vlan");
50+
51+
handlers.insert(VLANFields::VLAN_ID, schema.addScalarField("VLAN_ID", getVLANIdField));
52+
53+
return schema;
54+
}
55+
56+
VLANPlugin::VLANPlugin([[maybe_unused]] const std::string& params, FieldManager& manager)
3657
{
37-
init(params.c_str());
58+
createVLANSchema(manager, m_fieldHandlers);
59+
}
60+
61+
OnInitResult VLANPlugin::onInit(const FlowContext& flowContext, void* pluginContext)
62+
{
63+
if (!flowContext.packetContext.packet->layout.vlan.has_value()) {
64+
return OnInitResult::Irrelevant;
65+
}
66+
67+
auto vlanView = flowContext.packetContext.packet->getLayerView<amon::layers::VLANView>(
68+
std::get<amon::PacketLayer>(flowContext.packetContext.packet
69+
->layers[*flowContext.packetContext.packet->layout.vlan]));
70+
if (!vlanView.has_value()) {
71+
return OnInitResult::Irrelevant;
72+
}
73+
74+
std::construct_at(reinterpret_cast<VLANContext*>(pluginContext))->vlanId = vlanView->tag();
75+
m_fieldHandlers[VLANFields::VLAN_ID].setAsAvailable(flowContext.flowRecord);
76+
77+
return OnInitResult::ConstructedFinal;
3878
}
3979

40-
ProcessPlugin* VLANPlugin::copy()
80+
void VLANPlugin::onDestroy(void* pluginContext) noexcept
4181
{
42-
return new VLANPlugin(*this);
82+
std::destroy_at(reinterpret_cast<VLANContext*>(pluginContext));
4383
}
4484

45-
int VLANPlugin::post_create(Flow& rec, const Packet& pkt)
85+
PluginDataMemoryLayout VLANPlugin::getDataMemoryLayout() const noexcept
4686
{
47-
auto ext = new RecordExtVLAN(m_pluginID);
48-
ext->vlan_id = pkt.vlan_id;
49-
rec.add_extension(ext);
50-
return 0;
87+
return {
88+
.size = sizeof(VLANContext),
89+
.alignment = alignof(VLANContext),
90+
};
5191
}
5292

53-
static const PluginRegistrar<VLANPlugin, ProcessPluginFactory> vlanRegistrar(vlanPluginManifest);
93+
static const PluginRegistrar<
94+
VLANPlugin,
95+
PluginFactory<ProcessPlugin, const std::string&, FieldManager&>>
96+
vlanRegistrar(vlanPluginManifest);
5497

55-
} // namespace ipxp
98+
} // namespace ipxp::process::vlan

src/plugins/process/vlan/src/vlan.hpp

Lines changed: 54 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3,96 +3,76 @@
33
* @brief Plugin for parsing basicplus traffic.
44
* @author Jakub Antonín Štigler xstigl00@[email protected]
55
* @author Pavel Siska <[email protected]>
6+
* @author Damir Zainullin <[email protected]>
67
* @date 2025
78
*
8-
* Copyright (c) 2025 CESNET
9+
* Provides a plugin that parses VLAN traffic,
10+
* stores it in per-flow plugin data, and exposes that field via FieldManager.
911
*
10-
* SPDX-License-Identifier: BSD-3-Clause
12+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
1113
*/
1214

1315
#pragma once
1416

15-
#include <cstring>
17+
#include "vlanFields.hpp"
1618

17-
#ifdef WITH_NEMEA
18-
#include "fields.h"
19-
#endif
20-
21-
#include <cstdint>
2219
#include <sstream>
2320
#include <string>
2421

25-
#include <ipfixprobe/flowifc.hpp>
26-
#include <ipfixprobe/ipfix-elements.hpp>
27-
#include <ipfixprobe/packet.hpp>
28-
#include <ipfixprobe/processPlugin.hpp>
29-
30-
namespace ipxp {
31-
32-
#define VLAN_UNIREC_TEMPLATE "VLAN_ID"
22+
#include <fieldHandlersEnum.hpp>
23+
#include <fieldManager.hpp>
24+
#include <processPlugin.hpp>
3325

34-
UR_FIELDS(uint16 VLAN_ID)
26+
namespace ipxp::process::vlan {
3527

3628
/**
37-
* \brief Flow record extension header for storing parsed VLAN data.
38-
*/
39-
struct RecordExtVLAN : public RecordExt {
40-
// vlan id is in the host byte order
41-
uint16_t vlan_id;
42-
43-
RecordExtVLAN(int pluginID)
44-
: RecordExt(pluginID)
45-
, vlan_id(0)
46-
{
47-
}
48-
49-
#ifdef WITH_NEMEA
50-
virtual void fill_unirec(ur_template_t* tmplt, void* record)
51-
{
52-
ur_set(tmplt, record, F_VLAN_ID, vlan_id);
53-
}
54-
55-
const char* get_unirec_tmplt() const { return VLAN_UNIREC_TEMPLATE; }
56-
#endif
57-
58-
virtual int fill_ipfix(uint8_t* buffer, int size)
59-
{
60-
const int LEN = sizeof(vlan_id);
61-
62-
if (size < LEN) {
63-
return -1;
64-
}
65-
66-
*reinterpret_cast<uint16_t*>(buffer) = htons(vlan_id);
67-
return LEN;
68-
}
69-
70-
const char** get_ipfix_tmplt() const
71-
{
72-
static const char* ipfix_template[] = {IPFIX_VLAN_TEMPLATE(IPFIX_FIELD_NAMES) NULL};
73-
return ipfix_template;
74-
}
75-
76-
std::string get_text() const
77-
{
78-
std::ostringstream out;
79-
out << "vlan_id=\"" << vlan_id << '"';
80-
return out.str();
81-
}
82-
};
83-
84-
/**
85-
* \brief Process plugin for parsing VLAN packets.
29+
* @class VLANPlugin
30+
* @brief A plugin for parsing VLAN traffic.
31+
*
32+
* Collects and exports VLAN ID.
8633
*/
8734
class VLANPlugin : public ProcessPlugin {
8835
public:
89-
VLANPlugin(const std::string& params, int pluginID);
90-
OptionsParser* get_parser() const { return new OptionsParser("vlan", "Parse VLAN traffic"); }
91-
std::string get_name() const { return "vlan"; }
92-
RecordExt* get_ext() const { return new RecordExtVLAN(m_pluginID); }
93-
ProcessPlugin* copy();
94-
95-
int post_create(Flow& rec, const Packet& pkt);
36+
/**
37+
* @brief Constructs the VLAN plugin and initializes field handlers.
38+
* @param params String with plugin-specific parameters for configuration(currently unused).
39+
* @param manager Reference to the FieldManager for field handler registration.
40+
*/
41+
VLANPlugin(const std::string& params, FieldManager& manager);
42+
43+
/**
44+
* @brief Initializes plugin data for a new flow.
45+
*
46+
* Constructs `VLANExport` in `pluginContext` and sets VLAN value.
47+
*
48+
* 0 VLAN value means no VLAN tag present.
49+
*
50+
* @param flowContext Contextual information about the flow to fill new record.
51+
* @param pluginContext Pointer to pre-allocated memory to create record.
52+
* @return Result of the initialization process.
53+
*/
54+
OnInitResult onInit(const FlowContext& flowContext, void* pluginContext) override;
55+
56+
/**
57+
* @brief Destroys plugin data.
58+
*
59+
* Calls the destructor of `VLANContext` in `pluginContext`.
60+
*
61+
* @param pluginContext Pointer to `VLANContext`.
62+
*/
63+
void onDestroy(void* pluginContext) noexcept override;
64+
65+
/**
66+
* @brief Provides memory layout information for `VLANContext`.
67+
*
68+
* Returns the size and alignment requirements of `VLANContext`.
69+
*
70+
* @return Memory layout details for `VLANContext`.
71+
*/
72+
PluginDataMemoryLayout getDataMemoryLayout() const noexcept override;
73+
74+
private:
75+
FieldHandlers<VLANFields> m_fieldHandlers;
9676
};
9777

98-
} // namespace ipxp
78+
} // namespace ipxp::process::vlan
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/**
2+
* @file
3+
* @brief Definition of VLAN data structure.
4+
* @author Damir Zainullin <[email protected]>
5+
* @date 2025
6+
*
7+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
8+
*/
9+
10+
#pragma once
11+
12+
#include <cstdint>
13+
14+
namespace ipxp::process::vlan {
15+
16+
/**
17+
* @struct VLANContext
18+
* @brief Struct representing VLAN export data.
19+
*/
20+
struct VLANContext {
21+
uint16_t vlanId;
22+
};
23+
24+
} // namespace ipxp::process::vlan
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @file
3+
* @brief Definition of VLAN fields.
4+
* @author Damir Zainullin <[email protected]>
5+
* @date 2025
6+
*
7+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
8+
*/
9+
10+
#pragma once
11+
12+
#include <cstddef>
13+
14+
namespace ipxp::process::vlan {
15+
16+
/**
17+
* @enum VLANFields
18+
* @brief Enumerates the fields exported by the VLAN plugin.
19+
*
20+
* These enum values are used to index field handlers for this plugin.
21+
*/
22+
enum class VLANFields : std::size_t {
23+
VLAN_ID = 0,
24+
FIELDS_SIZE,
25+
};
26+
27+
} // namespace ipxp::process::vlan
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
2+
/**
3+
* @file vlanGetters.hpp
4+
* @brief Getters for VLAN plugin fields.
5+
* @author Damir Zainullin <[email protected]>
6+
* @date 2025
7+
*
8+
* @copyright Copyright (c) 2025 CESNET, z.s.p.o.
9+
*/
10+
11+
#pragma once
12+
13+
#include "vlanContext.hpp"
14+
15+
namespace ipxp::process::vlan {
16+
17+
inline constexpr const VLANContext& asVLANContext(const void* context) noexcept
18+
{
19+
return *static_cast<const VLANContext*>(context);
20+
}
21+
22+
// VLANField::VLAN_ID
23+
inline constexpr auto getVLANIdField
24+
= [](const void* context) { return asVLANContext(context).vlanId; };
25+
26+
} // namespace ipxp::process::vlan

0 commit comments

Comments
 (0)