blob: d7f044e24011426c742d2bdd118e21e4cbb6b958 [file] [log] [blame]
tom0eb04ca2014-08-25 14:34:51 -07001package org.projectfloodlight.openflow.types;
2
3import java.util.Arrays;
4
5import javax.annotation.Nonnull;
6
7import org.jboss.netty.buffer.ChannelBuffer;
8import org.projectfloodlight.openflow.exceptions.OFParseError;
9import org.projectfloodlight.openflow.util.HexString;
10
11import com.google.common.hash.PrimitiveSink;
12import com.google.common.primitives.Longs;
13
14/**
15 * Wrapper around a 6 byte mac address.
16 *
17 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
18 */
19
20public class MacAddress implements OFValueType<MacAddress> {
21 static final int MacAddrLen = 6;
22 private final long rawValue;
23
24 private final static long NONE_VAL = 0x0L;
25 public static final MacAddress NONE = new MacAddress(NONE_VAL);
26
27 private final static long BROADCAST_VAL = 0x0000FFFFFFFFFFFFL;
28 public static final MacAddress BROADCAST = new MacAddress(BROADCAST_VAL);
29
30 public static final MacAddress NO_MASK = MacAddress.of(0xFFFFFFFFFFFFFFFFl);
31 public static final MacAddress FULL_MASK = MacAddress.of(0x0);
32
33 private static final long LLDP_MAC_ADDRESS_MASK = 0xfffffffffff0L;
34 private static final long LLDP_MAC_ADDRESS_VALUE = 0x0180c2000000L;
35
36 private MacAddress(final long rawValue) {
37 this.rawValue = rawValue;
38 }
39
40 public static MacAddress of(final byte[] address) {
41 if (address.length != MacAddrLen)
42 throw new IllegalArgumentException(
43 "Mac address byte array must be exactly 6 bytes long; length = " + address.length);
44 long raw =
45 (address[0] & 0xFFL) << 40 | (address[1] & 0xFFL) << 32
46 | (address[2] & 0xFFL) << 24 | (address[3] & 0xFFL) << 16
47 | (address[4] & 0xFFL) << 8 | (address[5] & 0xFFL);
48 return MacAddress.of(raw);
49 }
50
51 public static MacAddress of(long raw) {
52 raw &= BROADCAST_VAL;
53 if(raw == NONE_VAL)
54 return NONE;
55 if (raw == BROADCAST_VAL)
56 return BROADCAST;
57 return new MacAddress(raw);
58 }
59
60 /** Parse a mac adress from the canonical string representation as
61 * 6 hex bytes separated by colons (01:02:03:04:05:06).
62 *
63 * @param macString - a mac address in canonical string representation
64 * @return the parsed MacAddress
65 * @throws IllegalArgumentException if macString is not a valid mac adddress
66 */
67 @Nonnull
68 public static MacAddress of(@Nonnull final String macString) throws IllegalArgumentException {
69 if (macString == null) {
70 throw new NullPointerException("macString must not be null");
71 }
72 int index = 0;
73 int shift = 40;
74 final String FORMAT_ERROR = "Mac address is not well-formed. " +
75 "It must consist of 6 hex digit pairs separated by colons: ";
76
77 long raw = 0;
78 if (macString.length() != 6 * 2 + 5)
79 throw new IllegalArgumentException(FORMAT_ERROR + macString);
80
81 while (shift >= 0) {
82 int digit1 = Character.digit(macString.charAt(index++), 16);
83 int digit2 = Character.digit(macString.charAt(index++), 16);
84 if ((digit1 < 0) || (digit2 < 0))
85 throw new IllegalArgumentException(FORMAT_ERROR + macString);
86 raw |= ((long) (digit1 << 4 | digit2)) << shift;
87
88 if (shift == 0)
89 break;
90 if (macString.charAt(index++) != ':')
91 throw new IllegalArgumentException(FORMAT_ERROR + macString);
92 shift -= 8;
93 }
94 return MacAddress.of(raw);
95 }
96
97 private volatile byte[] bytesCache = null;
98
99 public byte[] getBytes() {
100 if (bytesCache == null) {
101 synchronized (this) {
102 if (bytesCache == null) {
103 bytesCache =
104 new byte[] { (byte) ((rawValue >> 40) & 0xFF),
105 (byte) ((rawValue >> 32) & 0xFF),
106 (byte) ((rawValue >> 24) & 0xFF),
107 (byte) ((rawValue >> 16) & 0xFF),
108 (byte) ((rawValue >> 8) & 0xFF),
109 (byte) ((rawValue >> 0) & 0xFF) };
110 }
111 }
112 }
113 return Arrays.copyOf(bytesCache, bytesCache.length);
114 }
115
116 /**
117 * Returns {@code true} if the MAC address is the broadcast address.
118 * @return {@code true} if the MAC address is the broadcast address.
119 */
120 public boolean isBroadcast() {
121 return this == BROADCAST;
122 }
123
124 /**
125 * Returns {@code true} if the MAC address is a multicast address.
126 * @return {@code true} if the MAC address is a multicast address.
127 */
128 public boolean isMulticast() {
129 if (isBroadcast()) {
130 return false;
131 }
132 return (rawValue & (0x01L << 40)) != 0;
133 }
134
135 /**
136 * Returns {@code true} if the MAC address is an LLDP mac address.
137 * @return {@code true} if the MAC address is an LLDP mac address.
138 */
139 public boolean isLLDPAddress() {
140 return (rawValue & LLDP_MAC_ADDRESS_MASK) == LLDP_MAC_ADDRESS_VALUE;
141 }
142
143 @Override
144 public int getLength() {
145 return MacAddrLen;
146 }
147
148 @Override
149 public String toString() {
150 return HexString.toHexString(rawValue, 6);
151 }
152
153 @Override
154 public int hashCode() {
155 final int prime = 31;
156 int result = 1;
157 result = prime * result + (int) (rawValue ^ (rawValue >>> 32));
158 return result;
159 }
160
161 @Override
162 public boolean equals(final Object obj) {
163 if (this == obj)
164 return true;
165 if (obj == null)
166 return false;
167 if (getClass() != obj.getClass())
168 return false;
169 MacAddress other = (MacAddress) obj;
170 if (rawValue != other.rawValue)
171 return false;
172 return true;
173 }
174
175 public long getLong() {
176 return rawValue;
177 }
178
179 public void write6Bytes(ChannelBuffer c) {
180 c.writeInt((int) (this.rawValue >> 16));
181 c.writeShort((int) this.rawValue & 0xFFFF);
182 }
183
184 public static MacAddress read6Bytes(ChannelBuffer c) throws OFParseError {
185 long raw = c.readUnsignedInt() << 16 | c.readUnsignedShort();
186 return MacAddress.of(raw);
187 }
188
189 @Override
190 public MacAddress applyMask(MacAddress mask) {
191 return MacAddress.of(this.rawValue & mask.rawValue);
192 }
193
194 @Override
195 public int compareTo(MacAddress o) {
196 return Longs.compare(rawValue, o.rawValue);
197 }
198
199 @Override
200 public void putTo(PrimitiveSink sink) {
201 sink.putInt((int) (this.rawValue >> 16));
202 sink.putShort((short) (this.rawValue & 0xFFFF));
203 }
204
205
206
207}