064deadabe5b9b632d940b6704d2ceee8f84e4d4
[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 package org.onosproject.bgpio.protocol.ver4;
17
18 import org.jboss.netty.buffer.ChannelBuffer;
19 import org.onosproject.bgpio.exceptions.BGPParseException;
20 import org.onosproject.bgpio.protocol.BGPMessageReader;
21 import org.onosproject.bgpio.protocol.BGPMessageWriter;
22 import org.onosproject.bgpio.protocol.BGPNotificationMsg;
23 import org.onosproject.bgpio.protocol.BGPType;
24 import org.onosproject.bgpio.protocol.BGPVersion;
25 import org.onosproject.bgpio.types.BGPErrorType;
26 import org.onosproject.bgpio.types.BGPHeader;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 import com.google.common.base.MoreObjects;
31
32 /**
33  * A NOTIFICATION message is sent when an error condition is detected. The BGP connection is closed immediately after it
34  * is sent.
35  */
36 class BGPNotificationMsgVer4 implements BGPNotificationMsg {
37
38     /*
39           0                   1                   2                   3
40           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
41           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42           | Error code    | Error subcode |   Data (variable)             |
43           +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44               REFERENCE : RFC 4271
45     */
46
47     protected static final Logger log = LoggerFactory.getLogger(BGPNotificationMsgVer4.class);
48
49     static final byte PACKET_VERSION = 4;
50     //BGPHeader(19) + Error code(1) + Error subcode(1)
51     static final int TOTAL_MESSAGE_MIN_LENGTH = 21;
52     static final int PACKET_MINIMUM_LENGTH = 2;
53     static final BGPType MSG_TYPE = BGPType.NOTIFICATION;
54     static final byte DEFAULT_ERRORSUBCODE = 0;
55     static final byte[] MARKER = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
56             0x01, 0x01};
57     static final byte MESSAGE_TYPE = 3;
58     static final BGPHeader DEFAULT_MESSAGE_HEADER = new BGPHeader(MARKER, BGPHeader.DEFAULT_HEADER_LENGTH,
59                                                                   MESSAGE_TYPE);
60
61     private byte errorCode;
62     private byte errorSubCode;
63     private byte[] data;
64     private BGPHeader bgpHeader;
65     public static final BGPNotificationMsgVer4.Reader READER = new Reader();
66
67     /**
68      * Resets fields.
69      */
70     public BGPNotificationMsgVer4() {
71         this.bgpHeader = null;
72         this.data = null;
73         this.errorCode = 0;
74         this.errorSubCode = 0;
75     }
76
77     /**
78      * Constructor to initialize parameters.
79      *
80      * @param bgpHeader BGP Header in notification message
81      * @param errorCode error code
82      * @param errorSubCode error subcode
83      * @param data field
84      */
85     public BGPNotificationMsgVer4(BGPHeader bgpHeader, byte errorCode, byte errorSubCode, byte[] data) {
86         this.bgpHeader = bgpHeader;
87         this.data = data;
88         this.errorCode = errorCode;
89         this.errorSubCode = errorSubCode;
90     }
91
92     /**
93      * Reader reads BGP Notification Message from the channel buffer.
94      */
95     static class Reader implements BGPMessageReader<BGPNotificationMsg> {
96         @Override
97         public BGPNotificationMsg readFrom(ChannelBuffer cb, BGPHeader bgpHeader) throws BGPParseException {
98             byte errorCode;
99             byte errorSubCode;
100             if (cb.readableBytes() < PACKET_MINIMUM_LENGTH) {
101                 throw new BGPParseException("Not enough readable bytes");
102             }
103             errorCode = cb.readByte();
104             errorSubCode = cb.readByte();
105             //Message Length = 21 + Data Length
106             int dataLength = bgpHeader.getLength() - TOTAL_MESSAGE_MIN_LENGTH;
107             byte[] data = new byte[dataLength];
108             cb.readBytes(data, 0, dataLength);
109             return new BGPNotificationMsgVer4(bgpHeader, errorCode, errorSubCode, data);
110         }
111     }
112
113     /**
114      * Builder class for BGP notification message.
115      */
116     static class Builder implements BGPNotificationMsg.Builder {
117         private byte errorCode;
118         private byte errorSubCode;
119         private byte[] data;
120         private BGPHeader bgpHeader;
121         private boolean isErrorCodeSet = false;
122         private boolean isErrorSubCodeSet = false;
123         private boolean isBGPHeaderSet = false;
124
125         @Override
126         public BGPNotificationMsg build() throws BGPParseException {
127             BGPHeader bgpHeader = this.isBGPHeaderSet ? this.bgpHeader : DEFAULT_MESSAGE_HEADER;
128             if (!this.isErrorCodeSet) {
129                 throw new BGPParseException("Error code must be present");
130             }
131
132             byte errorSubCode = this.isErrorSubCodeSet ? this.errorSubCode : DEFAULT_ERRORSUBCODE;
133             return new BGPNotificationMsgVer4(bgpHeader, this.errorCode, errorSubCode, this.data);
134         }
135
136         @Override
137         public Builder setErrorCode(byte errorCode) {
138             this.errorCode = errorCode;
139             this.isErrorCodeSet = true;
140             return this;
141         }
142
143         @Override
144         public Builder setErrorSubCode(byte errorSubCode) {
145             this.errorSubCode = errorSubCode;
146             this.isErrorSubCodeSet = true;
147             return this;
148         }
149
150         @Override
151         public Builder setData(byte[] data) {
152             this.data = data;
153             return this;
154         }
155
156         @Override
157         public Builder setNotificationMsgHeader(BGPHeader header) {
158             this.bgpHeader = header;
159             this.isBGPHeaderSet = true;
160             return this;
161         }
162
163         @Override
164         public Builder setHeader(BGPHeader bgpMsgHeader) {
165             this.bgpHeader = bgpMsgHeader;
166             return this;
167         }
168     }
169
170     @Override
171     public BGPVersion getVersion() {
172         return BGPVersion.BGP_4;
173     }
174
175     @Override
176     public BGPType getType() {
177         return BGPType.NOTIFICATION;
178     }
179
180     @Override
181     public void writeTo(ChannelBuffer cb) throws BGPParseException {
182         WRITER.write(cb, this);
183     }
184
185     static final Writer WRITER = new Writer();
186
187     /**
188      * Writer writes BGP notification message to channel buffer.
189      */
190     static class Writer implements BGPMessageWriter<BGPNotificationMsgVer4> {
191         @Override
192         public void write(ChannelBuffer cb, BGPNotificationMsgVer4 message) throws BGPParseException {
193             int msgStartIndex = cb.writerIndex();
194             int headerLenIndex = message.bgpHeader.write(cb);
195             if (headerLenIndex <= 0) {
196                 throw new BGPParseException(BGPErrorType.MESSAGE_HEADER_ERROR, (byte) 0, null);
197             }
198             cb.writeByte(message.errorCode);
199             cb.writeByte(message.errorSubCode);
200             cb.writeBytes(message.data);
201
202             //Update message length field in notification message
203             int length = cb.writerIndex() - msgStartIndex;
204             cb.setShort(headerLenIndex, (short) length);
205             message.bgpHeader.setLength((short) length);
206         }
207     }
208
209     @Override
210     public byte getErrorCode() {
211         return this.errorCode;
212     }
213
214     /**
215      * Sets errorcode with specified errorcode.
216      *
217      * @param errorCode field
218      */
219     public void setErrorCode(byte errorCode) {
220         this.errorCode = errorCode;
221     }
222
223     @Override
224     public byte getErrorSubCode() {
225         return this.errorSubCode;
226     }
227
228     /**
229      * Sets error subcode with specified errorSubCode.
230      *
231      * @param errorSubCode field
232      */
233     public void setErrorSubCode(byte errorSubCode) {
234         this.errorSubCode = errorSubCode;
235     }
236
237     @Override
238     public byte[] getData() {
239         return this.data;
240     }
241
242     /**
243      * Sets error data with specified data.
244      *
245      * @param data field
246      */
247     public void setData(byte[] data) {
248         this.data = data;
249     }
250
251     @Override
252     public BGPHeader getHeader() {
253         return this.bgpHeader;
254     }
255
256     @Override
257     public String toString() {
258         return MoreObjects.toStringHelper(getClass())
259                 .omitNullValues()
260                 .add("bgpHeader", bgpHeader)
261                 .add("data", data)
262                 .add("errorCode", errorCode)
263                 .add("errorSubCode", errorSubCode)
264                 .toString();
265     }
266 }