netlink_packet_route/tc/qdiscs/
fq_codel.rs

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