Skip to content

Commit e5b7a46

Browse files
Merge pull request #239 from CESNET/ctt-controller
Merge CTT controller to CTT-Support dev branch
2 parents 2a56c98 + 036856d commit e5b7a46

File tree

9 files changed

+320
-11
lines changed

9 files changed

+320
-11
lines changed

configure.ac

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,32 @@ if [[ -z "$WITH_NDP_TRUE" ]]; then
226226
RPM_BUILDREQ+=" netcope-common-devel"
227227
fi
228228

229+
AC_ARG_WITH([ctt],
230+
AC_HELP_STRING([--with-ctt],[Compile ipfixprobe with ctt plugin for using Connection Tracking Table]),
231+
[
232+
if test "$withval" = "yes"; then
233+
withctt="yes"
234+
else
235+
withctt="no"
236+
fi
237+
], [withctt="no"]
238+
)
239+
240+
if test x${withctt} = xyes; then
241+
AC_LANG_PUSH([C++])
242+
CXXFLAGS="$CXXFLAGS -std=c++17"
243+
AC_CHECK_HEADERS([ctt.hpp], [libctt=yes], AC_MSG_ERROR([ctt.hpp not found. Try installing libctt-devel]))
244+
AC_LANG_POP([C++])
245+
fi
246+
247+
AM_CONDITIONAL(WITH_CTT, test x${libctt} = xyes && test x${withctt} = xyes)
248+
if [[ -z "$WITH_CTT_TRUE" ]]; then
249+
AC_DEFINE([WITH_CTT], [1], [Define to 1 if the ctt is available])
250+
LIBS="-lctt $LIBS"
251+
RPM_REQUIRES+=" libctt"
252+
RPM_BUILDREQ+=" libctt-devel"
253+
fi
254+
229255
AC_ARG_WITH([pcap],
230256
AC_HELP_STRING([--with-pcap],[Compile ipfixprobe with pcap plugin for capturing using libpcap library]),
231257
[

include/ipfixprobe/flowifc.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include <stdint.h>
3939
#include <stdlib.h>
4040
#include <sys/time.h>
41+
#include <chrono>
4142

4243
#ifdef WITH_NEMEA
4344
#include <unirec/unirec.h>
@@ -263,6 +264,14 @@ struct Flow : public Record {
263264
};
264265

265266
uint64_t flow_hash;
267+
268+
#ifdef WITH_CTT
269+
uint64_t flow_hash_ctt; /**< Flow hash for CTT. */
270+
bool record_in_ctt; /**< CTT - offload or not. */
271+
bool is_delayed; /**< Delayed export flag. */
272+
time_t delay_time; /**< Time until export of the flow is delayed. */
273+
#endif
274+
266275
PluginsStatus plugins_status; /**< Statuses of the process plugins for this flow, used to check
267276
if the flow process plugins requires all available data, only
268277
metadata or nothing of this. */
@@ -290,4 +299,5 @@ struct Flow : public Record {
290299
};
291300

292301
}
302+
293303
#endif /* IPXP_FLOWIFC_HPP */

include/ipfixprobe/packet.hpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ namespace ipxp {
4646
* \brief Structure for storing parsed packet fields
4747
*/
4848
struct Packet : public Record {
49-
Metadata_CTT cttmeta; /**< Metadata from CTT */
49+
#ifdef WITH_CTT
50+
Metadata_CTT cttmeta; /**< Metadata from CTT */
51+
bool cttmeta_valid; /**< True if CTT metadata is valid */
52+
#endif /* WITH_CTT */
5053
struct timeval ts;
5154

5255
uint8_t dst_mac[6];
@@ -108,7 +111,7 @@ struct Packet : public Record {
108111
* \brief Constructor.
109112
*/
110113
Packet() :
111-
ts({0}),
114+
cttmeta_valid(false), ts({0}),
112115
dst_mac(), src_mac(), ethertype(0),
113116
ip_len(0), ip_payload_len(0), ip_version(0), ip_ttl(0),
114117
ip_proto(0), ip_tos(0), ip_flags(0), src_ip({0}), dst_ip({0}), vlan_id(0),

include/ipfixprobe/storage.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ class StoragePlugin : public Plugin
189189
*/
190190
int plugins_post_create(Flow& rec, const Packet& pkt)
191191
{
192+
// if metadata are valid, add flow hash ctt to the flow record
193+
if (pkt.cttmeta_valid) {
194+
rec.flow_hash_ctt = pkt.cttmeta.flow_hash;
195+
}
192196
PluginStatusConverter plugin_status_converter(m_plugins_status);
193197
int ret = 0;
194198
for (unsigned int i = 0; i < m_plugin_cnt; i++) {

input/ndp.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <cstdint>
3131
#include <cstdio>
3232
#include <cstring>
33+
#include <iostream>
3334
#include <netinet/in.h>
3435
#include <sys/types.h>
3536
#include <cstdint>
@@ -170,7 +171,10 @@ InputPlugin::Result NdpPacketReader::get(PacketBlock &packets)
170171
m_stats.bad_metadata++;
171172
parse_packet(&opt, m_parser_stats, timestamp, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length);
172173
} else {
173-
parse_packet_ctt_metadata(&opt, m_parser_stats, ctt, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length);
174+
if (parse_packet_ctt_metadata(&opt, m_parser_stats, ctt, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length) == -1) {
175+
m_stats.bad_metadata++;
176+
parse_packet(&opt, m_parser_stats, timestamp, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length);
177+
}
174178
}
175179
} else {
176180
parse_packet(&opt, m_parser_stats, timestamp, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length);

input/parser.cpp

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include "parser.hpp"
3737
#include "headers.hpp"
38+
#include <ipfixprobe/cttmeta.hpp>
3839
#include <ipfixprobe/packet.hpp>
3940

4041
namespace ipxp {
@@ -776,12 +777,21 @@ void parse_packet(parser_opt_t *opt, ParserStats& stats, struct timeval ts, cons
776777
opt->pblock->bytes += len;
777778
}
778779

779-
void parse_packet_ctt_metadata(parser_opt_t *opt, ParserStats& stats, const Metadata_CTT& metadata, const uint8_t *data, uint16_t len, uint16_t caplen)
780+
int parse_packet_ctt_metadata(parser_opt_t *opt, ParserStats& stats, const Metadata_CTT& metadata, const uint8_t *data, uint16_t len, uint16_t caplen)
780781
{
781782
if (opt->pblock->cnt >= opt->pblock->size) {
782-
return;
783+
return 0;
783784
}
784785
Packet *pkt = &opt->pblock->pkts[opt->pblock->cnt];
786+
787+
// check metadata validity
788+
if (metadata.parser_status == PA_OK) {
789+
pkt->cttmeta_valid = true;
790+
} else {
791+
pkt->cttmeta_valid = false;
792+
return -1;
793+
}
794+
785795
pkt->cttmeta = metadata;
786796

787797
pkt->packet_len_wire = len;
@@ -831,7 +841,7 @@ void parse_packet_ctt_metadata(parser_opt_t *opt, ParserStats& stats, const Meta
831841
stats.pppoe_packets++;
832842
} else { // if not previous, we try delegate to original parser
833843
parse_packet(opt, stats, metadata.ts, data, len, caplen);
834-
return;
844+
return 0;
835845
}
836846

837847
// L4
@@ -843,11 +853,11 @@ void parse_packet_ctt_metadata(parser_opt_t *opt, ParserStats& stats, const Meta
843853
stats.udp_packets++;
844854
} else { // if not previous, we try delegate to original parser
845855
parse_packet(opt, stats, metadata.ts, data, len, caplen);
846-
return;
856+
return 0;
847857
}
848858
} catch (const char *err) {
849859
DEBUG_MSG("%s\n", err);
850-
return;
860+
return 0;
851861
}
852862

853863
if (pkt->vlan_id) {
@@ -880,6 +890,7 @@ void parse_packet_ctt_metadata(parser_opt_t *opt, ParserStats& stats, const Meta
880890
opt->packet_valid = true;
881891
opt->pblock->cnt++;
882892
opt->pblock->bytes += len;
893+
return 0;
883894
}
884895

885896
}

input/parser.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ typedef struct parser_opt_s {
8686
*/
8787
void parse_packet(parser_opt_t *opt, ParserStats& stats, struct timeval ts, const uint8_t *data, uint16_t len, uint16_t caplen);
8888

89-
void parse_packet_ctt_metadata(parser_opt_t *opt, ParserStats& stats, const Metadata_CTT& metadata, const uint8_t *data, uint16_t len, uint16_t caplen);
89+
int parse_packet_ctt_metadata(parser_opt_t *opt, ParserStats& stats, const Metadata_CTT& metadata, const uint8_t *data, uint16_t len, uint16_t caplen);
9090

9191
}
9292
#endif /* IPXP_INPUT_PARSER_HPP */

storage/cache.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <cstdlib>
3434
#include <iostream>
3535
#include <cstring>
36+
#include <ratio>
3637
#include <sys/time.h>
3738

3839
#include <ipfixprobe/ring.h>
@@ -138,10 +139,22 @@ void FlowRecord::create(const Packet &pkt, uint64_t hash)
138139
m_flow.src_port = pkt.src_port;
139140
m_flow.dst_port = pkt.dst_port;
140141
}
142+
#ifdef WITH_CTT
143+
m_flow.is_delayed = false;
144+
m_delayed_flow_waiting = false;
145+
#endif /* WITH_CTT */
141146
}
142147

143148
void FlowRecord::update(const Packet &pkt, bool src)
144149
{
150+
if (m_flow.is_delayed && !pkt.cttmeta.ctt_rec_matched) { // it means, the flow is waiting for export and it is not matched in CTT -> it must be new flow
151+
auto flow_hash = m_hash;
152+
m_delayed_flow = m_flow;
153+
m_delayed_flow_waiting = true;
154+
erase(); // erase the old flow, keeping the delayed flow
155+
create(pkt, flow_hash);
156+
return;
157+
}
145158
m_flow.time_last = pkt.ts;
146159
if (src) {
147160
m_flow.src_packets++;
@@ -192,6 +205,9 @@ void NHTFlowCache::init(const char *params)
192205
m_timeout_idx = 0;
193206
m_line_mask = (m_cache_size - 1) & ~(m_line_size - 1);
194207
m_line_new_idx = m_line_size / 2;
208+
#ifdef WITH_CTT
209+
m_ctt_controller.init(parser.m_dev, 0);
210+
#endif /* WITH_CTT */
195211

196212
if (m_export_queue == nullptr) {
197213
throw PluginError("output queue must be set before init");
@@ -256,6 +272,17 @@ void NHTFlowCache::set_queue(ipx_ring_t *queue)
256272

257273
void NHTFlowCache::export_flow(size_t index)
258274
{
275+
if (m_flow_table[index]->m_flow.is_delayed) {
276+
return;
277+
}
278+
if (m_flow_table[index]->m_delayed_flow_waiting && !m_flow_table[index]->m_delayed_flow.is_delayed) {
279+
m_total_exported++;
280+
update_flow_end_reason_stats(m_flow_table[index]->m_delayed_flow.end_reason);
281+
update_flow_record_stats(
282+
m_flow_table[index]->m_delayed_flow.src_packets
283+
+ m_flow_table[index]->m_delayed_flow.dst_packets);
284+
ipx_ring_push(m_export_queue, &m_flow_table[index]->m_delayed_flow);
285+
}
259286
m_total_exported++;
260287
update_flow_end_reason_stats(m_flow_table[index]->m_flow.end_reason);
261288
update_flow_record_stats(
@@ -502,6 +529,16 @@ void NHTFlowCache::export_expired(time_t ts)
502529
m_flow_table[i]->m_flow.end_reason = get_export_reason(m_flow_table[i]->m_flow);
503530
plugins_pre_export(m_flow_table[i]->m_flow);
504531
export_flow(i);
532+
if (!m_flow_table[i]->is_empty() && m_flow_table[i]->m_flow.is_delayed && m_flow_table[i]->m_flow.delay_time >= ts) {
533+
m_flow_table[i]->m_flow.is_delayed = false;
534+
plugins_pre_export(m_flow_table[i]->m_flow);
535+
export_flow(i);
536+
}
537+
if(!m_flow_table[i]->is_empty() && m_flow_table[i]->m_delayed_flow_waiting && m_flow_table[i]->m_delayed_flow.delay_time >= ts) {
538+
m_flow_table[i]->m_delayed_flow_waiting = false;
539+
plugins_pre_export(m_flow_table[i]->m_delayed_flow);
540+
export_flow(i);
541+
}
505542
#ifdef FLOW_CACHE_STATS
506543
m_expired++;
507544
#endif /* FLOW_CACHE_STATS */
@@ -658,4 +695,61 @@ void NHTFlowCache::prefetch_export_expired() const
658695
__builtin_prefetch(m_flow_table[i], 0, 1);
659696
}
660697
}
698+
699+
#ifdef WITH_CTT
700+
701+
void CttController::create_record(uint64_t flow_hash_ctt, const struct timeval& ts)
702+
{
703+
try {
704+
std::vector<std::byte> key = assemble_key(flow_hash_ctt);
705+
std::vector<std::byte> state = assemble_state(
706+
OffloadMode::PACKET_OFFLOAD,
707+
MetaType::FULL,
708+
ts);
709+
m_commander->write_record(std::move(key), std::move(state));
710+
}
711+
catch (const std::exception& e) {
712+
throw;
713+
}
714+
}
715+
716+
void CttController::export_record(uint64_t flow_hash_ctt)
717+
{
718+
try {
719+
std::vector<std::byte> key = assemble_key(flow_hash_ctt);
720+
m_commander->export_and_delete_record(std::move(key));
721+
}
722+
catch (const std::exception& e) {
723+
throw;
724+
}
725+
}
726+
727+
std::vector<std::byte> CttController::assemble_key(uint64_t flow_hash_ctt)
728+
{
729+
std::vector<std::byte> key(key_size_bytes, std::byte(0));
730+
for (size_t i = 0; i < sizeof(flow_hash_ctt) && i < key_size_bytes; ++i) {
731+
key[i] = static_cast<std::byte>((flow_hash_ctt >> (8 * i)) & 0xFF);
732+
}
733+
return key;
734+
}
735+
736+
std::vector<std::byte> CttController::assemble_state(
737+
OffloadMode offload_mode, MetaType meta_type, const struct timeval& ts)
738+
{
739+
std::vector<std::byte> state(state_size_bytes, std::byte(0));
740+
std::vector<std::byte> state_mask(state_mask_size_bytes, std::byte(0));
741+
742+
state[0] = static_cast<std::byte>(offload_mode);
743+
state[1] = static_cast<std::byte>(meta_type);
744+
745+
// timestamp in sec/ns format, 32+32 bits - 64 bits in total
746+
for (size_t i = 0; i < sizeof(ts.tv_sec) && i < 4; ++i) {
747+
state[2 + i] = static_cast<std::byte>((ts.tv_sec >> (8 * i)) & 0xFF);
748+
}
749+
for (size_t i = 0; i < sizeof(ts.tv_usec) && i < 4; ++i) {
750+
state[6 + i] = static_cast<std::byte>((ts.tv_usec >> (8 * i)) & 0xFF);
751+
}
752+
return state;
661753
}
754+
#endif // WITH_CTT
755+
}

0 commit comments

Comments
 (0)