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