blob: 7062a7de3f0e0888f0e89a077441d936e6670a82 [file] [log] [blame]
Priyanka B425e3c52015-11-13 14:31:15 +05301/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Priyanka B425e3c52015-11-13 14:31:15 +05303 *
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 */
16package org.onosproject.bgpio.protocol.ver4;
17
Shashikanth VH9bd644a2016-02-11 17:23:49 +053018import java.util.Iterator;
Priyanka B425e3c52015-11-13 14:31:15 +053019import java.util.LinkedList;
20import java.util.List;
21
22import org.jboss.netty.buffer.ChannelBuffer;
23import org.onlab.packet.IpPrefix;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053024import org.onosproject.bgpio.exceptions.BgpParseException;
25import org.onosproject.bgpio.protocol.BgpMessageReader;
Shashikanth VH44967ec2016-02-04 19:46:16 +053026import org.onosproject.bgpio.protocol.BgpMessageWriter;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053027import org.onosproject.bgpio.protocol.BgpType;
Priyanka B425e3c52015-11-13 14:31:15 +053028import org.onosproject.bgpio.protocol.BgpUpdateMsg;
Shashikanth VH44967ec2016-02-04 19:46:16 +053029import org.onosproject.bgpio.protocol.BgpVersion;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053030import org.onosproject.bgpio.types.BgpErrorType;
31import org.onosproject.bgpio.types.BgpHeader;
Shashikanth VH9bd644a2016-02-11 17:23:49 +053032import org.onosproject.bgpio.types.MpReachNlri;
33import org.onosproject.bgpio.types.MpUnReachNlri;
Shashikanth VH44967ec2016-02-04 19:46:16 +053034import org.onosproject.bgpio.util.Constants;
Priyanka B425e3c52015-11-13 14:31:15 +053035import org.onosproject.bgpio.util.Validation;
Shashikanth VH44967ec2016-02-04 19:46:16 +053036
37import org.onosproject.bgpio.types.BgpValueType;
Priyanka B425e3c52015-11-13 14:31:15 +053038import org.slf4j.Logger;
39import org.slf4j.LoggerFactory;
40
41import com.google.common.base.MoreObjects;
42
43/**
44 * BGP Update Message: UPDATE messages are used to transfer routing information
45 * between BGP peers. The information in the UPDATE message is used by core to
46 * construct a graph
47 */
48public class BgpUpdateMsgVer4 implements BgpUpdateMsg {
49
50 /* 0 1 2 3
51 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
52 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53 | |
54 + +
55 | |
56 + +
57 | Marker |
58 + +
59 | |
60 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 | Length | Type |
62 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
63 | Withdrawn Routes Length (2 octets) |
64 +-----------------------------------------------------+
65 | Withdrawn Routes (variable) |
66 +-----------------------------------------------------+
67 | Total Path Attribute Length (2 octets) |
68 +-----------------------------------------------------+
69 | Path Attributes (variable) |
70 +-----------------------------------------------------+
71 | Network Layer Reachability Information (variable) |
72 +-----------------------------------------------------+
73 REFERENCE : RFC 4271
74 */
75
76 protected static final Logger log = LoggerFactory
77 .getLogger(BgpUpdateMsgVer4.class);
78
79 public static final byte PACKET_VERSION = 4;
80 //Withdrawn Routes Length(2) + Total Path Attribute Length(2)
81 public static final int PACKET_MINIMUM_LENGTH = 4;
Shashikanth VH44967ec2016-02-04 19:46:16 +053082 public static final int MARKER_LENGTH = 16;
Priyanka B425e3c52015-11-13 14:31:15 +053083 public static final int BYTE_IN_BITS = 8;
84 public static final int MIN_LEN_AFTER_WITHDRW_ROUTES = 2;
85 public static final int MINIMUM_COMMON_HEADER_LENGTH = 19;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053086 public static final BgpType MSG_TYPE = BgpType.UPDATE;
Shashikanth VH44967ec2016-02-04 19:46:16 +053087 public static byte[] marker = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
88 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
89 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
90 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
91 public static final BgpHeader DEFAULT_UPDATE_HEADER = new BgpHeader(marker,
92 (short) PACKET_MINIMUM_LENGTH, (byte) 0X02);
Priyanka B425e3c52015-11-13 14:31:15 +053093 public static final BgpUpdateMsgVer4.Reader READER = new Reader();
94
95 private List<IpPrefix> withdrawnRoutes;
96 private BgpPathAttributes bgpPathAttributes;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053097 private BgpHeader bgpHeader;
Priyanka B425e3c52015-11-13 14:31:15 +053098 private List<IpPrefix> nlri;
99
100 /**
101 * Constructor to initialize parameters for BGP Update message.
102 *
103 * @param bgpHeader in Update message
104 * @param withdrawnRoutes withdrawn routes
105 * @param bgpPathAttributes BGP Path attributes
106 * @param nlri Network Layer Reachability Information
107 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530108 public BgpUpdateMsgVer4(BgpHeader bgpHeader, List<IpPrefix> withdrawnRoutes,
Priyanka B425e3c52015-11-13 14:31:15 +0530109 BgpPathAttributes bgpPathAttributes, List<IpPrefix> nlri) {
110 this.bgpHeader = bgpHeader;
111 this.withdrawnRoutes = withdrawnRoutes;
112 this.bgpPathAttributes = bgpPathAttributes;
113 this.nlri = nlri;
114 }
115
116 /**
117 * Reader reads BGP Update Message from the channel buffer.
118 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530119 static class Reader implements BgpMessageReader<BgpUpdateMsg> {
Priyanka B425e3c52015-11-13 14:31:15 +0530120
121 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530122 public BgpUpdateMsg readFrom(ChannelBuffer cb, BgpHeader bgpHeader)
123 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530124
125 if (cb.readableBytes() != (bgpHeader.getLength() - MINIMUM_COMMON_HEADER_LENGTH)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530126 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
127 BgpErrorType.BAD_MESSAGE_LENGTH, bgpHeader.getLength());
Priyanka B425e3c52015-11-13 14:31:15 +0530128 }
129
130 LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
131 LinkedList<IpPrefix> nlri = new LinkedList<>();
132 BgpPathAttributes bgpPathAttributes = new BgpPathAttributes();
133 // Reading Withdrawn Routes Length
134 Short withDrwLen = cb.readShort();
135
136 if (cb.readableBytes() < withDrwLen) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530137 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
138 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530139 cb.readableBytes());
140 }
141 ChannelBuffer tempCb = cb.readBytes(withDrwLen);
142 if (withDrwLen != 0) {
143 // Parsing WithdrawnRoutes
144 withDrwRoutes = parseWithdrawnRoutes(tempCb);
145 }
146 if (cb.readableBytes() < MIN_LEN_AFTER_WITHDRW_ROUTES) {
147 log.debug("Bgp Path Attribute len field not present");
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530148 throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR,
149 BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null);
Priyanka B425e3c52015-11-13 14:31:15 +0530150 }
151
152 // Reading Total Path Attribute Length
153 short totPathAttrLen = cb.readShort();
154 int len = withDrwLen + totPathAttrLen + PACKET_MINIMUM_LENGTH;
155 if (len > bgpHeader.getLength()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530156 throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR,
157 BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null);
Priyanka B425e3c52015-11-13 14:31:15 +0530158 }
159 if (totPathAttrLen != 0) {
160 // Parsing BGPPathAttributes
161 if (cb.readableBytes() < totPathAttrLen) {
162 Validation
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530163 .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
164 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530165 cb.readableBytes());
166 }
167 tempCb = cb.readBytes(totPathAttrLen);
168 bgpPathAttributes = BgpPathAttributes.read(tempCb);
169 }
170 if (cb.readableBytes() > 0) {
171 // Parsing NLRI
172 nlri = parseNlri(cb);
173 }
174 return new BgpUpdateMsgVer4(bgpHeader, withDrwRoutes,
175 bgpPathAttributes, nlri);
176 }
177 }
178
179 /**
Shashikanth VH44967ec2016-02-04 19:46:16 +0530180 * Builder class for BGP update message.
181 */
182 static class Builder implements BgpUpdateMsg.Builder {
183 BgpHeader bgpMsgHeader = null;
Shashikanth VH44967ec2016-02-04 19:46:16 +0530184 BgpPathAttributes bgpPathAttributes;
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530185 List<IpPrefix> withdrawnRoutes;
186 List<IpPrefix> nlri;
Shashikanth VH44967ec2016-02-04 19:46:16 +0530187
188 @Override
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530189 public BgpUpdateMsg build() {
Shashikanth VH44967ec2016-02-04 19:46:16 +0530190 BgpHeader bgpMsgHeader = DEFAULT_UPDATE_HEADER;
191
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530192 return new BgpUpdateMsgVer4(bgpMsgHeader, withdrawnRoutes, bgpPathAttributes, nlri);
Shashikanth VH44967ec2016-02-04 19:46:16 +0530193 }
194
195 @Override
196 public Builder setHeader(BgpHeader bgpMsgHeader) {
197 this.bgpMsgHeader = bgpMsgHeader;
198 return this;
199 }
200
201 @Override
Shashikanth VH44967ec2016-02-04 19:46:16 +0530202 public Builder setBgpPathAttributes(List<BgpValueType> attributes) {
203 this.bgpPathAttributes = new BgpPathAttributes(attributes);
204 return this;
205 }
206
Shashikanth VH44967ec2016-02-04 19:46:16 +0530207 }
208
209 public static final Writer WRITER = new Writer();
210
211 /**
212 * Writer class for writing BGP update message to channel buffer.
213 */
214 public static class Writer implements BgpMessageWriter<BgpUpdateMsgVer4> {
215
216 @Override
217 public void write(ChannelBuffer cb, BgpUpdateMsgVer4 message) throws BgpParseException {
218
219 int startIndex = cb.writerIndex();
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530220 short afi = 0;
221 byte safi = 0;
Shashikanth VH44967ec2016-02-04 19:46:16 +0530222
223 // write common header and get msg length index
224 int msgLenIndex = message.bgpHeader.write(cb);
225
226 if (msgLenIndex <= 0) {
227 throw new BgpParseException("Unable to write message header.");
228 }
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530229 List<BgpValueType> pathAttr = message.bgpPathAttributes.pathAttributes();
230 if (pathAttr != null) {
231 Iterator<BgpValueType> listIterator = pathAttr.iterator();
Shashikanth VH44967ec2016-02-04 19:46:16 +0530232
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530233 while (listIterator.hasNext()) {
234 BgpValueType attr = listIterator.next();
235 if (attr instanceof MpReachNlri) {
236 MpReachNlri mpReach = (MpReachNlri) attr;
237 afi = mpReach.afi();
238 safi = mpReach.safi();
239 } else if (attr instanceof MpUnReachNlri) {
240 MpUnReachNlri mpUnReach = (MpUnReachNlri) attr;
241 afi = mpUnReach.afi();
242 safi = mpUnReach.safi();
243 }
Shashikanth VHe38c21e2016-05-26 21:37:25 +0530244 }
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530245
Shashikanth VHe38c21e2016-05-26 21:37:25 +0530246 if ((afi == Constants.AFI_FLOWSPEC_VALUE) || (afi == Constants.AFI_VALUE)) {
247 //unfeasible route length
248 cb.writeShort(0);
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530249 }
250
Shashikanth VH44967ec2016-02-04 19:46:16 +0530251 }
252
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530253 if (message.bgpPathAttributes != null) {
254 message.bgpPathAttributes.write(cb);
255 }
Shashikanth VH44967ec2016-02-04 19:46:16 +0530256
257 // write UPDATE Object Length
258 int length = cb.writerIndex() - startIndex;
259 cb.setShort(msgLenIndex, (short) length);
260 message.bgpHeader.setLength((short) length);
261 }
262 }
263
264 /**
Priyanka B425e3c52015-11-13 14:31:15 +0530265 * Parses NLRI from channel buffer.
266 *
267 * @param cb channelBuffer
268 * @return list of IP Prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530269 * @throws BgpParseException while parsing NLRI
Priyanka B425e3c52015-11-13 14:31:15 +0530270 */
271 public static LinkedList<IpPrefix> parseNlri(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530272 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530273 LinkedList<IpPrefix> nlri = new LinkedList<>();
274 while (cb.readableBytes() > 0) {
275 int length = cb.readByte();
276 IpPrefix ipPrefix;
277 if (length == 0) {
278 byte[] prefix = new byte[] {0};
279 ipPrefix = Validation.bytesToPrefix(prefix, length);
280 nlri.add(ipPrefix);
281 } else {
282 int len = length / BYTE_IN_BITS;
283 int reminder = length % BYTE_IN_BITS;
284 if (reminder > 0) {
285 len = len + 1;
286 }
287 if (cb.readableBytes() < len) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530288 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
289 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530290 cb.readableBytes());
291 }
292 byte[] prefix = new byte[len];
293 cb.readBytes(prefix, 0, len);
294 ipPrefix = Validation.bytesToPrefix(prefix, length);
295 nlri.add(ipPrefix);
296 }
297 }
298 return nlri;
299 }
300
301 /**
302 * Parsing withdrawn routes from channel buffer.
303 *
304 * @param cb channelBuffer
305 * @return list of IP prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530306 * @throws BgpParseException while parsing withdrawn routes
Priyanka B425e3c52015-11-13 14:31:15 +0530307 */
308 public static LinkedList<IpPrefix> parseWithdrawnRoutes(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530309 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530310 LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
311 while (cb.readableBytes() > 0) {
312 int length = cb.readByte();
313 IpPrefix ipPrefix;
314 if (length == 0) {
315 byte[] prefix = new byte[] {0};
316 ipPrefix = Validation.bytesToPrefix(prefix, length);
317 withDrwRoutes.add(ipPrefix);
318 } else {
319 int len = length / BYTE_IN_BITS;
320 int reminder = length % BYTE_IN_BITS;
321 if (reminder > 0) {
322 len = len + 1;
323 }
324 if (cb.readableBytes() < len) {
325 Validation
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530326 .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
327 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530328 cb.readableBytes());
329 }
330 byte[] prefix = new byte[len];
331 cb.readBytes(prefix, 0, len);
332 ipPrefix = Validation.bytesToPrefix(prefix, length);
333 withDrwRoutes.add(ipPrefix);
334 }
335 }
336 return withDrwRoutes;
337 }
338
339 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530340 public BgpVersion getVersion() {
341 return BgpVersion.BGP_4;
Priyanka B425e3c52015-11-13 14:31:15 +0530342 }
343
344 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530345 public BgpType getType() {
346 return BgpType.UPDATE;
Priyanka B425e3c52015-11-13 14:31:15 +0530347 }
348
349 @Override
Shashikanth VH44967ec2016-02-04 19:46:16 +0530350 public void writeTo(ChannelBuffer channelBuffer) {
351 try {
352 WRITER.write(channelBuffer, this);
353 } catch (BgpParseException e) {
354 log.debug("[writeTo] Error: " + e.toString());
355 }
Priyanka B425e3c52015-11-13 14:31:15 +0530356 }
357
358 @Override
359 public BgpPathAttributes bgpPathAttributes() {
360 return this.bgpPathAttributes;
361 }
362
363 @Override
364 public List<IpPrefix> withdrawnRoutes() {
365 return withdrawnRoutes;
366 }
367
368 @Override
369 public List<IpPrefix> nlri() {
370 return nlri;
371 }
372
373 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530374 public BgpHeader getHeader() {
Priyanka B425e3c52015-11-13 14:31:15 +0530375 return this.bgpHeader;
376 }
377
378 @Override
379 public String toString() {
380 return MoreObjects.toStringHelper(getClass())
381 .omitNullValues()
382 .add("bgpHeader", bgpHeader)
383 .add("withDrawnRoutes", withdrawnRoutes)
384 .add("nlri", nlri)
385 .add("bgpPathAttributes", bgpPathAttributes)
386 .toString();
387 }
388}