blob: b6576a35876d555591f4044cd34a9c71e1546120 [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();
mohamedrahil00f6f262016-11-24 20:20:41 +0530133
Priyanka B425e3c52015-11-13 14:31:15 +0530134 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 }
mohamedrahil00f6f262016-11-24 20:20:41 +0530141 log.debug("Reading withdrawn routes length");
Priyanka B425e3c52015-11-13 14:31:15 +0530142 ChannelBuffer tempCb = cb.readBytes(withDrwLen);
143 if (withDrwLen != 0) {
144 // Parsing WithdrawnRoutes
145 withDrwRoutes = parseWithdrawnRoutes(tempCb);
mohamedrahil00f6f262016-11-24 20:20:41 +0530146 log.debug("Withdrawn routes parsed");
Priyanka B425e3c52015-11-13 14:31:15 +0530147 }
148 if (cb.readableBytes() < MIN_LEN_AFTER_WITHDRW_ROUTES) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530149 log.debug("Bgp path attribute len field not present");
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530150 throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR,
151 BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null);
Priyanka B425e3c52015-11-13 14:31:15 +0530152 }
153
154 // Reading Total Path Attribute Length
155 short totPathAttrLen = cb.readShort();
156 int len = withDrwLen + totPathAttrLen + PACKET_MINIMUM_LENGTH;
157 if (len > bgpHeader.getLength()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530158 throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR,
159 BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null);
Priyanka B425e3c52015-11-13 14:31:15 +0530160 }
mohamedrahil00f6f262016-11-24 20:20:41 +0530161 log.debug("Total path attribute length read");
Priyanka B425e3c52015-11-13 14:31:15 +0530162 if (totPathAttrLen != 0) {
163 // Parsing BGPPathAttributes
164 if (cb.readableBytes() < totPathAttrLen) {
165 Validation
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530166 .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
167 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530168 cb.readableBytes());
169 }
170 tempCb = cb.readBytes(totPathAttrLen);
171 bgpPathAttributes = BgpPathAttributes.read(tempCb);
172 }
173 if (cb.readableBytes() > 0) {
174 // Parsing NLRI
175 nlri = parseNlri(cb);
176 }
177 return new BgpUpdateMsgVer4(bgpHeader, withDrwRoutes,
178 bgpPathAttributes, nlri);
179 }
180 }
181
182 /**
Shashikanth VH44967ec2016-02-04 19:46:16 +0530183 * Builder class for BGP update message.
184 */
185 static class Builder implements BgpUpdateMsg.Builder {
186 BgpHeader bgpMsgHeader = null;
Shashikanth VH44967ec2016-02-04 19:46:16 +0530187 BgpPathAttributes bgpPathAttributes;
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530188 List<IpPrefix> withdrawnRoutes;
189 List<IpPrefix> nlri;
Shashikanth VH44967ec2016-02-04 19:46:16 +0530190
191 @Override
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530192 public BgpUpdateMsg build() {
Shashikanth VH44967ec2016-02-04 19:46:16 +0530193 BgpHeader bgpMsgHeader = DEFAULT_UPDATE_HEADER;
194
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530195 return new BgpUpdateMsgVer4(bgpMsgHeader, withdrawnRoutes, bgpPathAttributes, nlri);
Shashikanth VH44967ec2016-02-04 19:46:16 +0530196 }
197
198 @Override
199 public Builder setHeader(BgpHeader bgpMsgHeader) {
200 this.bgpMsgHeader = bgpMsgHeader;
201 return this;
202 }
203
204 @Override
Shashikanth VH44967ec2016-02-04 19:46:16 +0530205 public Builder setBgpPathAttributes(List<BgpValueType> attributes) {
206 this.bgpPathAttributes = new BgpPathAttributes(attributes);
207 return this;
208 }
209
Shashikanth VH44967ec2016-02-04 19:46:16 +0530210 }
211
212 public static final Writer WRITER = new Writer();
213
214 /**
215 * Writer class for writing BGP update message to channel buffer.
216 */
217 public static class Writer implements BgpMessageWriter<BgpUpdateMsgVer4> {
218
219 @Override
220 public void write(ChannelBuffer cb, BgpUpdateMsgVer4 message) throws BgpParseException {
221
222 int startIndex = cb.writerIndex();
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530223 short afi = 0;
224 byte safi = 0;
Shashikanth VH44967ec2016-02-04 19:46:16 +0530225
226 // write common header and get msg length index
227 int msgLenIndex = message.bgpHeader.write(cb);
228
229 if (msgLenIndex <= 0) {
230 throw new BgpParseException("Unable to write message header.");
231 }
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530232 List<BgpValueType> pathAttr = message.bgpPathAttributes.pathAttributes();
233 if (pathAttr != null) {
234 Iterator<BgpValueType> listIterator = pathAttr.iterator();
Shashikanth VH44967ec2016-02-04 19:46:16 +0530235
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530236 while (listIterator.hasNext()) {
237 BgpValueType attr = listIterator.next();
238 if (attr instanceof MpReachNlri) {
239 MpReachNlri mpReach = (MpReachNlri) attr;
240 afi = mpReach.afi();
241 safi = mpReach.safi();
242 } else if (attr instanceof MpUnReachNlri) {
243 MpUnReachNlri mpUnReach = (MpUnReachNlri) attr;
244 afi = mpUnReach.afi();
245 safi = mpUnReach.safi();
246 }
Shashikanth VHe38c21e2016-05-26 21:37:25 +0530247 }
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530248
Shashikanth VHe38c21e2016-05-26 21:37:25 +0530249 if ((afi == Constants.AFI_FLOWSPEC_VALUE) || (afi == Constants.AFI_VALUE)) {
250 //unfeasible route length
251 cb.writeShort(0);
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530252 }
253
Shashikanth VH44967ec2016-02-04 19:46:16 +0530254 }
255
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530256 if (message.bgpPathAttributes != null) {
257 message.bgpPathAttributes.write(cb);
258 }
Shashikanth VH44967ec2016-02-04 19:46:16 +0530259
260 // write UPDATE Object Length
261 int length = cb.writerIndex() - startIndex;
262 cb.setShort(msgLenIndex, (short) length);
263 message.bgpHeader.setLength((short) length);
264 }
265 }
266
267 /**
Priyanka B425e3c52015-11-13 14:31:15 +0530268 * Parses NLRI from channel buffer.
269 *
270 * @param cb channelBuffer
271 * @return list of IP Prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530272 * @throws BgpParseException while parsing NLRI
Priyanka B425e3c52015-11-13 14:31:15 +0530273 */
274 public static LinkedList<IpPrefix> parseNlri(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530275 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530276 LinkedList<IpPrefix> nlri = new LinkedList<>();
277 while (cb.readableBytes() > 0) {
278 int length = cb.readByte();
279 IpPrefix ipPrefix;
280 if (length == 0) {
281 byte[] prefix = new byte[] {0};
282 ipPrefix = Validation.bytesToPrefix(prefix, length);
283 nlri.add(ipPrefix);
284 } else {
285 int len = length / BYTE_IN_BITS;
286 int reminder = length % BYTE_IN_BITS;
287 if (reminder > 0) {
288 len = len + 1;
289 }
290 if (cb.readableBytes() < len) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530291 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
292 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530293 cb.readableBytes());
294 }
295 byte[] prefix = new byte[len];
296 cb.readBytes(prefix, 0, len);
297 ipPrefix = Validation.bytesToPrefix(prefix, length);
298 nlri.add(ipPrefix);
299 }
300 }
301 return nlri;
302 }
303
304 /**
305 * Parsing withdrawn routes from channel buffer.
306 *
307 * @param cb channelBuffer
308 * @return list of IP prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530309 * @throws BgpParseException while parsing withdrawn routes
Priyanka B425e3c52015-11-13 14:31:15 +0530310 */
311 public static LinkedList<IpPrefix> parseWithdrawnRoutes(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530312 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530313 LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
314 while (cb.readableBytes() > 0) {
315 int length = cb.readByte();
316 IpPrefix ipPrefix;
317 if (length == 0) {
318 byte[] prefix = new byte[] {0};
319 ipPrefix = Validation.bytesToPrefix(prefix, length);
320 withDrwRoutes.add(ipPrefix);
321 } else {
322 int len = length / BYTE_IN_BITS;
323 int reminder = length % BYTE_IN_BITS;
324 if (reminder > 0) {
325 len = len + 1;
326 }
327 if (cb.readableBytes() < len) {
328 Validation
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530329 .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
330 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530331 cb.readableBytes());
332 }
333 byte[] prefix = new byte[len];
334 cb.readBytes(prefix, 0, len);
335 ipPrefix = Validation.bytesToPrefix(prefix, length);
336 withDrwRoutes.add(ipPrefix);
337 }
338 }
339 return withDrwRoutes;
340 }
341
342 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530343 public BgpVersion getVersion() {
344 return BgpVersion.BGP_4;
Priyanka B425e3c52015-11-13 14:31:15 +0530345 }
346
347 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530348 public BgpType getType() {
349 return BgpType.UPDATE;
Priyanka B425e3c52015-11-13 14:31:15 +0530350 }
351
352 @Override
Shashikanth VH44967ec2016-02-04 19:46:16 +0530353 public void writeTo(ChannelBuffer channelBuffer) {
354 try {
355 WRITER.write(channelBuffer, this);
356 } catch (BgpParseException e) {
357 log.debug("[writeTo] Error: " + e.toString());
358 }
Priyanka B425e3c52015-11-13 14:31:15 +0530359 }
360
361 @Override
362 public BgpPathAttributes bgpPathAttributes() {
363 return this.bgpPathAttributes;
364 }
365
366 @Override
367 public List<IpPrefix> withdrawnRoutes() {
368 return withdrawnRoutes;
369 }
370
371 @Override
372 public List<IpPrefix> nlri() {
373 return nlri;
374 }
375
376 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530377 public BgpHeader getHeader() {
Priyanka B425e3c52015-11-13 14:31:15 +0530378 return this.bgpHeader;
379 }
380
381 @Override
382 public String toString() {
383 return MoreObjects.toStringHelper(getClass())
384 .omitNullValues()
385 .add("bgpHeader", bgpHeader)
386 .add("withDrawnRoutes", withdrawnRoutes)
387 .add("nlri", nlri)
388 .add("bgpPathAttributes", bgpPathAttributes)
389 .toString();
390 }
391}