blob: 4d94e1dbe5a6907139ff81c00c2f0c3580f97247 [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 */
Jonathan Hart20d8e512014-10-16 11:05:52 -070016package org.onlab.onos.sdnip.bgp;
17
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;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.IpPrefix;
27
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
34 final IpAddress bgpId; // The BGP ID
35 final long localPref; // Local preference for routes
36 final long multiExitDisc = 20; // MED value
37
38 ChannelHandlerContext savedCtx;
39
40 /**
41 * Constructor for given BGP ID.
42 *
43 * @param bgpId the BGP ID to use
44 * @param localPref the local preference for the routes to use
45 */
46 TestBgpPeerChannelHandler(IpAddress bgpId,
47 long localPref) {
48 this.bgpId = bgpId;
49 this.localPref = localPref;
50 }
51
52 /**
53 * Closes the channel.
54 */
55 void closeChannel() {
56 savedCtx.getChannel().close();
57 }
58
59 @Override
60 public void channelConnected(ChannelHandlerContext ctx,
61 ChannelStateEvent channelEvent) {
62 this.savedCtx = ctx;
63 // Prepare and transmit BGP OPEN message
64 ChannelBuffer message = prepareBgpOpen();
65 ctx.getChannel().write(message);
66
67 // Prepare and transmit BGP KEEPALIVE message
68 message = prepareBgpKeepalive();
69 ctx.getChannel().write(message);
70 }
71
72 @Override
73 public void channelDisconnected(ChannelHandlerContext ctx,
74 ChannelStateEvent channelEvent) {
75 // Nothing to do
76 }
77
78 /**
79 * Prepares BGP OPEN message.
80 *
81 * @return the message to transmit (BGP header included)
82 */
83 ChannelBuffer prepareBgpOpen() {
84 ChannelBuffer message =
85 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
86 message.writeByte(BgpConstants.BGP_VERSION);
87 message.writeShort((int) PEER_AS);
88 message.writeShort(PEER_HOLDTIME);
89 message.writeInt(bgpId.toInt());
90 message.writeByte(0); // No Optional Parameters
91 return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
92 }
93
94 /**
95 * Prepares BGP UPDATE message.
96 *
97 * @param nextHopRouter the next-hop router address for the routes to add
98 * @param addedRoutes the routes to add
99 * @param withdrawnRoutes the routes to withdraw
100 * @return the message to transmit (BGP header included)
101 */
102 ChannelBuffer prepareBgpUpdate(IpAddress nextHopRouter,
103 Collection<IpPrefix> addedRoutes,
104 Collection<IpPrefix> withdrawnRoutes) {
105 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);
123 // AS_PATH: Two Path Segments of 3 ASes each
124 attrFlags = 0x40; // Transitive flag
125 pathAttributes.writeByte(attrFlags);
126 pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE);
127 pathAttributes.writeByte(16); // Data length
128 byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
129 pathAttributes.writeByte(pathSegmentType1);
130 pathAttributes.writeByte(3); // Three ASes
131 pathAttributes.writeShort(65010); // AS=65010
132 pathAttributes.writeShort(65020); // AS=65020
133 pathAttributes.writeShort(65030); // AS=65030
134 byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
135 pathAttributes.writeByte(pathSegmentType2);
136 pathAttributes.writeByte(3); // Three ASes
137 pathAttributes.writeShort(65041); // AS=65041
138 pathAttributes.writeShort(65042); // AS=65042
139 pathAttributes.writeShort(65043); // AS=65043
140 // NEXT_HOP: nextHopRouter
141 attrFlags = 0x40; // Transitive flag
142 pathAttributes.writeByte(attrFlags);
143 pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE);
144 pathAttributes.writeByte(4); // Data length
145 pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router
146 // LOCAL_PREF: localPref
147 attrFlags = 0x40; // Transitive flag
148 pathAttributes.writeByte(attrFlags);
149 pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE);
150 pathAttributes.writeByte(4); // Data length
151 pathAttributes.writeInt((int) localPref); // Preference value
152 // MULTI_EXIT_DISC: multiExitDisc
153 attrFlags = 0x80; // Optional
154 // Non-Transitive flag
155 pathAttributes.writeByte(attrFlags);
156 pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE);
157 pathAttributes.writeByte(4); // Data length
158 pathAttributes.writeInt((int) multiExitDisc); // Preference value
159 // The NLRI prefixes
160 encodedPrefixes = encodePackedPrefixes(addedRoutes);
161
162 // Write the Path Attributes, beginning with its length
163 message.writeShort(pathAttributes.readableBytes());
164 message.writeBytes(pathAttributes);
165 message.writeBytes(encodedPrefixes);
166
167 return prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE, message);
168 }
169
170 /**
171 * Encodes a collection of IPv4 network prefixes in a packed format.
172 * <p>
173 * The IPv4 prefixes are encoded in the form:
174 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
175 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
176 * of an octet).
177 *
178 * @param prefixes the prefixes to encode
179 * @return the buffer with the encoded prefixes
180 */
181 private ChannelBuffer encodePackedPrefixes(Collection<IpPrefix> prefixes) {
182 ChannelBuffer message =
183 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
184
185 // Write each of the prefixes
186 for (IpPrefix prefix : prefixes) {
187 int prefixBitlen = prefix.prefixLength();
188 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
189 message.writeByte(prefixBitlen);
190
Pavlin Radoslavov855ea2d2014-10-30 15:32:39 -0700191 IpAddress address = prefix.address();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700192 long value = address.toInt() & 0xffffffffL;
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700193 for (int i = 0; i < IpAddress.INET_BYTE_LENGTH; i++) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700194 if (prefixBytelen-- == 0) {
195 break;
196 }
197 long nextByte =
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700198 (value >> ((IpAddress.INET_BYTE_LENGTH - i - 1) * 8)) & 0xff;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700199 message.writeByte((int) nextByte);
200 }
201 }
202
203 return message;
204 }
205
206 /**
207 * Prepares BGP KEEPALIVE message.
208 *
209 * @return the message to transmit (BGP header included)
210 */
211 ChannelBuffer prepareBgpKeepalive() {
212 ChannelBuffer message =
213 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
214 return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
215 }
216
217 /**
218 * Prepares BGP NOTIFICATION message.
219 *
220 * @param errorCode the BGP NOTIFICATION Error Code
221 * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
222 * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
223 * @param payload the BGP NOTIFICATION Data if applicable, otherwise null
224 * @return the message to transmit (BGP header included)
225 */
226 ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
227 ChannelBuffer data) {
228 ChannelBuffer message =
229 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
230 // Prepare the NOTIFICATION message payload
231 message.writeByte(errorCode);
232 message.writeByte(errorSubcode);
233 if (data != null) {
234 message.writeBytes(data);
235 }
236 return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
237 }
238
239 /**
240 * Prepares BGP message.
241 *
242 * @param type the BGP message type
243 * @param payload the message payload to transmit (BGP header excluded)
244 * @return the message to transmit (BGP header included)
245 */
246 private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
247 ChannelBuffer message =
248 ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
249 payload.readableBytes());
250
251 // Write the marker
252 for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
253 message.writeByte(0xff);
254 }
255
256 // Write the rest of the BGP header
257 message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
258 payload.readableBytes());
259 message.writeByte(type);
260
261 // Write the payload
262 message.writeBytes(payload);
263 return message;
264 }
265}