netlink_packet_route/tc/actions/
mirror.rs

1// SPDX-License-Identifier: MIT
2
3/// Mirror 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::{DefaultNla, Nla, NlaBuffer},
11    traits::{Emitable, Parseable},
12    DecodeError,
13};
14
15use super::{
16    TcActionGeneric, TcActionGenericBuffer, Tcf, TcfBuffer, TC_TCF_BUF_LEN,
17};
18
19/// Traffic control action used to mirror or redirect packets.
20#[derive(Debug, PartialEq, Eq, Clone)]
21#[non_exhaustive]
22pub struct TcActionMirror {}
23impl TcActionMirror {
24    /// The `TcActionAttribute::Kind` of this action.
25    pub const KIND: &'static str = "mirred";
26}
27
28const TCA_MIRRED_TM: u16 = 1;
29const TCA_MIRRED_PARMS: u16 = 2;
30
31/// Options for the `TcActionMirror` action.
32#[derive(Debug, PartialEq, Eq, Clone)]
33#[non_exhaustive]
34pub enum TcActionMirrorOption {
35    /// Rule installation and usage time
36    Tm(Tcf),
37    /// Parameters for the mirred action.
38    Parms(TcMirror),
39    /// Other attributes unknown at the time of writing.
40    Other(DefaultNla),
41}
42
43impl Nla for TcActionMirrorOption {
44    fn value_len(&self) -> usize {
45        match self {
46            Self::Tm(_) => TC_TCF_BUF_LEN,
47            Self::Parms(_) => TC_MIRRED_BUF_LEN,
48            Self::Other(attr) => attr.value_len(),
49        }
50    }
51
52    fn emit_value(&self, buffer: &mut [u8]) {
53        match self {
54            Self::Tm(p) => p.emit(buffer),
55            Self::Parms(p) => p.emit(buffer),
56            Self::Other(attr) => attr.emit_value(buffer),
57        }
58    }
59    fn kind(&self) -> u16 {
60        match self {
61            Self::Tm(_) => TCA_MIRRED_TM,
62            Self::Parms(_) => TCA_MIRRED_PARMS,
63            Self::Other(nla) => nla.kind(),
64        }
65    }
66}
67
68impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
69    for TcActionMirrorOption
70{
71    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
72        let payload = buf.value();
73        Ok(match buf.kind() {
74            TCA_MIRRED_TM => {
75                Self::Tm(Tcf::parse(&TcfBuffer::new_checked(payload)?)?)
76            }
77            TCA_MIRRED_PARMS => Self::Parms(TcMirror::parse(
78                &TcMirrorBuffer::new_checked(payload)?,
79            )?),
80            _ => Self::Other(DefaultNla::parse(buf)?),
81        })
82    }
83}
84
85const TC_MIRRED_BUF_LEN: usize = TcActionGeneric::BUF_LEN + 8;
86
87/// Parameters for the mirred action.
88#[derive(Debug, PartialEq, Eq, Clone, Default)]
89#[non_exhaustive]
90pub struct TcMirror {
91    /// Generic action parameters.
92    pub generic: TcActionGeneric,
93    /// Describes how the packet be mirrored or redirected.
94    pub eaction: TcMirrorActionType,
95    /// Interface index to mirror or redirect to.
96    pub ifindex: u32,
97}
98
99// kernel struct `tc_mirred`
100buffer!(TcMirrorBuffer(TC_MIRRED_BUF_LEN) {
101    generic: (slice, 0..20),
102    eaction: (i32, 20..24),
103    ifindex: (u32, 24..28),
104});
105
106impl Emitable for TcMirror {
107    fn buffer_len(&self) -> usize {
108        TC_MIRRED_BUF_LEN
109    }
110
111    fn emit(&self, buffer: &mut [u8]) {
112        let mut packet = TcMirrorBuffer::new(buffer);
113        self.generic.emit(packet.generic_mut());
114        packet.set_eaction(self.eaction.into());
115        packet.set_ifindex(self.ifindex);
116    }
117}
118
119impl<T: AsRef<[u8]> + ?Sized> Parseable<TcMirrorBuffer<&T>> for TcMirror {
120    fn parse(buf: &TcMirrorBuffer<&T>) -> Result<Self, DecodeError> {
121        Ok(Self {
122            generic: TcActionGeneric::parse(&TcActionGenericBuffer::new(
123                buf.generic(),
124            ))?,
125            eaction: buf.eaction().into(),
126            ifindex: buf.ifindex(),
127        })
128    }
129}
130
131const TCA_EGRESS_REDIR: i32 = 1;
132const TCA_EGRESS_MIRROR: i32 = 2;
133const TCA_INGRESS_REDIR: i32 = 3;
134const TCA_INGRESS_MIRROR: i32 = 4;
135
136/// Type of mirroring or redirecting action.
137#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
138#[non_exhaustive]
139pub enum TcMirrorActionType {
140    #[default]
141    /// Redirect to the egress pipeline.
142    EgressRedir,
143    /// Mirror to the egress pipeline.
144    EgressMirror,
145    /// Redirect to the ingress pipeline.
146    IngressRedir,
147    /// Mirror to the ingress pipeline.
148    IngressMirror,
149    /// Other action type unknown at the time of writing.
150    Other(i32),
151}
152
153impl From<i32> for TcMirrorActionType {
154    fn from(d: i32) -> Self {
155        match d {
156            TCA_EGRESS_REDIR => Self::EgressRedir,
157            TCA_EGRESS_MIRROR => Self::EgressMirror,
158            TCA_INGRESS_REDIR => Self::IngressRedir,
159            TCA_INGRESS_MIRROR => Self::IngressMirror,
160            _ => Self::Other(d),
161        }
162    }
163}
164
165impl From<TcMirrorActionType> for i32 {
166    fn from(v: TcMirrorActionType) -> i32 {
167        match v {
168            TcMirrorActionType::EgressRedir => TCA_EGRESS_REDIR,
169            TcMirrorActionType::EgressMirror => TCA_EGRESS_MIRROR,
170            TcMirrorActionType::IngressRedir => TCA_INGRESS_REDIR,
171            TcMirrorActionType::IngressMirror => TCA_INGRESS_MIRROR,
172            TcMirrorActionType::Other(d) => d,
173        }
174    }
175}