blob: 6b933c9a086e02e4d42e40625d5caf5fb21afe42 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.sdnip.bgp;
Jonathan Hart20d8e512014-10-16 11:05:52 -070017
18import java.util.Collection;
19
20import org.jboss.netty.buffer.ChannelBuffer;
21import org.jboss.netty.buffer.ChannelBuffers;
22import org.jboss.netty.channel.ChannelHandlerContext;
23import org.jboss.netty.channel.ChannelStateEvent;
24import org.jboss.netty.channel.SimpleChannelHandler;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080025import org.onlab.packet.Ip4Address;
26import org.onlab.packet.Ip4Prefix;
Jonathan Hart20d8e512014-10-16 11:05:52 -070027
28/**
29 * Class for handling the remote BGP Peer session.
30 */
31class TestBgpPeerChannelHandler extends SimpleChannelHandler {
32 static final long PEER_AS = 65001;
33 static final int PEER_HOLDTIME = 120; // 120 seconds
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080034 final Ip4Address bgpId; // The BGP ID
Jonathan Hart20d8e512014-10-16 11:05:52 -070035 ChannelHandlerContext savedCtx;
36
37 /**
38 * Constructor for given BGP ID.
39 *
40 * @param bgpId the BGP ID to use
Jonathan Hart20d8e512014-10-16 11:05:52 -070041 */
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080042 TestBgpPeerChannelHandler(Ip4Address bgpId) {
Jonathan Hart20d8e512014-10-16 11:05:52 -070043 this.bgpId = bgpId;
Jonathan Hart20d8e512014-10-16 11:05:52 -070044 }
45
46 /**
47 * Closes the channel.
48 */
49 void closeChannel() {
50 savedCtx.getChannel().close();
51 }
52
53 @Override
54 public void channelConnected(ChannelHandlerContext ctx,
55 ChannelStateEvent channelEvent) {
56 this.savedCtx = ctx;
57 // Prepare and transmit BGP OPEN message
58 ChannelBuffer message = prepareBgpOpen();
59 ctx.getChannel().write(message);
60
61 // Prepare and transmit BGP KEEPALIVE message
62 message = prepareBgpKeepalive();
63 ctx.getChannel().write(message);
64 }
65
66 @Override
67 public void channelDisconnected(ChannelHandlerContext ctx,
68 ChannelStateEvent channelEvent) {
69 // Nothing to do
70 }
71
72 /**
73 * Prepares BGP OPEN message.
74 *
75 * @return the message to transmit (BGP header included)
76 */
77 ChannelBuffer prepareBgpOpen() {
78 ChannelBuffer message =
79 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
80 message.writeByte(BgpConstants.BGP_VERSION);
81 message.writeShort((int) PEER_AS);
82 message.writeShort(PEER_HOLDTIME);
83 message.writeInt(bgpId.toInt());
84 message.writeByte(0); // No Optional Parameters
85 return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
86 }
87
88 /**
89 * Prepares BGP UPDATE message.
90 *
91 * @param nextHopRouter the next-hop router address for the routes to add
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -080092 * @param localPref the local preference for the routes to use
93 * @param multiExitDisc the MED value
94 * @param asPath the AS path for the routes to add
Jonathan Hart20d8e512014-10-16 11:05:52 -070095 * @param addedRoutes the routes to add
96 * @param withdrawnRoutes the routes to withdraw
97 * @return the message to transmit (BGP header included)
98 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080099 ChannelBuffer prepareBgpUpdate(Ip4Address nextHopRouter,
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800100 long localPref,
101 long multiExitDisc,
102 BgpRouteEntry.AsPath asPath,
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800103 Collection<Ip4Prefix> addedRoutes,
104 Collection<Ip4Prefix> withdrawnRoutes) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700105 int attrFlags;
106 ChannelBuffer message =
107 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
108 ChannelBuffer pathAttributes =
109 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
110
111 // Encode the Withdrawn Routes
112 ChannelBuffer encodedPrefixes = encodePackedPrefixes(withdrawnRoutes);
113 message.writeShort(encodedPrefixes.readableBytes());
114 message.writeBytes(encodedPrefixes);
115
116 // Encode the Path Attributes
117 // ORIGIN: IGP
118 attrFlags = 0x40; // Transitive flag
119 pathAttributes.writeByte(attrFlags);
120 pathAttributes.writeByte(BgpConstants.Update.Origin.TYPE);
121 pathAttributes.writeByte(1); // Data length
122 pathAttributes.writeByte(BgpConstants.Update.Origin.IGP);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800123
124 // AS_PATH: asPath
Jonathan Hart20d8e512014-10-16 11:05:52 -0700125 attrFlags = 0x40; // Transitive flag
126 pathAttributes.writeByte(attrFlags);
127 pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE);
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800128 ChannelBuffer encodedAsPath = encodeAsPath(asPath);
129 pathAttributes.writeByte(encodedAsPath.readableBytes()); // Data length
130 pathAttributes.writeBytes(encodedAsPath);
Jonathan Hart20d8e512014-10-16 11:05:52 -0700131 // NEXT_HOP: nextHopRouter
132 attrFlags = 0x40; // Transitive flag
133 pathAttributes.writeByte(attrFlags);
134 pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE);
135 pathAttributes.writeByte(4); // Data length
136 pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router
137 // LOCAL_PREF: localPref
138 attrFlags = 0x40; // Transitive flag
139 pathAttributes.writeByte(attrFlags);
140 pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE);
141 pathAttributes.writeByte(4); // Data length
142 pathAttributes.writeInt((int) localPref); // Preference value
143 // MULTI_EXIT_DISC: multiExitDisc
144 attrFlags = 0x80; // Optional
145 // Non-Transitive flag
146 pathAttributes.writeByte(attrFlags);
147 pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE);
148 pathAttributes.writeByte(4); // Data length
149 pathAttributes.writeInt((int) multiExitDisc); // Preference value
150 // The NLRI prefixes
151 encodedPrefixes = encodePackedPrefixes(addedRoutes);
152
153 // Write the Path Attributes, beginning with its length
154 message.writeShort(pathAttributes.readableBytes());
155 message.writeBytes(pathAttributes);
156 message.writeBytes(encodedPrefixes);
157
158 return prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE, message);
159 }
160
161 /**
162 * Encodes a collection of IPv4 network prefixes in a packed format.
163 * <p>
164 * The IPv4 prefixes are encoded in the form:
165 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
166 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
167 * of an octet).
168 *
169 * @param prefixes the prefixes to encode
170 * @return the buffer with the encoded prefixes
171 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800172 private ChannelBuffer encodePackedPrefixes(Collection<Ip4Prefix> prefixes) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700173 ChannelBuffer message =
174 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
175
176 // Write each of the prefixes
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800177 for (Ip4Prefix prefix : prefixes) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700178 int prefixBitlen = prefix.prefixLength();
179 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
180 message.writeByte(prefixBitlen);
181
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800182 Ip4Address address = prefix.address();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700183 long value = address.toInt() & 0xffffffffL;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800184 for (int i = 0; i < Ip4Address.BYTE_LENGTH; i++) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700185 if (prefixBytelen-- == 0) {
186 break;
187 }
188 long nextByte =
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800189 (value >> ((Ip4Address.BYTE_LENGTH - i - 1) * 8)) & 0xff;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700190 message.writeByte((int) nextByte);
191 }
192 }
193
194 return message;
195 }
196
197 /**
Pavlin Radoslavov0af11c12014-12-10 18:16:25 -0800198 * Encodes an AS path.
199 *
200 * @param asPath the AS path to encode
201 * @return the buffer with the encoded AS path
202 */
203 private ChannelBuffer encodeAsPath(BgpRouteEntry.AsPath asPath) {
204 ChannelBuffer message =
205 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
206
207 for (BgpRouteEntry.PathSegment pathSegment : asPath.getPathSegments()) {
208 message.writeByte(pathSegment.getType());
209 message.writeByte(pathSegment.getSegmentAsNumbers().size());
210 for (Long asNumber : pathSegment.getSegmentAsNumbers()) {
211 message.writeShort(asNumber.intValue());
212 }
213 }
214
215 return message;
216 }
217
218 /**
Jonathan Hart20d8e512014-10-16 11:05:52 -0700219 * Prepares BGP KEEPALIVE message.
220 *
221 * @return the message to transmit (BGP header included)
222 */
223 ChannelBuffer prepareBgpKeepalive() {
224 ChannelBuffer message =
225 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
226 return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
227 }
228
229 /**
230 * Prepares BGP NOTIFICATION message.
231 *
232 * @param errorCode the BGP NOTIFICATION Error Code
233 * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
234 * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
235 * @param payload the BGP NOTIFICATION Data if applicable, otherwise null
236 * @return the message to transmit (BGP header included)
237 */
238 ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
239 ChannelBuffer data) {
240 ChannelBuffer message =
241 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
242 // Prepare the NOTIFICATION message payload
243 message.writeByte(errorCode);
244 message.writeByte(errorSubcode);
245 if (data != null) {
246 message.writeBytes(data);
247 }
248 return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
249 }
250
251 /**
252 * Prepares BGP message.
253 *
254 * @param type the BGP message type
255 * @param payload the message payload to transmit (BGP header excluded)
256 * @return the message to transmit (BGP header included)
257 */
258 private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
259 ChannelBuffer message =
260 ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
261 payload.readableBytes());
262
263 // Write the marker
264 for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
265 message.writeByte(0xff);
266 }
267
268 // Write the rest of the BGP header
269 message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
270 payload.readableBytes());
271 message.writeByte(type);
272
273 // Write the payload
274 message.writeBytes(payload);
275 return message;
276 }
277}