blob: 0b414578dac31614ac5628607504ac21ebfec69c [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 */
16
17
alshabibc4901cd2014-09-05 16:50:40 -070018
19package org.onlab.packet;
20
Charles Chan119eeb52015-10-27 12:40:25 -070021import org.onlab.packet.ndp.NeighborAdvertisement;
22import org.onlab.packet.ndp.NeighborSolicitation;
23import org.onlab.packet.ndp.Redirect;
24import org.onlab.packet.ndp.RouterAdvertisement;
25import org.onlab.packet.ndp.RouterSolicitation;
26
alshabibc4901cd2014-09-05 16:50:40 -070027import java.nio.ByteBuffer;
28import java.util.Arrays;
29import java.util.HashMap;
30import java.util.Map;
31
Jonathan Hart2a655752015-04-07 16:46:33 -070032import static com.google.common.base.Preconditions.checkNotNull;
33import static org.onlab.packet.PacketUtils.checkHeaderLength;
34import static org.onlab.packet.PacketUtils.checkInput;
alshabibc4901cd2014-09-05 16:50:40 -070035
36/**
Jian Li5fc14292015-12-04 11:30:46 -080037 * Ethernet Packet.
alshabibc4901cd2014-09-05 16:50:40 -070038 */
39public class Ethernet extends BasePacket {
40 private static final String HEXES = "0123456789ABCDEF";
Pier Ventre48ca5192016-11-28 16:52:24 -080041 private static final String HEX_PROTO = "0x%s";
Thomas Vachuska5dd52f72014-11-28 19:27:45 -080042
alshabib7b808c52015-06-26 14:22:24 -070043 public static final short TYPE_ARP = EthType.EtherType.ARP.ethType().toShort();
44 public static final short TYPE_RARP = EthType.EtherType.RARP.ethType().toShort();
45 public static final short TYPE_IPV4 = EthType.EtherType.IPV4.ethType().toShort();
46 public static final short TYPE_IPV6 = EthType.EtherType.IPV6.ethType().toShort();
47 public static final short TYPE_LLDP = EthType.EtherType.LLDP.ethType().toShort();
48 public static final short TYPE_VLAN = EthType.EtherType.VLAN.ethType().toShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +000049 public static final short TYPE_QINQ = EthType.EtherType.QINQ.ethType().toShort();
alshabib7b808c52015-06-26 14:22:24 -070050 public static final short TYPE_BSN = EthType.EtherType.BDDP.ethType().toShort();
51
Jon Hall8c7b06a2017-02-22 13:37:33 -080052 public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();
alshabib7b808c52015-06-26 14:22:24 -070053 public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort();
alshabibcaf1ca22015-06-25 15:18:16 -070054
Jonathan Hart2a655752015-04-07 16:46:33 -070055
alshabibcaf1ca22015-06-25 15:18:16 -070056 public static final short VLAN_UNTAGGED = (short) 0xffff;
Jonathan Hart2a655752015-04-07 16:46:33 -070057
58 public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
59 public static final short VLAN_HEADER_LENGTH = 4; // bytes
60
alshabibc4901cd2014-09-05 16:50:40 -070061 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
Jonathan Hart2a655752015-04-07 16:46:33 -070062
63 private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP =
64 new HashMap<>();
alshabibc4901cd2014-09-05 16:50:40 -070065
66 static {
alshabibcaf1ca22015-06-25 15:18:16 -070067 for (EthType.EtherType ethType : EthType.EtherType.values()) {
alshabib7b808c52015-06-26 14:22:24 -070068 if (ethType.deserializer() != null) {
Jonathan Hart2a655752015-04-07 16:46:33 -070069 ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer());
alshabibcaf1ca22015-06-25 15:18:16 -070070 }
71 }
alshabibc4901cd2014-09-05 16:50:40 -070072 }
73
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070074 protected MacAddress destinationMACAddress;
75 protected MacAddress sourceMACAddress;
alshabibc4901cd2014-09-05 16:50:40 -070076 protected byte priorityCode;
Amit Ghosh764a1b42017-03-18 08:20:06 +000077 protected byte qInQPriorityCode;
alshabibc4901cd2014-09-05 16:50:40 -070078 protected short vlanID;
Amit Ghosh764a1b42017-03-18 08:20:06 +000079 protected short qinqVID;
80 protected short qinqTPID;
alshabibc4901cd2014-09-05 16:50:40 -070081 protected short etherType;
82 protected boolean pad = false;
83
84 /**
85 * By default, set Ethernet to untagged.
86 */
87 public Ethernet() {
88 super();
89 this.vlanID = Ethernet.VLAN_UNTAGGED;
Amit Ghosh764a1b42017-03-18 08:20:06 +000090 this.qinqVID = Ethernet.VLAN_UNTAGGED;
91 this.qinqTPID = TYPE_QINQ;
alshabibc4901cd2014-09-05 16:50:40 -070092 }
93
94 /**
95 * Gets the destination MAC address.
96 *
97 * @return the destination MAC as a byte array
98 */
99 public byte[] getDestinationMACAddress() {
100 return this.destinationMACAddress.toBytes();
101 }
102
103 /**
104 * Gets the destination MAC address.
105 *
106 * @return the destination MAC
107 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700108 public MacAddress getDestinationMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700109 return this.destinationMACAddress;
110 }
111
112 /**
113 * Sets the destination MAC address.
114 *
tom5f18cf32014-09-13 14:10:57 -0700115 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700116 * @return the Ethernet frame
117 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800118 public Ethernet setDestinationMACAddress(final MacAddress destMac) {
119 this.destinationMACAddress = checkNotNull(destMac);
120 return this;
121 }
122
123 /**
124 * Sets the destination MAC address.
125 *
126 * @param destMac the destination MAC to set
127 * @return the Ethernet frame
128 */
alshabibc4901cd2014-09-05 16:50:40 -0700129 public Ethernet setDestinationMACAddress(final byte[] destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700130 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700131 return this;
132 }
133
134 /**
135 * Sets the destination MAC address.
136 *
tom5f18cf32014-09-13 14:10:57 -0700137 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700138 * @return the Ethernet frame
139 */
140 public Ethernet setDestinationMACAddress(final String destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700141 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700142 return this;
143 }
144
145 /**
146 * Gets the source MAC address.
147 *
148 * @return the source MACAddress as a byte array
149 */
150 public byte[] getSourceMACAddress() {
151 return this.sourceMACAddress.toBytes();
152 }
153
154 /**
155 * Gets the source MAC address.
156 *
157 * @return the source MACAddress
158 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700159 public MacAddress getSourceMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700160 return this.sourceMACAddress;
161 }
162
163 /**
164 * Sets the source MAC address.
165 *
tom5f18cf32014-09-13 14:10:57 -0700166 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700167 * @return the Ethernet frame
168 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800169 public Ethernet setSourceMACAddress(final MacAddress sourceMac) {
170 this.sourceMACAddress = checkNotNull(sourceMac);
171 return this;
172 }
173
174 /**
175 * Sets the source MAC address.
176 *
177 * @param sourceMac the source MAC to set
178 * @return the Ethernet frame
179 */
alshabibc4901cd2014-09-05 16:50:40 -0700180 public Ethernet setSourceMACAddress(final byte[] sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700181 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700182 return this;
183 }
184
185 /**
186 * Sets the source MAC address.
187 *
tom5f18cf32014-09-13 14:10:57 -0700188 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700189 * @return the Ethernet frame
190 */
191 public Ethernet setSourceMACAddress(final String sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700192 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700193 return this;
194 }
195
196 /**
197 * Gets the priority code.
198 *
199 * @return the priorityCode
200 */
201 public byte getPriorityCode() {
202 return this.priorityCode;
203 }
204
205 /**
206 * Sets the priority code.
207 *
tom5f18cf32014-09-13 14:10:57 -0700208 * @param priority the priorityCode to set
alshabibc4901cd2014-09-05 16:50:40 -0700209 * @return the Ethernet frame
210 */
211 public Ethernet setPriorityCode(final byte priority) {
212 this.priorityCode = priority;
213 return this;
214 }
215
216 /**
Amit Ghosh764a1b42017-03-18 08:20:06 +0000217 * Gets the QinQ priority code.
218 *
219 * @return the qInQPriorityCode
220 */
221 public byte getQinQPriorityCode() {
222 return this.qInQPriorityCode;
223 }
224
225 /**
226 * Sets the QinQ priority code.
227 *
228 * @param priority the priorityCode to set
229 * @return the Ethernet frame
230 */
231 public Ethernet setQinQPriorityCode(final byte priority) {
232 this.qInQPriorityCode = priority;
233 return this;
234 }
235
236 /**
alshabibc4901cd2014-09-05 16:50:40 -0700237 * Gets the VLAN ID.
238 *
239 * @return the vlanID
240 */
241 public short getVlanID() {
242 return this.vlanID;
243 }
244
245 /**
246 * Sets the VLAN ID.
247 *
tom5f18cf32014-09-13 14:10:57 -0700248 * @param vlan the vlanID to set
alshabibc4901cd2014-09-05 16:50:40 -0700249 * @return the Ethernet frame
250 */
251 public Ethernet setVlanID(final short vlan) {
252 this.vlanID = vlan;
253 return this;
254 }
255
256 /**
Amit Ghosh764a1b42017-03-18 08:20:06 +0000257 * Gets the QinQ VLAN ID.
258 *
259 * @return the QinQ vlanID
260 */
261 public short getQinQVID() {
262 return this.qinqVID;
263 }
264
265 /**
266 * Sets the QinQ VLAN ID.
267 *
268 * @param vlan the vlanID to set
269 * @return the Ethernet frame
270 */
271 public Ethernet setQinQVID(final short vlan) {
272 this.qinqVID = vlan;
273 return this;
274 }
275 /**
276 * Gets the QinQ TPID.
277 *
278 * @return the QinQ TPID
279 */
280 public short getQinQTPID() {
281 return this.qinqTPID;
282 }
283
284 /**
285 * Sets the QinQ TPID.
286 *
287 * @param tpId the TPID to set
288 * @return the Ethernet frame
289 */
290 public Ethernet setQinQTPID(final short tpId) {
291 if (tpId != TYPE_VLAN && tpId != TYPE_QINQ) {
292 return null;
293 }
294 this.qinqTPID = tpId;
295 return this;
296 }
297 /**
alshabibc4901cd2014-09-05 16:50:40 -0700298 * Gets the Ethernet type.
299 *
300 * @return the etherType
301 */
302 public short getEtherType() {
303 return this.etherType;
304 }
305
306 /**
307 * Sets the Ethernet type.
308 *
tom5f18cf32014-09-13 14:10:57 -0700309 * @param ethType the etherType to set
alshabibc4901cd2014-09-05 16:50:40 -0700310 * @return the Ethernet frame
311 */
312 public Ethernet setEtherType(final short ethType) {
313 this.etherType = ethType;
314 return this;
315 }
316
317 /**
318 * @return True if the Ethernet frame is broadcast, false otherwise
319 */
320 public boolean isBroadcast() {
321 assert this.destinationMACAddress.length() == 6;
322 return this.destinationMACAddress.isBroadcast();
323 }
324
325 /**
326 * @return True is the Ethernet frame is multicast, False otherwise
327 */
328 public boolean isMulticast() {
329 return this.destinationMACAddress.isMulticast();
330 }
331
332 /**
333 * Pad this packet to 60 bytes minimum, filling with zeros?
334 *
335 * @return the pad
336 */
337 public boolean isPad() {
338 return this.pad;
339 }
340
341 /**
342 * Pad this packet to 60 bytes minimum, filling with zeros?
343 *
tom5f18cf32014-09-13 14:10:57 -0700344 * @param pd
alshabibc4901cd2014-09-05 16:50:40 -0700345 * the pad to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800346 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700347 */
348 public Ethernet setPad(final boolean pd) {
349 this.pad = pd;
350 return this;
351 }
352
353 @Override
354 public byte[] serialize() {
355 byte[] payloadData = null;
356 if (this.payload != null) {
357 this.payload.setParent(this);
358 payloadData = this.payload.serialize();
359 }
360 int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
Amit Ghosh764a1b42017-03-18 08:20:06 +0000361 + (this.qinqVID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
alshabibc4901cd2014-09-05 16:50:40 -0700362 + (payloadData == null ? 0 : payloadData.length);
363 if (this.pad && length < 60) {
364 length = 60;
365 }
366 final byte[] data = new byte[length];
367 final ByteBuffer bb = ByteBuffer.wrap(data);
368 bb.put(this.destinationMACAddress.toBytes());
369 bb.put(this.sourceMACAddress.toBytes());
Amit Ghosh764a1b42017-03-18 08:20:06 +0000370 if (this.qinqVID != Ethernet.VLAN_UNTAGGED) {
371 bb.putShort(this.qinqTPID);
372 bb.putShort((short) (this.qInQPriorityCode << 13 | this.qinqVID & 0x0fff));
373 }
alshabibc4901cd2014-09-05 16:50:40 -0700374 if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
alshabib10580802015-02-18 18:30:33 -0800375 bb.putShort(TYPE_VLAN);
alshabibc4901cd2014-09-05 16:50:40 -0700376 bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
377 }
378 bb.putShort(this.etherType);
379 if (payloadData != null) {
380 bb.put(payloadData);
381 }
382 if (this.pad) {
383 Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
384 }
385 return data;
386 }
387
388 @Override
389 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700390 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700391 if (length <= 0) {
392 return null;
393 }
394 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
395 if (this.destinationMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700396 this.destinationMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700397 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700398 final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700399 bb.get(dstAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700400 this.destinationMACAddress = MacAddress.valueOf(dstAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700401
402 if (this.sourceMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700403 this.sourceMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700404 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700405 final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700406 bb.get(srcAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700407 this.sourceMACAddress = MacAddress.valueOf(srcAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700408
409 short ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000410 if (ethType == TYPE_QINQ) {
411 final short tci = bb.getShort();
412 this.qInQPriorityCode = (byte) (tci >> 13 & 0x07);
413 this.qinqVID = (short) (tci & 0x0fff);
414 this.qinqTPID = TYPE_QINQ;
415 ethType = bb.getShort();
416 }
417
alshabib10580802015-02-18 18:30:33 -0800418 if (ethType == TYPE_VLAN) {
alshabibc4901cd2014-09-05 16:50:40 -0700419 final short tci = bb.getShort();
420 this.priorityCode = (byte) (tci >> 13 & 0x07);
421 this.vlanID = (short) (tci & 0x0fff);
422 ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000423
424 // there might be one more tag with 1q TPID
425 if (ethType == TYPE_VLAN) {
426 // packet is double tagged with 1q TPIDs
427 // We handle only double tagged packets here and assume that in this case
428 // TYPE_QINQ above was not hit
429 // We put the values retrieved above with TYPE_VLAN in
430 // qInQ fields
431 this.qInQPriorityCode = this.priorityCode;
432 this.qinqVID = this.vlanID;
433 this.qinqTPID = TYPE_VLAN;
434
435 final short innerTci = bb.getShort();
436 this.priorityCode = (byte) (innerTci >> 13 & 0x07);
437 this.vlanID = (short) (innerTci & 0x0fff);
438 ethType = bb.getShort();
439 }
alshabibc4901cd2014-09-05 16:50:40 -0700440 } else {
441 this.vlanID = Ethernet.VLAN_UNTAGGED;
442 }
443 this.etherType = ethType;
444
445 IPacket payload;
Jonathan Hart2a655752015-04-07 16:46:33 -0700446 Deserializer<? extends IPacket> deserializer;
447 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
448 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
alshabibc4901cd2014-09-05 16:50:40 -0700449 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700450 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700451 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700452 try {
453 this.payload = deserializer.deserialize(data, bb.position(),
454 bb.limit() - bb.position());
455 this.payload.setParent(this);
456 } catch (DeserializationException e) {
457 return this;
458 }
alshabibc4901cd2014-09-05 16:50:40 -0700459 return this;
460 }
461
462 /**
463 * Checks to see if a string is a valid MAC address.
464 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800465 * @param macAddress string to test if it is a valid MAC
alshabibc4901cd2014-09-05 16:50:40 -0700466 * @return True if macAddress is a valid MAC, False otherwise
467 */
468 public static boolean isMACAddress(final String macAddress) {
469 final String[] macBytes = macAddress.split(":");
470 if (macBytes.length != 6) {
471 return false;
472 }
473 for (int i = 0; i < 6; ++i) {
474 if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
475 || Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(
476 1)) == -1) {
477 return false;
478 }
479 }
480 return true;
481 }
482
483 /**
484 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
485 * matter, and returns a corresponding byte[].
486 *
487 * @param macAddress
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800488 * The MAC address to convert into a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700489 * @return The macAddress as a byte array
490 */
491 public static byte[] toMACAddress(final String macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700492 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700493 }
494
495 /**
496 * Accepts a MAC address and returns the corresponding long, where the MAC
497 * bytes are set on the lower order bytes of the long.
498 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800499 * @param macAddress MAC address as a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700500 * @return a long containing the mac address bytes
501 */
502 public static long toLong(final byte[] macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700503 return MacAddress.valueOf(macAddress).toLong();
alshabibc4901cd2014-09-05 16:50:40 -0700504 }
505
506 /**
507 * Converts a long MAC address to a byte array.
508 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800509 * @param macAddress MAC address set on the lower order bytes of the long
alshabibc4901cd2014-09-05 16:50:40 -0700510 * @return the bytes of the mac address
511 */
512 public static byte[] toByteArray(final long macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700513 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700514 }
515
516 /*
517 * (non-Javadoc)
518 *
519 * @see java.lang.Object#hashCode()
520 */
521 @Override
522 public int hashCode() {
523 final int prime = 7867;
524 int result = super.hashCode();
525 result = prime * result + this.destinationMACAddress.hashCode();
526 result = prime * result + this.etherType;
Amit Ghosh764a1b42017-03-18 08:20:06 +0000527 result = prime * result + this.qinqVID;
528 result = prime * result + this.qInQPriorityCode;
alshabibc4901cd2014-09-05 16:50:40 -0700529 result = prime * result + this.vlanID;
530 result = prime * result + this.priorityCode;
531 result = prime * result + (this.pad ? 1231 : 1237);
532 result = prime * result + this.sourceMACAddress.hashCode();
533 return result;
534 }
535
536 /*
537 * (non-Javadoc)
538 *
539 * @see java.lang.Object#equals(java.lang.Object)
540 */
541 @Override
542 public boolean equals(final Object obj) {
543 if (this == obj) {
544 return true;
545 }
546 if (!super.equals(obj)) {
547 return false;
548 }
549 if (!(obj instanceof Ethernet)) {
550 return false;
551 }
552 final Ethernet other = (Ethernet) obj;
553 if (!this.destinationMACAddress.equals(other.destinationMACAddress)) {
554 return false;
555 }
Amit Ghosh764a1b42017-03-18 08:20:06 +0000556 if (this.qInQPriorityCode != other.qInQPriorityCode) {
557 return false;
558 }
559 if (this.qinqVID != other.qinqVID) {
560 return false;
561 }
alshabibc4901cd2014-09-05 16:50:40 -0700562 if (this.priorityCode != other.priorityCode) {
563 return false;
564 }
565 if (this.vlanID != other.vlanID) {
566 return false;
567 }
568 if (this.etherType != other.etherType) {
569 return false;
570 }
571 if (this.pad != other.pad) {
572 return false;
573 }
574 if (!this.sourceMACAddress.equals(other.sourceMACAddress)) {
575 return false;
576 }
577 return true;
578 }
579
580 /*
581 * (non-Javadoc)
582 *
583 * @see java.lang.Object#toString(java.lang.Object)
584 */
585 @Override
586 public String toString() {
587
Yuta HIGUCHI2dce08a2017-04-20 21:57:48 -0700588 final StringBuilder sb = new StringBuilder("\n");
alshabibc4901cd2014-09-05 16:50:40 -0700589
590 final IPacket pkt = this.getPayload();
591
592 if (pkt instanceof ARP) {
593 sb.append("arp");
594 } else if (pkt instanceof LLDP) {
595 sb.append("lldp");
596 } else if (pkt instanceof ICMP) {
597 sb.append("icmp");
598 } else if (pkt instanceof IPv4) {
599 sb.append("ip");
600 } else if (pkt instanceof DHCP) {
601 sb.append("dhcp");
602 } else {
Pier Ventre48ca5192016-11-28 16:52:24 -0800603 /*
604 * When we don't know the protocol, we print using
605 * the well known hex format instead of a decimal
606 * value.
607 */
608 sb.append(String.format(HEX_PROTO,
609 Integer.toHexString(this.getEtherType() & 0xffff)));
alshabibc4901cd2014-09-05 16:50:40 -0700610 }
611
Amit Ghosh764a1b42017-03-18 08:20:06 +0000612 if (this.getQinQVID() != Ethernet.VLAN_UNTAGGED) {
613 sb.append("\ndl_qinqVlan: ");
614 sb.append(this.getQinQVID());
615 sb.append("\ndl_qinqVlan_pcp: ");
616 sb.append(this.getQinQPriorityCode());
617 }
618
alshabibc4901cd2014-09-05 16:50:40 -0700619 sb.append("\ndl_vlan: ");
620 if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) {
621 sb.append("untagged");
622 } else {
623 sb.append(this.getVlanID());
624 }
625 sb.append("\ndl_vlan_pcp: ");
626 sb.append(this.getPriorityCode());
627 sb.append("\ndl_src: ");
628 sb.append(bytesToHex(this.getSourceMACAddress()));
629 sb.append("\ndl_dst: ");
630 sb.append(bytesToHex(this.getDestinationMACAddress()));
631
632 if (pkt instanceof ARP) {
633 final ARP p = (ARP) pkt;
634 sb.append("\nnw_src: ");
635 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
636 .getSenderProtocolAddress())));
637 sb.append("\nnw_dst: ");
638 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
639 .getTargetProtocolAddress())));
640 } else if (pkt instanceof LLDP) {
641 sb.append("lldp packet");
642 } else if (pkt instanceof ICMP) {
643 final ICMP icmp = (ICMP) pkt;
644 sb.append("\nicmp_type: ");
645 sb.append(icmp.getIcmpType());
646 sb.append("\nicmp_code: ");
647 sb.append(icmp.getIcmpCode());
648 } else if (pkt instanceof IPv4) {
649 final IPv4 p = (IPv4) pkt;
650 sb.append("\nnw_src: ");
651 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
652 sb.append("\nnw_dst: ");
653 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
654 sb.append("\nnw_tos: ");
655 sb.append(p.getDiffServ());
656 sb.append("\nnw_proto: ");
657 sb.append(p.getProtocol());
658
Charles Chan119eeb52015-10-27 12:40:25 -0700659 IPacket payload = pkt.getPayload();
660 if (payload != null) {
661 if (payload instanceof TCP) {
662 sb.append("\ntp_src: ");
663 sb.append(((TCP) payload).getSourcePort());
664 sb.append("\ntp_dst: ");
665 sb.append(((TCP) payload).getDestinationPort());
alshabibc4901cd2014-09-05 16:50:40 -0700666
Charles Chan119eeb52015-10-27 12:40:25 -0700667 } else if (payload instanceof UDP) {
668 sb.append("\ntp_src: ");
669 sb.append(((UDP) payload).getSourcePort());
670 sb.append("\ntp_dst: ");
671 sb.append(((UDP) payload).getDestinationPort());
672 } else if (payload instanceof ICMP) {
673 final ICMP icmp = (ICMP) payload;
674 sb.append("\nicmp_type: ");
675 sb.append(icmp.getIcmpType());
676 sb.append("\nicmp_code: ");
677 sb.append(icmp.getIcmpCode());
678 }
alshabibc4901cd2014-09-05 16:50:40 -0700679 }
Charles Chan119eeb52015-10-27 12:40:25 -0700680 } else if (pkt instanceof IPv6) {
681 final IPv6 ipv6 = (IPv6) pkt;
682 sb.append("\nipv6_src: ");
683 sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString());
684 sb.append("\nipv6_dst: ");
685 sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString());
686 sb.append("\nipv6_proto: ");
687 sb.append(ipv6.getNextHeader());
alshabibc4901cd2014-09-05 16:50:40 -0700688
Charles Chan119eeb52015-10-27 12:40:25 -0700689 IPacket payload = pkt.getPayload();
690 if (payload != null && payload instanceof ICMP6) {
691 final ICMP6 icmp6 = (ICMP6) payload;
692 sb.append("\nicmp6_type: ");
693 sb.append(icmp6.getIcmpType());
694 sb.append("\nicmp6_code: ");
695 sb.append(icmp6.getIcmpCode());
696
697 payload = payload.getPayload();
698 if (payload != null) {
699 if (payload instanceof NeighborSolicitation) {
700 final NeighborSolicitation ns = (NeighborSolicitation) payload;
701 sb.append("\nns_target_addr: ");
702 sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString());
703 ns.getOptions().forEach(option -> {
704 sb.append("\noption_type: ");
705 sb.append(option.type());
706 sb.append("\noption_data: ");
707 sb.append(bytesToHex(option.data()));
708 });
709 } else if (payload instanceof NeighborAdvertisement) {
710 final NeighborAdvertisement na = (NeighborAdvertisement) payload;
711 sb.append("\nna_target_addr: ");
712 sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString());
713 sb.append("\nna_solicited_flag: ");
714 sb.append(na.getSolicitedFlag());
715 sb.append("\nna_router_flag: ");
716 sb.append(na.getRouterFlag());
717 sb.append("\nna_override_flag: ");
718 sb.append(na.getOverrideFlag());
719 na.getOptions().forEach(option -> {
720 sb.append("\noption_type: ");
721 sb.append(option.type());
722 sb.append("\noption_data: ");
723 sb.append(bytesToHex(option.data()));
724 });
725 } else if (payload instanceof RouterSolicitation) {
726 final RouterSolicitation rs = (RouterSolicitation) payload;
727 sb.append("\nrs");
728 rs.getOptions().forEach(option -> {
729 sb.append("\noption_type: ");
730 sb.append(option.type());
731 sb.append("\noption_data: ");
732 sb.append(bytesToHex(option.data()));
733 });
734 } else if (payload instanceof RouterAdvertisement) {
735 final RouterAdvertisement ra = (RouterAdvertisement) payload;
736 sb.append("\nra_hop_limit: ");
737 sb.append(ra.getCurrentHopLimit());
738 sb.append("\nra_mflag: ");
739 sb.append(ra.getMFlag());
740 sb.append("\nra_oflag: ");
741 sb.append(ra.getOFlag());
742 sb.append("\nra_reachable_time: ");
743 sb.append(ra.getReachableTime());
744 sb.append("\nra_retransmit_time: ");
745 sb.append(ra.getRetransmitTimer());
746 sb.append("\nra_router_lifetime: ");
747 sb.append(ra.getRouterLifetime());
748 ra.getOptions().forEach(option -> {
749 sb.append("\noption_type: ");
750 sb.append(option.type());
751 sb.append("\noption_data: ");
752 sb.append(bytesToHex(option.data()));
753 });
754 } else if (payload instanceof Redirect) {
755 final Redirect rd = (Redirect) payload;
756 sb.append("\nrd_target_addr: ");
757 sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString());
758 rd.getOptions().forEach(option -> {
759 sb.append("\noption_type: ");
760 sb.append(option.type());
761 sb.append("\noption_data: ");
762 sb.append(bytesToHex(option.data()));
763 });
764 }
765 }
alshabibc4901cd2014-09-05 16:50:40 -0700766 }
alshabibc4901cd2014-09-05 16:50:40 -0700767 } else if (pkt instanceof DHCP) {
768 sb.append("\ndhcp packet");
769 } else if (pkt instanceof Data) {
770 sb.append("\ndata packet");
771 } else if (pkt instanceof LLC) {
772 sb.append("\nllc packet");
773 } else {
tom5f18cf32014-09-13 14:10:57 -0700774 sb.append("\nunknown packet");
alshabibc4901cd2014-09-05 16:50:40 -0700775 }
776
777 return sb.toString();
778 }
779
780 public static String bytesToHex(byte[] in) {
781 final StringBuilder builder = new StringBuilder();
782 for (byte b : in) {
783 builder.append(String.format("%02x", b));
784 }
785 return builder.toString();
786 }
787
Jonathan Hart2a655752015-04-07 16:46:33 -0700788 /**
789 * Deserializer function for Ethernet packets.
790 *
791 * @return deserializer function
792 */
793 public static Deserializer<Ethernet> deserializer() {
794 return (data, offset, length) -> {
795 checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
796
797 byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
798
799 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
800 Ethernet eth = new Ethernet();
801 // Read destination MAC address into buffer
802 bb.get(addressBuffer);
803 eth.setDestinationMACAddress(addressBuffer);
804
805 // Read source MAC address into buffer
806 bb.get(addressBuffer);
807 eth.setSourceMACAddress(addressBuffer);
808
809 short ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000810 if (ethType == TYPE_QINQ) {
811 // in this case we excpect 2 VLAN headers
812 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH + VLAN_HEADER_LENGTH);
813 final short tci = bb.getShort();
814 eth.setQinQPriorityCode((byte) (tci >> 13 & 0x07));
815 eth.setQinQVID((short) (tci & 0x0fff));
816 eth.setQinQTPID(TYPE_QINQ);
817 ethType = bb.getShort();
818 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700819 if (ethType == TYPE_VLAN) {
820 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
821 final short tci = bb.getShort();
822 eth.setPriorityCode((byte) (tci >> 13 & 0x07));
823 eth.setVlanID((short) (tci & 0x0fff));
824 ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000825
826 if (ethType == TYPE_VLAN) {
827 // We handle only double tagged packets here and assume that in this case
828 // TYPE_QINQ above was not hit
829 // We put the values retrieved above with TYPE_VLAN in
830 // qInQ fields
831 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
832 eth.setQinQPriorityCode(eth.getPriorityCode());
833 eth.setQinQVID(eth.getVlanID());
834 eth.setQinQTPID(TYPE_VLAN);
835
836 final short innerTci = bb.getShort();
837 eth.setPriorityCode((byte) (innerTci >> 13 & 0x07));
838 eth.setVlanID((short) (innerTci & 0x0fff));
839 ethType = bb.getShort();
840 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700841 } else {
842 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
843 }
844 eth.setEtherType(ethType);
845
846 IPacket payload;
847 Deserializer<? extends IPacket> deserializer;
848 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
849 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
850 } else {
851 deserializer = Data.deserializer();
852 }
853 payload = deserializer.deserialize(data, bb.position(),
854 bb.limit() - bb.position());
855 payload.setParent(eth);
856 eth.setPayload(payload);
857
858 return eth;
859 };
860 }
alshabibc4901cd2014-09-05 16:50:40 -0700861}