/* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.controller.liblldp; import com.google.common.collect.Iterables; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Class that represents the LLDP frame objects */ public class LLDP extends Packet { private static final String CHASSISID = "ChassisId"; private static final String SYSTEMNAMEID = "SystemNameID"; private static final String PORTID = "PortId"; private static final String TTL = "TTL"; private static final int LLDPDefaultTlvs = 3; private static final LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0).setType((byte) 0); public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80, (byte) 0xc2, 0, 0, (byte) 0xe }; private Map mandatoryTLVs; private Map optionalTLVs; private Map customTLVs; /** * Default constructor that creates the tlvList LinkedHashMap */ public LLDP() { super(); init(); } /** * Constructor that creates the tlvList LinkedHashMap and sets the write access for the same */ public LLDP(final boolean writeAccess) { super(writeAccess); init(); } private void init() { mandatoryTLVs = new LinkedHashMap<>(LLDPDefaultTlvs); optionalTLVs = new LinkedHashMap<>(); customTLVs = new LinkedHashMap<>(); } /** * @param String * - description of the type of TLV * @return byte - type of TLV */ private byte getType(final String typeDesc) { if (typeDesc.equals(CHASSISID)) { return LLDPTLV.TLVType.ChassisID.getValue(); } else if (typeDesc.equals(PORTID)) { return LLDPTLV.TLVType.PortID.getValue(); } else if (typeDesc.equals(TTL)) { return LLDPTLV.TLVType.TTL.getValue(); } else if (typeDesc.equals(SYSTEMNAMEID)) { return LLDPTLV.TLVType.SystemName.getValue(); } else { return LLDPTLV.TLVType.Unknown.getValue(); } } private LLDPTLV getFromTLVs(final Byte type) { LLDPTLV tlv = null; tlv = mandatoryTLVs.get(type); if (tlv == null) { tlv = optionalTLVs.get(type); } return tlv; } private void putToTLVs(final Byte type, final LLDPTLV tlv) { if (type == LLDPTLV.TLVType.ChassisID.getValue() || type == LLDPTLV.TLVType.PortID.getValue() || type == LLDPTLV.TLVType.TTL.getValue()) { mandatoryTLVs.put(type, tlv); } else if (type != LLDPTLV.TLVType.Custom.getValue()) { optionalTLVs.put(type, tlv); } } /** * @param type * - description of the type of TLV * @return LLDPTLV - full TLV */ public LLDPTLV getTLV(final String type) { return getFromTLVs(getType(type)); } public LLDPTLV getCustomTLV(final CustomTLVKey key) { return customTLVs.get(key); } /** * @param type * - description of the type of TLV * @param tlv * - tlv to set */ public void setTLV(final String type, final LLDPTLV tlv) { putToTLVs(getType(type), tlv); } /** * @return the chassisId TLV */ public LLDPTLV getChassisId() { return getTLV(CHASSISID); } /** * @param chassisId * - the chassisId to set */ public LLDP setChassisId(final LLDPTLV chassisId) { setTLV(CHASSISID, chassisId); return this; } /** * @return the SystemName TLV */ public LLDPTLV getSystemNameId() { return getTLV(SYSTEMNAMEID); } /** * @param systemNameId * - the systemNameId to set */ public LLDP setSystemNameId(final LLDPTLV systemNameId) { setTLV(SYSTEMNAMEID, systemNameId); return this; } /** * @return LLDPTLV - the portId TLV */ public LLDPTLV getPortId() { return getTLV(PORTID); } /** * @param portId * - the portId to set * @return LLDP */ public LLDP setPortId(final LLDPTLV portId) { setTLV(PORTID, portId); return this; } /** * @return LLDPTLV - the ttl TLV */ public LLDPTLV getTtl() { return getTLV(TTL); } /** * @param ttl * - the ttl to set * @return LLDP */ public LLDP setTtl(final LLDPTLV ttl) { setTLV(TTL, ttl); return this; } /** * @return the optionalTLVList */ public Iterable getOptionalTLVList() { return optionalTLVs.values(); } /** * @return the customTlvList */ public Iterable getCustomTlvList() { return customTLVs.values(); } /** * @param optionalTLVList * the optionalTLVList to set * @return LLDP */ public LLDP setOptionalTLVList(final List optionalTLVList) { for (LLDPTLV tlv : optionalTLVList) { optionalTLVs.put(tlv.getType(), tlv); } return this; } /** * @param customTLV * the list of custom TLVs to set * @return this LLDP */ public LLDP addCustomTLV(final LLDPTLV customTLV) { CustomTLVKey key = new CustomTLVKey(LLDPTLV.extractCustomOUI(customTLV), LLDPTLV.extractCustomSubtype(customTLV)); customTLVs.put(key, customTLV); return this; } @Override public Packet deserialize(final byte[] data, final int bitOffset, final int size) throws PacketException { int lldpOffset = bitOffset; // LLDP start int lldpSize = size; // LLDP size if (LOG.isTraceEnabled()) { LOG.trace("LLDP: {} (offset {} bitsize {})", new Object[] { HexEncode.bytesToHexString(data), lldpOffset, lldpSize }); } /* * Deserialize the TLVs until we reach the end of the packet */ while (lldpSize > 0) { LLDPTLV tlv = new LLDPTLV(); tlv.deserialize(data, lldpOffset, lldpSize); if (tlv.getType() == 0 && tlv.getLength() == 0) { break; } int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits lldpOffset += tlvSize; lldpSize -= tlvSize; if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) { addCustomTLV(tlv); } else { this.putToTLVs(tlv.getType(), tlv); } } return this; } @Override public byte[] serialize() throws PacketException { int startOffset = 0; byte[] serializedBytes = new byte[getLLDPPacketLength()]; final Iterable allTlvs = Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values()); for (LLDPTLV tlv : allTlvs) { int numBits = tlv.getTLVSize(); try { BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), startOffset, numBits); } catch (final BufferException e) { throw new PacketException(e.getMessage()); } startOffset += numBits; } // Now add the empty LLDPTLV at the end try { BitBufferHelper.setBytes(serializedBytes, LLDP.emptyTLV.serialize(), startOffset, LLDP.emptyTLV.getTLVSize()); } catch (final BufferException e) { throw new PacketException(e.getMessage()); } if (LOG.isTraceEnabled()) { LOG.trace("LLDP: serialized: {}", HexEncode.bytesToHexString(serializedBytes)); } return serializedBytes; } /** * Returns the size of LLDP packet in bytes * * @return int - LLDP Packet size in bytes */ private int getLLDPPacketLength() { int len = 0; for (LLDPTLV lldptlv : Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values())) { len += lldptlv.getTLVSize(); } len += LLDP.emptyTLV.getTLVSize(); return len / NetUtils.NumBitsInAByte; } }