blob: 6ada6a9315152a5484e34bec3e970962f3fefc79 [file] [log] [blame]
manikkaraj k9eb6cac2019-05-09 12:32:03 -04001package ethernet
2
3import (
4 "encoding/binary"
5 "errors"
6 "io"
7)
8
9const (
10 // VLANNone is a special VLAN ID which indicates that no VLAN is being
11 // used in a Frame. In this case, the VLAN's other fields may be used
12 // to indicate a Frame's priority.
13 VLANNone = 0x000
14
15 // VLANMax is a reserved VLAN ID which may indicate a wildcard in some
16 // management systems, but may not be configured or transmitted in a
17 // VLAN tag.
18 VLANMax = 0xfff
19)
20
21var (
22 // ErrInvalidVLAN is returned when a VLAN tag is invalid due to one of the
23 // following reasons:
24 // - Priority of greater than 7 is detected
25 // - ID of greater than 4094 (0xffe) is detected
26 // - A customer VLAN does not follow a service VLAN (when using Q-in-Q)
27 ErrInvalidVLAN = errors.New("invalid VLAN")
28)
29
30// Priority is an IEEE P802.1p priority level. Priority can be any value from
31// 0 to 7.
32//
33// It is important to note that priority 1 (PriorityBackground) actually has
34// a lower priority than 0 (PriorityBestEffort). All other Priority constants
35// indicate higher priority as the integer values increase.
36type Priority uint8
37
38// IEEE P802.1p recommended priority levels. Note that PriorityBackground has
39// a lower priority than PriorityBestEffort.
40const (
41 PriorityBackground Priority = 1
42 PriorityBestEffort Priority = 0
43 PriorityExcellentEffort Priority = 2
44 PriorityCriticalApplications Priority = 3
45 PriorityVideo Priority = 4
46 PriorityVoice Priority = 5
47 PriorityInternetworkControl Priority = 6
48 PriorityNetworkControl Priority = 7
49)
50
51// A VLAN is an IEEE 802.1Q Virtual LAN (VLAN) tag. A VLAN contains
52// information regarding traffic priority and a VLAN identifier for
53// a given Frame.
54type VLAN struct {
55 // Priority specifies a IEEE P802.1p priority level. Priority can be any
56 // value from 0 to 7.
57 Priority Priority
58
59 // DropEligible indicates if a Frame is eligible to be dropped in the
60 // presence of network congestion.
61 DropEligible bool
62
63 // ID specifies the VLAN ID for a Frame. ID can be any value from 0 to
64 // 4094 (0x000 to 0xffe), allowing up to 4094 VLANs.
65 //
66 // If ID is 0 (0x000, VLANNone), no VLAN is specified, and the other fields
67 // simply indicate a Frame's priority.
68 ID uint16
69}
70
71// MarshalBinary allocates a byte slice and marshals a VLAN into binary form.
72func (v *VLAN) MarshalBinary() ([]byte, error) {
73 b := make([]byte, 2)
74 _, err := v.read(b)
75 return b, err
76}
77
78// read reads data from a VLAN into b. read is used to marshal a VLAN into
79// binary form, but does not allocate on its own.
80func (v *VLAN) read(b []byte) (int, error) {
81 // Check for VLAN priority in valid range
82 if v.Priority > PriorityNetworkControl {
83 return 0, ErrInvalidVLAN
84 }
85
86 // Check for VLAN ID in valid range
87 if v.ID >= VLANMax {
88 return 0, ErrInvalidVLAN
89 }
90
91 // 3 bits: priority
92 ub := uint16(v.Priority) << 13
93
94 // 1 bit: drop eligible
95 var drop uint16
96 if v.DropEligible {
97 drop = 1
98 }
99 ub |= drop << 12
100
101 // 12 bits: VLAN ID
102 ub |= v.ID
103
104 binary.BigEndian.PutUint16(b, ub)
105 return 2, nil
106}
107
108// UnmarshalBinary unmarshals a byte slice into a VLAN.
109func (v *VLAN) UnmarshalBinary(b []byte) error {
110 // VLAN tag is always 2 bytes
111 if len(b) != 2 {
112 return io.ErrUnexpectedEOF
113 }
114
115 // 3 bits: priority
116 // 1 bit : drop eligible
117 // 12 bits: VLAN ID
118 ub := binary.BigEndian.Uint16(b[0:2])
119 v.Priority = Priority(uint8(ub >> 13))
120 v.DropEligible = ub&0x1000 != 0
121 v.ID = ub & 0x0fff
122
123 // Check for VLAN ID in valid range
124 if v.ID >= VLANMax {
125 return ErrInvalidVLAN
126 }
127
128 return nil
129}