netlink_packet_route/neighbour_table/
attribute.rs

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