blob: 01a4254d64b1b1dc0bb84c47a36be3b9b53d3e9b [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
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070027import com.google.common.collect.ImmutableMap;
28
alshabibc4901cd2014-09-05 16:50:40 -070029import java.nio.ByteBuffer;
30import java.util.Arrays;
alshabibc4901cd2014-09-05 16:50:40 -070031import java.util.Map;
32
Jonathan Hart2a655752015-04-07 16:46:33 -070033import static com.google.common.base.Preconditions.checkNotNull;
34import static org.onlab.packet.PacketUtils.checkHeaderLength;
35import static org.onlab.packet.PacketUtils.checkInput;
alshabibc4901cd2014-09-05 16:50:40 -070036
37/**
Jian Li5fc14292015-12-04 11:30:46 -080038 * Ethernet Packet.
alshabibc4901cd2014-09-05 16:50:40 -070039 */
40public class Ethernet extends BasePacket {
41 private static final String HEXES = "0123456789ABCDEF";
Pier Ventre48ca5192016-11-28 16:52:24 -080042 private static final String HEX_PROTO = "0x%s";
Thomas Vachuska5dd52f72014-11-28 19:27:45 -080043
alshabib7b808c52015-06-26 14:22:24 -070044 public static final short TYPE_ARP = EthType.EtherType.ARP.ethType().toShort();
45 public static final short TYPE_RARP = EthType.EtherType.RARP.ethType().toShort();
46 public static final short TYPE_IPV4 = EthType.EtherType.IPV4.ethType().toShort();
47 public static final short TYPE_IPV6 = EthType.EtherType.IPV6.ethType().toShort();
48 public static final short TYPE_LLDP = EthType.EtherType.LLDP.ethType().toShort();
49 public static final short TYPE_VLAN = EthType.EtherType.VLAN.ethType().toShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +000050 public static final short TYPE_QINQ = EthType.EtherType.QINQ.ethType().toShort();
alshabib7b808c52015-06-26 14:22:24 -070051 public static final short TYPE_BSN = EthType.EtherType.BDDP.ethType().toShort();
52
Jon Hall8c7b06a2017-02-22 13:37:33 -080053 public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();
alshabib7b808c52015-06-26 14:22:24 -070054 public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort();
alshabibcaf1ca22015-06-25 15:18:16 -070055
Jonathan Hart2a655752015-04-07 16:46:33 -070056
alshabibcaf1ca22015-06-25 15:18:16 -070057 public static final short VLAN_UNTAGGED = (short) 0xffff;
Jonathan Hart2a655752015-04-07 16:46:33 -070058
59 public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
60 public static final short VLAN_HEADER_LENGTH = 4; // bytes
61
alshabibc4901cd2014-09-05 16:50:40 -070062 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
Jonathan Hart2a655752015-04-07 16:46:33 -070063
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070064 private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP;
alshabibc4901cd2014-09-05 16:50:40 -070065
66 static {
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070067 ImmutableMap.Builder<Short, Deserializer<? extends IPacket>> builder =
68 ImmutableMap.builder();
69
alshabibcaf1ca22015-06-25 15:18:16 -070070 for (EthType.EtherType ethType : EthType.EtherType.values()) {
alshabib7b808c52015-06-26 14:22:24 -070071 if (ethType.deserializer() != null) {
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070072 builder.put(ethType.ethType().toShort(), ethType.deserializer());
alshabibcaf1ca22015-06-25 15:18:16 -070073 }
74 }
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070075 ETHERTYPE_DESERIALIZER_MAP = builder.build();
alshabibc4901cd2014-09-05 16:50:40 -070076 }
77
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070078 protected MacAddress destinationMACAddress;
79 protected MacAddress sourceMACAddress;
alshabibc4901cd2014-09-05 16:50:40 -070080 protected byte priorityCode;
Amit Ghosh764a1b42017-03-18 08:20:06 +000081 protected byte qInQPriorityCode;
alshabibc4901cd2014-09-05 16:50:40 -070082 protected short vlanID;
Amit Ghosh764a1b42017-03-18 08:20:06 +000083 protected short qinqVID;
84 protected short qinqTPID;
alshabibc4901cd2014-09-05 16:50:40 -070085 protected short etherType;
86 protected boolean pad = false;
87
88 /**
89 * By default, set Ethernet to untagged.
90 */
91 public Ethernet() {
92 super();
93 this.vlanID = Ethernet.VLAN_UNTAGGED;
Amit Ghosh764a1b42017-03-18 08:20:06 +000094 this.qinqVID = Ethernet.VLAN_UNTAGGED;
95 this.qinqTPID = TYPE_QINQ;
alshabibc4901cd2014-09-05 16:50:40 -070096 }
97
98 /**
99 * Gets the destination MAC address.
100 *
101 * @return the destination MAC as a byte array
102 */
103 public byte[] getDestinationMACAddress() {
104 return this.destinationMACAddress.toBytes();
105 }
106
107 /**
108 * Gets the destination MAC address.
109 *
110 * @return the destination MAC
111 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700112 public MacAddress getDestinationMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700113 return this.destinationMACAddress;
114 }
115
116 /**
117 * Sets the destination MAC address.
118 *
tom5f18cf32014-09-13 14:10:57 -0700119 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700120 * @return the Ethernet frame
121 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800122 public Ethernet setDestinationMACAddress(final MacAddress destMac) {
123 this.destinationMACAddress = checkNotNull(destMac);
124 return this;
125 }
126
127 /**
128 * Sets the destination MAC address.
129 *
130 * @param destMac the destination MAC to set
131 * @return the Ethernet frame
132 */
alshabibc4901cd2014-09-05 16:50:40 -0700133 public Ethernet setDestinationMACAddress(final byte[] destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700134 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700135 return this;
136 }
137
138 /**
139 * Sets the destination MAC address.
140 *
tom5f18cf32014-09-13 14:10:57 -0700141 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700142 * @return the Ethernet frame
143 */
144 public Ethernet setDestinationMACAddress(final String destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700145 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700146 return this;
147 }
148
149 /**
150 * Gets the source MAC address.
151 *
152 * @return the source MACAddress as a byte array
153 */
154 public byte[] getSourceMACAddress() {
155 return this.sourceMACAddress.toBytes();
156 }
157
158 /**
159 * Gets the source MAC address.
160 *
161 * @return the source MACAddress
162 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700163 public MacAddress getSourceMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700164 return this.sourceMACAddress;
165 }
166
167 /**
168 * Sets the source MAC address.
169 *
tom5f18cf32014-09-13 14:10:57 -0700170 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700171 * @return the Ethernet frame
172 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800173 public Ethernet setSourceMACAddress(final MacAddress sourceMac) {
174 this.sourceMACAddress = checkNotNull(sourceMac);
175 return this;
176 }
177
178 /**
179 * Sets the source MAC address.
180 *
181 * @param sourceMac the source MAC to set
182 * @return the Ethernet frame
183 */
alshabibc4901cd2014-09-05 16:50:40 -0700184 public Ethernet setSourceMACAddress(final byte[] sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700185 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700186 return this;
187 }
188
189 /**
190 * Sets the source MAC address.
191 *
tom5f18cf32014-09-13 14:10:57 -0700192 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700193 * @return the Ethernet frame
194 */
195 public Ethernet setSourceMACAddress(final String sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700196 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700197 return this;
198 }
199
200 /**
201 * Gets the priority code.
202 *
203 * @return the priorityCode
204 */
205 public byte getPriorityCode() {
206 return this.priorityCode;
207 }
208
209 /**
210 * Sets the priority code.
211 *
tom5f18cf32014-09-13 14:10:57 -0700212 * @param priority the priorityCode to set
alshabibc4901cd2014-09-05 16:50:40 -0700213 * @return the Ethernet frame
214 */
215 public Ethernet setPriorityCode(final byte priority) {
216 this.priorityCode = priority;
217 return this;
218 }
219
220 /**
Amit Ghosh764a1b42017-03-18 08:20:06 +0000221 * Gets the QinQ priority code.
222 *
223 * @return the qInQPriorityCode
224 */
225 public byte getQinQPriorityCode() {
226 return this.qInQPriorityCode;
227 }
228
229 /**
230 * Sets the QinQ priority code.
231 *
232 * @param priority the priorityCode to set
233 * @return the Ethernet frame
234 */
235 public Ethernet setQinQPriorityCode(final byte priority) {
236 this.qInQPriorityCode = priority;
237 return this;
238 }
239
240 /**
alshabibc4901cd2014-09-05 16:50:40 -0700241 * Gets the VLAN ID.
242 *
243 * @return the vlanID
244 */
245 public short getVlanID() {
246 return this.vlanID;
247 }
248
249 /**
250 * Sets the VLAN ID.
251 *
tom5f18cf32014-09-13 14:10:57 -0700252 * @param vlan the vlanID to set
alshabibc4901cd2014-09-05 16:50:40 -0700253 * @return the Ethernet frame
254 */
255 public Ethernet setVlanID(final short vlan) {
256 this.vlanID = vlan;
257 return this;
258 }
259
260 /**
Amit Ghosh764a1b42017-03-18 08:20:06 +0000261 * Gets the QinQ VLAN ID.
262 *
263 * @return the QinQ vlanID
264 */
265 public short getQinQVID() {
266 return this.qinqVID;
267 }
268
269 /**
270 * Sets the QinQ VLAN ID.
271 *
272 * @param vlan the vlanID to set
273 * @return the Ethernet frame
274 */
275 public Ethernet setQinQVID(final short vlan) {
276 this.qinqVID = vlan;
277 return this;
278 }
279 /**
280 * Gets the QinQ TPID.
281 *
282 * @return the QinQ TPID
283 */
284 public short getQinQTPID() {
285 return this.qinqTPID;
286 }
287
288 /**
289 * Sets the QinQ TPID.
290 *
291 * @param tpId the TPID to set
292 * @return the Ethernet frame
293 */
294 public Ethernet setQinQTPID(final short tpId) {
295 if (tpId != TYPE_VLAN && tpId != TYPE_QINQ) {
296 return null;
297 }
298 this.qinqTPID = tpId;
299 return this;
300 }
301 /**
alshabibc4901cd2014-09-05 16:50:40 -0700302 * Gets the Ethernet type.
303 *
304 * @return the etherType
305 */
306 public short getEtherType() {
307 return this.etherType;
308 }
309
310 /**
311 * Sets the Ethernet type.
312 *
tom5f18cf32014-09-13 14:10:57 -0700313 * @param ethType the etherType to set
alshabibc4901cd2014-09-05 16:50:40 -0700314 * @return the Ethernet frame
315 */
316 public Ethernet setEtherType(final short ethType) {
317 this.etherType = ethType;
318 return this;
319 }
320
321 /**
322 * @return True if the Ethernet frame is broadcast, false otherwise
323 */
324 public boolean isBroadcast() {
325 assert this.destinationMACAddress.length() == 6;
326 return this.destinationMACAddress.isBroadcast();
327 }
328
329 /**
330 * @return True is the Ethernet frame is multicast, False otherwise
331 */
332 public boolean isMulticast() {
333 return this.destinationMACAddress.isMulticast();
334 }
335
336 /**
337 * Pad this packet to 60 bytes minimum, filling with zeros?
338 *
339 * @return the pad
340 */
341 public boolean isPad() {
342 return this.pad;
343 }
344
345 /**
346 * Pad this packet to 60 bytes minimum, filling with zeros?
347 *
tom5f18cf32014-09-13 14:10:57 -0700348 * @param pd
alshabibc4901cd2014-09-05 16:50:40 -0700349 * the pad to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800350 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700351 */
352 public Ethernet setPad(final boolean pd) {
353 this.pad = pd;
354 return this;
355 }
356
357 @Override
358 public byte[] serialize() {
359 byte[] payloadData = null;
360 if (this.payload != null) {
361 this.payload.setParent(this);
362 payloadData = this.payload.serialize();
363 }
364 int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
Amit Ghosh764a1b42017-03-18 08:20:06 +0000365 + (this.qinqVID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
alshabibc4901cd2014-09-05 16:50:40 -0700366 + (payloadData == null ? 0 : payloadData.length);
367 if (this.pad && length < 60) {
368 length = 60;
369 }
370 final byte[] data = new byte[length];
371 final ByteBuffer bb = ByteBuffer.wrap(data);
372 bb.put(this.destinationMACAddress.toBytes());
373 bb.put(this.sourceMACAddress.toBytes());
Amit Ghosh764a1b42017-03-18 08:20:06 +0000374 if (this.qinqVID != Ethernet.VLAN_UNTAGGED) {
375 bb.putShort(this.qinqTPID);
376 bb.putShort((short) (this.qInQPriorityCode << 13 | this.qinqVID & 0x0fff));
377 }
alshabibc4901cd2014-09-05 16:50:40 -0700378 if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
alshabib10580802015-02-18 18:30:33 -0800379 bb.putShort(TYPE_VLAN);
alshabibc4901cd2014-09-05 16:50:40 -0700380 bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
381 }
382 bb.putShort(this.etherType);
383 if (payloadData != null) {
384 bb.put(payloadData);
385 }
386 if (this.pad) {
387 Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
388 }
389 return data;
390 }
391
392 @Override
393 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700394 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700395 if (length <= 0) {
396 return null;
397 }
398 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
399 if (this.destinationMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700400 this.destinationMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700401 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700402 final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700403 bb.get(dstAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700404 this.destinationMACAddress = MacAddress.valueOf(dstAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700405
406 if (this.sourceMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700407 this.sourceMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700408 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700409 final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700410 bb.get(srcAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700411 this.sourceMACAddress = MacAddress.valueOf(srcAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700412
413 short ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000414 if (ethType == TYPE_QINQ) {
415 final short tci = bb.getShort();
416 this.qInQPriorityCode = (byte) (tci >> 13 & 0x07);
417 this.qinqVID = (short) (tci & 0x0fff);
418 this.qinqTPID = TYPE_QINQ;
419 ethType = bb.getShort();
420 }
421
alshabib10580802015-02-18 18:30:33 -0800422 if (ethType == TYPE_VLAN) {
alshabibc4901cd2014-09-05 16:50:40 -0700423 final short tci = bb.getShort();
424 this.priorityCode = (byte) (tci >> 13 & 0x07);
425 this.vlanID = (short) (tci & 0x0fff);
426 ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000427
428 // there might be one more tag with 1q TPID
429 if (ethType == TYPE_VLAN) {
430 // packet is double tagged with 1q TPIDs
431 // We handle only double tagged packets here and assume that in this case
432 // TYPE_QINQ above was not hit
433 // We put the values retrieved above with TYPE_VLAN in
434 // qInQ fields
435 this.qInQPriorityCode = this.priorityCode;
436 this.qinqVID = this.vlanID;
437 this.qinqTPID = TYPE_VLAN;
438
439 final short innerTci = bb.getShort();
440 this.priorityCode = (byte) (innerTci >> 13 & 0x07);
441 this.vlanID = (short) (innerTci & 0x0fff);
442 ethType = bb.getShort();
443 }
alshabibc4901cd2014-09-05 16:50:40 -0700444 } else {
445 this.vlanID = Ethernet.VLAN_UNTAGGED;
446 }
447 this.etherType = ethType;
448
449 IPacket payload;
Jonathan Hart2a655752015-04-07 16:46:33 -0700450 Deserializer<? extends IPacket> deserializer;
451 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
452 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
alshabibc4901cd2014-09-05 16:50:40 -0700453 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700454 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700455 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700456 try {
457 this.payload = deserializer.deserialize(data, bb.position(),
458 bb.limit() - bb.position());
459 this.payload.setParent(this);
460 } catch (DeserializationException e) {
461 return this;
462 }
alshabibc4901cd2014-09-05 16:50:40 -0700463 return this;
464 }
465
466 /**
467 * Checks to see if a string is a valid MAC address.
468 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800469 * @param macAddress string to test if it is a valid MAC
alshabibc4901cd2014-09-05 16:50:40 -0700470 * @return True if macAddress is a valid MAC, False otherwise
471 */
472 public static boolean isMACAddress(final String macAddress) {
473 final String[] macBytes = macAddress.split(":");
474 if (macBytes.length != 6) {
475 return false;
476 }
477 for (int i = 0; i < 6; ++i) {
478 if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
479 || Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(
480 1)) == -1) {
481 return false;
482 }
483 }
484 return true;
485 }
486
487 /**
488 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
489 * matter, and returns a corresponding byte[].
490 *
491 * @param macAddress
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800492 * The MAC address to convert into a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700493 * @return The macAddress as a byte array
494 */
495 public static byte[] toMACAddress(final String macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700496 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700497 }
498
499 /**
500 * Accepts a MAC address and returns the corresponding long, where the MAC
501 * bytes are set on the lower order bytes of the long.
502 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800503 * @param macAddress MAC address as a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700504 * @return a long containing the mac address bytes
505 */
506 public static long toLong(final byte[] macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700507 return MacAddress.valueOf(macAddress).toLong();
alshabibc4901cd2014-09-05 16:50:40 -0700508 }
509
510 /**
511 * Converts a long MAC address to a byte array.
512 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800513 * @param macAddress MAC address set on the lower order bytes of the long
alshabibc4901cd2014-09-05 16:50:40 -0700514 * @return the bytes of the mac address
515 */
516 public static byte[] toByteArray(final long macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700517 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700518 }
519
520 /*
521 * (non-Javadoc)
522 *
523 * @see java.lang.Object#hashCode()
524 */
525 @Override
526 public int hashCode() {
527 final int prime = 7867;
528 int result = super.hashCode();
529 result = prime * result + this.destinationMACAddress.hashCode();
530 result = prime * result + this.etherType;
Amit Ghosh764a1b42017-03-18 08:20:06 +0000531 result = prime * result + this.qinqVID;
532 result = prime * result + this.qInQPriorityCode;
alshabibc4901cd2014-09-05 16:50:40 -0700533 result = prime * result + this.vlanID;
534 result = prime * result + this.priorityCode;
535 result = prime * result + (this.pad ? 1231 : 1237);
536 result = prime * result + this.sourceMACAddress.hashCode();
537 return result;
538 }
539
540 /*
541 * (non-Javadoc)
542 *
543 * @see java.lang.Object#equals(java.lang.Object)
544 */
545 @Override
546 public boolean equals(final Object obj) {
547 if (this == obj) {
548 return true;
549 }
550 if (!super.equals(obj)) {
551 return false;
552 }
553 if (!(obj instanceof Ethernet)) {
554 return false;
555 }
556 final Ethernet other = (Ethernet) obj;
557 if (!this.destinationMACAddress.equals(other.destinationMACAddress)) {
558 return false;
559 }
Amit Ghosh764a1b42017-03-18 08:20:06 +0000560 if (this.qInQPriorityCode != other.qInQPriorityCode) {
561 return false;
562 }
563 if (this.qinqVID != other.qinqVID) {
564 return false;
565 }
alshabibc4901cd2014-09-05 16:50:40 -0700566 if (this.priorityCode != other.priorityCode) {
567 return false;
568 }
569 if (this.vlanID != other.vlanID) {
570 return false;
571 }
572 if (this.etherType != other.etherType) {
573 return false;
574 }
575 if (this.pad != other.pad) {
576 return false;
577 }
578 if (!this.sourceMACAddress.equals(other.sourceMACAddress)) {
579 return false;
580 }
581 return true;
582 }
583
584 /*
585 * (non-Javadoc)
586 *
587 * @see java.lang.Object#toString(java.lang.Object)
588 */
589 @Override
590 public String toString() {
591
Yuta HIGUCHI2dce08a2017-04-20 21:57:48 -0700592 final StringBuilder sb = new StringBuilder("\n");
alshabibc4901cd2014-09-05 16:50:40 -0700593
594 final IPacket pkt = this.getPayload();
595
596 if (pkt instanceof ARP) {
597 sb.append("arp");
598 } else if (pkt instanceof LLDP) {
599 sb.append("lldp");
600 } else if (pkt instanceof ICMP) {
601 sb.append("icmp");
602 } else if (pkt instanceof IPv4) {
603 sb.append("ip");
604 } else if (pkt instanceof DHCP) {
605 sb.append("dhcp");
606 } else {
Pier Ventre48ca5192016-11-28 16:52:24 -0800607 /*
608 * When we don't know the protocol, we print using
609 * the well known hex format instead of a decimal
610 * value.
611 */
612 sb.append(String.format(HEX_PROTO,
613 Integer.toHexString(this.getEtherType() & 0xffff)));
alshabibc4901cd2014-09-05 16:50:40 -0700614 }
615
Amit Ghosh764a1b42017-03-18 08:20:06 +0000616 if (this.getQinQVID() != Ethernet.VLAN_UNTAGGED) {
617 sb.append("\ndl_qinqVlan: ");
618 sb.append(this.getQinQVID());
619 sb.append("\ndl_qinqVlan_pcp: ");
620 sb.append(this.getQinQPriorityCode());
621 }
622
alshabibc4901cd2014-09-05 16:50:40 -0700623 sb.append("\ndl_vlan: ");
624 if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) {
625 sb.append("untagged");
626 } else {
627 sb.append(this.getVlanID());
628 }
629 sb.append("\ndl_vlan_pcp: ");
630 sb.append(this.getPriorityCode());
631 sb.append("\ndl_src: ");
632 sb.append(bytesToHex(this.getSourceMACAddress()));
633 sb.append("\ndl_dst: ");
634 sb.append(bytesToHex(this.getDestinationMACAddress()));
635
636 if (pkt instanceof ARP) {
637 final ARP p = (ARP) pkt;
638 sb.append("\nnw_src: ");
639 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
640 .getSenderProtocolAddress())));
641 sb.append("\nnw_dst: ");
642 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
643 .getTargetProtocolAddress())));
644 } else if (pkt instanceof LLDP) {
645 sb.append("lldp packet");
646 } else if (pkt instanceof ICMP) {
647 final ICMP icmp = (ICMP) pkt;
648 sb.append("\nicmp_type: ");
649 sb.append(icmp.getIcmpType());
650 sb.append("\nicmp_code: ");
651 sb.append(icmp.getIcmpCode());
652 } else if (pkt instanceof IPv4) {
653 final IPv4 p = (IPv4) pkt;
654 sb.append("\nnw_src: ");
655 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
656 sb.append("\nnw_dst: ");
657 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
658 sb.append("\nnw_tos: ");
659 sb.append(p.getDiffServ());
660 sb.append("\nnw_proto: ");
661 sb.append(p.getProtocol());
662
Charles Chan119eeb52015-10-27 12:40:25 -0700663 IPacket payload = pkt.getPayload();
664 if (payload != null) {
665 if (payload instanceof TCP) {
666 sb.append("\ntp_src: ");
667 sb.append(((TCP) payload).getSourcePort());
668 sb.append("\ntp_dst: ");
669 sb.append(((TCP) payload).getDestinationPort());
alshabibc4901cd2014-09-05 16:50:40 -0700670
Charles Chan119eeb52015-10-27 12:40:25 -0700671 } else if (payload instanceof UDP) {
672 sb.append("\ntp_src: ");
673 sb.append(((UDP) payload).getSourcePort());
674 sb.append("\ntp_dst: ");
675 sb.append(((UDP) payload).getDestinationPort());
676 } else if (payload instanceof ICMP) {
677 final ICMP icmp = (ICMP) payload;
678 sb.append("\nicmp_type: ");
679 sb.append(icmp.getIcmpType());
680 sb.append("\nicmp_code: ");
681 sb.append(icmp.getIcmpCode());
682 }
alshabibc4901cd2014-09-05 16:50:40 -0700683 }
Charles Chan119eeb52015-10-27 12:40:25 -0700684 } else if (pkt instanceof IPv6) {
685 final IPv6 ipv6 = (IPv6) pkt;
686 sb.append("\nipv6_src: ");
687 sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString());
688 sb.append("\nipv6_dst: ");
689 sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString());
690 sb.append("\nipv6_proto: ");
691 sb.append(ipv6.getNextHeader());
alshabibc4901cd2014-09-05 16:50:40 -0700692
Charles Chan119eeb52015-10-27 12:40:25 -0700693 IPacket payload = pkt.getPayload();
694 if (payload != null && payload instanceof ICMP6) {
695 final ICMP6 icmp6 = (ICMP6) payload;
696 sb.append("\nicmp6_type: ");
697 sb.append(icmp6.getIcmpType());
698 sb.append("\nicmp6_code: ");
699 sb.append(icmp6.getIcmpCode());
700
701 payload = payload.getPayload();
702 if (payload != null) {
703 if (payload instanceof NeighborSolicitation) {
704 final NeighborSolicitation ns = (NeighborSolicitation) payload;
705 sb.append("\nns_target_addr: ");
706 sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString());
707 ns.getOptions().forEach(option -> {
708 sb.append("\noption_type: ");
709 sb.append(option.type());
710 sb.append("\noption_data: ");
711 sb.append(bytesToHex(option.data()));
712 });
713 } else if (payload instanceof NeighborAdvertisement) {
714 final NeighborAdvertisement na = (NeighborAdvertisement) payload;
715 sb.append("\nna_target_addr: ");
716 sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString());
717 sb.append("\nna_solicited_flag: ");
718 sb.append(na.getSolicitedFlag());
719 sb.append("\nna_router_flag: ");
720 sb.append(na.getRouterFlag());
721 sb.append("\nna_override_flag: ");
722 sb.append(na.getOverrideFlag());
723 na.getOptions().forEach(option -> {
724 sb.append("\noption_type: ");
725 sb.append(option.type());
726 sb.append("\noption_data: ");
727 sb.append(bytesToHex(option.data()));
728 });
729 } else if (payload instanceof RouterSolicitation) {
730 final RouterSolicitation rs = (RouterSolicitation) payload;
731 sb.append("\nrs");
732 rs.getOptions().forEach(option -> {
733 sb.append("\noption_type: ");
734 sb.append(option.type());
735 sb.append("\noption_data: ");
736 sb.append(bytesToHex(option.data()));
737 });
738 } else if (payload instanceof RouterAdvertisement) {
739 final RouterAdvertisement ra = (RouterAdvertisement) payload;
740 sb.append("\nra_hop_limit: ");
741 sb.append(ra.getCurrentHopLimit());
742 sb.append("\nra_mflag: ");
743 sb.append(ra.getMFlag());
744 sb.append("\nra_oflag: ");
745 sb.append(ra.getOFlag());
746 sb.append("\nra_reachable_time: ");
747 sb.append(ra.getReachableTime());
748 sb.append("\nra_retransmit_time: ");
749 sb.append(ra.getRetransmitTimer());
750 sb.append("\nra_router_lifetime: ");
751 sb.append(ra.getRouterLifetime());
752 ra.getOptions().forEach(option -> {
753 sb.append("\noption_type: ");
754 sb.append(option.type());
755 sb.append("\noption_data: ");
756 sb.append(bytesToHex(option.data()));
757 });
758 } else if (payload instanceof Redirect) {
759 final Redirect rd = (Redirect) payload;
760 sb.append("\nrd_target_addr: ");
761 sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString());
762 rd.getOptions().forEach(option -> {
763 sb.append("\noption_type: ");
764 sb.append(option.type());
765 sb.append("\noption_data: ");
766 sb.append(bytesToHex(option.data()));
767 });
768 }
769 }
alshabibc4901cd2014-09-05 16:50:40 -0700770 }
alshabibc4901cd2014-09-05 16:50:40 -0700771 } else if (pkt instanceof DHCP) {
772 sb.append("\ndhcp packet");
773 } else if (pkt instanceof Data) {
774 sb.append("\ndata packet");
775 } else if (pkt instanceof LLC) {
776 sb.append("\nllc packet");
777 } else {
tom5f18cf32014-09-13 14:10:57 -0700778 sb.append("\nunknown packet");
alshabibc4901cd2014-09-05 16:50:40 -0700779 }
780
781 return sb.toString();
782 }
783
784 public static String bytesToHex(byte[] in) {
785 final StringBuilder builder = new StringBuilder();
786 for (byte b : in) {
787 builder.append(String.format("%02x", b));
788 }
789 return builder.toString();
790 }
791
Jonathan Hart2a655752015-04-07 16:46:33 -0700792 /**
793 * Deserializer function for Ethernet packets.
794 *
795 * @return deserializer function
796 */
797 public static Deserializer<Ethernet> deserializer() {
798 return (data, offset, length) -> {
799 checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
800
801 byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
802
803 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
804 Ethernet eth = new Ethernet();
805 // Read destination MAC address into buffer
806 bb.get(addressBuffer);
807 eth.setDestinationMACAddress(addressBuffer);
808
809 // Read source MAC address into buffer
810 bb.get(addressBuffer);
811 eth.setSourceMACAddress(addressBuffer);
812
813 short ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000814 if (ethType == TYPE_QINQ) {
815 // in this case we excpect 2 VLAN headers
816 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH + VLAN_HEADER_LENGTH);
817 final short tci = bb.getShort();
818 eth.setQinQPriorityCode((byte) (tci >> 13 & 0x07));
819 eth.setQinQVID((short) (tci & 0x0fff));
820 eth.setQinQTPID(TYPE_QINQ);
821 ethType = bb.getShort();
822 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700823 if (ethType == TYPE_VLAN) {
824 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
825 final short tci = bb.getShort();
826 eth.setPriorityCode((byte) (tci >> 13 & 0x07));
827 eth.setVlanID((short) (tci & 0x0fff));
828 ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000829
830 if (ethType == TYPE_VLAN) {
831 // We handle only double tagged packets here and assume that in this case
832 // TYPE_QINQ above was not hit
833 // We put the values retrieved above with TYPE_VLAN in
834 // qInQ fields
835 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
836 eth.setQinQPriorityCode(eth.getPriorityCode());
837 eth.setQinQVID(eth.getVlanID());
838 eth.setQinQTPID(TYPE_VLAN);
839
840 final short innerTci = bb.getShort();
841 eth.setPriorityCode((byte) (innerTci >> 13 & 0x07));
842 eth.setVlanID((short) (innerTci & 0x0fff));
843 ethType = bb.getShort();
844 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700845 } else {
846 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
847 }
848 eth.setEtherType(ethType);
849
850 IPacket payload;
851 Deserializer<? extends IPacket> deserializer;
852 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
853 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
854 } else {
855 deserializer = Data.deserializer();
856 }
857 payload = deserializer.deserialize(data, bb.position(),
858 bb.limit() - bb.position());
859 payload.setParent(eth);
860 eth.setPayload(payload);
861
862 return eth;
863 };
864 }
alshabibc4901cd2014-09-05 16:50:40 -0700865}