blob: 794b3b71bcf0b0af3ce7b3f20b3766fb1e713758 [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2* Copyright 2011, Big Switch Networks, Inc.
3* Originally created by David Erickson, Stanford University
4*
5* Licensed under the Apache License, Version 2.0 (the "License"); you may
6* not use this file except in compliance with the License. You may obtain
7* a copy of the License at
8*
9* http://www.apache.org/licenses/LICENSE-2.0
10*
11* Unless required by applicable law or agreed to in writing, software
12* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14* License for the specific language governing permissions and limitations
15* under the License.
16**/
17
Jonathan Hartdeda0ba2014-04-03 11:14:12 -070018package net.onrc.onos.core.packet;
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080019
20import java.nio.ByteBuffer;
21import java.util.Arrays;
22import java.util.HashMap;
23import java.util.Map;
24
25import net.floodlightcontroller.util.MACAddress;
Jonathan Harta99ec672014-04-03 11:30:34 -070026
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -080027import org.openflow.util.HexString;
28
29/**
30 *
31 * @author David Erickson (daviderickson@cs.stanford.edu)
32 */
33public class Ethernet extends BasePacket {
34 private static String HEXES = "0123456789ABCDEF";
35 public static final short TYPE_ARP = 0x0806;
36 public static final short TYPE_RARP = (short) 0x8035;
37 public static final short TYPE_IPv4 = 0x0800;
38 public static final short TYPE_LLDP = (short) 0x88cc;
39 public static final short TYPE_BSN = (short) 0x8942;
40 public static final short VLAN_UNTAGGED = (short)0xffff;
41 public static final short DATALAYER_ADDRESS_LENGTH = 6; // bytes
42 public static Map<Short, Class<? extends IPacket>> etherTypeClassMap;
43
44 static {
45 etherTypeClassMap = new HashMap<Short, Class<? extends IPacket>>();
46 etherTypeClassMap.put(TYPE_ARP, ARP.class);
47 etherTypeClassMap.put(TYPE_RARP, ARP.class);
48 etherTypeClassMap.put(TYPE_IPv4, IPv4.class);
49 etherTypeClassMap.put(TYPE_LLDP, LLDP.class);
50 etherTypeClassMap.put(TYPE_BSN, BSN.class);
51 }
52
53 protected MACAddress destinationMACAddress;
54 protected MACAddress sourceMACAddress;
55 protected byte priorityCode;
56 protected short vlanID;
57 protected short etherType;
58 protected boolean pad = false;
59
60 /**
61 * By default, set Ethernet to untagged
62 */
63 public Ethernet() {
64 super();
65 this.vlanID = VLAN_UNTAGGED;
66 }
67
68 /**
69 * @return the destination MAC as a byte array
70 */
71 public byte[] getDestinationMACAddress() {
72 return destinationMACAddress.toBytes();
73 }
74
75 /**
76 * @return the destination MAC
77 */
78 public MACAddress getDestinationMAC() {
79 return destinationMACAddress;
80 }
81
82 /**
83 * @param destinationMACAddress the destination MAC to set
84 */
85 public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) {
86 this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
87 return this;
88 }
89
90 /**
91 * @param destinationMACAddress the destination MAC to set
92 */
93 public Ethernet setDestinationMACAddress(String destinationMACAddress) {
94 this.destinationMACAddress = MACAddress.valueOf(destinationMACAddress);
95 return this;
96 }
97
98 /**
99 * @return the source MACAddress as a byte array
100 */
101 public byte[] getSourceMACAddress() {
102 return sourceMACAddress.toBytes();
103 }
104
105 /**
106 * @return the source MACAddress
107 */
108 public MACAddress getSourceMAC() {
109 return sourceMACAddress;
110 }
111
112 /**
113 * @param sourceMACAddress the source MAC to set
114 */
115 public Ethernet setSourceMACAddress(byte[] sourceMACAddress) {
116 this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
117 return this;
118 }
119
120 /**
121 * @param sourceMACAddress the source MAC to set
122 */
123 public Ethernet setSourceMACAddress(String sourceMACAddress) {
124 this.sourceMACAddress = MACAddress.valueOf(sourceMACAddress);
125 return this;
126 }
127
128 /**
129 * @return the priorityCode
130 */
131 public byte getPriorityCode() {
132 return priorityCode;
133 }
134
135 /**
136 * @param priorityCode the priorityCode to set
137 */
138 public Ethernet setPriorityCode(byte priorityCode) {
139 this.priorityCode = priorityCode;
140 return this;
141 }
142
143 /**
144 * @return the vlanID
145 */
146 public short getVlanID() {
147 return vlanID;
148 }
149
150 /**
151 * @param vlanID the vlanID to set
152 */
153 public Ethernet setVlanID(short vlanID) {
154 this.vlanID = vlanID;
155 return this;
156 }
157
158 /**
159 * @return the etherType
160 */
161 public short getEtherType() {
162 return etherType;
163 }
164
165 /**
166 * @param etherType the etherType to set
167 */
168 public Ethernet setEtherType(short etherType) {
169 this.etherType = etherType;
170 return this;
171 }
172
173 /**
174 * @return True if the Ethernet frame is broadcast, false otherwise
175 */
176 public boolean isBroadcast() {
177 assert(destinationMACAddress.length() == 6);
178 return destinationMACAddress.isBroadcast();
179 }
180
181 /**
182 * @return True is the Ethernet frame is multicast, False otherwise
183 */
184 public boolean isMulticast() {
185 return destinationMACAddress.isMulticast();
186 }
187 /**
188 * Pad this packet to 60 bytes minimum, filling with zeros?
189 * @return the pad
190 */
191 public boolean isPad() {
192 return pad;
193 }
194
195 /**
196 * Pad this packet to 60 bytes minimum, filling with zeros?
197 * @param pad the pad to set
198 */
199 public Ethernet setPad(boolean pad) {
200 this.pad = pad;
201 return this;
202 }
203
204 public byte[] serialize() {
205 byte[] payloadData = null;
206 if (payload != null) {
207 payload.setParent(this);
208 payloadData = payload.serialize();
209 }
210 int length = 14 + ((vlanID == VLAN_UNTAGGED) ? 0 : 4) +
211 ((payloadData == null) ? 0 : payloadData.length);
212 if (pad && length < 60) {
213 length = 60;
214 }
215 byte[] data = new byte[length];
216 ByteBuffer bb = ByteBuffer.wrap(data);
217 bb.put(destinationMACAddress.toBytes());
218 bb.put(sourceMACAddress.toBytes());
219 if (vlanID != VLAN_UNTAGGED) {
220 bb.putShort((short) 0x8100);
221 bb.putShort((short) ((priorityCode << 13) | (vlanID & 0x0fff)));
222 }
223 bb.putShort(etherType);
224 if (payloadData != null)
225 bb.put(payloadData);
226 if (pad) {
227 Arrays.fill(data, bb.position(), data.length, (byte)0x0);
228 }
229 return data;
230 }
231
232 @Override
233 public IPacket deserialize(byte[] data, int offset, int length) {
234 if (length <= 0)
235 return null;
236 ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
237 if (this.destinationMACAddress == null)
238 this.destinationMACAddress = MACAddress.valueOf(new byte[6]);
239 byte[] dstAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
240 bb.get(dstAddr);
241 this.destinationMACAddress = MACAddress.valueOf(dstAddr);
242
243 if (this.sourceMACAddress == null)
244 this.sourceMACAddress = MACAddress.valueOf(new byte[6]);
245 byte[] srcAddr = new byte[MACAddress.MAC_ADDRESS_LENGTH];
246 bb.get(srcAddr);
247 this.sourceMACAddress = MACAddress.valueOf(srcAddr);
248
249 short etherType = bb.getShort();
250 if (etherType == (short) 0x8100) {
251 short tci = bb.getShort();
252 this.priorityCode = (byte) ((tci >> 13) & 0x07);
253 this.vlanID = (short) (tci & 0x0fff);
254 etherType = bb.getShort();
255 } else {
256 this.vlanID = VLAN_UNTAGGED;
257 }
258 this.etherType = etherType;
259
260 IPacket payload;
261 if (Ethernet.etherTypeClassMap.containsKey(this.etherType)) {
262 Class<? extends IPacket> clazz = Ethernet.etherTypeClassMap.get(this.etherType);
263 try {
264 payload = clazz.newInstance();
265 } catch (Exception e) {
266 throw new RuntimeException("Error parsing payload for Ethernet packet", e);
267 }
268 } else {
269 payload = new Data();
270 }
271 this.payload = payload.deserialize(data, bb.position(), bb.limit()-bb.position());
272 this.payload.setParent(this);
273 return this;
274 }
275
276 /**
277 * Checks to see if a string is a valid MAC address.
278 * @param macAddress
279 * @return True if macAddress is a valid MAC, False otherwise
280 */
281 public static boolean isMACAddress(String macAddress) {
282 String[] macBytes = macAddress.split(":");
283 if (macBytes.length != 6)
284 return false;
285 for (int i = 0; i < 6; ++i) {
286 if (HEXES.indexOf(macBytes[i].toUpperCase().charAt(0)) == -1 ||
287 HEXES.indexOf(macBytes[i].toUpperCase().charAt(1)) == -1) {
288 return false;
289 }
290 }
291 return true;
292 }
293
294 /**
295 * Accepts a MAC address of the form 00:aa:11:bb:22:cc, case does not
296 * matter, and returns a corresponding byte[].
297 * @param macAddress The MAC address to convert into a bye array
298 * @return The macAddress as a byte array
299 */
300 public static byte[] toMACAddress(String macAddress) {
301 return MACAddress.valueOf(macAddress).toBytes();
302 }
303
304
305 /**
306 * Accepts a MAC address and returns the corresponding long, where the
307 * MAC bytes are set on the lower order bytes of the long.
308 * @param macAddress
309 * @return a long containing the mac address bytes
310 */
311 public static long toLong(byte[] macAddress) {
312 return MACAddress.valueOf(macAddress).toLong();
313 }
314
315 /**
316 * Convert a long MAC address to a byte array
317 * @param macAddress
318 * @return the bytes of the mac address
319 */
320 public static byte[] toByteArray(long macAddress) {
321 return MACAddress.valueOf(macAddress).toBytes();
322 }
323
324 /* (non-Javadoc)
325 * @see java.lang.Object#hashCode()
326 */
327 @Override
328 public int hashCode() {
329 final int prime = 7867;
330 int result = super.hashCode();
331 result = prime * result + destinationMACAddress.hashCode();
332 result = prime * result + etherType;
333 result = prime * result + vlanID;
334 result = prime * result + priorityCode;
335 result = prime * result + (pad ? 1231 : 1237);
336 result = prime * result + sourceMACAddress.hashCode();
337 return result;
338 }
339
340 /* (non-Javadoc)
341 * @see java.lang.Object#equals(java.lang.Object)
342 */
343 @Override
344 public boolean equals(Object obj) {
345 if (this == obj)
346 return true;
347 if (!super.equals(obj))
348 return false;
349 if (!(obj instanceof Ethernet))
350 return false;
351 Ethernet other = (Ethernet) obj;
352 if (!destinationMACAddress.equals(other.destinationMACAddress))
353 return false;
354 if (priorityCode != other.priorityCode)
355 return false;
356 if (vlanID != other.vlanID)
357 return false;
358 if (etherType != other.etherType)
359 return false;
360 if (pad != other.pad)
361 return false;
362 if (!sourceMACAddress.equals(other.sourceMACAddress))
363 return false;
364 return true;
365 }
366
367 /* (non-Javadoc)
368 * @see java.lang.Object#toString(java.lang.Object)
369 */
370 @Override
371 public String toString() {
372
373 StringBuffer sb = new StringBuffer("\n");
374
375 IPacket pkt = (IPacket) this.getPayload();
376
377 if (pkt instanceof ARP)
378 sb.append("arp");
379 else if (pkt instanceof LLDP)
380 sb.append("lldp");
381 else if (pkt instanceof ICMP)
382 sb.append("icmp");
383 else if (pkt instanceof IPv4)
384 sb.append("ip");
385 else if (pkt instanceof DHCP)
386 sb.append("dhcp");
387 else sb.append(this.getEtherType());
388
389 sb.append("\ndl_vlan: ");
390 if (this.getVlanID() == Ethernet.VLAN_UNTAGGED)
391 sb.append("untagged");
392 else
393 sb.append(this.getVlanID());
394 sb.append("\ndl_vlan_pcp: ");
395 sb.append(this.getPriorityCode());
396 sb.append("\ndl_src: ");
397 sb.append(HexString.toHexString(this.getSourceMACAddress()));
398 sb.append("\ndl_dst: ");
399 sb.append(HexString.toHexString(this.getDestinationMACAddress()));
400
401
402 if (pkt instanceof ARP) {
403 ARP p = (ARP) pkt;
404 sb.append("\nnw_src: ");
405 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p.getSenderProtocolAddress())));
406 sb.append("\nnw_dst: ");
407 sb.append(IPv4.fromIPv4Address(IPv4.toIPv4Address(p.getTargetProtocolAddress())));
408 }
409 else if (pkt instanceof LLDP) {
410 sb.append("lldp packet");
411 }
412 else if (pkt instanceof ICMP) {
413 ICMP icmp = (ICMP) pkt;
414 sb.append("\nicmp_type: ");
415 sb.append(icmp.getIcmpType());
416 sb.append("\nicmp_code: ");
417 sb.append(icmp.getIcmpCode());
418 }
419 else if (pkt instanceof IPv4) {
420 IPv4 p = (IPv4) pkt;
421 sb.append("\nnw_src: ");
422 sb.append(IPv4.fromIPv4Address(p.getSourceAddress()));
423 sb.append("\nnw_dst: ");
424 sb.append(IPv4.fromIPv4Address(p.getDestinationAddress()));
425 sb.append("\nnw_tos: ");
426 sb.append(p.getDiffServ());
427 sb.append("\nnw_proto: ");
428 sb.append(p.getProtocol());
429
430 if (pkt instanceof TCP) {
431 sb.append("\ntp_src: ");
432 sb.append(((TCP) pkt).getSourcePort());
433 sb.append("\ntp_dst: ");
434 sb.append(((TCP) pkt).getDestinationPort());
435
436 } else if (pkt instanceof UDP) {
437 sb.append("\ntp_src: ");
438 sb.append(((UDP) pkt).getSourcePort());
439 sb.append("\ntp_dst: ");
440 sb.append(((UDP) pkt).getDestinationPort());
441 }
442
443 if (pkt instanceof ICMP) {
444 ICMP icmp = (ICMP) pkt;
445 sb.append("\nicmp_type: ");
446 sb.append(icmp.getIcmpType());
447 sb.append("\nicmp_code: ");
448 sb.append(icmp.getIcmpCode());
449 }
450
451 }
452 else if (pkt instanceof DHCP) {
453 sb.append("\ndhcp packet");
454 }
455 else if (pkt instanceof Data) {
456 sb.append("\ndata packet");
457 }
458 else if (pkt instanceof LLC) {
459 sb.append("\nllc packet");
460 }
461 else if (pkt instanceof BPDU) {
462 sb.append("\nbpdu packet");
463 }
464 else sb.append("\nunknwon packet");
465
466 return sb.toString();
467 }
468
469}