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