blob: 92086f3a7a4904246cee511526d928dae0e19ec3 [file] [log] [blame]
Pavlin Radoslavov80f3e182014-12-15 10:46:18 -08001/*
2 * Copyright 2014 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.sdnip.bgp;
17
18import org.jboss.netty.buffer.ChannelBuffer;
19import org.jboss.netty.buffer.ChannelBuffers;
20import org.jboss.netty.channel.ChannelHandlerContext;
21import org.onlab.packet.Ip4Address;
22import org.onosproject.sdnip.bgp.BgpConstants.Notifications;
23import org.onosproject.sdnip.bgp.BgpConstants.Notifications.OpenMessageError;
24import org.slf4j.Logger;
25import org.slf4j.LoggerFactory;
26
27/**
28 * A class for handling BGP OPEN messages.
29 */
30final class BgpOpen {
31 private static final Logger log = LoggerFactory.getLogger(BgpOpen.class);
32
33 /**
34 * Default constructor.
35 * <p>
36 * The constructor is private to prevent creating an instance of
37 * this utility class.
38 */
39 private BgpOpen() {
40 }
41
42 /**
43 * Processes BGP OPEN message.
44 *
45 * @param bgpSession the BGP Session to use
46 * @param ctx the Channel Handler Context
47 * @param message the message to process
48 */
49 static void processBgpOpen(BgpSession bgpSession,
50 ChannelHandlerContext ctx,
51 ChannelBuffer message) {
52 int minLength =
53 BgpConstants.BGP_OPEN_MIN_LENGTH - BgpConstants.BGP_HEADER_LENGTH;
54 if (message.readableBytes() < minLength) {
55 log.debug("BGP RX OPEN Error from {}: " +
56 "Message length {} too short. Must be at least {}",
57 bgpSession.getRemoteAddress(), message.readableBytes(),
58 minLength);
59 //
60 // ERROR: Bad Message Length
61 //
62 // Send NOTIFICATION and close the connection
63 ChannelBuffer txMessage =
64 BgpNotification.prepareBgpNotificationBadMessageLength(
65 message.readableBytes() + BgpConstants.BGP_HEADER_LENGTH);
66 ctx.getChannel().write(txMessage);
67 bgpSession.closeSession(ctx);
68 return;
69 }
70
71 //
72 // Parse the OPEN message
73 //
74 // Remote BGP version
75 int remoteBgpVersion = message.readUnsignedByte();
76 if (remoteBgpVersion != BgpConstants.BGP_VERSION) {
77 log.debug("BGP RX OPEN Error from {}: " +
78 "Unsupported BGP version {}. Should be {}",
79 bgpSession.getRemoteAddress(), remoteBgpVersion,
80 BgpConstants.BGP_VERSION);
81 //
82 // ERROR: Unsupported Version Number
83 //
84 // Send NOTIFICATION and close the connection
85 int errorCode = OpenMessageError.ERROR_CODE;
86 int errorSubcode = OpenMessageError.UNSUPPORTED_VERSION_NUMBER;
87 ChannelBuffer data = ChannelBuffers.buffer(2);
88 data.writeShort(BgpConstants.BGP_VERSION);
89 ChannelBuffer txMessage =
90 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
91 data);
92 ctx.getChannel().write(txMessage);
93 bgpSession.closeSession(ctx);
94 return;
95 }
96 bgpSession.setRemoteBgpVersion(remoteBgpVersion);
97
98 // Remote AS number
99 long remoteAs = message.readUnsignedShort();
100 //
101 // Verify that the AS number is same for all other BGP Sessions
102 // NOTE: This check applies only for our use-case where all BGP
103 // sessions are iBGP.
104 //
105 for (BgpSession bs : bgpSession.getBgpSessionManager().getBgpSessions()) {
106 if ((bs.getRemoteAs() != 0) && (remoteAs != bs.getRemoteAs())) {
107 log.debug("BGP RX OPEN Error from {}: Bad Peer AS {}. " +
108 "Expected {}",
109 bgpSession.getRemoteAddress(), remoteAs,
110 bs.getRemoteAs());
111 //
112 // ERROR: Bad Peer AS
113 //
114 // Send NOTIFICATION and close the connection
115 int errorCode = OpenMessageError.ERROR_CODE;
116 int errorSubcode = OpenMessageError.BAD_PEER_AS;
117 ChannelBuffer txMessage =
118 BgpNotification.prepareBgpNotification(errorCode,
119 errorSubcode, null);
120 ctx.getChannel().write(txMessage);
121 bgpSession.closeSession(ctx);
122 return;
123 }
124 }
125 bgpSession.setRemoteAs(remoteAs);
126
127 // Remote Hold Time
128 long remoteHoldtime = message.readUnsignedShort();
129 if ((remoteHoldtime != 0) &&
130 (remoteHoldtime < BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME)) {
131 log.debug("BGP RX OPEN Error from {}: " +
132 "Unacceptable Hold Time field {}. " +
133 "Should be 0 or at least {}",
134 bgpSession.getRemoteAddress(), remoteHoldtime,
135 BgpConstants.BGP_KEEPALIVE_MIN_HOLDTIME);
136 //
137 // ERROR: Unacceptable Hold Time
138 //
139 // Send NOTIFICATION and close the connection
140 int errorCode = OpenMessageError.ERROR_CODE;
141 int errorSubcode = OpenMessageError.UNACCEPTABLE_HOLD_TIME;
142 ChannelBuffer txMessage =
143 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
144 null);
145 ctx.getChannel().write(txMessage);
146 bgpSession.closeSession(ctx);
147 return;
148 }
149 bgpSession.setRemoteHoldtime(remoteHoldtime);
150
151 // Remote BGP Identifier
152 Ip4Address remoteBgpId =
153 Ip4Address.valueOf((int) message.readUnsignedInt());
154 bgpSession.setRemoteBgpId(remoteBgpId);
155
156 // Optional Parameters
157 int optParamLen = message.readUnsignedByte();
158 if (message.readableBytes() < optParamLen) {
159 log.debug("BGP RX OPEN Error from {}: " +
160 "Invalid Optional Parameter Length field {}. " +
161 "Remaining Optional Parameters {}",
162 bgpSession.getRemoteAddress(), optParamLen,
163 message.readableBytes());
164 //
165 // ERROR: Invalid Optional Parameter Length field: Unspecific
166 //
167 // Send NOTIFICATION and close the connection
168 int errorCode = OpenMessageError.ERROR_CODE;
169 int errorSubcode = Notifications.ERROR_SUBCODE_UNSPECIFIC;
170 ChannelBuffer txMessage =
171 BgpNotification.prepareBgpNotification(errorCode, errorSubcode,
172 null);
173 ctx.getChannel().write(txMessage);
174 bgpSession.closeSession(ctx);
175 return;
176 }
177 // NOTE: Parse the optional parameters (if needed)
178 message.readBytes(optParamLen); // NOTE: data ignored
179
180 log.debug("BGP RX OPEN message from {}: " +
181 "BGPv{} AS {} BGP-ID {} Holdtime {}",
182 bgpSession.getRemoteAddress(), remoteBgpVersion, remoteAs,
183 remoteBgpId, remoteHoldtime);
184
185 // Send my OPEN followed by KEEPALIVE
186 ChannelBuffer txMessage = prepareBgpOpen(bgpSession);
187 ctx.getChannel().write(txMessage);
188 //
189 txMessage = BgpKeepalive.prepareBgpKeepalive();
190 ctx.getChannel().write(txMessage);
191
192 // Start the KEEPALIVE timer
193 bgpSession.restartKeepaliveTimer(ctx);
194
195 // Start the Session Timeout timer
196 bgpSession.restartSessionTimeoutTimer(ctx);
197 }
198
199 /**
200 * Prepares BGP OPEN message.
201 *
202 * @param bgpSession the BGP Session to use
203 * @return the message to transmit (BGP header included)
204 */
205 private static ChannelBuffer prepareBgpOpen(BgpSession bgpSession) {
206 ChannelBuffer message =
207 ChannelBuffers.buffer(BgpConstants.BGP_MESSAGE_MAX_LENGTH);
208
209 //
210 // Prepare the OPEN message payload
211 //
212 message.writeByte(bgpSession.getLocalBgpVersion());
213 message.writeShort((int) bgpSession.getLocalAs());
214 message.writeShort((int) bgpSession.getLocalHoldtime());
215 message.writeInt(bgpSession.getLocalBgpId().toInt());
216 message.writeByte(0); // No Optional Parameters
217 return BgpMessage.prepareBgpMessage(BgpConstants.BGP_TYPE_OPEN,
218 message);
219 }
220}