1use 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 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 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}