blob: e31781873bc46ecd8b3772b64887ed8c6d7a06f2 [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();
49 public static final short TYPE_BSN = EthType.EtherType.BDDP.ethType().toShort();
50
Jon Hall8c7b06a2017-02-22 13:37:33 -080051 public static final short MPLS_UNICAST = EthType.EtherType.MPLS_UNICAST.ethType().toShort();
alshabib7b808c52015-06-26 14:22:24 -070052 public static final short MPLS_MULTICAST = EthType.EtherType.MPLS_MULTICAST.ethType().toShort();
alshabibcaf1ca22015-06-25 15:18:16 -070053
Jonathan Hart2a655752015-04-07 16:46:33 -070054
alshabibcaf1ca22015-06-25 15:18:16 -070055 public static final short VLAN_UNTAGGED = (short) 0xffff;
Jonathan Hart2a655752015-04-07 16:46:33 -070056
57 public static final short ETHERNET_HEADER_LENGTH = 14; // bytes
58 public static final short VLAN_HEADER_LENGTH = 4; // bytes
59
alshabibc4901cd2014-09-05 16:50:40 -070060 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
Jonathan Hart2a655752015-04-07 16:46:33 -070061
62 private static final Map<Short, Deserializer<? extends IPacket>> ETHERTYPE_DESERIALIZER_MAP =
63 new HashMap<>();
alshabibc4901cd2014-09-05 16:50:40 -070064
65 static {
alshabibcaf1ca22015-06-25 15:18:16 -070066 for (EthType.EtherType ethType : EthType.EtherType.values()) {
alshabib7b808c52015-06-26 14:22:24 -070067 if (ethType.deserializer() != null) {
Jonathan Hart2a655752015-04-07 16:46:33 -070068 ETHERTYPE_DESERIALIZER_MAP.put(ethType.ethType().toShort(), ethType.deserializer());
alshabibcaf1ca22015-06-25 15:18:16 -070069 }
70 }
alshabibc4901cd2014-09-05 16:50:40 -070071 }
72
Ayaka Koshibea9c199f2014-09-16 16:21:40 -070073 protected MacAddress destinationMACAddress;
74 protected MacAddress sourceMACAddress;
alshabibc4901cd2014-09-05 16:50:40 -070075 protected byte priorityCode;
76 protected short vlanID;
77 protected short etherType;
78 protected boolean pad = false;
79
80 /**
81 * By default, set Ethernet to untagged.
82 */
83 public Ethernet() {
84 super();
85 this.vlanID = Ethernet.VLAN_UNTAGGED;
86 }
87
88 /**
89 * Gets the destination MAC address.
90 *
91 * @return the destination MAC as a byte array
92 */
93 public byte[] getDestinationMACAddress() {
94 return this.destinationMACAddress.toBytes();
95 }
96
97 /**
98 * Gets the destination MAC address.
99 *
100 * @return the destination MAC
101 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700102 public MacAddress getDestinationMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700103 return this.destinationMACAddress;
104 }
105
106 /**
107 * Sets the destination MAC address.
108 *
tom5f18cf32014-09-13 14:10:57 -0700109 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700110 * @return the Ethernet frame
111 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800112 public Ethernet setDestinationMACAddress(final MacAddress destMac) {
113 this.destinationMACAddress = checkNotNull(destMac);
114 return this;
115 }
116
117 /**
118 * Sets the destination MAC address.
119 *
120 * @param destMac the destination MAC to set
121 * @return the Ethernet frame
122 */
alshabibc4901cd2014-09-05 16:50:40 -0700123 public Ethernet setDestinationMACAddress(final byte[] destMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700124 this.destinationMACAddress = MacAddress.valueOf(destMac);
alshabibc4901cd2014-09-05 16:50:40 -0700125 return this;
126 }
127
128 /**
129 * Sets the destination MAC address.
130 *
tom5f18cf32014-09-13 14:10:57 -0700131 * @param destMac the destination MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700132 * @return the Ethernet frame
133 */
134 public Ethernet setDestinationMACAddress(final String 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 * Gets the source MAC address.
141 *
142 * @return the source MACAddress as a byte array
143 */
144 public byte[] getSourceMACAddress() {
145 return this.sourceMACAddress.toBytes();
146 }
147
148 /**
149 * Gets the source MAC address.
150 *
151 * @return the source MACAddress
152 */
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700153 public MacAddress getSourceMAC() {
alshabibc4901cd2014-09-05 16:50:40 -0700154 return this.sourceMACAddress;
155 }
156
157 /**
158 * Sets the source MAC address.
159 *
tom5f18cf32014-09-13 14:10:57 -0700160 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700161 * @return the Ethernet frame
162 */
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800163 public Ethernet setSourceMACAddress(final MacAddress sourceMac) {
164 this.sourceMACAddress = checkNotNull(sourceMac);
165 return this;
166 }
167
168 /**
169 * Sets the source MAC address.
170 *
171 * @param sourceMac the source MAC to set
172 * @return the Ethernet frame
173 */
alshabibc4901cd2014-09-05 16:50:40 -0700174 public Ethernet setSourceMACAddress(final byte[] sourceMac) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700175 this.sourceMACAddress = MacAddress.valueOf(sourceMac);
alshabibc4901cd2014-09-05 16:50:40 -0700176 return this;
177 }
178
179 /**
180 * Sets the source MAC address.
181 *
tom5f18cf32014-09-13 14:10:57 -0700182 * @param sourceMac the source MAC to set
alshabibc4901cd2014-09-05 16:50:40 -0700183 * @return the Ethernet frame
184 */
185 public Ethernet setSourceMACAddress(final String 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 * Gets the priority code.
192 *
193 * @return the priorityCode
194 */
195 public byte getPriorityCode() {
196 return this.priorityCode;
197 }
198
199 /**
200 * Sets the priority code.
201 *
tom5f18cf32014-09-13 14:10:57 -0700202 * @param priority the priorityCode to set
alshabibc4901cd2014-09-05 16:50:40 -0700203 * @return the Ethernet frame
204 */
205 public Ethernet setPriorityCode(final byte priority) {
206 this.priorityCode = priority;
207 return this;
208 }
209
210 /**
211 * Gets the VLAN ID.
212 *
213 * @return the vlanID
214 */
215 public short getVlanID() {
216 return this.vlanID;
217 }
218
219 /**
220 * Sets the VLAN ID.
221 *
tom5f18cf32014-09-13 14:10:57 -0700222 * @param vlan the vlanID to set
alshabibc4901cd2014-09-05 16:50:40 -0700223 * @return the Ethernet frame
224 */
225 public Ethernet setVlanID(final short vlan) {
226 this.vlanID = vlan;
227 return this;
228 }
229
230 /**
231 * Gets the Ethernet type.
232 *
233 * @return the etherType
234 */
235 public short getEtherType() {
236 return this.etherType;
237 }
238
239 /**
240 * Sets the Ethernet type.
241 *
tom5f18cf32014-09-13 14:10:57 -0700242 * @param ethType the etherType to set
alshabibc4901cd2014-09-05 16:50:40 -0700243 * @return the Ethernet frame
244 */
245 public Ethernet setEtherType(final short ethType) {
246 this.etherType = ethType;
247 return this;
248 }
249
250 /**
251 * @return True if the Ethernet frame is broadcast, false otherwise
252 */
253 public boolean isBroadcast() {
254 assert this.destinationMACAddress.length() == 6;
255 return this.destinationMACAddress.isBroadcast();
256 }
257
258 /**
259 * @return True is the Ethernet frame is multicast, False otherwise
260 */
261 public boolean isMulticast() {
262 return this.destinationMACAddress.isMulticast();
263 }
264
265 /**
266 * Pad this packet to 60 bytes minimum, filling with zeros?
267 *
268 * @return the pad
269 */
270 public boolean isPad() {
271 return this.pad;
272 }
273
274 /**
275 * Pad this packet to 60 bytes minimum, filling with zeros?
276 *
tom5f18cf32014-09-13 14:10:57 -0700277 * @param pd
alshabibc4901cd2014-09-05 16:50:40 -0700278 * the pad to set
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800279 * @return this
alshabibc4901cd2014-09-05 16:50:40 -0700280 */
281 public Ethernet setPad(final boolean pd) {
282 this.pad = pd;
283 return this;
284 }
285
286 @Override
287 public byte[] serialize() {
288 byte[] payloadData = null;
289 if (this.payload != null) {
290 this.payload.setParent(this);
291 payloadData = this.payload.serialize();
292 }
293 int length = 14 + (this.vlanID == Ethernet.VLAN_UNTAGGED ? 0 : 4)
294 + (payloadData == null ? 0 : payloadData.length);
295 if (this.pad && length < 60) {
296 length = 60;
297 }
298 final byte[] data = new byte[length];
299 final ByteBuffer bb = ByteBuffer.wrap(data);
300 bb.put(this.destinationMACAddress.toBytes());
301 bb.put(this.sourceMACAddress.toBytes());
302 if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
alshabib10580802015-02-18 18:30:33 -0800303 bb.putShort(TYPE_VLAN);
alshabibc4901cd2014-09-05 16:50:40 -0700304 bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
305 }
306 bb.putShort(this.etherType);
307 if (payloadData != null) {
308 bb.put(payloadData);
309 }
310 if (this.pad) {
311 Arrays.fill(data, bb.position(), data.length, (byte) 0x0);
312 }
313 return data;
314 }
315
316 @Override
317 public IPacket deserialize(final byte[] data, final int offset,
Jonathan Hart2a655752015-04-07 16:46:33 -0700318 final int length) {
alshabibc4901cd2014-09-05 16:50:40 -0700319 if (length <= 0) {
320 return null;
321 }
322 final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
323 if (this.destinationMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700324 this.destinationMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700325 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700326 final byte[] dstAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700327 bb.get(dstAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700328 this.destinationMACAddress = MacAddress.valueOf(dstAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700329
330 if (this.sourceMACAddress == null) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700331 this.sourceMACAddress = MacAddress.valueOf(new byte[6]);
alshabibc4901cd2014-09-05 16:50:40 -0700332 }
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700333 final byte[] srcAddr = new byte[MacAddress.MAC_ADDRESS_LENGTH];
alshabibc4901cd2014-09-05 16:50:40 -0700334 bb.get(srcAddr);
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700335 this.sourceMACAddress = MacAddress.valueOf(srcAddr);
alshabibc4901cd2014-09-05 16:50:40 -0700336
337 short ethType = bb.getShort();
alshabib10580802015-02-18 18:30:33 -0800338 if (ethType == TYPE_VLAN) {
alshabibc4901cd2014-09-05 16:50:40 -0700339 final short tci = bb.getShort();
340 this.priorityCode = (byte) (tci >> 13 & 0x07);
341 this.vlanID = (short) (tci & 0x0fff);
342 ethType = bb.getShort();
343 } else {
344 this.vlanID = Ethernet.VLAN_UNTAGGED;
345 }
346 this.etherType = ethType;
347
348 IPacket payload;
Jonathan Hart2a655752015-04-07 16:46:33 -0700349 Deserializer<? extends IPacket> deserializer;
350 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
351 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
alshabibc4901cd2014-09-05 16:50:40 -0700352 } else {
Jonathan Hart2a655752015-04-07 16:46:33 -0700353 deserializer = Data.deserializer();
alshabibc4901cd2014-09-05 16:50:40 -0700354 }
Jonathan Hart2a655752015-04-07 16:46:33 -0700355 try {
356 this.payload = deserializer.deserialize(data, bb.position(),
357 bb.limit() - bb.position());
358 this.payload.setParent(this);
359 } catch (DeserializationException e) {
360 return this;
361 }
alshabibc4901cd2014-09-05 16:50:40 -0700362 return this;
363 }
364
365 /**
366 * Checks to see if a string is a valid MAC address.
367 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800368 * @param macAddress string to test if it is a valid MAC
alshabibc4901cd2014-09-05 16:50:40 -0700369 * @return True if macAddress is a valid MAC, False otherwise
370 */
371 public static boolean isMACAddress(final String macAddress) {
372 final String[] macBytes = macAddress.split(":");
373 if (macBytes.length != 6) {
374 return false;
375 }
376 for (int i = 0; i < 6; ++i) {
377 if (Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1
378 || Ethernet.HEXES.indexOf(macBytes[i].toUpperCase().charAt(
379 1)) == -1) {
380 return false;
381 }
382 }
383 return true;
384 }
385
386 /**
387 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
388 * matter, and returns a corresponding byte[].
389 *
390 * @param macAddress
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800391 * The MAC address to convert into a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700392 * @return The macAddress as a byte array
393 */
394 public static byte[] toMACAddress(final String macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700395 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700396 }
397
398 /**
399 * Accepts a MAC address and returns the corresponding long, where the MAC
400 * bytes are set on the lower order bytes of the long.
401 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800402 * @param macAddress MAC address as a byte array
alshabibc4901cd2014-09-05 16:50:40 -0700403 * @return a long containing the mac address bytes
404 */
405 public static long toLong(final byte[] macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700406 return MacAddress.valueOf(macAddress).toLong();
alshabibc4901cd2014-09-05 16:50:40 -0700407 }
408
409 /**
410 * Converts a long MAC address to a byte array.
411 *
Yuta HIGUCHI2281b3f2014-11-04 00:20:48 -0800412 * @param macAddress MAC address set on the lower order bytes of the long
alshabibc4901cd2014-09-05 16:50:40 -0700413 * @return the bytes of the mac address
414 */
415 public static byte[] toByteArray(final long macAddress) {
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700416 return MacAddress.valueOf(macAddress).toBytes();
alshabibc4901cd2014-09-05 16:50:40 -0700417 }
418
419 /*
420 * (non-Javadoc)
421 *
422 * @see java.lang.Object#hashCode()
423 */
424 @Override
425 public int hashCode() {
426 final int prime = 7867;
427 int result = super.hashCode();
428 result = prime * result + this.destinationMACAddress.hashCode();
429 result = prime * result + this.etherType;
430 result = prime * result + this.vlanID;
431 result = prime * result + this.priorityCode;
432 result = prime * result + (this.pad ? 1231 : 1237);
433 result = prime * result + this.sourceMACAddress.hashCode();
434 return result;
435 }
436
437 /*
438 * (non-Javadoc)
439 *
440 * @see java.lang.Object#equals(java.lang.Object)
441 */
442 @Override
443 public boolean equals(final Object obj) {
444 if (this == obj) {
445 return true;
446 }
447 if (!super.equals(obj)) {
448 return false;
449 }
450 if (!(obj instanceof Ethernet)) {
451 return false;
452 }
453 final Ethernet other = (Ethernet) obj;
454 if (!this.destinationMACAddress.equals(other.destinationMACAddress)) {
455 return false;
456 }
457 if (this.priorityCode != other.priorityCode) {
458 return false;
459 }
460 if (this.vlanID != other.vlanID) {
461 return false;
462 }
463 if (this.etherType != other.etherType) {
464 return false;
465 }
466 if (this.pad != other.pad) {
467 return false;
468 }
469 if (!this.sourceMACAddress.equals(other.sourceMACAddress)) {
470 return false;
471 }
472 return true;
473 }
474
475 /*
476 * (non-Javadoc)
477 *
478 * @see java.lang.Object#toString(java.lang.Object)
479 */
480 @Override
481 public String toString() {
482
483 final StringBuffer sb = new StringBuffer("\n");
484
485 final IPacket pkt = this.getPayload();
486
487 if (pkt instanceof ARP) {
488 sb.append("arp");
489 } else if (pkt instanceof LLDP) {
490 sb.append("lldp");
491 } else if (pkt instanceof ICMP) {
492 sb.append("icmp");
493 } else if (pkt instanceof IPv4) {
494 sb.append("ip");
495 } else if (pkt instanceof DHCP) {
496 sb.append("dhcp");
497 } else {
Pier Ventre48ca5192016-11-28 16:52:24 -0800498 /*
499 * When we don't know the protocol, we print using
500 * the well known hex format instead of a decimal
501 * value.
502 */
503 sb.append(String.format(HEX_PROTO,
504 Integer.toHexString(this.getEtherType() & 0xffff)));
alshabibc4901cd2014-09-05 16:50:40 -0700505 }
506
507 sb.append("\ndl_vlan: ");
508 if (this.getVlanID() == Ethernet.VLAN_UNTAGGED) {
509 sb.append("untagged");
510 } else {
511 sb.append(this.getVlanID());
512 }
513 sb.append("\ndl_vlan_pcp: ");
514 sb.append(this.getPriorityCode());
515 sb.append("\ndl_src: ");
516 sb.append(bytesToHex(this.getSourceMACAddress()));
517 sb.append("\ndl_dst: ");
518 sb.append(bytesToHex(this.getDestinationMACAddress()));
519
520 if (pkt instanceof ARP) {
521 final ARP p = (ARP) pkt;
522 sb.append("\nnw_src: ");
523 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
524 .getSenderProtocolAddress())));
525 sb.append("\nnw_dst: ");
526 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p
527 .getTargetProtocolAddress())));
528 } else if (pkt instanceof LLDP) {
529 sb.append("lldp packet");
530 } else if (pkt instanceof ICMP) {
531 final ICMP icmp = (ICMP) pkt;
532 sb.append("\nicmp_type: ");
533 sb.append(icmp.getIcmpType());
534 sb.append("\nicmp_code: ");
535 sb.append(icmp.getIcmpCode());
536 } else if (pkt instanceof IPv4) {
537 final IPv4 p = (IPv4) pkt;
538 sb.append("\nnw_src: ");
539 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
540 sb.append("\nnw_dst: ");
541 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
542 sb.append("\nnw_tos: ");
543 sb.append(p.getDiffServ());
544 sb.append("\nnw_proto: ");
545 sb.append(p.getProtocol());
546
Charles Chan119eeb52015-10-27 12:40:25 -0700547 IPacket payload = pkt.getPayload();
548 if (payload != null) {
549 if (payload instanceof TCP) {
550 sb.append("\ntp_src: ");
551 sb.append(((TCP) payload).getSourcePort());
552 sb.append("\ntp_dst: ");
553 sb.append(((TCP) payload).getDestinationPort());
alshabibc4901cd2014-09-05 16:50:40 -0700554
Charles Chan119eeb52015-10-27 12:40:25 -0700555 } else if (payload instanceof UDP) {
556 sb.append("\ntp_src: ");
557 sb.append(((UDP) payload).getSourcePort());
558 sb.append("\ntp_dst: ");
559 sb.append(((UDP) payload).getDestinationPort());
560 } else if (payload instanceof ICMP) {
561 final ICMP icmp = (ICMP) payload;
562 sb.append("\nicmp_type: ");
563 sb.append(icmp.getIcmpType());
564 sb.append("\nicmp_code: ");
565 sb.append(icmp.getIcmpCode());
566 }
alshabibc4901cd2014-09-05 16:50:40 -0700567 }
Charles Chan119eeb52015-10-27 12:40:25 -0700568 } else if (pkt instanceof IPv6) {
569 final IPv6 ipv6 = (IPv6) pkt;
570 sb.append("\nipv6_src: ");
571 sb.append(Ip6Address.valueOf(ipv6.getSourceAddress()).toString());
572 sb.append("\nipv6_dst: ");
573 sb.append(Ip6Address.valueOf(ipv6.getDestinationAddress()).toString());
574 sb.append("\nipv6_proto: ");
575 sb.append(ipv6.getNextHeader());
alshabibc4901cd2014-09-05 16:50:40 -0700576
Charles Chan119eeb52015-10-27 12:40:25 -0700577 IPacket payload = pkt.getPayload();
578 if (payload != null && payload instanceof ICMP6) {
579 final ICMP6 icmp6 = (ICMP6) payload;
580 sb.append("\nicmp6_type: ");
581 sb.append(icmp6.getIcmpType());
582 sb.append("\nicmp6_code: ");
583 sb.append(icmp6.getIcmpCode());
584
585 payload = payload.getPayload();
586 if (payload != null) {
587 if (payload instanceof NeighborSolicitation) {
588 final NeighborSolicitation ns = (NeighborSolicitation) payload;
589 sb.append("\nns_target_addr: ");
590 sb.append(Ip6Address.valueOf(ns.getTargetAddress()).toString());
591 ns.getOptions().forEach(option -> {
592 sb.append("\noption_type: ");
593 sb.append(option.type());
594 sb.append("\noption_data: ");
595 sb.append(bytesToHex(option.data()));
596 });
597 } else if (payload instanceof NeighborAdvertisement) {
598 final NeighborAdvertisement na = (NeighborAdvertisement) payload;
599 sb.append("\nna_target_addr: ");
600 sb.append(Ip6Address.valueOf(na.getTargetAddress()).toString());
601 sb.append("\nna_solicited_flag: ");
602 sb.append(na.getSolicitedFlag());
603 sb.append("\nna_router_flag: ");
604 sb.append(na.getRouterFlag());
605 sb.append("\nna_override_flag: ");
606 sb.append(na.getOverrideFlag());
607 na.getOptions().forEach(option -> {
608 sb.append("\noption_type: ");
609 sb.append(option.type());
610 sb.append("\noption_data: ");
611 sb.append(bytesToHex(option.data()));
612 });
613 } else if (payload instanceof RouterSolicitation) {
614 final RouterSolicitation rs = (RouterSolicitation) payload;
615 sb.append("\nrs");
616 rs.getOptions().forEach(option -> {
617 sb.append("\noption_type: ");
618 sb.append(option.type());
619 sb.append("\noption_data: ");
620 sb.append(bytesToHex(option.data()));
621 });
622 } else if (payload instanceof RouterAdvertisement) {
623 final RouterAdvertisement ra = (RouterAdvertisement) payload;
624 sb.append("\nra_hop_limit: ");
625 sb.append(ra.getCurrentHopLimit());
626 sb.append("\nra_mflag: ");
627 sb.append(ra.getMFlag());
628 sb.append("\nra_oflag: ");
629 sb.append(ra.getOFlag());
630 sb.append("\nra_reachable_time: ");
631 sb.append(ra.getReachableTime());
632 sb.append("\nra_retransmit_time: ");
633 sb.append(ra.getRetransmitTimer());
634 sb.append("\nra_router_lifetime: ");
635 sb.append(ra.getRouterLifetime());
636 ra.getOptions().forEach(option -> {
637 sb.append("\noption_type: ");
638 sb.append(option.type());
639 sb.append("\noption_data: ");
640 sb.append(bytesToHex(option.data()));
641 });
642 } else if (payload instanceof Redirect) {
643 final Redirect rd = (Redirect) payload;
644 sb.append("\nrd_target_addr: ");
645 sb.append(Ip6Address.valueOf(rd.getTargetAddress()).toString());
646 rd.getOptions().forEach(option -> {
647 sb.append("\noption_type: ");
648 sb.append(option.type());
649 sb.append("\noption_data: ");
650 sb.append(bytesToHex(option.data()));
651 });
652 }
653 }
alshabibc4901cd2014-09-05 16:50:40 -0700654 }
alshabibc4901cd2014-09-05 16:50:40 -0700655 } else if (pkt instanceof DHCP) {
656 sb.append("\ndhcp packet");
657 } else if (pkt instanceof Data) {
658 sb.append("\ndata packet");
659 } else if (pkt instanceof LLC) {
660 sb.append("\nllc packet");
661 } else {
tom5f18cf32014-09-13 14:10:57 -0700662 sb.append("\nunknown packet");
alshabibc4901cd2014-09-05 16:50:40 -0700663 }
664
665 return sb.toString();
666 }
667
668 public static String bytesToHex(byte[] in) {
669 final StringBuilder builder = new StringBuilder();
670 for (byte b : in) {
671 builder.append(String.format("%02x", b));
672 }
673 return builder.toString();
674 }
675
Jonathan Hart2a655752015-04-07 16:46:33 -0700676 /**
677 * Deserializer function for Ethernet packets.
678 *
679 * @return deserializer function
680 */
681 public static Deserializer<Ethernet> deserializer() {
682 return (data, offset, length) -> {
683 checkInput(data, offset, length, ETHERNET_HEADER_LENGTH);
684
685 byte[] addressBuffer = new byte[DATALAYER_ADDRESS_LENGTH];
686
687 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
688 Ethernet eth = new Ethernet();
689 // Read destination MAC address into buffer
690 bb.get(addressBuffer);
691 eth.setDestinationMACAddress(addressBuffer);
692
693 // Read source MAC address into buffer
694 bb.get(addressBuffer);
695 eth.setSourceMACAddress(addressBuffer);
696
697 short ethType = bb.getShort();
698 if (ethType == TYPE_VLAN) {
699 checkHeaderLength(length, ETHERNET_HEADER_LENGTH + VLAN_HEADER_LENGTH);
700 final short tci = bb.getShort();
701 eth.setPriorityCode((byte) (tci >> 13 & 0x07));
702 eth.setVlanID((short) (tci & 0x0fff));
703 ethType = bb.getShort();
704 } else {
705 eth.setVlanID(Ethernet.VLAN_UNTAGGED);
706 }
707 eth.setEtherType(ethType);
708
709 IPacket payload;
710 Deserializer<? extends IPacket> deserializer;
711 if (Ethernet.ETHERTYPE_DESERIALIZER_MAP.containsKey(ethType)) {
712 deserializer = Ethernet.ETHERTYPE_DESERIALIZER_MAP.get(ethType);
713 } else {
714 deserializer = Data.deserializer();
715 }
716 payload = deserializer.deserialize(data, bb.position(),
717 bb.limit() - bb.position());
718 payload.setParent(eth);
719 eth.setPayload(payload);
720
721 return eth;
722 };
723 }
alshabibc4901cd2014-09-05 16:50:40 -0700724}