blob: 22f8a0a3e3b6f2b0ec451edfbc09ba804a165e88 [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;
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 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 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080046 TestBgpPeerChannelHandler(Ip4Address bgpId, long localPref) {
Jonathan Hart20d8e512014-10-16 11:05:52 -070047 this.bgpId = bgpId;
48 this.localPref = localPref;
49 }
50
51 /**
52 * Closes the channel.
53 */
54 void closeChannel() {
55 savedCtx.getChannel().close();
56 }
57
58 @Override
59 public void channelConnected(ChannelHandlerContext ctx,
60 ChannelStateEvent channelEvent) {
61 this.savedCtx = ctx;
62 // Prepare and transmit BGP OPEN message
63 ChannelBuffer message = prepareBgpOpen();
64 ctx.getChannel().write(message);
65
66 // Prepare and transmit BGP KEEPALIVE message
67 message = prepareBgpKeepalive();
68 ctx.getChannel().write(message);
69 }
70
71 @Override
72 public void channelDisconnected(ChannelHandlerContext ctx,
73 ChannelStateEvent channelEvent) {
74 // Nothing to do
75 }
76
77 /**
78 * Prepares BGP OPEN message.
79 *
80 * @return the message to transmit (BGP header included)
81 */
82 ChannelBuffer prepareBgpOpen() {
83 ChannelBuffer message =
84 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
85 message.writeByte(BgpConstants.BGP_VERSION);
86 message.writeShort((int) PEER_AS);
87 message.writeShort(PEER_HOLDTIME);
88 message.writeInt(bgpId.toInt());
89 message.writeByte(0); // No Optional Parameters
90 return prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN, message);
91 }
92
93 /**
94 * Prepares BGP UPDATE message.
95 *
96 * @param nextHopRouter the next-hop router address for the routes to add
97 * @param addedRoutes the routes to add
98 * @param withdrawnRoutes the routes to withdraw
99 * @return the message to transmit (BGP header included)
100 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800101 ChannelBuffer prepareBgpUpdate(Ip4Address nextHopRouter,
102 Collection<Ip4Prefix> addedRoutes,
103 Collection<Ip4Prefix> withdrawnRoutes) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700104 int attrFlags;
105 ChannelBuffer message =
106 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
107 ChannelBuffer pathAttributes =
108 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
109
110 // Encode the Withdrawn Routes
111 ChannelBuffer encodedPrefixes = encodePackedPrefixes(withdrawnRoutes);
112 message.writeShort(encodedPrefixes.readableBytes());
113 message.writeBytes(encodedPrefixes);
114
115 // Encode the Path Attributes
116 // ORIGIN: IGP
117 attrFlags = 0x40; // Transitive flag
118 pathAttributes.writeByte(attrFlags);
119 pathAttributes.writeByte(BgpConstants.Update.Origin.TYPE);
120 pathAttributes.writeByte(1); // Data length
121 pathAttributes.writeByte(BgpConstants.Update.Origin.IGP);
122 // AS_PATH: Two Path Segments of 3 ASes each
123 attrFlags = 0x40; // Transitive flag
124 pathAttributes.writeByte(attrFlags);
125 pathAttributes.writeByte(BgpConstants.Update.AsPath.TYPE);
126 pathAttributes.writeByte(16); // Data length
127 byte pathSegmentType1 = (byte) BgpConstants.Update.AsPath.AS_SEQUENCE;
128 pathAttributes.writeByte(pathSegmentType1);
129 pathAttributes.writeByte(3); // Three ASes
130 pathAttributes.writeShort(65010); // AS=65010
131 pathAttributes.writeShort(65020); // AS=65020
132 pathAttributes.writeShort(65030); // AS=65030
133 byte pathSegmentType2 = (byte) BgpConstants.Update.AsPath.AS_SET;
134 pathAttributes.writeByte(pathSegmentType2);
135 pathAttributes.writeByte(3); // Three ASes
136 pathAttributes.writeShort(65041); // AS=65041
137 pathAttributes.writeShort(65042); // AS=65042
138 pathAttributes.writeShort(65043); // AS=65043
139 // NEXT_HOP: nextHopRouter
140 attrFlags = 0x40; // Transitive flag
141 pathAttributes.writeByte(attrFlags);
142 pathAttributes.writeByte(BgpConstants.Update.NextHop.TYPE);
143 pathAttributes.writeByte(4); // Data length
144 pathAttributes.writeInt(nextHopRouter.toInt()); // Next-hop router
145 // LOCAL_PREF: localPref
146 attrFlags = 0x40; // Transitive flag
147 pathAttributes.writeByte(attrFlags);
148 pathAttributes.writeByte(BgpConstants.Update.LocalPref.TYPE);
149 pathAttributes.writeByte(4); // Data length
150 pathAttributes.writeInt((int) localPref); // Preference value
151 // MULTI_EXIT_DISC: multiExitDisc
152 attrFlags = 0x80; // Optional
153 // Non-Transitive flag
154 pathAttributes.writeByte(attrFlags);
155 pathAttributes.writeByte(BgpConstants.Update.MultiExitDisc.TYPE);
156 pathAttributes.writeByte(4); // Data length
157 pathAttributes.writeInt((int) multiExitDisc); // Preference value
158 // The NLRI prefixes
159 encodedPrefixes = encodePackedPrefixes(addedRoutes);
160
161 // Write the Path Attributes, beginning with its length
162 message.writeShort(pathAttributes.readableBytes());
163 message.writeBytes(pathAttributes);
164 message.writeBytes(encodedPrefixes);
165
166 return prepareBgpMessage(BgpConstants.BGP_TYPE_UPDATE, message);
167 }
168
169 /**
170 * Encodes a collection of IPv4 network prefixes in a packed format.
171 * <p>
172 * The IPv4 prefixes are encoded in the form:
173 * <Length, Prefix> where Length is the length in bits of the IPv4 prefix,
174 * and Prefix is the IPv4 prefix (padded with trailing bits to the end
175 * of an octet).
176 *
177 * @param prefixes the prefixes to encode
178 * @return the buffer with the encoded prefixes
179 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800180 private ChannelBuffer encodePackedPrefixes(Collection<Ip4Prefix> prefixes) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700181 ChannelBuffer message =
182 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
183
184 // Write each of the prefixes
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800185 for (Ip4Prefix prefix : prefixes) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700186 int prefixBitlen = prefix.prefixLength();
187 int prefixBytelen = (prefixBitlen + 7) / 8; // Round-up
188 message.writeByte(prefixBitlen);
189
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800190 Ip4Address address = prefix.address();
Jonathan Hart20d8e512014-10-16 11:05:52 -0700191 long value = address.toInt() & 0xffffffffL;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800192 for (int i = 0; i < Ip4Address.BYTE_LENGTH; i++) {
Jonathan Hart20d8e512014-10-16 11:05:52 -0700193 if (prefixBytelen-- == 0) {
194 break;
195 }
196 long nextByte =
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800197 (value >> ((Ip4Address.BYTE_LENGTH - i - 1) * 8)) & 0xff;
Jonathan Hart20d8e512014-10-16 11:05:52 -0700198 message.writeByte((int) nextByte);
199 }
200 }
201
202 return message;
203 }
204
205 /**
206 * Prepares BGP KEEPALIVE message.
207 *
208 * @return the message to transmit (BGP header included)
209 */
210 ChannelBuffer prepareBgpKeepalive() {
211 ChannelBuffer message =
212 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
213 return prepareBgpMessage(BgpConstants.BGP_TYPE_KEEPALIVE, message);
214 }
215
216 /**
217 * Prepares BGP NOTIFICATION message.
218 *
219 * @param errorCode the BGP NOTIFICATION Error Code
220 * @param errorSubcode the BGP NOTIFICATION Error Subcode if applicable,
221 * otherwise BgpConstants.Notifications.ERROR_SUBCODE_UNSPECIFIC
222 * @param payload the BGP NOTIFICATION Data if applicable, otherwise null
223 * @return the message to transmit (BGP header included)
224 */
225 ChannelBuffer prepareBgpNotification(int errorCode, int errorSubcode,
226 ChannelBuffer data) {
227 ChannelBuffer message =
228 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
229 // Prepare the NOTIFICATION message payload
230 message.writeByte(errorCode);
231 message.writeByte(errorSubcode);
232 if (data != null) {
233 message.writeBytes(data);
234 }
235 return prepareBgpMessage(BgpConstants.BGP_TYPE_NOTIFICATION, message);
236 }
237
238 /**
239 * Prepares BGP message.
240 *
241 * @param type the BGP message type
242 * @param payload the message payload to transmit (BGP header excluded)
243 * @return the message to transmit (BGP header included)
244 */
245 private ChannelBuffer prepareBgpMessage(int type, ChannelBuffer payload) {
246 ChannelBuffer message =
247 ChannelBuffers.buffer(BgpConstants.BGP_HEADER_LENGTH +
248 payload.readableBytes());
249
250 // Write the marker
251 for (int i = 0; i < BgpConstants.BGP_HEADER_MARKER_LENGTH; i++) {
252 message.writeByte(0xff);
253 }
254
255 // Write the rest of the BGP header
256 message.writeShort(BgpConstants.BGP_HEADER_LENGTH +
257 payload.readableBytes());
258 message.writeByte(type);
259
260 // Write the payload
261 message.writeBytes(payload);
262 return message;
263 }
264}