From 2e3179653fe57131a2e2eeb13f2063b4d668ef7d Mon Sep 17 00:00:00 2001 From: Michael Mileusnich Date: Tue, 16 Dec 2025 13:16:40 -0600 Subject: [PATCH 1/2] feat: Perf fixes --- Cargo.toml | 2 +- RELEASES.md | 5 +++++ src/static_versions/v5.rs | 8 ++++---- src/static_versions/v7.rs | 8 ++++---- src/variable_versions/ipfix.rs | 16 ++++++++++------ src/variable_versions/v9.rs | 5 +++-- 6 files changed, 27 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0bb9c4fb..f1fc79e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "netflow_parser" description = "Parser for Netflow Cisco V5, V7, V9, IPFIX" -version = "0.6.6" +version = "0.6.7" edition = "2024" authors = ["michael.mileusnich@gmail.com"] license = "MIT OR Apache-2.0" diff --git a/RELEASES.md b/RELEASES.md index cc051d33..8d985faf 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,8 @@ +# 0.6.7 +* Performance optimizations in V5 and V7 serialization - eliminated unnecessary Vec allocations in `to_be_bytes()`. +* Improved error handling in IPFIX data parsing - parse errors on non-empty templates now properly propagate instead of silently converting to Empty flowsets, while maintaining backward compatibility for empty templates. +* Added capacity pre-allocation for V9 flowset vectors to reduce reallocations during parsing. + # 0.6.6 * Added configurable field mappings for V9 and IPFIX in NetflowCommon. * New `V9FieldMappingConfig` and `IPFixFieldMappingConfig` structs allow customizing which fields map to `NetflowCommonFlowSet`. diff --git a/src/static_versions/v5.rs b/src/static_versions/v5.rs index 0bbdf2c8..2d462b0b 100644 --- a/src/static_versions/v5.rs +++ b/src/static_versions/v5.rs @@ -119,9 +119,8 @@ impl V5 { let header_version = self.header.version.to_be_bytes(); let header_count = self.header.count.to_be_bytes(); let header_sys_up_time = self.header.sys_up_time.to_be_bytes(); - let mut header_unix_timestamp = self.header.unix_secs.to_be_bytes().to_vec(); - let header_unix_nsecs = self.header.unix_nsecs.to_be_bytes().to_vec(); - header_unix_timestamp.extend_from_slice(&header_unix_nsecs); + let header_unix_secs = self.header.unix_secs.to_be_bytes(); + let header_unix_nsecs = self.header.unix_nsecs.to_be_bytes(); let header_flow_seq = self.header.flow_sequence.to_be_bytes(); let header_engine_type = self.header.engine_type.to_be_bytes(); let header_engine_id = self.header.engine_id.to_be_bytes(); @@ -132,7 +131,8 @@ impl V5 { result.extend_from_slice(&header_version); result.extend_from_slice(&header_count); result.extend_from_slice(&header_sys_up_time); - result.extend_from_slice(&header_unix_timestamp); + result.extend_from_slice(&header_unix_secs); + result.extend_from_slice(&header_unix_nsecs); result.extend_from_slice(&header_flow_seq); result.extend_from_slice(&header_engine_type); result.extend_from_slice(&header_engine_id); diff --git a/src/static_versions/v7.rs b/src/static_versions/v7.rs index 55be985d..ef936c39 100644 --- a/src/static_versions/v7.rs +++ b/src/static_versions/v7.rs @@ -120,9 +120,8 @@ impl V7 { let header_version = self.header.version.to_be_bytes(); let header_count = self.header.count.to_be_bytes(); let header_sys_up_time = self.header.sys_up_time.to_be_bytes(); - let mut header_unix_timestamp = self.header.unix_secs.to_be_bytes().to_vec(); - let header_unix_nsecs = self.header.unix_nsecs.to_be_bytes().to_vec(); - header_unix_timestamp.extend_from_slice(&header_unix_nsecs); + let header_unix_secs = self.header.unix_secs.to_be_bytes(); + let header_unix_nsecs = self.header.unix_nsecs.to_be_bytes(); let header_flow_seq = self.header.flow_sequence.to_be_bytes(); let reserved = self.header.reserved.to_be_bytes(); @@ -131,7 +130,8 @@ impl V7 { result.extend_from_slice(&header_version); result.extend_from_slice(&header_count); result.extend_from_slice(&header_sys_up_time); - result.extend_from_slice(&header_unix_timestamp); + result.extend_from_slice(&header_unix_secs); + result.extend_from_slice(&header_unix_nsecs); result.extend_from_slice(&header_flow_seq); result.extend_from_slice(&reserved); diff --git a/src/variable_versions/ipfix.rs b/src/variable_versions/ipfix.rs index dd53e605..cf2691b3 100644 --- a/src/variable_versions/ipfix.rs +++ b/src/variable_versions/ipfix.rs @@ -237,14 +237,18 @@ impl FlowSetBody { // Parse Data _ => { if let Some(template) = parser.templates.get(&id) { - match Data::parse(i, template) { - Ok((i, data)) => Ok((i, FlowSetBody::Data(data))), - Err(_) => Ok((i, FlowSetBody::Empty)), + if template.get_fields().is_empty() { + Ok((i, FlowSetBody::Empty)) + } else { + let (i, data) = Data::parse(i, template)?; + Ok((i, FlowSetBody::Data(data))) } } else if let Some(options_template) = parser.ipfix_options_templates.get(&id) { - match OptionsData::parse(i, options_template) { - Ok((i, data)) => Ok((i, FlowSetBody::OptionsData(data))), - Err(_) => Ok((i, FlowSetBody::Empty)), + if options_template.get_fields().is_empty() { + Ok((i, FlowSetBody::Empty)) + } else { + let (i, data) = OptionsData::parse(i, options_template)?; + Ok((i, FlowSetBody::OptionsData(data))) } } else if let Some(v9_template) = parser.v9_templates.get(&id) { let (i, data) = V9Data::parse(i, v9_template)?; diff --git a/src/variable_versions/v9.rs b/src/variable_versions/v9.rs index fa2bcd19..e0df7e81 100644 --- a/src/variable_versions/v9.rs +++ b/src/variable_versions/v9.rs @@ -449,8 +449,9 @@ impl FlowSetParser { parser: &mut V9Parser, record_count: u16, ) -> IResult<&'a [u8], Vec> { - let (remaining, flowsets) = - (0..record_count).try_fold((i, Vec::new()), |(remaining, mut flowsets), _| { + let (remaining, flowsets) = (0..record_count).try_fold( + (i, Vec::with_capacity(record_count as usize)), + |(remaining, mut flowsets), _| { if remaining.is_empty() { return Ok((remaining, flowsets)); } From 90da0d2aa8a89016dcc6175409a5dd6d7df60e84 Mon Sep 17 00:00:00 2001 From: Michael Mileusnich Date: Tue, 16 Dec 2025 13:17:55 -0600 Subject: [PATCH 2/2] fix: fmt --- src/variable_versions/v9.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/variable_versions/v9.rs b/src/variable_versions/v9.rs index e0df7e81..8f6adc1f 100644 --- a/src/variable_versions/v9.rs +++ b/src/variable_versions/v9.rs @@ -458,7 +458,8 @@ impl FlowSetParser { let (i, flowset) = FlowSet::parse(remaining, parser)?; flowsets.push(flowset); Ok((i, flowsets)) - })?; + }, + )?; Ok((remaining, flowsets)) }