netlink_tc/qdiscs/
fq_codel.rs1use serde::{Deserialize, Serialize};
2
3use crate::{errors::TcError, TcOption};
4
5#[derive(Clone, Debug, Default, PartialEq)]
7pub struct FqCodel {
8 pub target: u32,
9 pub limit: u32,
10 pub interval: u32,
11 pub ecn: u32,
12 pub flows: u32,
13 pub quantum: u32,
14 pub ce_threshold: u32,
15 pub drop_batch_size: u32,
16 pub memory_limit: u32,
17}
18
19impl FqCodel {
20 pub fn new(opts: Vec<TcOption>) -> Self {
21 unmarshal_fq_codel(opts)
22 }
23}
24
25#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
27pub struct FqCodelXStats {
28 pub maxpacket: u32,
29 pub drop_overlimit: u32,
30 pub ecn_mark: u32,
31 pub new_flow_count: u32,
32 pub new_flows_len: u32,
33 pub old_flows_len: u32,
34 pub ce_mark: u32,
35 pub memory_usage: u32,
36 pub drop_overmemory: u32,
37}
38
39impl FqCodelXStats {
40 pub fn new(bytes: &[u8]) -> Result<Self, TcError> {
41 unmarshal_fq_codel_xstats(bytes)
42 }
43}
44
45#[derive(Debug, Default, PartialEq, Eq, Clone)]
46pub enum TcaFqCodel {
47 #[default]
48 Unspec = 0,
49 Target,
50 Limit,
51 Interval,
52 Ecn,
53 Flows,
54 Quantum,
55 CeThreshold,
56 DropBatchSize,
57 MemoryLimit,
58 Max,
59}
60
61impl From<u16> for TcaFqCodel {
62 fn from(v: u16) -> Self {
63 match v {
64 0 => TcaFqCodel::Unspec,
65 1 => TcaFqCodel::Target,
66 2 => TcaFqCodel::Limit,
67 3 => TcaFqCodel::Interval,
68 4 => TcaFqCodel::Ecn,
69 5 => TcaFqCodel::Flows,
70 6 => TcaFqCodel::Quantum,
71 7 => TcaFqCodel::CeThreshold,
72 8 => TcaFqCodel::DropBatchSize,
73 9 => TcaFqCodel::MemoryLimit,
74 _ => TcaFqCodel::Max,
75 }
76 }
77}
78
79fn unmarshal_fq_codel(opts: Vec<TcOption>) -> FqCodel {
80 let mut fq = FqCodel::default();
81
82 for opt in opts {
83 let kind = TcaFqCodel::from(opt.kind);
84 if opt.bytes.len() < 4 {
85 continue;
87 }
88 let value = u32::from_ne_bytes(opt.bytes[..4].try_into().unwrap());
89 match kind {
90 TcaFqCodel::Target => fq.target = value,
91 TcaFqCodel::Limit => fq.limit = value,
92 TcaFqCodel::Interval => fq.interval = value,
93 TcaFqCodel::Ecn => fq.ecn = value,
94 TcaFqCodel::Flows => fq.flows = value,
95 TcaFqCodel::Quantum => fq.quantum = value,
96 TcaFqCodel::CeThreshold => fq.ce_threshold = value,
97 TcaFqCodel::DropBatchSize => fq.drop_batch_size = value,
98 TcaFqCodel::MemoryLimit => fq.memory_limit = value,
99 _ => (),
100 }
101 }
102
103 fq
104}
105
106fn unmarshal_fq_codel_xstats(bytes: &[u8]) -> Result<FqCodelXStats, TcError> {
107 if bytes.len() < 40 {
108 return Err(TcError::InvalidAttribute(
109 "FqCodel XStats requires 40 bytes".to_string(),
110 ));
111 }
112 let buf: [u8; 4] = bytes[..4]
113 .try_into()
114 .map_err(|_| TcError::Decode("Failed to extract FqCodel XStats kind".to_string()))?;
115 let kind = u32::from_ne_bytes(buf);
116 if kind == 0 {
117 bincode::deserialize(&bytes[4..]).map_err(TcError::UnmarshalStruct)
118 } else {
119 Err(TcError::InvalidAttribute(format!(
120 "FqCodel XStats has unidentified kind: {kind}"
121 )))
122 }
123}