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