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