Merge "Bug 2820 - problem to add second TLV with type 127."
[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.Collections;
12 import com.google.common.collect.Iterables;
13 import java.util.ArrayList;
14 import java.util.LinkedHashMap;
15 import java.util.List;
16 import java.util.Map;
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 = Collections.emptyList();
35
36     /**
37      * Default constructor that creates the tlvList LinkedHashMap
38      */
39     public LLDP() {
40         super();
41         tlvList = new LinkedHashMap<Byte, LLDPTLV>(LLDPDefaultTlvs);
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 {
67             return LLDPTLV.TLVType.Unknown.getValue();
68         }
69     }
70
71     /**
72      * @param String
73      *            - description of the type of TLV
74      * @return LLDPTLV - full TLV
75      */
76     public LLDPTLV getTLV(String type) {
77         return tlvList.get(getType(type));
78     }
79
80     /**
81      * @param String
82      *            - description of the type of TLV
83      * @param LLDPTLV
84      *            - tlv to set
85      * @return void
86      */
87     public void setTLV(String type, LLDPTLV tlv) {
88         tlvList.put(getType(type), tlv);
89     }
90
91     /**
92      * @return the chassisId TLV
93      */
94     public LLDPTLV getChassisId() {
95         return getTLV(CHASSISID);
96     }
97
98     /**
99      * @param LLDPTLV
100      *            - the chassisId to set
101      */
102     public LLDP setChassisId(LLDPTLV chassisId) {
103         tlvList.put(getType(CHASSISID), chassisId);
104         return this;
105     }
106
107     /**
108      * @return the SystemName TLV
109      */
110     public LLDPTLV getSystemNameId() {
111         return getTLV(SYSTEMNAMEID);
112     }
113
114     /**
115      * @param LLDPTLV
116      *            - the chassisId to set
117      */
118     public LLDP setSystemNameId(LLDPTLV systemNameId) {
119         tlvList.put(getType(SYSTEMNAMEID), systemNameId);
120         return this;
121     }
122
123     /**
124      * @return LLDPTLV - the portId TLV
125      */
126     public LLDPTLV getPortId() {
127         return tlvList.get(getType(PORTID));
128     }
129
130     /**
131      * @param LLDPTLV
132      *            - the portId to set
133      * @return LLDP
134      */
135     public LLDP setPortId(LLDPTLV portId) {
136         tlvList.put(getType(PORTID), portId);
137         return this;
138     }
139
140     /**
141      * @return LLDPTLV - the ttl TLV
142      */
143     public LLDPTLV getTtl() {
144         return tlvList.get(getType(TTL));
145     }
146
147     /**
148      * @param LLDPTLV
149      *            - the ttl to set
150      * @return LLDP
151      */
152     public LLDP setTtl(LLDPTLV ttl) {
153         tlvList.put(getType(TTL), ttl);
154         return this;
155     }
156
157     /**
158      * @return the optionalTLVList
159      */
160     public List<LLDPTLV> getOptionalTLVList() {
161         List<LLDPTLV> list = new ArrayList<LLDPTLV>();
162         for (Map.Entry<Byte, LLDPTLV> entry : tlvList.entrySet()) {
163             byte type = entry.getKey();
164             if ((type == LLDPTLV.TLVType.ChassisID.getValue())
165                     || (type == LLDPTLV.TLVType.PortID.getValue())
166                     || (type == LLDPTLV.TLVType.TTL.getValue())) {
167                 continue;
168             } else {
169                 list.add(entry.getValue());
170             }
171         }
172         return list;
173     }
174
175     /**
176      * @param optionalTLVList
177      *            the optionalTLVList to set
178      * @return LLDP
179      */
180     public LLDP setOptionalTLVList(List<LLDPTLV> optionalTLVList) {
181         for (LLDPTLV tlv : optionalTLVList) {
182             tlvList.put(tlv.getType(), tlv);
183         }
184         return this;
185     }
186
187     /**
188      * @param customTLVList
189      *            the list of custom TLVs to set
190      * @return this LLDP
191      */
192     public LLDP setCustomTLVList(final List<LLDPTLV> customTLVList) {
193         this.customTlvList = new ArrayList<>(customTLVList);
194         return this;
195     }
196
197     @Override
198     public Packet deserialize(byte[] data, int bitOffset, int size)
199             throws PacketException {
200         int lldpOffset = bitOffset; // LLDP start
201         int lldpSize = size; // LLDP size
202
203         if (logger.isTraceEnabled()) {
204           logger.trace("LLDP: {} (offset {} bitsize {})", new Object[] {
205                   HexEncode.bytesToHexString(data), lldpOffset, lldpSize });
206         }
207         /*
208          * Deserialize the TLVs until we reach the end of the packet
209          */
210         while (lldpSize > 0) {
211             LLDPTLV tlv = new LLDPTLV();
212             tlv.deserialize(data, lldpOffset, lldpSize);
213             if (tlv.getType() == 0 && tlv.getLength() == 0) {
214                break;
215             }
216             int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
217             lldpOffset += tlvSize;
218             lldpSize -= tlvSize;
219             this.tlvList.put(tlv.getType(), tlv);
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(tlvList.values(), customTlvList);
230         for (LLDPTLV tlv : allTlvs) {
231             int numBits = tlv.getTLVSize();
232             try {
233                 BitBufferHelper.setBytes(serializedBytes, tlv.serialize(),
234                         startOffset, numBits);
235             } catch (BufferException e) {
236                 throw new PacketException(e.getMessage());
237             }
238             startOffset += numBits;
239         }
240         // Now add the empty LLDPTLV at the end
241         try {
242             BitBufferHelper.setBytes(serializedBytes,
243                     LLDP.emptyTLV.serialize(), startOffset,
244                     LLDP.emptyTLV.getTLVSize());
245         } catch (BufferException e) {
246             throw new PacketException(e.getMessage());
247         }
248
249         if (logger.isTraceEnabled()) {
250           logger.trace("LLDP: serialized: {}",
251                   HexEncode.bytesToHexString(serializedBytes));
252         }
253         return serializedBytes;
254     }
255
256     /**
257      * Returns the size of LLDP packet in bytes
258      *
259      * @return int - LLDP Packet size in bytes
260      */
261     private int getLLDPPacketLength() {
262         int len = 0;
263         LLDPTLV tlv;
264
265         for (Map.Entry<Byte, LLDPTLV> entry : this.tlvList.entrySet()) {
266             tlv = entry.getValue();
267             len += tlv.getTLVSize();
268         }
269
270         for (LLDPTLV customTlv : this.customTlvList) {
271             len += customTlv.getTLVSize();
272         }
273
274         len += LLDP.emptyTLV.getTLVSize();
275
276         return len / NetUtils.NumBitsInAByte;
277     }
278 }