blob: e2bf2183f4aa78efce52cf726c9c3138e4314b58 [file] [log] [blame]
Priyanka B425e3c52015-11-13 14:31:15 +05301/*
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 */
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 }
244
245 if ((afi == Constants.AFI_FLOWSPEC_VALUE) && ((safi == Constants.SAFI_FLOWSPEC_VALUE)
246 || (safi == Constants.VPN_SAFI_FLOWSPEC_VALUE))) {
247 //unfeasible route length
248 cb.writeShort(0);
249 }
250 }
251
Shashikanth VH44967ec2016-02-04 19:46:16 +0530252 }
253
Shashikanth VH9bd644a2016-02-11 17:23:49 +0530254 if (message.bgpPathAttributes != null) {
255 message.bgpPathAttributes.write(cb);
256 }
Shashikanth VH44967ec2016-02-04 19:46:16 +0530257
258 // write UPDATE Object Length
259 int length = cb.writerIndex() - startIndex;
260 cb.setShort(msgLenIndex, (short) length);
261 message.bgpHeader.setLength((short) length);
262 }
263 }
264
265 /**
Priyanka B425e3c52015-11-13 14:31:15 +0530266 * Parses NLRI from channel buffer.
267 *
268 * @param cb channelBuffer
269 * @return list of IP Prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530270 * @throws BgpParseException while parsing NLRI
Priyanka B425e3c52015-11-13 14:31:15 +0530271 */
272 public static LinkedList<IpPrefix> parseNlri(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530273 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530274 LinkedList<IpPrefix> nlri = new LinkedList<>();
275 while (cb.readableBytes() > 0) {
276 int length = cb.readByte();
277 IpPrefix ipPrefix;
278 if (length == 0) {
279 byte[] prefix = new byte[] {0};
280 ipPrefix = Validation.bytesToPrefix(prefix, length);
281 nlri.add(ipPrefix);
282 } else {
283 int len = length / BYTE_IN_BITS;
284 int reminder = length % BYTE_IN_BITS;
285 if (reminder > 0) {
286 len = len + 1;
287 }
288 if (cb.readableBytes() < len) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530289 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
290 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530291 cb.readableBytes());
292 }
293 byte[] prefix = new byte[len];
294 cb.readBytes(prefix, 0, len);
295 ipPrefix = Validation.bytesToPrefix(prefix, length);
296 nlri.add(ipPrefix);
297 }
298 }
299 return nlri;
300 }
301
302 /**
303 * Parsing withdrawn routes from channel buffer.
304 *
305 * @param cb channelBuffer
306 * @return list of IP prefix
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530307 * @throws BgpParseException while parsing withdrawn routes
Priyanka B425e3c52015-11-13 14:31:15 +0530308 */
309 public static LinkedList<IpPrefix> parseWithdrawnRoutes(ChannelBuffer cb)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530310 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530311 LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
312 while (cb.readableBytes() > 0) {
313 int length = cb.readByte();
314 IpPrefix ipPrefix;
315 if (length == 0) {
316 byte[] prefix = new byte[] {0};
317 ipPrefix = Validation.bytesToPrefix(prefix, length);
318 withDrwRoutes.add(ipPrefix);
319 } else {
320 int len = length / BYTE_IN_BITS;
321 int reminder = length % BYTE_IN_BITS;
322 if (reminder > 0) {
323 len = len + 1;
324 }
325 if (cb.readableBytes() < len) {
326 Validation
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530327 .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
328 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530329 cb.readableBytes());
330 }
331 byte[] prefix = new byte[len];
332 cb.readBytes(prefix, 0, len);
333 ipPrefix = Validation.bytesToPrefix(prefix, length);
334 withDrwRoutes.add(ipPrefix);
335 }
336 }
337 return withDrwRoutes;
338 }
339
340 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530341 public BgpVersion getVersion() {
342 return BgpVersion.BGP_4;
Priyanka B425e3c52015-11-13 14:31:15 +0530343 }
344
345 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530346 public BgpType getType() {
347 return BgpType.UPDATE;
Priyanka B425e3c52015-11-13 14:31:15 +0530348 }
349
350 @Override
Shashikanth VH44967ec2016-02-04 19:46:16 +0530351 public void writeTo(ChannelBuffer channelBuffer) {
352 try {
353 WRITER.write(channelBuffer, this);
354 } catch (BgpParseException e) {
355 log.debug("[writeTo] Error: " + e.toString());
356 }
Priyanka B425e3c52015-11-13 14:31:15 +0530357 }
358
359 @Override
360 public BgpPathAttributes bgpPathAttributes() {
361 return this.bgpPathAttributes;
362 }
363
364 @Override
365 public List<IpPrefix> withdrawnRoutes() {
366 return withdrawnRoutes;
367 }
368
369 @Override
370 public List<IpPrefix> nlri() {
371 return nlri;
372 }
373
374 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530375 public BgpHeader getHeader() {
Priyanka B425e3c52015-11-13 14:31:15 +0530376 return this.bgpHeader;
377 }
378
379 @Override
380 public String toString() {
381 return MoreObjects.toStringHelper(getClass())
382 .omitNullValues()
383 .add("bgpHeader", bgpHeader)
384 .add("withDrawnRoutes", withdrawnRoutes)
385 .add("nlri", nlri)
386 .add("bgpPathAttributes", bgpPathAttributes)
387 .toString();
388 }
389}