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