blob: 40c63d44392c91713d1893a45bbd1971a15435da [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 VH0a82a8e2016-02-02 20:42:53 +053047import org.onosproject.bgpio.util.Constants;
Shashikanth VH6de20d32015-10-09 12:04:13 +053048import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
Satish Ke107e662015-09-21 19:00:17 +053050
Jonathan Hart51539b82015-10-29 09:53:04 -070051import java.io.IOException;
52import java.net.InetAddress;
53import java.net.InetSocketAddress;
54import java.net.SocketAddress;
55import java.net.UnknownHostException;
56import java.nio.channels.ClosedChannelException;
57import java.util.Collections;
Jonathan Hart51539b82015-10-29 09:53:04 -070058import java.util.List;
59import java.util.ListIterator;
Shashikanth VHb650bfa2016-04-18 12:54:03 +053060import java.util.concurrent.CopyOnWriteArrayList;
Jonathan Hart51539b82015-10-29 09:53:04 -070061import java.util.concurrent.RejectedExecutionException;
62
Satish Ke107e662015-09-21 19:00:17 +053063/**
64 * Channel handler deals with the bgp peer connection and dispatches messages from peer to the appropriate locations.
65 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053066class BgpChannelHandler extends IdleStateAwareChannelHandler {
Satish Ke107e662015-09-21 19:00:17 +053067
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053068 private static final Logger log = LoggerFactory.getLogger(BgpChannelHandler.class);
Vidyashree Ramaee293252015-11-18 17:00:11 +053069 static final int BGP_MIN_HOLDTIME = 3;
Shashikanth VH6de20d32015-10-09 12:04:13 +053070 static final int BGP_MAX_KEEPALIVE_INTERVAL = 3;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053071 private BgpPeer bgpPeer;
72 private BgpId thisbgpId;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053073 private Channel channel;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053074 private BgpKeepAliveTimer keepAliveTimer = null;
Shashikanth VH6de20d32015-10-09 12:04:13 +053075 private short peerHoldTime = 0;
76 private short negotiatedHoldTime = 0;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053077 private long peerAsNum;
Shashikanth VH6de20d32015-10-09 12:04:13 +053078 private int peerIdentifier;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +053079 private BgpPacketStatsImpl bgpPacketStats;
Shashikanth VH6de20d32015-10-09 12:04:13 +053080 static final int MAX_WRONG_COUNT_PACKET = 5;
Vidyashree Ramaee293252015-11-18 17:00:11 +053081 static final byte MULTI_PROTOCOL_EXTN_CAPA_TYPE = 1;
82 static final byte FOUR_OCTET_AS_NUM_CAPA_TYPE = 65;
83 static final int AS_TRANS = 23456;
84 static final int MAX_AS2_NUM = 65535;
85 static final short AFI = 16388;
86 static final byte RES = 0;
87 static final byte SAFI = 71;
Shashikanth VHb650bfa2016-04-18 12:54:03 +053088 static final byte MAX_UNSUPPORTED_CAPABILITY = 5;
Shashikanth VH6de20d32015-10-09 12:04:13 +053089
90 // State needs to be volatile because the HandshakeTimeoutHandler
91 // needs to check if the handshake is complete
92 private volatile ChannelState state;
93
94 // When a bgp peer with a ip addresss is found (i.e we already have a
95 // connected peer with the same ip), the new peer is immediately
96 // disconnected. At that point netty callsback channelDisconnected() which
Shashikanth VH9f8afb42015-11-04 18:00:30 +053097 // proceeds to cleaup peer state - we need to ensure that it does not
98 // cleanup
Shashikanth VH6de20d32015-10-09 12:04:13 +053099 // peer state for the older (still connected) peer
Jonathan Hart51539b82015-10-29 09:53:04 -0700100 private volatile Boolean duplicateBgpIdFound;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530101 // Indicates the bgp version used by this bgp peer
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530102 protected BgpVersion bgpVersion;
103 private BgpController bgpController;
104 protected BgpFactory factory4;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530105 private boolean isIbgpSession;
106 private BgpSessionInfoImpl sessionInfo;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530107 private BgpPeerManagerImpl peerManager;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530108 private InetSocketAddress inetAddress;
109 private IpAddress ipAddress;
110 private SocketAddress address;
111 private String peerAddr;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530112 private BgpCfg bgpconfig;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530113 List<BgpValueType> remoteBgpCapability;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530114
Satish Ke107e662015-09-21 19:00:17 +0530115 /**
116 * Create a new unconnected BGPChannelHandler.
117 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530118 * @param bgpController bgp controller
Satish Ke107e662015-09-21 19:00:17 +0530119 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530120 BgpChannelHandler(BgpController bgpController) {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530121 this.bgpController = bgpController;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530122 this.peerManager = (BgpPeerManagerImpl) bgpController.peerManager();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530123 this.state = ChannelState.IDLE;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530124 this.factory4 = Controller.getBgpMessageFactory4();
Jonathan Hart51539b82015-10-29 09:53:04 -0700125 this.duplicateBgpIdFound = Boolean.FALSE;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530126 this.bgpPacketStats = new BgpPacketStatsImpl();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530127 this.bgpconfig = bgpController.getConfig();
Satish Ke107e662015-09-21 19:00:17 +0530128 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530129
130 // To disconnect peer session.
131 public void disconnectPeer() {
132 bgpPeer.disconnectPeer();
133 }
134
135 // *************************
136 // Channel State Machine
137 // *************************
138
139 /**
140 * The state machine for handling the peer/channel state. All state transitions should happen from within the state
141 * machine (and not from other parts of the code)
142 */
143 enum ChannelState {
144 /**
145 * Initial state before channel is connected.
146 */
147 IDLE(false) {
148
149 },
150
151 OPENSENT(false) {
152 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530153 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530154 log.debug("message received in OPENSENT state");
155 // check for OPEN message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530156 if (m.getType() != BgpType.OPEN) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530157 // When the message type is not keep alive message increment the wrong packet statistics
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530158 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR,
159 BgpErrorType.RECEIVE_UNEXPECTED_MESSAGE_IN_OPENSENT_STATE,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530160 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530161 log.debug("Message is not OPEN message");
162 } else {
163 log.debug("Sending keep alive message in OPENSENT state");
164 h.bgpPacketStats.addInPacket();
165
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530166 BgpOpenMsg pOpenmsg = (BgpOpenMsg) m;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530167 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530168
169 // validate capabilities and open msg
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530170 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530171 if (h.connectionCollisionDetection(BgpPeerCfg.State.OPENCONFIRM,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530172 h.peerIdentifier, h.peerAddr)) {
173 h.channel.close();
174 return;
175 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530176 log.debug("Sending handshake OPEN message");
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530177 h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530178
179 /*
180 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
181 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
182 * received in the OPEN message
183 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530184 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530185 if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
186 h.channel.getPipeline().replace("holdTime",
187 "holdTime",
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530188 new ReadTimeoutHandler(BgpPipelineFactory.TIMER,
Shashikanth VH6de20d32015-10-09 12:04:13 +0530189 h.peerHoldTime));
190 }
191
192 log.info("Hold Time : " + h.peerHoldTime);
193
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530194 // update AS number
195 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530196 }
197
198 // Send keepalive message to peer.
199 h.sendKeepAliveMessage();
200 h.bgpPacketStats.addOutPacket();
201 h.setState(OPENCONFIRM);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530202 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.OPENCONFIRM);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530203 }
204 }
205 },
206
207 OPENWAIT(false) {
208 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530209 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530210 log.debug("Message received in OPEN WAIT State");
211
212 // check for open message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530213 if (m.getType() != BgpType.OPEN) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530214 // When the message type is not open message increment the wrong packet statistics
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530215 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR, BgpErrorType.UNSPECIFIED_ERROR,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530216 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530217 log.debug("Message is not OPEN message");
218 } else {
219 h.bgpPacketStats.addInPacket();
220
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530221 BgpOpenMsg pOpenmsg = (BgpOpenMsg) m;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530222 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530223
224 // Validate open message
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530225 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530226 if (h.connectionCollisionDetection(BgpPeerCfg.State.OPENSENT,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530227 h.peerIdentifier, h.peerAddr)) {
228 h.channel.close();
229 return;
230 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530231 log.debug("Sending handshake OPEN message");
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530232 h.remoteBgpCapability = pOpenmsg.getCapabilityTlv();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530233
234 /*
235 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
236 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
237 * received in the OPEN message
238 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530239 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530240 if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
241 h.channel.getPipeline().replace("holdTime",
242 "holdTime",
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530243 new ReadTimeoutHandler(BgpPipelineFactory.TIMER,
Shashikanth VH6de20d32015-10-09 12:04:13 +0530244 h.peerHoldTime));
245 }
246
247 log.debug("Hold Time : " + h.peerHoldTime);
248
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530249 // update AS number
250 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530251
252 h.sendHandshakeOpenMessage();
253 h.bgpPacketStats.addOutPacket();
254 h.setState(OPENCONFIRM);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530255 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.OPENCONFIRM);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530256 }
257 }
258 }
259 },
260
261 OPENCONFIRM(false) {
262 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530263 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530264 log.debug("Message received in OPENCONFIRM state");
265 // check for keep alive message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530266 if (m.getType() != BgpType.KEEP_ALIVE) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530267 // When the message type is not keep alive message handle the wrong packet
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530268 h.processUnknownMsg(BgpErrorType.FINITE_STATE_MACHINE_ERROR,
269 BgpErrorType.RECEIVE_UNEXPECTED_MESSAGE_IN_OPENCONFIRM_STATE,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530270 m.getType().getType());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530271 log.debug("Message is not KEEPALIVE message");
272 } else {
273
274 // Set the peer connected status
275 h.bgpPacketStats.addInPacket();
276 log.debug("Sending keep alive message in OPENCONFIRM state");
277
278 final InetSocketAddress inetAddress = (InetSocketAddress) h.address;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530279 h.thisbgpId = BgpId.bgpId(IpAddress.valueOf(inetAddress.getAddress()));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530280
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530281 // set session parameters
282 h.negotiatedHoldTime = (h.peerHoldTime < h.bgpconfig.getHoldTime()) ? h.peerHoldTime
283 : h.bgpconfig.getHoldTime();
284 h.sessionInfo = new BgpSessionInfoImpl(h.thisbgpId, h.bgpVersion, h.peerAsNum, h.peerHoldTime,
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530285 h.peerIdentifier, h.negotiatedHoldTime, h.isIbgpSession,
286 h.remoteBgpCapability);
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530287
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530288 h.bgpPeer = h.peerManager.getBgpPeerInstance(h.bgpController, h.sessionInfo, h.bgpPacketStats);
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530289 // set the status of bgp as connected
Shashikanth VH6de20d32015-10-09 12:04:13 +0530290 h.bgpPeer.setConnected(true);
291 h.bgpPeer.setChannel(h.channel);
292
Shashikanth VH6de20d32015-10-09 12:04:13 +0530293 /*
294 * RFC 4271, When an OPEN message is received, sends a KEEPALIVE message, If the negotiated hold
295 * time value is zero, then the HoldTimer and KeepaliveTimer are not started. A reasonable maximum
296 * time between KEEPALIVE messages would be one third of the Hold Time interval.
297 */
Shashikanth VH6de20d32015-10-09 12:04:13 +0530298
299 if (h.negotiatedHoldTime != 0) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530300 h.keepAliveTimer = new BgpKeepAliveTimer(h,
Shashikanth VH447c6b02015-11-25 21:25:35 +0530301 (h.negotiatedHoldTime / BGP_MAX_KEEPALIVE_INTERVAL));
Shashikanth VHdae80402015-11-20 14:20:33 +0530302 } else {
303 h.sendKeepAliveMessage();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530304 }
305
306 h.bgpPacketStats.addOutPacket();
307
308 // set the state handshake completion.
309 h.setHandshakeComplete(true);
310
311 if (!h.peerManager.addConnectedPeer(h.thisbgpId, h.bgpPeer)) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530312 disconnectDuplicate(h);
313 } else {
314 h.setState(ESTABLISHED);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530315 h.bgpconfig.setPeerConnState(h.peerAddr, BgpPeerCfg.State.ESTABLISHED);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530316 }
317 }
318 }
319 },
320
321 ESTABLISHED(true) {
322 @Override
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530323 void processBgpMessage(BgpChannelHandler h, BgpMessage m) throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530324 log.debug("Message received in established state " + m.getType());
325 // dispatch the message
326 h.dispatchMessage(m);
327 }
328 };
329
330 private boolean handshakeComplete;
331
332 ChannelState(boolean handshakeComplete) {
333 this.handshakeComplete = handshakeComplete;
334 }
335
336 /**
337 * Is this a state in which the handshake has completed?
338 *
339 * @return true if the handshake is complete
340 */
341 public boolean isHandshakeComplete() {
342 return this.handshakeComplete;
343 }
344
345 /**
346 * Disconnect duplicate peer connection.
347 *
348 * @param h channel handler
349 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530350 protected void disconnectDuplicate(BgpChannelHandler h) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530351 log.error("Duplicated BGP IP or incompleted cleanup - " + "" + "disconnecting channel {}",
352 h.getPeerInfoString());
Jonathan Hart51539b82015-10-29 09:53:04 -0700353 h.duplicateBgpIdFound = Boolean.TRUE;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530354 h.channel.disconnect();
355 }
356
357 // set handshake completion status
358 public void setHandshakeComplete(boolean handshakeComplete) {
359 this.handshakeComplete = handshakeComplete;
360 }
361
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530362 void processBgpMessage(BgpChannelHandler bgpChannelHandler, BgpMessage pm)
363 throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530364 // TODO Auto-generated method stub
365 log.debug("BGP message stub");
366 }
367
368 }
369
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530370 //Stop keepalive timer
371 private void stopKeepAliveTimer() {
372 if ((keepAliveTimer != null) && (keepAliveTimer.getKeepAliveTimer() != null)) {
373 keepAliveTimer.getKeepAliveTimer().cancel();
374 }
375 }
376
Shashikanth VH6de20d32015-10-09 12:04:13 +0530377 // *************************
378 // Channel handler methods
379 // *************************
380
381 @Override
382 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
383
384 channel = e.getChannel();
385 log.info("BGP connected from {}", channel.getRemoteAddress());
386
387 address = channel.getRemoteAddress();
388 if (!(address instanceof InetSocketAddress)) {
389 throw new IOException("Invalid peer connection.");
390 }
391
Shashikanth VH97e571e2016-01-05 12:15:14 +0530392 // Connection should establish only if local ip and Autonomous system number is configured.
393 if (bgpconfig.getState() != BgpCfg.State.IP_AS_CONFIGURED) {
394 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_REJECTED, null);
395 channel.close();
396 log.info("BGP local AS and router ID not configured");
397 return;
398 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530399
400 inetAddress = (InetSocketAddress) address;
Shashikanth VHdae80402015-11-20 14:20:33 +0530401 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530402
Shashikanth VH97e571e2016-01-05 12:15:14 +0530403 // if peer is not configured disconnect session
404 if (!bgpconfig.isPeerConfigured(peerAddr)) {
405 log.debug("Peer is not configured {}", peerAddr);
406 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_REJECTED, null);
407 channel.close();
408 return;
409 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530410
411 // if connection is already established close channel
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530412 if (peerManager.isPeerConnected(BgpId.bgpId(IpAddress.valueOf(peerAddr)))) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530413 log.debug("Duplicate connection received, peer {}", peerAddr);
414 channel.close();
415 return;
416 }
417
418 if (null != channel.getPipeline().get("PassiveHandler")) {
419 log.info("BGP handle connection request from peer");
420 // Wait for open message from bgp peer
421 setState(ChannelState.OPENWAIT);
422 } else if (null != channel.getPipeline().get("ActiveHandler")) {
423 log.info("BGP handle connection response from peer");
424
425 sendHandshakeOpenMessage();
426 bgpPacketStats.addOutPacket();
427 setState(ChannelState.OPENSENT);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530428 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.OPENSENT);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530429 }
430 }
431
432 @Override
433 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
434
435 channel = e.getChannel();
436 log.info("BGP disconnected callback for bgp:{}. Cleaning up ...", getPeerInfoString());
437
438 address = channel.getRemoteAddress();
439 if (!(address instanceof InetSocketAddress)) {
440 throw new IOException("Invalid peer connection.");
441 }
442
443 inetAddress = (InetSocketAddress) address;
Shashikanth VHdae80402015-11-20 14:20:33 +0530444 peerAddr = IpAddress.valueOf(inetAddress.getAddress()).toString();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530445
446 if (thisbgpId != null) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700447 if (!duplicateBgpIdFound) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530448 // if the disconnected peer (on this ChannelHandler)
449 // was not one with a duplicate, it is safe to remove all
450 // state for it at the controller. Notice that if the disconnected
451 // peer was a duplicate-ip, calling the method below would clear
452 // all state for the original peer (with the same ip),
453 // which we obviously don't want.
454 log.debug("{}:removal called", getPeerInfoString());
455 if (bgpPeer != null) {
Shashikanth VH3fe37982015-11-30 11:50:07 +0530456 BgpPeerImpl peer = (BgpPeerImpl) bgpPeer;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530457 peerManager.removeConnectedPeer(thisbgpId);
Jonathan Hart51539b82015-10-29 09:53:04 -0700458 peer.updateLocalRibOnPeerDisconnect();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530459 }
Shashikanth VH447c6b02015-11-25 21:25:35 +0530460
461 // Retry connection if connection is lost to bgp speaker/peer
462 if ((channel != null) && (null != channel.getPipeline().get("ActiveHandler"))) {
463 BgpConnectPeerImpl connectPeer;
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530464 BgpPeerCfg.State peerCfgState;
Shashikanth VH447c6b02015-11-25 21:25:35 +0530465
466 peerCfgState = bgpconfig.getPeerConnState(peerAddr);
467 // on session disconnect using configuration, do not retry
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530468 if (!peerCfgState.equals(BgpPeerCfg.State.IDLE)) {
Shashikanth VH447c6b02015-11-25 21:25:35 +0530469 log.debug("Connection reset by peer, retry, STATE:{}", peerCfgState);
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530470 BgpPeerConfig peerConfig = (BgpPeerConfig) bgpconfig.displayPeers(peerAddr);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530471
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530472 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530473 connectPeer = new BgpConnectPeerImpl(bgpController, peerAddr, Controller.getBgpPortNum());
474 peerConfig.setConnectPeer(connectPeer);
475 }
476 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530477 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530478 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530479 } else {
480 // A duplicate was disconnected on this ChannelHandler,
481 // this is the same peer reconnecting, but the original state was
482 // not cleaned up - XXX check liveness of original ChannelHandler
483 log.debug("{}:duplicate found", getPeerInfoString());
Jonathan Hart51539b82015-10-29 09:53:04 -0700484 duplicateBgpIdFound = Boolean.FALSE;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530485 }
486
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530487 stopKeepAliveTimer();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530488 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530489 bgpconfig.setPeerConnState(peerAddr, BgpPeerCfg.State.IDLE);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530490 log.warn("No bgp ip in channelHandler registered for " + "disconnected peer {}", getPeerInfoString());
491 }
492 }
493
494 @Override
495 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
496
497 log.info("[exceptionCaught]: " + e.toString());
498
499 if (e.getCause() instanceof ReadTimeoutException) {
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530500 // device timeout
501 log.error("Disconnecting device {} due to read timeout", getPeerInfoString());
502 sendNotification(BgpErrorType.HOLD_TIMER_EXPIRED, (byte) 0, null);
503 state = ChannelState.IDLE;
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530504 stopKeepAliveTimer();
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530505 ctx.getChannel().close();
506 return;
Shashikanth VH6de20d32015-10-09 12:04:13 +0530507 } else if (e.getCause() instanceof ClosedChannelException) {
508 log.debug("Channel for bgp {} already closed", getPeerInfoString());
509 } else if (e.getCause() instanceof IOException) {
510 log.error("Disconnecting peer {} due to IO Error: {}", getPeerInfoString(), e.getCause().getMessage());
511 if (log.isDebugEnabled()) {
512 // still print stack trace if debug is enabled
513 log.debug("StackTrace for previous Exception: ", e.getCause());
514 }
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530515 stopKeepAliveTimer();
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530516 ctx.getChannel().close();
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530517 } else if (e.getCause() instanceof BgpParseException) {
Shashikanth VHdae80402015-11-20 14:20:33 +0530518 byte[] data = new byte[] {};
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530519 BgpParseException errMsg = (BgpParseException) e.getCause();
Shashikanth VHdae80402015-11-20 14:20:33 +0530520 byte errorCode = errMsg.getErrorCode();
521 byte errorSubCode = errMsg.getErrorSubCode();
522 ChannelBuffer tempCb = errMsg.getData();
523 if (tempCb != null) {
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530524 int dataLength = tempCb.readableBytes();
Shashikanth VHdae80402015-11-20 14:20:33 +0530525 data = new byte[dataLength];
526 tempCb.readBytes(data, 0, dataLength);
527 }
528 sendNotification(errorCode, errorSubCode, data);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530529 } else if (e.getCause() instanceof RejectedExecutionException) {
530 log.warn("Could not process message: queue full");
531 } else {
Shashikanth VH3dd13cf2015-12-14 11:53:46 +0530532 stopKeepAliveTimer();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530533 log.error("Error while processing message from peer " + getPeerInfoString() + "state " + this.state);
Shashikanth VHa33f9a02015-12-05 12:22:23 +0530534 ctx.getChannel().close();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530535 }
536 }
537
538 @Override
539 public String toString() {
540 return getPeerInfoString();
541 }
542
543 @Override
544 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
545 if (e.getMessage() instanceof List) {
546 @SuppressWarnings("Unchecked")
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530547 List<BgpMessage> msglist = (List<BgpMessage>) e.getMessage();
548 for (BgpMessage pm : msglist) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530549 // Do the actual packet processing
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530550 state.processBgpMessage(this, pm);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530551 }
552 } else {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530553 state.processBgpMessage(this, (BgpMessage) e.getMessage());
Shashikanth VH6de20d32015-10-09 12:04:13 +0530554 }
555 }
556
Shashikanth VH447c6b02015-11-25 21:25:35 +0530557 /**
558 * Check for connection collision.
559 *
560 * @param state connection state
561 * @param peerIdentifier BGP peer identifier
562 * @param peerAddr BGP peer address
563 * @return true if bgp spreakers initiated connection
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530564 * @throws BgpParseException on error while procession collision detection
Shashikanth VH447c6b02015-11-25 21:25:35 +0530565 * @throws IOException on error while procession collision detection
566 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530567 public boolean connectionCollisionDetection(BgpPeerCfg.State state, int peerIdentifier, String peerAddr)
568 throws IOException, BgpParseException {
Shashikanth VH447c6b02015-11-25 21:25:35 +0530569 /*
570 * RFC 4271, Section 6.8, Based on the value of the BGP identifier, a convention is established for detecting
571 * which BGP connection is to be preserved when a collision occurs. The convention is to compare the BGP
572 * Identifiers of the peers involved in the collision and to retain only the connection initiated by the BGP
573 * speaker with the higher-valued BGP Identifier..
574 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530575 BgpPeerCfg.State currentState = bgpconfig.getPeerConnState(peerAddr);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530576 if (currentState.equals(state)) {
577 if (((Ip4Address.valueOf(bgpconfig.getRouterId())).compareTo(Ip4Address.valueOf(peerIdentifier))) > 0) {
578 // send notification
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530579 sendNotification(BgpErrorType.CEASE, BgpErrorType.CONNECTION_COLLISION_RESOLUTION, null);
Shashikanth VH447c6b02015-11-25 21:25:35 +0530580 log.debug("Connection collision detected, local id: {}, peer id: {}, peer state:{}, in state:{}",
581 (Ip4Address.valueOf(bgpconfig.getRouterId())), (Ip4Address.valueOf(peerIdentifier)),
582 currentState, state);
583 return true;
584 }
585 }
586
587 return false;
588 }
589
Shashikanth VH6de20d32015-10-09 12:04:13 +0530590 // *************************
591 // Channel utility methods
592 // *************************
593 /**
594 * Set handshake status.
595 *
596 * @param handshakeComplete handshake complete status
597 */
598 public void setHandshakeComplete(boolean handshakeComplete) {
599 this.state.setHandshakeComplete(handshakeComplete);
600 }
601
602 /**
603 * Is this a state in which the handshake has completed?
604 *
605 * @return true if the handshake is complete
606 */
607 public boolean isHandshakeComplete() {
608 return state.isHandshakeComplete();
609 }
610
611 /**
612 * To handle the BGP message.
613 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530614 * @param m bgp message
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530615 * @throws BgpParseException throw exception
Shashikanth VH6de20d32015-10-09 12:04:13 +0530616 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530617 private void dispatchMessage(BgpMessage m) throws BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530618 bgpPacketStats.addInPacket();
Jonathan Hart51539b82015-10-29 09:53:04 -0700619 bgpController.processBgpPacket(thisbgpId, m);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530620 }
621
622 /**
623 * Return a string describing this peer based on the already available information (ip address and/or remote
624 * socket).
625 *
626 * @return display string
627 */
628 private String getPeerInfoString() {
629 if (bgpPeer != null) {
630 return bgpPeer.toString();
631 }
632 String channelString;
633 if (channel == null || channel.getRemoteAddress() == null) {
634 channelString = "?";
635 } else {
636 channelString = channel.getRemoteAddress().toString();
637 }
638 String bgpIpString;
639 // TODO: implement functionality to get bgp id string
640 bgpIpString = "?";
641 return String.format("[%s BGP-IP[%s]]", channelString, bgpIpString);
642 }
643
644 /**
645 * Update the channels state. Only called from the state machine. TODO: enforce restricted state transitions
646 *
647 * @param state
648 */
649 private void setState(ChannelState state) {
650 this.state = state;
651 }
652
653 /**
654 * get packet statistics.
655 *
656 * @return packet statistics
657 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530658 public BgpPacketStatsImpl getBgpPacketStats() {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530659 return bgpPacketStats;
660 }
661
662 /**
663 * Send handshake open message to the peer.
664 *
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530665 * @throws IOException, BgpParseException
Shashikanth VH6de20d32015-10-09 12:04:13 +0530666 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530667 private void sendHandshakeOpenMessage() throws IOException, BgpParseException {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530668 int bgpId;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530669 BgpCfg.FlowSpec flowSpec = bgpconfig.flowSpecCapability();
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530670 boolean flowSpecStatus = false;
671 boolean vpnFlowSpecStatus = false;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530672
Shashikanth VH97e571e2016-01-05 12:15:14 +0530673 bgpId = Ip4Address.valueOf(bgpconfig.getRouterId()).toInt();
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530674
675 if (flowSpec == BgpCfg.FlowSpec.IPV4) {
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530676 flowSpecStatus = true;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530677 } else if (flowSpec == BgpCfg.FlowSpec.VPNV4) {
678 vpnFlowSpecStatus = true;
679 } else if (flowSpec == BgpCfg.FlowSpec.IPV4_VPNV4) {
680 flowSpecStatus = true;
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530681 vpnFlowSpecStatus = true;
682 }
683
Shashikanth VH97e571e2016-01-05 12:15:14 +0530684 BgpMessage msg = factory4.openMessageBuilder().setAsNumber((short) bgpconfig.getAsNumber())
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530685 .setHoldTime(bgpconfig.getHoldTime()).setBgpId(bgpId)
686 .setLsCapabilityTlv(bgpconfig.getLsCapability())
687 .setLargeAsCapabilityTlv(bgpconfig.getLargeASCapability())
688 .setFlowSpecCapabilityTlv(flowSpecStatus)
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530689 .setVpnFlowSpecCapabilityTlv(vpnFlowSpecStatus)
690 .setFlowSpecRpdCapabilityTlv(bgpconfig.flowSpecRpdCapability()).build();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530691 log.debug("Sending open message to {}", channel.getRemoteAddress());
692 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530693
694 }
695
696 /**
Shashikanth VHdae80402015-11-20 14:20:33 +0530697 * Send notification message to peer.
698 *
699 * @param errorCode error code send in notification
700 * @param errorSubCode sub error code send in notification
701 * @param data data to send in notification
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530702 * @throws IOException, BgpParseException while building message
Shashikanth VHdae80402015-11-20 14:20:33 +0530703 */
704 private void sendNotification(byte errorCode, byte errorSubCode, byte[] data)
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530705 throws IOException, BgpParseException {
706 BgpMessage msg = factory4.notificationMessageBuilder().setErrorCode(errorCode)
Shashikanth VH447c6b02015-11-25 21:25:35 +0530707 .setErrorSubCode(errorSubCode).setData(data).build();
Shashikanth VHdae80402015-11-20 14:20:33 +0530708 log.debug("Sending notification message to {}", channel.getRemoteAddress());
709 channel.write(Collections.singletonList(msg));
710 }
711
712 /**
Shashikanth VH6de20d32015-10-09 12:04:13 +0530713 * Send keep alive message.
714 *
715 * @throws IOException when channel is disconnected
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530716 * @throws BgpParseException while building keep alive message
Shashikanth VH6de20d32015-10-09 12:04:13 +0530717 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530718 synchronized void sendKeepAliveMessage() throws IOException, BgpParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530719
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530720 BgpMessage msg = factory4.keepaliveMessageBuilder().build();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530721 log.debug("Sending keepalive message to {}", channel.getRemoteAddress());
722 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530723 }
724
725 /**
Shashikanth VH6de20d32015-10-09 12:04:13 +0530726 * Process unknown BGP message received.
727 *
Shashikanth VHdae80402015-11-20 14:20:33 +0530728 * @param errorCode error code
729 * @param errorSubCode error sub code
730 * @param data message type
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530731 * @throws BgpParseException while processing error messsage
Shashikanth VHdae80402015-11-20 14:20:33 +0530732 * @throws IOException while processing error message
Shashikanth VH6de20d32015-10-09 12:04:13 +0530733 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530734 public void processUnknownMsg(byte errorCode, byte errorSubCode, byte data) throws BgpParseException, IOException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530735 log.debug("UNKNOWN message received");
Shashikanth VHdae80402015-11-20 14:20:33 +0530736 byte[] byteArray = new byte[1];
737 byteArray[0] = data;
738 sendNotification(errorCode, errorSubCode, byteArray);
739 channel.close();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530740 }
741
742 /**
Vidyashree Ramaee293252015-11-18 17:00:11 +0530743 * BGP open message validation.
Shashikanth VH6de20d32015-10-09 12:04:13 +0530744 *
745 * @param h channel handler
Vidyashree Ramaee293252015-11-18 17:00:11 +0530746 * @param openMsg open message
747 * @return true if valid message, otherwise false
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530748 * @throws BgpParseException throw exception
Shashikanth VH6de20d32015-10-09 12:04:13 +0530749 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530750 public boolean openMsgValidation(BgpChannelHandler h, BgpOpenMsg openMsg) throws BgpParseException {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530751 boolean result;
752
753 // Validate BGP ID
754 result = bgpIdValidation(openMsg);
755 if (!result) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530756 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_BGP_IDENTIFIER, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530757 }
758
Shashikanth VH97e571e2016-01-05 12:15:14 +0530759 // Validate AS number
760 result = asNumberValidation(h, openMsg);
761 if (!result) {
762 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
763 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530764
765 // Validate hold timer
766 if ((openMsg.getHoldTime() != 0) && (openMsg.getHoldTime() < BGP_MIN_HOLDTIME)) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530767 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNACCEPTABLE_HOLD_TIME, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530768 }
769
770 // Validate capabilities
771 result = capabilityValidation(h, openMsg);
772 return result;
773 }
774
775 /**
776 * Capability Validation.
777 *
778 * @param h channel handler
779 * @param openmsg open message
780 * @return success or failure
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530781 * @throws BgpParseException
Vidyashree Ramaee293252015-11-18 17:00:11 +0530782 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530783 private boolean capabilityValidation(BgpChannelHandler h, BgpOpenMsg openmsg) throws BgpParseException {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530784 log.debug("capabilityValidation");
785
Vidyashree Ramaee293252015-11-18 17:00:11 +0530786 boolean isFourOctetCapabilityExits = false;
787 int capAsNum = 0;
788
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530789 List<BgpValueType> capabilityTlv = openmsg.getCapabilityTlv();
790 ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530791 List<BgpValueType> unSupportedCapabilityTlv = new CopyOnWriteArrayList<BgpValueType>();
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530792 ListIterator<BgpValueType> unSupportedCaplistIterator = unSupportedCapabilityTlv.listIterator();
793 BgpValueType tempTlv;
Vidyashree Ramaee293252015-11-18 17:00:11 +0530794 boolean isLargeAsCapabilityCfg = h.bgpconfig.getLargeASCapability();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530795 boolean isFlowSpecRpdCapabilityCfg = h.bgpconfig.flowSpecRpdCapability();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530796 boolean isLsCapabilityCfg = h.bgpconfig.getLsCapability();
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530797 boolean isFlowSpecIpv4CapabilityCfg = false;
798 boolean isFlowSpecVpnv4CapabilityCfg = false;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530799 MultiProtocolExtnCapabilityTlv tempCapability;
800 boolean isMultiProtocolLsCapability = false;
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530801 boolean isMultiProtocolFlowSpecRpdCapability = false;
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530802 boolean isMultiProtocolFlowSpecCapability = false;
803 boolean isMultiProtocolVpnFlowSpecCapability = false;
Shashikanth VH580bdeb2016-02-19 17:26:03 +0530804 BgpCfg.FlowSpec flowSpec = h.bgpconfig.flowSpecCapability();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530805
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530806 if (flowSpec == BgpCfg.FlowSpec.IPV4) {
807 isFlowSpecIpv4CapabilityCfg = true;
808 } else if (flowSpec == BgpCfg.FlowSpec.VPNV4) {
809 isFlowSpecVpnv4CapabilityCfg = true;
810 } else if (flowSpec == BgpCfg.FlowSpec.IPV4_VPNV4) {
811 isFlowSpecIpv4CapabilityCfg = true;
812 isFlowSpecVpnv4CapabilityCfg = true;
Shashikanth VHdcfb7b52016-02-05 12:56:23 +0530813 }
814
Vidyashree Ramaee293252015-11-18 17:00:11 +0530815 while (listIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530816 BgpValueType tlv = listIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530817 if (tlv.getType() == MULTI_PROTOCOL_EXTN_CAPA_TYPE) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530818 tempCapability = (MultiProtocolExtnCapabilityTlv) tlv;
819 if (Constants.SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
820 isMultiProtocolFlowSpecCapability = true;
821 }
822
823 if (Constants.VPN_SAFI_FLOWSPEC_VALUE == tempCapability.getSafi()) {
824 isMultiProtocolVpnFlowSpecCapability = true;
825 }
826
827 if (SAFI == tempCapability.getSafi()) {
828 isMultiProtocolLsCapability = true;
829 }
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530830
831 if (Constants.SAFI_FLOWSPEC_RPD_VALUE == tempCapability.getSafi()) {
832 isMultiProtocolFlowSpecRpdCapability = true;
833 }
Vidyashree Ramaee293252015-11-18 17:00:11 +0530834 }
835 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
836 isFourOctetCapabilityExits = true;
837 capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
838 }
839 }
840
841 if (isFourOctetCapabilityExits) {
842 if (capAsNum > MAX_AS2_NUM) {
843 if (openmsg.getAsNumber() != AS_TRANS) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530844 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530845 }
846 } else {
847 if (capAsNum != openmsg.getAsNumber()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530848 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.BAD_PEER_AS, null);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530849 }
850 }
851 }
852
853 if ((isLsCapabilityCfg)) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530854 if (!isMultiProtocolLsCapability) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530855 tempTlv = new MultiProtocolExtnCapabilityTlv(AFI, RES, SAFI);
856 unSupportedCapabilityTlv.add(tempTlv);
857 }
858 }
859
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530860 if (isFlowSpecIpv4CapabilityCfg) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530861 if (!isMultiProtocolFlowSpecCapability) {
862 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
863 RES, Constants.SAFI_FLOWSPEC_VALUE);
864 unSupportedCapabilityTlv.add(tempTlv);
865 }
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530866 }
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530867
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530868 if (isFlowSpecVpnv4CapabilityCfg) {
Shashikanth VH0a82a8e2016-02-02 20:42:53 +0530869 if (!isMultiProtocolVpnFlowSpecCapability) {
870 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_VALUE,
871 RES, Constants.VPN_SAFI_FLOWSPEC_VALUE);
872 unSupportedCapabilityTlv.add(tempTlv);
873 }
874 }
875
Vidyashree Ramaee293252015-11-18 17:00:11 +0530876 if ((isLargeAsCapabilityCfg)) {
877 if (!isFourOctetCapabilityExits) {
878 tempTlv = new FourOctetAsNumCapabilityTlv(h.bgpconfig.getAsNumber());
879 unSupportedCapabilityTlv.add(tempTlv);
880 }
881 }
882
Shashikanth VHb650bfa2016-04-18 12:54:03 +0530883 if ((isFlowSpecRpdCapabilityCfg)) {
884 if (!isMultiProtocolFlowSpecRpdCapability) {
885 tempTlv = new MultiProtocolExtnCapabilityTlv(Constants.AFI_FLOWSPEC_RPD_VALUE,
886 RES, Constants.SAFI_FLOWSPEC_RPD_VALUE,
887 Constants.RPD_CAPABILITY_SEND_VALUE);
888 unSupportedCapabilityTlv.add(tempTlv);
889 }
890 }
891
892 if (unSupportedCapabilityTlv.size() == MAX_UNSUPPORTED_CAPABILITY) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530893 ChannelBuffer buffer = ChannelBuffers.dynamicBuffer();
894 while (unSupportedCaplistIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530895 BgpValueType tlv = unSupportedCaplistIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530896 tlv.write(buffer);
897 }
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530898 throw new BgpParseException(BgpErrorType.OPEN_MESSAGE_ERROR, BgpErrorType.UNSUPPORTED_CAPABILITY, buffer);
Vidyashree Ramaee293252015-11-18 17:00:11 +0530899 } else {
900 return true;
901 }
902 }
903
904 /**
905 * AS Number Validation.
906 *
907 * @param h channel Handler
908 * @param openMsg open message
909 * @return true or false
910 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530911 private boolean asNumberValidation(BgpChannelHandler h, BgpOpenMsg openMsg) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530912 log.debug("AS Num validation");
913
914 int capAsNum = 0;
915 boolean isFourOctetCapabilityExits = false;
916
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530917 BgpPeerCfg peerCfg = h.bgpconfig.displayPeers(peerAddr);
918 List<BgpValueType> capabilityTlv = openMsg.getCapabilityTlv();
919 ListIterator<BgpValueType> listIterator = capabilityTlv.listIterator();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530920
921 while (listIterator.hasNext()) {
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530922 BgpValueType tlv = listIterator.next();
Vidyashree Ramaee293252015-11-18 17:00:11 +0530923 if (tlv.getType() == FOUR_OCTET_AS_NUM_CAPA_TYPE) {
924 isFourOctetCapabilityExits = true;
925 capAsNum = ((FourOctetAsNumCapabilityTlv) tlv).getInt();
926 }
927 }
928
929 if (peerCfg.getAsNumber() > MAX_AS2_NUM) {
930 if (openMsg.getAsNumber() != AS_TRANS) {
931 return false;
932 }
933
934 if (!isFourOctetCapabilityExits) {
935 return false;
936 }
937
938 if (peerCfg.getAsNumber() != capAsNum) {
939 return false;
940 }
941
942 isIbgpSession = peerCfg.getIsIBgp();
943 if (isIbgpSession) {
944 // IBGP - AS number should be same for Peer and local if it is IBGP
945 if (h.bgpconfig.getAsNumber() != capAsNum) {
946 return false;
947 }
948 }
949 } else {
950
951 if (openMsg.getAsNumber() != peerCfg.getAsNumber()) {
952 return false;
953 }
954
955 if (isFourOctetCapabilityExits) {
956 if (capAsNum != peerCfg.getAsNumber()) {
957 return false;
958 }
959 }
960
961 isIbgpSession = peerCfg.getIsIBgp();
962 if (isIbgpSession) {
963 // IBGP - AS number should be same for Peer and local if it is IBGP
964 if (openMsg.getAsNumber() != h.bgpconfig.getAsNumber()) {
965 return false;
966 }
967 }
968 }
969 return true;
970 }
971
972 /**
973 * Validates BGP ID.
974 *
975 * @param openMsg open message
976 * @return true or false
977 */
Shashikanth VH5dd8dbe2015-11-26 13:22:18 +0530978 private boolean bgpIdValidation(BgpOpenMsg openMsg) {
Vidyashree Ramaee293252015-11-18 17:00:11 +0530979 String openMsgBgpId = Ip4Address.valueOf(openMsg.getBgpId()).toString();
980
981 InetAddress ipAddress;
982 try {
983 ipAddress = InetAddress.getByName(openMsgBgpId);
984 if (ipAddress.isMulticastAddress()) {
985 return false;
986 }
987 } catch (UnknownHostException e) {
988 log.debug("InetAddress convertion failed");
989 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530990 return true;
991 }
992}