netlink_packet_route/tc/actions/
action.rs

1// SPDX-License-Identifier: MIT
2
3use super::{TcActionMirror, TcActionMirrorOption, TcActionNat, TcActionNatOption};
4use crate::tc::{TcError, TcStats2};
5use byteorder::{ByteOrder, NativeEndian};
6use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer, NlasIterator, NLA_F_NESTED};
7use netlink_packet_utils::parsers::{parse_string, parse_u32};
8use netlink_packet_utils::traits::{Emitable, Parseable, ParseableParametrized};
9use netlink_packet_utils::DecodeError;
10
11const TCA_ACT_TAB: u16 = 1;
12
13#[derive(Debug, PartialEq, Eq, Clone)]
14#[non_exhaustive]
15pub struct TcAction {
16    pub tab: u16,
17    pub attributes: Vec<TcActionAttribute>,
18}
19
20impl Default for TcAction {
21    fn default() -> Self {
22        Self { tab: TCA_ACT_TAB, attributes: Vec::new() }
23    }
24}
25
26impl Nla for TcAction {
27    fn value_len(&self) -> usize {
28        self.attributes.as_slice().buffer_len()
29    }
30
31    fn emit_value(&self, buffer: &mut [u8]) {
32        self.attributes.as_slice().emit(buffer)
33    }
34
35    fn kind(&self) -> u16 {
36        self.tab
37    }
38}
39
40impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for TcAction {
41    type Error = TcError;
42    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, TcError> {
43        let mut attributes = vec![];
44        let mut kind = String::new();
45
46        for iter in NlasIterator::new(buf.value()) {
47            let buf = iter?;
48            let payload = buf.value();
49            attributes.push(match buf.kind() {
50                TCA_ACT_KIND => {
51                    kind = parse_string(payload)
52                        .map_err(|error| TcError::ParseAction { kind: "TCA_ACT_KIND", error })?;
53                    TcActionAttribute::Kind(kind.clone())
54                }
55                TCA_ACT_OPTIONS => {
56                    let mut nlas = vec![];
57                    for nla in NlasIterator::new(payload) {
58                        let nla = nla?;
59                        nlas.push(TcActionOption::parse_with_param(&nla, &kind)?);
60                    }
61                    TcActionAttribute::Options(nlas)
62                }
63                TCA_ACT_INDEX => TcActionAttribute::Index(
64                    parse_u32(payload)
65                        .map_err(|error| TcError::ParseAction { kind: "TCA_ACT_INDEX", error })?,
66                ),
67                TCA_ACT_STATS => {
68                    let mut nlas = vec![];
69                    for nla in NlasIterator::new(payload) {
70                        let nla = nla?;
71                        nlas.push(TcStats2::parse_with_param(&nla, &kind)?);
72                    }
73                    TcActionAttribute::Stats(nlas)
74                }
75                TCA_ACT_COOKIE => TcActionAttribute::Cookie(payload.to_vec()),
76                TCA_ACT_IN_HW_COUNT => {
77                    TcActionAttribute::InHwCount(parse_u32(payload).map_err(|error| {
78                        TcError::ParseAction { kind: "TCA_ACT_IN_HW_COUNT", error }
79                    })?)
80                }
81                kind => TcActionAttribute::Other(
82                    DefaultNla::parse(&buf).map_err(|error| TcError::UnknownNla { kind, error })?,
83                ),
84            });
85        }
86        Ok(Self { tab: buf.kind(), attributes })
87    }
88}
89
90const TCA_ACT_KIND: u16 = 1;
91const TCA_ACT_OPTIONS: u16 = 2;
92const TCA_ACT_INDEX: u16 = 3;
93const TCA_ACT_STATS: u16 = 4;
94// const TCA_ACT_PAD: u16 = 5;
95const TCA_ACT_COOKIE: u16 = 6;
96// const TCA_ACT_FLAGS: u16 = 7;
97// const TCA_ACT_HW_STATS: u16 = 8;
98// const TCA_ACT_USED_HW_STATS: u16 = 9;
99const TCA_ACT_IN_HW_COUNT: u16 = 10;
100
101#[derive(Debug, PartialEq, Eq, Clone)]
102#[non_exhaustive]
103pub enum TcActionAttribute {
104    Kind(String),
105    Options(Vec<TcActionOption>),
106    Index(u32),
107    Stats(Vec<TcStats2>),
108    Cookie(Vec<u8>),
109    InHwCount(u32),
110    Other(DefaultNla),
111}
112
113impl Nla for TcActionAttribute {
114    fn value_len(&self) -> usize {
115        match self {
116            Self::Cookie(bytes) => bytes.len(),
117            Self::Kind(k) => k.len() + 1,
118            Self::Options(opt) => opt.as_slice().buffer_len(),
119            Self::Index(_) | Self::InHwCount(_) => 4,
120            Self::Stats(s) => s.as_slice().buffer_len(),
121            Self::Other(attr) => attr.value_len(),
122        }
123    }
124    fn emit_value(&self, buffer: &mut [u8]) {
125        match self {
126            Self::Cookie(bytes) => buffer.copy_from_slice(bytes.as_slice()),
127            Self::Kind(string) => {
128                buffer[..string.as_bytes().len()].copy_from_slice(string.as_bytes());
129                buffer[string.as_bytes().len()] = 0;
130            }
131            Self::Options(opt) => opt.as_slice().emit(buffer),
132            Self::Index(value) | Self::InHwCount(value) => NativeEndian::write_u32(buffer, *value),
133            Self::Stats(s) => s.as_slice().emit(buffer),
134            Self::Other(attr) => attr.emit_value(buffer),
135        }
136    }
137    fn kind(&self) -> u16 {
138        match self {
139            Self::Kind(_) => TCA_ACT_KIND,
140            Self::Options(_) => TCA_ACT_OPTIONS | NLA_F_NESTED,
141            Self::Index(_) => TCA_ACT_INDEX,
142            Self::Stats(_) => TCA_ACT_STATS,
143            Self::Cookie(_) => TCA_ACT_COOKIE,
144            Self::InHwCount(_) => TCA_ACT_IN_HW_COUNT,
145            Self::Other(nla) => nla.kind(),
146        }
147    }
148}
149
150#[derive(Debug, PartialEq, Eq, Clone)]
151#[non_exhaustive]
152pub enum TcActionOption {
153    Mirror(TcActionMirrorOption),
154    Nat(TcActionNatOption),
155    Other(DefaultNla),
156}
157
158impl Nla for TcActionOption {
159    fn value_len(&self) -> usize {
160        match self {
161            Self::Mirror(nla) => nla.value_len(),
162            Self::Nat(nla) => nla.value_len(),
163            Self::Other(nla) => nla.value_len(),
164        }
165    }
166
167    fn emit_value(&self, buffer: &mut [u8]) {
168        match self {
169            Self::Mirror(nla) => nla.emit_value(buffer),
170            Self::Nat(nla) => nla.emit_value(buffer),
171            Self::Other(nla) => nla.emit_value(buffer),
172        }
173    }
174
175    fn kind(&self) -> u16 {
176        match self {
177            Self::Mirror(nla) => nla.kind(),
178            Self::Nat(nla) => nla.kind(),
179            Self::Other(nla) => nla.kind(),
180        }
181    }
182}
183
184impl<'a, T, S> ParseableParametrized<NlaBuffer<&'a T>, S> for TcActionOption
185where
186    T: AsRef<[u8]> + ?Sized,
187    S: AsRef<str>,
188{
189    type Error = TcError;
190    fn parse_with_param(buf: &NlaBuffer<&'a T>, kind: S) -> Result<Self, TcError> {
191        Ok(match kind.as_ref() {
192            TcActionMirror::KIND => {
193                Self::Mirror(TcActionMirrorOption::parse(buf).map_err(TcError::ParseMirrorAction)?)
194            }
195            TcActionNat::KIND => {
196                Self::Nat(TcActionNatOption::parse(buf).map_err(TcError::ParseMirrorAction)?)
197            }
198            _ => Self::Other(DefaultNla::parse(buf).map_err(TcError::ParseMirrorAction)?),
199        })
200    }
201}
202
203// `define tc_gen` in `linux/pkt_cls.h`
204#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
205#[non_exhaustive]
206pub struct TcActionGeneric {
207    pub index: u32,
208    pub capab: u32,
209    pub action: TcActionType,
210    pub refcnt: i32,
211    pub bindcnt: i32,
212}
213
214impl TcActionGeneric {
215    pub(crate) const BUF_LEN: usize = 20;
216}
217
218buffer!(TcActionGenericBuffer(TcActionGeneric::BUF_LEN) {
219    index: (u32, 0..4),
220    capab: (u32, 4..8),
221    action: (i32, 8..12),
222    refcnt: (i32, 12..16),
223    bindcnt: (i32, 16..20),
224});
225
226impl Emitable for TcActionGeneric {
227    fn buffer_len(&self) -> usize {
228        Self::BUF_LEN
229    }
230
231    fn emit(&self, buffer: &mut [u8]) {
232        let mut packet = TcActionGenericBuffer::new(buffer);
233        packet.set_index(self.index);
234        packet.set_capab(self.capab);
235        packet.set_action(self.action.into());
236        packet.set_refcnt(self.refcnt);
237        packet.set_bindcnt(self.bindcnt);
238    }
239}
240
241impl<T: AsRef<[u8]>> Parseable<TcActionGenericBuffer<T>> for TcActionGeneric {
242    type Error = DecodeError;
243    fn parse(buf: &TcActionGenericBuffer<T>) -> Result<Self, DecodeError> {
244        Ok(Self {
245            index: buf.index(),
246            capab: buf.capab(),
247            action: buf.action().into(),
248            refcnt: buf.refcnt(),
249            bindcnt: buf.bindcnt(),
250        })
251    }
252}
253
254const TC_ACT_UNSPEC: i32 = -1;
255const TC_ACT_OK: i32 = 0;
256const TC_ACT_RECLASSIFY: i32 = 1;
257const TC_ACT_SHOT: i32 = 2;
258const TC_ACT_PIPE: i32 = 3;
259const TC_ACT_STOLEN: i32 = 4;
260const TC_ACT_QUEUED: i32 = 5;
261const TC_ACT_REPEAT: i32 = 6;
262const TC_ACT_REDIRECT: i32 = 7;
263const TC_ACT_TRAP: i32 = 8;
264
265#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
266#[non_exhaustive]
267pub enum TcActionType {
268    #[default]
269    Unspec,
270    Ok,
271    Reclassify,
272    Shot,
273    Pipe,
274    Stolen,
275    Queued,
276    Repeat,
277    Redirect,
278    Trap,
279    Other(i32),
280}
281
282impl From<i32> for TcActionType {
283    fn from(d: i32) -> Self {
284        match d {
285            TC_ACT_UNSPEC => Self::Unspec,
286            TC_ACT_OK => Self::Ok,
287            TC_ACT_RECLASSIFY => Self::Reclassify,
288            TC_ACT_SHOT => Self::Shot,
289            TC_ACT_PIPE => Self::Pipe,
290            TC_ACT_STOLEN => Self::Stolen,
291            TC_ACT_QUEUED => Self::Queued,
292            TC_ACT_REPEAT => Self::Repeat,
293            TC_ACT_REDIRECT => Self::Redirect,
294            TC_ACT_TRAP => Self::Trap,
295            _ => Self::Other(d),
296        }
297    }
298}
299
300impl From<TcActionType> for i32 {
301    fn from(v: TcActionType) -> i32 {
302        match v {
303            TcActionType::Unspec => TC_ACT_UNSPEC,
304            TcActionType::Ok => TC_ACT_OK,
305            TcActionType::Reclassify => TC_ACT_RECLASSIFY,
306            TcActionType::Shot => TC_ACT_SHOT,
307            TcActionType::Pipe => TC_ACT_PIPE,
308            TcActionType::Stolen => TC_ACT_STOLEN,
309            TcActionType::Queued => TC_ACT_QUEUED,
310            TcActionType::Repeat => TC_ACT_REPEAT,
311            TcActionType::Redirect => TC_ACT_REDIRECT,
312            TcActionType::Trap => TC_ACT_TRAP,
313            TcActionType::Other(d) => d,
314        }
315    }
316}