ca3630b4f3ba80eaedb71a1f456edbcfb0845966
[openflowplugin.git] / libraries / liblldp / src / main / java / org / opendaylight / openflowplugin / libraries / 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.openflowplugin.libraries.liblldp;
10
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;
15 import java.util.Map;
16 import org.slf4j.Logger;
17 import org.slf4j.LoggerFactory;
18
19 /**
20  * Class that represents the LLDP frame objects.
21  */
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 String SYSTEMDESC = "SystemDesc";
29     private static final String PORTDESC = "PortDesc";
30     private static final String SYSTEMCAPABILITIES = "SystemCapabilities";
31     private static final String MANAGEMENTADDRESS = "ManagementAddress";
32     private static final int LLDP_DEFAULT_TLVS = 3;
33     private static final LLDPTLV EMPTY_TLV = new LLDPTLV().setLength((short) 0).setType((byte) 0);
34     @SuppressFBWarnings("MS_PKGPROTECT")
35     public static final byte[] LLDP_MULTICAST_MAC = { 1, (byte) 0x80, (byte) 0xc2, 0, 0, (byte) 0xe };
36
37     private Map<Byte, LLDPTLV> mandatoryTLVs;
38     private Map<Byte, LLDPTLV> optionalTLVs;
39     private Map<CustomTLVKey, LLDPTLV> customTLVs;
40
41     /**
42      * Default constructor that creates the tlvList LinkedHashMap.
43      */
44     public LLDP() {
45         init();
46     }
47
48     /**
49      * Constructor that creates the tlvList LinkedHashMap and sets the write access for the same.
50      */
51     public LLDP(final boolean writeAccess) {
52         super(writeAccess);
53         init();
54     }
55
56     private void init() {
57         mandatoryTLVs = new LinkedHashMap<>(LLDP_DEFAULT_TLVS);
58         optionalTLVs = new LinkedHashMap<>();
59         customTLVs = new LinkedHashMap<>();
60     }
61
62     /**
63      * Returns the TLV byte type.
64      *
65      * @param typeDesc description of the type of TLV
66      * @return byte type of TLV
67      */
68     private byte getType(final String typeDesc) {
69         switch (typeDesc) {
70             case CHASSISID:
71                 return LLDPTLV.TLVType.ChassisID.getValue();
72             case PORTID:
73                 return LLDPTLV.TLVType.PortID.getValue();
74             case TTL:
75                 return LLDPTLV.TLVType.TTL.getValue();
76             case SYSTEMNAMEID:
77                 return LLDPTLV.TLVType.SystemName.getValue();
78             case SYSTEMDESC:
79                 return LLDPTLV.TLVType.SystemDesc.getValue();
80             case PORTDESC:
81                 return LLDPTLV.TLVType.PortDesc.getValue();
82             case SYSTEMCAPABILITIES:
83                 return LLDPTLV.TLVType.SystemCapabilities.getValue();
84             case MANAGEMENTADDRESS:
85                 return LLDPTLV.TLVType.ManagementAddress.getValue();
86             default:
87                 return LLDPTLV.TLVType.Unknown.getValue();
88         }
89     }
90
91     private LLDPTLV getFromTLVs(final Byte type) {
92         LLDPTLV tlv;
93         tlv = mandatoryTLVs.get(type);
94         if (tlv == null) {
95             tlv = optionalTLVs.get(type);
96         }
97         return tlv;
98     }
99
100     private void putToTLVs(final Byte type, final LLDPTLV tlv) {
101         if (type == LLDPTLV.TLVType.ChassisID.getValue() || type == LLDPTLV.TLVType.PortID.getValue()
102                 || type == LLDPTLV.TLVType.TTL.getValue()) {
103             mandatoryTLVs.put(type, tlv);
104         } else if (type != LLDPTLV.TLVType.Custom.getValue()) {
105             optionalTLVs.put(type, tlv);
106         }
107     }
108
109     /**
110      * Gets the full LLDPTLV.
111      *
112      * @param type description of the type of TLV
113      * @return LLDPTLV - full TLV
114      */
115     public LLDPTLV getTLV(final String type) {
116         return getFromTLVs(getType(type));
117     }
118
119     public LLDPTLV getCustomTLV(final CustomTLVKey key) {
120         return customTLVs.get(key);
121     }
122
123     /**
124      * Sets the LLDPTLV for a type.
125      *
126      * @param type description of the type of TLV
127      * @param tlv tlv to set
128      */
129     public void setTLV(final String type, final LLDPTLV tlv) {
130         putToTLVs(getType(type), tlv);
131     }
132
133     /**
134      * Returns the chassisId TLV.
135      */
136     public LLDPTLV getChassisId() {
137         return getTLV(CHASSISID);
138     }
139
140     public LLDP setChassisId(final LLDPTLV chassisId) {
141         setTLV(CHASSISID, chassisId);
142         return this;
143     }
144
145     /**
146      * Returns the SystemName TLV.
147      */
148     public LLDPTLV getSystemNameId() {
149         return getTLV(SYSTEMNAMEID);
150     }
151
152     public LLDP setSystemNameId(final LLDPTLV systemNameId) {
153         setTLV(SYSTEMNAMEID, systemNameId);
154         return this;
155     }
156
157     /**
158      * Returns the portId TLV.
159      */
160     public LLDPTLV getPortId() {
161         return getTLV(PORTID);
162     }
163
164     public LLDP setPortId(final LLDPTLV portId) {
165         setTLV(PORTID, portId);
166         return this;
167     }
168
169     /**
170      * Return the ttl TLV.
171      */
172     public LLDPTLV getTtl() {
173         return getTLV(TTL);
174     }
175
176     public LLDP setTtl(final LLDPTLV ttl) {
177         setTLV(TTL, ttl);
178         return this;
179     }
180
181     /**
182      * Return the SystemDesc TLV.
183      */
184     public LLDPTLV getSystemDesc() {
185         return getTLV(SYSTEMDESC);
186     }
187
188     public LLDP setSystemDesc(final LLDPTLV systemDesc) {
189         setTLV(SYSTEMDESC, systemDesc);
190         return this;
191     }
192
193     /**
194      * Return the PortDesc TLV.
195      */
196     public LLDPTLV getPortDesc() {
197         return getTLV(PORTDESC);
198     }
199
200     public LLDP setPortDesc(final LLDPTLV portDesc) {
201         setTLV(PORTDESC, portDesc);
202         return this;
203     }
204
205     /**
206      * Return the SystemCapabilities TLV.
207      */
208     public LLDPTLV getSystemCapabilities() {
209         return getTLV(SYSTEMCAPABILITIES);
210     }
211
212     public LLDP setSystemCapabilities(final LLDPTLV systemCapabilities) {
213         setTLV(SYSTEMCAPABILITIES, systemCapabilities);
214         return this;
215     }
216
217     /**
218      * Return the ManagementAddress TLV.
219      */
220     public LLDPTLV getManagementAddress() {
221         return getTLV(MANAGEMENTADDRESS);
222     }
223
224     public LLDP setManagementAddress(final LLDPTLV managementAddress) {
225         setTLV(MANAGEMENTADDRESS, managementAddress);
226         return this;
227     }
228
229     /**
230      * Returns the optionalTLVList.
231      */
232     public Iterable<LLDPTLV> getOptionalTLVList() {
233         return optionalTLVs.values();
234     }
235
236     /**
237      * Returns the customTlvList.
238      */
239     public Iterable<LLDPTLV> getCustomTlvList() {
240         return customTLVs.values();
241     }
242
243     public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) {
244         for (LLDPTLV tlv : optionalTLVList) {
245             optionalTLVs.put(tlv.getType(), tlv);
246         }
247         return this;
248     }
249
250     public LLDP addCustomTLV(final LLDPTLV customTLV) {
251         CustomTLVKey key = new CustomTLVKey(LLDPTLV.extractCustomOUI(customTLV),
252                 LLDPTLV.extractCustomSubtype(customTLV));
253         customTLVs.put(key, customTLV);
254
255         return this;
256     }
257
258     @Override
259     public Packet deserialize(final byte[] data, final int bitOffset, final int size) throws PacketException {
260         int lldpOffset = bitOffset; // LLDP start
261         int lldpSize = size; // LLDP size
262
263         if (LOG.isTraceEnabled()) {
264             LOG.trace("LLDP: {} (offset {} bitsize {})", HexEncode.bytesToHexString(data), lldpOffset, lldpSize);
265         }
266         /*
267          * Deserialize the TLVs until we reach the end of the packet
268          */
269         while (lldpSize > 0) {
270             LLDPTLV tlv = new LLDPTLV();
271             tlv.deserialize(data, lldpOffset, lldpSize);
272             if (tlv.getType() == 0 && tlv.getLength() == 0) {
273                 break;
274             }
275             int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
276             lldpOffset += tlvSize;
277             lldpSize -= tlvSize;
278             if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
279                 addCustomTLV(tlv);
280             } else {
281                 this.putToTLVs(tlv.getType(), tlv);
282             }
283         }
284         return this;
285     }
286
287     @Override
288     public byte[] serialize() throws PacketException {
289         int startOffset = 0;
290         byte[] serializedBytes = new byte[getLLDPPacketLength()];
291
292         final Iterable<LLDPTLV> allTlvs = Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(),
293                 customTLVs.values());
294         for (LLDPTLV tlv : allTlvs) {
295             int numBits = tlv.getTLVSize();
296             try {
297                 BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), startOffset, numBits);
298             } catch (final BufferException e) {
299                 throw new PacketException("Error from setBytes", e);
300             }
301             startOffset += numBits;
302         }
303         // Now add the empty LLDPTLV at the end
304         try {
305             BitBufferHelper.setBytes(serializedBytes, LLDP.EMPTY_TLV.serialize(), startOffset,
306                     LLDP.EMPTY_TLV.getTLVSize());
307         } catch (final BufferException e) {
308             throw new PacketException("Error from setBytes", e);
309         }
310
311         if (LOG.isTraceEnabled()) {
312             LOG.trace("LLDP: serialized: {}", HexEncode.bytesToHexString(serializedBytes));
313         }
314         return serializedBytes;
315     }
316
317     /**
318      * Returns the size of LLDP packet in bytes.
319      *
320      * @return int - LLDP Packet size in bytes
321      */
322     private int getLLDPPacketLength() {
323         int len = 0;
324
325         for (LLDPTLV lldptlv : Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values())) {
326             len += lldptlv.getTLVSize();
327         }
328
329         len += LLDP.EMPTY_TLV.getTLVSize();
330
331         return len / NetUtils.NUM_BITS_IN_A_BYTE;
332     }
333 }
334