below_model/
tc_model.rs

1use std::time::Duration;
2
3use serde::Deserialize;
4use serde::Serialize;
5use tc::QDisc;
6use tc::TcStat;
7use tc::TcStats;
8use tc::XStats;
9
10use crate::Field;
11use crate::FieldId;
12use crate::Nameable;
13use crate::Queriable;
14
15/// rate! macro calculates the rate of a field for given sample and last objects.
16/// It basically calls count_per_sec! macro after extracting the field from the objects.
17macro_rules! rate {
18    ($field:ident, $sample:ident, $last:ident, $target_type:ty) => {{
19        $last.and_then(|(last, d)| {
20            let s = $sample.$field;
21            let l = last.$field;
22            count_per_sec!(l, s, d, $target_type)
23        })
24    }};
25}
26
27#[below_derive::queriable_derives]
28pub struct TcModel {
29    #[queriable(subquery)]
30    pub tc: Vec<SingleTcModel>,
31}
32
33impl TcModel {
34    pub fn new(sample: &TcStats, last: Option<(&TcStats, Duration)>) -> Self {
35        // Assumption: sample and last are always ordered
36        let tc = match last {
37            Some((last_tcs, d)) if last_tcs.len() == sample.len() => sample
38                .iter()
39                .zip(last_tcs.iter())
40                .map(|(sample, last)| SingleTcModel::new(sample, Some((last, d))))
41                .collect::<Vec<_>>(),
42            _ => Vec::new(),
43        };
44
45        Self { tc }
46    }
47}
48
49#[below_derive::queriable_derives]
50pub struct SingleTcModel {
51    /// Name of the interface
52    pub interface: String,
53    /// Name of the qdisc
54    pub kind: String,
55
56    pub qlen: Option<u32>,
57    pub bps: Option<u32>,
58    pub pps: Option<u32>,
59
60    pub bytes_per_sec: Option<u64>,
61    pub packets_per_sec: Option<u32>,
62    pub backlog_per_sec: Option<u32>,
63    pub drops_per_sec: Option<u32>,
64    pub requeues_per_sec: Option<u32>,
65    pub overlimits_per_sec: Option<u32>,
66
67    #[queriable(subquery)]
68    pub qdisc: Option<QDiscModel>,
69
70    #[queriable(subquery)]
71    pub xstats: Option<XStatsModel>,
72}
73
74impl Nameable for SingleTcModel {
75    fn name() -> &'static str {
76        "tc"
77    }
78}
79
80impl SingleTcModel {
81    pub fn new(sample: &TcStat, last: Option<(&TcStat, Duration)>) -> Self {
82        let mut tc_model = SingleTcModel {
83            interface: sample.if_name.clone(),
84            kind: sample.kind.clone(),
85            ..Default::default()
86        };
87
88        let stats = &sample.stats;
89        tc_model.qlen = stats.qlen;
90        tc_model.bps = stats.bps;
91        tc_model.pps = stats.pps;
92
93        if let Some((l, d)) = last {
94            let last = &l.stats;
95            tc_model.bytes_per_sec = count_per_sec!(last.bytes, stats.bytes, d, u64);
96            tc_model.packets_per_sec = count_per_sec!(last.packets, stats.packets, d, u32);
97            tc_model.backlog_per_sec = count_per_sec!(last.backlog, stats.backlog, d, u32);
98            tc_model.drops_per_sec = count_per_sec!(last.drops, stats.drops, d, u32);
99            tc_model.requeues_per_sec = count_per_sec!(last.requeues, stats.requeues, d, u32);
100            tc_model.overlimits_per_sec = count_per_sec!(last.overlimits, stats.overlimits, d, u32);
101        }
102
103        if let Some(sample) = stats.xstats.as_ref() {
104            let last = last.and_then(|(last, d)| last.stats.xstats.as_ref().map(|l| (l, d)));
105
106            tc_model.xstats = XStatsModel::new(sample, last);
107        }
108
109        if let Some(sample) = sample.qdisc.as_ref() {
110            tc_model.qdisc = Some(QDiscModel::new(sample));
111        }
112
113        tc_model
114    }
115}
116
117#[below_derive::queriable_derives]
118pub struct QDiscModel {
119    #[queriable(subquery)]
120    pub fq_codel: Option<FqCodelQDiscModel>,
121}
122
123impl QDiscModel {
124    fn new(sample: &QDisc) -> Self {
125        match sample {
126            QDisc::FqCodel(sample) => Self {
127                fq_codel: Some(FqCodelQDiscModel::new(sample)),
128            },
129        }
130    }
131}
132
133#[below_derive::queriable_derives]
134pub struct FqCodelQDiscModel {
135    pub target: u32,
136    pub limit: u32,
137    pub interval: u32,
138    pub ecn: u32,
139    pub quantum: u32,
140    pub ce_threshold: u32,
141    pub drop_batch_size: u32,
142    pub memory_limit: u32,
143    pub flows: u32,
144}
145
146impl FqCodelQDiscModel {
147    fn new(sample: &tc::FqCodelQDisc) -> Self {
148        Self {
149            target: sample.target,
150            limit: sample.limit,
151            interval: sample.interval,
152            ecn: sample.ecn,
153            quantum: sample.quantum,
154            ce_threshold: sample.ce_threshold,
155            drop_batch_size: sample.drop_batch_size,
156            memory_limit: sample.memory_limit,
157            flows: sample.flows,
158        }
159    }
160}
161
162#[derive(
163    Clone,
164    Debug,
165    Default,
166    PartialEq,
167    Serialize,
168    Deserialize,
169    below_derive::Queriable
170)]
171pub struct XStatsModel {
172    #[queriable(subquery)]
173    pub fq_codel: Option<FqCodelXStatsModel>,
174}
175
176impl XStatsModel {
177    fn new(sample: &XStats, last: Option<(&XStats, Duration)>) -> Option<Self> {
178        match (sample, last) {
179            (XStats::FqCodel(sample), Some((XStats::FqCodel(last), d))) => match (sample, last) {
180                (
181                    tc::FqCodelXStats::FqCodelQdiscStats(sample),
182                    tc::FqCodelXStats::FqCodelQdiscStats(last),
183                ) => Some(Self {
184                    fq_codel: Some(FqCodelXStatsModel::new(sample, Some((last, d)))),
185                }),
186            },
187            _ => None,
188        }
189    }
190}
191
192#[derive(
193    Clone,
194    Debug,
195    Default,
196    PartialEq,
197    Serialize,
198    Deserialize,
199    below_derive::Queriable
200)]
201pub struct FqCodelXStatsModel {
202    // FqCodelQdXStats
203    pub maxpacket: u32,
204    pub ecn_mark: u32,
205    pub new_flows_len: u32,
206    pub old_flows_len: u32,
207    pub ce_mark: u32,
208    pub drop_overlimit_per_sec: Option<u32>,
209    pub new_flow_count_per_sec: Option<u32>,
210    pub memory_usage_per_sec: Option<u32>,
211    pub drop_overmemory_per_sec: Option<u32>,
212}
213
214impl FqCodelXStatsModel {
215    fn new(sample: &tc::FqCodelQdStats, last: Option<(&tc::FqCodelQdStats, Duration)>) -> Self {
216        Self {
217            maxpacket: sample.maxpacket,
218            ecn_mark: sample.ecn_mark,
219            new_flows_len: sample.new_flows_len,
220            old_flows_len: sample.old_flows_len,
221            ce_mark: sample.ce_mark,
222            drop_overlimit_per_sec: rate!(drop_overlimit, sample, last, u32),
223            new_flow_count_per_sec: rate!(drop_overlimit, sample, last, u32),
224            memory_usage_per_sec: rate!(drop_overlimit, sample, last, u32),
225            drop_overmemory_per_sec: rate!(drop_overlimit, sample, last, u32),
226        }
227    }
228}