netlink_packet_route/link/link_info/
vxlan.rs

1// SPDX-License-Identifier: MIT
2
3use anyhow::Context;
4use byteorder::{BigEndian, ByteOrder, NativeEndian};
5use netlink_packet_utils::nla::{DefaultNla, Nla, NlaBuffer};
6use netlink_packet_utils::parsers::{parse_u16_be, parse_u32, parse_u8};
7use netlink_packet_utils::traits::Parseable;
8use netlink_packet_utils::DecodeError;
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(Vec<u8>),
47    Group6(Vec<u8>),
48    Link(u32),
49    Local(Vec<u8>),
50    Local6(Vec<u8>),
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(_) => 4,
107            Self::Local(bytes) | Self::Local6(bytes) | Self::Group(bytes) | Self::Group6(bytes) => {
108                bytes.len()
109            }
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) => NativeEndian::write_u32(buffer, *value),
121            Self::Gbp(_value) | Self::Gpe(_value) | Self::RemCsumNoPartial(_value) => (),
122            Self::Tos(value) | Self::Ttl(value) | Self::Df(value) => buffer[0] = *value,
123            Self::Vnifilter(value)
124            | Self::Localbypass(value)
125            | Self::Learning(value)
126            | Self::Proxy(value)
127            | Self::Rsc(value)
128            | Self::L2Miss(value)
129            | Self::L3Miss(value)
130            | Self::CollectMetadata(value)
131            | Self::UDPCsum(value)
132            | Self::UDPZeroCsumTX(value)
133            | Self::UDPZeroCsumRX(value)
134            | Self::RemCsumTX(value)
135            | Self::RemCsumRX(value)
136            | Self::TtlInherit(value) => buffer[0] = *value as u8,
137            Self::Local(value) | Self::Group(value) | Self::Group6(value) | Self::Local6(value) => {
138                buffer.copy_from_slice(value.as_slice())
139            }
140            Self::Port(value) => BigEndian::write_u16(buffer, *value),
141            Self::PortRange(range) => {
142                BigEndian::write_u16(buffer, range.0);
143                BigEndian::write_u16(&mut buffer[2..], range.1)
144            }
145            Self::Other(nla) => nla.emit_value(buffer),
146        }
147    }
148
149    fn kind(&self) -> u16 {
150        match self {
151            Self::Id(_) => IFLA_VXLAN_ID,
152            Self::Group(_) => IFLA_VXLAN_GROUP,
153            Self::Group6(_) => IFLA_VXLAN_GROUP6,
154            Self::Link(_) => IFLA_VXLAN_LINK,
155            Self::Local(_) => IFLA_VXLAN_LOCAL,
156            Self::Local6(_) => IFLA_VXLAN_LOCAL6,
157            Self::Tos(_) => IFLA_VXLAN_TOS,
158            Self::Ttl(_) => IFLA_VXLAN_TTL,
159            Self::Label(_) => IFLA_VXLAN_LABEL,
160            Self::Learning(_) => IFLA_VXLAN_LEARNING,
161            Self::Ageing(_) => IFLA_VXLAN_AGEING,
162            Self::Limit(_) => IFLA_VXLAN_LIMIT,
163            Self::PortRange(_) => IFLA_VXLAN_PORT_RANGE,
164            Self::Proxy(_) => IFLA_VXLAN_PROXY,
165            Self::Rsc(_) => IFLA_VXLAN_RSC,
166            Self::L2Miss(_) => IFLA_VXLAN_L2MISS,
167            Self::L3Miss(_) => IFLA_VXLAN_L3MISS,
168            Self::CollectMetadata(_) => IFLA_VXLAN_COLLECT_METADATA,
169            Self::Port(_) => IFLA_VXLAN_PORT,
170            Self::UDPCsum(_) => IFLA_VXLAN_UDP_CSUM,
171            Self::UDPZeroCsumTX(_) => IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
172            Self::UDPZeroCsumRX(_) => IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
173            Self::RemCsumTX(_) => IFLA_VXLAN_REMCSUM_TX,
174            Self::RemCsumRX(_) => IFLA_VXLAN_REMCSUM_RX,
175            Self::Gbp(_) => IFLA_VXLAN_GBP,
176            Self::Gpe(_) => IFLA_VXLAN_GPE,
177            Self::RemCsumNoPartial(_) => IFLA_VXLAN_REMCSUM_NOPARTIAL,
178            Self::TtlInherit(_) => IFLA_VXLAN_TTL_INHERIT,
179            Self::Df(_) => IFLA_VXLAN_DF,
180            Self::Vnifilter(_) => IFLA_VXLAN_VNIFILTER,
181            Self::Localbypass(_) => IFLA_VXLAN_LOCALBYPASS,
182            Self::Other(nla) => nla.kind(),
183        }
184    }
185}
186
187impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for InfoVxlan {
188    type Error = DecodeError;
189    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
190        let payload = buf.value();
191        Ok(match buf.kind() {
192            IFLA_VXLAN_ID => Self::Id(parse_u32(payload).context("invalid IFLA_VXLAN_ID value")?),
193            IFLA_VXLAN_GROUP => Self::Group(payload.to_vec()),
194            IFLA_VXLAN_GROUP6 => Self::Group6(payload.to_vec()),
195            IFLA_VXLAN_LINK => {
196                Self::Link(parse_u32(payload).context("invalid IFLA_VXLAN_LINK value")?)
197            }
198            IFLA_VXLAN_LOCAL => Self::Local(payload.to_vec()),
199            IFLA_VXLAN_LOCAL6 => Self::Local6(payload.to_vec()),
200            IFLA_VXLAN_TOS => Self::Tos(parse_u8(payload).context("invalid IFLA_VXLAN_TOS value")?),
201            IFLA_VXLAN_TTL => Self::Ttl(parse_u8(payload).context("invalid IFLA_VXLAN_TTL value")?),
202            IFLA_VXLAN_LABEL => {
203                Self::Label(parse_u32(payload).context("invalid IFLA_VXLAN_LABEL value")?)
204            }
205            IFLA_VXLAN_LEARNING => {
206                Self::Learning(parse_u8(payload).context("invalid IFLA_VXLAN_LEARNING value")? > 0)
207            }
208            IFLA_VXLAN_AGEING => {
209                Self::Ageing(parse_u32(payload).context("invalid IFLA_VXLAN_AGEING value")?)
210            }
211            IFLA_VXLAN_LIMIT => {
212                Self::Limit(parse_u32(payload).context("invalid IFLA_VXLAN_LIMIT value")?)
213            }
214            IFLA_VXLAN_PROXY => {
215                Self::Proxy(parse_u8(payload).context("invalid IFLA_VXLAN_PROXY value")? > 0)
216            }
217            IFLA_VXLAN_RSC => {
218                Self::Rsc(parse_u8(payload).context("invalid IFLA_VXLAN_RSC value")? > 0)
219            }
220            IFLA_VXLAN_L2MISS => {
221                Self::L2Miss(parse_u8(payload).context("invalid IFLA_VXLAN_L2MISS value")? > 0)
222            }
223            IFLA_VXLAN_L3MISS => {
224                Self::L3Miss(parse_u8(payload).context("invalid IFLA_VXLAN_L3MISS value")? > 0)
225            }
226            IFLA_VXLAN_COLLECT_METADATA => Self::CollectMetadata(
227                parse_u8(payload).context("invalid IFLA_VXLAN_COLLECT_METADATA value")? > 0,
228            ),
229            IFLA_VXLAN_PORT_RANGE => {
230                let err = "invalid IFLA_VXLAN_PORT value";
231                if payload.len() != 4 {
232                    return Err(err.into());
233                }
234                let low = parse_u16_be(&payload[0..2]).context(err)?;
235                let high = parse_u16_be(&payload[2..]).context(err)?;
236                Self::PortRange((low, high))
237            }
238            IFLA_VXLAN_PORT => {
239                Self::Port(parse_u16_be(payload).context("invalid IFLA_VXLAN_PORT value")?)
240            }
241            IFLA_VXLAN_UDP_CSUM => {
242                Self::UDPCsum(parse_u8(payload).context("invalid IFLA_VXLAN_UDP_CSUM value")? > 0)
243            }
244            IFLA_VXLAN_UDP_ZERO_CSUM6_TX => Self::UDPZeroCsumTX(
245                parse_u8(payload).context("invalid IFLA_VXLAN_UDP_ZERO_CSUM6_TX value")? > 0,
246            ),
247            IFLA_VXLAN_UDP_ZERO_CSUM6_RX => Self::UDPZeroCsumRX(
248                parse_u8(payload).context("invalid IFLA_VXLAN_UDP_ZERO_CSUM6_RX value")? > 0,
249            ),
250            IFLA_VXLAN_REMCSUM_TX => Self::RemCsumTX(
251                parse_u8(payload).context("invalid IFLA_VXLAN_REMCSUM_TX value")? > 0,
252            ),
253            IFLA_VXLAN_REMCSUM_RX => Self::RemCsumRX(
254                parse_u8(payload).context("invalid IFLA_VXLAN_REMCSUM_RX value")? > 0,
255            ),
256            IFLA_VXLAN_DF => Self::Df(parse_u8(payload).context("invalid IFLA_VXLAN_DF value")?),
257            IFLA_VXLAN_GBP => Self::Gbp(true),
258            IFLA_VXLAN_GPE => Self::Gpe(true),
259            IFLA_VXLAN_REMCSUM_NOPARTIAL => Self::RemCsumNoPartial(true),
260            IFLA_VXLAN_TTL_INHERIT => Self::TtlInherit(
261                parse_u8(payload).context("invalid IFLA_VXLAN_TTL_INHERIT value")? > 0,
262            ),
263            IFLA_VXLAN_VNIFILTER => Self::Vnifilter(
264                parse_u8(payload).context("invalid IFLA_VXLAN_VNIFILTER value")? > 0,
265            ),
266            IFLA_VXLAN_LOCALBYPASS => Self::Localbypass(
267                parse_u8(payload).context("invalid IFLA_VXLAN_LOCALBYPASS value")? > 0,
268            ),
269            unknown_kind => Self::Other(DefaultNla::parse(buf).context(format!(
270                "Failed to parse IFLA_INFO_DATA(vxlan) NLA type: {unknown_kind} as DefaultNla"
271            ))?),
272        })
273    }
274}