packet_strata/packet/tunnel/
vxlan.rs1use std::fmt::{self, Formatter};
66
67use zerocopy::byteorder::{BigEndian, U32};
68use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
69
70use crate::packet::protocol::EtherProto;
71use crate::packet::{HeaderParser, PacketHeader};
72
73pub const VXLAN_PORT: u16 = 4789;
75
76pub const VXLAN_MAX_VNI: u32 = 0xFFFFFF;
78
79#[repr(C, packed)]
94#[derive(FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, KnownLayout, Immutable)]
95pub struct VxlanHeader {
96 flags_reserved: U32<BigEndian>,
97 vni_reserved: U32<BigEndian>,
98}
99
100impl VxlanHeader {
101 const VNI_MASK: u32 = 0xFFFFFF00;
103 const VNI_SHIFT: u32 = 8;
104
105 const FLAGS_MASK: u32 = 0xFF000000;
107 const FLAG_I_MASK: u32 = 0x08000000;
108
109 const RESERVED1_MASK: u32 = 0x00FFFFFF;
111 const RESERVED2_MASK: u32 = 0x000000FF;
112
113 #[allow(unused)]
114 const NAME: &'static str = "VxlanHeader";
115
116 #[inline]
118 pub fn flags(&self) -> u8 {
119 ((self.flags_reserved.get() & Self::FLAGS_MASK) >> 24) as u8
120 }
121
122 #[inline]
126 pub fn is_vni_valid(&self) -> bool {
127 self.flags_reserved.get() & Self::FLAG_I_MASK != 0
128 }
129
130 #[inline]
134 pub fn vni(&self) -> u32 {
135 (self.vni_reserved.get() & Self::VNI_MASK) >> Self::VNI_SHIFT
136 }
137
138 #[inline]
140 pub fn vni_raw(&self) -> u32 {
141 self.vni_reserved.get()
142 }
143
144 #[inline]
146 pub fn reserved1(&self) -> u32 {
147 self.flags_reserved.get() & Self::RESERVED1_MASK
148 }
149
150 #[inline]
152 pub fn reserved2(&self) -> u8 {
153 (self.vni_reserved.get() & Self::RESERVED2_MASK) as u8
154 }
155
156 #[inline]
161 fn is_valid(&self) -> bool {
162 self.is_vni_valid()
164 }
165
166 #[inline]
170 pub fn is_valid_strict(&self) -> bool {
171 self.is_vni_valid() && self.reserved1() == 0 && self.reserved2() == 0
172 }
173}
174
175impl PacketHeader for VxlanHeader {
176 const NAME: &'static str = "VxlanHeader";
177 type InnerType = EtherProto;
178
179 #[inline]
180 fn inner_type(&self) -> Self::InnerType {
181 EtherProto::TEB
183 }
184
185 #[inline]
186 fn total_len(&self, _buf: &[u8]) -> usize {
187 Self::FIXED_LEN
188 }
189
190 #[inline]
191 fn is_valid(&self) -> bool {
192 self.is_valid()
193 }
194}
195
196impl HeaderParser for VxlanHeader {
197 type Output<'a> = &'a VxlanHeader;
198
199 #[inline]
200 fn into_view<'a>(header: &'a Self, _raw_options: &'a [u8]) -> Self::Output<'a> {
201 header
202 }
203}
204
205impl fmt::Display for VxlanHeader {
206 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
207 write!(
208 f,
209 "VXLAN vni={} flags=0x{:02x}{}",
210 self.vni(),
211 self.flags(),
212 if self.is_vni_valid() { " [I]" } else { "" }
213 )
214 }
215}
216
217#[inline]
219pub fn is_vxlan_port(dst_port: u16) -> bool {
220 dst_port == VXLAN_PORT
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 #[test]
228 fn test_vxlan_header_size() {
229 assert_eq!(std::mem::size_of::<VxlanHeader>(), 8);
230 assert_eq!(VxlanHeader::FIXED_LEN, 8);
231 }
232
233 #[test]
234 fn test_vxlan_basic_header() {
235 let header = VxlanHeader {
236 flags_reserved: U32::new(0x08000000), vni_reserved: U32::new(0x00006400), };
239
240 assert!(header.is_vni_valid());
241 assert_eq!(header.vni(), 100);
242 assert_eq!(header.flags(), 0x08);
243 assert!(header.is_valid());
244 assert!(header.is_valid_strict());
245 }
246
247 #[test]
248 fn test_vxlan_vni_values() {
249 let header = VxlanHeader {
251 flags_reserved: U32::new(0x08000000),
252 vni_reserved: U32::new(0x12345600),
253 };
254
255 assert_eq!(header.vni(), 0x123456);
256 assert!(header.is_valid());
257 }
258
259 #[test]
260 fn test_vxlan_max_vni() {
261 let header = VxlanHeader {
263 flags_reserved: U32::new(0x08000000),
264 vni_reserved: U32::new(0xFFFFFF00),
265 };
266
267 assert_eq!(header.vni(), VXLAN_MAX_VNI);
268 assert!(header.is_valid());
269 }
270
271 #[test]
272 fn test_vxlan_zero_vni() {
273 let header = VxlanHeader {
275 flags_reserved: U32::new(0x08000000),
276 vni_reserved: U32::new(0x00000000),
277 };
278
279 assert_eq!(header.vni(), 0);
280 assert!(header.is_valid());
281 }
282
283 #[test]
284 fn test_vxlan_invalid_no_i_flag() {
285 let header = VxlanHeader {
287 flags_reserved: U32::new(0x00000000), vni_reserved: U32::new(0x00006400),
289 };
290
291 assert!(!header.is_vni_valid());
292 assert!(!header.is_valid());
293 }
294
295 #[test]
296 fn test_vxlan_reserved_bits() {
297 let header = VxlanHeader {
299 flags_reserved: U32::new(0x08123456), vni_reserved: U32::new(0x00006401), };
302
303 assert!(header.is_vni_valid());
304 assert!(header.is_valid()); assert!(!header.is_valid_strict()); assert_eq!(header.reserved1(), 0x123456);
307 assert_eq!(header.reserved2(), 0x01);
308 }
309
310 #[test]
311 fn test_vxlan_parsing_basic() {
312 let mut packet = Vec::new();
313
314 packet.extend_from_slice(&0x08000000u32.to_be_bytes()); packet.extend_from_slice(&0x00006400u32.to_be_bytes()); packet.extend_from_slice(b"ethernet");
320
321 let result = VxlanHeader::from_bytes(&packet);
322 assert!(result.is_ok());
323
324 let (header, payload) = result.unwrap();
325 assert!(header.is_vni_valid());
326 assert_eq!(header.vni(), 100);
327 assert_eq!(payload, b"ethernet");
328 }
329
330 #[test]
331 fn test_vxlan_parsing_with_vni() {
332 let mut packet = Vec::new();
333
334 packet.extend_from_slice(&0x08000000u32.to_be_bytes()); packet.extend_from_slice(&0xABCDEF00u32.to_be_bytes()); let result = VxlanHeader::from_bytes(&packet);
338 assert!(result.is_ok());
339
340 let (header, _) = result.unwrap();
341 assert_eq!(header.vni(), 0xABCDEF);
342 }
343
344 #[test]
345 fn test_vxlan_parsing_too_small() {
346 let packet = vec![0u8; 7]; let result = VxlanHeader::from_bytes(&packet);
349 assert!(result.is_err());
350 }
351
352 #[test]
353 fn test_vxlan_parsing_invalid_no_i_flag() {
354 let mut packet = Vec::new();
355
356 packet.extend_from_slice(&0x00000000u32.to_be_bytes()); packet.extend_from_slice(&0x00006400u32.to_be_bytes()); let result = VxlanHeader::from_bytes(&packet);
360 assert!(result.is_err()); }
362
363 #[test]
364 fn test_vxlan_inner_type() {
365 let header = VxlanHeader {
366 flags_reserved: U32::new(0x08000000),
367 vni_reserved: U32::new(0x00006400),
368 };
369
370 assert_eq!(header.inner_type(), EtherProto::TEB);
372 }
373
374 #[test]
375 fn test_vxlan_display() {
376 let header = VxlanHeader {
377 flags_reserved: U32::new(0x08000000),
378 vni_reserved: U32::new(0x00006400),
379 };
380
381 let display = format!("{}", header);
382 assert!(display.contains("VXLAN"));
383 assert!(display.contains("vni=100"));
384 assert!(display.contains("[I]"));
385 }
386
387 #[test]
388 fn test_vxlan_display_no_i_flag() {
389 let header = VxlanHeader {
390 flags_reserved: U32::new(0x00000000), vni_reserved: U32::new(0x00006400),
392 };
393
394 let display = format!("{}", header);
395 assert!(display.contains("VXLAN"));
396 assert!(!display.contains("[I]"));
397 }
398
399 #[test]
400 fn test_vxlan_port_check() {
401 assert!(is_vxlan_port(4789));
402 assert!(!is_vxlan_port(4788));
403 assert!(!is_vxlan_port(80));
404 }
405
406 #[test]
407 fn test_vxlan_flags_byte() {
408 let header1 = VxlanHeader {
410 flags_reserved: U32::new(0x08000000), vni_reserved: U32::new(0x00000000),
412 };
413 assert_eq!(header1.flags(), 0x08);
414
415 let header2 = VxlanHeader {
416 flags_reserved: U32::new(0xFF000000), vni_reserved: U32::new(0x00000000),
418 };
419 assert_eq!(header2.flags(), 0xFF);
420 assert!(header2.is_vni_valid()); }
422
423 #[test]
424 fn test_vxlan_multicast_vni() {
425 let header = VxlanHeader {
427 flags_reserved: U32::new(0x08000000),
428 vni_reserved: U32::new(0x000FA000), };
430
431 assert_eq!(header.vni(), 4000);
432 assert!(header.is_valid());
433 }
434
435 #[test]
436 fn test_vxlan_real_world_scenario() {
437 let mut packet = Vec::new();
439
440 packet.extend_from_slice(&[0x08, 0x00, 0x00, 0x00]); packet.extend_from_slice(&[0x00, 0x13, 0x88, 0x00]); packet.extend_from_slice(&[
446 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x08, 0x00, ]);
450
451 let (header, payload) = VxlanHeader::from_bytes(&packet).unwrap();
452 assert_eq!(header.vni(), 5000);
453 assert!(header.is_vni_valid());
454 assert_eq!(payload.len(), 14); }
456
457 #[test]
458 fn test_vxlan_header_length() {
459 let header = VxlanHeader {
460 flags_reserved: U32::new(0x08000000),
461 vni_reserved: U32::new(0x00006400),
462 };
463
464 assert_eq!(header.total_len(&[]), 8);
466 }
467}