netlink_packet_route/rtnl/tc/nlas/action/
mod.rs

1// SPDX-License-Identifier: MIT
2
3pub mod mirred;
4pub mod nat;
5
6use anyhow::Context;
7use byteorder::{ByteOrder, NativeEndian};
8
9use netlink_packet_utils::{
10    nla::{self, DefaultNla, NlaBuffer, NlasIterator, NLA_F_NESTED},
11    parsers::{parse_string, parse_u32},
12    traits::{Emitable, Parseable, ParseableParametrized},
13    DecodeError,
14};
15
16use crate::tc::{constants::*, Stats2};
17
18pub const TC_GEN_BUF_LEN: usize = 20;
19
20#[derive(Debug, PartialEq, Eq, Clone)]
21#[non_exhaustive]
22pub struct Action {
23    pub tab: u16,
24    pub nlas: Vec<ActNla>,
25}
26
27impl Default for Action {
28    fn default() -> Self {
29        Self {
30            tab: TCA_ACT_TAB,
31            nlas: Vec::new(),
32        }
33    }
34}
35
36impl nla::Nla for Action {
37    fn value_len(&self) -> usize {
38        self.nlas.as_slice().buffer_len()
39    }
40
41    fn emit_value(&self, buffer: &mut [u8]) {
42        self.nlas.as_slice().emit(buffer)
43    }
44
45    fn kind(&self) -> u16 {
46        self.tab
47    }
48}
49
50impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Action {
51    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
52        let mut nlas = vec![];
53        let mut kind = String::new();
54
55        for iter in NlasIterator::new(buf.value()) {
56            let buf = iter.context("invalid action nla")?;
57            let payload = buf.value();
58            nlas.push(match buf.kind() {
59                TCA_ACT_UNSPEC => ActNla::Unspec(payload.to_vec()),
60                TCA_ACT_KIND => {
61                    kind = parse_string(payload)
62                        .context("failed to parse TCA_ACT_KIND")?;
63                    ActNla::Kind(kind.clone())
64                }
65                TCA_ACT_OPTIONS => {
66                    let mut nlas = vec![];
67                    for nla in NlasIterator::new(payload) {
68                        let nla = nla.context("invalid TCA_ACT_OPTIONS")?;
69                        nlas.push(
70                            ActOpt::parse_with_param(&nla, &kind)
71                                .context("failed to parse TCA_ACT_OPTIONS")?,
72                        )
73                    }
74                    ActNla::Options(nlas)
75                }
76                TCA_ACT_INDEX => ActNla::Index(
77                    parse_u32(payload)
78                        .context("failed to parse TCA_ACT_INDEX")?,
79                ),
80                TCA_ACT_STATS => {
81                    let mut nlas = vec![];
82                    for nla in NlasIterator::new(payload) {
83                        let nla = nla.context("invalid TCA_ACT_STATS")?;
84                        nlas.push(
85                            Stats2::parse(&nla)
86                                .context("failed to parse TCA_ACT_STATS")?,
87                        );
88                    }
89                    ActNla::Stats(nlas)
90                }
91                TCA_ACT_COOKIE => ActNla::Cookie(payload.to_vec()),
92                _ => ActNla::Other(
93                    DefaultNla::parse(&buf)
94                        .context("failed to parse action nla")?,
95                ),
96            });
97        }
98        Ok(Self {
99            tab: buf.kind(),
100            nlas,
101        })
102    }
103}
104
105#[derive(Debug, PartialEq, Eq, Clone)]
106#[non_exhaustive]
107pub enum ActNla {
108    Unspec(Vec<u8>),
109    Kind(String),
110    Options(Vec<ActOpt>),
111    Index(u32),
112    Stats(Vec<Stats2>),
113    Cookie(Vec<u8>),
114    Other(DefaultNla),
115}
116
117impl nla::Nla for ActNla {
118    fn value_len(&self) -> usize {
119        use self::ActNla::*;
120        match self {
121            Unspec(bytes) | Cookie(bytes) => bytes.len(),
122            Kind(k) => k.len() + 1,
123            Options(opt) => opt.as_slice().buffer_len(),
124            Index(_) => 4,
125            Stats(s) => s.as_slice().buffer_len(),
126            Other(attr) => attr.value_len(),
127        }
128    }
129    fn emit_value(&self, buffer: &mut [u8]) {
130        use self::ActNla::*;
131        match self {
132            Unspec(bytes) | Cookie(bytes) => {
133                buffer.copy_from_slice(bytes.as_slice())
134            }
135            Kind(string) => {
136                buffer[..string.as_bytes().len()]
137                    .copy_from_slice(string.as_bytes());
138                buffer[string.as_bytes().len()] = 0;
139            }
140            Options(opt) => opt.as_slice().emit(buffer),
141            Index(value) => NativeEndian::write_u32(buffer, *value),
142            Stats(s) => s.as_slice().emit(buffer),
143            Other(attr) => attr.emit_value(buffer),
144        }
145    }
146    fn kind(&self) -> u16 {
147        use self::ActNla::*;
148        match self {
149            Unspec(_) => TCA_ACT_UNSPEC,
150            Kind(_) => TCA_ACT_KIND,
151            Options(_) => TCA_ACT_OPTIONS | NLA_F_NESTED,
152            Index(_) => TCA_ACT_INDEX,
153            Stats(_) => TCA_ACT_STATS,
154            Cookie(_) => TCA_ACT_COOKIE,
155            Other(nla) => nla.kind(),
156        }
157    }
158}
159
160#[derive(Debug, PartialEq, Eq, Clone)]
161#[non_exhaustive]
162pub enum ActOpt {
163    Mirred(mirred::Nla),
164    Nat(nat::Nla),
165    // Other options
166    Other(DefaultNla),
167}
168
169impl nla::Nla for ActOpt {
170    fn value_len(&self) -> usize {
171        use self::ActOpt::*;
172        match self {
173            Mirred(nla) => nla.value_len(),
174            Nat(nla) => nla.value_len(),
175            Other(nla) => nla.value_len(),
176        }
177    }
178
179    fn emit_value(&self, buffer: &mut [u8]) {
180        use self::ActOpt::*;
181        match self {
182            Mirred(nla) => nla.emit_value(buffer),
183            Nat(nla) => nla.emit_value(buffer),
184            Other(nla) => nla.emit_value(buffer),
185        }
186    }
187
188    fn kind(&self) -> u16 {
189        use self::ActOpt::*;
190        match self {
191            Mirred(nla) => nla.kind(),
192            Nat(nla) => nla.kind(),
193            Other(nla) => nla.kind(),
194        }
195    }
196}
197
198impl<'a, T, S> ParseableParametrized<NlaBuffer<&'a T>, S> for ActOpt
199where
200    T: AsRef<[u8]> + ?Sized,
201    S: AsRef<str>,
202{
203    fn parse_with_param(
204        buf: &NlaBuffer<&'a T>,
205        kind: S,
206    ) -> Result<Self, DecodeError> {
207        Ok(match kind.as_ref() {
208            mirred::KIND => Self::Mirred(
209                mirred::Nla::parse(buf)
210                    .context("failed to parse mirred action")?,
211            ),
212            nat::KIND => Self::Nat(
213                nat::Nla::parse(buf).context("failed to parse nat action")?,
214            ),
215            _ => Self::Other(
216                DefaultNla::parse(buf)
217                    .context("failed to parse action options")?,
218            ),
219        })
220    }
221}
222
223#[derive(Debug, PartialEq, Eq, Clone, Default)]
224#[non_exhaustive]
225pub struct TcGen {
226    pub index: u32,
227    pub capab: u32,
228    pub action: i32,
229    pub refcnt: i32,
230    pub bindcnt: i32,
231}
232
233buffer!(TcGenBuffer(TC_GEN_BUF_LEN) {
234    index: (u32, 0..4),
235    capab: (u32, 4..8),
236    action: (i32, 8..12),
237    refcnt: (i32, 12..16),
238    bindcnt: (i32, 16..20),
239});
240
241impl Emitable for TcGen {
242    fn buffer_len(&self) -> usize {
243        TC_GEN_BUF_LEN
244    }
245
246    fn emit(&self, buffer: &mut [u8]) {
247        let mut packet = TcGenBuffer::new(buffer);
248        packet.set_index(self.index);
249        packet.set_capab(self.capab);
250        packet.set_action(self.action);
251        packet.set_refcnt(self.refcnt);
252        packet.set_bindcnt(self.bindcnt);
253    }
254}
255
256impl<T: AsRef<[u8]>> Parseable<TcGenBuffer<T>> for TcGen {
257    fn parse(buf: &TcGenBuffer<T>) -> Result<Self, DecodeError> {
258        Ok(Self {
259            index: buf.index(),
260            capab: buf.capab(),
261            action: buf.action(),
262            refcnt: buf.refcnt(),
263            bindcnt: buf.bindcnt(),
264        })
265    }
266}