OPNFLWPLUG-898 Improve code quality in liblldp module
[openflowplugin.git] / libraries / liblldp / src / main / java / org / opendaylight / openflowplugin / libraries / liblldp / LLDPTLV.java
1 /*
2  * Copyright (c) 2013 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
9 package org.opendaylight.openflowplugin.libraries.liblldp;
10
11 import java.io.UnsupportedEncodingException;
12 import java.nio.charset.Charset;
13 import java.nio.charset.StandardCharsets;
14 import java.util.Arrays;
15 import java.util.HashMap;
16 import java.util.LinkedHashMap;
17 import java.util.Map;
18 import org.apache.commons.lang3.ArrayUtils;
19 import org.apache.commons.lang3.tuple.MutablePair;
20 import org.apache.commons.lang3.tuple.Pair;
21
22 /**
23  * Class that represents the LLDPTLV objects.
24  */
25 @SuppressWarnings("checkstyle:AbbreviationAsWordInName")
26 public class LLDPTLV extends Packet {
27     private static final String TYPE = "Type";
28     private static final String LENGTH = "Length";
29     private static final String VALUE = "Value";
30     private static final int LLDPTLV_FIELDS = 3;
31
32     /** OpenFlow OUI. */
33     static final byte[] OFOUI = new byte[] { (byte) 0x00, (byte) 0x26, (byte) 0xe1 };
34
35     /** Length of Organizationally defined subtype field of TLV in bytes.   */
36     private static final byte CUSTOM_TLV_SUB_TYPE_LENGTH = (byte)1;
37
38     /** OpenFlow subtype: nodeConnectorId of source. */
39     private static final byte[] CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID = new byte[] { 0 };
40
41     /** OpenFlow subtype: custom sec = hash code of verification of origin of LLDP. */
42     private static final byte[] CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC = new byte[] { 1 };
43
44     private static final int CUSTOM_TLV_OFFSET = OFOUI.length + CUSTOM_TLV_SUB_TYPE_LENGTH;
45     private static final byte[] CHASSISID_SUB_TYPE = new byte[] { 4 }; // MAC address for the system
46     private static final byte[] PORTID_SUB_TYPE = new byte[] { 7 }; // locally assigned
47
48     public enum TLVType {
49         Unknown((byte) 0), ChassisID((byte) 1), PortID((byte) 2), TTL((byte) 3), PortDesc(
50                 (byte) 4), SystemName((byte) 5), SystemDesc((byte) 6), Custom(
51                         (byte) 127);
52
53         private final byte value;
54
55         TLVType(final byte value) {
56             this.value = value;
57         }
58
59         public byte getValue() {
60             return value;
61         }
62     }
63
64     private static final Map<String, Pair<Integer, Integer>> FIELD_COORDINATES = new LinkedHashMap<>();
65
66     static {
67         FIELD_COORDINATES.put(TYPE, new MutablePair<>(0, 7));
68         FIELD_COORDINATES.put(LENGTH, new MutablePair<>(7, 9));
69         FIELD_COORDINATES.put(VALUE, new MutablePair<>(16, 0));
70     }
71
72     protected Map<String, byte[]> fieldValues;
73
74     /**
75      * Default constructor that creates and sets the hash map values and sets the payload to null.
76      */
77     public LLDPTLV() {
78         payload = null;
79         fieldValues = new HashMap<>(LLDPTLV_FIELDS);
80         hdrFieldCoordMap = FIELD_COORDINATES;
81         hdrFieldsMap = fieldValues;
82     }
83
84     /**
85      * Constructor that writes the passed LLDPTLV values to the hdrFieldsMap.
86      */
87     public LLDPTLV(final LLDPTLV other) {
88         for (Map.Entry<String, byte[]> entry : other.hdrFieldsMap.entrySet()) {
89             this.hdrFieldsMap.put(entry.getKey(), entry.getValue());
90         }
91     }
92
93     /**
94      * Returns the length of TLV.
95      */
96     public int getLength() {
97         return (int) BitBufferHelper.toNumber(fieldValues.get(LENGTH),
98                 FIELD_COORDINATES.get(LENGTH).getRight());
99     }
100
101     /**
102      * Returns the type of TLV.
103      */
104     public byte getType() {
105         return BitBufferHelper.getByte(fieldValues.get(TYPE));
106     }
107
108     /**
109      * Returns the value field of TLV.
110      */
111     public byte[] getValue() {
112         return fieldValues.get(VALUE);
113     }
114
115     /**
116      * Sets the type.
117      *
118      * @param type the type to set
119      * @return LLDPTLV
120      */
121     public LLDPTLV setType(final byte type) {
122         byte[] lldpTLVtype = { type };
123         fieldValues.put(TYPE, lldpTLVtype);
124         return this;
125     }
126
127     /**
128      * Sets the length.
129      *
130      * @param length the length to set
131      * @return LLDPTLV
132      */
133     public LLDPTLV setLength(final short length) {
134         fieldValues.put(LENGTH, BitBufferHelper.toByteArray(length));
135         return this;
136     }
137
138     /**
139      * Sets the value.
140      *
141      * @param value the value to set
142      * @return LLDPTLV
143      */
144     public LLDPTLV setValue(final byte[] value) {
145         fieldValues.put(VALUE, value);
146         return this;
147     }
148
149     @Override
150     public void setHeaderField(final String headerField, final byte[] readValue) {
151         hdrFieldsMap.put(headerField, readValue);
152     }
153
154     @Override
155     public int hashCode() {
156         final int prime = 31;
157         int result = super.hashCode();
158         result = prime * result
159                 + (fieldValues == null ? 0 : fieldValues.hashCode());
160         return result;
161     }
162
163     @Override
164     public boolean equals(final Object obj) {
165         if (this == obj) {
166             return true;
167         }
168         if (!super.equals(obj)) {
169             return false;
170         }
171         if (getClass() != obj.getClass()) {
172             return false;
173         }
174         LLDPTLV other = (LLDPTLV) obj;
175         if (fieldValues == null) {
176             if (other.fieldValues != null) {
177                 return false;
178             }
179         } else if (!fieldValues.equals(other.fieldValues)) {
180             return false;
181         }
182         return true;
183     }
184
185     @Override
186     public int getfieldnumBits(final String fieldName) {
187         if (fieldName.equals(VALUE)) {
188             return NetUtils.NUM_BITS_IN_A_BYTE * BitBufferHelper.getShort(
189                     fieldValues.get(LENGTH), FIELD_COORDINATES.get(LENGTH).getRight());
190         }
191         return FIELD_COORDINATES.get(fieldName).getRight();
192     }
193
194     /**
195      * Returns the size in bits of the whole TLV.
196      *
197      * @return int - size in bits of full TLV
198      */
199     public int getTLVSize() {
200         return LLDPTLV.FIELD_COORDINATES.get(TYPE).getRight() + // static
201                 LLDPTLV.FIELD_COORDINATES.get(LENGTH).getRight() + // static
202                 getfieldnumBits(VALUE); // variable
203     }
204
205     /**
206      * Creates the SystemName TLV value.
207      *
208      * @param nodeId
209      *            node identifier string
210      * @return the SystemName TLV value in byte array
211      */
212     public static byte[] createSystemNameTLVValue(final String nodeId) {
213         return nodeId.getBytes(StandardCharsets.UTF_8);
214     }
215
216     /**
217      * Creates the ChassisID TLV value including the subtype and ChassisID string.
218      *
219      * @param nodeId
220      *            node identifier string
221      * @return the ChassisID TLV value in byte array
222      */
223     public static byte[] createChassisIDTLVValue(final String nodeId) {
224         byte[] nid = HexEncode.bytesFromHexString(nodeId);
225         byte[] cid = new byte[6];
226         int srcPos = 0;
227         int dstPos = 0;
228
229         if (nid.length > cid.length) {
230             srcPos = nid.length - cid.length;
231         } else {
232             dstPos = cid.length - nid.length;
233         }
234         System.arraycopy(nid, srcPos, cid, dstPos, cid.length);
235
236         byte[] cidValue = new byte[cid.length + CHASSISID_SUB_TYPE.length];
237
238         System.arraycopy(CHASSISID_SUB_TYPE, 0, cidValue, 0,
239                 CHASSISID_SUB_TYPE.length);
240         System.arraycopy(cid, 0, cidValue, CHASSISID_SUB_TYPE.length, cid.length);
241
242         return cidValue;
243     }
244
245     /**
246      * Creates the PortID TLV value including the subtype and PortID string.
247      *
248      * @param portId
249      *            port identifier string
250      * @return the PortID TLV value in byte array
251      */
252     public static byte[] createPortIDTLVValue(final String portId) {
253         byte[] pid = portId.getBytes(Charset.defaultCharset());
254         byte[] pidValue = new byte[pid.length + PORTID_SUB_TYPE.length];
255
256         System.arraycopy(PORTID_SUB_TYPE, 0, pidValue, 0, PORTID_SUB_TYPE.length);
257         System.arraycopy(pid, 0, pidValue, PORTID_SUB_TYPE.length, pid.length);
258
259         return pidValue;
260     }
261
262     /**
263      * Creates the custom TLV value including OUI, subtype and custom string.
264      *
265      * @param customString
266      *            port identifier string
267      * @return the custom TLV value in byte array
268      * @see #createCustomTLVValue(byte[],byte[])
269      */
270     public static byte[] createCustomTLVValue(final String customString) {
271         byte[] customByteArray = customString.getBytes(Charset.defaultCharset());
272         return createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID, customByteArray);
273     }
274
275     /**
276      * Creates the custom TLV value including OUI, subtype and custom string.
277      *
278      * @param subtype openflow subtype
279      * @param customByteArray
280      *            port identifier string
281      * @return the custom TLV value in byte array
282      */
283     public static byte[] createCustomTLVValue(final byte[] subtype, final byte[] customByteArray) {
284         byte[] customValue = new byte[CUSTOM_TLV_OFFSET + customByteArray.length];
285
286         System.arraycopy(OFOUI, 0, customValue, 0, OFOUI.length);
287         System.arraycopy(subtype, 0, customValue, OFOUI.length, 1);
288         System.arraycopy(customByteArray, 0, customValue, CUSTOM_TLV_OFFSET,
289                 customByteArray.length);
290
291         return customValue;
292     }
293
294     /**
295      * Creates a custom TLV value including OUI of sub type custom sec and custom bytes value.
296      *
297      * @param customValue the custom value
298      * @return the custom TLV value in byte array
299      */
300     public static byte[] createSecSubTypeCustomTLVValue(final byte[] customValue) {
301         return createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC, customValue);
302     }
303
304     /**
305      * Retrieves the string from TLV value and returns it in HexString format.
306      *
307      * @param tlvValue
308      *            the TLV value
309      * @param tlvLen
310      *            the TLV length
311      * @return the HexString
312      */
313     public static String getHexStringValue(final byte[] tlvValue, final int tlvLen) {
314         byte[] cidBytes = new byte[tlvLen - CHASSISID_SUB_TYPE.length];
315         System.arraycopy(tlvValue, CHASSISID_SUB_TYPE.length, cidBytes, 0,
316                 cidBytes.length);
317         return HexEncode.bytesToHexStringFormat(cidBytes);
318     }
319
320     /**
321      * Retrieves the string from TLV value.
322      *
323      * @param tlvValue
324      *            the TLV value
325      * @param tlvLen
326      *            the TLV length
327      * @return the string
328      */
329     public static String getStringValue(final byte[] tlvValue, final int tlvLen) {
330         byte[] pidSubType = new byte[PORTID_SUB_TYPE.length];
331         byte[] pidBytes = new byte[tlvLen - PORTID_SUB_TYPE.length];
332         System.arraycopy(tlvValue, 0, pidSubType, 0,
333                 pidSubType.length);
334         System.arraycopy(tlvValue, PORTID_SUB_TYPE.length, pidBytes, 0,
335                 pidBytes.length);
336         if (pidSubType[0] == (byte) 0x3) {
337             return HexEncode.bytesToHexStringFormat(pidBytes);
338         } else {
339             return new String(pidBytes, Charset.defaultCharset());
340         }
341     }
342
343     /**
344      * Retrieves the custom string from the Custom TLV value which includes OUI, subtype and custom string.
345      *
346      * @param customTlvValue
347      *            the custom TLV value
348      * @param customTlvLen
349      *            the custom TLV length
350      * @return the custom string
351      */
352     public static String getCustomString(final byte[] customTlvValue, final int customTlvLen) {
353         String customString = "";
354         byte[] vendor = new byte[3];
355         System.arraycopy(customTlvValue, 0, vendor, 0, vendor.length);
356         if (Arrays.equals(vendor, LLDPTLV.OFOUI)) {
357             int customArrayLength = customTlvLen - CUSTOM_TLV_OFFSET;
358             byte[] customArray = new byte[customArrayLength];
359             System.arraycopy(customTlvValue, CUSTOM_TLV_OFFSET, customArray, 0, customArrayLength);
360             try {
361                 customString = new String(customArray, "UTF-8");
362             } catch (final UnsupportedEncodingException e) {
363                 LOG.warn("Error creating string from the custom TLV value: {}", Arrays.toString(customTlvValue), e);
364             }
365         }
366
367         return customString;
368     }
369
370     public static int extractCustomOUI(final LLDPTLV lldptlv) {
371         byte[] value = lldptlv.getValue();
372         return BitBufferHelper.getInt(ArrayUtils.subarray(value, 0, 3));
373     }
374
375     public static byte extractCustomSubtype(final LLDPTLV lldptlv) {
376         byte[] value = lldptlv.getValue();
377         return BitBufferHelper.getByte(ArrayUtils.subarray(value, 3, 4));
378     }
379
380     public static CustomTLVKey createPortSubTypeCustomTLVKey() throws BufferException {
381         return new CustomTLVKey(BitBufferHelper.getInt(OFOUI), CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID[0]);
382     }
383
384     public static CustomTLVKey createSecSubTypeCustomTLVKey() throws BufferException {
385         return new CustomTLVKey(BitBufferHelper.getInt(LLDPTLV.OFOUI), LLDPTLV.CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC[0]);
386     }
387 }