netlink_tc/qdiscs/
fq_codel.rs

1use serde::{Deserialize, Serialize};
2
3use crate::{errors::TcError, TcOption};
4
5/// Defined in `include/uapi/linux/sch_fq_codel.c`.
6#[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/// Defined in `include/uapi/linux/pkt_sched.h` as `struct tc_fq_codel_xstats`.
26#[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            // TODO: log error
86            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}