3 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
5 * This program and the accompanying materials are made available under the
6 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7 * and is available at http://www.eclipse.org/legal/epl-v10.html
13 package org.opendaylight.controller.sal.packet;
15 import java.net.InetAddress;
16 import java.util.HashMap;
17 import java.util.LinkedHashMap;
19 import java.util.Random;
21 import org.apache.commons.lang3.builder.EqualsBuilder;
22 import org.apache.commons.lang3.builder.HashCodeBuilder;
23 import org.apache.commons.lang3.tuple.ImmutablePair;
24 import org.apache.commons.lang3.tuple.Pair;
25 import org.opendaylight.controller.sal.utils.IPProtocols;
26 import org.opendaylight.controller.sal.utils.NetUtils;
29 * Class that represents the IPv4 packet objects
34 public class IPv4 extends Packet {
35 private static final String VERSION = "Version";
36 private static final String HEADERLENGTH = "HeaderLength";
37 private static final String DIFFSERV = "DiffServ";
38 private static final String ECN = "ECN";
39 private static final String TOTLENGTH = "TotalLength";
40 private static final String IDENTIFICATION = "Identification";
41 private static final String FLAGS = "Flags";
42 private static final String FRAGOFFSET = "FragmentOffset";
43 private static final String TTL = "TTL";
44 private static final String PROTOCOL = "Protocol";
45 private static final String CHECKSUM = "Checksum";
46 private static final String SIP = "SourceIPAddress";
47 private static final String DIP = "DestinationIPAddress";
48 private static final String OPTIONS = "Options";
50 public static Map<Byte, Class<? extends Packet>> protocolClassMap;
52 protocolClassMap = new HashMap<Byte, Class<? extends Packet>>();
53 protocolClassMap.put(IPProtocols.ICMP.byteValue(), ICMP.class);
54 protocolClassMap.put(IPProtocols.UDP.byteValue(), UDP.class);
55 protocolClassMap.put(IPProtocols.TCP.byteValue(), TCP.class);
57 private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
58 private static final long serialVersionUID = 1L;
60 put(VERSION, new ImmutablePair<Integer, Integer>(0, 4));
61 put(HEADERLENGTH, new ImmutablePair<Integer, Integer>(4, 4));
62 put(DIFFSERV, new ImmutablePair<Integer, Integer>(8, 6));
63 put(ECN, new ImmutablePair<Integer, Integer>(14, 2));
64 put(TOTLENGTH, new ImmutablePair<Integer, Integer>(16, 16));
65 put(IDENTIFICATION, new ImmutablePair<Integer, Integer>(32, 16));
66 put(FLAGS, new ImmutablePair<Integer, Integer>(48, 3));
67 put(FRAGOFFSET, new ImmutablePair<Integer, Integer>(51, 13));
68 put(TTL, new ImmutablePair<Integer, Integer>(64, 8));
69 put(PROTOCOL, new ImmutablePair<Integer, Integer>(72, 8));
70 put(CHECKSUM, new ImmutablePair<Integer, Integer>(80, 16));
71 put(SIP, new ImmutablePair<Integer, Integer>(96, 32));
72 put(DIP, new ImmutablePair<Integer, Integer>(128, 32));
73 put(OPTIONS, new ImmutablePair<Integer, Integer>(160, 0));
77 private Map<String, byte[]> fieldValues;
80 * Default constructor that sets the version to 4, headerLength to 5,
81 * and flags to 2. The default value for the identification is set to a
82 * random number and the remaining fields are set to 0.
86 fieldValues = new HashMap<String, byte[]>();
87 hdrFieldCoordMap = fieldCoordinates;
88 hdrFieldsMap = fieldValues;
91 setHeaderLength((byte) 5);
92 setDiffServ((byte) 0);
93 setIdentification(generateId());
95 setFragmentOffset((short) 0);
100 * The write access to the packet is set in this constructor.
101 * Constructor that sets the version to 4, headerLength to 5,
102 * and flags to 2. The default value for the identification is set to a
103 * random number and the remaining fields are set to 0.
106 public IPv4(boolean writeAccess) {
108 fieldValues = new HashMap<String, byte[]>();
109 hdrFieldCoordMap = fieldCoordinates;
110 hdrFieldsMap = fieldValues;
112 setVersion((byte) 4);
113 setHeaderLength((byte) 5);
114 setDiffServ((byte) 0);
115 setIdentification(generateId());
117 setFragmentOffset((short) 0);
122 * Gets the IP version stored
123 * @return the version
125 public byte getVersion() {
126 return (BitBufferHelper.getByte(fieldValues.get(VERSION)));
130 * Gets the IP header length stored
131 * @return the headerLength in bytes
133 public int getHeaderLen() {
134 return (4 * BitBufferHelper.getByte(fieldValues.get(HEADERLENGTH)));
138 * Gets the header length in bits, from the header length stored and options if any
139 * @return HeaderLength to serialize code
142 public int getHeaderSize() {
143 int headerLen = this.getHeaderLen();
147 byte[] options = hdrFieldsMap.get(OPTIONS);
149 headerLen += options.length;
151 return headerLen * NetUtils.NumBitsInAByte;
156 * Gets the differential services value stored
157 * @return the diffServ
159 public byte getDiffServ() {
160 return BitBufferHelper.getByte(fieldValues.get(DIFFSERV));
164 * Gets the ecn bits stored
165 * @return the ecn bits
167 public byte getECN() {
168 return BitBufferHelper.getByte(fieldValues.get(ECN));
172 * Gets the total length of the IP header in bytes
173 * @return the totalLength
175 public short getTotalLength() {
176 return (BitBufferHelper.getShort(fieldValues.get(TOTLENGTH)));
180 * Gets the identification value stored
181 * @return the identification
183 public short getIdentification() {
184 return (BitBufferHelper.getShort(fieldValues.get(IDENTIFICATION)));
188 * Gets the flag values stored
191 public byte getFlags() {
192 return (BitBufferHelper.getByte(fieldValues.get(FLAGS)));
196 * Gets the TTL value stored
199 public byte getTtl() {
200 return (BitBufferHelper.getByte(fieldValues.get(TTL)));
204 * Gets the protocol value stored
205 * @return the protocol
207 public byte getProtocol() {
208 return (BitBufferHelper.getByte(fieldValues.get(PROTOCOL)));
212 * Gets the checksum value stored
213 * @return the checksum
215 public short getChecksum() {
216 return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));
220 * Gets the fragment offset stored
221 * @return the fragmentOffset
223 public short getFragmentOffset() {
224 return (BitBufferHelper.getShort(fieldValues.get(FRAGOFFSET)));
228 * Gets the source IP address stored
229 * @return the sourceAddress
231 public int getSourceAddress() {
232 return (BitBufferHelper.getInt(fieldValues.get(SIP)));
236 * Gets the destination IP address stored
237 * @return the destinationAddress
239 public int getDestinationAddress() {
240 return (BitBufferHelper.getInt(fieldValues.get(DIP)));
244 * gets the Options stored
245 * @return the options
247 public byte[] getOptions() {
248 return (fieldValues.get(OPTIONS));
253 * Stores the value of fields read from data stream
254 * Variable header value like payload protocol, is stored here
256 public void setHeaderField(String headerField, byte[] readValue) {
257 if (headerField.equals(PROTOCOL)) {
258 payloadClass = protocolClassMap.get(readValue[0]);
260 hdrFieldsMap.put(headerField, readValue);
264 * Stores the IP version from the header
265 * @param version the version to set
268 public IPv4 setVersion(byte ipVersion) {
269 byte[] version = BitBufferHelper.toByteArray(ipVersion);
270 fieldValues.put(VERSION, version);
275 * Stores the length of IP header in words (2 bytes)
276 * @param headerLength the headerLength to set
279 public IPv4 setHeaderLength(byte ipheaderLength) {
280 byte[] headerLength = BitBufferHelper.toByteArray(ipheaderLength);
281 fieldValues.put(HEADERLENGTH, headerLength);
286 * Stores the differential services value from the IP header
287 * @param diffServ the diffServ to set
290 public IPv4 setDiffServ(byte ipdiffServ) {
291 byte[] diffServ = BitBufferHelper.toByteArray(ipdiffServ);
292 fieldValues.put(DIFFSERV, diffServ);
297 * Stores the ECN bits from the header
298 * @param ECN bits to set
301 public IPv4 setECN(byte ecn) {
302 byte[] ecnbytes = BitBufferHelper.toByteArray(ecn);
303 fieldValues.put(ECN, ecnbytes);
308 * Stores the total length of IP header in bytes
309 * @param totalLength the totalLength to set
312 public IPv4 setTotalLength(short iptotalLength) {
313 byte[] totalLength = BitBufferHelper.toByteArray(iptotalLength);
314 fieldValues.put(TOTLENGTH, totalLength);
319 * Stores the identification number from the header
320 * @param identification the identification to set
323 public IPv4 setIdentification(short ipIdentification) {
324 byte[] identification = BitBufferHelper.toByteArray(ipIdentification);
325 fieldValues.put(IDENTIFICATION, identification);
330 * Stores the IP flags value
331 * @param flags the flags to set
334 public IPv4 setFlags(byte ipFlags) {
335 byte[] flags = { ipFlags };
336 fieldValues.put(FLAGS, flags);
341 * Stores the IP fragmentation offset value
342 * @param fragmentOffset the fragmentOffset to set
345 public IPv4 setFragmentOffset(short ipFragmentOffset) {
346 byte[] fragmentOffset = BitBufferHelper.toByteArray(ipFragmentOffset);
347 fieldValues.put(FRAGOFFSET, fragmentOffset);
352 * Stores the TTL value
353 * @param ttl the ttl to set
356 public IPv4 setTtl(byte ipTtl) {
357 byte[] ttl = BitBufferHelper.toByteArray(ipTtl);
358 fieldValues.put(TTL, ttl);
363 * Stores the protocol value of the IP payload
364 * @param protocol the protocol to set
367 public IPv4 setProtocol(byte ipProtocol) {
368 byte[] protocol = BitBufferHelper.toByteArray(ipProtocol);
369 fieldValues.put(PROTOCOL, protocol);
374 * @param checksum the checksum to set
376 /*public IPv4 setChecksum() {
377 short ipChecksum = computeChecksum();
378 byte[] checksum = BitBufferHelper.toByteArray(ipChecksum);
379 fieldValues.put(CHECKSUM, checksum);
384 * Stores the IP source address from the header
385 * @param sourceAddress the sourceAddress to set
388 public IPv4 setSourceAddress(InetAddress ipSourceAddress) {
389 byte[] sourceAddress = ipSourceAddress.getAddress();
390 fieldValues.put(SIP, sourceAddress);
395 * Stores the IP destination address from the header
396 * @param the destination Address to set
399 public IPv4 setDestinationAddress(InetAddress ipDestinationAddress) {
400 byte[] sourceAddress = ipDestinationAddress.getAddress();
401 fieldValues.put(DIP, sourceAddress);
406 * Stores the IP destination address from the header
407 * @param destinationAddress the destinationAddress to set
410 public IPv4 setDestinationAddress(int ipDestinationAddress) {
411 byte[] destinationAddress = BitBufferHelper
412 .toByteArray(ipDestinationAddress);
413 fieldValues.put(DIP, destinationAddress);
418 * Generate a random number to set the Identification field
422 private short generateId() {
423 Random randomgen = new Random();
424 return (short) (randomgen.nextInt(Short.MAX_VALUE + 1));
428 * Store the options from IP header
429 * @param options - byte[]
432 public IPv4 setOptions(byte[] options) {
433 fieldValues.put(OPTIONS, options);
434 byte newIHL = (byte) (5 + options.length);
435 setHeaderLength(newIHL);
441 * Computes the header checksum
442 * @param byte[] hdrBytes - serialized bytes
443 * @param int endBitOffset - end bit Offset
444 * @return short - the computed checksum
446 private short computeChecksum(byte[] hdrBytes, int endByteOffset) {
447 int startByteOffset = endByteOffset - getHeaderLen();
448 short checkSum = (short) 0;
449 int sum = 0, carry = 0, finalSum = 0;
451 int checksumStartByte = startByteOffset + getfieldOffset(CHECKSUM)
452 / NetUtils.NumBitsInAByte;
454 for (int i = startByteOffset; i <= (endByteOffset - 1); i = i + 2) {
455 //Skip, if the current bytes are checkSum bytes
456 if (i == checksumStartByte)
458 StringBuffer sbuffer = new StringBuffer();
459 sbuffer.append(String.format("%02X", hdrBytes[i]));
460 if (i < (hdrBytes.length - 1))
461 sbuffer.append(String.format("%02X", hdrBytes[i + 1]));
463 parsedHex = Integer.valueOf(sbuffer.toString(), 16);
466 carry = (sum >> 16) & 0xFF;
467 finalSum = (sum & 0xFFFF) + carry;
468 checkSum = (short) ~((short) finalSum & 0xFFFF);
473 public int hashCode() {
474 return HashCodeBuilder.reflectionHashCode(this);
478 public boolean equals(Object obj) {
479 return EqualsBuilder.reflectionEquals(this, obj);
484 * Gets the number of bits for the fieldname specified
485 * If the fieldname has variable length like "Options", then this value is computed using the
486 * options length and the header length
487 * @param fieldname - String
488 * @return number of bits for fieldname - int
490 public int getfieldnumBits(String fieldName) {
491 if (fieldName.equals(OPTIONS)) {
492 byte[] options = getOptions();
493 return ((options == null) ? 0 : (options.length - getHeaderLen()));
495 return (((Pair<Integer, Integer>) hdrFieldCoordMap.get(fieldName))
501 * Method to perform post serialization - like computation of checksum of serialized header
502 * @param serializedBytes
504 * @Exception throws exception
506 protected void postSerializeCustomOperation(byte[] serializedBytes)
508 int startOffset = this.getfieldOffset(CHECKSUM);
509 int numBits = this.getfieldnumBits(CHECKSUM);
510 byte[] checkSum = BitBufferHelper.toByteArray(computeChecksum(
511 serializedBytes, serializedBytes.length));
512 BitBufferHelper.setBytes(serializedBytes, checkSum, startOffset,
519 * Stores the payload of IP, serializes it and stores the length of serialized payload
520 * bytes in Total Length
521 * @param payload - Packet
523 public void setPayload(Packet payload) {
524 this.payload = payload;
526 * Deriving the Total Lenght here
527 * TODO: See if we can derive the total length during
528 * another phase (during serialization/deserialization)
530 int payloadLength = 0;
532 payloadLength = payload.serialize().length;
533 } catch (Exception e) {
536 this.setTotalLength((short) (this.getHeaderLen() + payloadLength));
541 * Method to perform post deserialization - like compare computed checksum with
542 * the one obtained from IP header
544 protected void postDeserializeCustomOperation(byte[] data, int endBitOffset) {
545 int endByteOffset = endBitOffset / NetUtils.NumBitsInAByte;
546 int computedChecksum = computeChecksum(data, endByteOffset);
547 int actualChecksum = BitBufferHelper.getInt(fieldValues.get(CHECKSUM));
548 if (computedChecksum != actualChecksum)