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