sflow_parser/models/
core.rs

1//! sFlow v5 data models
2//!
3//! This module contains the data structures representing sFlow v5 datagrams
4//! as defined in <https://sflow.org/sflow_version_5.txt>
5
6use std::net::{Ipv4Addr, Ipv6Addr};
7
8/// MAC address (6 bytes)
9///
10/// Represents a 48-bit IEEE 802 MAC address.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct MacAddress(pub [u8; 6]);
14
15impl MacAddress {
16    /// Create a new MAC address from 6 bytes
17    pub const fn new(bytes: [u8; 6]) -> Self {
18        Self(bytes)
19    }
20
21    /// Get the MAC address as a byte array
22    pub const fn as_bytes(&self) -> &[u8; 6] {
23        &self.0
24    }
25
26    /// Check if this is a broadcast address (FF:FF:FF:FF:FF:FF)
27    pub fn is_broadcast(&self) -> bool {
28        self.0 == [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
29    }
30
31    /// Check if this is a multicast address (first byte has LSB set)
32    pub fn is_multicast(&self) -> bool {
33        self.0[0] & 0x01 != 0
34    }
35
36    /// Check if this is a unicast address
37    pub fn is_unicast(&self) -> bool {
38        !self.is_multicast()
39    }
40}
41
42impl std::fmt::Display for MacAddress {
43    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44        write!(
45            f,
46            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
47            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
48        )
49    }
50}
51
52impl From<[u8; 6]> for MacAddress {
53    fn from(bytes: [u8; 6]) -> Self {
54        Self(bytes)
55    }
56}
57
58impl From<MacAddress> for [u8; 6] {
59    fn from(mac: MacAddress) -> Self {
60        mac.0
61    }
62}
63
64/// sFlow datagram version
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
67pub enum DatagramVersion {
68    Version5 = 5,
69}
70
71/// Address types supported by sFlow
72///
73/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
74///
75/// ```text
76/// enum address_type {
77///    UNKNOWN = 0,
78///    IP_V4   = 1,
79///    IP_V6   = 2
80/// }
81///
82/// union address (address_type type) {
83///    case UNKNOWN:
84///       void;
85///    case IP_V4:
86///       ip_v4 ip;
87///    case IP_V6:
88///       ip_v6 ip;
89/// }
90/// ```
91#[derive(Debug, Clone, PartialEq, Eq)]
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93pub enum Address {
94    /// Unknown address type
95    Unknown,
96    /// IPv4 address
97    IPv4(Ipv4Addr),
98    /// IPv6 address
99    IPv6(Ipv6Addr),
100}
101
102/// Data format identifier
103///
104/// Encodes enterprise ID and format number in a single 32-bit value.
105/// Top 20 bits = enterprise ID, bottom 12 bits = format number.
106///
107/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
108///
109/// ```text
110/// typedef unsigned int data_format;
111/// /* The data_format uniquely identifies the format of an opaque structure in
112///    the sFlow specification. For example, the combination of enterprise = 0
113///    and format = 1 identifies the "sampled_header" flow_data structure. */
114/// ```
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
117pub struct DataFormat(pub u32);
118
119impl DataFormat {
120    pub fn new(enterprise: u32, format: u32) -> Self {
121        Self((enterprise << 12) | (format & 0xFFF))
122    }
123
124    pub fn enterprise(&self) -> u32 {
125        self.0 >> 12
126    }
127
128    pub fn format(&self) -> u32 {
129        self.0 & 0xFFF
130    }
131}
132
133/// sFlow data source identifier
134///
135/// Identifies the source of the data. Top 8 bits = source type, bottom 24 bits = index.
136///
137/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
138///
139/// ```text
140/// typedef unsigned int sflow_data_source;
141/// /* The sflow_data_source is encoded as follows:
142///    The most significant byte of the sflow_data_source is used to indicate the type of
143///    sFlowDataSource (e.g. ifIndex, smonVlanDataSource, entPhysicalEntry) and the lower
144///    three bytes contain the relevant index value. */
145/// ```
146#[derive(Debug, Clone, Copy, PartialEq, Eq)]
147#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
148pub struct DataSource(pub u32);
149
150impl DataSource {
151    pub fn new(source_type: u8, index: u32) -> Self {
152        Self(((source_type as u32) << 24) | (index & 0xFFFFFF))
153    }
154
155    pub fn source_type(&self) -> u8 {
156        (self.0 >> 24) as u8
157    }
158
159    pub fn index(&self) -> u32 {
160        self.0 & 0xFFFFFF
161    }
162}
163
164/// Expanded data source (for ifIndex >= 2^24)
165///
166/// Used when the index value exceeds 24 bits (16,777,215).
167///
168/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
169///
170/// ```text
171/// struct sflow_data_source_expanded {
172///    unsigned int source_id_type;  /* sFlowDataSource type */
173///    unsigned int source_id_index; /* sFlowDataSource index */
174/// }
175/// ```
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
177#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
178pub struct DataSourceExpanded {
179    /// Source type (e.g., 0 = ifIndex, 1 = smonVlanDataSource, 2 = entPhysicalEntry)
180    pub source_id_type: u32,
181    /// Source index value
182    pub source_id_index: u32,
183}
184
185/// Interface identifier
186///
187/// Compact encoding for interface identification. Top 2 bits indicate format:
188/// - 00 = Single interface (value is ifIndex)
189/// - 01 = Packet discarded (value is reason code)
190/// - 10 = Multiple destination interfaces (value is number of interfaces)
191///
192/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
193///
194/// ```text
195/// typedef unsigned int interface;
196/// /* Encoding of the interface value:
197///    Bits 31-30: Format
198///       00 = ifIndex (0-0x3FFFFFFF)
199///       01 = Packet discarded
200///       10 = Multiple destinations
201///    Bits 29-0: Value */
202/// ```
203#[derive(Debug, Clone, Copy, PartialEq, Eq)]
204#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
205pub struct Interface(pub u32);
206
207impl Interface {
208    pub fn format(&self) -> u8 {
209        (self.0 >> 30) as u8
210    }
211
212    pub fn value(&self) -> u32 {
213        self.0 & 0x3FFFFFFF
214    }
215
216    pub fn is_single(&self) -> bool {
217        self.format() == 0
218    }
219
220    pub fn is_discarded(&self) -> bool {
221        self.format() == 1
222    }
223
224    pub fn is_multiple(&self) -> bool {
225        self.format() == 2
226    }
227}
228
229/// Expanded interface (for ifIndex >= 2^24)
230///
231/// Used when the interface index exceeds 30 bits (1,073,741,823).
232///
233/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
234///
235/// ```text
236/// struct interface_expanded {
237///    unsigned int format;        /* interface format */
238///    unsigned int value;         /* interface value,
239///                                   Note: 0xFFFFFFFF is the maximum value and must be used
240///                                   to indicate traffic originating or terminating in device
241///                                   (do not use 0x3FFFFFFF value from compact encoding example) */
242/// }
243/// ```
244///
245/// **ERRATUM:** 0xFFFFFFFF is the maximum value and must be used to indicate traffic
246/// originating or terminating in device (do not use 0x3FFFFFFF value from compact encoding example).
247#[derive(Debug, Clone, Copy, PartialEq, Eq)]
248#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
249pub struct InterfaceExpanded {
250    /// Interface format (0 = ifIndex, 1 = packet discarded, 2 = multiple destinations)
251    pub format: u32,
252    /// Interface value
253    /// **ERRATUM:** 0xFFFFFFFF indicates traffic originating or terminating in device
254    pub value: u32,
255}
256
257/// Flow data types
258#[derive(Debug, Clone, PartialEq, Eq)]
259#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
260pub enum FlowData {
261    /// Sampled Header - Format (0,1)
262    SampledHeader(crate::models::record_flows::SampledHeader),
263    /// Sampled Ethernet - Format (0,2)
264    SampledEthernet(crate::models::record_flows::SampledEthernet),
265    /// Sampled IPv4 - Format (0,3)
266    SampledIpv4(crate::models::record_flows::SampledIpv4),
267    /// Sampled IPv6 - Format (0,4)
268    SampledIpv6(crate::models::record_flows::SampledIpv6),
269    /// Extended Switch - Format (0,1001)
270    ExtendedSwitch(crate::models::record_flows::ExtendedSwitch),
271    /// Extended Router - Format (0,1002)
272    ExtendedRouter(crate::models::record_flows::ExtendedRouter),
273    /// Extended Gateway - Format (0,1003)
274    ExtendedGateway(crate::models::record_flows::ExtendedGateway),
275    /// Extended User - Format (0,1004)
276    ExtendedUser(crate::models::record_flows::ExtendedUser),
277    /// Extended URL - Format (0,1005) - DEPRECATED
278    ExtendedUrl(crate::models::record_flows::ExtendedUrl),
279    /// Extended MPLS - Format (0,1006)
280    ExtendedMpls(crate::models::record_flows::ExtendedMpls),
281    /// Extended NAT - Format (0,1007)
282    ExtendedNat(crate::models::record_flows::ExtendedNat),
283    /// Extended MPLS Tunnel - Format (0,1008)
284    ExtendedMplsTunnel(crate::models::record_flows::ExtendedMplsTunnel),
285    /// Extended MPLS VC - Format (0,1009)
286    ExtendedMplsVc(crate::models::record_flows::ExtendedMplsVc),
287    /// Extended MPLS FEC - Format (0,1010)
288    ExtendedMplsFec(crate::models::record_flows::ExtendedMplsFec),
289    /// Extended MPLS LVP FEC - Format (0,1011)
290    ExtendedMplsLvpFec(crate::models::record_flows::ExtendedMplsLvpFec),
291    /// Extended VLAN Tunnel - Format (0,1012)
292    ExtendedVlanTunnel(crate::models::record_flows::ExtendedVlanTunnel),
293    /// Extended 802.11 Payload - Format (0,1013)
294    Extended80211Payload(crate::models::record_flows::Extended80211Payload),
295    /// Extended 802.11 RX - Format (0,1014)
296    Extended80211Rx(crate::models::record_flows::Extended80211Rx),
297    /// Extended 802.11 TX - Format (0,1015)
298    Extended80211Tx(crate::models::record_flows::Extended80211Tx),
299    /// Extended 802.11 Aggregation - Format (0,1016)
300    Extended80211Aggregation(crate::models::record_flows::Extended80211Aggregation),
301    /// Extended OpenFlow v1 - Format (0,1017) - DEPRECATED
302    ExtendedOpenFlowV1(crate::models::record_flows::ExtendedOpenFlowV1),
303    /// Extended NAT Port - Format (0,1020)
304    ExtendedNatPort(crate::models::record_flows::ExtendedNatPort),
305    /// Extended InfiniBand BTH - Format (0,1033)
306    ExtendedInfiniBandBth(crate::models::record_flows::ExtendedInfiniBandBth),
307    /// Extended L2 Tunnel Egress - Format (0,1021)
308    ExtendedL2TunnelEgress(crate::models::record_flows::ExtendedL2TunnelEgress),
309    /// Extended L2 Tunnel Ingress - Format (0,1022)
310    ExtendedL2TunnelIngress(crate::models::record_flows::ExtendedL2TunnelIngress),
311    /// Extended IPv4 Tunnel Egress - Format (0,1023)
312    ExtendedIpv4TunnelEgress(crate::models::record_flows::ExtendedIpv4TunnelEgress),
313    /// Extended IPv4 Tunnel Ingress - Format (0,1024)
314    ExtendedIpv4TunnelIngress(crate::models::record_flows::ExtendedIpv4TunnelIngress),
315    /// Extended IPv6 Tunnel Egress - Format (0,1025)
316    ExtendedIpv6TunnelEgress(crate::models::record_flows::ExtendedIpv6TunnelEgress),
317    /// Extended IPv6 Tunnel Ingress - Format (0,1026)
318    ExtendedIpv6TunnelIngress(crate::models::record_flows::ExtendedIpv6TunnelIngress),
319    /// Extended Decapsulate Egress - Format (0,1027)
320    ExtendedDecapsulateEgress(crate::models::record_flows::ExtendedDecapsulateEgress),
321    /// Extended Decapsulate Ingress - Format (0,1028)
322    ExtendedDecapsulateIngress(crate::models::record_flows::ExtendedDecapsulateIngress),
323    /// Extended VNI Egress - Format (0,1029)
324    ExtendedVniEgress(crate::models::record_flows::ExtendedVniEgress),
325    /// Extended VNI Ingress - Format (0,1030)
326    ExtendedVniIngress(crate::models::record_flows::ExtendedVniIngress),
327    /// Extended InfiniBand LRH - Format (0,1031)
328    ExtendedInfiniBandLrh(crate::models::record_flows::ExtendedInfiniBandLrh),
329    /// Extended InfiniBand GRH - Format (0,1032)
330    ExtendedInfiniBandGrh(crate::models::record_flows::ExtendedInfiniBandGrh),
331    /// Extended Egress Queue - Format (0,1036)
332    ExtendedEgressQueue(crate::models::record_flows::ExtendedEgressQueue),
333    /// Extended ACL - Format (0,1037)
334    ExtendedAcl(crate::models::record_flows::ExtendedAcl),
335    /// Extended Function - Format (0,1038)
336    ExtendedFunction(crate::models::record_flows::ExtendedFunction),
337    /// Extended Transit - Format (0,1039)
338    ExtendedTransit(crate::models::record_flows::ExtendedTransit),
339    /// Extended Queue - Format (0,1040)
340    ExtendedQueue(crate::models::record_flows::ExtendedQueue),
341    /// Extended Socket IPv4 - Format (0,2100)
342    ExtendedSocketIpv4(crate::models::record_flows::ExtendedSocketIpv4),
343    /// Extended Socket IPv6 - Format (0,2101)
344    ExtendedSocketIpv6(crate::models::record_flows::ExtendedSocketIpv6),
345    /// Extended Proxy Socket IPv4 - Format (0,2102)
346    ExtendedProxySocketIpv4(crate::models::record_flows::ExtendedProxySocketIpv4),
347    /// Extended Proxy Socket IPv6 - Format (0,2103)
348    ExtendedProxySocketIpv6(crate::models::record_flows::ExtendedProxySocketIpv6),
349    /// Memcache Operation - Format (0,2200)
350    MemcacheOperation(crate::models::record_flows::MemcacheOperation),
351    /// Application Operation - Format (0,2202)
352    AppOperation(crate::models::record_flows::AppOperation),
353    /// Application Parent Context - Format (0,2203)
354    AppParentContext(crate::models::record_flows::AppParentContext),
355    /// Application Initiator - Format (0,2204)
356    AppInitiator(crate::models::record_flows::AppInitiator),
357    /// Application Target - Format (0,2205)
358    AppTarget(crate::models::record_flows::AppTarget),
359    /// HTTP Request - Format (0,2206)
360    HttpRequest(crate::models::record_flows::HttpRequest),
361    /// Extended Proxy Request - Format (0,2207)
362    ExtendedProxyRequest(crate::models::record_flows::ExtendedProxyRequest),
363    /// Extended BST Egress Queue - Format (4413,1)
364    ExtendedBstEgressQueue(crate::models::record_flows::ExtendedBstEgressQueue),
365    /// Unknown or unparsed format
366    Unknown { format: DataFormat, data: Vec<u8> },
367}
368
369/// Flow record containing flow data
370#[derive(Debug, Clone, PartialEq, Eq)]
371#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
372pub struct FlowRecord {
373    pub flow_format: DataFormat,
374    pub flow_data: FlowData,
375}
376
377/// Counter data types
378#[derive(Debug, Clone, PartialEq)]
379#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
380pub enum CounterData {
381    /// Generic Interface Counters - Format (0,1)
382    GenericInterface(crate::models::record_counters::GenericInterfaceCounters),
383    /// Ethernet Interface Counters - Format (0,2)
384    EthernetInterface(crate::models::record_counters::EthernetInterfaceCounters),
385    /// Token Ring Counters - Format (0,3)
386    TokenRing(crate::models::record_counters::TokenRingCounters),
387    /// 100BaseVG Counters - Format (0,4)
388    Vg100Interface(crate::models::record_counters::Vg100InterfaceCounters),
389    /// VLAN Counters - Format (0,5)
390    Vlan(crate::models::record_counters::VlanCounters),
391    /// IEEE 802.11 Counters - Format (0,6)
392    Ieee80211(crate::models::record_counters::Ieee80211Counters),
393    /// LAG Port Statistics - Format (0,7)
394    LagPortStats(crate::models::record_counters::LagPortStats),
395    /// InfiniBand Counters - Format (0,9)
396    InfiniBandCounters(crate::models::record_counters::InfiniBandCounters),
397    /// Optical SFP/QSFP Counters - Format (0,10)
398    OpticalSfpQsfp(crate::models::record_counters::OpticalSfpQsfp),
399    /// Processor Counters - Format (0,1001)
400    Processor(crate::models::record_counters::ProcessorCounters),
401    /// Radio Utilization - Format (0,1002)
402    RadioUtilization(crate::models::record_counters::RadioUtilization),
403    /// OpenFlow Port - Format (0,1004)
404    OpenFlowPort(crate::models::record_counters::OpenFlowPort),
405    /// OpenFlow Port Name - Format (0,1005)
406    OpenFlowPortName(crate::models::record_counters::OpenFlowPortName),
407    /// Host Description - Format (0,2000)
408    HostDescription(crate::models::record_counters::HostDescription),
409    /// Host Adapters - Format (0,2001)
410    HostAdapters(crate::models::record_counters::HostAdapters),
411    /// Host Parent - Format (0,2002)
412    HostParent(crate::models::record_counters::HostParent),
413    /// Host CPU - Format (0,2003)
414    HostCpu(crate::models::record_counters::HostCpu),
415    /// Host Memory - Format (0,2004)
416    HostMemory(crate::models::record_counters::HostMemory),
417    /// Host Disk I/O - Format (0,2005)
418    HostDiskIo(crate::models::record_counters::HostDiskIo),
419    /// Host Network I/O - Format (0,2006)
420    HostNetIo(crate::models::record_counters::HostNetIo),
421    /// MIB-2 IP Group - Format (0,2007)
422    Mib2IpGroup(crate::models::record_counters::Mib2IpGroup),
423    /// MIB-2 ICMP Group - Format (0,2008)
424    Mib2IcmpGroup(crate::models::record_counters::Mib2IcmpGroup),
425    /// MIB-2 TCP Group - Format (0,2009)
426    Mib2TcpGroup(crate::models::record_counters::Mib2TcpGroup),
427    /// MIB-2 UDP Group - Format (0,2010)
428    Mib2UdpGroup(crate::models::record_counters::Mib2UdpGroup),
429    /// Virtual Node - Format (0,2100)
430    VirtualNode(crate::models::record_counters::VirtualNode),
431    /// Virtual CPU - Format (0,2101)
432    VirtualCpu(crate::models::record_counters::VirtualCpu),
433    /// Virtual Memory - Format (0,2102)
434    VirtualMemory(crate::models::record_counters::VirtualMemory),
435    /// Virtual Disk I/O - Format (0,2103)
436    VirtualDiskIo(crate::models::record_counters::VirtualDiskIo),
437    /// Virtual Network I/O - Format (0,2104)
438    VirtualNetIo(crate::models::record_counters::VirtualNetIo),
439    /// JVM Runtime - Format (0,2105)
440    JvmRuntime(crate::models::record_counters::JvmRuntime),
441    /// JVM Statistics - Format (0,2106)
442    JvmStatistics(crate::models::record_counters::JvmStatistics),
443    /// HTTP Counters - Format (0,2201)
444    HttpCounters(crate::models::record_counters::HttpCounters),
445    /// App Operations - Format (0,2202)
446    AppOperations(crate::models::record_counters::AppOperations),
447    /// App Resources - Format (0,2203)
448    AppResources(crate::models::record_counters::AppResources),
449    /// Memcache Counters - Format (0,2204)
450    MemcacheCounters(crate::models::record_counters::MemcacheCounters),
451    /// App Workers - Format (0,2206)
452    AppWorkers(crate::models::record_counters::AppWorkers),
453    /// Broadcom Device Buffer Utilization - Format (4413,1)
454    BroadcomDeviceBuffers(crate::models::record_counters::BroadcomDeviceBuffers),
455    /// Broadcom Port Buffer Utilization - Format (4413,2)
456    BroadcomPortBuffers(crate::models::record_counters::BroadcomPortBuffers),
457    /// Broadcom Switch ASIC Table Utilization - Format (4413,3)
458    BroadcomTables(crate::models::record_counters::BroadcomTables),
459    /// NVIDIA GPU Statistics - Format (5703,1)
460    NvidiaGpu(crate::models::record_counters::NvidiaGpu),
461    /// Unknown or unparsed format
462    Unknown { format: DataFormat, data: Vec<u8> },
463}
464
465/// Counter record containing counter data
466#[derive(Debug, Clone, PartialEq)]
467#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
468pub struct CounterRecord {
469    pub counter_format: DataFormat,
470    pub counter_data: CounterData,
471}
472
473/// Compact flow sample - Format (0,1)
474///
475/// Contains sampled packet information with compact encoding for interfaces.
476///
477/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
478///
479/// ```text
480/// /* Format of a single flow sample */
481/// /* opaque = sample_data; enterprise = 0; format = 1 */
482///
483/// struct flow_sample {
484///    unsigned int sequence_number;  /* Incremented with each flow sample
485///                                      generated by this sFlow Instance. */
486///    sflow_data_source source_id;   /* sFlowDataSource */
487///    unsigned int sampling_rate;    /* sFlowPacketSamplingRate */
488///    unsigned int sample_pool;      /* Total number of packets that could have been
489///                                      sampled (i.e. packets skipped by sampling process
490///                                      + total number of samples) */
491///    unsigned int drops;            /* Number of times that the sFlow agent detected
492///                                      that a packet marked to be sampled was dropped
493///                                      due to lack of resources. */
494///    interface input;               /* Input interface */
495///    interface output;              /* Output interface */
496///    flow_record flow_records<>;    /* Information about sampled packet */
497/// }
498/// ```
499///
500/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
501#[derive(Debug, Clone, PartialEq, Eq)]
502#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
503pub struct FlowSample {
504    /// Sequence number incremented with each flow sample generated by this sFlow Instance
505    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
506    pub sequence_number: u32,
507    /// sFlow data source identifier
508    pub source_id: DataSource,
509    /// Sampling rate (1 in N packets)
510    pub sampling_rate: u32,
511    /// Total packets that could have been sampled
512    pub sample_pool: u32,
513    /// Number of dropped samples due to lack of resources
514    pub drops: u32,
515    /// Input interface
516    pub input: Interface,
517    /// Output interface
518    pub output: Interface,
519    /// Flow records describing the sampled packet
520    pub flow_records: Vec<FlowRecord>,
521}
522
523/// Compact counters sample - Format (0,2)
524///
525/// Contains interface and system counter statistics.
526///
527/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
528///
529/// ```text
530/// /* Format of a single counter sample */
531/// /* opaque = sample_data; enterprise = 0; format = 2 */
532///
533/// struct counters_sample {
534///    unsigned int sequence_number;   /* Incremented with each counter sample
535///                                       generated by this sFlow Instance. */
536///    sflow_data_source source_id;    /* sFlowDataSource */
537///    counter_record counters<>;      /* Counters polled for this source */
538/// }
539/// ```
540///
541/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
542#[derive(Debug, Clone, PartialEq)]
543#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
544pub struct CountersSample {
545    /// Sequence number incremented with each counter sample generated by this sFlow Instance
546    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
547    pub sequence_number: u32,
548    /// sFlow data source identifier
549    pub source_id: DataSource,
550    /// Counter records for this source
551    pub counters: Vec<CounterRecord>,
552}
553
554/// Expanded flow sample - Format (0,3)
555///
556/// Flow sample with expanded encoding for large interface indices (>= 2^24).
557///
558/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
559///
560/// ```text
561/// /* Format of a single expanded flow sample */
562/// /* opaque = sample_data; enterprise = 0; format = 3 */
563///
564/// struct flow_sample_expanded {
565///    unsigned int sequence_number;  /* Incremented with each flow sample
566///                                      generated by this sFlow Instance. */
567///    sflow_data_source_expanded source_id; /* sFlowDataSource */
568///    unsigned int sampling_rate;    /* sFlowPacketSamplingRate */
569///    unsigned int sample_pool;      /* Total number of packets that could have been
570///                                      sampled (i.e. packets skipped by sampling process
571///                                      + total number of samples) */
572///    unsigned int drops;            /* Number of times that the sFlow agent detected
573///                                      that a packet marked to be sampled was dropped
574///                                      due to lack of resources. */
575///    interface_expanded input;      /* Input interface */
576///    interface_expanded output;     /* Output interface */
577///    flow_record flow_records<>;    /* Information about sampled packet */
578/// }
579/// ```
580///
581/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
582#[derive(Debug, Clone, PartialEq, Eq)]
583#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
584pub struct FlowSampleExpanded {
585    /// Sequence number incremented with each flow sample generated by this sFlow Instance
586    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
587    pub sequence_number: u32,
588    /// Expanded sFlow data source identifier
589    pub source_id: DataSourceExpanded,
590    /// Sampling rate (1 in N packets)
591    pub sampling_rate: u32,
592    /// Total packets that could have been sampled
593    pub sample_pool: u32,
594    /// Number of dropped samples due to lack of resources
595    pub drops: u32,
596    /// Input interface (expanded)
597    pub input: InterfaceExpanded,
598    /// Output interface (expanded)
599    pub output: InterfaceExpanded,
600    /// Flow records describing the sampled packet
601    pub flow_records: Vec<FlowRecord>,
602}
603
604/// Expanded counter sample - Format (0,4)
605///
606/// Counter sample with expanded encoding for large interface indices (>= 2^24).
607///
608/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
609///
610/// ```text
611/// /* Format of a single expanded counters sample */
612/// /* opaque = sample_data; enterprise = 0; format = 4 */
613///
614/// struct counters_sample_expanded {
615///    unsigned int sequence_number;   /* Incremented with each counter sample
616///                                       generated by this sFlow Instance. */
617///    sflow_data_source_expanded source_id; /* sFlowDataSource */
618///    counter_record counters<>;      /* Counters polled for this source */
619/// }
620/// ```
621///
622/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
623#[derive(Debug, Clone, PartialEq)]
624#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
625pub struct CountersSampleExpanded {
626    /// Sequence number incremented with each counter sample generated by this sFlow Instance
627    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
628    pub sequence_number: u32,
629    /// Expanded sFlow data source identifier
630    pub source_id: DataSourceExpanded,
631    /// Counter records for this source
632    pub counters: Vec<CounterRecord>,
633}
634
635/// Discarded packet sample - Format (0,5)
636///
637/// # XDR Definition ([sFlow Drops](https://sflow.org/sflow_drops.txt))
638///
639/// ```text
640/// /* Format of a single discarded packet event */
641/// /* opaque = sample_data; enterprise = 0; format = 5 */
642/// struct discarded_packet {
643///    unsigned int sequence_number;  /* Incremented with each discarded packet
644///                                      record generated by this source_id. */
645///    sflow_data_source_expanded source_id; /* sFlowDataSource */
646///    unsigned int drops;            /* Number of times that the sFlow agent
647///                                      detected that a discarded packet record
648///                                      was dropped by the rate limit, or because
649///                                      of a lack of resources. The drops counter
650///                                      reports the total number of drops detected
651///                                      since the agent was last reset. Note: An
652///                                      agent that cannot detect drops will always
653///                                      report zero. */
654///    unsigned int inputifindex;     /* If set, ifIndex of interface packet was
655///                                      received on. Zero if unknown. Must identify
656///                                      physical port consistent with flow_sample
657///                                      input interface. */
658///    unsigned int outputifindex;    /* If set, ifIndex for egress drops. Zero
659///                                      otherwise. Must identify physical port
660///                                      consistent with flow_sample output
661///                                      interface. */
662///    drop_reason reason;            /* Reason for dropping packet. */
663///    flow_record discard_records<>; /* Information about the discarded packet. */
664/// }
665/// ```
666#[derive(Debug, Clone, PartialEq, Eq)]
667#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
668pub struct DiscardedPacket {
669    /// Sequence number incremented with each discarded packet record
670    pub sequence_number: u32,
671
672    /// sFlow data source
673    pub source_id: DataSourceExpanded,
674
675    /// Number of discarded packet records dropped by rate limit or lack of resources
676    pub drops: u32,
677
678    /// Input interface index (0 if unknown)
679    pub input_ifindex: u32,
680
681    /// Output interface index (0 if not egress drop)
682    pub output_ifindex: u32,
683
684    /// Reason for dropping the packet
685    pub reason: crate::models::record_flows::DropReason,
686
687    /// Flow records describing the discarded packet
688    pub flow_records: Vec<FlowRecord>,
689}
690
691/// Sample data types
692#[derive(Debug, Clone, PartialEq)]
693#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
694pub enum SampleData {
695    FlowSample(FlowSample),
696    CountersSample(CountersSample),
697    FlowSampleExpanded(FlowSampleExpanded),
698    CountersSampleExpanded(CountersSampleExpanded),
699    DiscardedPacket(DiscardedPacket),
700    Unknown { format: DataFormat, data: Vec<u8> },
701}
702
703/// Sample record
704#[derive(Debug, Clone, PartialEq)]
705#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
706pub struct SampleRecord {
707    pub sample_type: DataFormat,
708    pub sample_data: SampleData,
709}
710
711/// sFlow v5 datagram
712///
713/// Top-level structure containing one or more samples.
714///
715/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
716///
717/// ```text
718/// /* sFlow version 5 datagram */
719///
720/// struct sflow_datagram {
721///    unsigned int version;        /* sFlow version (5) */
722///    address agent_address;       /* IP address of sampling agent */
723///    unsigned int sub_agent_id;   /* Used to distinguish multiple sFlow instances
724///                                    on the same agent */
725///    unsigned int sequence_number;/* Incremented with each sample datagram generated
726///                                    by a sub-agent within an agent */
727///    unsigned int uptime;         /* Current time (in milliseconds since device
728///                                    last booted). Should be set as close to
729///                                    datagram transmission time as possible. */
730///    sample_record samples<>;     /* An array of sample records */
731/// }
732/// ```
733#[derive(Debug, Clone, PartialEq)]
734#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
735pub struct SFlowDatagram {
736    /// sFlow protocol version (always 5)
737    pub version: DatagramVersion,
738    /// IP address of the sFlow agent
739    pub agent_address: Address,
740    /// Sub-agent identifier (distinguishes multiple sFlow instances on same agent)
741    pub sub_agent_id: u32,
742    /// Datagram sequence number (incremented with each datagram from this sub-agent)
743    pub sequence_number: u32,
744    /// Device uptime in milliseconds since last boot
745    pub uptime: u32,
746    /// Array of sample records
747    pub samples: Vec<SampleRecord>,
748}
749
750impl SFlowDatagram {
751    /// Create a new sFlow v5 datagram
752    pub fn new(
753        agent_address: Address,
754        sub_agent_id: u32,
755        sequence_number: u32,
756        uptime: u32,
757    ) -> Self {
758        Self {
759            version: DatagramVersion::Version5,
760            agent_address,
761            sub_agent_id,
762            sequence_number,
763            uptime,
764            samples: Vec::new(),
765        }
766    }
767}