blob: d7f044e24011426c742d2bdd118e21e4cbb6b958 [file] [log] [blame]
Yotam Harcholf3f11152013-09-05 16:47:16 -07001package org.projectfloodlight.openflow.types;
2
Andreas Wundsam5f71b412014-02-18 12:56:35 -08003import java.util.Arrays;
4
Andreas Wundsam3700d162014-03-11 04:43:38 -07005import javax.annotation.Nonnull;
6
Yotam Harcholf3f11152013-09-05 16:47:16 -07007import org.jboss.netty.buffer.ChannelBuffer;
8import org.projectfloodlight.openflow.exceptions.OFParseError;
9import org.projectfloodlight.openflow.util.HexString;
10
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070011import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -070012import com.google.common.primitives.Longs;
13
Yotam Harcholf3f11152013-09-05 16:47:16 -070014/**
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
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070024 private final static long NONE_VAL = 0x0L;
25 public static final MacAddress NONE = new MacAddress(NONE_VAL);
26
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070027 private final static long BROADCAST_VAL = 0x0000FFFFFFFFFFFFL;
28 public static final MacAddress BROADCAST = new MacAddress(BROADCAST_VAL);
29
Yotam Harcholf3f11152013-09-05 16:47:16 -070030 public static final MacAddress NO_MASK = MacAddress.of(0xFFFFFFFFFFFFFFFFl);
31 public static final MacAddress FULL_MASK = MacAddress.of(0x0);
32
Shudong Zhoua4fb4c62014-02-10 16:57:45 -080033 private static final long LLDP_MAC_ADDRESS_MASK = 0xfffffffffff0L;
34 private static final long LLDP_MAC_ADDRESS_VALUE = 0x0180c2000000L;
Shudong Zhoue5a36802014-02-09 14:54:14 -080035
Yotam Harcholf3f11152013-09-05 16:47:16 -070036 private MacAddress(final long rawValue) {
37 this.rawValue = rawValue;
38 }
39
40 public static MacAddress of(final byte[] address) {
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070041 if (address.length != MacAddrLen)
42 throw new IllegalArgumentException(
43 "Mac address byte array must be exactly 6 bytes long; length = " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -070044 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
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070051 public static MacAddress of(long raw) {
52 raw &= BROADCAST_VAL;
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070053 if(raw == NONE_VAL)
54 return NONE;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070055 if (raw == BROADCAST_VAL)
56 return BROADCAST;
Yotam Harcholf3f11152013-09-05 16:47:16 -070057 return new MacAddress(raw);
58 }
59
Andreas Wundsam3700d162014-03-11 04:43:38 -070060 /** 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 }
Yotam Harcholf3f11152013-09-05 16:47:16 -070072 int index = 0;
73 int shift = 40;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070074 final String FORMAT_ERROR = "Mac address is not well-formed. " +
75 "It must consist of 6 hex digit pairs separated by colons: ";
Yotam Harcholf3f11152013-09-05 16:47:16 -070076
77 long raw = 0;
Andreas Wundsam3700d162014-03-11 04:43:38 -070078 if (macString.length() != 6 * 2 + 5)
79 throw new IllegalArgumentException(FORMAT_ERROR + macString);
Yotam Harcholf3f11152013-09-05 16:47:16 -070080
81 while (shift >= 0) {
Andreas Wundsam3700d162014-03-11 04:43:38 -070082 int digit1 = Character.digit(macString.charAt(index++), 16);
83 int digit2 = Character.digit(macString.charAt(index++), 16);
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070084 if ((digit1 < 0) || (digit2 < 0))
Andreas Wundsam3700d162014-03-11 04:43:38 -070085 throw new IllegalArgumentException(FORMAT_ERROR + macString);
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070086 raw |= ((long) (digit1 << 4 | digit2)) << shift;
Yotam Harcholf3f11152013-09-05 16:47:16 -070087
88 if (shift == 0)
89 break;
Andreas Wundsam3700d162014-03-11 04:43:38 -070090 if (macString.charAt(index++) != ':')
91 throw new IllegalArgumentException(FORMAT_ERROR + macString);
Yotam Harcholf3f11152013-09-05 16:47:16 -070092 shift -= 8;
93 }
94 return MacAddress.of(raw);
95 }
96
Andreas Wundsam4e2469e2014-02-17 15:32:43 -080097 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -070098
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 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800113 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700114 }
115
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -0700116 /**
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
Shudong Zhoue5a36802014-02-09 14:54:14 -0800135 /**
Shudong Zhoua4fb4c62014-02-10 16:57:45 -0800136 * 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.
Shudong Zhoue5a36802014-02-09 14:54:14 -0800138 */
Shudong Zhoua4fb4c62014-02-10 16:57:45 -0800139 public boolean isLLDPAddress() {
140 return (rawValue & LLDP_MAC_ADDRESS_MASK) == LLDP_MAC_ADDRESS_VALUE;
Shudong Zhoue5a36802014-02-09 14:54:14 -0800141 }
142
Yotam Harcholf3f11152013-09-05 16:47:16 -0700143 @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
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700194 @Override
195 public int compareTo(MacAddress o) {
196 return Longs.compare(rawValue, o.rawValue);
197 }
198
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700199 @Override
200 public void putTo(PrimitiveSink sink) {
201 sink.putInt((int) (this.rawValue >> 16));
202 sink.putShort((short) (this.rawValue & 0xFFFF));
203 }
204
Yotam Harcholf3f11152013-09-05 16:47:16 -0700205
206
207}