1use 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;
94const TCA_ACT_COOKIE: u16 = 6;
96const 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#[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}