blob: 6ada6a9315152a5484e34bec3e970962f3fefc79 [file] [log] [blame]
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
)
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
// - A customer VLAN does not follow a service VLAN (when using Q-in-Q)
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
}