netlink_packet_route/tc/
attribute.rs

1// SPDX-License-Identifier: MIT
2
3use super::{TcError, TcOption, TcStats, TcStats2, TcStatsBuffer, TcXstats, VecTcOption};
4use byteorder::{ByteOrder, NativeEndian};
5use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator};
6use netlink_packet_utils::parsers::{parse_string, parse_u32, parse_u8};
7use netlink_packet_utils::{Emitable, Parseable, ParseableParametrized};
8
9const TCA_KIND: u16 = 1;
10const TCA_OPTIONS: u16 = 2;
11const TCA_STATS: u16 = 3;
12const TCA_XSTATS: u16 = 4;
13const TCA_RATE: u16 = 5;
14const TCA_FCNT: u16 = 6;
15const TCA_STATS2: u16 = 7;
16const TCA_STAB: u16 = 8;
17// const TCA_PAD: u16 = 9;
18const TCA_DUMP_INVISIBLE: u16 = 10;
19const TCA_CHAIN: u16 = 11;
20const TCA_HW_OFFLOAD: u16 = 12;
21// const TCA_INGRESS_BLOCK: u16 = 13; // TODO
22// const TCA_EGRESS_BLOCK: u16 = 14; // TODO
23
24#[derive(Debug, PartialEq, Eq, Clone)]
25#[non_exhaustive]
26pub enum TcAttribute {
27    /// Name of queueing discipline
28    Kind(String),
29    /// Options follow
30    Options(Vec<TcOption>),
31    /// Statistics
32    Stats(TcStats),
33    /// Module-specific statistics
34    Xstats(TcXstats),
35    /// Rate limit
36    Rate(Vec<u8>),
37    Fcnt(Vec<u8>),
38    Stats2(Vec<TcStats2>),
39    Stab(Vec<u8>),
40    Chain(u32),
41    HwOffload(u8),
42    DumpInvisible(bool),
43    Other(DefaultNla),
44}
45
46impl Nla for TcAttribute {
47    fn value_len(&self) -> usize {
48        match *self {
49            Self::Rate(ref bytes) | Self::Fcnt(ref bytes) | Self::Stab(ref bytes) => bytes.len(),
50            Self::Chain(_) => 4,
51            Self::Xstats(ref v) => v.buffer_len(),
52            Self::HwOffload(_) => 1,
53            Self::Stats2(ref v) => v.as_slice().buffer_len(),
54            Self::Stats(ref v) => v.buffer_len(),
55            Self::Kind(ref string) => string.as_bytes().len() + 1,
56            Self::Options(ref opt) => opt.as_slice().buffer_len(),
57            Self::DumpInvisible(_) => 0, // The existence of NLA means true
58            Self::Other(ref attr) => attr.value_len(),
59        }
60    }
61
62    fn emit_value(&self, buffer: &mut [u8]) {
63        match *self {
64            Self::Rate(ref bytes) | Self::Fcnt(ref bytes) | Self::Stab(ref bytes) => {
65                buffer.copy_from_slice(bytes.as_slice())
66            }
67            Self::Chain(v) => NativeEndian::write_u32(buffer, v),
68            Self::Xstats(ref v) => v.emit(buffer),
69            Self::HwOffload(ref val) => buffer[0] = *val,
70            Self::Stats2(ref stats) => stats.as_slice().emit(buffer),
71            Self::Stats(ref stats) => stats.emit(buffer),
72            Self::Kind(ref string) => {
73                buffer[..string.as_bytes().len()].copy_from_slice(string.as_bytes());
74                buffer[string.as_bytes().len()] = 0;
75            }
76            Self::Options(ref opt) => opt.as_slice().emit(buffer),
77            Self::DumpInvisible(_) => (),
78            Self::Other(ref attr) => attr.emit_value(buffer),
79        }
80    }
81
82    fn kind(&self) -> u16 {
83        match *self {
84            Self::Kind(_) => TCA_KIND,
85            Self::Options(_) => TCA_OPTIONS,
86            Self::Stats(_) => TCA_STATS,
87            Self::Xstats(_) => TCA_XSTATS,
88            Self::Rate(_) => TCA_RATE,
89            Self::Fcnt(_) => TCA_FCNT,
90            Self::Stats2(_) => TCA_STATS2,
91            Self::Stab(_) => TCA_STAB,
92            Self::Chain(_) => TCA_CHAIN,
93            Self::HwOffload(_) => TCA_HW_OFFLOAD,
94            Self::DumpInvisible(_) => TCA_DUMP_INVISIBLE,
95            Self::Other(ref nla) => nla.kind(),
96        }
97    }
98}
99
100impl<'a, T: AsRef<[u8]> + ?Sized> ParseableParametrized<NlaBuffer<&'a T>, &str> for TcAttribute {
101    type Error = TcError;
102    fn parse_with_param(buf: &NlaBuffer<&'a T>, kind: &str) -> Result<Self, Self::Error> {
103        let payload = buf.value();
104        Ok(match buf.kind() {
105            TCA_KIND => TcAttribute::Kind(
106                parse_string(payload)
107                    .map_err(|error| TcError::InvalidValue { kind: "TCA_KIND", error })?,
108            ),
109            TCA_OPTIONS => TcAttribute::Options(VecTcOption::parse_with_param(buf, kind)?.0),
110            TCA_STATS => TcAttribute::Stats(
111                TcStats::parse(
112                    &TcStatsBuffer::new_checked(payload)
113                        .map_err(|error| TcError::InvalidValue { kind: "TCA_STATS", error })?,
114                )
115                .map_err(|error| TcError::InvalidValue { kind: "TCA_STATS", error })?,
116            ),
117            TCA_XSTATS => TcAttribute::Xstats(TcXstats::parse_with_param(buf, kind)?),
118            TCA_RATE => TcAttribute::Rate(payload.to_vec()),
119            TCA_FCNT => TcAttribute::Fcnt(payload.to_vec()),
120            TCA_STATS2 => {
121                let mut nlas = vec![];
122                for nla in NlasIterator::new(payload) {
123                    let nla = nla?;
124                    nlas.push(TcStats2::parse_with_param(&nla, kind)?);
125                }
126                TcAttribute::Stats2(nlas)
127            }
128            TCA_STAB => TcAttribute::Stab(payload.to_vec()),
129            TCA_CHAIN => TcAttribute::Chain(
130                parse_u32(payload)
131                    .map_err(|error| TcError::InvalidValue { kind: "TCA_CHAIN", error })?,
132            ),
133            TCA_HW_OFFLOAD => TcAttribute::HwOffload(
134                parse_u8(payload)
135                    .map_err(|error| TcError::InvalidValue { kind: "TCA_HW_OFFLOAD", error })?,
136            ),
137            TCA_DUMP_INVISIBLE => TcAttribute::DumpInvisible(true),
138            kind => TcAttribute::Other(
139                DefaultNla::parse(buf).map_err(|error| TcError::UnknownNla { kind, error })?,
140            ),
141        })
142    }
143}