blob: d6ce49a43565a7ae8b65eccc9e3e695be89ec965 [file] [log] [blame]
Priyanka B425e3c52015-11-13 14:31:15 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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
Ray Milkey9c9cde42018-01-12 14:22:06 -080076 private static final Logger log = LoggerFactory
Priyanka B425e3c52015-11-13 14:31:15 +053077 .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;
Ray Milkeye4afdb52017-04-05 09:42:04 -070087 private static byte[] marker = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
Shashikanth VH44967ec2016-02-04 19:46:16 +053088 (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
Mohammad Shahid30fedc52017-08-09 11:49:40 +0530249 if ((afi == Constants.AFI_FLOWSPEC_VALUE)
250 || (afi == Constants.AFI_VALUE)) {
Shashikanth VHe38c21e2016-05-26 21:37:25 +0530251 //unfeasible route length
252 cb.writeShort(0);
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530253 }
254
Mohammad Shahid30fedc52017-08-09 11:49:40 +0530255 if ((afi == Constants.AFI_EVPN_VALUE)
256 && (safi == Constants.SAFI_EVPN_VALUE)) {
257 cb.writeShort(0);
258 }
259
Shashikanth VH44967ec2016-02-04 19:46:16 +0530260 }
261
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530262 if (message.bgpPathAttributes != null) {
263 message.bgpPathAttributes.write(cb);
264 }
Shashikanth VH44967ec2016-02-04 19:46:16 +0530265
266 // write UPDATE Object Length
267 int length = cb.writerIndex() - startIndex;
268 cb.setShort(msgLenIndex, (short) length);
269 message.bgpHeader.setLength((short) length);
270 }
271 }
272
273 /**
Priyanka B425e3c52015-11-13 14:31:15 +0530274 * Parses NLRI from channel buffer.
275 *
276 * @param cb channelBuffer
277 * @return list of IP Prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530278 * @throws BgpParseException while parsing NLRI
Priyanka B425e3c52015-11-13 14:31:15 +0530279 */
280 public static LinkedList<IpPrefix> parseNlri(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530281 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530282 LinkedList<IpPrefix> nlri = new LinkedList<>();
283 while (cb.readableBytes() > 0) {
284 int length = cb.readByte();
285 IpPrefix ipPrefix;
286 if (length == 0) {
287 byte[] prefix = new byte[] {0};
288 ipPrefix = Validation.bytesToPrefix(prefix, length);
289 nlri.add(ipPrefix);
290 } else {
291 int len = length / BYTE_IN_BITS;
292 int reminder = length % BYTE_IN_BITS;
293 if (reminder > 0) {
294 len = len + 1;
295 }
296 if (cb.readableBytes() < len) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530297 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
298 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530299 cb.readableBytes());
300 }
301 byte[] prefix = new byte[len];
302 cb.readBytes(prefix, 0, len);
303 ipPrefix = Validation.bytesToPrefix(prefix, length);
304 nlri.add(ipPrefix);
305 }
306 }
307 return nlri;
308 }
309
310 /**
311 * Parsing withdrawn routes from channel buffer.
312 *
313 * @param cb channelBuffer
314 * @return list of IP prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530315 * @throws BgpParseException while parsing withdrawn routes
Priyanka B425e3c52015-11-13 14:31:15 +0530316 */
317 public static LinkedList<IpPrefix> parseWithdrawnRoutes(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530318 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530319 LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
320 while (cb.readableBytes() > 0) {
321 int length = cb.readByte();
322 IpPrefix ipPrefix;
323 if (length == 0) {
324 byte[] prefix = new byte[] {0};
325 ipPrefix = Validation.bytesToPrefix(prefix, length);
326 withDrwRoutes.add(ipPrefix);
327 } else {
328 int len = length / BYTE_IN_BITS;
329 int reminder = length % BYTE_IN_BITS;
330 if (reminder > 0) {
331 len = len + 1;
332 }
333 if (cb.readableBytes() < len) {
334 Validation
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530335 .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
336 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530337 cb.readableBytes());
338 }
339 byte[] prefix = new byte[len];
340 cb.readBytes(prefix, 0, len);
341 ipPrefix = Validation.bytesToPrefix(prefix, length);
342 withDrwRoutes.add(ipPrefix);
343 }
344 }
345 return withDrwRoutes;
346 }
347
348 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530349 public BgpVersion getVersion() {
350 return BgpVersion.BGP_4;
Priyanka B425e3c52015-11-13 14:31:15 +0530351 }
352
353 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530354 public BgpType getType() {
355 return BgpType.UPDATE;
Priyanka B425e3c52015-11-13 14:31:15 +0530356 }
357
358 @Override
Shashikanth VH44967ec2016-02-04 19:46:16 +0530359 public void writeTo(ChannelBuffer channelBuffer) {
360 try {
361 WRITER.write(channelBuffer, this);
362 } catch (BgpParseException e) {
363 log.debug("[writeTo] Error: " + e.toString());
364 }
Priyanka B425e3c52015-11-13 14:31:15 +0530365 }
366
367 @Override
368 public BgpPathAttributes bgpPathAttributes() {
369 return this.bgpPathAttributes;
370 }
371
372 @Override
373 public List<IpPrefix> withdrawnRoutes() {
374 return withdrawnRoutes;
375 }
376
377 @Override
378 public List<IpPrefix> nlri() {
379 return nlri;
380 }
381
382 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530383 public BgpHeader getHeader() {
Priyanka B425e3c52015-11-13 14:31:15 +0530384 return this.bgpHeader;
385 }
386
387 @Override
388 public String toString() {
389 return MoreObjects.toStringHelper(getClass())
390 .omitNullValues()
391 .add("bgpHeader", bgpHeader)
392 .add("withDrawnRoutes", withdrawnRoutes)
393 .add("nlri", nlri)
394 .add("bgpPathAttributes", bgpPathAttributes)
395 .toString();
396 }
397}