4d7cb16e58584b883375e00dfaf8e1199fc83b69
[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.PcepEroObject;
25 import org.onosproject.pcepio.types.AutonomousSystemTlv;
26 import org.onosproject.pcepio.types.IPv4SubObject;
27 import org.onosproject.pcepio.types.IPv6SubObject;
28 import org.onosproject.pcepio.types.PathKeySubObject;
29 import org.onosproject.pcepio.types.PcepErrorDetailInfo;
30 import org.onosproject.pcepio.types.PcepObjectHeader;
31 import org.onosproject.pcepio.types.PcepValueType;
32 import org.onosproject.pcepio.types.SrEroSubObject;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import com.google.common.base.MoreObjects;
37
38 /**
39  * Provides PCEP Ero Object.
40  */
41 public class PcepEroObjectVer1 implements PcepEroObject {
42     /*
43      * rfc3209
44       0                   1                   2                   3
45       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
46      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47      | Object-Class  |   OT  |Res|P|I|   Object Length (bytes)       |
48      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49      |                                                               |
50      //                        (Subobjects)                          //
51      |                                                               |
52      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53
54      If a Path message contains multiple EXPLICIT_ROUTE objects, only the
55      first object is meaningful.  Subsequent EXPLICIT_ROUTE objects MAY be
56      ignored and SHOULD NOT be propagated.
57
58      In current implementation, only strict hops are supported. So,
59      empty ERO with no sub-objects is considered illegal.
60
61      Subobjects:
62       0                   1
63       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
64      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
65      |L|    Type     |     Length    | (Subobject contents)          |
66      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-------------//----------------+
67
68       L
69
70          The L bit is an attribute of the subobject.  The L bit is set
71          if the subobject represents a loose hop in the explicit route.
72          If the bit is not set, the subobject represents a strict hop in
73          the explicit route.
74
75       Type
76
77          The Type indicates the type of contents of the subobject.
78
79
80       Subobject 1: IPv4 address
81
82       0                   1                   2                   3
83       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
84      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
85      |L|    Type     |     Length    | IPv4 address (4 bytes)        |
86      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
87      | IPv4 address (continued)      | Prefix Length |      Resvd    |
88      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
89
90      Subobject 2:  IPv6 Prefix
91
92       0                   1                   2                   3
93       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
94      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
95      |L|    Type     |     Length    | IPv6 address (16 bytes)       |
96      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
97      | IPv6 address (continued)                                      |
98      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
99      | IPv6 address (continued)                                      |
100      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
101      | IPv6 address (continued)                                      |
102      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
103      | IPv6 address (continued)      | Prefix Length |      Resvd    |
104      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
105
106      Subobject 3:  Autonomous System Number
107
108      The contents of an Autonomous System (AS) number subobject are a 2-
109      octet AS number.  The abstract node represented by this subobject is
110      the set of nodes belonging to the autonomous system.
111
112      The length of the AS number subobject is 4 octets.
113
114      Subobject 4: PATH_KEY_32_BIT_SUB_OBJ_TYPE:
115
116       Pathkey subobject(RFC 5520):
117       0                   1                   2                   3
118       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
119      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
120      |L|    Type     |     Length    |           Path-Key            |
121      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
122      |                         PCE ID (4 bytes)                      |
123      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
124
125      Subobject 5: SR_ERO_SUB_OBJ_TYPE:
126
127        SR-ERO subobject: (draft-ietf-pce-segment-routing-00)
128       0                   1                   2                   3
129       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
130      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
131      |L|    Type     |     Length    |  ST   |     Flags     |F|S|C|M|
132      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
133      |                              SID                              |
134      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
135      //                        NAI (variable)                       //
136      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
137      */
138
139     protected static final Logger log = LoggerFactory.getLogger(PcepEroObjectVer1.class);
140
141     public static final byte ERO_OBJ_TYPE = 1;
142     public static final byte ERO_OBJ_CLASS = 7;
143     public static final byte ERO_OBJECT_VERSION = 1;
144     public static final short ERO_OBJ_MINIMUM_LENGTH = 12;
145     public static final byte IPV4_TYPE = 1;
146     public static final byte PATH_KEY_32_BIT_SUB_OBJ_TYPE = 64;
147     public static final int LABEL_SUB_OBJ_TYPE = 3;
148     public static final int SR_ERO_SUB_OBJ_TYPE = 96;
149     public static final int OBJECT_HEADER_LENGTH = 4;
150     public static final int YTYPE_SHIFT_VALUE = 0x7F;
151
152     static final PcepObjectHeader DEFAULT_ERO_OBJECT_HEADER = new PcepObjectHeader(ERO_OBJ_CLASS, ERO_OBJ_TYPE,
153             PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, ERO_OBJ_MINIMUM_LENGTH);
154
155     private PcepObjectHeader eroObjHeader;
156     private LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
157
158     /**
159      * reset variables.
160      */
161     public PcepEroObjectVer1() {
162         this.eroObjHeader = null;
163         this.llSubObjects = null;
164     }
165
166     /**
167      * Constructor to initialize parameters of ERO object.
168      *
169      * @param eroObjHeader ERO object header
170      * @param llSubObjects list of sub objects.
171      */
172     public PcepEroObjectVer1(PcepObjectHeader eroObjHeader, LinkedList<PcepValueType> llSubObjects) {
173
174         this.eroObjHeader = eroObjHeader;
175         this.llSubObjects = llSubObjects;
176     }
177
178     /**
179      * Returns ERO object header.
180      *
181      * @return eroObjHeader ERO object header
182      */
183     public PcepObjectHeader getEroObjHeader() {
184         return this.eroObjHeader;
185     }
186
187     /**
188      * Sets Object Header.
189      *
190      * @param obj ERO object header
191      */
192     public void setEroObjHeader(PcepObjectHeader obj) {
193         this.eroObjHeader = obj;
194     }
195
196     @Override
197     public LinkedList<PcepValueType> getSubObjects() {
198         return this.llSubObjects;
199     }
200
201     @Override
202     public void setSubObjects(LinkedList<PcepValueType> llSubObjects) {
203         this.llSubObjects = llSubObjects;
204     }
205
206     /**
207      * Reads from channel buffer and returns object of PcepEroObject.
208      *
209      * @param cb channel buffer.
210      * @return  object of PcepEroObject
211      * @throws PcepParseException when ERO object is not present in channel buffer
212      */
213     public static PcepEroObject read(ChannelBuffer cb) throws PcepParseException {
214
215         PcepObjectHeader eroObjHeader;
216         LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
217
218         eroObjHeader = PcepObjectHeader.read(cb);
219
220         if (eroObjHeader.getObjClass() != PcepEroObjectVer1.ERO_OBJ_CLASS) {
221             log.debug("ErrorType:" + PcepErrorDetailInfo.ERROR_TYPE_6 + " ErrorValue:"
222                     + PcepErrorDetailInfo.ERROR_VALUE_9);
223             throw new PcepParseException(PcepErrorDetailInfo.ERROR_TYPE_6, PcepErrorDetailInfo.ERROR_VALUE_9);
224         }
225
226         if (eroObjHeader.getObjLen() > OBJECT_HEADER_LENGTH) {
227             ChannelBuffer tempCb = cb.readBytes(eroObjHeader.getObjLen() - OBJECT_HEADER_LENGTH);
228             llSubObjects = parseSubObjects(tempCb);
229         }
230         return new PcepEroObjectVer1(eroObjHeader, llSubObjects);
231     }
232
233     /**
234      * Parse list of Sub Objects.
235      *
236      * @param cb channel buffer
237      * @return list of Sub Objects
238      * @throws PcepParseException when fails to parse sub object list
239      */
240     protected static LinkedList<PcepValueType> parseSubObjects(ChannelBuffer cb) throws PcepParseException {
241
242         LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
243
244         while (0 < cb.readableBytes()) {
245
246             //check the Type of the TLV
247             byte yType = cb.readByte();
248             yType = (byte) (yType & (YTYPE_SHIFT_VALUE));
249             byte hLength = cb.readByte();
250
251             PcepValueType subObj;
252
253             switch (yType) {
254
255             case IPv4SubObject.TYPE:
256                 subObj = IPv4SubObject.read(cb);
257                 break;
258             case IPv6SubObject.TYPE:
259                 byte[] ipv6Value = new byte[IPv6SubObject.VALUE_LENGTH];
260                 cb.readBytes(ipv6Value, 0, IPv6SubObject.VALUE_LENGTH);
261                 subObj = new IPv6SubObject(ipv6Value);
262                 break;
263             case AutonomousSystemTlv.TYPE:
264                 subObj = AutonomousSystemTlv.read(cb);
265                 break;
266             case PathKeySubObject.TYPE:
267                 subObj = PathKeySubObject.read(cb);
268                 break;
269             case SrEroSubObject.TYPE:
270                 subObj = SrEroSubObject.read(cb);
271                 break;
272             default:
273                 throw new PcepParseException("Unexpected sub object. Type: " + (int) yType);
274             }
275             // Check for the padding
276             int pad = hLength % 4;
277             if (0 < pad) {
278                 pad = 4 - pad;
279                 if (pad <= cb.readableBytes()) {
280                     cb.skipBytes(pad);
281                 }
282             }
283
284             llSubObjects.add(subObj);
285         }
286         if (0 < cb.readableBytes()) {
287             throw new PcepParseException("Subobject parsing error. Extra bytes received.");
288         }
289         return llSubObjects;
290     }
291
292     @Override
293     public int write(ChannelBuffer cb) throws PcepParseException {
294
295         //write Object header
296         int objStartIndex = cb.writerIndex();
297
298         int objLenIndex = eroObjHeader.write(cb);
299
300         if (objLenIndex <= 0) {
301             throw new PcepParseException("Failed to write ERO object header. Index " + objLenIndex);
302         }
303
304         ListIterator<PcepValueType> listIterator = llSubObjects.listIterator();
305
306         while (listIterator.hasNext()) {
307             listIterator.next().write(cb);
308         }
309
310         //Update object length now
311         int length = cb.writerIndex() - objStartIndex;
312         cb.setShort(objLenIndex, (short) length);
313         //will be helpful during print().
314         eroObjHeader.setObjLen((short) length);
315
316         //As per RFC the length of object should be multiples of 4
317         int pad = length % 4;
318
319         if (pad != 0) {
320             pad = 4 - pad;
321             for (int i = 0; i < pad; i++) {
322                 cb.writeByte((byte) 0);
323             }
324             length = length + pad;
325         }
326
327         objLenIndex = cb.writerIndex();
328         return objLenIndex;
329     }
330
331     /**
332      * Builder class for PCEP ERO object.
333      */
334     public static class Builder implements PcepEroObject.Builder {
335
336         private boolean bIsHeaderSet = false;
337
338         private boolean bIsPFlagSet = false;
339         private boolean bPFlag;
340
341         private boolean bIsIFlagSet = false;
342         private boolean bIFlag;
343
344         private PcepObjectHeader eroObjHeader;
345         LinkedList<PcepValueType> llSubObjects = new LinkedList<>();
346
347         @Override
348         public PcepEroObject build() {
349
350             PcepObjectHeader eroObjHeader = this.bIsHeaderSet ? this.eroObjHeader : DEFAULT_ERO_OBJECT_HEADER;
351
352             if (bIsPFlagSet) {
353                 eroObjHeader.setPFlag(bPFlag);
354             }
355
356             if (bIsIFlagSet) {
357                 eroObjHeader.setIFlag(bIFlag);
358             }
359
360             return new PcepEroObjectVer1(eroObjHeader, this.llSubObjects);
361         }
362
363         @Override
364         public PcepObjectHeader getEroObjHeader() {
365             return this.eroObjHeader;
366         }
367
368         @Override
369         public Builder setEroObjHeader(PcepObjectHeader obj) {
370             this.eroObjHeader = obj;
371             this.bIsHeaderSet = true;
372             return this;
373         }
374
375         @Override
376         public LinkedList<PcepValueType> getSubObjects() {
377             return this.llSubObjects;
378         }
379
380         @Override
381         public Builder setSubObjects(LinkedList<PcepValueType> llSubObjects) {
382             this.llSubObjects = llSubObjects;
383             return this;
384         }
385
386         @Override
387         public Builder setPFlag(boolean value) {
388             this.bPFlag = value;
389             this.bIsPFlagSet = true;
390             return this;
391         }
392
393         @Override
394         public Builder setIFlag(boolean value) {
395             this.bIFlag = value;
396             this.bIsIFlagSet = true;
397             return this;
398         }
399     }
400
401     @Override
402     public String toString() {
403         return MoreObjects.toStringHelper(getClass())
404                 .add("EroObjHeader", eroObjHeader).add("SubObjects", llSubObjects)
405                 .toString();
406     }
407 }