bcc679d38f27d27f43786b8f61b0a2b9c2dac565
[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.PcepCloseMsg;
25 import org.onosproject.pcepio.protocol.PcepMessageReader;
26 import org.onosproject.pcepio.protocol.PcepMessageWriter;
27 import org.onosproject.pcepio.protocol.PcepType;
28 import org.onosproject.pcepio.protocol.PcepVersion;
29 import org.onosproject.pcepio.types.PcepObjectHeader;
30 import org.onosproject.pcepio.types.PcepValueType;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import com.google.common.base.MoreObjects;
35
36 /**
37  * Provides PCEP Close Message.
38  */
39 class PcepCloseMsgVer1 implements PcepCloseMsg {
40
41     /*
42      * RFC : 5440 , section : 6.8
43      * <Close Message>           ::= <Common Header> <CLOSE>
44      *
45          0                   1                   2                   3
46          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
47         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48         | Ver |  Flags  |  Message-Type |       Message-Length          |
49         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50         | Object-Class  |   OT  |Res|P|I|   Object Length (bytes)       |
51         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52         |          Reserved             |      Flags    |    Reason     |
53         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54         |                                                               |
55         //                         Optional TLVs                       //
56         |                                                               |
57         +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58      */
59
60     protected static final Logger log = LoggerFactory.getLogger(PcepCloseMsgVer1.class);
61
62     // Pcep version: 1
63     public static final byte PACKET_VERSION = 1;
64     public static final int PACKET_MINIMUM_LENGTH = 12;
65     public static final PcepType MSG_TYPE = PcepType.CLOSE;
66     public static final byte CLOSE_OBJ_TYPE = 1;
67     public static final byte CLOSE_OBJ_CLASS = 15;
68     public static final byte CLOSE_OBJECT_VERSION = 1;
69     public static final byte DEFAULT_REASON = 1; // Default reason to close
70     public static final short CLOSE_OBJ_MINIMUM_LENGTH = 8;
71     public static final int SHIFT_FLAG = 5;
72     static final PcepObjectHeader DEFAULT_CLOSE_HEADER = new PcepObjectHeader(CLOSE_OBJ_CLASS, CLOSE_OBJ_TYPE,
73             PcepObjectHeader.REQ_OBJ_OPTIONAL_PROCESS, PcepObjectHeader.RSP_OBJ_PROCESSED, CLOSE_OBJ_MINIMUM_LENGTH);
74
75     private final PcepObjectHeader closeObjHeader;
76     private byte yReason;
77     private LinkedList<PcepValueType> llOptionalTlv;
78
79     public static final PcepCloseMsgVer1.Reader READER = new Reader();
80
81     /**
82      * Reader class for reading close message for channel buffer.
83      */
84     static class Reader implements PcepMessageReader<PcepCloseMsg> {
85         PcepObjectHeader closeObjHeader;
86         byte yReason;
87         // Optional TLV
88         private LinkedList<PcepValueType> llOptionalTlv;
89
90         @Override
91         public PcepCloseMsg readFrom(ChannelBuffer cb) throws PcepParseException {
92
93             if (cb.readableBytes() < PACKET_MINIMUM_LENGTH) {
94                 throw new PcepParseException("Packet size is less than the minimum length.");
95             }
96             // fixed value property version == 1
97             byte version = cb.readByte();
98             version = (byte) (version >> SHIFT_FLAG);
99             if (version != PACKET_VERSION) {
100                 throw new PcepParseException("Wrong version. Expected=PcepVersion.PCEP_1(1), got=" + version);
101             }
102             // fixed value property type == 7
103             byte type = cb.readByte();
104             if (type != MSG_TYPE.getType()) {
105                 throw new PcepParseException("Wrong type. Expected=PcepType.CLOSE(7), got=" + type);
106             }
107             short length = cb.readShort();
108             if (length < PACKET_MINIMUM_LENGTH) {
109                 throw new PcepParseException("Wrong length. Expected to be >= " + PACKET_MINIMUM_LENGTH + ", was: "
110                         + length);
111             }
112             closeObjHeader = PcepObjectHeader.read(cb);
113             // Reserved
114             cb.readShort();
115             // Flags
116             cb.readByte();
117             // Reason
118             yReason = cb.readByte();
119             // parse optional TLV
120             llOptionalTlv = parseOptionalTlv(cb);
121             return new PcepCloseMsgVer1(closeObjHeader, yReason, llOptionalTlv);
122         }
123     }
124
125     /**
126      * Parse the list of Optional Tlvs.
127      *
128      * @param cb channel buffer
129      * @return list of Optional Tlvs
130      * @throws PcepParseException when fails to parse optional tlvs
131      */
132     public static LinkedList<PcepValueType> parseOptionalTlv(ChannelBuffer cb) throws PcepParseException {
133
134         LinkedList<PcepValueType> llOptionalTlv = new LinkedList<>();
135         /*
136          rfc 5440:
137          Optional TLVs may be included within the CLOSE object body. The
138          specification of such TLVs is outside the scope of this document.
139          */
140         return llOptionalTlv;
141     }
142
143     /**
144      * constructor to initialize PCEP close Message with all the parameters.
145      *
146      * @param closeObjHeader object header for close message
147      * @param yReason reason for closing the channel
148      * @param llOptionalTlv list of optional tlvs
149      */
150     PcepCloseMsgVer1(PcepObjectHeader closeObjHeader, byte yReason, LinkedList<PcepValueType> llOptionalTlv) {
151
152         this.closeObjHeader = closeObjHeader;
153         this.yReason = yReason;
154         this.llOptionalTlv = llOptionalTlv;
155     }
156
157     /**
158      * Builder class for PCEP close message.
159      */
160     static class Builder implements PcepCloseMsg.Builder {
161
162         // PCEP Close message fields
163         private boolean bIsHeaderSet = false;
164         private PcepObjectHeader closeObjHeader;
165         private boolean bIsReasonSet = false;
166         private byte yReason;
167         private LinkedList<PcepValueType> llOptionalTlv = new LinkedList<>();
168
169         private boolean bIsPFlagSet = false;
170         private boolean bPFlag;
171
172         private boolean bIsIFlagSet = false;
173         private boolean bIFlag;
174
175         @Override
176         public PcepVersion getVersion() {
177             return PcepVersion.PCEP_1;
178         }
179
180         @Override
181         public PcepType getType() {
182             return PcepType.CLOSE;
183         }
184
185         @Override
186         public PcepCloseMsg build() {
187
188             PcepObjectHeader closeObjHeader = this.bIsHeaderSet ? this.closeObjHeader : DEFAULT_CLOSE_HEADER;
189             byte yReason = this.bIsReasonSet ? this.yReason : DEFAULT_REASON;
190
191             if (bIsPFlagSet) {
192                 closeObjHeader.setPFlag(bPFlag);
193             }
194
195             if (bIsIFlagSet) {
196                 closeObjHeader.setIFlag(bIFlag);
197             }
198             return new PcepCloseMsgVer1(closeObjHeader, yReason, this.llOptionalTlv);
199         }
200
201         @Override
202         public PcepObjectHeader getCloseObjHeader() {
203             return this.closeObjHeader;
204         }
205
206         @Override
207         public Builder setCloseObjHeader(PcepObjectHeader obj) {
208             this.closeObjHeader = obj;
209             this.bIsHeaderSet = true;
210             return this;
211         }
212
213         @Override
214         public byte getReason() {
215             return this.yReason;
216         }
217
218         @Override
219         public Builder setReason(byte value) {
220             this.yReason = value;
221             this.bIsReasonSet = true;
222             return this;
223         }
224
225         @Override
226         public Builder setOptionalTlv(LinkedList<PcepValueType> llOptionalTlv) {
227             this.llOptionalTlv = llOptionalTlv;
228             return this;
229         }
230
231         @Override
232         public LinkedList<PcepValueType> getOptionalTlv() {
233             return this.llOptionalTlv;
234         }
235
236         @Override
237         public Builder setPFlag(boolean value) {
238             this.bPFlag = value;
239             this.bIsPFlagSet = true;
240             return this;
241         }
242
243         @Override
244         public Builder setIFlag(boolean value) {
245             this.bIFlag = value;
246             this.bIsIFlagSet = true;
247             return this;
248         }
249     }
250
251     @Override
252     public void writeTo(ChannelBuffer cb) throws PcepParseException {
253         WRITER.write(cb, this);
254     }
255
256     static final Writer WRITER = new Writer();
257
258     /**
259      * Writer class for writing close message to channel buffer.
260      */
261     static class Writer implements PcepMessageWriter<PcepCloseMsgVer1> {
262
263         @Override
264         public void write(ChannelBuffer cb, PcepCloseMsgVer1 message) throws PcepParseException {
265             int startIndex = cb.writerIndex();
266             // first 3 bits set to version
267             cb.writeByte((byte) (PACKET_VERSION << SHIFT_FLAG));
268             // message type
269             cb.writeByte(MSG_TYPE.getType());
270             // length is length of variable message, will be updated at the end
271             // Store the position of message
272             // length in buffer
273             int msgLenIndex = cb.writerIndex();
274             cb.writeShort((short) 0);
275             int objStartIndex = cb.writerIndex();
276             int objLenIndex = message.closeObjHeader.write(cb);
277             if (objLenIndex <= 0) {
278                 throw new PcepParseException("Failed to write Close object header.");
279             }
280             // first 3 bits set to version
281             cb.writeShort(0); // Reserved
282             cb.writeByte(0); // Flags
283             cb.writeByte(message.yReason);
284             // Pack optional TLV
285             packOptionalTlv(cb, message);
286             int length = cb.writerIndex() - objStartIndex;
287             cb.setShort(objLenIndex, (short) length);
288             // will be helpful during print().
289             message.closeObjHeader.setObjLen((short) length);
290             // As per RFC the length of object should be
291             // multiples of 4
292             int pad = length % 4;
293             if (pad != 0) {
294                 pad = 4 - pad;
295                 for (int i = 0; i < pad; i++) {
296                     cb.writeByte((byte) 0);
297                 }
298                 length = length + pad;
299             }
300             // update message length field
301             length = cb.writerIndex() - startIndex;
302             cb.setShort(msgLenIndex, (short) length);
303         }
304
305         public void packOptionalTlv(ChannelBuffer cb, PcepCloseMsgVer1 message) {
306
307             LinkedList<PcepValueType> llOptionalTlv = message.llOptionalTlv;
308             ListIterator<PcepValueType> listIterator = llOptionalTlv.listIterator();
309             while (listIterator.hasNext()) {
310                 listIterator.next().write(cb);
311             }
312         }
313     }
314
315     @Override
316     public PcepVersion getVersion() {
317         return PcepVersion.PCEP_1;
318     }
319
320     @Override
321     public PcepType getType() {
322         return MSG_TYPE;
323     }
324
325     @Override
326     public byte getReason() {
327         return this.yReason;
328     }
329
330     @Override
331     public void setReason(byte value) {
332         this.yReason = value;
333     }
334
335     @Override
336     public LinkedList<PcepValueType> getOptionalTlv() {
337         return this.llOptionalTlv;
338     }
339
340     @Override
341     public void setOptionalTlv(LinkedList<PcepValueType> llOptionalTlv) {
342         this.llOptionalTlv = llOptionalTlv;
343     }
344
345     @Override
346     public String toString() {
347         return MoreObjects.toStringHelper(getClass())
348                 .add("closeObjectHeader", closeObjHeader).add("Reason", yReason)
349                 .add("OptionalTlvlist", llOptionalTlv).toString();
350     }
351 }