From: Jozef Gloncak Date: Tue, 17 Mar 2015 10:34:03 +0000 (+0100) Subject: Bug 2820 - problem to add second TLV with type 127. X-Git-Tag: release/beryllium~615^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=80aa6ca219506d06a8ad1628271598ffb4fb8710 Bug 2820 - problem to add second TLV with type 127. Custom TLVs aren't saved to map with key type but are stored in standalone array. - fixed list copy (for custom TLV list) - extended test - involved custom TLV list items into packet length counting - published Change-Id: Ifa1cab17206e1be37022bc8b49f7990649cbd356 Signed-off-by: Jozef Gloncak Signed-off-by: Michal Rehak (cherry picked from commit 254ab138bab0132a9afafe6227bc998e9dfa7a44) --- diff --git a/opendaylight/commons/liblldp/pom.xml b/opendaylight/commons/liblldp/pom.xml index 148a4f3792..286c68e677 100644 --- a/opendaylight/commons/liblldp/pom.xml +++ b/opendaylight/commons/liblldp/pom.xml @@ -24,6 +24,15 @@ org.slf4j slf4j-api + + org.slf4j + slf4j-log4j12 + test + + + com.google.guava + guava + @@ -35,8 +44,8 @@ org.slf4j, - org.apache.commons.lang3.builder, - org.apache.commons.lang3.tuple + org.apache.commons.lang3.*, + com.google.common.* org.opendaylight.controller.liblldp diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java index 9b7efbb1e6..94f25c03a3 100644 --- a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java +++ b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.liblldp; +import java.util.Collections; +import com.google.common.collect.Iterables; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; @@ -29,6 +31,8 @@ public class LLDP extends Packet { (byte) 0xc2, 0, 0, (byte) 0xe }; private Map tlvList; + private List customTlvList = Collections.emptyList(); + /** * Default constructor that creates the tlvList LinkedHashMap */ @@ -180,6 +184,16 @@ public class LLDP extends Packet { return this; } + /** + * @param customTLVList + * the list of custom TLVs to set + * @return this LLDP + */ + public LLDP setCustomTLVList(final List customTLVList) { + this.customTlvList = new ArrayList<>(customTLVList); + return this; + } + @Override public Packet deserialize(byte[] data, int bitOffset, int size) throws PacketException { @@ -212,8 +226,8 @@ public class LLDP extends Packet { int startOffset = 0; byte[] serializedBytes = new byte[getLLDPPacketLength()]; - for (Map.Entry entry : tlvList.entrySet()) { - LLDPTLV tlv = entry.getValue(); + final Iterable allTlvs = Iterables.concat(tlvList.values(), customTlvList); + for (LLDPTLV tlv : allTlvs) { int numBits = tlv.getTLVSize(); try { BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), @@ -252,6 +266,11 @@ public class LLDP extends Packet { tlv = entry.getValue(); len += tlv.getTLVSize(); } + + for (LLDPTLV customTlv : this.customTlvList) { + len += customTlv.getTLVSize(); + } + len += LLDP.emptyTLV.getTLVSize(); return len / NetUtils.NumBitsInAByte; diff --git a/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/liblldp/LLDPTest.java b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/liblldp/LLDPTest.java new file mode 100644 index 0000000000..a9cfa727ce --- /dev/null +++ b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/liblldp/LLDPTest.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 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.controller.liblldp; + +import static org.junit.Assert.assertArrayEquals; + +import java.util.ArrayList; + +import java.util.List; +import org.junit.internal.ArrayComparisonFailure; +import org.junit.Test; +import org.apache.commons.lang3.ArrayUtils; + +/** + * Test of {@link LLDP} serialization feature (TODO: and deserialization) + */ +public class LLDPTest { + + private static final byte[] CHASSIS_ID_VALUE = "chassis".getBytes(); + private static final short CHASSIS_ID_LENGTH = (short) CHASSIS_ID_VALUE.length; + + private static final byte[] TTL_VALUE = new byte[] { (byte) 0, (byte) 100 }; + private static final short TTL_LENGTH = (short) TTL_VALUE.length; + + private static final byte[] PORT_VALUE = "dummy port id".getBytes(); + private static final short PORT_LENGTH = (short) PORT_VALUE.length; + + private static final byte[] SYSTEM_NAME_VALUE = "dummy system name".getBytes(); + private static final short SYSTEM_NAME_LENGTH = (short) SYSTEM_NAME_VALUE.length; + + private static final byte SYSTEM_CAPABILITIES_TLV = 8; + private static final byte[] SYSTEM_CAPABILITIES_VALUE = "dummy system capabilities".getBytes(); + private static final short SYSTEM_CAPABILITIES_LENGTH = (short) SYSTEM_CAPABILITIES_VALUE.length; + + private static final byte[] OUI = new byte[] { (byte) 0X11, (byte) 0X22, (byte) 0X33 }; + + private static final byte[] OUI_SUBTYPE_A = new byte[] { (byte) 0 }; + private static final byte[] CUSTOM_SUBTYPE_A_VALUE = "first custom value A".getBytes(); + private static final short CUSTOM_SUBTYPE_A_LENGTH = (short) (OUI.length + OUI_SUBTYPE_A.length + CUSTOM_SUBTYPE_A_VALUE.length); + + private static final byte[] OUI_SUBTYPE_B = new byte[] { (byte) 1 }; + private static final byte[] CUSTOM_SUBTYPE_B_VALUE = "second custom value B".getBytes(); + private static final short CUSTOM_SUBTYPE_B_LENGTH = (short) (OUI.length + OUI_SUBTYPE_B.length + CUSTOM_SUBTYPE_B_VALUE.length); + + /** + * Tests whether serialization of LLDP packet is correct + * @see LLDP#serialize() + * @throws PacketException + */ + @Test + public void testSerialize() throws PacketException { + LLDP lldpBuilder = new LLDP(); + + lldpBuilder.setChassisId(dummyTlv(LLDPTLV.TLVType.ChassisID.getValue(), CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE)); + lldpBuilder.setTtl(dummyTlv(LLDPTLV.TLVType.TTL.getValue(), TTL_LENGTH, TTL_VALUE)); + lldpBuilder.setPortId(dummyTlv(LLDPTLV.TLVType.PortID.getValue(), PORT_LENGTH, PORT_VALUE)); + lldpBuilder.setSystemNameId(dummyTlv(LLDPTLV.TLVType.SystemName.getValue(), SYSTEM_NAME_LENGTH, + SYSTEM_NAME_VALUE)); + + // adding optional TLVs for which doesn't exist special set* methods in LLDP + final List optionalTLVs = new ArrayList<>(); + // System Capabilities TLV (type = 7) + optionalTLVs.add(dummyTlv(SYSTEM_CAPABILITIES_TLV, SYSTEM_CAPABILITIES_LENGTH, SYSTEM_CAPABILITIES_VALUE)); + lldpBuilder.setOptionalTLVList(optionalTLVs); + + // // adding custom TLVs + final List customTLVs = new ArrayList<>(); + customTLVs.add(dummyCustomTlv(LLDPTLV.TLVType.Custom.getValue(), OUI, OUI_SUBTYPE_A, + CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE)); + customTLVs.add(dummyCustomTlv(LLDPTLV.TLVType.Custom.getValue(), OUI, OUI_SUBTYPE_B, + CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE)); + lldpBuilder.setCustomTLVList(customTLVs); + + byte[] serialized = lldpBuilder.serialize(); + + int offset = 0; + offset = checkTLV(serialized, offset, (byte) 0b00000010, "ChassisID", CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE); + offset = checkTLV(serialized, offset, (byte) 0b00000110, "TTL", TTL_LENGTH, TTL_VALUE); + offset = checkTLV(serialized, offset, (byte) 0b00000100, "PortID", PORT_LENGTH, PORT_VALUE); + offset = checkTLV(serialized, offset, (byte) 0b00001010, "SystemName", SYSTEM_NAME_LENGTH, SYSTEM_NAME_VALUE); + offset = checkTLV(serialized, offset, (byte) 0b00010000, "System capabilities", SYSTEM_CAPABILITIES_LENGTH, + SYSTEM_CAPABILITIES_VALUE); + offset = checkTLV(serialized, offset, (byte) 0b11111110, "Custom subtype A", CUSTOM_SUBTYPE_A_LENGTH, + CUSTOM_SUBTYPE_A_VALUE, OUI[0], OUI[1], OUI[2], OUI_SUBTYPE_A[0]); + offset = checkTLV(serialized, offset, (byte) 0b11111110, "Custom subtype B", CUSTOM_SUBTYPE_B_LENGTH, + CUSTOM_SUBTYPE_B_VALUE, OUI[0], OUI[1], OUI[2], OUI_SUBTYPE_B[0]); + + } + + private static int checkTLV(byte[] serializedData, int offset, byte typeTLVBits, String typeTLVName, short lengthTLV, + byte[] valueTLV, byte... bytesBeforeValue) throws ArrayComparisonFailure { + byte[] concreteTlvAwaited = awaitedBytes(typeTLVBits, lengthTLV, valueTLV, bytesBeforeValue); + int concreteTlvAwaitLength = concreteTlvAwaited.length; + assertArrayEquals("Serialization problem " + typeTLVName, concreteTlvAwaited, + ArrayUtils.subarray(serializedData, offset, offset + concreteTlvAwaitLength)); + return offset + concreteTlvAwaitLength; + } + + private static byte[] awaitedBytes(byte typeTLV, short length, byte[] value, byte[] bytesBeforeValue) { + byte[] awaited = ArrayUtils.EMPTY_BYTE_ARRAY; + + // 0 - the less meaning byte (right), 1 most meaning byte (left) + byte lengthByte0 = (byte) length; + byte lengthByte1 = (byte) (length >> 8); + + awaited = ArrayUtils.addAll(awaited, (byte) (typeTLV | lengthByte1), lengthByte0); + awaited = ArrayUtils.addAll(awaited, bytesBeforeValue); + awaited = ArrayUtils.addAll(awaited, value); + return awaited; + } + + private static LLDPTLV dummyCustomTlv(final byte tlvType, byte[] oui, byte[] ouiSubtype, short customLength, + byte[] subtypeValue) { + byte[] fullCustomValue = new byte[0]; + fullCustomValue = ArrayUtils.addAll(fullCustomValue, oui); + fullCustomValue = ArrayUtils.addAll(fullCustomValue, ouiSubtype); + fullCustomValue = ArrayUtils.addAll(fullCustomValue, subtypeValue); + return dummyTlv(tlvType, customLength, fullCustomValue); + } + + private static LLDPTLV dummyTlv(final byte concreteTlv, final short concreteLength, final byte[] concreteValue) { + LLDPTLV tlv = new LLDPTLV(); + tlv.setType(concreteTlv).setLength(concreteLength).setValue(concreteValue); + return tlv; + } +}