netlink_packet_route/neighbour_table/
attribute.rs

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