2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.openflowplugin.libraries.liblldp;
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;
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;
25 * Class that represents the LLDPTLV objects.
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;
36 static final byte[] OFOUI = new byte[] { (byte) 0x00, (byte) 0x26, (byte) 0xe1 };
38 /** Length of Organizationally defined subtype field of TLV in bytes. */
39 private static final byte CUSTOM_TLV_SUB_TYPE_LENGTH = (byte)1;
41 /** OpenFlow subtype: nodeConnectorId of source. */
42 private static final byte[] CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID = new byte[] { 0 };
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 };
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
52 Unknown((byte) 0), ChassisID((byte) 1), PortID((byte) 2), TTL((byte) 3), PortDesc(
53 (byte) 4), SystemName((byte) 5), SystemDesc((byte) 6), Custom(
56 private final byte value;
58 TLVType(final byte value) {
62 public byte getValue() {
67 private static final Map<String, Pair<Integer, Integer>> FIELD_COORDINATES = new LinkedHashMap<>();
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));
75 protected Map<String, byte[]> fieldValues;
78 * Default constructor that creates and sets the hash map values and sets the payload to null.
82 fieldValues = new HashMap<>(LLDPTLV_FIELDS);
83 hdrFieldCoordMap = FIELD_COORDINATES;
84 hdrFieldsMap = fieldValues;
88 * Constructor that writes the passed LLDPTLV values to the hdrFieldsMap.
90 public LLDPTLV(final LLDPTLV other) {
91 for (Map.Entry<String, byte[]> entry : other.hdrFieldsMap.entrySet()) {
92 this.hdrFieldsMap.put(entry.getKey(), entry.getValue());
97 * Returns the length of TLV.
99 public int getLength() {
100 return (int) BitBufferHelper.toNumber(fieldValues.get(LENGTH),
101 FIELD_COORDINATES.get(LENGTH).getRight());
105 * Returns the type of TLV.
107 public byte getType() {
108 return BitBufferHelper.getByte(fieldValues.get(TYPE));
112 * Returns the value field of TLV.
114 public byte[] getValue() {
115 return fieldValues.get(VALUE);
121 * @param type the type to set
124 public LLDPTLV setType(final byte type) {
125 byte[] lldpTLVtype = { type };
126 fieldValues.put(TYPE, lldpTLVtype);
133 * @param length the length to set
136 public LLDPTLV setLength(final short length) {
137 fieldValues.put(LENGTH, BitBufferHelper.toByteArray(length));
144 * @param value the value to set
147 public LLDPTLV setValue(final byte[] value) {
148 fieldValues.put(VALUE, value);
153 public void setHeaderField(final String headerField, final byte[] readValue) {
154 hdrFieldsMap.put(headerField, readValue);
158 public int hashCode() {
159 final int prime = 31;
160 int result = super.hashCode();
161 result = prime * result
162 + (fieldValues == null ? 0 : fieldValues.hashCode());
167 public boolean equals(final Object obj) {
171 if (!super.equals(obj)) {
174 if (getClass() != obj.getClass()) {
177 LLDPTLV other = (LLDPTLV) obj;
178 if (fieldValues == null) {
179 if (other.fieldValues != null) {
182 } else if (!fieldValues.equals(other.fieldValues)) {
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());
194 return FIELD_COORDINATES.get(fieldName).getRight();
198 * Returns the size in bits of the whole TLV.
200 * @return int - size in bits of full TLV
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
209 * Creates the SystemName TLV value.
212 * node identifier string
213 * @return the SystemName TLV value in byte array
215 public static byte[] createSystemNameTLVValue(final String nodeId) {
216 return nodeId.getBytes(StandardCharsets.UTF_8);
220 * Creates the ChassisID TLV value including the subtype and ChassisID string.
223 * node identifier string
224 * @return the ChassisID TLV value in byte array
226 public static byte[] createChassisIDTLVValue(final String nodeId) {
227 byte[] nid = HexEncode.bytesFromHexString(nodeId);
228 byte[] cid = new byte[6];
232 if (nid.length > cid.length) {
233 srcPos = nid.length - cid.length;
235 dstPos = cid.length - nid.length;
237 System.arraycopy(nid, srcPos, cid, dstPos, cid.length);
239 byte[] cidValue = new byte[cid.length + CHASSISID_SUB_TYPE.length];
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);
249 * Creates the PortID TLV value including the subtype and PortID string.
252 * port identifier string
253 * @return the PortID TLV value in byte array
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];
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);
266 * Creates the custom TLV value including OUI, subtype and custom string.
268 * @param customString
269 * port identifier string
270 * @return the custom TLV value in byte array
271 * @see #createCustomTLVValue(byte[],byte[])
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);
279 * Creates the custom TLV value including OUI, subtype and custom string.
281 * @param subtype openflow subtype
282 * @param customByteArray
283 * port identifier string
284 * @return the custom TLV value in byte array
286 public static byte[] createCustomTLVValue(final byte[] subtype, final byte[] customByteArray) {
287 byte[] customValue = new byte[CUSTOM_TLV_OFFSET + customByteArray.length];
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);
298 * Creates a custom TLV value including OUI of sub type custom sec and custom bytes value.
300 * @param customValue the custom value
301 * @return the custom TLV value in byte array
303 public static byte[] createSecSubTypeCustomTLVValue(final byte[] customValue) {
304 return createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC, customValue);
308 * Retrieves the string from TLV value and returns it in HexString format.
314 * @return the HexString
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,
320 return HexEncode.bytesToHexStringFormat(cidBytes);
324 * Retrieves the string from TLV value.
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,
337 System.arraycopy(tlvValue, PORTID_SUB_TYPE.length, pidBytes, 0,
339 if (pidSubType[0] == (byte) 0x3) {
340 return HexEncode.bytesToHexStringFormat(pidBytes);
342 return new String(pidBytes, Charset.defaultCharset());
347 * Retrieves the custom string from the Custom TLV value which includes OUI, subtype and custom string.
349 * @param customTlvValue
350 * the custom TLV value
351 * @param customTlvLen
352 * the custom TLV length
353 * @return the custom string
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);
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);
373 public static int extractCustomOUI(final LLDPTLV lldptlv) {
374 byte[] value = lldptlv.getValue();
375 return BitBufferHelper.getInt(ArrayUtils.subarray(value, 0, 3));
378 public static byte extractCustomSubtype(final LLDPTLV lldptlv) {
379 byte[] value = lldptlv.getValue();
380 return BitBufferHelper.getByte(ArrayUtils.subarray(value, 3, 4));
383 public static CustomTLVKey createPortSubTypeCustomTLVKey() throws BufferException {
384 return new CustomTLVKey(BitBufferHelper.getInt(OFOUI), CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID[0]);
387 public static CustomTLVKey createSecSubTypeCustomTLVKey() throws BufferException {
388 return new CustomTLVKey(BitBufferHelper.getInt(LLDPTLV.OFOUI), LLDPTLV.CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC[0]);