blob: 1f6e5bc72fab45e1411bfae2a658419dfb038027 [file] [log] [blame]
Satish Ke107e662015-09-21 19:00:17 +05301/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Satish Ke107e662015-09-21 19:00:17 +05303 *
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 */
16
17package org.onosproject.bgp.controller.impl;
18
Vidyashree Ramaee293252015-11-18 17:00:11 +053019import org.jboss.netty.buffer.ChannelBuffer;
20import org.jboss.netty.buffer.ChannelBuffers;
Shashikanth VH6de20d32015-10-09 12:04:13 +053021import org.jboss.netty.channel.Channel;
22import org.jboss.netty.channel.ChannelHandlerContext;
23import org.jboss.netty.channel.ChannelStateEvent;
24import org.jboss.netty.channel.ExceptionEvent;
25import org.jboss.netty.channel.MessageEvent;
Satish Ke107e662015-09-21 19:00:17 +053026import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
Shashikanth VH6de20d32015-10-09 12:04:13 +053027import org.jboss.netty.handler.timeout.ReadTimeoutException;
28import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053029import org.onlab.packet.Ip4Address;
Shashikanth VH6de20d32015-10-09 12:04:13 +053030import org.onlab.packet.IpAddress;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053031import org.onosproject.bgp.controller.BgpCfg;
32import org.onosproject.bgp.controller.BgpController;
33import org.onosproject.bgp.controller.BgpId;
34import org.onosproject.bgp.controller.BgpPeer;
35import org.onosproject.bgp.controller.BgpPeerCfg;
36import org.onosproject.bgp.controller.impl.BgpControllerImpl.BgpPeerManagerImpl;
37import org.onosproject.bgpio.exceptions.BgpParseException;
38import org.onosproject.bgpio.protocol.BgpFactory;
39import org.onosproject.bgpio.protocol.BgpMessage;
40import org.onosproject.bgpio.protocol.BgpOpenMsg;
41import org.onosproject.bgpio.protocol.BgpType;
42import org.onosproject.bgpio.protocol.BgpVersion;
43import org.onosproject.bgpio.types.BgpErrorType;
44import org.onosproject.bgpio.types.BgpValueType;
Vidyashree Ramaee293252015-11-18 17:00:11 +053045import org.onosproject.bgpio.types.FourOctetAsNumCapabilityTlv;
46import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
Shashikanth VHb58cfd52016-04-21 16:45:50 +053047import org.onosproject.bgpio.types.RpdCapabilityTlv;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +053048import org.onosproject.bgpio.util.Constants;
Shashikanth VH6de20d32015-10-09 12:04:13 +053049import org.slf4j.Logger;
50import org.slf4j.LoggerFactory;
Satish Ke107e662015-09-21 19:00:17 +053051
Jonathan Hart51539b82015-10-29 09:53:04 -070052import java.io.IOException;
53import java.net.InetAddress;
54import java.net.InetSocketAddress;
55import java.net.SocketAddress;
56import java.net.UnknownHostException;
57import java.nio.channels.ClosedChannelException;
58import java.util.Collections;
Jonathan Hart51539b82015-10-29 09:53:04 -070059import java.util.List;
60import java.util.ListIterator;
Shashikanth VHb650bfa2016-04-18 12:54:03 +053061import java.util.concurrent.CopyOnWriteArrayList;
Jonathan Hart51539b82015-10-29 09:53:04 -070062import java.util.concurrent.RejectedExecutionException;
63
Satish Ke107e662015-09-21 19:00:17 +053064/**
65 * Channel handler deals with the bgp peer connection and dispatches messages from peer to the appropriate locations.
66 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053067class BgpChannelHandler extends IdleStateAwareChannelHandler {
Satish Ke107e662015-09-21 19:00:17 +053068
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053069 private static final Logger log = LoggerFactory.getLogger(BgpChannelHandler.class);
Vidyashree Ramaee293252015-11-18 17:00:11 +053070 static final int BGP_MIN_HOLDTIME = 3;
Shashikanth VH6de20d32015-10-09 12:04:13 +053071 static final int BGP_MAX_KEEPALIVE_INTERVAL = 3;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053072 private BgpPeer bgpPeer;
73 private BgpId thisbgpId;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053074 private Channel channel;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053075 private BgpKeepAliveTimer keepAliveTimer = null;
Shashikanth VH6de20d32015-10-09 12:04:13 +053076 private short peerHoldTime = 0;
77 private short negotiatedHoldTime = 0;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053078 private long peerAsNum;
Shashikanth VH6de20d32015-10-09 12:04:13 +053079 private int peerIdentifier;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053080 private BgpPacketStatsImpl bgpPacketStats;
Shashikanth VH6de20d32015-10-09 12:04:13 +053081 static final int MAX_WRONG_COUNT_PACKET = 5;
Vidyashree Ramaee293252015-11-18 17:00:11 +053082 static final byte MULTI_PROTOCOL_EXTN_CAPA_TYPE = 1;
83 static final byte FOUR_OCTET_AS_NUM_CAPA_TYPE = 65;
84 static final int AS_TRANS = 23456;
85 static final int MAX_AS2_NUM = 65535;
86 static final short AFI = 16388;
87 static final byte RES = 0;
88 static final byte SAFI = 71;
Shashikanth VHb650bfa2016-04-18 12:54:03 +053089 static final byte MAX_UNSUPPORTED_CAPABILITY = 5;
Shashikanth VH6de20d32015-10-09 12:04:13 +053090
91 // State needs to be volatile because the HandshakeTimeoutHandler
92 // needs to check if the handshake is complete
93 private volatile ChannelState state;
94
95 // When a bgp peer with a ip addresss is found (i.e we already have a
96 // connected peer with the same ip), the new peer is immediately
97 // disconnected. At that point netty callsback channelDisconnected() which
Shashikanth VH9f8afb42015-11-04 18:00:30 +053098 // proceeds to cleaup peer state - we need to ensure that it does not
99 // cleanup
Shashikanth VH6de20d32015-10-09 12:04:13 +0530100 // peer state for the older (still connected) peer
Jonathan Hart51539b82015-10-29 09:53:04 -0700101 private volatile Boolean duplicateBgpIdFound;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530102 // Indicates the bgp version used by this bgp peer
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530103 protected BgpVersion bgpVersion;
104 private BgpController bgpController;
105 protected BgpFactory factory4;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530106 private boolean isIbgpSession;
107 private BgpSessionInfoImpl sessionInfo;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530108 private BgpPeerManagerImpl peerManager;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530109 private InetSocketAddress inetAddress;
110 private IpAddress ipAddress;
111 private SocketAddress address;
112 private String peerAddr;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530113 private BgpCfg bgpconfig;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530114 List<BgpValueType> remoteBgpCapability;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530115
Satish Ke107e662015-09-21 19:00:17 +0530116 /**
117 * Create a new unconnected BGPChannelHandler.
118 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530119 * @param bgpController bgp controller
Satish Ke107e662015-09-21 19:00:17 +0530120 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530121 BgpChannelHandler(BgpController bgpController) {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530122 this.bgpController = bgpController;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530123 this.peerManager = (BgpPeerManagerImpl) bgpController.peerManager();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530124 this.state = ChannelState.IDLE;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530125 this.factory4 = Controller.getBgpMessageFactory4();
Jonathan Hart51539b82015-10-29 09:53:04 -0700126 this.duplicateBgpIdFound = Boolean.FALSE;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530127 this.bgpPacketStats = new BgpPacketStatsImpl();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530128 this.bgpconfig = bgpController.getConfig();
Satish Ke107e662015-09-21 19:00:17 +0530129 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530130
131 // To disconnect peer session.
132 public void disconnectPeer() {
133 bgpPeer.disconnectPeer();
134 }
135
136 // *************************
137 // Channel State Machine
138 // *************************
139
140 /**
141 * The state machine for handling the peer/channel state. All state transitions should happen from within the state
142 * machine (and not from other parts of the code)
143 */
144 enum ChannelState {
145 /**
146 * Initial state before channel is connected.
147 */
148 IDLE(false) {
149
150 },
151
152 OPENSENT(false) {
153 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530154 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530155 log.debug("message received in OPENSENT state");
156 // check for OPEN message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530157 if (m.getType() != BgpType.OPEN) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530158 // When the message type is not keep alive message increment the wrong packet statistics
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530159 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR,
160 BgpErrorType.RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_STATE,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530161 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530162 log.debug("Message is not OPEN message");
163 } else {
164 log.debug("Sending keep alive message in OPENSENT state");
165 h.bgpPacketStats.addInPacket();
166
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530167 BgpOpenMsg pOpenmsg = (BgpOpenMsg) m;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530168 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530169
170 // validate capabilities and open msg
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530171 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530172 if (h.connectionCollisionDetection(BgpPeerCfg.State.OPENCONFIRM,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530173 h.peerIdentifier, h.peerAddr)) {
174 h.channel.close();
175 return;
176 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530177 log.debug("Sending handshake OPEN message");
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530178 h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530179
180 /*
181 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
182 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
183 * received in the OPEN message
184 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530185 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530186 if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
187 h.channel.getPipeline().replace("holdTime",
188 "holdTime",
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530189 new ReadTimeoutHandler(BgpPipelineFactory.TIMER,
Shashikanth VH6de20d32015-10-09 12:04:13 +0530190 h.peerHoldTime));
191 }
192
193 log.info("Hold Time : " + h.peerHoldTime);
194
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530195 // update AS number
196 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530197 }
198
199 // Send keepalive message to peer.
200 h.sendKeepAliveMessage();
201 h.bgpPacketStats.addOutPacket();
202 h.setState(OPENCONFIRM);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530203 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.OPENCONFIRM);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530204 }
205 }
206 },
207
208 OPENWAIT(false) {
209 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530210 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530211 log.debug("Message received in OPEN WAIT State");
212
213 // check for open message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530214 if (m.getType() != BgpType.OPEN) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530215 // When the message type is not open message increment the wrong packet statistics
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530216 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR, BgpErrorType.UNSPECIFIED_ERROR,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530217 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530218 log.debug("Message is not OPEN message");
219 } else {
220 h.bgpPacketStats.addInPacket();
221
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530222 BgpOpenMsg pOpenmsg = (BgpOpenMsg) m;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530223 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530224
225 // Validate open message
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530226 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530227 if (h.connectionCollisionDetection(BgpPeerCfg.State.OPENSENT,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530228 h.peerIdentifier, h.peerAddr)) {
229 h.channel.close();
230 return;
231 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530232 log.debug("Sending handshake OPEN message");
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530233 h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530234
235 /*
236 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
237 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
238 * received in the OPEN message
239 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530240 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530241 if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
242 h.channel.getPipeline().replace("holdTime",
243 "holdTime",
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530244 new ReadTimeoutHandler(BgpPipelineFactory.TIMER,
Shashikanth VH6de20d32015-10-09 12:04:13 +0530245 h.peerHoldTime));
246 }
247
248 log.debug("Hold Time : " + h.peerHoldTime);
249
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530250 // update AS number
251 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530252
253 h.sendHandshakeOpenMessage();
254 h.bgpPacketStats.addOutPacket();
255 h.setState(OPENCONFIRM);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530256 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.OPENCONFIRM);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530257 }
258 }
259 }
260 },
261
262 OPENCONFIRM(false) {
263 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530264 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530265 log.debug("Message received in OPENCONFIRM state");
266 // check for keep alive message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530267 if (m.getType() != BgpType.KEEP_ALIVE) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530268 // When the message type is not keep alive message handle the wrong packet
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530269 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR,
270 BgpErrorType.RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530271 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530272 log.debug("Message is not KEEPALIVE message");
273 } else {
274
275 // Set the peer connected status
276 h.bgpPacketStats.addInPacket();
277 log.debug("Sending keep alive message in OPENCONFIRM state");
278
279 final InetSocketAddress inetAddress = (InetSocketAddress) h.address;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530280 h.thisbgpId = BgpId.bgpId(IpAddress.valueOf(inetAddress.getAddress()));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530281
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530282 // set session parameters
283 h.negotiatedHoldTime = (h.peerHoldTime < h.bgpconfig.getHoldTime()) ? h.peerHoldTime
284 : h.bgpconfig.getHoldTime();
285 h.sessionInfo = new BgpSessionInfoImpl(h.thisbgpId, h.bgpVersion, h.peerAsNum, h.peerHoldTime,
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530286 h.peerIdentifier, h.negotiatedHoldTime, h.isIbgpSession,
287 h.remoteBgpCapability);
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530288
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530289 h.bgpPeer = h.peerManager.getBgpPeerInstance(h.bgpController, h.sessionInfo, h.bgpPacketStats);
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530290 // set the status of bgp as connected
Shashikanth VH6de20d32015-10-09 12:04:13 +0530291 h.bgpPeer.setConnected(true);
292 h.bgpPeer.setChannel(h.channel);
293
Shashikanth VH6de20d32015-10-09 12:04:13 +0530294 /*
295 * RFC 4271, When an OPEN message is received, sends a KEEPALIVE message, If the negotiated hold
296 * time value is zero, then the HoldTimer and KeepaliveTimer are not started. A reasonable maximum
297 * time between KEEPALIVE messages would be one third of the Hold Time interval.
298 */
Shashikanth VH6de20d32015-10-09 12:04:13 +0530299
300 if (h.negotiatedHoldTime != 0) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530301 h.keepAliveTimer = new BgpKeepAliveTimer(h,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530302 (h.negotiatedHoldTime / BGP_MAX_KEEPALIVE_INTERVAL));
Shashikanth VHdae80402015-11-20 14:20:33 +0530303 } else {
304 h.sendKeepAliveMessage();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530305 }
306
307 h.bgpPacketStats.addOutPacket();
308
309 // set the state handshake completion.
310 h.setHandshakeComplete(true);
311
312 if (!h.peerManager.addConnectedPeer(h.thisbgpId, h.bgpPeer)) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530313 disconnectDuplicate(h);
314 } else {
315 h.setState(ESTABLISHED);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530316 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.ESTABLISHED);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530317 }
318 }
319 }
320 },
321
322 ESTABLISHED(true) {
323 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530324 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530325 log.debug("Message received in established state " + m.getType());
326 // dispatch the message
327 h.dispatchMessage(m);
328 }
329 };
330
331 private boolean handshakeComplete;
332
333 ChannelState(boolean handshakeComplete) {
334 this.handshakeComplete = handshakeComplete;
335 }
336
337 /**
338 * Is this a state in which the handshake has completed?
339 *
340 * @return true if the handshake is complete
341 */
342 public boolean isHandshakeComplete() {
343 return this.handshakeComplete;
344 }
345
346 /**
347 * Disconnect duplicate peer connection.
348 *
349 * @param h channel handler
350 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530351 protected void disconnectDuplicate(BgpChannelHandler h) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530352 log.error("Duplicated BGP IP or incompleted cleanup - " + "" + "disconnecting channel {}",
353 h.getPeerInfoString());
Jonathan Hart51539b82015-10-29 09:53:04 -0700354 h.duplicateBgpIdFound = Boolean.TRUE;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530355 h.channel.disconnect();
356 }
357
358 // set handshake completion status
359 public void setHandshakeComplete(boolean handshakeComplete) {
360 this.handshakeComplete = handshakeComplete;
361 }
362
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530363 void processBgpMessage(BgpChannelHandler bgpChannelHandler, BgpMessage pm)
364 throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530365 // TODO Auto-generated method stub
366 log.debug("BGP message stub");
367 }
368
369 }
370
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530371 //Stop keepalive timer
372 private void stopKeepAliveTimer() {
373 if ((keepAliveTimer != null) && (keepAliveTimer.getKeepAliveTimer() != null)) {
374 keepAliveTimer.getKeepAliveTimer().cancel();
375 }
376 }
377
Shashikanth VH6de20d32015-10-09 12:04:13 +0530378 // *************************
379 // Channel handler methods
380 // *************************
381
382 @Override
383 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
384
385 channel = e.getChannel();
386 log.info("BGP connected from {}", channel.getRemoteAddress());
387
388 address = channel.getRemoteAddress();
389 if (!(address instanceof InetSocketAddress)) {
390 throw new IOException("Invalid peer connection.");
391 }
392
Shashikanth VH97e571e2016-01-05 12:15:14 +0530393 // Connection should establish only if local ip and Autonomous system number is configured.
394 if (bgpconfig.getState() != BgpCfg.State.IP_AS_CONFIGURED) {
395 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_REJECTED, null);
396 channel.close();
397 log.info("BGP local AS and router ID not configured");
398 return;
399 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530400
401 inetAddress = (InetSocketAddress) address;
Shashikanth VHdae80402015-11-20 14:20:33 +0530402 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530403
Shashikanth VH97e571e2016-01-05 12:15:14 +0530404 // if peer is not configured disconnect session
405 if (!bgpconfig.isPeerConfigured(peerAddr)) {
406 log.debug("Peer is not configured {}", peerAddr);
407 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_REJECTED, null);
408 channel.close();
409 return;
410 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530411
412 // if connection is already established close channel
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530413 if (peerManager.isPeerConnected(BgpId.bgpId(IpAddress.valueOf(peerAddr)))) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530414 log.debug("Duplicate connection received, peer {}", peerAddr);
415 channel.close();
416 return;
417 }
418
419 if (null != channel.getPipeline().get("PassiveHandler")) {
420 log.info("BGP handle connection request from peer");
421 // Wait for open message from bgp peer
422 setState(ChannelState.OPENWAIT);
423 } else if (null != channel.getPipeline().get("ActiveHandler")) {
424 log.info("BGP handle connection response from peer");
425
426 sendHandshakeOpenMessage();
427 bgpPacketStats.addOutPacket();
428 setState(ChannelState.OPENSENT);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530429 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.OPENSENT);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530430 }
431 }
432
433 @Override
434 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
435
436 channel = e.getChannel();
437 log.info("BGP disconnected callback for bgp:{}. Cleaning up ...", getPeerInfoString());
438
439 address = channel.getRemoteAddress();
440 if (!(address instanceof InetSocketAddress)) {
441 throw new IOException("Invalid peer connection.");
442 }
443
444 inetAddress = (InetSocketAddress) address;
Shashikanth VHdae80402015-11-20 14:20:33 +0530445 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530446
447 if (thisbgpId != null) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700448 if (!duplicateBgpIdFound) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530449 // if the disconnected peer (on this ChannelHandler)
450 // was not one with a duplicate, it is safe to remove all
451 // state for it at the controller. Notice that if the disconnected
452 // peer was a duplicate-ip, calling the method below would clear
453 // all state for the original peer (with the same ip),
454 // which we obviously don't want.
455 log.debug("{}:removal called", getPeerInfoString());
456 if (bgpPeer != null) {
Shashikanth VH3fe37982015-11-30 11:50:07 +0530457 BgpPeerImpl peer = (BgpPeerImpl) bgpPeer;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530458 peerManager.removeConnectedPeer(thisbgpId);
Jonathan Hart51539b82015-10-29 09:53:04 -0700459 peer.updateLocalRibOnPeerDisconnect();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530460 }
Shashikanth VH447c6b02015-11-25 21:25:35 +0530461
462 // Retry connection if connection is lost to bgp speaker/peer
463 if ((channel != null) && (null != channel.getPipeline().get("ActiveHandler"))) {
464 BgpConnectPeerImpl connectPeer;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530465 BgpPeerCfg.State peerCfgState;
Shashikanth VH447c6b02015-11-25 21:25:35 +0530466
467 peerCfgState = bgpconfig.getPeerConnState(peerAddr);
468 // on session disconnect using configuration, do not retry
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530469 if (!peerCfgState.equals(BgpPeerCfg.State.IDLE)) {
Shashikanth VH447c6b02015-11-25 21:25:35 +0530470 log.debug("Connection reset by peer, retry, STATE:{}", peerCfgState);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530471 BgpPeerConfig peerConfig = (BgpPeerConfig) bgpconfig.displayPeers(peerAddr);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530472
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530473 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530474 connectPeer = new BgpConnectPeerImpl(bgpController, peerAddr, Controller.getBgpPortNum());
475 peerConfig.setConnectPeer(connectPeer);
476 }
477 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530478 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530479 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530480 } else {
481 // A duplicate was disconnected on this ChannelHandler,
482 // this is the same peer reconnecting, but the original state was
483 // not cleaned up - XXX check liveness of original ChannelHandler
484 log.debug("{}:duplicate found", getPeerInfoString());
Jonathan Hart51539b82015-10-29 09:53:04 -0700485 duplicateBgpIdFound = Boolean.FALSE;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530486 }
487
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530488 stopKeepAliveTimer();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530489 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530490 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530491 log.warn("No bgp ip in channelHandler registered for " + "disconnected peer {}", getPeerInfoString());
492 }
493 }
494
495 @Override
496 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
497
Priyanka B7e48cb22016-07-01 16:17:58 +0530498 log.error("[exceptionCaught]: " + e.toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530499
500 if (e.getCause() instanceof ReadTimeoutException) {
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530501 // device timeout
mohamedrahil00f6f262016-11-24 20:20:41 +0530502 bgpController.closedSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530503 log.error("Disconnecting device {} due to read timeout", getPeerInfoString());
504 sendNotification(BgpErrorType.HOLD_TIMER_EXPIRED, (byte) 0, null);
505 state = ChannelState.IDLE;
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530506 stopKeepAliveTimer();
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530507 ctx.getChannel().close();
508 return;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530509 } else if (e.getCause() instanceof ClosedChannelException) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530510 bgpController.activeSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530511 log.debug("Channel for bgp {} already closed", getPeerInfoString());
512 } else if (e.getCause() instanceof IOException) {
513 log.error("Disconnecting peer {} due to IO Error: {}", getPeerInfoString(), e.getCause().getMessage());
mohamedrahil00f6f262016-11-24 20:20:41 +0530514 bgpController.closedSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530515 if (log.isDebugEnabled()) {
516 // still print stack trace if debug is enabled
517 log.debug("StackTrace for previous Exception: ", e.getCause());
518 }
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530519 stopKeepAliveTimer();
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530520 ctx.getChannel().close();
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530521 } else if (e.getCause() instanceof BgpParseException) {
Shashikanth VHdae80402015-11-20 14:20:33 +0530522 byte[] data = new byte[] {};
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530523 BgpParseException errMsg = (BgpParseException) e.getCause();
Shashikanth VHdae80402015-11-20 14:20:33 +0530524 byte errorCode = errMsg.getErrorCode();
525 byte errorSubCode = errMsg.getErrorSubCode();
mohamedrahil00f6f262016-11-24 20:20:41 +0530526 bgpController.activeSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VHdae80402015-11-20 14:20:33 +0530527 ChannelBuffer tempCb = errMsg.getData();
528 if (tempCb != null) {
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530529 int dataLength = tempCb.readableBytes();
Shashikanth VHdae80402015-11-20 14:20:33 +0530530 data = new byte[dataLength];
531 tempCb.readBytes(data, 0, dataLength);
532 }
533 sendNotification(errorCode, errorSubCode, data);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530534 } else if (e.getCause() instanceof RejectedExecutionException) {
535 log.warn("Could not process message: queue full");
mohamedrahil00f6f262016-11-24 20:20:41 +0530536 bgpController.activeSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530537 } else {
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530538 stopKeepAliveTimer();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530539 log.error("Error while processing message from peer " + getPeerInfoString() + "state " + this.state);
mohamedrahil00f6f262016-11-24 20:20:41 +0530540 bgpController.closedSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530541 ctx.getChannel().close();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530542 }
543 }
544
545 @Override
546 public String toString() {
547 return getPeerInfoString();
548 }
549
550 @Override
551 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
552 if (e.getMessage() instanceof List) {
553 @SuppressWarnings("Unchecked")
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530554 List<BgpMessage> msglist = (List<BgpMessage>) e.getMessage();
555 for (BgpMessage pm : msglist) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530556 // Do the actual packet processing
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530557 state.processBgpMessage(this, pm);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530558 }
559 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530560 state.processBgpMessage(this, (BgpMessage) e.getMessage());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530561 }
562 }
563
Shashikanth VH447c6b02015-11-25 21:25:35 +0530564 /**
565 * Check for connection collision.
566 *
567 * @param state connection state
568 * @param peerIdentifier BGP peer identifier
569 * @param peerAddr BGP peer address
570 * @return true if bgp spreakers initiated connection
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530571 * @throws BgpParseException on error while procession collision detection
Shashikanth VH447c6b02015-11-25 21:25:35 +0530572 * @throws IOException on error while procession collision detection
573 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530574 public boolean connectionCollisionDetection(BgpPeerCfg.State state, int peerIdentifier, String peerAddr)
575 throws IOException, BgpParseException {
Shashikanth VH447c6b02015-11-25 21:25:35 +0530576 /*
577 * RFC 4271, Section 6.8, Based on the value of the BGP identifier, a convention is established for detecting
578 * which BGP connection is to be preserved when a collision occurs. The convention is to compare the BGP
579 * Identifiers of the peers involved in the collision and to retain only the connection initiated by the BGP
580 * speaker with the higher-valued BGP Identifier..
581 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530582 BgpPeerCfg.State currentState = bgpconfig.getPeerConnState(peerAddr);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530583 if (currentState.equals(state)) {
584 if (((Ip4Address.valueOf(bgpconfig.getRouterId())).compareTo(Ip4Address.valueOf(peerIdentifier))) > 0) {
585 // send notification
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530586 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_COLLISION_RESOLUTION, null);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530587 log.debug("Connection collision detected, local id: {}, peer id: {}, peer state:{}, in state:{}",
588 (Ip4Address.valueOf(bgpconfig.getRouterId())), (Ip4Address.valueOf(peerIdentifier)),
589 currentState, state);
590 return true;
591 }
592 }
593
594 return false;
595 }
596
Shashikanth VH6de20d32015-10-09 12:04:13 +0530597 // *************************
598 // Channel utility methods
599 // *************************
600 /**
601 * Set handshake status.
602 *
603 * @param handshakeComplete handshake complete status
604 */
605 public void setHandshakeComplete(boolean handshakeComplete) {
606 this.state.setHandshakeComplete(handshakeComplete);
607 }
608
609 /**
610 * Is this a state in which the handshake has completed?
611 *
612 * @return true if the handshake is complete
613 */
614 public boolean isHandshakeComplete() {
615 return state.isHandshakeComplete();
616 }
617
618 /**
619 * To handle the BGP message.
620 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530621 * @param m bgp message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530622 * @throws BgpParseException throw exception
Shashikanth VH6de20d32015-10-09 12:04:13 +0530623 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530624 private void dispatchMessage(BgpMessage m) throws BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530625 bgpPacketStats.addInPacket();
Jonathan Hart51539b82015-10-29 09:53:04 -0700626 bgpController.processBgpPacket(thisbgpId, m);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530627 }
628
629 /**
630 * Return a string describing this peer based on the already available information (ip address and/or remote
631 * socket).
632 *
633 * @return display string
634 */
635 private String getPeerInfoString() {
636 if (bgpPeer != null) {
637 return bgpPeer.toString();
638 }
639 String channelString;
640 if (channel == null || channel.getRemoteAddress() == null) {
641 channelString = "?";
642 } else {
643 channelString = channel.getRemoteAddress().toString();
644 }
645 String bgpIpString;
646 // TODO: implement functionality to get bgp id string
647 bgpIpString = "?";
648 return String.format("[%s BGP-IP[%s]]", channelString, bgpIpString);
649 }
650
651 /**
652 * Update the channels state. Only called from the state machine. TODO: enforce restricted state transitions
653 *
654 * @param state
655 */
656 private void setState(ChannelState state) {
657 this.state = state;
658 }
659
660 /**
661 * get packet statistics.
662 *
663 * @return packet statistics
664 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530665 public BgpPacketStatsImpl getBgpPacketStats() {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530666 return bgpPacketStats;
667 }
668
669 /**
670 * Send handshake open message to the peer.
671 *
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530672 * @throws IOException, BgpParseException
Shashikanth VH6de20d32015-10-09 12:04:13 +0530673 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530674 private void sendHandshakeOpenMessage() throws IOException, BgpParseException {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530675 int bgpId;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530676 BgpCfg.FlowSpec flowSpec = bgpconfig.flowSpecCapability();
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530677 boolean flowSpecStatus = false;
678 boolean vpnFlowSpecStatus = false;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530679
Shashikanth VH97e571e2016-01-05 12:15:14 +0530680 bgpId = Ip4Address.valueOf(bgpconfig.getRouterId()).toInt();
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530681
682 if (flowSpec == BgpCfg.FlowSpec.IPV4) {
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530683 flowSpecStatus = true;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530684 } else if (flowSpec == BgpCfg.FlowSpec.VPNV4) {
685 vpnFlowSpecStatus = true;
686 } else if (flowSpec == BgpCfg.FlowSpec.IPV4_VPNV4) {
687 flowSpecStatus = true;
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530688 vpnFlowSpecStatus = true;
689 }
690
Shashikanth VH97e571e2016-01-05 12:15:14 +0530691 BgpMessage msg = factory4.openMessageBuilder().setAsNumber((short) bgpconfig.getAsNumber())
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530692 .setHoldTime(bgpconfig.getHoldTime()).setBgpId(bgpId)
693 .setLsCapabilityTlv(bgpconfig.getLsCapability())
694 .setLargeAsCapabilityTlv(bgpconfig.getLargeASCapability())
695 .setFlowSpecCapabilityTlv(flowSpecStatus)
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530696 .setVpnFlowSpecCapabilityTlv(vpnFlowSpecStatus)
697 .setFlowSpecRpdCapabilityTlv(bgpconfig.flowSpecRpdCapability()).build();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530698 log.debug("Sending open message to {}", channel.getRemoteAddress());
699 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530700
701 }
702
703 /**
Shashikanth VHdae80402015-11-20 14:20:33 +0530704 * Send notification message to peer.
705 *
706 * @param errorCode error code send in notification
707 * @param errorSubCode sub error code send in notification
708 * @param data data to send in notification
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530709 * @throws IOException, BgpParseException while building message
Shashikanth VHdae80402015-11-20 14:20:33 +0530710 */
711 private void sendNotification(byte errorCode, byte errorSubCode, byte[] data)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530712 throws IOException, BgpParseException {
713 BgpMessage msg = factory4.notificationMessageBuilder().setErrorCode(errorCode)
Shashikanth VH447c6b02015-11-25 21:25:35 +0530714 .setErrorSubCode(errorSubCode).setData(data).build();
Shashikanth VHdae80402015-11-20 14:20:33 +0530715 log.debug("Sending notification message to {}", channel.getRemoteAddress());
716 channel.write(Collections.singletonList(msg));
717 }
718
719 /**
Shashikanth VH6de20d32015-10-09 12:04:13 +0530720 * Send keep alive message.
721 *
722 * @throws IOException when channel is disconnected
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530723 * @throws BgpParseException while building keep alive message
Shashikanth VH6de20d32015-10-09 12:04:13 +0530724 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530725 synchronized void sendKeepAliveMessage() throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530726
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530727 BgpMessage msg = factory4.keepaliveMessageBuilder().build();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530728 log.debug("Sending keepalive message to {}", channel.getRemoteAddress());
729 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530730 }
731
732 /**
Shashikanth VH6de20d32015-10-09 12:04:13 +0530733 * Process unknown BGP message received.
734 *
Shashikanth VHdae80402015-11-20 14:20:33 +0530735 * @param errorCode error code
736 * @param errorSubCode error sub code
737 * @param data message type
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530738 * @throws BgpParseException while processing error messsage
Shashikanth VHdae80402015-11-20 14:20:33 +0530739 * @throws IOException while processing error message
Shashikanth VH6de20d32015-10-09 12:04:13 +0530740 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530741 public void processUnknownMsg(byte errorCode, byte errorSubCode, byte data) throws BgpParseException, IOException {
mohamedrahil00f6f262016-11-24 20:20:41 +0530742 log.debug("Unknown message received");
Shashikanth VHdae80402015-11-20 14:20:33 +0530743 byte[] byteArray = new byte[1];
744 byteArray[0] = data;
745 sendNotification(errorCode, errorSubCode, byteArray);
746 channel.close();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530747 }
748
749 /**
Vidyashree Ramaee293252015-11-18 17:00:11 +0530750 * BGP open message validation.
Shashikanth VH6de20d32015-10-09 12:04:13 +0530751 *
752 * @param h channel handler
Vidyashree Ramaee293252015-11-18 17:00:11 +0530753 * @param openMsg open message
754 * @return true if valid message, otherwise false
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530755 * @throws BgpParseException throw exception
Shashikanth VH6de20d32015-10-09 12:04:13 +0530756 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530757 public boolean openMsgValidation(BgpChannelHandler h, BgpOpenMsg openMsg) throws BgpParseException {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530758 boolean result;
759
760 // Validate BGP ID
761 result = bgpIdValidation(openMsg);
762 if (!result) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530763 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_BGP_IDENTIFIER, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530764 }
765
Shashikanth VH97e571e2016-01-05 12:15:14 +0530766 // Validate AS number
767 result = asNumberValidation(h, openMsg);
768 if (!result) {
769 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
770 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530771
772 // Validate hold timer
773 if ((openMsg.getHoldTime() != 0) && (openMsg.getHoldTime() < BGP_MIN_HOLDTIME)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530774 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNACCEPTABLE_HOLD_TIME, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530775 }
776
777 // Validate capabilities
778 result = capabilityValidation(h, openMsg);
779 return result;
780 }
781
782 /**
783 * Capability Validation.
784 *
785 * @param h channel handler
786 * @param openmsg open message
787 * @return success or failure
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530788 * @throws BgpParseException
Vidyashree Ramaee293252015-11-18 17:00:11 +0530789 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530790 private boolean capabilityValidation(BgpChannelHandler h, BgpOpenMsg openmsg) throws BgpParseException {
mohamedrahil00f6f262016-11-24 20:20:41 +0530791 log.debug("capability validation");
Vidyashree Ramaee293252015-11-18 17:00:11 +0530792
Vidyashree Ramaee293252015-11-18 17:00:11 +0530793 boolean isFourOctetCapabilityExits = false;
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530794 boolean isRpdCapabilityExits = false;
Vidyashree Ramaee293252015-11-18 17:00:11 +0530795 int capAsNum = 0;
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530796 byte sendReceive = 0;
Vidyashree Ramaee293252015-11-18 17:00:11 +0530797
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530798 List<BgpValueType> capabilityTlv = openmsg.getCapabilityTlv();
799 ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530800 List<BgpValueType> unSupportedCapabilityTlv = new CopyOnWriteArrayList<BgpValueType>();
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530801 ListIterator<BgpValueType> unSupportedCaplistIterator = unSupportedCapabilityTlv.listIterator();
802 BgpValueType tempTlv;
Vidyashree Ramaee293252015-11-18 17:00:11 +0530803 boolean isLargeAsCapabilityCfg = h.bgpconfig.getLargeASCapability();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530804 boolean isFlowSpecRpdCapabilityCfg = h.bgpconfig.flowSpecRpdCapability();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530805 boolean isLsCapabilityCfg = h.bgpconfig.getLsCapability();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530806 boolean isFlowSpecIpv4CapabilityCfg = false;
807 boolean isFlowSpecVpnv4CapabilityCfg = false;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530808 MultiProtocolExtnCapabilityTlv tempCapability;
809 boolean isMultiProtocolLsCapability = false;
810 boolean isMultiProtocolFlowSpecCapability = false;
811 boolean isMultiProtocolVpnFlowSpecCapability = false;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530812 BgpCfg.FlowSpec flowSpec = h.bgpconfig.flowSpecCapability();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530813
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530814 if (flowSpec == BgpCfg.FlowSpec.IPV4) {
815 isFlowSpecIpv4CapabilityCfg = true;
816 } else if (flowSpec == BgpCfg.FlowSpec.VPNV4) {
817 isFlowSpecVpnv4CapabilityCfg = true;
818 } else if (flowSpec == BgpCfg.FlowSpec.IPV4_VPNV4) {
819 isFlowSpecIpv4CapabilityCfg = true;
820 isFlowSpecVpnv4CapabilityCfg = true;
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530821 }
822
Vidyashree Ramaee293252015-11-18 17:00:11 +0530823 while (listIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530824 BgpValueType tlv = listIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530825 if (tlv.getType() == MULTI_PROTOCOL_EXTN_CAPA_TYPE) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530826 tempCapability = (MultiProtocolExtnCapabilityTlv) tlv;
827 if (Constants.SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
828 isMultiProtocolFlowSpecCapability = true;
829 }
830
831 if (Constants.VPN_SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
832 isMultiProtocolVpnFlowSpecCapability = true;
833 }
834
835 if (SAFI == tempCapability.getSafi()) {
836 isMultiProtocolLsCapability = true;
837 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530838 }
839 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
840 isFourOctetCapabilityExits = true;
841 capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
842 }
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530843
844 if (tlv.getType() == RpdCapabilityTlv.TYPE) {
845 isRpdCapabilityExits = true;
846 sendReceive = ((RpdCapabilityTlv) tlv).sendReceive();
847 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530848 }
849
850 if (isFourOctetCapabilityExits) {
851 if (capAsNum > MAX_AS2_NUM) {
852 if (openmsg.getAsNumber() != AS_TRANS) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530853 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530854 }
855 } else {
856 if (capAsNum != openmsg.getAsNumber()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530857 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530858 }
859 }
860 }
861
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530862 if (isRpdCapabilityExits) {
863 if (sendReceive > 2) {
864 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNSUPPORTED_CAPABILITY, null);
865 }
866 }
867
Vidyashree Ramaee293252015-11-18 17:00:11 +0530868 if ((isLsCapabilityCfg)) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530869 if (!isMultiProtocolLsCapability) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530870 tempTlv = new MultiProtocolExtnCapabilityTlv(AFI, RES, SAFI);
871 unSupportedCapabilityTlv.add(tempTlv);
872 }
873 }
874
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530875 if (isFlowSpecIpv4CapabilityCfg) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530876 if (!isMultiProtocolFlowSpecCapability) {
877 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
878 RES, Constants.SAFI_FLOWSPEC_VALUE);
879 unSupportedCapabilityTlv.add(tempTlv);
880 }
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530881 }
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530882
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530883 if (isFlowSpecVpnv4CapabilityCfg) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530884 if (!isMultiProtocolVpnFlowSpecCapability) {
885 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
886 RES, Constants.VPN_SAFI_FLOWSPEC_VALUE);
887 unSupportedCapabilityTlv.add(tempTlv);
888 }
889 }
890
Vidyashree Ramaee293252015-11-18 17:00:11 +0530891 if ((isLargeAsCapabilityCfg)) {
892 if (!isFourOctetCapabilityExits) {
893 tempTlv = new FourOctetAsNumCapabilityTlv(h.bgpconfig.getAsNumber());
894 unSupportedCapabilityTlv.add(tempTlv);
895 }
896 }
897
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530898 if ((isFlowSpecRpdCapabilityCfg)) {
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530899 if (!isRpdCapabilityExits) {
900 tempTlv = new RpdCapabilityTlv(Constants.RPD_CAPABILITY_SEND_VALUE);
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530901 unSupportedCapabilityTlv.add(tempTlv);
902 }
903 }
904
905 if (unSupportedCapabilityTlv.size() == MAX_UNSUPPORTED_CAPABILITY) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530906 ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
907 while (unSupportedCaplistIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530908 BgpValueType tlv = unSupportedCaplistIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530909 tlv.write(buffer);
910 }
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530911 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNSUPPORTED_CAPABILITY, buffer);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530912 } else {
913 return true;
914 }
915 }
916
917 /**
918 * AS Number Validation.
919 *
920 * @param h channel Handler
921 * @param openMsg open message
922 * @return true or false
923 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530924 private boolean asNumberValidation(BgpChannelHandler h, BgpOpenMsg openMsg) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530925 log.debug("AS number validation");
Vidyashree Ramaee293252015-11-18 17:00:11 +0530926
927 int capAsNum = 0;
928 boolean isFourOctetCapabilityExits = false;
929
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530930 BgpPeerCfg peerCfg = h.bgpconfig.displayPeers(peerAddr);
931 List<BgpValueType> capabilityTlv = openMsg.getCapabilityTlv();
932 ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530933
934 while (listIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530935 BgpValueType tlv = listIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530936 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
937 isFourOctetCapabilityExits = true;
938 capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
939 }
940 }
941
942 if (peerCfg.getAsNumber() > MAX_AS2_NUM) {
943 if (openMsg.getAsNumber() != AS_TRANS) {
944 return false;
945 }
946
947 if (!isFourOctetCapabilityExits) {
948 return false;
949 }
950
951 if (peerCfg.getAsNumber() != capAsNum) {
952 return false;
953 }
954
955 isIbgpSession = peerCfg.getIsIBgp();
956 if (isIbgpSession) {
957 // IBGP - AS number should be same for Peer and local if it is IBGP
958 if (h.bgpconfig.getAsNumber() != capAsNum) {
959 return false;
960 }
961 }
962 } else {
963
964 if (openMsg.getAsNumber() != peerCfg.getAsNumber()) {
965 return false;
966 }
967
968 if (isFourOctetCapabilityExits) {
969 if (capAsNum != peerCfg.getAsNumber()) {
970 return false;
971 }
972 }
973
974 isIbgpSession = peerCfg.getIsIBgp();
975 if (isIbgpSession) {
976 // IBGP - AS number should be same for Peer and local if it is IBGP
977 if (openMsg.getAsNumber() != h.bgpconfig.getAsNumber()) {
978 return false;
979 }
980 }
981 }
982 return true;
983 }
984
985 /**
986 * Validates BGP ID.
987 *
988 * @param openMsg open message
989 * @return true or false
990 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530991 private boolean bgpIdValidation(BgpOpenMsg openMsg) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530992 String openMsgBgpId = Ip4Address.valueOf(openMsg.getBgpId()).toString();
993
994 InetAddress ipAddress;
995 try {
996 ipAddress = InetAddress.getByName(openMsgBgpId);
997 if (ipAddress.isMulticastAddress()) {
998 return false;
999 }
1000 } catch (UnknownHostException e) {
1001 log.debug("InetAddress convertion failed");
1002 }
Shashikanth VH6de20d32015-10-09 12:04:13 +05301003 return true;
1004 }
1005}