Minor changes in LibLLDP
[controller.git] / opendaylight / commons / liblldp / src / main / java / org / opendaylight / controller / liblldp / LLDP.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.liblldp;
10
11 import com.google.common.collect.Iterables;
12 import java.util.LinkedHashMap;
13 import java.util.List;
14 import java.util.Map;
15
16 /**
17  * Class that represents the LLDP frame objects
18  */
19
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 LLDPDefaultTlvs = 3;
26     private static final LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0).setType((byte) 0);
27     public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80, (byte) 0xc2, 0, 0, (byte) 0xe };
28
29     private Map<Byte, LLDPTLV> mandatoryTLVs;
30     private Map<Byte, LLDPTLV> optionalTLVs;
31     private Map<CustomTLVKey, LLDPTLV> customTLVs;
32
33     /**
34      * Default constructor that creates the tlvList LinkedHashMap
35      */
36     public LLDP() {
37         super();
38         init();
39     }
40
41     /**
42      * Constructor that creates the tlvList LinkedHashMap and sets the write access for the same
43      */
44     public LLDP(boolean writeAccess) {
45         super(writeAccess);
46         init();
47     }
48
49     private void init() {
50         mandatoryTLVs = new LinkedHashMap<>(LLDPDefaultTlvs);
51         optionalTLVs = new LinkedHashMap<>();
52         customTLVs = new LinkedHashMap<>();
53     }
54
55     /**
56      * @param String
57      *            - description of the type of TLV
58      * @return byte - type of TLV
59      */
60     private byte getType(String typeDesc) {
61         if (typeDesc.equals(CHASSISID)) {
62             return LLDPTLV.TLVType.ChassisID.getValue();
63         } else if (typeDesc.equals(PORTID)) {
64             return LLDPTLV.TLVType.PortID.getValue();
65         } else if (typeDesc.equals(TTL)) {
66             return LLDPTLV.TLVType.TTL.getValue();
67         } else if (typeDesc.equals(SYSTEMNAMEID)) {
68             return LLDPTLV.TLVType.SystemName.getValue();
69         } else {
70             return LLDPTLV.TLVType.Unknown.getValue();
71         }
72     }
73
74     private LLDPTLV getFromTLVs(Byte type) {
75         LLDPTLV tlv = null;
76         tlv = mandatoryTLVs.get(type);
77         if (tlv == null) {
78             tlv = optionalTLVs.get(type);
79         }
80         return tlv;
81     }
82
83     private void putToTLVs(final Byte type, final LLDPTLV tlv) {
84         if (type == LLDPTLV.TLVType.ChassisID.getValue() || type == LLDPTLV.TLVType.PortID.getValue()
85                 || type == LLDPTLV.TLVType.TTL.getValue()) {
86             mandatoryTLVs.put(type, tlv);
87         } else if (type != LLDPTLV.TLVType.Custom.getValue()) {
88             optionalTLVs.put(type, tlv);
89         }
90     }
91
92     /**
93      * @param String
94      *            - description of the type of TLV
95      * @return LLDPTLV - full TLV
96      */
97     public LLDPTLV getTLV(String type) {
98         return getFromTLVs(getType(type));
99     }
100
101     public LLDPTLV getCustomTLV(CustomTLVKey key) {
102         return customTLVs.get(key);
103     }
104
105     /**
106      * @param String
107      *            - description of the type of TLV
108      * @param LLDPTLV
109      *            - tlv to set
110      * @return void
111      */
112     public void setTLV(String type, LLDPTLV tlv) {
113         putToTLVs(getType(type), tlv);
114     }
115
116     /**
117      * @return the chassisId TLV
118      */
119     public LLDPTLV getChassisId() {
120         return getTLV(CHASSISID);
121     }
122
123     /**
124      * @param LLDPTLV
125      *            - the chassisId to set
126      */
127     public LLDP setChassisId(LLDPTLV chassisId) {
128         setTLV(CHASSISID, chassisId);
129         return this;
130     }
131
132     /**
133      * @return the SystemName TLV
134      */
135     public LLDPTLV getSystemNameId() {
136         return getTLV(SYSTEMNAMEID);
137     }
138
139     /**
140      * @param LLDPTLV
141      *            - the chassisId to set
142      */
143     public LLDP setSystemNameId(LLDPTLV systemNameId) {
144         setTLV(SYSTEMNAMEID, systemNameId);
145         return this;
146     }
147
148     /**
149      * @return LLDPTLV - the portId TLV
150      */
151     public LLDPTLV getPortId() {
152         return getTLV(PORTID);
153     }
154
155     /**
156      * @param LLDPTLV
157      *            - the portId to set
158      * @return LLDP
159      */
160     public LLDP setPortId(LLDPTLV portId) {
161         setTLV(PORTID, portId);
162         return this;
163     }
164
165     /**
166      * @return LLDPTLV - the ttl TLV
167      */
168     public LLDPTLV getTtl() {
169         return getTLV(TTL);
170     }
171
172     /**
173      * @param LLDPTLV
174      *            - the ttl to set
175      * @return LLDP
176      */
177     public LLDP setTtl(LLDPTLV ttl) {
178         setTLV(TTL, ttl);
179         return this;
180     }
181
182     /**
183      * @return the optionalTLVList
184      */
185     public Iterable<LLDPTLV> getOptionalTLVList() {
186         return optionalTLVs.values();
187     }
188
189     /**
190      * @return the customTlvList
191      */
192     public Iterable<LLDPTLV> getCustomTlvList() {
193         return customTLVs.values();
194     }
195
196     /**
197      * @param optionalTLVList
198      *            the optionalTLVList to set
199      * @return LLDP
200      */
201     public LLDP setOptionalTLVList(List<LLDPTLV> optionalTLVList) {
202         for (LLDPTLV tlv : optionalTLVList) {
203             optionalTLVs.put(tlv.getType(), tlv);
204         }
205         return this;
206     }
207
208     /**
209      * @param customTLVList
210      *            the list of custom TLVs to set
211      * @return this LLDP
212      */
213     public LLDP addCustomTLV(final LLDPTLV customTLV) {
214         CustomTLVKey key = new CustomTLVKey(LLDPTLV.extractCustomOUI(customTLV),
215                 LLDPTLV.extractCustomSubtype(customTLV));
216         customTLVs.put(key, customTLV);
217
218         return this;
219     }
220
221     @Override
222     public Packet deserialize(byte[] data, int bitOffset, int size) throws PacketException {
223         int lldpOffset = bitOffset; // LLDP start
224         int lldpSize = size; // LLDP size
225
226         if (logger.isTraceEnabled()) {
227             logger.trace("LLDP: {} (offset {} bitsize {})", new Object[] { HexEncode.bytesToHexString(data),
228                     lldpOffset, lldpSize });
229         }
230         /*
231          * Deserialize the TLVs until we reach the end of the packet
232          */
233         while (lldpSize > 0) {
234             LLDPTLV tlv = new LLDPTLV();
235             tlv.deserialize(data, lldpOffset, lldpSize);
236             if (tlv.getType() == 0 && tlv.getLength() == 0) {
237                 break;
238             }
239             int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
240             lldpOffset += tlvSize;
241             lldpSize -= tlvSize;
242             if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
243                 addCustomTLV(tlv);
244             } else {
245                 this.putToTLVs(tlv.getType(), tlv);
246             }
247         }
248         return this;
249     }
250
251     @Override
252     public byte[] serialize() throws PacketException {
253         int startOffset = 0;
254         byte[] serializedBytes = new byte[getLLDPPacketLength()];
255
256         final Iterable<LLDPTLV> allTlvs = Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values());
257         for (LLDPTLV tlv : allTlvs) {
258             int numBits = tlv.getTLVSize();
259             try {
260                 BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), startOffset, numBits);
261             } catch (BufferException e) {
262                 throw new PacketException(e.getMessage());
263             }
264             startOffset += numBits;
265         }
266         // Now add the empty LLDPTLV at the end
267         try {
268             BitBufferHelper.setBytes(serializedBytes, LLDP.emptyTLV.serialize(), startOffset,
269                     LLDP.emptyTLV.getTLVSize());
270         } catch (BufferException e) {
271             throw new PacketException(e.getMessage());
272         }
273
274         if (logger.isTraceEnabled()) {
275             logger.trace("LLDP: serialized: {}", HexEncode.bytesToHexString(serializedBytes));
276         }
277         return serializedBytes;
278     }
279
280     /**
281      * Returns the size of LLDP packet in bytes
282      *
283      * @return int - LLDP Packet size in bytes
284      */
285     private int getLLDPPacketLength() {
286         int len = 0;
287
288         for (LLDPTLV lldptlv : Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values())) {
289             len += lldptlv.getTLVSize();
290         }
291
292         len += LLDP.emptyTLV.getTLVSize();
293
294         return len / NetUtils.NumBitsInAByte;
295     }
296 }