netlink_packet_route/tc/qdiscs/
fq_codel.rs1use netlink_packet_core::{
4 emit_u32, parse_u32, parse_u8, DecodeError, DefaultNla, Emitable,
5 ErrorContext, Nla, NlaBuffer, Parseable,
6};
7
8#[derive(Debug, PartialEq, Eq, Clone)]
9#[non_exhaustive]
10pub struct TcQdiscFqCodel {}
11
12impl TcQdiscFqCodel {
13 pub(crate) const KIND: &'static str = "fq_codel";
14}
15
16const TC_FQ_CODEL_QD_STATS_LEN: usize = 36;
17const TC_FQ_CODEL_CL_STATS_LEN: usize = 24;
18
19const TCA_FQ_CODEL_XSTATS_QDISC: u32 = 0;
20const TCA_FQ_CODEL_XSTATS_CLASS: u32 = 1;
21
22#[derive(Debug, PartialEq, Eq, Clone)]
23#[non_exhaustive]
24pub enum TcFqCodelXstats {
25 Qdisc(TcFqCodelQdStats),
26 Class(TcFqCodelClStats),
27 Other(Vec<u8>),
28}
29
30impl<T: AsRef<[u8]> + ?Sized> Parseable<T> for TcFqCodelXstats {
31 fn parse(buf: &T) -> Result<Self, DecodeError> {
32 if buf.as_ref().len() < 4 {
33 return Err(DecodeError::from(format!(
34 "Invalid TcFqCodelXstats {:?}",
35 buf.as_ref()
36 )));
37 }
38 let mut buf_type_bytes = [0; 4];
39 buf_type_bytes.copy_from_slice(&buf.as_ref()[0..4]);
40
41 let buf_type = u32::from_ne_bytes(buf_type_bytes);
42
43 match buf_type {
44 TCA_FQ_CODEL_XSTATS_QDISC => {
45 Ok(Self::Qdisc(TcFqCodelQdStats::parse(
46 &TcFqCodelQdStatsBuffer::new(&buf.as_ref()[4..]),
47 )?))
48 }
49 TCA_FQ_CODEL_XSTATS_CLASS => {
50 Ok(Self::Class(TcFqCodelClStats::parse(
51 &TcFqCodelClStatsBuffer::new(&buf.as_ref()[4..]),
52 )?))
53 }
54 _ => Ok(Self::Other(buf.as_ref().to_vec())),
55 }
56 }
57}
58
59impl Emitable for TcFqCodelXstats {
60 fn buffer_len(&self) -> usize {
61 match self {
62 Self::Qdisc(_) => {
63 TC_FQ_CODEL_QD_STATS_LEN + std::mem::size_of::<u32>()
64 }
65 Self::Class(_) => {
66 TC_FQ_CODEL_CL_STATS_LEN + std::mem::size_of::<u32>()
67 }
68 Self::Other(v) => v.len(),
69 }
70 }
71
72 fn emit(&self, buffer: &mut [u8]) {
73 match self {
74 Self::Qdisc(v) => {
75 buffer[0..4]
76 .copy_from_slice(&TCA_FQ_CODEL_XSTATS_QDISC.to_ne_bytes());
77 v.emit(&mut buffer[4..]);
78 }
79 Self::Class(v) => {
80 buffer[0..4]
81 .copy_from_slice(&TCA_FQ_CODEL_XSTATS_CLASS.to_ne_bytes());
82 v.emit(&mut buffer[4..]);
83 }
84 Self::Other(v) => buffer.copy_from_slice(v.as_slice()),
85 }
86 }
87}
88
89#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
90#[non_exhaustive]
91pub struct TcFqCodelQdStats {
92 pub maxpacket: u32,
93 pub drop_overlimit: u32,
94 pub ecn_mark: u32,
95 pub new_flow_count: u32,
96 pub new_flows_len: u32,
97 pub old_flows_len: u32,
98 pub ce_mark: u32,
99 pub memory_usage: u32,
100 pub drop_overmemory: u32,
101}
102
103buffer!(TcFqCodelQdStatsBuffer(TC_FQ_CODEL_QD_STATS_LEN) {
104 maxpacket: (u32, 0..4),
105 drop_overlimit: (u32, 4..8),
106 ecn_mark: (u32, 8..12),
107 new_flow_count: (u32, 12..16),
108 new_flows_len: (u32, 16..20),
109 old_flows_len: (u32, 20..24),
110 ce_mark: (u32, 24..28),
111 memory_usage: (u32, 28..32),
112 drop_overmemory: (u32,32..36),
113});
114
115impl<T: AsRef<[u8]>> Parseable<TcFqCodelQdStatsBuffer<T>> for TcFqCodelQdStats {
116 fn parse(buf: &TcFqCodelQdStatsBuffer<T>) -> Result<Self, DecodeError> {
117 Ok(Self {
118 maxpacket: buf.maxpacket(),
119 drop_overlimit: buf.drop_overlimit(),
120 ecn_mark: buf.ecn_mark(),
121 new_flow_count: buf.new_flow_count(),
122 new_flows_len: buf.new_flows_len(),
123 old_flows_len: buf.old_flows_len(),
124 ce_mark: buf.ce_mark(),
125 memory_usage: buf.memory_usage(),
126 drop_overmemory: buf.drop_overmemory(),
127 })
128 }
129}
130
131impl Emitable for TcFqCodelQdStats {
132 fn buffer_len(&self) -> usize {
133 TC_FQ_CODEL_QD_STATS_LEN + std::mem::size_of::<u32>()
134 }
135
136 fn emit(&self, buffer: &mut [u8]) {
137 let mut buffer = TcFqCodelQdStatsBuffer::new(buffer);
138 buffer.set_maxpacket(self.maxpacket);
139 buffer.set_drop_overlimit(self.drop_overlimit);
140 buffer.set_ecn_mark(self.ecn_mark);
141 buffer.set_new_flow_count(self.new_flow_count);
142 buffer.set_new_flows_len(self.new_flows_len);
143 buffer.set_old_flows_len(self.old_flows_len);
144 buffer.set_ce_mark(self.ce_mark);
145 buffer.set_memory_usage(self.memory_usage);
146 buffer.set_drop_overmemory(self.drop_overmemory);
147 }
148}
149
150#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
151#[non_exhaustive]
152pub struct TcFqCodelClStats {
153 deficit: i32,
154 ldelay: u32,
155 count: u32,
156 lastcount: u32,
157 dropping: u32,
158 drop_next: i32,
159}
160
161buffer!(TcFqCodelClStatsBuffer(TC_FQ_CODEL_CL_STATS_LEN) {
162 deficit: (i32, 0..4),
163 ldelay: (u32,4..8),
164 count: (u32, 8..12),
165 lastcount: (u32, 12..16),
166 dropping: (u32, 16..20),
167 drop_next: (i32, 20..24),
168});
169
170impl<T: AsRef<[u8]>> Parseable<TcFqCodelClStatsBuffer<T>> for TcFqCodelClStats {
171 fn parse(buf: &TcFqCodelClStatsBuffer<T>) -> Result<Self, DecodeError> {
172 Ok(Self {
173 deficit: buf.deficit(),
174 ldelay: buf.ldelay(),
175 count: buf.count(),
176 lastcount: buf.lastcount(),
177 dropping: buf.dropping(),
178 drop_next: buf.drop_next(),
179 })
180 }
181}
182
183impl Emitable for TcFqCodelClStats {
184 fn buffer_len(&self) -> usize {
185 TC_FQ_CODEL_CL_STATS_LEN + std::mem::size_of::<u32>()
186 }
187
188 fn emit(&self, buffer: &mut [u8]) {
189 let mut buffer = TcFqCodelClStatsBuffer::new(buffer);
190 buffer.set_deficit(self.deficit);
191 buffer.set_ldelay(self.ldelay);
192 buffer.set_count(self.count);
193 buffer.set_lastcount(self.lastcount);
194 buffer.set_dropping(self.dropping);
195 buffer.set_drop_next(self.drop_next);
196 }
197}
198
199const TCA_FQ_CODEL_TARGET: u16 = 1;
200const TCA_FQ_CODEL_LIMIT: u16 = 2;
201const TCA_FQ_CODEL_INTERVAL: u16 = 3;
202const TCA_FQ_CODEL_ECN: u16 = 4;
203const TCA_FQ_CODEL_FLOWS: u16 = 5;
204const TCA_FQ_CODEL_QUANTUM: u16 = 6;
205const TCA_FQ_CODEL_CE_THRESHOLD: u16 = 7;
206const TCA_FQ_CODEL_DROP_BATCH_SIZE: u16 = 8;
207const TCA_FQ_CODEL_MEMORY_LIMIT: u16 = 9;
208const TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR: u16 = 10;
209const TCA_FQ_CODEL_CE_THRESHOLD_MASK: u16 = 11;
210
211#[derive(Debug, PartialEq, Eq, Clone)]
212#[non_exhaustive]
213pub enum TcQdiscFqCodelOption {
214 Target(u32),
215 Limit(u32),
216 Interval(u32),
217 Ecn(u32),
218 Flows(u32),
219 Quantum(u32),
220 CeThreshold(u32),
221 DropBatchSize(u32),
222 MemoryLimit(u32),
223 CeThresholdSelector(u8),
224 CeThresholdMask(u8),
225 Other(DefaultNla),
226}
227
228impl Nla for TcQdiscFqCodelOption {
229 fn value_len(&self) -> usize {
230 match self {
231 Self::Target(_)
232 | Self::Limit(_)
233 | Self::Interval(_)
234 | Self::Ecn(_)
235 | Self::Flows(_)
236 | Self::Quantum(_)
237 | Self::CeThreshold(_)
238 | Self::DropBatchSize(_)
239 | Self::MemoryLimit(_) => 4,
240 Self::CeThresholdSelector(_) | Self::CeThresholdMask(_) => 1,
241 Self::Other(attr) => attr.value_len(),
242 }
243 }
244
245 fn emit_value(&self, buffer: &mut [u8]) {
246 match self {
247 Self::Target(d)
248 | Self::Limit(d)
249 | Self::Interval(d)
250 | Self::Ecn(d)
251 | Self::Flows(d)
252 | Self::Quantum(d)
253 | Self::CeThreshold(d)
254 | Self::DropBatchSize(d)
255 | Self::MemoryLimit(d) => emit_u32(buffer, *d).unwrap(),
256 Self::CeThresholdSelector(d) | Self::CeThresholdMask(d) => {
257 buffer[0] = *d
258 }
259 Self::Other(attr) => attr.emit_value(buffer),
260 }
261 }
262
263 fn kind(&self) -> u16 {
264 match self {
265 Self::Target(_) => TCA_FQ_CODEL_TARGET,
266 Self::Limit(_) => TCA_FQ_CODEL_LIMIT,
267 Self::Interval(_) => TCA_FQ_CODEL_INTERVAL,
268 Self::Ecn(_) => TCA_FQ_CODEL_ECN,
269 Self::Flows(_) => TCA_FQ_CODEL_FLOWS,
270 Self::Quantum(_) => TCA_FQ_CODEL_QUANTUM,
271 Self::CeThreshold(_) => TCA_FQ_CODEL_CE_THRESHOLD,
272 Self::DropBatchSize(_) => TCA_FQ_CODEL_DROP_BATCH_SIZE,
273 Self::MemoryLimit(_) => TCA_FQ_CODEL_MEMORY_LIMIT,
274 Self::CeThresholdSelector(_) => TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR,
275 Self::CeThresholdMask(_) => TCA_FQ_CODEL_CE_THRESHOLD_MASK,
276 Self::Other(attr) => attr.kind(),
277 }
278 }
279}
280
281impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
282 for TcQdiscFqCodelOption
283{
284 fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
285 let payload = buf.value();
286 Ok(match buf.kind() {
287 TCA_FQ_CODEL_TARGET => Self::Target(
288 parse_u32(payload)
289 .context("failed to parse TCA_FQ_CODEL_TARGET")?,
290 ),
291 TCA_FQ_CODEL_LIMIT => Self::Limit(
292 parse_u32(payload)
293 .context("failed to parse TCA_FQ_CODEL_LIMIT")?,
294 ),
295 TCA_FQ_CODEL_INTERVAL => Self::Interval(
296 parse_u32(payload)
297 .context("failed to parse TCA_FQ_CODEL_INTERVAL")?,
298 ),
299 TCA_FQ_CODEL_ECN => Self::Ecn(
300 parse_u32(payload)
301 .context("failed to parse TCA_FQ_CODEL_ECN")?,
302 ),
303 TCA_FQ_CODEL_FLOWS => Self::Flows(
304 parse_u32(payload)
305 .context("failed to parse TCA_FQ_CODEL_FLOWS")?,
306 ),
307 TCA_FQ_CODEL_QUANTUM => Self::Quantum(
308 parse_u32(payload)
309 .context("failed to parse TCA_FQ_CODEL_QUANTUM")?,
310 ),
311 TCA_FQ_CODEL_CE_THRESHOLD => Self::CeThreshold(
312 parse_u32(payload)
313 .context("failed to parse TCA_FQ_CODEL_CETHRESHOLD")?,
314 ),
315 TCA_FQ_CODEL_DROP_BATCH_SIZE => Self::DropBatchSize(
316 parse_u32(payload)
317 .context("failed to parse TCA_FQ_CODEL_DROP_BATCH_SIZE")?,
318 ),
319 TCA_FQ_CODEL_MEMORY_LIMIT => Self::MemoryLimit(
320 parse_u32(payload)
321 .context("failed to parse TCA_FQ_CODEL_MEMORY_LIMIT")?,
322 ),
323 TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR => {
324 Self::CeThresholdSelector(parse_u8(payload).context(
325 "failed to parse TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR",
326 )?)
327 }
328 TCA_FQ_CODEL_CE_THRESHOLD_MASK => {
329 Self::CeThresholdMask(parse_u8(payload).context(
330 "failed to parse TCA_FQ_CODEL_CE_THRESHOLD_MASK",
331 )?)
332 }
333 _ => Self::Other(
334 DefaultNla::parse(buf).context("failed to parse u32 nla")?,
335 ),
336 })
337 }
338}