-
Notifications
You must be signed in to change notification settings - Fork 0
/
vlan.go
136 lines (115 loc) · 3.67 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
128
129
130
131
132
133
134
135
136
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 system, but may not configured or transmitted in a
// VLAN tag.
VLANMax = 0xfff
)
var (
// 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
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 (PriorityBestEffor). 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 prirority than PriorityBestEffor
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 an IEEE 802.1p priority level.
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.
//
// If a VLAN ID is too large (greater than 4094), ErrInvalidVLAN is returned.
// If a VLAN priority is too large (greater than 7), ErrInvalidVLAN is returned.
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
//
// If the byte slice does not contain exactly 2 bytes of data,
// io.ErrUnexpectedEOF is returned
//
// If a VLAN ID is too large (greater than 4094), ErrInvalidVLAN is returned.
func (v *VLAN) UnmarshalBinary(b []byte) error {
// VLAN tag is always 2 bytes
if len(b) != 2 {
return io.ErrUnexpectedEOF
}
// 3 bits: priority
// 1 bits: 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
}