blob: f592ea8106f7ae20fcd1537a282228723488a8f5 [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
Yotam Harcholf3f11152013-09-05 16:47:16 -07005import org.jboss.netty.buffer.ChannelBuffer;
6import org.projectfloodlight.openflow.exceptions.OFParseError;
7import org.projectfloodlight.openflow.util.HexString;
8
Andreas Wundsam22ba3af2013-10-04 16:00:30 -07009import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -070010import com.google.common.primitives.Longs;
11
Yotam Harcholf3f11152013-09-05 16:47:16 -070012/**
13 * Wrapper around a 6 byte mac address.
14 *
15 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
16 */
17
18public class MacAddress implements OFValueType<MacAddress> {
19 static final int MacAddrLen = 6;
20 private final long rawValue;
21
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070022 private final static long NONE_VAL = 0x0L;
23 public static final MacAddress NONE = new MacAddress(NONE_VAL);
24
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070025 private final static long BROADCAST_VAL = 0x0000FFFFFFFFFFFFL;
26 public static final MacAddress BROADCAST = new MacAddress(BROADCAST_VAL);
27
Yotam Harcholf3f11152013-09-05 16:47:16 -070028 public static final MacAddress NO_MASK = MacAddress.of(0xFFFFFFFFFFFFFFFFl);
29 public static final MacAddress FULL_MASK = MacAddress.of(0x0);
30
Shudong Zhoua4fb4c62014-02-10 16:57:45 -080031 private static final long LLDP_MAC_ADDRESS_MASK = 0xfffffffffff0L;
32 private static final long LLDP_MAC_ADDRESS_VALUE = 0x0180c2000000L;
Shudong Zhoue5a36802014-02-09 14:54:14 -080033
Yotam Harcholf3f11152013-09-05 16:47:16 -070034 private MacAddress(final long rawValue) {
35 this.rawValue = rawValue;
36 }
37
38 public static MacAddress of(final byte[] address) {
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070039 if (address.length != MacAddrLen)
40 throw new IllegalArgumentException(
41 "Mac address byte array must be exactly 6 bytes long; length = " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -070042 long raw =
43 (address[0] & 0xFFL) << 40 | (address[1] & 0xFFL) << 32
44 | (address[2] & 0xFFL) << 24 | (address[3] & 0xFFL) << 16
45 | (address[4] & 0xFFL) << 8 | (address[5] & 0xFFL);
46 return MacAddress.of(raw);
47 }
48
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070049 public static MacAddress of(long raw) {
50 raw &= BROADCAST_VAL;
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070051 if(raw == NONE_VAL)
52 return NONE;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070053 if (raw == BROADCAST_VAL)
54 return BROADCAST;
Yotam Harcholf3f11152013-09-05 16:47:16 -070055 return new MacAddress(raw);
56 }
57
58 public static MacAddress of(final String string) {
59 int index = 0;
60 int shift = 40;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070061 final String FORMAT_ERROR = "Mac address is not well-formed. " +
62 "It must consist of 6 hex digit pairs separated by colons: ";
Yotam Harcholf3f11152013-09-05 16:47:16 -070063
64 long raw = 0;
65 if (string.length() != 6 * 2 + 5)
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070066 throw new IllegalArgumentException(FORMAT_ERROR + string);
Yotam Harcholf3f11152013-09-05 16:47:16 -070067
68 while (shift >= 0) {
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070069 int digit1 = Character.digit(string.charAt(index++), 16);
70 int digit2 = Character.digit(string.charAt(index++), 16);
71 if ((digit1 < 0) || (digit2 < 0))
72 throw new IllegalArgumentException(FORMAT_ERROR + string);
73 raw |= ((long) (digit1 << 4 | digit2)) << shift;
Yotam Harcholf3f11152013-09-05 16:47:16 -070074
75 if (shift == 0)
76 break;
77 if (string.charAt(index++) != ':')
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070078 throw new IllegalArgumentException(FORMAT_ERROR + string);
Yotam Harcholf3f11152013-09-05 16:47:16 -070079 shift -= 8;
80 }
81 return MacAddress.of(raw);
82 }
83
Andreas Wundsam4e2469e2014-02-17 15:32:43 -080084 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -070085
86 public byte[] getBytes() {
87 if (bytesCache == null) {
88 synchronized (this) {
89 if (bytesCache == null) {
90 bytesCache =
91 new byte[] { (byte) ((rawValue >> 40) & 0xFF),
92 (byte) ((rawValue >> 32) & 0xFF),
93 (byte) ((rawValue >> 24) & 0xFF),
94 (byte) ((rawValue >> 16) & 0xFF),
95 (byte) ((rawValue >> 8) & 0xFF),
96 (byte) ((rawValue >> 0) & 0xFF) };
97 }
98 }
99 }
Andreas Wundsam5f71b412014-02-18 12:56:35 -0800100 return Arrays.copyOf(bytesCache, bytesCache.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -0700101 }
102
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -0700103 /**
104 * Returns {@code true} if the MAC address is the broadcast address.
105 * @return {@code true} if the MAC address is the broadcast address.
106 */
107 public boolean isBroadcast() {
108 return this == BROADCAST;
109 }
110
111 /**
112 * Returns {@code true} if the MAC address is a multicast address.
113 * @return {@code true} if the MAC address is a multicast address.
114 */
115 public boolean isMulticast() {
116 if (isBroadcast()) {
117 return false;
118 }
119 return (rawValue & (0x01L << 40)) != 0;
120 }
121
Shudong Zhoue5a36802014-02-09 14:54:14 -0800122 /**
Shudong Zhoua4fb4c62014-02-10 16:57:45 -0800123 * Returns {@code true} if the MAC address is an LLDP mac address.
124 * @return {@code true} if the MAC address is an LLDP mac address.
Shudong Zhoue5a36802014-02-09 14:54:14 -0800125 */
Shudong Zhoua4fb4c62014-02-10 16:57:45 -0800126 public boolean isLLDPAddress() {
127 return (rawValue & LLDP_MAC_ADDRESS_MASK) == LLDP_MAC_ADDRESS_VALUE;
Shudong Zhoue5a36802014-02-09 14:54:14 -0800128 }
129
Yotam Harcholf3f11152013-09-05 16:47:16 -0700130 @Override
131 public int getLength() {
132 return MacAddrLen;
133 }
134
135 @Override
136 public String toString() {
137 return HexString.toHexString(rawValue, 6);
138 }
139
140 @Override
141 public int hashCode() {
142 final int prime = 31;
143 int result = 1;
144 result = prime * result + (int) (rawValue ^ (rawValue >>> 32));
145 return result;
146 }
147
148 @Override
149 public boolean equals(final Object obj) {
150 if (this == obj)
151 return true;
152 if (obj == null)
153 return false;
154 if (getClass() != obj.getClass())
155 return false;
156 MacAddress other = (MacAddress) obj;
157 if (rawValue != other.rawValue)
158 return false;
159 return true;
160 }
161
162 public long getLong() {
163 return rawValue;
164 }
165
166 public void write6Bytes(ChannelBuffer c) {
167 c.writeInt((int) (this.rawValue >> 16));
168 c.writeShort((int) this.rawValue & 0xFFFF);
169 }
170
171 public static MacAddress read6Bytes(ChannelBuffer c) throws OFParseError {
172 long raw = c.readUnsignedInt() << 16 | c.readUnsignedShort();
173 return MacAddress.of(raw);
174 }
175
176 @Override
177 public MacAddress applyMask(MacAddress mask) {
178 return MacAddress.of(this.rawValue & mask.rawValue);
179 }
180
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700181 @Override
182 public int compareTo(MacAddress o) {
183 return Longs.compare(rawValue, o.rawValue);
184 }
185
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700186 @Override
187 public void putTo(PrimitiveSink sink) {
188 sink.putInt((int) (this.rawValue >> 16));
189 sink.putShort((short) (this.rawValue & 0xFFFF));
190 }
191
Yotam Harcholf3f11152013-09-05 16:47:16 -0700192
193
194}