blob: 4e419c8ffa6559ac0a72d7ec05a9ae1d441b712d [file] [log] [blame]
Satish Ke107e662015-09-21 19:00:17 +05301/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.bgp.controller.impl;
18
Shashikanth VH6de20d32015-10-09 12:04:13 +053019import java.io.IOException;
20import java.net.InetSocketAddress;
21import java.net.SocketAddress;
22import java.nio.channels.ClosedChannelException;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053023import java.util.Collections;
Shashikanth VH6de20d32015-10-09 12:04:13 +053024import java.util.Date;
25import java.util.List;
26import java.util.concurrent.RejectedExecutionException;
27
28import org.jboss.netty.channel.Channel;
29import org.jboss.netty.channel.ChannelHandlerContext;
30import org.jboss.netty.channel.ChannelStateEvent;
31import org.jboss.netty.channel.ExceptionEvent;
32import org.jboss.netty.channel.MessageEvent;
Satish Ke107e662015-09-21 19:00:17 +053033import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
Shashikanth VH6de20d32015-10-09 12:04:13 +053034import org.jboss.netty.handler.timeout.ReadTimeoutException;
35import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053036import org.onlab.packet.Ip4Address;
Shashikanth VH6de20d32015-10-09 12:04:13 +053037import org.onlab.packet.IpAddress;
38import org.onosproject.bgp.controller.BGPCfg;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053039import org.onosproject.bgp.controller.BGPController;
Shashikanth VH6de20d32015-10-09 12:04:13 +053040import org.onosproject.bgp.controller.BGPId;
41import org.onosproject.bgp.controller.BGPPeer;
42import org.onosproject.bgp.controller.BGPPeerCfg;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053043import org.onosproject.bgp.controller.impl.BGPControllerImpl.BGPPeerManagerImpl;
Shashikanth VH6de20d32015-10-09 12:04:13 +053044import org.onosproject.bgpio.exceptions.BGPParseException;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053045import org.onosproject.bgpio.protocol.BGPFactory;
Shashikanth VH6de20d32015-10-09 12:04:13 +053046import org.onosproject.bgpio.protocol.BGPMessage;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053047import org.onosproject.bgpio.protocol.BGPOpenMsg;
Shashikanth VH6de20d32015-10-09 12:04:13 +053048import org.onosproject.bgpio.protocol.BGPType;
49import org.onosproject.bgpio.protocol.BGPVersion;
50import org.slf4j.Logger;
51import org.slf4j.LoggerFactory;
Satish Ke107e662015-09-21 19:00:17 +053052
53/**
54 * Channel handler deals with the bgp peer connection and dispatches messages from peer to the appropriate locations.
55 */
56class BGPChannelHandler extends IdleStateAwareChannelHandler {
57
Shashikanth VH6de20d32015-10-09 12:04:13 +053058 private static final Logger log = LoggerFactory.getLogger(BGPChannelHandler.class);
59
60 static final int BGP_MAX_KEEPALIVE_INTERVAL = 3;
61 private BGPPeer bgpPeer;
62 private BGPId thisbgpId;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053063 private Channel channel;
Shashikanth VH6de20d32015-10-09 12:04:13 +053064 private BGPKeepAliveTimer keepAliveTimer = null;
65 private short peerHoldTime = 0;
66 private short negotiatedHoldTime = 0;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053067 private long peerAsNum;
Shashikanth VH6de20d32015-10-09 12:04:13 +053068 private int peerIdentifier;
69 private BGPPacketStatsImpl bgpPacketStats;
70 static final int MAX_WRONG_COUNT_PACKET = 5;
71
72 // State needs to be volatile because the HandshakeTimeoutHandler
73 // needs to check if the handshake is complete
74 private volatile ChannelState state;
75
76 // When a bgp peer with a ip addresss is found (i.e we already have a
77 // connected peer with the same ip), the new peer is immediately
78 // disconnected. At that point netty callsback channelDisconnected() which
Shashikanth VH9f8afb42015-11-04 18:00:30 +053079 // proceeds to cleaup peer state - we need to ensure that it does not
80 // cleanup
Shashikanth VH6de20d32015-10-09 12:04:13 +053081 // peer state for the older (still connected) peer
82 private volatile Boolean duplicateBGPIdFound;
83 // Indicates the bgp version used by this bgp peer
84 protected BGPVersion bgpVersion;
Shashikanth VH9f8afb42015-11-04 18:00:30 +053085 private BGPController bgpController;
86 protected BGPFactory factory4;
87 private boolean isIbgpSession;
88 private BgpSessionInfoImpl sessionInfo;
89 private BGPPeerManagerImpl peerManager;
Shashikanth VH6de20d32015-10-09 12:04:13 +053090 private InetSocketAddress inetAddress;
91 private IpAddress ipAddress;
92 private SocketAddress address;
93 private String peerAddr;
94 private BGPCfg bgpconfig;
95
Satish Ke107e662015-09-21 19:00:17 +053096 /**
97 * Create a new unconnected BGPChannelHandler.
98 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +053099 * @param bgpController bgp controller
Satish Ke107e662015-09-21 19:00:17 +0530100 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530101 BGPChannelHandler(BGPController bgpController) {
102 this.bgpController = bgpController;
103 this.peerManager = (BGPPeerManagerImpl) bgpController.peerManager();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530104 this.state = ChannelState.IDLE;
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530105 this.factory4 = Controller.getBGPMessageFactory4();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530106 this.duplicateBGPIdFound = Boolean.FALSE;
107 this.bgpPacketStats = new BGPPacketStatsImpl();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530108 this.bgpconfig = bgpController.getConfig();
Satish Ke107e662015-09-21 19:00:17 +0530109 }
Shashikanth VH6de20d32015-10-09 12:04:13 +0530110
111 // To disconnect peer session.
112 public void disconnectPeer() {
113 bgpPeer.disconnectPeer();
114 }
115
116 // *************************
117 // Channel State Machine
118 // *************************
119
120 /**
121 * The state machine for handling the peer/channel state. All state transitions should happen from within the state
122 * machine (and not from other parts of the code)
123 */
124 enum ChannelState {
125 /**
126 * Initial state before channel is connected.
127 */
128 IDLE(false) {
129
130 },
131
132 OPENSENT(false) {
133 @Override
134 void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
135 log.debug("message received in OPENSENT state");
136 // check for OPEN message
137 if (m.getType() != BGPType.OPEN) {
138 // When the message type is not keep alive message increment the wrong packet statistics
139 h.processUnknownMsg();
140 log.debug("Message is not OPEN message");
141 } else {
142 log.debug("Sending keep alive message in OPENSENT state");
143 h.bgpPacketStats.addInPacket();
144
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530145 BGPOpenMsg pOpenmsg = (BGPOpenMsg) m;
146 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530147
148 // validate capabilities and open msg
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530149 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530150 log.debug("Sending handshake OPEN message");
151
152 /*
153 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
154 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
155 * received in the OPEN message
156 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530157 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530158 if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
159 h.channel.getPipeline().replace("holdTime",
160 "holdTime",
161 new ReadTimeoutHandler(BGPPipelineFactory.TIMER,
162 h.peerHoldTime));
163 }
164
165 log.info("Hold Time : " + h.peerHoldTime);
166
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530167 // update AS number
168 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530169 }
170
171 // Send keepalive message to peer.
172 h.sendKeepAliveMessage();
173 h.bgpPacketStats.addOutPacket();
174 h.setState(OPENCONFIRM);
175 h.bgpconfig.setPeerConnState(h.peerAddr, BGPPeerCfg.State.OPENCONFIRM);
176 }
177 }
178 },
179
180 OPENWAIT(false) {
181 @Override
182 void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
183 log.debug("Message received in OPEN WAIT State");
184
185 // check for open message
186 if (m.getType() != BGPType.OPEN) {
187 // When the message type is not open message increment the wrong packet statistics
188 h.processUnknownMsg();
189 log.debug("Message is not OPEN message");
190 } else {
191 h.bgpPacketStats.addInPacket();
192
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530193 BGPOpenMsg pOpenmsg = (BGPOpenMsg) m;
194 h.peerIdentifier = pOpenmsg.getBgpId();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530195
196 // Validate open message
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530197 if (h.openMsgValidation(h, pOpenmsg)) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530198 log.debug("Sending handshake OPEN message");
199
200 /*
201 * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
202 * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
203 * received in the OPEN message
204 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530205 h.peerHoldTime = pOpenmsg.getHoldTime();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530206 if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
207 h.channel.getPipeline().replace("holdTime",
208 "holdTime",
209 new ReadTimeoutHandler(BGPPipelineFactory.TIMER,
210 h.peerHoldTime));
211 }
212
213 log.debug("Hold Time : " + h.peerHoldTime);
214
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530215 // update AS number
216 h.peerAsNum = pOpenmsg.getAsNumber();
Shashikanth VH6de20d32015-10-09 12:04:13 +0530217
218 h.sendHandshakeOpenMessage();
219 h.bgpPacketStats.addOutPacket();
220 h.setState(OPENCONFIRM);
221 }
222 }
223 }
224 },
225
226 OPENCONFIRM(false) {
227 @Override
228 void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
229 log.debug("Message received in OPENCONFIRM state");
230 // check for keep alive message
231 if (m.getType() != BGPType.KEEP_ALIVE) {
232 // When the message type is not keep alive message handle the wrong packet
233 h.processUnknownMsg();
234 log.debug("Message is not KEEPALIVE message");
235 } else {
236
237 // Set the peer connected status
238 h.bgpPacketStats.addInPacket();
239 log.debug("Sending keep alive message in OPENCONFIRM state");
240
241 final InetSocketAddress inetAddress = (InetSocketAddress) h.address;
242 h.thisbgpId = BGPId.bgpId(IpAddress.valueOf(inetAddress.getAddress()));
243
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530244 // set session parameters
245 h.negotiatedHoldTime = (h.peerHoldTime < h.bgpconfig.getHoldTime()) ? h.peerHoldTime
246 : h.bgpconfig.getHoldTime();
247 h.sessionInfo = new BgpSessionInfoImpl(h.thisbgpId, h.bgpVersion, h.peerAsNum, h.peerHoldTime,
248 h.peerIdentifier, h.negotiatedHoldTime, h.isIbgpSession);
249
250 h.bgpPeer = h.peerManager.getBGPPeerInstance(h.bgpController, h.sessionInfo, h.bgpPacketStats);
251 // set the status of bgp as connected
Shashikanth VH6de20d32015-10-09 12:04:13 +0530252 h.bgpPeer.setConnected(true);
253 h.bgpPeer.setChannel(h.channel);
254
Shashikanth VH6de20d32015-10-09 12:04:13 +0530255 /*
256 * RFC 4271, When an OPEN message is received, sends a KEEPALIVE message, If the negotiated hold
257 * time value is zero, then the HoldTimer and KeepaliveTimer are not started. A reasonable maximum
258 * time between KEEPALIVE messages would be one third of the Hold Time interval.
259 */
260 h.sendKeepAliveMessage();
261
262 if (h.negotiatedHoldTime != 0) {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530263 h.keepAliveTimer = new BGPKeepAliveTimer(h,
264 (h.negotiatedHoldTime / BGP_MAX_KEEPALIVE_INTERVAL));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530265 }
266
267 h.bgpPacketStats.addOutPacket();
268
269 // set the state handshake completion.
270 h.setHandshakeComplete(true);
271
272 if (!h.peerManager.addConnectedPeer(h.thisbgpId, h.bgpPeer)) {
273 /*
274 * RFC 4271, Section 6.8, Based on the value of the BGP identifier, a convention is established
275 * for detecting which BGP connection is to be preserved when a collision occurs. The convention
276 * is to compare the BGP Identifiers of the peers involved in the collision and to retain only
277 * the connection initiated by the BGP speaker with the higher-valued BGP Identifier..
278 */
279 // TODO: Connection collision handling.
280 disconnectDuplicate(h);
281 } else {
282 h.setState(ESTABLISHED);
283 h.bgpconfig.setPeerConnState(h.peerAddr, BGPPeerCfg.State.ESTABLISHED);
284 }
285 }
286 }
287 },
288
289 ESTABLISHED(true) {
290 @Override
291 void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
292 log.debug("Message received in established state " + m.getType());
293 // dispatch the message
294 h.dispatchMessage(m);
295 }
296 };
297
298 private boolean handshakeComplete;
299
300 ChannelState(boolean handshakeComplete) {
301 this.handshakeComplete = handshakeComplete;
302 }
303
304 /**
305 * Is this a state in which the handshake has completed?
306 *
307 * @return true if the handshake is complete
308 */
309 public boolean isHandshakeComplete() {
310 return this.handshakeComplete;
311 }
312
313 /**
314 * Disconnect duplicate peer connection.
315 *
316 * @param h channel handler
317 */
318 protected void disconnectDuplicate(BGPChannelHandler h) {
319 log.error("Duplicated BGP IP or incompleted cleanup - " + "" + "disconnecting channel {}",
320 h.getPeerInfoString());
321 h.duplicateBGPIdFound = Boolean.TRUE;
322 h.channel.disconnect();
323 }
324
325 // set handshake completion status
326 public void setHandshakeComplete(boolean handshakeComplete) {
327 this.handshakeComplete = handshakeComplete;
328 }
329
330 void processBGPMessage(BGPChannelHandler bgpChannelHandler, BGPMessage pm)
331 throws IOException, BGPParseException {
332 // TODO Auto-generated method stub
333 log.debug("BGP message stub");
334 }
335
336 }
337
338 // *************************
339 // Channel handler methods
340 // *************************
341
342 @Override
343 public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
344
345 channel = e.getChannel();
346 log.info("BGP connected from {}", channel.getRemoteAddress());
347
348 address = channel.getRemoteAddress();
349 if (!(address instanceof InetSocketAddress)) {
350 throw new IOException("Invalid peer connection.");
351 }
352
353 // Connection should establish only if local ip and Autonomous system number is configured.
354 if (bgpconfig.getState() != BGPCfg.State.IP_AS_CONFIGURED) {
355 channel.close();
356 log.info("BGP local AS and router ID not configured");
357 return;
358 }
359
360 inetAddress = (InetSocketAddress) address;
361 ipAddress = IpAddress.valueOf(inetAddress.getAddress());
362 peerAddr = ipAddress.toString();
363
364 // if peer is not configured disconnect session
365 if (!bgpconfig.isPeerConfigured(peerAddr)) {
366 log.debug("Peer is not configured {}", peerAddr);
367 channel.close();
368 return;
369 }
370
371 // if connection is already established close channel
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530372 if (peerManager.isPeerConnected(BGPId.bgpId(IpAddress.valueOf(peerAddr)))) {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530373 log.debug("Duplicate connection received, peer {}", peerAddr);
374 channel.close();
375 return;
376 }
377
378 if (null != channel.getPipeline().get("PassiveHandler")) {
379 log.info("BGP handle connection request from peer");
380 // Wait for open message from bgp peer
381 setState(ChannelState.OPENWAIT);
382 } else if (null != channel.getPipeline().get("ActiveHandler")) {
383 log.info("BGP handle connection response from peer");
384
385 sendHandshakeOpenMessage();
386 bgpPacketStats.addOutPacket();
387 setState(ChannelState.OPENSENT);
388 bgpconfig.setPeerConnState(peerAddr, BGPPeerCfg.State.OPENSENT);
389 }
390 }
391
392 @Override
393 public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
394
395 channel = e.getChannel();
396 log.info("BGP disconnected callback for bgp:{}. Cleaning up ...", getPeerInfoString());
397
398 address = channel.getRemoteAddress();
399 if (!(address instanceof InetSocketAddress)) {
400 throw new IOException("Invalid peer connection.");
401 }
402
403 inetAddress = (InetSocketAddress) address;
404 ipAddress = IpAddress.valueOf(inetAddress.getAddress());
405 peerAddr = ipAddress.toString();
406
407 if (thisbgpId != null) {
408 if (!duplicateBGPIdFound) {
409 // if the disconnected peer (on this ChannelHandler)
410 // was not one with a duplicate, it is safe to remove all
411 // state for it at the controller. Notice that if the disconnected
412 // peer was a duplicate-ip, calling the method below would clear
413 // all state for the original peer (with the same ip),
414 // which we obviously don't want.
415 log.debug("{}:removal called", getPeerInfoString());
416 if (bgpPeer != null) {
417 peerManager.removeConnectedPeer(thisbgpId);
418 }
419 } else {
420 // A duplicate was disconnected on this ChannelHandler,
421 // this is the same peer reconnecting, but the original state was
422 // not cleaned up - XXX check liveness of original ChannelHandler
423 log.debug("{}:duplicate found", getPeerInfoString());
424 duplicateBGPIdFound = Boolean.FALSE;
425 }
426
427 if (null != keepAliveTimer) {
428 keepAliveTimer.getKeepAliveTimer().cancel();
429 }
430 } else {
431 log.warn("No bgp ip in channelHandler registered for " + "disconnected peer {}", getPeerInfoString());
432 }
433 }
434
435 @Override
436 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
437
438 log.info("[exceptionCaught]: " + e.toString());
439
440 if (e.getCause() instanceof ReadTimeoutException) {
441 if ((ChannelState.OPENWAIT == state) || (ChannelState.OPENSENT == state)) {
442
443 // When ReadTimeout timer is expired in OPENWAIT/OPENSENT state, it is considered
444 // TODO: Send notification
445 channel.close();
446 state = ChannelState.IDLE;
447 return;
448 } else if (ChannelState.OPENCONFIRM == state) {
449
450 // When ReadTimeout timer is expired in OPENCONFIRM state.
451 // TODO: Send Notification
452 channel.close();
453 state = ChannelState.IDLE;
454 return;
455 }
456 } else if (e.getCause() instanceof ClosedChannelException) {
457 log.debug("Channel for bgp {} already closed", getPeerInfoString());
458 } else if (e.getCause() instanceof IOException) {
459 log.error("Disconnecting peer {} due to IO Error: {}", getPeerInfoString(), e.getCause().getMessage());
460 if (log.isDebugEnabled()) {
461 // still print stack trace if debug is enabled
462 log.debug("StackTrace for previous Exception: ", e.getCause());
463 }
464 channel.close();
465 } else if (e.getCause() instanceof BGPParseException) {
466 // TODO: SEND NOTIFICATION
467 log.debug("BGP Parse Exception: ", e.getCause());
468 } else if (e.getCause() instanceof RejectedExecutionException) {
469 log.warn("Could not process message: queue full");
470 } else {
471 log.error("Error while processing message from peer " + getPeerInfoString() + "state " + this.state);
472 channel.close();
473 }
474 }
475
476 @Override
477 public String toString() {
478 return getPeerInfoString();
479 }
480
481 @Override
482 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
483 if (e.getMessage() instanceof List) {
484 @SuppressWarnings("Unchecked")
485 List<BGPMessage> msglist = (List<BGPMessage>) e.getMessage();
486 for (BGPMessage pm : msglist) {
487 // Do the actual packet processing
488 state.processBGPMessage(this, pm);
489 }
490 } else {
491 state.processBGPMessage(this, (BGPMessage) e.getMessage());
492 }
493 }
494
495 // *************************
496 // Channel utility methods
497 // *************************
498 /**
499 * Set handshake status.
500 *
501 * @param handshakeComplete handshake complete status
502 */
503 public void setHandshakeComplete(boolean handshakeComplete) {
504 this.state.setHandshakeComplete(handshakeComplete);
505 }
506
507 /**
508 * Is this a state in which the handshake has completed?
509 *
510 * @return true if the handshake is complete
511 */
512 public boolean isHandshakeComplete() {
513 return state.isHandshakeComplete();
514 }
515
516 /**
517 * To handle the BGP message.
518 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530519 * @param m bgp message
520 * @throws BGPParseException throw exception
Shashikanth VH6de20d32015-10-09 12:04:13 +0530521 */
522 private void dispatchMessage(BGPMessage m) throws BGPParseException {
523 bgpPacketStats.addInPacket();
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530524 bgpController.processBGPPacket(thisbgpId, m);
Shashikanth VH6de20d32015-10-09 12:04:13 +0530525 }
526
527 /**
528 * Return a string describing this peer based on the already available information (ip address and/or remote
529 * socket).
530 *
531 * @return display string
532 */
533 private String getPeerInfoString() {
534 if (bgpPeer != null) {
535 return bgpPeer.toString();
536 }
537 String channelString;
538 if (channel == null || channel.getRemoteAddress() == null) {
539 channelString = "?";
540 } else {
541 channelString = channel.getRemoteAddress().toString();
542 }
543 String bgpIpString;
544 // TODO: implement functionality to get bgp id string
545 bgpIpString = "?";
546 return String.format("[%s BGP-IP[%s]]", channelString, bgpIpString);
547 }
548
549 /**
550 * Update the channels state. Only called from the state machine. TODO: enforce restricted state transitions
551 *
552 * @param state
553 */
554 private void setState(ChannelState state) {
555 this.state = state;
556 }
557
558 /**
559 * get packet statistics.
560 *
561 * @return packet statistics
562 */
563 public BGPPacketStatsImpl getBgpPacketStats() {
564 return bgpPacketStats;
565 }
566
567 /**
568 * Send handshake open message to the peer.
569 *
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530570 * @throws IOException, BGPParseException
Shashikanth VH6de20d32015-10-09 12:04:13 +0530571 */
572 private void sendHandshakeOpenMessage() throws IOException, BGPParseException {
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530573 int bgpId;
574
575 bgpId = Ip4Address.valueOf(bgpconfig.getRouterId()).toInt();
576 BGPMessage msg = factory4.openMessageBuilder().setAsNumber((short) bgpconfig.getAsNumber())
577 .setHoldTime(bgpconfig.getHoldTime()).setBgpId(bgpId).build();
578 log.debug("Sending open message to {}", channel.getRemoteAddress());
579 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530580
581 }
582
583 /**
584 * Send keep alive message.
585 *
586 * @throws IOException when channel is disconnected
587 * @throws BGPParseException while building keep alive message
588 */
589 synchronized void sendKeepAliveMessage() throws IOException, BGPParseException {
590
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530591 BGPMessage msg = factory4.keepaliveMessageBuilder().build();
592 log.debug("Sending keepalive message to {}", channel.getRemoteAddress());
593 channel.write(Collections.singletonList(msg));
Shashikanth VH6de20d32015-10-09 12:04:13 +0530594 }
595
596 /**
597 * Send notification and close channel with peer.
598 */
599 private void sendErrNotificationAndCloseChannel() {
600 // TODO: send notification
601 channel.close();
602 }
603
604 /**
605 * Process unknown BGP message received.
606 *
607 * @throws BGPParseException when received invalid message
608 */
609 public void processUnknownMsg() throws BGPParseException {
610 log.debug("UNKNOWN message received");
611 Date now = null;
612 if (bgpPacketStats.wrongPacketCount() == 0) {
613 now = new Date();
614 bgpPacketStats.setTime(now.getTime());
615 bgpPacketStats.addWrongPacket();
616 sendErrNotificationAndCloseChannel();
617 }
618 if (bgpPacketStats.wrongPacketCount() > 1) {
619 Date lastest = new Date();
620 bgpPacketStats.addWrongPacket();
621 // converting to seconds
622 if (((lastest.getTime() - bgpPacketStats.getTime()) / 1000) > 60) {
623 now = lastest;
624 bgpPacketStats.setTime(now.getTime());
625 bgpPacketStats.resetWrongPacket();
626 bgpPacketStats.addWrongPacket();
627 } else if (((int) (lastest.getTime() - now.getTime()) / 1000) < 60) {
628 if (MAX_WRONG_COUNT_PACKET <= bgpPacketStats.wrongPacketCount()) {
629 // reset once wrong packet count reaches MAX_WRONG_COUNT_PACKET
630 bgpPacketStats.resetWrongPacket();
631 // max wrong packets received send error message and close the session
632 sendErrNotificationAndCloseChannel();
633 }
634 }
635 }
636 }
637
638 /**
639 * Open message validation.
640 *
641 * @param h channel handler
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530642 * @param pOpenmsg open message
Shashikanth VH6de20d32015-10-09 12:04:13 +0530643 * @return true if validation succeed, otherwise false
644 * @throws BGPParseException when received invalid message
645 */
Shashikanth VH9f8afb42015-11-04 18:00:30 +0530646 public boolean openMsgValidation(BGPChannelHandler h, BGPOpenMsg pOpenmsg) throws BGPParseException {
Shashikanth VH6de20d32015-10-09 12:04:13 +0530647 // TODO: Open message validation.
648 return true;
649 }
650}