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 HW Trap - Format (0,1041)
342 ExtendedHwTrap(crate::models::record_flows::ExtendedHwTrap),
343 /// Extended Linux Drop Reason - Format (0,1042)
344 ExtendedLinuxDropReason(crate::models::record_flows::ExtendedLinuxDropReason),
345 /// Extended Socket IPv4 - Format (0,2100)
346 ExtendedSocketIpv4(crate::models::record_flows::ExtendedSocketIpv4),
347 /// Extended Socket IPv6 - Format (0,2101)
348 ExtendedSocketIpv6(crate::models::record_flows::ExtendedSocketIpv6),
349 /// Extended Proxy Socket IPv4 - Format (0,2102)
350 ExtendedProxySocketIpv4(crate::models::record_flows::ExtendedProxySocketIpv4),
351 /// Extended Proxy Socket IPv6 - Format (0,2103)
352 ExtendedProxySocketIpv6(crate::models::record_flows::ExtendedProxySocketIpv6),
353 /// Memcache Operation - Format (0,2200)
354 MemcacheOperation(crate::models::record_flows::MemcacheOperation),
355 /// HTTP Request - Format (0,2201) - DEPRECATED
356 HttpRequestDeprecated(crate::models::record_flows::HttpRequestDeprecated),
357 /// Application Operation - Format (0,2202)
358 AppOperation(crate::models::record_flows::AppOperation),
359 /// Application Parent Context - Format (0,2203)
360 AppParentContext(crate::models::record_flows::AppParentContext),
361 /// Application Initiator - Format (0,2204)
362 AppInitiator(crate::models::record_flows::AppInitiator),
363 /// Application Target - Format (0,2205)
364 AppTarget(crate::models::record_flows::AppTarget),
365 /// HTTP Request - Format (0,2206)
366 HttpRequest(crate::models::record_flows::HttpRequest),
367 /// Extended Proxy Request - Format (0,2207)
368 ExtendedProxyRequest(crate::models::record_flows::ExtendedProxyRequest),
369 /// Extended BST Egress Queue - Format (4413,1)
370 ExtendedBstEgressQueue(crate::models::record_flows::ExtendedBstEgressQueue),
371 /// Unknown or unparsed format
372 Unknown { format: DataFormat, data: Vec<u8> },
373}
374
375/// Flow record containing flow data
376#[derive(Debug, Clone, PartialEq, Eq)]
377#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
378pub struct FlowRecord {
379 pub flow_format: DataFormat,
380 pub flow_data: FlowData,
381}
382
383/// Counter data types
384#[derive(Debug, Clone, PartialEq)]
385#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
386pub enum CounterData {
387 /// Generic Interface Counters - Format (0,1)
388 GenericInterface(crate::models::record_counters::GenericInterfaceCounters),
389 /// Ethernet Interface Counters - Format (0,2)
390 EthernetInterface(crate::models::record_counters::EthernetInterfaceCounters),
391 /// Token Ring Counters - Format (0,3)
392 TokenRing(crate::models::record_counters::TokenRingCounters),
393 /// 100BaseVG Counters - Format (0,4)
394 Vg100Interface(crate::models::record_counters::Vg100InterfaceCounters),
395 /// VLAN Counters - Format (0,5)
396 Vlan(crate::models::record_counters::VlanCounters),
397 /// IEEE 802.11 Counters - Format (0,6)
398 Ieee80211(crate::models::record_counters::Ieee80211Counters),
399 /// LAG Port Statistics - Format (0,7)
400 LagPortStats(crate::models::record_counters::LagPortStats),
401 /// InfiniBand Counters - Format (0,9)
402 InfiniBandCounters(crate::models::record_counters::InfiniBandCounters),
403 /// Optical SFP/QSFP Counters - Format (0,10)
404 OpticalSfpQsfp(crate::models::record_counters::OpticalSfpQsfp),
405 /// Processor Counters - Format (0,1001)
406 Processor(crate::models::record_counters::ProcessorCounters),
407 /// Radio Utilization - Format (0,1002)
408 RadioUtilization(crate::models::record_counters::RadioUtilization),
409 /// OpenFlow Port - Format (0,1004)
410 OpenFlowPort(crate::models::record_counters::OpenFlowPort),
411 /// OpenFlow Port Name - Format (0,1005)
412 OpenFlowPortName(crate::models::record_counters::OpenFlowPortName),
413 /// Host Description - Format (0,2000)
414 HostDescription(crate::models::record_counters::HostDescription),
415 /// Host Adapters - Format (0,2001)
416 HostAdapters(crate::models::record_counters::HostAdapters),
417 /// Host Parent - Format (0,2002)
418 HostParent(crate::models::record_counters::HostParent),
419 /// Host CPU - Format (0,2003)
420 HostCpu(crate::models::record_counters::HostCpu),
421 /// Host Memory - Format (0,2004)
422 HostMemory(crate::models::record_counters::HostMemory),
423 /// Host Disk I/O - Format (0,2005)
424 HostDiskIo(crate::models::record_counters::HostDiskIo),
425 /// Host Network I/O - Format (0,2006)
426 HostNetIo(crate::models::record_counters::HostNetIo),
427 /// MIB-2 IP Group - Format (0,2007)
428 Mib2IpGroup(crate::models::record_counters::Mib2IpGroup),
429 /// MIB-2 ICMP Group - Format (0,2008)
430 Mib2IcmpGroup(crate::models::record_counters::Mib2IcmpGroup),
431 /// MIB-2 TCP Group - Format (0,2009)
432 Mib2TcpGroup(crate::models::record_counters::Mib2TcpGroup),
433 /// MIB-2 UDP Group - Format (0,2010)
434 Mib2UdpGroup(crate::models::record_counters::Mib2UdpGroup),
435 /// Virtual Node - Format (0,2100)
436 VirtualNode(crate::models::record_counters::VirtualNode),
437 /// Virtual CPU - Format (0,2101)
438 VirtualCpu(crate::models::record_counters::VirtualCpu),
439 /// Virtual Memory - Format (0,2102)
440 VirtualMemory(crate::models::record_counters::VirtualMemory),
441 /// Virtual Disk I/O - Format (0,2103)
442 VirtualDiskIo(crate::models::record_counters::VirtualDiskIo),
443 /// Virtual Network I/O - Format (0,2104)
444 VirtualNetIo(crate::models::record_counters::VirtualNetIo),
445 /// JVM Runtime - Format (0,2105)
446 JvmRuntime(crate::models::record_counters::JvmRuntime),
447 /// JVM Statistics - Format (0,2106)
448 JvmStatistics(crate::models::record_counters::JvmStatistics),
449 /// Memcache Counters - Format (0,2200) - DEPRECATED
450 MemcacheCountersDeprecated(crate::models::record_counters::MemcacheCountersDeprecated),
451 /// HTTP Counters - Format (0,2201)
452 HttpCounters(crate::models::record_counters::HttpCounters),
453 /// App Operations - Format (0,2202)
454 AppOperations(crate::models::record_counters::AppOperations),
455 /// App Resources - Format (0,2203)
456 AppResources(crate::models::record_counters::AppResources),
457 /// Memcache Counters - Format (0,2204)
458 MemcacheCounters(crate::models::record_counters::MemcacheCounters),
459 /// App Workers - Format (0,2206)
460 AppWorkers(crate::models::record_counters::AppWorkers),
461 /// Broadcom Device Buffer Utilization - Format (4413,1)
462 BroadcomDeviceBuffers(crate::models::record_counters::BroadcomDeviceBuffers),
463 /// Broadcom Port Buffer Utilization - Format (4413,2)
464 BroadcomPortBuffers(crate::models::record_counters::BroadcomPortBuffers),
465 /// Broadcom Switch ASIC Table Utilization - Format (4413,3)
466 BroadcomTables(crate::models::record_counters::BroadcomTables),
467 /// NVIDIA GPU Statistics - Format (5703,1)
468 NvidiaGpu(crate::models::record_counters::NvidiaGpu),
469 /// Unknown or unparsed format
470 Unknown { format: DataFormat, data: Vec<u8> },
471}
472
473/// Counter record containing counter data
474#[derive(Debug, Clone, PartialEq)]
475#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
476pub struct CounterRecord {
477 pub counter_format: DataFormat,
478 pub counter_data: CounterData,
479}
480
481/// Compact flow sample - Format (0,1)
482///
483/// Contains sampled packet information with compact encoding for interfaces.
484///
485/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
486///
487/// ```text
488/// /* Format of a single flow sample */
489/// /* opaque = sample_data; enterprise = 0; format = 1 */
490///
491/// struct flow_sample {
492/// unsigned int sequence_number; /* Incremented with each flow sample
493/// generated by this sFlow Instance. */
494/// sflow_data_source source_id; /* sFlowDataSource */
495/// unsigned int sampling_rate; /* sFlowPacketSamplingRate */
496/// unsigned int sample_pool; /* Total number of packets that could have been
497/// sampled (i.e. packets skipped by sampling process
498/// + total number of samples) */
499/// unsigned int drops; /* Number of times that the sFlow agent detected
500/// that a packet marked to be sampled was dropped
501/// due to lack of resources. */
502/// interface input; /* Input interface */
503/// interface output; /* Output interface */
504/// flow_record flow_records<>; /* Information about sampled packet */
505/// }
506/// ```
507///
508/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
509#[derive(Debug, Clone, PartialEq, Eq)]
510#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
511pub struct FlowSample {
512 /// Sequence number incremented with each flow sample generated by this sFlow Instance
513 /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
514 pub sequence_number: u32,
515 /// sFlow data source identifier
516 pub source_id: DataSource,
517 /// Sampling rate (1 in N packets)
518 pub sampling_rate: u32,
519 /// Total packets that could have been sampled
520 pub sample_pool: u32,
521 /// Number of dropped samples due to lack of resources
522 pub drops: u32,
523 /// Input interface
524 pub input: Interface,
525 /// Output interface
526 pub output: Interface,
527 /// Flow records describing the sampled packet
528 pub flow_records: Vec<FlowRecord>,
529}
530
531/// Compact counters sample - Format (0,2)
532///
533/// Contains interface and system counter statistics.
534///
535/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
536///
537/// ```text
538/// /* Format of a single counter sample */
539/// /* opaque = sample_data; enterprise = 0; format = 2 */
540///
541/// struct counters_sample {
542/// unsigned int sequence_number; /* Incremented with each counter sample
543/// generated by this sFlow Instance. */
544/// sflow_data_source source_id; /* sFlowDataSource */
545/// counter_record counters<>; /* Counters polled for this source */
546/// }
547/// ```
548///
549/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
550#[derive(Debug, Clone, PartialEq)]
551#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
552pub struct CountersSample {
553 /// Sequence number incremented with each counter sample generated by this sFlow Instance
554 /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
555 pub sequence_number: u32,
556 /// sFlow data source identifier
557 pub source_id: DataSource,
558 /// Counter records for this source
559 pub counters: Vec<CounterRecord>,
560}
561
562/// Expanded flow sample - Format (0,3)
563///
564/// Flow sample with expanded encoding for large interface indices (>= 2^24).
565///
566/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
567///
568/// ```text
569/// /* Format of a single expanded flow sample */
570/// /* opaque = sample_data; enterprise = 0; format = 3 */
571///
572/// struct flow_sample_expanded {
573/// unsigned int sequence_number; /* Incremented with each flow sample
574/// generated by this sFlow Instance. */
575/// sflow_data_source_expanded source_id; /* sFlowDataSource */
576/// unsigned int sampling_rate; /* sFlowPacketSamplingRate */
577/// unsigned int sample_pool; /* Total number of packets that could have been
578/// sampled (i.e. packets skipped by sampling process
579/// + total number of samples) */
580/// unsigned int drops; /* Number of times that the sFlow agent detected
581/// that a packet marked to be sampled was dropped
582/// due to lack of resources. */
583/// interface_expanded input; /* Input interface */
584/// interface_expanded output; /* Output interface */
585/// flow_record flow_records<>; /* Information about sampled packet */
586/// }
587/// ```
588///
589/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
590#[derive(Debug, Clone, PartialEq, Eq)]
591#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
592pub struct FlowSampleExpanded {
593 /// Sequence number incremented with each flow sample generated by this sFlow Instance
594 /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
595 pub sequence_number: u32,
596 /// Expanded sFlow data source identifier
597 pub source_id: DataSourceExpanded,
598 /// Sampling rate (1 in N packets)
599 pub sampling_rate: u32,
600 /// Total packets that could have been sampled
601 pub sample_pool: u32,
602 /// Number of dropped samples due to lack of resources
603 pub drops: u32,
604 /// Input interface (expanded)
605 pub input: InterfaceExpanded,
606 /// Output interface (expanded)
607 pub output: InterfaceExpanded,
608 /// Flow records describing the sampled packet
609 pub flow_records: Vec<FlowRecord>,
610}
611
612/// Expanded counter sample - Format (0,4)
613///
614/// Counter sample with expanded encoding for large interface indices (>= 2^24).
615///
616/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
617///
618/// ```text
619/// /* Format of a single expanded counters sample */
620/// /* opaque = sample_data; enterprise = 0; format = 4 */
621///
622/// struct counters_sample_expanded {
623/// unsigned int sequence_number; /* Incremented with each counter sample
624/// generated by this sFlow Instance. */
625/// sflow_data_source_expanded source_id; /* sFlowDataSource */
626/// counter_record counters<>; /* Counters polled for this source */
627/// }
628/// ```
629///
630/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
631#[derive(Debug, Clone, PartialEq)]
632#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
633pub struct CountersSampleExpanded {
634 /// Sequence number incremented with each counter sample generated by this sFlow Instance
635 /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
636 pub sequence_number: u32,
637 /// Expanded sFlow data source identifier
638 pub source_id: DataSourceExpanded,
639 /// Counter records for this source
640 pub counters: Vec<CounterRecord>,
641}
642
643/// Discarded packet sample - Format (0,5)
644///
645/// # XDR Definition ([sFlow Drops](https://sflow.org/sflow_drops.txt))
646///
647/// ```text
648/// /* Format of a single discarded packet event */
649/// /* opaque = sample_data; enterprise = 0; format = 5 */
650/// struct discarded_packet {
651/// unsigned int sequence_number; /* Incremented with each discarded packet
652/// record generated by this source_id. */
653/// sflow_data_source_expanded source_id; /* sFlowDataSource */
654/// unsigned int drops; /* Number of times that the sFlow agent
655/// detected that a discarded packet record
656/// was dropped by the rate limit, or because
657/// of a lack of resources. The drops counter
658/// reports the total number of drops detected
659/// since the agent was last reset. Note: An
660/// agent that cannot detect drops will always
661/// report zero. */
662/// unsigned int inputifindex; /* If set, ifIndex of interface packet was
663/// received on. Zero if unknown. Must identify
664/// physical port consistent with flow_sample
665/// input interface. */
666/// unsigned int outputifindex; /* If set, ifIndex for egress drops. Zero
667/// otherwise. Must identify physical port
668/// consistent with flow_sample output
669/// interface. */
670/// drop_reason reason; /* Reason for dropping packet. */
671/// flow_record discard_records<>; /* Information about the discarded packet. */
672/// }
673/// ```
674#[derive(Debug, Clone, PartialEq, Eq)]
675#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
676pub struct DiscardedPacket {
677 /// Sequence number incremented with each discarded packet record
678 pub sequence_number: u32,
679
680 /// sFlow data source
681 pub source_id: DataSourceExpanded,
682
683 /// Number of discarded packet records dropped by rate limit or lack of resources
684 pub drops: u32,
685
686 /// Input interface index (0 if unknown)
687 pub input_ifindex: u32,
688
689 /// Output interface index (0 if not egress drop)
690 pub output_ifindex: u32,
691
692 /// Reason for dropping the packet
693 pub reason: crate::models::record_flows::DropReason,
694
695 /// Flow records describing the discarded packet
696 pub flow_records: Vec<FlowRecord>,
697}
698
699/// Sample data types
700#[derive(Debug, Clone, PartialEq)]
701#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
702pub enum SampleData {
703 FlowSample(FlowSample),
704 CountersSample(CountersSample),
705 FlowSampleExpanded(FlowSampleExpanded),
706 CountersSampleExpanded(CountersSampleExpanded),
707 DiscardedPacket(DiscardedPacket),
708 Unknown { format: DataFormat, data: Vec<u8> },
709}
710
711/// Sample record
712#[derive(Debug, Clone, PartialEq)]
713#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
714pub struct SampleRecord {
715 pub sample_type: DataFormat,
716 pub sample_data: SampleData,
717}
718
719/// sFlow v5 datagram
720///
721/// Top-level structure containing one or more samples.
722///
723/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
724///
725/// ```text
726/// /* sFlow version 5 datagram */
727///
728/// struct sflow_datagram {
729/// unsigned int version; /* sFlow version (5) */
730/// address agent_address; /* IP address of sampling agent */
731/// unsigned int sub_agent_id; /* Used to distinguish multiple sFlow instances
732/// on the same agent */
733/// unsigned int sequence_number;/* Incremented with each sample datagram generated
734/// by a sub-agent within an agent */
735/// unsigned int uptime; /* Current time (in milliseconds since device
736/// last booted). Should be set as close to
737/// datagram transmission time as possible. */
738/// sample_record samples<>; /* An array of sample records */
739/// }
740/// ```
741#[derive(Debug, Clone, PartialEq)]
742#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
743pub struct SFlowDatagram {
744 /// sFlow protocol version (always 5)
745 pub version: DatagramVersion,
746 /// IP address of the sFlow agent
747 pub agent_address: Address,
748 /// Sub-agent identifier (distinguishes multiple sFlow instances on same agent)
749 pub sub_agent_id: u32,
750 /// Datagram sequence number (incremented with each datagram from this sub-agent)
751 pub sequence_number: u32,
752 /// Device uptime in milliseconds since last boot
753 pub uptime: u32,
754 /// Array of sample records
755 pub samples: Vec<SampleRecord>,
756}
757
758impl SFlowDatagram {
759 /// Create a new sFlow v5 datagram
760 pub fn new(
761 agent_address: Address,
762 sub_agent_id: u32,
763 sequence_number: u32,
764 uptime: u32,
765 ) -> Self {
766 Self {
767 version: DatagramVersion::Version5,
768 agent_address,
769 sub_agent_id,
770 sequence_number,
771 uptime,
772 samples: Vec::new(),
773 }
774 }
775}