Skip to main content

netgauze_flow_pkt/
lib.rs

1// Copyright (C) 2022-present The NetGauze Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//    http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12// implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! Flow packet types and utilities for IPFIX and NetFlow v9.
17//!
18//! This crate provides data models, information elements, and (optional)
19//! codecs for working with IPFIX and NetFlow v9 packets. It includes helpers
20//! to inspect packet metadata and to manipulate fields for IPFIX data records.
21//!
22//! # Example
23//!
24//! ```rust
25//! use chrono::{TimeZone, Utc};
26//! use netgauze_flow_pkt::ipfix::{IpfixPacket, Set};
27//! use netgauze_flow_pkt::{DataSetId, FlowInfo};
28//!
29//! let export_time = Utc.with_ymd_and_hms(2024, 6, 20, 14, 0, 0).unwrap();
30//! let ipfix = IpfixPacket::new(
31//!     export_time,
32//!     1,
33//!     42,
34//!     Box::new([Set::Data {
35//!         id: DataSetId::new(400).unwrap(),
36//!         records: Box::new([]),
37//!     }]),
38//! );
39//!
40//! let flow = FlowInfo::IPFIX(ipfix);
41//! assert_eq!(flow.observation_domain_id(), 42);
42//! ```
43
44#[cfg(feature = "codec")]
45pub mod codec;
46pub mod ie;
47pub mod ipfix;
48pub mod netflow;
49#[cfg(feature = "serde")]
50pub mod wire;
51
52use crate::ie::*;
53use serde::{Deserialize, Serialize};
54use std::ops::Deref;
55
56/// Errors for FlowInfo operations
57#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, strum_macros::Display)]
58pub enum FlowInfoError {
59    /// NetFlow v9 is not supported for this operation
60    #[strum(serialize = "NetFlow v9 is not supported for this operation")]
61    NetFlowV9NotSupported,
62}
63
64impl std::error::Error for FlowInfoError {}
65
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
67pub enum FlowInfo {
68    NetFlowV9(netflow::NetFlowV9Packet),
69    IPFIX(ipfix::IpfixPacket),
70}
71
72impl FlowInfo {
73    pub const fn export_time(&self) -> chrono::DateTime<chrono::Utc> {
74        match self {
75            Self::IPFIX(packet) => packet.export_time(),
76            Self::NetFlowV9(packet) => packet.unix_time(),
77        }
78    }
79
80    pub const fn sequence_number(&self) -> u32 {
81        match self {
82            Self::IPFIX(packet) => packet.sequence_number(),
83            Self::NetFlowV9(packet) => packet.sequence_number(),
84        }
85    }
86
87    pub const fn observation_domain_id(&self) -> u32 {
88        match self {
89            Self::IPFIX(packet) => packet.observation_domain_id(),
90            Self::NetFlowV9(packet) => packet.source_id(),
91        }
92    }
93
94    /// Add fields to all data records in the flow packet
95    pub fn with_fields_added(self, add_fields: &[Field]) -> Result<Self, FlowInfoError> {
96        match self {
97            Self::IPFIX(packet) => Ok(Self::IPFIX(packet.with_fields_added(add_fields))),
98            Self::NetFlowV9(_) => Err(FlowInfoError::NetFlowV9NotSupported),
99        }
100    }
101
102    /// Add scope fields to all data records in the flow packet
103    pub fn with_scope_fields_added(
104        self,
105        add_scope_fields: &[Field],
106    ) -> Result<Self, FlowInfoError> {
107        match self {
108            Self::IPFIX(packet) => Ok(Self::IPFIX(
109                packet.with_scope_fields_added(add_scope_fields),
110            )),
111            Self::NetFlowV9(_) => Err(FlowInfoError::NetFlowV9NotSupported),
112        }
113    }
114}
115
116/// Errors when crafting a new Set
117#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, strum_macros::Display)]
118pub enum FieldSpecifierError {
119    /// Specified field length was out of the range defined by the registry
120    #[strum(to_string = "Invalid length specified {0} for IE: {1:?}")]
121    InvalidLength(u16, IE),
122}
123
124impl std::error::Error for FieldSpecifierError {}
125
126/// Field Specifier
127///
128/// ```text
129/// 0                   1                   2                   3
130/// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
131/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
132/// |E|  Information Element ident. |        Field Length           |
133/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
134/// |                      Enterprise Number                        |
135/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
136/// ```
137#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
138#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
139pub struct FieldSpecifier {
140    element_id: IE,
141    length: u16,
142}
143
144impl FieldSpecifier {
145    pub fn new(element_id: IE, length: u16) -> Result<Self, FieldSpecifierError> {
146        if let Some(range) = element_id.length_range()
147            && !range.contains(&length)
148        {
149            return Err(FieldSpecifierError::InvalidLength(length, element_id));
150        };
151        Ok(Self { element_id, length })
152    }
153
154    pub const fn element_id(&self) -> IE {
155        self.element_id
156    }
157
158    pub const fn length(&self) -> u16 {
159        self.length
160    }
161}
162
163#[derive(Copy, Clone, PartialEq, Eq, Debug, Serialize, Deserialize, strum_macros::Display)]
164pub enum DataSetIdError {
165    #[strum(serialize = "Invalid data set id specified: {0}")]
166    InvalidId(u16),
167}
168
169impl std::error::Error for DataSetIdError {}
170
171#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)]
172#[cfg_attr(feature = "fuzz", derive(arbitrary::Arbitrary))]
173pub struct DataSetId(u16);
174
175/// Values 256 and above are used for Data Sets
176pub(crate) const DATA_SET_MIN_ID: u16 = 256;
177
178impl DataSetId {
179    pub const fn new(id: u16) -> Result<Self, DataSetIdError> {
180        if id < DATA_SET_MIN_ID {
181            Err(DataSetIdError::InvalidId(id))
182        } else {
183            Ok(Self(id))
184        }
185    }
186
187    #[inline]
188    pub const fn id(&self) -> u16 {
189        self.0
190    }
191}
192
193impl Deref for DataSetId {
194    type Target = u16;
195
196    fn deref(&self) -> &Self::Target {
197        &self.0
198    }
199}
200
201#[cfg(feature = "fuzz")]
202fn arbitrary_datetime(
203    u: &mut arbitrary::Unstructured<'_>,
204) -> arbitrary::Result<chrono::DateTime<chrono::Utc>> {
205    use chrono::TimeZone;
206    loop {
207        let seconds = u.int_in_range(0..=i64::MAX)?;
208        if let chrono::LocalResult::Single(tt) = chrono::Utc.timestamp_opt(seconds, 0) {
209            return Ok(tt);
210        }
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use super::*;
217    use crate::ie::protocolIdentifier;
218    use crate::ipfix::IpfixPacket;
219    use crate::netflow::NetFlowV9Packet;
220    use chrono::{TimeZone, Utc};
221    use netgauze_iana::tcp::TCPHeaderFlags;
222
223    #[test]
224    fn test_flow_info_api() {
225        let export_time = Utc.with_ymd_and_hms(2024, 6, 20, 14, 0, 0).unwrap();
226        let sequence_number = 2;
227        let observation_domain = 100;
228        let ipfix_data = IpfixPacket::new(
229            export_time,
230            sequence_number,
231            observation_domain,
232            Box::new([ipfix::Set::Data {
233                id: DataSetId::new(400).unwrap(),
234                records: Box::new([]),
235            }]),
236        );
237        let netflow_data = NetFlowV9Packet::new(
238            45646,
239            export_time,
240            sequence_number,
241            observation_domain,
242            Box::new([netflow::Set::Data {
243                id: DataSetId::new(400).unwrap(),
244                records: Box::new([]),
245            }]),
246        );
247
248        let flow_ipfix = FlowInfo::IPFIX(ipfix_data.clone());
249        let flow_netflow = FlowInfo::NetFlowV9(netflow_data.clone());
250
251        assert_eq!(ipfix_data.export_time(), export_time);
252        assert_eq!(ipfix_data.sequence_number(), sequence_number);
253        assert_eq!(ipfix_data.observation_domain_id(), observation_domain);
254        assert_eq!(netflow_data.unix_time(), export_time);
255        assert_eq!(netflow_data.sequence_number(), sequence_number);
256        assert_eq!(netflow_data.source_id(), observation_domain);
257        assert_eq!(flow_ipfix.export_time(), export_time);
258        assert_eq!(flow_ipfix.sequence_number(), sequence_number);
259        assert_eq!(flow_ipfix.observation_domain_id(), observation_domain);
260        assert_eq!(flow_netflow.export_time(), export_time);
261        assert_eq!(flow_netflow.sequence_number(), sequence_number);
262        assert_eq!(flow_netflow.observation_domain_id(), observation_domain);
263    }
264
265    #[test]
266    fn test_supports_arithmetic() {
267        // octetArray doesn't support arithmetic operations
268        assert!(!IE::mplsLabelStackSection.supports_arithmetic_ops());
269        assert!(!IE::paddingOctets.supports_arithmetic_ops());
270        // number types (except unsigned256) supports arithmetic ops,
271        assert!(IE::destinationIPv4PrefixLength.supports_arithmetic_ops());
272        assert!(IE::flowActiveTimeout.supports_arithmetic_ops());
273        assert!(IE::distinctCountOfSourceIPv4Address.supports_arithmetic_ops());
274        assert!(IE::postMCastPacketDeltaCount.supports_arithmetic_ops());
275        assert!(!IE::ipv6ExtensionHeadersFull.supports_arithmetic_ops());
276        assert!(IE::mibObjectValueInteger.supports_arithmetic_ops());
277        assert!(IE::absoluteError.supports_arithmetic_ops());
278        // numbers that are identifiers, flags, or have subregistries don't support
279        // arithmetic ops
280        assert!(!IE::ipClassOfService.supports_arithmetic_ops());
281        assert!(!IE::egressInterface.supports_arithmetic_ops());
282        assert!(!IE::forwardingStatus.supports_arithmetic_ops());
283        // Bool doesn't support arithmetic ops
284        assert!(!IE::dataRecordsReliability.supports_arithmetic_ops());
285        // Time doesn't support arithmetic ops
286        assert!(!IE::observationTimeSeconds.supports_arithmetic_ops());
287        assert!(!IE::observationTimeMilliseconds.supports_arithmetic_ops());
288        assert!(!IE::observationTimeNanoseconds.supports_arithmetic_ops());
289        assert!(!IE::observationTimeMicroseconds.supports_arithmetic_ops());
290        // IP addresses don't support arithmetic ops
291        assert!(!IE::sourceIPv4Address.supports_arithmetic_ops());
292        assert!(!IE::sourceIPv6Address.supports_arithmetic_ops());
293        // List doesn't support arithmetic ops
294        assert!(!IE::bgpSourceCommunityList.supports_arithmetic_ops());
295        assert!(!IE::ipv6ExtensionHeaderTypeCountList.supports_arithmetic_ops());
296        assert!(!IE::subTemplateMultiList.supports_arithmetic_ops());
297    }
298
299    #[test]
300    fn test_supports_bitwise_ops() {
301        // octetArray supports bitwise operations
302        assert!(IE::mplsLabelStackSection.supports_bitwise_ops());
303        assert!(IE::paddingOctets.supports_bitwise_ops());
304        // number types (including unsigned256) supports bitwise ops,
305        assert!(IE::destinationIPv4PrefixLength.supports_bitwise_ops());
306        assert!(IE::flowActiveTimeout.supports_bitwise_ops());
307        assert!(IE::distinctCountOfSourceIPv4Address.supports_bitwise_ops());
308        assert!(IE::postMCastPacketDeltaCount.supports_bitwise_ops());
309        assert!(IE::ipv6ExtensionHeadersFull.supports_bitwise_ops());
310        assert!(IE::mibObjectValueInteger.supports_bitwise_ops());
311        // numbers that are identifiers, flags, or have subregistries support bitwise
312        // ops
313        assert!(IE::ipClassOfService.supports_bitwise_ops());
314        assert!(IE::egressInterface.supports_bitwise_ops());
315        assert!(IE::forwardingStatus.supports_bitwise_ops());
316        // Bool doesn't support bitwise ops
317        assert!(IE::dataRecordsReliability.supports_bitwise_ops());
318        // Time doesn't support bitwise ops
319        assert!(!IE::observationTimeSeconds.supports_bitwise_ops());
320        assert!(!IE::observationTimeMilliseconds.supports_bitwise_ops());
321        assert!(!IE::observationTimeNanoseconds.supports_bitwise_ops());
322        assert!(!IE::observationTimeMicroseconds.supports_bitwise_ops());
323        // IP addresses support bitwise ops
324        assert!(IE::sourceIPv4Address.supports_bitwise_ops());
325        assert!(IE::sourceIPv6Address.supports_bitwise_ops());
326    }
327
328    #[test]
329    fn test_supports_comparison_ops() {
330        // octetArray doesn't support comparison operations
331        assert!(!IE::mplsLabelStackSection.supports_comparison_ops());
332        assert!(!IE::paddingOctets.supports_comparison_ops());
333        // number types (excluding unsigned256) supports comparison ops,
334        assert!(IE::destinationIPv4PrefixLength.supports_comparison_ops());
335        assert!(IE::flowActiveTimeout.supports_comparison_ops());
336        assert!(IE::distinctCountOfSourceIPv4Address.supports_comparison_ops());
337        assert!(IE::postMCastPacketDeltaCount.supports_comparison_ops());
338        assert!(!IE::ipv6ExtensionHeadersFull.supports_comparison_ops());
339        assert!(IE::mibObjectValueInteger.supports_comparison_ops());
340        // numbers that are identifiers, flags, or have subregistries support comparison
341        // ops
342        assert!(IE::ipClassOfService.supports_comparison_ops());
343        assert!(IE::egressInterface.supports_comparison_ops());
344        assert!(IE::forwardingStatus.supports_comparison_ops());
345        // Bool doesn't support comparison ops
346        assert!(!IE::dataRecordsReliability.supports_comparison_ops());
347        // Time supports comparison ops
348        assert!(IE::observationTimeSeconds.supports_comparison_ops());
349        assert!(IE::observationTimeMilliseconds.supports_comparison_ops());
350        assert!(IE::observationTimeNanoseconds.supports_comparison_ops());
351        assert!(IE::observationTimeMicroseconds.supports_comparison_ops());
352        // IP addresses support comparison ops
353        assert!(IE::sourceIPv4Address.supports_comparison_ops());
354        assert!(IE::sourceIPv6Address.supports_comparison_ops());
355    }
356
357    #[test]
358    fn test_field_add() {
359        let mut octet1 = Field::octetDeltaCount(100);
360        let octet2 = Field::octetDeltaCount(200);
361        let packet1 = Field::packetDeltaCount(300);
362
363        let result_err1 = octet1.add_field(&packet1);
364        let result_err2 = octet1.add_assign_field(&packet1);
365        let result = octet1.add_field(&octet2).expect("add field");
366        octet1
367            .add_assign_field(&octet2)
368            .expect("add field mut failed");
369        let expected = Field::octetDeltaCount(300);
370        let expected_err = Some(FieldOperationError::InapplicableAdd(
371            IE::octetDeltaCount,
372            IE::packetDeltaCount,
373        ));
374
375        assert_eq!(result, expected);
376        assert_eq!(octet1, expected);
377        assert_eq!(result_err1.err(), expected_err);
378        assert_eq!(result_err2.err(), expected_err);
379    }
380
381    #[test]
382    fn test_field_min() {
383        let mut field1 = Field::octetDeltaCount(100);
384        let field2 = Field::octetDeltaCount(200);
385        let packet1 = Field::packetDeltaCount(300);
386
387        let result_err1 = field1.min_field(&packet1);
388        let result_err2 = field1.min_assign_field(&packet1);
389        let result = field1.min_field(&field2).expect("min field");
390        field1
391            .min_assign_field(&field2)
392            .expect("min field mut failed");
393        let expected = Field::octetDeltaCount(100);
394        let expected_err = Some(FieldOperationError::InapplicableMin(
395            IE::octetDeltaCount,
396            IE::packetDeltaCount,
397        ));
398
399        assert_eq!(result, expected);
400        assert_eq!(field1, expected);
401        assert_eq!(result_err1.err(), expected_err);
402        assert_eq!(result_err2.err(), expected_err);
403    }
404
405    #[test]
406    fn test_field_max() {
407        let mut field1 = Field::octetDeltaCount(100);
408        let field2 = Field::octetDeltaCount(200);
409        let packet1 = Field::packetDeltaCount(300);
410
411        let result_err1 = field1.max_field(&packet1);
412        let result_err2 = field1.max_assign_field(&packet1);
413        let result = field1.max_field(&field2).expect("max field");
414        field1
415            .max_assign_field(&field2)
416            .expect("max field mut failed");
417        let expected = Field::octetDeltaCount(200);
418        let expected_err = Some(FieldOperationError::InapplicableMax(
419            IE::octetDeltaCount,
420            IE::packetDeltaCount,
421        ));
422
423        assert_eq!(result, expected);
424        assert_eq!(field1, expected);
425        assert_eq!(result_err1.err(), expected_err);
426        assert_eq!(result_err2.err(), expected_err);
427    }
428
429    #[test]
430    fn test_field_bitwise_or() {
431        let mut field1 = Field::octetDeltaCount(100);
432        let field2 = Field::octetDeltaCount(200);
433        let packet1 = Field::packetDeltaCount(300);
434
435        let result_err1 = field1.bitwise_or_field(&packet1);
436        let result_err2 = field1.bitwise_or_assign_field(&packet1);
437        let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
438        field1
439            .bitwise_or_assign_field(&field2)
440            .expect("bitwise or field mut failed");
441        let expected = Field::octetDeltaCount(236);
442        let expected_err = Some(FieldOperationError::InapplicableBitwise(
443            IE::octetDeltaCount,
444            IE::packetDeltaCount,
445        ));
446
447        assert_eq!(result, expected);
448        assert_eq!(field1, expected);
449        assert_eq!(result_err1.err(), expected_err);
450        assert_eq!(result_err2.err(), expected_err);
451    }
452
453    #[test]
454    fn test_field_bitwise_or_tcp_control_bits() {
455        let mut field1 = Field::tcpControlBits(TCPHeaderFlags::from(0x01u8));
456        let field2 = Field::tcpControlBits(TCPHeaderFlags::from(0x02u8));
457        let packet1 = Field::packetDeltaCount(300);
458
459        let result_err1 = field1.bitwise_or_field(&packet1);
460        let result_err2 = field1.bitwise_or_assign_field(&packet1);
461        let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
462        field1
463            .bitwise_or_assign_field(&field2)
464            .expect("bitwise or field mut failed");
465        let expected = Field::tcpControlBits(TCPHeaderFlags::from(0x03u8));
466        let expected_err = Some(FieldOperationError::InapplicableBitwise(
467            IE::tcpControlBits,
468            IE::packetDeltaCount,
469        ));
470
471        assert_eq!(result, expected);
472        assert_eq!(field1, expected);
473        assert_eq!(result_err1.err(), expected_err);
474        assert_eq!(result_err2.err(), expected_err);
475    }
476
477    #[test]
478    fn test_field_bitwise_or_protocol_identifier() {
479        let mut field1 = Field::protocolIdentifier(protocolIdentifier::ICMP);
480        let field2 = Field::protocolIdentifier(protocolIdentifier::IGMP);
481        let packet1 = Field::packetDeltaCount(300);
482
483        let result_err1 = field1.bitwise_or_field(&packet1);
484        let result_err2 = field1.bitwise_or_assign_field(&packet1);
485        let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
486        field1
487            .bitwise_or_assign_field(&field2)
488            .expect("bitwise or field mut failed");
489        let expected = Field::protocolIdentifier(protocolIdentifier::from(0x03u8));
490        let expected_err = Some(FieldOperationError::InapplicableBitwise(
491            IE::protocolIdentifier,
492            IE::packetDeltaCount,
493        ));
494
495        assert_eq!(result, expected);
496        assert_eq!(field1, expected);
497        assert_eq!(result_err1.err(), expected_err);
498        assert_eq!(result_err2.err(), expected_err);
499    }
500
501    #[test]
502    fn test_vmware_ops() {
503        let mut vendor_field1 = vmware::Field::averageLatency(100);
504        let vendor_field2 = vmware::Field::averageLatency(200);
505        let vendor_other_field = vmware::Field::algControlFlowId(123);
506
507        let result_err1 = vendor_field1.add_field(&vendor_other_field);
508        let result_err2 = vendor_field1.add_assign_field(&vendor_other_field);
509        let result = vendor_field1.add_field(&vendor_field2).expect("add field");
510        vendor_field1
511            .add_assign_field(&vendor_field2)
512            .expect("add field");
513        let expected = vmware::Field::averageLatency(300);
514        let expected_err = Some(vmware::FieldOperationError::InapplicableAdd(
515            vmware::IE::averageLatency,
516            vmware::IE::algControlFlowId,
517        ));
518
519        assert_eq!(result, expected);
520        assert_eq!(vendor_field1, expected);
521        assert_eq!(result_err1.err(), expected_err);
522        assert_eq!(result_err2.err(), expected_err);
523    }
524
525    #[test]
526    fn test_vendor_field_add() {
527        let mut field1 = Field::VMWare(vmware::Field::averageLatency(100));
528        let field2 = Field::VMWare(vmware::Field::averageLatency(200));
529        let other_field = Field::VMWare(vmware::Field::algControlFlowId(123));
530
531        let result_err1 = field1.add_field(&other_field);
532        let result_err2 = field1.add_assign_field(&other_field);
533        let result = field1.add_field(&field2).expect("add field");
534        field1.add_assign_field(&field2).expect("add field");
535        let expected = Field::VMWare(vmware::Field::averageLatency(300));
536        let expected_err = Some(FieldOperationError::InapplicableAdd(
537            IE::VMWare(vmware::IE::averageLatency),
538            IE::VMWare(vmware::IE::algControlFlowId),
539        ));
540
541        assert_eq!(result, expected);
542        assert_eq!(field1, expected);
543        assert_eq!(result_err1.err(), expected_err);
544        assert_eq!(result_err2.err(), expected_err);
545    }
546
547    #[test]
548    fn test_vendor_field_min() {
549        let mut field1 = Field::VMWare(vmware::Field::averageLatency(100));
550        let field2 = Field::VMWare(vmware::Field::averageLatency(200));
551        let other_field = Field::VMWare(vmware::Field::algControlFlowId(123));
552
553        let result_err1 = field1.min_field(&other_field);
554        let result_err2 = field1.min_assign_field(&other_field);
555        let result = field1.min_field(&field2).expect("min field");
556        field1.min_assign_field(&field2).expect("min field");
557        let expected = Field::VMWare(vmware::Field::averageLatency(100));
558        let expected_err = Some(FieldOperationError::InapplicableMin(
559            IE::VMWare(vmware::IE::averageLatency),
560            IE::VMWare(vmware::IE::algControlFlowId),
561        ));
562
563        assert_eq!(result, expected);
564        assert_eq!(field1, expected);
565        assert_eq!(result_err1.err(), expected_err);
566        assert_eq!(result_err2.err(), expected_err);
567    }
568
569    #[test]
570    fn test_vendor_field_max() {
571        let mut field1 = Field::VMWare(vmware::Field::averageLatency(100));
572        let field2 = Field::VMWare(vmware::Field::averageLatency(200));
573        let other_field = Field::VMWare(vmware::Field::algControlFlowId(123));
574
575        let result_err1 = field1.max_field(&other_field);
576        let result_err2 = field1.max_assign_field(&other_field);
577        let result = field1.max_field(&field2).expect("max field");
578        field1.max_assign_field(&field2).expect("max field");
579        let expected = Field::VMWare(vmware::Field::averageLatency(200));
580        let expected_err = Some(FieldOperationError::InapplicableMax(
581            IE::VMWare(vmware::IE::averageLatency),
582            IE::VMWare(vmware::IE::algControlFlowId),
583        ));
584
585        assert_eq!(result, expected);
586        assert_eq!(field1, expected);
587        assert_eq!(result_err1.err(), expected_err);
588        assert_eq!(result_err2.err(), expected_err);
589    }
590
591    #[test]
592    fn test_vendor_field_bitwise_or() {
593        let mut field1 = Field::VMWare(vmware::Field::algControlFlowId(100));
594        let field2 = Field::VMWare(vmware::Field::algControlFlowId(200));
595        let other_field = Field::VMWare(vmware::Field::averageLatency(123));
596
597        let result_err1 = field1.bitwise_or_field(&other_field);
598        let result_err2 = field1.bitwise_or_field(&other_field);
599        let result = field1.bitwise_or_field(&field2).expect("bitwise or field");
600        field1
601            .bitwise_or_assign_field(&field2)
602            .expect("bitwise or field");
603        let expected = Field::VMWare(vmware::Field::algControlFlowId(236));
604        let expected_err = Some(FieldOperationError::InapplicableBitwise(
605            IE::VMWare(vmware::IE::algControlFlowId),
606            IE::VMWare(vmware::IE::averageLatency),
607        ));
608
609        assert_eq!(result, expected);
610        assert_eq!(field1, expected);
611        assert_eq!(result_err1.err(), expected_err);
612        assert_eq!(result_err2.err(), expected_err);
613    }
614}