netlink_packet_route/link/link_info/
vxlan.rs

1// SPDX-License-Identifier: MIT
2
3use std::net::{Ipv4Addr, Ipv6Addr};
4
5use netlink_packet_core::{
6    emit_u16_be, emit_u32, parse_u16_be, parse_u32, parse_u8, DecodeError,
7    DefaultNla, ErrorContext, Nla, NlaBuffer, Parseable,
8};
9
10const IFLA_VXLAN_ID: u16 = 1;
11const IFLA_VXLAN_GROUP: u16 = 2;
12const IFLA_VXLAN_LINK: u16 = 3;
13const IFLA_VXLAN_LOCAL: u16 = 4;
14const IFLA_VXLAN_TTL: u16 = 5;
15const IFLA_VXLAN_TOS: u16 = 6;
16const IFLA_VXLAN_LEARNING: u16 = 7;
17const IFLA_VXLAN_AGEING: u16 = 8;
18const IFLA_VXLAN_LIMIT: u16 = 9;
19const IFLA_VXLAN_PORT_RANGE: u16 = 10;
20const IFLA_VXLAN_PROXY: u16 = 11;
21const IFLA_VXLAN_RSC: u16 = 12;
22const IFLA_VXLAN_L2MISS: u16 = 13;
23const IFLA_VXLAN_L3MISS: u16 = 14;
24const IFLA_VXLAN_PORT: u16 = 15;
25const IFLA_VXLAN_GROUP6: u16 = 16;
26const IFLA_VXLAN_LOCAL6: u16 = 17;
27const IFLA_VXLAN_UDP_CSUM: u16 = 18;
28const IFLA_VXLAN_UDP_ZERO_CSUM6_TX: u16 = 19;
29const IFLA_VXLAN_UDP_ZERO_CSUM6_RX: u16 = 20;
30const IFLA_VXLAN_REMCSUM_TX: u16 = 21;
31const IFLA_VXLAN_REMCSUM_RX: u16 = 22;
32const IFLA_VXLAN_GBP: u16 = 23;
33const IFLA_VXLAN_REMCSUM_NOPARTIAL: u16 = 24;
34const IFLA_VXLAN_COLLECT_METADATA: u16 = 25;
35const IFLA_VXLAN_LABEL: u16 = 26;
36const IFLA_VXLAN_GPE: u16 = 27;
37const IFLA_VXLAN_TTL_INHERIT: u16 = 28;
38const IFLA_VXLAN_DF: u16 = 29;
39const IFLA_VXLAN_VNIFILTER: u16 = 30;
40const IFLA_VXLAN_LOCALBYPASS: u16 = 31;
41
42#[derive(Debug, PartialEq, Eq, Clone)]
43#[non_exhaustive]
44pub enum InfoVxlan {
45    Id(u32),
46    Group(Ipv4Addr),
47    Group6(Ipv6Addr),
48    Link(u32),
49    Local(Ipv4Addr),
50    Local6(Ipv6Addr),
51    Tos(u8),
52    Ttl(u8),
53    Label(u32),
54    Learning(bool),
55    Ageing(u32),
56    Limit(u32),
57    PortRange((u16, u16)),
58    Proxy(bool),
59    Rsc(bool),
60    L2Miss(bool),
61    L3Miss(bool),
62    CollectMetadata(bool),
63    Port(u16),
64    UDPCsum(bool),
65    UDPZeroCsumTX(bool),
66    UDPZeroCsumRX(bool),
67    RemCsumTX(bool),
68    RemCsumRX(bool),
69    Gbp(bool),
70    Gpe(bool),
71    RemCsumNoPartial(bool),
72    TtlInherit(bool),
73    Df(u8),
74    Vnifilter(bool),
75    Localbypass(bool),
76    Other(DefaultNla),
77}
78
79impl Nla for InfoVxlan {
80    fn value_len(&self) -> usize {
81        match self {
82            Self::Tos(_)
83            | Self::Ttl(_)
84            | Self::Learning(_)
85            | Self::Proxy(_)
86            | Self::Rsc(_)
87            | Self::L2Miss(_)
88            | Self::L3Miss(_)
89            | Self::CollectMetadata(_)
90            | Self::UDPCsum(_)
91            | Self::UDPZeroCsumTX(_)
92            | Self::UDPZeroCsumRX(_)
93            | Self::RemCsumTX(_)
94            | Self::RemCsumRX(_)
95            | Self::TtlInherit(_)
96            | Self::Df(_)
97            | Self::Vnifilter(_)
98            | Self::Localbypass(_) => 1,
99            Self::Gbp(_) | Self::Gpe(_) | Self::RemCsumNoPartial(_) => 0,
100            Self::Port(_) => 2,
101            Self::Id(_)
102            | Self::Label(_)
103            | Self::Link(_)
104            | Self::Ageing(_)
105            | Self::Limit(_)
106            | Self::PortRange(_)
107            | Self::Group(_)
108            | Self::Local(_) => 4,
109            Self::Group6(_) | Self::Local6(_) => 16,
110            Self::Other(nla) => nla.value_len(),
111        }
112    }
113
114    fn emit_value(&self, buffer: &mut [u8]) {
115        match self {
116            Self::Id(value)
117            | Self::Label(value)
118            | Self::Link(value)
119            | Self::Ageing(value)
120            | Self::Limit(value) => emit_u32(buffer, *value).unwrap(),
121            Self::Gbp(_value)
122            | Self::Gpe(_value)
123            | Self::RemCsumNoPartial(_value) => (),
124            Self::Tos(value) | Self::Ttl(value) | Self::Df(value) => {
125                buffer[0] = *value
126            }
127            Self::Vnifilter(value)
128            | Self::Localbypass(value)
129            | Self::Learning(value)
130            | Self::Proxy(value)
131            | Self::Rsc(value)
132            | Self::L2Miss(value)
133            | Self::L3Miss(value)
134            | Self::CollectMetadata(value)
135            | Self::UDPCsum(value)
136            | Self::UDPZeroCsumTX(value)
137            | Self::UDPZeroCsumRX(value)
138            | Self::RemCsumTX(value)
139            | Self::RemCsumRX(value)
140            | Self::TtlInherit(value) => buffer[0] = *value as u8,
141            Self::Group(value) | Self::Local(value) => {
142                buffer.copy_from_slice(&value.octets())
143            }
144            Self::Group6(value) | Self::Local6(value) => {
145                buffer.copy_from_slice(&value.octets())
146            }
147            Self::Port(value) => emit_u16_be(buffer, *value).unwrap(),
148            Self::PortRange(range) => {
149                emit_u16_be(buffer, range.0).unwrap();
150                emit_u16_be(&mut buffer[2..], range.1).unwrap()
151            }
152            Self::Other(nla) => nla.emit_value(buffer),
153        }
154    }
155
156    fn kind(&self) -> u16 {
157        match self {
158            Self::Id(_) => IFLA_VXLAN_ID,
159            Self::Group(_) => IFLA_VXLAN_GROUP,
160            Self::Group6(_) => IFLA_VXLAN_GROUP6,
161            Self::Link(_) => IFLA_VXLAN_LINK,
162            Self::Local(_) => IFLA_VXLAN_LOCAL,
163            Self::Local6(_) => IFLA_VXLAN_LOCAL6,
164            Self::Tos(_) => IFLA_VXLAN_TOS,
165            Self::Ttl(_) => IFLA_VXLAN_TTL,
166            Self::Label(_) => IFLA_VXLAN_LABEL,
167            Self::Learning(_) => IFLA_VXLAN_LEARNING,
168            Self::Ageing(_) => IFLA_VXLAN_AGEING,
169            Self::Limit(_) => IFLA_VXLAN_LIMIT,
170            Self::PortRange(_) => IFLA_VXLAN_PORT_RANGE,
171            Self::Proxy(_) => IFLA_VXLAN_PROXY,
172            Self::Rsc(_) => IFLA_VXLAN_RSC,
173            Self::L2Miss(_) => IFLA_VXLAN_L2MISS,
174            Self::L3Miss(_) => IFLA_VXLAN_L3MISS,
175            Self::CollectMetadata(_) => IFLA_VXLAN_COLLECT_METADATA,
176            Self::Port(_) => IFLA_VXLAN_PORT,
177            Self::UDPCsum(_) => IFLA_VXLAN_UDP_CSUM,
178            Self::UDPZeroCsumTX(_) => IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
179            Self::UDPZeroCsumRX(_) => IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
180            Self::RemCsumTX(_) => IFLA_VXLAN_REMCSUM_TX,
181            Self::RemCsumRX(_) => IFLA_VXLAN_REMCSUM_RX,
182            Self::Gbp(_) => IFLA_VXLAN_GBP,
183            Self::Gpe(_) => IFLA_VXLAN_GPE,
184            Self::RemCsumNoPartial(_) => IFLA_VXLAN_REMCSUM_NOPARTIAL,
185            Self::TtlInherit(_) => IFLA_VXLAN_TTL_INHERIT,
186            Self::Df(_) => IFLA_VXLAN_DF,
187            Self::Vnifilter(_) => IFLA_VXLAN_VNIFILTER,
188            Self::Localbypass(_) => IFLA_VXLAN_LOCALBYPASS,
189            Self::Other(nla) => nla.kind(),
190        }
191    }
192}
193
194impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVxlan {
195    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
196        let payload = buf.value();
197        Ok(match buf.kind() {
198            IFLA_VXLAN_ID => Self::Id(
199                parse_u32(payload).context("invalid IFLA_VXLAN_ID value")?,
200            ),
201            IFLA_VXLAN_GROUP => {
202                if payload.len() == 4 {
203                    let mut data = [0u8; 4];
204                    data.copy_from_slice(&payload[0..4]);
205                    Self::Group(Ipv4Addr::from(data))
206                } else {
207                    return Err(DecodeError::from(format!(
208                        "Invalid IFLA_VXLAN_GROUP, got unexpected length of \
209                         IPv4 address payload {payload:?}"
210                    )));
211                }
212            }
213            IFLA_VXLAN_LOCAL => {
214                if payload.len() == 4 {
215                    let mut data = [0u8; 4];
216                    data.copy_from_slice(&payload[0..4]);
217                    Self::Local(Ipv4Addr::from(data))
218                } else {
219                    return Err(DecodeError::from(format!(
220                        "Invalid IFLA_VXLAN_LOCAL, got unexpected length of \
221                         IPv4 address payload {payload:?}"
222                    )));
223                }
224            }
225            IFLA_VXLAN_GROUP6 => {
226                if payload.len() == 16 {
227                    let mut data = [0u8; 16];
228                    data.copy_from_slice(&payload[0..16]);
229                    Self::Group6(Ipv6Addr::from(data))
230                } else {
231                    return Err(DecodeError::from(format!(
232                        "Invalid IFLA_VXLAN_GROUP6, got unexpected length of \
233                         IPv6 address payload {payload:?}"
234                    )));
235                }
236            }
237            IFLA_VXLAN_LOCAL6 => {
238                if payload.len() == 16 {
239                    let mut data = [0u8; 16];
240                    data.copy_from_slice(&payload[0..16]);
241                    Self::Local6(Ipv6Addr::from(data))
242                } else {
243                    return Err(DecodeError::from(format!(
244                        "Invalid IFLA_VXLAN_LOCAL6, got unexpected length of \
245                         IPv6 address payload {payload:?}"
246                    )));
247                }
248            }
249            IFLA_VXLAN_LINK => Self::Link(
250                parse_u32(payload).context("invalid IFLA_VXLAN_LINK value")?,
251            ),
252            IFLA_VXLAN_TOS => Self::Tos(
253                parse_u8(payload).context("invalid IFLA_VXLAN_TOS value")?,
254            ),
255            IFLA_VXLAN_TTL => Self::Ttl(
256                parse_u8(payload).context("invalid IFLA_VXLAN_TTL value")?,
257            ),
258            IFLA_VXLAN_LABEL => Self::Label(
259                parse_u32(payload).context("invalid IFLA_VXLAN_LABEL value")?,
260            ),
261            IFLA_VXLAN_LEARNING => Self::Learning(
262                parse_u8(payload)
263                    .context("invalid IFLA_VXLAN_LEARNING value")?
264                    > 0,
265            ),
266            IFLA_VXLAN_AGEING => Self::Ageing(
267                parse_u32(payload)
268                    .context("invalid IFLA_VXLAN_AGEING value")?,
269            ),
270            IFLA_VXLAN_LIMIT => Self::Limit(
271                parse_u32(payload).context("invalid IFLA_VXLAN_LIMIT value")?,
272            ),
273            IFLA_VXLAN_PROXY => Self::Proxy(
274                parse_u8(payload).context("invalid IFLA_VXLAN_PROXY value")?
275                    > 0,
276            ),
277            IFLA_VXLAN_RSC => Self::Rsc(
278                parse_u8(payload).context("invalid IFLA_VXLAN_RSC value")? > 0,
279            ),
280            IFLA_VXLAN_L2MISS => Self::L2Miss(
281                parse_u8(payload).context("invalid IFLA_VXLAN_L2MISS value")?
282                    > 0,
283            ),
284            IFLA_VXLAN_L3MISS => Self::L3Miss(
285                parse_u8(payload).context("invalid IFLA_VXLAN_L3MISS value")?
286                    > 0,
287            ),
288            IFLA_VXLAN_COLLECT_METADATA => Self::CollectMetadata(
289                parse_u8(payload)
290                    .context("invalid IFLA_VXLAN_COLLECT_METADATA value")?
291                    > 0,
292            ),
293            IFLA_VXLAN_PORT_RANGE => {
294                let err = "invalid IFLA_VXLAN_PORT value";
295                if payload.len() != 4 {
296                    return Err(err.into());
297                }
298                let low = parse_u16_be(&payload[0..2]).context(err)?;
299                let high = parse_u16_be(&payload[2..]).context(err)?;
300                Self::PortRange((low, high))
301            }
302            IFLA_VXLAN_PORT => Self::Port(
303                parse_u16_be(payload)
304                    .context("invalid IFLA_VXLAN_PORT value")?,
305            ),
306            IFLA_VXLAN_UDP_CSUM => Self::UDPCsum(
307                parse_u8(payload)
308                    .context("invalid IFLA_VXLAN_UDP_CSUM value")?
309                    > 0,
310            ),
311            IFLA_VXLAN_UDP_ZERO_CSUM6_TX => Self::UDPZeroCsumTX(
312                parse_u8(payload)
313                    .context("invalid IFLA_VXLAN_UDP_ZERO_CSUM6_TX value")?
314                    > 0,
315            ),
316            IFLA_VXLAN_UDP_ZERO_CSUM6_RX => Self::UDPZeroCsumRX(
317                parse_u8(payload)
318                    .context("invalid IFLA_VXLAN_UDP_ZERO_CSUM6_RX value")?
319                    > 0,
320            ),
321            IFLA_VXLAN_REMCSUM_TX => Self::RemCsumTX(
322                parse_u8(payload)
323                    .context("invalid IFLA_VXLAN_REMCSUM_TX value")?
324                    > 0,
325            ),
326            IFLA_VXLAN_REMCSUM_RX => Self::RemCsumRX(
327                parse_u8(payload)
328                    .context("invalid IFLA_VXLAN_REMCSUM_RX value")?
329                    > 0,
330            ),
331            IFLA_VXLAN_DF => Self::Df(
332                parse_u8(payload).context("invalid IFLA_VXLAN_DF value")?,
333            ),
334            IFLA_VXLAN_GBP => Self::Gbp(true),
335            IFLA_VXLAN_GPE => Self::Gpe(true),
336            IFLA_VXLAN_REMCSUM_NOPARTIAL => Self::RemCsumNoPartial(true),
337            IFLA_VXLAN_TTL_INHERIT => Self::TtlInherit(
338                parse_u8(payload)
339                    .context("invalid IFLA_VXLAN_TTL_INHERIT value")?
340                    > 0,
341            ),
342            IFLA_VXLAN_VNIFILTER => Self::Vnifilter(
343                parse_u8(payload)
344                    .context("invalid IFLA_VXLAN_VNIFILTER value")?
345                    > 0,
346            ),
347            IFLA_VXLAN_LOCALBYPASS => Self::Localbypass(
348                parse_u8(payload)
349                    .context("invalid IFLA_VXLAN_LOCALBYPASS value")?
350                    > 0,
351            ),
352            unknown_kind => {
353                Self::Other(DefaultNla::parse(buf).context(format!(
354                    "Failed to parse IFLA_INFO_DATA(vxlan) NLA type: \
355                     {unknown_kind} as DefaultNla"
356                ))?)
357            }
358        })
359    }
360}