netlink_packet_route/route/
seg6.rs1use std::net::{IpAddr, Ipv6Addr};
4
5use netlink_packet_core::{
6 DecodeError, DefaultNla, ErrorContext, Nla, NlaBuffer, Parseable,
7};
8
9use crate::ip::{emit_ip_addr, parse_ipv6_addr};
10
11const SEG6_IPTUN_MODE_INLINE: u32 = 0;
12const SEG6_IPTUN_MODE_ENCAP: u32 = 1;
13#[derive(Debug, PartialEq, Eq, Clone, Copy)]
18#[non_exhaustive]
19pub enum Seg6Mode {
20 Inline,
22 Encap,
24 Other(u32),
28}
29
30impl From<Seg6Mode> for u32 {
31 fn from(value: Seg6Mode) -> Self {
32 match value {
33 Seg6Mode::Inline => SEG6_IPTUN_MODE_INLINE,
34 Seg6Mode::Encap => SEG6_IPTUN_MODE_ENCAP,
35 Seg6Mode::Other(i) => i,
36 }
37 }
38}
39
40impl From<u32> for Seg6Mode {
41 fn from(value: u32) -> Self {
42 match value {
43 SEG6_IPTUN_MODE_INLINE => Seg6Mode::Inline,
44 SEG6_IPTUN_MODE_ENCAP => Seg6Mode::Encap,
45 v => Seg6Mode::Other(v),
46 }
47 }
48}
49
50const SEG6_IPTUNNEL_SRH: u16 = 1;
51
52#[derive(Debug, PartialEq, Eq, Clone)]
55#[non_exhaustive]
56pub enum RouteSeg6IpTunnel {
57 Seg6(Seg6Header),
59 Other(DefaultNla),
60}
61
62impl Nla for RouteSeg6IpTunnel {
63 fn value_len(&self) -> usize {
64 match self {
65 RouteSeg6IpTunnel::Seg6(v) => v.value_len(),
66 RouteSeg6IpTunnel::Other(v) => v.value_len(),
67 }
68 }
69
70 fn kind(&self) -> u16 {
71 match self {
72 RouteSeg6IpTunnel::Seg6(v) => v.kind(),
73 RouteSeg6IpTunnel::Other(v) => v.kind(),
74 }
75 }
76
77 fn emit_value(&self, buffer: &mut [u8]) {
78 match self {
79 RouteSeg6IpTunnel::Seg6(v) => v.emit_value(buffer),
80 RouteSeg6IpTunnel::Other(v) => v.emit_value(buffer),
81 }
82 }
83}
84
85const SEG6_HEADER_LEN: usize = 12;
86
87buffer!(Seg6MessageBuffer(SEG6_HEADER_LEN) {
88 mode: (u32, 0..4),
89 nexthdr: (u8, 4),
90 hdrlen: (u8, 5),
91 seg_type: (u8, 6),
92 segments_left: (u8, 7),
93 first_segment: (u8, 8),
94 flags: (u8, 9),
95 tag: (u16, 10..12),
96 segments: (slice, SEG6_HEADER_LEN..),
97});
98
99const SEG6_SEGMENT_LEN: usize = 16;
100
101buffer!(Seg6SegmentBuffer(SEG6_SEGMENT_LEN) {
102 segment: (slice, 0..SEG6_SEGMENT_LEN),
103 rest: (slice, SEG6_SEGMENT_LEN..)
104});
105
106#[derive(Debug, PartialEq, Eq, Clone)]
109#[non_exhaustive]
110pub struct Seg6Header {
111 pub mode: Seg6Mode,
113 pub segments: Vec<Ipv6Addr>,
115}
116
117impl Seg6Header {
118 fn push_segments(buf: &mut [u8], mut segments: Vec<Ipv6Addr>) {
119 if let Some(segment) = segments.pop() {
120 let mut segment_buffer = Seg6SegmentBuffer::new(buf);
121 emit_ip_addr(&IpAddr::V6(segment), segment_buffer.segment_mut());
122 Self::push_segments(segment_buffer.rest_mut(), segments);
123 }
124 }
125
126 fn get_segments(
127 buf: &[u8],
128 segments: &mut Vec<Ipv6Addr>,
129 ) -> Result<(), DecodeError> {
130 if buf.len() >= SEG6_SEGMENT_LEN {
132 let segment_buffer = Seg6SegmentBuffer::new(buf);
133 let segment = parse_ipv6_addr(segment_buffer.segment())?;
134 segments.push(segment);
135 Self::get_segments(segment_buffer.rest(), segments)?;
136 }
137 Ok(())
138 }
139}
140
141impl Nla for Seg6Header {
142 fn value_len(&self) -> usize {
143 let segments = match self.mode {
144 Seg6Mode::Inline => self.segments.len() + 1,
148 Seg6Mode::Encap => self.segments.len(),
149 Seg6Mode::Other(_) => self.segments.len(),
150 };
151 12 + 16 * segments
152 }
153
154 fn kind(&self) -> u16 {
155 SEG6_IPTUNNEL_SRH
156 }
157
158 fn emit_value(&self, buffer: &mut [u8]) {
159 let mut seg6_header = Seg6MessageBuffer::new(buffer);
169
170 let mut number_segments = self.segments.len();
171 if matches!(self.mode, Seg6Mode::Inline) {
172 number_segments += 1 }
174
175 let srhlen = 8 + 16 * number_segments;
176
177 seg6_header.set_mode(self.mode.into());
178 seg6_header.set_nexthdr(0);
179 seg6_header.set_hdrlen(((srhlen >> 3) - 1) as u8);
180 seg6_header.set_seg_type(4);
181 seg6_header.set_segments_left((number_segments - 1) as u8);
182 seg6_header.set_first_segment((number_segments - 1) as u8);
183 seg6_header.set_flags(0);
184 seg6_header.set_tag(0);
185
186 let mut segments = self.segments.clone();
187
188 if matches!(self.mode, Seg6Mode::Inline) {
190 segments.push("::".parse().expect("Impossible error"))
191 }
192
193 Seg6Header::push_segments(seg6_header.segments_mut(), segments);
194 }
195}
196
197impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>>
198 for RouteSeg6IpTunnel
199{
200 fn parse(
201 buf: &NlaBuffer<&'a T>,
202 ) -> Result<Self, netlink_packet_core::DecodeError> {
203 let payload = buf.value();
204 Ok(match buf.kind() {
205 SEG6_IPTUNNEL_SRH => {
206 let seg6_header = Seg6MessageBuffer::new(payload);
207
208 let mut segments: Vec<Ipv6Addr> = vec![];
209 Seg6Header::get_segments(
210 seg6_header.segments(),
211 &mut segments,
212 )?;
213
214 let mut segments: Vec<Ipv6Addr> =
215 segments.into_iter().rev().collect();
216
217 if matches!(seg6_header.mode().into(), Seg6Mode::Inline) {
218 segments.pop(); }
220
221 RouteSeg6IpTunnel::Seg6(Seg6Header {
222 mode: seg6_header.mode().into(),
223 segments,
224 })
225 }
226 _ => Self::Other(
227 DefaultNla::parse(buf)
228 .context("invalid NLA value (unknown type) value")?,
229 ),
230 })
231 }
232}