1use netlink_packet_route::tc;
16use netlink_packet_route::tc::TcAttribute;
17use netlink_packet_route::tc::TcFqCodelXstats;
18use netlink_packet_route::tc::TcMessage;
19use netlink_packet_route::tc::TcOption;
20use netlink_packet_route::tc::TcQdiscFqCodelOption;
21use serde::Deserialize;
22use serde::Serialize;
23
24const FQ_CODEL: &str = "fq_codel";
25
26#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
28pub struct TcStat {
29 pub if_index: u32,
31 pub if_name: String,
33 pub handle: u32,
35 pub parent: u32,
37 pub kind: String,
39 pub stats: Stats,
41 pub qdisc: Option<QDisc>,
43}
44
45impl TcStat {
46 pub fn new(if_name: String, tc_msg: &TcMessage) -> Self {
47 let if_index = tc_msg.header.index as u32;
48 let mut tc = Self {
49 if_index,
50 if_name,
51 handle: tc_msg.header.handle.into(),
52 parent: tc_msg.header.parent.into(),
53 ..Default::default()
54 };
55 let mut opts = Vec::new();
56
57 for attr in &tc_msg.attributes {
58 match attr {
59 TcAttribute::Kind(name) => tc.kind.clone_from(name),
60 TcAttribute::Options(tc_opts) => opts = tc_opts.to_vec(),
61 TcAttribute::Stats(tc_stats) => {
62 tc.stats.bps = Some(tc_stats.bps);
63 tc.stats.pps = Some(tc_stats.pps);
64 }
65 TcAttribute::Stats2(tc_stats) => {
66 for stat in tc_stats {
67 match stat {
68 tc::TcStats2::Basic(basic) => {
69 tc.stats.bytes = Some(basic.bytes);
70 tc.stats.packets = Some(basic.packets);
71 }
72 tc::TcStats2::Queue(queue) => {
73 tc.stats.qlen = Some(queue.qlen);
74 tc.stats.backlog = Some(queue.backlog);
75 tc.stats.drops = Some(queue.drops);
76 tc.stats.requeues = Some(queue.requeues);
77 tc.stats.overlimits = Some(queue.overlimits);
78 }
79 _ => {}
80 }
81 }
82 }
83 TcAttribute::Xstats(tc::TcXstats::FqCodel(fq_codel_xstats)) => {
84 tc.stats.xstats = FqCodelXStats::new(fq_codel_xstats).map(XStats::FqCodel);
85 }
86 _ => {}
87 }
88 }
89
90 tc.qdisc = QDisc::new(&tc.kind, opts);
91
92 tc
93 }
94}
95
96#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
98pub struct Stats {
99 pub bytes: Option<u64>,
102 pub packets: Option<u32>,
104
105 pub qlen: Option<u32>,
108 pub backlog: Option<u32>,
110 pub drops: Option<u32>,
112 pub requeues: Option<u32>,
113 pub overlimits: Option<u32>,
115
116 pub xstats: Option<XStats>,
119
120 pub bps: Option<u32>,
122 pub pps: Option<u32>,
124}
125
126#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
128pub enum QDisc {
129 FqCodel(FqCodelQDisc),
130}
131
132impl QDisc {
133 fn new(kind: &str, opts: Vec<TcOption>) -> Option<Self> {
134 if kind == FQ_CODEL {
135 let mut fq_codel = FqCodelQDisc::default();
136 for opt in opts {
137 if let TcOption::FqCodel(fq_codel_opt) = opt {
138 match fq_codel_opt {
139 TcQdiscFqCodelOption::Target(target) => fq_codel.target = target,
140 TcQdiscFqCodelOption::Limit(limit) => fq_codel.limit = limit,
141 TcQdiscFqCodelOption::Interval(interval) => fq_codel.interval = interval,
142 TcQdiscFqCodelOption::Ecn(ecn) => fq_codel.ecn = ecn,
143 TcQdiscFqCodelOption::Flows(flows) => fq_codel.flows = flows,
144 TcQdiscFqCodelOption::Quantum(quantum) => fq_codel.quantum = quantum,
145 TcQdiscFqCodelOption::CeThreshold(ce_threshold) => {
146 fq_codel.ce_threshold = ce_threshold
147 }
148 TcQdiscFqCodelOption::DropBatchSize(drop_batch_size) => {
149 fq_codel.drop_batch_size = drop_batch_size
150 }
151 TcQdiscFqCodelOption::MemoryLimit(memory_limit) => {
152 fq_codel.memory_limit = memory_limit
153 }
154 _ => {}
155 }
156 }
157 }
158 return Some(Self::FqCodel(fq_codel));
159 }
160 None
161 }
162}
163
164#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
165pub enum XStats {
166 FqCodel(FqCodelXStats),
167}
168
169#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
170pub struct FqCodelQDisc {
171 pub target: u32,
173 pub limit: u32,
175 pub interval: u32,
177 pub ecn: u32,
179 pub flows: u32,
181 pub quantum: u32,
183 pub ce_threshold: u32,
185 pub drop_batch_size: u32,
187 pub memory_limit: u32,
189}
190
191#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
192pub enum FqCodelXStats {
193 FqCodelQdiscStats(FqCodelQdStats),
194}
195
196#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
197pub struct FqCodelQdStats {
198 pub maxpacket: u32,
200 pub drop_overlimit: u32,
202 pub ecn_mark: u32,
204 pub new_flow_count: u32,
206 pub new_flows_len: u32,
208 pub old_flows_len: u32,
210 pub ce_mark: u32,
212 pub memory_usage: u32,
214 pub drop_overmemory: u32,
216}
217
218impl FqCodelXStats {
219 pub fn new(xstats: &TcFqCodelXstats) -> Option<Self> {
220 match xstats {
221 TcFqCodelXstats::Qdisc(qdisc) => {
222 Some(FqCodelXStats::FqCodelQdiscStats(FqCodelQdStats {
223 maxpacket: qdisc.maxpacket,
224 drop_overlimit: qdisc.drop_overlimit,
225 ecn_mark: qdisc.ecn_mark,
226 new_flow_count: qdisc.new_flow_count,
227 new_flows_len: qdisc.new_flows_len,
228 old_flows_len: qdisc.old_flows_len,
229 ce_mark: qdisc.ce_mark,
230 memory_usage: qdisc.memory_usage,
231 drop_overmemory: qdisc.drop_overmemory,
232 }))
233 }
234 _ => None,
235 }
236 }
237}