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
8 package org.opendaylight.openflowplugin.libraries.liblldp;
10 import com.google.common.collect.Iterables;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.util.LinkedHashMap;
13 import java.util.List;
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
19 * Class that represents the LLDP frame objects.
21 public class LLDP extends Packet {
22 private static final Logger LOG = LoggerFactory.getLogger(LLDP.class);
23 private static final String CHASSISID = "ChassisId";
24 private static final String SYSTEMNAMEID = "SystemNameID";
25 private static final String PORTID = "PortId";
26 private static final String TTL = "TTL";
27 private static final String SYSTEMDESC = "SystemDesc";
28 private static final String PORTDESC = "PortDesc";
29 private static final String SYSTEMCAPABILITIES = "SystemCapabilities";
30 private static final String MANAGEMENTADDRESS = "ManagementAddress";
31 private static final int LLDP_DEFAULT_TLVS = 3;
32 private static final LLDPTLV EMPTY_TLV = new LLDPTLV().setLength((short) 0).setType((byte) 0);
33 @SuppressFBWarnings("MS_PKGPROTECT")
34 public static final byte[] LLDP_MULTICAST_MAC = { 1, (byte) 0x80, (byte) 0xc2, 0, 0, (byte) 0xe };
36 private final Map<Byte, LLDPTLV> mandatoryTLVs = new LinkedHashMap<>(LLDP_DEFAULT_TLVS);
37 private final Map<Byte, LLDPTLV> optionalTLVs = new LinkedHashMap<>();
38 private final Map<CustomTLVKey, LLDPTLV> customTLVs = new LinkedHashMap<>();
41 * Default constructor that creates the tlvList LinkedHashMap.
48 * Constructor that creates the tlvList LinkedHashMap and sets the write access for the same.
50 public LLDP(final boolean writeAccess) {
55 * Returns the TLV byte type.
57 * @param typeDesc description of the type of TLV
58 * @return byte type of TLV
60 private static byte getType(final String typeDesc) {
63 return LLDPTLV.TLVType.ChassisID.getValue();
65 return LLDPTLV.TLVType.PortID.getValue();
67 return LLDPTLV.TLVType.TTL.getValue();
69 return LLDPTLV.TLVType.SystemName.getValue();
71 return LLDPTLV.TLVType.SystemDesc.getValue();
73 return LLDPTLV.TLVType.PortDesc.getValue();
74 case SYSTEMCAPABILITIES:
75 return LLDPTLV.TLVType.SystemCapabilities.getValue();
76 case MANAGEMENTADDRESS:
77 return LLDPTLV.TLVType.ManagementAddress.getValue();
79 return LLDPTLV.TLVType.Unknown.getValue();
83 private LLDPTLV getFromTLVs(final Byte type) {
85 tlv = mandatoryTLVs.get(type);
87 tlv = optionalTLVs.get(type);
92 private void putToTLVs(final Byte type, final LLDPTLV tlv) {
93 if (type == LLDPTLV.TLVType.ChassisID.getValue() || type == LLDPTLV.TLVType.PortID.getValue()
94 || type == LLDPTLV.TLVType.TTL.getValue()) {
95 mandatoryTLVs.put(type, tlv);
96 } else if (type != LLDPTLV.TLVType.Custom.getValue()) {
97 optionalTLVs.put(type, tlv);
102 * Gets the full LLDPTLV.
104 * @param type description of the type of TLV
105 * @return LLDPTLV - full TLV
107 public LLDPTLV getTLV(final String type) {
108 return getFromTLVs(getType(type));
111 public LLDPTLV getCustomTLV(final CustomTLVKey key) {
112 return customTLVs.get(key);
116 * Sets the LLDPTLV for a type.
118 * @param type description of the type of TLV
119 * @param tlv tlv to set
121 public void setTLV(final String type, final LLDPTLV tlv) {
122 putToTLVs(getType(type), tlv);
126 * Returns the chassisId TLV.
128 public LLDPTLV getChassisId() {
129 return getTLV(CHASSISID);
132 public LLDP setChassisId(final LLDPTLV chassisId) {
133 setTLV(CHASSISID, chassisId);
138 * Returns the SystemName TLV.
140 public LLDPTLV getSystemNameId() {
141 return getTLV(SYSTEMNAMEID);
144 public LLDP setSystemNameId(final LLDPTLV systemNameId) {
145 setTLV(SYSTEMNAMEID, systemNameId);
150 * Returns the portId TLV.
152 public LLDPTLV getPortId() {
153 return getTLV(PORTID);
156 public LLDP setPortId(final LLDPTLV portId) {
157 setTLV(PORTID, portId);
162 * Return the ttl TLV.
164 public LLDPTLV getTtl() {
168 public LLDP setTtl(final LLDPTLV ttl) {
174 * Return the SystemDesc TLV.
176 public LLDPTLV getSystemDesc() {
177 return getTLV(SYSTEMDESC);
180 public LLDP setSystemDesc(final LLDPTLV systemDesc) {
181 setTLV(SYSTEMDESC, systemDesc);
186 * Return the PortDesc TLV.
188 public LLDPTLV getPortDesc() {
189 return getTLV(PORTDESC);
192 public LLDP setPortDesc(final LLDPTLV portDesc) {
193 setTLV(PORTDESC, portDesc);
198 * Return the SystemCapabilities TLV.
200 public LLDPTLV getSystemCapabilities() {
201 return getTLV(SYSTEMCAPABILITIES);
204 public LLDP setSystemCapabilities(final LLDPTLV systemCapabilities) {
205 setTLV(SYSTEMCAPABILITIES, systemCapabilities);
210 * Return the ManagementAddress TLV.
212 public LLDPTLV getManagementAddress() {
213 return getTLV(MANAGEMENTADDRESS);
216 public LLDP setManagementAddress(final LLDPTLV managementAddress) {
217 setTLV(MANAGEMENTADDRESS, managementAddress);
222 * Returns the optionalTLVList.
224 public Iterable<LLDPTLV> getOptionalTLVList() {
225 return optionalTLVs.values();
229 * Returns the customTlvList.
231 public Iterable<LLDPTLV> getCustomTlvList() {
232 return customTLVs.values();
235 public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) {
236 for (LLDPTLV tlv : optionalTLVList) {
237 optionalTLVs.put(tlv.getType(), tlv);
242 public LLDP addCustomTLV(final LLDPTLV customTLV) {
243 CustomTLVKey key = new CustomTLVKey(LLDPTLV.extractCustomOUI(customTLV),
244 LLDPTLV.extractCustomSubtype(customTLV));
245 customTLVs.put(key, customTLV);
251 public Packet deserialize(final byte[] data, final int bitOffset, final int size) throws PacketException {
252 int lldpOffset = bitOffset; // LLDP start
253 int lldpSize = size; // LLDP size
255 if (LOG.isTraceEnabled()) {
256 LOG.trace("LLDP: {} (offset {} bitsize {})", HexEncode.bytesToHexString(data), lldpOffset, lldpSize);
259 * Deserialize the TLVs until we reach the end of the packet
261 while (lldpSize > 0) {
262 LLDPTLV tlv = new LLDPTLV();
263 tlv.deserialize(data, lldpOffset, lldpSize);
264 if (tlv.getType() == 0 && tlv.getLength() == 0) {
267 int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
268 lldpOffset += tlvSize;
270 if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
273 this.putToTLVs(tlv.getType(), tlv);
280 public byte[] serialize() throws PacketException {
282 byte[] serializedBytes = new byte[getLLDPPacketLength()];
284 final Iterable<LLDPTLV> allTlvs = Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(),
285 customTLVs.values());
286 for (LLDPTLV tlv : allTlvs) {
287 int numBits = tlv.getTLVSize();
289 BitBufferHelper.copyBitsFromLsb(serializedBytes, tlv.serialize(), startOffset, numBits);
290 } catch (final BufferException e) {
291 throw new PacketException("Error from setBytes", e);
293 startOffset += numBits;
295 // Now add the empty LLDPTLV at the end
297 BitBufferHelper.copyBitsFromLsb(serializedBytes, LLDP.EMPTY_TLV.serialize(), startOffset,
298 LLDP.EMPTY_TLV.getTLVSize());
299 } catch (final BufferException e) {
300 throw new PacketException("Error from setBytes", e);
303 if (LOG.isTraceEnabled()) {
304 LOG.trace("LLDP: serialized: {}", HexEncode.bytesToHexString(serializedBytes));
306 return serializedBytes;
310 * Returns the size of LLDP packet in bytes.
312 * @return int - LLDP Packet size in bytes
314 private int getLLDPPacketLength() {
317 for (LLDPTLV lldptlv : Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values())) {
318 len += lldptlv.getTLVSize();
321 len += LLDP.EMPTY_TLV.getTLVSize();
323 return len / NetUtils.NUM_BITS_IN_A_BYTE;