netlink_packet_route/link/link_info/
netkit.rs

1// SPDX-License-Identifier: MIT
2
3use netlink_packet_core::{
4    emit_u16, emit_u32, parse_u16, parse_u32, parse_u8, DecodeError,
5    DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer, Parseable,
6};
7
8use super::super::{LinkMessage, LinkMessageBuffer};
9
10const NETKIT_L2: u32 = 0;
11const NETKIT_L3: u32 = 1;
12
13#[derive(Debug, PartialEq, Eq, Clone, Copy)]
14#[non_exhaustive]
15pub enum NetkitMode {
16    L2,
17    L3,
18    Other(u32),
19}
20
21impl From<NetkitMode> for u32 {
22    fn from(mode: NetkitMode) -> Self {
23        match mode {
24            NetkitMode::L2 => NETKIT_L2,
25            NetkitMode::L3 => NETKIT_L3,
26            NetkitMode::Other(value) => value,
27        }
28    }
29}
30
31impl From<u32> for NetkitMode {
32    fn from(value: u32) -> Self {
33        match value {
34            NETKIT_L2 => NetkitMode::L2,
35            NETKIT_L3 => NetkitMode::L3,
36            _ => NetkitMode::Other(value),
37        }
38    }
39}
40
41const NETKIT_PASS: u32 = 0;
42const NETKIT_DROP: u32 = 2;
43const NETKIT_REDIRECT: u32 = 7;
44
45#[derive(Debug, PartialEq, Eq, Clone, Copy)]
46#[non_exhaustive]
47pub enum NetkitPolicy {
48    Pass,
49    Drop,
50    Redirect,
51    Other(u32),
52}
53
54impl NetkitPolicy {
55    /// Alias for the `Pass` policy
56    #[allow(non_upper_case_globals)]
57    pub const Forward: NetkitPolicy = Self::Pass;
58}
59
60impl From<NetkitPolicy> for u32 {
61    fn from(policy: NetkitPolicy) -> Self {
62        match policy {
63            NetkitPolicy::Pass => NETKIT_PASS,
64            NetkitPolicy::Drop => NETKIT_DROP,
65            NetkitPolicy::Redirect => NETKIT_REDIRECT,
66            NetkitPolicy::Other(value) => value,
67        }
68    }
69}
70
71impl From<u32> for NetkitPolicy {
72    fn from(value: u32) -> Self {
73        match value {
74            NETKIT_PASS => NetkitPolicy::Pass,
75            NETKIT_DROP => NetkitPolicy::Drop,
76            _ => NetkitPolicy::Other(value),
77        }
78    }
79}
80
81const NETKIT_SCRUB_NONE: u32 = 0;
82const NETKIT_SCRUB_DEFAULT: u32 = 1;
83
84#[derive(Debug, PartialEq, Eq, Clone, Copy)]
85#[non_exhaustive]
86pub enum NetkitScrub {
87    None,
88    Default,
89}
90
91impl From<NetkitScrub> for u32 {
92    fn from(scrub: NetkitScrub) -> Self {
93        match scrub {
94            NetkitScrub::None => NETKIT_SCRUB_NONE,
95            _ => NETKIT_SCRUB_DEFAULT,
96        }
97    }
98}
99
100impl From<u32> for NetkitScrub {
101    fn from(value: u32) -> Self {
102        match value {
103            NETKIT_SCRUB_NONE => NetkitScrub::None,
104            _ => NetkitScrub::Default,
105        }
106    }
107}
108
109const IFLA_NETKIT_PEER_INFO: u16 = 1;
110const IFLA_NETKIT_PRIMARY: u16 = 2;
111const IFLA_NETKIT_POLICY: u16 = 3;
112const IFLA_NETKIT_PEER_POLICY: u16 = 4;
113const IFLA_NETKIT_MODE: u16 = 5;
114const IFLA_NETKIT_SCRUB: u16 = 6;
115const IFLA_NETKIT_PEER_SCRUB: u16 = 7;
116const IFLA_NETKIT_HEADROOM: u16 = 8;
117const IFLA_NETKIT_TAILROOM: u16 = 9;
118
119#[derive(Debug, PartialEq, Eq, Clone)]
120#[non_exhaustive]
121pub enum InfoNetkit {
122    Peer(LinkMessage),
123    Primary(bool),
124    Policy(NetkitPolicy),
125    PeerPolicy(NetkitPolicy),
126    Mode(NetkitMode),
127    Scrub(NetkitScrub),
128    PeerScrub(NetkitScrub),
129    Headroom(u16),
130    Tailroom(u16),
131    Other(DefaultNla),
132}
133
134impl Nla for InfoNetkit {
135    fn value_len(&self) -> usize {
136        match *self {
137            Self::Peer(ref message) => message.buffer_len(),
138            Self::Primary(_) => 1,
139            Self::Policy(_) | Self::PeerPolicy(_) | Self::Mode(_) => 4,
140            Self::Scrub(_) | Self::PeerScrub(_) => 4,
141            Self::Headroom(_) | Self::Tailroom(_) => 4,
142            Self::Other(ref attr) => attr.value_len(),
143        }
144    }
145
146    fn emit_value(&self, buffer: &mut [u8]) {
147        match *self {
148            Self::Peer(ref message) => message.emit(buffer),
149            Self::Primary(value) => {
150                buffer[0] = value as u8;
151            }
152            Self::Policy(value) | Self::PeerPolicy(value) => {
153                emit_u32(buffer, value.into()).unwrap();
154            }
155            Self::Mode(value) => {
156                emit_u32(buffer, value.into()).unwrap();
157            }
158            Self::Scrub(value) | Self::PeerScrub(value) => {
159                emit_u32(buffer, value.into()).unwrap();
160            }
161            Self::Headroom(value) | Self::Tailroom(value) => {
162                emit_u16(buffer, value).unwrap();
163            }
164            Self::Other(ref attr) => attr.emit_value(buffer),
165        }
166    }
167
168    fn kind(&self) -> u16 {
169        match *self {
170            Self::Peer(_) => IFLA_NETKIT_PEER_INFO,
171            Self::Primary(_) => IFLA_NETKIT_PRIMARY,
172            Self::Policy(_) => IFLA_NETKIT_POLICY,
173            Self::PeerPolicy(_) => IFLA_NETKIT_PEER_POLICY,
174            Self::Mode(_) => IFLA_NETKIT_MODE,
175            Self::Scrub(_) => IFLA_NETKIT_SCRUB,
176            Self::PeerScrub(_) => IFLA_NETKIT_PEER_SCRUB,
177            Self::Headroom(_) => IFLA_NETKIT_HEADROOM,
178            Self::Tailroom(_) => IFLA_NETKIT_TAILROOM,
179            Self::Other(ref attr) => attr.kind(),
180        }
181    }
182}
183
184impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoNetkit {
185    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
186        let payload = buf.value();
187        Ok(match buf.kind() {
188            IFLA_NETKIT_PEER_INFO => {
189                let err = "failed to parse netkit peer info";
190                let buffer =
191                    LinkMessageBuffer::new_checked(&payload).context(err)?;
192                Self::Peer(LinkMessage::parse(&buffer).context(err)?)
193            }
194            IFLA_NETKIT_PRIMARY => {
195                let value = parse_u8(payload)? != 0;
196                Self::Primary(value)
197            }
198            IFLA_NETKIT_POLICY => Self::Policy(parse_u32(payload)?.into()),
199            IFLA_NETKIT_PEER_POLICY => {
200                Self::PeerPolicy(parse_u32(payload)?.into())
201            }
202            IFLA_NETKIT_MODE => Self::Mode(parse_u32(payload)?.into()),
203            IFLA_NETKIT_SCRUB => Self::Scrub(parse_u32(payload)?.into()),
204            IFLA_NETKIT_PEER_SCRUB => {
205                Self::PeerScrub(parse_u32(payload)?.into())
206            }
207            IFLA_NETKIT_HEADROOM => Self::Headroom(parse_u16(payload)?),
208            IFLA_NETKIT_TAILROOM => Self::Tailroom(parse_u16(payload)?),
209            kind => Self::Other(
210                DefaultNla::parse(buf)
211                    .context(format!("unknown NLA type {kind} for netkit"))?,
212            ),
213        })
214    }
215}