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