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::nla::{DefaultNla, Nla, NlaBuffer};
6use netlink_packet_utils::parsers::{parse_u32, parse_u8};
7use netlink_packet_utils::traits::{Emitable, Parseable};
8use netlink_packet_utils::DecodeError;
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(&TcFqCodelQdStatsBuffer::new(&buf.as_ref()[4..]))
48                        .unwrap(),
49                ))
50            }
51            TCA_FQ_CODEL_XSTATS_CLASS => {
52                // unwrap: we never fail below to parse TcFqCodelQdStats.
53                Ok(Self::Class(
54                    TcFqCodelClStats::parse(&TcFqCodelClStatsBuffer::new(&buf.as_ref()[4..]))
55                        .unwrap(),
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(_) => TC_FQ_CODEL_QD_STATS_LEN + std::mem::size_of::<u32>(),
67            Self::Class(_) => TC_FQ_CODEL_CL_STATS_LEN + std::mem::size_of::<u32>(),
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].copy_from_slice(&TCA_FQ_CODEL_XSTATS_QDISC.to_ne_bytes());
76                v.emit(&mut buffer[4..]);
77            }
78            Self::Class(v) => {
79                buffer[0..4].copy_from_slice(&TCA_FQ_CODEL_XSTATS_CLASS.to_ne_bytes());
80                v.emit(&mut buffer[4..]);
81            }
82            Self::Other(v) => buffer.copy_from_slice(v.as_slice()),
83        }
84    }
85}
86
87#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
88#[non_exhaustive]
89pub struct TcFqCodelQdStats {
90    pub maxpacket: u32,
91    pub drop_overlimit: u32,
92    pub ecn_mark: u32,
93    pub new_flow_count: u32,
94    pub new_flows_len: u32,
95    pub old_flows_len: u32,
96    pub ce_mark: u32,
97    pub memory_usage: u32,
98    pub drop_overmemory: u32,
99}
100
101buffer!(TcFqCodelQdStatsBuffer(TC_FQ_CODEL_QD_STATS_LEN) {
102    maxpacket: (u32, 0..4),
103    drop_overlimit: (u32, 4..8),
104    ecn_mark: (u32, 8..12),
105    new_flow_count: (u32, 12..16),
106    new_flows_len: (u32, 16..20),
107    old_flows_len: (u32, 20..24),
108    ce_mark: (u32, 24..28),
109    memory_usage: (u32, 28..32),
110    drop_overmemory: (u32,32..36),
111});
112
113impl<T: AsRef<[u8]>> Parseable<TcFqCodelQdStatsBuffer<T>> for TcFqCodelQdStats {
114    type Error = ();
115    fn parse(buf: &TcFqCodelQdStatsBuffer<T>) -> Result<Self, ()> {
116        Ok(Self {
117            maxpacket: buf.maxpacket(),
118            drop_overlimit: buf.drop_overlimit(),
119            ecn_mark: buf.ecn_mark(),
120            new_flow_count: buf.new_flow_count(),
121            new_flows_len: buf.new_flows_len(),
122            old_flows_len: buf.old_flows_len(),
123            ce_mark: buf.ce_mark(),
124            memory_usage: buf.memory_usage(),
125            drop_overmemory: buf.drop_overmemory(),
126        })
127    }
128}
129
130impl Emitable for TcFqCodelQdStats {
131    fn buffer_len(&self) -> usize {
132        TC_FQ_CODEL_QD_STATS_LEN + std::mem::size_of::<u32>()
133    }
134
135    fn emit(&self, buffer: &mut [u8]) {
136        let mut buffer = TcFqCodelQdStatsBuffer::new(buffer);
137        buffer.set_maxpacket(self.maxpacket);
138        buffer.set_drop_overlimit(self.drop_overlimit);
139        buffer.set_ecn_mark(self.ecn_mark);
140        buffer.set_new_flow_count(self.new_flow_count);
141        buffer.set_new_flows_len(self.new_flows_len);
142        buffer.set_old_flows_len(self.old_flows_len);
143        buffer.set_ce_mark(self.ce_mark);
144        buffer.set_memory_usage(self.memory_usage);
145        buffer.set_drop_overmemory(self.drop_overmemory);
146    }
147}
148
149#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
150#[non_exhaustive]
151pub struct TcFqCodelClStats {
152    deficit: i32,
153    ldelay: u32,
154    count: u32,
155    lastcount: u32,
156    dropping: u32,
157    drop_next: i32,
158}
159
160buffer!(TcFqCodelClStatsBuffer(TC_FQ_CODEL_CL_STATS_LEN) {
161    deficit: (i32, 0..4),
162    ldelay: (u32,4..8),
163    count: (u32, 8..12),
164    lastcount: (u32, 12..16),
165    dropping: (u32, 16..20),
166    drop_next: (i32, 20..24),
167});
168
169impl<T: AsRef<[u8]>> Parseable<TcFqCodelClStatsBuffer<T>> for TcFqCodelClStats {
170    type Error = DecodeError;
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) => NativeEndian::write_u32(buffer, *d),
256            Self::CeThresholdSelector(d) | Self::CeThresholdMask(d) => buffer[0] = *d,
257            Self::Other(attr) => attr.emit_value(buffer),
258        }
259    }
260
261    fn kind(&self) -> u16 {
262        match self {
263            Self::Target(_) => TCA_FQ_CODEL_TARGET,
264            Self::Limit(_) => TCA_FQ_CODEL_LIMIT,
265            Self::Interval(_) => TCA_FQ_CODEL_INTERVAL,
266            Self::Ecn(_) => TCA_FQ_CODEL_ECN,
267            Self::Flows(_) => TCA_FQ_CODEL_FLOWS,
268            Self::Quantum(_) => TCA_FQ_CODEL_QUANTUM,
269            Self::CeThreshold(_) => TCA_FQ_CODEL_CE_THRESHOLD,
270            Self::DropBatchSize(_) => TCA_FQ_CODEL_DROP_BATCH_SIZE,
271            Self::MemoryLimit(_) => TCA_FQ_CODEL_MEMORY_LIMIT,
272            Self::CeThresholdSelector(_) => TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR,
273            Self::CeThresholdMask(_) => TCA_FQ_CODEL_CE_THRESHOLD_MASK,
274            Self::Other(attr) => attr.kind(),
275        }
276    }
277}
278
279impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for TcQdiscFqCodelOption {
280    type Error = TcError;
281    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, TcError> {
282        let payload = buf.value();
283        Ok(match buf.kind() {
284            TCA_FQ_CODEL_TARGET => {
285                Self::Target(parse_u32(payload).map_err(|error| TcError::InvalidValue {
286                    kind: "TCA_FQ_CODEL_TARGET",
287                    error,
288                })?)
289            }
290            TCA_FQ_CODEL_LIMIT => Self::Limit(
291                parse_u32(payload)
292                    .map_err(|error| TcError::InvalidValue { kind: "TCA_FQ_CODEL_LIMIT", error })?,
293            ),
294            TCA_FQ_CODEL_INTERVAL => {
295                Self::Interval(parse_u32(payload).map_err(|error| TcError::InvalidValue {
296                    kind: "TCA_FQ_CODEL_INTERVAL",
297                    error,
298                })?)
299            }
300            TCA_FQ_CODEL_ECN => Self::Ecn(
301                parse_u32(payload)
302                    .map_err(|error| TcError::InvalidValue { kind: "TCA_FQ_CODEL_ECN", error })?,
303            ),
304            TCA_FQ_CODEL_FLOWS => Self::Flows(
305                parse_u32(payload)
306                    .map_err(|error| TcError::InvalidValue { kind: "TCA_FQ_CODEL_FLOWS", error })?,
307            ),
308            TCA_FQ_CODEL_QUANTUM => {
309                Self::Quantum(parse_u32(payload).map_err(|error| TcError::InvalidValue {
310                    kind: "TCA_FQ_CODEL_QUANTUM",
311                    error,
312                })?)
313            }
314            TCA_FQ_CODEL_CE_THRESHOLD => {
315                Self::CeThreshold(parse_u32(payload).map_err(|error| TcError::InvalidValue {
316                    kind: "TCA_FQ_CODEL_CE_THRESHOLD",
317                    error,
318                })?)
319            }
320            TCA_FQ_CODEL_DROP_BATCH_SIZE => {
321                Self::DropBatchSize(parse_u32(payload).map_err(|error| TcError::InvalidValue {
322                    kind: "TCA_FQ_CODEL_DROP_BATCH_SIZE",
323                    error,
324                })?)
325            }
326            TCA_FQ_CODEL_MEMORY_LIMIT => {
327                Self::MemoryLimit(parse_u32(payload).map_err(|error| TcError::InvalidValue {
328                    kind: "TCA_FQ_CODEL_MEMORY_LIMIT",
329                    error,
330                })?)
331            }
332            TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR => {
333                Self::CeThresholdSelector(parse_u8(payload).map_err(|error| {
334                    TcError::InvalidValue { kind: "TCA_FQ_CODEL_CE_THRESHOLD_SELECTOR", error }
335                })?)
336            }
337            TCA_FQ_CODEL_CE_THRESHOLD_MASK => {
338                Self::CeThresholdMask(parse_u8(payload).map_err(|error| TcError::InvalidValue {
339                    kind: "TCA_FQ_CODEL_CE_THRESHOLD_MASK",
340                    error,
341                })?)
342            }
343            kind => Self::Other(
344                DefaultNla::parse(buf).map_err(|error| TcError::UnknownNla { kind, error })?,
345            ),
346        })
347    }
348}