Bug 2820 - LLDP TLV support and testing 12/16512/7
authorJozef Gloncak <jgloncak@cisco.com>
Tue, 17 Mar 2015 11:50:15 +0000 (12:50 +0100)
committerJozef Gloncak <jgloncak@cisco.com>
Fri, 20 Mar 2015 07:40:46 +0000 (08:40 +0100)
- enhancement: deserialization now supports custom TLV
- tests:
  - LLDP.deserialize
  - LLDPTLV.createCustomValue
  - LLDPTLV.getCustomString
  - beautified (checkstyle)

Change-Id: I56c807b46d889266fc43cdc9b35d00bf17bb4d09
Signed-off-by: Jozef Gloncak <jgloncak@cisco.com>
Signed-off-by: Michal Rehak <mirehak@cisco.com>
(cherry picked from commit 91a47340196d4a5bbf9beaaed9a202bf4a8836d9)

opendaylight/commons/liblldp/pom.xml
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java
opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/liblldp/LLDPTLVTest.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/liblldp/LLDPTest.java
opendaylight/commons/liblldp/src/test/resources/log4j.xml [new file with mode: 0644]

index 286c68e677e664383ec70cd81bcd9cc898ee37b6..5e14c92ee78de72c3a3e1b13a2c2ca53159a4bc8 100644 (file)
@@ -27,7 +27,6 @@
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-log4j12</artifactId>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-log4j12</artifactId>
-      <scope>test</scope>
     </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
     </dependency>
     <dependency>
       <groupId>com.google.guava</groupId>
index 94f25c03a302523cec0e275f18074020b90e4820..c7dc6915ad32b432054c9a3d2c08e4b046003aec 100644 (file)
@@ -8,7 +8,6 @@
 
 package org.opendaylight.controller.liblldp;
 
 
 package org.opendaylight.controller.liblldp;
 
-import java.util.Collections;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
@@ -31,14 +30,15 @@ public class LLDP extends Packet {
             (byte) 0xc2, 0, 0, (byte) 0xe };
     private Map<Byte, LLDPTLV> tlvList;
 
             (byte) 0xc2, 0, 0, (byte) 0xe };
     private Map<Byte, LLDPTLV> tlvList;
 
-    private List<LLDPTLV> customTlvList = Collections.emptyList();
+    private List<LLDPTLV> customTlvList;
 
     /**
      * Default constructor that creates the tlvList LinkedHashMap
      */
     public LLDP() {
         super();
 
     /**
      * Default constructor that creates the tlvList LinkedHashMap
      */
     public LLDP() {
         super();
-        tlvList = new LinkedHashMap<Byte, LLDPTLV>(LLDPDefaultTlvs);
+        tlvList = new LinkedHashMap<>(LLDPDefaultTlvs);
+        customTlvList = new ArrayList<>();
     }
 
     /**
     }
 
     /**
@@ -63,6 +63,8 @@ public class LLDP extends Packet {
             return LLDPTLV.TLVType.PortID.getValue();
         } else if (typeDesc.equals(TTL)) {
             return LLDPTLV.TLVType.TTL.getValue();
             return LLDPTLV.TLVType.PortID.getValue();
         } else if (typeDesc.equals(TTL)) {
             return LLDPTLV.TLVType.TTL.getValue();
+        } else if (typeDesc.equals(SYSTEMNAMEID)) {
+            return LLDPTLV.TLVType.SystemName.getValue();
         } else {
             return LLDPTLV.TLVType.Unknown.getValue();
         }
         } else {
             return LLDPTLV.TLVType.Unknown.getValue();
         }
@@ -163,7 +165,8 @@ public class LLDP extends Packet {
             byte type = entry.getKey();
             if ((type == LLDPTLV.TLVType.ChassisID.getValue())
                     || (type == LLDPTLV.TLVType.PortID.getValue())
             byte type = entry.getKey();
             if ((type == LLDPTLV.TLVType.ChassisID.getValue())
                     || (type == LLDPTLV.TLVType.PortID.getValue())
-                    || (type == LLDPTLV.TLVType.TTL.getValue())) {
+                    || (type == LLDPTLV.TLVType.TTL.getValue())
+                    || (type == LLDPTLV.TLVType.SystemName.getValue())) {
                 continue;
             } else {
                 list.add(entry.getValue());
                 continue;
             } else {
                 list.add(entry.getValue());
@@ -172,6 +175,13 @@ public class LLDP extends Packet {
         return list;
     }
 
         return list;
     }
 
+    /**
+     * @return the customTlvList
+     */
+    public List<LLDPTLV> getCustomTlvList() {
+        return customTlvList;
+    }
+
     /**
      * @param optionalTLVList
      *            the optionalTLVList to set
     /**
      * @param optionalTLVList
      *            the optionalTLVList to set
@@ -216,7 +226,11 @@ public class LLDP extends Packet {
             int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
             lldpOffset += tlvSize;
             lldpSize -= tlvSize;
             int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
             lldpOffset += tlvSize;
             lldpSize -= tlvSize;
-            this.tlvList.put(tlv.getType(), tlv);
+            if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
+                customTlvList.add(tlv);
+            } else {
+                this.tlvList.put(tlv.getType(), tlv);
+            }
         }
         return this;
     }
         }
         return this;
     }
diff --git a/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/liblldp/LLDPTLVTest.java b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/liblldp/LLDPTLVTest.java
new file mode 100644 (file)
index 0000000..23f8ae6
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * 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 org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.io.BaseEncoding;
+import com.google.common.primitives.Bytes;
+
+/**
+ *
+ */
+public class LLDPTLVTest {
+
+    /** dummy custom tlv value */
+    private static final String CUSTOM_TLV_ULTIMATE = "What do you get when you multiply 6 by 9?";
+    /** dummy custom tlv value in binary form */
+    private static final byte[] CUSTOM_TLV_ULTIMATE_BIN = new byte[] {
+        0x57, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x67, 0x65, 0x74,
+        0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6d, 0x75, 0x6c, 0x74, 0x69,
+        0x70, 0x6c, 0x79, 0x20, 0x36, 0x20, 0x62, 0x79, 0x20, 0x39, 0x3f
+    };
+
+    private static final Logger LOG = LoggerFactory.getLogger(LLDPTLVTest.class);
+
+    /**
+     * Test method for
+     * {@link org.opendaylight.controller.liblldp.LLDPTLV#createCustomTLVValue(java.lang.String)}
+     * .
+     */
+    @Test
+    public void testCreateCustomTLVValue() {
+        byte[] tlv = LLDPTLV.createCustomTLVValue(CUSTOM_TLV_ULTIMATE);
+
+        byte[] expectedCustomTlv = Bytes.concat(new byte[] {
+                // custom type (7b) + length (9b) = 16b = 2B  (skipped)
+                // 0x7f, 24,
+                // openflow OUI
+                0x00, 0x26, (byte) 0xe1,
+                // subtype
+                0x00},
+                // custom value
+                CUSTOM_TLV_ULTIMATE_BIN);
+
+        BaseEncoding be = BaseEncoding.base16().withSeparator(" ", 2).lowerCase();
+        LOG.debug("expected: {}", be.encode(expectedCustomTlv));
+        LOG.debug("actual  : {}", be.encode(tlv));
+        Assert.assertArrayEquals(expectedCustomTlv, tlv);
+    }
+
+    /**
+     * Test method for
+     * {@link org.opendaylight.controller.liblldp.LLDPTLV#getCustomString(byte[], int)}
+     * .
+     * @throws Exception
+     */
+    @Test
+    public void testGetCustomString() throws Exception {
+        byte[] inputCustomTlv = Bytes.concat(new byte[] {
+                // custom type (7b) + length (9b) = 16b = 2B  (skipped)
+                // 0x7f, 24,
+                // openflow OUI
+                0x00, 0x26, (byte) 0xe1,
+                // subtype
+                0x00},
+                // custom value
+                CUSTOM_TLV_ULTIMATE_BIN);
+
+        String actual = LLDPTLV.getCustomString(inputCustomTlv, inputCustomTlv.length);
+        LOG.debug("actual custom TLV value as string: {}", actual);
+        Assert.assertEquals(CUSTOM_TLV_ULTIMATE, actual);
+    }
+}
index a9cfa727ce55d59b8517d2efced43e1d1f535791..1a14e0b650e9d041b9e862301a6ffb35f420768f 100644 (file)
@@ -10,17 +10,24 @@ package org.opendaylight.controller.liblldp;
 import static org.junit.Assert.assertArrayEquals;
 
 import java.util.ArrayList;
 import static org.junit.Assert.assertArrayEquals;
 
 import java.util.ArrayList;
-
 import java.util.List;
 import java.util.List;
-import org.junit.internal.ArrayComparisonFailure;
-import org.junit.Test;
+
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.ArrayUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.internal.ArrayComparisonFailure;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.primitives.Bytes;
 
 /**
  * Test of {@link LLDP} serialization feature (TODO: and deserialization)
  */
 public class LLDPTest {
 
 
 /**
  * Test of {@link LLDP} serialization feature (TODO: and deserialization)
  */
 public class LLDPTest {
 
+    private static final Logger LOG = LoggerFactory.getLogger(LLDPTest.class);
+
     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[] CHASSIS_ID_VALUE = "chassis".getBytes();
     private static final short CHASSIS_ID_LENGTH = (short) CHASSIS_ID_VALUE.length;
 
@@ -49,6 +56,7 @@ public class LLDPTest {
 
     /**
      * Tests whether serialization of LLDP packet is correct
 
     /**
      * Tests whether serialization of LLDP packet is correct
+     *
      * @see LLDP#serialize()
      * @throws PacketException
      */
      * @see LLDP#serialize()
      * @throws PacketException
      */
@@ -82,14 +90,78 @@ public class LLDPTest {
         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) 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]);
+        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]);
+
+    }
 
 
+    /**
+     * Tests whether serialization of LLDP packet is correct
+     *
+     * @see LLDP#deserialize(byte[], int, int)
+     * @throws Exception
+     */
+    @Test
+    public void testDeserialize() throws Exception {
+        LLDP lldp = new LLDP();
+        byte[] bytesBeforeCustomA = new byte[] { 0x00, 0x26, (byte) 0xe1, OUI_SUBTYPE_A[0] };
+        byte[] bytesBeforeCustomB = new byte[] { 0x00, 0x26, (byte) 0xe1, OUI_SUBTYPE_B[0] };
+
+        byte[] rawLldpTlv = Bytes.concat(
+                awaitedBytes((byte) 0b00000010, CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE, null),
+                awaitedBytes((byte) 0b00000110, TTL_LENGTH, TTL_VALUE, null),
+                awaitedBytes((byte) 0b00000100, PORT_LENGTH, PORT_VALUE, null),
+                awaitedBytes((byte) 0b00001010, SYSTEM_NAME_LENGTH, SYSTEM_NAME_VALUE, null),
+                awaitedBytes((byte) 0b00010010, SYSTEM_CAPABILITIES_LENGTH,
+                        SYSTEM_CAPABILITIES_VALUE, null),
+                awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE,
+                        bytesBeforeCustomA),
+                awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE,
+                        bytesBeforeCustomB));
+
+        lldp.deserialize(rawLldpTlv, 0, rawLldpTlv.length * NetUtils.NumBitsInAByte);
+        Assert.assertEquals("chassis", new String(lldp.getChassisId().getValue()));
+        Assert.assertArrayEquals(TTL_VALUE, lldp.getTtl().getValue());
+        Assert.assertEquals("dummy port id", new String(lldp.getPortId().getValue()));
+        Assert.assertEquals("dummy system name", new String(lldp.getSystemNameId().getValue()));
+
+        // optional items check
+        List<LLDPTLV> tlvOptionalList = lldp.getOptionalTLVList();
+        Assert.assertEquals(1, tlvOptionalList.size());
+
+        LLDPTLV itemOpt0 = tlvOptionalList.get(0);
+        Assert.assertEquals(9, itemOpt0.getType());
+        Assert.assertEquals("dummy system capabilities", new String(itemOpt0.getValue()));
+
+        // custom items check
+        List<LLDPTLV> tlvCustomList = lldp.getCustomTlvList();
+        Assert.assertEquals(2, tlvCustomList.size());
+
+        checkCustomTlv(tlvCustomList.get(0), "first custom value A");
+        checkCustomTlv(tlvCustomList.get(1), "second custom value B");
+    }
+
+    /**
+     * @param customItem
+     * @param expectedValue
+     */
+    private static void checkCustomTlv(LLDPTLV customItem, String expectedValue) {
+        Assert.assertEquals(127, customItem.getType());
+        LOG.debug("custom TLV1.length: {}", customItem.getLength());
+        Assert.assertEquals(expectedValue,
+                new String(
+                        LLDPTLV.getCustomString(
+                                customItem.getValue(),
+                                customItem.getLength()))
+        );
     }
 
     private static int checkTLV(byte[] serializedData, int offset, byte typeTLVBits, String typeTLVName, short lengthTLV,
     }
 
     private static int checkTLV(byte[] serializedData, int offset, byte typeTLVBits, String typeTLVName, short lengthTLV,
diff --git a/opendaylight/commons/liblldp/src/test/resources/log4j.xml b/opendaylight/commons/liblldp/src/test/resources/log4j.xml
new file mode 100644 (file)
index 0000000..9196fc4
--- /dev/null
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">\r
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">\r
+\r
+    <appender name="console" class="org.apache.log4j.ConsoleAppender">\r
+        <layout class="org.apache.log4j.PatternLayout">\r
+            <param name="ConversionPattern" value="%-6p %d{HH:mm:ss.SSS} [%10.10t] %30.30c %x - %m%n" />\r
+        </layout>\r
+    </appender>\r
+\r
+    <logger name="org.opendaylight.controller.liblldp" additivity="false">\r
+        <level value="DEBUG" />\r
+        <appender-ref ref="console" />\r
+    </logger>\r
+\r
+    <root>\r
+        <priority value="INFO" />\r
+        <appender-ref ref="console" />\r
+    </root>\r
+</log4j:configuration>\r