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