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