Support IP deserialization when PACKET_IN carries Ethernet FCS
Some switches carry Ethernet FCS in the PACKET_IN.
In that case, Ethernet FCS should not be treated as IP payload.
payload length: the length specified in IP header
remaining length: the actual remaining bytes
payload < remaining: padding or Ethernet FCS exists, use payload length
payload = remaining: usual case, use either one
payload > remaining: fragmented packets, use remaining length
In addition,
- Fix unit test. TotalLen should never be smaller than headerLen * 4
- Refactoring unit tests
Change-Id: I5d4736ad89ea2ab4ac3bd0cfaeb91da5d974db64
diff --git a/utils/misc/src/main/java/org/onlab/packet/IPv4.java b/utils/misc/src/main/java/org/onlab/packet/IPv4.java
index ac27918..b8b58bc 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IPv4.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IPv4.java
@@ -709,8 +709,12 @@
} else {
deserializer = Data.deserializer();
}
- ipv4.payload = deserializer.deserialize(data, bb.position(),
- bb.limit() - bb.position());
+
+ int remainingLength = bb.limit() - bb.position();
+ int payloadLength = ipv4.totalLength - ipv4.headerLength * 4;
+ int bytesToRead = (payloadLength <= remainingLength) ?
+ payloadLength : remainingLength;
+ ipv4.payload = deserializer.deserialize(data, bb.position(), bytesToRead);
ipv4.payload.setParent(ipv4);
if (ipv4.totalLength != length) {
diff --git a/utils/misc/src/main/java/org/onlab/packet/IPv6.java b/utils/misc/src/main/java/org/onlab/packet/IPv6.java
index e88998d..d1eb4f0 100644
--- a/utils/misc/src/main/java/org/onlab/packet/IPv6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/IPv6.java
@@ -367,8 +367,12 @@
} else {
deserializer = Data.deserializer();
}
- ipv6.payload = deserializer.deserialize(data, bb.position(),
- bb.limit() - bb.position());
+
+ int remainingLength = bb.limit() - bb.position();
+ int payloadLength = ipv6.payloadLength;
+ int bytesToRead = (payloadLength <= remainingLength) ?
+ payloadLength : remainingLength;
+ ipv6.payload = deserializer.deserialize(data, bb.position(), bytesToRead);
ipv6.payload.setParent(ipv6);
return ipv6;
diff --git a/utils/misc/src/test/java/org/onlab/packet/IPv4Test.java b/utils/misc/src/test/java/org/onlab/packet/IPv4Test.java
index 83c474e..21acdb0 100644
--- a/utils/misc/src/test/java/org/onlab/packet/IPv4Test.java
+++ b/utils/misc/src/test/java/org/onlab/packet/IPv4Test.java
@@ -30,21 +30,21 @@
*/
public class IPv4Test {
- private Deserializer<IPv4> deserializer;
+ private static Deserializer<IPv4> deserializer;
- private byte version = 4;
- private byte headerLength = 6;
- private byte diffServ = 2;
- private short totalLength = 20;
- private short identification = 1;
- private byte flags = 1;
- private short fragmentOffset = 1;
- private byte ttl = 60;
- private byte protocol = 4;
- private short checksum = 4;
- private int sourceAddress = 1;
- private int destinationAddress = 2;
- private byte[] options = new byte[] {0x1, 0x2, 0x3, 0x4};
+ private static final byte VERSION = 4;
+ private static final byte HEADER_LENGTH = 6;
+ private static final byte DIFF_SERV = 2;
+ private static final short TOTAL_LENGTH = 60;
+ private static final short IDENTIFICATION = 1;
+ private static final byte FLAGS = 1;
+ private static final short FRAGMENT_OFFSET = 1;
+ private static final byte TTL = 60;
+ private static final byte PROTOCOL = 4;
+ private static final short CHECKSUM = 4;
+ private static final int SOURCE_ADDRESS = 1;
+ private static final int DESTINATION_ADDRESS = 2;
+ private static final byte[] OPTIONS = new byte[] {0x1, 0x2, 0x3, 0x4};
private byte[] headerBytes;
@@ -52,19 +52,19 @@
public void setUp() throws Exception {
deserializer = IPv4.deserializer();
- ByteBuffer bb = ByteBuffer.allocate(headerLength * 4);
+ ByteBuffer bb = ByteBuffer.allocate(HEADER_LENGTH * 4);
- bb.put((byte) ((version & 0xf) << 4 | headerLength & 0xf));
- bb.put(diffServ);
- bb.putShort(totalLength);
- bb.putShort(identification);
- bb.putShort((short) ((flags & 0x7) << 13 | fragmentOffset & 0x1fff));
- bb.put(ttl);
- bb.put(protocol);
- bb.putShort(checksum);
- bb.putInt(sourceAddress);
- bb.putInt(destinationAddress);
- bb.put(options);
+ bb.put((byte) ((VERSION & 0xf) << 4 | HEADER_LENGTH & 0xf));
+ bb.put(DIFF_SERV);
+ bb.putShort(TOTAL_LENGTH);
+ bb.putShort(IDENTIFICATION);
+ bb.putShort((short) ((FLAGS & 0x7) << 13 | FRAGMENT_OFFSET & 0x1fff));
+ bb.put(TTL);
+ bb.put(PROTOCOL);
+ bb.putShort(CHECKSUM);
+ bb.putInt(SOURCE_ADDRESS);
+ bb.putInt(DESTINATION_ADDRESS);
+ bb.put(OPTIONS);
headerBytes = bb.array();
}
@@ -86,18 +86,18 @@
public void testDeserialize() throws Exception {
IPv4 ipv4 = deserializer.deserialize(headerBytes, 0, headerBytes.length);
- assertEquals(version, ipv4.getVersion());
- assertEquals(headerLength, ipv4.getHeaderLength());
- assertEquals(diffServ, ipv4.getDiffServ());
- assertEquals(totalLength, ipv4.getTotalLength());
- assertEquals(identification, ipv4.getIdentification());
- assertEquals(flags, ipv4.getFlags());
- assertEquals(fragmentOffset, ipv4.getFragmentOffset());
- assertEquals(ttl, ipv4.getTtl());
- assertEquals(protocol, ipv4.getProtocol());
- assertEquals(checksum, ipv4.getChecksum());
- assertEquals(sourceAddress, ipv4.getSourceAddress());
- assertEquals(destinationAddress, ipv4.getDestinationAddress());
+ assertEquals(VERSION, ipv4.getVersion());
+ assertEquals(HEADER_LENGTH, ipv4.getHeaderLength());
+ assertEquals(DIFF_SERV, ipv4.getDiffServ());
+ assertEquals(TOTAL_LENGTH, ipv4.getTotalLength());
+ assertEquals(IDENTIFICATION, ipv4.getIdentification());
+ assertEquals(FLAGS, ipv4.getFlags());
+ assertEquals(FRAGMENT_OFFSET, ipv4.getFragmentOffset());
+ assertEquals(TTL, ipv4.getTtl());
+ assertEquals(PROTOCOL, ipv4.getProtocol());
+ assertEquals(CHECKSUM, ipv4.getChecksum());
+ assertEquals(SOURCE_ADDRESS, ipv4.getSourceAddress());
+ assertEquals(DESTINATION_ADDRESS, ipv4.getDestinationAddress());
assertTrue(ipv4.isTruncated());
}
@@ -109,17 +109,17 @@
IPv4 ipv4 = deserializer.deserialize(headerBytes, 0, headerBytes.length);
String str = ipv4.toString();
- assertTrue(StringUtils.contains(str, "version=" + version));
- assertTrue(StringUtils.contains(str, "headerLength=" + headerLength));
- assertTrue(StringUtils.contains(str, "diffServ=" + diffServ));
- assertTrue(StringUtils.contains(str, "totalLength=" + totalLength));
- assertTrue(StringUtils.contains(str, "identification=" + identification));
- assertTrue(StringUtils.contains(str, "flags=" + flags));
- assertTrue(StringUtils.contains(str, "fragmentOffset=" + fragmentOffset));
- assertTrue(StringUtils.contains(str, "ttl=" + ttl));
- assertTrue(StringUtils.contains(str, "protocol=" + protocol));
- assertTrue(StringUtils.contains(str, "checksum=" + checksum));
- assertTrue(StringUtils.contains(str, "sourceAddress=" + sourceAddress));
- assertTrue(StringUtils.contains(str, "destinationAddress=" + destinationAddress));
+ assertTrue(StringUtils.contains(str, "version=" + VERSION));
+ assertTrue(StringUtils.contains(str, "headerLength=" + HEADER_LENGTH));
+ assertTrue(StringUtils.contains(str, "diffServ=" + DIFF_SERV));
+ assertTrue(StringUtils.contains(str, "totalLength=" + TOTAL_LENGTH));
+ assertTrue(StringUtils.contains(str, "identification=" + IDENTIFICATION));
+ assertTrue(StringUtils.contains(str, "flags=" + FLAGS));
+ assertTrue(StringUtils.contains(str, "fragmentOffset=" + FRAGMENT_OFFSET));
+ assertTrue(StringUtils.contains(str, "ttl=" + TTL));
+ assertTrue(StringUtils.contains(str, "protocol=" + PROTOCOL));
+ assertTrue(StringUtils.contains(str, "checksum=" + CHECKSUM));
+ assertTrue(StringUtils.contains(str, "sourceAddress=" + SOURCE_ADDRESS));
+ assertTrue(StringUtils.contains(str, "destinationAddress=" + DESTINATION_ADDRESS));
}
}