use std::fmt::{self, Formatter};
use zerocopy::byteorder::{BigEndian, U16, U32};
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
use crate::packet::protocol::EtherProto;
use crate::packet::{HeaderParser, PacketHeader};
pub const GENEVE_PORT: u16 = 6081;
pub const GENEVE_MAX_VNI: u32 = 0xFFFFFF;
pub const GENEVE_MAX_OPTIONS_LEN: usize = 252;
pub const GENEVE_VERSION: u8 = 0;
#[repr(C, packed)]
#[derive(FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, KnownLayout, Immutable)]
pub struct GeneveHeader {
ver_optlen_flags: U16<BigEndian>,
protocol_type: U16<BigEndian>,
vni_reserved: U32<BigEndian>,
}
impl GeneveHeader {
const VERSION_MASK: u16 = 0xC000;
const VERSION_SHIFT: u16 = 14;
const OPTLEN_MASK: u16 = 0x3F00;
const OPTLEN_SHIFT: u16 = 8;
const FLAG_O_MASK: u16 = 0x0080;
const FLAG_C_MASK: u16 = 0x0040;
const RESERVED_MASK: u16 = 0x003F;
const VNI_MASK: u32 = 0xFFFFFF00;
const VNI_SHIFT: u32 = 8;
const VNI_RESERVED_MASK: u32 = 0x000000FF;
#[allow(unused)]
const NAME: &'static str = "GeneveHeader";
#[inline]
pub fn version(&self) -> u8 {
((self.ver_optlen_flags.get() & Self::VERSION_MASK) >> Self::VERSION_SHIFT) as u8
}
#[inline]
pub fn options_length_units(&self) -> u8 {
((self.ver_optlen_flags.get() & Self::OPTLEN_MASK) >> Self::OPTLEN_SHIFT) as u8
}
#[inline]
pub fn options_length(&self) -> usize {
self.options_length_units() as usize * 4
}
#[inline]
pub fn is_oam(&self) -> bool {
self.ver_optlen_flags.get() & Self::FLAG_O_MASK != 0
}
#[inline]
pub fn is_critical(&self) -> bool {
self.ver_optlen_flags.get() & Self::FLAG_C_MASK != 0
}
#[inline]
pub fn reserved_flags(&self) -> u8 {
(self.ver_optlen_flags.get() & Self::RESERVED_MASK) as u8
}
#[inline]
pub fn protocol_type(&self) -> EtherProto {
self.protocol_type.get().into()
}
#[inline]
pub fn protocol_type_raw(&self) -> u16 {
self.protocol_type.get()
}
#[inline]
pub fn vni(&self) -> u32 {
(self.vni_reserved.get() & Self::VNI_MASK) >> Self::VNI_SHIFT
}
#[inline]
pub fn reserved_vni(&self) -> u8 {
(self.vni_reserved.get() & Self::VNI_RESERVED_MASK) as u8
}
#[inline]
pub fn header_length(&self) -> usize {
Self::FIXED_LEN + self.options_length()
}
#[inline]
fn is_valid(&self) -> bool {
if self.version() != GENEVE_VERSION {
return false;
}
if self.options_length() > GENEVE_MAX_OPTIONS_LEN {
return false;
}
true
}
#[inline]
pub fn is_valid_strict(&self) -> bool {
self.is_valid() && self.reserved_flags() == 0 && self.reserved_vni() == 0
}
pub fn flags_string(&self) -> String {
let mut flags = Vec::new();
if self.is_oam() {
flags.push("O");
}
if self.is_critical() {
flags.push("C");
}
if flags.is_empty() {
"none".to_string()
} else {
flags.join("")
}
}
}
#[derive(Debug, Clone)]
pub struct GeneveHeaderOpt<'a> {
pub header: &'a GeneveHeader,
pub options: &'a [u8],
}
impl<'a> GeneveHeaderOpt<'a> {
pub fn options_iter(&self) -> GeneveOptionsIter<'a> {
GeneveOptionsIter {
data: self.options,
offset: 0,
}
}
#[inline]
pub fn has_options(&self) -> bool {
!self.options.is_empty()
}
}
impl std::ops::Deref for GeneveHeaderOpt<'_> {
type Target = GeneveHeader;
#[inline]
fn deref(&self) -> &Self::Target {
self.header
}
}
impl PacketHeader for GeneveHeader {
const NAME: &'static str = "GeneveHeader";
type InnerType = EtherProto;
#[inline]
fn inner_type(&self) -> Self::InnerType {
self.protocol_type()
}
#[inline]
fn total_len(&self, _buf: &[u8]) -> usize {
self.header_length()
}
#[inline]
fn is_valid(&self) -> bool {
self.is_valid()
}
}
impl HeaderParser for GeneveHeader {
type Output<'a> = GeneveHeaderOpt<'a>;
#[inline]
fn into_view<'a>(header: &'a Self, options: &'a [u8]) -> Self::Output<'a> {
GeneveHeaderOpt { header, options }
}
}
impl fmt::Display for GeneveHeader {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"Geneve v{} vni={} proto={}(0x{:04x}) opt_len={} flags={}",
self.version(),
self.vni(),
self.protocol_type(),
self.protocol_type().0,
self.options_length(),
self.flags_string()
)
}
}
impl fmt::Display for GeneveHeaderOpt<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"Geneve v{} vni={} proto={} opt_len={} flags={}",
self.version(),
self.vni(),
self.protocol_type(),
self.options_length(),
self.flags_string()
)?;
if self.has_options() {
write!(f, " options={}", self.options_iter().count())?;
}
Ok(())
}
}
#[derive(Debug, Clone, Copy)]
pub struct GeneveOption<'a> {
pub option_class: u16,
pub option_type: u8,
pub length_units: u8,
pub data: &'a [u8],
}
impl<'a> GeneveOption<'a> {
pub const HEADER_SIZE: usize = 4;
#[inline]
pub fn is_critical(&self) -> bool {
self.option_type & 0x80 != 0
}
#[inline]
pub fn type_value(&self) -> u8 {
self.option_type & 0x7F
}
#[inline]
pub fn data_length(&self) -> usize {
self.length_units as usize * 4
}
#[inline]
pub fn total_length(&self) -> usize {
Self::HEADER_SIZE + self.data_length()
}
}
impl fmt::Display for GeneveOption<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"GeneveOpt class=0x{:04x} type=0x{:02x}{} len={}",
self.option_class,
self.option_type,
if self.is_critical() { "(C)" } else { "" },
self.data_length()
)
}
}
pub struct GeneveOptionsIter<'a> {
data: &'a [u8],
offset: usize,
}
impl<'a> Iterator for GeneveOptionsIter<'a> {
type Item = GeneveOption<'a>;
fn next(&mut self) -> Option<Self::Item> {
if self.offset + GeneveOption::HEADER_SIZE > self.data.len() {
return None;
}
let option_class = u16::from_be_bytes([self.data[self.offset], self.data[self.offset + 1]]);
let option_type = self.data[self.offset + 2];
let length_byte = self.data[self.offset + 3];
let length_units = length_byte & 0x1F;
let data_len = length_units as usize * 4;
let data_start = self.offset + GeneveOption::HEADER_SIZE;
let data_end = data_start + data_len;
if data_end > self.data.len() {
return None;
}
let option = GeneveOption {
option_class,
option_type,
length_units,
data: &self.data[data_start..data_end],
};
self.offset = data_end;
Some(option)
}
}
#[inline]
pub fn is_geneve_port(dst_port: u16) -> bool {
dst_port == GENEVE_PORT
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_geneve_header_size() {
assert_eq!(std::mem::size_of::<GeneveHeader>(), 8);
assert_eq!(GeneveHeader::FIXED_LEN, 8);
}
#[test]
fn test_geneve_basic_header() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x0000), protocol_type: U16::new(0x6558), vni_reserved: U32::new(0x00006400), };
assert_eq!(header.version(), 0);
assert_eq!(header.options_length_units(), 0);
assert_eq!(header.options_length(), 0);
assert!(!header.is_oam());
assert!(!header.is_critical());
assert_eq!(header.protocol_type(), EtherProto::TEB);
assert_eq!(header.vni(), 100);
assert!(header.is_valid());
assert!(header.is_valid_strict());
}
#[test]
fn test_geneve_with_options() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x0200), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00010000), };
assert_eq!(header.version(), 0);
assert_eq!(header.options_length_units(), 2);
assert_eq!(header.options_length(), 8);
assert_eq!(header.header_length(), 16); assert_eq!(header.vni(), 256);
assert!(header.is_valid());
}
#[test]
fn test_geneve_flags() {
let header_oam = GeneveHeader {
ver_optlen_flags: U16::new(0x0080), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert!(header_oam.is_oam());
assert!(!header_oam.is_critical());
let header_crit = GeneveHeader {
ver_optlen_flags: U16::new(0x0040), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert!(!header_crit.is_oam());
assert!(header_crit.is_critical());
let header_both = GeneveHeader {
ver_optlen_flags: U16::new(0x00C0), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert!(header_both.is_oam());
assert!(header_both.is_critical());
}
#[test]
fn test_geneve_vni_values() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x0000),
protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x12345600),
};
assert_eq!(header.vni(), 0x123456);
}
#[test]
fn test_geneve_max_vni() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x0000),
protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0xFFFFFF00),
};
assert_eq!(header.vni(), GENEVE_MAX_VNI);
}
#[test]
fn test_geneve_invalid_version() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x4000), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(header.version(), 1);
assert!(!header.is_valid());
}
#[test]
fn test_geneve_parsing_basic() {
let mut packet = Vec::new();
packet.extend_from_slice(&0x0000u16.to_be_bytes()); packet.extend_from_slice(&0x6558u16.to_be_bytes()); packet.extend_from_slice(&0x00006400u32.to_be_bytes());
packet.extend_from_slice(b"ethernet");
let result = GeneveHeader::from_bytes(&packet);
assert!(result.is_ok());
let (header, payload) = result.unwrap();
assert_eq!(header.version(), 0);
assert_eq!(header.vni(), 100);
assert_eq!(header.options_length(), 0);
assert!(!header.has_options());
assert_eq!(payload, b"ethernet");
}
#[test]
fn test_geneve_parsing_with_options() {
let mut packet = Vec::new();
packet.extend_from_slice(&0x0200u16.to_be_bytes()); packet.extend_from_slice(&0x6558u16.to_be_bytes()); packet.extend_from_slice(&0x00010000u32.to_be_bytes());
packet.extend_from_slice(&0x0001u16.to_be_bytes()); packet.push(0x80); packet.push(0x01); packet.extend_from_slice(&[0x12, 0x34, 0x56, 0x78]);
packet.extend_from_slice(b"data");
let result = GeneveHeader::from_bytes(&packet);
assert!(result.is_ok());
let (header, payload) = result.unwrap();
assert_eq!(header.vni(), 256);
assert_eq!(header.options_length(), 8);
assert!(header.has_options());
assert_eq!(payload, b"data");
let mut opts = header.options_iter();
let opt1 = opts.next().unwrap();
assert_eq!(opt1.option_class, 0x0001);
assert_eq!(opt1.option_type, 0x80);
assert!(opt1.is_critical());
assert_eq!(opt1.data_length(), 4);
assert_eq!(opt1.data, &[0x12, 0x34, 0x56, 0x78]);
assert!(opts.next().is_none());
}
#[test]
fn test_geneve_parsing_too_small() {
let packet = vec![0u8; 7];
let result = GeneveHeader::from_bytes(&packet);
assert!(result.is_err());
}
#[test]
fn test_geneve_parsing_invalid_version() {
let mut packet = Vec::new();
packet.extend_from_slice(&0x4000u16.to_be_bytes()); packet.extend_from_slice(&0x6558u16.to_be_bytes());
packet.extend_from_slice(&0x00000000u32.to_be_bytes());
let result = GeneveHeader::from_bytes(&packet);
assert!(result.is_err());
}
#[test]
fn test_geneve_inner_type() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x0000),
protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00006400),
};
assert_eq!(header.inner_type(), EtherProto::TEB);
}
#[test]
fn test_geneve_display() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x00C0), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00006400),
};
let display = format!("{}", header);
assert!(display.contains("Geneve"));
assert!(display.contains("vni=100"));
assert!(display.contains("OC"));
}
#[test]
fn test_geneve_flags_string() {
let header1 = GeneveHeader {
ver_optlen_flags: U16::new(0x0000),
protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(header1.flags_string(), "none");
let header2 = GeneveHeader {
ver_optlen_flags: U16::new(0x0080), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(header2.flags_string(), "O");
let header3 = GeneveHeader {
ver_optlen_flags: U16::new(0x00C0), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(header3.flags_string(), "OC");
}
#[test]
fn test_geneve_port_check() {
assert!(is_geneve_port(6081));
assert!(!is_geneve_port(4789)); assert!(!is_geneve_port(80));
}
#[test]
fn test_geneve_option_parsing() {
let option_data = vec![
0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, ];
let mut iter = GeneveOptionsIter {
data: &option_data,
offset: 0,
};
let opt = iter.next().unwrap();
assert_eq!(opt.option_class, 0x0001);
assert_eq!(opt.option_type, 0x01);
assert!(!opt.is_critical());
assert_eq!(opt.type_value(), 0x01);
assert_eq!(opt.length_units, 2);
assert_eq!(opt.data_length(), 8);
assert_eq!(opt.total_length(), 12);
}
#[test]
fn test_geneve_multiple_options() {
let mut packet = Vec::new();
packet.extend_from_slice(&0x0400u16.to_be_bytes()); packet.extend_from_slice(&0x6558u16.to_be_bytes());
packet.extend_from_slice(&0x00000000u32.to_be_bytes());
packet.extend_from_slice(&0x0001u16.to_be_bytes());
packet.push(0x01);
packet.push(0x01); packet.extend_from_slice(&[0xAA, 0xBB, 0xCC, 0xDD]);
packet.extend_from_slice(&0x0002u16.to_be_bytes());
packet.push(0x82); packet.push(0x01);
packet.extend_from_slice(&[0x11, 0x22, 0x33, 0x44]);
let (header, _) = GeneveHeader::from_bytes(&packet).unwrap();
let opts: Vec<_> = header.options_iter().collect();
assert_eq!(opts.len(), 2);
assert_eq!(opts[0].option_class, 0x0001);
assert!(!opts[0].is_critical());
assert_eq!(opts[1].option_class, 0x0002);
assert!(opts[1].is_critical());
}
#[test]
fn test_geneve_max_options_length() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x3F00), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(header.options_length_units(), 63);
assert_eq!(header.options_length(), 252);
assert!(header.is_valid());
}
#[test]
fn test_geneve_header_length_calculation() {
let h1 = GeneveHeader {
ver_optlen_flags: U16::new(0x0000),
protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(h1.header_length(), 8);
let h2 = GeneveHeader {
ver_optlen_flags: U16::new(0x0200),
protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(h2.header_length(), 16);
let h3 = GeneveHeader {
ver_optlen_flags: U16::new(0x3F00),
protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x00000000),
};
assert_eq!(h3.header_length(), 260);
}
#[test]
fn test_geneve_reserved_bits() {
let header = GeneveHeader {
ver_optlen_flags: U16::new(0x003F), protocol_type: U16::new(0x6558),
vni_reserved: U32::new(0x000000FF), };
assert_eq!(header.reserved_flags(), 0x3F);
assert_eq!(header.reserved_vni(), 0xFF);
assert!(header.is_valid()); assert!(!header.is_valid_strict()); }
}