Skip to content

Commit 95a10c2

Browse files
committed
ndp input plugin - add support and asserts for parsing ctt metadata
1 parent c4019b7 commit 95a10c2

File tree

2 files changed

+111
-4
lines changed

2 files changed

+111
-4
lines changed

input/ndp.cpp

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,36 @@
2727
*
2828
*/
2929

30+
#include <cstdint>
3031
#include <cstdio>
3132
#include <cstring>
3233
#include <iostream>
34+
#include <netinet/in.h>
35+
#include <sys/types.h>
36+
#include <cstdint>
37+
#include <cstddef>
38+
#include <inttypes.h>
3339

3440
#include "ndp.hpp"
41+
#include "ipfixprobe/packet.hpp"
42+
#include "ipfixprobe/plugin.hpp"
3543
#include "parser.hpp"
3644

3745
namespace ipxp {
3846

47+
uint64_t extract(const uint8_t* bitvec, size_t start_bit, size_t bit_length) {
48+
size_t start_byte = start_bit / 8;
49+
size_t end_bit = start_bit + bit_length;
50+
size_t end_byte = (end_bit + 7) / 8;
51+
uint64_t value = 0;
52+
for (size_t i = 0; i < end_byte - start_byte; ++i) {
53+
value |= static_cast<uint64_t>(bitvec[start_byte + i]) << (8 * i);
54+
}
55+
value >>= (start_bit % 8);
56+
uint64_t mask = (bit_length == 64) ? ~0ULL : ((1ULL << bit_length) - 1);
57+
return value & mask;
58+
}
59+
3960
telemetry::Content NdpPacketReader::get_queue_telemetry()
4061
{
4162
telemetry::Dict dict;
@@ -71,6 +92,9 @@ void NdpPacketReader::init(const char *params)
7192
if (parser.m_dev.empty()) {
7293
throw PluginError("specify device path");
7394
}
95+
if (parser.m_metadata == "ctt") {
96+
m_ctt_metadata = true;
97+
}
7498
init_ifc(parser.m_dev);
7599
}
76100

@@ -86,6 +110,38 @@ void NdpPacketReader::init_ifc(const std::string &dev)
86110
}
87111
}
88112

113+
void NdpPacketReader::parse_ctt_metadata(const ndp_packet *ndp_packet, Metadata_CTT &ctt)
114+
{
115+
if (ndp_packet->header_length != 32) {
116+
throw PluginError("Metadata bad length, cannot parse, length: " + std::to_string(ndp_packet->header_length));
117+
}
118+
const uint8_t *metadata = ndp_packet->header;
119+
120+
ctt.ts.tv_usec = extract(metadata, 0, 32);
121+
ctt.ts.tv_sec = extract(metadata, 32, 32);
122+
ctt.vlan_tci = extract(metadata, 64, 16);
123+
ctt.vlan_vld = extract(metadata, 80, 1);
124+
ctt.vlan_stripped = extract(metadata, 81, 1);
125+
ctt.ip_csum_status = extract(metadata, 82, 2);
126+
ctt.l4_csum_status = extract(metadata, 84, 2);
127+
ctt.parser_status = extract(metadata, 86, 2);
128+
ctt.ifc = extract(metadata, 88, 8);
129+
ctt.filter_bitmap = extract(metadata, 96, 16);
130+
ctt.ctt_export_trig = extract(metadata, 112, 1);
131+
ctt.ctt_rec_matched = extract(metadata, 113, 1);
132+
ctt.ctt_rec_created = extract(metadata, 114, 1);
133+
ctt.ctt_rec_deleted = extract(metadata, 115, 1);
134+
ctt.flow_hash = extract(metadata, 128, 64);
135+
ctt.l2_len = extract(metadata, 192, 7);
136+
ctt.l3_len = extract(metadata, 199, 9);
137+
ctt.l4_len = extract(metadata, 208, 8);
138+
ctt.l2_ptype = extract(metadata, 216, 4);
139+
ctt.l3_ptype = extract(metadata, 220, 4);
140+
ctt.l4_ptype = extract(metadata, 224, 4);
141+
142+
return;
143+
}
144+
89145
InputPlugin::Result NdpPacketReader::get(PacketBlock &packets)
90146
{
91147
parser_opt_t opt = {&packets, false, false, 0};
@@ -107,7 +163,30 @@ InputPlugin::Result NdpPacketReader::get(PacketBlock &packets)
107163
throw PluginError(ndpReader.error_msg);
108164
}
109165
read_pkts++;
110-
parse_packet(&opt, m_parser_stats, timestamp, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length);
166+
if (m_ctt_metadata) {
167+
Metadata_CTT ctt;
168+
parse_ctt_metadata(ndp_packet, ctt);
169+
parse_packet(&opt, m_parser_stats, timestamp, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length);
170+
171+
Packet *pkt = &opt.pblock->pkts[opt.pblock->cnt - 1];
172+
173+
// verify metadata with original parser
174+
if(ctt.l2_len + ctt.l3_len + ctt.l4_len != pkt->packet_len - pkt->payload_len) {
175+
printf("Error: ctt.l2_len (%d) + ctt.l3_len (%d) + ctt.l4_len (%d) != pkt->packet_len (%d) - pkt->payload_len (%d)\n", ctt.l2_len, ctt.l3_len, ctt.l4_len, pkt->packet_len, pkt->payload_len);
176+
}
177+
if(pkt->ip_proto == IPPROTO_TCP) {
178+
if(ctt.l4_ptype != 0x1) {
179+
printf("Error: ctt.l4_ptype (%d) != 0x1 but protocol is TCP (%d)\n", ctt.l4_ptype, pkt->ip_proto);
180+
}
181+
}
182+
if(pkt->ip_proto == IPPROTO_UDP) {
183+
if(ctt.l4_ptype != 0x2) {
184+
printf("Error: ctt.l4_ptype (%d) != 0x2 but protocol is UDP (%d)\n", ctt.l4_ptype, pkt->ip_proto);
185+
}
186+
}
187+
} else {
188+
parse_packet(&opt, m_parser_stats, timestamp, ndp_packet->data, ndp_packet->data_length, ndp_packet->data_length);
189+
}
111190
}
112191

113192
m_seen += read_pkts;

input/ndp.hpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#ifndef IPXP_INPUT_NDP_HPP
3131
#define IPXP_INPUT_NDP_HPP
3232

33+
#include <bits/types/struct_timeval.h>
3334
#include <ndpreader.hpp>
3435

3536
#include <ipfixprobe/input.hpp>
@@ -39,18 +40,42 @@
3940

4041
namespace ipxp {
4142

43+
struct Metadata_CTT {
44+
timeval ts;
45+
uint16_t vlan_tci;
46+
bool vlan_vld : 1;
47+
bool vlan_stripped : 1;
48+
uint8_t ip_csum_status : 2;
49+
uint8_t l4_csum_status : 2;
50+
uint8_t parser_status : 2;
51+
uint8_t ifc;
52+
uint16_t filter_bitmap;
53+
uint8_t ctt_export_trig : 1;
54+
uint8_t ctt_rec_matched : 1;
55+
uint8_t ctt_rec_created : 1;
56+
uint8_t ctt_rec_deleted : 1;
57+
uint64_t flow_hash;
58+
uint8_t l2_len : 7;
59+
uint16_t l3_len : 9;
60+
uint8_t l4_len : 8;
61+
uint8_t l2_ptype : 4;
62+
uint8_t l3_ptype : 4;
63+
uint8_t l4_ptype : 4;
64+
};
65+
4266
class NdpOptParser : public OptionsParser
4367
{
4468
public:
4569
std::string m_dev;
4670
uint64_t m_id;
71+
std::string m_metadata;
4772

48-
NdpOptParser() : OptionsParser("ndp", "Input plugin for reading packets from a ndp device"), m_dev(""), m_id(0)
73+
NdpOptParser() : OptionsParser("ndp", "Input plugin for reading packets from a ndp device"), m_dev(""), m_id(0), m_metadata("")
4974
{
5075
register_option("d", "dev", "PATH", "Path to a device file", [this](const char *arg){m_dev = arg; return true;}, OptionFlags::RequiredArgument);
5176
register_option("I", "id", "NUM", "Link identifier number",
52-
[this](const char *arg){try {m_id = str2num<decltype(m_id)>(arg);} catch(std::invalid_argument &e) {return false;} return true;},
53-
OptionFlags::RequiredArgument);
77+
[this](const char *arg){try {m_id = str2num<decltype(m_id)>(arg);} catch(std::invalid_argument &e) {return false;} return true;}, OptionFlags::RequiredArgument);
78+
register_option("M", "meta", "Metadata type", "Choose metadata type if any", [this](const char *arg){m_metadata = arg; return true;}, OptionFlags::RequiredArgument);
5479
}
5580
};
5681

@@ -81,7 +106,10 @@ class NdpPacketReader : public InputPlugin
81106
NdpReader ndpReader;
82107
RxStats m_stats = {};
83108

109+
bool m_ctt_metadata = false;
110+
84111
void init_ifc(const std::string &dev);
112+
void parse_ctt_metadata(const ndp_packet *ndp_packet, Metadata_CTT &ctt);
85113
};
86114

87115
}

0 commit comments

Comments
 (0)