netlink_packet_route/tc/qdiscs/
fq_codel.rs

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