You can create new process or input plugins for ipfixprobe if they are not implemented.

Process plugin

ℹ️ Replace _PLUGIN_NAME_ and _plugin_name_ with plugin name with respected cases.

1️⃣ Create a new directory in src/plugins/process with the name of your plugin, and inside create src directory and CMakeList.txt file.

2️⃣ Add files _plugin_name_.cpp and _plugin_name_.hpp to src directory.

3️⃣ Copy content CMakeList.txt from another process plugin and modify it for your plugin.

➡️ The final file structure should look like this:

src/plugins/process/_plugin_name_/
├── src/
│   ├── _plugin_name_.cpp
│   └── _plugin_name_.h
├── CMakeLists.txt
└── README.md

4️⃣ Add directory to CMakeList.txt in src/plugins/process. (add this: add_subdirectory(_plugin_name_))

5️⃣ Implement process plugin event functions:

6️⃣ Implement _PLUGIN_NAME__UNIREC_TEMPLATE, IPFIX__PLUGIN_NAME__TEMPLATE, and fill_ipfix, fill_unirec functions.

7️⃣ Add IPFIX__PLUGIN_NAME__TEMPLATE to ipfix-elements.hpp.

➡️ Here is boilerplate source code for .cpp and .hpp files. (Use the already implemented process plugins as inspiration)

⚠️ If you do NOT modify pre_create, post_create, pre_update, post_update, pre_export functions, please remove them from _plugin_name_.cpp and _plugin_name_.hpp

   #include "_PLUGIN_NAME_.hpp"

#include <iostream>

#include <ipfixprobe/pluginFactory/pluginManifest.hpp>
#include <ipfixprobe/pluginFactory/pluginRegistrar.hpp>

namespace ipxp {

static const PluginManifest _plugin_name_PluginManifest = {
	.name = "_plugin_name_",
	.description = "description",
	.pluginVersion = "1.0.0",
	.apiVersion = "1.0.0",
	.usage =
		[]() {
			OptionsParser parser("_plugin_name_", "description");
			parser.usage(std::cout);
		},
};

_PLUGIN_NAME_Plugin::_PLUGIN_NAME_Plugin(const std::string& params, int pluginID)
    : ProcessPlugin(pluginID)
{
	(void) params;
}

_PLUGIN_NAME_Plugin::~_PLUGIN_NAME_Plugin()
{
	close();
}

void _PLUGIN_NAME_Plugin::init(const char* params)
{
	(void) params;
}

void _PLUGIN_NAME_Plugin::close() {}

ProcessPlugin* _PLUGIN_NAME_Plugin::copy()
{
	return new _PLUGIN_NAME_Plugin(*this);
}

int _PLUGIN_NAME_Plugin::pre_create(Packet& pkt)
{
	(void) pkt;
	return 0;
}

int _PLUGIN_NAME_Plugin::post_create(Flow& rec, const Packet& pkt)
{
    (void) rec;
    (void) pkt;
	return 0;
}

int _PLUGIN_NAME_Plugin::pre_update(Flow& rec, Packet& pkt)
{
    (void) rec;
    (void) pkt;
	return 0;
}

int _PLUGIN_NAME_Plugin::post_update(Flow& rec, const Packet& pkt)
{
	(void) rec;
	(void) pkt;
	return 0;
}

void _PLUGIN_NAME_Plugin::pre_export(Flow& rec)
{
    (void) rec;
}

static const PluginRegistrar<_PLUGIN_NAME_Plugin, ProcessPluginFactory>
	_plugin_name_Registrar(_plugin_name_PluginManifest);

} // namespace ipxp

   

   #pragma once

#include <sstream>
#include <string>

#ifdef WITH_NEMEA
#include "fields.h"
#endif

#include <ipfixprobe/flowifc.hpp>
#include <ipfixprobe/ipfix-elements.hpp>
#include <ipfixprobe/packet.hpp>
#include <ipfixprobe/processPlugin.hpp>

namespace ipxp {

#define _PLUGIN_NAME__UNIREC_TEMPLATE   \
	"IP_TTL,IP_TTL_REV,..." //example fields


// See https://github.com/CESNET/Nemea-Framework/tree/master/unirec for help with unirec fields.
UR_FIELDS(
	// uint8 IP_TTL, //example fields
	// uint8 IP_TTL_REV,
    // ---
)

/**
 * \brief Flow record extension header for storing parsed BASICPLUS packets.
 */
struct RecordExt_PLUGIN_NAME_ : public RecordExt {

// ---

	RecordExt_PLUGIN_NAME_(int pluginID)
		: RecordExt(pluginID)
	{
        // initialize any internal state if needed
        // --
	}

#ifdef WITH_NEMEA
	virtual void fill_unirec(ur_template_t* tmplt, void* record)
	{
        // Fill UniRec fields here
        // ---
	}

	const char* get_unirec_tmplt() const { return _PLUGIN_NAME__UNIREC_TEMPLATE; }
#endif

	virtual int fill_ipfix(uint8_t* buffer, int size)
	{
        // Fill IPFIX fields here
        // --
	}

	const char** get_ipfix_tmplt() const
	{
        //need to add template to ipfix-elements.hpp
		static const char* ipfix_tmplt[] = {IPFIX__PLUGIN_NAME__TEMPLATE(IPFIX_FIELD_NAMES) nullptr};
		return ipfix_tmplt;
	}

	std::string get_text() const
	{
		std::ostringstream out;

        // Generate string representation

		return out.str();
	}
};

class _PLUGIN_NAME_Plugin : public ProcessPlugin {
public:
	_PLUGIN_NAME_Plugin(const std::string& params, int pluginID);
	~_PLUGIN_NAME_Plugin();

	void init(const char* params);
	void close();

	OptionsParser* get_parser() const
	{
		return new OptionsParser("_plugin_name_", "description");
	}

	std::string get_name() const { return "_plugin_name_"; }
	RecordExt* get_ext() const { return new RecordExt_PLUGIN_NAME_(m_pluginID); }
	ProcessPlugin* copy();

	int pre_create(Packet& pkt);

	int post_create(Flow& rec, const Packet& pkt);

	int pre_update(Flow& rec, Packet& pkt);

	int post_update(Flow& rec, const Packet& pkt);

	void pre_export(Flow& rec);
};

} // namespace ipxp

   

⚠️ To use ipfixprobe with the new plugin as systemd, you need to add it to schema.json and config2args.py in the init/ directory.

Input Plugin

ℹ️ Replace _PLUGIN_NAME_ and _plugin_name_ with plugin name with respected cases.

1️⃣ Create a new directory in src/plugins/input with the name of your plugin, and inside create a src directory and CMakeList.txt file.

2️⃣ Add files _plugin_name_.cpp and _plugin_name_.hpp to src directory.

3️⃣ Copy content CMakeList.txt from another process plugin and modify it for your plugin.

➡️ The final file structure should look like this:

src/plugins/input/_plugin_name_/
├── src/
│   ├── _plugin_name_.cpp
│   └── _plugin_name_.h
├── CMakeLists.txt
└── README.md

4️⃣ Add directory to CMakeList.txt in src/plugins/input. (add this: add_subdirectory(_plugin_name_))

5️⃣ Implement process plugin event functions (init, close), and input plugin method get to receive new packets.

6️⃣ Implement handling command-line arguments.

➡️ Here is boilerplate source code for .cpp and .hpp files. (Use the already implemented input plugins as inspiration)

#include "_plugin_name_.hpp"

#include "parser.hpp"

#include <ipfixprobe/pluginFactory/pluginManifest.hpp>
#include <ipfixprobe/pluginFactory/pluginRegistrar.hpp>

namespace ipxp {

static const PluginManifest _plugin_name_PluginManifest = {
	.name = "_plugin_name_",
	.description = "description",
	.pluginVersion = "1.0.0",
	.apiVersion = "1.0.0",
	.usage =
		[]() {
			_PLUGIN_NAME_OptParser parser;
			parser.usage(std::cout);
		},
};

_PLUGIN_NAME_Reader::_PLUGIN_NAME_Reader(const std::string& params)

// init parameters here

{
	init(params.c_str());
}

_PLUGIN_NAME_Reader::~_PLUGIN_NAME_Reader()
{
	close();
}

void _PLUGIN_NAME_Reader::init(const char* params)
{
	_PLUGIN_NAME_OptParser parser;
	try {
		parser.parse(params);
	} catch (ParserError& e) {
		throw PluginError(e.what());
	}

    // implement initilization

}

void _PLUGIN_NAME_Reader::close()
{
    //---
}


InputPlugin::Result _PLUGIN_NAME_Reader::get(PacketBlock& packets)
{
    (void) packets;
    // ---
}

static const PluginRegistrar<_PLUGIN_NAME_Reader, InputPluginFactory> _plugin_name_Registrar(_plugin_name_PluginManifest);

} // namespace ipxp

#pragma once

#include <ipfixprobe/inputPlugin.hpp>
#include <ipfixprobe/options.hpp>
#include <ipfixprobe/packet.hpp>
#include <ipfixprobe/utils.hpp>

namespace ipxp {

class _PLUGIN_NAME_OptParser : public OptionsParser {
public:

    //define options

	_PLUGIN_NAME_OptParser()
		: OptionsParser("_plugin_name_", "description")
        //init options
	{
		register_option(
			"short_name",
			"long_name",
			"type",
			"description",
			[this](const char* arg) {
                //handle arg
				return true; //false
			},
			OptionFlags::_OPTION_ //RequiredArgument, OptionalArgument, NoArgument
        );

        // add more here
	}
};

class _PLUGIN_NAME_Reader : public InputPlugin {
public:
	_PLUGIN_NAME_Reader(const std::string& params);
	~_PLUGIN_NAME_Reader();
	void init(const char* params);
	void close();
	OptionsParser* get_parser() const { return new _PLUGIN_NAME_OptParser(); }
	std::string get_name() const { return "_plugin_name_"; }
	InputPlugin::Result get(PacketBlock& packets);

private:
    //private functions
};

} // namespace ipxp

⚠️ To use ipfixprobe with the new plugin as systemd, you need to add it to schema.json and config2args.py in the init/ directory.