packet_strata/tracker/
vni.rs

1//! Virtual Network Identifier (VNI) management
2//!
3//! This module handles VNI layer information, including VLAN, MPLS, GRE, VXLAN,
4//! Geneve, and various IP tunneling protocols.
5//!
6//! # Overview
7//!
8//! Instead of the traditional "tunnel" concept, this module uses a layer-based
9//! approach where each VNI represents a specific network encapsulation layer.
10//! Multiple layers can be stacked to represent complex network topologies.
11//!
12//! # Design Philosophy
13//!
14//! Each VNI layer type is represented as an enum variant with exactly the fields
15//! it needs - no more, no less. This makes invalid states unrepresentable and
16//! provides excellent type safety.
17//!
18//! # Example
19//!
20//! ```ignore
21//! use packet_strata::tracker::vni::{VniLayer, VniMapper};
22//!
23//! let mut mapper = VniMapper::new();
24//!
25//! // Create a VLAN VNI
26//! let vlan = VniLayer::vlan(100);
27//!
28//! // Get or create a VNI ID
29//! let vni_id = mapper.get_or_create_vni_id(&[vlan]);
30//!
31//! // Look up the VNI stack later
32//! if let Some(stack) = mapper.lookup_vni(&vni_id) {
33//!     println!("VNI stack: {:?}", stack);
34//! }
35//! ```
36
37use serde::{Deserialize, Serialize};
38use smallvec::SmallVec;
39use std::collections::BTreeMap;
40use std::fmt;
41use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
42
43use crate::packet::ether::EtherHeaderVlan;
44use crate::packet::header::{LinkLayer, NetworkLayer, NetworkTunnelLayer, TunnelLayer};
45use crate::packet::Packet;
46
47/// Error types for VNI operations
48#[derive(Debug, Clone, PartialEq, Eq)]
49pub enum VniError {
50    /// Invalid IP header length
51    InvalidHeaderLength,
52    /// Invalid IP version
53    InvalidIpVersion,
54}
55
56impl fmt::Display for VniError {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        match self {
59            Self::InvalidHeaderLength => write!(f, "Invalid IP header length"),
60            Self::InvalidIpVersion => write!(f, "Invalid IP version"),
61        }
62    }
63}
64
65impl std::error::Error for VniError {}
66
67/// Network layer types for VNI encapsulation
68///
69/// Each variant contains exactly the fields required for that specific layer type.
70/// This makes invalid states unrepresentable at compile time.
71#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
72pub enum VniLayer {
73    /// IEEE 802.1Q VLAN
74    ///
75    /// Contains only the VLAN ID (12-bit value, 0-4095)
76    Vlan { vid: u16 },
77
78    /// Multiprotocol Label Switching
79    ///
80    /// Contains only the MPLS label (20-bit value)
81    Mpls { label: u32 },
82
83    /// Generic Routing Encapsulation (RFC 2784, RFC 2890)
84    ///
85    /// Contains protocol type, optional key, and tunnel endpoints
86    Gre {
87        protocol_type: u16,
88        key: Option<u32>,
89        endpoints: [IpAddr; 2],
90    },
91
92    /// Network Virtualization using Generic Routing Encapsulation (NVGRE)
93    ///
94    /// Contains protocol type, VSID/FlowID (24-bit VSID + 8-bit FlowID), and tunnel endpoints
95    NvGre {
96        protocol_type: u16,
97        vsid_flowid: u32,
98        endpoints: [IpAddr; 2],
99    },
100
101    /// Virtual Extensible LAN (RFC 7348)
102    ///
103    /// Contains VNI (24-bit), optional Group Policy ID, and tunnel endpoints
104    Vxlan {
105        vni: u32,
106        group_id: u16,
107        endpoints: [IpAddr; 2],
108    },
109
110    /// Generic Network Virtualization Encapsulation (RFC 8926)
111    ///
112    /// Contains VNI (24-bit), protocol type, and tunnel endpoints
113    Geneve {
114        vni: u32,
115        protocol_type: u16,
116        endpoints: [IpAddr; 2],
117    },
118
119    /// IP-in-IP Encapsulation (RFC 2003) - IPv4-in-IPv4
120    ///
121    /// Also known as IPIP. Contains only tunnel endpoints.
122    Ipip { endpoints: [IpAddr; 2] },
123
124    /// IPv4-in-IPv6 Tunnel (RFC 2473)
125    ///
126    /// Used for DS-Lite (RFC 6333) and other 4in6 tunneling scenarios.
127    Ip4in6 { endpoints: [IpAddr; 2] },
128
129    /// IPv6-in-IPv4 Tunnel (RFC 4213)
130    ///
131    /// Also known as 6in4, SIT (Simple Internet Transition), or configured tunnels.
132    Sit { endpoints: [IpAddr; 2] },
133
134    /// IPv6-in-IPv6 Tunnel (RFC 2473)
135    ///
136    /// Generic IPv6 packet tunneling in IPv6.
137    Ip6Tnl { endpoints: [IpAddr; 2] },
138
139    /// GPRS Tunneling Protocol User Plane (GTP-U, 3GPP TS 29.281)
140    ///
141    /// Contains TEID (32-bit Tunnel Endpoint Identifier) and endpoints.
142    /// Note: GTP-C (Control Plane) messages are signaling, not tunnels.
143    GtpU { teid: u32, endpoints: [IpAddr; 2] },
144
145    /// Teredo Tunneling (RFC 4380)
146    ///
147    /// IPv6 over UDP/IPv4 NAT traversal. Contains tunnel endpoints.
148    Teredo { endpoints: [IpAddr; 2] },
149
150    /// L2TPv2 - Layer 2 Tunneling Protocol version 2 (RFC 2661)
151    ///
152    /// Contains Tunnel ID (16-bit), Session ID (16-bit), and endpoints.
153    L2tpV2 {
154        tunnel_id: u16,
155        session_id: u16,
156        endpoints: [IpAddr; 2],
157    },
158
159    /// L2TPv3 - Layer 2 Tunneling Protocol version 3 (RFC 3931)
160    ///
161    /// Contains Control Connection ID or Session ID (32-bit) and endpoints.
162    L2tpV3 {
163        session_id: u32,
164        endpoints: [IpAddr; 2],
165    },
166
167    /// Provider Backbone Bridge (IEEE 802.1ah) - MAC-in-MAC
168    ///
169    /// Contains I-SID (24-bit Service Instance Identifier) and optional B-VID.
170    Pbb { isid: u32, bvid: Option<u16> },
171
172    /// Stateless Transport Tunneling (STT)
173    ///
174    /// VMware's tunneling protocol. Contains Context ID (64-bit) and endpoints.
175    Stt {
176        context_id: u64,
177        endpoints: [IpAddr; 2],
178    },
179
180    /// Point-to-Point Tunneling Protocol (RFC 2637)
181    ///
182    /// Uses enhanced GRE. Contains Call ID (16-bit) and endpoints.
183    Pptp {
184        call_id: u16,
185        endpoints: [IpAddr; 2],
186    },
187}
188
189impl fmt::Display for VniLayer {
190    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191        match self {
192            Self::Vlan { vid } => write!(f, "vlan({})", vid),
193            Self::Mpls { label } => write!(f, "mpls({})", label),
194            Self::Gre {
195                protocol_type,
196                key,
197                endpoints,
198            } => {
199                write!(f, "gre(ptype:0x{:04x}", protocol_type)?;
200                if let Some(k) = key {
201                    write!(f, " key:{}", k)?;
202                }
203                write!(f, " {}↔{})", endpoints[0], endpoints[1])
204            }
205            Self::NvGre {
206                protocol_type,
207                vsid_flowid,
208                endpoints,
209            } => {
210                write!(
211                    f,
212                    "nvgre(ptype:0x{:04x} vsid:{} {}↔{})",
213                    protocol_type, vsid_flowid, endpoints[0], endpoints[1]
214                )
215            }
216            Self::Vxlan {
217                vni,
218                group_id,
219                endpoints,
220            } => {
221                write!(f, "vxlan(vni:{}", vni)?;
222                if *group_id != 0 {
223                    write!(f, " gid:{}", group_id)?;
224                }
225                write!(f, " {}↔{})", endpoints[0], endpoints[1])
226            }
227            Self::Geneve {
228                vni,
229                protocol_type,
230                endpoints,
231            } => {
232                write!(
233                    f,
234                    "geneve(vni:{} ptype:0x{:04x} {}↔{})",
235                    vni, protocol_type, endpoints[0], endpoints[1]
236                )
237            }
238            Self::Ipip { endpoints } => {
239                write!(f, "ipip({}↔{})", endpoints[0], endpoints[1])
240            }
241            Self::Ip4in6 { endpoints } => {
242                write!(f, "ip4in6({}↔{})", endpoints[0], endpoints[1])
243            }
244            Self::Sit { endpoints } => {
245                write!(f, "sit({}↔{})", endpoints[0], endpoints[1])
246            }
247            Self::Ip6Tnl { endpoints } => {
248                write!(f, "ip6tnl({}↔{})", endpoints[0], endpoints[1])
249            }
250            Self::GtpU { teid, endpoints } => {
251                write!(
252                    f,
253                    "gtp-u(teid:0x{:08x} {}↔{})",
254                    teid, endpoints[0], endpoints[1]
255                )
256            }
257            Self::Teredo { endpoints } => {
258                write!(f, "teredo({}↔{})", endpoints[0], endpoints[1])
259            }
260            Self::L2tpV2 {
261                tunnel_id,
262                session_id,
263                endpoints,
264            } => {
265                write!(
266                    f,
267                    "l2tpv2(tid:{} sid:{} {}↔{})",
268                    tunnel_id, session_id, endpoints[0], endpoints[1]
269                )
270            }
271            Self::L2tpV3 {
272                session_id,
273                endpoints,
274            } => {
275                write!(
276                    f,
277                    "l2tpv3(sid:{} {}↔{})",
278                    session_id, endpoints[0], endpoints[1]
279                )
280            }
281            Self::Pbb { isid, bvid } => {
282                write!(f, "pbb(isid:{}", isid)?;
283                if let Some(b) = bvid {
284                    write!(f, " bvid:{}", b)?;
285                }
286                write!(f, ")")
287            }
288            Self::Stt {
289                context_id,
290                endpoints,
291            } => {
292                write!(
293                    f,
294                    "stt(ctx:0x{:016x} {}↔{})",
295                    context_id, endpoints[0], endpoints[1]
296                )
297            }
298            Self::Pptp { call_id, endpoints } => {
299                write!(
300                    f,
301                    "pptp(call:{} {}↔{})",
302                    call_id, endpoints[0], endpoints[1]
303                )
304            }
305        }
306    }
307}
308
309impl From<&LinkLayer<'_>> for SmallVec<[VniLayer; 2]> {
310    fn from(value: &LinkLayer<'_>) -> Self {
311        match value {
312            LinkLayer::Ethernet(EtherHeaderVlan::VLAN8021Q(_, eth8021q)) => {
313                let mut sv = SmallVec::<[VniLayer; 2]>::new();
314                sv.push(VniLayer::Vlan {
315                    vid: eth8021q.vlan_id(),
316                });
317                sv
318            }
319            LinkLayer::Ethernet(EtherHeaderVlan::VLAN8021QNested(_, eth8021q, eth8021q_n)) => {
320                let mut sv = SmallVec::<[VniLayer; 2]>::new();
321                sv.push(VniLayer::Vlan {
322                    vid: eth8021q.vlan_id(),
323                });
324                sv.push(VniLayer::Vlan {
325                    vid: eth8021q_n.vlan_id(),
326                });
327                sv
328            }
329            _ => SmallVec::<[VniLayer; 2]>::new(),
330        }
331    }
332}
333
334impl TryFrom<&NetworkTunnelLayer<'_>> for VniLayer {
335    type Error = ();
336    fn try_from(ip_tunnel: &NetworkTunnelLayer<'_>) -> Result<Self, Self::Error> {
337        // Extract endpoints from outer IP header if present
338        let endpoints: Option<[IpAddr; 2]> = ip_tunnel.outer().and_then(|outer| {
339            match outer {
340                NetworkLayer::Ipv4(ipv4) => Some([ipv4.src_ip().into(), ipv4.dst_ip().into()]),
341                NetworkLayer::Ipv6(ipv6) => Some([ipv6.src_ip().into(), ipv6.dst_ip().into()]),
342                NetworkLayer::Mpls(_) => None, // MPLS doesn't have IP endpoints
343            }
344        });
345
346        // Process the tunnel based on type
347        match ip_tunnel.tunnel() {
348            TunnelLayer::Vxlan(vxlan) => endpoints.ok_or(()).map(|endpoints| VniLayer::Vxlan {
349                vni: vxlan.vni(),
350                group_id: 0,
351                endpoints,
352            }),
353            TunnelLayer::Geneve(geneve) => endpoints.ok_or(()).map(|endpoints| VniLayer::Geneve {
354                vni: geneve.header.vni(),
355                protocol_type: geneve.header.protocol_type_raw(),
356                endpoints,
357            }),
358            TunnelLayer::Gre(gre) => endpoints.ok_or(()).map(|endpoints| VniLayer::Gre {
359                protocol_type: gre.header.protocol_type().into(),
360                key: gre.key(),
361                endpoints,
362            }),
363            TunnelLayer::Teredo(_teredo) => endpoints
364                .ok_or(())
365                .map(|endpoints| VniLayer::Teredo { endpoints }),
366            TunnelLayer::Gtpv1(gtp) => endpoints.ok_or(()).map(|endpoints| VniLayer::GtpU {
367                teid: gtp.header.teid(),
368                endpoints,
369            }),
370            TunnelLayer::Gtpv2(_gtp) => {
371                // GTPv2 is control plane, not a tunnel for VNI purposes
372                Err(())
373            }
374            TunnelLayer::L2tpv2(l2tp) => endpoints.ok_or(()).map(|endpoints| VniLayer::L2tpV2 {
375                tunnel_id: l2tp.tunnel_id(),
376                session_id: l2tp.session_id(),
377                endpoints,
378            }),
379            TunnelLayer::L2tpv3(l2tp) => endpoints.ok_or(()).map(|endpoints| VniLayer::L2tpV3 {
380                session_id: l2tp.session_id(),
381                endpoints,
382            }),
383            TunnelLayer::Nvgre(nvgre) => endpoints.ok_or(()).map(|endpoints| VniLayer::NvGre {
384                protocol_type: nvgre.protocol_type_raw(),
385                vsid_flowid: nvgre.vsid() << 8 | nvgre.flow_id() as u32,
386                endpoints,
387            }),
388            TunnelLayer::Pbb(pbb) => {
389                // PBB (Provider Backbone Bridge) is MAC-in-MAC, doesn't need IP endpoints
390                Ok(VniLayer::Pbb {
391                    isid: pbb.isid(),
392                    bvid: pbb.bvid(),
393                })
394            }
395            TunnelLayer::Stt(stt) => endpoints.ok_or(()).map(|endpoints| VniLayer::Stt {
396                context_id: stt.context_id(),
397                endpoints,
398            }),
399            TunnelLayer::Pptp(pptp) => endpoints.ok_or(()).map(|endpoints| VniLayer::Pptp {
400                call_id: pptp.header.call_id(),
401                endpoints,
402            }),
403            TunnelLayer::Ipip(ipip) => {
404                // IPIP tunnels have access to outer IP headers embedded in the tunnel
405                match ipip.outer_header() {
406                    crate::packet::tunnel::ipip::OuterIpHeader::V4(ipv4) => {
407                        let src = ipv4.header.src_ip_raw();
408                        let dst = ipv4.header.dst_ip_raw();
409                        let mut endpoints = [
410                            IpAddr::V4(Ipv4Addr::from(src)),
411                            IpAddr::V4(Ipv4Addr::from(dst)),
412                        ];
413                        endpoints.sort();
414
415                        match ipip.tunnel_type() {
416                            crate::packet::tunnel::ipip::IpipType::Ipip => {
417                                Ok(VniLayer::Ipip { endpoints })
418                            }
419                            crate::packet::tunnel::ipip::IpipType::Sit => {
420                                Ok(VniLayer::Sit { endpoints })
421                            }
422                            _ => Err(()),
423                        }
424                    }
425                    crate::packet::tunnel::ipip::OuterIpHeader::V6(ipv6) => {
426                        let src = ipv6.header.src_ip_raw();
427                        let dst = ipv6.header.dst_ip_raw();
428                        let mut endpoints = [
429                            IpAddr::V6(Ipv6Addr::from(dst)),
430                            IpAddr::V6(Ipv6Addr::from(src)),
431                        ];
432                        endpoints.sort();
433
434                        match ipip.tunnel_type() {
435                            crate::packet::tunnel::ipip::IpipType::Ip4in6 => {
436                                Ok(VniLayer::Ip4in6 { endpoints })
437                            }
438                            crate::packet::tunnel::ipip::IpipType::Ip6Tnl => {
439                                Ok(VniLayer::Ip6Tnl { endpoints })
440                            }
441                            _ => Err(()),
442                        }
443                    }
444                }
445            }
446        }
447    }
448}
449
450/// Convert a Packet to a VNI layer stack
451///
452/// This efficiently extracts VNI information from:
453/// 1. Link layer (VLAN tags) - produces SmallVec<[VniLayer; 2]>
454/// 2. Tunnel layers - each NetworkTunnelLayer converted to VniLayer
455///
456/// The result is the concatenation of link VNI layers followed by tunnel VNI layers.
457/// This operation may fail (returning Err(())) if any tunnel layer cannot be converted.
458impl TryFrom<&Packet<'_>> for SmallVec<[VniLayer; 4]> {
459    type Error = ();
460
461    fn try_from(packet: &Packet<'_>) -> Result<Self, Self::Error> {
462        let mut vni_stack: SmallVec<[VniLayer; 4]> = SmallVec::new();
463
464        // Extract VLAN information from link layer directly into vni_stack
465        // This avoids creating a temporary SmallVec
466        match packet.link() {
467            LinkLayer::Ethernet(EtherHeaderVlan::VLAN8021Q(_, eth8021q)) => {
468                vni_stack.push(VniLayer::Vlan {
469                    vid: eth8021q.vlan_id(),
470                });
471            }
472            LinkLayer::Ethernet(EtherHeaderVlan::VLAN8021QNested(_, eth8021q, eth8021q_n)) => {
473                vni_stack.push(VniLayer::Vlan {
474                    vid: eth8021q.vlan_id(),
475                });
476                vni_stack.push(VniLayer::Vlan {
477                    vid: eth8021q_n.vlan_id(),
478                });
479            }
480            _ => {
481                // No VLAN, nothing to add
482            }
483        }
484
485        // Process each tunnel layer
486        for network_tunnel in packet.tunnels() {
487            // Try to convert NetworkTunnelLayer to VniLayer
488            match VniLayer::try_from(network_tunnel) {
489                Ok(vni_layer) => vni_stack.push(vni_layer),
490                Err(_) => {
491                    // Skip tunnels that don't have VNI semantics (like GTPv2 control plane)
492                    continue;
493                }
494            }
495        }
496
497        Ok(vni_stack)
498    }
499}
500
501/// VNI identifier (opaque handle)
502///
503/// This is an opaque identifier used to reference a specific VNI layer stack
504/// in the mapper. The actual value has no semantic meaning outside of the mapper.
505#[derive(
506    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Serialize, Deserialize,
507)]
508pub struct VniId(u32);
509
510impl VniId {
511    /// Get the raw u32 value (primarily for debugging/serialization)
512    #[inline]
513    pub const fn as_u32(&self) -> u32 {
514        self.0
515    }
516
517    /// Create a VniId from a u32 (primarily for deserialization)
518    #[inline]
519    pub const fn from_u32(value: u32) -> Self {
520        Self(value)
521    }
522}
523
524impl fmt::Display for VniId {
525    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
526        write!(f, "VniId({})", self.0)
527    }
528}
529
530/// Maps VNI layer stacks to unique identifiers
531///
532/// This structure maintains bidirectional mappings between VNI layer stacks
533/// and unique identifiers using `BTreeMap` instead of `HashMap`.
534///
535/// # Why BTreeMap instead of HashMap?
536///
537/// 1. **Avoids expensive hashing**: Computing the hash of `SmallVec<[VniLayer; 4]>`
538///    requires hashing each `VniLayer` variant, which contains nested enums, arrays
539///    of `IpAddr`, and optional fields. This is computationally expensive.
540///
541/// 2. **Better cache locality**: BTreeMap stores data in nodes that fit in cache lines,
542///    resulting in fewer cache misses than HashMap's scattered buckets.
543///
544/// 3. **Predictable performance**: O(log n) is consistent and predictable, while
545///    HashMap can have worst-case O(n) on hash collisions or resizing.
546///
547/// 4. **Ordered iteration**: BTreeMap naturally provides ordered iteration, useful
548///    for debugging and consistent output.
549///
550/// 5. **Practical performance**: For typical workloads with thousands of VNI stacks,
551///    O(log n) ≈ 10-20 comparisons is faster than computing expensive hashes.
552///
553/// # Performance Characteristics
554///
555/// - **Lookup**: O(log n) comparisons using `Ord` implementation
556/// - **Insert**: O(log n) with potential node splits
557/// - **Memory**: ~60 bytes overhead per node, better locality than HashMap
558/// - **No rehashing**: Unlike HashMap, never needs to rehash on growth
559///
560/// # Thread Safety
561///
562/// This structure is not thread-safe. If you need concurrent access, wrap it
563/// in an appropriate synchronization primitive (e.g., `Mutex`, `RwLock`, `Arc<DashMap>`).
564///
565/// # Example
566///
567/// ```ignore
568/// use packet_strata::tracker::vni::{VniLayer, VniMapper};
569///
570/// let mut mapper = VniMapper::new();
571///
572/// // Create some VNI layers
573/// let vlan = VniLayer::vlan(100);
574/// let vlan2 = VniLayer::vlan(200);
575///
576/// // Map a single-layer stack
577/// let id1 = mapper.get_or_create_vni_id(&[vlan.clone()]);
578///
579/// // Map a multi-layer stack (e.g., VLAN + IP tunnel)
580/// let id2 = mapper.get_or_create_vni_id(&[vlan, vlan2]);
581///
582/// // The same stack always gets the same ID
583/// let vlan_again = VniLayer::vlan(100);
584/// let id3 = mapper.get_or_create_vni_id(&[vlan_again]);
585/// assert_eq!(id1, id3);
586/// ```
587pub struct VniMapper {
588    /// Forward mapping: layer stack -> ID (using BTreeMap for efficient ordering)
589    forward: BTreeMap<SmallVec<[VniLayer; 4]>, VniId>,
590    /// Reverse mapping: ID -> layer stack (using BTreeMap for cache efficiency)
591    reverse: BTreeMap<VniId, SmallVec<[VniLayer; 4]>>,
592    /// Counter for generating new IDs
593    counter: u32,
594}
595
596impl VniMapper {
597    /// Create a new VNI mapper
598    pub fn new() -> Self {
599        Self {
600            forward: BTreeMap::new(),
601            reverse: BTreeMap::new(),
602            counter: 0,
603        }
604    }
605
606    /// Get or create a VNI ID for the given layer stack
607    ///
608    /// If the exact layer stack already exists, returns its existing ID.
609    /// Otherwise, creates a new ID and stores the mapping.
610    ///
611    /// # Arguments
612    ///
613    /// * `vni_stack` - Slice of VNI layers (ordered from outermost to innermost)
614    ///
615    /// # Returns
616    ///
617    /// A `VniId` that uniquely identifies this layer stack
618    pub fn get_or_create_vni_id(&mut self, vni_stack: &[VniLayer]) -> VniId {
619        let stack_vec: SmallVec<[VniLayer; 4]> = vni_stack.iter().cloned().collect();
620
621        if let Some(&id) = self.forward.get(&stack_vec) {
622            return id;
623        }
624
625        self.counter += 1;
626        let id = VniId(self.counter);
627
628        self.forward.insert(stack_vec.clone(), id);
629        self.reverse.insert(id, stack_vec);
630
631        id
632    }
633
634    /// Look up the VNI layer stack for a given ID
635    ///
636    /// # Arguments
637    ///
638    /// * `id` - The VNI ID to look up
639    ///
640    /// # Returns
641    ///
642    /// `Some(&[VniLayer])` if the ID exists, `None` otherwise
643    pub fn lookup_vni(&self, id: VniId) -> Option<&[VniLayer]> {
644        self.reverse.get(&id).map(|v| v.as_slice())
645    }
646
647    /// Get the number of unique VNI stacks
648    pub fn len(&self) -> usize {
649        self.reverse.len()
650    }
651
652    /// Check if the mapper is empty
653    pub fn is_empty(&self) -> bool {
654        self.reverse.is_empty()
655    }
656
657    /// Clear all mappings and reset the counter
658    pub fn clear(&mut self) {
659        self.forward.clear();
660        self.reverse.clear();
661        self.counter = 0;
662    }
663
664    /// Get an iterator over all VNI IDs and their layer stacks
665    pub fn iter(&self) -> impl Iterator<Item = (VniId, &[VniLayer])> {
666        self.reverse
667            .iter()
668            .map(|(&id, stack)| (id, stack.as_slice()))
669    }
670}
671
672impl Default for VniMapper {
673    fn default() -> Self {
674        Self::new()
675    }
676}
677
678#[cfg(test)]
679mod tests {
680    use super::*;
681    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
682
683    // ========================================================================
684    // VniError Tests
685    // ========================================================================
686
687    #[test]
688    fn test_vni_error_display() {
689        let err1 = VniError::InvalidHeaderLength;
690        assert_eq!(err1.to_string(), "Invalid IP header length");
691
692        let err2 = VniError::InvalidIpVersion;
693        assert_eq!(err2.to_string(), "Invalid IP version");
694    }
695
696    #[test]
697    fn test_vni_error_clone_eq() {
698        let err1 = VniError::InvalidHeaderLength;
699        let err2 = err1.clone();
700        assert_eq!(err1, err2);
701
702        let err3 = VniError::InvalidIpVersion;
703        assert_ne!(err1, err3);
704    }
705
706    // ========================================================================
707    // VniLayer Tests - Construction and Display
708    // ========================================================================
709
710    // ========================================================================
711    // VniLayer Equality and Ordering Tests
712    // ========================================================================
713
714    #[test]
715    fn test_vni_layer_equality() {
716        let vlan1 = VniLayer::Vlan { vid: 100 };
717        let vlan2 = VniLayer::Vlan { vid: 100 };
718        let vlan3 = VniLayer::Vlan { vid: 200 };
719
720        assert_eq!(vlan1, vlan2);
721        assert_ne!(vlan1, vlan3);
722
723        let mpls1 = VniLayer::Mpls { label: 100 };
724        assert_ne!(vlan1, mpls1); // Different variants
725    }
726
727    #[test]
728    fn test_vni_layer_ordering() {
729        let vlan1 = VniLayer::Vlan { vid: 100 };
730        let vlan2 = VniLayer::Vlan { vid: 200 };
731        let _mpls = VniLayer::Mpls { label: 100 };
732
733        assert!(vlan1 < vlan2);
734        // Ordering between different variants depends on enum declaration order
735    }
736
737    #[test]
738    fn test_vni_layer_clone_hash() {
739        let endpoints = [
740            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
741            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
742        ];
743
744        let vxlan1 = VniLayer::Vxlan {
745            vni: 100,
746            group_id: 0,
747            endpoints,
748        };
749        let vxlan2 = vxlan1.clone();
750
751        assert_eq!(vxlan1, vxlan2);
752
753        // Test that it can be used in hash-based collections
754        use std::collections::HashSet;
755        let mut set = HashSet::new();
756        set.insert(vxlan1.clone());
757        assert!(set.contains(&vxlan2));
758    }
759
760    // ========================================================================
761    // VniId Tests
762    // ========================================================================
763
764    #[test]
765    fn test_vni_id_creation() {
766        let id = VniId::from_u32(42);
767        assert_eq!(id.as_u32(), 42);
768    }
769
770    #[test]
771    fn test_vni_id_display() {
772        let id = VniId::from_u32(100);
773        assert_eq!(format!("{}", id), "VniId(100)");
774    }
775
776    #[test]
777    fn test_vni_id_equality() {
778        let id1 = VniId::from_u32(42);
779        let id2 = VniId::from_u32(42);
780        let id3 = VniId::from_u32(43);
781
782        assert_eq!(id1, id2);
783        assert_ne!(id1, id3);
784    }
785
786    // ========================================================================
787    // VniMapper Tests
788    // ========================================================================
789
790    #[test]
791    fn test_vni_mapper_new() {
792        let mapper = VniMapper::new();
793        assert_eq!(mapper.len(), 0);
794        assert!(mapper.is_empty());
795    }
796
797    #[test]
798    fn test_vni_mapper_default() {
799        let mapper = VniMapper::default();
800        assert_eq!(mapper.len(), 0);
801        assert!(mapper.is_empty());
802    }
803
804    #[test]
805    fn test_vni_mapper_single_layer() {
806        let mut mapper = VniMapper::new();
807        let vlan = VniLayer::Vlan { vid: 100 };
808
809        let id = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan));
810        assert_eq!(mapper.len(), 1);
811        assert!(!mapper.is_empty());
812
813        // Same stack should return same ID
814        let id2 = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan));
815        assert_eq!(id, id2);
816        assert_eq!(mapper.len(), 1); // No new entry created
817
818        // Lookup should work
819        let stack = mapper.lookup_vni(id).unwrap();
820        assert_eq!(stack.len(), 1);
821        assert_eq!(stack[0], vlan);
822    }
823
824    #[test]
825    fn test_vni_mapper_multi_layer() {
826        let mut mapper = VniMapper::new();
827        let vlan1 = VniLayer::Vlan { vid: 100 };
828        let vlan2 = VniLayer::Vlan { vid: 200 };
829
830        let id = mapper.get_or_create_vni_id(&[vlan1.clone(), vlan2.clone()]);
831        assert_eq!(mapper.len(), 1);
832
833        let stack = mapper.lookup_vni(id).unwrap();
834        assert_eq!(stack.len(), 2);
835        assert_eq!(stack[0], vlan1);
836        assert_eq!(stack[1], vlan2);
837    }
838
839    #[test]
840    fn test_vni_mapper_different_stacks() {
841        let mut mapper = VniMapper::new();
842        let vlan100 = VniLayer::Vlan { vid: 100 };
843        let vlan200 = VniLayer::Vlan { vid: 200 };
844        let mpls = VniLayer::Mpls { label: 1000 };
845
846        let id1 = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan100));
847        let id2 = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan200));
848        let id3 = mapper.get_or_create_vni_id(&[vlan100.clone(), mpls.clone()]);
849
850        assert_ne!(id1, id2);
851        assert_ne!(id1, id3);
852        assert_ne!(id2, id3);
853        assert_eq!(mapper.len(), 3);
854    }
855
856    #[test]
857    fn test_vni_mapper_order_matters() {
858        let mut mapper = VniMapper::new();
859        let vlan = VniLayer::Vlan { vid: 100 };
860        let mpls = VniLayer::Mpls { label: 1000 };
861
862        let id1 = mapper.get_or_create_vni_id(&[vlan.clone(), mpls.clone()]);
863        let id2 = mapper.get_or_create_vni_id(&[mpls.clone(), vlan.clone()]);
864
865        // Order matters - these should be different
866        assert_ne!(id1, id2);
867        assert_eq!(mapper.len(), 2);
868    }
869
870    #[test]
871    fn test_vni_mapper_lookup_nonexistent() {
872        let mapper = VniMapper::new();
873        let id = VniId::from_u32(999);
874
875        assert!(mapper.lookup_vni(id).is_none());
876    }
877
878    #[test]
879    fn test_vni_mapper_clear() {
880        let mut mapper = VniMapper::new();
881        let vlan = VniLayer::Vlan { vid: 100 };
882
883        let id1 = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan));
884        assert_eq!(mapper.len(), 1);
885
886        mapper.clear();
887        assert_eq!(mapper.len(), 0);
888        assert!(mapper.is_empty());
889
890        // After clear, lookup should fail
891        assert!(mapper.lookup_vni(id1).is_none());
892
893        // New ID should start from 1 again
894        let id2 = mapper.get_or_create_vni_id(&[vlan]);
895        assert_eq!(id2.as_u32(), 1);
896    }
897
898    #[test]
899    fn test_vni_mapper_iter() {
900        let mut mapper = VniMapper::new();
901        let vlan1 = VniLayer::Vlan { vid: 100 };
902        let vlan2 = VniLayer::Vlan { vid: 200 };
903        let mpls = VniLayer::Mpls { label: 1000 };
904
905        mapper.get_or_create_vni_id(std::slice::from_ref(&vlan1));
906        mapper.get_or_create_vni_id(std::slice::from_ref(&vlan2));
907        mapper.get_or_create_vni_id(std::slice::from_ref(&mpls));
908
909        let entries: Vec<_> = mapper.iter().collect();
910        assert_eq!(entries.len(), 3);
911
912        // Check that all stacks are present
913        let stacks: Vec<_> = entries.iter().map(|(_, stack)| stack).collect();
914        assert!(stacks.iter().any(|s| s.len() == 1 && s[0] == vlan1));
915        assert!(stacks.iter().any(|s| s.len() == 1 && s[0] == vlan2));
916        assert!(stacks.iter().any(|s| s.len() == 1 && s[0] == mpls));
917    }
918
919    #[test]
920    fn test_vni_mapper_counter_increment() {
921        let mut mapper = VniMapper::new();
922        let vlan1 = VniLayer::Vlan { vid: 100 };
923        let vlan2 = VniLayer::Vlan { vid: 200 };
924        let vlan3 = VniLayer::Vlan { vid: 300 };
925
926        let id1 = mapper.get_or_create_vni_id(&[vlan1]);
927        let id2 = mapper.get_or_create_vni_id(&[vlan2]);
928        let id3 = mapper.get_or_create_vni_id(&[vlan3]);
929
930        assert_eq!(id1.as_u32(), 1);
931        assert_eq!(id2.as_u32(), 2);
932        assert_eq!(id3.as_u32(), 3);
933    }
934
935    // ========================================================================
936    // Complex Scenario Tests
937    // ========================================================================
938
939    #[test]
940    fn test_complex_tunnel_stack() {
941        let mut mapper = VniMapper::new();
942        let endpoints = [
943            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
944            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
945        ];
946
947        // Complex stack: VLAN + VXLAN + VLAN (nested virtualization)
948        let outer_vlan = VniLayer::Vlan { vid: 100 };
949        let vxlan = VniLayer::Vxlan {
950            vni: 5000,
951            group_id: 0,
952            endpoints,
953        };
954        let inner_vlan = VniLayer::Vlan { vid: 200 };
955
956        let id =
957            mapper.get_or_create_vni_id(&[outer_vlan.clone(), vxlan.clone(), inner_vlan.clone()]);
958
959        let stack = mapper.lookup_vni(id).unwrap();
960        assert_eq!(stack.len(), 3);
961        assert_eq!(stack[0], outer_vlan);
962        assert_eq!(stack[1], vxlan);
963        assert_eq!(stack[2], inner_vlan);
964    }
965
966    #[test]
967    fn test_multiple_tunnel_types() {
968        let mut mapper = VniMapper::new();
969        let endpoints_v4 = [
970            IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)),
971            IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)),
972        ];
973        let endpoints_v6 = [
974            IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)),
975            IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2)),
976        ];
977
978        let vxlan = VniLayer::Vxlan {
979            vni: 100,
980            group_id: 0,
981            endpoints: endpoints_v4,
982        };
983        let geneve = VniLayer::Geneve {
984            vni: 200,
985            protocol_type: 0x6558,
986            endpoints: endpoints_v6,
987        };
988        let gre = VniLayer::Gre {
989            protocol_type: 0x0800,
990            key: Some(300),
991            endpoints: endpoints_v4,
992        };
993
994        let id1 = mapper.get_or_create_vni_id(&[vxlan]);
995        let id2 = mapper.get_or_create_vni_id(&[geneve]);
996        let id3 = mapper.get_or_create_vni_id(&[gre]);
997
998        assert_eq!(mapper.len(), 3);
999        assert_ne!(id1, id2);
1000        assert_ne!(id2, id3);
1001        assert_ne!(id1, id3);
1002    }
1003
1004    #[test]
1005    fn test_empty_stack() {
1006        let mut mapper = VniMapper::new();
1007        let id = mapper.get_or_create_vni_id(&[]);
1008
1009        assert_eq!(mapper.len(), 1);
1010        let stack = mapper.lookup_vni(id).unwrap();
1011        assert_eq!(stack.len(), 0);
1012    }
1013
1014    #[test]
1015    fn test_vni_mapper_reuse_after_partial_clear() {
1016        let mut mapper = VniMapper::new();
1017        let vlan = VniLayer::Vlan { vid: 100 };
1018
1019        let id1 = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan));
1020        assert_eq!(id1.as_u32(), 1);
1021
1022        mapper.clear();
1023
1024        let id2 = mapper.get_or_create_vni_id(&[vlan]);
1025        assert_eq!(id2.as_u32(), 1); // Counter resets
1026    }
1027
1028    // ========================================================================
1029    // Edge Cases and Boundary Tests
1030    // ========================================================================
1031
1032    #[test]
1033    fn test_max_vlan_id() {
1034        let vlan = VniLayer::Vlan { vid: 4095 }; // Max 12-bit value
1035        assert_eq!(format!("{}", vlan), "vlan(4095)");
1036    }
1037
1038    #[test]
1039    fn test_max_mpls_label() {
1040        let mpls = VniLayer::Mpls { label: 0xFFFFF }; // Max 20-bit value
1041        assert_eq!(format!("{}", mpls), "mpls(1048575)");
1042    }
1043
1044    #[test]
1045    fn test_vxlan_24bit_vni() {
1046        let endpoints = [
1047            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1048            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1049        ];
1050
1051        let vxlan = VniLayer::Vxlan {
1052            vni: 0xFFFFFF, // Max 24-bit value
1053            group_id: 0,
1054            endpoints,
1055        };
1056        assert!(format!("{}", vxlan).contains("vni:16777215"));
1057    }
1058
1059    #[test]
1060    fn test_mixed_ipv4_ipv6_endpoints() {
1061        // While unusual, the type system allows mixed IP versions in comparisons
1062        let endpoints1 = [
1063            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1064            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1065        ];
1066        let endpoints2 = [
1067            IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)),
1068            IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2)),
1069        ];
1070
1071        let ipip_v4 = VniLayer::Ipip {
1072            endpoints: endpoints1,
1073        };
1074        let ipip_v6 = VniLayer::Ip6Tnl {
1075            endpoints: endpoints2,
1076        };
1077
1078        assert_ne!(ipip_v4, ipip_v6);
1079    }
1080
1081    #[test]
1082    fn test_vni_layer_size() {
1083        // Ensure VniLayer variants don't grow unexpectedly
1084        use std::mem::size_of;
1085
1086        // This is a regression test - if size increases significantly, investigate
1087        let size = size_of::<VniLayer>();
1088
1089        // VniLayer should be reasonably sized (less than 64 bytes on 64-bit systems)
1090        // The largest variant is likely Stt or one with [IpAddr; 2] which is 2*32=64 bytes for IPv6
1091        assert!(
1092            size <= 128,
1093            "VniLayer size is {}, expected <= 128 bytes",
1094            size
1095        );
1096    }
1097
1098    #[test]
1099    fn test_smallvec_inline_capacity() {
1100        // Verify that SmallVec doesn't allocate for common cases
1101        let vlan1 = VniLayer::Vlan { vid: 100 };
1102        let vlan2 = VniLayer::Vlan { vid: 200 };
1103
1104        let mut sv = SmallVec::<[VniLayer; 4]>::new();
1105        sv.push(vlan1);
1106        sv.push(vlan2);
1107
1108        // With capacity 4, this should not spill to heap
1109        assert!(!sv.spilled());
1110    }
1111
1112    #[test]
1113    fn test_btreemap_ordering() {
1114        let mut mapper = VniMapper::new();
1115
1116        // Insert in non-sequential order
1117        let vlan200 = VniLayer::Vlan { vid: 200 };
1118        let vlan100 = VniLayer::Vlan { vid: 100 };
1119        let vlan300 = VniLayer::Vlan { vid: 300 };
1120
1121        mapper.get_or_create_vni_id(&[vlan200]);
1122        mapper.get_or_create_vni_id(&[vlan100]);
1123        mapper.get_or_create_vni_id(&[vlan300]);
1124
1125        // BTreeMap should maintain some order
1126        let entries: Vec<_> = mapper.iter().collect();
1127        assert_eq!(entries.len(), 3);
1128    }
1129
1130    // ========================================================================
1131    // From<LinkLayer> Conversion Tests
1132    // ========================================================================
1133    // Note: Testing From<LinkLayer> requires constructing actual packet bytes
1134    // which is complex. The implementation is straightforward pattern matching,
1135    // so we rely on integration tests for full coverage.
1136
1137    // ========================================================================
1138    // From<IpTunnel> Conversion Tests
1139    // ========================================================================
1140    // Note: Testing From<IpTunnel> requires constructing actual tunnel packets
1141    // which is complex. The implementation is tested through integration tests.
1142
1143    #[test]
1144    fn test_vni_layer_debug_format() {
1145        // Verify Debug trait works for all variants
1146        let vlan = VniLayer::Vlan { vid: 100 };
1147        let debug_str = format!("{:?}", vlan);
1148        assert!(debug_str.contains("Vlan"));
1149        assert!(debug_str.contains("100"));
1150    }
1151
1152    #[test]
1153    fn test_multiple_identical_stacks() {
1154        let mut mapper = VniMapper::new();
1155        let endpoints = [
1156            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1157            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1158        ];
1159
1160        let vxlan1 = VniLayer::Vxlan {
1161            vni: 100,
1162            group_id: 0,
1163            endpoints,
1164        };
1165        let vxlan2 = VniLayer::Vxlan {
1166            vni: 100,
1167            group_id: 0,
1168            endpoints,
1169        };
1170
1171        let id1 = mapper.get_or_create_vni_id(&[vxlan1]);
1172        let id2 = mapper.get_or_create_vni_id(&[vxlan2]);
1173
1174        // Should get same ID for identical stacks
1175        assert_eq!(id1, id2);
1176        assert_eq!(mapper.len(), 1);
1177    }
1178
1179    #[test]
1180    fn test_endpoint_ordering_consistency() {
1181        let endpoints1 = [
1182            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1183            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1184        ];
1185        let endpoints2 = [
1186            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1187            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1188        ];
1189
1190        let ipip1 = VniLayer::Ipip {
1191            endpoints: endpoints1,
1192        };
1193        let ipip2 = VniLayer::Ipip {
1194            endpoints: endpoints2,
1195        };
1196
1197        // Different endpoint order should be different
1198        assert_ne!(ipip1, ipip2);
1199    }
1200
1201    #[test]
1202    fn test_gre_with_and_without_key() {
1203        let mut mapper = VniMapper::new();
1204        let endpoints = [
1205            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1206            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1207        ];
1208
1209        let gre_no_key = VniLayer::Gre {
1210            protocol_type: 0x0800,
1211            key: None,
1212            endpoints,
1213        };
1214        let gre_with_key = VniLayer::Gre {
1215            protocol_type: 0x0800,
1216            key: Some(100),
1217            endpoints,
1218        };
1219
1220        let id1 = mapper.get_or_create_vni_id(&[gre_no_key]);
1221        let id2 = mapper.get_or_create_vni_id(&[gre_with_key]);
1222
1223        assert_ne!(id1, id2);
1224        assert_eq!(mapper.len(), 2);
1225    }
1226
1227    #[test]
1228    fn test_vni_mapper_with_all_layer_types() {
1229        let mut mapper = VniMapper::new();
1230        let endpoints_v4 = [
1231            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1232            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1233        ];
1234        let endpoints_v6 = [
1235            IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1)),
1236            IpAddr::V6(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 2)),
1237        ];
1238
1239        // Create one of each layer type
1240        let layers = vec![
1241            VniLayer::Vlan { vid: 100 },
1242            VniLayer::Mpls { label: 1000 },
1243            VniLayer::Gre {
1244                protocol_type: 0x0800,
1245                key: None,
1246                endpoints: endpoints_v4,
1247            },
1248            VniLayer::NvGre {
1249                protocol_type: 0x6558,
1250                vsid_flowid: 100,
1251                endpoints: endpoints_v4,
1252            },
1253            VniLayer::Vxlan {
1254                vni: 5000,
1255                group_id: 0,
1256                endpoints: endpoints_v4,
1257            },
1258            VniLayer::Geneve {
1259                vni: 1000,
1260                protocol_type: 0x6558,
1261                endpoints: endpoints_v6,
1262            },
1263            VniLayer::Ipip {
1264                endpoints: endpoints_v4,
1265            },
1266            VniLayer::Ip4in6 {
1267                endpoints: endpoints_v6,
1268            },
1269            VniLayer::Sit {
1270                endpoints: endpoints_v4,
1271            },
1272            VniLayer::Ip6Tnl {
1273                endpoints: endpoints_v6,
1274            },
1275            VniLayer::GtpU {
1276                teid: 0x12345678,
1277                endpoints: endpoints_v4,
1278            },
1279            VniLayer::Teredo {
1280                endpoints: endpoints_v4,
1281            },
1282            VniLayer::L2tpV2 {
1283                tunnel_id: 100,
1284                session_id: 200,
1285                endpoints: endpoints_v4,
1286            },
1287            VniLayer::L2tpV3 {
1288                session_id: 0xabcdef,
1289                endpoints: endpoints_v6,
1290            },
1291            VniLayer::Pbb {
1292                isid: 0x123456,
1293                bvid: Some(100),
1294            },
1295            VniLayer::Stt {
1296                context_id: 0x123456789abcdef0,
1297                endpoints: endpoints_v4,
1298            },
1299            VniLayer::Pptp {
1300                call_id: 1234,
1301                endpoints: endpoints_v4,
1302            },
1303        ];
1304
1305        // Each should get a unique ID
1306        let mut ids = Vec::new();
1307        for layer in &layers {
1308            let id = mapper.get_or_create_vni_id(std::slice::from_ref(layer));
1309            ids.push(id);
1310        }
1311
1312        assert_eq!(mapper.len(), layers.len());
1313
1314        // All IDs should be unique
1315        for i in 0..ids.len() {
1316            for j in (i + 1)..ids.len() {
1317                assert_ne!(
1318                    ids[i], ids[j],
1319                    "IDs at positions {} and {} should be different",
1320                    i, j
1321                );
1322            }
1323        }
1324    }
1325
1326    #[test]
1327    fn test_vni_id_ordering() {
1328        let id1 = VniId::from_u32(1);
1329        let id2 = VniId::from_u32(2);
1330        let id3 = VniId::from_u32(2);
1331
1332        assert!(id1 < id2);
1333        assert_eq!(id2, id3);
1334        assert!(id1 != id2);
1335    }
1336
1337    #[test]
1338    fn test_smallvec_spill_behavior() {
1339        // Test that we can handle more than inline capacity
1340        let vlan1 = VniLayer::Vlan { vid: 100 };
1341        let vlan2 = VniLayer::Vlan { vid: 200 };
1342        let vlan3 = VniLayer::Vlan { vid: 300 };
1343        let vlan4 = VniLayer::Vlan { vid: 400 };
1344        let vlan5 = VniLayer::Vlan { vid: 500 };
1345
1346        let mut sv = SmallVec::<[VniLayer; 4]>::new();
1347        sv.push(vlan1);
1348        sv.push(vlan2);
1349        sv.push(vlan3);
1350        sv.push(vlan4);
1351
1352        assert!(!sv.spilled()); // Should still be inline with capacity 4
1353
1354        sv.push(vlan5);
1355        assert!(sv.spilled()); // Should spill to heap now
1356        assert_eq!(sv.len(), 5);
1357    }
1358
1359    #[test]
1360    fn test_vni_mapper_consistency_after_many_insertions() {
1361        let mut mapper = VniMapper::new();
1362
1363        // Insert many unique stacks
1364        for i in 0..100 {
1365            let vlan = VniLayer::Vlan { vid: i };
1366            mapper.get_or_create_vni_id(&[vlan]);
1367        }
1368
1369        assert_eq!(mapper.len(), 100);
1370
1371        // Verify all can be looked up
1372        for i in 1..=100 {
1373            let id = VniId::from_u32(i);
1374            assert!(mapper.lookup_vni(id).is_some());
1375        }
1376    }
1377
1378    #[test]
1379    fn test_vni_error_is_error_trait() {
1380        use std::error::Error;
1381
1382        let err = VniError::InvalidHeaderLength;
1383        let _: &dyn Error = &err; // Should compile
1384
1385        // Test error source (should be None for these simple errors)
1386        assert!(err.source().is_none());
1387    }
1388
1389    // ========================================================================
1390    // Regression Tests - Complex Scenarios
1391    // ========================================================================
1392
1393    #[test]
1394    fn test_regression_vni_mapper_id_stability() {
1395        // Regression: VNI IDs should be stable across multiple gets
1396        let mut mapper = VniMapper::new();
1397        let endpoints = [
1398            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1399            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1400        ];
1401
1402        let vxlan = VniLayer::Vxlan {
1403            vni: 5000,
1404            group_id: 0,
1405            endpoints,
1406        };
1407
1408        let id1 = mapper.get_or_create_vni_id(std::slice::from_ref(&vxlan));
1409        let id2 = mapper.get_or_create_vni_id(std::slice::from_ref(&vxlan));
1410        let id3 = mapper.get_or_create_vni_id(std::slice::from_ref(&vxlan));
1411
1412        assert_eq!(id1, id2);
1413        assert_eq!(id2, id3);
1414        assert_eq!(mapper.len(), 1);
1415    }
1416
1417    #[test]
1418    fn test_regression_vni_layer_protocol_type_variations() {
1419        // Regression: Different protocol types should create different VNI layers
1420        let endpoints = [
1421            IpAddr::V4(Ipv4Addr::new(192, 168, 1, 1)),
1422            IpAddr::V4(Ipv4Addr::new(192, 168, 1, 2)),
1423        ];
1424
1425        let gre_ipv4 = VniLayer::Gre {
1426            protocol_type: 0x0800, // IPv4
1427            key: None,
1428            endpoints,
1429        };
1430
1431        let gre_ipv6 = VniLayer::Gre {
1432            protocol_type: 0x86DD, // IPv6
1433            key: None,
1434            endpoints,
1435        };
1436
1437        assert_ne!(gre_ipv4, gre_ipv6);
1438    }
1439
1440    #[test]
1441    fn test_regression_vxlan_group_id_zero_vs_nonzero() {
1442        // Regression: group_id=0 and group_id!=0 should be different
1443        let endpoints = [
1444            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1445            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1446        ];
1447
1448        let vxlan1 = VniLayer::Vxlan {
1449            vni: 100,
1450            group_id: 0,
1451            endpoints,
1452        };
1453
1454        let vxlan2 = VniLayer::Vxlan {
1455            vni: 100,
1456            group_id: 1,
1457            endpoints,
1458        };
1459
1460        assert_ne!(vxlan1, vxlan2);
1461    }
1462
1463    #[test]
1464    fn test_regression_nvgre_vsid_flowid_encoding() {
1465        // Regression: VSID and FlowID should be properly encoded in 32-bit field
1466        let endpoints = [
1467            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1468            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1469        ];
1470
1471        // VSID is 24 bits, FlowID is 8 bits
1472        let vsid: u32 = 0x123456;
1473        let flow_id: u8 = 0xAB;
1474        let combined = (vsid << 8) | flow_id as u32;
1475
1476        let _nvgre = VniLayer::NvGre {
1477            protocol_type: 0x6558,
1478            vsid_flowid: combined,
1479            endpoints,
1480        };
1481    }
1482
1483    #[test]
1484    fn test_regression_pbb_with_optional_bvid() {
1485        // Regression: PBB with and without bvid should be different
1486        let pbb1 = VniLayer::Pbb {
1487            isid: 0x123456,
1488            bvid: None,
1489        };
1490
1491        let pbb2 = VniLayer::Pbb {
1492            isid: 0x123456,
1493            bvid: Some(0),
1494        };
1495
1496        let pbb3 = VniLayer::Pbb {
1497            isid: 0x123456,
1498            bvid: Some(100),
1499        };
1500
1501        assert_ne!(pbb1, pbb2);
1502        assert_ne!(pbb2, pbb3);
1503    }
1504
1505    #[test]
1506    fn test_regression_l2tp_versions_distinct() {
1507        // Regression: L2TPv2 and L2TPv3 should be distinct even with similar IDs
1508        let endpoints = [
1509            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1510            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1511        ];
1512
1513        let l2tpv2 = VniLayer::L2tpV2 {
1514            tunnel_id: 100,
1515            session_id: 200,
1516            endpoints,
1517        };
1518
1519        let l2tpv3 = VniLayer::L2tpV3 {
1520            session_id: 200,
1521            endpoints,
1522        };
1523
1524        // Different variants, should not be equal
1525        assert_ne!(format!("{:?}", l2tpv2), format!("{:?}", l2tpv3));
1526    }
1527
1528    #[test]
1529    fn test_regression_endpoint_ipv4_vs_ipv6() {
1530        // Regression: IPv4 and IPv6 endpoints should create different layers
1531        let endpoints_v4 = [
1532            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1533            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1534        ];
1535
1536        let endpoints_v6 = [
1537            IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x0a00, 0x0001)),
1538            IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x0a00, 0x0002)),
1539        ];
1540
1541        let ipip_v4 = VniLayer::Ipip {
1542            endpoints: endpoints_v4,
1543        };
1544        let ipip_v6_as_ip6tnl = VniLayer::Ip6Tnl {
1545            endpoints: endpoints_v6,
1546        };
1547
1548        // Different types and IP versions
1549        assert_ne!(format!("{:?}", ipip_v4), format!("{:?}", ipip_v6_as_ip6tnl));
1550    }
1551
1552    #[test]
1553    fn test_regression_vni_mapper_large_scale() {
1554        // Regression: Mapper should handle many unique stacks efficiently
1555        let mut mapper = VniMapper::new();
1556        let mut all_ids = Vec::new();
1557
1558        // Create 1000 unique VNI stacks
1559        for i in 0..1000 {
1560            let vlan = VniLayer::Vlan { vid: i };
1561            let id = mapper.get_or_create_vni_id(&[vlan]);
1562            all_ids.push(id);
1563        }
1564
1565        assert_eq!(mapper.len(), 1000);
1566
1567        // All IDs should be unique
1568        for i in 0..all_ids.len() {
1569            for j in (i + 1)..all_ids.len() {
1570                assert_ne!(all_ids[i], all_ids[j]);
1571            }
1572        }
1573
1574        // All should be retrievable
1575        for (idx, id) in all_ids.iter().enumerate() {
1576            let stack = mapper.lookup_vni(*id).unwrap();
1577            assert_eq!(stack.len(), 1);
1578            match &stack[0] {
1579                VniLayer::Vlan { vid } => {
1580                    assert_eq!(*vid, idx as u16);
1581                }
1582                _ => panic!("Expected Vlan variant"),
1583            }
1584        }
1585    }
1586
1587    #[test]
1588    fn test_regression_deep_vni_stack() {
1589        // Regression: Test deeply nested VNI stacks (beyond SmallVec inline capacity)
1590        let mut mapper = VniMapper::new();
1591        let endpoints = [
1592            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1593            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1594        ];
1595
1596        let layers = vec![
1597            VniLayer::Vlan { vid: 100 },
1598            VniLayer::Mpls { label: 1000 },
1599            VniLayer::Vlan { vid: 200 },
1600            VniLayer::Vxlan {
1601                vni: 5000,
1602                group_id: 0,
1603                endpoints,
1604            },
1605            VniLayer::Vlan { vid: 300 },
1606            VniLayer::Mpls { label: 2000 },
1607        ];
1608
1609        let id = mapper.get_or_create_vni_id(&layers);
1610        let retrieved = mapper.lookup_vni(id).unwrap();
1611
1612        assert_eq!(retrieved.len(), layers.len());
1613        for (i, layer) in layers.iter().enumerate() {
1614            assert_eq!(&retrieved[i], layer);
1615        }
1616    }
1617
1618    // ========================================================================
1619    // TryFrom<&Packet> Conversion Tests
1620    // ========================================================================
1621
1622    #[test]
1623    fn test_packet_to_vni_empty() {
1624        use crate::packet::iter::LinkType;
1625        use crate::packet::{Packet, ParseMode};
1626
1627        // Simple Ethernet + IPv4 packet (no VLAN, no tunnel)
1628        let packet_bytes = vec![
1629            // Ethernet header
1630            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // dst MAC
1631            0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, // src MAC
1632            0x08, 0x00, // EtherType: IPv4
1633            // IPv4 header (minimal, 20 bytes)
1634            0x45, 0x00, 0x00, 0x1c, // version, IHL, DSCP, total length (28)
1635            0x00, 0x00, 0x00, 0x00, // ID, flags
1636            0x40, 0x01, 0x00, 0x00, // TTL, protocol (ICMP), checksum
1637            0x0a, 0x00, 0x00, 0x01, // src IP
1638            0x0a, 0x00, 0x00, 0x02, // dst IP
1639            // ICMP Echo Request
1640            0x08, 0x00, 0x00, 0x00, // type, code, checksum
1641            0x00, 0x01, 0x00, 0x01, // ID, sequence
1642        ];
1643
1644        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Outermost)
1645            .expect("Should parse packet");
1646
1647        let vni_stack: SmallVec<[VniLayer; 4]> =
1648            (&packet).try_into().expect("Should convert to VNI stack");
1649
1650        // No VLAN, no tunnel = empty VNI stack
1651        assert_eq!(vni_stack.len(), 0);
1652    }
1653
1654    #[test]
1655    fn test_packet_to_vni_vlan_only() {
1656        use crate::packet::iter::LinkType;
1657        use crate::packet::{Packet, ParseMode};
1658
1659        // Ethernet + 802.1Q VLAN + IPv4
1660        let packet_bytes = vec![
1661            // Ethernet header
1662            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // dst MAC
1663            0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, // src MAC
1664            0x81, 0x00, // EtherType: 802.1Q
1665            // VLAN tag
1666            0x00, 0x64, // PCP=0, DEI=0, VID=100
1667            0x08, 0x00, // EtherType: IPv4
1668            // IPv4 header
1669            0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x0a, 0x00,
1670            0x00, 0x01, 0x0a, 0x00, 0x00, 0x02, // ICMP
1671            0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
1672        ];
1673
1674        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Outermost)
1675            .expect("Should parse packet");
1676
1677        let vni_stack: SmallVec<[VniLayer; 4]> =
1678            (&packet).try_into().expect("Should convert to VNI stack");
1679
1680        // Should have 1 VLAN layer
1681        assert_eq!(vni_stack.len(), 1);
1682        assert!(matches!(vni_stack[0], VniLayer::Vlan { vid: 100 }));
1683    }
1684
1685    #[test]
1686    fn test_packet_to_vni_vxlan_tunnel() {
1687        use crate::packet::iter::LinkType;
1688        use crate::packet::{Packet, ParseMode};
1689
1690        // Create a VXLAN packet: Ethernet + IPv4 + UDP + VXLAN + inner Ethernet
1691        let mut packet_bytes = Vec::new();
1692
1693        // Outer Ethernet
1694        packet_bytes.extend_from_slice(&[
1695            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, // dst MAC
1696            0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, // src MAC
1697            0x08, 0x00, // EtherType: IPv4
1698        ]);
1699
1700        // Outer IPv4
1701        packet_bytes.extend_from_slice(&[
1702            0x45, 0x00, 0x00, 0x3c, // version, IHL, total length (60 bytes)
1703            0x00, 0x00, 0x00, 0x00, // ID, flags
1704            0x40, 0x11, 0x00, 0x00, // TTL=64, protocol=UDP, checksum
1705            10, 0, 0, 1, // src IP: 10.0.0.1
1706            10, 0, 0, 2, // dst IP: 10.0.0.2
1707        ]);
1708
1709        // UDP header
1710        packet_bytes.extend_from_slice(&[
1711            0x30, 0x39, // src port: 12345
1712            0x12, 0xb5, // dst port: 4789 (VXLAN)
1713            0x00, 0x28, // length: 40 bytes
1714            0x00, 0x00, // checksum
1715        ]);
1716
1717        // VXLAN header
1718        packet_bytes.extend_from_slice(&[
1719            0x08, 0x00, 0x00, 0x00, // flags (I=1)
1720            0x00, 0x01, 0xf4, 0x00, // VNI=500 (0x1f4)
1721        ]);
1722
1723        // Inner Ethernet
1724        packet_bytes.extend_from_slice(&[
1725            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x08,
1726            0x00, // EtherType: IPv4
1727        ]);
1728
1729        // Inner IPv4 (with ICMP)
1730        packet_bytes.extend_from_slice(&[
1731            0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 192, 168, 1, 1,
1732            192, 168, 1, 2, // ICMP
1733            0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
1734        ]);
1735
1736        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Innermost)
1737            .expect("Should parse VXLAN packet");
1738
1739        let vni_stack: SmallVec<[VniLayer; 4]> =
1740            (&packet).try_into().expect("Should convert to VNI stack");
1741
1742        // Should have 1 VXLAN tunnel layer
1743        assert_eq!(vni_stack.len(), 1);
1744        match &vni_stack[0] {
1745            VniLayer::Vxlan { vni, endpoints, .. } => {
1746                assert_eq!(*vni, 500);
1747                // Check endpoints are the outer IPs
1748                assert!(endpoints.contains(&IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))));
1749                assert!(endpoints.contains(&IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2))));
1750            }
1751            _ => panic!("Expected VXLAN layer"),
1752        }
1753    }
1754
1755    #[test]
1756    fn test_packet_to_vni_vlan_plus_vxlan() {
1757        use crate::packet::iter::LinkType;
1758        use crate::packet::{Packet, ParseMode};
1759
1760        // VLAN + VXLAN tunnel
1761        let mut packet_bytes = Vec::new();
1762
1763        // Outer Ethernet with VLAN
1764        packet_bytes.extend_from_slice(&[
1765            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x81,
1766            0x00, // EtherType: 802.1Q
1767            0x00, 0xc8, // VID=200
1768            0x08, 0x00, // EtherType: IPv4
1769        ]);
1770
1771        // Outer IPv4
1772        packet_bytes.extend_from_slice(&[
1773            0x45, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x11, 0x00, 0x00, 172, 16, 0, 1,
1774            172, 16, 0, 2,
1775        ]);
1776
1777        // UDP
1778        packet_bytes.extend_from_slice(&[0x30, 0x39, 0x12, 0xb5, 0x00, 0x28, 0x00, 0x00]);
1779
1780        // VXLAN
1781        packet_bytes.extend_from_slice(&[
1782            0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, // VNI=10
1783        ]);
1784
1785        // Inner Ethernet
1786        packet_bytes.extend_from_slice(&[
1787            0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x08, 0x00,
1788        ]);
1789
1790        // Inner IPv4
1791        packet_bytes.extend_from_slice(&[
1792            0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 192, 168, 1, 1,
1793            192, 168, 1, 2, // ICMP
1794            0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
1795        ]);
1796
1797        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Innermost)
1798            .expect("Should parse packet");
1799
1800        let vni_stack: SmallVec<[VniLayer; 4]> =
1801            (&packet).try_into().expect("Should convert to VNI stack");
1802
1803        // In Innermost mode, the parser overrides the link layer with the inner Ethernet,
1804        // so we only get the VXLAN tunnel (the outer VLAN is lost)
1805        assert_eq!(
1806            vni_stack.len(),
1807            1,
1808            "Expected 1 layer (VXLAN only), got {}",
1809            vni_stack.len()
1810        );
1811
1812        // Should be VXLAN
1813        match &vni_stack[0] {
1814            VniLayer::Vxlan { vni, endpoints, .. } => {
1815                assert_eq!(*vni, 10);
1816                // Verify endpoints
1817                assert!(endpoints.contains(&IpAddr::V4(Ipv4Addr::new(172, 16, 0, 1))));
1818                assert!(endpoints.contains(&IpAddr::V4(Ipv4Addr::new(172, 16, 0, 2))));
1819            }
1820            _ => panic!("Expected VXLAN layer"),
1821        }
1822    }
1823
1824    #[test]
1825    fn test_packet_to_vni_nested_vlan() {
1826        use crate::packet::iter::LinkType;
1827        use crate::packet::{Packet, ParseMode};
1828
1829        // Q-in-Q (nested VLAN)
1830        let packet_bytes = vec![
1831            // Ethernet
1832            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x81,
1833            0x00, // EtherType: 802.1Q
1834            0x00, 0x64, // Outer VLAN: VID=100
1835            0x81, 0x00, // EtherType: 802.1Q (nested)
1836            0x00, 0xc8, // Inner VLAN: VID=200
1837            0x08, 0x00, // EtherType: IPv4
1838            // IPv4
1839            0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x0a, 0x00,
1840            0x00, 0x01, 0x0a, 0x00, 0x00, 0x02, // ICMP
1841            0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
1842        ];
1843
1844        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Outermost)
1845            .expect("Should parse packet");
1846
1847        let vni_stack: SmallVec<[VniLayer; 4]> =
1848            (&packet).try_into().expect("Should convert to VNI stack");
1849
1850        // Should have 2 VLAN layers
1851        assert_eq!(vni_stack.len(), 2);
1852        assert!(matches!(vni_stack[0], VniLayer::Vlan { vid: 100 }));
1853        assert!(matches!(vni_stack[1], VniLayer::Vlan { vid: 200 }));
1854    }
1855
1856    #[test]
1857    fn test_packet_to_vni_with_vni_mapper() {
1858        use crate::packet::iter::LinkType;
1859        use crate::packet::{Packet, ParseMode};
1860
1861        // Test integration with VniMapper
1862        let packet_bytes = vec![
1863            // Ethernet with VLAN
1864            0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0x81, 0x00,
1865            0x01, 0x2c, // VID=300
1866            0x08, 0x00, // IPv4
1867            0x45, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x0a, 0x00,
1868            0x00, 0x01, 0x0a, 0x00, 0x00, 0x02, // ICMP
1869            0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
1870        ];
1871
1872        let packet = Packet::from_bytes(&packet_bytes, LinkType::Ethernet, ParseMode::Outermost)
1873            .expect("Should parse packet");
1874
1875        let vni_stack: SmallVec<[VniLayer; 4]> =
1876            (&packet).try_into().expect("Should convert to VNI stack");
1877
1878        // Use with VniMapper
1879        let mut mapper = VniMapper::new();
1880        let vni_id = mapper.get_or_create_vni_id(&vni_stack);
1881
1882        // Should be able to look it up
1883        let retrieved = mapper.lookup_vni(vni_id).unwrap();
1884        assert_eq!(retrieved.len(), 1);
1885        assert!(matches!(retrieved[0], VniLayer::Vlan { vid: 300 }));
1886    }
1887
1888    #[test]
1889    fn test_regression_vni_id_u32_boundary() {
1890        // Regression: Test VniId at various u32 boundaries
1891        let id_zero = VniId::from_u32(0);
1892        let id_max = VniId::from_u32(u32::MAX);
1893        let id_mid = VniId::from_u32(u32::MAX / 2);
1894
1895        assert_eq!(id_zero.as_u32(), 0);
1896        assert_eq!(id_max.as_u32(), u32::MAX);
1897        assert_eq!(id_mid.as_u32(), u32::MAX / 2);
1898
1899        assert_ne!(id_zero, id_max);
1900        assert_ne!(id_mid, id_max);
1901    }
1902
1903    #[test]
1904    fn test_regression_mapper_clear_and_reuse() {
1905        // Regression: After clear, mapper should work exactly as new
1906        let mut mapper = VniMapper::new();
1907        let vlan = VniLayer::Vlan { vid: 100 };
1908
1909        // First cycle
1910        let id1 = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan));
1911        assert_eq!(id1.as_u32(), 1);
1912        assert_eq!(mapper.len(), 1);
1913
1914        // Clear
1915        mapper.clear();
1916        assert_eq!(mapper.len(), 0);
1917        assert!(mapper.is_empty());
1918
1919        // Second cycle - should behave identically
1920        let id2 = mapper.get_or_create_vni_id(std::slice::from_ref(&vlan));
1921        assert_eq!(id2.as_u32(), 1); // Counter resets
1922        assert_eq!(mapper.len(), 1);
1923
1924        // Third cycle with different VLAN
1925        let vlan2 = VniLayer::Vlan { vid: 200 };
1926        let id3 = mapper.get_or_create_vni_id(&[vlan2]);
1927        assert_eq!(id3.as_u32(), 2);
1928        assert_eq!(mapper.len(), 2);
1929    }
1930
1931    #[test]
1932    fn test_regression_mixed_tunnel_stack_uniqueness() {
1933        // Regression: Complex stacks with similar components should be unique
1934        let mut mapper = VniMapper::new();
1935        let endpoints = [
1936            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)),
1937            IpAddr::V4(Ipv4Addr::new(10, 0, 0, 2)),
1938        ];
1939
1940        let vlan100 = VniLayer::Vlan { vid: 100 };
1941        let vlan200 = VniLayer::Vlan { vid: 200 };
1942        let vxlan = VniLayer::Vxlan {
1943            vni: 5000,
1944            group_id: 0,
1945            endpoints,
1946        };
1947
1948        // Different orderings and combinations
1949        let id1 = mapper.get_or_create_vni_id(&[vlan100.clone(), vxlan.clone()]);
1950        let id2 = mapper.get_or_create_vni_id(&[vxlan.clone(), vlan100.clone()]);
1951        let id3 = mapper.get_or_create_vni_id(&[vlan100.clone(), vlan200.clone(), vxlan.clone()]);
1952        let id4 = mapper.get_or_create_vni_id(&[vlan100.clone(), vxlan.clone(), vlan200.clone()]);
1953
1954        // All should be unique
1955        assert_ne!(id1, id2);
1956        assert_ne!(id1, id3);
1957        assert_ne!(id1, id4);
1958        assert_ne!(id2, id3);
1959        assert_ne!(id2, id4);
1960        assert_ne!(id3, id4);
1961
1962        assert_eq!(mapper.len(), 4);
1963    }
1964}