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