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

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