blob: 38dc1eb8270907a9f6a494f01c2d7e7f38adb0aa [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
alshabibc4901cd2014-09-05 16:50:40 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
alshabibc4901cd2014-09-05 16:50:40 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska24c849c2014-10-27 09:53:05 -070015 */
alshabibc4901cd2014-09-05 16:50:40 -070016
17/**
18 *
19 */
20package org.onlab.packet;
21
22import java.nio.ByteBuffer;
Jian Li5fc14292015-12-04 11:30:46 -080023import java.util.Arrays;
Jonathan Hart2a655752015-04-07 16:46:33 -070024import java.util.LinkedList;
alshabibc4901cd2014-09-05 16:50:40 -070025import java.util.List;
26
Jian Li5fc14292015-12-04 11:30:46 -080027import static com.google.common.base.MoreObjects.toStringHelper;
Jonathan Hart2a655752015-04-07 16:46:33 -070028import static org.onlab.packet.PacketUtils.*;
29
alshabibc4901cd2014-09-05 16:50:40 -070030/**
Jian Li5fc14292015-12-04 11:30:46 -080031 * Representation of an LLDP Packet.
alshabibc4901cd2014-09-05 16:50:40 -070032 */
33public class LLDP extends BasePacket {
Jonathan Hart2a655752015-04-07 16:46:33 -070034 public static final byte CHASSIS_TLV_TYPE = 1;
35 public static final short CHASSIS_TLV_SIZE = 7;
36 public static final byte CHASSIS_TLV_SUBTYPE = 4;
37
38 public static final byte PORT_TLV_TYPE = 2;
39 public static final short PORT_TLV_SIZE = 5;
40 public static final byte PORT_TLV_SUBTYPE = 2;
41
42 public static final byte TTL_TLV_TYPE = 3;
43 public static final short TTL_TLV_SIZE = 2;
44
alshabibc4901cd2014-09-05 16:50:40 -070045 protected LLDPTLV chassisId;
46 protected LLDPTLV portId;
47 protected LLDPTLV ttl;
48 protected List<LLDPTLV> optionalTLVList;
49 protected short ethType;
50
51 public LLDP() {
Jonathan Hart2a655752015-04-07 16:46:33 -070052 this.optionalTLVList = new LinkedList<>();
alshabibc4901cd2014-09-05 16:50:40 -070053 this.ethType = Ethernet.TYPE_LLDP;
54 }
55
56 /**
57 * @return the chassisId
58 */
59 public LLDPTLV getChassisId() {
60 return this.chassisId;
61 }
62
63 /**
Jian Li5fc14292015-12-04 11:30:46 -080064 * @param chassis the chassisId to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080065 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070066 */
67 public LLDP setChassisId(final LLDPTLV chassis) {
68 this.chassisId = chassis;
69 return this;
70 }
71
72 /**
73 * @return the portId
74 */
75 public LLDPTLV getPortId() {
76 return this.portId;
77 }
78
79 /**
Jian Li5fc14292015-12-04 11:30:46 -080080 * @param portId the portId to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080081 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070082 */
83 public LLDP setPortId(final LLDPTLV portId) {
84 this.portId = portId;
85 return this;
86 }
87
88 /**
89 * @return the ttl
90 */
91 public LLDPTLV getTtl() {
92 return this.ttl;
93 }
94
95 /**
Jian Li5fc14292015-12-04 11:30:46 -080096 * @param ttl the ttl to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -080097 * @return this
alshabibc4901cd2014-09-05 16:50:40 -070098 */
99 public LLDP setTtl(final LLDPTLV ttl) {
100 this.ttl = ttl;
101 return this;
102 }
103
104 /**
105 * @return the optionalTLVList
106 */
107 public List<LLDPTLV> getOptionalTLVList() {
108 return this.optionalTLVList;
109 }
110
111 /**
Jian Li5fc14292015-12-04 11:30:46 -0800112 * @param optionalTLVList the optionalTLVList to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800113 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700114 */
115 public LLDP setOptionalTLVList(final List<LLDPTLV> optionalTLVList) {
116 this.optionalTLVList = optionalTLVList;
117 return this;
118 }
119
120 @Override
121 public byte[] serialize() {
122 int length = 2 + this.chassisId.getLength() + 2
123 + this.portId.getLength() + 2 + this.ttl.getLength() + 2;
124 for (final LLDPTLV tlv : this.optionalTLVList) {
125 length += 2 + tlv.getLength();
126 }
127
128 final byte[] data = new byte[length];
129 final ByteBuffer bb = ByteBuffer.wrap(data);
130 bb.put(this.chassisId.serialize());
131 bb.put(this.portId.serialize());
132 bb.put(this.ttl.serialize());
133 for (final LLDPTLV tlv : this.optionalTLVList) {
134 bb.put(tlv.serialize());
135 }
136 bb.putShort((short) 0); // End of LLDPDU
137
138 /*
139 * if (this.parent != null && this.parent instanceof Ethernet) {
140 * ((Ethernet) this.parent).setEtherType(this.ethType); }
141 */
142
143 return data;
144 }
145
146 @Override
147 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700148 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700149 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
150 LLDPTLV tlv;
151 do {
Jonathan Hart2a655752015-04-07 16:46:33 -0700152 try {
153 tlv = new LLDPOrganizationalTLV().deserialize(bb);
154 } catch (DeserializationException e) {
155 break;
156 }
alshabibc4901cd2014-09-05 16:50:40 -0700157
158 // if there was a failure to deserialize stop processing TLVs
159 if (tlv == null) {
160 break;
161 }
162 switch (tlv.getType()) {
Jian Li5fc14292015-12-04 11:30:46 -0800163 case 0x0:
164 // can throw this one away, its just an end delimiter
165 break;
166 case 0x1:
167 this.chassisId = tlv;
168 break;
169 case 0x2:
170 this.portId = tlv;
171 break;
172 case 0x3:
173 this.ttl = tlv;
174 break;
alshabib7911a052014-10-16 17:49:37 -0700175
Jian Li5fc14292015-12-04 11:30:46 -0800176 default:
177 this.optionalTLVList.add(tlv);
178 break;
alshabibc4901cd2014-09-05 16:50:40 -0700179 }
180 } while (tlv.getType() != 0 && bb.hasRemaining());
181 return this;
182 }
183
184 /*
185 * (non-Javadoc)
186 *
187 * @see java.lang.Object#hashCode()
188 */
189 @Override
190 public int hashCode() {
191 final int prime = 883;
192 int result = super.hashCode();
193 result = prime * result
194 + (this.chassisId == null ? 0 : this.chassisId.hashCode());
195 result = prime * result + this.optionalTLVList.hashCode();
196 result = prime * result
197 + (this.portId == null ? 0 : this.portId.hashCode());
198 result = prime * result + (this.ttl == null ? 0 : this.ttl.hashCode());
199 return result;
200 }
201
202 /*
203 * (non-Javadoc)
204 *
205 * @see java.lang.Object#equals(java.lang.Object)
206 */
207 @Override
208 public boolean equals(final Object obj) {
209 if (this == obj) {
210 return true;
211 }
212 if (!super.equals(obj)) {
213 return false;
214 }
215 if (!(obj instanceof LLDP)) {
216 return false;
217 }
218 final LLDP other = (LLDP) obj;
219 if (this.chassisId == null) {
220 if (other.chassisId != null) {
221 return false;
222 }
223 } else if (!this.chassisId.equals(other.chassisId)) {
224 return false;
225 }
226 if (!this.optionalTLVList.equals(other.optionalTLVList)) {
227 return false;
228 }
229 if (this.portId == null) {
230 if (other.portId != null) {
231 return false;
232 }
233 } else if (!this.portId.equals(other.portId)) {
234 return false;
235 }
236 if (this.ttl == null) {
237 if (other.ttl != null) {
238 return false;
239 }
240 } else if (!this.ttl.equals(other.ttl)) {
241 return false;
242 }
243 return true;
244 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700245
246 /**
247 * Deserializer function for LLDP packets.
248 *
249 * @return deserializer function
250 */
251 public static Deserializer<LLDP> deserializer() {
252 return (data, offset, length) -> {
253 checkInput(data, offset, length, 0);
254
255 LLDP lldp = new LLDP();
256
257 int currentIndex = 0;
258
259 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
260 LLDPTLV tlv;
261 do {
262 // Each new TLV must be a minimum of 2 bytes
263 // (containing the type and length fields).
264 currentIndex += 2;
265 checkHeaderLength(length, currentIndex);
266
267 tlv = new LLDPOrganizationalTLV().deserialize(bb);
268
269 // if there was a failure to deserialize stop processing TLVs
270 if (tlv == null) {
271 break;
272 }
273 switch (tlv.getType()) {
Jian Li5fc14292015-12-04 11:30:46 -0800274 case 0x0:
275 // can throw this one away, it's just an end delimiter
276 break;
277 case 0x1:
278 lldp.chassisId = tlv;
279 break;
280 case 0x2:
281 lldp.portId = tlv;
282 break;
283 case 0x3:
284 lldp.ttl = tlv;
285 break;
286 default:
287 lldp.optionalTLVList.add(tlv);
288 break;
Jonathan Hart2a655752015-04-07 16:46:33 -0700289 }
290
291 currentIndex += tlv.getLength();
292 } while (tlv.getType() != 0);
293
294 return lldp;
295 };
296 }
297
Jian Li5fc14292015-12-04 11:30:46 -0800298 @Override
299 public String toString() {
300 return toStringHelper(getClass())
301 .add("chassisId", Arrays.toString(chassisId.getValue()))
302 .add("portId", Arrays.toString(portId.getValue()))
303 .add("ttl", Arrays.toString(ttl.getValue()))
304 .add("ethType", Short.toString(ethType))
305 .toString();
306
307 // TODO: need to handle optionalTLVList
308 }
alshabibc4901cd2014-09-05 16:50:40 -0700309}