blob: e3af9601d8655692d5bf51d4befcc7270918e67e [file] [log] [blame]
Thomas Vachuska24c849c2014-10-27 09:53:05 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
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();
Gustavo Silva2bcc8052021-01-22 13:48:30 -030052 public static final short TYPE_PPPOED = EthType.EtherType.PPPoED.ethType().toShort();
alshabib7b808c52015-06-26 14:22:24 -070053
Jon Hall8c7b06a2017-02-22 13:37:33 -080054 public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();
alshabib7b808c52015-06-26 14:22:24 -070055 public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort();
alshabibcaf1ca22015-06-25 15:18:16 -070056
Jonathan Hart2a655752015-04-07 16:46:33 -070057
alshabibcaf1ca22015-06-25 15:18:16 -070058 public static final short VLAN_UNTAGGED = (short) 0xffff;
Jonathan Hart2a655752015-04-07 16:46:33 -070059
60 public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
61 public static final short VLAN_HEADER_LENGTH = 4; // bytes
62
alshabibc4901cd2014-09-05 16:50:40 -070063 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
Jonathan Hart2a655752015-04-07 16:46:33 -070064
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070065 private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP;
alshabibc4901cd2014-09-05 16:50:40 -070066
67 static {
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070068 ImmutableMap.Builder<Short, Deserializer<? extends IPacket>> builder =
69 ImmutableMap.builder();
70
alshabibcaf1ca22015-06-25 15:18:16 -070071 for (EthType.EtherType ethType : EthType.EtherType.values()) {
alshabib7b808c52015-06-26 14:22:24 -070072 if (ethType.deserializer() != null) {
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070073 builder.put(ethType.ethType().toShort(), ethType.deserializer());
alshabibcaf1ca22015-06-25 15:18:16 -070074 }
75 }
Yuta HIGUCHIbfc2e922017-06-07 21:46:05 -070076 ETHERTYPE_DESERIALIZER_MAP = builder.build();
alshabibc4901cd2014-09-05 16:50:40 -070077 }
78
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070079 protected MacAddress destinationMACAddress;
80 protected MacAddress sourceMACAddress;
alshabibc4901cd2014-09-05 16:50:40 -070081 protected byte priorityCode;
Amit Ghosh764a1b42017-03-18 08:20:06 +000082 protected byte qInQPriorityCode;
alshabibc4901cd2014-09-05 16:50:40 -070083 protected short vlanID;
Amit Ghosh764a1b42017-03-18 08:20:06 +000084 protected short qinqVID;
85 protected short qinqTPID;
alshabibc4901cd2014-09-05 16:50:40 -070086 protected short etherType;
87 protected boolean pad = false;
88
89 /**
90 * By default, set Ethernet to untagged.
91 */
92 public Ethernet() {
93 super();
94 this.vlanID = Ethernet.VLAN_UNTAGGED;
Amit Ghosh764a1b42017-03-18 08:20:06 +000095 this.qinqVID = Ethernet.VLAN_UNTAGGED;
96 this.qinqTPID = TYPE_QINQ;
alshabibc4901cd2014-09-05 16:50:40 -070097 }
98
99 /**
100 * Gets the destination MAC address.
101 *
102 * @return the destination MAC as a byte array
103 */
104 public byte[] getDestinationMACAddress() {
105 return this.destinationMACAddress.toBytes();
106 }
107
108 /**
109 * Gets the destination MAC address.
110 *
111 * @return the destination MAC
112 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700113 public MacAddress getDestinationMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700114 return this.destinationMACAddress;
115 }
116
117 /**
118 * Sets the destination MAC address.
119 *
tom5f18cf32014-09-13 14:10:57 -0700120 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700121 * @return the Ethernet frame
122 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800123 public Ethernet setDestinationMACAddress(final MacAddress destMac) {
124 this.destinationMACAddress = checkNotNull(destMac);
125 return this;
126 }
127
128 /**
129 * Sets the destination MAC address.
130 *
131 * @param destMac the destination MAC to set
132 * @return the Ethernet frame
133 */
alshabibc4901cd2014-09-05 16:50:40 -0700134 public Ethernet setDestinationMACAddress(final byte[] destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700135 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700136 return this;
137 }
138
139 /**
140 * Sets the destination MAC address.
141 *
tom5f18cf32014-09-13 14:10:57 -0700142 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700143 * @return the Ethernet frame
144 */
145 public Ethernet setDestinationMACAddress(final String destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700146 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700147 return this;
148 }
149
150 /**
151 * Gets the source MAC address.
152 *
153 * @return the source MACAddress as a byte array
154 */
155 public byte[] getSourceMACAddress() {
156 return this.sourceMACAddress.toBytes();
157 }
158
159 /**
160 * Gets the source MAC address.
161 *
162 * @return the source MACAddress
163 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700164 public MacAddress getSourceMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700165 return this.sourceMACAddress;
166 }
167
168 /**
169 * Sets the source MAC address.
170 *
tom5f18cf32014-09-13 14:10:57 -0700171 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700172 * @return the Ethernet frame
173 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800174 public Ethernet setSourceMACAddress(final MacAddress sourceMac) {
175 this.sourceMACAddress = checkNotNull(sourceMac);
176 return this;
177 }
178
179 /**
180 * Sets the source MAC address.
181 *
182 * @param sourceMac the source MAC to set
183 * @return the Ethernet frame
184 */
alshabibc4901cd2014-09-05 16:50:40 -0700185 public Ethernet setSourceMACAddress(final byte[] sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700186 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700187 return this;
188 }
189
190 /**
191 * Sets the source MAC address.
192 *
tom5f18cf32014-09-13 14:10:57 -0700193 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700194 * @return the Ethernet frame
195 */
196 public Ethernet setSourceMACAddress(final String sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700197 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700198 return this;
199 }
200
201 /**
202 * Gets the priority code.
203 *
204 * @return the priorityCode
205 */
206 public byte getPriorityCode() {
207 return this.priorityCode;
208 }
209
210 /**
211 * Sets the priority code.
212 *
tom5f18cf32014-09-13 14:10:57 -0700213 * @param priority the priorityCode to set
alshabibc4901cd2014-09-05 16:50:40 -0700214 * @return the Ethernet frame
215 */
216 public Ethernet setPriorityCode(final byte priority) {
217 this.priorityCode = priority;
218 return this;
219 }
220
221 /**
Amit Ghosh764a1b42017-03-18 08:20:06 +0000222 * Gets the QinQ priority code.
223 *
224 * @return the qInQPriorityCode
225 */
226 public byte getQinQPriorityCode() {
227 return this.qInQPriorityCode;
228 }
229
230 /**
231 * Sets the QinQ priority code.
232 *
233 * @param priority the priorityCode to set
234 * @return the Ethernet frame
235 */
236 public Ethernet setQinQPriorityCode(final byte priority) {
237 this.qInQPriorityCode = priority;
238 return this;
239 }
240
241 /**
alshabibc4901cd2014-09-05 16:50:40 -0700242 * Gets the VLAN ID.
243 *
244 * @return the vlanID
245 */
246 public short getVlanID() {
247 return this.vlanID;
248 }
249
250 /**
251 * Sets the VLAN ID.
252 *
tom5f18cf32014-09-13 14:10:57 -0700253 * @param vlan the vlanID to set
alshabibc4901cd2014-09-05 16:50:40 -0700254 * @return the Ethernet frame
255 */
256 public Ethernet setVlanID(final short vlan) {
257 this.vlanID = vlan;
258 return this;
259 }
260
261 /**
Amit Ghosh764a1b42017-03-18 08:20:06 +0000262 * Gets the QinQ VLAN ID.
263 *
264 * @return the QinQ vlanID
265 */
266 public short getQinQVID() {
267 return this.qinqVID;
268 }
269
270 /**
271 * Sets the QinQ VLAN ID.
272 *
273 * @param vlan the vlanID to set
274 * @return the Ethernet frame
275 */
276 public Ethernet setQinQVID(final short vlan) {
277 this.qinqVID = vlan;
278 return this;
279 }
280 /**
281 * Gets the QinQ TPID.
282 *
283 * @return the QinQ TPID
284 */
285 public short getQinQTPID() {
286 return this.qinqTPID;
287 }
288
289 /**
290 * Sets the QinQ TPID.
291 *
292 * @param tpId the TPID to set
293 * @return the Ethernet frame
294 */
295 public Ethernet setQinQTPID(final short tpId) {
296 if (tpId != TYPE_VLAN && tpId != TYPE_QINQ) {
297 return null;
298 }
299 this.qinqTPID = tpId;
300 return this;
301 }
302 /**
alshabibc4901cd2014-09-05 16:50:40 -0700303 * Gets the Ethernet type.
304 *
305 * @return the etherType
306 */
307 public short getEtherType() {
308 return this.etherType;
309 }
310
311 /**
312 * Sets the Ethernet type.
313 *
tom5f18cf32014-09-13 14:10:57 -0700314 * @param ethType the etherType to set
alshabibc4901cd2014-09-05 16:50:40 -0700315 * @return the Ethernet frame
316 */
317 public Ethernet setEtherType(final short ethType) {
318 this.etherType = ethType;
319 return this;
320 }
321
322 /**
323 * @return True if the Ethernet frame is broadcast, false otherwise
324 */
325 public boolean isBroadcast() {
326 assert this.destinationMACAddress.length() == 6;
327 return this.destinationMACAddress.isBroadcast();
328 }
329
330 /**
331 * @return True is the Ethernet frame is multicast, False otherwise
332 */
333 public boolean isMulticast() {
334 return this.destinationMACAddress.isMulticast();
335 }
336
337 /**
338 * Pad this packet to 60 bytes minimum, filling with zeros?
339 *
340 * @return the pad
341 */
342 public boolean isPad() {
343 return this.pad;
344 }
345
346 /**
347 * Pad this packet to 60 bytes minimum, filling with zeros?
348 *
tom5f18cf32014-09-13 14:10:57 -0700349 * @param pd
alshabibc4901cd2014-09-05 16:50:40 -0700350 * the pad to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800351 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700352 */
353 public Ethernet setPad(final boolean pd) {
354 this.pad = pd;
355 return this;
356 }
357
358 @Override
359 public byte[] serialize() {
360 byte[] payloadData = null;
361 if (this.payload != null) {
362 this.payload.setParent(this);
363 payloadData = this.payload.serialize();
364 }
365 int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
Amit Ghosh764a1b42017-03-18 08:20:06 +0000366 + (this.qinqVID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
alshabibc4901cd2014-09-05 16:50:40 -0700367 + (payloadData == null ? 0 : payloadData.length);
368 if (this.pad && length < 60) {
369 length = 60;
370 }
371 final byte[] data = new byte[length];
372 final ByteBuffer bb = ByteBuffer.wrap(data);
373 bb.put(this.destinationMACAddress.toBytes());
374 bb.put(this.sourceMACAddress.toBytes());
Amit Ghosh764a1b42017-03-18 08:20:06 +0000375 if (this.qinqVID != Ethernet.VLAN_UNTAGGED) {
376 bb.putShort(this.qinqTPID);
377 bb.putShort((short) (this.qInQPriorityCode << 13 | this.qinqVID & 0x0fff));
378 }
alshabibc4901cd2014-09-05 16:50:40 -0700379 if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
alshabib10580802015-02-18 18:30:33 -0800380 bb.putShort(TYPE_VLAN);
alshabibc4901cd2014-09-05 16:50:40 -0700381 bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
382 }
383 bb.putShort(this.etherType);
384 if (payloadData != null) {
385 bb.put(payloadData);
386 }
387 if (this.pad) {
388 Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
389 }
390 return data;
391 }
392
alshabibc4901cd2014-09-05 16:50:40 -0700393 /**
394 * Checks to see if a string is a valid MAC address.
395 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800396 * @param macAddress string to test if it is a valid MAC
alshabibc4901cd2014-09-05 16:50:40 -0700397 * @return True if macAddress is a valid MAC, False otherwise
398 */
399 public static boolean isMACAddress(final String macAddress) {
400 final String[] macBytes = macAddress.split(":");
401 if (macBytes.length != 6) {
402 return false;
403 }
404 for (int i = 0; i < 6; ++i) {
405 if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
406 || Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(
407 1)) == -1) {
408 return false;
409 }
410 }
411 return true;
412 }
413
414 /**
415 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
416 * matter, and returns a corresponding byte[].
417 *
418 * @param macAddress
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800419 * The MAC address to convert into a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700420 * @return The macAddress as a byte array
421 */
422 public static byte[] toMACAddress(final String macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700423 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700424 }
425
426 /**
427 * Accepts a MAC address and returns the corresponding long, where the MAC
428 * bytes are set on the lower order bytes of the long.
429 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800430 * @param macAddress MAC address as a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700431 * @return a long containing the mac address bytes
432 */
433 public static long toLong(final byte[] macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700434 return MacAddress.valueOf(macAddress).toLong();
alshabibc4901cd2014-09-05 16:50:40 -0700435 }
436
437 /**
438 * Converts a long MAC address to a byte array.
439 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800440 * @param macAddress MAC address set on the lower order bytes of the long
alshabibc4901cd2014-09-05 16:50:40 -0700441 * @return the bytes of the mac address
442 */
443 public static byte[] toByteArray(final long macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700444 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700445 }
446
447 /*
448 * (non-Javadoc)
449 *
450 * @see java.lang.Object#hashCode()
451 */
452 @Override
453 public int hashCode() {
454 final int prime = 7867;
455 int result = super.hashCode();
456 result = prime * result + this.destinationMACAddress.hashCode();
457 result = prime * result + this.etherType;
Amit Ghosh764a1b42017-03-18 08:20:06 +0000458 result = prime * result + this.qinqVID;
459 result = prime * result + this.qInQPriorityCode;
alshabibc4901cd2014-09-05 16:50:40 -0700460 result = prime * result + this.vlanID;
461 result = prime * result + this.priorityCode;
462 result = prime * result + (this.pad ? 1231 : 1237);
463 result = prime * result + this.sourceMACAddress.hashCode();
464 return result;
465 }
466
467 /*
468 * (non-Javadoc)
469 *
470 * @see java.lang.Object#equals(java.lang.Object)
471 */
472 @Override
473 public boolean equals(final Object obj) {
474 if (this == obj) {
475 return true;
476 }
477 if (!super.equals(obj)) {
478 return false;
479 }
480 if (!(obj instanceof Ethernet)) {
481 return false;
482 }
483 final Ethernet other = (Ethernet) obj;
484 if (!this.destinationMACAddress.equals(other.destinationMACAddress)) {
485 return false;
486 }
Amit Ghosh764a1b42017-03-18 08:20:06 +0000487 if (this.qInQPriorityCode != other.qInQPriorityCode) {
488 return false;
489 }
490 if (this.qinqVID != other.qinqVID) {
491 return false;
492 }
alshabibc4901cd2014-09-05 16:50:40 -0700493 if (this.priorityCode != other.priorityCode) {
494 return false;
495 }
496 if (this.vlanID != other.vlanID) {
497 return false;
498 }
499 if (this.etherType != other.etherType) {
500 return false;
501 }
502 if (this.pad != other.pad) {
503 return false;
504 }
505 if (!this.sourceMACAddress.equals(other.sourceMACAddress)) {
506 return false;
507 }
508 return true;
509 }
510
511 /*
512 * (non-Javadoc)
513 *
514 * @see java.lang.Object#toString(java.lang.Object)
515 */
516 @Override
517 public String toString() {
Yuta HIGUCHI2dce08a2017-04-20 21:57:48 -0700518 final StringBuilder sb = new StringBuilder("\n");
alshabibc4901cd2014-09-05 16:50:40 -0700519 final IPacket pkt = this.getPayload();
520
521 if (pkt instanceof ARP) {
522 sb.append("arp");
pierf8e328d2019-06-28 22:17:31 +0200523 } else if (pkt instanceof MPLS) {
524 sb.append("mpls");
alshabibc4901cd2014-09-05 16:50:40 -0700525 } else if (pkt instanceof LLDP) {
526 sb.append("lldp");
527 } else if (pkt instanceof ICMP) {
528 sb.append("icmp");
529 } else if (pkt instanceof IPv4) {
530 sb.append("ip");
531 } else if (pkt instanceof DHCP) {
532 sb.append("dhcp");
533 } else {
pierf8e328d2019-06-28 22:17:31 +0200534 // Just print the ethertype
Pier Ventre48ca5192016-11-28 16:52:24 -0800535 sb.append(String.format(HEX_PROTO,
536 Integer.toHexString(this.getEtherType() & 0xffff)));
alshabibc4901cd2014-09-05 16:50:40 -0700537 }
538
Amit Ghosh764a1b42017-03-18 08:20:06 +0000539 if (this.getQinQVID() != Ethernet.VLAN_UNTAGGED) {
540 sb.append("\ndl_qinqVlan: ");
541 sb.append(this.getQinQVID());
542 sb.append("\ndl_qinqVlan_pcp: ");
543 sb.append(this.getQinQPriorityCode());
544 }
545
alshabibc4901cd2014-09-05 16:50:40 -0700546 sb.append("\ndl_vlan: ");
547 if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) {
548 sb.append("untagged");
549 } else {
550 sb.append(this.getVlanID());
551 }
552 sb.append("\ndl_vlan_pcp: ");
553 sb.append(this.getPriorityCode());
554 sb.append("\ndl_src: ");
555 sb.append(bytesToHex(this.getSourceMACAddress()));
556 sb.append("\ndl_dst: ");
557 sb.append(bytesToHex(this.getDestinationMACAddress()));
558
559 if (pkt instanceof ARP) {
560 final ARP p = (ARP) pkt;
561 sb.append("\nnw_src: ");
562 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
563 .getSenderProtocolAddress())));
564 sb.append("\nnw_dst: ");
565 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
566 .getTargetProtocolAddress())));
pierf8e328d2019-06-28 22:17:31 +0200567 } else if (pkt instanceof MPLS) {
568 final MPLS p = (MPLS) pkt;
569 sb.append("\nmpls: ");
570 sb.append(this.etherType == MPLS_UNICAST ? "unicast" : "multicast");
571 sb.append("\nmpls_label: ");
572 sb.append(p.label);
alshabibc4901cd2014-09-05 16:50:40 -0700573 } else if (pkt instanceof LLDP) {
574 sb.append("lldp packet");
575 } else if (pkt instanceof ICMP) {
576 final ICMP icmp = (ICMP) pkt;
577 sb.append("\nicmp_type: ");
578 sb.append(icmp.getIcmpType());
579 sb.append("\nicmp_code: ");
580 sb.append(icmp.getIcmpCode());
581 } else if (pkt instanceof IPv4) {
582 final IPv4 p = (IPv4) pkt;
583 sb.append("\nnw_src: ");
584 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
585 sb.append("\nnw_dst: ");
586 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
587 sb.append("\nnw_tos: ");
588 sb.append(p.getDiffServ());
589 sb.append("\nnw_proto: ");
590 sb.append(p.getProtocol());
591
Charles Chan119eeb52015-10-27 12:40:25 -0700592 IPacket payload = pkt.getPayload();
593 if (payload != null) {
594 if (payload instanceof TCP) {
595 sb.append("\ntp_src: ");
596 sb.append(((TCP) payload).getSourcePort());
597 sb.append("\ntp_dst: ");
598 sb.append(((TCP) payload).getDestinationPort());
Charles Chan119eeb52015-10-27 12:40:25 -0700599 } else if (payload instanceof UDP) {
600 sb.append("\ntp_src: ");
601 sb.append(((UDP) payload).getSourcePort());
602 sb.append("\ntp_dst: ");
603 sb.append(((UDP) payload).getDestinationPort());
604 } else if (payload instanceof ICMP) {
605 final ICMP icmp = (ICMP) payload;
606 sb.append("\nicmp_type: ");
607 sb.append(icmp.getIcmpType());
608 sb.append("\nicmp_code: ");
609 sb.append(icmp.getIcmpCode());
610 }
alshabibc4901cd2014-09-05 16:50:40 -0700611 }
Charles Chan119eeb52015-10-27 12:40:25 -0700612 } else if (pkt instanceof IPv6) {
613 final IPv6 ipv6 = (IPv6) pkt;
614 sb.append("\nipv6_src: ");
615 sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString());
616 sb.append("\nipv6_dst: ");
617 sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString());
618 sb.append("\nipv6_proto: ");
619 sb.append(ipv6.getNextHeader());
alshabibc4901cd2014-09-05 16:50:40 -0700620
Charles Chan119eeb52015-10-27 12:40:25 -0700621 IPacket payload = pkt.getPayload();
622 if (payload != null && payload instanceof ICMP6) {
623 final ICMP6 icmp6 = (ICMP6) payload;
624 sb.append("\nicmp6_type: ");
625 sb.append(icmp6.getIcmpType());
626 sb.append("\nicmp6_code: ");
627 sb.append(icmp6.getIcmpCode());
628
629 payload = payload.getPayload();
630 if (payload != null) {
631 if (payload instanceof NeighborSolicitation) {
632 final NeighborSolicitation ns = (NeighborSolicitation) payload;
633 sb.append("\nns_target_addr: ");
634 sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString());
635 ns.getOptions().forEach(option -> {
636 sb.append("\noption_type: ");
637 sb.append(option.type());
638 sb.append("\noption_data: ");
639 sb.append(bytesToHex(option.data()));
640 });
641 } else if (payload instanceof NeighborAdvertisement) {
642 final NeighborAdvertisement na = (NeighborAdvertisement) payload;
643 sb.append("\nna_target_addr: ");
644 sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString());
645 sb.append("\nna_solicited_flag: ");
646 sb.append(na.getSolicitedFlag());
647 sb.append("\nna_router_flag: ");
648 sb.append(na.getRouterFlag());
649 sb.append("\nna_override_flag: ");
650 sb.append(na.getOverrideFlag());
651 na.getOptions().forEach(option -> {
652 sb.append("\noption_type: ");
653 sb.append(option.type());
654 sb.append("\noption_data: ");
655 sb.append(bytesToHex(option.data()));
656 });
657 } else if (payload instanceof RouterSolicitation) {
658 final RouterSolicitation rs = (RouterSolicitation) payload;
659 sb.append("\nrs");
660 rs.getOptions().forEach(option -> {
661 sb.append("\noption_type: ");
662 sb.append(option.type());
663 sb.append("\noption_data: ");
664 sb.append(bytesToHex(option.data()));
665 });
666 } else if (payload instanceof RouterAdvertisement) {
667 final RouterAdvertisement ra = (RouterAdvertisement) payload;
668 sb.append("\nra_hop_limit: ");
669 sb.append(ra.getCurrentHopLimit());
670 sb.append("\nra_mflag: ");
671 sb.append(ra.getMFlag());
672 sb.append("\nra_oflag: ");
673 sb.append(ra.getOFlag());
674 sb.append("\nra_reachable_time: ");
675 sb.append(ra.getReachableTime());
676 sb.append("\nra_retransmit_time: ");
677 sb.append(ra.getRetransmitTimer());
678 sb.append("\nra_router_lifetime: ");
679 sb.append(ra.getRouterLifetime());
680 ra.getOptions().forEach(option -> {
681 sb.append("\noption_type: ");
682 sb.append(option.type());
683 sb.append("\noption_data: ");
684 sb.append(bytesToHex(option.data()));
685 });
686 } else if (payload instanceof Redirect) {
687 final Redirect rd = (Redirect) payload;
688 sb.append("\nrd_target_addr: ");
689 sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString());
690 rd.getOptions().forEach(option -> {
691 sb.append("\noption_type: ");
692 sb.append(option.type());
693 sb.append("\noption_data: ");
694 sb.append(bytesToHex(option.data()));
695 });
696 }
697 }
alshabibc4901cd2014-09-05 16:50:40 -0700698 }
alshabibc4901cd2014-09-05 16:50:40 -0700699 } else if (pkt instanceof DHCP) {
700 sb.append("\ndhcp packet");
701 } else if (pkt instanceof Data) {
702 sb.append("\ndata packet");
703 } else if (pkt instanceof LLC) {
704 sb.append("\nllc packet");
Saurav Dasa432cf82018-10-11 15:29:24 -0700705 } else if (pkt instanceof EAPOL) {
706 sb.append("\neapol");
Gustavo Silva2bcc8052021-01-22 13:48:30 -0300707 } else if (pkt instanceof PPPoED) {
708 sb.append("\npppoed packet");
alshabibc4901cd2014-09-05 16:50:40 -0700709 } else {
tom5f18cf32014-09-13 14:10:57 -0700710 sb.append("\nunknown packet");
alshabibc4901cd2014-09-05 16:50:40 -0700711 }
alshabibc4901cd2014-09-05 16:50:40 -0700712 return sb.toString();
713 }
714
715 public static String bytesToHex(byte[] in) {
716 final StringBuilder builder = new StringBuilder();
717 for (byte b : in) {
718 builder.append(String.format("%02x", b));
719 }
720 return builder.toString();
721 }
722
Jonathan Hart2a655752015-04-07 16:46:33 -0700723 /**
724 * Deserializer function for Ethernet packets.
725 *
726 * @return deserializer function
727 */
728 public static Deserializer<Ethernet> deserializer() {
729 return (data, offset, length) -> {
730 checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
731
732 byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
733
734 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
735 Ethernet eth = new Ethernet();
736 // Read destination MAC address into buffer
737 bb.get(addressBuffer);
738 eth.setDestinationMACAddress(addressBuffer);
739
740 // Read source MAC address into buffer
741 bb.get(addressBuffer);
742 eth.setSourceMACAddress(addressBuffer);
743
744 short ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000745 if (ethType == TYPE_QINQ) {
746 // in this case we excpect 2 VLAN headers
747 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH + VLAN_HEADER_LENGTH);
748 final short tci = bb.getShort();
749 eth.setQinQPriorityCode((byte) (tci >> 13 & 0x07));
750 eth.setQinQVID((short) (tci & 0x0fff));
751 eth.setQinQTPID(TYPE_QINQ);
752 ethType = bb.getShort();
753 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700754 if (ethType == TYPE_VLAN) {
755 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
756 final short tci = bb.getShort();
757 eth.setPriorityCode((byte) (tci >> 13 & 0x07));
758 eth.setVlanID((short) (tci & 0x0fff));
759 ethType = bb.getShort();
Amit Ghosh764a1b42017-03-18 08:20:06 +0000760
761 if (ethType == TYPE_VLAN) {
762 // We handle only double tagged packets here and assume that in this case
763 // TYPE_QINQ above was not hit
764 // We put the values retrieved above with TYPE_VLAN in
765 // qInQ fields
766 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
767 eth.setQinQPriorityCode(eth.getPriorityCode());
768 eth.setQinQVID(eth.getVlanID());
769 eth.setQinQTPID(TYPE_VLAN);
770
771 final short innerTci = bb.getShort();
772 eth.setPriorityCode((byte) (innerTci >> 13 & 0x07));
773 eth.setVlanID((short) (innerTci & 0x0fff));
774 ethType = bb.getShort();
775 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700776 } else {
777 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
778 }
779 eth.setEtherType(ethType);
780
781 IPacket payload;
782 Deserializer<? extends IPacket> deserializer;
783 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
784 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
785 } else {
786 deserializer = Data.deserializer();
787 }
788 payload = deserializer.deserialize(data, bb.position(),
789 bb.limit() - bb.position());
790 payload.setParent(eth);
791 eth.setPayload(payload);
792
793 return eth;
794 };
795 }
Ray Milkeyf0c47612017-09-28 11:29:38 -0700796
797 /**
798 * Make an exact copy of the ethernet packet.
799 *
800 * @return copy of the packet
801 */
802 public Ethernet duplicate() {
803 try {
804 byte[] data = serialize();
805 return deserializer().deserialize(data, 0, data.length);
806 } catch (DeserializationException dex) {
807 // If we can't make an object out of the serialized data, its a defect
808 throw new IllegalStateException(dex);
809 }
810 }
alshabibc4901cd2014-09-05 16:50:40 -0700811}