netlink_packet_route/rtnl/tc/
message.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use netlink_packet_utils::{
5    nla::{DefaultNla, NlasIterator},
6    parsers::{parse_string, parse_u8},
7    traits::{Emitable, Parseable, ParseableParametrized},
8    DecodeError,
9};
10
11use crate::{
12    constants::*,
13    nlas::tc::{Nla, Stats, Stats2, StatsBuffer, TcOpt},
14    TcMessageBuffer, TC_HEADER_LEN,
15};
16
17#[derive(Debug, PartialEq, Eq, Clone, Default)]
18#[non_exhaustive]
19pub struct TcMessage {
20    pub header: TcHeader,
21    pub nlas: Vec<Nla>,
22}
23
24impl TcMessage {
25    pub fn into_parts(self) -> (TcHeader, Vec<Nla>) {
26        (self.header, self.nlas)
27    }
28
29    pub fn from_parts(header: TcHeader, nlas: Vec<Nla>) -> Self {
30        TcMessage { header, nlas }
31    }
32
33    /// Create a new `TcMessage` with the given index
34    pub fn with_index(index: i32) -> Self {
35        Self {
36            header: TcHeader {
37                index,
38                ..Default::default()
39            },
40            nlas: Vec::new(),
41        }
42    }
43}
44
45#[derive(Debug, PartialEq, Eq, Clone, Default)]
46pub struct TcHeader {
47    pub family: u8,
48    // Interface index
49    pub index: i32,
50    // Qdisc handle
51    pub handle: u32,
52    // Parent Qdisc
53    pub parent: u32,
54    pub info: u32,
55}
56
57impl Emitable for TcHeader {
58    fn buffer_len(&self) -> usize {
59        TC_HEADER_LEN
60    }
61
62    fn emit(&self, buffer: &mut [u8]) {
63        let mut packet = TcMessageBuffer::new(buffer);
64        packet.set_family(self.family);
65        packet.set_index(self.index);
66        packet.set_handle(self.handle);
67        packet.set_parent(self.parent);
68        packet.set_info(self.info);
69    }
70}
71
72impl Emitable for TcMessage {
73    fn buffer_len(&self) -> usize {
74        self.header.buffer_len() + self.nlas.as_slice().buffer_len()
75    }
76
77    fn emit(&self, buffer: &mut [u8]) {
78        self.header.emit(buffer);
79        self.nlas
80            .as_slice()
81            .emit(&mut buffer[self.header.buffer_len()..]);
82    }
83}
84
85impl<T: AsRef<[u8]>> Parseable<TcMessageBuffer<T>> for TcHeader {
86    fn parse(buf: &TcMessageBuffer<T>) -> Result<Self, DecodeError> {
87        Ok(Self {
88            family: buf.family(),
89            index: buf.index(),
90            handle: buf.handle(),
91            parent: buf.parent(),
92            info: buf.info(),
93        })
94    }
95}
96
97impl<'a, T: AsRef<[u8]> + 'a> Parseable<TcMessageBuffer<&'a T>> for TcMessage {
98    fn parse(buf: &TcMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
99        Ok(Self {
100            header: TcHeader::parse(buf)
101                .context("failed to parse tc message header")?,
102            nlas: Vec::<Nla>::parse(buf)
103                .context("failed to parse tc message NLAs")?,
104        })
105    }
106}
107
108impl<'a, T: AsRef<[u8]> + 'a> Parseable<TcMessageBuffer<&'a T>> for Vec<Nla> {
109    fn parse(buf: &TcMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
110        let mut nlas = vec![];
111        let mut kind = String::new();
112
113        for nla_buf in buf.nlas() {
114            let buf = nla_buf.context("invalid tc nla")?;
115            let payload = buf.value();
116            let nla = match buf.kind() {
117                TCA_UNSPEC => Nla::Unspec(payload.to_vec()),
118                TCA_KIND => {
119                    kind = parse_string(payload).context("invalid TCA_KIND")?;
120                    Nla::Kind(kind.clone())
121                }
122                TCA_OPTIONS => {
123                    let mut nlas = vec![];
124                    for nla in NlasIterator::new(payload) {
125                        let nla = nla.context("invalid TCA_OPTIONS")?;
126                        nlas.push(
127                            TcOpt::parse_with_param(&nla, &kind)
128                                .context("failed to parse TCA_OPTIONS")?,
129                        )
130                    }
131                    Nla::Options(nlas)
132                }
133                TCA_STATS => Nla::Stats(
134                    Stats::parse(
135                        &StatsBuffer::new_checked(payload)
136                            .context("invalid TCA_STATS")?,
137                    )
138                    .context("failed to parse TCA_STATS")?,
139                ),
140                TCA_XSTATS => Nla::XStats(payload.to_vec()),
141                TCA_RATE => Nla::Rate(payload.to_vec()),
142                TCA_FCNT => Nla::Fcnt(payload.to_vec()),
143                TCA_STATS2 => {
144                    let mut nlas = vec![];
145                    for nla in NlasIterator::new(payload) {
146                        let nla = nla.context("invalid TCA_STATS2")?;
147                        nlas.push(
148                            Stats2::parse(&nla)
149                                .context("failed to parse TCA_STATS2")?,
150                        );
151                    }
152                    Nla::Stats2(nlas)
153                }
154                TCA_STAB => Nla::Stab(payload.to_vec()),
155                TCA_CHAIN => Nla::Chain(payload.to_vec()),
156                TCA_HW_OFFLOAD => Nla::HwOffload(
157                    parse_u8(payload)
158                        .context("failed to parse TCA_HW_OFFLOAD")?,
159                ),
160                _ => Nla::Other(
161                    DefaultNla::parse(&buf)
162                        .context("failed to parse tc nla")?,
163                ),
164            };
165
166            nlas.push(nla);
167        }
168        Ok(nlas)
169    }
170}