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