4df42e05ffa01112d9d6a583afe06607d766e3e9
[onosfw.git] /
1 /*
2  * Copyright 2015 Open Networking Laboratory
3  *
4  * 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
7  *
8  *     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.
15  */
16
17 package org.onosproject.pcepio.protocol.ver1;
18
19 import java.util.LinkedList;
20 import java.util.ListIterator;
21
22 import org.jboss.netty.buffer.ChannelBuffer;
23 import org.onosproject.pcepio.exceptions.PcepParseException;
24 import org.onosproject.pcepio.protocol.PcepRroObject;
25 import org.onosproject.pcepio.types.IPv4SubObject;
26 import org.onosproject.pcepio.types.IPv6SubObject;
27 import org.onosproject.pcepio.types.LabelSubObject;
28 import org.onosproject.pcepio.types.PcepObjectHeader;
29 import org.onosproject.pcepio.types.PcepValueType;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import com.google.common.base.MoreObjects;
34
35 /**
36  * Provides PCEP RRO object.
37  */
38 public class PcepRroObjectVer1 implements PcepRroObject {
39
40     /*
41      * rfc3209
42           0                   1                   2                   3
43           0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
44          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45          | Object-Class  |   OT  |Res|P|I|   Object Length (bytes)       |
46          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47          |                                                               |
48          //                        (Subobjects)                          //
49          |                                                               |
50          +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51
52             Each subobject has its own Length
53             field.  The length contains the total length of the subobject in
54             bytes, including the Type and Length fields.  The length MUST always
55             be a multiple of 4, and at least 4.
56
57             An empty RRO with no subobjects is considered illegal.
58             Three kinds of subobjects are currently defined.
59
60            Subobject 1: IPv4 address
61
62             0                   1                   2                   3
63             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
64            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
65            |      Type     |     Length    | IPv4 address (4 bytes)        |
66            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
67            | IPv4 address (continued)      | Prefix Length |      Flags    |
68            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
69
70            Subobject 2: IPv6 address
71
72             0                   1                   2                   3
73             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
74            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
75            |      Type     |     Length    | IPv6 address (16 bytes)       |
76            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
77            | IPv6 address (continued)                                      |
78            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79            | IPv6 address (continued)                                      |
80            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81            | IPv6 address (continued)                                      |
82            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
83            | IPv6 address (continued)      | Prefix Length |      Flags    |
84            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85
86            Subobject 3, Label
87
88             0                   1                   2                   3
89             0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
90            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
91            |     Type      |     Length    |    Flags      |   C-Type      |
92            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
93            |       Contents of Label Object                                |
94            +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95
96      */
97     protected static final Logger log = LoggerFactory.getLogger(PcepRroObjectVer1.class);
98
99     public static final byte RRO_OBJ_TYPE = 1;
100     public static final byte RRO_OBJ_CLASS = 8;
101     public static final byte RRO_OBJECT_VERSION = 1;
102     public static final short RRO_OBJ_MINIMUM_LENGTH = 12;
103     public static final int OBJECT_HEADER_LENGTH = 4;
104     public static final int YTYPE_SHIFT_VALUE = 0x7F;
105
106     static final PcepObjectHeader DEFAULT_RRO_OBJECT_HEADER = new PcepObjectHeader(RRO_OBJ_CLASS, RRO_OBJ_TYPE,
107             PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, RRO_OBJ_MINIMUM_LENGTH);
108
109     private short rroObjType = 0;
110     private byte length;
111     private byte prefixLength;
112     private byte resvd;
113     PcepObjectHeader rroObjHeader;
114     private LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
115
116     /**
117      * Reset variables.
118      */
119     public PcepRroObjectVer1() {
120         this.rroObjHeader = null;
121         this.rroObjType = 0;
122         this.length = 0;
123     }
124
125     /**
126      * constructor to initialize parameters for RRO object.
127      *
128      * @param rroObjHeader RRO object header
129      * @param llSubObjects list of sub objects
130      */
131     public PcepRroObjectVer1(PcepObjectHeader rroObjHeader, LinkedList<PcepValueType> llSubObjects) {
132         this.rroObjHeader = rroObjHeader;
133         this.llSubObjects = llSubObjects;
134     }
135
136     /**
137      * Returns PCEP RRO Object Header.
138      *
139      * @return rroObjHeader RRO Object header
140      */
141     public PcepObjectHeader getRroObjHeader() {
142         return this.rroObjHeader;
143     }
144
145     /**
146      * Sets PCEP RRO Object Header.
147      *
148      * @param obj Object header
149      */
150     public void setRroObjHeader(PcepObjectHeader obj) {
151         this.rroObjHeader = obj;
152     }
153
154     @Override
155     public LinkedList<PcepValueType> getSubObjects() {
156         return this.llSubObjects;
157     }
158
159     @Override
160     public void setSubObjects(LinkedList<PcepValueType> llSubObjects) {
161         this.llSubObjects = llSubObjects;
162     }
163
164     /**
165      * Reads the channel buffer and returns object of PcepRroObject.
166      *
167      * @param cb of type channel buffer
168      * @return object of PcepRroObject
169      * @throws PcepParseException when fails to read from channel buffer
170      */
171     public static PcepRroObject read(ChannelBuffer cb) throws PcepParseException {
172
173         PcepObjectHeader rroObjHeader;
174         LinkedList<PcepValueType> llSubObjects;
175         rroObjHeader = PcepObjectHeader.read(cb);
176
177         //take only RroObject buffer.
178         ChannelBuffer tempCb = cb.readBytes(rroObjHeader.getObjLen() - OBJECT_HEADER_LENGTH);
179         llSubObjects = parseSubObjects(tempCb);
180
181         return new PcepRroObjectVer1(rroObjHeader, llSubObjects);
182     }
183
184     /**
185      * Returns list of sub objects.
186      *
187      * @param cb of type channel buffer
188      * @return list of sub objects
189      * @throws PcepParseException when fails to parse list of sub objects
190      */
191     protected static LinkedList<PcepValueType> parseSubObjects(ChannelBuffer cb) throws PcepParseException {
192
193         LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
194
195         while (0 < cb.readableBytes()) {
196
197             //check the Type of the Sub objects
198             byte yType = cb.readByte();
199             yType = (byte) (yType & (YTYPE_SHIFT_VALUE));
200             byte hLength = cb.readByte();
201
202             PcepValueType subObj;
203
204             switch (yType) {
205
206             case IPv4SubObject.TYPE:
207                 subObj = IPv4SubObject.read(cb);
208                 break;
209             case IPv6SubObject.TYPE:
210                 byte[] ipv6Value = new byte[IPv6SubObject.VALUE_LENGTH];
211                 cb.readBytes(ipv6Value, 0, IPv6SubObject.VALUE_LENGTH);
212                 subObj = new IPv6SubObject(ipv6Value);
213                 break;
214             case LabelSubObject.TYPE:
215                 subObj = LabelSubObject.read(cb);
216                 break;
217             default:
218                 throw new PcepParseException(" Unexpected sub object. Type: " + (int) yType);
219             }
220             // Check for the padding
221             int pad = hLength % 4;
222             if (0 < pad) {
223                 pad = 4 - pad;
224                 if (pad <= cb.readableBytes()) {
225                     cb.skipBytes(pad);
226                 }
227             }
228             llSubObjects.add(subObj);
229         }
230
231         return llSubObjects;
232     }
233
234     @Override
235     public int write(ChannelBuffer cb) throws PcepParseException {
236         //write Object header
237         int objStartIndex = cb.writerIndex();
238
239         int objLenIndex = rroObjHeader.write(cb);
240
241         if (objLenIndex <= 0) {
242             throw new PcepParseException(" object Length Index" + objLenIndex);
243         }
244
245         ListIterator<PcepValueType> listIterator = llSubObjects.listIterator();
246
247         while (listIterator.hasNext()) {
248             listIterator.next().write(cb);
249         }
250
251         //Update object length now
252         int length = cb.writerIndex() - objStartIndex;
253         cb.setShort(objLenIndex, (short) length);
254         //will be helpful during print().
255         rroObjHeader.setObjLen((short) length);
256
257         //As per RFC the length of object should be multiples of 4
258         int pad = length % 4;
259
260         if (0 != pad) {
261             pad = 4 - pad;
262             for (int i = 0; i < pad; i++) {
263                 cb.writeByte((byte) 0);
264             }
265             length = length + pad;
266         }
267         objLenIndex = cb.writerIndex();
268         return objLenIndex;
269     }
270
271     /**
272      * Builder class for PCEP RRO object.
273      */
274     public static class Builder implements PcepRroObject.Builder {
275         private boolean bIsHeaderSet = false;
276
277         private PcepObjectHeader rroObjHeader;
278         LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
279
280         private boolean bIsPFlagSet = false;
281         private boolean bPFlag;
282
283         private boolean bIsIFlagSet = false;
284         private boolean bIFlag;
285
286         @Override
287         public PcepRroObject build() {
288
289             PcepObjectHeader rroObjHeader = this.bIsHeaderSet ? this.rroObjHeader : DEFAULT_RRO_OBJECT_HEADER;
290
291             if (bIsPFlagSet) {
292                 rroObjHeader.setPFlag(bPFlag);
293             }
294
295             if (bIsIFlagSet) {
296                 rroObjHeader.setIFlag(bIFlag);
297             }
298             return new PcepRroObjectVer1(rroObjHeader, this.llSubObjects);
299         }
300
301         @Override
302         public PcepObjectHeader getRroObjHeader() {
303             return this.rroObjHeader;
304         }
305
306         @Override
307         public Builder setRroObjHeader(PcepObjectHeader obj) {
308             this.rroObjHeader = obj;
309             this.bIsHeaderSet = true;
310             return this;
311         }
312
313         @Override
314         public LinkedList<PcepValueType> getSubObjects() {
315             return this.llSubObjects;
316         }
317
318         @Override
319         public Builder setSubObjects(LinkedList<PcepValueType> llSubObjects) {
320             this.llSubObjects = llSubObjects;
321             return this;
322         }
323
324         @Override
325         public Builder setPFlag(boolean value) {
326             this.bPFlag = value;
327             this.bIsPFlagSet = true;
328             return this;
329         }
330
331         @Override
332         public Builder setIFlag(boolean value) {
333             this.bIFlag = value;
334             this.bIsIFlagSet = true;
335             return this;
336         }
337     }
338
339     @Override
340     public String toString() {
341         return MoreObjects.toStringHelper(getClass())
342                 .add("SubObjects", llSubObjects)
343                 .toString();
344     }
345 }