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