netlink_packet_route/neighbour_table/
attribute.rs

1// SPDX-License-Identifier: MIT
2
3use super::param::VecNeighbourTableParameter;
4use super::{
5    NeighbourTableConfig, NeighbourTableConfigBuffer, NeighbourTableError, NeighbourTableParameter,
6    NeighbourTableStats, NeighbourTableStatsBuffer,
7};
8use byteorder::{ByteOrder, NativeEndian};
9use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer};
10use netlink_packet_utils::parsers::{parse_string, parse_u32, parse_u64};
11use netlink_packet_utils::{Emitable, Parseable};
12
13const NDTA_NAME: u16 = 1;
14const NDTA_THRESH1: u16 = 2;
15const NDTA_THRESH2: u16 = 3;
16const NDTA_THRESH3: u16 = 4;
17const NDTA_CONFIG: u16 = 5;
18const NDTA_PARMS: u16 = 6;
19const NDTA_STATS: u16 = 7;
20const NDTA_GC_INTERVAL: u16 = 8;
21
22#[derive(Debug, PartialEq, Eq, Clone)]
23#[non_exhaustive]
24pub enum NeighbourTableAttribute {
25    Parms(Vec<NeighbourTableParameter>),
26    Name(String),
27    Threshold1(u32),
28    Threshold2(u32),
29    Threshold3(u32),
30    Config(NeighbourTableConfig),
31    Stats(NeighbourTableStats),
32    GcInterval(u64),
33    Other(DefaultNla),
34}
35
36impl Nla for NeighbourTableAttribute {
37    fn value_len(&self) -> usize {
38        match self {
39            Self::Parms(v) => v.as_slice().buffer_len(),
40            Self::Stats(v) => v.buffer_len(),
41            Self::Config(v) => v.buffer_len(),
42            // strings: +1 because we need to append a nul byte
43            Self::Name(s) => s.len() + 1,
44            Self::Threshold1(_) | Self::Threshold2(_) | Self::Threshold3(_) => 4,
45            Self::GcInterval(_) => 8,
46            Self::Other(attr) => attr.value_len(),
47        }
48    }
49
50    fn emit_value(&self, buffer: &mut [u8]) {
51        match self {
52            Self::Parms(v) => v.as_slice().emit(buffer),
53            Self::Stats(v) => v.emit(buffer),
54            Self::Config(v) => v.emit(buffer),
55            Self::Name(string) => {
56                buffer[..string.len()].copy_from_slice(string.as_bytes());
57                buffer[string.len()] = 0;
58            }
59            Self::GcInterval(value) => NativeEndian::write_u64(buffer, *value),
60            Self::Threshold1(value) | Self::Threshold2(value) | Self::Threshold3(value) => {
61                NativeEndian::write_u32(buffer, *value)
62            }
63            Self::Other(attr) => attr.emit_value(buffer),
64        }
65    }
66
67    fn kind(&self) -> u16 {
68        match self {
69            Self::Name(_) => NDTA_NAME,
70            Self::Config(_) => NDTA_CONFIG,
71            Self::Stats(_) => NDTA_STATS,
72            Self::Parms(_) => NDTA_PARMS,
73            Self::GcInterval(_) => NDTA_GC_INTERVAL,
74            Self::Threshold1(_) => NDTA_THRESH1,
75            Self::Threshold2(_) => NDTA_THRESH2,
76            Self::Threshold3(_) => NDTA_THRESH3,
77            Self::Other(attr) => attr.kind(),
78        }
79    }
80}
81
82impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for NeighbourTableAttribute {
83    type Error = NeighbourTableError;
84    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, Self::Error> {
85        let payload = buf.value();
86        Ok(match buf.kind() {
87            NDTA_NAME => {
88                Self::Name(parse_string(payload).map_err(|error| {
89                    NeighbourTableError::InvalidValue { kind: "NDTA_NAME", error }
90                })?)
91            }
92            NDTA_CONFIG => Self::Config(
93                NeighbourTableConfig::parse(
94                    &NeighbourTableConfigBuffer::new_checked(payload).map_err(|error| {
95                        NeighbourTableError::InvalidValue { kind: "NDTA_CONFIG", error }
96                    })?,
97                )
98                .map_err(|error| NeighbourTableError::InvalidValue {
99                    kind: "NDTA_CONFIG",
100                    error,
101                })?,
102            ),
103            NDTA_STATS => Self::Stats(
104                NeighbourTableStats::parse(
105                    &NeighbourTableStatsBuffer::new_checked(payload).map_err(|error| {
106                        NeighbourTableError::InvalidValue { kind: "NDTA_STATS", error }
107                    })?,
108                )
109                .map_err(|error| NeighbourTableError::InvalidValue { kind: "NDTA_STATS", error })?,
110            ),
111            NDTA_PARMS => {
112                Self::Parms(VecNeighbourTableParameter::parse(&NlaBuffer::new_checked(payload)?)?.0)
113            }
114            NDTA_GC_INTERVAL => Self::GcInterval(parse_u64(payload).map_err(|error| {
115                NeighbourTableError::InvalidValue { kind: "NDTA_GC_INTERVAL", error }
116            })?),
117            NDTA_THRESH1 => Self::Threshold1(parse_u32(payload).map_err(|error| {
118                NeighbourTableError::InvalidValue { kind: "NDTA_THRESH1", error }
119            })?),
120            NDTA_THRESH2 => Self::Threshold2(parse_u32(payload).map_err(|error| {
121                NeighbourTableError::InvalidValue { kind: "NDTA_THRESH2", error }
122            })?),
123            NDTA_THRESH3 => Self::Threshold3(parse_u32(payload).map_err(|error| {
124                NeighbourTableError::InvalidValue { kind: "NDTA_THRESH3", error }
125            })?),
126            kind => Self::Other(
127                DefaultNla::parse(buf)
128                    .map_err(|error| NeighbourTableError::UnknownNla { kind, error })?,
129            ),
130        })
131    }
132}