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>
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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();
+ }
+}
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.
*/
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.
*/
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();
*/
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();
+ }
+ }
+ }
}
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 {
/**
*/
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.
* @param v The Ethernet type value.
*/
private EtherTypes(int v) {
- value = v;
+ value = (short)v;
}
/**
* @return An integer that represents the Ethernet type value.
*/
public int intValue() {
- return value;
+ return (value & NumberUtils.MASK_SHORT);
}
/**
* @return A short integer that represents the Ethernet type value.
*/
public short shortValue() {
- return (short)value;
+ return value;
}
}
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 {
/**
*/
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.
* @param v The IP protocol number.
*/
private InetProtocols(int v) {
- value = v;
+ value = (byte)v;
}
/**
* @return An integer that represents the IP protocol number.
*/
public int intValue() {
- return value;
+ return (int)(value & MASK_BYTE);
}
/**
* @return A short integer that represents the IP protocol number.
*/
public short shortValue() {
- return (short)value;
+ return (short)(value & MASK_BYTE);
}
/**
* @return A byte that represents the IP protocol number.
*/
public byte byteValue() {
- return (byte)value;
+ return value;
}
}
*/
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.
*/
* 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;
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;
}
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);
+ }
+ }
}
/**
* Test case for
- * {@link VTNException#VTNException(VtnErrorTag, String, Thowable)} and
+ * {@link VTNException#VTNException(VtnErrorTag, String, Throwable)} and
* the followings.
*
* <ul>
/**
* Test case for
- * {@link VTNException#VTNException(String, Thowable)} and
+ * {@link VTNException#VTNException(String, Throwable)} and
* the followings.
*
* <ul>
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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]);
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
}
}
}
+
+ /**
+ * 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));
+ }
+ }
+ }
}
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()));
+ }
+ }
}
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);
+ }
+ }
+ }
}
}
}
+ /**
+ * 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)}.
*/
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;
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;
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.
* @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;
* @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;
* 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());
}
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
*/
private final SalPort ingressPort;
- /**
- * A {@link RawPacket} instance which represents the received packet.
- */
- private final RawPacket payload;
-
/**
* Decoded ethernet frame.
*/
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);
}
public PacketInEvent(VTNPacketListener l, PacketInEvent ev) {
listener = l;
ingressPort = ev.ingressPort;
- payload = ev.payload;
ethernet = ev.ethernet;
}
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.
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;
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.
*/
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.
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;
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.
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;
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.
*/
* 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;
}
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;
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.
*/
*/
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();
* 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;
}
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
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
Values v = getValues();
Ip4Network ipn = v.getSourceAddress();
if (ipn == null) {
- ipn = new Ip4Network(packet.getSourceAddress());
+ ipn = packet.getSourceAddress();
v.setSourceAddress(ipn);
}
Values v = getValues();
Ip4Network ipn = v.getDestinationAddress();
if (ipn == null) {
- ipn = new Ip4Network(packet.getDestinationAddress());
+ ipn = packet.getDestinationAddress();
v.setDestinationAddress(ipn);
}
/**
* 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;
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;
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.
*/
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.
*/
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;
}
/**
* 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;
* @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.
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.
*/
* @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;
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.
*/
* @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;
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;
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;
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;
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.
*
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.
*/
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;
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;
*/
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).
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.
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);
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);
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);
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.
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;
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;
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;
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;
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;
import org.opendaylight.vtn.manager.internal.TestBase;
-import org.opendaylight.controller.sal.packet.IPv4;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
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;
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;
/**
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;
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;
/**
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;
import org.opendaylight.vtn.manager.internal.TestBase;
-import org.opendaylight.controller.sal.packet.IPv4;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
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;
import org.opendaylight.vtn.manager.internal.TestBase;
-import org.opendaylight.controller.sal.packet.IPv4;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
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;
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;
/**
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;
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;
/**
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;
import org.opendaylight.vtn.manager.internal.TestBase;
-import org.opendaylight.controller.sal.packet.Ethernet;
import org.opendaylight.controller.sal.utils.StatusCode;
/**
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.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;
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;
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}.
*/
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;
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}.
*/
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());
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());
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;
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}.
*/
*/
@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();
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;
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}.
*/
*/
@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);
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;
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;
}
}
- /**
- * 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)}.
*/
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);
- }
}
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}.
*/
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;
// 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();
* 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;
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;
/**
* IP address.
*/
- private final InetAddress inetAddress;
+ private final IpNetwork inetAddress;
/**
* MD-SAL node connector identifier which specifies the switch port
byte[] addr = IPV4_ADDRESS_BASE.clone();
addr[addr.length - 1] = (byte)index;
- inetAddress = InetAddress.getByAddress(addr);
+ inetAddress = new Ip4Network(addr);
portIdentifier = pid;
vlan = vid;
}
/**
* Return IP address of this host.
*
- * @return An {@link InetAddress} instance.
+ * @return An {@link IpNetwork} instance.
*/
- public InetAddress getInetAddress() {
+ public IpNetwork getInetAddress() {
return inetAddress;
}
* @return A byte array which represents the IP address of this host.
*/
public byte[] getRawInetAddress() {
- return inetAddress.getAddress();
+ return inetAddress.getBytes();
}
/**
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);
}
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
/**
* 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.
* @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());
}
/**
*
* @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;
}
*
* @return The destination IP address to be set.
*/
- public InetAddress getAddress() {
+ public IpNetwork getAddress() {
return address;
}
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
/**
* 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.
* @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());
}
/**
*
* @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;
}
*
* @return The source IP address to be set.
*/
- public InetAddress getAddress() {
+ public IpNetwork getAddress() {
return address;
}
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;
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;
/**
* IP address to be probed.
*/
- private InetAddress probeAddress;
+ private IpNetwork probeAddress;
/**
* VLAN ID used for IP address probe.
/**
* 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;
}
/**
* 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;
afc.setSenderHardwareAddress(ctlrMac).
setTargetHardwareAddress(sourceAddress).
setSenderProtocolAddress(TestBase.IPV4_ZERO).
- setTargetProtocolAddress(probeAddress.getAddress());
+ setTargetProtocolAddress(probeAddress.getBytes());
return efc.verify(ofmock, bytes, vlanIds);
}
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;
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;
/**
* The source IP address.
*/
- private InetAddress sourceAddress;
+ private Ip4Network sourceAddress;
/**
* The target IP address.
*/
- private InetAddress destinationAddress;
+ private Ip4Network destinationAddress;
/**
* IP protocl number.
* @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);
* @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);
}
/**
* 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;
}
/**
* 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;
}
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());
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)) {
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
/**
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;
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;
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;