netlink_packet_route/rtnl/address/nlas/
mod.rs

1// SPDX-License-Identifier: MIT
2
3mod cache_info;
4pub use self::cache_info::*;
5
6use std::mem::size_of;
7
8use anyhow::Context;
9use byteorder::{ByteOrder, NativeEndian};
10use netlink_packet_utils::{
11    nla::{self, DefaultNla, NlaBuffer},
12    parsers::{parse_string, parse_u32},
13    traits::Parseable,
14    DecodeError,
15};
16
17use crate::constants::*;
18
19#[derive(Debug, PartialEq, Eq, Clone)]
20#[non_exhaustive]
21pub enum Nla {
22    Unspec(Vec<u8>),
23    Address(Vec<u8>),
24    Local(Vec<u8>),
25    Label(String),
26    Broadcast(Vec<u8>),
27    Anycast(Vec<u8>),
28    CacheInfo(Vec<u8>),
29    Multicast(Vec<u8>),
30    Flags(u32),
31    Other(DefaultNla),
32}
33
34impl nla::Nla for Nla {
35    #[rustfmt::skip]
36    fn value_len(&self) -> usize {
37        use self::Nla::*;
38        match *self {
39            // Vec<u8>
40            Unspec(ref bytes)
41                | Address(ref bytes)
42                | Local(ref bytes)
43                | Broadcast(ref bytes)
44                | Anycast(ref bytes)
45                | Multicast(ref bytes) => bytes.len(),
46
47            // strings: +1 because we need to append a nul byte
48            Label(ref string) => string.as_bytes().len() + 1,
49
50            // u32
51            Flags(_) => size_of::<u32>(),
52
53            // Native
54            CacheInfo(ref buffer) => buffer.len(),
55
56            // Defaults
57            Other(ref attr)  => attr.value_len(),
58        }
59    }
60
61    #[rustfmt::skip]
62    fn emit_value(&self, buffer: &mut [u8]) {
63        use self::Nla::*;
64        match *self {
65            // Vec<u8>
66            Unspec(ref bytes)
67                | Address(ref bytes)
68                | Local(ref bytes)
69                | Broadcast(ref bytes)
70                | Anycast(ref bytes)
71                | CacheInfo(ref bytes)
72                | Multicast(ref bytes) => buffer.copy_from_slice(bytes.as_slice()),
73
74            // String
75            Label(ref string) => {
76                buffer[..string.len()].copy_from_slice(string.as_bytes());
77                buffer[string.len()] = 0;
78            }
79
80            // u32
81            Flags(ref value) => NativeEndian::write_u32(buffer, *value),
82
83
84            // Default
85            Other(ref attr) => attr.emit_value(buffer),
86        }
87    }
88
89    fn kind(&self) -> u16 {
90        use self::Nla::*;
91        match *self {
92            Unspec(_) => IFA_UNSPEC,
93            Address(_) => IFA_ADDRESS,
94            Local(_) => IFA_LOCAL,
95            Label(_) => IFA_LABEL,
96            Broadcast(_) => IFA_BROADCAST,
97            Anycast(_) => IFA_ANYCAST,
98            CacheInfo(_) => IFA_CACHEINFO,
99            Multicast(_) => IFA_MULTICAST,
100            Flags(_) => IFA_FLAGS,
101            Other(ref nla) => nla.kind(),
102        }
103    }
104}
105
106impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for Nla {
107    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
108        use self::Nla::*;
109        let payload = buf.value();
110        Ok(match buf.kind() {
111            IFA_UNSPEC => Unspec(payload.to_vec()),
112            IFA_ADDRESS => Address(payload.to_vec()),
113            IFA_LOCAL => Local(payload.to_vec()),
114            IFA_LABEL => {
115                Label(parse_string(payload).context("invalid IFA_LABEL value")?)
116            }
117            IFA_BROADCAST => Broadcast(payload.to_vec()),
118            IFA_ANYCAST => Anycast(payload.to_vec()),
119            IFA_CACHEINFO => CacheInfo(payload.to_vec()),
120            IFA_MULTICAST => Multicast(payload.to_vec()),
121            IFA_FLAGS => {
122                Flags(parse_u32(payload).context("invalid IFA_FLAGS value")?)
123            }
124            kind => Other(
125                DefaultNla::parse(buf)
126                    .context(format!("unknown NLA type {kind}"))?,
127            ),
128        })
129    }
130}