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;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
20 * Class that represents the LLDP frame objects.
22 public class LLDP extends Packet {
23 private static final Logger LOG = LoggerFactory.getLogger(LLDP.class);
24 private static final String CHASSISID = "ChassisId";
25 private static final String SYSTEMNAMEID = "SystemNameID";
26 private static final String PORTID = "PortId";
27 private static final String TTL = "TTL";
28 private static final int LLDP_DEFAULT_TLVS = 3;
29 private static final LLDPTLV EMPTY_TLV = new LLDPTLV().setLength((short) 0).setType((byte) 0);
30 @SuppressFBWarnings("MS_PKGPROTECT")
31 public static final byte[] LLDP_MULTICAST_MAC = { 1, (byte) 0x80, (byte) 0xc2, 0, 0, (byte) 0xe };
33 private Map<Byte, LLDPTLV> mandatoryTLVs;
34 private Map<Byte, LLDPTLV> optionalTLVs;
35 private Map<CustomTLVKey, LLDPTLV> customTLVs;
38 * Default constructor that creates the tlvList LinkedHashMap.
45 * Constructor that creates the tlvList LinkedHashMap and sets the write access for the same.
47 public LLDP(final boolean writeAccess) {
53 mandatoryTLVs = new LinkedHashMap<>(LLDP_DEFAULT_TLVS);
54 optionalTLVs = new LinkedHashMap<>();
55 customTLVs = new LinkedHashMap<>();
59 * Returns the TLV byte type.
61 * @param typeDesc description of the type of TLV
62 * @return byte type of TLV
64 private byte getType(final String typeDesc) {
67 return LLDPTLV.TLVType.ChassisID.getValue();
69 return LLDPTLV.TLVType.PortID.getValue();
71 return LLDPTLV.TLVType.TTL.getValue();
73 return LLDPTLV.TLVType.SystemName.getValue();
75 return LLDPTLV.TLVType.Unknown.getValue();
79 private LLDPTLV getFromTLVs(final Byte type) {
81 tlv = mandatoryTLVs.get(type);
83 tlv = optionalTLVs.get(type);
88 private void putToTLVs(final Byte type, final LLDPTLV tlv) {
89 if (type == LLDPTLV.TLVType.ChassisID.getValue() || type == LLDPTLV.TLVType.PortID.getValue()
90 || type == LLDPTLV.TLVType.TTL.getValue()) {
91 mandatoryTLVs.put(type, tlv);
92 } else if (type != LLDPTLV.TLVType.Custom.getValue()) {
93 optionalTLVs.put(type, tlv);
98 * Gets the full LLDPTLV.
100 * @param type description of the type of TLV
101 * @return LLDPTLV - full TLV
103 public LLDPTLV getTLV(final String type) {
104 return getFromTLVs(getType(type));
107 public LLDPTLV getCustomTLV(final CustomTLVKey key) {
108 return customTLVs.get(key);
112 * Sets the LLDPTLV for a type.
114 * @param type description of the type of TLV
115 * @param tlv tlv to set
117 public void setTLV(final String type, final LLDPTLV tlv) {
118 putToTLVs(getType(type), tlv);
122 * Returns the chassisId TLV.
124 public LLDPTLV getChassisId() {
125 return getTLV(CHASSISID);
128 public LLDP setChassisId(final LLDPTLV chassisId) {
129 setTLV(CHASSISID, chassisId);
134 * Returns the SystemName TLV.
136 public LLDPTLV getSystemNameId() {
137 return getTLV(SYSTEMNAMEID);
140 public LLDP setSystemNameId(final LLDPTLV systemNameId) {
141 setTLV(SYSTEMNAMEID, systemNameId);
146 * Returns the portId TLV.
148 public LLDPTLV getPortId() {
149 return getTLV(PORTID);
152 public LLDP setPortId(final LLDPTLV portId) {
153 setTLV(PORTID, portId);
158 * Return the ttl TLV.
160 public LLDPTLV getTtl() {
164 public LLDP setTtl(final LLDPTLV ttl) {
170 * Returns the optionalTLVList.
172 public Iterable<LLDPTLV> getOptionalTLVList() {
173 return optionalTLVs.values();
177 * Returns the customTlvList.
179 public Iterable<LLDPTLV> getCustomTlvList() {
180 return customTLVs.values();
183 public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) {
184 for (LLDPTLV tlv : optionalTLVList) {
185 optionalTLVs.put(tlv.getType(), tlv);
190 public LLDP addCustomTLV(final LLDPTLV customTLV) {
191 CustomTLVKey key = new CustomTLVKey(LLDPTLV.extractCustomOUI(customTLV),
192 LLDPTLV.extractCustomSubtype(customTLV));
193 customTLVs.put(key, customTLV);
199 public Packet deserialize(final byte[] data, final int bitOffset, final int size) throws PacketException {
200 int lldpOffset = bitOffset; // LLDP start
201 int lldpSize = size; // LLDP size
203 if (LOG.isTraceEnabled()) {
204 LOG.trace("LLDP: {} (offset {} bitsize {})", HexEncode.bytesToHexString(data), lldpOffset, lldpSize);
207 * Deserialize the TLVs until we reach the end of the packet
209 while (lldpSize > 0) {
210 LLDPTLV tlv = new LLDPTLV();
211 tlv.deserialize(data, lldpOffset, lldpSize);
212 if (tlv.getType() == 0 && tlv.getLength() == 0) {
215 int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
216 lldpOffset += tlvSize;
218 if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
221 this.putToTLVs(tlv.getType(), tlv);
228 public byte[] serialize() throws PacketException {
230 byte[] serializedBytes = new byte[getLLDPPacketLength()];
232 final Iterable<LLDPTLV> allTlvs = Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(),
233 customTLVs.values());
234 for (LLDPTLV tlv : allTlvs) {
235 int numBits = tlv.getTLVSize();
237 BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), startOffset, numBits);
238 } catch (final BufferException e) {
239 throw new PacketException("Error from setBytes", e);
241 startOffset += numBits;
243 // Now add the empty LLDPTLV at the end
245 BitBufferHelper.setBytes(serializedBytes, LLDP.EMPTY_TLV.serialize(), startOffset,
246 LLDP.EMPTY_TLV.getTLVSize());
247 } catch (final BufferException e) {
248 throw new PacketException("Error from setBytes", e);
251 if (LOG.isTraceEnabled()) {
252 LOG.trace("LLDP: serialized: {}", HexEncode.bytesToHexString(serializedBytes));
254 return serializedBytes;
258 * Returns the size of LLDP packet in bytes.
260 * @return int - LLDP Packet size in bytes
262 private int getLLDPPacketLength() {
265 for (LLDPTLV lldptlv : Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values())) {
266 len += lldptlv.getTLVSize();
269 len += LLDP.EMPTY_TLV.getTLVSize();
271 return len / NetUtils.NUM_BITS_IN_A_BYTE;