Skip to content

Commit 5dc1509

Browse files
authored
Merge pull request #176 from CESNET/flow-hash-plugin
Flow hash plugin
2 parents 470984e + 07c5625 commit 5dc1509

File tree

8 files changed

+234
-5
lines changed

8 files changed

+234
-5
lines changed

Makefile.am

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,9 @@ ipfixprobe_process_src=\
132132
process/vlan.hpp \
133133
process/vlan.cpp \
134134
process/nettisa.hpp \
135-
process/nettisa.cpp
135+
process/nettisa.cpp \
136+
process/flow_hash.hpp \
137+
process/flow_hash.cpp
136138

137139
if WITH_QUIC
138140
ipfixprobe_process_src+=\

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,14 @@ List of fields exported together with basic flow fields on the interface by VLAN
643643
|:------------:|:------:|:--------------------------:|
644644
| VLAN_ID | uint16 | Vlan ID (used in flow key) |
645645

646+
### Flow Hash
647+
648+
List of fields exported together with basic flow fields on interface by flow_hash plugin.
649+
650+
| Output field | Type | Description |
651+
|:------------------:|:------:|:---------------------------------:|
652+
| FLOW_ID | uint64 | Hash of the flow - unique flow id |
653+
646654
## Simplified function diagram
647655
Diagram below shows how `ipfixprobe` works.
648656

include/ipfixprobe/flowifc.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,8 @@ struct Record {
246246
* \brief Flow record struct constaining basic flow record data and extension headers.
247247
*/
248248
struct Flow : public Record {
249+
uint64_t flow_hash;
250+
249251
struct timeval time_first;
250252
struct timeval time_last;
251253
uint64_t src_bytes;

include/ipfixprobe/ipfix-elements.hpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ namespace ipxp {
8080
#define INPUT_INTERFACE(F) F(0, 10, 4, &this->dir_bit_field)
8181
#define OUTPUT_INTERFACE(F) F(0, 14, 2, nullptr)
8282
#define FLOW_END_REASON(F) F(0, 136, 1, &flow.end_reason)
83+
#define FLOW_ID(F) F(0, 148, 8, &flow.flow_hash)
8384

8485
#define ETHERTYPE(F) F(0, 256, 2, nullptr)
8586

@@ -346,7 +347,7 @@ namespace ipxp {
346347
F(HTTP_CONTENT_TYPE) \
347348
F(HTTP_SERVER) \
348349
F(HTTP_SET_COOKIE_NAMES) \
349-
F(HTTP_STATUS)
350+
F(HTTP_STATUS)
350351

351352
#define IPFIX_RTSP_TEMPLATE(F) \
352353
F(RTSP_METHOD) \
@@ -529,6 +530,10 @@ namespace ipxp {
529530
F(NTS_TIME_DISTRIBUTION) \
530531
F(NTS_SWITCHING_RATIO)
531532

533+
534+
#define IPFIX_FLOW_HASH_TEMPLATE(F) \
535+
F(FLOW_ID)
536+
532537
#ifdef WITH_FLEXPROBE
533538
#define IPFIX_FLEXPROBE_DATA_TEMPLATE(F) F(FX_FRAME_SIGNATURE) F(FX_INPUT_INTERFACE)
534539
#define IPFIX_FLEXPROBE_TCP_TEMPLATE(F) F(FX_TCP_TRACKING)
@@ -573,7 +578,8 @@ namespace ipxp {
573578
IPFIX_FLEXPROBE_ENCR_TEMPLATE(F) \
574579
IPFIX_SSADETECTOR_TEMPLATE(F) \
575580
IPFIX_ICMP_TEMPLATE(F) \
576-
IPFIX_NETTISA_TEMPLATE(F)
581+
IPFIX_NETTISA_TEMPLATE(F) \
582+
IPFIX_FLOW_HASH_TEMPLATE(F)
577583

578584
/**
579585
* Helper macro, convert FIELD into its name as a C literal.

process/create_plugin.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ struct RecordExt${PLUGIN_UPPER} : public RecordExt {
7878
}
7979
8080
#ifdef WITH_NEMEA
81-
virtual void fill_unirec(ur_template_t *tmplt, void *record)
81+
void fill_unirec(ur_template_t *tmplt, void *record) override
8282
{
8383
}
8484
@@ -88,7 +88,7 @@ struct RecordExt${PLUGIN_UPPER} : public RecordExt {
8888
}
8989
#endif
9090
91-
virtual int fill_ipfix(uint8_t *buffer, int size)
91+
int fill_ipfix(uint8_t *buffer, int size) override
9292
{
9393
return 0;
9494
}

process/flow_hash.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* \file flow_hash.cpp
3+
* \brief Plugin for parsing flow_hash traffic.
4+
* \author Jakub Antonín Štigler [email protected]
5+
* \date 2023
6+
*/
7+
/*
8+
* Copyright (C) 2023 CESNET
9+
*
10+
* LICENSE TERMS
11+
*
12+
* Redistribution and use in source and binary forms, with or without
13+
* modification, are permitted provided that the following conditions
14+
* are met:
15+
* 1. Redistributions of source code must retain the above copyright
16+
* notice, this list of conditions and the following disclaimer.
17+
* 2. Redistributions in binary form must reproduce the above copyright
18+
* notice, this list of conditions and the following disclaimer in
19+
* the documentation and/or other materials provided with the
20+
* distribution.
21+
* 3. Neither the name of the Company nor the names of its contributors
22+
* may be used to endorse or promote products derived from this
23+
* software without specific prior written permission.
24+
*
25+
*
26+
*
27+
*/
28+
29+
#include <iostream>
30+
31+
#include "flow_hash.hpp"
32+
33+
namespace ipxp {
34+
35+
int RecordExtFLOW_HASH::REGISTERED_ID = -1;
36+
37+
__attribute__((constructor)) static void register_this_plugin()
38+
{
39+
static PluginRecord rec = PluginRecord("flow_hash", [](){return new FLOW_HASHPlugin();});
40+
register_plugin(&rec);
41+
RecordExtFLOW_HASH::REGISTERED_ID = register_extension();
42+
}
43+
44+
FLOW_HASHPlugin::FLOW_HASHPlugin()
45+
{
46+
}
47+
48+
FLOW_HASHPlugin::~FLOW_HASHPlugin()
49+
{
50+
}
51+
52+
void FLOW_HASHPlugin::init(const char *params)
53+
{
54+
}
55+
56+
void FLOW_HASHPlugin::close()
57+
{
58+
}
59+
60+
ProcessPlugin *FLOW_HASHPlugin::copy()
61+
{
62+
return new FLOW_HASHPlugin(*this);
63+
}
64+
65+
int FLOW_HASHPlugin::post_create(Flow &rec, const Packet &pkt)
66+
{
67+
auto ext = new RecordExtFLOW_HASH();
68+
69+
ext->flow_hash = rec.flow_hash;
70+
71+
rec.add_extension(ext);
72+
73+
return 0;
74+
}
75+
76+
}
77+

process/flow_hash.hpp

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/**
2+
* \file flow_hash.hpp
3+
* \brief Plugin for parsing flow_hash traffic.
4+
* \author Jakub Antonín Štigler [email protected]
5+
* \date 2023
6+
*/
7+
/*
8+
* Copyright (C) 2023 CESNET
9+
*
10+
* LICENSE TERMS
11+
*
12+
* Redistribution and use in source and binary forms, with or without
13+
* modification, are permitted provided that the following conditions
14+
* are met:
15+
* 1. Redistributions of source code must retain the above copyright
16+
* notice, this list of conditions and the following disclaimer.
17+
* 2. Redistributions in binary form must reproduce the above copyright
18+
* notice, this list of conditions and the following disclaimer in
19+
* the documentation and/or other materials provided with the
20+
* distribution.
21+
* 3. Neither the name of the Company nor the names of its contributors
22+
* may be used to endorse or promote products derived from this
23+
* software without specific prior written permission.
24+
*
25+
*
26+
*
27+
*/
28+
29+
#ifndef IPXP_PROCESS_FLOW_HASH_HPP
30+
#define IPXP_PROCESS_FLOW_HASH_HPP
31+
32+
#include <cstring>
33+
34+
#ifdef WITH_NEMEA
35+
#include "fields.h"
36+
#endif
37+
38+
#include <string>
39+
#include <sstream>
40+
41+
#include <ipfixprobe/process.hpp>
42+
#include <ipfixprobe/flowifc.hpp>
43+
#include <ipfixprobe/packet.hpp>
44+
#include <ipfixprobe/ipfix-elements.hpp>
45+
#include <ipfixprobe/byte-utils.hpp>
46+
47+
namespace ipxp {
48+
49+
#define FLOW_HASH_UNIREC_TEMPLATE "FLOW_ID"
50+
51+
UR_FIELDS (
52+
uint64 FLOW_ID
53+
)
54+
55+
/**
56+
* \brief Flow record extension header for storing parsed FLOW_HASH data.
57+
*/
58+
struct RecordExtFLOW_HASH : public RecordExt {
59+
static int REGISTERED_ID;
60+
61+
// Value in host byte order
62+
uint64_t flow_hash;
63+
64+
RecordExtFLOW_HASH() : RecordExt(REGISTERED_ID)
65+
{
66+
flow_hash = 0;
67+
}
68+
69+
#ifdef WITH_NEMEA
70+
void fill_unirec(ur_template_t *tmplt, void *record) override
71+
{
72+
ur_set(tmplt, record, F_FLOW_ID, flow_hash);
73+
}
74+
75+
const char *get_unirec_tmplt() const
76+
{
77+
return FLOW_HASH_UNIREC_TEMPLATE;
78+
}
79+
#endif
80+
81+
int fill_ipfix(uint8_t *buffer, int size) override
82+
{
83+
constexpr int LEN = sizeof(flow_hash);
84+
85+
if (size < LEN) {
86+
return -1;
87+
}
88+
89+
// value is converted from host byte-order to network byte-order
90+
*reinterpret_cast<decltype(flow_hash) *>(buffer) = swap_uint64(flow_hash);
91+
92+
return LEN;
93+
}
94+
95+
const char **get_ipfix_tmplt() const
96+
{
97+
static const char *ipfix_template[] = {
98+
IPFIX_FLOW_HASH_TEMPLATE(IPFIX_FIELD_NAMES)
99+
NULL
100+
};
101+
return ipfix_template;
102+
}
103+
104+
std::string get_text() const
105+
{
106+
std::ostringstream out;
107+
out << std::hex << "flow_id=\"" << flow_hash << '"';
108+
109+
return out.str();
110+
}
111+
};
112+
113+
/**
114+
* \brief Process plugin for parsing FLOW_HASH packets.
115+
*/
116+
class FLOW_HASHPlugin : public ProcessPlugin
117+
{
118+
public:
119+
FLOW_HASHPlugin();
120+
~FLOW_HASHPlugin();
121+
void init(const char *params);
122+
void close();
123+
OptionsParser *get_parser() const { return new OptionsParser("flow_hash", "Export flow hash as flow id"); }
124+
std::string get_name() const { return "flow_hash"; }
125+
RecordExt *get_ext() const { return new RecordExtFLOW_HASH(); }
126+
ProcessPlugin *copy();
127+
128+
int post_create(Flow &rec, const Packet &pkt);
129+
};
130+
131+
}
132+
#endif /* IPXP_PROCESS_FLOW_HASH_HPP */
133+

storage/cache.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ void FlowRecord::create(const Packet &pkt, uint64_t hash)
107107

108108
m_flow.time_first = pkt.ts;
109109
m_flow.time_last = pkt.ts;
110+
m_flow.flow_hash = hash;
110111

111112
memcpy(m_flow.src_mac, pkt.src_mac, 6);
112113
memcpy(m_flow.dst_mac, pkt.dst_mac, 6);

0 commit comments

Comments
 (0)