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