Skip to content

Commit b23ceef

Browse files
authored
utils: cleanup MacAddress and MacAddressTest (#8988)
* utils: cleanup MacAddress and MacAddressTest Cleanup old mac address handling code to use JDK11 lib instead of hacks. Also really strange to see some basic string parsing code was written by hand, replaced with Long.parseValue(str, 16) to convert hex string to long. Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com> * address review comments Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com> --------- Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
1 parent 08132ac commit b23ceef

File tree

2 files changed

+40
-207
lines changed

2 files changed

+40
-207
lines changed

utils/src/main/java/com/cloud/utils/net/MacAddress.java

Lines changed: 33 additions & 200 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,19 @@
1919

2020
package com.cloud.utils.net;
2121

22-
import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable;
23-
24-
import java.io.BufferedReader;
25-
import java.io.File;
26-
import java.io.IOException;
27-
import java.io.InputStreamReader;
2822
import java.net.InetAddress;
23+
import java.net.NetworkInterface;
24+
import java.net.SocketException;
2925
import java.net.UnknownHostException;
26+
import java.util.Collections;
3027
import java.util.Formatter;
31-
32-
import org.apache.log4j.Logger;
28+
import java.util.List;
3329

3430
/**
3531
* This class retrieves the (first) MAC address for the machine is it is loaded on and stores it statically for retrieval.
3632
* It can also be used for formatting MAC addresses.
37-
* copied fnd addpeted rom the public domain utility from John Burkard.
3833
**/
3934
public class MacAddress {
40-
private static final Logger s_logger = Logger.getLogger(MacAddress.class);
4135
private long _addr = 0;
4236

4337
protected MacAddress() {
@@ -75,213 +69,52 @@ public String toString() {
7569
return toString(":");
7670
}
7771

78-
private static MacAddress s_address;
79-
static {
80-
String macAddress = null;
81-
82-
Process p = null;
83-
BufferedReader in = null;
72+
private static MacAddress macAddress;
8473

74+
static {
75+
String macString = null;
8576
try {
86-
String osname = System.getProperty("os.name");
87-
88-
if (osname.startsWith("Windows")) {
89-
p = Runtime.getRuntime().exec(new String[] {"ipconfig", "/all"}, null);
90-
} else if (osname.startsWith("Solaris") || osname.startsWith("SunOS")) {
91-
// Solaris code must appear before the generic code
92-
String hostName = MacAddress.getFirstLineOfCommand(new String[] {"uname", "-n"});
93-
if (hostName != null) {
94-
p = Runtime.getRuntime().exec(new String[] {"/usr/sbin/arp", hostName}, null);
95-
}
96-
} else if (new File("/usr/sbin/lanscan").exists()) {
97-
p = Runtime.getRuntime().exec(new String[] {"/usr/sbin/lanscan"}, null);
98-
} else if (new File("/sbin/ifconfig").exists()) {
99-
p = Runtime.getRuntime().exec(new String[] {"/sbin/ifconfig", "-a"}, null);
100-
}
101-
102-
if (p != null) {
103-
in = new BufferedReader(new InputStreamReader(p.getInputStream()), 128);
104-
String l = null;
105-
while ((l = in.readLine()) != null) {
106-
macAddress = MacAddress.parse(l);
107-
if (macAddress != null) {
108-
short parsedShortMacAddress = MacAddress.parseShort(macAddress);
109-
if (parsedShortMacAddress != 0xff && parsedShortMacAddress != 0x00)
110-
break;
77+
final List<NetworkInterface> nics = Collections.list(NetworkInterface.getNetworkInterfaces());
78+
Collections.reverse(nics);
79+
for (final NetworkInterface nic : nics) {
80+
final byte[] mac = nic.getHardwareAddress();
81+
if (mac != null &&
82+
!nic.isVirtual() &&
83+
!nic.isLoopback() &&
84+
!nic.getName().startsWith("br") &&
85+
!nic.getName().startsWith("veth") &&
86+
!nic.getName().startsWith("vnet")) {
87+
StringBuilder macAddressBuilder = new StringBuilder();
88+
for (byte b : mac) {
89+
macAddressBuilder.append(String.format("%02X", b));
11190
}
112-
macAddress = null;
91+
macString = macAddressBuilder.toString();
92+
break;
11393
}
11494
}
115-
116-
} catch (SecurityException ex) {
117-
s_logger.info("[ignored] security exception in static initializer of MacAddress", ex);
118-
} catch (IOException ex) {
119-
s_logger.info("[ignored] io exception in static initializer of MacAddress");
120-
} finally {
121-
if (p != null) {
122-
closeAutoCloseable(in, "closing init process input stream");
123-
closeAutoCloseable(p.getErrorStream(), "closing init process error output stream");
124-
closeAutoCloseable(p.getOutputStream(), "closing init process std output stream");
125-
p.destroy();
126-
}
95+
} catch (SocketException ignore) {
12796
}
12897

129-
long clockSeqAndNode = 0;
98+
long macAddressLong = 0;
13099

131-
if (macAddress != null) {
132-
if (macAddress.indexOf(':') != -1) {
133-
clockSeqAndNode |= MacAddress.parseLong(macAddress);
134-
} else if (macAddress.startsWith("0x")) {
135-
clockSeqAndNode |= MacAddress.parseLong(macAddress.substring(2));
136-
}
100+
if (macString != null) {
101+
macAddressLong = Long.parseLong(macString, 16);
137102
} else {
138103
try {
139104
byte[] local = InetAddress.getLocalHost().getAddress();
140-
clockSeqAndNode |= (local[0] << 24) & 0xFF000000L;
141-
clockSeqAndNode |= (local[1] << 16) & 0xFF0000;
142-
clockSeqAndNode |= (local[2] << 8) & 0xFF00;
143-
clockSeqAndNode |= local[3] & 0xFF;
105+
macAddressLong |= (local[0] << 24) & 0xFF000000L;
106+
macAddressLong |= (local[1] << 16) & 0xFF0000;
107+
macAddressLong |= (local[2] << 8) & 0xFF00;
108+
macAddressLong |= local[3] & 0xFF;
144109
} catch (UnknownHostException ex) {
145-
clockSeqAndNode |= (long)(Math.random() * 0x7FFFFFFF);
110+
macAddressLong |= (long)(Math.random() * 0x7FFFFFFF);
146111
}
147112
}
148113

149-
s_address = new MacAddress(clockSeqAndNode);
114+
MacAddress.macAddress = new MacAddress(macAddressLong);
150115
}
151116

152117
public static MacAddress getMacAddress() {
153-
return s_address;
154-
}
155-
156-
private static String getFirstLineOfCommand(String[] commands) throws IOException {
157-
158-
Process p = null;
159-
BufferedReader reader = null;
160-
161-
try {
162-
p = Runtime.getRuntime().exec(commands);
163-
reader = new BufferedReader(new InputStreamReader(p.getInputStream()), 128);
164-
165-
return reader.readLine();
166-
} finally {
167-
if (p != null) {
168-
closeAutoCloseable(reader, "closing process input stream");
169-
closeAutoCloseable(p.getErrorStream(), "closing process error output stream");
170-
closeAutoCloseable(p.getOutputStream(), "closing process std output stream");
171-
p.destroy();
172-
}
173-
}
174-
175-
}
176-
177-
/**
178-
* The MAC address parser attempts to find the following patterns:
179-
* <ul>
180-
* <li>.{1,2}:.{1,2}:.{1,2}:.{1,2}:.{1,2}:.{1,2}</li>
181-
* <li>.{1,2}-.{1,2}-.{1,2}-.{1,2}-.{1,2}-.{1,2}</li>
182-
* </ul>
183-
*
184-
* This is copied from the author below. The author encouraged copying
185-
* it.
186-
*
187-
*/
188-
static String parse(String in) {
189-
190-
// lanscan
191-
192-
int hexStart = in.indexOf("0x");
193-
if (hexStart != -1) {
194-
int hexEnd = in.indexOf(' ', hexStart);
195-
if (hexEnd != -1) {
196-
return in.substring(hexStart, hexEnd);
197-
}
198-
}
199-
200-
int octets = 0;
201-
int lastIndex, old, end;
202-
203-
if (in.indexOf('-') > -1) {
204-
in = in.replace('-', ':');
205-
}
206-
207-
lastIndex = in.lastIndexOf(':');
208-
209-
if (lastIndex > in.length() - 2)
210-
return null;
211-
212-
end = Math.min(in.length(), lastIndex + 3);
213-
214-
++octets;
215-
old = lastIndex;
216-
while (octets != 5 && lastIndex != -1 && lastIndex > 1) {
217-
lastIndex = in.lastIndexOf(':', --lastIndex);
218-
if (old - lastIndex == 3 || old - lastIndex == 2) {
219-
++octets;
220-
old = lastIndex;
221-
}
222-
}
223-
224-
if (octets == 5 && lastIndex > 1) {
225-
return in.substring(lastIndex - 2, end).trim();
226-
}
227-
return null;
228-
}
229-
230-
/**
231-
* Parses a <code>long</code> from a hex encoded number. This method will skip
232-
* all characters that are not 0-9 and a-f (the String is lower cased first).
233-
* Returns 0 if the String does not contain any interesting characters.
234-
*
235-
* @param s the String to extract a <code>long</code> from, may not be <code>null</code>
236-
* @return a <code>long</code>
237-
* @throws NullPointerException if the String is <code>null</code>
238-
*/
239-
private static long parseLong(String s) throws NullPointerException {
240-
s = s.toLowerCase();
241-
long out = 0;
242-
byte shifts = 0;
243-
char c;
244-
for (int i = 0; i < s.length() && shifts < 16; i++) {
245-
c = s.charAt(i);
246-
if ((c > 47) && (c < 58)) {
247-
out <<= 4;
248-
++shifts;
249-
out |= c - 48;
250-
} else if ((c > 96) && (c < 103)) {
251-
++shifts;
252-
out <<= 4;
253-
out |= c - 87;
254-
}
255-
}
256-
return out;
257-
}
258-
259-
/**
260-
* Parses a <code>short</code> from a hex encoded number. This method will skip
261-
* all characters that are not 0-9 and a-f (the String is lower cased first).
262-
* Returns 0 if the String does not contain any interesting characters.
263-
*
264-
* @param s the String to extract a <code>short</code> from, may not be <code>null</code>
265-
* @return a <code>short</code>
266-
* @throws NullPointerException if the String is <code>null</code>
267-
*/
268-
private static short parseShort(String s) throws NullPointerException {
269-
s = s.toLowerCase();
270-
short out = 0;
271-
byte shifts = 0;
272-
char c;
273-
for (int i = 0; i < s.length() && shifts < 4; i++) {
274-
c = s.charAt(i);
275-
if ((c > 47) && (c < 58)) {
276-
out <<= 4;
277-
++shifts;
278-
out |= c - 48;
279-
} else if ((c > 96) && (c < 103)) {
280-
++shifts;
281-
out <<= 4;
282-
out |= c - 87;
283-
}
284-
}
285-
return out;
118+
return macAddress;
286119
}
287120
}

utils/src/test/java/com/cloud/utils/net/MacAddressTest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ public final void testMacAddressLong() throws Exception {
4141
public final void testMacAddressToLong() throws Exception {
4242
// TODO this test should fail this address is beyond the acceptable range for macaddresses
4343
MacAddress mac = new MacAddress(Long.MAX_VALUE);
44-
assertEquals(Long.MAX_VALUE,mac.toLong());
44+
assertEquals(Long.MAX_VALUE, mac.toLong());
4545
System.out.println(mac.toString());
4646
}
4747

48-
// TODO public final void testToLong() throws Exception {
49-
// TODO public final void testToByteArray() throws Exception {
50-
// TODO public final void testToStringString() throws Exception {
51-
// TODO public final void testToString() throws Exception {
52-
// TODO public final void testGetMacAddress() throws Exception {
53-
// TODO public final void testParse() throws Exception {
48+
@Test
49+
public final void testSpecificMacAddress() throws Exception {
50+
// Test specific mac address 76:3F:76:EB:02:81
51+
MacAddress mac = new MacAddress(130014950130305L);
52+
assertEquals("76:3f:76:eb:02:81", mac.toString());
53+
}
5454
}

0 commit comments

Comments
 (0)