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 Fiber Channel - Format (0,1018)
304    ExtendedFc(crate::models::record_flows::ExtendedFc),
305    /// Extended Queue Length - Format (0,1019)
306    ExtendedQueueLength(crate::models::record_flows::ExtendedQueueLength),
307    /// Extended NAT Port - Format (0,1020)
308    ExtendedNatPort(crate::models::record_flows::ExtendedNatPort),
309    /// Extended L2 Tunnel Egress - Format (0,1021)
310    ExtendedL2TunnelEgress(crate::models::record_flows::ExtendedL2TunnelEgress),
311    /// Extended L2 Tunnel Ingress - Format (0,1022)
312    ExtendedL2TunnelIngress(crate::models::record_flows::ExtendedL2TunnelIngress),
313    /// Extended IPv4 Tunnel Egress - Format (0,1023)
314    ExtendedIpv4TunnelEgress(crate::models::record_flows::ExtendedIpv4TunnelEgress),
315    /// Extended IPv4 Tunnel Ingress - Format (0,1024)
316    ExtendedIpv4TunnelIngress(crate::models::record_flows::ExtendedIpv4TunnelIngress),
317    /// Extended IPv6 Tunnel Egress - Format (0,1025)
318    ExtendedIpv6TunnelEgress(crate::models::record_flows::ExtendedIpv6TunnelEgress),
319    /// Extended IPv6 Tunnel Ingress - Format (0,1026)
320    ExtendedIpv6TunnelIngress(crate::models::record_flows::ExtendedIpv6TunnelIngress),
321    /// Extended Decapsulate Egress - Format (0,1027)
322    ExtendedDecapsulateEgress(crate::models::record_flows::ExtendedDecapsulateEgress),
323    /// Extended Decapsulate Ingress - Format (0,1028)
324    ExtendedDecapsulateIngress(crate::models::record_flows::ExtendedDecapsulateIngress),
325    /// Extended VNI Egress - Format (0,1029)
326    ExtendedVniEgress(crate::models::record_flows::ExtendedVniEgress),
327    /// Extended VNI Ingress - Format (0,1030)
328    ExtendedVniIngress(crate::models::record_flows::ExtendedVniIngress),
329    /// Extended InfiniBand LRH - Format (0,1031)
330    ExtendedInfiniBandLrh(crate::models::record_flows::ExtendedInfiniBandLrh),
331    /// Extended InfiniBand GRH - Format (0,1032)
332    ExtendedInfiniBandGrh(crate::models::record_flows::ExtendedInfiniBandGrh),
333    /// Extended InfiniBand BTH - Format (0,1033)
334    ExtendedInfiniBandBth(crate::models::record_flows::ExtendedInfiniBandBth),
335    /// Extended VLAN In - Format (0,1034)
336    ExtendedVlanIn(crate::models::record_flows::ExtendedVlanIn),
337    /// Extended VLAN Out - Format (0,1035)
338    ExtendedVlanOut(crate::models::record_flows::ExtendedVlanOut),
339    /// Extended Egress Queue - Format (0,1036)
340    ExtendedEgressQueue(crate::models::record_flows::ExtendedEgressQueue),
341    /// Extended ACL - Format (0,1037)
342    ExtendedAcl(crate::models::record_flows::ExtendedAcl),
343    /// Extended Function - Format (0,1038)
344    ExtendedFunction(crate::models::record_flows::ExtendedFunction),
345    /// Extended Transit - Format (0,1039)
346    ExtendedTransit(crate::models::record_flows::ExtendedTransit),
347    /// Extended Queue - Format (0,1040)
348    ExtendedQueue(crate::models::record_flows::ExtendedQueue),
349    /// Extended HW Trap - Format (0,1041)
350    ExtendedHwTrap(crate::models::record_flows::ExtendedHwTrap),
351    /// Extended Linux Drop Reason - Format (0,1042)
352    ExtendedLinuxDropReason(crate::models::record_flows::ExtendedLinuxDropReason),
353    /// Transaction - Format (0,2000)
354    Transaction(crate::models::record_flows::Transaction),
355    /// Extended NFS Storage Transaction - Format (0,2001)
356    ExtendedNfsStorageTransaction(crate::models::record_flows::ExtendedNfsStorageTransaction),
357    /// Extended SCSI Storage Transaction - Format (0,2002)
358    ExtendedScsiStorageTransaction(crate::models::record_flows::ExtendedScsiStorageTransaction),
359    /// Extended HTTP Transaction - Format (0,2003)
360    ExtendedHttpTransaction(crate::models::record_flows::ExtendedHttpTransaction),
361    /// Extended Socket IPv4 - Format (0,2100)
362    ExtendedSocketIpv4(crate::models::record_flows::ExtendedSocketIpv4),
363    /// Extended Socket IPv6 - Format (0,2101)
364    ExtendedSocketIpv6(crate::models::record_flows::ExtendedSocketIpv6),
365    /// Extended Proxy Socket IPv4 - Format (0,2102)
366    ExtendedProxySocketIpv4(crate::models::record_flows::ExtendedProxySocketIpv4),
367    /// Extended Proxy Socket IPv6 - Format (0,2103)
368    ExtendedProxySocketIpv6(crate::models::record_flows::ExtendedProxySocketIpv6),
369    /// Memcache Operation - Format (0,2200)
370    MemcacheOperation(crate::models::record_flows::MemcacheOperation),
371    /// HTTP Request - Format (0,2201) - DEPRECATED
372    HttpRequestDeprecated(crate::models::record_flows::HttpRequestDeprecated),
373    /// Application Operation - Format (0,2202)
374    AppOperation(crate::models::record_flows::AppOperation),
375    /// Application Parent Context - Format (0,2203)
376    AppParentContext(crate::models::record_flows::AppParentContext),
377    /// Application Initiator - Format (0,2204)
378    AppInitiator(crate::models::record_flows::AppInitiator),
379    /// Application Target - Format (0,2205)
380    AppTarget(crate::models::record_flows::AppTarget),
381    /// HTTP Request - Format (0,2206)
382    HttpRequest(crate::models::record_flows::HttpRequest),
383    /// Extended Proxy Request - Format (0,2207)
384    ExtendedProxyRequest(crate::models::record_flows::ExtendedProxyRequest),
385    /// Extended Nav Timing - Format (0,2208)
386    ExtendedNavTiming(crate::models::record_flows::ExtendedNavTiming),
387    /// Extended TCP Info - Format (0,2209)
388    ExtendedTcpInfo(crate::models::record_flows::ExtendedTcpInfo),
389    /// Extended Entities - Format (0,2210)
390    ExtendedEntities(crate::models::record_flows::ExtendedEntities),
391    /// Extended BST Egress Queue - Format (4413,1)
392    ExtendedBstEgressQueue(crate::models::record_flows::ExtendedBstEgressQueue),
393    /// Unknown or unparsed format
394    Unknown { format: DataFormat, data: Vec<u8> },
395}
396
397/// Flow record containing flow data
398#[derive(Debug, Clone, PartialEq, Eq)]
399#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
400pub struct FlowRecord {
401    pub flow_format: DataFormat,
402    pub flow_data: FlowData,
403}
404
405/// Counter data types
406#[derive(Debug, Clone, PartialEq)]
407#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
408pub enum CounterData {
409    /// Generic Interface Counters - Format (0,1)
410    GenericInterface(crate::models::record_counters::GenericInterfaceCounters),
411    /// Ethernet Interface Counters - Format (0,2)
412    EthernetInterface(crate::models::record_counters::EthernetInterfaceCounters),
413    /// Token Ring Counters - Format (0,3)
414    TokenRing(crate::models::record_counters::TokenRingCounters),
415    /// 100BaseVG Counters - Format (0,4)
416    Vg100Interface(crate::models::record_counters::Vg100InterfaceCounters),
417    /// VLAN Counters - Format (0,5)
418    Vlan(crate::models::record_counters::VlanCounters),
419    /// IEEE 802.11 Counters - Format (0,6)
420    Ieee80211(crate::models::record_counters::Ieee80211Counters),
421    /// LAG Port Statistics - Format (0,7)
422    LagPortStats(crate::models::record_counters::LagPortStats),
423    /// Slow Path Counts - Format (0,8)
424    SlowPathCounts(crate::models::record_counters::SlowPathCounts),
425    /// InfiniBand Counters - Format (0,9)
426    InfiniBandCounters(crate::models::record_counters::InfiniBandCounters),
427    /// Optical SFP/QSFP Counters - Format (0,10)
428    OpticalSfpQsfp(crate::models::record_counters::OpticalSfpQsfp),
429    /// Processor Counters - Format (0,1001)
430    Processor(crate::models::record_counters::ProcessorCounters),
431    /// Radio Utilization - Format (0,1002)
432    RadioUtilization(crate::models::record_counters::RadioUtilization),
433    /// Queue Length - Format (0,1003)
434    QueueLength(crate::models::record_counters::QueueLength),
435    /// OpenFlow Port - Format (0,1004)
436    OpenFlowPort(crate::models::record_counters::OpenFlowPort),
437    /// OpenFlow Port Name - Format (0,1005)
438    OpenFlowPortName(crate::models::record_counters::OpenFlowPortName),
439    /// Host Description - Format (0,2000)
440    HostDescription(crate::models::record_counters::HostDescription),
441    /// Host Adapters - Format (0,2001)
442    HostAdapters(crate::models::record_counters::HostAdapters),
443    /// Host Parent - Format (0,2002)
444    HostParent(crate::models::record_counters::HostParent),
445    /// Host CPU - Format (0,2003)
446    HostCpu(crate::models::record_counters::HostCpu),
447    /// Host Memory - Format (0,2004)
448    HostMemory(crate::models::record_counters::HostMemory),
449    /// Host Disk I/O - Format (0,2005)
450    HostDiskIo(crate::models::record_counters::HostDiskIo),
451    /// Host Network I/O - Format (0,2006)
452    HostNetIo(crate::models::record_counters::HostNetIo),
453    /// MIB-2 IP Group - Format (0,2007)
454    Mib2IpGroup(crate::models::record_counters::Mib2IpGroup),
455    /// MIB-2 ICMP Group - Format (0,2008)
456    Mib2IcmpGroup(crate::models::record_counters::Mib2IcmpGroup),
457    /// MIB-2 TCP Group - Format (0,2009)
458    Mib2TcpGroup(crate::models::record_counters::Mib2TcpGroup),
459    /// MIB-2 UDP Group - Format (0,2010)
460    Mib2UdpGroup(crate::models::record_counters::Mib2UdpGroup),
461    /// Virtual Node - Format (0,2100)
462    VirtualNode(crate::models::record_counters::VirtualNode),
463    /// Virtual CPU - Format (0,2101)
464    VirtualCpu(crate::models::record_counters::VirtualCpu),
465    /// Virtual Memory - Format (0,2102)
466    VirtualMemory(crate::models::record_counters::VirtualMemory),
467    /// Virtual Disk I/O - Format (0,2103)
468    VirtualDiskIo(crate::models::record_counters::VirtualDiskIo),
469    /// Virtual Network I/O - Format (0,2104)
470    VirtualNetIo(crate::models::record_counters::VirtualNetIo),
471    /// JVM Runtime - Format (0,2105)
472    JvmRuntime(crate::models::record_counters::JvmRuntime),
473    /// JVM Statistics - Format (0,2106)
474    JvmStatistics(crate::models::record_counters::JvmStatistics),
475    /// Memcache Counters - Format (0,2200) - DEPRECATED
476    MemcacheCountersDeprecated(crate::models::record_counters::MemcacheCountersDeprecated),
477    /// HTTP Counters - Format (0,2201)
478    HttpCounters(crate::models::record_counters::HttpCounters),
479    /// App Operations - Format (0,2202)
480    AppOperations(crate::models::record_counters::AppOperations),
481    /// App Resources - Format (0,2203)
482    AppResources(crate::models::record_counters::AppResources),
483    /// Memcache Counters - Format (0,2204)
484    MemcacheCounters(crate::models::record_counters::MemcacheCounters),
485    /// App Workers - Format (0,2206)
486    AppWorkers(crate::models::record_counters::AppWorkers),
487    /// OVS DP Stats - Format (0,2207)
488    OvsDpStats(crate::models::record_counters::OvsDpStats),
489    /// Energy Consumption - Format (0,3000)
490    Energy(crate::models::record_counters::Energy),
491    /// Temperature - Format (0,3001)
492    Temperature(crate::models::record_counters::Temperature),
493    /// Humidity - Format (0,3002)
494    Humidity(crate::models::record_counters::Humidity),
495    /// Fans - Format (0,3003)
496    Fans(crate::models::record_counters::Fans),
497    /// Broadcom Device Buffer Utilization - Format (4413,1)
498    BroadcomDeviceBuffers(crate::models::record_counters::BroadcomDeviceBuffers),
499    /// Broadcom Port Buffer Utilization - Format (4413,2)
500    BroadcomPortBuffers(crate::models::record_counters::BroadcomPortBuffers),
501    /// Broadcom Switch ASIC Table Utilization - Format (4413,3)
502    BroadcomTables(crate::models::record_counters::BroadcomTables),
503    /// NVIDIA GPU Statistics - Format (5703,1)
504    NvidiaGpu(crate::models::record_counters::NvidiaGpu),
505    /// Unknown or unparsed format
506    Unknown { format: DataFormat, data: Vec<u8> },
507}
508
509/// Counter record containing counter data
510#[derive(Debug, Clone, PartialEq)]
511#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
512pub struct CounterRecord {
513    pub counter_format: DataFormat,
514    pub counter_data: CounterData,
515}
516
517/// Compact flow sample - Format (0,1)
518///
519/// Contains sampled packet information with compact encoding for interfaces.
520///
521/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
522///
523/// ```text
524/// /* Format of a single flow sample */
525/// /* opaque = sample_data; enterprise = 0; format = 1 */
526///
527/// struct flow_sample {
528///    unsigned int sequence_number;  /* Incremented with each flow sample
529///                                      generated by this sFlow Instance. */
530///    sflow_data_source source_id;   /* sFlowDataSource */
531///    unsigned int sampling_rate;    /* sFlowPacketSamplingRate */
532///    unsigned int sample_pool;      /* Total number of packets that could have been
533///                                      sampled (i.e. packets skipped by sampling process
534///                                      + total number of samples) */
535///    unsigned int drops;            /* Number of times that the sFlow agent detected
536///                                      that a packet marked to be sampled was dropped
537///                                      due to lack of resources. */
538///    interface input;               /* Input interface */
539///    interface output;              /* Output interface */
540///    flow_record flow_records<>;    /* Information about sampled packet */
541/// }
542/// ```
543///
544/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
545#[derive(Debug, Clone, PartialEq, Eq)]
546#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
547pub struct FlowSample {
548    /// Sequence number incremented with each flow sample generated by this sFlow Instance
549    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
550    pub sequence_number: u32,
551    /// sFlow data source identifier
552    pub source_id: DataSource,
553    /// Sampling rate (1 in N packets)
554    pub sampling_rate: u32,
555    /// Total packets that could have been sampled
556    pub sample_pool: u32,
557    /// Number of dropped samples due to lack of resources
558    pub drops: u32,
559    /// Input interface
560    pub input: Interface,
561    /// Output interface
562    pub output: Interface,
563    /// Flow records describing the sampled packet
564    pub flow_records: Vec<FlowRecord>,
565}
566
567/// Compact counters sample - Format (0,2)
568///
569/// Contains interface and system counter statistics.
570///
571/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
572///
573/// ```text
574/// /* Format of a single counter sample */
575/// /* opaque = sample_data; enterprise = 0; format = 2 */
576///
577/// struct counters_sample {
578///    unsigned int sequence_number;   /* Incremented with each counter sample
579///                                       generated by this sFlow Instance. */
580///    sflow_data_source source_id;    /* sFlowDataSource */
581///    counter_record counters<>;      /* Counters polled for this source */
582/// }
583/// ```
584///
585/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
586#[derive(Debug, Clone, PartialEq)]
587#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
588pub struct CountersSample {
589    /// Sequence number incremented with each counter sample generated by this sFlow Instance
590    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
591    pub sequence_number: u32,
592    /// sFlow data source identifier
593    pub source_id: DataSource,
594    /// Counter records for this source
595    pub counters: Vec<CounterRecord>,
596}
597
598/// Expanded flow sample - Format (0,3)
599///
600/// Flow sample with expanded encoding for large interface indices (>= 2^24).
601///
602/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
603///
604/// ```text
605/// /* Format of a single expanded flow sample */
606/// /* opaque = sample_data; enterprise = 0; format = 3 */
607///
608/// struct flow_sample_expanded {
609///    unsigned int sequence_number;  /* Incremented with each flow sample
610///                                      generated by this sFlow Instance. */
611///    sflow_data_source_expanded source_id; /* sFlowDataSource */
612///    unsigned int sampling_rate;    /* sFlowPacketSamplingRate */
613///    unsigned int sample_pool;      /* Total number of packets that could have been
614///                                      sampled (i.e. packets skipped by sampling process
615///                                      + total number of samples) */
616///    unsigned int drops;            /* Number of times that the sFlow agent detected
617///                                      that a packet marked to be sampled was dropped
618///                                      due to lack of resources. */
619///    interface_expanded input;      /* Input interface */
620///    interface_expanded output;     /* Output interface */
621///    flow_record flow_records<>;    /* Information about sampled packet */
622/// }
623/// ```
624///
625/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
626#[derive(Debug, Clone, PartialEq, Eq)]
627#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
628pub struct FlowSampleExpanded {
629    /// Sequence number incremented with each flow sample generated by this sFlow Instance
630    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
631    pub sequence_number: u32,
632    /// Expanded sFlow data source identifier
633    pub source_id: DataSourceExpanded,
634    /// Sampling rate (1 in N packets)
635    pub sampling_rate: u32,
636    /// Total packets that could have been sampled
637    pub sample_pool: u32,
638    /// Number of dropped samples due to lack of resources
639    pub drops: u32,
640    /// Input interface (expanded)
641    pub input: InterfaceExpanded,
642    /// Output interface (expanded)
643    pub output: InterfaceExpanded,
644    /// Flow records describing the sampled packet
645    pub flow_records: Vec<FlowRecord>,
646}
647
648/// Expanded counter sample - Format (0,4)
649///
650/// Counter sample with expanded encoding for large interface indices (>= 2^24).
651///
652/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
653///
654/// ```text
655/// /* Format of a single expanded counters sample */
656/// /* opaque = sample_data; enterprise = 0; format = 4 */
657///
658/// struct counters_sample_expanded {
659///    unsigned int sequence_number;   /* Incremented with each counter sample
660///                                       generated by this sFlow Instance. */
661///    sflow_data_source_expanded source_id; /* sFlowDataSource */
662///    counter_record counters<>;      /* Counters polled for this source */
663/// }
664/// ```
665///
666/// **ERRATUM:** Sequence number clarified as incremented per "sFlow Instance" instead of "source_id".
667#[derive(Debug, Clone, PartialEq)]
668#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
669pub struct CountersSampleExpanded {
670    /// Sequence number incremented with each counter sample generated by this sFlow Instance
671    /// **ERRATUM:** Clarified as "sFlow Instance" instead of "source_id"
672    pub sequence_number: u32,
673    /// Expanded sFlow data source identifier
674    pub source_id: DataSourceExpanded,
675    /// Counter records for this source
676    pub counters: Vec<CounterRecord>,
677}
678
679/// Drop reason codes for discarded packets
680///
681/// # XDR Definition ([sFlow Drops](https://sflow.org/sflow_drops.txt))
682///
683/// ```text
684/// /* The drop_reason enumeration may be expanded over time.
685///    sFlow collectors must be prepared to receive discard_packet
686///    structures with unrecognized drop_reason values.
687///
688///    This document expands on the discard reason codes 0-262 defined
689///    in the sFlow Version 5 [1] interface typedef and this expanded list
690///    should be regarded as an expansion of the reason codes in the
691///    interface typdef and are valid anywhere the typedef is referenced.
692///
693///    Codes 263-288 are defined in Devlink Trap [2]. Drop reason / group
694///    names from the Devlink Trap document are preserved where they define
695///    new reason codes, or referenced as comments where they map to existing
696///    codes.
697///
698///    Codes 289-303 are reasons that have yet to be upstreamed to Devlink Trap,
699///    but the intent is that they will eventually be upstreamed and documented as
700///    part of the Linux API [2], and so they have been reserved.
701///
702///    The authoritative list of drop reasons will be maintained
703///    at sflow.org */
704///
705/// enum drop_reason {
706///    net_unreachable      = 0,
707///    host_unreachable     = 1,
708///    protocol_unreachable = 2,
709///    port_unreachable     = 3,
710///    frag_needed          = 4,
711///    src_route_failed     = 5,
712///    dst_net_unknown      = 6, /* ipv4_lpm_miss, ipv6_lpm_miss */
713///    dst_host_unknown     = 7,
714///    src_host_isolated    = 8,
715///    dst_net_prohibited   = 9, /* reject_route */
716///    dst_host_prohibited  = 10,
717///    dst_net_tos_unreachable  = 11,
718///    dst_host_tos_unreacheable = 12,
719///    comm_admin_prohibited = 13,
720///    host_precedence_violation = 14,
721///    precedence_cutoff    = 15,
722///    unknown              = 256,
723///    ttl_exceeded         = 257, /* ttl_value_is_too_small */
724///    acl                  = 258, /* ingress_flow_action_drop,
725///                                   egress_flow_action_drop
726///                                   group acl_drops */
727///    no_buffer_space      = 259, /* tail_drop */
728///    red                  = 260, /* early_drop */
729///    traffic_shaping      = 261,
730///    pkt_too_big          = 262, /* mtu_value_is_too_small */
731///    src_mac_is_multicast = 263,
732///    vlan_tag_mismatch    = 264,
733///    ingress_vlan_filter  = 265,
734///    ingress_spanning_tree_filter = 266,
735///    port_list_is_empty   = 267,
736///    port_loopback_filter = 268,
737///    blackhole_route      = 269,
738///    non_ip               = 270,
739///    uc_dip_over_mc_dmac  = 271,
740///    dip_is_loopback_address = 272,
741///    sip_is_mc            = 273,
742///    sip_is_loopback_address = 274,
743///    ip_header_corrupted  = 275,
744///    ipv4_sip_is_limited_bc = 276,
745///    ipv6_mc_dip_reserved_scope = 277,
746///    ipv6_mc_dip_interface_local_scope = 278,
747///    unresolved_neigh     = 279,
748///    mc_reverse_path_forwarding = 280,
749///    non_routable_packet  = 281,
750///    decap_error          = 282,
751///    overlay_smac_is_mc   = 283,
752///    unknown_l2           = 284, /* group l2_drops */
753///    unknown_l3           = 285, /* group l3_drops */
754///    unknown_l3_exception = 286, /* group l3_exceptions */
755///    unknown_buffer       = 287, /* group buffer_drops */
756///    unknown_tunnel       = 288, /* group tunnel_drops */
757///    unknown_l4           = 289,
758///    sip_is_unspecified   = 290,
759///    mlag_port_isolation  = 291,
760///    blackhole_arp_neigh  = 292,
761///    src_mac_is_dmac      = 293,
762///    dmac_is_reserved     = 294,
763///    sip_is_class_e       = 295,
764///    mc_dmac_mismatch     = 296,
765///    sip_is_dip           = 297,
766///    dip_is_local_network = 298,
767///    dip_is_link_local    = 299,
768///    overlay_smac_is_dmac = 300,
769///    egress_vlan_filter   = 301,
770///    uc_reverse_path_forwarding = 302,
771///    split_horizon        = 303
772/// }
773/// ```
774#[derive(Debug, Clone, Copy, PartialEq, Eq)]
775#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
776#[repr(u32)]
777pub enum DropReason {
778    NetUnreachable = 0,
779    HostUnreachable = 1,
780    ProtocolUnreachable = 2,
781    PortUnreachable = 3,
782    FragNeeded = 4,
783    SrcRouteFailed = 5,
784    DstNetUnknown = 6,
785    DstHostUnknown = 7,
786    SrcHostIsolated = 8,
787    DstNetProhibited = 9,
788    DstHostProhibited = 10,
789    DstNetTosUnreachable = 11,
790    DstHostTosUnreachable = 12,
791    CommAdminProhibited = 13,
792    HostPrecedenceViolation = 14,
793    PrecedenceCutoff = 15,
794    Unknown = 256,
795    TtlExceeded = 257,
796    Acl = 258,
797    NoBufferSpace = 259,
798    Red = 260,
799    TrafficShaping = 261,
800    PktTooBig = 262,
801    SrcMacIsMulticast = 263,
802    VlanTagMismatch = 264,
803    IngressVlanFilter = 265,
804    IngressSpanningTreeFilter = 266,
805    PortListIsEmpty = 267,
806    PortLoopbackFilter = 268,
807    BlackholeRoute = 269,
808    NonIp = 270,
809    UcDipOverMcDmac = 271,
810    DipIsLoopbackAddress = 272,
811    SipIsMc = 273,
812    SipIsLoopbackAddress = 274,
813    IpHeaderCorrupted = 275,
814    Ipv4SipIsLimitedBc = 276,
815    Ipv6McDipReservedScope = 277,
816    Ipv6McDipInterfaceLocalScope = 278,
817    UnresolvedNeigh = 279,
818    McReversePathForwarding = 280,
819    NonRoutablePacket = 281,
820    DecapError = 282,
821    OverlaySmacIsMc = 283,
822    UnknownL2 = 284,
823    UnknownL3 = 285,
824    UnknownL3Exception = 286,
825    UnknownBuffer = 287,
826    UnknownTunnel = 288,
827    UnknownL4 = 289,
828    SipIsUnspecified = 290,
829    MlagPortIsolation = 291,
830    BlackholeArpNeigh = 292,
831    SrcMacIsDmac = 293,
832    DmacIsReserved = 294,
833    SipIsClassE = 295,
834    McDmacMismatch = 296,
835    SipIsDip = 297,
836    DipIsLocalNetwork = 298,
837    DipIsLinkLocal = 299,
838    OverlaySmacIsDmac = 300,
839    EgressVlanFilter = 301,
840    UcReversePathForwarding = 302,
841    SplitHorizon = 303,
842}
843
844impl DropReason {
845    /// Convert from u32 value to DropReason enum
846    ///
847    /// This is a mechanical mapping of u32 values to enum variants
848    /// defined in the sFlow specification. The function is tested
849    /// with representative samples rather than exhaustively.
850    pub fn from_u32(value: u32) -> Option<Self> {
851        match value {
852            0 => Some(DropReason::NetUnreachable),
853            1 => Some(DropReason::HostUnreachable),
854            2 => Some(DropReason::ProtocolUnreachable),
855            3 => Some(DropReason::PortUnreachable),
856            4 => Some(DropReason::FragNeeded),
857            5 => Some(DropReason::SrcRouteFailed),
858            6 => Some(DropReason::DstNetUnknown),
859            7 => Some(DropReason::DstHostUnknown),
860            8 => Some(DropReason::SrcHostIsolated),
861            9 => Some(DropReason::DstNetProhibited),
862            10 => Some(DropReason::DstHostProhibited),
863            11 => Some(DropReason::DstNetTosUnreachable),
864            12 => Some(DropReason::DstHostTosUnreachable),
865            13 => Some(DropReason::CommAdminProhibited),
866            14 => Some(DropReason::HostPrecedenceViolation),
867            15 => Some(DropReason::PrecedenceCutoff),
868            256 => Some(DropReason::Unknown),
869            257 => Some(DropReason::TtlExceeded),
870            258 => Some(DropReason::Acl),
871            259 => Some(DropReason::NoBufferSpace),
872            260 => Some(DropReason::Red),
873            261 => Some(DropReason::TrafficShaping),
874            262 => Some(DropReason::PktTooBig),
875            263 => Some(DropReason::SrcMacIsMulticast),
876            264 => Some(DropReason::VlanTagMismatch),
877            265 => Some(DropReason::IngressVlanFilter),
878            266 => Some(DropReason::IngressSpanningTreeFilter),
879            267 => Some(DropReason::PortListIsEmpty),
880            268 => Some(DropReason::PortLoopbackFilter),
881            269 => Some(DropReason::BlackholeRoute),
882            270 => Some(DropReason::NonIp),
883            271 => Some(DropReason::UcDipOverMcDmac),
884            272 => Some(DropReason::DipIsLoopbackAddress),
885            273 => Some(DropReason::SipIsMc),
886            274 => Some(DropReason::SipIsLoopbackAddress),
887            275 => Some(DropReason::IpHeaderCorrupted),
888            276 => Some(DropReason::Ipv4SipIsLimitedBc),
889            277 => Some(DropReason::Ipv6McDipReservedScope),
890            278 => Some(DropReason::Ipv6McDipInterfaceLocalScope),
891            279 => Some(DropReason::UnresolvedNeigh),
892            280 => Some(DropReason::McReversePathForwarding),
893            281 => Some(DropReason::NonRoutablePacket),
894            282 => Some(DropReason::DecapError),
895            283 => Some(DropReason::OverlaySmacIsMc),
896            284 => Some(DropReason::UnknownL2),
897            285 => Some(DropReason::UnknownL3),
898            286 => Some(DropReason::UnknownL3Exception),
899            287 => Some(DropReason::UnknownBuffer),
900            288 => Some(DropReason::UnknownTunnel),
901            289 => Some(DropReason::UnknownL4),
902            290 => Some(DropReason::SipIsUnspecified),
903            291 => Some(DropReason::MlagPortIsolation),
904            292 => Some(DropReason::BlackholeArpNeigh),
905            293 => Some(DropReason::SrcMacIsDmac),
906            294 => Some(DropReason::DmacIsReserved),
907            295 => Some(DropReason::SipIsClassE),
908            296 => Some(DropReason::McDmacMismatch),
909            297 => Some(DropReason::SipIsDip),
910            298 => Some(DropReason::DipIsLocalNetwork),
911            299 => Some(DropReason::DipIsLinkLocal),
912            300 => Some(DropReason::OverlaySmacIsDmac),
913            301 => Some(DropReason::EgressVlanFilter),
914            302 => Some(DropReason::UcReversePathForwarding),
915            303 => Some(DropReason::SplitHorizon),
916            _ => None,
917        }
918    }
919}
920
921/// Discarded packet sample - Format (0,5)
922///
923/// # XDR Definition ([sFlow Drops](https://sflow.org/sflow_drops.txt))
924///
925/// ```text
926/// /* Format of a single discarded packet event */
927/// /* opaque = sample_data; enterprise = 0; format = 5 */
928/// struct discarded_packet {
929///    unsigned int sequence_number;  /* Incremented with each discarded packet
930///                                      record generated by this source_id. */
931///    sflow_data_source_expanded source_id; /* sFlowDataSource */
932///    unsigned int drops;            /* Number of times that the sFlow agent
933///                                      detected that a discarded packet record
934///                                      was dropped by the rate limit, or because
935///                                      of a lack of resources. The drops counter
936///                                      reports the total number of drops detected
937///                                      since the agent was last reset. Note: An
938///                                      agent that cannot detect drops will always
939///                                      report zero. */
940///    unsigned int inputifindex;     /* If set, ifIndex of interface packet was
941///                                      received on. Zero if unknown. Must identify
942///                                      physical port consistent with flow_sample
943///                                      input interface. */
944///    unsigned int outputifindex;    /* If set, ifIndex for egress drops. Zero
945///                                      otherwise. Must identify physical port
946///                                      consistent with flow_sample output
947///                                      interface. */
948///    drop_reason reason;            /* Reason for dropping packet. */
949///    flow_record discard_records<>; /* Information about the discarded packet. */
950/// }
951/// ```
952#[derive(Debug, Clone, PartialEq, Eq)]
953#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
954pub struct DiscardedPacket {
955    /// Sequence number incremented with each discarded packet record
956    pub sequence_number: u32,
957
958    /// sFlow data source
959    pub source_id: DataSourceExpanded,
960
961    /// Number of discarded packet records dropped by rate limit or lack of resources
962    pub drops: u32,
963
964    /// Input interface index (0 if unknown)
965    pub input_ifindex: u32,
966
967    /// Output interface index (0 if not egress drop)
968    pub output_ifindex: u32,
969
970    /// Reason for dropping the packet
971    pub reason: DropReason,
972
973    /// Flow records describing the discarded packet
974    pub flow_records: Vec<FlowRecord>,
975}
976
977/// Sample data types
978#[derive(Debug, Clone, PartialEq)]
979#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
980pub enum SampleData {
981    FlowSample(FlowSample),
982    CountersSample(CountersSample),
983    FlowSampleExpanded(FlowSampleExpanded),
984    CountersSampleExpanded(CountersSampleExpanded),
985    DiscardedPacket(DiscardedPacket),
986    /// sFlow-RT Custom Metrics - Format (4300,1002)
987    /// Opaque data - structure defined at runtime via sFlow-RT API
988    RtMetric {
989        format: DataFormat,
990        data: Vec<u8>,
991    },
992    /// sFlow-RT Custom Flow Metrics - Format (4300,1003)
993    /// Opaque data - structure defined at runtime via sFlow-RT API
994    RtFlow {
995        format: DataFormat,
996        data: Vec<u8>,
997    },
998    Unknown {
999        format: DataFormat,
1000        data: Vec<u8>,
1001    },
1002}
1003
1004/// Sample record
1005#[derive(Debug, Clone, PartialEq)]
1006#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1007pub struct SampleRecord {
1008    pub sample_type: DataFormat,
1009    pub sample_data: SampleData,
1010}
1011
1012/// sFlow v5 datagram
1013///
1014/// Top-level structure containing one or more samples.
1015///
1016/// # XDR Definition ([sFlow v5](https://sflow.org/sflow_version_5.txt))
1017///
1018/// ```text
1019/// /* sFlow version 5 datagram */
1020///
1021/// struct sflow_datagram {
1022///    unsigned int version;        /* sFlow version (5) */
1023///    address agent_address;       /* IP address of sampling agent */
1024///    unsigned int sub_agent_id;   /* Used to distinguish multiple sFlow instances
1025///                                    on the same agent */
1026///    unsigned int sequence_number;/* Incremented with each sample datagram generated
1027///                                    by a sub-agent within an agent */
1028///    unsigned int uptime;         /* Current time (in milliseconds since device
1029///                                    last booted). Should be set as close to
1030///                                    datagram transmission time as possible. */
1031///    sample_record samples<>;     /* An array of sample records */
1032/// }
1033/// ```
1034#[derive(Debug, Clone, PartialEq)]
1035#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
1036pub struct SFlowDatagram {
1037    /// sFlow protocol version (always 5)
1038    pub version: DatagramVersion,
1039    /// IP address of the sFlow agent
1040    pub agent_address: Address,
1041    /// Sub-agent identifier (distinguishes multiple sFlow instances on same agent)
1042    pub sub_agent_id: u32,
1043    /// Datagram sequence number (incremented with each datagram from this sub-agent)
1044    pub sequence_number: u32,
1045    /// Device uptime in milliseconds since last boot
1046    pub uptime: u32,
1047    /// Array of sample records
1048    pub samples: Vec<SampleRecord>,
1049}
1050
1051impl SFlowDatagram {
1052    /// Create a new sFlow v5 datagram
1053    pub fn new(
1054        agent_address: Address,
1055        sub_agent_id: u32,
1056        sequence_number: u32,
1057        uptime: u32,
1058    ) -> Self {
1059        Self {
1060            version: DatagramVersion::Version5,
1061            agent_address,
1062            sub_agent_id,
1063            sequence_number,
1064            uptime,
1065            samples: Vec::new(),
1066        }
1067    }
1068}