Skip to content

Commit ec1f1ad

Browse files
Michael MileusnichMichael Mileusnich
authored andcommitted
Optimized template lookups
1 parent 9612843 commit ec1f1ad

File tree

4 files changed

+30
-45
lines changed

4 files changed

+30
-45
lines changed

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,12 +390,14 @@ mod tests {
390390
field_type:
391391
super::variable_versions::ipfix_lookup::IPFixField::PacketDeltaCount,
392392
field_length: 2,
393+
enterprise_number: None,
393394
},
394395
IPFixTemplateField {
395396
field_type_number: 8,
396397
field_type:
397398
super::variable_versions::ipfix_lookup::IPFixField::SourceIpv4address,
398399
field_length: 4,
400+
enterprise_number: None,
399401
},
400402
];
401403
let template = IPFixTemplate {

src/snapshots/netflow_parser__tests__it_parses_ipfix_options_template.snap

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,14 @@ expression: "NetflowParser::default().parse_bytes(&packet)"
1818
template_id: 260
1919
field_count: 3
2020
scope_field_count: 1
21-
scope_field_specifiers:
21+
fields:
2222
- field_type_number: 123
2323
field_type: Enterprise
2424
field_length: 4
2525
enterprise_number: 2
26-
field_specifiers:
2726
- field_type_number: 32809
2827
field_type: ExportedMessageTotalCount
2928
field_length: 2
3029
- field_type_number: 32810
3130
field_type: ExportedFlowRecordTotalCount
3231
field_length: 2
33-

src/snapshots/netflow_parser__tests__it_parses_ipfix_options_template_with_data.snap

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ expression: "NetflowParser::default().parse_bytes(&packet)"
1818
template_id: 260
1919
field_count: 3
2020
scope_field_count: 1
21-
scope_field_specifiers:
21+
fields:
2222
- field_type_number: 123
2323
field_type: Enterprise
2424
field_length: 4
2525
enterprise_number: 2
26-
field_specifiers:
2726
- field_type_number: 32809
2827
field_type: ExportedMessageTotalCount
2928
field_length: 2
@@ -46,4 +45,3 @@ expression: "NetflowParser::default().parse_bytes(&packet)"
4645
DataNumber: 7710
4746
Enterprise:
4847
DataNumber: 2
49-

src/variable_versions/ipfix.rs

Lines changed: 26 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::{NetflowByteParserVariable, NetflowPacketResult, ParsedNetflow};
1313

1414
use nom::bytes::complete::take;
1515
use nom::error::{Error as NomError, ErrorKind};
16+
use nom::multi::count;
1617
use nom::number::complete::{be_u128, be_u32};
1718
use nom::Err as NomErr;
1819
use nom::IResult;
@@ -118,12 +119,12 @@ pub struct OptionsTemplate {
118119
pub template_id: u16,
119120
pub field_count: u16,
120121
pub scope_field_count: u16,
121-
#[nom(Count = "scope_field_count")]
122-
pub scope_field_specifiers: Vec<OptionsTemplateField>,
123122
#[nom(
124-
Count = "(field_count.checked_sub(scope_field_count).unwrap_or(field_count)) as usize"
123+
PreExec = "let combined_count = scope_field_count as usize +
124+
field_count.checked_sub(scope_field_count).unwrap_or(field_count) as usize;",
125+
Parse = "count(|i| TemplateField::parse(i, true), combined_count as usize)"
125126
)]
126-
pub field_specifiers: Vec<OptionsTemplateField>,
127+
pub fields: Vec<TemplateField>,
127128
#[nom(Cond = "!i.is_empty()")]
128129
#[serde(skip_serializing)]
129130
padding: Option<u16>,
@@ -133,23 +134,28 @@ pub struct OptionsTemplate {
133134
pub struct Template {
134135
pub template_id: u16,
135136
pub field_count: u16,
136-
#[nom(Count = "field_count")]
137+
#[nom(Parse = "count(|i| TemplateField::parse(i, false), field_count as usize)")]
137138
pub fields: Vec<TemplateField>,
138139
}
139140

140141
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Nom)]
141-
pub struct OptionsTemplateField {
142+
#[nom(ExtraArgs(options_template: bool))]
143+
pub struct TemplateField {
142144
pub field_type_number: u16,
143145
#[nom(Value(IPFixField::from(field_type_number)))]
144146
pub field_type: IPFixField,
145-
field_length: u16,
147+
pub field_length: u16,
146148
#[nom(
147-
Cond = "field_type_number > 32767",
148-
PostExec = "let field_type_number = field_type_number.overflowing_sub(32768).0;",
149-
PostExec = "let field_type = set_entperprise_field(field_type, enterprise_number);"
149+
Cond = "options_template && field_type_number > 32767",
150+
PostExec = "let field_type_number = if options_template {
151+
field_type_number.overflowing_sub(32768).0
152+
} else { field_type_number };",
153+
PostExec = "let field_type = if options_template {
154+
set_entperprise_field(field_type, enterprise_number)
155+
} else { field_type };"
150156
)]
151157
#[serde(skip_serializing_if = "Option::is_none")]
152-
enterprise_number: Option<u32>,
158+
pub enterprise_number: Option<u32>,
153159
}
154160

155161
fn set_entperprise_field(field_type: IPFixField, enterprise_number: Option<u32>) -> IPFixField {
@@ -159,14 +165,6 @@ fn set_entperprise_field(field_type: IPFixField, enterprise_number: Option<u32>)
159165
}
160166
}
161167

162-
#[derive(Debug, PartialEq, Eq, Clone, Serialize, PartialOrd, Ord, Nom)]
163-
pub struct TemplateField {
164-
pub field_type_number: u16,
165-
#[nom(Value(IPFixField::from(field_type_number)))]
166-
pub field_type: IPFixField,
167-
pub field_length: u16,
168-
}
169-
170168
/// Parses options template
171169
fn parse_options_template(i: &[u8], length: u16) -> IResult<&[u8], OptionsTemplate> {
172170
let (remaining, taken) = take(length.checked_sub(4).unwrap_or(length))(i)?;
@@ -177,37 +175,26 @@ fn parse_options_template(i: &[u8], length: u16) -> IResult<&[u8], OptionsTempla
177175
// Hacky way when using Template as generic T to cast to a common field type.
178176
// We use OptionsTemplateField as it is the same as type Template Field but
179177
// with enterprise_field. In TemplateField tpe enterprise_field is just None.
180-
trait CommonTemplateFields {
181-
fn get_fields(&self) -> Vec<OptionsTemplateField>;
178+
trait CommonTemplate {
179+
fn get_fields(&self) -> &Vec<TemplateField>;
182180
}
183181

184-
impl CommonTemplateFields for Template {
185-
fn get_fields(&self) -> Vec<OptionsTemplateField> {
186-
self.fields
187-
.iter()
188-
.map(|f| OptionsTemplateField {
189-
field_length: f.field_length,
190-
field_type: f.field_type,
191-
field_type_number: f.field_type_number,
192-
enterprise_number: None,
193-
})
194-
.collect()
182+
impl CommonTemplate for Template {
183+
fn get_fields(&self) -> &Vec<TemplateField> {
184+
&self.fields
195185
}
196186
}
197187

198-
impl CommonTemplateFields for OptionsTemplate {
199-
fn get_fields(&self) -> Vec<OptionsTemplateField> {
200-
let mut temp = vec![];
201-
temp.append(&mut self.scope_field_specifiers.clone());
202-
temp.append(&mut self.field_specifiers.clone());
203-
temp
188+
impl CommonTemplate for OptionsTemplate {
189+
fn get_fields(&self) -> &Vec<TemplateField> {
190+
&self.fields
204191
}
205192
}
206193

207194
/// Takes a byte stream and a cached template.
208195
/// Fields get matched to static types.
209196
/// Returns BTree of IPFix Types & Fields or IResult Error.
210-
fn parse_fields<'a, T: CommonTemplateFields>(
197+
fn parse_fields<'a, T: CommonTemplate>(
211198
i: &'a [u8],
212199
template: Option<&T>,
213200
) -> IResult<&'a [u8], Vec<BTreeMap<IPFixField, FieldValue>>> {

0 commit comments

Comments
 (0)