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 com.google.common.collect.Iterables;
12 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
13 import java.util.LinkedHashMap;
14 import java.util.List;
18 * Class that represents the LLDP frame objects.
20 public class LLDP extends Packet {
21 private static final String CHASSISID = "ChassisId";
22 private static final String SYSTEMNAMEID = "SystemNameID";
23 private static final String PORTID = "PortId";
24 private static final String TTL = "TTL";
25 private static final int LLDP_DEFAULT_TLVS = 3;
26 private static final LLDPTLV EMPTY_TLV = new LLDPTLV().setLength((short) 0).setType((byte) 0);
27 @SuppressFBWarnings("MS_PKGPROTECT")
28 public static final byte[] LLDP_MULTICAST_MAC = { 1, (byte) 0x80, (byte) 0xc2, 0, 0, (byte) 0xe };
30 private Map<Byte, LLDPTLV> mandatoryTLVs;
31 private Map<Byte, LLDPTLV> optionalTLVs;
32 private Map<CustomTLVKey, LLDPTLV> customTLVs;
35 * Default constructor that creates the tlvList LinkedHashMap.
42 * Constructor that creates the tlvList LinkedHashMap and sets the write access for the same.
44 public LLDP(final boolean writeAccess) {
50 mandatoryTLVs = new LinkedHashMap<>(LLDP_DEFAULT_TLVS);
51 optionalTLVs = new LinkedHashMap<>();
52 customTLVs = new LinkedHashMap<>();
56 * Returns the TLV byte type.
58 * @param typeDesc description of the type of TLV
59 * @return byte type of TLV
61 private byte getType(final String typeDesc) {
64 return LLDPTLV.TLVType.ChassisID.getValue();
66 return LLDPTLV.TLVType.PortID.getValue();
68 return LLDPTLV.TLVType.TTL.getValue();
70 return LLDPTLV.TLVType.SystemName.getValue();
72 return LLDPTLV.TLVType.Unknown.getValue();
76 private LLDPTLV getFromTLVs(final Byte type) {
78 tlv = mandatoryTLVs.get(type);
80 tlv = optionalTLVs.get(type);
85 private void putToTLVs(final Byte type, final LLDPTLV tlv) {
86 if (type == LLDPTLV.TLVType.ChassisID.getValue() || type == LLDPTLV.TLVType.PortID.getValue()
87 || type == LLDPTLV.TLVType.TTL.getValue()) {
88 mandatoryTLVs.put(type, tlv);
89 } else if (type != LLDPTLV.TLVType.Custom.getValue()) {
90 optionalTLVs.put(type, tlv);
95 * Gets the full LLDPTLV.
97 * @param type description of the type of TLV
98 * @return LLDPTLV - full TLV
100 public LLDPTLV getTLV(final String type) {
101 return getFromTLVs(getType(type));
104 public LLDPTLV getCustomTLV(final CustomTLVKey key) {
105 return customTLVs.get(key);
109 * Sets the LLDPTLV for a type.
111 * @param type description of the type of TLV
112 * @param tlv tlv to set
114 public void setTLV(final String type, final LLDPTLV tlv) {
115 putToTLVs(getType(type), tlv);
119 * Returns the chassisId TLV.
121 public LLDPTLV getChassisId() {
122 return getTLV(CHASSISID);
125 public LLDP setChassisId(final LLDPTLV chassisId) {
126 setTLV(CHASSISID, chassisId);
131 * Returns the SystemName TLV.
133 public LLDPTLV getSystemNameId() {
134 return getTLV(SYSTEMNAMEID);
137 public LLDP setSystemNameId(final LLDPTLV systemNameId) {
138 setTLV(SYSTEMNAMEID, systemNameId);
143 * Returns the portId TLV.
145 public LLDPTLV getPortId() {
146 return getTLV(PORTID);
149 public LLDP setPortId(final LLDPTLV portId) {
150 setTLV(PORTID, portId);
155 * Return the ttl TLV.
157 public LLDPTLV getTtl() {
161 public LLDP setTtl(final LLDPTLV ttl) {
167 * Returns the optionalTLVList.
169 public Iterable<LLDPTLV> getOptionalTLVList() {
170 return optionalTLVs.values();
174 * Returns the customTlvList.
176 public Iterable<LLDPTLV> getCustomTlvList() {
177 return customTLVs.values();
180 public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) {
181 for (LLDPTLV tlv : optionalTLVList) {
182 optionalTLVs.put(tlv.getType(), tlv);
187 public LLDP addCustomTLV(final LLDPTLV customTLV) {
188 CustomTLVKey key = new CustomTLVKey(LLDPTLV.extractCustomOUI(customTLV),
189 LLDPTLV.extractCustomSubtype(customTLV));
190 customTLVs.put(key, customTLV);
196 public Packet deserialize(final byte[] data, final int bitOffset, final int size) throws PacketException {
197 int lldpOffset = bitOffset; // LLDP start
198 int lldpSize = size; // LLDP size
200 if (LOG.isTraceEnabled()) {
201 LOG.trace("LLDP: {} (offset {} bitsize {})", HexEncode.bytesToHexString(data), lldpOffset, lldpSize);
204 * Deserialize the TLVs until we reach the end of the packet
206 while (lldpSize > 0) {
207 LLDPTLV tlv = new LLDPTLV();
208 tlv.deserialize(data, lldpOffset, lldpSize);
209 if (tlv.getType() == 0 && tlv.getLength() == 0) {
212 int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
213 lldpOffset += tlvSize;
215 if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
218 this.putToTLVs(tlv.getType(), tlv);
225 public byte[] serialize() throws PacketException {
227 byte[] serializedBytes = new byte[getLLDPPacketLength()];
229 final Iterable<LLDPTLV> allTlvs = Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(),
230 customTLVs.values());
231 for (LLDPTLV tlv : allTlvs) {
232 int numBits = tlv.getTLVSize();
234 BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), startOffset, numBits);
235 } catch (final BufferException e) {
236 throw new PacketException("Error from setBytes", e);
238 startOffset += numBits;
240 // Now add the empty LLDPTLV at the end
242 BitBufferHelper.setBytes(serializedBytes, LLDP.EMPTY_TLV.serialize(), startOffset,
243 LLDP.EMPTY_TLV.getTLVSize());
244 } catch (final BufferException e) {
245 throw new PacketException("Error from setBytes", e);
248 if (LOG.isTraceEnabled()) {
249 LOG.trace("LLDP: serialized: {}", HexEncode.bytesToHexString(serializedBytes));
251 return serializedBytes;
255 * Returns the size of LLDP packet in bytes.
257 * @return int - LLDP Packet size in bytes
259 private int getLLDPPacketLength() {
262 for (LLDPTLV lldptlv : Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values())) {
263 len += lldptlv.getTLVSize();
266 len += LLDP.EMPTY_TLV.getTLVSize();
268 return len / NetUtils.NUM_BITS_IN_A_BYTE;