1use 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;
33const 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}