Skip to content
Snippets Groups Projects
Commit ae0906a7 authored by Sho SHIMIZU's avatar Sho SHIMIZU
Browse files

Add a class representing MAC address and use it in the Ethernet class.

parent 86d856be
No related branches found
No related tags found
No related merge requests found
...@@ -22,6 +22,7 @@ import java.util.Arrays; ...@@ -22,6 +22,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import net.floodlightcontroller.util.MACAddress;
import org.openflow.util.HexString; import org.openflow.util.HexString;
/** /**
...@@ -29,7 +30,6 @@ import org.openflow.util.HexString; ...@@ -29,7 +30,6 @@ import org.openflow.util.HexString;
* @author David Erickson (daviderickson@cs.stanford.edu) * @author David Erickson (daviderickson@cs.stanford.edu)
*/ */
public class Ethernet extends BasePacket { public class Ethernet extends BasePacket {
private static String HEXES = "0123456789ABCDEF";
public static final short TYPE_ARP = 0x0806; public static final short TYPE_ARP = 0x0806;
public static final short TYPE_IPv4 = 0x0800; public static final short TYPE_IPv4 = 0x0800;
public static final short TYPE_LLDP = (short) 0x88cc; public static final short TYPE_LLDP = (short) 0x88cc;
...@@ -43,8 +43,8 @@ public class Ethernet extends BasePacket { ...@@ -43,8 +43,8 @@ public class Ethernet extends BasePacket {
etherTypeClassMap.put(TYPE_LLDP, LLDP.class); etherTypeClassMap.put(TYPE_LLDP, LLDP.class);
} }
protected byte[] destinationMACAddress; protected MACAddress destinationMACAddress;
protected byte[] sourceMACAddress; protected MACAddress sourceMACAddress;
protected byte priorityCode; protected byte priorityCode;
protected short vlanID; protected short vlanID;
protected short etherType; protected short etherType;
...@@ -62,14 +62,14 @@ public class Ethernet extends BasePacket { ...@@ -62,14 +62,14 @@ public class Ethernet extends BasePacket {
* @return the destinationMACAddress * @return the destinationMACAddress
*/ */
public byte[] getDestinationMACAddress() { public byte[] getDestinationMACAddress() {
return destinationMACAddress; return destinationMACAddress.toBytes();
} }
/** /**
* @param destinationMACAddress the destinationMACAddress to set * @param destinationMACAddress the destinationMACAddress to set
*/ */
public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) { public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) {
this.destinationMACAddress = destinationMACAddress; this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
return this; return this;
} }
...@@ -77,8 +77,7 @@ public class Ethernet extends BasePacket { ...@@ -77,8 +77,7 @@ public class Ethernet extends BasePacket {
* @param destinationMACAddress the destinationMACAddress to set * @param destinationMACAddress the destinationMACAddress to set
*/ */
public Ethernet setDestinationMACAddress(String destinationMACAddress) { public Ethernet setDestinationMACAddress(String destinationMACAddress) {
this.destinationMACAddress = Ethernet this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
.toMACAddress(destinationMACAddress);
return this; return this;
} }
...@@ -86,14 +85,14 @@ public class Ethernet extends BasePacket { ...@@ -86,14 +85,14 @@ public class Ethernet extends BasePacket {
* @return the sourceMACAddress * @return the sourceMACAddress
*/ */
public byte[] getSourceMACAddress() { public byte[] getSourceMACAddress() {
return sourceMACAddress; return sourceMACAddress.toBytes();
} }
/** /**
* @param sourceMACAddress the sourceMACAddress to set * @param sourceMACAddress the sourceMACAddress to set
*/ */
public Ethernet setSourceMACAddress(byte[] sourceMACAddress) { public Ethernet setSourceMACAddress(byte[] sourceMACAddress) {
this.sourceMACAddress = sourceMACAddress; this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
return this; return this;
} }
...@@ -101,7 +100,7 @@ public class Ethernet extends BasePacket { ...@@ -101,7 +100,7 @@ public class Ethernet extends BasePacket {
* @param sourceMACAddress the sourceMACAddress to set * @param sourceMACAddress the sourceMACAddress to set
*/ */
public Ethernet setSourceMACAddress(String sourceMACAddress) { public Ethernet setSourceMACAddress(String sourceMACAddress) {
this.sourceMACAddress = Ethernet.toMACAddress(sourceMACAddress); this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
return this; return this;
} }
...@@ -154,22 +153,15 @@ public class Ethernet extends BasePacket { ...@@ -154,22 +153,15 @@ public class Ethernet extends BasePacket {
* @return True if the Ethernet frame is broadcast, false otherwise * @return True if the Ethernet frame is broadcast, false otherwise
*/ */
public boolean isBroadcast() { public boolean isBroadcast() {
assert(destinationMACAddress.length == 6); assert(destinationMACAddress.length() == 6);
for (byte b : destinationMACAddress) { return destinationMACAddress.isBroadcast();
if (b != -1) // checks if equal to 0xff
return false;
}
return true;
} }
/** /**
* @return True is the Ethernet frame is multicast, False otherwise * @return True is the Ethernet frame is multicast, False otherwise
*/ */
public boolean isMulticast() { public boolean isMulticast() {
if (this.isBroadcast()) { return destinationMACAddress.isMulticast();
return false;
}
return (destinationMACAddress[0] & 0x01) != 0;
} }
/** /**
* Pad this packet to 60 bytes minimum, filling with zeros? * Pad this packet to 60 bytes minimum, filling with zeros?
...@@ -201,8 +193,8 @@ public class Ethernet extends BasePacket { ...@@ -201,8 +193,8 @@ public class Ethernet extends BasePacket {
} }
byte[] data = new byte[length]; byte[] data = new byte[length];
ByteBuffer bb = ByteBuffer.wrap(data); ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(destinationMACAddress); bb.put(destinationMACAddress.toBytes());
bb.put(sourceMACAddress); bb.put(sourceMACAddress.toBytes());
if (vlanID != VLAN_UNTAGGED) { if (vlanID != VLAN_UNTAGGED) {
bb.putShort((short) 0x8100); bb.putShort((short) 0x8100);
bb.putShort((short) ((priorityCode << 13) | (vlanID & 0x0fff))); bb.putShort((short) ((priorityCode << 13) | (vlanID & 0x0fff)));
...@@ -220,12 +212,16 @@ public class Ethernet extends BasePacket { ...@@ -220,12 +212,16 @@ public class Ethernet extends BasePacket {
public IPacket deserialize(byte[] data, int offset, int length) { public IPacket deserialize(byte[] data, int offset, int length) {
ByteBuffer bb = ByteBuffer.wrap(data, offset, length); ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
if (this.destinationMACAddress == null) if (this.destinationMACAddress == null)
this.destinationMACAddress = new byte[6]; this.destinationMACAddress = MACAddress.valueOf(new byte[6]);
bb.get(this.destinationMACAddress); byte[] dstAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
bb.get(dstAddr);
this.destinationMACAddress = MACAddress.valueOf(dstAddr);
if (this.sourceMACAddress == null) if (this.sourceMACAddress == null)
this.sourceMACAddress = new byte[6]; this.sourceMACAddress = MACAddress.valueOf(new byte[6]);
bb.get(this.sourceMACAddress); byte[] srcAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
bb.get(srcAddr);
this.sourceMACAddress = MACAddress.valueOf(srcAddr);
short etherType = bb.getShort(); short etherType = bb.getShort();
if (etherType == (short) 0x8100) { if (etherType == (short) 0x8100) {
...@@ -254,20 +250,6 @@ public class Ethernet extends BasePacket { ...@@ -254,20 +250,6 @@ public class Ethernet extends BasePacket {
return this; return this;
} }
public static boolean isMACAddress(String macAddress) {
String[] macBytes = macAddress.split(":");
if (macBytes.length != 6)
return false;
for (int i = 0; i < 6; ++i) {
if (HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1 ||
HEXES.indexOf(macBytes[i].toUpperCase().charAt(1)) == -1) {
return false;
}
}
return true;
}
/** /**
* Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
* matter, and returns a corresponding byte[]. * matter, and returns a corresponding byte[].
...@@ -275,24 +257,10 @@ public class Ethernet extends BasePacket { ...@@ -275,24 +257,10 @@ public class Ethernet extends BasePacket {
* @return * @return
*/ */
public static byte[] toMACAddress(String macAddress) { public static byte[] toMACAddress(String macAddress) {
byte[] address = new byte[6]; return MACAddress.valueOf(macAddress).toBytes();
if (!Ethernet.isMACAddress(macAddress)) {
throw new IllegalArgumentException(
"Specified MAC Address must contain 12 hex digits" +
" separated pairwise by :'s.");
}
String[] macBytes = macAddress.split(":");
for (int i = 0; i < 6; ++i) {
address[i] = (byte) ((HEXES.indexOf(macBytes[i].toUpperCase()
.charAt(0)) << 4) | HEXES.indexOf(macBytes[i].toUpperCase()
.charAt(1)));
}
return address;
} }
/** /**
* Accepts a MAC address and returns the corresponding long, where the * Accepts a MAC address and returns the corresponding long, where the
* MAC bytes are set on the lower order bytes of the long. * MAC bytes are set on the lower order bytes of the long.
...@@ -300,28 +268,16 @@ public class Ethernet extends BasePacket { ...@@ -300,28 +268,16 @@ public class Ethernet extends BasePacket {
* @return a long containing the mac address bytes * @return a long containing the mac address bytes
*/ */
public static long toLong(byte[] macAddress) { public static long toLong(byte[] macAddress) {
long mac = 0; return MACAddress.valueOf(macAddress).toLong();
for (int i = 0; i < 6; i++) {
long t = (macAddress[i] & 0xffL) << ((5-i)*8);
mac |= t;
}
return mac;
} }
/** /**
* Convert a long MAC address to a byte array * Convert a long MAC address to a byte array
* @param macAddress * @param macAddress
* @return the bytes of the mac address * @return the bytes of the mac address
*/ */
public static byte[] toByteArray(long macAddress) { public static byte[] toByteArray(long macAddress) {
return new byte[] { return MACAddress.valueOf(macAddress).toBytes();
(byte)((macAddress >> 40) & 0xff),
(byte)((macAddress >> 32) & 0xff),
(byte)((macAddress >> 24) & 0xff),
(byte)((macAddress >> 16) & 0xff),
(byte)((macAddress >> 8 ) & 0xff),
(byte)((macAddress >> 0) & 0xff)
};
} }
/* (non-Javadoc) /* (non-Javadoc)
...@@ -331,10 +287,10 @@ public class Ethernet extends BasePacket { ...@@ -331,10 +287,10 @@ public class Ethernet extends BasePacket {
public int hashCode() { public int hashCode() {
final int prime = 7867; final int prime = 7867;
int result = super.hashCode(); int result = super.hashCode();
result = prime * result + Arrays.hashCode(destinationMACAddress); result = prime * result + destinationMACAddress.hashCode();
result = prime * result + etherType; result = prime * result + etherType;
result = prime * result + (pad ? 1231 : 1237); result = prime * result + (pad ? 1231 : 1237);
result = prime * result + Arrays.hashCode(sourceMACAddress); result = prime * result + sourceMACAddress.hashCode();
return result; return result;
} }
...@@ -350,7 +306,7 @@ public class Ethernet extends BasePacket { ...@@ -350,7 +306,7 @@ public class Ethernet extends BasePacket {
if (!(obj instanceof Ethernet)) if (!(obj instanceof Ethernet))
return false; return false;
Ethernet other = (Ethernet) obj; Ethernet other = (Ethernet) obj;
if (!Arrays.equals(destinationMACAddress, other.destinationMACAddress)) if (!destinationMACAddress.equals(other.destinationMACAddress))
return false; return false;
if (priorityCode != other.priorityCode) if (priorityCode != other.priorityCode)
return false; return false;
...@@ -360,7 +316,7 @@ public class Ethernet extends BasePacket { ...@@ -360,7 +316,7 @@ public class Ethernet extends BasePacket {
return false; return false;
if (pad != other.pad) if (pad != other.pad)
return false; return false;
if (!Arrays.equals(sourceMACAddress, other.sourceMACAddress)) if (!sourceMACAddress.equals(other.sourceMACAddress))
return false; return false;
return true; return true;
} }
......
package net.floodlightcontroller.util;
import java.util.Arrays;
/**
* The class representing MAC address.
*
* @author Sho Shimizu (sho.shimizu@gmail.com)
*/
public class MACAddress {
public static final int MAC_ADDRESS_LENGTH = 6;
private byte[] address = new byte[MAC_ADDRESS_LENGTH];
private MACAddress(byte[] address) {
this.address = Arrays.copyOf(address, MAC_ADDRESS_LENGTH);
}
/**
* Reteruns a MAC address instance representing the value of the specified {@code String}.
* @param address the String representation of the MAC Address to be parsed.
* @return a MAC Address instance representing the value of the specified {@code String}.
* @throws IllegalArgumentException if the string cannot be parsed as a MAC address.
*/
public static MACAddress valueOf(String address) {
String[] elements = address.split(":");
if (elements.length != MAC_ADDRESS_LENGTH) {
throw new IllegalArgumentException(
"Specified MAC Address must contain 12 hex digits" +
" separated pairwise by :'s.");
}
byte[] addressInBytes = new byte[MAC_ADDRESS_LENGTH];
for (int i = 0; i < MAC_ADDRESS_LENGTH; i++) {
String element = elements[i];
addressInBytes[i] = (byte)Integer.parseInt(element, 16);
}
return new MACAddress(addressInBytes);
}
/**
* Returns a MAC address instance representing the specified {@code byte} array.
* @param address the byte array to be parsed.
* @return a MAC address instance representing the specified {@code byte} array.
* @throws IllegalArgumentException if the byte array cannot be parsed as a MAC address.
*/
public static MACAddress valueOf(byte[] address) {
if (address.length != MAC_ADDRESS_LENGTH) {
throw new IllegalArgumentException("the length is not " + MAC_ADDRESS_LENGTH);
}
return new MACAddress(address);
}
/**
* Returns a MAC address instance representing the specified {@code long} value.
* The lower 48 bits of the long value are used to parse as a MAC address.
* @param address the long value to be parsed. The lower 48 bits are used for a MAC address.
* @return a MAC address instance representing the specified {@code long} value.
* @throws IllegalArgumentException if the long value cannot be parsed as a MAC address.
*/
public static MACAddress valueOf(long address) {
byte[] addressInBytes = new byte[] {
(byte)((address >> 40) & 0xff),
(byte)((address >> 32) & 0xff),
(byte)((address >> 24) & 0xff),
(byte)((address >> 16) & 0xff),
(byte)((address >> 8 ) & 0xff),
(byte)((address >> 0) & 0xff)
};
return new MACAddress(addressInBytes);
}
/**
* Returns the length of the {@code MACAddress}.
* @return the length of the {@code MACAddress}.
*/
public int length() {
return address.length;
}
/**
* Returns the value of the {@code MACAddress} as a {@code byte} array.
* @return the numeric value represented by this object after conversion to type {@code byte} array.
*/
public byte[] toBytes() {
return Arrays.copyOf(address, address.length);
}
/**
* Returns the value of the {@code MACAddress} as a {@code long}.
* @return the numeric value represented by this object after conversion to type {@code long}.
*/
public long toLong() {
long mac = 0;
for (int i = 0; i < 6; i++) {
long t = (address[i] & 0xffL) << ((5 - i) * 8);
mac |= t;
}
return mac;
}
/**
* Returns {@code true} if the MAC address is the broadcast address.
* @return {@code true} if the MAC address is the broadcast address.
*/
public boolean isBroadcast() {
for (byte b : address) {
if (b != -1) // checks if equal to 0xff
return false;
}
return true;
}
/**
* Returns {@code true} if the MAC address is the multicast address.
* @return {@code true} if the MAC address is the multicast address.
*/
public boolean isMulticast() {
if (isBroadcast()) {
return false;
}
return (address[0] & 0x01) != 0;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof MACAddress)) {
return false;
}
MACAddress other = (MACAddress)o;
return Arrays.equals(this.address, other.address);
}
@Override
public int hashCode() {
return Arrays.hashCode(this.address);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
for (byte b: address) {
if (builder.length() > 0) {
builder.append(":");
}
builder.append(String.format("%02X", b & 0xFF));
}
return builder.toString();
}
}
package net.floodlightcontroller.util;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* @author Sho Shimizu (sho.shimizu@gmail.com)
*/
public class MACAddressTest {
@Test
public void testValueOf() {
MACAddress address = MACAddress.valueOf("00:01:02:03:04:05");
assertEquals(address,
MACAddress.valueOf(new byte[]{0x00, 0x01, 0x02, 0x03, 0x04, 0x05}));
assertEquals("00:01:02:03:04:05", address.toString());
address = MACAddress.valueOf("FF:FE:FD:10:20:30");
assertEquals(address,
MACAddress.valueOf(new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0xFD, 0x10, 0x20, 0x30}));
assertEquals("FF:FE:FD:10:20:30", address.toString());
address = MACAddress.valueOf("00:11:22:aa:bb:cc");
assertEquals(address,
MACAddress.valueOf(new byte[]{0x00, 0x11, 0x22, (byte)0xaa, (byte)0xbb, (byte)0xcc}));
}
@Test(expected=NumberFormatException.class)
public void testIllegalFormat() {
MACAddress address = MACAddress.valueOf("0T:00:01:02:03:04");
}
@Test(expected=IllegalArgumentException.class)
public void testLongStringFields() {
MACAddress address = MACAddress.valueOf("00:01:02:03:04:05:06");
}
@Test(expected=IllegalArgumentException.class)
public void testShortStringFields() {
MACAddress address = MACAddress.valueOf("00:01:02:03:04");
}
@Test(expected=IllegalArgumentException.class)
public void testLongByteFields() {
MACAddress address = MACAddress.valueOf(new byte[]{0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
}
@Test(expected=IllegalArgumentException.class)
public void testShortByteField() {
MACAddress address = MACAddress.valueOf(new byte[]{0x01, 0x01, 0x02, 0x03, 0x04});
}
// Test data is imported from net.floodlightcontroller.packet.EthernetTest
@Test
public void testToLong() {
assertEquals(
281474976710655L,
MACAddress.valueOf(new byte[]{(byte) 0xff, (byte) 0xff,
(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff}).toLong());
assertEquals(
1103823438081L,
MACAddress.valueOf(new byte[] { (byte) 0x01, (byte) 0x01,
(byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x01 }).toLong());
assertEquals(
141289400074368L,
MACAddress.valueOf(new byte[] { (byte) 0x80, (byte) 0x80,
(byte) 0x80, (byte) 0x80, (byte) 0x80, (byte) 0x80 }).toLong());
}
@Test
public void testIsBroadcast() {
assertTrue(MACAddress.valueOf("FF:FF:FF:FF:FF:FF").isBroadcast());
assertFalse(MACAddress.valueOf("11:22:33:44:55:66").isBroadcast());
}
@Test
public void testIsMulticast() {
assertTrue(MACAddress.valueOf("01:80:C2:00:00:00").isMulticast());
assertFalse(MACAddress.valueOf("FF:FF:FF:FF:FF:FF").isMulticast());
assertFalse(MACAddress.valueOf("11:22:33:44:55:66").isBroadcast());
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment