From 1f1a75dbc30e140455a9cd6b11cf1c8f55d9da41 Mon Sep 17 00:00:00 2001 From: Connor Sanders Date: Tue, 1 Jul 2025 12:42:18 -0500 Subject: [PATCH 1/4] Update vxlan.rs (#58) Introduce robust and RFC-compliant structures for Virtual eXtensible Local Area Network (RFC 7348) and headers, significantly improving VXLAN message handling. Key improvements include: * Adding vni_and_reserved2 Attribute * Removed BitfieldUnit * Added implementation method * Added Unit Tests Co-authored-by: Sven Cowart --- src/vxlan.rs | 244 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 228 insertions(+), 16 deletions(-) diff --git a/src/vxlan.rs b/src/vxlan.rs index 1b3fc27..8caaa71 100644 --- a/src/vxlan.rs +++ b/src/vxlan.rs @@ -1,33 +1,245 @@ use core::mem; -use crate::bitfield::BitfieldUnit; - -/// VXLAN header, which is present at the beginning of every UDP payload containing VXLAN packets. +/// VXLAN (Virtual eXtensible Local Area Network) header. +/// +/// Encapsulates OSI layer 2 Ethernet frames within layer 4 UDP packets. +/// Uses a 24-bit VXLAN Network Identifier (VNI) for traffic segregation. +/// Header length: 8 bytes. +/// Reference: RFC 7348. #[repr(C, packed)] #[derive(Debug, Copy, Clone)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] pub struct VxlanHdr { - /// VXLAN flags. See [`VxlanHdr::vni_valid`] and [`VxlanHdr::set_vni_valid`]. - pub flags: BitfieldUnit<[u8; 1usize]>, - pub _reserved: [u8; 3], - /// VXLAN Virtual Network Identifier. - /// - /// This is a 24-bit number combined with reserved bytes, see [`VxlanHdr::vni`] and - /// [`VxlanHdr::set_vni`]. + /// Flags (8 bits). Bit 3 (I flag) must be 1 if VNI is present. Other bits are reserved (R). + pub flags: u8, + /// Reserved field (24 bits). Must be zero on transmission. + pub _reserved1: [u8; 3], + /// Contains the 24-bit VNI (upper 3 bytes) and an 8-bit reserved field (the lowest byte). + /// The reserved field (the lowest byte) must be zero on transmission. pub vni: [u8; 3], - pub _padding: u8, + pub _reserved2: u8, } +/// Mask for the I-flag (VNI Present flag, bit 3) in the `flags` field. +pub const VXLAN_I_FLAG_MASK: u8 = 0x08; + impl VxlanHdr { - pub const LEN: usize = mem::size_of::(); + /// Length of the VXLAN header in bytes (8 bytes). + pub const LEN: usize = mem::size_of::(); + + /// Creates a new `VxlanHdr`. + /// + /// Sets the I-flag, zeros reserved fields, and sets the VNI. + /// + /// # Parameters + /// - `vni`: The 24-bit VXLAN Network Identifier. + /// + /// # Returns + /// A new `VxlanHdr` instance. + pub fn new(vni: u32) -> Self { + let mut hdr = VxlanHdr { + flags: VXLAN_I_FLAG_MASK, + _reserved1: [0u8; 3], + vni: [0u8; 3], + _reserved2: 0u8, + }; + hdr.set_vni(vni); + hdr + } + + /// Creates a new `VxlanHdr`. + /// + /// Sets the I-flag, zeros reserved fields, and sets the VNI. + /// + /// # Parameters + /// - `flags`: The 8-bit value to set for the flag field. + /// - `vni`: The 24-bit VXLAN Network Identifier. + /// + /// # Returns + /// A new `VxlanHdr` instance. + pub fn with_flags(flags: u8, vni: [u8; 3]) -> Self { + Self { + flags, + _reserved1: [0; 3], + vni, + _reserved2: 0, + } + } + + /// Returns the raw flags' byte. + /// + /// # Returns + /// The 8-bit flags field. + #[inline] + pub fn flags(&self) -> u8 { + self.flags + } + + /// Sets the raw flags byte. + /// + /// # Parameters + /// - `flags`: The 8-bit value to set for the flags field. + #[inline] + pub fn set_flags(&mut self, flags: u8) { + self.flags = flags; + } + + /// Checks if the I-flag (VNI Present) is set. + /// + /// # Returns + /// `true` if the I-flag is set, `false` otherwise. + #[inline] + pub fn vni_present(&self) -> bool { + (self.flags & VXLAN_I_FLAG_MASK) == VXLAN_I_FLAG_MASK + } + /// Sets or clears the I-flag (VNI Present). + /// + /// Preserves other flag bits. + /// + /// # Parameters + /// - `present`: If `true`, sets the I-flag; otherwise, clears it. #[inline] - pub fn vni_valid(&self) -> bool { - self.flags.get_bit(4) + pub fn set_vni_present(&mut self, present: bool) { + if present { + self.flags |= VXLAN_I_FLAG_MASK; + } else { + self.flags &= !VXLAN_I_FLAG_MASK; + } } + /// Returns the VXLAN Network Identifier (VNI). + /// + /// # Returns + /// The 24-bit VNI as a `u32`. + #[inline] + pub fn vni(&self) -> u32 { + u32::from_be_bytes([0, self.vni[0], self.vni[1], self.vni[2]]) + } + + /// Sets the VXLAN Network Identifier (VNI). + /// + /// Masks the input `vni` to 24 bits. Preserves the `reserved2` field. + /// + /// # Parameters + /// - `vni`: The 24-bit VNI value. #[inline] - pub fn set_vni_valid(&mut self, val: bool) { - self.flags.set_bit(4, val) + pub fn set_vni(&mut self, vni: u32) { + let vni_24bit = vni & 0x00FF_FFFF; + let vni_bytes = vni_24bit.to_be_bytes(); + self.vni[0] = vni_bytes[1]; + self.vni[1] = vni_bytes[2]; + self.vni[2] = vni_bytes[3]; + } +} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_vxlanhdr_len() { + assert_eq!(VxlanHdr::LEN, 8, "VXLAN header length should be 8 bytes"); + } + + #[test] + fn test_vxlanhdr_new() { + let vni_val: u32 = 0xABCDEF; + let hdr = VxlanHdr::new(vni_val); + assert_eq!( + hdr.flags(), + VXLAN_I_FLAG_MASK, + "Flags should have I-flag set and others zero" + ); + assert!(hdr.vni_present(), "VNI present flag should be set by new()"); + assert_eq!(hdr.vni(), vni_val, "VNI should be set correctly by new()"); + } + + #[test] + fn test_flags_management() { + let mut hdr = VxlanHdr::new(0x123); + hdr.set_flags(0xFF); + assert_eq!(hdr.flags(), 0xFF); + assert!( + hdr.vni_present(), + "I-flag should be set if flags byte is 0xFF" + ); + hdr.set_flags(0x00); + assert!( + !hdr.vni_present(), + "I-flag should be clear if flags byte is 0x00" + ); + hdr.set_vni_present(true); + assert_eq!( + hdr.flags(), + VXLAN_I_FLAG_MASK, + "set_vni_present(true) should set I-flag" + ); + assert!(hdr.vni_present()); + hdr.set_vni_present(false); + assert_eq!( + hdr.flags(), + 0x00, + "set_vni_present(false) should clear I-flag" + ); + assert!(!hdr.vni_present()); + hdr.set_flags(0xF0); + assert!(!hdr.vni_present()); + hdr.set_vni_present(true); + assert_eq!( + hdr.flags(), + 0xF0 | VXLAN_I_FLAG_MASK, + "Setting I-flag should preserve other bits" + ); + assert!(hdr.vni_present()); + hdr.set_vni_present(false); + assert_eq!( + hdr.flags(), + 0xF0 & !VXLAN_I_FLAG_MASK, + "Clearing I-flag should preserve other bits" + ); + assert!(!hdr.vni_present()); + } + + #[test] + fn test_vni_management() { + let mut hdr = VxlanHdr::new(0); + let vni_val: u32 = 0xABCDEF; + hdr.set_vni(vni_val); + assert_eq!(hdr.vni(), vni_val, "VNI should be set correctly"); + let large_vni: u32 = 0x12ABCDEF; + hdr.set_vni(large_vni); + assert_eq!(hdr.vni(), 0xABCDEF, "VNI should be masked to 24 bits"); + hdr.set_vni(0); + assert_eq!(hdr.vni(), 0, "VNI should be settable to 0"); + let max_vni: u32 = 0xFFFFFF; + hdr.set_vni(max_vni); + assert_eq!(hdr.vni(), max_vni, "Max 24-bit VNI should be settable"); + hdr.set_vni(0x123456); + assert_eq!(hdr.vni(), 0x123456, "VNI should be updated"); + } + + #[test] + fn test_field_storage_and_retrieval_direct_manipulation() { + let mut hdr = VxlanHdr::with_flags(0x08, [0xAB, 0xCD, 0xEF]); + hdr.flags = 0x08; + hdr.vni = [0xAB, 0xCD, 0xEF]; + assert_eq!(hdr.flags(), 0x08); + assert!(hdr.vni_present()); + assert_eq!(hdr.vni(), 0xABCDEF); + hdr.set_vni_present(false); + assert_eq!( + hdr.flags, 0x00, + "Direct field check after set_vni_present(false)" + ); + hdr.set_vni(0x654321); + assert_eq!(hdr.vni[0], 0x65, "Byte 0 of vni after set_vni"); + assert_eq!(hdr.vni[1], 0x43, "Byte 1 of vni after set_vni"); + assert_eq!(hdr.vni[2], 0x21, "Byte 2 of vni after set_vni"); + assert_eq!(hdr.vni(), 0x654321); + assert_eq!( + hdr.vni[0], 0x65, + "Byte 0 of vni preserved after set_reserved2" + ); + assert_eq!(hdr.vni(), 0x654321); } } From 993395c4b170eab033acd5822692918a9b9e6b85 Mon Sep 17 00:00:00 2001 From: Veronica Manchola Date: Tue, 1 Jul 2025 13:45:08 -0400 Subject: [PATCH 2/4] Adds support for GENEVE (#67) * **`GeneveHdr` struct**: A `#[repr(C, packed)]` struct is defined to accurately model the Geneve header format, ensuring correct memory layout. * **Field Accessors**: Provides `get` and `set` methods for all fields of the Geneve header, including: * `ver` (Version) * `opt_len` (Option Length) * `o_flag` (OAM Flag) * `c_flag` (Critical Options Present Flag) * `protocol_type` (Encapsulated Protocol Type, handled with network byte order) * `vni` (Virtual Network Identifier, handled with network byte order and 24-bit masking) * **Bitfield Handling**: The methods correctly handle bitfield extraction and insertion for `ver`, `opt_len`, `o_flag`, and `c_flag`. * **Network Byte Order**: `protocol_type` and `vni` conversions correctly handle big-endian (network byte order). * **Unit Tests**: Comprehensive unit tests are included to verify the correct behavior of all getters, setters, bitfield operations, and byte order conversions. This addition provides foundational support for parsing and constructing Geneve encapsulated packets within the project. --- src/geneve.rs | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 2 files changed, 262 insertions(+) create mode 100644 src/geneve.rs diff --git a/src/geneve.rs b/src/geneve.rs new file mode 100644 index 0000000..8304cfc --- /dev/null +++ b/src/geneve.rs @@ -0,0 +1,261 @@ +/// Represents a Geneve (Generic Network Virtualization Encapsulation) header, according to RFC 8926. +/// Geneve is an encapsulation protocol designed for network virtualization. + +#[repr(C, packed)] +#[derive(Debug, Copy, Clone, Default)] + +pub struct GeneveHdr { + /// Combined field: Version (2 bits) and Option Length (6 bits). + pub ver_opt_len: u8, + /// Combined field: OAM flag (1 bit), Critical flag (1 bit), Reserved (6 bits). + pub o_c_rsvd: u8, + /// Protocol Type of the encapsulated payload (16 bits). + pub protocol_type: [u8; 2], + /// Virtual Network Identifier (VNI) (24 bits). + pub vni: [u8; 3], + /// Reserved field (8 bits). MUST be zero on transmission. + pub reserved2: u8, +} + +impl GeneveHdr { + /// The length of the Geneve header in bytes. + pub const LEN: usize = core::mem::size_of::(); + + /// Returns the Geneve protocol version (2 bits). + /// + /// According to RFC 8926, the current version is 0. + #[inline] + pub fn ver(&self) -> u8 { + (self.ver_opt_len >> 6) & 0x03 + } + + /// Sets the Geneve protocol version (2 bits). + /// + /// `ver` should be a 2-bit value (0-3). + #[inline] + pub fn set_ver(&mut self, ver: u8) { + let preserved_bits = self.ver_opt_len & 0x3F; + self.ver_opt_len = preserved_bits | ((ver & 0x03) << 6); + } + + /// Returns the length of the option fields in 4-byte multiples (6 bits). + #[inline] + pub fn opt_len(&self) -> u8 { + self.ver_opt_len & 0x3F + } + + /// Sets the length of the option fields (6 bits). + /// + /// `opt_len` should be a 6-bit value (0-63). + #[inline] + pub fn set_opt_len(&mut self, opt_len: u8) { + let preserved_bits = self.ver_opt_len & 0xC0; + self.ver_opt_len = preserved_bits | (opt_len & 0x3F); + } + + /// Returns the OAM (Operations, Administration, and Maintenance) packet flag (1 bit). + /// + /// If set (1), this packet is an OAM packet. Referred to as 'O' bit in RFC 8926. + #[inline] + pub fn o_flag(&self) -> u8 { + (self.o_c_rsvd >> 7) & 0x01 + } + + /// Sets the OAM packet flag (1 bit). + /// + /// `o_flag` should be a 1-bit value (0 or 1). + #[inline] + pub fn set_o_flag(&mut self, o_flag: u8) { + let preserved_bits = self.o_c_rsvd & 0x7F; + self.o_c_rsvd = preserved_bits | ((o_flag & 0x01) << 7); + } + + /// Returns the Critical Options Present flag (1 bit). + /// + /// If set (1), one or more options are marked as critical. Referred to as 'C' bit in RFC 8926. + #[inline] + pub fn c_flag(&self) -> u8 { + (self.o_c_rsvd >> 6) & 0x01 + } + + /// Sets the Critical Options Present flag (1 bit). + /// + /// `c_flag` should be a 1-bit value (0 or 1). + #[inline] + pub fn set_c_flag(&mut self, c_flag: u8) { + let preserved_bits = self.o_c_rsvd & 0xBF; + self.o_c_rsvd = preserved_bits | ((c_flag & 0x01) << 6); + } + + /// Returns the Protocol Type of the encapsulated payload (16 bits, network byte order). + /// + /// This follows the Ethertype convention. + #[inline] + pub fn protocol_type(&self) -> u16 { + u16::from_be_bytes(self.protocol_type) + } + + /// Sets the Protocol Type (16 bits). + /// + /// The value is stored in network byte order. + #[inline] + pub fn set_protocol_type(&mut self, protocol_type: u16) { + self.protocol_type = protocol_type.to_be_bytes(); + } + + /// Returns the Virtual Network Identifier (VNI) (24 bits). + #[inline] + pub fn vni(&self) -> u32 { + u32::from_be_bytes([0, self.vni[0], self.vni[1], self.vni[2]]) + } + + /// Sets the Virtual Network Identifier (VNI) (24 bits). + /// + /// `vni` should be a 24-bit value. Higher bits are masked. + /// The value is stored in network byte order. + #[inline] + pub fn set_vni(&mut self, vni: u32) { + let vni_val = vni & 0x00FFFFFF; + let bytes = vni_val.to_be_bytes(); + self.vni[0] = bytes[1]; + self.vni[1] = bytes[2]; + self.vni[2] = bytes[3] + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_len() { + assert_eq!(GeneveHdr::LEN, 8); + } + + #[test] + fn test_default() { + let hdr = GeneveHdr::default(); + assert_eq!(hdr.ver_opt_len, 0); + assert_eq!(hdr.o_c_rsvd, 0); + assert_eq!(hdr.protocol_type, [0, 0]); + assert_eq!(hdr.vni, [0, 0, 0]); + assert_eq!(hdr.reserved2, 0); + + assert_eq!(hdr.ver(), 0); + assert_eq!(hdr.opt_len(), 0); + assert_eq!(hdr.o_flag(), 0); + assert_eq!(hdr.c_flag(), 0); + assert_eq!(hdr.protocol_type(), 0); + assert_eq!(hdr.vni(), 0); + } + + #[test] + fn test_ver() { + let mut hdr = GeneveHdr::default(); + hdr.set_ver(0b10); // Version 2 + assert_eq!(hdr.ver(), 0b10); + assert_eq!(hdr.ver_opt_len, 0b10000000, "Raw byte for ver failed"); + + hdr.set_ver(0b111); // Input 7 (3 bits), should be masked to 0b11 (3) + assert_eq!(hdr.ver(), 0b11); + assert_eq!(hdr.ver_opt_len, 0b11000000, "Masking for ver failed"); + + // Test interaction with opt_len + hdr.ver_opt_len = 0; // Reset + hdr.set_opt_len(0x3F); // Max opt_len (all lower 6 bits set) + hdr.set_ver(0b01); + assert_eq!(hdr.ver(), 0b01); + assert_eq!(hdr.opt_len(), 0x3F, "opt_len altered by set_ver"); + assert_eq!(hdr.ver_opt_len, 0b01111111, "Interaction with opt_len failed"); + } + + #[test] + fn test_opt_len() { + let mut hdr = GeneveHdr::default(); + hdr.set_opt_len(0x2A); // 42 + assert_eq!(hdr.opt_len(), 0x2A); + assert_eq!(hdr.ver_opt_len, 0b00101010, "Raw byte for opt_len failed"); + + hdr.set_opt_len(0xFF); // Input 255, should be masked to 0x3F (63) + assert_eq!(hdr.opt_len(), 0x3F); + assert_eq!(hdr.ver_opt_len, 0b00111111, "Masking for opt_len failed"); + + // Test interaction with ver + hdr.ver_opt_len = 0; // Reset + hdr.set_ver(0b11); // Max ver (top 2 bits set) + hdr.set_opt_len(0x15); // 21 + assert_eq!(hdr.ver(), 0b11, "ver altered by set_opt_len"); + assert_eq!(hdr.opt_len(), 0x15); + assert_eq!(hdr.ver_opt_len, 0b11010101, "Interaction with ver failed"); + } + + #[test] + fn test_o_flag() { + let mut hdr = GeneveHdr::default(); + hdr.set_o_flag(1); + assert_eq!(hdr.o_flag(), 1); + assert_eq!(hdr.o_c_rsvd, 0b10000000, "Raw byte for o_flag failed"); + + // The implementation correctly masks the input, so an input of 2 (0b10) becomes 0. + // This sets the o_flag back to 0. + hdr.set_o_flag(0b10); + assert_eq!(hdr.o_flag(), 0); + assert_eq!(hdr.o_c_rsvd, 0b00000000, "Masking for o_flag failed"); + + // Test that setting the O flag preserves the C flag and reserved bits. + hdr.o_c_rsvd = 0; // Reset + hdr.set_c_flag(1); // o_c_rsvd is now 0b01000000 + + // Now, set the O flag. + hdr.set_o_flag(1); + + // Verify that only the O flag bit changed. + assert_eq!(hdr.o_flag(), 1, "o_flag should be 1"); + assert_eq!(hdr.c_flag(), 1, "c_flag should be preserved"); + } + + #[test] + fn test_c_flag() { + let mut hdr = GeneveHdr::default(); + hdr.set_c_flag(1); + assert_eq!(hdr.c_flag(), 1); + assert_eq!(hdr.o_c_rsvd, 0b01000000, "Raw byte for c_flag failed"); + + // The implementation correctly masks the input, so an input of 2 (0b10) becomes 0. + // This sets the c_flag back to 0. + hdr.set_c_flag(0b10); + assert_eq!(hdr.c_flag(), 0); + assert_eq!(hdr.o_c_rsvd, 0b00000000, "Masking for c_flag failed"); + + // Test that setting the C flag preserves the O flag and reserved bits. + hdr.o_c_rsvd = 0; // Reset + hdr.set_o_flag(1); // o_c_rsvd is now 0b10000000 + + // Now, set the C flag. + hdr.set_c_flag(1); + + // Verify that only the C flag bit changed. + assert_eq!(hdr.c_flag(), 1, "c_flag should be 1"); + assert_eq!(hdr.o_flag(), 1, "o_flag should be preserved"); + } + + #[test] + fn test_protocol_type() { + let mut hdr = GeneveHdr::default(); + hdr.set_protocol_type(0xABCD); + assert_eq!(hdr.protocol_type(), 0xABCD); + assert_eq!(hdr.protocol_type, [0xAB, 0xCD], "Raw bytes for protocol_type failed (Big Endian check)"); + } + + #[test] + fn test_vni() { + let mut hdr = GeneveHdr::default(); + hdr.set_vni(0x00123456); + assert_eq!(hdr.vni(), 0x00123456); + assert_eq!(hdr.vni, [0x12, 0x34, 0x56], "Raw bytes for VNI failed (Big Endian check)"); + + hdr.set_vni(0xFF123456); // Input with >24 bits + assert_eq!(hdr.vni(), 0x00123456, "Masking for VNI failed"); + assert_eq!(hdr.vni, [0x12, 0x34, 0x56], "Raw bytes after VNI masking failed"); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index b5df8b5..b4f4bd2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,3 +14,4 @@ pub mod udp; pub mod vlan; pub mod vxlan; pub mod llc; +pub mod geneve; From 8e9e1436c8e89d918d34a677d45cc4a59d47d44b Mon Sep 17 00:00:00 2001 From: Michal Rostecki Date: Wed, 14 May 2025 17:56:47 +0200 Subject: [PATCH 3/4] ci: Run rustfmt, clippy and tests for multiple targets * Update `actions/checkout` action. * Use `dtolnay/rust-toolchain` action instead of `actions-rs`. * Run rustfmt and clippy. * Add the following cross targets: * `aarch64` * `bpfel`, `bpfeb` * `riscv64gc` * `wasm32` * `x86_64` test updated nightly matrix drop nightly targets since they haven't been built for over 3 years add clippy to components list skip useless transmute and too many args clippy warnings drop wasm target drop riscv for now add cross-compilation build tests for cross compiled arch add ignore for useless_transmute and too_many_arguments fix ignore opts include musl cross compiling as well remove std feature add std as a feature, but make no_std default run fmt only on stable only run fmt on x86 stable drop std feature since it seems to be unused remove serde no_std warning fix formatting in lib and llc drop std features in cargo.toml sync src --- .github/workflows/test.yml | 62 ++++++++++++++++++++++++++++++++------ README.md | 2 -- src/lib.rs | 2 +- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 87c8e8c..eaaeb0e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,16 +12,60 @@ on: jobs: test: runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - beta + - nightly + target: + - aarch64-unknown-linux-gnu + - aarch64-unknown-linux-musl + - riscv64gc-unknown-linux-gnu + - x86_64-unknown-linux-gnu + - x86_64-unknown-linux-musl + env: + CARGO_BUILD_TARGET: ${{ matrix.target }} + RUST_BACKTRACE: full steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - override: true + - name: Install cross-compilation tools + run: | + sudo apt-get update + sudo apt-get install -y gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu musl-tools - - name: Test - env: - RUST_BACKTRACE: full + - name: Configure Cargo for cross-compilation run: | - cargo test --verbose + mkdir -p .cargo + cat > .cargo/config.toml < Date: Wed, 2 Jul 2025 12:11:09 -0400 Subject: [PATCH 4/4] fix clippy error in doc comment in geneve --- src/geneve.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/geneve.rs b/src/geneve.rs index 8304cfc..43c8ca1 100644 --- a/src/geneve.rs +++ b/src/geneve.rs @@ -1,6 +1,6 @@ /// Represents a Geneve (Generic Network Virtualization Encapsulation) header, according to RFC 8926. /// Geneve is an encapsulation protocol designed for network virtualization. - +/// #[repr(C, packed)] #[derive(Debug, Copy, Clone, Default)] @@ -258,4 +258,4 @@ mod tests { assert_eq!(hdr.vni(), 0x00123456, "Masking for VNI failed"); assert_eq!(hdr.vni, [0x12, 0x34, 0x56], "Raw bytes after VNI masking failed"); } -} \ No newline at end of file +}