Bug 2820 - LLDP TLV support and testing
[controller.git] / opendaylight / commons / liblldp / src / test / java / org / opendaylight / controller / liblldp / LLDPTest.java
1 /*
2  * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.liblldp;
9
10 import static org.junit.Assert.assertArrayEquals;
11
12 import java.util.ArrayList;
13 import java.util.List;
14
15 import org.apache.commons.lang3.ArrayUtils;
16 import org.junit.Assert;
17 import org.junit.Test;
18 import org.junit.internal.ArrayComparisonFailure;
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21
22 import com.google.common.primitives.Bytes;
23
24 /**
25  * Test of {@link LLDP} serialization feature (TODO: and deserialization)
26  */
27 public class LLDPTest {
28
29     private static final Logger LOG = LoggerFactory.getLogger(LLDPTest.class);
30
31     private static final byte[] CHASSIS_ID_VALUE = "chassis".getBytes();
32     private static final short CHASSIS_ID_LENGTH = (short) CHASSIS_ID_VALUE.length;
33
34     private static final byte[] TTL_VALUE = new byte[] { (byte) 0, (byte) 100 };
35     private static final short TTL_LENGTH = (short) TTL_VALUE.length;
36
37     private static final byte[] PORT_VALUE = "dummy port id".getBytes();
38     private static final short PORT_LENGTH = (short) PORT_VALUE.length;
39
40     private static final byte[] SYSTEM_NAME_VALUE = "dummy system name".getBytes();
41     private static final short SYSTEM_NAME_LENGTH = (short) SYSTEM_NAME_VALUE.length;
42
43     private static final byte SYSTEM_CAPABILITIES_TLV = 8;
44     private static final byte[] SYSTEM_CAPABILITIES_VALUE = "dummy system capabilities".getBytes();
45     private static final short SYSTEM_CAPABILITIES_LENGTH = (short) SYSTEM_CAPABILITIES_VALUE.length;
46
47     private static final byte[] OUI = new byte[] { (byte) 0X11, (byte) 0X22, (byte) 0X33 };
48
49     private static final byte[] OUI_SUBTYPE_A = new byte[] { (byte) 0 };
50     private static final byte[] CUSTOM_SUBTYPE_A_VALUE = "first custom value A".getBytes();
51     private static final short CUSTOM_SUBTYPE_A_LENGTH = (short) (OUI.length + OUI_SUBTYPE_A.length + CUSTOM_SUBTYPE_A_VALUE.length);
52
53     private static final byte[] OUI_SUBTYPE_B = new byte[] { (byte) 1 };
54     private static final byte[] CUSTOM_SUBTYPE_B_VALUE = "second custom value B".getBytes();
55     private static final short CUSTOM_SUBTYPE_B_LENGTH = (short) (OUI.length + OUI_SUBTYPE_B.length + CUSTOM_SUBTYPE_B_VALUE.length);
56
57     /**
58      * Tests whether serialization of LLDP packet is correct
59      *
60      * @see LLDP#serialize()
61      * @throws PacketException
62      */
63     @Test
64     public void testSerialize() throws PacketException {
65         LLDP lldpBuilder = new LLDP();
66
67         lldpBuilder.setChassisId(dummyTlv(LLDPTLV.TLVType.ChassisID.getValue(), CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE));
68         lldpBuilder.setTtl(dummyTlv(LLDPTLV.TLVType.TTL.getValue(), TTL_LENGTH, TTL_VALUE));
69         lldpBuilder.setPortId(dummyTlv(LLDPTLV.TLVType.PortID.getValue(), PORT_LENGTH, PORT_VALUE));
70         lldpBuilder.setSystemNameId(dummyTlv(LLDPTLV.TLVType.SystemName.getValue(), SYSTEM_NAME_LENGTH,
71                 SYSTEM_NAME_VALUE));
72
73         // adding optional TLVs for which doesn't exist special set* methods in LLDP
74         final List<LLDPTLV> optionalTLVs = new ArrayList<>();
75         // System Capabilities TLV (type = 7)
76         optionalTLVs.add(dummyTlv(SYSTEM_CAPABILITIES_TLV, SYSTEM_CAPABILITIES_LENGTH, SYSTEM_CAPABILITIES_VALUE));
77         lldpBuilder.setOptionalTLVList(optionalTLVs);
78
79         // // adding custom TLVs
80          final List<LLDPTLV> customTLVs = new ArrayList<>();
81          customTLVs.add(dummyCustomTlv(LLDPTLV.TLVType.Custom.getValue(), OUI, OUI_SUBTYPE_A,
82          CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE));
83          customTLVs.add(dummyCustomTlv(LLDPTLV.TLVType.Custom.getValue(), OUI, OUI_SUBTYPE_B,
84          CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE));
85          lldpBuilder.setCustomTLVList(customTLVs);
86
87         byte[] serialized = lldpBuilder.serialize();
88
89         int offset = 0;
90         offset = checkTLV(serialized, offset, (byte) 0b00000010, "ChassisID", CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE);
91         offset = checkTLV(serialized, offset, (byte) 0b00000110, "TTL", TTL_LENGTH, TTL_VALUE);
92         offset = checkTLV(serialized, offset, (byte) 0b00000100, "PortID", PORT_LENGTH, PORT_VALUE);
93         offset = checkTLV(serialized, offset, (byte) 0b00001010, "SystemName", SYSTEM_NAME_LENGTH,
94                 SYSTEM_NAME_VALUE);
95         offset = checkTLV(serialized, offset, (byte) 0b00010000, "System capabilities",
96                 SYSTEM_CAPABILITIES_LENGTH, SYSTEM_CAPABILITIES_VALUE);
97         offset = checkTLV(serialized, offset, (byte) 0b11111110, "Custom subtype A",
98                 CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE, OUI[0], OUI[1], OUI[2],
99                 OUI_SUBTYPE_A[0]);
100         offset = checkTLV(serialized, offset, (byte) 0b11111110, "Custom subtype B",
101                 CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE, OUI[0], OUI[1], OUI[2],
102                 OUI_SUBTYPE_B[0]);
103
104     }
105
106     /**
107      * Tests whether serialization of LLDP packet is correct
108      *
109      * @see LLDP#deserialize(byte[], int, int)
110      * @throws Exception
111      */
112     @Test
113     public void testDeserialize() throws Exception {
114         LLDP lldp = new LLDP();
115         byte[] bytesBeforeCustomA = new byte[] { 0x00, 0x26, (byte) 0xe1, OUI_SUBTYPE_A[0] };
116         byte[] bytesBeforeCustomB = new byte[] { 0x00, 0x26, (byte) 0xe1, OUI_SUBTYPE_B[0] };
117
118         byte[] rawLldpTlv = Bytes.concat(
119                 awaitedBytes((byte) 0b00000010, CHASSIS_ID_LENGTH, CHASSIS_ID_VALUE, null),
120                 awaitedBytes((byte) 0b00000110, TTL_LENGTH, TTL_VALUE, null),
121                 awaitedBytes((byte) 0b00000100, PORT_LENGTH, PORT_VALUE, null),
122                 awaitedBytes((byte) 0b00001010, SYSTEM_NAME_LENGTH, SYSTEM_NAME_VALUE, null),
123                 awaitedBytes((byte) 0b00010010, SYSTEM_CAPABILITIES_LENGTH,
124                         SYSTEM_CAPABILITIES_VALUE, null),
125                 awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_A_LENGTH, CUSTOM_SUBTYPE_A_VALUE,
126                         bytesBeforeCustomA),
127                 awaitedBytes((byte) 0b11111110, CUSTOM_SUBTYPE_B_LENGTH, CUSTOM_SUBTYPE_B_VALUE,
128                         bytesBeforeCustomB));
129
130         lldp.deserialize(rawLldpTlv, 0, rawLldpTlv.length * NetUtils.NumBitsInAByte);
131         Assert.assertEquals("chassis", new String(lldp.getChassisId().getValue()));
132         Assert.assertArrayEquals(TTL_VALUE, lldp.getTtl().getValue());
133         Assert.assertEquals("dummy port id", new String(lldp.getPortId().getValue()));
134         Assert.assertEquals("dummy system name", new String(lldp.getSystemNameId().getValue()));
135
136         // optional items check
137         List<LLDPTLV> tlvOptionalList = lldp.getOptionalTLVList();
138         Assert.assertEquals(1, tlvOptionalList.size());
139
140         LLDPTLV itemOpt0 = tlvOptionalList.get(0);
141         Assert.assertEquals(9, itemOpt0.getType());
142         Assert.assertEquals("dummy system capabilities", new String(itemOpt0.getValue()));
143
144         // custom items check
145         List<LLDPTLV> tlvCustomList = lldp.getCustomTlvList();
146         Assert.assertEquals(2, tlvCustomList.size());
147
148         checkCustomTlv(tlvCustomList.get(0), "first custom value A");
149         checkCustomTlv(tlvCustomList.get(1), "second custom value B");
150     }
151
152     /**
153      * @param customItem
154      * @param expectedValue
155      */
156     private static void checkCustomTlv(LLDPTLV customItem, String expectedValue) {
157         Assert.assertEquals(127, customItem.getType());
158         LOG.debug("custom TLV1.length: {}", customItem.getLength());
159         Assert.assertEquals(expectedValue,
160                 new String(
161                         LLDPTLV.getCustomString(
162                                 customItem.getValue(),
163                                 customItem.getLength()))
164         );
165     }
166
167     private static int checkTLV(byte[] serializedData, int offset, byte typeTLVBits, String typeTLVName, short lengthTLV,
168             byte[] valueTLV, byte... bytesBeforeValue) throws ArrayComparisonFailure {
169         byte[] concreteTlvAwaited = awaitedBytes(typeTLVBits, lengthTLV, valueTLV, bytesBeforeValue);
170         int concreteTlvAwaitLength = concreteTlvAwaited.length;
171         assertArrayEquals("Serialization problem " + typeTLVName, concreteTlvAwaited,
172                 ArrayUtils.subarray(serializedData, offset, offset + concreteTlvAwaitLength));
173         return offset + concreteTlvAwaitLength;
174     }
175
176     private static byte[] awaitedBytes(byte typeTLV, short length, byte[] value, byte[] bytesBeforeValue) {
177         byte[] awaited = ArrayUtils.EMPTY_BYTE_ARRAY;
178
179         // 0 - the less meaning byte (right), 1 most meaning byte (left)
180         byte lengthByte0 = (byte) length;
181         byte lengthByte1 = (byte) (length >> 8);
182
183         awaited = ArrayUtils.addAll(awaited, (byte) (typeTLV | lengthByte1), lengthByte0);
184         awaited = ArrayUtils.addAll(awaited, bytesBeforeValue);
185         awaited = ArrayUtils.addAll(awaited, value);
186         return awaited;
187     }
188
189     private static LLDPTLV dummyCustomTlv(final byte tlvType, byte[] oui, byte[] ouiSubtype, short customLength,
190             byte[] subtypeValue) {
191         byte[] fullCustomValue = new byte[0];
192         fullCustomValue = ArrayUtils.addAll(fullCustomValue, oui);
193         fullCustomValue = ArrayUtils.addAll(fullCustomValue, ouiSubtype);
194         fullCustomValue = ArrayUtils.addAll(fullCustomValue, subtypeValue);
195         return dummyTlv(tlvType, customLength, fullCustomValue);
196     }
197
198     private static LLDPTLV dummyTlv(final byte concreteTlv, final short concreteLength, final byte[] concreteValue) {
199         LLDPTLV tlv = new LLDPTLV();
200         tlv.setType(concreteTlv).setLength(concreteLength).setValue(concreteValue);
201         return tlv;
202     }
203 }