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)]
12pub struct MacAddress(pub [u8; 6]);
13
14impl MacAddress {
15    /// Create a new MAC address from 6 bytes
16    pub const fn new(bytes: [u8; 6]) -> Self {
17        Self(bytes)
18    }
19
20    /// Get the MAC address as a byte array
21    pub const fn as_bytes(&self) -> &[u8; 6] {
22        &self.0
23    }
24
25    /// Check if this is a broadcast address (FF:FF:FF:FF:FF:FF)
26    pub fn is_broadcast(&self) -> bool {
27        self.0 == [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
28    }
29
30    /// Check if this is a multicast address (first byte has LSB set)
31    pub fn is_multicast(&self) -> bool {
32        self.0[0] & 0x01 != 0
33    }
34
35    /// Check if this is a unicast address
36    pub fn is_unicast(&self) -> bool {
37        !self.is_multicast()
38    }
39}
40
41impl std::fmt::Display for MacAddress {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        write!(
44            f,
45            "{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
46            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
47        )
48    }
49}
50
51impl From<[u8; 6]> for MacAddress {
52    fn from(bytes: [u8; 6]) -> Self {
53        Self(bytes)
54    }
55}
56
57impl From<MacAddress> for [u8; 6] {
58    fn from(mac: MacAddress) -> Self {
59        mac.0
60    }
61}
62
63/// sFlow datagram version
64#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum DatagramVersion {
66    Version5 = 5,
67}
68
69/// Address types supported by sFlow
70#[derive(Debug, Clone, PartialEq, Eq)]
71pub enum Address {
72    Unknown,
73    IPv4(Ipv4Addr),
74    IPv6(Ipv6Addr),
75}
76
77/// Data format identifier
78/// Top 20 bits = enterprise ID, bottom 12 bits = format number
79#[derive(Debug, Clone, Copy, PartialEq, Eq)]
80pub struct DataFormat(pub u32);
81
82impl DataFormat {
83    pub fn new(enterprise: u32, format: u32) -> Self {
84        Self((enterprise << 12) | (format & 0xFFF))
85    }
86
87    pub fn enterprise(&self) -> u32 {
88        self.0 >> 12
89    }
90
91    pub fn format(&self) -> u32 {
92        self.0 & 0xFFF
93    }
94}
95
96/// sFlow data source identifier
97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
98pub struct DataSource(pub u32);
99
100impl DataSource {
101    pub fn new(source_type: u8, index: u32) -> Self {
102        Self(((source_type as u32) << 24) | (index & 0xFFFFFF))
103    }
104
105    pub fn source_type(&self) -> u8 {
106        (self.0 >> 24) as u8
107    }
108
109    pub fn index(&self) -> u32 {
110        self.0 & 0xFFFFFF
111    }
112}
113
114/// Expanded data source (for ifIndex >= 2^24)
115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
116pub struct DataSourceExpanded {
117    pub source_id_type: u32,
118    pub source_id_index: u32,
119}
120
121/// Interface identifier
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub struct Interface(pub u32);
124
125impl Interface {
126    pub fn format(&self) -> u8 {
127        (self.0 >> 30) as u8
128    }
129
130    pub fn value(&self) -> u32 {
131        self.0 & 0x3FFFFFFF
132    }
133
134    pub fn is_single(&self) -> bool {
135        self.format() == 0
136    }
137
138    pub fn is_discarded(&self) -> bool {
139        self.format() == 1
140    }
141
142    pub fn is_multiple(&self) -> bool {
143        self.format() == 2
144    }
145}
146
147/// Expanded interface (for ifIndex >= 2^24)
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149pub struct InterfaceExpanded {
150    pub format: u32,
151    pub value: u32,
152}
153
154/// Flow data types
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub enum FlowData {
157    /// Sampled Header - Format (0,1)
158    SampledHeader(crate::models::record_flows::SampledHeader),
159    /// Sampled Ethernet - Format (0,2)
160    SampledEthernet(crate::models::record_flows::SampledEthernet),
161    /// Sampled IPv4 - Format (0,3)
162    SampledIpv4(crate::models::record_flows::SampledIpv4),
163    /// Sampled IPv6 - Format (0,4)
164    SampledIpv6(crate::models::record_flows::SampledIpv6),
165    /// Extended Switch - Format (0,1001)
166    ExtendedSwitch(crate::models::record_flows::ExtendedSwitch),
167    /// Extended Router - Format (0,1002)
168    ExtendedRouter(crate::models::record_flows::ExtendedRouter),
169    /// Extended Gateway - Format (0,1003)
170    ExtendedGateway(crate::models::record_flows::ExtendedGateway),
171    /// Extended User - Format (0,1004)
172    ExtendedUser(crate::models::record_flows::ExtendedUser),
173    /// Extended URL - Format (0,1005)
174    /// Note: This format is deprecated but kept for backward compatibility
175    ExtendedUrl(crate::models::record_flows::ExtendedUrl),
176    /// Extended MPLS - Format (0,1006)
177    ExtendedMpls(crate::models::record_flows::ExtendedMpls),
178    /// Extended NAT - Format (0,1007)
179    ExtendedNat(crate::models::record_flows::ExtendedNat),
180    /// Extended MPLS Tunnel - Format (0,1008)
181    ExtendedMplsTunnel(crate::models::record_flows::ExtendedMplsTunnel),
182    /// Extended MPLS VC - Format (0,1009)
183    ExtendedMplsVc(crate::models::record_flows::ExtendedMplsVc),
184    /// Extended MPLS FEC - Format (0,1010)
185    ExtendedMplsFec(crate::models::record_flows::ExtendedMplsFec),
186    /// Extended MPLS LVP FEC - Format (0,1011)
187    ExtendedMplsLvpFec(crate::models::record_flows::ExtendedMplsLvpFec),
188    /// Extended VLAN Tunnel - Format (0,1012)
189    ExtendedVlanTunnel(crate::models::record_flows::ExtendedVlanTunnel),
190    /// Extended 802.11 Payload - Format (0,1013)
191    Extended80211Payload(crate::models::record_flows::Extended80211Payload),
192    /// Extended 802.11 RX - Format (0,1014)
193    Extended80211Rx(crate::models::record_flows::Extended80211Rx),
194    /// Extended 802.11 TX - Format (0,1015)
195    Extended80211Tx(crate::models::record_flows::Extended80211Tx),
196    /// Extended 802.11 Aggregation - Format (0,1016)
197    Extended80211Aggregation(crate::models::record_flows::Extended80211Aggregation),
198    /// Extended OpenFlow v1 - Format (0,1017) - DEPRECATED
199    ExtendedOpenFlowV1(crate::models::record_flows::ExtendedOpenFlowV1),
200    /// Extended L2 Tunnel Egress - Format (0,1021)
201    ExtendedL2TunnelEgress(crate::models::record_flows::ExtendedL2TunnelEgress),
202    /// Extended L2 Tunnel Ingress - Format (0,1022)
203    ExtendedL2TunnelIngress(crate::models::record_flows::ExtendedL2TunnelIngress),
204    /// Extended IPv4 Tunnel Egress - Format (0,1023)
205    ExtendedIpv4TunnelEgress(crate::models::record_flows::ExtendedIpv4TunnelEgress),
206    /// Extended IPv4 Tunnel Ingress - Format (0,1024)
207    ExtendedIpv4TunnelIngress(crate::models::record_flows::ExtendedIpv4TunnelIngress),
208    /// Extended IPv6 Tunnel Egress - Format (0,1025)
209    ExtendedIpv6TunnelEgress(crate::models::record_flows::ExtendedIpv6TunnelEgress),
210    /// Extended IPv6 Tunnel Ingress - Format (0,1026)
211    ExtendedIpv6TunnelIngress(crate::models::record_flows::ExtendedIpv6TunnelIngress),
212    /// Extended Decapsulate Egress - Format (0,1027)
213    ExtendedDecapsulateEgress(crate::models::record_flows::ExtendedDecapsulateEgress),
214    /// Extended Decapsulate Ingress - Format (0,1028)
215    ExtendedDecapsulateIngress(crate::models::record_flows::ExtendedDecapsulateIngress),
216    /// Extended VNI Egress - Format (0,1029)
217    ExtendedVniEgress(crate::models::record_flows::ExtendedVniEgress),
218    /// Extended VNI Ingress - Format (0,1030)
219    ExtendedVniIngress(crate::models::record_flows::ExtendedVniIngress),
220    /// Extended Egress Queue - Format (0,1036)
221    ExtendedEgressQueue(crate::models::record_flows::ExtendedEgressQueue),
222    /// Extended ACL - Format (0,1037)
223    ExtendedAcl(crate::models::record_flows::ExtendedAcl),
224    /// Extended Function - Format (0,1038)
225    ExtendedFunction(crate::models::record_flows::ExtendedFunction),
226    /// Extended Transit - Format (0,1039)
227    ExtendedTransit(crate::models::record_flows::ExtendedTransit),
228    /// Extended Queue - Format (0,1040)
229    ExtendedQueue(crate::models::record_flows::ExtendedQueue),
230    /// Extended Socket IPv4 - Format (0,2100)
231    ExtendedSocketIpv4(crate::models::record_flows::ExtendedSocketIpv4),
232    /// Extended Socket IPv6 - Format (0,2101)
233    ExtendedSocketIpv6(crate::models::record_flows::ExtendedSocketIpv6),
234    /// Application Operation - Format (0,2202)
235    AppOperation(crate::models::record_flows::AppOperation),
236    /// Application Parent Context - Format (0,2203)
237    AppParentContext(crate::models::record_flows::AppParentContext),
238    /// Application Initiator - Format (0,2204)
239    AppInitiator(crate::models::record_flows::AppInitiator),
240    /// Application Target - Format (0,2205)
241    AppTarget(crate::models::record_flows::AppTarget),
242    /// Unknown or unparsed format
243    Unknown { format: DataFormat, data: Vec<u8> },
244}
245
246/// Flow record containing flow data
247#[derive(Debug, Clone, PartialEq, Eq)]
248pub struct FlowRecord {
249    pub flow_format: DataFormat,
250    pub flow_data: FlowData,
251}
252
253/// Counter data types
254#[derive(Debug, Clone, PartialEq)]
255pub enum CounterData {
256    /// Generic Interface Counters - Format (0,1)
257    GenericInterface(crate::models::record_counters::GenericInterfaceCounters),
258    /// Ethernet Interface Counters - Format (0,2)
259    EthernetInterface(crate::models::record_counters::EthernetInterfaceCounters),
260    /// Token Ring Counters - Format (0,3)
261    TokenRing(crate::models::record_counters::TokenRingCounters),
262    /// 100BaseVG Counters - Format (0,4)
263    Vg100Interface(crate::models::record_counters::Vg100InterfaceCounters),
264    /// VLAN Counters - Format (0,5)
265    Vlan(crate::models::record_counters::VlanCounters),
266    /// IEEE 802.11 Counters - Format (0,6)
267    Ieee80211(crate::models::record_counters::Ieee80211Counters),
268    /// Processor Counters - Format (0,1001)
269    Processor(crate::models::record_counters::ProcessorCounters),
270    /// Radio Utilization - Format (0,1002)
271    RadioUtilization(crate::models::record_counters::RadioUtilization),
272    /// Host Description - Format (0,2000)
273    HostDescription(crate::models::record_counters::HostDescription),
274    /// Host Adapters - Format (0,2001)
275    HostAdapters(crate::models::record_counters::HostAdapters),
276    /// Host Parent - Format (0,2002)
277    HostParent(crate::models::record_counters::HostParent),
278    /// Host CPU - Format (0,2003)
279    HostCpu(crate::models::record_counters::HostCpu),
280    /// Host Memory - Format (0,2004)
281    HostMemory(crate::models::record_counters::HostMemory),
282    /// Host Disk I/O - Format (0,2005)
283    HostDiskIo(crate::models::record_counters::HostDiskIo),
284    /// Host Network I/O - Format (0,2006)
285    HostNetIo(crate::models::record_counters::HostNetIo),
286    /// Virtual Node - Format (0,2100)
287    VirtualNode(crate::models::record_counters::VirtualNode),
288    /// Virtual CPU - Format (0,2101)
289    VirtualCpu(crate::models::record_counters::VirtualCpu),
290    /// Virtual Memory - Format (0,2102)
291    VirtualMemory(crate::models::record_counters::VirtualMemory),
292    /// Virtual Disk I/O - Format (0,2103)
293    VirtualDiskIo(crate::models::record_counters::VirtualDiskIo),
294    /// Virtual Network I/O - Format (0,2104)
295    VirtualNetIo(crate::models::record_counters::VirtualNetIo),
296    /// OpenFlow Port - Format (0,1004)
297    OpenFlowPort(crate::models::record_counters::OpenFlowPort),
298    /// OpenFlow Port Name - Format (0,1005)
299    OpenFlowPortName(crate::models::record_counters::OpenFlowPortName),
300    /// App Operations - Format (0,2202)
301    AppOperations(crate::models::record_counters::AppOperations),
302    /// App Resources - Format (0,2203)
303    AppResources(crate::models::record_counters::AppResources),
304    /// App Workers - Format (0,2206)
305    AppWorkers(crate::models::record_counters::AppWorkers),
306    /// Unknown or unparsed format
307    Unknown { format: DataFormat, data: Vec<u8> },
308}
309
310/// Counter record containing counter data
311#[derive(Debug, Clone, PartialEq)]
312pub struct CounterRecord {
313    pub counter_format: DataFormat,
314    pub counter_data: CounterData,
315}
316
317/// Compact flow sample (enterprise=0, format=1)
318#[derive(Debug, Clone, PartialEq, Eq)]
319pub struct FlowSample {
320    pub sequence_number: u32,
321    pub source_id: DataSource,
322    pub sampling_rate: u32,
323    pub sample_pool: u32,
324    pub drops: u32,
325    pub input: Interface,
326    pub output: Interface,
327    pub flow_records: Vec<FlowRecord>,
328}
329
330/// Compact counters sample (enterprise=0, format=2)
331#[derive(Debug, Clone, PartialEq)]
332pub struct CountersSample {
333    pub sequence_number: u32,
334    pub source_id: DataSource,
335    pub counters: Vec<CounterRecord>,
336}
337
338/// Expanded flow sample (enterprise=0, format=3)
339#[derive(Debug, Clone, PartialEq, Eq)]
340pub struct FlowSampleExpanded {
341    pub sequence_number: u32,
342    pub source_id: DataSourceExpanded,
343    pub sampling_rate: u32,
344    pub sample_pool: u32,
345    pub drops: u32,
346    pub input: InterfaceExpanded,
347    pub output: InterfaceExpanded,
348    pub flow_records: Vec<FlowRecord>,
349}
350
351/// Expanded counter sample (enterprise=0, format=4)
352#[derive(Debug, Clone, PartialEq)]
353pub struct CountersSampleExpanded {
354    pub sequence_number: u32,
355    pub source_id: DataSourceExpanded,
356    pub counters: Vec<CounterRecord>,
357}
358
359/// Discarded packet sample (enterprise=0, format=5)
360///
361/// # XDR Definition ([sFlow Drops](https://sflow.org/sflow_drops.txt))
362///
363/// ```text
364/// /* Format of a single discarded packet event */
365/// /* opaque = sample_data; enterprise = 0; format = 5 */
366/// struct discarded_packet {
367///    unsigned int sequence_number;  /* Incremented with each discarded packet
368///                                      record generated by this source_id. */
369///    sflow_data_source_expanded source_id; /* sFlowDataSource */
370///    unsigned int drops;            /* Number of times that the sFlow agent
371///                                      detected that a discarded packet record
372///                                      was dropped by the rate limit, or because
373///                                      of a lack of resources. The drops counter
374///                                      reports the total number of drops detected
375///                                      since the agent was last reset. Note: An
376///                                      agent that cannot detect drops will always
377///                                      report zero. */
378///    unsigned int inputifindex;     /* If set, ifIndex of interface packet was
379///                                      received on. Zero if unknown. Must identify
380///                                      physical port consistent with flow_sample
381///                                      input interface. */
382///    unsigned int outputifindex;    /* If set, ifIndex for egress drops. Zero
383///                                      otherwise. Must identify physical port
384///                                      consistent with flow_sample output
385///                                      interface. */
386///    drop_reason reason;            /* Reason for dropping packet. */
387///    flow_record discard_records<>; /* Information about the discarded packet. */
388/// }
389/// ```
390#[derive(Debug, Clone, PartialEq, Eq)]
391pub struct DiscardedPacket {
392    /// Sequence number incremented with each discarded packet record
393    pub sequence_number: u32,
394
395    /// sFlow data source
396    pub source_id: DataSourceExpanded,
397
398    /// Number of discarded packet records dropped by rate limit or lack of resources
399    pub drops: u32,
400
401    /// Input interface index (0 if unknown)
402    pub input_ifindex: u32,
403
404    /// Output interface index (0 if not egress drop)
405    pub output_ifindex: u32,
406
407    /// Reason for dropping the packet
408    pub reason: crate::models::record_flows::DropReason,
409
410    /// Flow records describing the discarded packet
411    pub flow_records: Vec<FlowRecord>,
412}
413
414/// Sample data types
415#[derive(Debug, Clone, PartialEq)]
416pub enum SampleData {
417    FlowSample(FlowSample),
418    CountersSample(CountersSample),
419    FlowSampleExpanded(FlowSampleExpanded),
420    CountersSampleExpanded(CountersSampleExpanded),
421    DiscardedPacket(DiscardedPacket),
422    Unknown { format: DataFormat, data: Vec<u8> },
423}
424
425/// Sample record
426#[derive(Debug, Clone, PartialEq)]
427pub struct SampleRecord {
428    pub sample_type: DataFormat,
429    pub sample_data: SampleData,
430}
431
432/// sFlow v5 datagram
433#[derive(Debug, Clone, PartialEq)]
434pub struct SFlowDatagram {
435    pub version: DatagramVersion,
436    pub agent_address: Address,
437    pub sub_agent_id: u32,
438    pub sequence_number: u32,
439    pub uptime: u32,
440    pub samples: Vec<SampleRecord>,
441}
442
443impl SFlowDatagram {
444    /// Create a new sFlow v5 datagram
445    pub fn new(
446        agent_address: Address,
447        sub_agent_id: u32,
448        sequence_number: u32,
449        uptime: u32,
450    ) -> Self {
451        Self {
452            version: DatagramVersion::Version5,
453            agent_address,
454            sub_agent_id,
455            sequence_number,
456            uptime,
457            samples: Vec::new(),
458        }
459    }
460}