Import AD-SAL packet parser/generator. 15/28515/1
authorShigeru Yasuda <s-yasuda@da.jp.nec.com>
Fri, 16 Oct 2015 17:12:02 +0000 (02:12 +0900)
committerShigeru Yasuda <s-yasuda@da.jp.nec.com>
Fri, 16 Oct 2015 17:12:02 +0000 (02:12 +0900)
Although packet parser is located in manager bundle, it is only for
VTN internal use.

Change-Id: I31d239d032fdc04d73e3288ca1e22f96c588dc8b
Signed-off-by: Shigeru Yasuda <s-yasuda@da.jp.nec.com>
77 files changed:
manager/api/pom.xml
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/ARP.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/Ethernet.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/ICMP.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/IEEE8021Q.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/IPv4.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/Packet.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/PacketException.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/TCP.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/packet/UDP.java [new file with mode: 0644]
manager/api/src/main/java/org/opendaylight/vtn/manager/util/ByteUtils.java
manager/api/src/main/java/org/opendaylight/vtn/manager/util/EtherTypes.java
manager/api/src/main/java/org/opendaylight/vtn/manager/util/InetProtocols.java
manager/api/src/main/java/org/opendaylight/vtn/manager/util/NumberUtils.java
manager/api/src/test/java/org/opendaylight/vtn/manager/VTNExceptionTest.java
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/ARPTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/EthernetTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/ICMPTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/IEEE8021QTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/IPv4Test.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/PacketExceptionTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/PacketTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/TCPTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/packet/UDPTest.java [new file with mode: 0644]
manager/api/src/test/java/org/opendaylight/vtn/manager/util/ByteUtilsTest.java
manager/api/src/test/java/org/opendaylight/vtn/manager/util/EtherTypesTest.java
manager/api/src/test/java/org/opendaylight/vtn/manager/util/InetProtocolsTest.java
manager/api/src/test/java/org/opendaylight/vtn/manager/util/NumberUtilsTest.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/PacketContext.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/VTNManagerProvider.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/MacMapImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortBridge.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/PortInterface.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/cluster/VlanMapImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/PacketInEvent.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/VTNPacketService.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/CachedPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4Packet.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/L4Packet.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/PortProtoPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacket.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/provider/VTNManagerProviderImpl.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/MiscUtils.java
manager/implementation/src/main/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilder.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/TestBase.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlDstActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDlSrcActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetDscpActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpCodeActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetIcmpTypeActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4DstActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetInet4SrcActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetTpDstActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetTpSrcActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/cluster/SetVlanPcpActionImplTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/EtherPacketTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/IcmpPacketTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/Inet4PacketTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/TcpPacketTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/packet/cache/UdpPacketTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/MiscUtilsTest.java
manager/implementation/src/test/java/org/opendaylight/vtn/manager/internal/util/packet/ArpPacketBuilderTest.java
manager/it/core/src/test/java/org/opendaylight/vtn/manager/it/core/VTNManagerIT.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/TestHost.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/action/SetInet4DstVerifier.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/action/SetInet4SrcVerifier.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/packet/ArpFactory.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/packet/EthernetFactory.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/packet/Icmp4Factory.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/packet/Inet4Factory.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/packet/PacketFactory.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/packet/TcpFactory.java
manager/it/util/src/main/java/org/opendaylight/vtn/manager/it/util/packet/UdpFactory.java

index f750b56ff946bd06866aad60568115f403fde2c8..71815ebd3713f01af31d3070716e0ab41e155bc7 100644 (file)
@@ -77,6 +77,8 @@
               org.opendaylight.controller.sal.packet.address,
               org.opendaylight.controller.sal.utils,
               org.opendaylight.yang.gen.v1.*,
+              org.slf4j,
+              com.google.common.*,
               com.fasterxml.jackson.databind.annotation,
               javax.xml.bind.annotation,
               javax.xml.bind.annotation.adapters
       <artifactId>hosttracker</artifactId>
     </dependency>
 
+    <!-- Google Guava -->
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+
     <!-- Jackson -->
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
       <artifactId>jackson-module-jaxb-annotations</artifactId>
       <scope>test</scope>
     </dependency>
+
+    <!-- SLF4J API -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/ARP.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/ARP.java
new file mode 100644 (file)
index 0000000..36fb574
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.util.NumberUtils.toBytes;
+
+import java.util.Map;
+
+import org.opendaylight.vtn.manager.util.EtherAddress;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+
+/**
+ * {@code ARP} describes an ARP packet.
+ *
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public final class ARP extends Packet {
+    /**
+     * The number of bits in the ARP header.
+     */
+    private static final int  HEADER_SIZE = 224;
+
+    /**
+     * The field name that indicates the hardware type.
+     */
+    private static final String  HWTYPE = "HardwareType";
+
+    /**
+     * The field name that indicates the protocol type.
+     */
+    private static final String  PTYPE = "ProtocolType";
+
+    /**
+     * The field name that indicates the hardware address length.
+     */
+    private static final String  HWADDRLENGTH = "HardwareAddressLength";
+
+    /**
+     * The field name that indicates the protocol address length.
+     */
+    private static final String  PADDRLENGTH = "ProtocolAddressLength";
+
+    /**
+     * The field name that indicates the operation code.
+     */
+    private static final String  OPCODE = "OpCode";
+
+    /**
+     * The field name that indicates the sender hardware address.
+     */
+    private static final String  SENDERHWADDR = "SenderHardwareAddress";
+
+    /**
+     * The field name that indicates the sender protocol address.
+     */
+    private static final String  SENDERPADDR = "SenderProtocolAddress";
+
+    /**
+     * The field name that indicates the target hardware address.
+     */
+    private static final String  TARGETHWADDR = "TargetHardwareAddress";
+
+    /**
+     * The field name that indicates the target protocol address.
+     */
+    private static final String  TARGETPADDR = "TargetProtocolAddress";
+
+    /**
+     * The hardware tyep value that indicates Ethernet.
+     */
+    public static final short  HW_TYPE_ETHERNET = 0x1;
+
+    /**
+     * The ARP operation code that indicates ARP request.
+     */
+    public static final short  REQUEST = 0x1;
+
+    /**
+     * The ARP operation code that indicates ARP reply.
+     */
+    public static final short  REPLY = 0x2;
+
+    /**
+     * A map that determines the ARP packet header format.
+     */
+    private static final Map<String, HeaderField>  HEADER_FORMAT;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        int etherBits = EtherAddress.SIZE * Byte.SIZE;
+        int ipv4Bits = Ip4Network.SIZE * Byte.SIZE;
+        HEADER_FORMAT = new HeaderMapBuilder().
+            addNumber(HWTYPE, Short.SIZE).
+            addNumber(PTYPE, Short.SIZE).
+            addNumber(HWADDRLENGTH, Byte.SIZE).
+            addNumber(PADDRLENGTH, Byte.SIZE).
+            addNumber(OPCODE, Short.SIZE).
+            addByte(SENDERHWADDR, etherBits).
+            addByte(SENDERPADDR, ipv4Bits).
+            addByte(TARGETHWADDR, etherBits).
+            addByte(TARGETPADDR, ipv4Bits).
+            build();
+    }
+
+    /**
+     * Gets the hardware type from the stored ARP header.
+     *
+     * @return  The hardware type.
+     */
+    public short getHardwareType() {
+        return getShort(HWTYPE);
+    }
+
+    /**
+     * Gets the protocol type from the stored ARP header.
+     *
+     * @return  The protocol type.
+     */
+    public short getProtocolType() {
+        return getShort(PTYPE);
+    }
+
+    /**
+     * Gets the hardware address length from the stored ARP header.
+     *
+     * @return  The length of the hardware address.
+     */
+    public byte getHardwareAddressLength() {
+        return getByte(HWADDRLENGTH);
+    }
+
+    /**
+     * Get the protocol address length from Protocol header.
+     *
+     * @return  The length of the protocol address.
+     */
+    public byte getProtocolAddressLength() {
+        return getByte(PADDRLENGTH);
+    }
+
+    /**
+     * Gets the opCode from stored ARP header.
+     *
+     * @return  The operation code.
+     */
+    public short getOpCode() {
+        return getShort(OPCODE);
+    }
+
+    /**
+     * Gets the sender hardware address from the stored ARP header.
+     *
+     * @return  The sender hardware address.
+     *          {@code null} if not configured.
+     */
+    public byte[] getSenderHardwareAddress() {
+        return getBytes(SENDERHWADDR);
+    }
+
+    /**
+     * Gets the IP address from the stored ARP header.
+     *
+     * @return  The sender protocol address.
+     *          {@code null} if not configured.
+     */
+    public byte[] getSenderProtocolAddress() {
+        return getBytes(SENDERPADDR);
+    }
+
+    /**
+     * Gets the hardware address from the stored ARP header.
+     *
+     * @return  The target hardware address.
+     *          {@code null} if not configured.
+     */
+    public byte[] getTargetHardwareAddress() {
+        return getBytes(TARGETHWADDR);
+    }
+
+    /**
+     * Gets the target protocol address.
+     *
+     * @return  The target protocol address.
+     *          {@code null} if not configured.
+     */
+    public byte[] getTargetProtocolAddress() {
+        return getBytes(TARGETPADDR);
+    }
+
+    /**
+     * Sets the hardware Type for the current ARP object instance.
+     *
+     * @param hwtype  The hardwareType to set.
+     * @return  This instance.
+     */
+    public ARP setHardwareType(short hwtype) {
+        getHeaderFieldMap().put(HWTYPE, toBytes(hwtype));
+        return this;
+    }
+
+    /**
+     * Sets the protocol Type for the current ARP object instance.
+     *
+     * @param ptype  The protocol type to set.
+     * @return  This instance.
+     */
+    public ARP setProtocolType(short ptype) {
+        getHeaderFieldMap().put(PTYPE, toBytes(ptype));
+        return this;
+    }
+
+    /**
+     * Sets the hardware address length for the current ARP object instance.
+     *
+     * @param len  The length of the hardware address.
+     * @return  This instance.
+     */
+    public ARP setHardwareAddressLength(byte len) {
+        getHeaderFieldMap().put(HWADDRLENGTH, new byte[]{len});
+        return this;
+    }
+
+    /**
+     * Sets the Protocol address for the current ARP object instance.
+     *
+     * @param len  The length of the protocol address.
+     * @return  This instance.
+     */
+    public ARP setProtocolAddressLength(byte len) {
+        getHeaderFieldMap().put(PADDRLENGTH, new byte[]{len});
+        return this;
+    }
+
+    /**
+     * Sets the opCode for the current ARP object instance.
+     *
+     * @param op  The operation code.
+     * @return  This instance.
+     */
+    public ARP setOpCode(short op) {
+        getHeaderFieldMap().put(OPCODE, toBytes(op));
+        return this;
+    }
+
+    /**
+     * Sets the sender hardware address for the current ARP object instance.
+     *
+     * @param addr  The sender hardware address.
+     * @return  This instance.
+     */
+    public ARP setSenderHardwareAddress(byte[] addr) {
+        getHeaderFieldMap().put(SENDERHWADDR, addr.clone());
+        return this;
+    }
+
+    /**
+     * Sets the target hardware address for the current ARP object instance.
+     *
+     * @param addr  The target hardware address.
+     * @return  This instance.
+     */
+    public ARP setTargetHardwareAddress(byte[] addr) {
+        getHeaderFieldMap().put(TARGETHWADDR, addr.clone());
+        return this;
+    }
+
+    /**
+     * Sets the sender protocol address for the current ARP object instance.
+     *
+     * @param addr  The sender protocol address.
+     * @return  This instance.
+     */
+    public ARP setSenderProtocolAddress(byte[] addr) {
+        getHeaderFieldMap().put(SENDERPADDR, addr.clone());
+        return this;
+    }
+
+    /**
+     * Sets the target protocol address for the current ARP object instance.
+     *
+     * @param addr  The target protocol address.
+     * @return  This instance.
+     */
+    public ARP setTargetProtocolAddress(byte[] addr) {
+        getHeaderFieldMap().put(TARGETPADDR, addr.clone());
+        return this;
+    }
+
+    // Packet
+
+    /**
+     * Gets the header size in bits.
+     *
+     * @return The ARP header size in bits.
+     */
+    @Override
+    public int getHeaderSize() {
+        return HEADER_SIZE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Map<String, HeaderField> getHeaderFormat() {
+        return HEADER_FORMAT;
+    }
+
+    // Object
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ARP clone() {
+        return (ARP)super.clone();
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/Ethernet.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/Ethernet.java
new file mode 100644 (file)
index 0000000..dd4febf
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.util.NumberUtils.toBytes;
+import static org.opendaylight.vtn.manager.util.NumberUtils.toShort;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.opendaylight.vtn.manager.util.EtherAddress;
+import org.opendaylight.vtn.manager.util.EtherTypes;
+
+/**
+ * {@code Ethernet} describes an Ethernet frame.
+ *
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public class Ethernet extends Packet {
+    /**
+     * The number of bits in the Ethernet header.
+     */
+    private static final int  HEADER_SIZE = 112;
+
+    /**
+     * The field name that indicates the destination MAC address.
+     */
+    private static final String  DMAC = "DestinationMACAddress";
+
+    /**
+     * The field name that indicates the source MAC address.
+     */
+    private static final String  SMAC = "SourceMACAddress";
+
+    /**
+     * The field name that indicates the Ethernet type.
+     */
+    static final String  ETHT = "EtherType";
+
+    /**
+     * A map that determines the IPv4 packet header format.
+     */
+    private static final Map<String, HeaderField>  HEADER_FORMAT;
+
+    /**
+     * A set of supported payload types.
+     */
+    private static final Map<EtherTypes, Class<? extends Packet>> PAYLOAD_TYPES;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        // Initialize the Ethernet header format.
+        int addrSize = EtherAddress.SIZE * Byte.SIZE;
+        HEADER_FORMAT = new HeaderMapBuilder().
+            addByte(DMAC, addrSize).
+            addByte(SMAC, addrSize).
+            addNumber(ETHT, Short.SIZE).
+            build();
+
+        // Initialize the payload types.
+        EnumMap<EtherTypes, Class<? extends Packet>> typeMap =
+            new EnumMap(EtherTypes.class);
+        typeMap.put(EtherTypes.IPV4, IPv4.class);
+        typeMap.put(EtherTypes.ARP, ARP.class);
+        typeMap.put(EtherTypes.VLAN, IEEE8021Q.class);
+        PAYLOAD_TYPES = ImmutableMap.copyOf(typeMap);
+    }
+
+    /**
+     * Determine the payload type for the given Ethernet type.
+     *
+     * @param type  The Ethernet type value.
+     * @return  A class for the payload type.
+     *          {@code null} if no payload type is defined for the given
+     *          Ethernet type.
+     */
+    static Class<? extends Packet> getPayloadClass(short type) {
+        EtherTypes etype = EtherTypes.forValue(type);
+        return (etype == null) ? null : PAYLOAD_TYPES.get(etype);
+    }
+
+    /**
+     * Gets the destination MAC address stored.
+     *
+     * @return  The destination MAC address.
+     *          {@code null} if not configured.
+     */
+    public byte[] getDestinationMACAddress() {
+        return getHeaderFieldMap().get(DMAC);
+    }
+
+    /**
+     * Gets the source MAC address stored.
+     *
+     * @return  The source MAC address.
+     *          {@code null} if not configured.
+     */
+    public byte[] getSourceMACAddress() {
+        return getHeaderFieldMap().get(SMAC);
+    }
+
+    /**
+     * Gets the etherType stored.
+     *
+     * @return  The Ethernet type.
+     */
+    public short getEtherType() {
+        return getShort(ETHT);
+    }
+
+    /**
+     * Sets the destination MAC address for the current Ethernet object.
+     *
+     * @param mac  The destination MAC address.
+     *             {@code null} cannot be specified.
+     * @return  This instance.
+     */
+    public Ethernet setDestinationMACAddress(byte[] mac) {
+        getHeaderFieldMap().put(DMAC, mac.clone());
+        return this;
+    }
+
+    /**
+     * Sets the source MAC address for the current Ethernet object.
+     *
+     * @param mac  The source MAC address.
+     *             {@code null} cannot be specified.
+     * @return  This instance.
+     */
+    public Ethernet setSourceMACAddress(byte[] mac) {
+        getHeaderFieldMap().put(SMAC, mac.clone());
+        return this;
+    }
+
+    /**
+     * Sets the etherType for the current Ethernet object.
+     *
+     * @param type  The Ethernet type.
+     * @return  This instance.
+     */
+    public Ethernet setEtherType(short type) {
+        getHeaderFieldMap().put(ETHT, toBytes(type));
+        return this;
+    }
+
+    // Packet
+
+    /**
+     * Return the number of bits in the Ethernet header.
+     *
+     * @return  The number of bits in the Ethernet header.
+     */
+    @Override
+    public int getHeaderSize() {
+        return HEADER_SIZE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Map<String, HeaderField> getHeaderFormat() {
+        return HEADER_FORMAT;
+    }
+
+    /**
+     * Stores the value of fields read from data stream.
+     *
+     * @param name   The name of the header field.
+     * @param value  The value to be associated with the specified header
+     *               field. {@code null} cannot be specified.
+     */
+    @Override
+    protected void setHeaderField(String name, byte[] value) {
+        if (name.equals(ETHT)) {
+            short etype = toShort(value);
+            setPayloadClass(getPayloadClass(etype));
+        }
+
+        super.setHeaderField(name, value);
+    }
+
+    // Object
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Ethernet clone() {
+        return (Ethernet)super.clone();
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/ICMP.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/ICMP.java
new file mode 100644 (file)
index 0000000..3ac6391
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.packet.IPv4.CKSUM_BYTES;
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_BYTE;
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_SHORT;
+import static org.opendaylight.vtn.manager.util.NumberUtils.toBytes;
+
+import java.util.Map;
+
+import org.opendaylight.vtn.manager.util.ByteUtils;
+
+/**
+ * {@code ICMP} describes an ICMP packet.
+ *
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public final class ICMP extends Packet {
+    /**
+     * The number of bits in the ICMP header.
+     */
+    private static final int  HEADER_SIZE = 64;
+
+    /**
+     * The field name that indicates the ICMP type.
+     */
+    private static final String  TYPE = "Type";
+
+    /**
+     * The field name that indicates the ICMP code.
+     */
+    private static final String  CODE = "Code";
+
+    /**
+     * The field name that indicates the checksum.
+     */
+    private static final String  CHECKSUM = "Checksum";
+
+    /**
+     * The field name that indicates the ICMP identifier.
+     */
+    private static final String  IDENTIFIER = "Identifier";
+
+    /**
+     * The field name that indicates the sequence number.
+     */
+    private static final String  SEQNUMBER = "SequenceNumber";
+
+    /**
+     * A map that determines the ICMP packet header format.
+     */
+    private static final Map<String, HeaderField>  HEADER_FORMAT;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        HEADER_FORMAT = new HeaderMapBuilder().
+            addNumber(TYPE, Byte.SIZE).
+            addNumber(CODE, Byte.SIZE).
+            addNumber(CHECKSUM, Short.SIZE).
+            addNumber(IDENTIFIER, Short.SIZE).
+            addNumber(SEQNUMBER, Short.SIZE).
+            build();
+    }
+
+    /**
+     * Sets the type for the current ICMP message.
+     *
+     * @param type  The ICMP message type
+     * @return  This ICMP object
+     */
+    public ICMP setType(byte type) {
+        getHeaderFieldMap().put(TYPE, new byte[]{type});
+        return this;
+    }
+
+    /**
+     * Returns the type field of the current ICMP packet.
+     *
+     * @return  The type code of the current ICMP packet
+     */
+    public byte getType() {
+        return getByte(TYPE);
+    }
+
+    /**
+     * Sets the ICMP code (type subtype) for the current ICMP object instance.
+     *
+     * @param code  The ICMP message type subtype
+     * @return  This ICMP object
+     */
+    public ICMP setCode(byte code) {
+        getHeaderFieldMap().put(CODE, new byte[]{code});
+        return this;
+    }
+
+    /**
+     * Gets the ICMP code (type subtype) for the current ICMP object instance.
+     *
+     * @return  The ICMP message type subtype
+     */
+    public byte getCode() {
+        return getByte(CODE);
+    }
+
+    /**
+     * Sets the ICMP checksum for the current ICMP object instance.
+     *
+     * @param cksum  The checksum value to be set.
+     * @return  This instance.
+     */
+    public ICMP setChecksum(short cksum) {
+        getHeaderFieldMap().put(CHECKSUM, toBytes(cksum));
+        return this;
+    }
+
+    /**
+     * Return the ICMP checksum in this packet.
+     *
+     * @return  The ICMP checksum value.
+     */
+    public short getChecksum() {
+        return getShort(CHECKSUM);
+    }
+
+    /**
+     * Sets the ICMP identifier for the current ICMP object instance.
+     * @param id  The ICMP identifier to be set.
+     * @return  This instance.
+     */
+    public ICMP setIdentifier(short id) {
+        getHeaderFieldMap().put(IDENTIFIER, toBytes(id));
+        return this;
+    }
+
+    /**
+     * Gets the ICMP identifier of the current ICMP object instance.
+     *
+     * @return  The ICMP identifier.
+     */
+    public short getIdentifier() {
+        return getShort(IDENTIFIER);
+    }
+
+    /**
+     * Sets the ICMP sequence number for the current ICMP object instance.
+     *
+     * @param seq  The ICMP sequence number to be set.
+     * @return  This instance.
+     */
+    public ICMP setSequenceNumber(short seq) {
+        getHeaderFieldMap().put(SEQNUMBER, toBytes(seq));
+        return this;
+    }
+
+    /**
+     * Gets the ICMP sequence number of the current ICMP object instance.
+     *
+     * @return  The ICMP sequence number.
+     */
+    public short getSequenceNumber() {
+        return getShort(SEQNUMBER);
+    }
+
+    /**
+     * Computes the ICMP checksum on the serialized ICMP message.
+     *
+     * @param data   The data stream.
+     * @param start  The byte index on the data stream from which the ICMP
+     *               packet starts.
+     * @return  The checksum value.
+     */
+    private short computeChecksum(byte[] data, int start) {
+        int sum = 0;
+        int wordData;
+        int end = (start + HEADER_SIZE / Byte.SIZE) + getRawPayloadSize();
+        int checksumStartByte = start + getFieldOffset(CHECKSUM) / Byte.SIZE;
+        int even = end & ~1;
+
+        for (int i = start; i < even; i += CKSUM_BYTES) {
+            // Skip, if the current bytes are checkSum bytes
+            if (i != checksumStartByte) {
+                wordData = ((data[i] & MASK_BYTE) << Byte.SIZE) |
+                    (data[i + 1] & MASK_BYTE);
+                sum = sum + wordData;
+            }
+        }
+        if (even < end) {
+            // Add the last octet with zero padding.
+            wordData = (data[even] & MASK_BYTE) << Byte.SIZE;
+            sum = sum + wordData;
+        }
+
+        int carry = sum >>> Short.SIZE;
+        int finalSum = (sum & MASK_SHORT) + carry;
+        return (short)~((short)finalSum & MASK_SHORT);
+    }
+
+    // Packet
+
+    /**
+     * Gets the header size in bits.
+     *
+     * @return The ICMP header size in bits.
+     */
+    @Override
+    public int getHeaderSize() {
+        return HEADER_SIZE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Map<String, HeaderField> getHeaderFormat() {
+        return HEADER_FORMAT;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void postSerializeCustomOperation(byte[] myBytes)
+        throws PacketException {
+        String field = CHECKSUM;
+        try {
+            HeaderField entry = HEADER_FORMAT.get(field);
+            int off = getFieldOffset(field, entry);
+            int nbits = getFieldNumBits(field, entry);
+            byte[] cksum = toBytes(computeChecksum(myBytes, 0));
+            ByteUtils.setBits(myBytes, cksum, off, nbits);
+            getHeaderFieldMap().put(CHECKSUM, cksum);
+        } catch (RuntimeException e) {
+            throw new PacketException("Failed to update checksum.", e);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void postDeserializeCustomOperation(byte[] data, int offset) {
+        short computed = computeChecksum(data, offset / Byte.SIZE);
+        short actual = getChecksum();
+        if (computed != actual) {
+            setCorrupted(true);
+        }
+    }
+
+    // Object
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public ICMP clone() {
+        return (ICMP)super.clone();
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/IEEE8021Q.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/IEEE8021Q.java
new file mode 100644 (file)
index 0000000..39a2cb5
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.packet.Ethernet.ETHT;
+import static org.opendaylight.vtn.manager.packet.Ethernet.getPayloadClass;
+import static org.opendaylight.vtn.manager.util.NumberUtils.toBytes;
+import static org.opendaylight.vtn.manager.util.NumberUtils.toShort;
+
+import java.util.Map;
+
+/**
+ * {@code IEEE8021Q} describes an IEEE 802.1Q VLAN tag.
+ *
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public final class IEEE8021Q extends Packet {
+    /**
+     * The number of bits in the VLAN tag.
+     */
+    private static final int  HEADER_SIZE = 32;
+
+    /**
+     * The field name that indicates the priority code point.
+     */
+    private static final String  PCP = "PriorityCodePoint";
+
+    /**
+     * The field name that indicates the canonical format indicator.
+     */
+    private static final String  CFI = "CanonicalFormatIndicator";
+
+    /**
+     * The field name that indicates the VLAN ID.
+     */
+    private static final String  VID = "VlanIdentifier";
+
+    /**
+     * The number of bits in the prioriy code point field.
+     */
+    private static final int  BITS_PCP = 3;
+
+    /**
+     * The number of bits in the canonical format indicator field.
+     */
+    private static final int  BITS_CFI = 1;
+
+    /**
+     * The number of bits in the VLAN ID field.
+     */
+    private static final int  BITS_VID = 12;
+
+    /**
+     * A map that determines the IEEE 802.1Q header format.
+     */
+    private static final Map<String, HeaderField>  HEADER_FORMAT;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        HEADER_FORMAT = new HeaderMapBuilder().
+            addNumber(PCP, BITS_PCP).
+            addNumber(CFI, BITS_CFI).
+            addNumber(VID, BITS_VID).
+            addNumber(ETHT, Short.SIZE).
+            build();
+    }
+
+    /**
+     * Gets the priority code point(PCP) stored.
+     *
+     * @return  The priority code point value.
+     */
+    public byte getPcp() {
+        return getByte(PCP);
+    }
+
+    /**
+     * Gets the canonical format indicator(CFI) stored.
+     *
+     * @return  The canonical format indicator value.
+     */
+    public byte getCfi() {
+        return getByte(CFI);
+    }
+
+    /**
+     * Gets the VLAN identifier(VID) stored.
+     *
+     * @return  The VLAN ID.
+     */
+    public short getVid() {
+        return getShort(VID);
+    }
+
+    /**
+     * Gets the Ethernet type stored.
+     *
+     * @return  The Ethernet type.
+     */
+    public short getEtherType() {
+        return getShort(ETHT);
+    }
+
+    /**
+     * Sets the priority code point(PCP) for the current IEEE 802.1Q object
+     * instance.
+     *
+     * @param pcp  The priority code point value.
+     * @return  This instance.
+     */
+    public IEEE8021Q setPcp(byte pcp) {
+        getHeaderFieldMap().put(PCP, new byte[]{pcp});
+        return this;
+    }
+
+    /**
+     * Sets the canonical format indicator(CFI) for the current IEEE 802.1Q
+     * object instance.
+     *
+     * @param cfi  The canonical format indicator value.
+     * @return  This instance.
+     */
+    public IEEE8021Q setCfi(byte cfi) {
+        getHeaderFieldMap().put(CFI, new byte[]{cfi});
+        return this;
+    }
+
+    /**
+     * Sets the VLAN identifier(VID) for the current IEEE 802.1Q instance.
+     *
+     * @param vid  The VLAN ID.
+     * @return  This instance.
+     */
+    public IEEE8021Q setVid(short vid) {
+        getHeaderFieldMap().put(VID, toBytes(vid));
+        return this;
+    }
+
+    /**
+     * Sets the etherType for the current IEEE 802.1Q object instance.
+     *
+     * @param type  The Ethernet type.
+     * @return  This instance.
+     */
+    public IEEE8021Q setEtherType(short type) {
+        getHeaderFieldMap().put(ETHT, toBytes(type));
+        return this;
+    }
+
+    // Packet
+
+    /**
+     * Gets the header size in bits.
+     *
+     * @return  The IEEE 802.1Q header size in bits.
+     */
+    @Override
+    public int getHeaderSize() {
+        return HEADER_SIZE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Map<String, HeaderField> getHeaderFormat() {
+        return HEADER_FORMAT;
+    }
+
+    /**
+     * Stores the value of fields read from data stream.
+     *
+     * @param name   The name of the header field.
+     * @param value  The value to be associated with the specified header
+     *               field. {@code null} cannot be specified.
+     */
+    @Override
+    protected void setHeaderField(String name, byte[] value) {
+        if (name.equals(ETHT)) {
+            short etype = toShort(value);
+            setPayloadClass(getPayloadClass(etype));
+        }
+
+        super.setHeaderField(name, value);
+    }
+
+    // Object
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IEEE8021Q clone() {
+        return (IEEE8021Q)super.clone();
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/IPv4.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/IPv4.java
new file mode 100644 (file)
index 0000000..50bc843
--- /dev/null
@@ -0,0 +1,766 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_BYTE;
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_SHORT;
+import static org.opendaylight.vtn.manager.util.NumberUtils.NUM_OCTETS_SHORT;
+import static org.opendaylight.vtn.manager.util.NumberUtils.toBytes;
+
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.opendaylight.vtn.manager.util.ByteUtils;
+import org.opendaylight.vtn.manager.util.InetProtocols;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+
+/**
+ * {@code IPv4} describes an IP version 4 packet.
+ *
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public final class IPv4 extends Packet {
+    /**
+     * The IPv4 version number.
+     */
+    public static final byte  IPV4_VERSION = 4;
+
+    /**
+     * The number of octets in IP checksum.
+     */
+    public static final int  CKSUM_BYTES = NUM_OCTETS_SHORT;
+
+    /**
+     * The field name that indicates the Inetnet Protocol version.
+     */
+    private static final String  VERSION = "Version";
+
+    /**
+     * The field name that indicates the IP header length.
+     */
+    private static final String  HEADERLENGTH = "HeaderLength";
+
+    /**
+     * The field name that indicates the IP differential service.
+     */
+    private static final String  DIFFSERV = "DiffServ";
+
+    /**
+     * The field name that indicates the ECN bits.
+     */
+    private static final String  ECN = "ECN";
+
+    /**
+     * The field name that indicates the total length.
+     */
+    private static final String  TOTLENGTH = "TotalLength";
+
+    /**
+     * The field name that indicates the IPv4 identification.
+     */
+    private static final String  IDENTIFICATION = "Identification";
+
+    /**
+     * The field name that indicates the IPv4 flags.
+     */
+    private static final String  FLAGS = "Flags";
+
+    /**
+     * The field name that indicates the IPv4 fragment offset.
+     */
+    private static final String  FRAGOFFSET = "FragmentOffset";
+
+    /**
+     * The field name that indicates the IPv4 Time-To-Live.
+     */
+    private static final String  TTL = "TTL";
+
+    /**
+     * The field name that indicates the IP protocol number.
+     */
+    private static final String  PROTOCOL = "Protocol";
+
+    /**
+     * The field name that indicates the IP checksum.
+     */
+    private static final String  CHECKSUM = "Checksum";
+
+    /**
+     * The field name that indicates the source IP address.
+     */
+    private static final String  SIP = "SourceIPAddress";
+
+    /**
+     * The field name that indicates the destination IP address.
+     */
+    private static final String  DIP = "DestinationIPAddress";
+
+    /**
+     * The field name that indicates the IPv4 options.
+     */
+    private static final String  OPTIONS = "Options";
+
+    /**
+     * The number of bits in the IP protocol version field.
+     */
+    private static final int  BITS_VERSION = 4;
+
+    /**
+     * The number of bits in the IP header length field.
+     */
+    private static final int  BITS_HEADERLENGTH = 4;
+
+    /**
+     * The number of bits in the IP differential service field.
+     */
+    private static final int  BITS_DIFFSERV = 6;
+
+    /**
+     * The number of bits in the ECN field.
+     */
+    private static final int  BITS_ECN = 2;
+
+    /**
+     * The number of bits in the IPv4 flags field.
+     */
+    private static final int  BITS_FLAGS = 3;
+
+    /**
+     * The number of bits in the IPv4 fragment offset field.
+     */
+    private static final int  BITS_FRAGOFFSET = 13;
+
+    /**
+     * The number of bits to calculate IPv4 unit size.
+     */
+    private static final int  UNIT_SIZE_SHIFT = 2;
+
+    /**
+     * The number of bytes in an IPv4 unit value.
+     */
+    private static final int  UNIT_SIZE = (1 << UNIT_SIZE_SHIFT);
+
+    /**
+     * The minimum size of the IPv4 header in bytes.
+     */
+    private static final int  MIN_HEADER_SIZE = 20;
+
+    /**
+     * The default value of the header length field.
+     */
+    private static final byte  DEFAULT_HEADER_LENGTH =
+        (byte)(MIN_HEADER_SIZE >>> UNIT_SIZE_SHIFT);
+
+    /**
+     * The default value of the IPv4 flags.
+     */
+    private static final byte  DEFAULT_FLAGS = 2;
+
+    /**
+     * A map that determines the IPv4 packet header format.
+     */
+    private static final Map<String, HeaderField>  HEADER_FORMAT;
+
+    /**
+     * A set of supported payload types.
+     */
+    private static final Map<InetProtocols, Class<? extends Packet>>  PAYLOAD_TYPES;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        // Initialize the IPv4 header format.
+        int addrSize = Ip4Network.SIZE * Byte.SIZE;
+        HEADER_FORMAT = new HeaderMapBuilder().
+            addNumber(VERSION, BITS_VERSION).
+            addNumber(HEADERLENGTH, BITS_HEADERLENGTH).
+            addNumber(DIFFSERV, BITS_DIFFSERV).
+            addNumber(ECN, BITS_ECN).
+            addNumber(TOTLENGTH, Short.SIZE).
+            addNumber(IDENTIFICATION, Short.SIZE).
+            addNumber(FLAGS, BITS_FLAGS).
+            addNumber(FRAGOFFSET, BITS_FRAGOFFSET).
+            addNumber(TTL, Byte.SIZE).
+            addNumber(PROTOCOL, Byte.SIZE).
+            addNumber(CHECKSUM, Short.SIZE).
+            addByte(SIP, addrSize).
+            addByte(DIP, addrSize).
+            addByte(OPTIONS, 0).
+            build();
+
+        // Initialize the payload types.
+        EnumMap<InetProtocols, Class<? extends Packet>> typeMap =
+            new EnumMap(InetProtocols.class);
+        typeMap.put(InetProtocols.ICMP, ICMP.class);
+        typeMap.put(InetProtocols.TCP, TCP.class);
+        typeMap.put(InetProtocols.UDP, UDP.class);
+        PAYLOAD_TYPES = ImmutableMap.copyOf(typeMap);
+    }
+
+    /**
+     * Determine the payload type for the given IP protocol number.
+     *
+     * @param proto  The IP protocol number.
+     * @return  A class for the payload type.
+     *          {@code null} if no payload type is defined for the given
+     *          IP protocol number.
+     */
+    static Class<? extends Packet> getPayloadClass(byte proto) {
+        InetProtocols ipproto = InetProtocols.forValue(proto);
+        return (ipproto == null) ? null : PAYLOAD_TYPES.get(ipproto);
+    }
+
+    /**
+     * Construct a new instance.
+     *
+     * <p>
+     *   This constructor sets the version to 4, headerLength to 5,
+     *   and flags to 2.
+     * </p>
+     */
+    public IPv4() {
+        setVersion(IPV4_VERSION);
+        setHeaderLength(DEFAULT_HEADER_LENGTH);
+        setFlags(DEFAULT_FLAGS);
+    }
+
+    /**
+     * Gets the IP version stored.
+     *
+     * @return  The IP version.
+     */
+    public byte getVersion() {
+        return getByte(VERSION);
+    }
+
+    /**
+     * Gets the IP header length stored.
+     *
+     * @return  The IP header length in bytes.
+     */
+    public int getHeaderLen() {
+        return (getByte(HEADERLENGTH) << UNIT_SIZE_SHIFT);
+    }
+
+    /**
+     * Gets the differential services value stored.
+     *
+     * @return  The differential services value.
+     */
+    public byte getDiffServ() {
+        return getByte(DIFFSERV);
+    }
+
+    /**
+     * Gets the ECN bits stored.
+     *
+     * @return  The ECN bits.
+     */
+    public byte getECN() {
+        return getByte(ECN);
+    }
+
+    /**
+     * Gets the total length of the IPv4 packe in bytes.
+     *
+     * @return  The total length of the IPv4 packet.
+     */
+    public short getTotalLength() {
+        return getShort(TOTLENGTH);
+    }
+
+    /**
+     * Gets the identification value stored.
+     *
+     * @return  The IP identification value.
+     */
+    public short getIdentification() {
+        return getShort(IDENTIFICATION);
+    }
+
+    /**
+     * Gets the flag values stored.
+     *
+     * @return  The IPv4 flags.
+     */
+    public byte getFlags() {
+        return getByte(FLAGS);
+    }
+
+    /**
+     * Gets the TTL value stored.
+     *
+     * @return  The TTL value.
+     */
+    public byte getTtl() {
+        return getByte(TTL);
+    }
+
+    /**
+     * Gets the protocol value stored.
+     *
+     * @return  The IP protocol number.
+     */
+    public byte getProtocol() {
+        return getByte(PROTOCOL);
+    }
+
+    /**
+     * Gets the checksum value stored.
+     *
+     * @return  The IP header checksum.
+     */
+    public short getChecksum() {
+        return getShort(CHECKSUM);
+    }
+
+    /**
+     * Gets the fragment offset stored.
+     *
+     * @return  The IP fragment offset.
+     */
+    public short getFragmentOffset() {
+        return getShort(FRAGOFFSET);
+    }
+
+    /**
+     * Gets the source IP address stored.
+     *
+     * @return  An {@link Ip4Network} instance that represents the source
+     *          IP address.
+     */
+    public Ip4Network getSourceAddress() {
+        return getIp4Network(SIP);
+    }
+
+    /**
+     * Gets the destination IP address stored.
+     *
+     * @return  An {@link Ip4Network} instance that represents the destination
+     *          IP address.
+     */
+    public Ip4Network getDestinationAddress() {
+        return getIp4Network(DIP);
+    }
+
+    /**
+     * Gets the Options stored.
+     *
+     * @return  The IPv4 options. {@code null} if no option is present.
+     */
+    public byte[] getOptions() {
+        byte[] opts = getHeaderFieldMap().get(OPTIONS);
+        return (opts == null || opts.length == 0) ? null : opts.clone();
+    }
+
+    /**
+     * Stores the IP version from the header.
+     *
+     * @param version  The version to set
+     * @return  This instance.
+     */
+    public IPv4 setVersion(byte version) {
+        getHeaderFieldMap().put(VERSION, new byte[]{version});
+        return this;
+    }
+
+    /**
+     * Stores the length of IP header in words (4 bytes).
+     *
+     * @param len  The headerLength to set.
+     * @return  This instance.
+     */
+    public IPv4 setHeaderLength(byte len) {
+        getHeaderFieldMap().put(HEADERLENGTH, new byte[]{len});
+        return this;
+    }
+
+    /**
+     * Stores the differential services value from the IP header.
+     *
+     * @param  dserv  The differential services value.
+     * @return  This instance.
+     */
+    public IPv4 setDiffServ(byte dserv) {
+        getHeaderFieldMap().put(DIFFSERV, new byte[]{dserv});
+        return this;
+    }
+
+    /**
+     * Stores the ECN bits from the header.
+     *
+     * @param ecn  The ECN bits to set.
+     * @return  This instance.
+     */
+    public IPv4 setECN(byte ecn) {
+        getHeaderFieldMap().put(ECN, new byte[]{ecn});
+        return this;
+    }
+
+    /**
+     * Stores the total length of IPv4 packet in bytes.
+     *
+     * @param len  The total length of the IPv4 packet.
+     * @return  This instance.
+     */
+    public IPv4 setTotalLength(short len) {
+        getHeaderFieldMap().put(TOTLENGTH, toBytes(len));
+        return this;
+    }
+
+    /**
+     * Stores the identification number from the header.
+     *
+     * @param id  The identification to set.
+     * @return  This instance.
+     */
+    public IPv4 setIdentification(short id) {
+        getHeaderFieldMap().put(IDENTIFICATION, toBytes(id));
+        return this;
+    }
+
+    /**
+     * Stores the IP flags value.
+     *
+     * @param flags  The flags to set.
+     * @return  This instance.
+     */
+    public IPv4 setFlags(byte flags) {
+        getHeaderFieldMap().put(FLAGS, new byte[]{flags});
+        return this;
+    }
+
+    /**
+     * Stores the IP fragmentation offset value.
+     *
+     * @param off  The fragmentation offset.
+     * @return  This instance.
+     */
+    public IPv4 setFragmentOffset(short off) {
+        getHeaderFieldMap().put(FRAGOFFSET, toBytes(off));
+        return this;
+    }
+
+    /**
+     * Stores the TTL value.
+     *
+     * @param ttl  The ttl to set.
+     * @return  This instance.
+     */
+    public IPv4 setTtl(byte ttl) {
+        getHeaderFieldMap().put(TTL, new byte[]{ttl});
+        return this;
+    }
+
+    /**
+     * Stores the protocol value of the IP payload.
+     *
+     * @param proto  The protocol to set.
+     * @return  This instance.
+     */
+    public IPv4 setProtocol(byte proto) {
+        getHeaderFieldMap().put(PROTOCOL, new byte[]{proto});
+        return this;
+    }
+
+    /**
+     * Set the IP checksum value.
+     *
+     * <p>
+     *   This method is only for testing.
+     *   IP checksum will be updated on serialization.
+     * </p>
+     *
+     * @param cksum  The IP checksum.
+     * @return  This instance.
+     */
+    public IPv4 setChecksum(short cksum) {
+        getHeaderFieldMap().put(CHECKSUM, toBytes(cksum));
+        return this;
+    }
+
+    /**
+     * Stores the IP source address from the header.
+     *
+     * <p>
+     *   The network prefix in the given paramter is always ignored.
+     * </p>
+     *
+     * @param addr  The source IP address.
+     * @return  This instance.
+     */
+    public IPv4 setSourceAddress(Ip4Network addr) {
+        getHeaderFieldMap().put(SIP, addr.getBytes());
+        return this;
+    }
+
+    /**
+     * Stores the IP destination address from the header.
+     *
+     * <p>
+     *   The network prefix in the given paramter is always ignored.
+     * </p>
+     *
+     * @param addr  The destination IP address.
+     * @return  This instance.
+     */
+    public IPv4 setDestinationAddress(Ip4Network addr) {
+        getHeaderFieldMap().put(DIP, addr.getBytes());
+        return this;
+    }
+
+    /**
+     * Store the options from IP header.
+     *
+     * @param options  The IP options.
+     * @return  This instance.
+     */
+    public IPv4 setOptions(byte[] options) {
+        Map<String, byte[]> map = getHeaderFieldMap();
+        byte newIHL = DEFAULT_HEADER_LENGTH;
+        if (options == null || options.length == 0) {
+            map.remove(OPTIONS);
+        } else {
+            int len = options.length;
+            int mask = UNIT_SIZE - 1;
+            int rlen = (len + mask) & ~mask;
+            byte[] newopt;
+            if (rlen > len) {
+                // Padding is required.
+                newopt = new byte[rlen];
+                System.arraycopy(options, 0, newopt, 0, len);
+                len = rlen;
+            } else {
+                newopt = options.clone();
+            }
+            map.put(OPTIONS, newopt);
+            newIHL += ((len & MASK_BYTE) >>> UNIT_SIZE_SHIFT);
+        }
+
+        map.put(HEADERLENGTH, new byte[]{newIHL});
+        return this;
+    }
+
+    /**
+     * Computes the IPv4 header checksum on the passed stream of bytes
+     * representing the packet.
+     *
+     * @param data    The byte stream.
+     * @param start  The byte offset from where the IPv4 packet starts.
+     * @return The computed checksum
+     */
+    short computeChecksum(byte[] data, int start) {
+        int end = start + getHeaderLen() - 1;
+        int sum = 0;
+        int wordData;
+        int checksumStart = start + (getFieldOffset(CHECKSUM) / Byte.SIZE);
+
+        for (int i = start; i <= end; i += CKSUM_BYTES) {
+            // Skip, if the current bytes are checkSum bytes
+            if (i != checksumStart) {
+                wordData = ((data[i] & MASK_BYTE) << Byte.SIZE) |
+                    (data[i + 1] & MASK_BYTE);
+                sum = sum + wordData;
+            }
+        }
+
+        int carry = sum >>> Short.SIZE;
+        int finalSum = (sum & MASK_SHORT) + carry;
+        return (short)~((short)finalSum & MASK_SHORT);
+    }
+
+    // Packet
+
+    /**
+     * Gets the header size in bits.
+     *
+     * @return  The number of bits constituting the header.
+     */
+    @Override
+    public int getHeaderSize() {
+        int len = getHeaderLen();
+        if (len == 0) {
+            len = MIN_HEADER_SIZE;
+        }
+
+        return len * Byte.SIZE;
+    }
+
+    /**
+     * Gets the number of bits for the specified field.
+     *
+     * <p>
+     *   If the fieldname has variable length like "Options", then this value
+     *   is computed using the header length.
+     * </p>
+     *
+     * @param name   The name of the header field.
+     * @param entry  The header field entry associated with {@code name}.
+     * @return  The number of bits of the requested field.
+     */
+    @Override
+    protected int getFieldNumBits(String name, HeaderField entry) {
+        return (name.equals(OPTIONS))
+            ? (getHeaderLen() - MIN_HEADER_SIZE) * Byte.SIZE
+            : entry.getNumBits();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Map<String, HeaderField> getHeaderFormat() {
+        return HEADER_FORMAT;
+    }
+
+    /**
+     * Stores the value of fields read from data stream.
+     *
+     * <p>
+     *   Variable header value like payload protocol, is stored here.
+     * </p>
+     *
+     * @param name   The name of the header field.
+     * @param value  The value to be associated with the specified header
+     *               field. {@code null} cannot be specified.
+     */
+    @Override
+    protected void setHeaderField(String name, byte[] value) {
+        Map<String, byte[]> map = getHeaderFieldMap();
+        if (name.equals(PROTOCOL)) {
+            // Don't set payloadClass if framgment offset is not zero.
+            byte[] fragoff = map.get(FRAGOFFSET);
+            if (isZeroShort(fragoff)) {
+                setPayloadClass(getPayloadClass(value[0]));
+            }
+        } else if (name.equals(FRAGOFFSET)) {
+            if (!isZeroShort(value)) {
+                // Clear payloadClass because protocol header is not present
+                // in this packet.
+                setPayloadClass(null);
+            }
+        } else if (name.equals(OPTIONS) &&
+                   (value == null || value.length == 0)) {
+            map.remove(name);
+            return;
+        }
+        map.put(name, value);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected boolean equalsField(String name, byte[] value1, byte[] value2) {
+        return (name.equals(OPTIONS))
+            ? Arrays.equals(value1, value2)
+            : super.equalsField(name, value1, value2);
+    }
+
+    /**
+     * Set the packet encapsulated by this IPv4 packet.
+     *
+     * <p>
+     *   This method updates the total length of the IPv4 packet.
+     * </p>
+     *
+     * @param p  The packet encapsulated by this IPv4 packet.
+     */
+    @Override
+    public void setPayload(Packet p) {
+        super.setPayload(p);
+
+        if (p != null) {
+            // Determine the total length.
+            int plen;
+            try {
+                plen = p.serialize().length;
+            } catch (PacketException e) {
+                throw new IllegalStateException(
+                    "Failed to serialize the specified payload.", e);
+            }
+
+            setTotalLength((short)(getHeaderLen() + plen));
+        }
+    }
+
+    /**
+     * This method gets called at the end of the serialization process.
+     *
+     * <p>
+     *   This method computes the IP checksum and stores it into the IP header.
+     * </p>
+     *
+     * @param myBytes  Serialized bytes.
+     * @throws PacketException  An error occurred.
+     */
+    @Override
+    protected void postSerializeCustomOperation(byte[] myBytes)
+        throws PacketException {
+        try {
+            Map<String, byte[]> map = getHeaderFieldMap();
+            String field = TOTLENGTH;
+            HeaderField entry = HEADER_FORMAT.get(field);
+            int off = getFieldOffset(field, entry);
+            int nbits = getFieldNumBits(field, entry);
+
+            // Recompute the total length field here.
+            byte[] total = toBytes((short)myBytes.length);
+            ByteUtils.setBits(myBytes, total, off, nbits);
+            map.put(TOTLENGTH, total);
+
+            // Compute the header checksum.
+            field = CHECKSUM;
+            entry = HEADER_FORMAT.get(field);
+            off = getFieldOffset(field, entry);
+            nbits = getFieldNumBits(field, entry);
+            byte[] cksum = toBytes(computeChecksum(myBytes, 0));
+            ByteUtils.setBits(myBytes, cksum, off, nbits);
+            map.put(CHECKSUM, cksum);
+        } catch (RuntimeException e) {
+            throw new PacketException("Failed to update checksum.", e);
+        }
+    }
+
+    /**
+     * This method re-computes the checksum of the bits received on the wire
+     * and validates it with the checksum in the bits received.
+     *
+     * @param data   The byte stream representing the Ethernet frame.
+     * @param offset The bit offset from where the byte array corresponding to
+     *               this Packet starts in the frame
+     */
+    @Override
+    protected void postDeserializeCustomOperation(byte[] data, int offset) {
+        short computed = computeChecksum(data, offset / Byte.SIZE);
+        short actual = getChecksum();
+        if (computed != actual) {
+            setCorrupted(true);
+        }
+    }
+
+    // Object
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public IPv4 clone() {
+        return (IPv4)super.clone();
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/Packet.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/Packet.java
new file mode 100644 (file)
index 0000000..6938c37
--- /dev/null
@@ -0,0 +1,811 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.util.NumberUtils.HASH_PRIME;
+import static org.opendaylight.vtn.manager.util.NumberUtils.toInteger;
+import static org.opendaylight.vtn.manager.util.NumberUtils.toShort;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map.Entry;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.opendaylight.vtn.manager.util.ByteUtils;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+
+/**
+ * {@code Packet} is an abstract class which represents the generic network
+ * packet object.
+ *
+ * <p>
+ *   It provides the basic methods which are common for all the packets,
+ *   like serialize and deserialize.
+ * </p>
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public abstract class Packet implements Cloneable {
+    /**
+     * Logger instance.
+     */
+    private static final Logger  LOG = LoggerFactory.getLogger(Packet.class);
+
+    /**
+     * Determine whether this packet is corrupted or not.
+     */
+    private boolean  corrupted;
+
+    /**
+     * The packet encapsulated by this packet.
+     */
+    private Packet  payload;
+
+    /**
+     * The unparsed raw payload carried by this packet.
+     */
+    private byte[]  rawPayload;
+
+    /**
+     * Header fields values.
+     */
+    private Map<String, byte[]>  hdrFieldsMap = new HashMap<>();
+
+    /**
+     * The class of the encapsulated packet object.
+     */
+    private Class<? extends Packet>  payloadClass;
+
+    /**
+     * {@code HeaderField} describes the location of the header field in the
+     * packet header.
+     */
+    static final class HeaderField {
+        /**
+         * The start bit offset for the header field.
+         */
+        private final int  offset;
+
+        /**
+         * The number of bits in the header field.
+         */
+        private final int  numBits;
+
+        /**
+         * The number of bytes in the buffer used to keep the value.
+         */
+        private final int  size;
+
+        /**
+         * Construct a new instance.
+         *
+         * @param off     The start bit offset for the header field.
+         * @param nbits   The number of bits in the header field.
+         * @param nbytes  The number of bytes in the buffer used to keep
+         *                the value.
+         */
+        private HeaderField(int off, int nbits, int nbytes) {
+            offset = off;
+            numBits = nbits;
+            size = nbytes;
+        }
+
+        /**
+         * Return the start bit offset for the header field.
+         *
+         * @return  The start offset bit for the header field.
+         */
+        int getOffset() {
+            return offset;
+        }
+
+        /**
+         * Return the number of bits in the header field.
+         *
+         * @return  The number of bits in the header field.
+         */
+        int getNumBits() {
+            return numBits;
+        }
+
+        /**
+         * Return the size of the buffer for the header field.
+         *
+         * @return  The number of bytes in the buffer used to keep the value.
+         */
+        int getSize() {
+            return size;
+        }
+
+        /**
+         * Return the hash code of the given value.
+         *
+         * @param value  A value associated with this header field.
+         * @return  The hash code of the given value.
+         */
+        int hash(byte[] value) {
+            byte[] v = value;
+            assert v == null || v.length == size;
+
+            if (v == null && size != 0) {
+                // Compute the hash code of the default value.
+                v = new byte[size];
+            }
+
+            return Arrays.hashCode(v);
+        }
+    }
+
+    /**
+     * Internal utility class to generate header format map.
+     *
+     * <p>
+     *   The order of the header fields iteration is the order in which its
+     *   entries were added.
+     * </p>
+     */
+    static final class HeaderMapBuilder {
+        /**
+         * A immutable map builder.
+         */
+        private final ImmutableMap.Builder<String, HeaderField> builder =
+            ImmutableMap.<String, HeaderField>builder();
+
+        /**
+         * The bit offset fot the next field.
+         */
+        private int  offset;
+
+        /**
+         * Add a new header field that keeps a byte array.
+         *
+         * @param name   The name of the header field.
+         * @param nbits  The number of bits in the header field.
+         * @return  This instance.
+         */
+        HeaderMapBuilder addByte(String name, int nbits) {
+            int size = (nbits + Byte.SIZE - 1) / Byte.SIZE;
+            return add(name, nbits, size);
+        }
+
+        /**
+         * Add a new header field that keeps a number.
+         *
+         * @param name   The name of the header field.
+         * @param nbits  The number of bits in the header field.
+         * @return  This instance.
+         */
+        HeaderMapBuilder addNumber(String name, int nbits) {
+            int size = (nbits + Byte.SIZE - 1) / Byte.SIZE;
+            if (size != 0) {
+                // Round up the size to a power of 2.
+                int leading = Integer.numberOfLeadingZeros(size);
+                int trailing = Integer.numberOfTrailingZeros(size);
+                if (leading + trailing < Integer.SIZE - 1) {
+                    size = 1 << (Integer.SIZE - leading);
+                }
+            }
+
+            return add(name, nbits, size);
+        }
+
+        /**
+         * Add a new header field.
+         *
+         * @param name   The name of the header field.
+         * @param nbits  The number of bits in the header field.
+         * @param size   The number of bytes in the buffer used to keep the
+         *               value.
+         * @return  This instance.
+         */
+        private HeaderMapBuilder add(String name, int nbits, int size) {
+            HeaderField field = new HeaderField(offset, nbits, size);
+            builder.put(name, field);
+            offset += nbits;
+            return this;
+        }
+
+        /**
+         * Create a new header field map.
+         *
+         * @return  A map that determines the format of the header fields.
+         */
+        Map<String, HeaderField> build() {
+            return builder.build();
+        }
+    }
+
+    /**
+     * Construct a new instance.
+     */
+    Packet() {
+    }
+
+    /**
+     * Return the packet encapsulated by this packet.
+     *
+     * @return  The packet encapsulated by this packet if present.
+     *          {@code null} if not present.
+     */
+    public final Packet getPayload() {
+        return payload;
+    }
+
+    /**
+     * Set the packet encapsulated by this packet.
+     *
+     * @param p  The packet encapsulated by this packet.
+     */
+    public void setPayload(Packet p) {
+        payload = p;
+    }
+
+    /**
+     * This method deserializes the data bits obtained from the wire into the
+     * respective header and payload which are of type Packet.
+     *
+     * @param data       Data from wire to deserialize.
+     * @param bitOffset  Bit position where packet header starts in data array.
+     * @param size       Size of packet in bits.
+     * @return  This instance.
+     * @throws PacketException  An error occurred.
+     */
+    public Packet deserialize(byte[] data, int bitOffset, int size)
+        throws PacketException {
+        // Deserialize the header fields one by one.
+        int startOffset = 0;
+        int numBits = 0;
+        payloadClass = null;
+        Map<String, HeaderField> fmtMap = getHeaderFormat();
+        for (Entry<String, HeaderField> entry: fmtMap.entrySet()) {
+            String hdrField = entry.getKey();
+            HeaderField hent = entry.getValue();
+            startOffset = bitOffset + getFieldOffset(hdrField, hent);
+            numBits = getFieldNumBits(hdrField, hent);
+
+            byte[] hdrFieldBytes;
+            try {
+                hdrFieldBytes = ByteUtils.getBits(data, startOffset, numBits);
+            } catch (RuntimeException e) {
+                String msg = "Failed to deserialize field: " + hdrField +
+                    ": off=" + startOffset + ", size=" + numBits +
+                    ", total=" + size;
+                throw new PacketException(msg, e);
+            }
+
+            /*
+             * Store the raw read value, checks the payload type and set the
+             * payloadClass accordingly
+             */
+            setHeaderField(hdrField, hdrFieldBytes);
+
+            if (LOG.isTraceEnabled()) {
+                LOG.trace("Deserializing: {}: {}: {} (offset {} bitsize {})",
+                          getClass().getSimpleName(), hdrField,
+                          ByteUtils.toHexString(hdrFieldBytes),
+                          startOffset, numBits);
+            }
+        }
+
+        // Deserialize the payload now
+        int payloadStart = startOffset + numBits;
+        int payloadSize = data.length * Byte.SIZE - payloadStart;
+
+        if (payloadClass != null) {
+            try {
+                payload = payloadClass.newInstance();
+            } catch (Exception e) {
+                throw new PacketException(
+                    "Error parsing payload for Ethernet packet", e);
+            }
+            payload.deserialize(data, payloadStart, payloadSize);
+        } else if (payloadSize > 0) {
+            /*
+             *  The payload class was not set, it means no class for parsing
+             *  this payload is present. Let's store the raw payload if any.
+             */
+            int start = payloadStart / Byte.SIZE;
+            int stop = start + payloadSize / Byte.SIZE;
+            rawPayload = Arrays.copyOfRange(data, start, stop);
+        }
+
+        // Take care of computation that can be done only after deserialization
+        postDeserializeCustomOperation(data, payloadStart - getHeaderSize());
+
+        return this;
+    }
+
+    /**
+     * This method serializes the header and payload from the respective
+     * packet class, into a single stream of bytes to be sent on the wire.
+     *
+     * @return  The byte array representing the serialized Packet.
+     * @throws PacketException  An error occurred.
+     */
+    public byte[] serialize() throws PacketException {
+        // Acquire or compute the serialized payload
+        byte[] payloadBytes = null;
+        if (payload != null) {
+            payloadBytes = payload.serialize();
+        } else if (rawPayload != null) {
+            payloadBytes = rawPayload;
+        }
+
+        int payloadSize = (payloadBytes == null) ? 0 : payloadBytes.length;
+
+        // Allocate the buffer to contain the full (header + payload) packet
+        int headerSize = getHeaderSize() / Byte.SIZE;
+        byte[] packetBytes = new byte[headerSize + payloadSize];
+        if (payloadSize != 0) {
+            System.arraycopy(payloadBytes, 0, packetBytes, headerSize,
+                             payloadSize);
+        }
+
+        // Serialize this packet header, field by field
+        Map<String, HeaderField> fmtMap = getHeaderFormat();
+        for (Entry<String, HeaderField> entry: fmtMap.entrySet()) {
+            String field = entry.getKey();
+            HeaderField hent = entry.getValue();
+            byte[] fieldBytes = hdrFieldsMap.get(field);
+            // Let's skip optional fields when not set
+            if (fieldBytes != null) {
+                int off = getFieldOffset(field, hent);
+                int nbits = getFieldNumBits(field, hent);
+                try {
+                    ByteUtils.setBits(packetBytes, fieldBytes, off, nbits);
+                } catch (RuntimeException e) {
+                    String msg = "Failed to serialize field: " + field +
+                        ": off=" + off + ", size=" + nbits +
+                        ", total=" + fieldBytes.length;
+                    throw new PacketException(msg, e);
+                }
+            }
+        }
+
+        // Perform post serialize operations (like checksum computation)
+        postSerializeCustomOperation(packetBytes);
+
+        if (LOG.isTraceEnabled()) {
+            LOG.trace("Serialized: {}: {}", getClass().getSimpleName(),
+                      ByteUtils.toHexString(packetBytes));
+        }
+
+        return packetBytes;
+    }
+
+    /**
+     * This method gets called at the end of the serialization process.
+     *
+     * It is intended for the child packets to insert some custom data into the
+     * output byte stream which cannot be done or cannot be done efficiently
+     * during the normal Packet.serialize() path. An example is the checksum
+     * computation for IPv4.
+     *
+     * @param myBytes  Serialized bytes.
+     * @throws PacketException  An error occurred.
+     */
+    protected void postSerializeCustomOperation(byte[] myBytes)
+        throws PacketException {
+    }
+
+    /**
+     * This method re-computes the checksum of the bits received on the wire
+     * and validates it with the checksum in the bits received.
+     *
+     * Since the computation of checksum varies based on the protocol,
+     * this method is overridden. Currently only IPv4 and ICMP do checksum
+     * computation and validation. TCP and UDP need to implement these if
+     * required.
+     *
+     * @param data   The byte stream representing the Ethernet frame.
+     * @param offset The bit offset from where the byte array corresponding to
+     *               this Packet starts in the frame
+     * @throws PacketException  An error occurred.
+     */
+    protected void postDeserializeCustomOperation(byte[] data, int offset)
+        throws PacketException {
+    }
+
+    /**
+     * Set a class that specifies the type of packets encapsulated by this
+     * packet.
+     *
+     * @param cls  A class that specifies the type of the payload packet.
+     */
+    protected final void setPayloadClass(Class<? extends Packet> cls) {
+        payloadClass = cls;
+    }
+
+    /**
+     * Associate the specified value with the specified header field.
+     *
+     * @param name   The name of the header field.
+     * @param value  The value to be associated with the specified header
+     *               field. {@code null} cannot be specified.
+     */
+    protected void setHeaderField(String name, byte[] value) {
+        hdrFieldsMap.put(name, value);
+    }
+
+    /**
+     * Return a map that keeps packet header fields.
+     *
+     * @return  A map that keeps packet header fields.
+     */
+    protected final Map<String, byte[]> getHeaderFieldMap() {
+        return hdrFieldsMap;
+    }
+
+    /**
+     * Gets the header length in bits.
+     *
+     * @return  The header length in bits.
+     */
+    public int getHeaderSize() {
+        int size = 0;
+
+        /*
+         * We need to iterate over the fields that were read in the frame
+         * (hdrFieldsMap) not all the possible ones described in the map
+         * returned by getHeaderFormat().
+         * For ex, 802.1Q may or may not be there
+         */
+        Map<String, HeaderField> fmtMap = getHeaderFormat();
+        for (Entry<String, byte[]> fieldEntry: hdrFieldsMap.entrySet()) {
+            if (fieldEntry.getValue() != null) {
+                String field = fieldEntry.getKey();
+                size += getFieldNumBits(field, fmtMap.get(field));
+            }
+        }
+        return size;
+    }
+
+    /**
+     * This method fetches the start bit offset for header field specified by
+     * {@code name}.
+     *
+     * @param name   The name of the header field.
+     * @return  The offset of the requested field.
+     */
+    public final int getFieldOffset(String name) {
+        return getFieldOffset(name, getHeaderFormat().get(name));
+    }
+
+    /**
+     * This method fetches the number of bits for header field specified by
+     * {@code name}.
+     *
+     * @param name  The name of the header field.
+     * @return  The number of bits of the requested field.
+     */
+    public final int getFieldNumBits(String name) {
+        return getFieldNumBits(name, getHeaderFormat().get(name));
+    }
+
+    /**
+     * Returns the raw payload carried by this packet in case payload was not
+     * parsed. Caller can call this function in case the getPaylod() returns
+     * {@code null}.
+     *
+     * @return  The raw payload if not parsable as an array of bytes.
+     *         {@code null} otherwise
+     */
+    public byte[] getRawPayload() {
+        return (rawPayload == null) ? null : rawPayload.clone();
+    }
+
+    /**
+     * Set a raw payload in the packet class.
+     *
+     * @param bytes  The raw payload as byte array.
+     */
+    public void setRawPayload(byte[] bytes) {
+        rawPayload = (bytes == null || bytes.length == 0)
+            ? null : bytes.clone();
+    }
+
+    /**
+     * Return whether the deserialized packet is to be considered corrupted.
+     * This is the case when the checksum computed after reconstructing the
+     * packet received from wire is not equal to the checksum read from the
+     * stream. For the Packet class which do not have a checksum field, this
+     * function will always return false.
+     *
+     * @return true if the deserialized packet's recomputed checksum is not
+     *         equal to the packet carried checksum
+     */
+    public final boolean isCorrupted() {
+        return corrupted;
+    }
+
+    /**
+     * Set a boolean value which determines whether this packet is corrupted
+     * or not.
+     *
+     * @param c  {@code true} indicates that this packet is corrupted.
+     */
+    protected final void setCorrupted(boolean c) {
+        corrupted = c;
+    }
+
+    /**
+     * Return the size of the raw payload in this packet.
+     *
+     * @return  The number of bytes in the raw payload.
+     */
+    protected final int getRawPayloadSize() {
+        return (rawPayload == null) ? 0 : rawPayload.length;
+    }
+
+    /**
+     * Return the offset of the header field configured in the given instance.
+     *
+     * @param name   The name of the header field.
+     * @param entry  The header field entry associated with {@code name}.
+     * @return  The offset of the requested field.
+     */
+    protected int getFieldOffset(String name, HeaderField entry) {
+        return entry.getOffset();
+    }
+
+    /**
+     * Return the number of bits in the header field configured in the given
+     * instance.
+     *
+     * @param name   The name of the header field.
+     * @param entry  The header field entry associated with {@code name}.
+     * @return  The number of bits of the requested field.
+     */
+    protected int getFieldNumBits(String name, HeaderField entry) {
+        return entry.getNumBits();
+    }
+
+    /**
+     * Compare the given header field values.
+     *
+     * @param name    The name of the header field.
+     * @param value1  The first header field value to be compared.
+     * @param value2  The second header field value to be compared.
+     * @return  {@code true} only if the given two header field values are
+     *          identical.
+     */
+    protected boolean equalsField(String name, byte[] value1, byte[] value2) {
+        boolean ret = (value1 == value2);
+        if (!ret) {
+            // null is identical to zero.
+            byte[] v1 = value1;
+            byte[] v2 = value2;
+            if (v1 == null) {
+                v1 = new byte[v2.length];
+            } else if (v2 == null) {
+                v2 = new byte[v1.length];
+            }
+            ret = Arrays.equals(v1, v2);
+        }
+
+        return ret;
+    }
+
+    /**
+     * Return the value of the specified field as a byte array.
+     *
+     * @param name  The name of the field.
+     * @return  A byte array.
+     */
+    protected final byte[] getBytes(String name) {
+        byte[] value = hdrFieldsMap.get(name);
+        return (value == null) ? null : value.clone();
+    }
+
+    /**
+     * Return the value of the specified field as a byte.
+     *
+     * @param name  The name of the field.
+     * @return  A byte value.
+     */
+    protected final byte getByte(String name) {
+        byte[] value = hdrFieldsMap.get(name);
+        return (value == null) ? 0 : value[0];
+    }
+
+    /**
+     * Return the value of the specified field as an integer.
+     *
+     * @param name  The name of the field.
+     * @return  An integer value.
+     */
+    protected final int getInt(String name) {
+        byte[] value = hdrFieldsMap.get(name);
+        return (value == null) ? 0 : toInteger(value);
+    }
+
+    /**
+     * Return the value of the specified field as a short integer.
+     *
+     * @param name  The name of the field.
+     * @return  A short integer value.
+     */
+    protected final short getShort(String name) {
+        byte[] value = hdrFieldsMap.get(name);
+        return (value == null) ? 0 : toShort(value);
+    }
+
+    /**
+     * Return the value of the specified field as an IPv4 address.
+     *
+     * @param name  The name of the field.
+     * @return  An {@link Ip4Network} instance.
+     */
+    protected final Ip4Network getIp4Network(String name) {
+        byte[] value = hdrFieldsMap.get(name);
+        return (value == null) ? new Ip4Network(0) : new Ip4Network(value);
+    }
+
+    /**
+     * Determine whether the given value represents a zero short value or not.
+     *
+     * @param value  A byte array that contains a short integer.
+     * @return  {@code true} only if the given value represents a zero.
+     */
+    protected final boolean isZeroShort(byte[] value) {
+        return (value == null || toShort(value) == 0);
+    }
+
+    /**
+     * Return a map that determines the format of the packet.
+     *
+     * @return  A map that determines the format of the packet.
+     */
+    protected abstract Map<String, HeaderField> getHeaderFormat();
+
+    /**
+     * Compute the hash code of the header field map.
+     *
+     * @return  The hash code of the header field map.
+     */
+    private int headerHashCode() {
+        int h = 0;
+        Map<String, HeaderField> fmtMap = getHeaderFormat();
+        for (Entry<String, HeaderField> entry: fmtMap.entrySet()) {
+            String field = entry.getKey();
+            HeaderField hf = entry.getValue();
+            h += (field.hashCode() ^ hf.hash(hdrFieldsMap.get(field)));
+        }
+
+        return h;
+    }
+
+    /**
+     * Determine whether the given header field map is equal to the map
+     * configured in this instance or not.
+     *
+     * @param map  The header field map to be compared.
+     *             Specifying {@code null} results in undefined behavior.
+     * @return  {@code true} only if the given map is equal to the header
+     *          field map in this instance.
+     */
+    private boolean headerEquals(Map<String, byte[]> map) {
+        for (String field: getHeaderFormat().keySet()) {
+            byte[] myData = hdrFieldsMap.get(field);
+            byte[] data = map.get(field);
+            if (!equalsField(field, myData, data)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Create a deep copy of the header field map in this packet.
+     *
+     * @return  A deep copy of the header field map in this packet.
+     */
+    private Map<String, byte[]> headerClone() {
+        Map<String, byte[]> copy = new HashMap<>();
+        for (Entry<String, byte[]> entry: hdrFieldsMap.entrySet()) {
+            String field = entry.getKey();
+            byte[] data = entry.getValue();
+            copy.put(field, data.clone());
+        }
+
+        return copy;
+    }
+
+    // Object
+
+    /**
+     * Return the hash code of this object.
+     *
+     * <p>
+     *   Note that this method never uses the payload to compute the hash code.
+     * </p>
+     *
+     * @return  The hash code.
+     */
+    @Override
+    public final int hashCode() {
+        return getClass().hashCode() * HASH_PRIME + headerHashCode();
+    }
+
+    /**
+     * Determine whether the given object is identical to this object.
+     *
+     * <p>
+     *   Note that this method never compares the payload encapsulated by
+     *   the packet.
+     * </p>
+     *
+     * @param o  An object to be compared.
+     * @return   {@code true} if identical. Otherwise {@code false}.
+     */
+    @Override
+    public final boolean equals(Object o) {
+        boolean ret = (o == this);
+        if (!ret && o != null && getClass().equals(o.getClass())) {
+            Packet pkt = (Packet)o;
+            ret = headerEquals(pkt.hdrFieldsMap);
+        }
+
+        return ret;
+    }
+
+    /**
+     * Return a string representation of this object.
+     *
+     * @return  A string representation of this object.
+     */
+    @Override
+    public final String toString() {
+        StringBuilder builder = new StringBuilder().
+            append(getClass().getSimpleName()).append('{');
+        String sep = "";
+        for (String field: getHeaderFormat().keySet()) {
+            byte[] value = hdrFieldsMap.get(field);
+            builder.append(sep).append(field).append('=').
+                append(ByteUtils.toHexString(value));
+            sep = ", ";
+        }
+
+        return builder.append('}').toString();
+    }
+
+    /**
+     * Return a deep copy of this packet.
+     *
+     * @return  A deep copy of this packet.
+     */
+    @Override
+    public Packet clone() {
+        try {
+            Packet copy = (Packet)super.clone();
+            copy.hdrFieldsMap = headerClone();
+
+            // Copy the payload.
+            // Note that we don't need to copy raw payload because it is
+            // never modified.
+            if (payload != null) {
+                copy.payload = payload.clone();
+            }
+
+            return copy;
+        } catch (CloneNotSupportedException e) {
+            throw new IllegalStateException("clone() failed", e);
+        }
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/PacketException.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/PacketException.java
new file mode 100644 (file)
index 0000000..2e465c6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import org.opendaylight.vtn.manager.VTNException;
+
+/**
+ * {@code VTNException} is an exception raised when the packet serialization
+ * or deserialization fails.
+ *
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public final class PacketException extends VTNException {
+    /**
+     * Version number for serialization.
+     */
+    private static final long serialVersionUID = -257294779623090915L;
+
+    /**
+     * Construct a new exception.
+     *
+     * @param msg   The detailed message.
+     */
+    public PacketException(String msg) {
+        super(msg);
+    }
+
+    /**
+     * Construct a new exception with specifying the cause of error.
+     *
+     * @param msg    The detailed message.
+     * @param cause  The {@link Throwable} object which indicates the cause
+     *               of error.
+     */
+    public PacketException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/TCP.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/TCP.java
new file mode 100644 (file)
index 0000000..565174f
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.util.NumberUtils.toBytes;
+
+import java.util.Map;
+
+/**
+ * {@code TCP} describes an TCP packet.
+ *
+ * <p>
+ *   TCP option is not supported. TCP option is treated as a part of TCP
+ *   payload.e
+ * </p>
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public final class TCP extends Packet {
+    /**
+     * The number of bits in the TCP header, excluding options.
+     */
+    private static final int  HEADER_SIZE = 160;
+
+    /**
+     * The field name that indicates the source port number.
+     */
+    private static final String  SRCPORT = "SourcePort";
+
+    /**
+     * The field name that indicates the destination port number.
+     */
+    private static final String  DESTPORT = "DestinationPort";
+
+    /**
+     * The field name that indicates the TCP sequence number.
+     */
+    private static final String  SEQNUMBER = "SequenceNumber";
+
+    /**
+     * The field name that indicates the TCP acknowledgement number.
+     */
+    private static final String  ACKNUMBER = "AcknowledgementNumber";
+
+    /**
+     * The field name that indicates the data offset.
+     */
+    private static final String  DATAOFFSET = "DataOffset";
+
+    /**
+     * The field name that indicates the reserved field.
+     */
+    private static final String  RESERVED = "Reserved";
+
+    /**
+     * The field name that indicates the header length and TCP flags.
+     */
+    private static final String  HEADERLENFLAGS = "HeaderLenFlags";
+
+    /**
+     * The field name that indicates the TCP window size.
+     */
+    private static final String  WINDOWSIZE = "WindowSize";
+
+    /**
+     * The field name that indicates the TCP checksum.
+     */
+    private static final String  CHECKSUM = "Checksum";
+
+    /**
+     * The field name that indicates the urgent pointer.
+     */
+    private static final String  URGENTPOINTER = "UrgentPointer";
+
+    /**
+     * The number of bits in the data offset field.
+     */
+    private static final int  BITS_DATAOFFSET = 4;
+
+    /**
+     * The number of bits in the reserved field.
+     */
+    private static final int  BITS_RESERVED = 3;
+
+    /**
+     * The number of bits in the header length and TCP flags field.
+     */
+    private static final int  BITS_HEADERLENFLAGS = 9;
+
+    /**
+     * A map that determines the TCP packet header format.
+     */
+    private static final Map<String, HeaderField>  HEADER_FORMAT;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        HEADER_FORMAT = new HeaderMapBuilder().
+            addNumber(SRCPORT, Short.SIZE).
+            addNumber(DESTPORT, Short.SIZE).
+            addNumber(SEQNUMBER, Integer.SIZE).
+            addNumber(ACKNUMBER, Integer.SIZE).
+            addNumber(DATAOFFSET, BITS_DATAOFFSET).
+            addNumber(RESERVED, BITS_RESERVED).
+            addNumber(HEADERLENFLAGS, BITS_HEADERLENFLAGS).
+            addNumber(WINDOWSIZE, Short.SIZE).
+            addNumber(CHECKSUM, Short.SIZE).
+            addNumber(URGENTPOINTER, Short.SIZE).
+            build();
+    }
+
+    /**
+     * Sets the TCP source port for the current TCP object instance.
+     *
+     * @param port  The source port number.
+     * @return  This instance.
+     */
+    public TCP setSourcePort(short port) {
+        getHeaderFieldMap().put(SRCPORT, toBytes(port));
+        return this;
+    }
+
+    /**
+     * Sets the TCP destination port for the current TCP object instance.
+     *
+     * @param port  The destination port number.
+     * @return  This instance.
+     */
+    public TCP setDestinationPort(short port) {
+        getHeaderFieldMap().put(DESTPORT, toBytes(port));
+        return this;
+    }
+
+    /**
+     * Sets the TCP sequence number for the current TCP object instance.
+     *
+     * @param seq  The TCP sequence number.
+     * @return  This instance.
+     */
+    public TCP setSequenceNumber(int seq) {
+        getHeaderFieldMap().put(SEQNUMBER, toBytes(seq));
+        return this;
+    }
+
+    /**
+     * Sets the TCP data offset for the current TCP object instance.
+     *
+     * @param off  The TCP data offset.
+     * @return  This instance.
+     */
+    public TCP setDataOffset(byte off) {
+        getHeaderFieldMap().put(DATAOFFSET, new byte[]{off});
+        return this;
+    }
+
+    /**
+     * Sets the TCP reserved bits for the current TCP object instance.
+     *
+     * @param resv  The reserved field value.
+     * @return  This instance.
+     */
+    public TCP setReserved(byte resv) {
+        getHeaderFieldMap().put(RESERVED, new byte[]{resv});
+        return this;
+    }
+
+    /**
+     * Sets the TCP Ack number for the current TCP object instance.
+     *
+     * @param acq  The TCP acknowledgement number.
+     * @return  This instance.
+     */
+    public TCP setAckNumber(int acq) {
+        getHeaderFieldMap().put(ACKNUMBER, toBytes(acq));
+        return this;
+    }
+
+    /**
+     * Sets the TCP flags for the current TCP object instance.
+     *
+     * @param flags  The TCP flags.
+     * @return  This instance.
+     */
+    public TCP setHeaderLenFlags(short flags) {
+        getHeaderFieldMap().put(HEADERLENFLAGS, toBytes(flags));
+        return this;
+    }
+
+    /**
+     * Sets the TCP window size for the current TCP object instance.
+     *
+     * @param wsize  The TCP window size.
+     * @return  This instance.
+     */
+    public TCP setWindowSize(short wsize) {
+        getHeaderFieldMap().put(WINDOWSIZE, toBytes(wsize));
+        return this;
+    }
+
+    /**
+     * Sets the TCP checksum for the current TCP object instance.
+     *
+     * @param cksum  The TCP checksum.
+     * @return  This instance.
+     */
+    public TCP setChecksum(short cksum) {
+        getHeaderFieldMap().put(CHECKSUM, toBytes(cksum));
+        return this;
+    }
+
+    /**
+     * Sets the TCP Urgent Pointer for the current TCP object instance.
+     *
+     * @param urg  The TCP urgent pointer.
+     * @return  This instance.
+     */
+    public TCP setUrgentPointer(short urg) {
+        getHeaderFieldMap().put(URGENTPOINTER, toBytes(urg));
+        return this;
+    }
+
+    /**
+     * Gets the stored source port value of TCP header.
+     *
+     * @return  The source port number.
+     */
+    public short getSourcePort() {
+        return getShort(SRCPORT);
+    }
+
+    /**
+     * Gets the stored destination port value of TCP header.
+     *
+     * @return  The destination port number.
+     */
+    public short getDestinationPort() {
+        return getShort(DESTPORT);
+    }
+
+    /**
+     * Return the TCP sequence number.
+     *
+     * @return  The TCP sequence number.
+     */
+    public int getSequenceNumber() {
+        return getInt(SEQNUMBER);
+    }
+
+    /**
+     * Return the TCP data offset.
+     *
+     * @return  The TCP data offset.
+     */
+    public byte getDataOffset() {
+        return getByte(DATAOFFSET);
+    }
+
+    /**
+     * Return the reserved field value.
+     *
+     * @return  The value configured in the reserved field.
+     */
+    public byte getReserved() {
+        return getByte(RESERVED);
+    }
+
+    /**
+     * Return the TCP acknowledgement number.
+     *
+     * @return  The TCP acknowledgement number.
+     */
+    public int getAckNumber() {
+        return getInt(ACKNUMBER);
+    }
+
+    /**
+     * Return the TCP header length and flags.
+     *
+     * @return  The value of TCP header length and flags.
+     */
+    public short getHeaderLenFlags() {
+        return getShort(HEADERLENFLAGS);
+    }
+
+    /**
+     * Return the TCP window size.
+     *
+     * @return  The TCP window size.
+     */
+    public short getWindowSize() {
+        return getShort(WINDOWSIZE);
+    }
+
+    /**
+     * Get the stored checksum value of the TCP header.
+     *
+     * @return  The TCP checksum.
+     */
+    public short getChecksum() {
+        return getShort(CHECKSUM);
+    }
+
+    /**
+     * Return the TCP urgent pointer.
+     *
+     * @return  The TCP urgent pointer.
+     */
+    public short getUrgentPointer() {
+        return getShort(URGENTPOINTER);
+    }
+
+    // Packet
+
+    /**
+     * Gets the header size in bits.
+     *
+     * @return The TCP header size in bits.
+     */
+    @Override
+    public int getHeaderSize() {
+        return HEADER_SIZE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Map<String, HeaderField> getHeaderFormat() {
+        return HEADER_FORMAT;
+    }
+
+    // Object
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public TCP clone() {
+        return (TCP)super.clone();
+    }
+}
diff --git a/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/UDP.java b/manager/api/src/main/java/org/opendaylight/vtn/manager/packet/UDP.java
new file mode 100644 (file)
index 0000000..9fdaa83
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.util.NumberUtils.toBytes;
+
+import java.util.Map;
+
+/**
+ * {@code UDP} describes an UDP packet.
+ *
+ * <p>
+ *   This class is provided only for VTN internal use.
+ *   This class may be changed without any notice.
+ * </p>
+ *
+ * @since  Beryllium
+ */
+public final class UDP extends Packet {
+    /**
+     * The number of bits in the UDP header.
+     */
+    private static final int  HEADER_SIZE = 64;
+
+    /**
+     * The field name that indicates the source port number.
+     */
+    private static final String  SRCPORT = "SourcePort";
+
+    /**
+     * The field name that indicates the destination port number.
+     */
+    private static final String  DESTPORT = "DestinationPort";
+
+    /**
+     * The field name that indicates the packet length.
+     */
+    private static final String  LENGTH = "Length";
+
+    /**
+     * The field name that indicates the UDP checksum.
+     */
+    private static final String  CHECKSUM = "Checksum";
+
+    /**
+     * A map that determines the UDP packet header format.
+     */
+    private static final Map<String, HeaderField>  HEADER_FORMAT;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        HEADER_FORMAT = new HeaderMapBuilder().
+            addNumber(SRCPORT, Short.SIZE).
+            addNumber(DESTPORT, Short.SIZE).
+            addNumber(LENGTH, Short.SIZE).
+            addNumber(CHECKSUM, Short.SIZE).
+            build();
+    }
+
+    /**
+     * Get the stored source port.
+     *
+     * @return  The source port number.
+     */
+    public short getSourcePort() {
+        return getShort(SRCPORT);
+    }
+
+    /**
+     * Get the stored destination port.
+     *
+     * @return  The destination port number.
+     */
+    public short getDestinationPort() {
+        return getShort(DESTPORT);
+    }
+
+    /**
+     * Gets the stored length of UDP packet.
+     *
+     * @return  The number of bytes in the UDP datagram.
+     */
+    public short getLength() {
+        return getShort(LENGTH);
+    }
+
+    /**
+     * Get the stored checksum value of the UDP packet.
+     *
+     * @return  The UDP checksum.
+     */
+    public short getChecksum() {
+        return getShort(CHECKSUM);
+    }
+
+    /**
+     * Sets the sourcePort value for the current UDP object instance.
+     *
+     * @param port  The source port number.
+     * @return  This instance.
+     */
+    public UDP setSourcePort(short port) {
+        getHeaderFieldMap().put(SRCPORT, toBytes(port));
+        return this;
+    }
+
+    /**
+     * Sets the destinationPort value for the current UDP object instance.
+     *
+     * @param port  The destination port number.
+     * @return  This instance.
+     */
+    public UDP setDestinationPort(short port) {
+        getHeaderFieldMap().put(DESTPORT, toBytes(port));
+        return this;
+    }
+
+    /**
+     * Set the UDP header length value for the current UDP object instance.
+     *
+     * @param len  The number of bytes in the UDP datagram.
+     * @return  This instance.
+     */
+    public UDP setLength(short len) {
+        getHeaderFieldMap().put(LENGTH, toBytes(len));
+        return this;
+    }
+
+    /**
+     * Set the checksum for the current UDP object instance.
+     *
+     * @param cksum  The UDP checksum.
+     * @return  This instance.
+     */
+    public UDP setChecksum(short cksum) {
+        getHeaderFieldMap().put(CHECKSUM, toBytes(cksum));
+        return this;
+    }
+
+    // Packet
+
+    /**
+     * Gets the header size in bits.
+     *
+     * @return  The UDP header size in bits.
+     */
+    @Override
+    public int getHeaderSize() {
+        return HEADER_SIZE;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected Map<String, HeaderField> getHeaderFormat() {
+        return HEADER_FORMAT;
+    }
+
+    // Object
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public UDP clone() {
+        return (UDP)super.clone();
+    }
+}
index 2d280b443efe11fd036a5ea7101cc2176315417b..e65616fab5750f48c4869ecb47209b7b4f2e9353 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.vtn.manager.util;
 
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_BYTE;
+
 /**
  * {@code ByteUtils} class is a collection of utility class fields and methods
  * for byte array handling.
@@ -31,6 +33,126 @@ public final class ByteUtils {
      */
     public static final int  HEX_RADIX = 16;
 
+    /**
+     * A private class to convert bit stream into the specified byte array.
+     */
+    private static final class BitStream {
+        /**
+         * The byte array to store result.
+         */
+        private final byte[]  result;
+
+        /**
+         * The current byte.
+         */
+        private byte  current;
+
+        /**
+         * The byte offset to store the next byte.
+         */
+        private int  resultOff;
+
+        /**
+         * The bit offset to store the next bits into the current byte.
+         */
+        private int  bitOff;
+
+        /**
+         * Construct a new instance that sets LSB aligned bits into the
+         * specified byte array.
+         *
+         * @param array  A byte array to store result.
+         * @param nbits  The total number of bits to be added.
+         */
+        private BitStream(byte[] array, int nbits) {
+            result = array;
+            int mod = nbits % Byte.SIZE;
+            bitOff = (mod == 0) ? 0 : Byte.SIZE - mod;
+        }
+
+        /**
+         * Construct a new instance that sets bits into the specified byte
+         * array with specifying the start position.
+         *
+         * @param array  A byte array to store result.
+         * @param start  Starting byte offset in the given array.
+         * @param boff   Starting bit offset in the first byte of the specified
+         *               byte array.
+         */
+        private BitStream(byte[] array, int start, int boff) {
+            result = array;
+            bitOff = boff;
+            resultOff = start;
+            if (boff != 0) {
+                byte b = result[start];
+                current = (byte)(b & (MASK_BYTE << (Byte.SIZE - boff)));
+            }
+        }
+
+        /**
+         * Add all the bits in the given byte to the bit stream.
+         *
+         * @param value  A byte value.
+         */
+        private void add(byte value) {
+            byte b = (byte)((value & MASK_BYTE) >>> bitOff);
+            current |= b;
+            result[resultOff++] = current;
+            current = (byte)(value << (Byte.SIZE - bitOff));
+        }
+
+        /**
+         * Add LSB aligned bits in the given byte to the bit stream.
+         *
+         * @param value  A byte value.
+         * @param start  The start bit offset.
+         * @param nbits  The number of bits to be added.
+         */
+        private void add(byte value, int start, int nbits) {
+            byte v = (byte)(value << start);
+            byte b = (byte)((v & MASK_BYTE) >>> bitOff);
+            int off = bitOff + nbits;
+            if (off < Byte.SIZE) {
+                int nshift = Byte.SIZE - off;
+                b = (byte)(b & (MASK_BYTE << nshift));
+                current |= b;
+                bitOff = off;
+            } else {
+                current |= b;
+                result[resultOff++] = current;
+                bitOff = off - Byte.SIZE;
+                if (bitOff > 0) {
+                    int nright = Byte.SIZE - nbits;
+                    int nleft = Byte.SIZE - bitOff;
+                    current = (byte)(((v & MASK_BYTE) >>> nright) << nleft);
+                } else {
+                    current = 0;
+                }
+            }
+        }
+
+        /**
+         * Write unwritten bits into the target array.
+         *
+         * @return  {@code true} if at least one bit is written.
+         *          {@code false} if all added bits are already written.
+         */
+        private boolean flush() {
+            boolean ret = (bitOff != 0);
+            if (ret) {
+                // Merge with a byte at the output byte.
+                byte cur = (byte)(result[resultOff] << bitOff);
+                cur = (byte)((cur & MASK_BYTE) >>> bitOff);
+
+                int nshift = Byte.SIZE - bitOff;
+                byte b = (byte)(((current & MASK_BYTE) >>> nshift) << nshift);
+                result[resultOff] = (byte)(cur | b);
+            }
+
+            return ret;
+        }
+    }
+
     /**
      * Private constructor that protects this class from instantiating.
      */
@@ -55,7 +177,7 @@ public final class ByteUtils {
         StringBuilder builder = new StringBuilder();
         for (byte b: bytes) {
             builder.append(sep).
-                append(String.format("%02x", b & NumberUtils.MASK_BYTE));
+                append(String.format("%02x", b & MASK_BYTE));
             sep = HEX_SEPARATOR;
         }
         return builder.toString();
@@ -100,10 +222,130 @@ public final class ByteUtils {
      */
     public static int parseHexOctet(String hex) {
         int octet = Integer.valueOf(hex, HEX_RADIX).intValue();
-        if (octet < 0 || octet > NumberUtils.MASK_BYTE) {
+        if (octet < 0 || octet > MASK_BYTE) {
             throw new NumberFormatException("Octet out of range: " + hex);
         }
 
         return octet;
     }
+
+    /**
+     * Read the specified number of bits from the given byte array.
+     *
+     * @param data   A byte array.
+     *               Specifying {@code null} results in undefined behavior.
+     * @param off    The bit offset to start fetching bits.
+     * @param nbits  The number of bits to be fetched.
+     * @return  A byte array that contains fetched bits (LSB aligned).
+     * @since  Beryllium
+     */
+    public static byte[] getBits(byte[] data, int off, int nbits) {
+        int round = Byte.SIZE - 1;
+        int nbytes = (nbits + round) / Byte.SIZE;
+        byte[] result = new byte[nbytes];
+        if (nbytes != 0) {
+            // Byte offset to the first byte to be read.
+            int start = off / Byte.SIZE;
+
+            // Start bit offset in the first byte.
+            int firstBit = off - (start * Byte.SIZE);
+
+            // The last bit offset (exclusive).
+            int lastoff = off + nbits;
+
+            // End bit offset (exclusive) in the last byte.
+            int lastBit = lastoff % Byte.SIZE;
+
+            if (firstBit == 0 && lastBit == 0) {
+                // No need to shift bits.
+                System.arraycopy(data, start, result, 0, nbytes);
+            } else {
+                BitStream bst = new BitStream(result, nbits);
+
+                // Add bits in the first byte.
+                boolean moreBytes = ((firstBit + nbits) > Byte.SIZE);
+                int nb = (moreBytes) ? Byte.SIZE - firstBit : nbits;
+                bst.add(data[start], firstBit, nb);
+
+                if (moreBytes) {
+                    // Determine the number of bytes to be read from the
+                    // source byte array.
+                    int nread = (lastoff + round) / Byte.SIZE;
+                    if (lastBit != 0) {
+                        nread--;
+                    }
+
+                    // Add bits except for the last byte.
+                    int index;
+                    for (index = start + 1; index < nread; index++) {
+                        bst.add(data[index]);
+                    }
+
+                    if (lastBit != 0) {
+                        // Add bits in the last byte.
+                        bst.add(data[index], 0, lastBit);
+                    }
+                }
+
+                assert !bst.flush();
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Copy bits in the specified input byte array into the specified output
+     * array.
+     *
+     * @param output  A byte array to store bits.
+     *                Specifying {@code null} results in undefined behavior.
+     * @param input   A byte array to be copied.
+     *                Bits in this array are expected to be aligned to LSB.
+     *                Specifying {@code null} results in undefined behavior.
+     * @param off     The bit offset of {@code output} to start inserting bits
+     *                from {@code input}.
+     * @param nbits   The number of bits to be copied.
+     * @since  Beryllium
+     */
+    public static void setBits(byte[] output, byte[] input, int off,
+                               int nbits) {
+        int round = Byte.SIZE - 1;
+        int nbytes = (nbits + round) / Byte.SIZE;
+        if (nbytes != 0) {
+            // Output byte offset to the first byte to store.
+            int start = off / Byte.SIZE;
+
+            // Output start bit offset in the first byte.
+            int firstBit = off - (start * Byte.SIZE);
+
+            // The number of bits (from LSB) in the first input byte to be
+            // copied.
+            int inputBits = nbits % Byte.SIZE;
+
+            if (firstBit == 0 && inputBits == 0) {
+                // No need to shift bits.
+                System.arraycopy(input, 0, output, start, nbytes);
+            } else {
+                BitStream bst = new BitStream(output, start, firstBit);
+
+                int index;
+                if (inputBits == 0) {
+                    index = 0;
+                } else {
+                    // Copy bits in the first byte.
+                    bst.add(input[0], Byte.SIZE - inputBits, inputBits);
+                    index = 1;
+                }
+
+                // Copy the rest of bits.
+                for (; index < nbytes; index++) {
+                    bst.add(input[index]);
+                }
+
+                // Flush unwritten bits.
+                bst.flush();
+            }
+        }
+    }
 }
index 5f0afab5466783b834b55d883a836efe42656e9d..df8d6b51ef23cd4dd5f80393f9cabdd54bde0f13 100644 (file)
@@ -8,8 +8,14 @@
 
 package org.opendaylight.vtn.manager.util;
 
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+
 /**
  * {@code EtherTypes} contains the common Ethernet types.
+ *
+ * @since  Beryllium
  */
 public enum EtherTypes {
     /**
@@ -37,10 +43,41 @@ public enum EtherTypes {
      */
     LLDP(0x88cc);
 
+    /**
+     * A map which keeps pairs of Ethernet types and {@link EtherTypes}
+     * instances.
+     */
+    private static final Map<Short, EtherTypes>  TYPE_MAP;
+
     /**
      * The Ethernet type value.
      */
-    private final int  value;
+    private final short  value;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        ImmutableMap.Builder<Short, EtherTypes> builder =
+            ImmutableMap.<Short, EtherTypes>builder();
+        for (EtherTypes type: EtherTypes.values()) {
+            builder.put(type.value, type);
+        }
+
+        TYPE_MAP = builder.build();
+    }
+
+    /**
+     * Convert the given Ethernet type vlaue into a {@link EtherTypes}
+     * instance.
+     *
+     * @param value  An Ethernet type value.
+     * @return  An {@link EtherTypes} instance if found.
+     *          {@code null} if not found.
+     */
+    public static EtherTypes forValue(short value) {
+        return TYPE_MAP.get(value);
+    }
 
     /**
      * Construct a new instance.
@@ -48,7 +85,7 @@ public enum EtherTypes {
      * @param v  The Ethernet type value.
      */
     private EtherTypes(int v) {
-        value = v;
+        value = (short)v;
     }
 
     /**
@@ -57,7 +94,7 @@ public enum EtherTypes {
      * @return  An integer that represents the Ethernet type value.
      */
     public int intValue() {
-        return value;
+        return (value & NumberUtils.MASK_SHORT);
     }
 
     /**
@@ -66,6 +103,6 @@ public enum EtherTypes {
      * @return  A short integer that represents the Ethernet type value.
      */
     public short shortValue() {
-        return (short)value;
+        return value;
     }
 }
index 6daf9255cfb439fc3430c67c9496659480189bb6..568f14fff0ff4fb2862e5e303a35e5e7634b3ab0 100644 (file)
@@ -8,8 +8,16 @@
 
 package org.opendaylight.vtn.manager.util;
 
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_BYTE;
+
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+
 /**
  * {@code InetProtocols} contains the common IP protocol numbers.
+ *
+ * @since  Beryllium
  */
 public enum InetProtocols {
     /**
@@ -27,10 +35,41 @@ public enum InetProtocols {
      */
     UDP(17);
 
+    /**
+     * A map which keeps pairs of IP protocol value and {@link InetProtocols}
+     * instances.
+     */
+    private static final Map<Byte, InetProtocols>  PROTO_MAP;
+
     /**
      * The IP protocol number.
      */
-    private final int  value;
+    private final byte  value;
+
+    /**
+     * Initialize static fields.
+     */
+    static {
+        ImmutableMap.Builder<Byte, InetProtocols> builder =
+            ImmutableMap.<Byte, InetProtocols>builder();
+        for (InetProtocols proto: InetProtocols.values()) {
+            builder.put(proto.value, proto);
+        }
+
+        PROTO_MAP = builder.build();
+    }
+
+    /**
+     * Convert the given IP protocol number into a {@link InetProtocols}
+     * instance.
+     *
+     * @param proto  An IP protocol number.
+     * @return  An {@link InetProtocols} instance if found.
+     *          {@code null} if not found.
+     */
+    public static InetProtocols forValue(byte proto) {
+        return PROTO_MAP.get(proto);
+    }
 
     /**
      * Construct a new instance.
@@ -38,7 +77,7 @@ public enum InetProtocols {
      * @param v  The IP protocol number.
      */
     private InetProtocols(int v) {
-        value = v;
+        value = (byte)v;
     }
 
     /**
@@ -47,7 +86,7 @@ public enum InetProtocols {
      * @return  An integer that represents the IP protocol number.
      */
     public int intValue() {
-        return value;
+        return (int)(value & MASK_BYTE);
     }
 
     /**
@@ -56,7 +95,7 @@ public enum InetProtocols {
      * @return  A short integer that represents the IP protocol number.
      */
     public short shortValue() {
-        return (short)value;
+        return (short)(value & MASK_BYTE);
     }
 
     /**
@@ -65,6 +104,6 @@ public enum InetProtocols {
      * @return  A byte that represents the IP protocol number.
      */
     public byte byteValue() {
-        return (byte)value;
+        return value;
     }
 }
index 2bf4a7ff8fdd6f55650aaa787765b1b0e5625ac1..785d3a428b6610d1a18c21a14d0dc2e588193366 100644 (file)
@@ -27,6 +27,20 @@ public final class NumberUtils {
      */
     public static final int  NUM_OCTETS_INTEGER = Integer.SIZE / Byte.SIZE;
 
+    /**
+     * The number of octets in a short integer value.
+     *
+     * @since  Beryllium
+     */
+    public static final int  NUM_OCTETS_SHORT = Short.SIZE / Byte.SIZE;
+
+    /**
+     * The number of octets in a byte value.
+     *
+     * @since  Beryllium
+     */
+    public static final int  NUM_OCTETS_BYTE = 1;
+
     /**
      * A mask value which represents all bits in a byte value.
      */
@@ -121,10 +135,7 @@ public final class NumberUtils {
      *    The length of {@code b} is not 4.
      */
     public static int toInteger(byte[] b) {
-        if (b.length != NUM_OCTETS_INTEGER) {
-            throw new IllegalArgumentException(
-                "Invalid byte array length: " + b.length);
-        }
+        checkLength(b, NUM_OCTETS_INTEGER);
 
         int index = 0;
         int value = (b[index++] & MASK_BYTE) << INT_SHIFT_OCTET1;
@@ -133,15 +144,46 @@ public final class NumberUtils {
         return value | (b[index] & MASK_BYTE);
     }
 
+    /**
+     * Convert a 2 bytes array into a short integer number.
+     *
+     * @param b  A 2 bytes array.
+     * @return   A short integer number.
+     * @throws NullPointerException
+     *    {@code b} is {@code null}.
+     * @throws IllegalArgumentException
+     *    The length of {@code b} is not 2.
+     * @since  Beryllium
+     */
+    public static short toShort(byte[] b) {
+        checkLength(b, NUM_OCTETS_SHORT);
+
+        int value = (b[0] & MASK_BYTE) << Byte.SIZE;
+        return (short)(value | (b[1] & MASK_BYTE));
+    }
+
     /**
      * Convert an integer value into an byte array.
      *
-     * @param i  An integer value.
+     * @param v  An integer value.
      * @return   A converted byte array.
      */
-    public static byte[] toBytes(int i) {
+    public static byte[] toBytes(int v) {
         byte[] b = new byte[NUM_OCTETS_INTEGER];
-        setInt(b, 0, i);
+        setInt(b, 0, v);
+        return b;
+    }
+
+    /**
+     * Convert a short integer value into an byte array.
+     *
+     * @param v  A short integer value.
+     * @return   A converted byte array.
+     * @since  Beryllium
+     */
+    public static byte[] toBytes(short v) {
+        byte[] b = new byte[NUM_OCTETS_SHORT];
+        setShort(b, 0, v);
         return b;
     }
 
@@ -251,4 +293,21 @@ public final class NumberUtils {
     public static boolean equalsDouble(double d1, double d2) {
         return (Double.doubleToLongBits(d1) == Double.doubleToLongBits(d2));
     }
+
+    /**
+     * Check the length of the given byte array.
+     *
+     * @param b    The byte array to be tested.
+     * @param len  The expected length of the byte array.
+     * @throws NullPointerException
+     *    {@code b} is {@code null}.
+     * @throws IllegalArgumentException
+     *    The length of {@code b} is invalid.
+     */
+    private static void checkLength(byte[] b, int len) {
+        if (b.length != len) {
+            throw new IllegalArgumentException(
+                "Invalid byte array length: " + b.length);
+        }
+    }
 }
index 75bc37996c088314cf26faf1502e7f36f41c7bd3..5f8eda1fd49b2e51e558f286dc2a7e6edd630c42 100644 (file)
@@ -94,7 +94,7 @@ public class VTNExceptionTest extends TestBase {
 
     /**
      * Test case for
-     * {@link VTNException#VTNException(VtnErrorTag, String, Thowable)} and
+     * {@link VTNException#VTNException(VtnErrorTag, String, Throwable)} and
      * the followings.
      *
      * <ul>
@@ -155,7 +155,7 @@ public class VTNExceptionTest extends TestBase {
 
     /**
      * Test case for
-     * {@link VTNException#VTNException(String, Thowable)} and
+     * {@link VTNException#VTNException(String, Throwable)} and
      * the followings.
      *
      * <ul>
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/ARPTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/ARPTest.java
new file mode 100644 (file)
index 0000000..74e1f29
--- /dev/null
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.util.EtherAddress;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link ARP}.
+ */
+public class ARPTest extends TestBase {
+    /**
+     * Test case for hardware type.
+     *
+     * <ul>
+     *   <li>{@link ARP#getHardwareType()}</li>
+     *   <li>{@link ARP#setHardwareType(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetHardwareType() {
+        ARP arp = new ARP();
+        assertEquals((short)0, arp.getHardwareType());
+
+        short[] types = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short hwtype: types) {
+            assertSame(arp, arp.setHardwareType(hwtype));
+            assertEquals(hwtype, arp.getHardwareType());
+        }
+    }
+
+    /**
+     * Test case for protocol type.
+     *
+     * <ul>
+     *   <li>{@link ARP#getProtocolType()}</li>
+     *   <li>{@link ARP#setProtocolType(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetProtocolType() {
+        ARP arp = new ARP();
+        assertEquals((short)0, arp.getProtocolType());
+
+        short[] types = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short ptype: types) {
+            assertSame(arp, arp.setProtocolType(ptype));
+            assertEquals(ptype, arp.getProtocolType());
+        }
+    }
+
+    /**
+     * Test case for the hardware address length.
+     *
+     * <ul>
+     *   <li>{@link ARP#getHardwareAddressLength()}</li>
+     *   <li>{@link ARP#setHardwareAddressLength(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetHardwareAddressLength() {
+        ARP arp = new ARP();
+        assertEquals((byte)0, arp.getHardwareAddressLength());
+
+        byte[] lengths = {0, 1, 9, 57, 127, -128, -127, -15, -2, -1};
+        for (byte len: lengths) {
+            assertSame(arp, arp.setHardwareAddressLength(len));
+            assertEquals(len, arp.getHardwareAddressLength());
+        }
+    }
+
+    /**
+     * Test cast for the protocol address length.
+     *
+     * <ul>
+     *   <li>{@link ARP#getProtocolAddressLength()}</li>
+     *   <li>{@link ARP#setProtocolAddressLength(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetProtocolAddressLength() {
+        ARP arp = new ARP();
+        assertEquals((byte)0, arp.getProtocolAddressLength());
+
+        byte[] lengths = {0, 1, 9, 57, 127, -128, -127, -15, -2, -1};
+        for (byte len: lengths) {
+            assertSame(arp, arp.setProtocolAddressLength(len));
+            assertEquals(len, arp.getProtocolAddressLength());
+        }
+    }
+
+    /**
+     * Test case for the operation code.
+     *
+     * <ul>
+     *   <li>{@link ARP#getOpCode()}</li>
+     *   <li>{@link ARP#setOpCode(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetOpCode() {
+        ARP arp = new ARP();
+        assertEquals((short)0, arp.getOpCode());
+
+        short[] codes = {0, 1, 2, 100, 127, 128, 30123, 32767, -30000, -2, -1};
+        for (short op: codes) {
+            assertSame(arp, arp.setOpCode(op));
+            assertEquals(op, arp.getOpCode());
+        }
+    }
+
+    /**
+     * Test case for the sender hardware address.
+     *
+     * <ul>
+     *   <li>{@link ARP#getSenderHardwareAddress()}</li>
+     *   <li>{@link ARP#setSenderHardwareAddress(byte[])}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetSenderHardwareAddress() {
+        ARP arp = new ARP();
+        assertEquals(null, arp.getSenderHardwareAddress());
+
+        EtherAddress[] addrs = {
+            new EtherAddress(0x123456789abcL),
+            new EtherAddress(0x001122334455L),
+            new EtherAddress(0x182cf31fa341L),
+        };
+
+        for (EtherAddress eaddr: addrs) {
+            byte[] baddr = eaddr.getBytes();
+            assertSame(arp, arp.setSenderHardwareAddress(baddr));
+
+            // The specified array should be copied.
+            baddr[0] = 0;
+            baddr[1] = 0;
+            assertArrayEquals(eaddr.getBytes(),
+                              arp.getSenderHardwareAddress());
+        }
+    }
+
+    /**
+     * Test case for the sender protocol address.
+     *
+     * <ul>
+     *   <li>{@link ARP#getSenderProtocolAddress()}</li>
+     *   <li>{@link ARP#setSenderProtocolAddress(byte[])}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetSenderProtocolAddress() {
+        ARP arp = new ARP();
+        assertEquals(null, arp.getSenderProtocolAddress());
+
+        Ip4Network[] addrs = {
+            new Ip4Network("192.168.123.234"),
+            new Ip4Network("10.20.30.40"),
+            new Ip4Network("220.39.195.254"),
+        };
+        for (Ip4Network addr: addrs) {
+            byte[] baddr = addr.getBytes();
+            assertSame(arp, arp.setSenderProtocolAddress(baddr));
+
+            // The specified array should be copied.
+            baddr[0] = 0;
+            baddr[1] = 0;
+            assertArrayEquals(addr.getBytes(), arp.getSenderProtocolAddress());
+        }
+    }
+
+    /**
+     * Test case for the target hardware address.
+     *
+     * <ul>
+     *   <li>{@link ARP#getSenderHardwareAddress()}</li>
+     *   <li>{@link ARP#setSenderHardwareAddress(byte[])}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetTargetHardwareAddress() {
+        ARP arp = new ARP();
+        assertEquals(null, arp.getTargetHardwareAddress());
+
+        EtherAddress[] addrs = {
+            new EtherAddress(0x123456789abcL),
+            new EtherAddress(0x001122334455L),
+            new EtherAddress(0x182cf31fa341L),
+        };
+
+        for (EtherAddress eaddr: addrs) {
+            byte[] baddr = eaddr.getBytes();
+            assertSame(arp, arp.setTargetHardwareAddress(baddr));
+
+            // The specified array should be copied.
+            baddr[0] = 0;
+            baddr[1] = 0;
+            assertArrayEquals(eaddr.getBytes(),
+                              arp.getTargetHardwareAddress());
+        }
+    }
+
+    /**
+     * Test case for the target protocol address.
+     *
+     * <ul>
+     *   <li>{@link ARP#getTargetProtocolAddress()}</li>
+     *   <li>{@link ARP#setTargetProtocolAddress(byte[])}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetTargetProtocolAddress() {
+        ARP arp = new ARP();
+        assertEquals(null, arp.getTargetProtocolAddress());
+
+        Ip4Network[] addrs = {
+            new Ip4Network("192.168.123.234"),
+            new Ip4Network("10.20.30.40"),
+            new Ip4Network("220.39.195.254"),
+        };
+        for (Ip4Network addr: addrs) {
+            byte[] baddr = addr.getBytes();
+            assertSame(arp, arp.setTargetProtocolAddress(baddr));
+
+            // The specified array should be copied.
+            baddr[0] = 0;
+            baddr[1] = 0;
+            assertArrayEquals(addr.getBytes(), arp.getTargetProtocolAddress());
+        }
+    }
+
+    /**
+     * Test case for {@link ARP#clone()}.
+     */
+    @Test
+    public void testClone() {
+        short hwtype = 1;
+        short ptype = 123;
+        byte hlen = 6;
+        byte plen = 4;
+        short op = 7;
+        EtherAddress sha = new EtherAddress(0x001122334455L);
+        EtherAddress tha = new EtherAddress(0xa0b0c0d0e0f0L);
+        Ip4Network spa = new Ip4Network("1.2.3.4");
+        Ip4Network tpa = new Ip4Network("192.168.34.56");
+        ARP arp = new ARP().
+            setHardwareType(hwtype).
+            setProtocolType(ptype).
+            setHardwareAddressLength(hlen).
+            setProtocolAddressLength(plen).
+            setOpCode(op).
+            setSenderHardwareAddress(sha.getBytes()).
+            setTargetHardwareAddress(tha.getBytes()).
+            setSenderProtocolAddress(spa.getBytes()).
+            setTargetProtocolAddress(tpa.getBytes());
+
+        ARP copy = arp.clone();
+        assertNotSame(arp, copy);
+        assertEquals(arp, copy);
+        assertEquals(arp.hashCode(), copy.hashCode());
+
+        // Modifying the source packet should never affect a deep copy.
+        short hwtype1 = 3;
+        short ptype1 = 45;
+        byte hlen1 = 4;
+        byte plen1 = 8;
+        short op1 = 1;
+        EtherAddress sha1 = new EtherAddress(0xaabbccddeeffL);
+        EtherAddress tha1 = new EtherAddress(0x000011112222L);
+        Ip4Network spa1 = new Ip4Network("10.20.30.40");
+        Ip4Network tpa1 = new Ip4Network("10.20.30.1");
+        arp.setHardwareType(hwtype1).
+            setProtocolType(ptype1).
+            setHardwareAddressLength(hlen1).
+            setProtocolAddressLength(plen1).
+            setOpCode(op1).
+            setSenderHardwareAddress(sha1.getBytes()).
+            setTargetHardwareAddress(tha1.getBytes()).
+            setSenderProtocolAddress(spa1.getBytes()).
+            setTargetProtocolAddress(tpa1.getBytes());
+
+        assertEquals(hwtype, copy.getHardwareType());
+        assertEquals(ptype, copy.getProtocolType());
+        assertEquals(hlen, copy.getHardwareAddressLength());
+        assertEquals(plen, copy.getProtocolAddressLength());
+        assertEquals(op, copy.getOpCode());
+        assertArrayEquals(sha.getBytes(), copy.getSenderHardwareAddress());
+        assertArrayEquals(tha.getBytes(), copy.getTargetHardwareAddress());
+        assertArrayEquals(spa.getBytes(), copy.getSenderProtocolAddress());
+        assertArrayEquals(tpa.getBytes(), copy.getTargetProtocolAddress());
+
+        assertEquals(hwtype1, arp.getHardwareType());
+        assertEquals(ptype1, arp.getProtocolType());
+        assertEquals(hlen1, arp.getHardwareAddressLength());
+        assertEquals(plen1, arp.getProtocolAddressLength());
+        assertEquals(op1, arp.getOpCode());
+        assertArrayEquals(sha1.getBytes(), arp.getSenderHardwareAddress());
+        assertArrayEquals(tha1.getBytes(), arp.getTargetHardwareAddress());
+        assertArrayEquals(spa1.getBytes(), arp.getSenderProtocolAddress());
+        assertArrayEquals(tpa1.getBytes(), arp.getTargetProtocolAddress());
+    }
+
+    /**
+     * Test for serialization and deserialization.
+     *
+     * <ul>
+     *   <li>{@link Packet#serialize()}</li>
+     *   <li>{@link Packet#deserialize(byte[], int, int)}</li>
+     * </ul>
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testSerialize() throws Exception {
+        byte[] raw = {
+            // Hardware type.
+            (byte)0x00, (byte)0x01,
+
+            // Protocol type.
+            (byte)0x08, (byte)0x00,
+
+            // Hardware address length.
+            (byte)0x06,
+
+            // Protocol address length.
+            (byte)0x04,
+
+            // Operation code.
+            (byte)0x00, 0x01,
+
+            // Sender hardware address.
+            (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67,
+            (byte)0x89, (byte)0xab,
+
+            // Sender protocol address.
+            (byte)10, (byte)20, (byte)30, (byte)40,
+
+            // Target hardware address.
+            (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff,
+            (byte)0xff, (byte)0xff,
+
+            // Target protocol address.
+            (byte)192, (byte)168, (byte)123, (byte)254,
+        };
+
+        EtherAddress sha = new EtherAddress(0x0123456789abL);
+        EtherAddress tha = EtherAddress.BROADCAST;
+        Ip4Network spa = new Ip4Network("10.20.30.40");
+        Ip4Network tpa = new Ip4Network("192.168.123.254");
+
+        // Deserialize raw packet.
+        ARP arp = new ARP();
+        arp.deserialize(raw, 0, raw.length * Byte.SIZE);
+        assertEquals((short)1, arp.getHardwareType());
+        assertEquals((short)0x800, arp.getProtocolType());
+        assertEquals((byte)6, arp.getHardwareAddressLength());
+        assertEquals((byte)4, arp.getProtocolAddressLength());
+        assertEquals((short)1, arp.getOpCode());
+        assertArrayEquals(sha.getBytes(), arp.getSenderHardwareAddress());
+        assertArrayEquals(tha.getBytes(), arp.getTargetHardwareAddress());
+        assertArrayEquals(spa.getBytes(), arp.getSenderProtocolAddress());
+        assertArrayEquals(tpa.getBytes(), arp.getTargetProtocolAddress());
+        assertEquals(null, arp.getPayload());
+        assertEquals(null, arp.getRawPayload());
+        assertEquals(false, arp.isCorrupted());
+
+        // Serialize packet.
+        assertArrayEquals(raw, arp.serialize());
+
+        // Serialize an empty packet.
+        arp = new ARP();
+        byte[] expected = new byte[28];
+        assertArrayEquals(expected, arp.serialize());
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/EthernetTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/EthernetTest.java
new file mode 100644 (file)
index 0000000..159d206
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.util.EtherAddress;
+import org.opendaylight.vtn.manager.util.EtherTypes;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link Ethernet}.
+ */
+public class EthernetTest extends TestBase {
+    /**
+     * Test case for {@link Ethernet#getPayloadClass(short)}.
+     */
+    @Test
+    public void testGetPayloadClass() {
+        short[] badTypes = {
+            (short)0x0000, (short)0x0011, (short)0x07ff, (short)0x0805,
+            (short)0x0899, (short)0x8001, (short)0x8101, (short)0x88a8,
+            (short)0x88cc, (short)0x9999, (short)0xabcd, (short)0xcdef,
+            (short)0xcef0, (short)0xf000, (short)0xfff0, (short)0xffff,
+        };
+
+        for (short type: badTypes) {
+            assertEquals(null, Ethernet.getPayloadClass(type));
+        }
+
+        assertEquals(IPv4.class, Ethernet.getPayloadClass((short)0x0800));
+        assertEquals(ARP.class, Ethernet.getPayloadClass((short)0x0806));
+        assertEquals(IEEE8021Q.class, Ethernet.getPayloadClass((short)0x8100));
+    }
+
+    /**
+     * Test case for the destination MAC address.
+     *
+     * <ul>
+     *   <li>{@link Ethernet#getDestinationMACAddress()}</li>
+     *   <li>{@link Ethernet#setDestinationMACAddress(byte[])}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetDestinationMACAddress() {
+        Ethernet eth = new Ethernet();
+        assertEquals(null, eth.getDestinationMACAddress());
+
+        EtherAddress[] addrs = {
+            new EtherAddress(0x123456789abcL),
+            new EtherAddress(0),
+            EtherAddress.BROADCAST,
+            new EtherAddress(0x00abcdef1122L),
+        };
+        for (EtherAddress eaddr: addrs) {
+            byte[] mac = eaddr.getBytes();
+            assertSame(eth, eth.setDestinationMACAddress(mac));
+
+            // Ensure the specified byte array is copied.
+            mac[0] = (byte)0xae;
+            assertArrayEquals(eaddr.getBytes(),
+                              eth.getDestinationMACAddress());
+        }
+    }
+
+    /**
+     * Test case for the source MAC address.
+     *
+     * <ul>
+     *   <li>{@link Ethernet#getSourceMACAddress()}</li>
+     *   <li>{@link Ethernet#setSourceMACAddress(byte[])}</li>
+     * </ul>
+     */
+    @Test
+    public void testSourceMACAddress() {
+        Ethernet eth = new Ethernet();
+        assertEquals(null, eth.getSourceMACAddress());
+
+        EtherAddress[] addrs = {
+            new EtherAddress(0x123456789abcL),
+            new EtherAddress(0),
+            EtherAddress.BROADCAST,
+            new EtherAddress(0x00abcdef1122L),
+        };
+        for (EtherAddress eaddr: addrs) {
+            byte[] mac = eaddr.getBytes();
+            assertSame(eth, eth.setSourceMACAddress(mac));
+
+            // Ensure the specified byte array is copied.
+            mac[0] = (byte)0xae;
+            assertArrayEquals(eaddr.getBytes(),
+                              eth.getSourceMACAddress());
+        }
+    }
+
+    /**
+     * Test case for the Ethernet type.
+     *
+     * <ul>
+     *   <li>{@link Ethernet#getEtherType()}</li>
+     *   <li>{@link Ethernet#setEtherType(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetEthertype() throws Exception {
+        Ethernet eth = new Ethernet();
+        assertEquals((short)0, eth.getEtherType());
+
+
+        short[] values = {
+            (short)0x0000, (short)0x0001, (short)0x0020, (short)0x03ff,
+            (short)0x07ff, (short)0x0800, (short)0x0999, (short)0x1abc,
+            (short)0x5678, (short)0x7fff, (short)0x8000, (short)0x8888,
+            (short)0xabcd, (short)0xcdef, (short)0xff00, (short)0xffff,
+        };
+        for (short v: values) {
+            assertSame(eth, eth.setEtherType(v));
+            assertEquals(v, eth.getEtherType());
+        }
+    }
+
+    /**
+     * Test case for {@link Ethernet#clone()}.
+     */
+    @Test
+    public void testClone() {
+        EtherAddress src = new EtherAddress(0x001122334455L);
+        EtherAddress dst = new EtherAddress(0x0abbccddeeffL);
+        short etype = EtherTypes.VLAN.shortValue();
+        Ethernet eth = new Ethernet().
+            setSourceMACAddress(src.getBytes()).
+            setDestinationMACAddress(dst.getBytes()).
+            setEtherType(etype);
+
+        byte pcp = 0;
+        byte cfi = 0;
+        short vid = 4095;
+        short vetype = EtherTypes.ARP.shortValue();
+        IEEE8021Q vlan = new IEEE8021Q().
+            setPcp(pcp).
+            setCfi(cfi).
+            setVid(vid).
+            setEtherType(vetype);
+
+        short hwtype = 1;
+        short ptype = 0x800;
+        byte hlen = 6;
+        byte plen = 4;
+        short op = 7;
+        EtherAddress sha = new EtherAddress(0x010203040506L);
+        EtherAddress tha = new EtherAddress(0xa0b0c0d0e0f0L);
+        Ip4Network spa = new Ip4Network("1.2.3.4");
+        Ip4Network tpa = new Ip4Network("192.168.34.56");
+        ARP arp = new ARP().
+            setHardwareType(hwtype).
+            setProtocolType(ptype).
+            setHardwareAddressLength(hlen).
+            setProtocolAddressLength(plen).
+            setOpCode(op).
+            setSenderHardwareAddress(sha.getBytes()).
+            setTargetHardwareAddress(tha.getBytes()).
+            setSenderProtocolAddress(spa.getBytes()).
+            setTargetProtocolAddress(tpa.getBytes());
+
+        vlan.setPayload(arp);
+        eth.setPayload(vlan);
+
+        Ethernet copy = eth.clone();
+        assertNotSame(eth, copy);
+        assertEquals(eth, copy);
+        assertEquals(eth.hashCode(), copy.hashCode());
+        assertEquals(null, copy.getRawPayload());
+
+        Packet payload1 = copy.getPayload();
+        assertNotSame(vlan, payload1);
+        assertEquals(vlan, payload1);
+        assertEquals(null, payload1.getRawPayload());
+
+        Packet payload2 = payload1.getPayload();
+        assertNotSame(arp, payload2);
+        assertEquals(arp, payload2);
+        assertEquals(null, payload2.getPayload());
+        assertEquals(null, payload2.getRawPayload());
+
+        // Modifying the source packet should never affect a deep copy.
+        EtherAddress src1 = new EtherAddress(0x0L);
+        EtherAddress dst1 = EtherAddress.BROADCAST;
+        short etype1 = 0x123;
+        eth.setSourceMACAddress(src1.getBytes()).
+            setDestinationMACAddress(dst1.getBytes()).
+            setEtherType(etype1);
+        eth.setPayload(null);
+
+        assertArrayEquals(src.getBytes(), copy.getSourceMACAddress());
+        assertArrayEquals(dst.getBytes(), copy.getDestinationMACAddress());
+        assertEquals(etype, copy.getEtherType());
+        assertEquals(payload1, copy.getPayload());
+        assertEquals(payload2, payload1.getPayload());
+        assertEquals(null, payload2.getPayload());
+
+        assertArrayEquals(src1.getBytes(), eth.getSourceMACAddress());
+        assertArrayEquals(dst1.getBytes(), eth.getDestinationMACAddress());
+        assertEquals(etype1, eth.getEtherType());
+        assertEquals(null, eth.getPayload());
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/ICMPTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/ICMPTest.java
new file mode 100644 (file)
index 0000000..0828425
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link ICMP}.
+ */
+public class ICMPTest extends TestBase {
+    /**
+     * Test case for ICMP type.
+     *
+     * <ul>
+     *   <li>{@link ICMP#getType()}</li>
+     *   <li>{@link ICMP#setType(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testSetType() {
+        ICMP icmp = new ICMP();
+        assertEquals((byte)0, icmp.getType());
+
+        byte[] values = {0, 1, 9, 57, 94, 127, -128, -127, -15, -2, -1};
+        for (byte type: values) {
+            assertSame(icmp, icmp.setType(type));
+            assertEquals(type, icmp.getType());
+        }
+    }
+
+    /**
+     * Test case for ICMP code.
+     *
+     * <ul>
+     *   <li>{@link ICMP#getCode()}</li>
+     *   <li>{@link ICMP#setCode(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testSetCode() {
+        ICMP icmp = new ICMP();
+        assertEquals((byte)0, icmp.getCode());
+
+        byte[] values = {0, 1, 9, 57, 94, 127, -128, -127, -15, -2, -1};
+        for (byte code: values) {
+            assertSame(icmp, icmp.setCode(code));
+            assertEquals(code, icmp.getCode());
+        }
+    }
+
+    /**
+     * Test case for ICMP checksum.
+     *
+     * <ul>
+     *   <li>{@link ICMP#getChecksum()}</li>
+     *   <li>{@link ICMP#setChecksum(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testSetChecksum() {
+        ICMP icmp = new ICMP();
+        assertEquals((short)0, icmp.getChecksum());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short cksum: values) {
+            assertSame(icmp, icmp.setChecksum(cksum));
+            assertEquals(cksum, icmp.getChecksum());
+        }
+    }
+
+    /**
+     * Test case for ICMP identifier.
+     *
+     * <ul>
+     *   <li>{@link ICMP#getIdentifier()}</li>
+     *   <li>{@link ICMP#setIdentifier(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testSetIdentifier() {
+        ICMP icmp = new ICMP();
+        assertEquals((short)0, icmp.getChecksum());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short id: values) {
+            assertSame(icmp, icmp.setIdentifier(id));
+            assertEquals(id, icmp.getIdentifier());
+        }
+    }
+
+    /**
+     * Test case for ICMP sequence number.
+     *
+     * <ul>
+     *   <li>{@link ICMP#getSequenceNumber()}</li>
+     *   <li>{@link ICMP#setSequenceNumber(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testSetSequenceNumber() {
+        ICMP icmp = new ICMP();
+        assertEquals((short)0, icmp.getSequenceNumber());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short seq: values) {
+            assertSame(icmp, icmp.setSequenceNumber(seq));
+            assertEquals(seq, icmp.getSequenceNumber());
+        }
+    }
+
+    /**
+     * Test case for {@link ICMP#clone()}.
+     */
+    @Test
+    public void testClone() {
+        byte type = 12;
+        byte code = 45;
+        short cksum = 18341;
+        short id = -29234;
+        short seq = 31721;
+        ICMP icmp = new ICMP().
+            setType(type).
+            setCode(code).
+            setChecksum(cksum).
+            setIdentifier(id).
+            setSequenceNumber(seq);
+
+        ICMP copy = icmp.clone();
+        assertNotSame(icmp, copy);
+        assertEquals(icmp, copy);
+        assertEquals(icmp.hashCode(), copy.hashCode());
+
+        // Modifying the source packet should never affect a deep copy.
+        byte type1 = 0;
+        byte code1 = 23;
+        short cksum1 = -29216;
+        short id1 = 3445;
+        short seq1 = 9163;
+        icmp.setType(type1).
+            setCode(code1).
+            setChecksum(cksum1).
+            setIdentifier(id1).
+            setSequenceNumber(seq1);
+
+        assertEquals(type, copy.getType());
+        assertEquals(code, copy.getCode());
+        assertEquals(cksum, copy.getChecksum());
+        assertEquals(id, copy.getIdentifier());
+        assertEquals(seq, copy.getSequenceNumber());
+
+        assertEquals(type1, icmp.getType());
+        assertEquals(code1, icmp.getCode());
+        assertEquals(cksum1, icmp.getChecksum());
+        assertEquals(id1, icmp.getIdentifier());
+        assertEquals(seq1, icmp.getSequenceNumber());
+    }
+
+    /**
+     * Test for serialization and deserialization.
+     *
+     * <ul>
+     *   <li>{@link Packet#serialize()}</li>
+     *   <li>{@link Packet#deserialize(byte[], int, int)}</li>
+     * </ul>
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testSerialization() throws Exception {
+        byte[] icmpRawPayload = {
+            (byte)0x38, (byte)0x26, (byte)0x9e, (byte)0x51,
+            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+            (byte)0x2e, (byte)0x6a, (byte)0x08, (byte)0x00,
+            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+            (byte)0x10, (byte)0x11, (byte)0x12, (byte)0x13,
+            (byte)0x14, (byte)0x15, (byte)0x16, (byte)0x17,
+            (byte)0x18, (byte)0x19, (byte)0x1a, (byte)0x1b,
+            (byte)0x1c, (byte)0x1d, (byte)0x1e, (byte)0x1f,
+            (byte)0x20, (byte)0x21, (byte)0x22, (byte)0x23,
+            (byte)0x24, (byte)0x25, (byte)0x26, (byte)0x27,
+            (byte)0x28, (byte)0x29, (byte)0x2a, (byte)0x2b,
+            (byte)0x2c, (byte)0x2d, (byte)0x2e, (byte)0x2f,
+            (byte)0x30, (byte)0x31, (byte)0x32, (byte)0x33,
+            (byte)0x34, (byte)0x35, (byte)0x36, (byte)0x37,
+        };
+        serializeTest(icmpRawPayload, (short)0xe553);
+
+        serializeTest(null, (short)0xb108);
+        serializeTest(new byte[0], (short)0xb108);
+
+        byte[] odd = {
+            (byte)0xba, (byte)0xd4, (byte)0xc7, (byte)0x53,
+            (byte)0xf8, (byte)0x59, (byte)0x68, (byte)0x77,
+            (byte)0xfd, (byte)0x27, (byte)0xe0, (byte)0x5b,
+            (byte)0xd0, (byte)0x2e, (byte)0x28, (byte)0x41,
+            (byte)0xa3, (byte)0x48, (byte)0x5d, (byte)0x2e,
+            (byte)0x7d, (byte)0x5b, (byte)0xd3, (byte)0x60,
+            (byte)0xb3, (byte)0x88, (byte)0x8d, (byte)0x0f,
+            (byte)0x1d, (byte)0x87, (byte)0x51, (byte)0x0f,
+            (byte)0x6a, (byte)0xff, (byte)0xf7, (byte)0xd4,
+            (byte)0x40, (byte)0x35, (byte)0x4e, (byte)0x01,
+            (byte)0x36,
+        };
+        serializeTest(odd, (short)0xd0ad);
+
+        // Large payload that causes 16-bit checksum overflow more than
+        // 255 times.
+        byte[] largeEven = new byte[1024];
+        Arrays.fill(largeEven, (byte)0xff);
+        serializeTest(largeEven, (short)0xb108);
+
+        byte[] largeOdd = new byte[1021];
+        Arrays.fill(largeOdd, (byte)0xff);
+        serializeTest(largeOdd, (short)0xb207);
+
+        // Serialize an empty packet.
+        ICMP icmp = new ICMP();
+        byte[] expected = new byte[8];
+
+        // Checksum should be updated.
+        expected[2] = (byte)0xff;
+        expected[3] = (byte)0xff;
+        assertArrayEquals(expected, icmp.serialize());
+    }
+
+    /**
+     * Ensure that the ICMP packet is serializable and deserializable.
+     *
+     * @param payload   The raw packet of the ICMP packet.
+     * @param checksum  The expected ICMP checksum.
+     * @throws Exception  An error occurred.
+     */
+    private void serializeTest(byte[] payload, short checksum)
+        throws Exception {
+        ICMP icmp = new ICMP();
+        icmp.setType((byte)8).setCode((byte)0).
+            setIdentifier((short)0x46f5).setSequenceNumber((short)2);
+        int payloadSize = 0;
+        if (payload != null) {
+            icmp.setRawPayload(payload);
+            payloadSize = payload.length;
+        }
+
+        // Serialize
+        byte[] data = icmp.serialize();
+        assertEquals(payloadSize + 8, data.length);
+
+        // Deserialize
+        ICMP icmpDes = new ICMP();
+        icmpDes.deserialize(data, 0, data.length);
+
+        assertFalse(icmpDes.isCorrupted());
+        assertEquals(checksum, icmpDes.getChecksum());
+        assertEquals(icmp, icmpDes);
+        assertEquals(false, icmpDes.isCorrupted());
+
+        // Ensure that data corruption can be detected.
+        data[0] = (byte)~data[0];
+        icmpDes = new ICMP();
+        icmpDes.deserialize(data, 0, data.length);
+        assertEquals(true, icmpDes.isCorrupted());
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/IEEE8021QTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/IEEE8021QTest.java
new file mode 100644 (file)
index 0000000..1574602
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.util.EtherAddress;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link IEEE8021Q}.
+ */
+public class IEEE8021QTest extends TestBase {
+    /**
+     * Test case for the priority code point.
+     *
+     * <ul>
+     *   <li>{@link IEEE8021Q#getPcp()}</li>
+     *   <li>{@link IEEE8021Q#setPcp(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetPcp() {
+        IEEE8021Q vlan = new IEEE8021Q();
+        assertEquals((byte)0, vlan.getPcp());
+
+        for (byte v = 0; v <= 7; v++) {
+            assertSame(vlan, vlan.setPcp(v));
+            assertEquals(v, vlan.getPcp());
+        }
+    }
+
+    /**
+     * Test case for the canonical format indicator.
+     *
+     * <ul>
+     *   <li>{@link IEEE8021Q#getCfi()}</li>
+     *   <li>{@link IEEE8021Q#setCfi(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetCfi() throws Exception {
+        IEEE8021Q vlan = new IEEE8021Q();
+        assertEquals((byte)0, vlan.getCfi());
+
+        for (byte v = 0; v <= 1; v++) {
+            assertSame(vlan, vlan.setCfi(v));
+            assertEquals(v, vlan.getCfi());
+        }
+    }
+
+    /**
+     * Test case for the VLAN ID.
+     *
+     * <ul>
+     *   <li>{@link IEEE8021Q#getVid()}</li>
+     *   <li>{@link IEEE8021Q#setVid(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetVid() throws Exception {
+        IEEE8021Q vlan = new IEEE8021Q();
+        assertEquals((short)0, vlan.getVid());
+
+        short[] values = {
+            0, 1, 4, 21, 127, 128, 254, 255, 256, 257, 1023, 1024, 1025,
+            2000, 3000, 4000, 4093, 4094, 4095,
+        };
+        for (short v: values) {
+            assertSame(vlan, vlan.setVid(v));
+            assertEquals(v, vlan.getVid());
+        }
+    }
+
+    /**
+     * Test case for the Ethernet type.
+     *
+     * <ul>
+     *   <li>{@link IEEE8021Q#getEtherType()}</li>
+     *   <li>{@link IEEE8021Q#setEtherType(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetEthertype() throws Exception {
+        IEEE8021Q vlan = new IEEE8021Q();
+        assertEquals((short)0, vlan.getVid());
+
+        short[] values = {
+            (short)0x0000, (short)0x0001, (short)0x0020, (short)0x03ff,
+            (short)0x07ff, (short)0x0800, (short)0x0999, (short)0x1abc,
+            (short)0x5678, (short)0x7fff, (short)0x8000, (short)0x8888,
+            (short)0xabcd, (short)0xcdef, (short)0xff00, (short)0xffff,
+        };
+        for (short v: values) {
+            assertSame(vlan, vlan.setEtherType(v));
+            assertEquals(v, vlan.getEtherType());
+        }
+    }
+
+    /**
+     * Ensure that the IEEE8021Q packet is deserializable.
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testDeserialize() throws Exception {
+        byte[] data = {
+            // Destination MAC address.
+            (byte)0x0a, (byte)0x0c, (byte)0x0e, (byte)0x14,
+            (byte)0x37, (byte)0x45,
+
+            // Source MAC address.
+            (byte)0xa6, (byte)0xec, (byte)0x9c, (byte)0xae,
+            (byte)0xb2, (byte)0x9f,
+
+            // Ether type.
+            (byte)0x81, (byte)0x00,
+
+            // VLAN tag
+            // PCP, CFI, and VLAN ID.
+            (byte)0xaf, (byte)0xfe,
+
+            // Ethernet type.
+            0x08, 0x06,
+
+            // ARP
+
+            // Hardware type.
+            0x00, 0x01,
+
+            // Protocol type.
+            0x08, 0x00,
+
+            // Hardware address length.
+            0x06,
+
+            // Protocol address length.
+            0x04,
+
+            // ARP operation code.
+            0x00, 0x01,
+
+            // Sender hardware address.
+            (byte)0xa6, (byte)0xec, (byte)0x9c, (byte)0xae,
+            (byte)0xb2, (byte)0x9f,
+
+            // Sender protocol address.
+            (byte)0x09, (byte)0x09, (byte)0x09, (byte)0x01,
+
+            // Target hardware address.
+            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+            (byte)0x00, (byte)0x00,
+
+            // Target protocol address.
+            (byte)0x09, (byte)0x09, (byte)0x09, (byte)0xfe,
+        };
+
+        short startOffset = 0;
+        short numBits = (short)(data.length * 8);
+        Ethernet eth = new Ethernet();
+        eth.deserialize(data, startOffset, numBits);
+
+        assertEquals((short)0x8100, eth.getEtherType());
+
+        IEEE8021Q vlan = (IEEE8021Q)eth.getPayload();
+        assertEquals((byte)0, vlan.getCfi());
+        assertEquals((byte)5, vlan.getPcp());
+        assertEquals((short)4094, vlan.getVid());
+        assertEquals((short)0x0806, vlan.getEtherType());
+
+        ARP arp = (ARP)vlan.getPayload();
+        assertEquals((short)0x1, arp.getHardwareType());
+        assertEquals((short)0x0800, arp.getProtocolType());
+        assertEquals((byte)0x06, arp.getHardwareAddressLength());
+        assertEquals((byte)0x04, arp.getProtocolAddressLength());
+        assertEquals((short)1, arp.getOpCode());
+
+        byte[] sha = {
+            (byte)0xa6, (byte)0xec, (byte)0x9c, (byte)0xae,
+            (byte)0xb2, (byte)0x9f,
+        };
+        byte[] spa = {
+            (byte)0x09, (byte)0x09, (byte)0x09, (byte)0x01,
+        };
+        byte[] tha = {
+            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+            (byte)0x00, (byte)0x00,
+        };
+        byte[] tpa = {
+            (byte)0x09, (byte)0x09, (byte)0x09, (byte)0xfe,
+        };
+        assertArrayEquals(sha, arp.getSenderHardwareAddress());
+        assertArrayEquals(spa, arp.getSenderProtocolAddress());
+        assertArrayEquals(tha, arp.getTargetHardwareAddress());
+        assertArrayEquals(tpa, arp.getTargetProtocolAddress());
+    }
+
+    /**
+     * Enshre that the IEEE8021Q packet is serializable.
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testSerialize() throws Exception {
+
+        byte[] dMac = {
+            (byte)0xa, (byte)0xc, (byte)0xe, (byte)0x14,
+            (byte)0x37, (byte)0x45,
+        };
+        byte[] sMac = {
+            (byte)0xa6, (byte)0xec, (byte)0x9c, (byte)0xae,
+            (byte)0xb2, (byte)0x9f,
+        };
+
+        Ethernet eth = new Ethernet().
+            setDestinationMACAddress(dMac).
+            setSourceMACAddress(sMac).
+            setEtherType((short)0x8100);
+
+        IEEE8021Q vlan = new IEEE8021Q().
+            setCfi((byte)0x0).
+            setPcp((byte)0x5).
+            setVid((short)4094).
+            setEtherType((short)0x806);
+
+        eth.setPayload(vlan);
+
+        ARP arp = new ARP().
+            setHardwareType((short)1).
+            setProtocolType((short)0x800).
+            setHardwareAddressLength((byte)0x6).
+            setProtocolAddressLength((byte)0x4).
+            setOpCode((byte)0x1);
+
+        byte[] sha = {
+            (byte)0xa6, (byte)0xec, (byte)0x9c, (byte)0xae,
+            (byte)0xb2, (byte)0x9f,
+        };
+        byte[] tha = {
+            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+            (byte)0x00, (byte)0x00,
+        };
+        byte[] spa = {(byte)0x9, (byte)0x9, (byte)0x9, (byte)0x01};
+        byte[] tpa = {(byte)0x9, (byte)0x9, (byte)0x9, (byte)0xfe};
+        arp.setSenderHardwareAddress(sha);
+        arp.setSenderProtocolAddress(spa);
+        arp.setTargetHardwareAddress(tha);
+        arp.setTargetProtocolAddress(tpa);
+
+        vlan.setPayload(arp);
+
+        byte[] data = eth.serialize();
+
+        // Ethernet header
+
+         // Destination MAC adress.
+        assertEquals((byte)0x0a, data[0]);
+        assertEquals((byte)0x0c, data[1]);
+        assertEquals((byte)0x0e, data[2]);
+        assertEquals((byte)0x14, data[3]);
+        assertEquals((byte)0x37, data[4]);
+        assertEquals((byte)0x45, data[5]);
+
+         // Source MAC address.
+        assertEquals((byte)0xa6, data[6]);
+        assertEquals((byte)0xec, data[7]);
+        assertEquals((byte)0x9c, data[8]);
+        assertEquals((byte)0xae, data[9]);
+        assertEquals((byte)0xb2, data[10]);
+        assertEquals((byte)0x9f, data[11]);
+
+        // Ethernet type.
+        assertEquals((byte)0x81, data[12]);
+        assertEquals((byte)0x00, data[13]);
+
+        // VLAN Tag
+
+        // PCP, CFI, VLAN ID
+        assertEquals((byte)0xaf, data[14]);
+        assertEquals((byte)0xfe, data[15]);
+
+        // Ethernet type.
+        assertEquals((byte)0x08, data[16]);
+        assertEquals((byte)0x06, data[17]);
+
+        // ARP
+
+        // Hardware type.
+        assertEquals((byte)0x00, data[18]);
+        assertEquals((byte)0x01, data[19]);
+
+        // Protocol type.
+        assertEquals((byte)0x08, data[20]);
+        assertEquals((byte)0x00, data[21]);
+
+        // Hardware address length.
+        assertEquals((byte)0x06, data[22]);
+
+        // Protocol address length.
+        assertEquals((byte)0x04, data[23]);
+
+        // ARP operation code.
+        assertEquals((byte)0x00, data[24]);
+        assertEquals((byte)0x01, data[25]);
+
+        // Sender hardware address.
+        assertEquals((byte)0xa6, data[26]);
+        assertEquals((byte)0xec, data[27]);
+        assertEquals((byte)0x9c, data[28]);
+        assertEquals((byte)0xae, data[29]);
+        assertEquals((byte)0xb2, data[30]);
+        assertEquals((byte)0x9f, data[31]);
+
+        // Sender protocol address.
+        assertEquals((byte)0x09, data[32]);
+        assertEquals((byte)0x09, data[33]);
+        assertEquals((byte)0x09, data[34]);
+        assertEquals((byte)0x01, data[35]);
+
+        // Target hardware address.
+        assertEquals((byte)0x00, data[36]);
+        assertEquals((byte)0x00, data[37]);
+        assertEquals((byte)0x00, data[38]);
+        assertEquals((byte)0x00, data[39]);
+        assertEquals((byte)0x00, data[40]);
+        assertEquals((byte)0x00, data[41]);
+
+        // Target protocol address
+        assertEquals((byte)0x09, data[42]);
+        assertEquals((byte)0x09, data[43]);
+        assertEquals((byte)0x09, data[44]);
+        assertEquals((byte)0xfe, data[45]);
+    }
+
+    /**
+     * Test case for {@link IEEE8021Q#clone()}.
+     */
+    @Test
+    public void testClone() {
+        byte pcp = 5;
+        byte cfi = 0;
+        short vid = 104;
+        short etype = 0x806;
+        IEEE8021Q vlan = new IEEE8021Q().
+            setPcp(pcp).
+            setCfi(cfi).
+            setVid(vid).
+            setEtherType(etype);
+
+        short hwtype = 1;
+        short ptype = 123;
+        byte hlen = 6;
+        byte plen = 4;
+        short op = 7;
+        EtherAddress sha = new EtherAddress(0x001122334455L);
+        EtherAddress tha = new EtherAddress(0xa0b0c0d0e0f0L);
+        Ip4Network spa = new Ip4Network("1.2.3.4");
+        Ip4Network tpa = new Ip4Network("192.168.34.56");
+        ARP arp = new ARP().
+            setHardwareType(hwtype).
+            setProtocolType(ptype).
+            setHardwareAddressLength(hlen).
+            setProtocolAddressLength(plen).
+            setOpCode(op).
+            setSenderHardwareAddress(sha.getBytes()).
+            setTargetHardwareAddress(tha.getBytes()).
+            setSenderProtocolAddress(spa.getBytes()).
+            setTargetProtocolAddress(tpa.getBytes());
+
+        vlan.setPayload(arp);
+
+        IEEE8021Q copy = vlan.clone();
+        assertNotSame(vlan, copy);
+        assertEquals(vlan, copy);
+        assertEquals(vlan.hashCode(), copy.hashCode());
+        assertEquals(null, copy.getRawPayload());
+
+        Packet payload = copy.getPayload();
+        assertNotSame(arp, payload);
+        assertEquals(arp, payload);
+        assertEquals(null, payload.getRawPayload());
+
+        // Modifying the source packet should never affect a deep copy.
+        byte pcp1 = 7;
+        byte cfi1 = 1;
+        short vid1 = 4095;
+        short etype1 = 0x811;
+        vlan.setPcp(pcp1).
+            setCfi(cfi1).
+            setVid(vid1).
+            setEtherType(etype1);
+        vlan.setPayload(null);
+
+        assertEquals(cfi, copy.getCfi());
+        assertEquals(pcp, copy.getPcp());
+        assertEquals(vid, copy.getVid());
+        assertEquals(etype, copy.getEtherType());
+
+        assertEquals(cfi1, vlan.getCfi());
+        assertEquals(pcp1, vlan.getPcp());
+        assertEquals(vid1, vlan.getVid());
+        assertEquals(etype1, vlan.getEtherType());
+
+        assertEquals(null, vlan.getPayload());
+        assertEquals(payload, copy.getPayload());
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/IPv4Test.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/IPv4Test.java
new file mode 100644 (file)
index 0000000..cee5ff4
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import static org.opendaylight.vtn.manager.util.NumberUtils.getUnsigned;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.util.EtherTypes;
+import org.opendaylight.vtn.manager.util.InetProtocols;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link IPv4}.
+ */
+public class IPv4Test extends TestBase {
+    /**
+     * Test case for {@link IPv4#getPayloadClass(byte)}.
+     */
+    @Test
+    public void testGetPayloadClass() {
+        for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+            Class<?> expected;
+            if (i == 1) {
+                expected = ICMP.class;
+            } else if (i == 6) {
+                expected = TCP.class;
+            } else if (i == 17) {
+                expected = UDP.class;
+            } else {
+                expected = null;
+            }
+
+            assertEquals(expected, IPv4.getPayloadClass((byte)i));
+        }
+    }
+
+    /**
+     * Test case for IP version.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getVersion()}</li>
+     *   <li>{@link IPv4#setVersion(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetVersion() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)4, ip.getVersion());
+
+        for (byte v = 0; v <= 15; v++) {
+            assertSame(ip, ip.setVersion(v));
+            assertEquals(v, ip.getVersion());
+        }
+    }
+
+    /**
+     * Test case for IP header length.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getHeaderLen()}</li>
+     *   <li>{@link IPv4#setHeaderLength(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetHeaderLength() {
+        IPv4 ip = new IPv4();
+        assertEquals(20, ip.getHeaderLen());
+
+        for (byte v = 0; v <= 15; v++) {
+            assertSame(ip, ip.setHeaderLength(v));
+            assertEquals(v * 4, ip.getHeaderLen());
+        }
+    }
+
+    /**
+     * Test case for IP differential services.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getDiffServ()}</li>
+     *   <li>{@link IPv4#setDiffServ(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetDiffServ() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getDiffServ());
+
+        for (byte v = 0; v <= 63; v++) {
+            assertSame(ip, ip.setDiffServ(v));
+            assertEquals(v, ip.getDiffServ());
+        }
+    }
+
+    /**
+     * Test case for IP ECN bits.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getECN()}</li>
+     *   <li>{@link IPv4#setECN(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetECN() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getECN());
+
+        for (byte v = 0; v <= 3; v++) {
+            assertSame(ip, ip.setECN(v));
+            assertEquals(v, ip.getECN());
+        }
+    }
+
+    /**
+     * Test case for the IP total length.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getTotalLength()}</li>
+     *   <li>{@link IPv4#setTotalLength(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetTotalLength() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getTotalLength());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short v: values) {
+            assertSame(ip, ip.setTotalLength(v));
+            assertEquals(v, ip.getTotalLength());
+        }
+    }
+
+    /**
+     * Test case for the IP identification.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getIdentification()}</li>
+     *   <li>{@link IPv4#setIdentification(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetIdentification() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getIdentification());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short v: values) {
+            assertSame(ip, ip.setIdentification(v));
+            assertEquals(v, ip.getIdentification());
+        }
+    }
+
+    /**
+     * Test case for the IPv4 flags.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getFlags()}</li>
+     *   <li>{@link IPv4#setFlags(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetFlags() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)2, ip.getFlags());
+
+        byte[] values = {0, 1, 9, 57, 94, 127, -128, -127, -15, -2, -1};
+        for (byte v: values) {
+            assertSame(ip, ip.setFlags(v));
+            assertEquals(v, ip.getFlags());
+        }
+    }
+
+    /**
+     * Test case for TTL.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getTtl()}</li>
+     *   <li>{@link IPv4#setTtl(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetTtl() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getTtl());
+
+        byte[] values = {0, 1, 9, 57, 94, 127, -128, -127, -15, -2, -1};
+        for (byte v: values) {
+            assertSame(ip, ip.setTtl(v));
+            assertEquals(v, ip.getTtl());
+        }
+    }
+
+    /**
+     * Test case for the IP protocol number.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getProtocol()}</li>
+     *   <li>{@link IPv4#setProtocol(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetProtocol() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getProtocol());
+
+        byte[] values = {0, 1, 9, 57, 94, 127, -128, -127, -15, -2, -1};
+        for (byte v: values) {
+            assertSame(ip, ip.setProtocol(v));
+            assertEquals(v, ip.getProtocol());
+        }
+    }
+
+    /**
+     * Test case for the IPv4 checksum.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getChecksum()}</li>
+     *   <li>{@link IPv4#setChecksum(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetChecksum() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getChecksum());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short v: values) {
+            assertSame(ip, ip.setChecksum(v));
+            assertEquals(v, ip.getChecksum());
+        }
+    }
+
+    /**
+     * Test case for the IP fragmentation offset.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getFragmentOffset()}</li>
+     *   <li>{@link IPv4#setFragmentOffset(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetFragmentOffset() {
+        IPv4 ip = new IPv4();
+        assertEquals((byte)0, ip.getFragmentOffset());
+
+        short[] values = {0, 1, 19, 456, 719, 1024, 2491, 6182, 8190, 8191};
+        for (short v: values) {
+            assertSame(ip, ip.setFragmentOffset(v));
+            assertEquals(v, ip.getFragmentOffset());
+        }
+    }
+
+    /**
+     * Test case for the source IP address.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getSourceAddress()}</li>
+     *   <li>{@link IPv4#setSourceAddress(Ip4Network)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetSourceAddress() {
+        IPv4 ip = new IPv4();
+        assertEquals(new Ip4Network(0), ip.getSourceAddress());
+
+        Ip4Network[] addrs = {
+            new Ip4Network("11.22.33.44"),
+            new Ip4Network("127.0.0.1"),
+            new Ip4Network("192.168.45.254"),
+            new Ip4Network("200.35.87.176"),
+        };
+        for (Ip4Network addr: addrs) {
+            assertSame(ip, ip.setSourceAddress(addr));
+            assertEquals(addr, ip.getSourceAddress());
+        }
+    }
+
+    /**
+     * Test case for the destination IP address.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getDestinationAddress()}</li>
+     *   <li>{@link IPv4#setDestinationAddress(Ip4Network)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetDestinationAddress() {
+        IPv4 ip = new IPv4();
+        assertEquals(new Ip4Network(0), ip.getDestinationAddress());
+
+        Ip4Network[] addrs = {
+            new Ip4Network("11.22.33.44"),
+            new Ip4Network("127.0.0.1"),
+            new Ip4Network("192.168.45.254"),
+            new Ip4Network("200.35.87.176"),
+        };
+        for (Ip4Network addr: addrs) {
+            assertSame(ip, ip.setDestinationAddress(addr));
+            assertEquals(addr, ip.getDestinationAddress());
+        }
+    }
+
+
+    /**
+     * Test case for the IPv4 options.
+     *
+     * <ul>
+     *   <li>{@link IPv4#getOptions()}</li>
+     *   <li>{@link IPv4#setOptions(byte[])}</li>
+     * </ul>
+     */
+    @Test
+    public void testOptions() throws Exception {
+        IPv4 ip = new IPv4();
+        assertEquals(20, ip.getHeaderLen());
+        assertEquals(160, ip.getHeaderSize());
+        assertEquals(0, ip.getFieldNumBits("Options"));
+
+        byte[][] options = {
+            new byte[] {
+                (byte)0x01,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+            },
+            null,
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05, (byte)0x06,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05, (byte)0x06, (byte)0x07,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08,
+            },
+            new byte[0],
+        };
+
+        byte[][] expected = {
+            new byte[] {
+                (byte)0x01, (byte)0x00, (byte)0x00, (byte)0x00,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x00, (byte)0x00,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x00,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+            },
+            null,
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05, (byte)0x00, (byte)0x00, (byte)0x00,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05, (byte)0x06, (byte)0x00, (byte)0x00,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x00,
+            },
+            new byte[] {
+                (byte)0x01, (byte)0x02, (byte)0x03, (byte)0x04,
+                (byte)0x05, (byte)0x06, (byte)0x07, (byte)0x08,
+            },
+            null,
+        };
+
+        byte[] echo = {
+            (byte)0x11, (byte)0x22, (byte)0x33, (byte)0x44,
+            (byte)0x55, (byte)0x66, (byte)0x77, (byte)0x88,
+            (byte)0x99, (byte)0xaa,
+        };
+        ICMP icmp = new ICMP();
+        icmp.setType((byte)8);
+        icmp.setCode((byte)0);
+        icmp.setIdentifier((short)0xabcd);
+        icmp.setSequenceNumber((short)7777);
+        icmp.setRawPayload(echo);
+
+        ip.setSourceAddress(new Ip4Network("192.168.10.20"));
+        ip.setDestinationAddress(new Ip4Network("192.168.30.40"));
+        ip.setProtocol(InetProtocols.ICMP.byteValue());
+
+        for (int i = 0; i < options.length; i++) {
+            byte[] opts = options[i];
+            byte[] exp = expected[i];
+
+            // Set IPv4 options.
+            int hlen = 20;
+            int optlen;
+            if (exp != null) {
+                optlen = exp.length;
+                hlen += optlen;
+            } else {
+                optlen = 0;
+            }
+            ip.setOptions(opts);
+            assertArrayEquals(exp, ip.getOptions());
+            assertEquals(hlen, ip.getHeaderLen());
+            assertEquals(hlen * 8, ip.getHeaderSize());
+            assertEquals(optlen * 8, ip.getFieldNumBits("Options"));
+
+            // Serialize/Deserialize test.
+            ip.setPayload(icmp);
+
+            byte[] raw = ip.serialize();
+            IPv4 newip = new IPv4();
+            newip.deserialize(raw, 0, raw.length * 8);
+            assertEquals(ip, newip);
+            assertEquals(icmp, newip.getPayload());
+            assertArrayEquals(exp, newip.getOptions());
+        }
+    }
+
+    /**
+     * Test case for the IPv4 checksum computation.
+     */
+    @Test
+    public void testChecksum() {
+        byte[] header = {
+            (byte)0x45, 00, 00, (byte)0x3c, (byte)0x1c,
+            (byte)0x46, (byte)0x40, 00, (byte)0x40, 06, (byte)0xb1,
+            (byte)0xe6, (byte)0xac, (byte)0x10, (byte)0x0a,
+            (byte)0x63, (byte)0xac, (byte)0x10, (byte)0x0a, (byte)0x0c
+        };
+        byte[] header2 = {
+            (byte)0x45, 00, 00, (byte)0x73, 00, 00,
+            (byte)0x40, 00, (byte)0x40, (byte)0x11, (byte)0xb8,
+            (byte)0x61, (byte)0xc0, (byte)0xa8, 00, 01, (byte)0xc0,
+            (byte)0xa8, 00, (byte)0xc7
+        };
+        byte[] header3 = {
+            (byte)0x45, 00, 00, (byte)0x47, (byte)0x73,
+            (byte)0x88, (byte)0x40, 00, (byte)0x40, 06, (byte)0xA2,
+            (byte)0xC4, (byte)0x83, (byte)0x9F, (byte)0x0E,
+            (byte)0x85, (byte)0x83, (byte)0x9F, (byte)0x0E, (byte)0xA1
+        };
+        byte[] header4 = {
+            (byte)0x45, 00, 00, (byte)0x54, 00, 00,
+            (byte)0x40, 00, (byte)0x40, 01, (byte)0xf0, (byte)0x8e,
+            (byte)0xc0, (byte)0xa8, (byte)0x64, (byte)0x65,
+            (byte)0xc0, (byte)0xa8, (byte)0x64, (byte)0x64
+        };
+        byte[] header5 = {
+            (byte)0x45, 00, 00, (byte)0x54, 00, 00,
+            (byte)0x40, 00, (byte)0x40, 01, (byte)0xef, (byte)0x8d,
+            (byte)0xc0, (byte)0xa8, (byte)0x64, (byte)0x65,
+            (byte)0xc0, (byte)0xa8, (byte)0x65, (byte)0x65
+        };
+        byte[] header6 = {
+            (byte)0x45, 00, 00, (byte)0x54, 00, 00,
+            (byte)0x40, 00, (byte)0x40, 01, (byte)0x0b, (byte)0x92,
+            (byte)0xc0, (byte)0xa8, (byte)0x64, (byte)0x65, (byte)0x9,
+            (byte)0x9, (byte)0x1, (byte)0x1
+        };
+        byte[] header7 = {
+            (byte)0x45, 00, 00, (byte)0x54, 00, 00,
+            (byte)0x40, 00, (byte)0x40, 01, (byte)0, (byte)0,
+            (byte)0xc0, (byte)0xa8, (byte)0x64, (byte)0x65, (byte)0x9,
+            (byte)0x9, (byte)0x2, (byte)0x2
+        };
+
+        IPv4 ip = new IPv4();
+        assertEquals(0xb1e6, getUnsigned(ip.computeChecksum(header, 0)));
+        assertEquals(0xb861, getUnsigned(ip.computeChecksum(header2, 0)));
+        assertEquals(0xa2c4, getUnsigned(ip.computeChecksum(header3, 0)));
+        assertEquals(0xf08e, getUnsigned(ip.computeChecksum(header4, 0)));
+        assertEquals(0xef8d, getUnsigned(ip.computeChecksum(header5, 0)));
+        assertEquals(0x0b92, getUnsigned(ip.computeChecksum(header6, 0)));
+        assertEquals(0x0a91, getUnsigned(ip.computeChecksum(header7, 0)));
+    }
+
+    /**
+     * Test case for serialization.
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testSerialization() throws Exception {
+        byte[] icmpRawPayload = {
+            (byte)0x38, (byte)0x26, (byte)0x9e, (byte)0x51,
+            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+            (byte)0x2e, (byte)0x6a, (byte)0x08, (byte)0x00,
+            (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00,
+            (byte)0x10, (byte)0x11, (byte)0x12, (byte)0x13,
+            (byte)0x14, (byte)0x15, (byte)0x16, (byte)0x17,
+            (byte)0x18, (byte)0x19, (byte)0x1a, (byte)0x1b,
+            (byte)0x1c, (byte)0x1d, (byte)0x1e, (byte)0x1f,
+            (byte)0x20, (byte)0x21, (byte)0x22, (byte)0x23,
+            (byte)0x24, (byte)0x25, (byte)0x26, (byte)0x27,
+            (byte)0x28, (byte)0x29, (byte)0x2a, (byte)0x2b,
+            (byte)0x2c, (byte)0x2d, (byte)0x2e, (byte)0x2f,
+            (byte)0x30, (byte)0x31, (byte)0x32, (byte)0x33,
+            (byte)0x34, (byte)0x35, (byte)0x36, (byte)0x37,
+        };
+
+        ICMP icmp = new ICMP();
+        icmp.setType((byte)8);
+        icmp.setCode((byte)0);
+        icmp.setIdentifier((short)0x46f5);
+        icmp.setSequenceNumber((short)2);
+        icmp.setRawPayload(icmpRawPayload);
+
+        IPv4 ip = new IPv4();
+        ip.setVersion((byte)4);
+        ip.setIdentification((short)5);
+        ip.setDiffServ((byte)0);
+        ip.setECN((byte)0);
+        ip.setTotalLength((short)84);
+        ip.setFlags((byte)2);
+        ip.setFragmentOffset((short)0);
+        ip.setTtl((byte)64);
+        ip.setProtocol(InetProtocols.ICMP.byteValue());
+        ip.setDestinationAddress(new Ip4Network("192.168.100.100"));
+        ip.setSourceAddress(new Ip4Network("192.168.100.101"));
+        ip.setPayload(icmp);
+
+        Ethernet eth = new Ethernet();
+        byte[] dstMac = {
+            (byte)0x98, (byte)0xfc, (byte)0x11, (byte)0x93,
+            (byte)0x5c, (byte)0xb8,
+        };
+        byte[] srcMac = {
+            (byte)0x00, (byte)0x24, (byte)0xd7, (byte)0xa9,
+            (byte)0xa3, (byte)0x50,
+        };
+        eth.setDestinationMACAddress(dstMac);
+        eth.setSourceMACAddress(srcMac);
+        eth.setEtherType(EtherTypes.IPV4.shortValue());
+        eth.setPayload(ip);
+
+        byte[] stream = eth.serialize();
+        Ethernet decEth = new Ethernet();
+        decEth.deserialize(stream, 0, stream.length * Byte.SIZE);
+
+        IPv4 decIp = (IPv4)decEth.getPayload();
+        assertFalse(decIp.isCorrupted());
+        assertTrue(ip.equals(decIp));
+
+        ICMP decIcmp = (ICMP)decIp.getPayload();
+        assertFalse(decIcmp.isCorrupted());
+        assertArrayEquals(icmpRawPayload, decIcmp.getRawPayload());
+    }
+
+    /**
+     * Test case for IPv4 header fragmentation.
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testFragment()throws Exception {
+        byte[] payload1 = new byte[0];
+        byte[] payload2 = {
+            (byte)0x61, (byte)0xd1, (byte)0x3d, (byte)0x51,
+            (byte)0x1b, (byte)0x75, (byte)0xa7, (byte)0x83,
+        };
+        byte[] payload3 = {
+            (byte)0xe7, (byte)0x0f, (byte)0x2d, (byte)0x7e,
+            (byte)0x15, (byte)0xba, (byte)0xe7, (byte)0x6d,
+            (byte)0xb5, (byte)0xc5, (byte)0xb5, (byte)0x37,
+            (byte)0x59, (byte)0xbc, (byte)0x91, (byte)0x43,
+            (byte)0xb5, (byte)0xb7, (byte)0xe4, (byte)0x28,
+            (byte)0xec, (byte)0x62, (byte)0x6b, (byte)0x6a,
+            (byte)0xd1, (byte)0xcb, (byte)0x79, (byte)0x1e,
+            (byte)0xfc, (byte)0x82, (byte)0xf5, (byte)0xb4,
+        };
+
+        // Ensure that the payload is not deserialized if the fragment offset
+        // is not zero.
+        byte proto = InetProtocols.TCP.byteValue();
+        fragmentTest(payload1, proto, (short)0xf250);
+        fragmentTest(payload2, proto, (short)0xf248);
+        fragmentTest(payload3, proto, (short)0xf230);
+
+        proto = InetProtocols.UDP.byteValue();
+        fragmentTest(payload1, proto, (short)0xf245);
+        fragmentTest(payload2, proto, (short)0xf23d);
+        fragmentTest(payload3, proto, (short)0xf225);
+
+        proto = InetProtocols.ICMP.byteValue();
+        fragmentTest(payload1, proto, (short)0xf255);
+        fragmentTest(payload2, proto, (short)0xf24d);
+        fragmentTest(payload3, proto, (short)0xf235);
+
+        // Ensure that the protocol header in the first fragment is
+        // deserialized.
+        proto = InetProtocols.TCP.byteValue();
+        TCP tcp = new TCP();
+        tcp.setSourcePort((short)1234).setDestinationPort((short)32000).
+            setSequenceNumber((int)0xd541f5f8).setAckNumber((int)0x58da787d).
+            setDataOffset((byte)5).setReserved((byte)0).
+            setHeaderLenFlags((short)0x18).setWindowSize((short)0x40e8).
+            setUrgentPointer((short)0x15f7).setChecksum((short)0x0d4e);
+        firstFragmentTest(tcp, payload1, proto, (short)0xdfe6);
+        tcp.setChecksum((short)0xab2a);
+        firstFragmentTest(tcp, payload2, proto, (short)0xdfde);
+        tcp.setChecksum((short)0x1c75);
+        firstFragmentTest(tcp, payload3, proto, (short)0xdfc6);
+
+        proto = InetProtocols.UDP.byteValue();
+        UDP udp = new UDP();
+        udp.setSourcePort((short)53).setDestinationPort((short)45383).
+            setLength((short)(payload1.length + 8)).setChecksum((short)0);
+        firstFragmentTest(udp, payload1, proto, (short)0xdfe7);
+        udp.setLength((short)(payload2.length + 8));
+        firstFragmentTest(udp, payload2, proto, (short)0xdfdf);
+        udp.setLength((short)(payload3.length + 8));
+        firstFragmentTest(udp, payload3, proto, (short)0xdfc7);
+
+        proto = InetProtocols.ICMP.byteValue();
+        ICMP icmp = new ICMP();
+        icmp.setType((byte)8).setCode((byte)0).setIdentifier((short)0x3d1e).
+            setSequenceNumber((short)1);
+        firstFragmentTest(icmp, payload1, proto, (short)0xdff7);
+        firstFragmentTest(icmp, payload2, proto, (short)0xdfef);
+        firstFragmentTest(icmp, payload3, proto, (short)0xdfd7);
+    }
+
+    /**
+     * Test case for {@link IPv4#clone()}.
+     */
+    @Test
+    public void testClone() {
+        byte dserv = 34;
+        byte ecn = 2;
+        short id = 4981;
+        byte flag = 5;
+        byte ttl = 116;
+        byte proto = InetProtocols.UDP.byteValue();
+        short fragoff = 45;
+        short cksum = 12345;
+        Ip4Network src = new Ip4Network("10.20.30.40");
+        Ip4Network dst = new Ip4Network("192.168.100.200");
+        IPv4 ip = new IPv4().
+            setDiffServ(dserv).
+            setECN(ecn).
+            setIdentification(id).
+            setFlags(flag).
+            setTtl(ttl).
+            setProtocol(proto).
+            setFragmentOffset(fragoff).
+            setChecksum(cksum).
+            setSourceAddress(src).
+            setDestinationAddress(dst);
+
+        UDP udp = new UDP().
+            setSourcePort((short)451).
+            setDestinationPort((short)17).
+            setLength((short)567).
+            setChecksum((short)0);
+
+        byte[] raw = {
+            (byte)0x8b, (byte)0xc5, (byte)0x0b, (byte)0x3a,
+            (byte)0xc2, (byte)0x3d, (byte)0xb2, (byte)0x65,
+        };
+        udp.setRawPayload(raw);
+        ip.setPayload(udp);
+
+        IPv4 copy = ip.clone();
+        assertNotSame(ip, copy);
+        assertEquals(ip, copy);
+        assertEquals(ip.hashCode(), copy.hashCode());
+        assertEquals(null, copy.getRawPayload());
+
+        Packet payload = copy.getPayload();
+        assertNotSame(udp, payload);
+        assertEquals(udp, payload);
+        assertArrayEquals(raw, payload.getRawPayload());
+
+        // Modifying the source packet should never affect a deep copy.
+        byte dserv1 = 3;
+        byte ecn1 = 0;
+        short id1 = -31984;
+        byte flag1 = 0;
+        byte ttl1 = 12;
+        short fragoff1 = 0;
+        short cksum1 = -32315;
+        Ip4Network src1 = new Ip4Network("11.22.33.44");
+        Ip4Network dst1 = new Ip4Network("192.168.100.253");
+        ip.setDiffServ(dserv1).
+            setECN(ecn1).
+            setIdentification(id1).
+            setFlags(flag1).
+            setTtl(ttl1).
+            setFragmentOffset(fragoff1).
+            setChecksum(cksum1).
+            setSourceAddress(src1).
+            setDestinationAddress(dst1);
+
+        UDP udp1 = new UDP().
+            setSourcePort((short)64120).
+            setDestinationPort((short)45).
+            setLength((short)333).
+            setChecksum((short)12345);
+        ip.setPayload(udp1);
+
+        assertEquals(dserv, copy.getDiffServ());
+        assertEquals(ecn, copy.getECN());
+        assertEquals(id, copy.getIdentification());
+        assertEquals(flag, copy.getFlags());
+        assertEquals(ttl, copy.getTtl());
+        assertEquals(fragoff, copy.getFragmentOffset());
+        assertEquals(cksum, copy.getChecksum());
+        assertEquals(src, copy.getSourceAddress());
+        assertEquals(dst, copy.getDestinationAddress());
+
+        assertEquals(dserv1, ip.getDiffServ());
+        assertEquals(ecn1, ip.getECN());
+        assertEquals(id1, ip.getIdentification());
+        assertEquals(flag1, ip.getFlags());
+        assertEquals(ttl1, ip.getTtl());
+        assertEquals(fragoff1, ip.getFragmentOffset());
+        assertEquals(cksum1, ip.getChecksum());
+        assertEquals(src1, ip.getSourceAddress());
+        assertEquals(dst1, ip.getDestinationAddress());
+
+        assertEquals(udp, copy.getPayload());
+        assertArrayEquals(raw, copy.getPayload().getRawPayload());
+        assertEquals(udp1, ip.getPayload());
+        assertEquals(null, ip.getPayload().getRawPayload());
+    }
+
+    /**
+     * Run the IPv4 fragmentation test.
+     *
+     * @param payload   The payload of the IPv4 packet.
+     * @param proto     The IP protocol number.
+     * @param checksum  The expected IPv4 checksum value.
+     * @throws Exception  An error occurred.
+     */
+    private void fragmentTest(byte[] payload, byte proto, short checksum)
+        throws Exception {
+        // Construct a fragmented raw IPv4 packet.
+        int ipv4Len = 20;
+        byte[] rawIp = new byte[ipv4Len + payload.length];
+
+        byte ipVersion = 4;
+        byte dscp = 35;
+        byte ecn = 2;
+        byte tos = (byte)((dscp << 2) | ecn);
+        short totalLen = (short)rawIp.length;
+        short id = 22143;
+        short offset = 0xb9;
+        byte ttl = 64;
+        byte[] srcIp = {(byte)0x0a, (byte)0x00, (byte)0x00, (byte)0x01};
+        byte[] dstIp = {(byte)0xc0, (byte)0xa9, (byte)0x66, (byte)0x23};
+
+        rawIp[0] = (byte)((ipVersion << 4) | (ipv4Len >> 2));
+        rawIp[1] = tos;
+        rawIp[2] = (byte)(totalLen >>> Byte.SIZE);
+        rawIp[3] = (byte)totalLen;
+        rawIp[4] = (byte)(id >>> Byte.SIZE);
+        rawIp[5] = (byte)id;
+        rawIp[6] = (byte)(offset >>> Byte.SIZE);
+        rawIp[7] = (byte)offset;
+        rawIp[8] = ttl;
+        rawIp[9] = proto;
+        rawIp[10] = (byte)(checksum >>> Byte.SIZE);
+        rawIp[11] = (byte)checksum;
+        System.arraycopy(srcIp, 0, rawIp, 12, srcIp.length);
+        System.arraycopy(dstIp, 0, rawIp, 16, srcIp.length);
+        System.arraycopy(payload, 0, rawIp, ipv4Len, payload.length);
+
+        // Deserialize.
+        IPv4 ipv4 = new IPv4();
+        ipv4.deserialize(rawIp, 0, rawIp.length * Byte.SIZE);
+
+        assertEquals(ipVersion, ipv4.getVersion());
+        assertEquals(ipv4Len, ipv4.getHeaderLen());
+        assertEquals(dscp, ipv4.getDiffServ());
+        assertEquals(ecn, ipv4.getECN());
+        assertEquals(totalLen, ipv4.getTotalLength());
+        assertEquals(id, ipv4.getIdentification());
+        assertEquals((byte)0, ipv4.getFlags());
+        assertEquals(offset, ipv4.getFragmentOffset());
+        assertEquals(ttl, ipv4.getTtl());
+        assertEquals(proto, ipv4.getProtocol());
+        assertEquals(checksum, ipv4.getChecksum());
+        assertArrayEquals(srcIp, ipv4.getSourceAddress().getBytes());
+        assertArrayEquals(dstIp, ipv4.getDestinationAddress().getBytes());
+        assertEquals(false, ipv4.isCorrupted());
+
+        // payloadClass should not be set if fragment offset is not zero.
+        assertEquals(null, ipv4.getPayload());
+        checkRawPayload(payload, ipv4.getRawPayload());
+
+        // Ensure that data corruption can be detected.
+        rawIp[1] = (byte)~rawIp[1];
+        ipv4 = new IPv4();
+        ipv4.deserialize(rawIp, 0, rawIp.length * Byte.SIZE);
+        assertEquals(true, ipv4.isCorrupted());
+    }
+
+    /**
+     * Ensure that the protocol header in the first fragment is deserialized.
+     *
+     * @param payload     The payload of the IPv4 packet.
+     * @param rawPayload  The raw payload of the IPv4 packet.
+     * @param proto       The IP protocol number.
+     * @param checksum    The expected IPv4 checksum value.
+     * @throws Exception  An error occurred.
+     */
+    private void firstFragmentTest(Packet payload, byte[] rawPayload,
+                                   byte proto, short checksum)
+        throws Exception {
+        // Construct a raw IPv4 packet with MF flag.
+        int ipv4Len = 20;
+        payload.setRawPayload(rawPayload);
+        byte[] payloadBytes = payload.serialize();
+        byte[] rawIp = new byte[ipv4Len + payloadBytes.length];
+
+        byte ipVersion = 4;
+        byte dscp = 13;
+        byte ecn = 1;
+        byte tos = (byte)((dscp << 2) | ecn);
+        short totalLen = (short)rawIp.length;
+        short id = 19834;
+        byte flags = 0x1;
+        short offset = 0;
+        short off = (short)(((short)flags << 13) | offset);
+        byte ttl = 64;
+        byte[] srcIp = {(byte)0xac, (byte)0x23, (byte)0x5b, (byte)0xfd};
+        byte[] dstIp = {(byte)0xc0, (byte)0xa8, (byte)0x64, (byte)0x71};
+
+        rawIp[0] = (byte)((ipVersion << 4) | (ipv4Len >> 2));
+        rawIp[1] = tos;
+        rawIp[2] = (byte)(totalLen >>> Byte.SIZE);
+        rawIp[3] = (byte)totalLen;
+        rawIp[4] = (byte)(id >>> Byte.SIZE);
+        rawIp[5] = (byte)id;
+        rawIp[6] = (byte)(off >>> Byte.SIZE);
+        rawIp[7] = (byte)off;
+        rawIp[8] = ttl;
+        rawIp[9] = proto;
+        rawIp[10] = (byte)(checksum >>> Byte.SIZE);
+        rawIp[11] = (byte)checksum;
+        System.arraycopy(srcIp, 0, rawIp, 12, srcIp.length);
+        System.arraycopy(dstIp, 0, rawIp, 16, srcIp.length);
+        System.arraycopy(payloadBytes, 0, rawIp, ipv4Len, payloadBytes.length);
+
+        // Deserialize.
+        IPv4 ipv4 = new IPv4();
+        ipv4.deserialize(rawIp, 0, rawIp.length * Byte.SIZE);
+
+        assertEquals(ipVersion, ipv4.getVersion());
+        assertEquals(ipv4Len, ipv4.getHeaderLen());
+        assertEquals(dscp, ipv4.getDiffServ());
+        assertEquals(ecn, ipv4.getECN());
+        assertEquals(totalLen, ipv4.getTotalLength());
+        assertEquals(id, ipv4.getIdentification());
+        assertEquals(flags, ipv4.getFlags());
+        assertEquals(offset, ipv4.getFragmentOffset());
+        assertEquals(ttl, ipv4.getTtl());
+        assertEquals(proto, ipv4.getProtocol());
+        assertEquals(checksum, ipv4.getChecksum());
+        assertArrayEquals(srcIp, ipv4.getSourceAddress().getBytes());
+        assertArrayEquals(dstIp, ipv4.getDestinationAddress().getBytes());
+        assertEquals(false, ipv4.isCorrupted());
+
+        // Protocol header in the first fragment should be deserialized.
+        assertEquals(null, ipv4.getRawPayload());
+
+        Packet desPayload = ipv4.getPayload();
+        assertEquals(payload, desPayload);
+        assertEquals(false, desPayload.isCorrupted());
+        checkRawPayload(rawPayload, desPayload.getRawPayload());
+    }
+
+    /**
+     * Compare the raw payload.
+     *
+     * @param expected  The expected raw payload.
+     * @param payload   The raw payload to be tested.
+     */
+    private void checkRawPayload(byte[] expected, byte[] payload) {
+        if (expected == null || expected.length == 0) {
+            assertEquals(null, payload);
+        } else {
+            assertArrayEquals(expected, payload);
+        }
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/PacketExceptionTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/PacketExceptionTest.java
new file mode 100644 (file)
index 0000000..5f77b9a
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnErrorTag;
+
+/**
+ * JUnit test for {@link PacketException}.
+ */
+public class PacketExceptionTest extends TestBase {
+    /**
+     * Test case for {@link PacketException#PacketException(String)}.
+     */
+    @Test
+    public void testDefault() {
+        String[] messages = {
+            null,
+            "message 1",
+            "message 2",
+        };
+
+        IllegalArgumentException cause = new IllegalArgumentException();
+        for (String msg: messages) {
+            PacketException e = new PacketException(msg);
+            assertEquals(VtnErrorTag.INTERNALERROR, e.getVtnErrorTag());
+            assertEquals(msg, e.getMessage());
+            assertEquals(null, e.getCause());
+
+            // Ensure that no cause is configured.
+            e.initCause(cause);
+            assertEquals(cause, e.getCause());
+        }
+    }
+
+    /**
+     * Test case for {@link PacketException#PacketException(String, Throwable)}.
+     */
+    @Test
+    public void testCause() {
+        String[] messages = {
+            null,
+            "message 1",
+            "message 2",
+        };
+        Throwable[] causes = {
+            new IllegalArgumentException(),
+            new IllegalStateException(),
+            new NullPointerException(),
+        };
+
+        for (String msg: messages) {
+            for (Throwable cause: causes) {
+                PacketException e = new PacketException(msg, cause);
+                assertEquals(VtnErrorTag.INTERNALERROR, e.getVtnErrorTag());
+                assertEquals(msg, e.getMessage());
+                assertEquals(cause, e.getCause());
+            }
+        }
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/PacketTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/PacketTest.java
new file mode 100644 (file)
index 0000000..b488328
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import java.util.Map;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link Packet}.
+ */
+public class PacketTest extends TestBase {
+    /**
+     * Test case for {@link Packet#deserialize(byte[], int, int)}.
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testDeserialize() throws Exception {
+        Ethernet eth = new Ethernet();
+        byte[] data = {
+            // Destination MAC address
+            10, 12, 14, 20, 55, 69,
+
+            // Source MAC address
+            -90, -20, -100, -82, -78, -97,
+
+            // Ethernet type (ARP)
+            0x08, 0x06,
+
+            // ARP
+
+            // Hardware type
+            0, 1,
+
+            // Protocol type (IPv4)
+            0x08, 0x00,
+
+            // Hardware address length
+            6,
+
+            // Protocol address length
+            4,
+
+            // ARP operation code
+            0, 1,
+
+            // Sender hardware address
+            -90, -20, -100, -82, -78, -97,
+
+            // Sender protocol address
+            10, 20, 30, 55,
+
+            // Target hardware address
+            0, 0, 0, 0, 0, 0,
+
+            // Target protocol address
+            10, 20, 30, -2,
+        };
+
+        eth.deserialize(data, 0, data.length * Byte.SIZE);
+
+        byte[] dstMac = eth.getDestinationMACAddress();
+        byte[] srcMac = eth.getSourceMACAddress();
+        short etype = eth.getEtherType();
+
+        assertEquals(10, dstMac[0]);
+        assertEquals(12, dstMac[1]);
+        assertEquals(14, dstMac[2]);
+        assertEquals(20, dstMac[3]);
+        assertEquals(55, dstMac[4]);
+        assertEquals(69, dstMac[5]);
+
+        assertEquals(-90, srcMac[0]);
+        assertEquals(-20, srcMac[1]);
+        assertEquals(-100, srcMac[2]);
+        assertEquals(-82, srcMac[3]);
+        assertEquals(-78, srcMac[4]);
+        assertEquals(-97, srcMac[5]);
+
+        assertEquals(0x806, etype);
+
+        ARP arp = (ARP)eth.getPayload();
+
+        assertEquals((byte)0x1, arp.getHardwareType());
+        assertEquals(2048, arp.getProtocolType());
+        assertEquals((byte)0x6, arp.getHardwareAddressLength());
+        assertEquals((byte)0x4, arp.getProtocolAddressLength());
+        assertEquals(1, arp.getOpCode());
+
+        byte[] sha = arp.getSenderHardwareAddress();
+        byte[] spa = arp.getSenderProtocolAddress();
+        byte[] tha = arp.getTargetHardwareAddress();
+        byte[] tpa = arp.getTargetProtocolAddress();
+
+        assertEquals((byte)0xA6, sha[0]);
+        assertEquals((byte)0xEC, sha[1]);
+        assertEquals((byte)0x9C, sha[2]);
+        assertEquals((byte)0xAE, sha[3]);
+        assertEquals((byte)0xB2, sha[4]);
+        assertEquals((byte)0x9F, sha[5]);
+
+        assertEquals((byte)10, spa[0]);
+        assertEquals((byte)20, spa[1]);
+        assertEquals((byte)30, spa[2]);
+        assertEquals((byte)55, spa[3]);
+
+        assertEquals((byte)0x0, tha[0]);
+        assertEquals((byte)0x0, tha[1]);
+        assertEquals((byte)0x0, tha[2]);
+        assertEquals((byte)0x0, tha[3]);
+        assertEquals((byte)0x0, tha[4]);
+        assertEquals((byte)0x0, tha[5]);
+
+        assertEquals((byte)10, tpa[0]);
+        assertEquals((byte)20, tpa[1]);
+        assertEquals((byte)30, tpa[2]);
+        assertEquals((byte)-2, tpa[3]);
+    }
+
+    /**
+     * Test case for {@link Packet#serialize()}.
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testSerialize() throws Exception {
+        Ethernet eth = new Ethernet();
+        Map<String, byte[]> header = eth.getHeaderFieldMap();
+
+        byte[] dstMac = {10, 12, 14, 20, 55, 69};
+        byte[] srcMac = {82, 97, 109, 117, 127, -50};
+        short etype = 0x0806;
+
+        eth.setDestinationMACAddress(dstMac);
+        eth.setSourceMACAddress(srcMac);
+        eth.setEtherType(etype);
+
+        assertArrayEquals(dstMac, header.get("DestinationMACAddress"));
+        assertArrayEquals(srcMac, header.get("SourceMACAddress"));
+
+        byte[] etypeData = {0x08, 0x06};
+        assertArrayEquals(etypeData, header.get("EtherType"));
+
+        byte[] data = eth.serialize();
+        assertEquals(10, data[0]);
+        assertEquals(12, data[1]);
+        assertEquals(14, data[2]);
+        assertEquals(20, data[3]);
+        assertEquals(55, data[4]);
+        assertEquals(69, data[5]);
+
+        assertEquals(82, data[6]);
+        assertEquals(97, data[7]);
+        assertEquals(109, data[8]);
+        assertEquals(117, data[9]);
+        assertEquals(127, data[10]);
+        assertEquals(-50, data[11]);
+
+        assertEquals(8, data[12]);
+        assertEquals(6, data[13]);
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/TCPTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/TCPTest.java
new file mode 100644 (file)
index 0000000..83d425e
--- /dev/null
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link TCP}.
+ */
+public class TCPTest extends TestBase {
+    /**
+     * Test case for TCP source port.
+     *
+     * <ul>
+     *   <li>{@link TCP#getSourcePort()}</li>
+     *   <li>{@link TCP#setSourcePort(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetSourcePort() {
+        TCP tcp = new TCP();
+        assertEquals((short)0, tcp.getSourcePort());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short port: values) {
+            assertSame(tcp, tcp.setSourcePort(port));
+            assertEquals(port, tcp.getSourcePort());
+        }
+    }
+
+    /**
+     * Test case for TCP destination port.
+     *
+     * <ul>
+     *   <li>{@link TCP#getDestinationPort()}</li>
+     *   <li>{@link TCP#setDestinationPort(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetDestinationPort() {
+        TCP tcp = new TCP();
+        assertEquals((short)0, tcp.getDestinationPort());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short port: values) {
+            assertSame(tcp, tcp.setDestinationPort(port));
+            assertEquals(port, tcp.getDestinationPort());
+        }
+    }
+
+    /**
+     * Test case for TCP sequence number.
+     *
+     * <ul>
+     *   <li>{@link TCP#getSequenceNumber()}</li>
+     *   <li>{@link TCP#setSequenceNumber(int)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetSequenceNumber() {
+        TCP tcp = new TCP();
+        assertEquals((short)0, tcp.getSequenceNumber());
+
+        int[] values = {
+            1, 123, 4678, 0x12345678, 0x7fffffff,
+            -1, -12934, -91287345, Integer.MIN_VALUE,
+        };
+        for (int seq: values) {
+            assertSame(tcp, tcp.setSequenceNumber(seq));
+            assertEquals(seq, tcp.getSequenceNumber());
+        }
+    }
+
+    /**
+     * Test case for TCP acknowledgement number.
+     *
+     * <ul>
+     *   <li>{@link TCP#getAckNumber()}</li>
+     *   <li>{@link TCP#setAckNumber(int)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetAckNumber() {
+        TCP tcp = new TCP();
+        assertEquals((short)0, tcp.getAckNumber());
+
+        int[] values = {
+            1, 123, 4678, 0x12345678, 0x7fffffff,
+            -1, -12934, -91287345, Integer.MIN_VALUE,
+        };
+        for (int ack: values) {
+            assertSame(tcp, tcp.setAckNumber(ack));
+            assertEquals(ack, tcp.getAckNumber());
+        }
+    }
+
+    /**
+     * Test case for TCP data offset.
+     *
+     * <ul>
+     *   <li>{@link TCP#getDataOffset()}</li>
+     *   <li>{@link TCP#setDataOffset(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetDataOffset() {
+        TCP tcp = new TCP();
+        assertEquals((byte)0, tcp.getDataOffset());
+
+        for (byte off = 0; off <= 15; off++) {
+            assertSame(tcp, tcp.setDataOffset(off));
+            assertEquals(off, tcp.getDataOffset());
+        }
+    }
+
+    /**
+     * Test case for reserved field.
+     *
+     * <ul>
+     *   <li>{@link TCP#getReserved()}</li>
+     *   <li>{@link TCP#setReserved(byte)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetReserved() {
+        TCP tcp = new TCP();
+        assertEquals((byte)0, tcp.getReserved());
+
+        for (byte resv = 0; resv <= 7; resv++) {
+            assertSame(tcp, tcp.setReserved(resv));
+            assertEquals(resv, tcp.getReserved());
+        }
+    }
+
+    /**
+     * Test case for TCP header length and TCP flags.
+     *
+     * <ul>
+     *   <li>{@link TCP#getHeaderLenFlags()}</li>
+     *   <li>{@link TCP#setHeaderLenFlags(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testHeaderLenFlags() {
+        TCP tcp = new TCP();
+        assertEquals((byte)0, tcp.getHeaderLenFlags());
+
+        short[] values = {0, 1, 33, 123, 312, 456, 509, 510, 511};
+        for (short flags: values) {
+            assertSame(tcp, tcp.setHeaderLenFlags(flags));
+            assertEquals(flags, tcp.getHeaderLenFlags());
+        }
+    }
+
+    /**
+     * Test case for TCP window size.
+     *
+     * <ul>
+     *   <li>{@link TCP#getWindowSize()}</li>
+     *   <li>{@link TCP#setWindowSize(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetWindowSize() {
+        TCP tcp = new TCP();
+        assertEquals((short)0, tcp.getWindowSize());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short wsize: values) {
+            assertSame(tcp, tcp.setWindowSize(wsize));
+            assertEquals(wsize, tcp.getWindowSize());
+        }
+    }
+
+    /**
+     * Test case for TCP checksum.
+     *
+     * <ul>
+     *   <li>{@link TCP#getChecksum()}</li>
+     *   <li>{@link TCP#setChecksum(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetChecksum() {
+        TCP tcp = new TCP();
+        assertEquals((short)0, tcp.getChecksum());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short cksum: values) {
+            assertSame(tcp, tcp.setChecksum(cksum));
+            assertEquals(cksum, tcp.getChecksum());
+        }
+    }
+
+    /**
+     * Test case for TCP urgent pointer.
+     *
+     * <ul>
+     *   <li>{@link TCP#getUrgentPointer()}</li>
+     *   <li>{@link TCP#setUrgentPointer(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetUrgentPointer() {
+        TCP tcp = new TCP();
+        assertEquals((short)0, tcp.getUrgentPointer());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short urg: values) {
+            assertSame(tcp, tcp.setUrgentPointer(urg));
+            assertEquals(urg, tcp.getUrgentPointer());
+        }
+    }
+
+    /**
+     * Test case for {@link TCP#clone()}.
+     */
+    @Test
+    public void testClone() {
+        short src = 16721;
+        short dst = 999;
+        int seq = 0x761231da;
+        int ack = 0x7319efc1;
+        byte off = 12;
+        byte resv = 2;
+        short flags = 503;
+        short wsize = 31982;
+        short cksum = -30981;
+        short urg = 7788;
+        TCP tcp = new TCP().
+            setSourcePort(src).
+            setDestinationPort(dst).
+            setSequenceNumber(seq).
+            setAckNumber(ack).
+            setDataOffset(off).
+            setReserved(resv).
+            setHeaderLenFlags(flags).
+            setWindowSize(wsize).
+            setChecksum(cksum).
+            setUrgentPointer(urg);
+
+        TCP copy = tcp.clone();
+        assertNotSame(tcp, copy);
+        assertEquals(tcp, copy);
+        assertEquals(tcp.hashCode(), copy.hashCode());
+        assertEquals(null, copy.getRawPayload());
+
+        // Modifying the source packet should never affect a deep copy.
+        short src1 = 29871;
+        short dst1 = 17;
+        int seq1 = (int)0xabcdef00;
+        int ack1 = (int)0x891d4fcb;
+        byte off1 = 3;
+        byte resv1 = 0;
+        byte flags1 = 81;
+        short wsize1 = 3600;
+        short cksum1 = 19826;
+        short urg1 = 4;
+        tcp.setSourcePort(src1).
+            setDestinationPort(dst1).
+            setSequenceNumber(seq1).
+            setAckNumber(ack1).
+            setDataOffset(off1).
+            setReserved(resv1).
+            setHeaderLenFlags(flags1).
+            setWindowSize(wsize1).
+            setChecksum(cksum1).
+            setUrgentPointer(urg1);
+        byte[] payload = {
+            (byte)0x9b, (byte)0x6d, (byte)0x30, (byte)0x0e,
+        };
+
+        assertEquals(src, copy.getSourcePort());
+        assertEquals(dst, copy.getDestinationPort());
+        assertEquals(seq, copy.getSequenceNumber());
+        assertEquals(ack, copy.getAckNumber());
+        assertEquals(off, copy.getDataOffset());
+        assertEquals(resv, copy.getReserved());
+        assertEquals(flags, copy.getHeaderLenFlags());
+        assertEquals(wsize, copy.getWindowSize());
+        assertEquals(cksum, copy.getChecksum());
+        assertEquals(urg, copy.getUrgentPointer());
+
+        assertEquals(src1, tcp.getSourcePort());
+        assertEquals(dst1, tcp.getDestinationPort());
+        assertEquals(seq1, tcp.getSequenceNumber());
+        assertEquals(ack1, tcp.getAckNumber());
+        assertEquals(off1, tcp.getDataOffset());
+        assertEquals(resv1, tcp.getReserved());
+        assertEquals(flags1, tcp.getHeaderLenFlags());
+        assertEquals(wsize1, tcp.getWindowSize());
+        assertEquals(cksum1, tcp.getChecksum());
+        assertEquals(urg1, tcp.getUrgentPointer());
+    }
+
+    /**
+     * Test for serialization and deserialization.
+     *
+     * <ul>
+     *   <li>{@link Packet#serialize()}</li>
+     *   <li>{@link Packet#deserialize(byte[], int, int)}</li>
+     * </ul>
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testSerialization() throws Exception {
+        byte[] raw = {
+            // Source port.
+            (byte)0x41, (byte)0x9c,
+
+            // Destination port.
+            (byte)0x00, (byte)0x35,
+
+            // Sequence number.
+            (byte)0x41, (byte)0xdb, (byte)0x3a, (byte)0x91,
+
+            // Acknowledgement number.
+            (byte)0xb7, (byte)0x05, (byte)0xb1, (byte)0x9b,
+
+            // Data offset, reserved, header length, and flags.
+            (byte)0x9c, (byte)0xc1,
+
+            // Window size.
+            (byte)0x52, (byte)0xd2,
+
+            // Checksum.
+            (byte)0xd9, (byte)0x04,
+
+            // Urgent pointer.
+            (byte)0x68, (byte)0xde,
+        };
+
+        short src = (short)0x419c;
+        short dst = (short)0x0035;
+        int seq = (int)0x41db3a91;
+        int ack = (int)0xb705b19b;
+        byte off = 0x9;
+        byte resv = 6;
+        short flags = 193;
+        short wsize = (short)0x52d2;
+        short cksum = (short)0xd904;
+        short urg = (short)0x68de;
+
+        // Deserialize raw packet.
+        TCP tcp = new TCP();
+        tcp.deserialize(raw, 0, raw.length * Byte.SIZE);
+        assertEquals(src, tcp.getSourcePort());
+        assertEquals(dst, tcp.getDestinationPort());
+        assertEquals(seq, tcp.getSequenceNumber());
+        assertEquals(ack, tcp.getAckNumber());
+        assertEquals(off, tcp.getDataOffset());
+        assertEquals(resv, tcp.getReserved());
+        assertEquals(flags, tcp.getHeaderLenFlags());
+        assertEquals(wsize, tcp.getWindowSize());
+        assertEquals(cksum, tcp.getChecksum());
+        assertEquals(urg, tcp.getUrgentPointer());
+        assertEquals(null, tcp.getPayload());
+        assertEquals(null, tcp.getRawPayload());
+        assertEquals(false, tcp.isCorrupted());
+
+        // Serialize packet.
+        assertArrayEquals(raw, tcp.serialize());
+
+        // Deserialize packet with TCP payload.
+        raw = new byte[]{
+            // Source port.
+            (byte)0xb0, (byte)0xd9,
+
+            // Destination port.
+            (byte)0x2e, (byte)0x8c,
+
+            // Sequence number.
+            (byte)0xe6, (byte)0x0d, (byte)0x2a, (byte)0xdb,
+
+            // Acknowledgement number.
+            (byte)0x5f, (byte)0x9c, (byte)0x76, (byte)0xf6,
+
+            // Data offset, reserved, header length, and flags.
+            (byte)0xc5, (byte)0x37,
+
+            // Window size.
+            (byte)0x49, (byte)0x6c,
+
+            // Checksum.
+            (byte)0x36, (byte)0xad,
+
+            // Urgent pointer.
+            (byte)0xd7, (byte)0xbd,
+
+            // Payload.
+            (byte)0x7d, (byte)0xc9, (byte)0x39, (byte)0xf2,
+            (byte)0xf1, (byte)0x4f, (byte)0xc4, (byte)0x73,
+            (byte)0x66,
+        };
+
+        src = (short)0xb0d9;
+        dst = (short)0x2e8c;
+        seq = (int)0xe60d2adb;
+        ack = (int)0x5f9c76f6;
+        off = 0xc;
+        resv = 2;
+        flags = 311;
+        wsize = (short)0x496c;
+        cksum = (short)0x36ad;
+        urg = (short)0xd7bd;
+        byte[] payload = {
+            (byte)0x7d, (byte)0xc9, (byte)0x39, (byte)0xf2,
+            (byte)0xf1, (byte)0x4f, (byte)0xc4, (byte)0x73,
+            (byte)0x66,
+        };
+
+        tcp = new TCP();
+        tcp.deserialize(raw, 0, raw.length * Byte.SIZE);
+        assertEquals(src, tcp.getSourcePort());
+        assertEquals(dst, tcp.getDestinationPort());
+        assertEquals(seq, tcp.getSequenceNumber());
+        assertEquals(ack, tcp.getAckNumber());
+        assertEquals(off, tcp.getDataOffset());
+        assertEquals(resv, tcp.getReserved());
+        assertEquals(flags, tcp.getHeaderLenFlags());
+        assertEquals(wsize, tcp.getWindowSize());
+        assertEquals(cksum, tcp.getChecksum());
+        assertEquals(urg, tcp.getUrgentPointer());
+        assertEquals(null, tcp.getPayload());
+        assertArrayEquals(payload, tcp.getRawPayload());
+        assertEquals(false, tcp.isCorrupted());
+
+        // Serialize packet.
+        assertArrayEquals(raw, tcp.serialize());
+
+        // Serialize an empty packet.
+        tcp = new TCP();
+        byte[] expected = new byte[20];
+        assertArrayEquals(expected, tcp.serialize());
+    }
+}
diff --git a/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/UDPTest.java b/manager/api/src/test/java/org/opendaylight/vtn/manager/packet/UDPTest.java
new file mode 100644 (file)
index 0000000..e82f4df
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2015 NEC Corporation. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.vtn.manager.packet;
+
+import org.junit.Test;
+
+import org.opendaylight.vtn.manager.TestBase;
+
+/**
+ * JUnit test for {@link UDP}.
+ */
+public class UDPTest extends TestBase {
+    /**
+     * Test case for UDP source port.
+     *
+     * <ul>
+     *   <li>{@link UDP#getSourcePort()}</li>
+     *   <li>{@link UDP#setSourcePort(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetSourcePort() {
+        UDP udp = new UDP();
+        assertEquals((short)0, udp.getSourcePort());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short port: values) {
+            assertSame(udp, udp.setSourcePort(port));
+            assertEquals(port, udp.getSourcePort());
+        }
+    }
+
+    /**
+     * Test case for UDP destination port.
+     *
+     * <ul>
+     *   <li>{@link UDP#getDestinationPort()}</li>
+     *   <li>{@link UDP#setDestinationPort(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetDestinationPort() {
+        UDP udp = new UDP();
+        assertEquals((short)0, udp.getDestinationPort());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short port: values) {
+            assertSame(udp, udp.setDestinationPort(port));
+            assertEquals(port, udp.getDestinationPort());
+        }
+    }
+
+    /**
+     * Test case for UDP datagram length.
+     *
+     * <ul>
+     *   <li>{@link UDP#getLength()}</li>
+     *   <li>{@link UDP#setLength(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetLength() {
+        UDP udp = new UDP();
+        assertEquals((short)0, udp.getLength());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short len: values) {
+            assertSame(udp, udp.setLength(len));
+            assertEquals(len, udp.getLength());
+        }
+    }
+
+    /**
+     * Test case for UDP checksum.
+     *
+     * <ul>
+     *   <li>{@link UDP#getChecksum()}</li>
+     *   <li>{@link UDP#setChecksum(short)}</li>
+     * </ul>
+     */
+    @Test
+    public void testGetChecksum() {
+        UDP udp = new UDP();
+        assertEquals((short)0, udp.getLength());
+
+        short[] values = {1, 4, 99, 2054, 30000, 32767, -32768, -2, -1};
+        for (short cksum: values) {
+            assertSame(udp, udp.setChecksum(cksum));
+            assertEquals(cksum, udp.getChecksum());
+        }
+    }
+
+    /**
+     * Test case for {@link UDP#clone()}.
+     */
+    @Test
+    public void testClone() {
+        short src = 32144;
+        short dst = 53;
+        short len = 3128;
+        short cksum = -28714;
+        byte[] payload = {
+            (byte)0x4e, (byte)0x99, (byte)0xe2, (byte)0x52,
+            (byte)0xc3, (byte)0x4f, (byte)0x3e, (byte)0xac,
+        };
+
+        UDP udp = new UDP().
+            setSourcePort(src).
+            setDestinationPort(dst).
+            setLength(len).
+            setChecksum(cksum);
+        udp.setRawPayload(payload);
+
+        UDP copy = udp.clone();
+        assertNotSame(udp, copy);
+        assertEquals(udp, copy);
+        assertEquals(udp.hashCode(), copy.hashCode());
+        assertArrayEquals(payload, copy.getRawPayload());
+
+        // Modifying the source packet should never affect a deep copy.
+        short src1 = 4567;
+        short dst1 = 80;
+        short len1 = 7811;
+        short cksum1 = 31985;
+        udp.setSourcePort(src1).
+            setDestinationPort(dst1).
+            setLength(len1).
+            setChecksum(cksum1);
+        udp.setRawPayload(null);
+
+        assertEquals(src, copy.getSourcePort());
+        assertEquals(dst, copy.getDestinationPort());
+        assertEquals(len, copy.getLength());
+        assertEquals(cksum, copy.getChecksum());
+        assertArrayEquals(payload, copy.getRawPayload());
+
+        assertEquals(src1, udp.getSourcePort());
+        assertEquals(dst1, udp.getDestinationPort());
+        assertEquals(len1, udp.getLength());
+        assertEquals(cksum1, udp.getChecksum());
+        assertEquals(null, udp.getRawPayload());
+    }
+
+    /**
+     * Test for serialization and deserialization.
+     *
+     * <ul>
+     *   <li>{@link Packet#serialize()}</li>
+     *   <li>{@link Packet#deserialize(byte[], int, int)}</li>
+     * </ul>
+     *
+     * @throws Exception  An error occurred.
+     */
+    @Test
+    public void testSerialization() throws Exception {
+        byte[] raw = {
+            // Source port.
+            (byte)0x01, (byte)0x35,
+
+            // Destination port.
+            (byte)0x31, (byte)0x9d,
+
+            // Length
+            (byte)0x01, (byte)0x16,
+
+            // Checksum
+            (byte)0xd4, (byte)0x41,
+        };
+
+        short src = (short)0x0135;
+        short dst = (short)0x319d;
+        short len = (short)0x0116;
+        short cksum = (short)0xd441;
+
+        // Deserialize raw packet.
+        UDP udp = new UDP();
+        udp.deserialize(raw, 0, raw.length * Byte.SIZE);
+        assertEquals(src, udp.getSourcePort());
+        assertEquals(dst, udp.getDestinationPort());
+        assertEquals(len, udp.getLength());
+        assertEquals(cksum, udp.getChecksum());
+        assertEquals(null, udp.getPayload());
+        assertEquals(null, udp.getRawPayload());
+        assertEquals(false, udp.isCorrupted());
+
+        // Serialize packet.
+        assertArrayEquals(raw, udp.serialize());
+
+        // Deserialize packet with UDP payload.
+        raw = new byte[]{
+            // Source port.
+            (byte)0x74, (byte)0x1d,
+
+            // Destination port.
+            (byte)0x00, (byte)0x31,
+
+            // Length
+            (byte)0x12, (byte)0x34,
+
+            // Checksum
+            (byte)0x91, (byte)0xdf,
+
+            // Payload
+            (byte)0x26, (byte)0xa6, (byte)0xdf, (byte)0x80,
+            (byte)0x06, (byte)0xb5, (byte)0xd6, (byte)0xa0,
+            (byte)0x66, (byte)0xf2, (byte)0x38, (byte)0x6e,
+            (byte)0x36, (byte)0x19, (byte)0xa9,
+        };
+
+        src = (short)0x741d;
+        dst = (short)0x0031;
+        len = (short)0x1234;
+        cksum = (short)0x91df;
+        byte[] payload = {
+            (byte)0x26, (byte)0xa6, (byte)0xdf, (byte)0x80,
+            (byte)0x06, (byte)0xb5, (byte)0xd6, (byte)0xa0,
+            (byte)0x66, (byte)0xf2, (byte)0x38, (byte)0x6e,
+            (byte)0x36, (byte)0x19, (byte)0xa9,
+        };
+
+        // Deserialize raw packet.
+        udp = new UDP();
+        udp.deserialize(raw, 0, raw.length * Byte.SIZE);
+        assertEquals(src, udp.getSourcePort());
+        assertEquals(dst, udp.getDestinationPort());
+        assertEquals(len, udp.getLength());
+        assertEquals(cksum, udp.getChecksum());
+        assertEquals(null, udp.getPayload());
+        assertArrayEquals(payload, udp.getRawPayload());
+        assertEquals(false, udp.isCorrupted());
+
+        // Serialize packet.
+        assertArrayEquals(raw, udp.serialize());
+
+        // Serialize an empty packet.
+        udp = new UDP();
+        byte[] expected = new byte[8];
+        assertArrayEquals(expected, udp.serialize());
+    }
+}
index dbf2d12fc746a50cb04659cd5f989c76014041ff..c9faf2da1abefd18eb22940aadb3ca4c100fe812 100644 (file)
@@ -128,4 +128,359 @@ public class ByteUtilsTest extends TestBase {
             }
         }
     }
+
+    /**
+     * Test case for {@link ByteUtils#getBits(byte[], int, int)}.
+     */
+    @Test
+    public void testGetBits() {
+        byte[] data = {10, 12, 14, 20, 55, 69, 82, 97, 109, 117, 127, -50};
+        byte[] bits;
+
+        // Zero bits
+        bits = ByteUtils.getBits(data, 10, 0);
+        assertEquals(0, bits.length);
+
+        // In case of simple byte copy
+        bits = ByteUtils.getBits(data, 88, 8);
+        assertEquals((byte)-50, bits[0]);
+        assertEquals(1, bits.length);
+
+        bits = ByteUtils.getBits(data, 8, 16);
+        assertEquals((byte)12, bits[0]);
+        assertEquals((byte)14, bits[1]);
+        assertEquals(2, bits.length);
+
+        bits = ByteUtils.getBits(data, 32, 32);
+        assertEquals((byte)55, bits[0]);
+        assertEquals((byte)69, bits[1]);
+        assertEquals((byte)82, bits[2]);
+        assertEquals((byte)97, bits[3]);
+        assertEquals(4, bits.length);
+
+        bits = ByteUtils.getBits(data, 16, 48);
+        assertEquals((byte)14, bits[0]);
+        assertEquals((byte)20, bits[1]);
+        assertEquals((byte)55, bits[2]);
+        assertEquals((byte)69, bits[3]);
+        assertEquals((byte)82, bits[4]);
+        assertEquals((byte)97, bits[5]);
+        assertEquals(6, bits.length);
+
+        // Partial bits
+        bits = ByteUtils.getBits(data, 40, 7);
+        assertEquals((byte)34, bits[0]);
+        assertEquals(1, bits.length);
+
+        bits = ByteUtils.getBits(data, 8, 13);
+        assertEquals((byte)1, bits[0]);
+        assertEquals((byte)-127, bits[1]);
+        assertEquals(2, bits.length);
+
+        bits = ByteUtils.getBits(data, 32, 28);
+        assertEquals((byte)3, bits[0]);
+        assertEquals((byte)116, bits[1]);
+        assertEquals((byte)85, bits[2]);
+        assertEquals((byte)38, bits[3]);
+        assertEquals(4, bits.length);
+
+        bits = ByteUtils.getBits(data, 16, 41);
+        assertEquals((byte)0, bits[0]);
+        assertEquals((byte)28, bits[1]);
+        assertEquals((byte)40, bits[2]);
+        assertEquals((byte)110, bits[3]);
+        assertEquals((byte)-118, bits[4]);
+        assertEquals((byte)-92, bits[5]);
+        assertEquals(6, bits.length);
+
+        // Unaligned
+        bits = ByteUtils.getBits(data, 3, 8);
+        assertEquals((byte)80, bits[0]);
+        assertEquals(1, bits.length);
+
+        bits = ByteUtils.getBits(data, 13, 16);
+        assertEquals((byte)-127, bits[0]);
+        assertEquals((byte)-62, bits[1]);
+        assertEquals(2, bits.length);
+
+        bits = ByteUtils.getBits(data, 5, 32);
+        assertEquals((byte)65, bits[0]);
+        assertEquals((byte)-127, bits[1]);
+        assertEquals((byte)-62, bits[2]);
+        assertEquals((byte)-122, bits[3]);
+        assertEquals(4, bits.length);
+
+        bits = ByteUtils.getBits(data, 23, 48);
+        assertEquals((byte)10, bits[0]);
+        assertEquals((byte)27, bits[1]);
+        assertEquals((byte)-94, bits[2]);
+        assertEquals((byte)-87, bits[3]);
+        assertEquals((byte)48, bits[4]);
+        assertEquals((byte)-74, bits[5]);
+        assertEquals(6, bits.length);
+
+        // Unaligned and partial bits
+        bits = ByteUtils.getBits(data, 66, 9);
+        assertEquals((byte)1, bits[0]);
+        assertEquals((byte)107, bits[1]);
+        assertEquals(2, bits.length);
+
+        bits = ByteUtils.getBits(data, 13, 15);
+        assertEquals((byte)64, bits[0]);
+        assertEquals((byte)-31, bits[1]);
+        assertEquals(2, bits.length);
+
+        bits = ByteUtils.getBits(data, 5, 29);
+        assertEquals((byte)8, bits[0]);
+        assertEquals((byte)48, bits[1]);
+        assertEquals((byte)56, bits[2]);
+        assertEquals((byte)80, bits[3]);
+        assertEquals(4, bits.length);
+
+        bits = ByteUtils.getBits(data, 31, 43);
+        assertEquals((byte)0, bits[0]);
+        assertEquals((byte)-35, bits[1]);
+        assertEquals((byte)21, bits[2]);
+        assertEquals((byte)73, bits[3]);
+        assertEquals((byte)-123, bits[4]);
+        assertEquals((byte)-75, bits[5]);
+        assertEquals(6, bits.length);
+
+        bits = ByteUtils.getBits(data, 4, 12);
+        assertEquals((byte)10, bits[0]);
+        assertEquals((byte)12, bits[1]);
+        assertEquals(2, bits.length);
+
+        byte[] data1 = {0, 8};
+        bits = ByteUtils.getBits(data1, 7, 9);
+        assertEquals((byte)0, bits[0]);
+        assertEquals((byte)8, bits[1]);
+        assertEquals(2, bits.length);
+
+        byte[] data2 = {2, 8};
+        bits = ByteUtils.getBits(data2, 0, 7);
+        assertEquals((byte)1, bits[0]);
+        assertEquals(1, bits.length);
+
+        bits = ByteUtils.getBits(data2, 7, 9);
+        assertEquals((byte)0, bits[0]);
+        assertEquals((byte)8, bits[1]);
+        assertEquals(2, bits.length);
+    }
+
+    /**
+     * Test case for {@link ByteUtils#setBits(byte[], byte[], int, int)}.
+     */
+    @Test
+    public void testSetBits() {
+        byte[] data = {
+            74, 79, 14, -110, 55, -3, 82, 97,
+            -63, 117, 127, -50, 127, 95, -31, 3,
+        };
+        byte[] original = data.clone();
+        byte[] expected = data.clone();
+
+        // Zero bits
+        byte[] input = {};
+        ByteUtils.setBits(data, input, 3, 0);
+        assertArrayEquals(original, data);
+
+        // In case of simple byte copy
+        int index = 1;
+        input = new byte[]{31};
+        ByteUtils.setBits(data, input, index * 8, input.length * Byte.SIZE);
+        expected[index] = input[0];
+        assertArrayEquals(expected, data);
+
+        index = 3;
+        input = new byte[]{91, -116};
+        ByteUtils.setBits(data, input, index * 8, input.length * Byte.SIZE);
+        for (int i = 0; i < input.length; i++) {
+            expected[index + i] = input[i];
+        }
+        assertArrayEquals(expected, data);
+
+        index = 7;
+        input = new byte[]{1, 93, -89, 73};
+        ByteUtils.setBits(data, input, index * 8, input.length * Byte.SIZE);
+        for (int i = 0; i < input.length; i++) {
+            expected[index + i] = input[i];
+        }
+        assertArrayEquals(expected, data);
+
+        index = 8;
+        input = new byte[]{33, 81, 124, -47, 10, 43, 77, -93};
+        ByteUtils.setBits(data, input, index * 8, input.length * Byte.SIZE);
+        for (int i = 0; i < input.length; i++) {
+            expected[index + i] = input[i];
+        }
+        assertArrayEquals(expected, data);
+
+        // Partial bits
+        data = original.clone();
+        expected = original.clone();
+        input = new byte[]{45};
+        index = 15;
+        ByteUtils.setBits(data, input, index * 8, 6);
+        expected[index] = -73;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{54, 77};
+        index = 2;
+        ByteUtils.setBits(data, input, index * 8, 14);
+        expected[index] = -39;
+        expected[index + 1] = 54;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{1, -36, 25, -121};
+        index = 7;
+        ByteUtils.setBits(data, input, index * 8, 25);
+        expected[index] = -18;
+        expected[index + 1] = 12;
+        expected[index + 2] = -61;
+        expected[index + 3] = -1;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{5, 57, 28, -66, 118, -13, -100, -75};
+        index = 6;
+        ByteUtils.setBits(data, input, index * 8, 59);
+        expected[index] = -89;
+        expected[index + 1] = 35;
+        expected[index + 2] = -105;
+        expected[index + 3] = -50;
+        expected[index + 4] = -34;
+        expected[index + 5] = 115;
+        expected[index + 6] = -106;
+        expected[index + 7] = -65;
+        assertArrayEquals(expected, data);
+
+        // Unaligned
+        data = original.clone();
+        expected = original.clone();
+        input = new byte[]{-74};
+        index = 0;
+        int off = 3;
+        ByteUtils.setBits(data, input, index * 8 + off,
+                          input.length * Byte.SIZE);
+        expected[index] = 86;
+        expected[index + 1] = -49;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{106, -51};
+        index = 13;
+        off = 7;
+        ByteUtils.setBits(data, input, index * 8 + off,
+                          input.length * Byte.SIZE);
+        expected[index] = 94;
+        expected[index + 1] = -43;
+        expected[index + 2] = -101;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{-121, 18, 58, -111};
+        index = 3;
+        off = 1;
+        ByteUtils.setBits(data, input, index * 8 + off,
+                          input.length * Byte.SIZE);
+        expected[index] = -61;
+        expected[index + 1] = -119;
+        expected[index + 2] = 29;
+        expected[index + 3] = 72;
+        expected[index + 4] = -31;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{-77, 26, -104, 54, 51, 21, -20, -45};
+        index = 7;
+        off = 6;
+        ByteUtils.setBits(data, input, index * 8 + off,
+                          input.length * Byte.SIZE);
+        expected[index] = -30;
+        expected[index + 1] = -52;
+        expected[index + 2] = 106;
+        expected[index + 3] = 96;
+        expected[index + 4] = -40;
+        expected[index + 5] = -52;
+        expected[index + 6] = 87;
+        expected[index + 7] = -77;
+        expected[index + 8] = 79;
+        assertArrayEquals(expected, data);
+
+        // Unaligned and partial bits
+        data = original.clone();
+        expected = original.clone();
+        input = new byte[]{9};
+        index = 11;
+        off = 6;
+        ByteUtils.setBits(data, input, index * 8 + off, 5);
+        expected[index] = -51;
+        expected[index + 1] = 63;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{29, 109};
+        index = 8;
+        off = 1;
+        ByteUtils.setBits(data, input, index * 8 + off, 14);
+        expected[index] = -70;
+        expected[index + 1] = -37;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{26, 53, -56, 59};
+        index = 1;
+        off = 3;
+        ByteUtils.setBits(data, input, index * 8 + off, 29);
+        expected[index] = 90;
+        expected[index + 1] = 53;
+        expected[index + 2] = -56;
+        expected[index + 3] = 59;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{40, -37, 78, -95, 53, 23, -52, 35};
+        index = 7;
+        off = 7;
+        ByteUtils.setBits(data, input, index * 8 + off, 63);
+        expected[index] = 96;
+        expected[index + 1] = -93;
+        expected[index + 2] = 109;
+        expected[index + 3] = 58;
+        expected[index + 4] = -124;
+        expected[index + 5] = -44;
+        expected[index + 6] = 95;
+        expected[index + 7] = 48;
+        expected[index + 8] = -113;
+        assertArrayEquals(expected, data);
+
+        input = new byte[]{0, 1};
+        data = new byte[]{6, 0};
+        ByteUtils.setBits(data, input, 7, 9);
+        assertEquals((byte)6, data[0]);
+        assertEquals((byte)1, data[1]);
+
+        input = new byte[]{1};
+        ByteUtils.setBits(data, input, 0, 1);
+        assertEquals((byte)-122, data[0]);
+        assertEquals((byte)1, data[1]);
+
+        ByteUtils.setBits(data, input, 3, 1);
+        assertEquals((byte)-106, data[0]);
+        assertEquals((byte)1, data[1]);
+
+        input = new byte[]{0x3};
+        data = new byte[]{0, -88, 0, 0};
+        ByteUtils.setBits(data, input, 14, 2);
+        assertEquals((byte)0, data[0]);
+        assertEquals((byte)-85, data[1]);
+        assertEquals((byte)0, data[2]);
+        assertEquals((byte)0, data[3]);
+
+        input = new byte[1];
+        for (int nbits = 1; nbits <= 8; nbits++) {
+            int mask = (1 << nbits) - 1;
+            input[0] = (byte)mask;
+            for (int boff = 0; boff <= 32 - nbits; boff++) {
+                data = new byte[]{0, 0, 0, 0};
+                ByteUtils.setBits(data, input, boff, nbits);
+                int exmask = mask << (32 - nbits - boff);
+                assertEquals(exmask, NumberUtils.toInteger(data));
+            }
+        }
+    }
 }
index 429a83b548339dd879cb40e828d33285b7ebc7fa..785f4f699a72048eaee10d17d2d7973eac886636 100644 (file)
@@ -39,4 +39,25 @@ public class EtherTypesTest extends TestBase {
         assertEquals((short)0x88a8, EtherTypes.QINQ.shortValue());
         assertEquals((short)0x88cc, EtherTypes.LLDP.shortValue());
     }
+
+    /**
+     * Test case for {@link EtherTypes#forValue(short)}.
+     */
+    @Test
+    public void testForValue() {
+        short[] badTypes = {
+            (short)0x0000, (short)0x0011, (short)0x07ff, (short)0x0805,
+            (short)0x7fff, (short)0x8000, (short)0x8101, (short)0x8888,
+            (short)0x8999, (short)0x9999, (short)0xabcd, (short)0xcdef,
+            (short)0xcef0, (short)0xf000, (short)0xfff0, (short)0xffff,
+        };
+
+        for (short type: badTypes) {
+            assertEquals(null, EtherTypes.forValue(type));
+        }
+
+        for (EtherTypes etype: EtherTypes.values()) {
+            assertEquals(etype, EtherTypes.forValue(etype.shortValue()));
+        }
+    }
 }
index e341f160bcb3b9a2aa89d8f75f660b83cca7cb74..457d7b41de082dae801c17a1162e9a3f0a11a60d 100644 (file)
@@ -45,4 +45,24 @@ public class InetProtocolsTest extends TestBase {
         assertEquals((byte)6, InetProtocols.TCP.byteValue());
         assertEquals((byte)17, InetProtocols.UDP.byteValue());
     }
+
+    /**
+     * Test case for {@link InetProtocols#forValue(byte)}.
+     */
+    @Test
+    public void testForValue() {
+        for (int i = Byte.MIN_VALUE; i <= Byte.MAX_VALUE; i++) {
+            byte value = (byte)i;
+            InetProtocols proto = InetProtocols.forValue(value);
+            if (i == 1) {
+                assertEquals(InetProtocols.ICMP, proto);
+            } else if (i == 6) {
+                assertEquals(InetProtocols.TCP, proto);
+            } else if (i == 17) {
+                assertEquals(InetProtocols.UDP, proto);
+            } else {
+                assertEquals(null, proto);
+            }
+        }
+    }
 }
index e5a2c9ce28e1ee28bbd0b3a0120d7c35e8cc5b1a..b13ebd51e45830fa7b0623538050963feb00248e 100644 (file)
@@ -161,6 +161,60 @@ public class NumberUtilsTest extends TestBase {
         }
     }
 
+    /**
+     * Test case for {@link NumberUtils#toShort(byte[])} and
+     * {@link NumberUtils#toBytes(short)}.
+     */
+    @Test
+    public void testToShortBytes() {
+        try {
+            NumberUtils.toShort((byte[])null);
+            unexpected();
+        } catch (NullPointerException e) {
+        }
+
+        for (int i = 0; i <= 10; i++) {
+            if (i == 2) {
+                continue;
+            }
+
+            byte[] b = new byte[i];
+            try {
+                NumberUtils.toShort(b);
+                unexpected();
+            } catch (IllegalArgumentException e) {
+                assertEquals("Invalid byte array length: " + i,
+                             e.getMessage());
+            }
+        }
+
+        HashMap<byte[], Short> cases = new HashMap<>();
+        cases.put(new byte[]{0, 0}, (short)0);
+        cases.put(new byte[]{0, 1}, (short)1);
+        cases.put(new byte[]{0, 2}, (short)2);
+        cases.put(new byte[]{0, (byte)0xff}, (short)255);
+        cases.put(new byte[]{1, 0}, (short)256);
+        cases.put(new byte[]{(byte)0x10, (byte)0xff}, (short)4351);
+        cases.put(new byte[]{(byte)0x59, (byte)0x34}, (short)22836);
+        cases.put(new byte[]{(byte)0x7f, (byte)0xfe}, (short)32766);
+        cases.put(new byte[]{(byte)0x7f, (byte)0xff}, (short)32767);
+        cases.put(new byte[]{(byte)0x80, (byte)0x00}, (short)-32768);
+        cases.put(new byte[]{(byte)0x80, (byte)0x01}, (short)-32767);
+        cases.put(new byte[]{(byte)0x9a, (byte)0x1b}, (short)-26085);
+        cases.put(new byte[]{(byte)0xde, (byte)0xad}, (short)-8531);
+        cases.put(new byte[]{(byte)0xff, (byte)0xfc}, (short)-4);
+        cases.put(new byte[]{(byte)0xff, (byte)0xfd}, (short)-3);
+        cases.put(new byte[]{(byte)0xff, (byte)0xfe}, (short)-2);
+        cases.put(new byte[]{(byte)0xff, (byte)0xff}, (short)-1);
+
+        for (Map.Entry<byte[], Short> entry: cases.entrySet()) {
+            byte[] b = entry.getKey();
+            short v = entry.getValue();
+            assertEquals(v, NumberUtils.toShort(b));
+            assertArrayEquals(b, NumberUtils.toBytes(v));
+        }
+    }
+
     /**
      * Test case for {@link NumberUtils#getUnsigned(byte)}.
      */
index 9965a1248a48c6cc31479a6038557fdcac1aa4b2..1b65815fa7b4b2905649eea631ecd43a060f951e 100644 (file)
@@ -23,6 +23,14 @@ import org.slf4j.LoggerFactory;
 import org.opendaylight.vtn.manager.VNodePath;
 import org.opendaylight.vtn.manager.VNodeRoute;
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.ARP;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.ICMP;
+import org.opendaylight.vtn.manager.packet.IEEE8021Q;
+import org.opendaylight.vtn.manager.packet.IPv4;
+import org.opendaylight.vtn.manager.packet.Packet;
+import org.opendaylight.vtn.manager.packet.TCP;
+import org.opendaylight.vtn.manager.packet.UDP;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.EtherTypes;
 import org.opendaylight.vtn.manager.util.Ip4Network;
@@ -57,15 +65,6 @@ import org.opendaylight.vtn.manager.internal.util.packet.Layer4Header;
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
 import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.packet.ARP;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.IPv4;
-import org.opendaylight.controller.sal.packet.Packet;
-import org.opendaylight.controller.sal.packet.RawPacket;
-import org.opendaylight.controller.sal.packet.TCP;
-import org.opendaylight.controller.sal.packet.UDP;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.rev150410.VirtualRouteReason;
 
@@ -89,9 +88,9 @@ public class PacketContext implements Cloneable, FlowMatchContext {
     private static final int  ETHER_TYPE_MASK = 0xffff;
 
     /**
-     * A received raw packet.
+     * A {@link SalPort} instance which specifies the ingress switch port.
      */
-    private final RawPacket  rawPacket;
+    private final SalPort  ingressPort;
 
     /**
      * PACKET_IN event.
@@ -218,7 +217,7 @@ public class PacketContext implements Cloneable, FlowMatchContext {
      * @param ev  A {@link PacketInEvent} instance.
      */
     PacketContext(PacketInEvent ev) {
-        rawPacket = ev.getPayload();
+        ingressPort = ev.getIngressPort();
         etherFrame = new EtherPacket(ev.getEthernet());
         txContext = ev.getTxContext();
         packetIn = ev;
@@ -237,7 +236,7 @@ public class PacketContext implements Cloneable, FlowMatchContext {
      * @param ctx    A MD-SAL datastore transaction only for read.
      */
     PacketContext(Ethernet ether, SalPort out, TxContext ctx) {
-        rawPacket = null;
+        ingressPort = null;
         etherFrame = new EtherPacket(ether);
         txContext = ctx;
         egressPort = out;
@@ -335,11 +334,11 @@ public class PacketContext implements Cloneable, FlowMatchContext {
      *          the packet was received from.
      */
     public PortVlan getIncomingNetwork() {
-        if (rawPacket == null) {
+        if (ingressPort == null) {
             return null;
         }
 
-        NodeConnector nc = rawPacket.getIncomingNodeConnector();
+        NodeConnector nc = ingressPort.getAdNodeConnector();
         return new PortVlan(nc, (short)etherFrame.getOriginalVlan());
     }
 
index 44983f0f3b083bfa4166f035e2bbfebfbfe690a1..148cdd1eaeca0b26af69d45980980bbcff72dc12 100644 (file)
@@ -71,6 +71,7 @@ import org.opendaylight.vtn.manager.flow.cond.FlowCondition;
 import org.opendaylight.vtn.manager.flow.cond.FlowMatch;
 import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
 import org.opendaylight.vtn.manager.flow.filter.FlowFilterId;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 import org.opendaylight.vtn.manager.util.VTNIdentifiableComparator;
@@ -137,7 +138,6 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector.NodeConnectorIDType;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.UpdateType;
-import org.opendaylight.controller.sal.packet.Ethernet;
 import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.utils.Status;
index 2169c9d25f214648c73eb8c039572a3e601a7054..6d72614f699cb50f2f39729f2095e5ff52638a06 100644 (file)
@@ -15,6 +15,7 @@ import java.util.concurrent.Future;
 import com.google.common.util.concurrent.FutureCallback;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Packet;
 
 import org.opendaylight.vtn.manager.internal.util.concurrent.VTNFuture;
 import org.opendaylight.vtn.manager.internal.util.flow.VTNFlowBuilder;
@@ -22,8 +23,6 @@ import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 
-import org.opendaylight.controller.sal.packet.Packet;
-
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 
index 12dfd44c85394a1b8d06c27b21220497dbd14be8..23fbb70b5f14854994e0c31d70546bed51376c47 100644 (file)
@@ -29,6 +29,7 @@ import org.opendaylight.vtn.manager.VBridgePath;
 import org.opendaylight.vtn.manager.VNodeRoute;
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.util.EtherAddress;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 
 import org.opendaylight.vtn.manager.internal.IVTNResourceManager;
 import org.opendaylight.vtn.manager.internal.MacAddressTable;
@@ -52,7 +53,6 @@ import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
 import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.packet.Ethernet;
 import org.opendaylight.controller.sal.packet.address.DataLinkAddress;
 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
 
index be1076b6dcd05922e3000d29f47e89dbaad77678..79f0d21228aec15a6d50ac22c6bed41e40886ef8 100644 (file)
@@ -20,6 +20,7 @@ import org.opendaylight.vtn.manager.VInterfacePath;
 import org.opendaylight.vtn.manager.VNodePath;
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.VTenantPath;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 
 import org.opendaylight.vtn.manager.internal.LockStack;
 import org.opendaylight.vtn.manager.internal.PacketContext;
@@ -36,7 +37,6 @@ import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.packet.Ethernet;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeState;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
index dee60a5b18f274b31dcd3678218fd67270b5bbf4..176d63e7f2f1d3757bc72d02ab1ed81fbe818f07 100644 (file)
@@ -24,6 +24,7 @@ import org.opendaylight.vtn.manager.VNodePath;
 import org.opendaylight.vtn.manager.VNodeRoute;
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.VTenantPath;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 
 import org.opendaylight.vtn.manager.internal.IVTNResourceManager;
@@ -49,7 +50,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.VTNFlowBuilder;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.UpdateType;
-import org.opendaylight.controller.sal.packet.Ethernet;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.rev150410.VirtualRouteReason;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
index 720e962b741e96186539a36b603b0c6cc576df0b..ff645c24203ba02ad31e6549ee8567962bdd095d 100644 (file)
@@ -21,6 +21,7 @@ import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.VTenantPath;
 import org.opendaylight.vtn.manager.VlanMap;
 import org.opendaylight.vtn.manager.VlanMapConfig;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 
 import org.opendaylight.vtn.manager.internal.IVTNResourceManager;
 import org.opendaylight.vtn.manager.internal.PacketContext;
@@ -40,7 +41,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev15020
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.packet.Ethernet;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.rev150410.VirtualRouteReason;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeState;
index fb5cbee36c0bfaa1f65e04f3601b9f5c1cdb0077..cf9c5aec54d4f4bd06bfd01c3a54009061d40e3e 100644 (file)
@@ -9,14 +9,13 @@
 package org.opendaylight.vtn.manager.internal.packet;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.PacketException;
 
 import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
 import org.opendaylight.vtn.manager.internal.util.tx.TxEvent;
 
 import org.opendaylight.controller.sal.core.ConstructionException;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.PacketException;
-import org.opendaylight.controller.sal.packet.RawPacket;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
 
@@ -35,11 +34,6 @@ public final class PacketInEvent extends TxEvent {
      */
     private final SalPort  ingressPort;
 
-    /**
-     * A {@link RawPacket} instance which represents the received packet.
-     */
-    private final RawPacket  payload;
-
     /**
      * Decoded ethernet frame.
      */
@@ -66,8 +60,6 @@ public final class PacketInEvent extends TxEvent {
         ingressPort = ingress;
 
         byte[] bytes = rcv.getPayload();
-        payload = new RawPacket(bytes);
-        payload.setIncomingNodeConnector(ingressPort.getAdNodeConnector());
         ethernet = new Ethernet();
         ethernet.deserialize(bytes, 0, bytes.length * Byte.SIZE);
     }
@@ -81,7 +73,6 @@ public final class PacketInEvent extends TxEvent {
     public PacketInEvent(VTNPacketListener l, PacketInEvent ev) {
         listener = l;
         ingressPort = ev.ingressPort;
-        payload = ev.payload;
         ethernet = ev.ethernet;
     }
 
@@ -95,16 +86,6 @@ public final class PacketInEvent extends TxEvent {
         return ingressPort;
     }
 
-    /**
-     * Return a {@link RawPacket} instance which represents the received
-     * packet.
-     *
-     * @return  A {@link RawPacket} instance.
-     */
-    public RawPacket getPayload() {
-        return payload;
-    }
-
     /**
      * Return a {@link Ethernet} instance which represents the received
      * packet.
index 1b4192fa538c892afed81b57e13be855f091f6ab..f989c84421d7f19b14d845e44655fe782cba456e 100644 (file)
@@ -22,6 +22,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherTypes;
 
 import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
@@ -45,8 +46,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.Pa
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
 
-import org.opendaylight.controller.sal.packet.Packet;
-
 /**
  * Provider of internal packet services.
  */
index b894da486a8d9ba4726d8dcf196e33a7d1117943..2968f63a91a415d1782bef6b68d4d7f0c80506d1 100644 (file)
@@ -9,11 +9,10 @@
 package org.opendaylight.vtn.manager.internal.packet.cache;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Packet;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
 
-import org.opendaylight.controller.sal.packet.Packet;
-
 /**
  * {@code CachedPacket} defines interfaces that implements cache for a
  * {@link Packet} instance.
index a0315da8edc8d6afa2c056246a9074f32601d9a8..70748f5ec9316e784bb60edc5bf89d20e8b1ed4a 100644 (file)
@@ -10,6 +10,9 @@ package org.opendaylight.vtn.manager.internal.packet.cache;
 
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IEEE8021Q;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
@@ -22,10 +25,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNEtherMatch;
 import org.opendaylight.vtn.manager.internal.util.packet.EtherHeader;
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.Packet;
-
 /**
  * {@code EtherPacket} class implements a cache for a {@link Ethernet}
  * instance including VLAN tag.
index c1172c70b11f9e714f70939b9d46dbce45d68d5c..d85332186c25255b9fb02cb61273d4926aae4fe9 100644 (file)
@@ -12,10 +12,10 @@ import java.util.Set;
 
 import org.opendaylight.vtn.manager.VTNException;
 
+import org.opendaylight.vtn.manager.packet.ICMP;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
-import org.opendaylight.vtn.manager.internal.util.MiscUtils;
 import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetIcmpCodeAction;
 import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetIcmpTypeAction;
 import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType;
@@ -23,8 +23,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNIcmpMatch;
 import org.opendaylight.vtn.manager.internal.util.packet.IcmpHeader;
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
-import org.opendaylight.controller.sal.packet.ICMP;
-
 /**
  * {@code IcmpPacket} class implements a cache for an {@link ICMP} instance.
  */
@@ -208,13 +206,11 @@ public final class IcmpPacket implements L4Packet, IcmpHeader {
      * Return an {@link ICMP} instance to set modified values.
      *
      * @return  An {@link ICMP} instance.
-     * @throws VTNException
-     *    Failed to copy the packet.
      */
-    private ICMP getPacketForWrite() throws VTNException {
+    private ICMP getPacketForWrite() {
         if (cloned) {
             // Create a copy of the original packet.
-            packet = MiscUtils.copy(packet, new ICMP());
+            packet = packet.clone();
             cloned = false;
         }
 
index 497e41312911b9a09c77d50a8daf2dda48ddf6d7..ed3c28fb5b146c3b7f95870c8d324ed8ed3fc583 100644 (file)
@@ -8,16 +8,15 @@
 
 package org.opendaylight.vtn.manager.internal.packet.cache;
 
-import java.net.InetAddress;
 import java.util.Set;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.IPv4;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 import org.opendaylight.vtn.manager.util.IpNetwork;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
-import org.opendaylight.vtn.manager.internal.util.MiscUtils;
 import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetInetDscpAction;
 import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetInetDstAction;
 import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetInetSrcAction;
@@ -26,8 +25,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNInet4Match;
 import org.opendaylight.vtn.manager.internal.util.packet.InetHeader;
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
-import org.opendaylight.controller.sal.packet.IPv4;
-
 /**
  * {@code Inet4Packet} class implements a cache for an {@link IPv4} instance.
  */
@@ -196,11 +193,10 @@ public final class Inet4Packet implements CachedPacket, InetHeader {
          */
         private void fill(IPv4 ipv4) {
             if (sourceAddress == null) {
-                sourceAddress = new Ip4Network(ipv4.getSourceAddress());
+                sourceAddress = ipv4.getSourceAddress();
             }
             if (destinationAddress == null) {
-                destinationAddress =
-                    new Ip4Network(ipv4.getDestinationAddress());
+                destinationAddress = ipv4.getDestinationAddress();
             }
             if (dscp == DSCP_NONE) {
                 dscp = ipv4.getDiffServ();
@@ -337,13 +333,11 @@ public final class Inet4Packet implements CachedPacket, InetHeader {
      * Return an {@link IPv4} instance to set modified values.
      *
      * @return  An {@link IPv4} instance.
-     * @throws VTNException
-     *    Failed to copy the packet.
      */
-    private IPv4 getPacketForWrite() throws VTNException {
+    private IPv4 getPacketForWrite() {
         if (cloned) {
             // Create a copy of the original packet.
-            packet = MiscUtils.copy(packet, new IPv4());
+            packet = packet.clone();
             cloned = false;
         }
 
@@ -383,9 +377,8 @@ public final class Inet4Packet implements CachedPacket, InetHeader {
             Ip4Network newIp = modifiedValues.getSourceAddress();
             if (oldIp.getAddress() != newIp.getAddress()) {
                 // Source address was modified.
-                InetAddress iaddr = newIp.getInetAddress();
                 ipv4 = getPacketForWrite();
-                ipv4.setSourceAddress(iaddr);
+                ipv4.setSourceAddress(newIp);
                 mod = true;
             } else if (pctx.hasMatchField(FlowMatchType.IP_SRC)) {
                 // Source IP address in the original packet is unchanged and
@@ -398,11 +391,10 @@ public final class Inet4Packet implements CachedPacket, InetHeader {
             newIp = modifiedValues.getDestinationAddress();
             if (oldIp.getAddress() != newIp.getAddress()) {
                 // Destination address was modified.
-                InetAddress iaddr = newIp.getInetAddress();
                 if (ipv4 == null) {
                     ipv4 = getPacketForWrite();
                 }
-                ipv4.setDestinationAddress(iaddr);
+                ipv4.setDestinationAddress(newIp);
                 mod = true;
             } else if (pctx.hasMatchField(FlowMatchType.IP_DST)) {
                 // Destination IP address in the original packet is unchanged
@@ -463,7 +455,7 @@ public final class Inet4Packet implements CachedPacket, InetHeader {
         Values v = getValues();
         Ip4Network ipn = v.getSourceAddress();
         if (ipn == null) {
-            ipn = new Ip4Network(packet.getSourceAddress());
+            ipn = packet.getSourceAddress();
             v.setSourceAddress(ipn);
         }
 
@@ -496,7 +488,7 @@ public final class Inet4Packet implements CachedPacket, InetHeader {
         Values v = getValues();
         Ip4Network ipn = v.getDestinationAddress();
         if (ipn == null) {
-            ipn = new Ip4Network(packet.getDestinationAddress());
+            ipn = packet.getDestinationAddress();
             v.setDestinationAddress(ipn);
         }
 
index 4515ce6ec52ba3241ae521c39065529b7aba20ce..5a1c0535e3273378fccf344717e12bc9bd6101da 100644 (file)
@@ -39,15 +39,14 @@ public interface L4Packet extends CachedPacket, Layer4Header {
 
     /**
      * Calculate the checksum of the packet, and set the computed checksum
-     * into a {@link org.opendaylight.controller.sal.packet.Packet} instance
+     * into a {@link org.opendaylight.vtn.manager.packet.Packet} instance
      * configured in this instance.
      *
      * @param ipv4  An {@link Inet4Packet} instance that contains this
      *              packet.
      * @return  {@code true} is returned if the checksum field was updated.
      *          {@code false} is returned if the packet was not modified.
-     * @throws VTNException
-     *    An error occurred.
+     * @throws VTNException  An error occurred.
      */
     boolean updateChecksum(Inet4Packet ipv4) throws VTNException;
 
index 9d34bd45c845d3c1648fb791508625da0e2cc9b2..97ff379f3771e38f5134ffe1c783b3a93b1b18fc 100644 (file)
@@ -8,9 +8,14 @@
 
 package org.opendaylight.vtn.manager.internal.packet.cache;
 
+import static org.opendaylight.vtn.manager.packet.IPv4.CKSUM_BYTES;
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_BYTE;
+import static org.opendaylight.vtn.manager.util.NumberUtils.MASK_SHORT;
+
 import java.util.Set;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
@@ -22,8 +27,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNPortRange;
 import org.opendaylight.vtn.manager.internal.util.packet.Layer4PortHeader;
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
-import org.opendaylight.controller.sal.packet.Packet;
-
 /**
  * {@code PortProtoPacket} class implements a cache for layer 4 protocol
  * header, which identifies the service using 16-bit port number.
@@ -42,11 +45,6 @@ public abstract class PortProtoPacket<T extends Packet>
      */
     private static final int  CKSUM_OK = 0xffff;
 
-    /**
-     * The number of octets in TCP/UDP checksum.
-     */
-    private static final int  CKSUM_BYTES = Short.SIZE / Byte.SIZE;
-
     /**
      * A mask value used to clear LSB.
      */
@@ -199,25 +197,25 @@ public abstract class PortProtoPacket<T extends Packet>
         byte[] header = ipv4.getHeaderForChecksum(proto, (short)data.length);
         int sum = 0;
         for (int i = 0; i < header.length; i += CKSUM_BYTES) {
-            int v = ((header[i] & NumberUtils.MASK_BYTE) << Byte.SIZE) |
-                (header[i + 1] & NumberUtils.MASK_BYTE);
+            int v = ((header[i] & MASK_BYTE) << Byte.SIZE) |
+                (header[i + 1] & MASK_BYTE);
             sum += v;
         }
 
         int rsize = (data.length & MASK_CLEAR_LSB);
         for (int i = 0; i < rsize; i += CKSUM_BYTES) {
-            int v = ((data[i] & NumberUtils.MASK_BYTE) << Byte.SIZE) |
-                (data[i + 1] & NumberUtils.MASK_BYTE);
+            int v = ((data[i] & MASK_BYTE) << Byte.SIZE) |
+                (data[i + 1] & MASK_BYTE);
             sum += v;
         }
         if (rsize < data.length) {
             // Zero padding is needed.
-            int v = (data[rsize] & NumberUtils.MASK_BYTE) << Byte.SIZE;
+            int v = (data[rsize] & MASK_BYTE) << Byte.SIZE;
             sum += v;
         }
 
         int carry = (sum >>> Short.SIZE);
-        return (sum & NumberUtils.MASK_SHORT) + carry;
+        return (sum & MASK_SHORT) + carry;
     }
 
     /**
@@ -287,10 +285,8 @@ public abstract class PortProtoPacket<T extends Packet>
      * Return a {@link Packet} instance to set modified values.
      *
      * @return  A {@link Packet} instance.
-     * @throws VTNException
-     *    Failed to copy the packet.
      */
-    protected final T getPacketForWrite() throws VTNException {
+    protected final T getPacketForWrite() {
         T pkt = getPacketForWrite(cloned);
         cloned = false;
         return pkt;
@@ -333,10 +329,8 @@ public abstract class PortProtoPacket<T extends Packet>
      * @param doCopy {@code true} is passed if the packet configured in this
      *               instance needs to be copied.
      * @return  A {@link Packet} instance.
-     * @throws VTNException
-     *    Failed to copy the packet.
      */
-    protected abstract T getPacketForWrite(boolean doCopy) throws VTNException;
+    protected abstract T getPacketForWrite(boolean doCopy);
 
     /**
      * Return the name of the protocol.
index d13fa982392dba69a03e40b9ad7bf9e953d8d221..d85ddc8e3c720b80d5db37a59f6fbe79bece4ec7 100644 (file)
@@ -9,15 +9,13 @@
 package org.opendaylight.vtn.manager.internal.packet.cache;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.TCP;
 
-import org.opendaylight.vtn.manager.internal.util.MiscUtils;
 import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType;
 import org.opendaylight.vtn.manager.internal.util.flow.match.VTNPortRange;
 import org.opendaylight.vtn.manager.internal.util.flow.match.VTNTcpMatch;
 import org.opendaylight.vtn.manager.internal.util.packet.TcpHeader;
 
-import org.opendaylight.controller.sal.packet.TCP;
-
 /**
  * {@code TcpPacket} class implements a cache for a {@link TCP} instance.
  */
@@ -93,14 +91,12 @@ public final class TcpPacket extends PortProtoPacket<TCP>
      * @param doCopy {@code true} is passed if the packet configured in this
      *               instance needs to be copied.
      * @return  A {@link TCP} instance.
-     * @throws VTNException
-     *    Failed to copy the packet.
      */
     @Override
-    protected TCP getPacketForWrite(boolean doCopy) throws VTNException {
+    protected TCP getPacketForWrite(boolean doCopy) {
         TCP pkt;
         if (doCopy) {
-            pkt = MiscUtils.copy(packet, new TCP());
+            pkt = packet.clone();
             packet = pkt;
         } else {
             pkt = packet;
index 8454a2b9126d4c821b0070c81a38c5ccd8539528..47fa6ce7ebe7260094bed803768b6a9f4a2e1780 100644 (file)
@@ -9,15 +9,13 @@
 package org.opendaylight.vtn.manager.internal.packet.cache;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.UDP;
 
-import org.opendaylight.vtn.manager.internal.util.MiscUtils;
 import org.opendaylight.vtn.manager.internal.util.flow.match.FlowMatchType;
 import org.opendaylight.vtn.manager.internal.util.flow.match.VTNPortRange;
 import org.opendaylight.vtn.manager.internal.util.flow.match.VTNUdpMatch;
 import org.opendaylight.vtn.manager.internal.util.packet.UdpHeader;
 
-import org.opendaylight.controller.sal.packet.UDP;
-
 /**
  * {@code UdpPacket} class implements a cache for a {@link UDP} instance.
  */
@@ -96,14 +94,12 @@ public final class UdpPacket extends PortProtoPacket<UDP>
      * @param doCopy {@code true} is passed if the packet configured in this
      *               instance needs to be copied.
      * @return  A {@link UDP} instance.
-     * @throws VTNException
-     *    Failed to copy the packet.
      */
     @Override
-    protected UDP getPacketForWrite(boolean doCopy) throws VTNException {
+    protected UDP getPacketForWrite(boolean doCopy) {
         UDP pkt;
         if (doCopy) {
-            pkt = MiscUtils.copy(packet, new UDP());
+            pkt = packet.clone();
             packet = pkt;
         } else {
             pkt = packet;
index 702715d3c9310f6e86954249e6a44c438f52f037..1d8229dba2f6f24a983c1b87256831376d4626eb 100644 (file)
@@ -26,6 +26,7 @@ import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.Version;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Packet;
 
 import org.opendaylight.vtn.manager.internal.FlowRemover;
 import org.opendaylight.vtn.manager.internal.RouteResolver;
@@ -61,8 +62,6 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 
-import org.opendaylight.controller.sal.packet.Packet;
-
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.binding.RpcService;
 import org.opendaylight.yangtools.yang.common.RpcResult;
index ad0ff6f5c0daeafb7511605b25168d5e37038783..9321a9d2866a34467219127da8a60b867388097b 100644 (file)
@@ -24,14 +24,12 @@ import java.util.Set;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
 import org.opendaylight.controller.sal.core.UpdateType;
-import org.opendaylight.controller.sal.packet.Packet;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
@@ -182,28 +180,6 @@ public final class MiscUtils {
         throw new IllegalStateException(builder.toString());
     }
 
-    /**
-     * Copy the contents of the given packet.
-     *
-     * @param src  The source {@link Packet} instance.
-     * @param dst  The destination {@link Packet} instance.
-     * @param <T>  Type of packet.
-     * @return  {@code dst}.
-     * @throws VTNException
-     *    Failed to copy the packet.
-     */
-    public static <T extends Packet> T copy(T src, T dst) throws VTNException {
-        try {
-            byte[] raw = src.serialize();
-            int nbits = raw.length * Byte.SIZE;
-            dst.deserialize(raw, 0, nbits);
-            return dst;
-        } catch (Exception e) {
-            // This should never happen.
-            throw new VTNException("Failed to copy the packet.", e);
-        }
-    }
-
     /**
      * Ensure that the given value is not null.
      *
index 9c09c8191250e4566b53512eb4baf22a122f5a08..f8ef3137a6fdc71a5ce1761ed8559d492852aa40 100644 (file)
@@ -11,15 +11,14 @@ package org.opendaylight.vtn.manager.internal.util.packet;
 import java.net.Inet4Address;
 import java.net.InetAddress;
 
+import org.opendaylight.vtn.manager.packet.ARP;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IEEE8021Q;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.EtherTypes;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 
-import org.opendaylight.controller.sal.packet.ARP;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.Packet;
-
 /**
  * {@code ArpPacketBuilder} is a utility to build an ARP packet.
  */
index 2da0ae5a7811155b307950ce3b07a168aee6e3cf..c52bb63e51e66b4c95f9795d5d9db04f000b74dc 100644 (file)
@@ -59,8 +59,14 @@ import org.opendaylight.vtn.manager.flow.action.FlowAction;
 import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
 import org.opendaylight.vtn.manager.flow.filter.FlowFilter;
 import org.opendaylight.vtn.manager.flow.filter.PassFilter;
+import org.opendaylight.vtn.manager.packet.ARP;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IEEE8021Q;
+import org.opendaylight.vtn.manager.packet.IPv4;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.EtherTypes;
+import org.opendaylight.vtn.manager.util.Ip4Network;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
 import org.opendaylight.vtn.manager.internal.cluster.MacMapPath;
@@ -79,12 +85,6 @@ import org.opendaylight.controller.sal.core.Edge;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.match.MatchType;
-import org.opendaylight.controller.sal.packet.ARP;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.IPv4;
-import org.opendaylight.controller.sal.packet.Packet;
-import org.opendaylight.controller.sal.packet.RawPacket;
 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
 import org.opendaylight.controller.sal.utils.GlobalConstants;
 import org.opendaylight.controller.sal.core.UpdateType;
@@ -1120,6 +1120,21 @@ public abstract class TestBase extends Assert {
      */
     protected static IPv4 createIPv4(InetAddress src, InetAddress dst,
                                      short proto, byte dscp) {
+        return createIPv4(new Ip4Network(src), new Ip4Network(dst),
+                          proto, dscp);
+    }
+
+    /**
+     * Create an {@link IPv4} instance.
+     *
+     * @param src    Source IP address.
+     * @param dst    Destination IP address.
+     * @param proto  IP protocol number.
+     * @param dscp   DSCP field value.
+     * @return  An {@link IPv4} instance.
+     */
+    protected static IPv4 createIPv4(Ip4Network src, Ip4Network dst,
+                                     short proto, byte dscp) {
         IPv4 pkt = new IPv4();
         return pkt.setSourceAddress(src).setDestinationAddress(dst).
             setProtocol((byte)proto).setDiffServ(dscp).
@@ -1195,24 +1210,6 @@ public abstract class TestBase extends Assert {
         return createIPv4(src, dst, proto, (byte)0, payload);
     }
 
-    /**
-     * create a {@link RawPacket} object.
-     *
-     * @param eth   A {@link Ethernet} object.
-     * @param nc    A incoming node connector.
-     * @return A {@link RawPacket} object.
-     */
-    protected RawPacket createRawPacket(Ethernet eth, NodeConnector nc) {
-        RawPacket raw = null;
-        try {
-            raw = new RawPacket(eth.serialize());
-        } catch (Exception e) {
-            unexpected(e);
-        }
-        raw.setIncomingNodeConnector(copy(nc));
-
-        return raw;
-    }
 
     /**
      * create a {@link Ethernet} object of IPv4 Packet.
@@ -1237,8 +1234,8 @@ public abstract class TestBase extends Assert {
             setFragmentOffset((short)0).
             setTtl((byte)64);
 
-        ip.setDestinationAddress(createInetAddress(target));
-        ip.setSourceAddress(createInetAddress(sender));
+        ip.setDestinationAddress(new Ip4Network(target));
+        ip.setSourceAddress(new Ip4Network(sender));
 
         Ethernet eth = new Ethernet();
         eth.setSourceMACAddress(src).setDestinationMACAddress(dst);
@@ -1248,7 +1245,7 @@ public abstract class TestBase extends Assert {
 
             IEEE8021Q vlantag = new IEEE8021Q();
             vlantag.setCfi((byte)0x0).setPcp((byte)0x0).setVid((short)vlan).
-                setEtherType(EtherTypes.IPV4.shortValue()).setParent(eth);
+                setEtherType(EtherTypes.IPV4.shortValue());
             eth.setPayload(vlantag);
 
             vlantag.setPayload(ip);
@@ -1288,8 +1285,8 @@ public abstract class TestBase extends Assert {
             eth.setEtherType(EtherTypes.VLAN.shortValue());
 
             IEEE8021Q vlantag = new IEEE8021Q();
-            vlantag.setCfi((byte)0x0).setPcp((byte)0x0).setVid(vlan)
-                    .setEtherType(EtherTypes.ARP.shortValue()).setParent(eth);
+            vlantag.setCfi((byte)0x0).setPcp((byte)0x0).setVid(vlan).
+                setEtherType(EtherTypes.ARP.shortValue());
             eth.setPayload(vlantag);
 
             vlantag.setPayload(arp);
@@ -1336,42 +1333,6 @@ public abstract class TestBase extends Assert {
                 createIPv4Packet(src, dst, sender, target, vlan), nc);
     }
 
-    /**
-     * create a {@link RawPacket} object of ARP Request.
-     *
-     * @param src       A source MAC address
-     * @param dst       A destination MAC address
-     * @param sender    A sender address
-     * @param target    A target address
-     * @param vlan      specify val ID. if vlan < 0, vlan tag is not added.
-     * @param nc        A node connector
-     * @param arptype   ARP.REQUEST or ARP.REPLY. (ARP Reply is not implemented yet )
-     * @return  A {@link PacketContext} object.
-     */
-    protected RawPacket createARPRawPacket(byte[] src, byte[] dst,
-            byte[] sender, byte[] target, short vlan, NodeConnector nc,
-            short arptype) {
-        return createRawPacket(
-                createARPPacket(src, dst, sender, target, vlan, arptype), nc);
-    }
-
-    /**
-     * create a {@link RawPacket} object of IPv4 packet.
-     *
-     * @param src       A source MAC address
-     * @param dst       A destination MAC address
-     * @param sender    A sender address
-     * @param target    A target address
-     * @param vlan      specify vlan ID. if vlan < 0, vlan tag is not added.
-     * @param nc        A node connector
-     * @return  A {@link PacketContext} object.
-     */
-    protected RawPacket createIPv4RawPacket(byte[] src, byte[] dst,
-            byte[] sender, byte[] target, short vlan, NodeConnector nc) {
-        return createRawPacket(
-                createIPv4Packet(src, dst, sender, target, vlan), nc);
-    }
-
     /**
      * Create a {@link EthernetHost} instance which represents the
      * specified MAC address and VLAN ID.
index a5ec09cd63de01319d67f517ebb0cc2eea91ed5c..577eeef42300ce4a032081895f3d88cd0a3eec5c 100644 (file)
@@ -19,6 +19,7 @@ import org.junit.Test;
 import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 import org.opendaylight.vtn.manager.util.ByteUtils;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 
@@ -30,7 +31,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetDlDstAction;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
index c7c86e94b3736095283241add4b33fad7286788c..3b817b8c0eed09de10dca6fa3183d176d673cc51 100644 (file)
@@ -19,6 +19,7 @@ import org.junit.Test;
 import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 import org.opendaylight.vtn.manager.util.ByteUtils;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 
@@ -30,7 +31,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetDlSrcAction;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
index 17e75b6630bbf1c38f799f6a7af67d6505141013..6fdae916de25cf52e5084c50b7c3325c517df4bc 100644 (file)
@@ -16,6 +16,7 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetDscpAction;
+import org.opendaylight.vtn.manager.packet.IPv4;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
@@ -25,7 +26,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetInetDscpActi
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.IPv4;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index 9c26ad3215aaccac8f5605cde7cb4c8f4e5e3113..858b8cfe138a8da429037d051e5683dd1dbd981f 100644 (file)
@@ -16,6 +16,9 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetIcmpCodeAction;
+import org.opendaylight.vtn.manager.packet.ICMP;
+import org.opendaylight.vtn.manager.packet.TCP;
+import org.opendaylight.vtn.manager.packet.UDP;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
 import org.opendaylight.vtn.manager.internal.packet.cache.IcmpPacket;
@@ -26,9 +29,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetIcmpCodeActi
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.TCP;
-import org.opendaylight.controller.sal.packet.UDP;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index 9a67338bf6b9a962813a3e5bfc5cbc788f3a3073..2c71e836c302268eab0bf5934566e2f6b2254056 100644 (file)
@@ -16,6 +16,9 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetIcmpTypeAction;
+import org.opendaylight.vtn.manager.packet.ICMP;
+import org.opendaylight.vtn.manager.packet.TCP;
+import org.opendaylight.vtn.manager.packet.UDP;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
 import org.opendaylight.vtn.manager.internal.packet.cache.IcmpPacket;
@@ -26,9 +29,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetIcmpTypeActi
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.TCP;
-import org.opendaylight.controller.sal.packet.UDP;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index f3115520ef60c3f25acd0583a58d45a5f11daaea..368f34930550762376a44ddf774fb83be9292db8 100644 (file)
@@ -20,6 +20,7 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetInet4DstAction;
+import org.opendaylight.vtn.manager.packet.IPv4;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 import org.opendaylight.vtn.manager.util.IpNetwork;
 
@@ -30,7 +31,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetInetDstActio
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.IPv4;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index 92ecfe2f2da7b414fba66e9e352ecbdd531afb5b..25c2955389fe1960ee28e3d8b4a931a6ad4dccc0 100644 (file)
@@ -20,6 +20,7 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetInet4SrcAction;
+import org.opendaylight.vtn.manager.packet.IPv4;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 import org.opendaylight.vtn.manager.util.IpNetwork;
 
@@ -30,7 +31,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetInetSrcActio
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.IPv4;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index dfc29c9f9e76f1d4e284db529383e991e4ab17be..cb96450bb7f2152f1092e1d59efbfc4474b7f613 100644 (file)
@@ -16,6 +16,9 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetTpDstAction;
+import org.opendaylight.vtn.manager.packet.ICMP;
+import org.opendaylight.vtn.manager.packet.TCP;
+import org.opendaylight.vtn.manager.packet.UDP;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
 import org.opendaylight.vtn.manager.internal.packet.cache.IcmpPacket;
@@ -26,9 +29,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetPortDstActio
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.TCP;
-import org.opendaylight.controller.sal.packet.UDP;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index dcb9274bc3f94c2d08b5af0dc70b4c4bb0a87aa3..f137db4e03a0fe7169d5d80d3b03934650378cbc 100644 (file)
@@ -16,6 +16,9 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetTpSrcAction;
+import org.opendaylight.vtn.manager.packet.ICMP;
+import org.opendaylight.vtn.manager.packet.TCP;
+import org.opendaylight.vtn.manager.packet.UDP;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
 import org.opendaylight.vtn.manager.internal.packet.cache.IcmpPacket;
@@ -26,9 +29,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetPortSrcActio
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.TCP;
-import org.opendaylight.controller.sal.packet.UDP;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index e6286708538f0fdc2085903be110f7ef21dad234..af6923041da56c9985f8403509a54a6b51d1d891 100644 (file)
@@ -16,6 +16,7 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.flow.action.SetVlanPcpAction;
+import org.opendaylight.vtn.manager.packet.Ethernet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
@@ -24,7 +25,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.action.VTNSetVlanPcpActio
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
 import org.opendaylight.controller.sal.utils.StatusCode;
 
 /**
index 730111b5310702fce64ddbccad922f16ce8e586d..492d210ee69626b8b45feb723a986d9c11130916 100644 (file)
@@ -17,6 +17,10 @@ import java.util.Set;
 
 import org.junit.Test;
 
+import org.opendaylight.vtn.manager.packet.ARP;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IEEE8021Q;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.EtherTypes;
 
@@ -33,10 +37,6 @@ import org.opendaylight.vtn.manager.internal.TestBase;
 
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
-import org.opendaylight.controller.sal.packet.ARP;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.Packet;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 import org.opendaylight.controller.sal.utils.NodeCreator;
 
index b59cc5dbc5d22645b64cd8e3ffbbebf5ef6cb3f6..057757fed469171a17539b0fe001764744cfe9f7 100644 (file)
@@ -17,6 +17,9 @@ import java.util.Set;
 
 import org.junit.Test;
 
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.ICMP;
+import org.opendaylight.vtn.manager.packet.IPv4;
 import org.opendaylight.vtn.manager.util.InetProtocols;
 
 import org.opendaylight.vtn.manager.internal.PacketContext;
@@ -28,10 +31,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNIcmpMatch;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.IPv4;
-
 /**
  * JUnit test for {@link IcmpPacket}.
  */
index 254364ae601afb53f96458ec0ba46cab52fadfd4..8c02a698f8029fdb972f00670aed07cb1da958df 100644 (file)
@@ -18,6 +18,8 @@ import java.util.Set;
 
 import org.junit.Test;
 
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IPv4;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
@@ -31,9 +33,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNInet4Match;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IPv4;
-
 /**
  * JUnit test for {@link Inet4Packet}.
  */
@@ -185,8 +184,8 @@ public class Inet4PacketTest extends TestBase {
             assertEquals(true, ip.commit(pctx));
             IPv4 newPkt = ip.getPacket();
             assertNotSame(pkt, newPkt);
-            assertEquals(src.getAddress(), newPkt.getSourceAddress());
-            assertEquals(dst.getAddress(), newPkt.getDestinationAddress());
+            assertEquals(src, newPkt.getSourceAddress());
+            assertEquals(dst, newPkt.getDestinationAddress());
             assertEquals((byte)proto, newPkt.getProtocol());
             assertEquals((byte)dscp, newPkt.getDiffServ());
 
@@ -228,8 +227,8 @@ public class Inet4PacketTest extends TestBase {
             assertEquals(dscp0, ipv4.getDscp());
             assertSame(pkt, ipv4.getPacket());
 
-            assertEquals(src0.getAddress(), pkt.getSourceAddress());
-            assertEquals(dst0.getAddress(), pkt.getDestinationAddress());
+            assertEquals(src0, pkt.getSourceAddress());
+            assertEquals(dst0, pkt.getDestinationAddress());
             assertEquals((byte)proto, pkt.getProtocol());
             assertEquals((byte)dscp0, pkt.getDiffServ());
 
index bf95219a4cabbf51beca6c742d88c50d351c0222..ee9fe0ed7443a810c60350456c8b0d3874eb91b2 100644 (file)
@@ -19,6 +19,11 @@ import java.util.Set;
 import org.junit.Test;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IPv4;
+import org.opendaylight.vtn.manager.packet.Packet;
+import org.opendaylight.vtn.manager.packet.PacketException;
+import org.opendaylight.vtn.manager.packet.TCP;
 import org.opendaylight.vtn.manager.util.InetProtocols;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 
@@ -32,11 +37,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNTcpMatch;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IPv4;
-import org.opendaylight.controller.sal.packet.PacketException;
-import org.opendaylight.controller.sal.packet.TCP;
-
 /**
  * JUnit test for {@link TcpPacket}.
  */
@@ -295,11 +295,17 @@ public class TcpPacketTest extends TestBase {
      */
     @Test
     public void testUpdateChecksum() throws Exception {
+        // Create a broken TCP packet.
+        TCP pkt = new TCP();
+        Map<String, byte[]> header = getFieldValue(
+            pkt, Packet.class, Map.class, "hdrFieldsMap");
+        header.put("WindowSize", new byte[]{0});
+
         // Ensure that an exception is wrapped by a VTNException.
         IPv4 ipv4 = new IPv4();
         Inet4Packet inet4 = new Inet4Packet(ipv4);
-        TCP pkt = new TCP();
         TcpPacket tcp = new TcpPacket(pkt);
+
         try {
             tcp.updateChecksum(inet4);
             unexpected();
index 5979e6dea0e35c3c069f3b76eb8754de0b32fff7..a6b995686f95a5d503d0c8da600be90f5b86c775 100644 (file)
@@ -19,6 +19,11 @@ import java.util.Set;
 import org.junit.Test;
 
 import org.opendaylight.vtn.manager.VTNException;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IPv4;
+import org.opendaylight.vtn.manager.packet.Packet;
+import org.opendaylight.vtn.manager.packet.PacketException;
+import org.opendaylight.vtn.manager.packet.UDP;
 import org.opendaylight.vtn.manager.util.InetProtocols;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 
@@ -32,11 +37,6 @@ import org.opendaylight.vtn.manager.internal.util.flow.match.VTNUdpMatch;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IPv4;
-import org.opendaylight.controller.sal.packet.PacketException;
-import org.opendaylight.controller.sal.packet.UDP;
-
 /**
  * JUnit test for {@link UdpPacket}.
  */
@@ -260,11 +260,16 @@ public class UdpPacketTest extends TestBase {
      */
     @Test
     public void testUpdateChecksum() throws Exception {
+        // Create a broken UDP packet.
+        UDP pkt = new UDP();
+        Map<String, byte[]> header = getFieldValue(
+            pkt, Packet.class, Map.class, "hdrFieldsMap");
+        header.put("Length", new byte[]{0});
+        pkt.setChecksum((short)1);
+
         // Ensure that an exception is wrapped by a VTNException.
         IPv4 ipv4 = new IPv4();
         Inet4Packet inet4 = new Inet4Packet(ipv4);
-        UDP pkt = new UDP();
-        pkt.setHeaderField("Checksum", new byte[]{1});
         UdpPacket udp = new UdpPacket(pkt);
         try {
             udp.updateChecksum(inet4);
index f2d7db3e37b62060be985a1dfb3a09f40a4dc0b1..bd2019566f39b19e3368f8fcd5104f9fbf519ad1 100644 (file)
@@ -30,8 +30,6 @@ import org.mockito.Mockito;
 
 import org.opendaylight.vtn.manager.VTNException;
 import org.opendaylight.vtn.manager.util.EtherAddress;
-import org.opendaylight.vtn.manager.util.EtherTypes;
-import org.opendaylight.vtn.manager.util.InetProtocols;
 import org.opendaylight.vtn.manager.util.NumberUtils;
 
 import org.opendaylight.vtn.manager.internal.util.rpc.RpcErrorTag;
@@ -39,15 +37,6 @@ import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.match.MatchType;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.IPv4;
-import org.opendaylight.controller.sal.packet.Packet;
-import org.opendaylight.controller.sal.packet.TCP;
-import org.opendaylight.controller.sal.packet.UDP;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeName;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnErrorTag;
 
@@ -235,274 +224,6 @@ public class MiscUtilsTest extends TestBase {
         }
     }
 
-    /**
-     * Test case for {@link MiscUtils#copy(Packet, Packet)}.
-     *
-     * @throws Exception  An error occurred.
-     */
-    @Test
-    public void testCopyPacket() throws Exception {
-        // Specifying null.
-        try {
-            MiscUtils.copy((Packet)null, (Packet)null);
-            unexpected();
-        } catch (VTNException e) {
-            checkException(e, "Failed to copy the packet.",
-                           VtnErrorTag.INTERNALERROR);
-            assertTrue(e.getCause() instanceof NullPointerException);
-        }
-
-        byte[] raw = {
-            (byte)0x7c, (byte)0xe8, (byte)0x07, (byte)0xde,
-            (byte)0xc5, (byte)0x1b, (byte)0x40, (byte)0x86,
-            (byte)0xc0, (byte)0xa1, (byte)0xe3, (byte)0xe0,
-            (byte)0x90, (byte)0xdd, (byte)0x0c, (byte)0xe6,
-        };
-
-        // Ensure that Ethernet instance with raw payload can be copied.
-        byte[] srcMac = {
-            (byte)0x00, (byte)0x11, (byte)0x22,
-            (byte)0x33, (byte)0x44, (byte)0x55,
-        };
-        byte[] dstMac = {
-            (byte)0xf0, (byte)0xfa, (byte)0xfb,
-            (byte)0xfc, (byte)0xfd, (byte)0xfe,
-        };
-        short etype = 0xa00;
-        short vid = MatchType.DL_VLAN_NONE;
-        byte pcp = 1;
-        for (int loop = 0; loop < 5; loop++) {
-            Ethernet org = createEthernet(srcMac, dstMac, etype, vid, pcp, raw);
-            Ethernet copy = new Ethernet();
-            assertSame(copy, MiscUtils.copy(org, copy));
-            checkCopy(org, copy, srcMac, dstMac, etype, vid, pcp, raw);
-            etype++;
-            vid++;
-            srcMac[3]++;
-            dstMac[4]++;
-        }
-
-        // Ensure that IPv4 instance with raw payload can be copied.
-        int srcIp = (int)0x0a010203;
-        int dstIp = (int)0xc0a864c8;
-        short ipproto = 30;
-        byte dscp = 0;
-        for (int loop = 0; loop < 5; loop++) {
-            IPv4 org = createIPv4(srcIp, dstIp, ipproto, dscp);
-            org.setRawPayload(raw);
-
-            // Copy the original in order to fix up header fields, such as
-            // checksum.
-            org = MiscUtils.copy(org, new IPv4());
-
-            IPv4 copy = new IPv4();
-            assertSame(copy, MiscUtils.copy(org, copy));
-            checkCopy(org, copy, srcIp, dstIp, ipproto, dscp, raw);
-            srcIp++;
-            dstIp++;
-            ipproto++;
-            dscp++;
-        }
-
-        // Ensure that TCP instance with raw payload can be copied.
-        int seq = 0x3333;
-        int ack = 0x4567;
-        byte dataOff = 0;
-        byte resv = 0;
-        short win = (short)0xfc00;
-        short urp = (short)0x5678;
-        short cksum = (short)0x1234;
-        short flags = 0x18;
-        short srcPort = 17;
-        short dstPort = 30000;
-        for (int loop = 0; loop < 5; loop++) {
-            TCP org = new TCP();
-            org.setSourcePort(srcPort).setDestinationPort(dstPort).
-                setSequenceNumber(seq).setAckNumber(ack).
-                setDataOffset(dataOff).setHeaderLenFlags(flags).
-                setReserved(resv).setWindowSize(win).setChecksum(cksum).
-                setUrgentPointer(urp).setRawPayload(raw);
-            TCP copy = new TCP();
-            assertSame(copy, MiscUtils.copy(org, copy));
-            checkCopy(org, copy, srcPort, dstPort, cksum, raw);
-
-            seq++;
-            ack++;
-            dataOff = (byte)((dataOff + 1) & 0xf);
-            cksum += 7;
-            srcPort++;
-            dstPort++;
-        }
-
-        // Ensure that UDP instance with raw payload can be copied.
-        srcPort = (short)45678;
-        dstPort = 133;
-        cksum = (short)0xf1a0;
-        short udpLen = (short)(raw.length + 8);
-        for (int loop = 0; loop < 5; loop++) {
-            UDP org = new UDP();
-            org.setSourcePort(srcPort).setDestinationPort(dstPort).
-                setLength(udpLen).setChecksum(cksum).setRawPayload(raw);
-            UDP copy = new UDP();
-            assertSame(copy, MiscUtils.copy(org, copy));
-            checkCopy(org, copy, srcPort, dstPort, cksum, raw);
-
-            srcPort++;
-            dstPort++;
-            cksum++;
-        }
-
-        // Ensure that ICMP instance with raw payload can be copied.
-        short icmpSeq = 0x13a9;
-        short icmpId = 0x7c;
-        byte icmpType = 0;
-        byte icmpCode = 6;
-        for (int loop = 0; loop < 5; loop++) {
-            ICMP org = new ICMP();
-            org.setType(icmpType).setCode(icmpCode).setIdentifier(icmpId).
-                setSequenceNumber(icmpSeq).setRawPayload(raw);
-
-            // Copy the original in order to fix up header fields, such as
-            // checksum.
-            org = MiscUtils.copy(org, new ICMP());
-
-            ICMP copy = new ICMP();
-            assertSame(copy, MiscUtils.copy(org, copy));
-            checkCopy(org, copy, icmpType, icmpCode, icmpId, icmpSeq, raw);
-
-            icmpSeq++;
-            icmpId++;
-            icmpType++;
-            icmpCode++;
-        }
-
-        // Ensure that nested Etherner frame can be copied.
-        InetProtocols[] protos = {
-            InetProtocols.TCP,
-            InetProtocols.UDP,
-            InetProtocols.ICMP,
-        };
-        int protoIndex = 0;
-        vid = MatchType.DL_VLAN_NONE;
-        etype = EtherTypes.IPV4.shortValue();
-        pcp = 0;
-        dscp = 0;
-        srcPort = 128;
-        dstPort = 12345;
-        cksum = (short)0xed03;
-        for (int loop = 0; loop < protos.length * 5; loop++) {
-            InetProtocols proto = protos[protoIndex];
-            protoIndex++;
-            if (protoIndex >= protos.length) {
-                protoIndex = 0;
-            }
-
-            Packet l4 = null;
-            switch (proto) {
-            case TCP:
-                l4 = new TCP().setSourcePort(srcPort).
-                    setDestinationPort(dstPort).setSequenceNumber(seq).
-                    setAckNumber(ack).setDataOffset(dataOff).
-                    setHeaderLenFlags(flags).setReserved(resv).
-                    setWindowSize(win).setChecksum(cksum).
-                    setUrgentPointer(urp);
-                break;
-
-            case UDP:
-                l4 = new UDP().setSourcePort(srcPort).
-                    setDestinationPort(dstPort).setLength(udpLen).
-                    setChecksum(cksum);
-                break;
-
-            case ICMP:
-                l4 = new ICMP().setType(icmpType).setCode(icmpCode).
-                    setIdentifier(icmpId).setSequenceNumber(icmpSeq);
-                break;
-
-            default:
-                unexpected();
-                break;
-            }
-
-            l4.setRawPayload(raw);
-
-            ipproto = proto.byteValue();
-            IPv4 ipv4 = createIPv4(srcIp, dstIp, ipproto, dscp);
-            ipv4.setPayload(l4);
-            Ethernet ether = createEthernet(srcMac, dstMac, etype, vid, pcp,
-                                            ipv4);
-
-            // Copy the original in order to fix up header fields, such as
-            // IP checksum.
-            ether = MiscUtils.copy(ether, new Ethernet());
-
-            Ethernet copy = new Ethernet();
-            assertSame(copy, MiscUtils.copy(ether, copy));
-            checkCopy(ether, copy, srcMac, dstMac, etype, vid, pcp, null);
-
-            IPv4 ipCopy;
-            if (vid == MatchType.DL_VLAN_NONE) {
-                ipv4 = (IPv4)ether.getPayload();
-                ipCopy = (IPv4)copy.getPayload();
-            } else {
-                Packet pkt = ether.getPayload();
-                ipv4 = (IPv4)pkt.getPayload();
-                pkt = copy.getPayload();
-                ipCopy = (IPv4)pkt.getPayload();
-            }
-            vid = (short)((vid + 1) & 0xfff);
-            srcMac[5]++;
-            dstMac[2]++;
-
-            // Check IPv4 packet.
-            checkCopy(ipv4, ipCopy, srcIp, dstIp, ipproto, dscp, null);
-            srcIp++;
-            dstIp++;
-            dscp = (byte)((dscp + 1) & 0x3f);
-
-            switch (proto) {
-            case TCP:
-                // Check TCP packet.
-                TCP tcp = (TCP)ipv4.getPayload();
-                TCP tcpCopy = (TCP)ipCopy.getPayload();
-                checkCopy(tcp, tcpCopy, srcPort, dstPort, cksum, raw);
-                seq++;
-                ack++;
-                dataOff = (byte)((dataOff + 1) & 0xf);
-                cksum += 13;
-                srcPort++;
-                dstPort++;
-                break;
-
-            case UDP:
-                // Check UDP packet.
-                UDP udp = (UDP)ipv4.getPayload();
-                UDP udpCopy = (UDP)ipCopy.getPayload();
-                checkCopy(udp, udpCopy, srcPort, dstPort, cksum, raw);
-                srcPort++;
-                dstPort++;
-                cksum += 23;
-                break;
-
-            case ICMP:
-                // Check ICMP packet.
-                ICMP icmp = (ICMP)ipv4.getPayload();
-                ICMP icmpCopy = (ICMP)ipCopy.getPayload();
-                checkCopy(icmp, icmpCopy, icmpType, icmpCode, icmpId, icmpSeq,
-                          raw);
-                icmpSeq++;
-                icmpId++;
-                icmpType++;
-                icmpCode++;
-                break;
-
-            default:
-                unexpected();
-                break;
-            }
-        }
-    }
-
     /**
      * Test case for {@link MiscUtils#checkNotNull(Object, Logger, String)}.
      */
@@ -883,173 +604,4 @@ public class MiscUtilsTest extends TestBase {
         assertEquals(desc, e.getMessage());
         assertEquals(vtag, e.getVtnErrorTag());
     }
-
-    /**
-     * Ensure that the raw payload of the packet was copied successfully.
-     *
-     * @param org   Original{@link Packet} instance.
-     * @param copy  A copy of {@code org}.
-     * @param raw    Expected raw payload.
-     */
-    private void checkRawPayloadCopy(Packet org, Packet copy, byte[] raw) {
-        byte[] rawPayload = copy.getRawPayload();
-        byte[] orgPayload = org.getRawPayload();
-        if (raw == null) {
-            assertEquals(null, rawPayload);
-            assertEquals(null, orgPayload);
-        } else {
-            assertEquals(null, org.getPayload());
-            assertEquals(null, copy.getPayload());
-            assertNotSame(raw, rawPayload);
-            assertNotSame(orgPayload, rawPayload);
-            assertArrayEquals(raw, rawPayload);
-            assertArrayEquals(raw, orgPayload);
-        }
-    }
-
-    /**
-     * Ensure that an {@link Ethernet} instance was copied successfully.
-     *
-     * @param org    Original {@link Ethernet} instance.
-     * @param copy   A copy of {@code org}.
-     * @param src    Expected source MAC address.
-     * @param dst    Expected destination MAC address.
-     * @param etype  Expected ethernet type.
-     * @param vid    Expected VLAN ID.
-     * @param pcp    Expected VLAN priority.
-     * @param raw    Expected raw payload.
-     */
-    private void checkCopy(Ethernet org, Ethernet copy, byte[] src, byte[] dst,
-                           short etype, short vid, byte pcp, byte[] raw) {
-        assertNotSame(copy, org);
-        assertEquals(copy, org);
-        assertArrayEquals(src, org.getSourceMACAddress());
-        assertArrayEquals(dst, org.getDestinationMACAddress());
-        assertArrayEquals(src, copy.getSourceMACAddress());
-        assertArrayEquals(dst, copy.getDestinationMACAddress());
-        Packet parent;
-        Packet orgParent;
-        if (vid == MatchType.DL_VLAN_NONE) {
-            assertEquals(etype, org.getEtherType());
-            assertEquals(etype, copy.getEtherType());
-            parent = copy;
-            orgParent = org;
-        } else {
-            assertEquals(EtherTypes.VLAN.shortValue(), org.getEtherType());
-            assertEquals(EtherTypes.VLAN.shortValue(), copy.getEtherType());
-            IEEE8021Q orgTag = (IEEE8021Q)org.getPayload();
-            IEEE8021Q vlanTag = (IEEE8021Q)copy.getPayload();
-            assertNotNull(vlanTag);
-            assertNotSame(orgTag, vlanTag);
-            assertEquals(orgTag, vlanTag);
-            assertEquals(etype, orgTag.getEtherType());
-            assertEquals(vid, orgTag.getVid());
-            assertEquals(pcp, orgTag.getPcp());
-            assertEquals((byte)0, orgTag.getCfi());
-            assertEquals(etype, vlanTag.getEtherType());
-            assertEquals(vid, vlanTag.getVid());
-            assertEquals(pcp, vlanTag.getPcp());
-            assertEquals((byte)0, vlanTag.getCfi());
-            parent = vlanTag;
-            orgParent = orgTag;
-        }
-
-        checkRawPayloadCopy(parent, orgParent, raw);
-    }
-
-    /**
-     * Ensure that an {@link IPv4} instance was copied successfully.
-     *
-     * @param org    Original {@link IPv4} instance.
-     * @param copy   A copy of {@code org}.
-     * @param src    Expected source IP address.
-     * @param dst    Expected destination IP address.
-     * @param proto  Expected IP protocol number.
-     * @param dscp   Expected DSCP field value.
-     * @param raw    Expected raw payload.
-     */
-    private void checkCopy(IPv4 org, IPv4 copy, int src, int dst, short proto,
-                           byte dscp, byte[] raw) {
-        assertNotSame(copy, org);
-        assertEquals(copy, org);
-        for (IPv4 ipv4: new IPv4[]{org, copy}) {
-            assertEquals(src, ipv4.getSourceAddress());
-            assertEquals(dst, ipv4.getDestinationAddress());
-            assertEquals((byte)proto, ipv4.getProtocol());
-            assertEquals(dscp, ipv4.getDiffServ());
-        }
-
-        checkRawPayloadCopy(org, copy, raw);
-    }
-
-    /**
-     * Ensure that an {@link TCP} instance was copied successfully.
-     *
-     * @param org    Original {@link TCP} instance.
-     * @param copy   A copy of {@code org}.
-     * @param src    Expected source port number.
-     * @param dst    Expected destination port number.
-     * @param cksum  Expected TCP checksum.
-     * @param raw    Expected raw payload.
-     */
-    private void checkCopy(TCP org, TCP copy, short src, short dst,
-                           short cksum, byte[] raw) {
-        assertNotSame(copy, org);
-        assertEquals(copy, org);
-        for (TCP tcp: new TCP[]{org, copy}) {
-            assertEquals(src, tcp.getSourcePort());
-            assertEquals(dst, tcp.getDestinationPort());
-            assertEquals(cksum, tcp.getChecksum());
-        }
-
-        checkRawPayloadCopy(org, copy, raw);
-    }
-
-    /**
-     * Ensure that an {@link UDP} instance was copied successfully.
-     *
-     * @param org    Original {@link UDP} instance.
-     * @param copy   A copy of {@code org}.
-     * @param src    Expected source port number.
-     * @param dst    Expected destination port number.
-     * @param cksum  Expected UDP checksum.
-     * @param raw    Expected raw payload.
-     */
-    private void checkCopy(UDP org, UDP copy, short src, short dst,
-                           short cksum, byte[] raw) {
-        assertNotSame(copy, org);
-        assertEquals(copy, org);
-        for (UDP udp: new UDP[]{org, copy}) {
-            assertEquals(src, udp.getSourcePort());
-            assertEquals(dst, udp.getDestinationPort());
-            assertEquals(cksum, udp.getChecksum());
-        }
-
-        checkRawPayloadCopy(org, copy, raw);
-    }
-
-    /**
-     * Ensure that an {@link ICMP} instance was copied successfully.
-     *
-     * @param org    Original {@link UDP} instance.
-     * @param copy   A copy of {@code org}.
-     * @param type   Expected ICMP type.
-     * @param code   Expected ICMP code.
-     * @param id     Expected identifier.
-     * @param seq    Expected sequence number.
-     * @param raw    Expected raw payload.
-     */
-    private void checkCopy(ICMP org, ICMP copy, byte type, byte code,
-                           short id, short seq, byte[] raw) {
-        assertNotSame(copy, org);
-        assertEquals(copy, org);
-        for (ICMP icmp: new ICMP[]{org, copy}) {
-            assertEquals(type, icmp.getType());
-            assertEquals(code, icmp.getCode());
-            assertEquals(id, icmp.getIdentifier());
-            assertEquals(seq, icmp.getSequenceNumber());
-        }
-
-        checkRawPayloadCopy(org, copy, raw);
-    }
 }
index 0a152824370e7769f484e1ac616acddcafe55740..74abc125f67fc73ba2f196f0af02b5a205fd7258 100644 (file)
@@ -12,17 +12,16 @@ import java.net.InetAddress;
 
 import org.junit.Test;
 
+import org.opendaylight.vtn.manager.packet.ARP;
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IEEE8021Q;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.EtherTypes;
 import org.opendaylight.vtn.manager.util.Ip4Network;
 
 import org.opendaylight.vtn.manager.internal.TestBase;
 
-import org.opendaylight.controller.sal.packet.ARP;
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.Packet;
-
 /**
  * JUnit test for {@link ArpPacketBuilder}.
  */
index 736b4f2cd33c943671dee8bad647d9179ad4a6ba..9740b9a5cb077d6cc92f11c0eb5a0030553557b2 100644 (file)
@@ -95,6 +95,7 @@ import org.opendaylight.vtn.manager.flow.cond.UdpMatch;
 import org.opendaylight.vtn.manager.util.EtherAddress;
 import org.opendaylight.vtn.manager.util.EtherTypes;
 import org.opendaylight.vtn.manager.util.InetProtocols;
+import org.opendaylight.vtn.manager.util.IpNetwork;
 
 import org.opendaylight.vtn.manager.it.ofmock.OfMockFlow;
 import org.opendaylight.vtn.manager.it.ofmock.OfMockLink;
@@ -3700,7 +3701,7 @@ public final class VTNManagerIT extends ModelDrivenTestBase {
 
         // Send ICMP packet from moved hosts.
         // This invalidates old MAC address table entries.
-        InetAddress dstIp = InetAddress.getByName("192.168.100.255");
+        IpNetwork dstIp = IpNetwork.create("192.168.100.255");
         for (Map.Entry<TestHost, TestHost> entry: oldHosts0.entrySet()) {
             TestHost oldHost = entry.getKey();
             TestHost newHost = entry.getValue();
@@ -3775,12 +3776,12 @@ public final class VTNManagerIT extends ModelDrivenTestBase {
      *                  A set of VLAN IDs mapped to the given vBridge must be
      *                  associated with the key.
      */
-    private void sendBroadcastIcmp(TestHost host, InetAddress dstIp,
+    private void sendBroadcastIcmp(TestHost host, IpNetwork dstIp,
                                    Map<String, Set<Short>> allPorts)
         throws Exception {
         String pid = host.getPortIdentifier();
         byte[] src = host.getMacAddress();
-        InetAddress srcIp = host.getInetAddress();
+        IpNetwork srcIp = host.getInetAddress();
         short vlan = host.getVlan();
         byte type = 8;
         byte code = 0;
index 37e9f71906fd07bc00c49c71607776aa6579d190..5486dcd45b413bbd780c818182b9f4d2a9f29e7d 100644 (file)
@@ -15,6 +15,8 @@ import java.util.Set;
 
 import org.opendaylight.vtn.manager.EthernetHost;
 import org.opendaylight.vtn.manager.MacAddressEntry;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+import org.opendaylight.vtn.manager.util.IpNetwork;
 
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
@@ -46,7 +48,7 @@ public final class TestHost {
     /**
      * IP address.
      */
-    private final InetAddress  inetAddress;
+    private final IpNetwork  inetAddress;
 
     /**
      * MD-SAL node connector identifier which specifies the switch port
@@ -74,7 +76,7 @@ public final class TestHost {
 
         byte[] addr = IPV4_ADDRESS_BASE.clone();
         addr[addr.length - 1] = (byte)index;
-        inetAddress = InetAddress.getByAddress(addr);
+        inetAddress = new Ip4Network(addr);
         portIdentifier = pid;
         vlan = vid;
     }
@@ -114,9 +116,9 @@ public final class TestHost {
     /**
      * Return IP address of this host.
      *
-     * @return  An {@link InetAddress} instance.
+     * @return  An {@link IpNetwork} instance.
      */
-    public InetAddress getInetAddress() {
+    public IpNetwork getInetAddress() {
         return inetAddress;
     }
 
@@ -126,7 +128,7 @@ public final class TestHost {
      * @return  A byte array which represents the IP address of this host.
      */
     public byte[] getRawInetAddress() {
-        return inetAddress.getAddress();
+        return inetAddress.getBytes();
     }
 
     /**
@@ -176,7 +178,7 @@ public final class TestHost {
     public MacAddressEntry getMacAddressEntry(boolean useIp) {
         NodeConnector nc = TestBase.toAdNodeConnector(portIdentifier);
         Set<InetAddress> ipaddrs = (useIp)
-            ? Collections.singleton(inetAddress)
+            ? Collections.singleton(inetAddress.getInetAddress())
             : null;
         return new MacAddressEntry(macAddress, vlan, nc, ipaddrs);
     }
index abbab2469c317625d499c0802233d099b0ef25ba..e2c2942f5094dab4549ce490fdd9a26af5a013e3 100644 (file)
@@ -9,23 +9,19 @@
 package org.opendaylight.vtn.manager.it.util.action;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import java.net.Inet4Address;
-import java.net.InetAddress;
 import java.util.ListIterator;
 
+import org.opendaylight.vtn.manager.util.Ip4Network;
+import org.opendaylight.vtn.manager.util.IpNetwork;
+
 import org.opendaylight.vtn.manager.it.util.packet.EthernetFactory;
 import org.opendaylight.vtn.manager.it.util.packet.Inet4Factory;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4;
-
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 
 /**
  * {@code SetDscpVerifier} is a utility class used to verify a SET_NW_DST
@@ -35,7 +31,7 @@ public final class SetInet4DstVerifier extends ActionVerifier {
     /**
      * The destination IP address to be set.
      */
-    private final InetAddress  address;
+    private final IpNetwork  address;
 
     /**
      * Ensure that the specified action is an expected SET_NW_DST action.
@@ -43,15 +39,10 @@ public final class SetInet4DstVerifier extends ActionVerifier {
      * @param it  Action list iterator.
      * @param ip  Expected destination IP address.
      */
-    public static void verify(ListIterator<Action> it, InetAddress ip) {
+    public static void verify(ListIterator<Action> it, IpNetwork ip) {
         SetNwDstActionCase act = verify(it, SetNwDstActionCase.class);
         SetNwDstAction snda = act.getSetNwDstAction();
-        Address addr = snda.getAddress();
-        assertTrue(addr instanceof Ipv4);
-        Ipv4 v4 = (Ipv4)addr;
-        Ipv4Prefix v4p = v4.getIpv4Address();
-        assertNotNull(v4p);
-        assertEquals(ip.getHostAddress(), v4p.getValue());
+        assertEquals(ip.getMdAddress(), snda.getAddress());
     }
 
     /**
@@ -59,8 +50,8 @@ public final class SetInet4DstVerifier extends ActionVerifier {
      *
      * @param ip  The destination IP address to be set.
      */
-    public SetInet4DstVerifier(InetAddress ip) {
-        assertTrue(ip instanceof Inet4Address);
+    public SetInet4DstVerifier(IpNetwork ip) {
+        assertTrue(ip instanceof Ip4Network);
         address = ip;
     }
 
@@ -69,7 +60,7 @@ public final class SetInet4DstVerifier extends ActionVerifier {
      *
      * @return  The destination IP address to be set.
      */
-    public InetAddress getAddress() {
+    public IpNetwork getAddress() {
         return address;
     }
 
index 74364b49dd8e7a62abc5f160946e092ff87b9ba9..00a0e786bbfc1d0ef935079903471d4c3f93c35f 100644 (file)
@@ -9,23 +9,19 @@
 package org.opendaylight.vtn.manager.it.util.action;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import java.net.Inet4Address;
-import java.net.InetAddress;
 import java.util.ListIterator;
 
+import org.opendaylight.vtn.manager.util.Ip4Network;
+import org.opendaylight.vtn.manager.util.IpNetwork;
+
 import org.opendaylight.vtn.manager.it.util.packet.EthernetFactory;
 import org.opendaylight.vtn.manager.it.util.packet.Inet4Factory;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.Address;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.address.address.Ipv4;
-
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Prefix;
 
 /**
  * {@code SetDscpVerifier} is a utility class used to verify a SET_NW_SRC
@@ -35,7 +31,7 @@ public final class SetInet4SrcVerifier extends ActionVerifier {
     /**
      * The source IP address to be set.
      */
-    private final InetAddress  address;
+    private final IpNetwork  address;
 
     /**
      * Ensure that the specified action is an expected SET_NW_SRC action.
@@ -43,15 +39,10 @@ public final class SetInet4SrcVerifier extends ActionVerifier {
      * @param it  Action list iterator.
      * @param ip  Expected source IP address.
      */
-    public static void verify(ListIterator<Action> it, InetAddress ip) {
+    public static void verify(ListIterator<Action> it, IpNetwork ip) {
         SetNwSrcActionCase act = verify(it, SetNwSrcActionCase.class);
         SetNwSrcAction snsa = act.getSetNwSrcAction();
-        Address addr = snsa.getAddress();
-        assertTrue(addr instanceof Ipv4);
-        Ipv4 v4 = (Ipv4)addr;
-        Ipv4Prefix v4p = v4.getIpv4Address();
-        assertNotNull(v4p);
-        assertEquals(ip.getHostAddress(), v4p.getValue());
+        assertEquals(ip.getMdAddress(), snsa.getAddress());
     }
 
     /**
@@ -59,8 +50,8 @@ public final class SetInet4SrcVerifier extends ActionVerifier {
      *
      * @param ip  The source IP address to be set.
      */
-    public SetInet4SrcVerifier(InetAddress ip) {
-        assertTrue(ip instanceof Inet4Address);
+    public SetInet4SrcVerifier(IpNetwork ip) {
+        assertTrue(ip instanceof Ip4Network);
         address = ip;
     }
 
@@ -69,7 +60,7 @@ public final class SetInet4SrcVerifier extends ActionVerifier {
      *
      * @return  The source IP address to be set.
      */
-    public InetAddress getAddress() {
+    public IpNetwork getAddress() {
         return address;
     }
 
index 8ead18824fa73c671053f376368c82585ed2bba1..8e2802601ee2a4190270da8732398358695a766b 100644 (file)
@@ -14,12 +14,12 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.ARP;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherTypes;
 
 import org.opendaylight.vtn.manager.it.util.match.FlowMatchType;
 
-import org.opendaylight.controller.sal.packet.ARP;
-import org.opendaylight.controller.sal.packet.Packet;
 import org.opendaylight.controller.sal.packet.address.EthernetAddress;
 
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
index d0baf49971b7f2f3c8c0406b37e1e2e1c7e35b0b..cc55f9dc147a980b51a4f72985059f60c96364cb 100644 (file)
@@ -13,22 +13,21 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import java.net.InetAddress;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.Ethernet;
+import org.opendaylight.vtn.manager.packet.IEEE8021Q;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherTypes;
+import org.opendaylight.vtn.manager.util.IpNetwork;
 
 import org.opendaylight.vtn.manager.it.ofmock.OfMockService;
 import org.opendaylight.vtn.manager.it.util.ModelDrivenTestBase;
 import org.opendaylight.vtn.manager.it.util.TestBase;
 import org.opendaylight.vtn.manager.it.util.match.FlowMatchType;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.IEEE8021Q;
-import org.opendaylight.controller.sal.packet.Packet;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.EthernetMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.VlanMatchBuilder;
@@ -66,7 +65,7 @@ public final class EthernetFactory extends PacketFactory {
     /**
      * IP address to be probed.
      */
-    private InetAddress  probeAddress;
+    private IpNetwork  probeAddress;
 
     /**
      * VLAN ID used for IP address probe.
@@ -139,9 +138,9 @@ public final class EthernetFactory extends PacketFactory {
     /**
      * Return an IP address to be probed.
      *
-     * @return  An {@link InetAddress} instance or {@code null}.
+     * @return  An {@link IpNetwork} instance or {@code null}.
      */
-    public InetAddress getProbeAddress() {
+    public IpNetwork getProbeAddress() {
         return probeAddress;
     }
 
@@ -212,11 +211,11 @@ public final class EthernetFactory extends PacketFactory {
     /**
      * Set a pair of IP address and VLAN ID for IP address probe.
      *
-     * @param ip   An {@link InetAddress} instance.
+     * @param ip   An {@link IpNetwork} instance.
      * @param vid  VLAN ID used for IP address probe.
      * @return  This instance.
      */
-    public EthernetFactory setProbe(InetAddress ip, short vid) {
+    public EthernetFactory setProbe(IpNetwork ip, short vid) {
         probeAddress = ip;
         probeVlan = vid;
         return this;
@@ -283,7 +282,7 @@ public final class EthernetFactory extends PacketFactory {
             afc.setSenderHardwareAddress(ctlrMac).
                 setTargetHardwareAddress(sourceAddress).
                 setSenderProtocolAddress(TestBase.IPV4_ZERO).
-                setTargetProtocolAddress(probeAddress.getAddress());
+                setTargetProtocolAddress(probeAddress.getBytes());
             return efc.verify(ofmock, bytes, vlanIds);
         }
 
index d83d7b323b78ae8f51986711b13b2fce73d266b4..557354caa169806a21017329bbfea2fcb586b75a 100644 (file)
@@ -13,13 +13,12 @@ import static org.junit.Assert.assertTrue;
 
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.ICMP;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.InetProtocols;
 
 import org.opendaylight.vtn.manager.it.util.match.FlowMatchType;
 
-import org.opendaylight.controller.sal.packet.ICMP;
-import org.opendaylight.controller.sal.packet.Packet;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.Icmpv4MatchBuilder;
 
index 0ae3ffd7981a2b3cfa7bde21762c02462249d53f..22cc836b887d511c9f48c3e5d9b6a54654ec43cf 100644 (file)
@@ -11,20 +11,16 @@ package org.opendaylight.vtn.manager.it.util.packet;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
-import static org.opendaylight.vtn.manager.it.util.ModelDrivenTestBase.toIpv4Prefix;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.IPv4;
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.EtherTypes;
-import org.opendaylight.vtn.manager.util.NumberUtils;
+import org.opendaylight.vtn.manager.util.Ip4Network;
+import org.opendaylight.vtn.manager.util.IpNetwork;
 
 import org.opendaylight.vtn.manager.it.util.match.FlowMatchType;
 
-import org.opendaylight.controller.sal.packet.IPv4;
-import org.opendaylight.controller.sal.packet.Packet;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._3.match.Ipv4MatchBuilder;
@@ -44,12 +40,12 @@ public final class Inet4Factory extends PacketFactory {
     /**
      * The source IP address.
      */
-    private InetAddress  sourceAddress;
+    private Ip4Network  sourceAddress;
 
     /**
      * The target IP address.
      */
-    private InetAddress  destinationAddress;
+    private Ip4Network  destinationAddress;
 
     /**
      * IP protocl number.
@@ -88,7 +84,7 @@ public final class Inet4Factory extends PacketFactory {
      * @return  An {@link Inet4Factory} instance.
      */
     public static Inet4Factory newInstance(EthernetFactory efc,
-                                           InetAddress src, InetAddress dst) {
+                                           IpNetwork src, IpNetwork dst) {
         Inet4Factory i4fc = new Inet4Factory(src, dst);
         efc.setEtherType(EtherTypes.IPV4.shortValue()).setNextFactory(i4fc);
 
@@ -106,7 +102,7 @@ public final class Inet4Factory extends PacketFactory {
      * @param src  The source IP address.
      * @param dst  The destination IP address.
      */
-    Inet4Factory(InetAddress src, InetAddress dst) {
+    Inet4Factory(IpNetwork src, IpNetwork dst) {
         setSourceAddress(src);
         setDestinationAddress(dst);
     }
@@ -114,18 +110,18 @@ public final class Inet4Factory extends PacketFactory {
     /**
      * Return the source IP address.
      *
-     * @return  An {@link InetAddress} or {@code null}.
+     * @return  An {@link Ip4Network} or {@code null}.
      */
-    public InetAddress getSourceAddress() {
+    public Ip4Network getSourceAddress() {
         return sourceAddress;
     }
 
     /**
      * Return the destination IP address.
      *
-     * @return  An {@link InetAddress} or {@code null}.
+     * @return  An {@link Ip4Network} or {@code null}.
      */
-    public InetAddress getDestinationAddress() {
+    public Ip4Network getDestinationAddress() {
         return destinationAddress;
     }
 
@@ -159,28 +155,24 @@ public final class Inet4Factory extends PacketFactory {
     /**
      * Set the source IP address.
      *
-     * @param ip  An {@link InetAddress}.
+     * @param ip  An {@link IpNetwork}.
      * @return  This instance.
      */
-    public Inet4Factory setSourceAddress(InetAddress ip) {
-        if (ip != null) {
-            assertTrue(ip instanceof Inet4Address);
-        }
-        sourceAddress = ip;
+    public Inet4Factory setSourceAddress(IpNetwork ip) {
+        assertEquals(Ip4Network.class, ip.getClass());
+        sourceAddress = (Ip4Network)ip;
         return this;
     }
 
     /**
      * Set the destination IP address.
      *
-     * @param ip  An {@link InetAddress}.
+     * @param ip  An {@link IpNetwork}.
      * @return  This instance.
      */
-    public Inet4Factory setDestinationAddress(InetAddress ip) {
-        if (ip != null) {
-            assertTrue(ip instanceof Inet4Address);
-        }
-        destinationAddress = ip;
+    public Inet4Factory setDestinationAddress(IpNetwork ip) {
+        assertEquals(Ip4Network.class, ip.getClass());
+        destinationAddress = (Ip4Network)ip;
         return this;
     }
 
@@ -238,10 +230,8 @@ public final class Inet4Factory extends PacketFactory {
         assertTrue(packet instanceof IPv4);
         IPv4 ip = (IPv4)packet;
 
-        int srcInet = toInteger(sourceAddress);
-        int dstInet = toInteger(destinationAddress);
-        assertEquals(srcInet, ip.getSourceAddress());
-        assertEquals(dstInet, ip.getDestinationAddress());
+        assertEquals(sourceAddress, ip.getSourceAddress());
+        assertEquals(destinationAddress, ip.getDestinationAddress());
         assertEquals(protocol, ip.getProtocol());
         assertEquals(timeToLive, ip.getTtl());
         assertEquals(dscp, ip.getDiffServ());
@@ -258,11 +248,12 @@ public final class Inet4Factory extends PacketFactory {
         Ipv4MatchBuilder i4mb = new Ipv4MatchBuilder();
 
         if (types.contains(FlowMatchType.IP_SRC)) {
-            i4mb.setIpv4Source(toIpv4Prefix(sourceAddress));
+            i4mb.setIpv4Source(sourceAddress.getIpPrefix().getIpv4Prefix());
             v4Count++;
         }
         if (types.contains(FlowMatchType.IP_DST)) {
-            i4mb.setIpv4Destination(toIpv4Prefix(destinationAddress));
+            i4mb.setIpv4Destination(destinationAddress.getIpPrefix().
+                                    getIpv4Prefix());
             v4Count++;
         }
         if (types.contains(FlowMatchType.IP_PROTO)) {
@@ -284,16 +275,6 @@ public final class Inet4Factory extends PacketFactory {
         return ipCount + v4Count;
     }
 
-    /**
-     * Convert an IPv4 address into an integer value.
-     *
-     * @param ip  An {@link InetAddress} instance.
-     * @return    An integer value.
-     */
-    private int toInteger(InetAddress ip) {
-        return NumberUtils.toInteger(ip.getAddress());
-    }
-
     // Object
 
     /**
index 378988820dc2adb7c0c7a6f8b9f2cb901d787825..cc861cd6c388bbc3482508c516be1e51da9378c1 100644 (file)
@@ -13,13 +13,12 @@ import static org.junit.Assert.fail;
 
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.Packet;
 import org.opendaylight.vtn.manager.util.ByteUtils;
 
 import org.opendaylight.vtn.manager.it.ofmock.OfMockUtils;
 import org.opendaylight.vtn.manager.it.util.match.FlowMatchType;
 
-import org.opendaylight.controller.sal.packet.Packet;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 
index 635c8da5a5dd54724881113962e4022aee17b34a..30463b79434f90a9171b1caa5f961cf9b3c158c6 100644 (file)
@@ -15,13 +15,12 @@ import static org.opendaylight.vtn.manager.it.util.ModelDrivenTestBase.toPortNum
 
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.Packet;
+import org.opendaylight.vtn.manager.packet.TCP;
 import org.opendaylight.vtn.manager.util.InetProtocols;
 
 import org.opendaylight.vtn.manager.it.util.match.FlowMatchType;
 
-import org.opendaylight.controller.sal.packet.Packet;
-import org.opendaylight.controller.sal.packet.TCP;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.TcpMatchBuilder;
 
index c841901ae45daae3e1150cdf0f2f54e78ca6baf3..7acfc80daaf78dc5ee2922d92200c4f72bbdafa8 100644 (file)
@@ -15,13 +15,12 @@ import static org.opendaylight.vtn.manager.it.util.ModelDrivenTestBase.toPortNum
 
 import java.util.Set;
 
+import org.opendaylight.vtn.manager.packet.Packet;
+import org.opendaylight.vtn.manager.packet.UDP;
 import org.opendaylight.vtn.manager.util.InetProtocols;
 
 import org.opendaylight.vtn.manager.it.util.match.FlowMatchType;
 
-import org.opendaylight.controller.sal.packet.Packet;
-import org.opendaylight.controller.sal.packet.UDP;
-
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.layer._4.match.UdpMatchBuilder;