nex_packet/
vlan.rs

1//! A VLAN (802.1Q) packet abstraction.
2//!
3use crate::{
4    ethernet::EtherType,
5    packet::{MutablePacket, Packet},
6};
7use bytes::{Buf, BufMut, Bytes, BytesMut};
8use nex_core::bitfield::{u1, u12be};
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12/// VLAN Header length in bytes
13pub const VLAN_HEADER_LEN: usize = 4;
14
15/// Class of Service (IEEE 802.1p Priority Code Point)
16#[repr(u8)]
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub enum ClassOfService {
20    // Background
21    BK = 1,
22    // Best Effort
23    BE = 0,
24    // Excellent Effort
25    EE = 2,
26    // Critical Applications
27    CA = 3,
28    // Video
29    VI = 4,
30    // Voice
31    VO = 5,
32    // Internetwork Control
33    IC = 6,
34    // Network Control
35    NC = 7,
36    /// Unknown Class of Service
37    Unknown(u8),
38}
39
40impl ClassOfService {
41    pub fn new(val: u8) -> Self {
42        match val {
43            0 => ClassOfService::BE,
44            1 => ClassOfService::BK,
45            2 => ClassOfService::EE,
46            3 => ClassOfService::CA,
47            4 => ClassOfService::VI,
48            5 => ClassOfService::VO,
49            6 => ClassOfService::IC,
50            7 => ClassOfService::NC,
51            other => ClassOfService::Unknown(other),
52        }
53    }
54
55    pub fn value(&self) -> u8 {
56        match *self {
57            ClassOfService::BK => 1,
58            ClassOfService::BE => 0,
59            ClassOfService::EE => 2,
60            ClassOfService::CA => 3,
61            ClassOfService::VI => 4,
62            ClassOfService::VO => 5,
63            ClassOfService::IC => 6,
64            ClassOfService::NC => 7,
65            ClassOfService::Unknown(v) => v,
66        }
67    }
68}
69
70/// VLAN header structure
71#[derive(Clone, Debug, PartialEq, Eq)]
72#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
73pub struct VlanHeader {
74    pub priority_code_point: ClassOfService,
75    pub drop_eligible_id: u1,
76    pub vlan_id: u12be,
77    pub ethertype: EtherType,
78}
79
80/// VLAN packet
81#[derive(Clone, Debug, PartialEq, Eq)]
82pub struct VlanPacket {
83    pub header: VlanHeader,
84    pub payload: Bytes,
85}
86
87impl Packet for VlanPacket {
88    type Header = VlanHeader;
89
90    fn from_buf(mut bytes: &[u8]) -> Option<Self> {
91        if bytes.len() < VLAN_HEADER_LEN {
92            return None;
93        }
94
95        // VLAN TCI
96        let tci = bytes.get_u16();
97        let pcp = ClassOfService::new(((tci >> 13) & 0b111) as u8);
98        let drop_eligible_id = ((tci >> 12) & 0b1) as u1;
99        let vlan_id = (tci & 0x0FFF) as u12be;
100
101        // EtherType
102        let ethertype = EtherType::new(bytes.get_u16());
103
104        // Payload
105        Some(VlanPacket {
106            header: VlanHeader {
107                priority_code_point: pcp,
108                drop_eligible_id,
109                vlan_id,
110                ethertype,
111            },
112            payload: Bytes::copy_from_slice(bytes),
113        })
114    }
115    fn from_bytes(mut bytes: Bytes) -> Option<Self> {
116        Self::from_buf(&mut bytes)
117    }
118
119    fn to_bytes(&self) -> Bytes {
120        let mut buf = BytesMut::with_capacity(VLAN_HEADER_LEN + self.payload.len());
121
122        let pcp_bits = (self.header.priority_code_point.value() as u16 & 0b111) << 13;
123        let dei_bits = (self.header.drop_eligible_id as u16 & 0b1) << 12;
124        let vlan_bits = self.header.vlan_id as u16 & 0x0FFF;
125
126        let tci = pcp_bits | dei_bits | vlan_bits;
127
128        buf.put_u16(tci);
129        buf.put_u16(self.header.ethertype.value());
130        buf.extend_from_slice(&self.payload);
131
132        buf.freeze()
133    }
134
135    fn header(&self) -> Bytes {
136        let mut buf = BytesMut::with_capacity(VLAN_HEADER_LEN);
137
138        let mut first = (self.header.priority_code_point.value() & 0b111) << 5;
139        first |= (self.header.drop_eligible_id & 0b1) << 4;
140        first |= ((self.header.vlan_id >> 8) & 0b0000_1111) as u8;
141
142        let second = (self.header.vlan_id & 0xFF) as u8;
143
144        buf.put_u8(first);
145        buf.put_u8(second);
146        buf.put_u16(self.header.ethertype.value());
147
148        buf.freeze()
149    }
150
151    fn payload(&self) -> Bytes {
152        self.payload.clone()
153    }
154
155    fn header_len(&self) -> usize {
156        VLAN_HEADER_LEN
157    }
158
159    fn payload_len(&self) -> usize {
160        self.payload.len()
161    }
162
163    fn total_len(&self) -> usize {
164        self.header_len() + self.payload_len()
165    }
166
167    fn into_parts(self) -> (Self::Header, Bytes) {
168        (self.header, self.payload)
169    }
170}
171
172/// Represents a mutable VLAN packet.
173pub struct MutableVlanPacket<'a> {
174    buffer: &'a mut [u8],
175}
176
177impl<'a> MutablePacket<'a> for MutableVlanPacket<'a> {
178    type Packet = VlanPacket;
179
180    fn new(buffer: &'a mut [u8]) -> Option<Self> {
181        if buffer.len() < VLAN_HEADER_LEN {
182            None
183        } else {
184            Some(Self { buffer })
185        }
186    }
187
188    fn packet(&self) -> &[u8] {
189        &*self.buffer
190    }
191
192    fn packet_mut(&mut self) -> &mut [u8] {
193        &mut *self.buffer
194    }
195
196    fn header(&self) -> &[u8] {
197        &self.packet()[..VLAN_HEADER_LEN]
198    }
199
200    fn header_mut(&mut self) -> &mut [u8] {
201        let (header, _) = (&mut *self.buffer).split_at_mut(VLAN_HEADER_LEN);
202        header
203    }
204
205    fn payload(&self) -> &[u8] {
206        &self.packet()[VLAN_HEADER_LEN..]
207    }
208
209    fn payload_mut(&mut self) -> &mut [u8] {
210        let (_, payload) = (&mut *self.buffer).split_at_mut(VLAN_HEADER_LEN);
211        payload
212    }
213}
214
215impl<'a> MutableVlanPacket<'a> {
216    pub fn new_unchecked(buffer: &'a mut [u8]) -> Self {
217        Self { buffer }
218    }
219
220    fn raw(&self) -> &[u8] {
221        &*self.buffer
222    }
223
224    fn raw_mut(&mut self) -> &mut [u8] {
225        &mut *self.buffer
226    }
227
228    pub fn get_priority_code_point(&self) -> ClassOfService {
229        let first = self.raw()[0];
230        ClassOfService::new(first >> 5)
231    }
232
233    pub fn set_priority_code_point(&mut self, class: ClassOfService) {
234        let buf = self.raw_mut();
235        buf[0] = (buf[0] & 0x1F) | ((class.value() & 0x07) << 5);
236    }
237
238    pub fn get_drop_eligible_id(&self) -> u1 {
239        ((self.raw()[0] >> 4) & 0x01) as u1
240    }
241
242    pub fn set_drop_eligible_id(&mut self, dei: u1) {
243        let buf = self.raw_mut();
244        buf[0] = (buf[0] & !(1 << 4)) | (((dei & 0x1) as u8) << 4);
245    }
246
247    pub fn get_vlan_id(&self) -> u16 {
248        let first = self.raw()[0] as u16 & 0x0F;
249        let second = self.raw()[1] as u16;
250        (first << 8) | second
251    }
252
253    pub fn set_vlan_id(&mut self, id: u16) {
254        let buf = self.raw_mut();
255        buf[0] = (buf[0] & 0xF0) | ((id >> 8) as u8 & 0x0F);
256        buf[1] = id as u8;
257    }
258
259    pub fn get_ethertype(&self) -> EtherType {
260        EtherType::new(u16::from_be_bytes([self.raw()[2], self.raw()[3]]))
261    }
262
263    pub fn set_ethertype(&mut self, ty: EtherType) {
264        self.raw_mut()[2..4].copy_from_slice(&ty.value().to_be_bytes());
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use super::*;
271
272    #[test]
273    fn test_vlan_parse() {
274        let raw = Bytes::from_static(&[
275            0x20, 0x00, // TCI: pcp=1 (BK), dei=0, vid=0
276            0x08, 0x00, // EtherType: IPv4
277            b'x', b'y', b'z',
278        ]);
279
280        let packet = VlanPacket::from_bytes(raw.clone()).unwrap();
281
282        assert_eq!(packet.header.priority_code_point, ClassOfService::BK);
283        assert_eq!(packet.header.drop_eligible_id, 0);
284        assert_eq!(packet.header.vlan_id, 0x000);
285        assert_eq!(packet.header.ethertype, EtherType::Ipv4);
286        assert_eq!(packet.payload, Bytes::from_static(b"xyz"));
287        assert_eq!(packet.to_bytes(), raw);
288    }
289
290    #[test]
291    fn test_vlan_parse_2() {
292        let raw = Bytes::from_static(&[
293            0x01, 0x00, // TCI: PCP=0(BE), DEI=0, VID=0x100
294            0x08, 0x00, // EtherType: IPv4
295            b'x', b'y', b'z',
296        ]);
297
298        let packet = VlanPacket::from_bytes(raw.clone()).unwrap();
299
300        assert_eq!(packet.header.priority_code_point, ClassOfService::BE);
301        assert_eq!(packet.header.drop_eligible_id, 0);
302        assert_eq!(packet.header.vlan_id, 0x100);
303        assert_eq!(packet.header.ethertype, EtherType::Ipv4);
304        assert_eq!(packet.payload, Bytes::from_static(b"xyz"));
305        assert_eq!(packet.to_bytes(), raw);
306    }
307
308    #[test]
309    fn test_mutable_vlan_packet_changes() {
310        let mut raw = [
311            0x00, 0x01, // TCI
312            0x08, 0x00, // EtherType: IPv4
313            b'a', b'b',
314        ];
315
316        let mut packet = MutableVlanPacket::new(&mut raw).expect("mutable vlan");
317        assert_eq!(packet.get_vlan_id(), 1);
318        packet.set_priority_code_point(ClassOfService::VO);
319        packet.set_vlan_id(0x0abc);
320        packet.set_ethertype(EtherType::Ipv6);
321        packet.payload_mut()[0] = b'z';
322
323        let frozen = packet.freeze().expect("freeze");
324        assert_eq!(frozen.header.priority_code_point, ClassOfService::VO);
325        assert_eq!(frozen.header.vlan_id, 0x0abc);
326        assert_eq!(frozen.header.ethertype, EtherType::Ipv6);
327        assert_eq!(frozen.payload[0], b'z');
328    }
329}