4d6af5947a9ff74959d990dd842e8b8c97c13028
[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 java.util.LinkedList;
19 import java.util.List;
20
21 import org.jboss.netty.buffer.ChannelBuffer;
22 import org.onlab.packet.IpPrefix;
23 import org.onosproject.bgpio.exceptions.BgpParseException;
24 import org.onosproject.bgpio.protocol.BgpMessageReader;
25 import org.onosproject.bgpio.protocol.BgpType;
26 import org.onosproject.bgpio.protocol.BgpUpdateMsg;
27 import org.onosproject.bgpio.types.BgpErrorType;
28 import org.onosproject.bgpio.types.BgpHeader;
29 import org.onosproject.bgpio.util.Validation;
30 import org.onosproject.bgpio.protocol.BgpVersion;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import com.google.common.base.MoreObjects;
35
36 /**
37  * BGP Update Message: UPDATE messages are used to transfer routing information
38  * between BGP peers. The information in the UPDATE message is used by core to
39  * construct a graph
40  */
41 public class BgpUpdateMsgVer4 implements BgpUpdateMsg {
42
43     /*      0                   1                   2                   3
44     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
45     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46     |                                                               |
47     +                                                               +
48     |                                                               |
49     +                                                               +
50     |                           Marker                              |
51     +                                                               +
52     |                                                               |
53     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
54     |          Length               |      Type     |
55     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56     |   Withdrawn Routes Length (2 octets)                |
57     +-----------------------------------------------------+
58     |   Withdrawn Routes (variable)                       |
59     +-----------------------------------------------------+
60     |   Total Path Attribute Length (2 octets)            |
61     +-----------------------------------------------------+
62     |   Path Attributes (variable)                        |
63     +-----------------------------------------------------+
64     |   Network Layer Reachability Information (variable) |
65     +-----------------------------------------------------+
66     REFERENCE : RFC 4271
67     */
68
69     protected static final Logger log = LoggerFactory
70             .getLogger(BgpUpdateMsgVer4.class);
71
72     public static final byte PACKET_VERSION = 4;
73     //Withdrawn Routes Length(2) + Total Path Attribute Length(2)
74     public static final int PACKET_MINIMUM_LENGTH = 4;
75     public static final int BYTE_IN_BITS = 8;
76     public static final int MIN_LEN_AFTER_WITHDRW_ROUTES = 2;
77     public static final int MINIMUM_COMMON_HEADER_LENGTH = 19;
78     public static final BgpType MSG_TYPE = BgpType.UPDATE;
79     public static final BgpUpdateMsgVer4.Reader READER = new Reader();
80
81     private List<IpPrefix> withdrawnRoutes;
82     private BgpPathAttributes bgpPathAttributes;
83     private BgpHeader bgpHeader;
84     private List<IpPrefix> nlri;
85
86     /**
87      * Constructor to initialize parameters for BGP Update message.
88      *
89      * @param bgpHeader in Update message
90      * @param withdrawnRoutes withdrawn routes
91      * @param bgpPathAttributes BGP Path attributes
92      * @param nlri Network Layer Reachability Information
93      */
94     public BgpUpdateMsgVer4(BgpHeader bgpHeader, List<IpPrefix> withdrawnRoutes,
95                      BgpPathAttributes bgpPathAttributes, List<IpPrefix> nlri) {
96         this.bgpHeader = bgpHeader;
97         this.withdrawnRoutes = withdrawnRoutes;
98         this.bgpPathAttributes = bgpPathAttributes;
99         this.nlri = nlri;
100     }
101
102     /**
103      * Reader reads BGP Update Message from the channel buffer.
104      */
105     static class Reader implements BgpMessageReader<BgpUpdateMsg> {
106
107         @Override
108         public BgpUpdateMsg readFrom(ChannelBuffer cb, BgpHeader bgpHeader)
109                 throws BgpParseException {
110
111             if (cb.readableBytes() != (bgpHeader.getLength() - MINIMUM_COMMON_HEADER_LENGTH)) {
112                 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
113                         BgpErrorType.BAD_MESSAGE_LENGTH, bgpHeader.getLength());
114             }
115
116             LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
117             LinkedList<IpPrefix> nlri = new LinkedList<>();
118             BgpPathAttributes bgpPathAttributes = new BgpPathAttributes();
119             // Reading Withdrawn Routes Length
120             Short withDrwLen = cb.readShort();
121
122             if (cb.readableBytes() < withDrwLen) {
123                 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
124                         BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
125                         cb.readableBytes());
126             }
127             ChannelBuffer tempCb = cb.readBytes(withDrwLen);
128             if (withDrwLen != 0) {
129                 // Parsing WithdrawnRoutes
130                 withDrwRoutes = parseWithdrawnRoutes(tempCb);
131             }
132             if (cb.readableBytes() < MIN_LEN_AFTER_WITHDRW_ROUTES) {
133                 log.debug("Bgp Path Attribute len field not present");
134                 throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR,
135                         BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null);
136             }
137
138             // Reading Total Path Attribute Length
139             short totPathAttrLen = cb.readShort();
140             int len = withDrwLen + totPathAttrLen + PACKET_MINIMUM_LENGTH;
141             if (len > bgpHeader.getLength()) {
142                 throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR,
143                         BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null);
144             }
145             if (totPathAttrLen != 0) {
146                 // Parsing BGPPathAttributes
147                 if (cb.readableBytes() < totPathAttrLen) {
148                     Validation
149                             .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
150                                          BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
151                                          cb.readableBytes());
152                 }
153                 tempCb = cb.readBytes(totPathAttrLen);
154                 bgpPathAttributes = BgpPathAttributes.read(tempCb);
155             }
156             if (cb.readableBytes() > 0) {
157                 // Parsing NLRI
158                 nlri = parseNlri(cb);
159             }
160             return new BgpUpdateMsgVer4(bgpHeader, withDrwRoutes,
161                     bgpPathAttributes, nlri);
162         }
163     }
164
165     /**
166      * Parses NLRI from channel buffer.
167      *
168      * @param cb channelBuffer
169      * @return list of IP Prefix
170      * @throws BgpParseException while parsing NLRI
171      */
172     public static LinkedList<IpPrefix> parseNlri(ChannelBuffer cb)
173             throws BgpParseException {
174         LinkedList<IpPrefix> nlri = new LinkedList<>();
175         while (cb.readableBytes() > 0) {
176             int length = cb.readByte();
177             IpPrefix ipPrefix;
178             if (length == 0) {
179                 byte[] prefix = new byte[] {0};
180                 ipPrefix = Validation.bytesToPrefix(prefix, length);
181                 nlri.add(ipPrefix);
182             } else {
183                 int len = length / BYTE_IN_BITS;
184                 int reminder = length % BYTE_IN_BITS;
185                 if (reminder > 0) {
186                     len = len + 1;
187                 }
188                 if (cb.readableBytes() < len) {
189                     Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
190                             BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
191                             cb.readableBytes());
192                 }
193                 byte[] prefix = new byte[len];
194                 cb.readBytes(prefix, 0, len);
195                 ipPrefix = Validation.bytesToPrefix(prefix, length);
196                 nlri.add(ipPrefix);
197             }
198         }
199         return nlri;
200     }
201
202     /**
203      * Parsing withdrawn routes from channel buffer.
204      *
205      * @param cb channelBuffer
206      * @return list of IP prefix
207      * @throws BgpParseException while parsing withdrawn routes
208      */
209     public static LinkedList<IpPrefix> parseWithdrawnRoutes(ChannelBuffer cb)
210             throws BgpParseException {
211         LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
212         while (cb.readableBytes() > 0) {
213             int length = cb.readByte();
214             IpPrefix ipPrefix;
215             if (length == 0) {
216                 byte[] prefix = new byte[] {0};
217                 ipPrefix = Validation.bytesToPrefix(prefix, length);
218                 withDrwRoutes.add(ipPrefix);
219             } else {
220                 int len = length / BYTE_IN_BITS;
221                 int reminder = length % BYTE_IN_BITS;
222                 if (reminder > 0) {
223                     len = len + 1;
224                 }
225                 if (cb.readableBytes() < len) {
226                     Validation
227                             .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
228                                          BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
229                                          cb.readableBytes());
230                 }
231                 byte[] prefix = new byte[len];
232                 cb.readBytes(prefix, 0, len);
233                 ipPrefix = Validation.bytesToPrefix(prefix, length);
234                 withDrwRoutes.add(ipPrefix);
235             }
236         }
237         return withDrwRoutes;
238     }
239
240     @Override
241     public BgpVersion getVersion() {
242         return BgpVersion.BGP_4;
243     }
244
245     @Override
246     public BgpType getType() {
247         return BgpType.UPDATE;
248     }
249
250     @Override
251     public void writeTo(ChannelBuffer channelBuffer) throws BgpParseException {
252         //Not to be implemented as of now
253     }
254
255     @Override
256     public BgpPathAttributes bgpPathAttributes() {
257         return this.bgpPathAttributes;
258     }
259
260     @Override
261     public List<IpPrefix> withdrawnRoutes() {
262         return withdrawnRoutes;
263     }
264
265     @Override
266     public List<IpPrefix> nlri() {
267         return nlri;
268     }
269
270     @Override
271     public BgpHeader getHeader() {
272         return this.bgpHeader;
273     }
274
275     @Override
276     public String toString() {
277         return MoreObjects.toStringHelper(getClass())
278                 .omitNullValues()
279                 .add("bgpHeader", bgpHeader)
280                 .add("withDrawnRoutes", withdrawnRoutes)
281                 .add("nlri", nlri)
282                 .add("bgpPathAttributes", bgpPathAttributes)
283                 .toString();
284     }
285 }