netlink_packet_route/tc/actions/
message.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    parse_string, parse_u32, parse_u32_be, DecodeError, DefaultNla, Emitable,
5    ErrorContext, Nla, NlaBuffer, NlasIterator, Parseable,
6};
7
8use crate::tc::{
9    actions::{TcActionMessageBuffer, TcActionMessageHeader},
10    TcAction,
11};
12
13/// Message to describe [tc-actions]
14///
15/// [tc-actions]: https://man7.org/linux/man-pages/man8/tc-actions.8.html
16#[derive(Debug, PartialEq, Eq, Clone, Default)]
17#[non_exhaustive]
18pub struct TcActionMessage {
19    /// Header of the message.
20    pub header: TcActionMessageHeader,
21    /// Attributes of the message.
22    pub attributes: Vec<TcActionMessageAttribute>,
23}
24
25const TCA_ACT_FLAG_LARGE_DUMP_ON: u32 = 1 << 0;
26const TCA_ACT_FLAG_TERSE_DUMP: u32 = 1 << 1;
27
28bitflags! {
29    /// Flags to configure action dumps (list operations).
30    #[derive(Debug, PartialEq, Eq, Clone, Copy, Default, PartialOrd, Ord, Hash)]
31    #[non_exhaustive]
32    pub struct TcActionMessageFlags: u32 {
33        /// If set, this flag enables more than `TCA_ACT_MAX_PRIO` actions in a single
34        /// actions listing operation.
35        const LargeDump = TCA_ACT_FLAG_LARGE_DUMP_ON;
36        /// If set, this flag restricts an action dump to only include essential
37        /// details.
38        const TerseDump = TCA_ACT_FLAG_TERSE_DUMP;
39        const _ = !0;
40    }
41}
42
43/// [`TcActionMessageFlagsWithSelector`] sets the [`TcActionMessageFlags`] which
44/// are to be included in an operation, based on the accompanying [`flags`] and
45/// [`selector`] fields.
46///
47/// [`flags`]: #structfield.flags
48/// [`selector`]: #structfield.selector
49#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, PartialOrd, Ord, Hash)]
50pub struct TcActionMessageFlagsWithSelector {
51    /// A bitmask of [`TcActionMessageFlags`] to be associated with an
52    /// operation.
53    pub flags: TcActionMessageFlags,
54    /// A bitmask to determine which flags are to be included in an operation.
55    ///
56    /// Any flags which are set in the [`flags`] field but which are not set in
57    /// the [`selector`] field will be ignored.
58    ///
59    /// [`flags`]: #structfield.flags
60    /// [`selector`]: #structfield.selector
61    pub selector: TcActionMessageFlags,
62}
63
64impl Nla for TcActionMessageFlagsWithSelector {
65    fn value_len(&self) -> usize {
66        8
67    }
68
69    fn kind(&self) -> u16 {
70        TCA_ROOT_FLAGS
71    }
72
73    fn emit_value(&self, buffer: &mut [u8]) {
74        buffer[..4].copy_from_slice(&self.flags.bits().to_ne_bytes());
75        buffer[4..8].copy_from_slice(&self.selector.bits().to_ne_bytes());
76    }
77}
78
79impl TcActionMessageFlagsWithSelector {
80    /// Create a new [`TcActionMessageFlagsWithSelector`] with the given
81    /// [`flags`].
82    /// The [`selector`] field is set to the same value as [`flags`] (i.e., none
83    /// of the [`flags`] will be ignored).
84    ///
85    /// [`flags`]: #structfield.flags
86    /// [`selector`]: #structfield.selector
87    #[must_use]
88    pub fn new(flags: TcActionMessageFlags) -> Self {
89        Self {
90            flags,
91            selector: flags,
92        }
93    }
94
95    /// Create a new [`TcActionMessageFlagsWithSelector`] with the given
96    /// [`flags`] and [`selector`].
97    ///
98    /// [`flags`]: #structfield.flags
99    /// [`selector`]: #structfield.selector
100    #[must_use]
101    pub fn new_with_selector(
102        flags: TcActionMessageFlags,
103        selector: TcActionMessageFlags,
104    ) -> Self {
105        Self { flags, selector }
106    }
107}
108
109impl<'a, T: AsRef<[u8]> + 'a + ?Sized> Parseable<NlaBuffer<&'a T>>
110    for TcActionMessageFlagsWithSelector
111{
112    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
113        let value = buf.value();
114        if value.len() != 8 {
115            return Err(DecodeError::from("invalid length"));
116        }
117        let flags = TcActionMessageFlags::from_bits(
118            parse_u32(&value[..4]).context("invalid flags")?,
119        )
120        .ok_or_else(|| DecodeError::from("invalid flags selector"))?;
121        let selector = TcActionMessageFlags::from_bits(
122            parse_u32(&value[4..]).context("invalid flags seclector")?,
123        )
124        .ok_or_else(|| DecodeError::from("invalid flags selector"))?;
125        Ok(Self::new_with_selector(flags, selector))
126    }
127}
128
129const TCA_ACT_TAB: u16 = 1;
130const TCA_ROOT_FLAGS: u16 = 2;
131const TCA_ROOT_COUNT: u16 = 3;
132const TCA_ROOT_TIME_DELTA: u16 = 4;
133const TCA_ROOT_EXT_WARN_MSG: u16 = 5;
134
135/// This enum is used to represent the different types of attributes that can be
136/// part of a [`TcActionMessage`].
137///
138/// This enum is non-exhaustive, additional variants may be added in the future.
139#[derive(Debug, PartialEq, Eq, Clone)]
140#[non_exhaustive]
141pub enum TcActionMessageAttribute {
142    /// Collection of `TcActions`.
143    Actions(Vec<TcAction>),
144    /// Flags to configure action dumps (list operations).
145    Flags(TcActionMessageFlagsWithSelector),
146    /// Number of actions being dumped.
147    RootCount(u32),
148    /// Time delta.
149    RootTimeDelta(u32),
150    /// Extended warning message.
151    RootExtWarnMsg(String),
152    /// Other attributes unknown at the time of writing.
153    Other(DefaultNla),
154}
155
156impl<'a, T: AsRef<[u8]> + 'a + ?Sized> Parseable<NlaBuffer<&'a T>>
157    for TcActionMessageAttribute
158{
159    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
160        Ok(match buf.kind() {
161            TCA_ACT_TAB => {
162                let actions = NlasIterator::new(buf.value())
163                    .map(|nla| TcAction::parse(&nla?))
164                    .collect::<Result<Vec<_>, _>>()?;
165                Self::Actions(actions)
166            }
167            TCA_ROOT_FLAGS => {
168                Self::Flags(TcActionMessageFlagsWithSelector::parse(buf)?)
169            }
170            TCA_ROOT_COUNT => {
171                let count =
172                    parse_u32(buf.value()).context("Invalid TCA_ROOT_COUNT")?;
173                Self::RootCount(count)
174            }
175            TCA_ROOT_TIME_DELTA => {
176                let delta = parse_u32_be(buf.value())
177                    .context("Invalid TCA_ROOT_TIME_DELTA")?;
178                Self::RootTimeDelta(delta)
179            }
180            TCA_ROOT_EXT_WARN_MSG => {
181                let msg = parse_string(buf.value())
182                    .context("Invalid TCA_ROOT_EXT_WARN_MSG")?;
183                Self::RootExtWarnMsg(msg)
184            }
185            _ => Self::Other(DefaultNla::parse(buf)?),
186        })
187    }
188}
189
190impl Nla for TcActionMessageAttribute {
191    fn value_len(&self) -> usize {
192        match self {
193            Self::Actions(actions) => actions.as_slice().buffer_len(),
194            Self::Flags(_) => 8,
195            Self::RootCount(_) => 4,
196            Self::RootTimeDelta(_) => 4,
197            Self::RootExtWarnMsg(msg) => msg.len(),
198            Self::Other(nla) => nla.value_len(),
199        }
200    }
201
202    fn kind(&self) -> u16 {
203        match self {
204            Self::Actions(_) => TCA_ACT_TAB,
205            Self::Flags(_) => TCA_ROOT_FLAGS,
206            Self::RootCount(_) => TCA_ROOT_COUNT,
207            Self::RootTimeDelta(_) => TCA_ROOT_TIME_DELTA,
208            Self::RootExtWarnMsg(_) => TCA_ROOT_EXT_WARN_MSG,
209            Self::Other(nla) => nla.kind(),
210        }
211    }
212
213    fn emit_value(&self, buffer: &mut [u8]) {
214        match self {
215            Self::Actions(actions) => actions.as_slice().emit(buffer),
216            Self::Flags(flags) => {
217                flags.emit_value(buffer);
218            }
219            Self::RootCount(count) => {
220                buffer.copy_from_slice(&count.to_ne_bytes());
221            }
222            Self::RootTimeDelta(delta) => {
223                buffer.copy_from_slice(&delta.to_be_bytes());
224            }
225            Self::RootExtWarnMsg(msg) => buffer.copy_from_slice(msg.as_bytes()),
226            Self::Other(nla) => nla.emit_value(buffer),
227        }
228    }
229}
230
231impl<'a, T: AsRef<[u8]> + 'a + ?Sized> Parseable<TcActionMessageBuffer<&'a T>>
232    for TcActionMessage
233{
234    fn parse(buf: &TcActionMessageBuffer<&'a T>) -> Result<Self, DecodeError> {
235        let attrs: Result<Vec<_>, DecodeError> = buf
236            .attributes()
237            .map(|attr| TcActionMessageAttribute::parse(&attr?))
238            .collect::<Result<Vec<_>, _>>();
239
240        Ok(Self {
241            header: TcActionMessageHeader::parse(buf)
242                .context("failed to parse tc message header")?,
243            attributes: attrs?,
244        })
245    }
246}
247
248impl Emitable for TcActionMessage {
249    fn buffer_len(&self) -> usize {
250        self.header.buffer_len() + self.attributes.as_slice().buffer_len()
251    }
252
253    fn emit(&self, buffer: &mut [u8]) {
254        self.header.emit(buffer);
255        self.attributes
256            .as_slice()
257            .emit(&mut buffer[self.header.buffer_len()..]);
258    }
259}