Mark AD-SAL interfaces as deprecated
[controller.git] / opendaylight / adsal / sal / api / src / main / java / org / opendaylight / controller / sal / packet / IPv4.java
1
2 /*
3  * Copyright (c) 2013-2014 Cisco Systems, Inc. and others.  All rights reserved.
4  *
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
8  */
9
10 /**
11  *
12  */
13 package org.opendaylight.controller.sal.packet;
14
15 import java.net.InetAddress;
16 import java.util.HashMap;
17 import java.util.LinkedHashMap;
18 import java.util.Map;
19 import java.util.Random;
20
21 import org.apache.commons.lang3.tuple.ImmutablePair;
22 import org.apache.commons.lang3.tuple.Pair;
23 import org.opendaylight.controller.sal.match.Match;
24 import org.opendaylight.controller.sal.match.MatchType;
25 import org.opendaylight.controller.sal.utils.IPProtocols;
26 import org.opendaylight.controller.sal.utils.NetUtils;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Class that represents the IPv4  packet objects
32  */
33 @Deprecated
34 public class IPv4 extends Packet {
35     protected static final Logger logger = LoggerFactory
36             .getLogger(IPv4.class);
37     private static final String VERSION = "Version";
38     private static final String HEADERLENGTH = "HeaderLength";
39     private static final String DIFFSERV = "DiffServ";
40     private static final String ECN = "ECN";
41     private static final String TOTLENGTH = "TotalLength";
42     private static final String IDENTIFICATION = "Identification";
43     private static final String FLAGS = "Flags";
44     private static final String FRAGOFFSET = "FragmentOffset";
45     private static final String TTL = "TTL";
46     private static final String PROTOCOL = "Protocol";
47     private static final String CHECKSUM = "Checksum";
48     private static final String SIP = "SourceIPAddress";
49     private static final String DIP = "DestinationIPAddress";
50     private static final String OPTIONS = "Options";
51
52     private static final int UNIT_SIZE_SHIFT = 2;
53     private static final int UNIT_SIZE = (1 << UNIT_SIZE_SHIFT);
54     private static final int MIN_HEADER_SIZE = 20;
55
56     public static final Map<Byte, Class<? extends Packet>> protocolClassMap;
57     static {
58         protocolClassMap = new HashMap<Byte, Class<? extends Packet>>();
59         protocolClassMap.put(IPProtocols.ICMP.byteValue(), ICMP.class);
60         protocolClassMap.put(IPProtocols.UDP.byteValue(), UDP.class);
61         protocolClassMap.put(IPProtocols.TCP.byteValue(), TCP.class);
62     }
63     private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
64         private static final long serialVersionUID = 1L;
65         {
66             put(VERSION, new ImmutablePair<Integer, Integer>(0, 4));
67             put(HEADERLENGTH, new ImmutablePair<Integer, Integer>(4, 4));
68             put(DIFFSERV, new ImmutablePair<Integer, Integer>(8, 6));
69             put(ECN, new ImmutablePair<Integer, Integer>(14, 2));
70             put(TOTLENGTH, new ImmutablePair<Integer, Integer>(16, 16));
71             put(IDENTIFICATION, new ImmutablePair<Integer, Integer>(32, 16));
72             put(FLAGS, new ImmutablePair<Integer, Integer>(48, 3));
73             put(FRAGOFFSET, new ImmutablePair<Integer, Integer>(51, 13));
74             put(TTL, new ImmutablePair<Integer, Integer>(64, 8));
75             put(PROTOCOL, new ImmutablePair<Integer, Integer>(72, 8));
76             put(CHECKSUM, new ImmutablePair<Integer, Integer>(80, 16));
77             put(SIP, new ImmutablePair<Integer, Integer>(96, 32));
78             put(DIP, new ImmutablePair<Integer, Integer>(128, 32));
79             put(OPTIONS, new ImmutablePair<Integer, Integer>(160, 0));
80         }
81     };
82
83     private final Map<String, byte[]> fieldValues;
84
85
86     /**
87      * Default constructor that sets the version to 4, headerLength to 5,
88      * and flags to 2.  The default value for the identification is set to a
89      * random number and the remaining fields are set to 0.
90      */
91     public IPv4() {
92         super();
93         fieldValues = new HashMap<String, byte[]>();
94         hdrFieldCoordMap = fieldCoordinates;
95         hdrFieldsMap = fieldValues;
96         corrupted = false;
97
98         setVersion((byte) 4);
99         setHeaderLength((byte) 5);
100         setDiffServ((byte) 0);
101         setECN((byte) 0);
102         setIdentification(generateId());
103         setFlags((byte) 2);
104         setFragmentOffset((short) 0);
105     }
106
107     /**
108      * The write access to the packet is set in this constructor.
109      * Constructor that sets the version to 4, headerLength to 5,
110      * and flags to 2.  The default value for the identification is set to a
111      * random number and the remaining fields are set to 0.
112      * @param boolean
113      */
114     public IPv4(boolean writeAccess) {
115         super(writeAccess);
116         fieldValues = new HashMap<String, byte[]>();
117         hdrFieldCoordMap = fieldCoordinates;
118         hdrFieldsMap = fieldValues;
119         corrupted = false;
120
121         setVersion((byte) 4);
122         setHeaderLength((byte) 5);
123         setDiffServ((byte) 0);
124         setECN((byte) 0);
125         setIdentification(generateId());
126         setFlags((byte) 2);
127         setFragmentOffset((short) 0);
128     }
129
130     /**
131      * Gets the IP version stored
132      * @return the version
133      */
134     public byte getVersion() {
135         return (BitBufferHelper.getByte(fieldValues.get(VERSION)));
136     }
137
138     /**
139      * Gets the IP header length stored
140      * @return the headerLength in bytes
141      */
142     public int getHeaderLen() {
143         return (4 * BitBufferHelper.getByte(fieldValues.get(HEADERLENGTH)));
144     }
145
146     /**
147      * Gets the header size in bits
148      * @return The number of bits constituting the header
149      */
150     @Override
151     public int getHeaderSize() {
152         int headerLen = this.getHeaderLen();
153         if (headerLen == 0) {
154             headerLen = MIN_HEADER_SIZE;
155         }
156
157         return headerLen * NetUtils.NumBitsInAByte;
158     }
159
160     /**
161      * Gets the differential services value stored
162      * @return the diffServ
163      */
164     public byte getDiffServ() {
165         return BitBufferHelper.getByte(fieldValues.get(DIFFSERV));
166     }
167
168     /**
169      * Gets the ecn bits stored
170      * @return the ecn bits
171      */
172     public byte getECN() {
173         return BitBufferHelper.getByte(fieldValues.get(ECN));
174     }
175
176     /**
177      * Gets the total length of the IP header in bytes
178      * @return the totalLength
179      */
180     public short getTotalLength() {
181         return (BitBufferHelper.getShort(fieldValues.get(TOTLENGTH)));
182     }
183
184     /**
185      * Gets the identification value stored
186      * @return the identification
187      */
188     public short getIdentification() {
189         return (BitBufferHelper.getShort(fieldValues.get(IDENTIFICATION)));
190     }
191
192     /**
193      * Gets the flag values stored
194      * @return the flags
195      */
196     public byte getFlags() {
197         return (BitBufferHelper.getByte(fieldValues.get(FLAGS)));
198     }
199
200     /**
201      * Gets the TTL value stored
202      * @return the ttl
203      */
204     public byte getTtl() {
205         return (BitBufferHelper.getByte(fieldValues.get(TTL)));
206     }
207
208     /**
209      * Gets the protocol value stored
210      * @return the protocol
211      */
212     public byte getProtocol() {
213         return (BitBufferHelper.getByte(fieldValues.get(PROTOCOL)));
214     }
215
216     /**
217      * Gets the checksum value stored
218      * @return the checksum
219      */
220     public short getChecksum() {
221         return (BitBufferHelper.getShort(fieldValues.get(CHECKSUM)));
222     }
223
224     /**
225      * Gets the fragment offset stored
226      * @return the fragmentOffset
227      */
228     public short getFragmentOffset() {
229         return (BitBufferHelper.getShort(fieldValues.get(FRAGOFFSET)));
230     }
231
232     /**
233      * Gets the source IP address stored
234      * @return the sourceAddress
235      */
236     public int getSourceAddress() {
237         return (BitBufferHelper.getInt(fieldValues.get(SIP)));
238     }
239
240     /**
241      * Gets the destination IP address stored
242      * @return the destinationAddress
243      */
244     public int getDestinationAddress() {
245         return (BitBufferHelper.getInt(fieldValues.get(DIP)));
246     }
247
248     /**
249      * gets the Options stored
250      * @return the options
251      */
252     public byte[] getOptions() {
253         return (fieldValues.get(OPTIONS));
254     }
255
256     @Override
257     /**
258      * Stores the value of fields read from data stream
259      * Variable header value like payload protocol, is stored here
260      */
261     public void setHeaderField(String headerField, byte[] readValue) {
262         if (headerField.equals(PROTOCOL)) {
263             // Don't set payloadClass if framgment offset is not zero.
264             byte[] fragoff = hdrFieldsMap.get(FRAGOFFSET);
265             if (fragoff == null || BitBufferHelper.getShort(fragoff) == 0) {
266                 payloadClass = protocolClassMap.get(readValue[0]);
267             }
268         } else if (headerField.equals(FRAGOFFSET)) {
269             if (readValue != null && BitBufferHelper.getShort(readValue) != 0) {
270                 // Clear payloadClass because protocol header is not present
271                 // in this packet.
272                 payloadClass = null;
273             }
274         } else if (headerField.equals(OPTIONS) &&
275                    (readValue == null || readValue.length == 0)) {
276             hdrFieldsMap.remove(headerField);
277             return;
278         }
279         hdrFieldsMap.put(headerField, readValue);
280     }
281
282     /**
283      * Stores the IP version from the header
284      * @param version the version to set
285      * @return @IPv4
286      */
287     public IPv4 setVersion(byte ipVersion) {
288         byte[] version = BitBufferHelper.toByteArray(ipVersion);
289         fieldValues.put(VERSION, version);
290         return this;
291     }
292
293     /**
294      * Stores the length of IP header in words (4 bytes)
295      * @param headerLength the headerLength to set
296      * @return IPv4
297      */
298     public IPv4 setHeaderLength(byte ipheaderLength) {
299         byte[] headerLength = BitBufferHelper.toByteArray(ipheaderLength);
300         fieldValues.put(HEADERLENGTH, headerLength);
301         return this;
302     }
303
304     /**
305      * Stores the differential services value from the IP header
306      * @param diffServ the diffServ to set
307      * @return IPv4
308      */
309     public IPv4 setDiffServ(byte ipdiffServ) {
310         byte[] diffServ = BitBufferHelper.toByteArray(ipdiffServ);
311         fieldValues.put(DIFFSERV, diffServ);
312         return this;
313     }
314
315     /**
316      * Stores the ECN bits from the header
317      * @param ECN bits to set
318      * @return IPv4
319      */
320     public IPv4 setECN(byte ecn) {
321         byte[] ecnbytes = BitBufferHelper.toByteArray(ecn);
322         fieldValues.put(ECN, ecnbytes);
323         return this;
324     }
325
326     /**
327      * Stores the total length of IP header in bytes
328      * @param totalLength the totalLength to set
329      * @return IPv4
330      */
331     public IPv4 setTotalLength(short iptotalLength) {
332         byte[] totalLength = BitBufferHelper.toByteArray(iptotalLength);
333         fieldValues.put(TOTLENGTH, totalLength);
334         return this;
335     }
336
337     /**
338      * Stores the identification number from the header
339      * @param identification the identification to set
340      * @return IPv4
341      */
342     public IPv4 setIdentification(short ipIdentification) {
343         byte[] identification = BitBufferHelper.toByteArray(ipIdentification);
344         fieldValues.put(IDENTIFICATION, identification);
345         return this;
346     }
347
348     /**
349      * Stores the IP flags value
350      * @param flags the flags to set
351      * @return IPv4
352      */
353     public IPv4 setFlags(byte ipFlags) {
354         byte[] flags = { ipFlags };
355         fieldValues.put(FLAGS, flags);
356         return this;
357     }
358
359     /**
360      * Stores the IP fragmentation offset value
361      * @param fragmentOffset the fragmentOffset to set
362      * @return IPv4
363      */
364     public IPv4 setFragmentOffset(short ipFragmentOffset) {
365         byte[] fragmentOffset = BitBufferHelper.toByteArray(ipFragmentOffset);
366         fieldValues.put(FRAGOFFSET, fragmentOffset);
367         return this;
368     }
369
370     /**
371      * Stores the TTL value
372      * @param ttl the ttl to set
373      * @return IPv4
374      */
375     public IPv4 setTtl(byte ipTtl) {
376         byte[] ttl = BitBufferHelper.toByteArray(ipTtl);
377         fieldValues.put(TTL, ttl);
378         return this;
379     }
380
381     /**
382      * Stores the protocol value of the IP payload
383      * @param protocol the protocol to set
384      * @return IPv4
385      */
386     public IPv4 setProtocol(byte ipProtocol) {
387         byte[] protocol = BitBufferHelper.toByteArray(ipProtocol);
388         fieldValues.put(PROTOCOL, protocol);
389         return this;
390     }
391
392     /**
393      * @param checksum the checksum to set
394      */
395     /*public IPv4 setChecksum() {
396         short ipChecksum = computeChecksum();
397         byte[] checksum = BitBufferHelper.toByteArray(ipChecksum);
398         fieldValues.put(CHECKSUM, checksum);
399         return this;
400     }*/
401
402     /**
403      * Stores the IP source address from the header
404      * @param sourceAddress the sourceAddress to set
405      * @return IPv4
406      */
407     public IPv4 setSourceAddress(InetAddress ipSourceAddress) {
408         byte[] sourceAddress = ipSourceAddress.getAddress();
409         fieldValues.put(SIP, sourceAddress);
410         return this;
411     }
412
413     /**
414      * Stores the IP destination address from the header
415      * @param the destination Address to set
416      * @return IPv4
417      */
418     public IPv4 setDestinationAddress(InetAddress ipDestinationAddress) {
419         byte[] sourceAddress = ipDestinationAddress.getAddress();
420         fieldValues.put(DIP, sourceAddress);
421         return this;
422     }
423
424     /**
425      * Stores the IP destination address from the header
426      * @param destinationAddress the destinationAddress to set
427      * @return IPv4
428      */
429     public IPv4 setDestinationAddress(int ipDestinationAddress) {
430         byte[] destinationAddress = BitBufferHelper
431                 .toByteArray(ipDestinationAddress);
432         fieldValues.put(DIP, destinationAddress);
433         return this;
434     }
435
436     /**
437      * Generate a random number to set the Identification field
438      * in IPv4 Header
439      * @return short
440      */
441     private short generateId() {
442         Random randomgen = new Random();
443         return (short) (randomgen.nextInt(Short.MAX_VALUE + 1));
444     }
445
446     /**
447      * Store the options from IP header
448      * @param options - byte[]
449      * @return IPv4
450      */
451     public IPv4 setOptions(byte[] options) {
452         byte newIHL = (byte)(MIN_HEADER_SIZE >>> UNIT_SIZE_SHIFT);
453         if (options == null || options.length == 0) {
454             fieldValues.remove(OPTIONS);
455         } else {
456             int len = options.length;
457             int rlen = (len + (UNIT_SIZE - 1)) & ~(UNIT_SIZE - 1);
458             if (rlen > len) {
459                 // Padding is required.
460                 byte[] newopt = new byte[rlen];
461                 System.arraycopy(options, 0, newopt, 0, len);
462                 options = newopt;
463                 len = rlen;
464             }
465             fieldValues.put(OPTIONS, options);
466             newIHL += (len >>> UNIT_SIZE_SHIFT);
467         }
468
469         setHeaderLength(newIHL);
470
471         return this;
472     }
473
474     /**
475      * Computes the IPv4 header checksum on the passed stream of bytes
476      * representing the packet
477      *
478      * @param data
479      *            The byte stream
480      * @param offset
481      *            The byte offset from where the IPv4 packet starts
482      * @return The computed checksum
483      */
484     short computeChecksum(byte[] data, int start) {
485         int end = start + getHeaderLen();
486         short checkSum = (short) 0;
487         int sum = 0, carry = 0, finalSum = 0;
488         int wordData;
489         int checksumStart = start
490                 + (getfieldOffset(CHECKSUM) / NetUtils.NumBitsInAByte);
491
492         for (int i = start; i <= (end - 1); i = i + 2) {
493             // Skip, if the current bytes are checkSum bytes
494             if (i == checksumStart) {
495                 continue;
496             }
497             wordData = ((data[i] << 8) & 0xFF00) + (data[i + 1] & 0xFF);
498             sum = sum + wordData;
499         }
500         carry = (sum >> 16) & 0xFF;
501         finalSum = (sum & 0xFFFF) + carry;
502         checkSum = (short) ~((short) finalSum & 0xFFFF);
503
504         return checkSum;
505     }
506
507     @Override
508     /**
509      * Gets the number of bits for the fieldname specified
510      * If the fieldname has variable length like "Options", then this value is computed using the header length
511      * @param fieldname - String
512      * @return number of bits for fieldname - int
513      */
514     public int getfieldnumBits(String fieldName) {
515         if (fieldName.equals(OPTIONS)) {
516             return (getHeaderLen() - MIN_HEADER_SIZE) * NetUtils.NumBitsInAByte;
517         }
518         return hdrFieldCoordMap.get(fieldName).getRight();
519     }
520
521     @Override
522     /**
523      * Method to perform post serialization - like computation of checksum of serialized header
524      * @param data
525      * @return void
526      * @Exception throws PacketException
527      */
528     protected void postSerializeCustomOperation(byte[] data)
529             throws PacketException {
530
531         // Recompute the total length field here
532         byte[] totalLength = BitBufferHelper.toByteArray((short) data.length);
533         try {
534             BitBufferHelper.setBytes(data, totalLength, getfieldOffset(TOTLENGTH),
535                     getfieldnumBits(TOTLENGTH));
536         } catch (BufferException e) {
537             throw new PacketException(e.getMessage());
538         }
539
540         // Now compute the Header Checksum
541         byte[] checkSum = BitBufferHelper.toByteArray(computeChecksum(data, 0));
542
543         try {
544             BitBufferHelper.setBytes(data, checkSum, getfieldOffset(CHECKSUM),
545                     getfieldnumBits(CHECKSUM));
546         } catch (BufferException e) {
547             throw new PacketException(e.getMessage());
548         }
549     }
550
551     @Override
552     /**
553      * Stores the payload of IP, serializes it and stores the length of serialized payload
554      * bytes in Total Length
555      * @param payload - Packet
556      */
557     /**
558      * Set the total length field in the IPv4 Object
559      * Note: this field will get overwritten during serialization phase.
560      */
561     public void setPayload(Packet payload) {
562         this.payload = payload;
563         /*
564          * Deriving the Total Length here
565          */
566         int payloadLength = 0;
567         if (payload != null) {
568             try {
569                 payloadLength = payload.serialize().length;
570             } catch (PacketException e) {
571                 logger.error("", e);
572             }
573         }
574
575         this.setTotalLength((short) (this.getHeaderLen() + payloadLength));
576     }
577
578
579     /**
580      * Method to perform post deserialization - like compare computed checksum with
581      * the one obtained from IP header
582      */
583     @Override
584     protected void postDeserializeCustomOperation(byte[] data, int startBitOffset) {
585         int start = startBitOffset / NetUtils.NumBitsInAByte;
586         short computedChecksum = computeChecksum(data, start);
587         short actualChecksum = BitBufferHelper.getShort(fieldValues.get(CHECKSUM));
588         if (computedChecksum != actualChecksum) {
589             corrupted = true;
590         }
591     }
592
593     @Override
594     public void populateMatch(Match match) {
595         match.setField(MatchType.NW_SRC, NetUtils.getInetAddress(this.getSourceAddress()));
596         match.setField(MatchType.NW_DST, NetUtils.getInetAddress(this.getDestinationAddress()));
597         match.setField(MatchType.NW_PROTO, this.getProtocol());
598         match.setField(MatchType.NW_TOS, this.getDiffServ());
599     }
600 }