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;
23 * Class that represents the LLDPTLV objects.
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;
33 static final byte[] OFOUI = new byte[] { (byte) 0x00, (byte) 0x26, (byte) 0xe1 };
35 /** Length of Organizationally defined subtype field of TLV in bytes. */
36 private static final byte CUSTOM_TLV_SUB_TYPE_LENGTH = (byte)1;
38 /** OpenFlow subtype: nodeConnectorId of source. */
39 private static final byte[] CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID = new byte[] { 0 };
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 };
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
49 Unknown((byte) 0), ChassisID((byte) 1), PortID((byte) 2), TTL((byte) 3), PortDesc(
50 (byte) 4), SystemName((byte) 5), SystemDesc((byte) 6), Custom(
53 private final byte value;
55 TLVType(final byte value) {
59 public byte getValue() {
64 private static final Map<String, Pair<Integer, Integer>> FIELD_COORDINATES = new LinkedHashMap<>();
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));
72 protected Map<String, byte[]> fieldValues;
75 * Default constructor that creates and sets the hash map values and sets the payload to null.
79 fieldValues = new HashMap<>(LLDPTLV_FIELDS);
80 hdrFieldCoordMap = FIELD_COORDINATES;
81 hdrFieldsMap = fieldValues;
85 * Constructor that writes the passed LLDPTLV values to the hdrFieldsMap.
87 public LLDPTLV(final LLDPTLV other) {
88 for (Map.Entry<String, byte[]> entry : other.hdrFieldsMap.entrySet()) {
89 this.hdrFieldsMap.put(entry.getKey(), entry.getValue());
94 * Returns the length of TLV.
96 public int getLength() {
97 return (int) BitBufferHelper.toNumber(fieldValues.get(LENGTH),
98 FIELD_COORDINATES.get(LENGTH).getRight());
102 * Returns the type of TLV.
104 public byte getType() {
105 return BitBufferHelper.getByte(fieldValues.get(TYPE));
109 * Returns the value field of TLV.
111 public byte[] getValue() {
112 return fieldValues.get(VALUE);
118 * @param type the type to set
121 public LLDPTLV setType(final byte type) {
122 byte[] lldpTLVtype = { type };
123 fieldValues.put(TYPE, lldpTLVtype);
130 * @param length the length to set
133 public LLDPTLV setLength(final short length) {
134 fieldValues.put(LENGTH, BitBufferHelper.toByteArray(length));
141 * @param value the value to set
144 public LLDPTLV setValue(final byte[] value) {
145 fieldValues.put(VALUE, value);
150 public void setHeaderField(final String headerField, final byte[] readValue) {
151 hdrFieldsMap.put(headerField, readValue);
155 public int hashCode() {
156 final int prime = 31;
157 int result = super.hashCode();
158 result = prime * result
159 + (fieldValues == null ? 0 : fieldValues.hashCode());
164 public boolean equals(final Object obj) {
168 if (!super.equals(obj)) {
171 if (getClass() != obj.getClass()) {
174 LLDPTLV other = (LLDPTLV) obj;
175 if (fieldValues == null) {
176 if (other.fieldValues != null) {
179 } else if (!fieldValues.equals(other.fieldValues)) {
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());
191 return FIELD_COORDINATES.get(fieldName).getRight();
195 * Returns the size in bits of the whole TLV.
197 * @return int - size in bits of full TLV
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
206 * Creates the SystemName TLV value.
209 * node identifier string
210 * @return the SystemName TLV value in byte array
212 public static byte[] createSystemNameTLVValue(final String nodeId) {
213 return nodeId.getBytes(StandardCharsets.UTF_8);
217 * Creates the ChassisID TLV value including the subtype and ChassisID string.
220 * node identifier string
221 * @return the ChassisID TLV value in byte array
223 public static byte[] createChassisIDTLVValue(final String nodeId) {
224 byte[] nid = HexEncode.bytesFromHexString(nodeId);
225 byte[] cid = new byte[6];
229 if (nid.length > cid.length) {
230 srcPos = nid.length - cid.length;
232 dstPos = cid.length - nid.length;
234 System.arraycopy(nid, srcPos, cid, dstPos, cid.length);
236 byte[] cidValue = new byte[cid.length + CHASSISID_SUB_TYPE.length];
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);
246 * Creates the PortID TLV value including the subtype and PortID string.
249 * port identifier string
250 * @return the PortID TLV value in byte array
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];
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);
263 * Creates the custom TLV value including OUI, subtype and custom string.
265 * @param customString
266 * port identifier string
267 * @return the custom TLV value in byte array
268 * @see #createCustomTLVValue(byte[],byte[])
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);
276 * Creates the custom TLV value including OUI, subtype and custom string.
278 * @param subtype openflow subtype
279 * @param customByteArray
280 * port identifier string
281 * @return the custom TLV value in byte array
283 public static byte[] createCustomTLVValue(final byte[] subtype, final byte[] customByteArray) {
284 byte[] customValue = new byte[CUSTOM_TLV_OFFSET + customByteArray.length];
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);
295 * Creates a custom TLV value including OUI of sub type custom sec and custom bytes value.
297 * @param customValue the custom value
298 * @return the custom TLV value in byte array
300 public static byte[] createSecSubTypeCustomTLVValue(final byte[] customValue) {
301 return createCustomTLVValue(CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC, customValue);
305 * Retrieves the string from TLV value and returns it in HexString format.
311 * @return the HexString
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,
317 return HexEncode.bytesToHexStringFormat(cidBytes);
321 * Retrieves the string from TLV value.
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,
334 System.arraycopy(tlvValue, PORTID_SUB_TYPE.length, pidBytes, 0,
336 if (pidSubType[0] == (byte) 0x3) {
337 return HexEncode.bytesToHexStringFormat(pidBytes);
339 return new String(pidBytes, Charset.defaultCharset());
344 * Retrieves the custom string from the Custom TLV value which includes OUI, subtype and custom string.
346 * @param customTlvValue
347 * the custom TLV value
348 * @param customTlvLen
349 * the custom TLV length
350 * @return the custom string
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);
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);
370 public static int extractCustomOUI(final LLDPTLV lldptlv) {
371 byte[] value = lldptlv.getValue();
372 return BitBufferHelper.getInt(ArrayUtils.subarray(value, 0, 3));
375 public static byte extractCustomSubtype(final LLDPTLV lldptlv) {
376 byte[] value = lldptlv.getValue();
377 return BitBufferHelper.getByte(ArrayUtils.subarray(value, 3, 4));
380 public static CustomTLVKey createPortSubTypeCustomTLVKey() throws BufferException {
381 return new CustomTLVKey(BitBufferHelper.getInt(OFOUI), CUSTOM_TLV_SUB_TYPE_NODE_CONNECTOR_ID[0]);
384 public static CustomTLVKey createSecSubTypeCustomTLVKey() throws BufferException {
385 return new CustomTLVKey(BitBufferHelper.getInt(LLDPTLV.OFOUI), LLDPTLV.CUSTOM_TLV_SUB_TYPE_CUSTOM_SEC[0]);