Merge "OPNFLWPLUG-983 Group and flow removal stats are not reported in order"
[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 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().intValue());
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)
190                     .getRight().intValue());
191         }
192         return FIELD_COORDINATES.get(fieldName).getRight();
193     }
194
195     /**
196      * Returns the size in bits of the whole TLV.
197      *
198      * @return int - size in bits of full TLV
199      */
200     public int getTLVSize() {
201         return LLDPTLV.FIELD_COORDINATES.get(TYPE).getRight() + // static
202                 LLDPTLV.FIELD_COORDINATES.get(LENGTH).getRight() + // static
203                 getfieldnumBits(VALUE); // variable
204     }
205
206     /**
207      * Creates the SystemName TLV value.
208      *
209      * @param nodeId
210      *            node identifier string
211      * @return the SystemName TLV value in byte array
212      */
213     public static byte[] createSystemNameTLVValue(final String nodeId) {
214         return nodeId.getBytes(StandardCharsets.UTF_8);
215     }
216
217     /**
218      * Creates the ChassisID TLV value including the subtype and ChassisID string.
219      *
220      * @param nodeId
221      *            node identifier string
222      * @return the ChassisID TLV value in byte array
223      */
224     public static byte[] createChassisIDTLVValue(final String nodeId) {
225         byte[] nid = HexEncode.bytesFromHexString(nodeId);
226         byte[] cid = new byte[6];
227         int srcPos = 0;
228         int dstPos = 0;
229
230         if (nid.length > cid.length) {
231             srcPos = nid.length - cid.length;
232         } else {
233             dstPos = cid.length - nid.length;
234         }
235         System.arraycopy(nid, srcPos, cid, dstPos, cid.length);
236
237         byte[] cidValue = new byte[cid.length + CHASSISID_SUB_TYPE.length];
238
239         System.arraycopy(CHASSISID_SUB_TYPE, 0, cidValue, 0,
240                 CHASSISID_SUB_TYPE.length);
241         System.arraycopy(cid, 0, cidValue, CHASSISID_SUB_TYPE.length, cid.length);
242
243         return cidValue;
244     }
245
246     /**
247      * Creates the PortID TLV value including the subtype and PortID string.
248      *
249      * @param portId
250      *            port identifier string
251      * @return the PortID TLV value in byte array
252      */
253     public static byte[] createPortIDTLVValue(final String portId) {
254         byte[] pid = portId.getBytes(Charset.defaultCharset());
255         byte[] pidValue = new byte[pid.length + PORTID_SUB_TYPE.length];
256
257         System.arraycopy(PORTID_SUB_TYPE, 0, pidValue, 0, PORTID_SUB_TYPE.length);
258         System.arraycopy(pid, 0, pidValue, PORTID_SUB_TYPE.length, pid.length);
259
260         return pidValue;
261     }
262
263     /**
264      * Creates the custom TLV value including OUI, subtype and custom string.
265      *
266      * @param customString
267      *            port identifier string
268      * @return the custom TLV value in byte array
269      * @see #createCustomTLVValue(byte[],byte[])
270      */
271     public static byte[] createCustomTLVValue(final String customString) {
272         byte[] customByteArray = customString.getBytes(Charset.defaultCharset());
273         return createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID, customByteArray);
274     }
275
276     /**
277      * Creates the custom TLV value including OUI, subtype and custom string.
278      *
279      * @param subtype openflow subtype
280      * @param customByteArray
281      *            port identifier string
282      * @return the custom TLV value in byte array
283      */
284     public static byte[] createCustomTLVValue(final byte[] subtype, final byte[] customByteArray) {
285         byte[] customValue = new byte[CUSTOM_TLV_OFFSET + customByteArray.length];
286
287         System.arraycopy(OFOUI, 0, customValue, 0, OFOUI.length);
288         System.arraycopy(subtype, 0, customValue, OFOUI.length, 1);
289         System.arraycopy(customByteArray, 0, customValue, CUSTOM_TLV_OFFSET,
290                 customByteArray.length);
291
292         return customValue;
293     }
294
295     /**
296      * Creates a custom TLV value including OUI of sub type custom sec and custom bytes value.
297      *
298      * @param customValue the custom value
299      * @return the custom TLV value in byte array
300      */
301     public static byte[] createSecSubTypeCustomTLVValue(final byte[] customValue) {
302         return createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC, customValue);
303     }
304
305     /**
306      * Retrieves the string from TLV value and returns it in HexString format.
307      *
308      * @param tlvValue
309      *            the TLV value
310      * @param tlvLen
311      *            the TLV length
312      * @return the HexString
313      */
314     public static String getHexStringValue(final byte[] tlvValue, final int tlvLen) {
315         byte[] cidBytes = new byte[tlvLen - CHASSISID_SUB_TYPE.length];
316         System.arraycopy(tlvValue, CHASSISID_SUB_TYPE.length, cidBytes, 0,
317                 cidBytes.length);
318         return HexEncode.bytesToHexStringFormat(cidBytes);
319     }
320
321     /**
322      * Retrieves the string from TLV value.
323      *
324      * @param tlvValue
325      *            the TLV value
326      * @param tlvLen
327      *            the TLV length
328      * @return the string
329      */
330     public static String getStringValue(final byte[] tlvValue, final int tlvLen) {
331         byte[] pidSubType = new byte[PORTID_SUB_TYPE.length];
332         byte[] pidBytes = new byte[tlvLen - PORTID_SUB_TYPE.length];
333         System.arraycopy(tlvValue, 0, pidSubType, 0,
334                 pidSubType.length);
335         System.arraycopy(tlvValue, PORTID_SUB_TYPE.length, pidBytes, 0,
336                 pidBytes.length);
337         if (pidSubType[0] == (byte) 0x3) {
338             return HexEncode.bytesToHexStringFormat(pidBytes);
339         } else {
340             return new String(pidBytes, Charset.defaultCharset());
341         }
342     }
343
344     /**
345      * Retrieves the custom string from the Custom TLV value which includes OUI, subtype and custom string.
346      *
347      * @param customTlvValue
348      *            the custom TLV value
349      * @param customTlvLen
350      *            the custom TLV length
351      * @return the custom string
352      */
353     public static String getCustomString(final byte[] customTlvValue, final int customTlvLen) {
354         String customString = "";
355         byte[] vendor = new byte[3];
356         System.arraycopy(customTlvValue, 0, vendor, 0, vendor.length);
357         if (Arrays.equals(vendor, LLDPTLV.OFOUI)) {
358             int customArrayLength = customTlvLen - CUSTOM_TLV_OFFSET;
359             byte[] customArray = new byte[customArrayLength];
360             System.arraycopy(customTlvValue, CUSTOM_TLV_OFFSET, customArray, 0, customArrayLength);
361             try {
362                 customString = new String(customArray, "UTF-8");
363             } catch (final UnsupportedEncodingException e) {
364                 LOG.warn("Error creating string from the custom TLV value: {}", Arrays.toString(customTlvValue), e);
365             }
366         }
367
368         return customString;
369     }
370
371     public static int extractCustomOUI(final LLDPTLV lldptlv) {
372         byte[] value = lldptlv.getValue();
373         return BitBufferHelper.getInt(ArrayUtils.subarray(value, 0, 3));
374     }
375
376     public static byte extractCustomSubtype(final LLDPTLV lldptlv) {
377         byte[] value = lldptlv.getValue();
378         return BitBufferHelper.getByte(ArrayUtils.subarray(value, 3, 4));
379     }
380
381     public static CustomTLVKey createPortSubTypeCustomTLVKey() throws BufferException {
382         return new CustomTLVKey(BitBufferHelper.getInt(OFOUI), CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID[0]);
383     }
384
385     public static CustomTLVKey createSecSubTypeCustomTLVKey() throws BufferException {
386         return new CustomTLVKey(BitBufferHelper.getInt(LLDPTLV.OFOUI), LLDPTLV.CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC[0]);
387     }
388 }