below_tc/
types.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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/// `Tc` represents a traffic control qdisc.
27#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
28pub struct TcStat {
29    /// Index of the network interface.
30    pub if_index: u32,
31    /// Name of the network interface.
32    pub if_name: String,
33    /// A unique identifier for the qdisc.
34    pub handle: u32,
35    /// Identifier of the parent qdisc.
36    pub parent: u32,
37    /// Type of the queueing discipline, e.g. `fq_codel`, `htb`, etc.
38    pub kind: String,
39    /// Detailed statistics of the qdisc, such as bytes, packets, qlen, etc.
40    pub stats: Stats,
41    /// qdisc wraps the specific qdisc type, e.g. `fq_codel`.
42    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/// `Stats` represents the statistics of a qdisc.
97#[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)]
98pub struct Stats {
99    // Stats2::StatsBasic
100    /// Number of enqueued bytes.
101    pub bytes: Option<u64>,
102    /// Number of enqueued packets.
103    pub packets: Option<u32>,
104
105    // Stats2::StatsQueue
106    /// Length of the queue.
107    pub qlen: Option<u32>,
108    /// Number of bytes pending in the queue.
109    pub backlog: Option<u32>,
110    /// Packets dropped because of lack of resources.
111    pub drops: Option<u32>,
112    pub requeues: Option<u32>,
113    /// Number of throttle events when this flow goes out of allocated bandwidth.
114    pub overlimits: Option<u32>,
115
116    // XStats
117    /// xstats wraps extended statistics of the qdisc.
118    pub xstats: Option<XStats>,
119
120    /// Current flow byte rate.
121    pub bps: Option<u32>,
122    /// Current flow packet rate.
123    pub pps: Option<u32>,
124}
125
126/// `QDisc` represents the queueing discipline of a network interface.
127#[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    /// Accceptable minimum standing/persistent queue delay.
172    pub target: u32,
173    /// Hard limit on the real queue size.
174    pub limit: u32,
175    /// Used to ensure that the measured minimum delay does not become too stale.
176    pub interval: u32,
177    /// Used to mark packets instead of dropping them.
178    pub ecn: u32,
179    /// Number of flows into which the incoming packets are classified.
180    pub flows: u32,
181    /// Number of bytes used as 'deficit' in the fair queuing algorithm.
182    pub quantum: u32,
183    /// Sets a threshold above which all packets are marked with ECN Congestion Experienced.
184    pub ce_threshold: u32,
185    /// Sets the maximum number of packets to drop when limit or memory_limit is exceeded.
186    pub drop_batch_size: u32,
187    /// Sets a limit on the total number of bytes that can be queued in this FQ-CoDel instance.
188    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    /// Largest packet we've seen so far
199    pub maxpacket: u32,
200    /// Number of time max qdisc packet limit was hit.
201    pub drop_overlimit: u32,
202    /// Number of packets ECN marked instead of being dropped.
203    pub ecn_mark: u32,
204    /// Number of time packets created a 'new flow'.
205    pub new_flow_count: u32,
206    /// Count of flows in new list.
207    pub new_flows_len: u32,
208    /// Count of flows in old list.
209    pub old_flows_len: u32,
210    /// Packets above ce_threshold.
211    pub ce_mark: u32,
212    /// Memory usage (bytes).
213    pub memory_usage: u32,
214    /// Number of time packets were dropped due to memory limit.
215    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}