packet_strata/packet/tunnel/
nvgre.rs

1//! NVGRE (Network Virtualization using GRE) protocol parser
2//!
3//! This module implements parsing for NVGRE as defined in RFC 7637.
4//! NVGRE uses GRE version 0 with the Key field to carry the Virtual Subnet ID (VSID)
5//! and FlowID for network virtualization.
6//!
7//! # NVGRE Header Format
8//!
9//! ```text
10//!  0                   1                   2                   3
11//!  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
12//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
13//! |0|0|1|0|0|00000|000|00000|  Ver |   Protocol Type (0x6558)     |
14//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15//! |               Virtual Subnet ID (VSID)        |    FlowID     |
16//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17//! |                   Ethernet Frame...                           |
18//! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19//! ```
20//!
21//! # Key differences from standard GRE
22//!
23//! - Version field MUST be 0
24//! - Key flag (K) MUST be set
25//! - Checksum flag (C) SHOULD NOT be set
26//! - Sequence flag (S) SHOULD NOT be set
27//! - Protocol type MUST be 0x6558 (Transparent Ethernet Bridging)
28//! - Key field is split into VSID (24 bits) and FlowID (8 bits)
29//!
30//! # Examples
31//!
32//! ## Basic NVGRE parsing
33//!
34//! ```
35//! use packet_strata::packet::tunnel::nvgre::NvgreHeader;
36//! use packet_strata::packet::protocol::EtherProto;
37//! use packet_strata::packet::HeaderParser;
38//!
39//! // NVGRE packet
40//! let packet = vec![
41//!     0x20, 0x00,  // flags_version (K flag set, version 0)
42//!     0x65, 0x58,  // protocol_type (TEB - Transparent Ethernet Bridging)
43//!     0x00, 0x01, 0x00,  // VSID = 256
44//!     0x01,  // FlowID = 1
45//!     // ... Ethernet frame follows ...
46//! ];
47//!
48//! let (header, payload) = NvgreHeader::from_bytes(&packet).unwrap();
49//! assert_eq!(header.version(), 0);
50//! assert_eq!(header.protocol_type(), EtherProto::TEB);
51//! assert_eq!(header.vsid(), 256);
52//! assert_eq!(header.flow_id(), 1);
53//! ```
54//!
55//! ## NVGRE with specific VSID
56//!
57//! ```
58//! use packet_strata::packet::tunnel::nvgre::NvgreHeader;
59//! use packet_strata::packet::protocol::EtherProto;
60//! use packet_strata::packet::HeaderParser;
61//!
62//! // NVGRE with VSID = 0x123456, FlowID = 0
63//! let packet = vec![
64//!     0x20, 0x00,  // flags_version
65//!     0x65, 0x58,  // protocol_type (TEB)
66//!     0x12, 0x34, 0x56,  // VSID = 0x123456
67//!     0x00,  // FlowID = 0
68//!     // ... Ethernet frame follows ...
69//! ];
70//!
71//! let (header, _) = NvgreHeader::from_bytes(&packet).unwrap();
72//! assert_eq!(header.vsid(), 0x123456);
73//! assert_eq!(header.flow_id(), 0);
74//! ```
75
76use std::fmt::{self, Formatter};
77
78use zerocopy::byteorder::{BigEndian, U16, U32};
79use zerocopy::{FromBytes, IntoBytes, Unaligned};
80
81use crate::packet::protocol::EtherProto;
82use crate::packet::{HeaderParser, PacketHeader};
83
84/// NVGRE Protocol Type (Transparent Ethernet Bridging)
85pub const NVGRE_PROTOCOL_TEB: u16 = 0x6558;
86
87/// Maximum VSID value (24-bit field)
88pub const NVGRE_MAX_VSID: u32 = 0xFFFFFF;
89
90/// Reserved VSID values according to RFC 7637
91pub const NVGRE_VSID_RESERVED_MIN: u32 = 0xFFFFF0;
92pub const NVGRE_VSID_RESERVED_MAX: u32 = 0xFFFFFF;
93
94/// NVGRE Header structure as defined in RFC 7637
95///
96/// This is the fixed 8-byte NVGRE header. The Key field is interpreted
97/// as VSID (24 bits) + FlowID (8 bits).
98///
99/// Header format (8 bytes):
100/// ```text
101///  0                   1                   2                   3
102///  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
103/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
104/// |0|0|1|0|0|00000|000|00000| Ver |   Protocol Type (0x6558)      |
105/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
106/// |               Virtual Subnet ID (VSID)        |    FlowID     |
107/// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
108/// ```
109#[repr(C, packed)]
110#[derive(
111    FromBytes, IntoBytes, Unaligned, Debug, Clone, Copy, zerocopy::KnownLayout, zerocopy::Immutable,
112)]
113pub struct NvgreHeader {
114    flags_version: U16<BigEndian>,
115    protocol_type: U16<BigEndian>,
116    vsid_flowid: U32<BigEndian>,
117}
118
119impl NvgreHeader {
120    // GRE Flags (in the high byte of flags_version)
121    pub const FLAG_CHECKSUM: u16 = 0x8000; // Checksum Present (C bit) - SHOULD be 0
122    pub const FLAG_ROUTING: u16 = 0x4000; // Routing Present (R bit) - MUST be 0
123    pub const FLAG_KEY: u16 = 0x2000; // Key Present (K bit) - MUST be 1
124    pub const FLAG_SEQUENCE: u16 = 0x1000; // Sequence Number Present (S bit) - SHOULD be 0
125    pub const FLAG_STRICT_ROUTE: u16 = 0x0800; // Strict Source Route (s bit) - MUST be 0
126
127    pub const VERSION_MASK: u16 = 0x0007; // Version field (bits 13-15)
128    pub const RECUR_MASK: u16 = 0x0700; // Recursion control (bits 5-7) - MUST be 0
129    pub const FLAGS_MASK: u16 = 0x00F8; // Reserved flags (bits 8-12) - MUST be 0
130
131    pub const VERSION_NVGRE: u16 = 0x0000; // NVGRE uses GRE version 0
132
133    // VSID/FlowID masks
134    const VSID_MASK: u32 = 0xFFFFFF00;
135    const VSID_SHIFT: u32 = 8;
136    const FLOWID_MASK: u32 = 0x000000FF;
137
138    #[allow(unused)]
139    const NAME: &'static str = "NvgreHeader";
140
141    /// Returns the flags and version field
142    #[inline]
143    pub fn flags_version(&self) -> u16 {
144        self.flags_version.get()
145    }
146
147    /// Returns the GRE version number (should be 0 for NVGRE)
148    #[inline]
149    pub fn version(&self) -> u8 {
150        (self.flags_version() & Self::VERSION_MASK) as u8
151    }
152
153    /// Returns the protocol type field (should be 0x6558 for NVGRE)
154    #[inline]
155    pub fn protocol_type(&self) -> EtherProto {
156        self.protocol_type.get().into()
157    }
158
159    /// Returns the raw protocol type value
160    #[inline]
161    pub fn protocol_type_raw(&self) -> u16 {
162        self.protocol_type.get()
163    }
164
165    /// Returns the Virtual Subnet ID (VSID) - 24 bits
166    ///
167    /// The VSID identifies the virtual network/segment. Valid values are 0 to 0xFFFFEF.
168    /// Values 0xFFFFF0 to 0xFFFFFF are reserved.
169    #[inline]
170    pub fn vsid(&self) -> u32 {
171        (self.vsid_flowid.get() & Self::VSID_MASK) >> Self::VSID_SHIFT
172    }
173
174    /// Returns the FlowID - 8 bits
175    ///
176    /// The FlowID is used for load balancing purposes. When not used, it SHOULD be set to 0.
177    #[inline]
178    pub fn flow_id(&self) -> u8 {
179        (self.vsid_flowid.get() & Self::FLOWID_MASK) as u8
180    }
181
182    /// Returns the raw 32-bit key field (VSID + FlowID combined)
183    #[inline]
184    pub fn key(&self) -> u32 {
185        self.vsid_flowid.get()
186    }
187
188    /// Check if Checksum Present flag is set (should be 0 for NVGRE)
189    #[inline]
190    pub fn has_checksum(&self) -> bool {
191        self.flags_version() & Self::FLAG_CHECKSUM != 0
192    }
193
194    /// Check if Routing Present flag is set (should be 0 for NVGRE)
195    #[inline]
196    pub fn has_routing(&self) -> bool {
197        self.flags_version() & Self::FLAG_ROUTING != 0
198    }
199
200    /// Check if Key Present flag is set (should always be 1 for NVGRE)
201    #[inline]
202    pub fn has_key(&self) -> bool {
203        self.flags_version() & Self::FLAG_KEY != 0
204    }
205
206    /// Check if Sequence Number Present flag is set (should be 0 for NVGRE)
207    #[inline]
208    pub fn has_sequence(&self) -> bool {
209        self.flags_version() & Self::FLAG_SEQUENCE != 0
210    }
211
212    /// Check if Strict Source Route flag is set (should be 0 for NVGRE)
213    #[inline]
214    pub fn has_strict_route(&self) -> bool {
215        self.flags_version() & Self::FLAG_STRICT_ROUTE != 0
216    }
217
218    /// Returns the recursion control value (should be 0 for NVGRE)
219    #[inline]
220    pub fn recursion_control(&self) -> u8 {
221        ((self.flags_version() & Self::RECUR_MASK) >> 8) as u8
222    }
223
224    /// Check if the VSID is in the reserved range (0xFFFFF0 - 0xFFFFFF)
225    #[inline]
226    pub fn is_vsid_reserved(&self) -> bool {
227        let vsid = self.vsid();
228        (NVGRE_VSID_RESERVED_MIN..=NVGRE_VSID_RESERVED_MAX).contains(&vsid)
229    }
230
231    /// Validates the NVGRE header according to RFC 7637
232    ///
233    /// Strict validation requires:
234    /// - Version MUST be 0
235    /// - Key flag MUST be set
236    /// - Routing flag MUST be 0
237    /// - Strict Source Route flag MUST be 0
238    /// - Recursion control MUST be 0
239    /// - Protocol type MUST be 0x6558 (TEB)
240    #[inline]
241    fn is_valid(&self) -> bool {
242        // Version MUST be 0
243        if self.version() != 0 {
244            return false;
245        }
246
247        // Key flag MUST be set
248        if !self.has_key() {
249            return false;
250        }
251
252        // Routing flag MUST be 0
253        if self.has_routing() {
254            return false;
255        }
256
257        // Strict Source Route flag MUST be 0
258        if self.has_strict_route() {
259            return false;
260        }
261
262        // Recursion control MUST be 0
263        if self.recursion_control() != 0 {
264            return false;
265        }
266
267        // Protocol type MUST be TEB (0x6558)
268        if self.protocol_type_raw() != NVGRE_PROTOCOL_TEB {
269            return false;
270        }
271
272        true
273    }
274
275    /// Validates the NVGRE header with relaxed rules
276    ///
277    /// This is less strict and only checks:
278    /// - Version is 0
279    /// - Key flag is set
280    #[inline]
281    pub fn is_valid_relaxed(&self) -> bool {
282        self.version() == 0 && self.has_key()
283    }
284
285    /// Returns a string representation of active flags
286    pub fn flags_string(&self) -> String {
287        let mut flags = Vec::new();
288
289        if self.has_checksum() {
290            flags.push("C");
291        }
292        if self.has_routing() {
293            flags.push("R");
294        }
295        if self.has_key() {
296            flags.push("K");
297        }
298        if self.has_sequence() {
299            flags.push("S");
300        }
301        if self.has_strict_route() {
302            flags.push("s");
303        }
304
305        if flags.is_empty() {
306            "none".to_string()
307        } else {
308            flags.join("")
309        }
310    }
311}
312
313impl PacketHeader for NvgreHeader {
314    const NAME: &'static str = "NvgreHeader";
315    type InnerType = EtherProto;
316
317    #[inline]
318    fn inner_type(&self) -> Self::InnerType {
319        self.protocol_type()
320    }
321
322    /// Returns the total header length in bytes (always 8 for NVGRE)
323    #[inline]
324    fn total_len(&self, _buf: &[u8]) -> usize {
325        Self::FIXED_LEN
326    }
327
328    /// Validates the NVGRE header
329    #[inline]
330    fn is_valid(&self) -> bool {
331        self.is_valid()
332    }
333}
334
335impl HeaderParser for NvgreHeader {
336    type Output<'a> = &'a NvgreHeader;
337
338    #[inline]
339    fn into_view<'a>(header: &'a Self, _raw_options: &'a [u8]) -> Self::Output<'a> {
340        header
341    }
342}
343
344impl fmt::Display for NvgreHeader {
345    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
346        write!(
347            f,
348            "NVGRE vsid={} flow_id={} proto={}(0x{:04x}) flags={}",
349            self.vsid(),
350            self.flow_id(),
351            self.protocol_type(),
352            self.protocol_type().0,
353            self.flags_string()
354        )
355    }
356}
357
358#[cfg(test)]
359mod tests {
360    use super::*;
361
362    #[test]
363    fn test_nvgre_header_size() {
364        assert_eq!(std::mem::size_of::<NvgreHeader>(), 8);
365        assert_eq!(NvgreHeader::FIXED_LEN, 8);
366    }
367
368    #[test]
369    fn test_nvgre_basic_header() {
370        let header = NvgreHeader {
371            flags_version: U16::new(0x2000), // Key present, version 0
372            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
373            vsid_flowid: U32::new(0x00010000), // VSID = 256, FlowID = 0
374        };
375
376        assert_eq!(header.version(), 0);
377        assert_eq!(header.protocol_type(), EtherProto::TEB);
378        assert!(header.has_key());
379        assert!(!header.has_checksum());
380        assert!(!header.has_sequence());
381        assert!(header.is_valid());
382        assert_eq!(header.vsid(), 256);
383        assert_eq!(header.flow_id(), 0);
384    }
385
386    #[test]
387    fn test_nvgre_vsid_flowid() {
388        // VSID = 0x123456, FlowID = 0xAB
389        let header = NvgreHeader {
390            flags_version: U16::new(0x2000),
391            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
392            vsid_flowid: U32::new(0x123456AB),
393        };
394
395        assert_eq!(header.vsid(), 0x123456);
396        assert_eq!(header.flow_id(), 0xAB);
397        assert_eq!(header.key(), 0x123456AB);
398    }
399
400    #[test]
401    fn test_nvgre_max_vsid() {
402        // VSID = 0xFFFFFF (max), FlowID = 0xFF
403        let header = NvgreHeader {
404            flags_version: U16::new(0x2000),
405            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
406            vsid_flowid: U32::new(0xFFFFFFFF),
407        };
408
409        assert_eq!(header.vsid(), 0xFFFFFF);
410        assert_eq!(header.flow_id(), 0xFF);
411        assert!(header.is_vsid_reserved());
412    }
413
414    #[test]
415    fn test_nvgre_reserved_vsid_range() {
416        // VSID = 0xFFFFF0 (first reserved)
417        let header1 = NvgreHeader {
418            flags_version: U16::new(0x2000),
419            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
420            vsid_flowid: U32::new(0xFFFFF000),
421        };
422        assert!(header1.is_vsid_reserved());
423
424        // VSID = 0xFFFFEF (last non-reserved)
425        let header2 = NvgreHeader {
426            flags_version: U16::new(0x2000),
427            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
428            vsid_flowid: U32::new(0xFFFFEF00),
429        };
430        assert!(!header2.is_vsid_reserved());
431    }
432
433    #[test]
434    fn test_nvgre_version_validation() {
435        // Invalid: version 1
436        let header = NvgreHeader {
437            flags_version: U16::new(0x2001), // Key present, but version 1
438            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
439            vsid_flowid: U32::new(0x00010000),
440        };
441        assert!(!header.is_valid());
442        assert!(!header.is_valid_relaxed());
443    }
444
445    #[test]
446    fn test_nvgre_key_flag_required() {
447        // Invalid: Key flag not set
448        let header = NvgreHeader {
449            flags_version: U16::new(0x0000), // version 0, but no key
450            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
451            vsid_flowid: U32::new(0x00010000),
452        };
453        assert!(!header.is_valid());
454        assert!(!header.is_valid_relaxed());
455    }
456
457    #[test]
458    fn test_nvgre_routing_forbidden() {
459        // Invalid: Routing flag set
460        let header = NvgreHeader {
461            flags_version: U16::new(0x6000), // Key + Routing
462            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
463            vsid_flowid: U32::new(0x00010000),
464        };
465        assert!(!header.is_valid());
466        // But relaxed validation passes
467        assert!(header.is_valid_relaxed());
468    }
469
470    #[test]
471    fn test_nvgre_wrong_protocol_type() {
472        // Invalid: Wrong protocol type (IPv4 instead of TEB)
473        let header = NvgreHeader {
474            flags_version: U16::new(0x2000),
475            protocol_type: U16::new(0x0800), // IPv4 instead of TEB
476            vsid_flowid: U32::new(0x00010000),
477        };
478        assert!(!header.is_valid());
479        // But relaxed validation passes
480        assert!(header.is_valid_relaxed());
481    }
482
483    #[test]
484    fn test_nvgre_with_checksum_flag() {
485        // Checksum flag set (SHOULD NOT, but not MUST NOT)
486        let header = NvgreHeader {
487            flags_version: U16::new(0xA000), // Key + Checksum
488            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
489            vsid_flowid: U32::new(0x00010000),
490        };
491        assert!(header.has_checksum());
492        // Still valid according to RFC (SHOULD NOT, not MUST NOT)
493        assert!(header.is_valid());
494    }
495
496    #[test]
497    fn test_nvgre_with_sequence_flag() {
498        // Sequence flag set (SHOULD NOT, but not MUST NOT)
499        let header = NvgreHeader {
500            flags_version: U16::new(0x3000), // Key + Sequence
501            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
502            vsid_flowid: U32::new(0x00010000),
503        };
504        assert!(header.has_sequence());
505        // Still valid according to RFC (SHOULD NOT, not MUST NOT)
506        assert!(header.is_valid());
507    }
508
509    #[test]
510    fn test_nvgre_parsing_basic() {
511        let mut packet = Vec::new();
512
513        // NVGRE header
514        packet.extend_from_slice(&0x2000u16.to_be_bytes()); // flags_version (K, v0)
515        packet.extend_from_slice(&NVGRE_PROTOCOL_TEB.to_be_bytes()); // protocol_type
516        packet.extend_from_slice(&0x00010001u32.to_be_bytes()); // VSID=256, FlowID=1
517
518        // Add some payload (Ethernet frame would follow)
519        packet.extend_from_slice(b"payload");
520
521        let result = NvgreHeader::from_bytes(&packet);
522        assert!(result.is_ok());
523
524        let (header, payload) = result.unwrap();
525        assert_eq!(header.version(), 0);
526        assert_eq!(header.protocol_type(), EtherProto::TEB);
527        assert_eq!(header.vsid(), 256);
528        assert_eq!(header.flow_id(), 1);
529        assert_eq!(payload, b"payload");
530    }
531
532    #[test]
533    fn test_nvgre_parsing_with_vsid() {
534        let mut packet = Vec::new();
535
536        packet.extend_from_slice(&0x2000u16.to_be_bytes()); // flags_version
537        packet.extend_from_slice(&NVGRE_PROTOCOL_TEB.to_be_bytes()); // protocol_type
538        packet.extend_from_slice(&0x12345600u32.to_be_bytes()); // VSID=0x123456, FlowID=0
539
540        let result = NvgreHeader::from_bytes(&packet);
541        assert!(result.is_ok());
542
543        let (header, _) = result.unwrap();
544        assert_eq!(header.vsid(), 0x123456);
545        assert_eq!(header.flow_id(), 0);
546    }
547
548    #[test]
549    fn test_nvgre_parsing_too_small() {
550        let packet = vec![0u8; 7]; // Only 7 bytes, need 8
551
552        let result = NvgreHeader::from_bytes(&packet);
553        assert!(result.is_err());
554    }
555
556    #[test]
557    fn test_nvgre_parsing_invalid_version() {
558        let mut packet = Vec::new();
559
560        // Invalid: version 1
561        packet.extend_from_slice(&0x2001u16.to_be_bytes()); // flags_version (K, v1)
562        packet.extend_from_slice(&NVGRE_PROTOCOL_TEB.to_be_bytes());
563        packet.extend_from_slice(&0x00010000u32.to_be_bytes());
564
565        let result = NvgreHeader::from_bytes(&packet);
566        assert!(result.is_err());
567    }
568
569    #[test]
570    fn test_nvgre_parsing_missing_key() {
571        let mut packet = Vec::new();
572
573        // Invalid: no key flag
574        packet.extend_from_slice(&0x0000u16.to_be_bytes()); // flags_version (no K)
575        packet.extend_from_slice(&NVGRE_PROTOCOL_TEB.to_be_bytes());
576        packet.extend_from_slice(&0x00010000u32.to_be_bytes());
577
578        let result = NvgreHeader::from_bytes(&packet);
579        assert!(result.is_err());
580    }
581
582    #[test]
583    fn test_nvgre_flags_string() {
584        let header1 = NvgreHeader {
585            flags_version: U16::new(0x2000), // K only
586            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
587            vsid_flowid: U32::new(0x00010000),
588        };
589        assert_eq!(header1.flags_string(), "K");
590
591        let header2 = NvgreHeader {
592            flags_version: U16::new(0xA000), // K + C
593            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
594            vsid_flowid: U32::new(0x00010000),
595        };
596        assert_eq!(header2.flags_string(), "CK");
597
598        let header3 = NvgreHeader {
599            flags_version: U16::new(0x3000), // K + S
600            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
601            vsid_flowid: U32::new(0x00010000),
602        };
603        assert_eq!(header3.flags_string(), "KS");
604    }
605
606    #[test]
607    fn test_nvgre_display() {
608        let header = NvgreHeader {
609            flags_version: U16::new(0x2000),
610            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
611            vsid_flowid: U32::new(0x00010001),
612        };
613
614        let display = format!("{}", header);
615        assert!(display.contains("NVGRE"));
616        assert!(display.contains("vsid=256"));
617        assert!(display.contains("flow_id=1"));
618    }
619
620    #[test]
621    fn test_nvgre_zero_vsid() {
622        let header = NvgreHeader {
623            flags_version: U16::new(0x2000),
624            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
625            vsid_flowid: U32::new(0x00000000), // VSID=0, FlowID=0
626        };
627
628        assert_eq!(header.vsid(), 0);
629        assert_eq!(header.flow_id(), 0);
630        assert!(header.is_valid());
631        assert!(!header.is_vsid_reserved());
632    }
633
634    #[test]
635    fn test_nvgre_inner_type() {
636        let header = NvgreHeader {
637            flags_version: U16::new(0x2000),
638            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
639            vsid_flowid: U32::new(0x00010000),
640        };
641
642        // inner_type should return TEB for encapsulated Ethernet
643        assert_eq!(header.inner_type(), EtherProto::TEB);
644    }
645
646    #[test]
647    fn test_nvgre_multicast_vsid() {
648        // Test with a typical multicast VSID scenario
649        let header = NvgreHeader {
650            flags_version: U16::new(0x2000),
651            protocol_type: U16::new(NVGRE_PROTOCOL_TEB),
652            vsid_flowid: U32::new(0x00ABCD00), // VSID=0xABCD (common test value)
653        };
654
655        assert_eq!(header.vsid(), 0x00ABCD);
656        assert!(!header.is_vsid_reserved());
657    }
658}