1use crate::afpacket::ffi;
4
5pub mod bpf;
6pub mod bpf_builder;
7pub(crate) mod bpf_compile;
8pub(crate) mod bpf_humanize;
9pub mod bpf_interp;
10pub mod busy_poll;
11pub mod ipnet;
12
13pub use bpf::{BpfFilter, BpfInsn, BuildError};
14pub use bpf_builder::BpfFilterBuilder;
15pub use busy_poll::BusyPollConfig;
16pub use ipnet::{IpNet, ParseIpNetError};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum FanoutMode {
21 Hash,
23 LoadBalance,
25 Cpu,
27 Rollover,
29 Random,
31 QueueMapping,
33 Ebpf,
40}
41
42impl FanoutMode {
43 pub(crate) const fn as_raw(self) -> u32 {
45 match self {
46 Self::Hash => ffi::PACKET_FANOUT_HASH,
47 Self::LoadBalance => ffi::PACKET_FANOUT_LB,
48 Self::Cpu => ffi::PACKET_FANOUT_CPU,
49 Self::Rollover => ffi::PACKET_FANOUT_ROLLOVER,
50 Self::Random => ffi::PACKET_FANOUT_RND,
51 Self::QueueMapping => ffi::PACKET_FANOUT_QM,
52 Self::Ebpf => ffi::PACKET_FANOUT_EBPF,
53 }
54 }
55}
56
57bitflags::bitflags! {
58 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
60 pub struct FanoutFlags: u16 {
61 const ROLLOVER = 0x1000;
63 const UNIQUE_ID = 0x2000;
65 const IGNORE_OUTGOING = 0x4000;
67 const DEFRAG = 0x8000;
69 }
70}
71
72#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
74pub enum TimestampSource {
75 #[default]
77 Software,
78 RawHardware,
80 SysHardware,
82}
83
84impl TimestampSource {
85 pub(crate) const fn as_raw(self) -> libc::c_int {
87 match self {
88 Self::Software => 0,
89 Self::RawHardware => 1,
90 Self::SysHardware => 2,
91 }
92 }
93}
94
95#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
115pub enum RingProfile {
116 Default,
119
120 HighThroughput,
123
124 LowLatency,
127
128 LowMemory,
131
132 JumboFrames,
135}
136
137impl RingProfile {
138 #[inline]
140 pub(crate) fn params(self) -> (usize, usize, usize, u32) {
141 match self {
142 Self::Default => (1 << 22, 64, 2048, 60),
143 Self::HighThroughput => (1 << 22, 256, 2048, 60),
144 Self::LowLatency => (1 << 18, 64, 2048, 1),
145 Self::LowMemory => (1 << 20, 16, 2048, 100),
146 Self::JumboFrames => (1 << 22, 64, 65536, 60),
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 #[test]
156 fn fanout_mode_as_raw() {
157 assert_eq!(FanoutMode::Hash.as_raw(), 0);
158 assert_eq!(FanoutMode::LoadBalance.as_raw(), 1);
159 assert_eq!(FanoutMode::Cpu.as_raw(), 2);
160 assert_eq!(FanoutMode::Rollover.as_raw(), 3);
161 assert_eq!(FanoutMode::Random.as_raw(), 4);
162 assert_eq!(FanoutMode::QueueMapping.as_raw(), 5);
163 }
164
165 #[test]
166 fn fanout_flags_bitwise() {
167 let flags = FanoutFlags::ROLLOVER | FanoutFlags::DEFRAG;
168 assert_eq!(flags.bits(), 0x9000);
169 assert!(flags.contains(FanoutFlags::ROLLOVER));
170 assert!(flags.contains(FanoutFlags::DEFRAG));
171 assert!(!flags.contains(FanoutFlags::UNIQUE_ID));
172 }
173
174 #[test]
175 fn timestamp_source_default() {
176 assert_eq!(TimestampSource::default(), TimestampSource::Software);
177 assert_eq!(TimestampSource::Software.as_raw(), 0);
178 }
179
180 #[test]
181 fn ring_profile_params_valid() {
182 for profile in [
183 RingProfile::Default,
184 RingProfile::HighThroughput,
185 RingProfile::LowLatency,
186 RingProfile::LowMemory,
187 RingProfile::JumboFrames,
188 ] {
189 let (block_size, block_count, frame_size, timeout_ms) = profile.params();
190 assert!(block_size.is_power_of_two(), "{profile:?} block_size");
191 assert!(block_size.is_multiple_of(4096), "{profile:?} page-aligned");
192 assert!(block_count > 0, "{profile:?} block_count");
193 assert!(
194 frame_size >= 68,
195 "{profile:?} frame_size >= TPACKET3_HDRLEN"
196 );
197 assert!(
198 frame_size.is_multiple_of(16),
199 "{profile:?} frame_size aligned"
200 );
201 assert!(
202 frame_size <= block_size,
203 "{profile:?} frame_size <= block_size"
204 );
205 let _ = timeout_ms;
206 }
207 }
208}