netlink_packet_route/tc/qdiscs/
fq_codel.rs

1// SPDX-License-Identifier: MIT
2
3use 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}