blob: 7b3264ee73fd9738d3bf6f172ab600e14e2337a1 [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
18import java.util.LinkedList;
19import java.util.List;
20
21import org.jboss.netty.buffer.ChannelBuffer;
22import org.onlab.packet.IpPrefix;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053023import org.onosproject.bgpio.exceptions.BgpParseException;
24import org.onosproject.bgpio.protocol.BgpMessageReader;
Shashikanth VH44967ec2016-02-04 19:46:16 +053025import org.onosproject.bgpio.protocol.BgpMessageWriter;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053026import org.onosproject.bgpio.protocol.BgpType;
Priyanka B425e3c52015-11-13 14:31:15 +053027import org.onosproject.bgpio.protocol.BgpUpdateMsg;
Shashikanth VH44967ec2016-02-04 19:46:16 +053028import org.onosproject.bgpio.protocol.BgpVersion;
29import org.onosproject.bgpio.protocol.flowspec.BgpFlowSpecDetails;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053030import org.onosproject.bgpio.types.BgpErrorType;
31import org.onosproject.bgpio.types.BgpHeader;
Shashikanth VH44967ec2016-02-04 19:46:16 +053032import org.onosproject.bgpio.util.Constants;
Priyanka B425e3c52015-11-13 14:31:15 +053033import org.onosproject.bgpio.util.Validation;
Shashikanth VH44967ec2016-02-04 19:46:16 +053034
35import org.onosproject.bgpio.types.BgpValueType;
Priyanka B425e3c52015-11-13 14:31:15 +053036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
38
39import com.google.common.base.MoreObjects;
40
41/**
42 * BGP Update Message: UPDATE messages are used to transfer routing information
43 * between BGP peers. The information in the UPDATE message is used by core to
44 * construct a graph
45 */
46public class BgpUpdateMsgVer4 implements BgpUpdateMsg {
47
48 /* 0 1 2 3
49 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
50 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 | |
52 + +
53 | |
54 + +
55 | Marker |
56 + +
57 | |
58 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
59 | Length | Type |
60 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
61 | Withdrawn Routes Length (2 octets) |
62 +-----------------------------------------------------+
63 | Withdrawn Routes (variable) |
64 +-----------------------------------------------------+
65 | Total Path Attribute Length (2 octets) |
66 +-----------------------------------------------------+
67 | Path Attributes (variable) |
68 +-----------------------------------------------------+
69 | Network Layer Reachability Information (variable) |
70 +-----------------------------------------------------+
71 REFERENCE : RFC 4271
72 */
73
74 protected static final Logger log = LoggerFactory
75 .getLogger(BgpUpdateMsgVer4.class);
76
77 public static final byte PACKET_VERSION = 4;
78 //Withdrawn Routes Length(2) + Total Path Attribute Length(2)
79 public static final int PACKET_MINIMUM_LENGTH = 4;
Shashikanth VH44967ec2016-02-04 19:46:16 +053080 public static final int MARKER_LENGTH = 16;
Priyanka B425e3c52015-11-13 14:31:15 +053081 public static final int BYTE_IN_BITS = 8;
82 public static final int MIN_LEN_AFTER_WITHDRW_ROUTES = 2;
83 public static final int MINIMUM_COMMON_HEADER_LENGTH = 19;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053084 public static final BgpType MSG_TYPE = BgpType.UPDATE;
Shashikanth VH44967ec2016-02-04 19:46:16 +053085 public static byte[] marker = new byte[] {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
86 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
87 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
88 (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
89 public static final BgpHeader DEFAULT_UPDATE_HEADER = new BgpHeader(marker,
90 (short) PACKET_MINIMUM_LENGTH, (byte) 0X02);
Priyanka B425e3c52015-11-13 14:31:15 +053091 public static final BgpUpdateMsgVer4.Reader READER = new Reader();
92
93 private List<IpPrefix> withdrawnRoutes;
94 private BgpPathAttributes bgpPathAttributes;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053095 private BgpHeader bgpHeader;
Priyanka B425e3c52015-11-13 14:31:15 +053096 private List<IpPrefix> nlri;
Shashikanth VH44967ec2016-02-04 19:46:16 +053097 private BgpFlowSpecDetails bgpFlowSpecComponents;
98 private short afi;
99 private byte safi;
Priyanka B425e3c52015-11-13 14:31:15 +0530100
101 /**
102 * Constructor to initialize parameters for BGP Update message.
103 *
104 * @param bgpHeader in Update message
105 * @param withdrawnRoutes withdrawn routes
106 * @param bgpPathAttributes BGP Path attributes
107 * @param nlri Network Layer Reachability Information
108 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530109 public BgpUpdateMsgVer4(BgpHeader bgpHeader, List<IpPrefix> withdrawnRoutes,
Priyanka B425e3c52015-11-13 14:31:15 +0530110 BgpPathAttributes bgpPathAttributes, List<IpPrefix> nlri) {
111 this.bgpHeader = bgpHeader;
112 this.withdrawnRoutes = withdrawnRoutes;
113 this.bgpPathAttributes = bgpPathAttributes;
114 this.nlri = nlri;
115 }
116
Shashikanth VH44967ec2016-02-04 19:46:16 +0530117 public BgpUpdateMsgVer4(BgpHeader bgpHeader, short afi, byte safi, BgpPathAttributes bgpPathAttributes,
118 BgpFlowSpecDetails bgpFlowSpecComponents) {
119 this.bgpHeader = bgpHeader;
120 this.bgpFlowSpecComponents = bgpFlowSpecComponents;
121 this.bgpPathAttributes = bgpPathAttributes;
122 this.afi = afi;
123 this.safi = safi;
124 }
125
Priyanka B425e3c52015-11-13 14:31:15 +0530126 /**
127 * Reader reads BGP Update Message from the channel buffer.
128 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530129 static class Reader implements BgpMessageReader<BgpUpdateMsg> {
Priyanka B425e3c52015-11-13 14:31:15 +0530130
131 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530132 public BgpUpdateMsg readFrom(ChannelBuffer cb, BgpHeader bgpHeader)
133 throws BgpParseException {
Priyanka B425e3c52015-11-13 14:31:15 +0530134
135 if (cb.readableBytes() != (bgpHeader.getLength() - MINIMUM_COMMON_HEADER_LENGTH)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530136 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
137 BgpErrorType.BAD_MESSAGE_LENGTH, bgpHeader.getLength());
Priyanka B425e3c52015-11-13 14:31:15 +0530138 }
139
140 LinkedList<IpPrefix> withDrwRoutes = new LinkedList<>();
141 LinkedList<IpPrefix> nlri = new LinkedList<>();
142 BgpPathAttributes bgpPathAttributes = new BgpPathAttributes();
143 // Reading Withdrawn Routes Length
144 Short withDrwLen = cb.readShort();
145
146 if (cb.readableBytes() < withDrwLen) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530147 Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
148 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530149 cb.readableBytes());
150 }
151 ChannelBuffer tempCb = cb.readBytes(withDrwLen);
152 if (withDrwLen != 0) {
153 // Parsing WithdrawnRoutes
154 withDrwRoutes = parseWithdrawnRoutes(tempCb);
155 }
156 if (cb.readableBytes() < MIN_LEN_AFTER_WITHDRW_ROUTES) {
157 log.debug("Bgp Path Attribute len field not present");
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 }
161
162 // Reading Total Path Attribute Length
163 short totPathAttrLen = cb.readShort();
164 int len = withDrwLen + totPathAttrLen + PACKET_MINIMUM_LENGTH;
165 if (len > bgpHeader.getLength()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530166 throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR,
167 BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null);
Priyanka B425e3c52015-11-13 14:31:15 +0530168 }
169 if (totPathAttrLen != 0) {
170 // Parsing BGPPathAttributes
171 if (cb.readableBytes() < totPathAttrLen) {
172 Validation
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530173 .validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR,
174 BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
Priyanka B425e3c52015-11-13 14:31:15 +0530175 cb.readableBytes());
176 }
177 tempCb = cb.readBytes(totPathAttrLen);
178 bgpPathAttributes = BgpPathAttributes.read(tempCb);
179 }
180 if (cb.readableBytes() > 0) {
181 // Parsing NLRI
182 nlri = parseNlri(cb);
183 }
184 return new BgpUpdateMsgVer4(bgpHeader, withDrwRoutes,
185 bgpPathAttributes, nlri);
186 }
187 }
188
189 /**
Shashikanth VH44967ec2016-02-04 19:46:16 +0530190 * Builder class for BGP update message.
191 */
192 static class Builder implements BgpUpdateMsg.Builder {
193 BgpHeader bgpMsgHeader = null;
194 BgpFlowSpecDetails bgpFlowSpecComponents;
195 BgpPathAttributes bgpPathAttributes;
196 private short afi;
197 private byte safi;
198
199 @Override
200 public BgpUpdateMsg build() /* throws BgpParseException */ {
201 BgpHeader bgpMsgHeader = DEFAULT_UPDATE_HEADER;
202
203 return new BgpUpdateMsgVer4(bgpMsgHeader, afi, safi, bgpPathAttributes, bgpFlowSpecComponents);
204 }
205
206 @Override
207 public Builder setHeader(BgpHeader bgpMsgHeader) {
208 this.bgpMsgHeader = bgpMsgHeader;
209 return this;
210 }
211
212 @Override
213 public Builder setBgpFlowSpecComponents(BgpFlowSpecDetails bgpFlowSpecComponents) {
214 this.bgpFlowSpecComponents = bgpFlowSpecComponents;
215 return this;
216 }
217
218 @Override
219 public Builder setBgpPathAttributes(List<BgpValueType> attributes) {
220 this.bgpPathAttributes = new BgpPathAttributes(attributes);
221 return this;
222 }
223
224 @Override
225 public Builder setNlriIdentifier(short afi, byte safi) {
226 this.afi = afi;
227 this.safi = safi;
228 return this;
229 }
230 }
231
232 public static final Writer WRITER = new Writer();
233
234 /**
235 * Writer class for writing BGP update message to channel buffer.
236 */
237 public static class Writer implements BgpMessageWriter<BgpUpdateMsgVer4> {
238
239 @Override
240 public void write(ChannelBuffer cb, BgpUpdateMsgVer4 message) throws BgpParseException {
241
242 int startIndex = cb.writerIndex();
243
244 // write common header and get msg length index
245 int msgLenIndex = message.bgpHeader.write(cb);
246
247 if (msgLenIndex <= 0) {
248 throw new BgpParseException("Unable to write message header.");
249 }
250
251 if ((message.afi == Constants.AFI_FLOWSPEC_VALUE) && (message.safi == Constants.SAFI_FLOWSPEC_VALUE)) {
252 //unfeasible route length
253 cb.writeShort(0);
254 }
255
256 // TODO: write path attributes
257
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}