netlink_packet_route/rtnl/tc/nlas/action/
mod.rs1pub 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(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}