blob: 48a4faff4d77b155e3d9ec2d8c8edd79a95cd345 [file] [log] [blame]
Yotam Harcholf3f11152013-09-05 16:47:16 -07001package org.projectfloodlight.openflow.types;
2
3import org.jboss.netty.buffer.ChannelBuffer;
4import org.projectfloodlight.openflow.exceptions.OFParseError;
5import org.projectfloodlight.openflow.util.HexString;
6
Andreas Wundsam22ba3af2013-10-04 16:00:30 -07007import com.google.common.hash.PrimitiveSink;
Andreas Wundsam85c961f2013-09-29 21:22:12 -07008import com.google.common.primitives.Longs;
9
Yotam Harcholf3f11152013-09-05 16:47:16 -070010/**
11 * Wrapper around a 6 byte mac address.
12 *
13 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
14 */
15
16public class MacAddress implements OFValueType<MacAddress> {
17 static final int MacAddrLen = 6;
18 private final long rawValue;
19
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070020 private final static long NONE_VAL = 0x0L;
21 public static final MacAddress NONE = new MacAddress(NONE_VAL);
22
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070023 private final static long BROADCAST_VAL = 0x0000FFFFFFFFFFFFL;
24 public static final MacAddress BROADCAST = new MacAddress(BROADCAST_VAL);
25
Yotam Harcholf3f11152013-09-05 16:47:16 -070026 public static final MacAddress NO_MASK = MacAddress.of(0xFFFFFFFFFFFFFFFFl);
27 public static final MacAddress FULL_MASK = MacAddress.of(0x0);
28
Shudong Zhoua4fb4c62014-02-10 16:57:45 -080029 private static final long LLDP_MAC_ADDRESS_MASK = 0xfffffffffff0L;
30 private static final long LLDP_MAC_ADDRESS_VALUE = 0x0180c2000000L;
Shudong Zhoue5a36802014-02-09 14:54:14 -080031
Yotam Harcholf3f11152013-09-05 16:47:16 -070032 private MacAddress(final long rawValue) {
33 this.rawValue = rawValue;
34 }
35
36 public static MacAddress of(final byte[] address) {
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070037 if (address.length != MacAddrLen)
38 throw new IllegalArgumentException(
39 "Mac address byte array must be exactly 6 bytes long; length = " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -070040 long raw =
41 (address[0] & 0xFFL) << 40 | (address[1] & 0xFFL) << 32
42 | (address[2] & 0xFFL) << 24 | (address[3] & 0xFFL) << 16
43 | (address[4] & 0xFFL) << 8 | (address[5] & 0xFFL);
44 return MacAddress.of(raw);
45 }
46
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070047 public static MacAddress of(long raw) {
48 raw &= BROADCAST_VAL;
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070049 if(raw == NONE_VAL)
50 return NONE;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070051 if (raw == BROADCAST_VAL)
52 return BROADCAST;
Yotam Harcholf3f11152013-09-05 16:47:16 -070053 return new MacAddress(raw);
54 }
55
56 public static MacAddress of(final String string) {
57 int index = 0;
58 int shift = 40;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070059 final String FORMAT_ERROR = "Mac address is not well-formed. " +
60 "It must consist of 6 hex digit pairs separated by colons: ";
Yotam Harcholf3f11152013-09-05 16:47:16 -070061
62 long raw = 0;
63 if (string.length() != 6 * 2 + 5)
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070064 throw new IllegalArgumentException(FORMAT_ERROR + string);
Yotam Harcholf3f11152013-09-05 16:47:16 -070065
66 while (shift >= 0) {
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070067 int digit1 = Character.digit(string.charAt(index++), 16);
68 int digit2 = Character.digit(string.charAt(index++), 16);
69 if ((digit1 < 0) || (digit2 < 0))
70 throw new IllegalArgumentException(FORMAT_ERROR + string);
71 raw |= ((long) (digit1 << 4 | digit2)) << shift;
Yotam Harcholf3f11152013-09-05 16:47:16 -070072
73 if (shift == 0)
74 break;
75 if (string.charAt(index++) != ':')
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070076 throw new IllegalArgumentException(FORMAT_ERROR + string);
Yotam Harcholf3f11152013-09-05 16:47:16 -070077 shift -= 8;
78 }
79 return MacAddress.of(raw);
80 }
81
Andreas Wundsam4e2469e2014-02-17 15:32:43 -080082 private volatile byte[] bytesCache = null;
Yotam Harcholf3f11152013-09-05 16:47:16 -070083
84 public byte[] getBytes() {
85 if (bytesCache == null) {
86 synchronized (this) {
87 if (bytesCache == null) {
88 bytesCache =
89 new byte[] { (byte) ((rawValue >> 40) & 0xFF),
90 (byte) ((rawValue >> 32) & 0xFF),
91 (byte) ((rawValue >> 24) & 0xFF),
92 (byte) ((rawValue >> 16) & 0xFF),
93 (byte) ((rawValue >> 8) & 0xFF),
94 (byte) ((rawValue >> 0) & 0xFF) };
95 }
96 }
97 }
Andreas Wundsam4e2469e2014-02-17 15:32:43 -080098 return bytesCache.clone();
Yotam Harcholf3f11152013-09-05 16:47:16 -070099 }
100
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -0700101 /**
102 * Returns {@code true} if the MAC address is the broadcast address.
103 * @return {@code true} if the MAC address is the broadcast address.
104 */
105 public boolean isBroadcast() {
106 return this == BROADCAST;
107 }
108
109 /**
110 * Returns {@code true} if the MAC address is a multicast address.
111 * @return {@code true} if the MAC address is a multicast address.
112 */
113 public boolean isMulticast() {
114 if (isBroadcast()) {
115 return false;
116 }
117 return (rawValue & (0x01L << 40)) != 0;
118 }
119
Shudong Zhoue5a36802014-02-09 14:54:14 -0800120 /**
Shudong Zhoua4fb4c62014-02-10 16:57:45 -0800121 * Returns {@code true} if the MAC address is an LLDP mac address.
122 * @return {@code true} if the MAC address is an LLDP mac address.
Shudong Zhoue5a36802014-02-09 14:54:14 -0800123 */
Shudong Zhoua4fb4c62014-02-10 16:57:45 -0800124 public boolean isLLDPAddress() {
125 return (rawValue & LLDP_MAC_ADDRESS_MASK) == LLDP_MAC_ADDRESS_VALUE;
Shudong Zhoue5a36802014-02-09 14:54:14 -0800126 }
127
Yotam Harcholf3f11152013-09-05 16:47:16 -0700128 @Override
129 public int getLength() {
130 return MacAddrLen;
131 }
132
133 @Override
134 public String toString() {
135 return HexString.toHexString(rawValue, 6);
136 }
137
138 @Override
139 public int hashCode() {
140 final int prime = 31;
141 int result = 1;
142 result = prime * result + (int) (rawValue ^ (rawValue >>> 32));
143 return result;
144 }
145
146 @Override
147 public boolean equals(final Object obj) {
148 if (this == obj)
149 return true;
150 if (obj == null)
151 return false;
152 if (getClass() != obj.getClass())
153 return false;
154 MacAddress other = (MacAddress) obj;
155 if (rawValue != other.rawValue)
156 return false;
157 return true;
158 }
159
160 public long getLong() {
161 return rawValue;
162 }
163
164 public void write6Bytes(ChannelBuffer c) {
165 c.writeInt((int) (this.rawValue >> 16));
166 c.writeShort((int) this.rawValue & 0xFFFF);
167 }
168
169 public static MacAddress read6Bytes(ChannelBuffer c) throws OFParseError {
170 long raw = c.readUnsignedInt() << 16 | c.readUnsignedShort();
171 return MacAddress.of(raw);
172 }
173
174 @Override
175 public MacAddress applyMask(MacAddress mask) {
176 return MacAddress.of(this.rawValue & mask.rawValue);
177 }
178
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700179 @Override
180 public int compareTo(MacAddress o) {
181 return Longs.compare(rawValue, o.rawValue);
182 }
183
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700184 @Override
185 public void putTo(PrimitiveSink sink) {
186 sink.putInt((int) (this.rawValue >> 16));
187 sink.putShort((short) (this.rawValue & 0xFFFF));
188 }
189
Yotam Harcholf3f11152013-09-05 16:47:16 -0700190
191
192}