vlan.go 3.5 KB

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