blob: 036d8e6e4374fdd844ad9c95f5deb8588de45500 [file] [log] [blame]
Satish Ke107e662015-09-21 19:00:17 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
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 VH215dd812017-03-10 17:44:09 +053027import org.jboss.netty.util.HashedWheelTimer;
28import org.jboss.netty.util.Timeout;
29import org.jboss.netty.util.Timer;
30import org.jboss.netty.util.TimerTask;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053031import org.onlab.packet.Ip4Address;
Shashikanth VH6de20d32015-10-09 12:04:13 +053032import org.onlab.packet.IpAddress;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053033import org.onosproject.bgp.controller.BgpCfg;
34import org.onosproject.bgp.controller.BgpController;
35import org.onosproject.bgp.controller.BgpId;
36import org.onosproject.bgp.controller.BgpPeer;
37import org.onosproject.bgp.controller.BgpPeerCfg;
38import org.onosproject.bgp.controller.impl.BgpControllerImpl.BgpPeerManagerImpl;
39import org.onosproject.bgpio.exceptions.BgpParseException;
40import org.onosproject.bgpio.protocol.BgpFactory;
41import org.onosproject.bgpio.protocol.BgpMessage;
42import org.onosproject.bgpio.protocol.BgpOpenMsg;
43import org.onosproject.bgpio.protocol.BgpType;
44import org.onosproject.bgpio.protocol.BgpVersion;
45import org.onosproject.bgpio.types.BgpErrorType;
46import org.onosproject.bgpio.types.BgpValueType;
Vidyashree Ramaee293252015-11-18 17:00:11 +053047import org.onosproject.bgpio.types.FourOctetAsNumCapabilityTlv;
48import org.onosproject.bgpio.types.MultiProtocolExtnCapabilityTlv;
Shashikanth VHb58cfd52016-04-21 16:45:50 +053049import org.onosproject.bgpio.types.RpdCapabilityTlv;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +053050import org.onosproject.bgpio.util.Constants;
Shashikanth VH6de20d32015-10-09 12:04:13 +053051import org.slf4j.Logger;
52import org.slf4j.LoggerFactory;
Satish Ke107e662015-09-21 19:00:17 +053053
Jonathan Hart51539b82015-10-29 09:53:04 -070054import java.io.IOException;
55import java.net.InetAddress;
56import java.net.InetSocketAddress;
57import java.net.SocketAddress;
58import java.net.UnknownHostException;
59import java.nio.channels.ClosedChannelException;
60import java.util.Collections;
Jonathan Hart51539b82015-10-29 09:53:04 -070061import java.util.List;
62import java.util.ListIterator;
Shashikanth VHb650bfa2016-04-18 12:54:03 +053063import java.util.concurrent.CopyOnWriteArrayList;
Jonathan Hart51539b82015-10-29 09:53:04 -070064import java.util.concurrent.RejectedExecutionException;
Shashikanth VH215dd812017-03-10 17:44:09 +053065import java.util.concurrent.TimeUnit;
66
67import static org.onlab.util.Tools.groupedThreads;
Jonathan Hart51539b82015-10-29 09:53:04 -070068
Satish Ke107e662015-09-21 19:00:17 +053069/**
70 * Channel handler deals with the bgp peer connection and dispatches messages from peer to the appropriate locations.
71 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053072class BgpChannelHandler extends IdleStateAwareChannelHandler {
Satish Ke107e662015-09-21 19:00:17 +053073
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053074 private static final Logger log = LoggerFactory.getLogger(BgpChannelHandler.class);
Vidyashree Ramaee293252015-11-18 17:00:11 +053075 static final int BGP_MIN_HOLDTIME = 3;
Shashikanth VH6de20d32015-10-09 12:04:13 +053076 static final int BGP_MAX_KEEPALIVE_INTERVAL = 3;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053077 private BgpPeer bgpPeer;
78 private BgpId thisbgpId;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053079 private Channel channel;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053080 private BgpKeepAliveTimer keepAliveTimer = null;
Shashikanth VH215dd812017-03-10 17:44:09 +053081 private short minHoldTime = 0;
Shashikanth VH6de20d32015-10-09 12:04:13 +053082 private short peerHoldTime = 0;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053083 private long peerAsNum;
Shashikanth VH6de20d32015-10-09 12:04:13 +053084 private int peerIdentifier;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053085 private BgpPacketStatsImpl bgpPacketStats;
Shashikanth VH6de20d32015-10-09 12:04:13 +053086 static final int MAX_WRONG_COUNT_PACKET = 5;
Vidyashree Ramaee293252015-11-18 17:00:11 +053087 static final byte MULTI_PROTOCOL_EXTN_CAPA_TYPE = 1;
88 static final byte FOUR_OCTET_AS_NUM_CAPA_TYPE = 65;
89 static final int AS_TRANS = 23456;
90 static final int MAX_AS2_NUM = 65535;
91 static final short AFI = 16388;
92 static final byte RES = 0;
93 static final byte SAFI = 71;
Shashikanth VHb650bfa2016-04-18 12:54:03 +053094 static final byte MAX_UNSUPPORTED_CAPABILITY = 5;
Shashikanth VH6de20d32015-10-09 12:04:13 +053095
96 // State needs to be volatile because the HandshakeTimeoutHandler
97 // needs to check if the handshake is complete
98 private volatile ChannelState state;
99
100 // When a bgp peer with a ip addresss is found (i.e we already have a
101 // connected peer with the same ip), the new peer is immediately
102 // disconnected. At that point netty callsback channelDisconnected() which
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530103 // proceeds to cleaup peer state - we need to ensure that it does not
104 // cleanup
Shashikanth VH6de20d32015-10-09 12:04:13 +0530105 // peer state for the older (still connected) peer
Jonathan Hart51539b82015-10-29 09:53:04 -0700106 private volatile Boolean duplicateBgpIdFound;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530107 // Indicates the bgp version used by this bgp peer
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530108 protected BgpVersion bgpVersion;
109 private BgpController bgpController;
110 protected BgpFactory factory4;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530111 private boolean isIbgpSession;
112 private BgpSessionInfoImpl sessionInfo;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530113 private BgpPeerManagerImpl peerManager;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530114 private InetSocketAddress inetAddress;
115 private IpAddress ipAddress;
116 private SocketAddress address;
117 private String peerAddr;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530118 private BgpCfg bgpconfig;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530119 List<BgpValueType> remoteBgpCapability;
Shashikanth VH215dd812017-03-10 17:44:09 +0530120 private Timer timer = new HashedWheelTimer(groupedThreads("BgpChannel", "timer-%d", log));
121 private volatile Timeout holdTimerTimeout;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530122
Satish Ke107e662015-09-21 19:00:17 +0530123 /**
124 * Create a new unconnected BGPChannelHandler.
125 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530126 * @param bgpController bgp controller
Satish Ke107e662015-09-21 19:00:17 +0530127 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530128 BgpChannelHandler(BgpController bgpController) {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530129 this.bgpController = bgpController;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530130 this.peerManager = (BgpPeerManagerImpl) bgpController.peerManager();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530131 this.state = ChannelState.IDLE;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530132 this.factory4 = Controller.getBgpMessageFactory4();
Jonathan Hart51539b82015-10-29 09:53:04 -0700133 this.duplicateBgpIdFound = Boolean.FALSE;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530134 this.bgpPacketStats = new BgpPacketStatsImpl();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530135 this.bgpconfig = bgpController.getConfig();
Satish Ke107e662015-09-21 19:00:17 +0530136 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530137
138 // To disconnect peer session.
139 public void disconnectPeer() {
140 bgpPeer.disconnectPeer();
141 }
142
143 // *************************
144 // Channel State Machine
145 // *************************
146
147 /**
148 * The state machine for handling the peer/channel state. All state transitions should happen from within the state
149 * machine (and not from other parts of the code)
150 */
151 enum ChannelState {
152 /**
153 * Initial state before channel is connected.
154 */
155 IDLE(false) {
156
157 },
158
159 OPENSENT(false) {
160 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530161 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530162 log.debug("message received in OPENSENT state");
163 // check for OPEN message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530164 if (m.getType() != BgpType.OPEN) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530165 // When the message type is not keep alive message increment the wrong packet statistics
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530166 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR,
167 BgpErrorType.RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_STATE,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530168 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530169 log.debug("Message is not OPEN message");
170 } else {
171 log.debug("Sending keep alive message in OPENSENT state");
172 h.bgpPacketStats.addInPacket();
173
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530174 BgpOpenMsg pOpenmsg = (BgpOpenMsg) m;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530175 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530176
177 // validate capabilities and open msg
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530178 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530179 if (h.connectionCollisionDetection(BgpPeerCfg.State.OPENCONFIRM,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530180 h.peerIdentifier, h.peerAddr)) {
181 h.channel.close();
182 return;
183 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530184 log.debug("Sending handshake OPEN message");
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530185 h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530186
187 /*
188 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
189 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
190 * received in the OPEN message
191 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530192 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH215dd812017-03-10 17:44:09 +0530193 h.minHoldTime = (short) Math.min(h.bgpconfig.getHoldTime(), pOpenmsg.getHoldTime());
194 h.restartHoldTimeoutTimer();
195 log.info("Hold Time : " + h.minHoldTime);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530196
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530197 // update AS number
198 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530199 }
200
201 // Send keepalive message to peer.
202 h.sendKeepAliveMessage();
203 h.bgpPacketStats.addOutPacket();
204 h.setState(OPENCONFIRM);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530205 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.OPENCONFIRM);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530206 }
207 }
208 },
209
210 OPENWAIT(false) {
211 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530212 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530213 log.debug("Message received in OPEN WAIT State");
214
215 // check for open message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530216 if (m.getType() != BgpType.OPEN) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530217 // When the message type is not open message increment the wrong packet statistics
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530218 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR, BgpErrorType.UNSPECIFIED_ERROR,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530219 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530220 log.debug("Message is not OPEN message");
221 } else {
222 h.bgpPacketStats.addInPacket();
223
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530224 BgpOpenMsg pOpenmsg = (BgpOpenMsg) m;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530225 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530226
227 // Validate open message
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530228 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530229 if (h.connectionCollisionDetection(BgpPeerCfg.State.OPENSENT,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530230 h.peerIdentifier, h.peerAddr)) {
231 h.channel.close();
232 return;
233 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530234 log.debug("Sending handshake OPEN message");
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530235 h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530236
237 /*
238 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
239 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
240 * received in the OPEN message
241 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530242 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH215dd812017-03-10 17:44:09 +0530243 h.minHoldTime = (short) Math.min(h.bgpconfig.getHoldTime(), pOpenmsg.getHoldTime());
244 h.restartHoldTimeoutTimer();
245 log.debug("Hold Time : " + h.minHoldTime);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530246
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530247 // update AS number
248 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530249
250 h.sendHandshakeOpenMessage();
251 h.bgpPacketStats.addOutPacket();
252 h.setState(OPENCONFIRM);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530253 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.OPENCONFIRM);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530254 }
255 }
256 }
257 },
258
259 OPENCONFIRM(false) {
260 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530261 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530262 log.debug("Message received in OPENCONFIRM state");
263 // check for keep alive message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530264 if (m.getType() != BgpType.KEEP_ALIVE) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530265 // When the message type is not keep alive message handle the wrong packet
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530266 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR,
267 BgpErrorType.RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530268 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530269 log.debug("Message is not KEEPALIVE message");
270 } else {
271
272 // Set the peer connected status
273 h.bgpPacketStats.addInPacket();
274 log.debug("Sending keep alive message in OPENCONFIRM state");
275
276 final InetSocketAddress inetAddress = (InetSocketAddress) h.address;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530277 h.thisbgpId = BgpId.bgpId(IpAddress.valueOf(inetAddress.getAddress()));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530278
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530279 h.sessionInfo = new BgpSessionInfoImpl(h.thisbgpId, h.bgpVersion, h.peerAsNum, h.peerHoldTime,
Shashikanth VH215dd812017-03-10 17:44:09 +0530280 h.peerIdentifier, h.minHoldTime, h.isIbgpSession,
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530281 h.remoteBgpCapability);
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530282
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530283 h.bgpPeer = h.peerManager.getBgpPeerInstance(h.bgpController, h.sessionInfo, h.bgpPacketStats);
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530284 // set the status of bgp as connected
Shashikanth VH6de20d32015-10-09 12:04:13 +0530285 h.bgpPeer.setConnected(true);
286 h.bgpPeer.setChannel(h.channel);
287
Shashikanth VH6de20d32015-10-09 12:04:13 +0530288 /*
289 * RFC 4271, When an OPEN message is received, sends a KEEPALIVE message, If the negotiated hold
290 * time value is zero, then the HoldTimer and KeepaliveTimer are not started. A reasonable maximum
291 * time between KEEPALIVE messages would be one third of the Hold Time interval.
292 */
Shashikanth VH6de20d32015-10-09 12:04:13 +0530293
Shashikanth VH215dd812017-03-10 17:44:09 +0530294 if (h.minHoldTime != 0) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530295 h.keepAliveTimer = new BgpKeepAliveTimer(h,
Shashikanth VH215dd812017-03-10 17:44:09 +0530296 (h.minHoldTime / BGP_MAX_KEEPALIVE_INTERVAL));
Shashikanth VHdae80402015-11-20 14:20:33 +0530297 } else {
298 h.sendKeepAliveMessage();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530299 }
300
301 h.bgpPacketStats.addOutPacket();
302
303 // set the state handshake completion.
304 h.setHandshakeComplete(true);
Shashikanth VH215dd812017-03-10 17:44:09 +0530305 h.restartHoldTimeoutTimer();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530306
307 if (!h.peerManager.addConnectedPeer(h.thisbgpId, h.bgpPeer)) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530308 disconnectDuplicate(h);
309 } else {
310 h.setState(ESTABLISHED);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530311 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.ESTABLISHED);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530312 }
313 }
314 }
315 },
316
317 ESTABLISHED(true) {
318 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530319 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530320 log.debug("Message received in established state " + m.getType());
321 // dispatch the message
Shashikanth VH215dd812017-03-10 17:44:09 +0530322 h.restartHoldTimeoutTimer();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530323 h.dispatchMessage(m);
324 }
325 };
326
327 private boolean handshakeComplete;
328
329 ChannelState(boolean handshakeComplete) {
330 this.handshakeComplete = handshakeComplete;
331 }
332
333 /**
334 * Is this a state in which the handshake has completed?
335 *
336 * @return true if the handshake is complete
337 */
338 public boolean isHandshakeComplete() {
339 return this.handshakeComplete;
340 }
341
342 /**
343 * Disconnect duplicate peer connection.
344 *
345 * @param h channel handler
346 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530347 protected void disconnectDuplicate(BgpChannelHandler h) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530348 log.error("Duplicated BGP IP or incompleted cleanup - " + "" + "disconnecting channel {}",
349 h.getPeerInfoString());
Jonathan Hart51539b82015-10-29 09:53:04 -0700350 h.duplicateBgpIdFound = Boolean.TRUE;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530351 h.channel.disconnect();
352 }
353
354 // set handshake completion status
355 public void setHandshakeComplete(boolean handshakeComplete) {
356 this.handshakeComplete = handshakeComplete;
357 }
358
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530359 void processBgpMessage(BgpChannelHandler bgpChannelHandler, BgpMessage pm)
360 throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530361 // TODO Auto-generated method stub
362 log.debug("BGP message stub");
363 }
364
365 }
366
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530367 //Stop keepalive timer
368 private void stopKeepAliveTimer() {
369 if ((keepAliveTimer != null) && (keepAliveTimer.getKeepAliveTimer() != null)) {
370 keepAliveTimer.getKeepAliveTimer().cancel();
371 }
372 }
373
Shashikanth VH215dd812017-03-10 17:44:09 +0530374 //Stop hold timer
375 private void stopSessionTimers() {
376 if ((keepAliveTimer != null) && (keepAliveTimer.getKeepAliveTimer() != null)) {
377 keepAliveTimer.getKeepAliveTimer().cancel();
378 }
379
380 if (holdTimerTimeout != null) {
381 holdTimerTimeout.cancel();
382 }
383 }
384
Shashikanth VH6de20d32015-10-09 12:04:13 +0530385 // *************************
386 // Channel handler methods
387 // *************************
388
389 @Override
390 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
391
392 channel = e.getChannel();
393 log.info("BGP connected from {}", channel.getRemoteAddress());
394
395 address = channel.getRemoteAddress();
396 if (!(address instanceof InetSocketAddress)) {
397 throw new IOException("Invalid peer connection.");
398 }
399
Shashikanth VH97e571e2016-01-05 12:15:14 +0530400 // Connection should establish only if local ip and Autonomous system number is configured.
401 if (bgpconfig.getState() != BgpCfg.State.IP_AS_CONFIGURED) {
402 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_REJECTED, null);
403 channel.close();
404 log.info("BGP local AS and router ID not configured");
405 return;
406 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530407
408 inetAddress = (InetSocketAddress) address;
Shashikanth VHdae80402015-11-20 14:20:33 +0530409 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530410
Shashikanth VH97e571e2016-01-05 12:15:14 +0530411 // if peer is not configured disconnect session
412 if (!bgpconfig.isPeerConfigured(peerAddr)) {
413 log.debug("Peer is not configured {}", peerAddr);
414 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_REJECTED, null);
415 channel.close();
416 return;
417 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530418
419 // if connection is already established close channel
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530420 if (peerManager.isPeerConnected(BgpId.bgpId(IpAddress.valueOf(peerAddr)))) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530421 log.debug("Duplicate connection received, peer {}", peerAddr);
422 channel.close();
423 return;
424 }
425
426 if (null != channel.getPipeline().get("PassiveHandler")) {
427 log.info("BGP handle connection request from peer");
428 // Wait for open message from bgp peer
429 setState(ChannelState.OPENWAIT);
430 } else if (null != channel.getPipeline().get("ActiveHandler")) {
431 log.info("BGP handle connection response from peer");
432
433 sendHandshakeOpenMessage();
434 bgpPacketStats.addOutPacket();
435 setState(ChannelState.OPENSENT);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530436 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.OPENSENT);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530437 }
438 }
439
440 @Override
441 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
442
443 channel = e.getChannel();
444 log.info("BGP disconnected callback for bgp:{}. Cleaning up ...", getPeerInfoString());
445
446 address = channel.getRemoteAddress();
447 if (!(address instanceof InetSocketAddress)) {
448 throw new IOException("Invalid peer connection.");
449 }
450
451 inetAddress = (InetSocketAddress) address;
Shashikanth VHdae80402015-11-20 14:20:33 +0530452 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530453
454 if (thisbgpId != null) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700455 if (!duplicateBgpIdFound) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530456 // if the disconnected peer (on this ChannelHandler)
457 // was not one with a duplicate, it is safe to remove all
458 // state for it at the controller. Notice that if the disconnected
459 // peer was a duplicate-ip, calling the method below would clear
460 // all state for the original peer (with the same ip),
461 // which we obviously don't want.
462 log.debug("{}:removal called", getPeerInfoString());
463 if (bgpPeer != null) {
Shashikanth VH3fe37982015-11-30 11:50:07 +0530464 BgpPeerImpl peer = (BgpPeerImpl) bgpPeer;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530465 peerManager.removeConnectedPeer(thisbgpId);
Jonathan Hart51539b82015-10-29 09:53:04 -0700466 peer.updateLocalRibOnPeerDisconnect();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530467 }
Shashikanth VH447c6b02015-11-25 21:25:35 +0530468
469 // Retry connection if connection is lost to bgp speaker/peer
470 if ((channel != null) && (null != channel.getPipeline().get("ActiveHandler"))) {
471 BgpConnectPeerImpl connectPeer;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530472 BgpPeerCfg.State peerCfgState;
Shashikanth VH447c6b02015-11-25 21:25:35 +0530473
474 peerCfgState = bgpconfig.getPeerConnState(peerAddr);
475 // on session disconnect using configuration, do not retry
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530476 if (!peerCfgState.equals(BgpPeerCfg.State.IDLE)) {
Shashikanth VH447c6b02015-11-25 21:25:35 +0530477 log.debug("Connection reset by peer, retry, STATE:{}", peerCfgState);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530478 BgpPeerConfig peerConfig = (BgpPeerConfig) bgpconfig.displayPeers(peerAddr);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530479
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530480 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530481 connectPeer = new BgpConnectPeerImpl(bgpController, peerAddr, Controller.getBgpPortNum());
482 peerConfig.setConnectPeer(connectPeer);
483 }
484 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530485 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530486 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530487 } else {
488 // A duplicate was disconnected on this ChannelHandler,
489 // this is the same peer reconnecting, but the original state was
490 // not cleaned up - XXX check liveness of original ChannelHandler
491 log.debug("{}:duplicate found", getPeerInfoString());
Jonathan Hart51539b82015-10-29 09:53:04 -0700492 duplicateBgpIdFound = Boolean.FALSE;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530493 }
494
Shashikanth VH215dd812017-03-10 17:44:09 +0530495 stopSessionTimers();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530496 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530497 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530498 log.warn("No bgp ip in channelHandler registered for " + "disconnected peer {}", getPeerInfoString());
499 }
500 }
501
502 @Override
503 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
504
Priyanka B7e48cb22016-07-01 16:17:58 +0530505 log.error("[exceptionCaught]: " + e.toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530506
Shashikanth VH215dd812017-03-10 17:44:09 +0530507 if (e.getCause() instanceof ClosedChannelException) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530508 bgpController.activeSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530509 log.debug("Channel for bgp {} already closed", getPeerInfoString());
510 } else if (e.getCause() instanceof IOException) {
511 log.error("Disconnecting peer {} due to IO Error: {}", getPeerInfoString(), e.getCause().getMessage());
mohamedrahil00f6f262016-11-24 20:20:41 +0530512 bgpController.closedSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530513 if (log.isDebugEnabled()) {
514 // still print stack trace if debug is enabled
515 log.debug("StackTrace for previous Exception: ", e.getCause());
516 }
Shashikanth VH215dd812017-03-10 17:44:09 +0530517 stopSessionTimers();
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530518 ctx.getChannel().close();
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530519 } else if (e.getCause() instanceof BgpParseException) {
Shashikanth VHdae80402015-11-20 14:20:33 +0530520 byte[] data = new byte[] {};
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530521 BgpParseException errMsg = (BgpParseException) e.getCause();
Shashikanth VHdae80402015-11-20 14:20:33 +0530522 byte errorCode = errMsg.getErrorCode();
523 byte errorSubCode = errMsg.getErrorSubCode();
mohamedrahil00f6f262016-11-24 20:20:41 +0530524 bgpController.activeSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VHdae80402015-11-20 14:20:33 +0530525 ChannelBuffer tempCb = errMsg.getData();
526 if (tempCb != null) {
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530527 int dataLength = tempCb.readableBytes();
Shashikanth VHdae80402015-11-20 14:20:33 +0530528 data = new byte[dataLength];
529 tempCb.readBytes(data, 0, dataLength);
530 }
531 sendNotification(errorCode, errorSubCode, data);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530532 } else if (e.getCause() instanceof RejectedExecutionException) {
533 log.warn("Could not process message: queue full");
mohamedrahil00f6f262016-11-24 20:20:41 +0530534 bgpController.activeSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530535 } else {
Shashikanth VH215dd812017-03-10 17:44:09 +0530536 stopSessionTimers();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530537 log.error("Error while processing message from peer " + getPeerInfoString() + "state " + this.state);
mohamedrahil00f6f262016-11-24 20:20:41 +0530538 bgpController.closedSessionExceptionAdd(peerAddr, e.getCause().toString());
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530539 ctx.getChannel().close();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530540 }
541 }
542
543 @Override
544 public String toString() {
545 return getPeerInfoString();
546 }
547
548 @Override
549 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
550 if (e.getMessage() instanceof List) {
551 @SuppressWarnings("Unchecked")
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530552 List<BgpMessage> msglist = (List<BgpMessage>) e.getMessage();
553 for (BgpMessage pm : msglist) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530554 // Do the actual packet processing
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530555 state.processBgpMessage(this, pm);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530556 }
557 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530558 state.processBgpMessage(this, (BgpMessage) e.getMessage());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530559 }
560 }
561
Shashikanth VH447c6b02015-11-25 21:25:35 +0530562 /**
563 * Check for connection collision.
564 *
565 * @param state connection state
566 * @param peerIdentifier BGP peer identifier
567 * @param peerAddr BGP peer address
568 * @return true if bgp spreakers initiated connection
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530569 * @throws BgpParseException on error while procession collision detection
Shashikanth VH447c6b02015-11-25 21:25:35 +0530570 * @throws IOException on error while procession collision detection
571 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530572 public boolean connectionCollisionDetection(BgpPeerCfg.State state, int peerIdentifier, String peerAddr)
573 throws IOException, BgpParseException {
Shashikanth VH447c6b02015-11-25 21:25:35 +0530574 /*
575 * RFC 4271, Section 6.8, Based on the value of the BGP identifier, a convention is established for detecting
576 * which BGP connection is to be preserved when a collision occurs. The convention is to compare the BGP
577 * Identifiers of the peers involved in the collision and to retain only the connection initiated by the BGP
578 * speaker with the higher-valued BGP Identifier..
579 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530580 BgpPeerCfg.State currentState = bgpconfig.getPeerConnState(peerAddr);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530581 if (currentState.equals(state)) {
582 if (((Ip4Address.valueOf(bgpconfig.getRouterId())).compareTo(Ip4Address.valueOf(peerIdentifier))) > 0) {
583 // send notification
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530584 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_COLLISION_RESOLUTION, null);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530585 log.debug("Connection collision detected, local id: {}, peer id: {}, peer state:{}, in state:{}",
586 (Ip4Address.valueOf(bgpconfig.getRouterId())), (Ip4Address.valueOf(peerIdentifier)),
587 currentState, state);
588 return true;
589 }
590 }
591
592 return false;
593 }
594
Shashikanth VH6de20d32015-10-09 12:04:13 +0530595 // *************************
596 // Channel utility methods
597 // *************************
598 /**
599 * Set handshake status.
600 *
601 * @param handshakeComplete handshake complete status
602 */
603 public void setHandshakeComplete(boolean handshakeComplete) {
604 this.state.setHandshakeComplete(handshakeComplete);
605 }
606
607 /**
608 * Is this a state in which the handshake has completed?
609 *
610 * @return true if the handshake is complete
611 */
612 public boolean isHandshakeComplete() {
613 return state.isHandshakeComplete();
614 }
615
616 /**
617 * To handle the BGP message.
618 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530619 * @param m bgp message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530620 * @throws BgpParseException throw exception
Shashikanth VH6de20d32015-10-09 12:04:13 +0530621 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530622 private void dispatchMessage(BgpMessage m) throws BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530623 bgpPacketStats.addInPacket();
Jonathan Hart51539b82015-10-29 09:53:04 -0700624 bgpController.processBgpPacket(thisbgpId, m);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530625 }
626
627 /**
628 * Return a string describing this peer based on the already available information (ip address and/or remote
629 * socket).
630 *
631 * @return display string
632 */
633 private String getPeerInfoString() {
634 if (bgpPeer != null) {
635 return bgpPeer.toString();
636 }
637 String channelString;
638 if (channel == null || channel.getRemoteAddress() == null) {
639 channelString = "?";
640 } else {
641 channelString = channel.getRemoteAddress().toString();
642 }
643 String bgpIpString;
644 // TODO: implement functionality to get bgp id string
645 bgpIpString = "?";
646 return String.format("[%s BGP-IP[%s]]", channelString, bgpIpString);
647 }
648
649 /**
650 * Update the channels state. Only called from the state machine. TODO: enforce restricted state transitions
651 *
652 * @param state
653 */
654 private void setState(ChannelState state) {
655 this.state = state;
656 }
657
658 /**
659 * get packet statistics.
660 *
661 * @return packet statistics
662 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530663 public BgpPacketStatsImpl getBgpPacketStats() {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530664 return bgpPacketStats;
665 }
666
667 /**
668 * Send handshake open message to the peer.
669 *
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530670 * @throws IOException, BgpParseException
Shashikanth VH6de20d32015-10-09 12:04:13 +0530671 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530672 private void sendHandshakeOpenMessage() throws IOException, BgpParseException {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530673 int bgpId;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530674 BgpCfg.FlowSpec flowSpec = bgpconfig.flowSpecCapability();
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530675 boolean flowSpecStatus = false;
676 boolean vpnFlowSpecStatus = false;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530677
Shashikanth VH97e571e2016-01-05 12:15:14 +0530678 bgpId = Ip4Address.valueOf(bgpconfig.getRouterId()).toInt();
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530679
Mohammad Shahid30fedc52017-08-09 11:49:40 +0530680 boolean evpnCapability = bgpconfig.getEvpnCapability();
681
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530682 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)
Mohammad Shahid30fedc52017-08-09 11:49:40 +0530697 .setEvpnCapabilityTlv(evpnCapability)
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530698 .setFlowSpecRpdCapabilityTlv(bgpconfig.flowSpecRpdCapability()).build();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530699 log.debug("Sending open message to {}", channel.getRemoteAddress());
700 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530701
702 }
703
704 /**
Shashikanth VHdae80402015-11-20 14:20:33 +0530705 * Send notification message to peer.
706 *
707 * @param errorCode error code send in notification
708 * @param errorSubCode sub error code send in notification
709 * @param data data to send in notification
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530710 * @throws IOException, BgpParseException while building message
Shashikanth VHdae80402015-11-20 14:20:33 +0530711 */
712 private void sendNotification(byte errorCode, byte errorSubCode, byte[] data)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530713 throws IOException, BgpParseException {
714 BgpMessage msg = factory4.notificationMessageBuilder().setErrorCode(errorCode)
Shashikanth VH447c6b02015-11-25 21:25:35 +0530715 .setErrorSubCode(errorSubCode).setData(data).build();
Shashikanth VHdae80402015-11-20 14:20:33 +0530716 log.debug("Sending notification message to {}", channel.getRemoteAddress());
717 channel.write(Collections.singletonList(msg));
718 }
719
720 /**
Shashikanth VH6de20d32015-10-09 12:04:13 +0530721 * Send keep alive message.
722 *
723 * @throws IOException when channel is disconnected
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530724 * @throws BgpParseException while building keep alive message
Shashikanth VH6de20d32015-10-09 12:04:13 +0530725 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530726 synchronized void sendKeepAliveMessage() throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530727
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530728 BgpMessage msg = factory4.keepaliveMessageBuilder().build();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530729 log.debug("Sending keepalive message to {}", channel.getRemoteAddress());
730 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530731 }
732
733 /**
Shashikanth VH6de20d32015-10-09 12:04:13 +0530734 * Process unknown BGP message received.
735 *
Shashikanth VHdae80402015-11-20 14:20:33 +0530736 * @param errorCode error code
737 * @param errorSubCode error sub code
738 * @param data message type
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530739 * @throws BgpParseException while processing error messsage
Shashikanth VHdae80402015-11-20 14:20:33 +0530740 * @throws IOException while processing error message
Shashikanth VH6de20d32015-10-09 12:04:13 +0530741 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530742 public void processUnknownMsg(byte errorCode, byte errorSubCode, byte data) throws BgpParseException, IOException {
mohamedrahil00f6f262016-11-24 20:20:41 +0530743 log.debug("Unknown message received");
Shashikanth VHdae80402015-11-20 14:20:33 +0530744 byte[] byteArray = new byte[1];
745 byteArray[0] = data;
746 sendNotification(errorCode, errorSubCode, byteArray);
747 channel.close();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530748 }
749
750 /**
Vidyashree Ramaee293252015-11-18 17:00:11 +0530751 * BGP open message validation.
Shashikanth VH6de20d32015-10-09 12:04:13 +0530752 *
753 * @param h channel handler
Vidyashree Ramaee293252015-11-18 17:00:11 +0530754 * @param openMsg open message
755 * @return true if valid message, otherwise false
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530756 * @throws BgpParseException throw exception
Shashikanth VH6de20d32015-10-09 12:04:13 +0530757 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530758 public boolean openMsgValidation(BgpChannelHandler h, BgpOpenMsg openMsg) throws BgpParseException {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530759 boolean result;
760
761 // Validate BGP ID
762 result = bgpIdValidation(openMsg);
763 if (!result) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530764 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_BGP_IDENTIFIER, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530765 }
766
Shashikanth VH97e571e2016-01-05 12:15:14 +0530767 // Validate AS number
768 result = asNumberValidation(h, openMsg);
769 if (!result) {
770 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
771 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530772
773 // Validate hold timer
774 if ((openMsg.getHoldTime() != 0) && (openMsg.getHoldTime() < BGP_MIN_HOLDTIME)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530775 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNACCEPTABLE_HOLD_TIME, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530776 }
777
778 // Validate capabilities
779 result = capabilityValidation(h, openMsg);
780 return result;
781 }
782
783 /**
784 * Capability Validation.
785 *
786 * @param h channel handler
787 * @param openmsg open message
788 * @return success or failure
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530789 * @throws BgpParseException
Vidyashree Ramaee293252015-11-18 17:00:11 +0530790 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530791 private boolean capabilityValidation(BgpChannelHandler h, BgpOpenMsg openmsg) throws BgpParseException {
mohamedrahil00f6f262016-11-24 20:20:41 +0530792 log.debug("capability validation");
Vidyashree Ramaee293252015-11-18 17:00:11 +0530793
Vidyashree Ramaee293252015-11-18 17:00:11 +0530794 boolean isFourOctetCapabilityExits = false;
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530795 boolean isRpdCapabilityExits = false;
Vidyashree Ramaee293252015-11-18 17:00:11 +0530796 int capAsNum = 0;
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530797 byte sendReceive = 0;
Vidyashree Ramaee293252015-11-18 17:00:11 +0530798
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530799 List<BgpValueType> capabilityTlv = openmsg.getCapabilityTlv();
800 ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530801 List<BgpValueType> unSupportedCapabilityTlv = new CopyOnWriteArrayList<BgpValueType>();
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530802 ListIterator<BgpValueType> unSupportedCaplistIterator = unSupportedCapabilityTlv.listIterator();
803 BgpValueType tempTlv;
Vidyashree Ramaee293252015-11-18 17:00:11 +0530804 boolean isLargeAsCapabilityCfg = h.bgpconfig.getLargeASCapability();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530805 boolean isFlowSpecRpdCapabilityCfg = h.bgpconfig.flowSpecRpdCapability();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530806 boolean isLsCapabilityCfg = h.bgpconfig.getLsCapability();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530807 boolean isFlowSpecIpv4CapabilityCfg = false;
808 boolean isFlowSpecVpnv4CapabilityCfg = false;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530809 MultiProtocolExtnCapabilityTlv tempCapability;
810 boolean isMultiProtocolLsCapability = false;
811 boolean isMultiProtocolFlowSpecCapability = false;
812 boolean isMultiProtocolVpnFlowSpecCapability = false;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530813 BgpCfg.FlowSpec flowSpec = h.bgpconfig.flowSpecCapability();
Mohammad Shahid30fedc52017-08-09 11:49:40 +0530814 boolean isEvpnCapability = false;
815 boolean isEvpnCapabilityCfg = h.bgpconfig
816 .getEvpnCapability();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530817
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530818 if (flowSpec == BgpCfg.FlowSpec.IPV4) {
819 isFlowSpecIpv4CapabilityCfg = true;
820 } else if (flowSpec == BgpCfg.FlowSpec.VPNV4) {
821 isFlowSpecVpnv4CapabilityCfg = true;
822 } else if (flowSpec == BgpCfg.FlowSpec.IPV4_VPNV4) {
823 isFlowSpecIpv4CapabilityCfg = true;
824 isFlowSpecVpnv4CapabilityCfg = true;
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530825 }
826
Vidyashree Ramaee293252015-11-18 17:00:11 +0530827 while (listIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530828 BgpValueType tlv = listIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530829 if (tlv.getType() == MULTI_PROTOCOL_EXTN_CAPA_TYPE) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530830 tempCapability = (MultiProtocolExtnCapabilityTlv) tlv;
831 if (Constants.SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
832 isMultiProtocolFlowSpecCapability = true;
833 }
834
Mohammad Shahid30fedc52017-08-09 11:49:40 +0530835 if (Constants.SAFI_EVPN_VALUE == tempCapability.getSafi()) {
836 isEvpnCapability = true;
837 }
838
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530839 if (Constants.VPN_SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
840 isMultiProtocolVpnFlowSpecCapability = true;
841 }
842
843 if (SAFI == tempCapability.getSafi()) {
844 isMultiProtocolLsCapability = true;
845 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530846 }
847 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
848 isFourOctetCapabilityExits = true;
849 capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
850 }
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530851
852 if (tlv.getType() == RpdCapabilityTlv.TYPE) {
853 isRpdCapabilityExits = true;
854 sendReceive = ((RpdCapabilityTlv) tlv).sendReceive();
855 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530856 }
857
858 if (isFourOctetCapabilityExits) {
859 if (capAsNum > MAX_AS2_NUM) {
860 if (openmsg.getAsNumber() != AS_TRANS) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530861 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530862 }
863 } else {
864 if (capAsNum != openmsg.getAsNumber()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530865 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530866 }
867 }
868 }
869
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530870 if (isRpdCapabilityExits) {
871 if (sendReceive > 2) {
872 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNSUPPORTED_CAPABILITY, null);
873 }
874 }
875
Vidyashree Ramaee293252015-11-18 17:00:11 +0530876 if ((isLsCapabilityCfg)) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530877 if (!isMultiProtocolLsCapability) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530878 tempTlv = new MultiProtocolExtnCapabilityTlv(AFI, RES, SAFI);
879 unSupportedCapabilityTlv.add(tempTlv);
880 }
881 }
882
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530883 if (isFlowSpecIpv4CapabilityCfg) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530884 if (!isMultiProtocolFlowSpecCapability) {
885 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
886 RES, Constants.SAFI_FLOWSPEC_VALUE);
887 unSupportedCapabilityTlv.add(tempTlv);
888 }
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530889 }
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530890
Mohammad Shahid30fedc52017-08-09 11:49:40 +0530891 if (isEvpnCapabilityCfg) {
892 if (!isEvpnCapability) {
893 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_EVPN_VALUE,
894 RES,
895 Constants.SAFI_EVPN_VALUE);
896 unSupportedCapabilityTlv.add(tempTlv);
897 }
898 }
899
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530900 if (isFlowSpecVpnv4CapabilityCfg) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530901 if (!isMultiProtocolVpnFlowSpecCapability) {
902 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
903 RES, Constants.VPN_SAFI_FLOWSPEC_VALUE);
904 unSupportedCapabilityTlv.add(tempTlv);
905 }
906 }
907
Vidyashree Ramaee293252015-11-18 17:00:11 +0530908 if ((isLargeAsCapabilityCfg)) {
909 if (!isFourOctetCapabilityExits) {
910 tempTlv = new FourOctetAsNumCapabilityTlv(h.bgpconfig.getAsNumber());
911 unSupportedCapabilityTlv.add(tempTlv);
912 }
913 }
914
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530915 if ((isFlowSpecRpdCapabilityCfg)) {
Shashikanth VHb58cfd52016-04-21 16:45:50 +0530916 if (!isRpdCapabilityExits) {
917 tempTlv = new RpdCapabilityTlv(Constants.RPD_CAPABILITY_SEND_VALUE);
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530918 unSupportedCapabilityTlv.add(tempTlv);
919 }
920 }
921
922 if (unSupportedCapabilityTlv.size() == MAX_UNSUPPORTED_CAPABILITY) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530923 ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
924 while (unSupportedCaplistIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530925 BgpValueType tlv = unSupportedCaplistIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530926 tlv.write(buffer);
927 }
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530928 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNSUPPORTED_CAPABILITY, buffer);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530929 } else {
930 return true;
931 }
932 }
933
934 /**
935 * AS Number Validation.
936 *
937 * @param h channel Handler
938 * @param openMsg open message
939 * @return true or false
940 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530941 private boolean asNumberValidation(BgpChannelHandler h, BgpOpenMsg openMsg) {
mohamedrahil00f6f262016-11-24 20:20:41 +0530942 log.debug("AS number validation");
Vidyashree Ramaee293252015-11-18 17:00:11 +0530943
944 int capAsNum = 0;
945 boolean isFourOctetCapabilityExits = false;
946
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530947 BgpPeerCfg peerCfg = h.bgpconfig.displayPeers(peerAddr);
948 List<BgpValueType> capabilityTlv = openMsg.getCapabilityTlv();
949 ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530950
951 while (listIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530952 BgpValueType tlv = listIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530953 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
954 isFourOctetCapabilityExits = true;
955 capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
956 }
957 }
958
959 if (peerCfg.getAsNumber() > MAX_AS2_NUM) {
960 if (openMsg.getAsNumber() != AS_TRANS) {
961 return false;
962 }
963
964 if (!isFourOctetCapabilityExits) {
965 return false;
966 }
967
968 if (peerCfg.getAsNumber() != capAsNum) {
969 return false;
970 }
971
972 isIbgpSession = peerCfg.getIsIBgp();
973 if (isIbgpSession) {
974 // IBGP - AS number should be same for Peer and local if it is IBGP
975 if (h.bgpconfig.getAsNumber() != capAsNum) {
976 return false;
977 }
978 }
979 } else {
980
981 if (openMsg.getAsNumber() != peerCfg.getAsNumber()) {
982 return false;
983 }
984
985 if (isFourOctetCapabilityExits) {
986 if (capAsNum != peerCfg.getAsNumber()) {
987 return false;
988 }
989 }
990
991 isIbgpSession = peerCfg.getIsIBgp();
992 if (isIbgpSession) {
993 // IBGP - AS number should be same for Peer and local if it is IBGP
994 if (openMsg.getAsNumber() != h.bgpconfig.getAsNumber()) {
995 return false;
996 }
997 }
998 }
999 return true;
1000 }
1001
1002 /**
1003 * Validates BGP ID.
1004 *
1005 * @param openMsg open message
1006 * @return true or false
1007 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +05301008 private boolean bgpIdValidation(BgpOpenMsg openMsg) {
Vidyashree Ramaee293252015-11-18 17:00:11 +05301009 String openMsgBgpId = Ip4Address.valueOf(openMsg.getBgpId()).toString();
1010
1011 InetAddress ipAddress;
1012 try {
1013 ipAddress = InetAddress.getByName(openMsgBgpId);
1014 if (ipAddress.isMulticastAddress()) {
1015 return false;
1016 }
1017 } catch (UnknownHostException e) {
1018 log.debug("InetAddress convertion failed");
1019 }
Shashikanth VH6de20d32015-10-09 12:04:13 +05301020 return true;
1021 }
Shashikanth VH215dd812017-03-10 17:44:09 +05301022
1023 /**
1024 * Restarts the BGP hold Timeout Timer.
1025 */
1026 void restartHoldTimeoutTimer() {
1027 if (peerHoldTime == 0) {
1028 return;
1029 }
1030 if (holdTimerTimeout != null) {
1031 holdTimerTimeout.cancel();
1032 }
1033 holdTimerTimeout = timer.newTimeout(new HoldTimerTimeout(), minHoldTime, TimeUnit.SECONDS);
1034 }
1035
1036 /**
1037 * Timer class for BGP hold timer timeout.
1038 */
1039 private final class HoldTimerTimeout implements TimerTask {
1040
1041 @Override
1042 public void run(Timeout timeout) throws Exception {
1043 if (timeout.isCancelled()) {
1044 return;
1045 }
1046 if (!channel.isOpen()) {
1047 return;
1048 }
1049
1050 log.debug("BGP hold timer expired: peer {}", channel.getRemoteAddress());
1051
1052 sendNotification(BgpErrorType.HOLD_TIMER_EXPIRED, (byte) 0, null);
1053 bgpController.closedSessionExceptionAdd(peerAddr, "BGP hold timer expired");
1054 stopSessionTimers();
1055 state = ChannelState.IDLE;
1056 channel.close();
1057 }
1058 }
Shashikanth VH6de20d32015-10-09 12:04:13 +05301059}