netlink_packet_route/link/link_info/
iptunnel.rs

1// SPDX-License-Identifier: MIT
2
3use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4
5use netlink_packet_core::{
6    emit_u16, emit_u16_be, emit_u32, parse_u16, parse_u16_be, parse_u32,
7    parse_u8, DecodeError, DefaultNla, ErrorContext, Nla, NlaBuffer, Parseable,
8    ParseableParametrized,
9};
10
11use crate::ip::{parse_ip_addr, IpProtocol};
12
13const IFLA_IPTUN_LINK: u16 = 1;
14const IFLA_IPTUN_LOCAL: u16 = 2;
15const IFLA_IPTUN_REMOTE: u16 = 3;
16const IFLA_IPTUN_TTL: u16 = 4;
17const IFLA_IPTUN_TOS: u16 = 5;
18const IFLA_IPTUN_ENCAP_LIMIT: u16 = 6;
19const IFLA_IPTUN_FLOWINFO: u16 = 7;
20const IFLA_IPTUN_FLAGS: u16 = 8;
21const IFLA_IPTUN_PROTO: u16 = 9;
22const IFLA_IPTUN_PMTUDISC: u16 = 10;
23const IFLA_IPTUN_6RD_PREFIX: u16 = 11;
24const IFLA_IPTUN_6RD_RELAY_PREFIX: u16 = 12;
25const IFLA_IPTUN_6RD_PREFIXLEN: u16 = 13;
26const IFLA_IPTUN_6RD_RELAY_PREFIXLEN: u16 = 14;
27const IFLA_IPTUN_ENCAP_TYPE: u16 = 15;
28const IFLA_IPTUN_ENCAP_FLAGS: u16 = 16;
29const IFLA_IPTUN_ENCAP_SPORT: u16 = 17;
30const IFLA_IPTUN_ENCAP_DPORT: u16 = 18;
31const IFLA_IPTUN_COLLECT_METADATA: u16 = 19;
32const IFLA_IPTUN_FWMARK: u16 = 20;
33
34#[derive(Debug, PartialEq, Eq, Clone)]
35#[non_exhaustive]
36pub enum InfoIpTunnel {
37    Link(u32),
38    Local(IpAddr),
39    Remote(IpAddr),
40    Ttl(u8),
41    Tos(u8),
42    EncapLimit(u8),
43    FlowInfo(u32),
44    Ipv6SitFlags(u16),
45    Ipv4Flags(u16),
46    Ipv6Flags(Ip6TunnelFlags),
47    Protocol(IpProtocol),
48    PMtuDisc(bool),
49    Ipv6RdPrefix(Ipv6Addr),
50    Ipv6RdRelayPrefix(Ipv4Addr),
51    Ipv6RdPrefixLen(u16),
52    Ipv6RdRelayPrefixLen(u16),
53    EncapType(TunnelEncapType),
54    EncapFlags(TunnelEncapFlags),
55    EncapSPort(u16),
56    EncapDPort(u16),
57    CollectMetadata(bool),
58    FwMark(u32),
59    Other(DefaultNla),
60}
61
62impl Nla for InfoIpTunnel {
63    fn value_len(&self) -> usize {
64        use self::InfoIpTunnel::*;
65        match self {
66            Ipv6RdPrefix(_) => 16,
67            Ipv6RdRelayPrefix(_) => 4,
68            Local(value) | Remote(value) => match value {
69                IpAddr::V4(_) => 4,
70                IpAddr::V6(_) => 16,
71            },
72            Link(_) | FwMark(_) | FlowInfo(_) | Ipv6Flags(_) => 4,
73            Ipv6SitFlags(_)
74            | Ipv4Flags(_)
75            | EncapType(_)
76            | EncapFlags(_)
77            | EncapSPort(_)
78            | EncapDPort(_)
79            | Ipv6RdPrefixLen(_)
80            | Ipv6RdRelayPrefixLen(_) => 2,
81            Ttl(_) | Tos(_) | Protocol(_) | PMtuDisc(_)
82            | CollectMetadata(_) | EncapLimit(_) => 1,
83            Other(nla) => nla.value_len(),
84        }
85    }
86
87    fn emit_value(&self, buffer: &mut [u8]) {
88        use self::InfoIpTunnel::*;
89        match self {
90            Ipv6RdPrefix(value) => buffer.copy_from_slice(&value.octets()),
91            Ipv6RdRelayPrefix(value) => buffer.copy_from_slice(&value.octets()),
92            Link(value) | FwMark(value) | FlowInfo(value) => {
93                emit_u32(buffer, *value).unwrap()
94            }
95            Ipv6Flags(f) => emit_u32(buffer, f.bits()).unwrap(),
96            Ipv6SitFlags(val) | Ipv4Flags(val) => {
97                emit_u16_be(buffer, *val).unwrap()
98            }
99            Local(value) | Remote(value) => match value {
100                IpAddr::V4(ipv4) => buffer.copy_from_slice(&ipv4.octets()),
101                IpAddr::V6(ipv6) => buffer.copy_from_slice(&ipv6.octets()),
102            },
103            EncapType(value) => emit_u16(buffer, (*value).into()).unwrap(),
104            EncapFlags(f) => emit_u16(buffer, f.bits()).unwrap(),
105            EncapSPort(value) | EncapDPort(value) => {
106                emit_u16_be(buffer, *value).unwrap()
107            }
108            Ipv6RdPrefixLen(value) | Ipv6RdRelayPrefixLen(value) => {
109                emit_u16(buffer, *value).unwrap()
110            }
111            Protocol(value) => buffer[0] = u8::from(*value),
112            Ttl(value) | Tos(value) | EncapLimit(value) => buffer[0] = *value,
113            PMtuDisc(value) | CollectMetadata(value) => {
114                buffer[0] = if *value { 1 } else { 0 }
115            }
116            Other(nla) => nla.emit_value(buffer),
117        }
118    }
119
120    fn kind(&self) -> u16 {
121        use self::InfoIpTunnel::*;
122        match self {
123            Link(_) => IFLA_IPTUN_LINK,
124            Local(_) => IFLA_IPTUN_LOCAL,
125            Remote(_) => IFLA_IPTUN_REMOTE,
126            Ttl(_) => IFLA_IPTUN_TTL,
127            Tos(_) => IFLA_IPTUN_TOS,
128            EncapLimit(_) => IFLA_IPTUN_ENCAP_LIMIT,
129            FlowInfo(_) => IFLA_IPTUN_FLOWINFO,
130            Ipv6SitFlags(_) | Ipv4Flags(_) | Ipv6Flags(_) => IFLA_IPTUN_FLAGS,
131            Protocol(_) => IFLA_IPTUN_PROTO,
132            PMtuDisc(_) => IFLA_IPTUN_PMTUDISC,
133            Ipv6RdPrefix(_) => IFLA_IPTUN_6RD_PREFIX,
134            Ipv6RdRelayPrefix(_) => IFLA_IPTUN_6RD_RELAY_PREFIX,
135            Ipv6RdPrefixLen(_) => IFLA_IPTUN_6RD_PREFIXLEN,
136            Ipv6RdRelayPrefixLen(_) => IFLA_IPTUN_6RD_RELAY_PREFIXLEN,
137            EncapType(_) => IFLA_IPTUN_ENCAP_TYPE,
138            EncapFlags(_) => IFLA_IPTUN_ENCAP_FLAGS,
139            EncapSPort(_) => IFLA_IPTUN_ENCAP_SPORT,
140            EncapDPort(_) => IFLA_IPTUN_ENCAP_DPORT,
141            CollectMetadata(_) => IFLA_IPTUN_COLLECT_METADATA,
142            FwMark(_) => IFLA_IPTUN_FWMARK,
143            Other(nla) => nla.kind(),
144        }
145    }
146}
147
148impl<'a, T: AsRef<[u8]> + ?Sized>
149    ParseableParametrized<NlaBuffer<&'a T>, super::InfoKind> for InfoIpTunnel
150{
151    fn parse_with_param(
152        buf: &NlaBuffer<&'a T>,
153        kind: super::InfoKind,
154    ) -> Result<Self, DecodeError> {
155        use self::InfoIpTunnel::*;
156        let payload = buf.value();
157        Ok(match buf.kind() {
158            IFLA_IPTUN_LINK => Link(
159                parse_u32(payload).context("invalid IFLA_IPTUN_LINK value")?,
160            ),
161            IFLA_IPTUN_LOCAL => {
162                let ip = parse_ip_addr(payload)
163                    .context("invalid IFLA_IPTUN_LOCAL")?;
164                Self::Local(ip)
165            }
166            IFLA_IPTUN_REMOTE => {
167                let ip = parse_ip_addr(payload)
168                    .context("invalid IFLA_IPTUN_REMOTE")?;
169                Self::Remote(ip)
170            }
171            IFLA_IPTUN_TTL => {
172                Ttl(parse_u8(payload)
173                    .context("invalid IFLA_IPTUN_TTL value")?)
174            }
175            IFLA_IPTUN_TOS => {
176                Tos(parse_u8(payload)
177                    .context("invalid IFLA_IPTUN_TOS value")?)
178            }
179            IFLA_IPTUN_ENCAP_LIMIT => EncapLimit(
180                parse_u8(payload)
181                    .context("invalid IFLA_IPTUN_ENCAP_LIMIT value")?,
182            ),
183            IFLA_IPTUN_FLOWINFO => FlowInfo(
184                parse_u32(payload)
185                    .context("invalid IFLA_IPTUN_FLOWINFO value")?,
186            ),
187            IFLA_IPTUN_FLAGS => match kind {
188                super::InfoKind::IpIp => InfoIpTunnel::Ipv4Flags(
189                    parse_u16_be(payload)
190                        .context("invalid IFLA_IPTUN_FLAGS for IPIP")?,
191                ),
192                super::InfoKind::SitTun => InfoIpTunnel::Ipv6SitFlags(
193                    parse_u16_be(payload)
194                        .context("invalid IFLA_IPTUN_FLAGS for SIT")?,
195                ),
196                super::InfoKind::Ip6Tnl => {
197                    InfoIpTunnel::Ipv6Flags(Ip6TunnelFlags::from_bits_retain(
198                        parse_u32(payload)
199                            .context("invalid IFLA_IPTUN_FLAGS for IP6")?,
200                    ))
201                }
202                _ => {
203                    return Err(DecodeError::from(format!(
204                        "unsupported InfoKind for IFLA_IPTUN_FLAGS: {kind:?}"
205                    )));
206                }
207            },
208            IFLA_IPTUN_PROTO => Protocol(IpProtocol::from(
209                parse_u8(payload).context("invalid IFLA_IPTUN_PROTO value")?,
210            )),
211            IFLA_IPTUN_PMTUDISC => PMtuDisc(
212                parse_u8(payload)
213                    .context("invalid IFLA_IPTUN_PMTUDISC value")?
214                    > 0,
215            ),
216            IFLA_IPTUN_6RD_PREFIX => {
217                if payload.len() == 16 {
218                    let mut data = [0u8; 16];
219                    data.copy_from_slice(&payload[0..16]);
220                    Self::Ipv6RdPrefix(Ipv6Addr::from(data))
221                } else {
222                    return Err(DecodeError::from(format!(
223                        "Invalid IFLA_IPTUN_6RD_PREFIX, got unexpected length \
224                         of IPv6 address payload {payload:?}"
225                    )));
226                }
227            }
228            IFLA_IPTUN_6RD_RELAY_PREFIX => {
229                if payload.len() == 4 {
230                    let mut data = [0u8; 4];
231                    data.copy_from_slice(&payload[0..4]);
232                    Self::Ipv6RdRelayPrefix(Ipv4Addr::from(data))
233                } else {
234                    return Err(DecodeError::from(format!(
235                        "Invalid IFLA_IPTUN_6RD_RELAY_PREFIX, got unexpected \
236                         length of IPv4 address payload {payload:?}"
237                    )));
238                }
239            }
240            IFLA_IPTUN_6RD_PREFIXLEN => Ipv6RdPrefixLen(
241                parse_u16(payload)
242                    .context("invalid IFLA_IPTUN_6RD_PREFIXLEN value")?,
243            ),
244            IFLA_IPTUN_6RD_RELAY_PREFIXLEN => Ipv6RdRelayPrefixLen(
245                parse_u16(payload)
246                    .context("invalid IFLA_IPTUN_6RD_RELAY_PREFIXLEN value")?,
247            ),
248            IFLA_IPTUN_ENCAP_TYPE => EncapType(
249                parse_u16(payload)
250                    .context("invalid IFLA_IPTUN_ENCAP_TYPE value")?
251                    .into(),
252            ),
253            IFLA_IPTUN_ENCAP_FLAGS => {
254                EncapFlags(TunnelEncapFlags::from_bits_retain(
255                    parse_u16(payload)
256                        .context("failed to parse IFLA_IPTUN_ENCAP_FLAGS")?,
257                ))
258            }
259            IFLA_IPTUN_ENCAP_SPORT => EncapSPort(
260                parse_u16_be(payload)
261                    .context("invalid IFLA_IPTUN_ENCAP_SPORT value")?,
262            ),
263            IFLA_IPTUN_ENCAP_DPORT => EncapDPort(
264                parse_u16_be(payload)
265                    .context("invalid IFLA_IPTUN_ENCAP_DPORT value")?,
266            ),
267            IFLA_IPTUN_COLLECT_METADATA => CollectMetadata(
268                parse_u8(payload)
269                    .context("invalid IFLA_IPTUN_COLLECT_METADATA value")?
270                    > 0,
271            ),
272            IFLA_IPTUN_FWMARK => FwMark(
273                parse_u32(payload)
274                    .context("invalid IFLA_IPTUN_FWMARK value")?,
275            ),
276            kind => Other(
277                DefaultNla::parse(buf)
278                    .context(format!("unknown NLA type {kind}"))?,
279            ),
280        })
281    }
282}
283
284const TUNNEL_ENCAP_NONE: u16 = 0;
285const TUNNEL_ENCAP_FOU: u16 = 1;
286const TUNNEL_ENCAP_GUE: u16 = 2;
287const TUNNEL_ENCAP_MPLS: u16 = 3;
288
289#[derive(Debug, PartialEq, Eq, Clone, Copy)]
290#[non_exhaustive]
291#[repr(u16)]
292pub enum TunnelEncapType {
293    None,
294    Fou,
295    Gue,
296    Mpls,
297    Other(u16),
298}
299
300impl From<u16> for TunnelEncapType {
301    fn from(d: u16) -> Self {
302        match d {
303            TUNNEL_ENCAP_NONE => Self::None,
304            TUNNEL_ENCAP_FOU => Self::Fou,
305            TUNNEL_ENCAP_GUE => Self::Gue,
306            TUNNEL_ENCAP_MPLS => Self::Mpls,
307            _ => Self::Other(d),
308        }
309    }
310}
311
312impl From<TunnelEncapType> for u16 {
313    fn from(d: TunnelEncapType) -> Self {
314        match d {
315            TunnelEncapType::None => TUNNEL_ENCAP_NONE,
316            TunnelEncapType::Fou => TUNNEL_ENCAP_FOU,
317            TunnelEncapType::Gue => TUNNEL_ENCAP_GUE,
318            TunnelEncapType::Mpls => TUNNEL_ENCAP_MPLS,
319            TunnelEncapType::Other(value) => value,
320        }
321    }
322}
323
324impl std::fmt::Display for TunnelEncapType {
325    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326        match self {
327            Self::None => write!(f, "none"),
328            Self::Fou => write!(f, "fou"),
329            Self::Gue => write!(f, "gue"),
330            Self::Mpls => write!(f, "mpls"),
331            Self::Other(d) => write!(f, "{d}"),
332        }
333    }
334}
335
336const TUNNEL_ENCAP_FLAG_CSUM: u16 = 1 << 0;
337const TUNNEL_ENCAP_FLAG_CSUM6: u16 = 1 << 1;
338const TUNNEL_ENCAP_FLAG_REMCSUM: u16 = 1 << 2;
339
340bitflags! {
341    #[non_exhaustive]
342    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
343    pub struct TunnelEncapFlags: u16 {
344        const CSum = TUNNEL_ENCAP_FLAG_CSUM;
345        const CSum6 = TUNNEL_ENCAP_FLAG_CSUM6;
346        const RemCSum = TUNNEL_ENCAP_FLAG_REMCSUM;
347        const _ = !0;
348    }
349}
350
351const IP6_TNL_F_IGN_ENCAP_LIMIT: u32 = 0x1;
352const IP6_TNL_F_USE_ORIG_TCLASS: u32 = 0x2;
353const IP6_TNL_F_USE_ORIG_FLOWLABEL: u32 = 0x4;
354const IP6_TNL_F_MIP6_DEV: u32 = 0x8;
355const IP6_TNL_F_RCV_DSCP_COPY: u32 = 0x10;
356const IP6_TNL_F_USE_ORIG_FWMARK: u32 = 0x20;
357const IP6_TNL_F_ALLOW_LOCAL_REMOTE: u32 = 0x40;
358
359const IP6_TNL_F_CAP_XMIT: u32 = 0x10000;
360const IP6_TNL_F_CAP_RCV: u32 = 0x20000;
361const IP6_TNL_F_CAP_PER_PACKET: u32 = 0x40000;
362
363bitflags! {
364    #[non_exhaustive]
365    #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
366    pub struct Ip6TunnelFlags: u32 {
367        const IgnEncapLimit = IP6_TNL_F_IGN_ENCAP_LIMIT;
368        const UseOrigTclass = IP6_TNL_F_USE_ORIG_TCLASS;
369        const UseOrigFlowlabel = IP6_TNL_F_USE_ORIG_FLOWLABEL;
370        const Mip6Dev = IP6_TNL_F_MIP6_DEV;
371        const RcvDscpCopy = IP6_TNL_F_RCV_DSCP_COPY;
372        const UseOrigFwMark = IP6_TNL_F_USE_ORIG_FWMARK;
373        const AllowLocalRemote = IP6_TNL_F_ALLOW_LOCAL_REMOTE;
374        const CapXmit = IP6_TNL_F_CAP_XMIT;
375        const CapRcv = IP6_TNL_F_CAP_RCV;
376        const CapPerPacket = IP6_TNL_F_CAP_PER_PACKET;
377        const _ = !0;
378    }
379}