Skip to content

Commit edeee93

Browse files
committed
NetFlow: minor fixes in NetFlow v5/v9 converters, added unit tests for NetFlow v9 converter
1 parent c2024ce commit edeee93

File tree

8 files changed

+2986
-20
lines changed

8 files changed

+2986
-20
lines changed

src/core/netflow2ipfix/netflow2ipfix.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@ ipx_nf5_conv_destroy(ipx_nf5_conv_t *conv);
6969
* @note
7070
* In case of an error (i.e. return code different from #IPX_OK) the original NetFlow Message
7171
* in the wrapper is untouched.
72+
* @note
73+
* Sequence number of the first IPFIX Message is deduced from the first NetFlow message to
74+
* convert. Sequence numbers of following converted messages is incremented independently
75+
* on the original NetFlow sequence number to avoid creation of invalid messages. In other words,
76+
* missing or reordered NetFlow messages don't affect correctness of the IPFIX stream.
77+
*
7278
* @param[in] conv Message converter
7379
* @param[in] wrapper Message wrapper
7480
* @return #IPX_OK on success
@@ -78,6 +84,15 @@ ipx_nf5_conv_destroy(ipx_nf5_conv_t *conv);
7884
int
7985
ipx_nf5_conv_process(ipx_nf5_conv_t *conv, ipx_msg_ipfix_t *wrapper);
8086

87+
/**
88+
* @brief Change verbosity level
89+
*
90+
* @param[in] conv Message converter
91+
* @param[in] v_new New verbosity level
92+
*/
93+
void
94+
ipx_nf5_conv_verb(ipx_nf5_conv_t *conv, enum ipx_verb_level v_new);
95+
8196
/**
8297
* @}
8398
*/
@@ -94,6 +109,13 @@ ipx_nf5_conv_process(ipx_nf5_conv_t *conv, ipx_msg_ipfix_t *wrapper);
94109
* stream (i.e. combination of an Exporter and Source ID).
95110
*
96111
* @note
112+
* NetFlow Field Specifiers with ID > 127 are not backwards compatible with IPFIX Information
113+
* Elements, therefore, after conversion these specifiers are defined as Enterprise Specific
114+
* fields with Enterprise Number 4294967294 (128 <= ID <= 32767) or Enterprise Number 4294967295
115+
* (32768 <= ID <= 65535). In the latter case, the ID of the field is changed to fit into
116+
* range 0..32767: newID = oldID - 32768.
117+
*
118+
* @note
97119
* In the context of IPFIX protocol, the Source ID is referred as Observation Domain ID (ODID)
98120
*
99121
* @{
@@ -133,6 +155,11 @@ ipx_nf9_conv_destroy(ipx_nf9_conv_t *conv);
133155
* @note
134156
* After conversion the IPFIX Message is not ready to be used for accessing flow records,
135157
* it MUST be processed by the IPFIX Parser first.
158+
* @note
159+
* Sequence numbers of IPFIX Messages are incremented independently on NetFlow messages to
160+
* convert and starts from 0. In other words, missing or reordered NetFlow messages don't
161+
* affect correctness of the IPFIX stream.
162+
*
136163
* @param[in] conv Message converter
137164
* @param[in] wrapper Message wrapper
138165
* @return #IPX_OK on success
@@ -142,6 +169,15 @@ ipx_nf9_conv_destroy(ipx_nf9_conv_t *conv);
142169
int
143170
ipx_nf9_conv_process(ipx_nf9_conv_t *conv, ipx_msg_ipfix_t *wrapper);
144171

172+
/**
173+
* @brief Change verbosity level
174+
*
175+
* @param[in] conv Message converter
176+
* @param[in] v_new New verbosity level
177+
*/
178+
void
179+
ipx_nf9_conv_verb(ipx_nf9_conv_t *conv, enum ipx_verb_level v_new);
180+
145181
/**
146182
* @}
147183
*/

src/core/netflow2ipfix/netflow5.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,4 +546,10 @@ ipx_nf5_conv_process(ipx_nf5_conv_t *conv, ipx_msg_ipfix_t *wrapper)
546546
wrapper->raw_pkt = ipx_msg;
547547
wrapper->raw_size = (uint16_t) ipx_size;
548548
return IPX_OK;
549+
}
550+
551+
void
552+
ipx_nf5_conv_verb(ipx_nf5_conv_t *conv, enum ipx_verb_level v_new)
553+
{
554+
conv->conf.vlevel = v_new;
549555
}

src/core/netflow2ipfix/netflow9.c

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#define NF_INCOMP_ID_MIN 128
3030
/// IPFIX Enterprise Number for incompatible NetFlow IEs (128 <= ID <= 32767)
3131
#define NF_INCOMP_EN_LOW 4294967294UL
32-
/// IPFIX Enterprise Number for incompatible NetFlow IEs (32767 <= ID <= 65535)
32+
/// IPFIX Enterprise Number for incompatible NetFlow IEs (32768 <= ID <= 65535)
3333
#define NF_INCOMP_EN_HIGH 4294967295UL
3434
/**
3535
* Maximum length of any IPFIX Message Set
@@ -62,15 +62,15 @@ struct nf2ipx_opts {
6262
*/
6363
static const struct nf2ipx_opts nf2ipx_opts_table[] = {
6464
// "System" -> iana:exportingProcessId
65-
{1U, 144U, 4U},
65+
{IPX_NF9_SCOPE_SYSTEM, 144U, 4U},
6666
// "Interface" -> iana:ingressInterface
67-
{2U, 10U, 4U},
67+
{IPX_NF9_SCOPE_INTERFACE, 10U, 4U},
6868
// "Line Card" -> iana:lineCardId
69-
{3U, 141U, 4U},
69+
{IPX_NF9_SCOPE_LINE_CARD, 141U, 4U},
7070
// "Cache" -> ??? (maybe iana:meteringProcessId)
71-
// {4, xxx, xxx},
71+
// {IPX_NF9_SCOPE_CACHE, xxx, xxx},
7272
// "Template" -> iana:templateId
73-
{5U, 145U, 2U}
73+
{IPX_NF9_SCOPE_TEMPLATE, 145U, 2U}
7474
};
7575

7676
/// Number of record the the Options conversion table
@@ -108,9 +108,9 @@ struct nf2ipx_data {
108108
*/
109109
static const struct nf2ipx_data nf2ipx_data_table[] = {
110110
// Conversion from relative to absolute TS: "LAST_SWITCHED" -> iana:flowEndMilliseconds
111-
{{21U, 4U}, {153U, 0U, 8U}, {NF2IPX_ITYPE_TS, 8U}},
111+
{{IPX_NF9_IE_LAST_SWITCHED, 4U}, {153U, 0U, 8U}, {NF2IPX_ITYPE_TS, 8U}},
112112
// Conversion from relative to absolute TS: "FIRST_SWITCHED" -> iana:flowStartMilliseconds
113-
{{22U, 4U}, {152U, 0U, 8U}, {NF2IPX_ITYPE_TS, 8U}}
113+
{{IPX_NF9_IE_FIRST_SWITCHED, 4U}, {152U, 0U, 8U}, {NF2IPX_ITYPE_TS, 8U}}
114114
};
115115

116116
/// Number of record the the Data conversion table */
@@ -801,7 +801,7 @@ conv_tmplt_from_data(ipx_nf9_conv_t *conv, const struct ipx_nf9_tset_iter *it, u
801801
* The function creates and appends a new IPFIX (Options) Template Set with converted
802802
* (Options) Template records to the new IPFIX Message. For each NetFlow (Options) Template
803803
* record a conversion function is called and the new IPFIX Template record is stored for future
804-
* using during parsing and Data record conversions.
804+
* parsing and Data record conversions.
805805
* @param[in] conv Converter internals
806806
* @param[in] flowset_hdr NetFlow (Options) Template Set to be converted
807807
* @return #IPX_OK on success
@@ -928,7 +928,7 @@ conv_process_tset(ipx_nf9_conv_t *conv, const struct ipx_nf9_set_hdr *flowset_hd
928928
static inline uint64_t
929929
conv_ts_rel2abs(const struct ipx_nf9_msg_hdr *hdr, const uint32_t *nf_ts)
930930
{
931-
const uint64_t hdr_exp = ntohl(hdr->unix_sec) * 1000U;
931+
const uint64_t hdr_exp = ntohl(hdr->unix_sec) * 1000ULL;
932932
const uint64_t hdr_sys = ntohl(hdr->sys_uptime);
933933
const uint64_t rec_sys = ntohl(*nf_ts);
934934
return (hdr_exp - hdr_sys) + rec_sys;
@@ -962,7 +962,6 @@ conv_process_drec(ipx_nf9_conv_t *conv, const struct ipx_nf9_msg_hdr *nf9_msg,
962962
// Execute conversion instructions
963963
const uint8_t *nf9_pos = nf9_rec;
964964
uint8_t *ipx_pos = conv_mem_ptr_now(conv);
965-
size_t offset_start = conv_mem_pos_get(conv);
966965

967966
for (size_t i = 0; i < tmplt->instr_size; ++i) {
968967
const struct nf2ipx_instr *instr = &tmplt->instr_data[i];
@@ -975,7 +974,7 @@ conv_process_drec(ipx_nf9_conv_t *conv, const struct ipx_nf9_msg_hdr *nf9_msg,
975974
break;
976975
case NF2IPX_ITYPE_TS:
977976
// Convert relative timestamp to absolute timestamp
978-
*((uint64_t *) ipx_pos) = conv_ts_rel2abs(nf9_msg, (uint32_t *) nf9_pos);
977+
*((uint64_t *) ipx_pos) = htobe64(conv_ts_rel2abs(nf9_msg, (uint32_t *) nf9_pos));
979978
nf9_pos += 4U; // NetFlow TS (FIRST_SWITCHED/LAST_SWITCHED)
980979
ipx_pos += 8U; // IPFIX TS (iana:flowStartMilliseconds/flowEndMilliseconds)
981980
break;
@@ -986,7 +985,6 @@ conv_process_drec(ipx_nf9_conv_t *conv, const struct ipx_nf9_msg_hdr *nf9_msg,
986985
}
987986

988987
// Commit written memory
989-
assert(tmplt->ipx_drec_len == (conv_mem_pos_get(conv) - offset_start));
990988
conv_mem_commit(conv, tmplt->ipx_drec_len);
991989
return IPX_OK;
992990
}
@@ -1014,7 +1012,7 @@ conv_process_dset(ipx_nf9_conv_t *conv, const struct ipx_nf9_set_hdr *flowset_hd
10141012
const struct nf9_trec *tmplt = nf9_tmplts_find(&conv->l1_table, tid);
10151013
if (!tmplt) {
10161014
// Template NOT found!
1017-
CONV_WARNING(conv, "Unable to convert NetFlow v9 Data Set (FlowSet ID: " PRIu16 ") to "
1015+
CONV_WARNING(conv, "Unable to convert NetFlow v9 Data Set (FlowSet ID: %" PRIu16 ") to "
10181016
"IPFIX due to missing NetFlow template. The Data FlowSet and its records will be "
10191017
"dropped!", tid);
10201018
return IPX_OK;
@@ -1129,7 +1127,7 @@ conv_process_msg(ipx_nf9_conv_t *conv, const struct ipx_nf9_msg_hdr *nf9_msg, ui
11291127
// (Options) Template FlowSet
11301128
rc_conv = conv_process_tset(conv, it.set);
11311129
} else {
1132-
// Unknown FlowSet ID
1130+
// Unknown FlowSet ID // TODO: skip unknown
11331131
CONV_ERROR(conv, "Unknown FlowSet ID %" PRIu16, flowset_id);
11341132
rc_conv = IPX_ERR_FORMAT;
11351133
}
@@ -1203,8 +1201,10 @@ ipx_nf9_conv_process(ipx_nf9_conv_t *conv, ipx_msg_ipfix_t *wrapper)
12031201
CONV_DEBUG(conv, "Converting a NetFlow Message v9 (seq. num. %" PRIu32 ") to an IPFIX Message "
12041202
"(new seq. num. %" PRIu32 ")", msg_seq, conv->ipx_seq_next);
12051203

1206-
bool old_oos = false; // Old (out of sequence message)
1204+
bool is_oos = false; // Old (out of sequence message)
12071205
if (conv->nf9_seq_next != msg_seq) {
1206+
is_oos = true;
1207+
12081208
if (!conv->nf9_seq_valid) {
12091209
// The first message to convert
12101210
conv->nf9_seq_valid = true;
@@ -1214,16 +1214,15 @@ ipx_nf9_conv_process(ipx_nf9_conv_t *conv, ipx_msg_ipfix_t *wrapper)
12141214
CONV_WARNING(conv, "Unexpected Sequence number (expected: %" PRIu32 ", got: %" PRId32 ")",
12151215
conv->nf9_seq_next, msg_seq);
12161216
if (conv_seq_num_cmp(msg_seq, conv->nf9_seq_next) > 0) {
1217-
conv->nf9_seq_next = msg_seq + 1; // Newer than expected
1218-
} else {
1219-
old_oos = true; // Older than expected
1217+
// Newer than expected (expect that all previous messages are lost)
1218+
conv->nf9_seq_next = msg_seq + 1;
12201219
}
12211220
}
12221221
}
12231222
conv->nf9_seq_valid = true;
12241223

12251224
// Update expected Sequence number of the next NetFlow message
1226-
if (!old_oos) {
1225+
if (!is_oos) {
12271226
++conv->nf9_seq_next;
12281227
}
12291228

@@ -1267,3 +1266,9 @@ ipx_nf9_conv_process(ipx_nf9_conv_t *conv, ipx_msg_ipfix_t *wrapper)
12671266
wrapper->raw_size = (uint16_t) ipx_size;
12681267
return IPX_OK;
12691268
}
1269+
1270+
void
1271+
ipx_nf9_conv_verb(ipx_nf9_conv_t *conv, enum ipx_verb_level v_new)
1272+
{
1273+
conv->vlevel = v_new;
1274+
}

0 commit comments

Comments
 (0)