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

1// SPDX-License-Identifier: MIT
2
3/// Mirred action
4///
5/// The mirred action allows packet mirroring (copying) or
6/// redirecting (stealing) the packet it receives. Mirroring is what
7/// is sometimes referred to as Switch Port Analyzer (SPAN) and is
8/// commonly used to analyze and/or debug flows.
9use netlink_packet_utils::{
10    nla::{self, DefaultNla, NlaBuffer},
11    traits::{Emitable, Parseable},
12    DecodeError,
13};
14
15use crate::tc::{constants::*, TC_GEN_BUF_LEN};
16
17pub const KIND: &str = "mirred";
18pub const TC_MIRRED_BUF_LEN: usize = TC_GEN_BUF_LEN + 8;
19
20#[derive(Debug, PartialEq, Eq, Clone)]
21#[non_exhaustive]
22pub enum Nla {
23    Unspec(Vec<u8>),
24    Tm(Vec<u8>),
25    Parms(TcMirred),
26    Other(DefaultNla),
27}
28
29impl nla::Nla for Nla {
30    fn value_len(&self) -> usize {
31        use self::Nla::*;
32        match self {
33            Unspec(bytes) | Tm(bytes) => bytes.len(),
34            Parms(_) => TC_MIRRED_BUF_LEN,
35            Other(attr) => attr.value_len(),
36        }
37    }
38
39    fn emit_value(&self, buffer: &mut [u8]) {
40        use self::Nla::*;
41        match self {
42            Unspec(bytes) | Tm(bytes) => {
43                buffer.copy_from_slice(bytes.as_slice())
44            }
45            Parms(p) => p.emit(buffer),
46            Other(attr) => attr.emit_value(buffer),
47        }
48    }
49    fn kind(&self) -> u16 {
50        use self::Nla::*;
51        match self {
52            Unspec(_) => TCA_MIRRED_UNSPEC,
53            Tm(_) => TCA_MIRRED_TM,
54            Parms(_) => TCA_MIRRED_PARMS,
55            Other(nla) => nla.kind(),
56        }
57    }
58}
59
60impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {
61    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
62        use self::Nla::*;
63        let payload = buf.value();
64        Ok(match buf.kind() {
65            TCA_MIRRED_UNSPEC => Unspec(payload.to_vec()),
66            TCA_MIRRED_TM => Tm(payload.to_vec()),
67            TCA_MIRRED_PARMS => {
68                Parms(TcMirred::parse(&TcMirredBuffer::new_checked(payload)?)?)
69            }
70            _ => Other(DefaultNla::parse(buf)?),
71        })
72    }
73}
74
75#[derive(Debug, PartialEq, Eq, Clone, Default)]
76#[non_exhaustive]
77pub struct TcMirred {
78    pub index: u32,
79    pub capab: u32,
80    pub action: i32,
81    pub refcnt: i32,
82    pub bindcnt: i32,
83
84    pub eaction: i32,
85    pub ifindex: u32,
86}
87
88buffer!(TcMirredBuffer(TC_MIRRED_BUF_LEN) {
89    index: (u32, 0..4),
90    capab: (u32, 4..8),
91    action: (i32, 8..12),
92    refcnt: (i32, 12..16),
93    bindcnt: (i32, 16..20),
94    eaction: (i32, TC_GEN_BUF_LEN..(TC_GEN_BUF_LEN + 4)),
95    ifindex: (u32, (TC_GEN_BUF_LEN + 4)..TC_MIRRED_BUF_LEN),
96});
97
98impl Emitable for TcMirred {
99    fn buffer_len(&self) -> usize {
100        TC_MIRRED_BUF_LEN
101    }
102
103    fn emit(&self, buffer: &mut [u8]) {
104        let mut packet = TcMirredBuffer::new(buffer);
105        packet.set_index(self.index);
106        packet.set_capab(self.capab);
107        packet.set_action(self.action);
108        packet.set_refcnt(self.refcnt);
109        packet.set_bindcnt(self.bindcnt);
110
111        packet.set_eaction(self.eaction);
112        packet.set_ifindex(self.ifindex);
113    }
114}
115
116impl<T: AsRef<[u8]>> Parseable<TcMirredBuffer<T>> for TcMirred {
117    fn parse(buf: &TcMirredBuffer<T>) -> Result<Self, DecodeError> {
118        Ok(Self {
119            index: buf.index(),
120            capab: buf.capab(),
121            action: buf.action(),
122            refcnt: buf.refcnt(),
123            bindcnt: buf.bindcnt(),
124            eaction: buf.eaction(),
125            ifindex: buf.ifindex(),
126        })
127    }
128}