OPNFLWPLUG-898 Improve code quality in liblldp module
[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
17 /**
18  * Class that represents the LLDP frame objects.
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 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 };
29
30     private Map<Byte, LLDPTLV> mandatoryTLVs;
31     private Map<Byte, LLDPTLV> optionalTLVs;
32     private Map<CustomTLVKey, LLDPTLV> customTLVs;
33
34     /**
35      * Default constructor that creates the tlvList LinkedHashMap.
36      */
37     public LLDP() {
38         init();
39     }
40
41     /**
42      * Constructor that creates the tlvList LinkedHashMap and sets the write access for the same.
43      */
44     public LLDP(final boolean writeAccess) {
45         super(writeAccess);
46         init();
47     }
48
49     private void init() {
50         mandatoryTLVs = new LinkedHashMap<>(LLDP_DEFAULT_TLVS);
51         optionalTLVs = new LinkedHashMap<>();
52         customTLVs = new LinkedHashMap<>();
53     }
54
55     /**
56      * Returns the TLV byte type.
57      *
58      * @param typeDesc description of the type of TLV
59      * @return byte type of TLV
60      */
61     private byte getType(final String typeDesc) {
62         switch (typeDesc) {
63             case CHASSISID:
64                 return LLDPTLV.TLVType.ChassisID.getValue();
65             case PORTID:
66                 return LLDPTLV.TLVType.PortID.getValue();
67             case TTL:
68                 return LLDPTLV.TLVType.TTL.getValue();
69             case SYSTEMNAMEID:
70                 return LLDPTLV.TLVType.SystemName.getValue();
71             default:
72                 return LLDPTLV.TLVType.Unknown.getValue();
73         }
74     }
75
76     private LLDPTLV getFromTLVs(final Byte type) {
77         LLDPTLV tlv;
78         tlv = mandatoryTLVs.get(type);
79         if (tlv == null) {
80             tlv = optionalTLVs.get(type);
81         }
82         return tlv;
83     }
84
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);
91         }
92     }
93
94     /**
95      * Gets the full LLDPTLV.
96      *
97      * @param type description of the type of TLV
98      * @return LLDPTLV - full TLV
99      */
100     public LLDPTLV getTLV(final String type) {
101         return getFromTLVs(getType(type));
102     }
103
104     public LLDPTLV getCustomTLV(final CustomTLVKey key) {
105         return customTLVs.get(key);
106     }
107
108     /**
109      * Sets the LLDPTLV for a type.
110      *
111      * @param type description of the type of TLV
112      * @param tlv tlv to set
113      */
114     public void setTLV(final String type, final LLDPTLV tlv) {
115         putToTLVs(getType(type), tlv);
116     }
117
118     /**
119      * Returns the chassisId TLV.
120      */
121     public LLDPTLV getChassisId() {
122         return getTLV(CHASSISID);
123     }
124
125     public LLDP setChassisId(final LLDPTLV chassisId) {
126         setTLV(CHASSISID, chassisId);
127         return this;
128     }
129
130     /**
131      * Returns the SystemName TLV.
132      */
133     public LLDPTLV getSystemNameId() {
134         return getTLV(SYSTEMNAMEID);
135     }
136
137     public LLDP setSystemNameId(final LLDPTLV systemNameId) {
138         setTLV(SYSTEMNAMEID, systemNameId);
139         return this;
140     }
141
142     /**
143      * Returns the portId TLV.
144      */
145     public LLDPTLV getPortId() {
146         return getTLV(PORTID);
147     }
148
149     public LLDP setPortId(final LLDPTLV portId) {
150         setTLV(PORTID, portId);
151         return this;
152     }
153
154     /**
155      * Return the ttl TLV.
156      */
157     public LLDPTLV getTtl() {
158         return getTLV(TTL);
159     }
160
161     public LLDP setTtl(final LLDPTLV ttl) {
162         setTLV(TTL, ttl);
163         return this;
164     }
165
166     /**
167      * Returns the optionalTLVList.
168      */
169     public Iterable<LLDPTLV> getOptionalTLVList() {
170         return optionalTLVs.values();
171     }
172
173     /**
174      * Returns the customTlvList.
175      */
176     public Iterable<LLDPTLV> getCustomTlvList() {
177         return customTLVs.values();
178     }
179
180     public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) {
181         for (LLDPTLV tlv : optionalTLVList) {
182             optionalTLVs.put(tlv.getType(), tlv);
183         }
184         return this;
185     }
186
187     public LLDP addCustomTLV(final LLDPTLV customTLV) {
188         CustomTLVKey key = new CustomTLVKey(LLDPTLV.extractCustomOUI(customTLV),
189                 LLDPTLV.extractCustomSubtype(customTLV));
190         customTLVs.put(key, customTLV);
191
192         return this;
193     }
194
195     @Override
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
199
200         if (LOG.isTraceEnabled()) {
201             LOG.trace("LLDP: {} (offset {} bitsize {})", HexEncode.bytesToHexString(data), lldpOffset, lldpSize);
202         }
203         /*
204          * Deserialize the TLVs until we reach the end of the packet
205          */
206         while (lldpSize > 0) {
207             LLDPTLV tlv = new LLDPTLV();
208             tlv.deserialize(data, lldpOffset, lldpSize);
209             if (tlv.getType() == 0 && tlv.getLength() == 0) {
210                 break;
211             }
212             int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
213             lldpOffset += tlvSize;
214             lldpSize -= tlvSize;
215             if (tlv.getType() == LLDPTLV.TLVType.Custom.getValue()) {
216                 addCustomTLV(tlv);
217             } else {
218                 this.putToTLVs(tlv.getType(), tlv);
219             }
220         }
221         return this;
222     }
223
224     @Override
225     public byte[] serialize() throws PacketException {
226         int startOffset = 0;
227         byte[] serializedBytes = new byte[getLLDPPacketLength()];
228
229         final Iterable<LLDPTLV> allTlvs = Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(),
230                 customTLVs.values());
231         for (LLDPTLV tlv : allTlvs) {
232             int numBits = tlv.getTLVSize();
233             try {
234                 BitBufferHelper.setBytes(serializedBytes, tlv.serialize(), startOffset, numBits);
235             } catch (final BufferException e) {
236                 throw new PacketException("Error from setBytes", e);
237             }
238             startOffset += numBits;
239         }
240         // Now add the empty LLDPTLV at the end
241         try {
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);
246         }
247
248         if (LOG.isTraceEnabled()) {
249             LOG.trace("LLDP: serialized: {}", HexEncode.bytesToHexString(serializedBytes));
250         }
251         return serializedBytes;
252     }
253
254     /**
255      * Returns the size of LLDP packet in bytes.
256      *
257      * @return int - LLDP Packet size in bytes
258      */
259     private int getLLDPPacketLength() {
260         int len = 0;
261
262         for (LLDPTLV lldptlv : Iterables.concat(mandatoryTLVs.values(), optionalTLVs.values(), customTLVs.values())) {
263             len += lldptlv.getTLVSize();
264         }
265
266         len += LLDP.EMPTY_TLV.getTLVSize();
267
268         return len / NetUtils.NUM_BITS_IN_A_BYTE;
269     }
270 }