netlink_packet_route/route/
lwtunnel.rs

1// SPDX-License-Identifier: MIT
2
3use std::{fmt::Debug, mem::size_of, net::Ipv6Addr};
4
5use netlink_packet_core::{
6    emit_u16_be, emit_u64_be, parse_u16_be, parse_u64_be, parse_u8,
7    DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
8    NlasIterator, Parseable, ParseableParametrized,
9};
10
11use super::{RouteMplsIpTunnel, RouteSeg6IpTunnel};
12use crate::ip::parse_ipv6_addr;
13
14const LWTUNNEL_ENCAP_NONE: u16 = 0;
15const LWTUNNEL_ENCAP_MPLS: u16 = 1;
16const LWTUNNEL_ENCAP_IP: u16 = 2;
17const LWTUNNEL_ENCAP_ILA: u16 = 3;
18const LWTUNNEL_ENCAP_IP6: u16 = 4;
19const LWTUNNEL_ENCAP_SEG6: u16 = 5;
20const LWTUNNEL_ENCAP_BPF: u16 = 6;
21const LWTUNNEL_ENCAP_SEG6_LOCAL: u16 = 7;
22const LWTUNNEL_ENCAP_RPL: u16 = 8;
23const LWTUNNEL_ENCAP_IOAM6: u16 = 9;
24const LWTUNNEL_ENCAP_XFRM: u16 = 10;
25
26const LWTUNNEL_IP6_UNSPEC: u16 = 0;
27const LWTUNNEL_IP6_ID: u16 = 1;
28const LWTUNNEL_IP6_DST: u16 = 2;
29const LWTUNNEL_IP6_SRC: u16 = 3;
30const LWTUNNEL_IP6_HOPLIMIT: u16 = 4;
31const LWTUNNEL_IP6_TC: u16 = 5;
32const LWTUNNEL_IP6_FLAGS: u16 = 6;
33//const LWTUNNEL_IP6_PAD: u16 = 7;
34//const LWTUNNEL_IP6_OPTS: u16 = 8;
35
36const IP_TUNNEL_CSUM_BIT: u16 = 1;
37const IP_TUNNEL_KEY_BIT: u16 = 4;
38const IP_TUNNEL_SEQ_BIT: u16 = 8;
39
40#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
41#[non_exhaustive]
42pub enum RouteLwEnCapType {
43    #[default]
44    None,
45    Mpls,
46    Ip,
47    Ila,
48    Ip6,
49    Seg6,
50    Bpf,
51    Seg6Local,
52    Rpl,
53    Ioam6,
54    Xfrm,
55    Other(u16),
56}
57
58impl From<u16> for RouteLwEnCapType {
59    fn from(d: u16) -> Self {
60        match d {
61            LWTUNNEL_ENCAP_NONE => Self::None,
62            LWTUNNEL_ENCAP_MPLS => Self::Mpls,
63            LWTUNNEL_ENCAP_IP => Self::Ip,
64            LWTUNNEL_ENCAP_ILA => Self::Ila,
65            LWTUNNEL_ENCAP_IP6 => Self::Ip6,
66            LWTUNNEL_ENCAP_SEG6 => Self::Seg6,
67            LWTUNNEL_ENCAP_BPF => Self::Bpf,
68            LWTUNNEL_ENCAP_SEG6_LOCAL => Self::Seg6Local,
69            LWTUNNEL_ENCAP_RPL => Self::Rpl,
70            LWTUNNEL_ENCAP_IOAM6 => Self::Ioam6,
71            LWTUNNEL_ENCAP_XFRM => Self::Xfrm,
72            _ => Self::Other(d),
73        }
74    }
75}
76
77impl From<RouteLwEnCapType> for u16 {
78    fn from(v: RouteLwEnCapType) -> u16 {
79        match v {
80            RouteLwEnCapType::None => LWTUNNEL_ENCAP_NONE,
81            RouteLwEnCapType::Mpls => LWTUNNEL_ENCAP_MPLS,
82            RouteLwEnCapType::Ip => LWTUNNEL_ENCAP_IP,
83            RouteLwEnCapType::Ila => LWTUNNEL_ENCAP_ILA,
84            RouteLwEnCapType::Ip6 => LWTUNNEL_ENCAP_IP6,
85            RouteLwEnCapType::Seg6 => LWTUNNEL_ENCAP_SEG6,
86            RouteLwEnCapType::Bpf => LWTUNNEL_ENCAP_BPF,
87            RouteLwEnCapType::Seg6Local => LWTUNNEL_ENCAP_SEG6_LOCAL,
88            RouteLwEnCapType::Rpl => LWTUNNEL_ENCAP_RPL,
89            RouteLwEnCapType::Ioam6 => LWTUNNEL_ENCAP_IOAM6,
90            RouteLwEnCapType::Xfrm => LWTUNNEL_ENCAP_XFRM,
91            RouteLwEnCapType::Other(d) => d,
92        }
93    }
94}
95
96impl Emitable for RouteLwEnCapType {
97    fn buffer_len(&self) -> usize {
98        2
99    }
100
101    fn emit(&self, buffer: &mut [u8]) {
102        buffer.copy_from_slice(&(u16::from(*self).to_ne_bytes()))
103    }
104}
105
106impl std::fmt::Display for RouteLwEnCapType {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        match self {
109            Self::None => write!(f, "none"),
110            Self::Mpls => write!(f, "mpls"),
111            Self::Ip => write!(f, "ip"),
112            Self::Ila => write!(f, "ila"),
113            Self::Ip6 => write!(f, "ip6"),
114            Self::Seg6 => write!(f, "seg6"),
115            Self::Bpf => write!(f, "bpf"),
116            Self::Seg6Local => write!(f, "seg6_local"),
117            Self::Rpl => write!(f, "rpl"),
118            Self::Ioam6 => write!(f, "ioam6"),
119            Self::Xfrm => write!(f, "xfrm"),
120            Self::Other(d) => write!(f, "other({d})"),
121        }
122    }
123}
124
125#[derive(Debug, PartialEq, Eq, Clone, Default)]
126#[non_exhaustive]
127pub enum RouteIp6Tunnel {
128    #[default]
129    Unspecified,
130    Id(u64),
131    Destination(Ipv6Addr),
132    Source(Ipv6Addr),
133    Hoplimit(u8),
134    Tc(u8),
135    Flags(RouteIp6TunnelFlags),
136    Other(DefaultNla),
137}
138
139bitflags! {
140    #[non_exhaustive]
141    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
142    pub struct RouteIp6TunnelFlags : u16 {
143        const Key = IP_TUNNEL_KEY_BIT;
144        const Checksum = IP_TUNNEL_CSUM_BIT;
145        const Sequence = IP_TUNNEL_SEQ_BIT;
146        const _ = !0;
147    }
148}
149
150impl std::fmt::Display for RouteIp6Tunnel {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        match self {
153            Self::Unspecified => write!(f, "unspecified"),
154            Self::Id(id) => write!(f, "id {id}"),
155            Self::Destination(dst) => write!(f, "dst {dst}"),
156            Self::Source(src) => write!(f, "src, {src}"),
157            Self::Hoplimit(hoplimit) => write!(f, "hoplimit {hoplimit}"),
158            Self::Tc(tc) => write!(f, "tc {tc}"),
159            Self::Flags(flags) => {
160                if flags.contains(RouteIp6TunnelFlags::Key) {
161                    write!(f, "key ")?;
162                }
163                if flags.contains(RouteIp6TunnelFlags::Checksum) {
164                    write!(f, "csum ")?;
165                }
166
167                if flags.contains(RouteIp6TunnelFlags::Sequence) {
168                    write!(f, "seq ")?;
169                }
170
171                Ok(())
172            }
173            Self::Other(other) => other.fmt(f),
174        }
175    }
176}
177
178impl Nla for RouteIp6Tunnel {
179    fn value_len(&self) -> usize {
180        match self {
181            Self::Unspecified => 0,
182            Self::Id(_) => size_of::<u64>(),
183            Self::Destination(_) => size_of::<Ipv6Addr>(),
184            Self::Source(_) => size_of::<Ipv6Addr>(),
185            Self::Hoplimit(_) => size_of::<u8>(),
186            Self::Tc(_) => size_of::<u8>(),
187            Self::Flags(_) => size_of::<u16>(),
188            Self::Other(_) => size_of::<DefaultNla>(),
189        }
190    }
191
192    fn kind(&self) -> u16 {
193        match self {
194            Self::Unspecified => LWTUNNEL_IP6_UNSPEC,
195            Self::Id(_) => LWTUNNEL_IP6_ID,
196            Self::Destination(_) => LWTUNNEL_IP6_DST,
197            Self::Source(_) => LWTUNNEL_IP6_SRC,
198            Self::Hoplimit(_) => LWTUNNEL_IP6_HOPLIMIT,
199            Self::Tc(_) => LWTUNNEL_IP6_TC,
200            Self::Flags(_) => LWTUNNEL_IP6_FLAGS,
201            Self::Other(other) => other.kind(),
202        }
203    }
204
205    fn emit_value(&self, buffer: &mut [u8]) {
206        match self {
207            Self::Unspecified => {}
208            Self::Id(id) => emit_u64_be(buffer, *id).unwrap(),
209            Self::Destination(ip) | Self::Source(ip) => {
210                buffer.copy_from_slice(&ip.octets());
211            }
212            Self::Hoplimit(value) | Self::Tc(value) => buffer[0] = *value,
213            Self::Flags(flags) => emit_u16_be(buffer, flags.bits()).unwrap(),
214            Self::Other(other) => other.emit_value(buffer),
215        }
216    }
217}
218
219impl<'a, T> Parseable<NlaBuffer<&'a T>> for RouteIp6Tunnel
220where
221    T: AsRef<[u8]> + ?Sized,
222{
223    fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
224        let payload = buf.value();
225        Ok(match buf.kind() {
226            LWTUNNEL_IP6_UNSPEC => Self::Unspecified,
227            LWTUNNEL_IP6_ID => Self::Id(
228                parse_u64_be(payload)
229                    .context("invalid LWTUNNEL_IP6_ID value")?,
230            ),
231            LWTUNNEL_IP6_DST => Self::Destination(
232                parse_ipv6_addr(payload)
233                    .context("invalid LWTUNNEL_IP6_DST value")?,
234            ),
235            LWTUNNEL_IP6_SRC => Self::Source(
236                parse_ipv6_addr(payload)
237                    .context("invalid LWTUNNEL_IP6_SRC value")?,
238            ),
239            LWTUNNEL_IP6_HOPLIMIT => Self::Hoplimit(
240                parse_u8(payload)
241                    .context("invalid LWTUNNEL_IP6_HOPLIMIT value")?,
242            ),
243            LWTUNNEL_IP6_TC => Self::Tc(
244                parse_u8(payload).context("invalid LWTUNNEL_IP6_TC value")?,
245            ),
246            LWTUNNEL_IP6_FLAGS => {
247                Self::Flags(RouteIp6TunnelFlags::from_bits_retain(
248                    parse_u16_be(payload)
249                        .context("invalid LWTUNNEL_IP6_FLAGS value")?,
250                ))
251            }
252            _ => Self::Other(DefaultNla::parse(buf)?),
253        })
254    }
255}
256
257#[derive(Debug, PartialEq, Eq, Clone)]
258#[non_exhaustive]
259pub enum RouteLwTunnelEncap {
260    Mpls(RouteMplsIpTunnel),
261    Seg6(RouteSeg6IpTunnel),
262    Ip6(RouteIp6Tunnel),
263    Other(DefaultNla),
264}
265
266impl Nla for RouteLwTunnelEncap {
267    fn value_len(&self) -> usize {
268        match self {
269            Self::Mpls(v) => v.value_len(),
270            Self::Seg6(v) => v.value_len(),
271            Self::Ip6(v) => v.value_len(),
272            Self::Other(v) => v.value_len(),
273        }
274    }
275
276    fn emit_value(&self, buffer: &mut [u8]) {
277        match self {
278            Self::Mpls(v) => v.emit_value(buffer),
279            Self::Seg6(v) => v.emit_value(buffer),
280            Self::Ip6(v) => v.emit_value(buffer),
281            Self::Other(v) => v.emit_value(buffer),
282        }
283    }
284
285    fn kind(&self) -> u16 {
286        match self {
287            Self::Mpls(v) => v.kind(),
288            Self::Seg6(v) => v.kind(),
289            Self::Ip6(v) => v.kind(),
290            Self::Other(v) => v.kind(),
291        }
292    }
293}
294
295impl<'a, T> ParseableParametrized<NlaBuffer<&'a T>, RouteLwEnCapType>
296    for RouteLwTunnelEncap
297where
298    T: AsRef<[u8]> + ?Sized,
299{
300    fn parse_with_param(
301        buf: &NlaBuffer<&'a T>,
302        kind: RouteLwEnCapType,
303    ) -> Result<Self, DecodeError> {
304        Ok(match kind {
305            RouteLwEnCapType::Mpls => {
306                Self::Mpls(RouteMplsIpTunnel::parse(buf)?)
307            }
308            RouteLwEnCapType::Seg6 => {
309                Self::Seg6(RouteSeg6IpTunnel::parse(buf)?)
310            }
311            RouteLwEnCapType::Ip6 => Self::Ip6(RouteIp6Tunnel::parse(buf)?),
312            _ => Self::Other(DefaultNla::parse(buf)?),
313        })
314    }
315}
316
317#[derive(Debug, PartialEq, Eq, Clone)]
318#[non_exhaustive]
319pub(crate) struct VecRouteLwTunnelEncap(pub(crate) Vec<RouteLwTunnelEncap>);
320
321impl<'a, T> ParseableParametrized<NlaBuffer<&'a T>, RouteLwEnCapType>
322    for VecRouteLwTunnelEncap
323where
324    T: AsRef<[u8]> + ?Sized,
325{
326    fn parse_with_param(
327        buf: &NlaBuffer<&'a T>,
328        kind: RouteLwEnCapType,
329    ) -> Result<Self, DecodeError> {
330        let mut ret = Vec::new();
331        for nla in NlasIterator::new(buf.value()) {
332            let nla =
333                nla.context(format!("Invalid RTA_ENCAP for kind: {kind}"))?;
334            ret.push(RouteLwTunnelEncap::parse_with_param(&nla, kind).context(
335                format!("Failed to parse RTA_ENCAP for kind: {kind}",),
336            )?)
337        }
338        Ok(Self(ret))
339    }
340}