1use core::mem;
2
3#[repr(C)]
10#[derive(Debug, Copy, Clone)]
11#[cfg_attr(feature = "wincode", derive(wincode::SchemaRead, wincode::SchemaWrite))]
12#[cfg_attr(feature = "wincode", wincode(assert_zero_copy))]
13pub struct VxlanHdr {
14 pub flags: u8,
16 pub _reserved1: [u8; 3],
18 pub vni: [u8; 3],
21 pub _reserved2: u8,
22}
23
24pub const VXLAN_I_FLAG_MASK: u8 = 0x08;
26
27impl VxlanHdr {
28 pub const LEN: usize = mem::size_of::<VxlanHdr>();
30
31 pub fn new(vni: u32) -> Self {
41 let mut hdr = VxlanHdr {
42 flags: VXLAN_I_FLAG_MASK,
43 _reserved1: [0u8; 3],
44 vni: [0u8; 3],
45 _reserved2: 0u8,
46 };
47 hdr.set_vni(vni);
48 hdr
49 }
50
51 pub fn with_flags(flags: u8, vni: [u8; 3]) -> Self {
62 Self {
63 flags,
64 _reserved1: [0; 3],
65 vni,
66 _reserved2: 0,
67 }
68 }
69
70 #[inline]
75 pub fn flags(&self) -> u8 {
76 self.flags
77 }
78
79 #[inline]
84 pub fn set_flags(&mut self, flags: u8) {
85 self.flags = flags;
86 }
87
88 #[inline]
93 pub fn vni_present(&self) -> bool {
94 (self.flags & VXLAN_I_FLAG_MASK) == VXLAN_I_FLAG_MASK
95 }
96
97 #[inline]
104 pub fn set_vni_present(&mut self, present: bool) {
105 if present {
106 self.flags |= VXLAN_I_FLAG_MASK;
107 } else {
108 self.flags &= !VXLAN_I_FLAG_MASK;
109 }
110 }
111
112 #[inline]
117 pub fn vni(&self) -> u32 {
118 u32::from_be_bytes([0, self.vni[0], self.vni[1], self.vni[2]])
119 }
120
121 #[inline]
128 pub fn set_vni(&mut self, vni: u32) {
129 let vni_24bit = vni & 0x00FF_FFFF;
130 let vni_bytes = vni_24bit.to_be_bytes();
131 self.vni[0] = vni_bytes[1];
132 self.vni[1] = vni_bytes[2];
133 self.vni[2] = vni_bytes[3];
134 }
135}
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_vxlanhdr_len() {
142 assert_eq!(VxlanHdr::LEN, 8, "VXLAN header length should be 8 bytes");
143 }
144
145 #[test]
146 fn test_vxlanhdr_new() {
147 let vni_val: u32 = 0xABCDEF;
148 let hdr = VxlanHdr::new(vni_val);
149 assert_eq!(
150 hdr.flags(),
151 VXLAN_I_FLAG_MASK,
152 "Flags should have I-flag set and others zero"
153 );
154 assert!(hdr.vni_present(), "VNI present flag should be set by new()");
155 assert_eq!(hdr.vni(), vni_val, "VNI should be set correctly by new()");
156 }
157
158 #[test]
159 fn test_flags_management() {
160 let mut hdr = VxlanHdr::new(0x123);
161 hdr.set_flags(0xFF);
162 assert_eq!(hdr.flags(), 0xFF);
163 assert!(
164 hdr.vni_present(),
165 "I-flag should be set if flags byte is 0xFF"
166 );
167 hdr.set_flags(0x00);
168 assert!(
169 !hdr.vni_present(),
170 "I-flag should be clear if flags byte is 0x00"
171 );
172 hdr.set_vni_present(true);
173 assert_eq!(
174 hdr.flags(),
175 VXLAN_I_FLAG_MASK,
176 "set_vni_present(true) should set I-flag"
177 );
178 assert!(hdr.vni_present());
179 hdr.set_vni_present(false);
180 assert_eq!(
181 hdr.flags(),
182 0x00,
183 "set_vni_present(false) should clear I-flag"
184 );
185 assert!(!hdr.vni_present());
186 hdr.set_flags(0xF0);
187 assert!(!hdr.vni_present());
188 hdr.set_vni_present(true);
189 assert_eq!(
190 hdr.flags(),
191 0xF0 | VXLAN_I_FLAG_MASK,
192 "Setting I-flag should preserve other bits"
193 );
194 assert!(hdr.vni_present());
195 hdr.set_vni_present(false);
196 assert_eq!(
197 hdr.flags(),
198 0xF0 & !VXLAN_I_FLAG_MASK,
199 "Clearing I-flag should preserve other bits"
200 );
201 assert!(!hdr.vni_present());
202 }
203
204 #[test]
205 fn test_vni_management() {
206 let mut hdr = VxlanHdr::new(0);
207 let vni_val: u32 = 0xABCDEF;
208 hdr.set_vni(vni_val);
209 assert_eq!(hdr.vni(), vni_val, "VNI should be set correctly");
210 let large_vni: u32 = 0x12ABCDEF;
211 hdr.set_vni(large_vni);
212 assert_eq!(hdr.vni(), 0xABCDEF, "VNI should be masked to 24 bits");
213 hdr.set_vni(0);
214 assert_eq!(hdr.vni(), 0, "VNI should be settable to 0");
215 let max_vni: u32 = 0xFFFFFF;
216 hdr.set_vni(max_vni);
217 assert_eq!(hdr.vni(), max_vni, "Max 24-bit VNI should be settable");
218 hdr.set_vni(0x123456);
219 assert_eq!(hdr.vni(), 0x123456, "VNI should be updated");
220 }
221
222 #[test]
223 fn test_field_storage_and_retrieval_direct_manipulation() {
224 let mut hdr = VxlanHdr::with_flags(0x08, [0xAB, 0xCD, 0xEF]);
225 hdr.flags = 0x08;
226 hdr.vni = [0xAB, 0xCD, 0xEF];
227 assert_eq!(hdr.flags(), 0x08);
228 assert!(hdr.vni_present());
229 assert_eq!(hdr.vni(), 0xABCDEF);
230 hdr.set_vni_present(false);
231 assert_eq!(
232 hdr.flags, 0x00,
233 "Direct field check after set_vni_present(false)"
234 );
235 hdr.set_vni(0x654321);
236 assert_eq!(hdr.vni[0], 0x65, "Byte 0 of vni after set_vni");
237 assert_eq!(hdr.vni[1], 0x43, "Byte 1 of vni after set_vni");
238 assert_eq!(hdr.vni[2], 0x21, "Byte 2 of vni after set_vni");
239 assert_eq!(hdr.vni(), 0x654321);
240 assert_eq!(
241 hdr.vni[0], 0x65,
242 "Byte 0 of vni preserved after set_reserved2"
243 );
244 assert_eq!(hdr.vni(), 0x654321);
245 }
246}