manikkaraj k | 9eb6cac | 2019-05-09 12:32:03 -0400 | [diff] [blame] | 1 | package ethernet |
| 2 | |
| 3 | import ( |
| 4 | "encoding/binary" |
| 5 | "errors" |
| 6 | "io" |
| 7 | ) |
| 8 | |
| 9 | const ( |
| 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 | |
| 21 | var ( |
| 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. |
| 36 | type Priority uint8 |
| 37 | |
| 38 | // IEEE P802.1p recommended priority levels. Note that PriorityBackground has |
| 39 | // a lower priority than PriorityBestEffort. |
| 40 | const ( |
| 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. |
| 54 | type 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. |
| 72 | func (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. |
| 80 | func (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. |
| 109 | func (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 | } |