blob: 009dae56bd62ca15eeba652bc4d89d709381983f [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 Wundsam85c961f2013-09-29 21:22:12 -07007import com.google.common.primitives.Longs;
8
Yotam Harcholf3f11152013-09-05 16:47:16 -07009/**
10 * Wrapper around a 6 byte mac address.
11 *
12 * @author Andreas Wundsam <andreas.wundsam@bigswitch.com>
13 */
14
15public class MacAddress implements OFValueType<MacAddress> {
16 static final int MacAddrLen = 6;
17 private final long rawValue;
18
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070019 private final static long NONE_VAL = 0x0L;
20 public static final MacAddress NONE = new MacAddress(NONE_VAL);
21
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070022 private final static long BROADCAST_VAL = 0x0000FFFFFFFFFFFFL;
23 public static final MacAddress BROADCAST = new MacAddress(BROADCAST_VAL);
24
Yotam Harcholf3f11152013-09-05 16:47:16 -070025 public static final MacAddress NO_MASK = MacAddress.of(0xFFFFFFFFFFFFFFFFl);
26 public static final MacAddress FULL_MASK = MacAddress.of(0x0);
27
28 private MacAddress(final long rawValue) {
29 this.rawValue = rawValue;
30 }
31
32 public static MacAddress of(final byte[] address) {
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070033 if (address.length != MacAddrLen)
34 throw new IllegalArgumentException(
35 "Mac address byte array must be exactly 6 bytes long; length = " + address.length);
Yotam Harcholf3f11152013-09-05 16:47:16 -070036 long raw =
37 (address[0] & 0xFFL) << 40 | (address[1] & 0xFFL) << 32
38 | (address[2] & 0xFFL) << 24 | (address[3] & 0xFFL) << 16
39 | (address[4] & 0xFFL) << 8 | (address[5] & 0xFFL);
40 return MacAddress.of(raw);
41 }
42
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070043 public static MacAddress of(long raw) {
44 raw &= BROADCAST_VAL;
Andreas Wundsamb75c4ad2013-09-23 14:45:35 -070045 if(raw == NONE_VAL)
46 return NONE;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070047 if (raw == BROADCAST_VAL)
48 return BROADCAST;
Yotam Harcholf3f11152013-09-05 16:47:16 -070049 return new MacAddress(raw);
50 }
51
52 public static MacAddress of(final String string) {
53 int index = 0;
54 int shift = 40;
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070055 final String FORMAT_ERROR = "Mac address is not well-formed. " +
56 "It must consist of 6 hex digit pairs separated by colons: ";
Yotam Harcholf3f11152013-09-05 16:47:16 -070057
58 long raw = 0;
59 if (string.length() != 6 * 2 + 5)
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070060 throw new IllegalArgumentException(FORMAT_ERROR + string);
Yotam Harcholf3f11152013-09-05 16:47:16 -070061
62 while (shift >= 0) {
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070063 int digit1 = Character.digit(string.charAt(index++), 16);
64 int digit2 = Character.digit(string.charAt(index++), 16);
65 if ((digit1 < 0) || (digit2 < 0))
66 throw new IllegalArgumentException(FORMAT_ERROR + string);
67 raw |= ((long) (digit1 << 4 | digit2)) << shift;
Yotam Harcholf3f11152013-09-05 16:47:16 -070068
69 if (shift == 0)
70 break;
71 if (string.charAt(index++) != ':')
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070072 throw new IllegalArgumentException(FORMAT_ERROR + string);
Yotam Harcholf3f11152013-09-05 16:47:16 -070073 shift -= 8;
74 }
75 return MacAddress.of(raw);
76 }
77
78 volatile byte[] bytesCache = null;
79
80 public byte[] getBytes() {
81 if (bytesCache == null) {
82 synchronized (this) {
83 if (bytesCache == null) {
84 bytesCache =
85 new byte[] { (byte) ((rawValue >> 40) & 0xFF),
86 (byte) ((rawValue >> 32) & 0xFF),
87 (byte) ((rawValue >> 24) & 0xFF),
88 (byte) ((rawValue >> 16) & 0xFF),
89 (byte) ((rawValue >> 8) & 0xFF),
90 (byte) ((rawValue >> 0) & 0xFF) };
91 }
92 }
93 }
94 return bytesCache;
95 }
96
Rob Vaterlaus83f40ab2013-10-14 15:44:46 -070097 /**
98 * Returns {@code true} if the MAC address is the broadcast address.
99 * @return {@code true} if the MAC address is the broadcast address.
100 */
101 public boolean isBroadcast() {
102 return this == BROADCAST;
103 }
104
105 /**
106 * Returns {@code true} if the MAC address is a multicast address.
107 * @return {@code true} if the MAC address is a multicast address.
108 */
109 public boolean isMulticast() {
110 if (isBroadcast()) {
111 return false;
112 }
113 return (rawValue & (0x01L << 40)) != 0;
114 }
115
Yotam Harcholf3f11152013-09-05 16:47:16 -0700116 @Override
117 public int getLength() {
118 return MacAddrLen;
119 }
120
121 @Override
122 public String toString() {
123 return HexString.toHexString(rawValue, 6);
124 }
125
126 @Override
127 public int hashCode() {
128 final int prime = 31;
129 int result = 1;
130 result = prime * result + (int) (rawValue ^ (rawValue >>> 32));
131 return result;
132 }
133
134 @Override
135 public boolean equals(final Object obj) {
136 if (this == obj)
137 return true;
138 if (obj == null)
139 return false;
140 if (getClass() != obj.getClass())
141 return false;
142 MacAddress other = (MacAddress) obj;
143 if (rawValue != other.rawValue)
144 return false;
145 return true;
146 }
147
148 public long getLong() {
149 return rawValue;
150 }
151
152 public void write6Bytes(ChannelBuffer c) {
153 c.writeInt((int) (this.rawValue >> 16));
154 c.writeShort((int) this.rawValue & 0xFFFF);
155 }
156
157 public static MacAddress read6Bytes(ChannelBuffer c) throws OFParseError {
158 long raw = c.readUnsignedInt() << 16 | c.readUnsignedShort();
159 return MacAddress.of(raw);
160 }
161
162 @Override
163 public MacAddress applyMask(MacAddress mask) {
164 return MacAddress.of(this.rawValue & mask.rawValue);
165 }
166
Andreas Wundsam85c961f2013-09-29 21:22:12 -0700167 @Override
168 public int compareTo(MacAddress o) {
169 return Longs.compare(rawValue, o.rawValue);
170 }
171
Yotam Harcholf3f11152013-09-05 16:47:16 -0700172
173
174}