aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl')
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java601
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java179
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPKeepAliveTimer.java72
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java12
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerImpl.java191
-rwxr-xr-xframework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPSessionInfo.java149
6 files changed, 1190 insertions, 14 deletions
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
index 942d3658..c17736ed 100755
--- a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPChannelHandler.java
@@ -16,19 +16,616 @@
package org.onosproject.bgp.controller.impl;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.channels.ClosedChannelException;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.jboss.netty.channel.Channel;
+import org.jboss.netty.channel.ChannelHandlerContext;
+import org.jboss.netty.channel.ChannelStateEvent;
+import org.jboss.netty.channel.ExceptionEvent;
+import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.handler.timeout.IdleStateAwareChannelHandler;
+import org.jboss.netty.handler.timeout.ReadTimeoutException;
+import org.jboss.netty.handler.timeout.ReadTimeoutHandler;
+import org.onlab.packet.IpAddress;
+import org.onosproject.bgp.controller.BGPCfg;
+import org.onosproject.bgp.controller.BGPId;
+import org.onosproject.bgp.controller.BGPPeer;
+import org.onosproject.bgp.controller.BGPPeerCfg;
+import org.onosproject.bgp.controller.impl.BGPControllerImpl.BGPPeerManager;
+import org.onosproject.bgpio.exceptions.BGPParseException;
+import org.onosproject.bgpio.protocol.BGPMessage;
+//import org.onosproject.bgpio.protocol.BGPOpenMsg;
+import org.onosproject.bgpio.protocol.BGPType;
+import org.onosproject.bgpio.protocol.BGPVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Channel handler deals with the bgp peer connection and dispatches messages from peer to the appropriate locations.
*/
class BGPChannelHandler extends IdleStateAwareChannelHandler {
- // TODO: implement FSM and session handling mechanism
+ private static final Logger log = LoggerFactory.getLogger(BGPChannelHandler.class);
+
+ static final int BGP_MAX_KEEPALIVE_INTERVAL = 3;
+ private BGPPeer bgpPeer;
+ private BGPId thisbgpId;
+ Channel channel;
+ private BGPKeepAliveTimer keepAliveTimer = null;
+ private short peerHoldTime = 0;
+ private short negotiatedHoldTime = 0;
+ private short peerAsNum;
+ private int peerIdentifier;
+ private BGPPacketStatsImpl bgpPacketStats;
+ static final int MAX_WRONG_COUNT_PACKET = 5;
+
+ // State needs to be volatile because the HandshakeTimeoutHandler
+ // needs to check if the handshake is complete
+ private volatile ChannelState state;
+
+ // When a bgp peer with a ip addresss is found (i.e we already have a
+ // connected peer with the same ip), the new peer is immediately
+ // disconnected. At that point netty callsback channelDisconnected() which
+ // proceeds to cleaup peer state - we need to ensure that it does not cleanup
+ // peer state for the older (still connected) peer
+ private volatile Boolean duplicateBGPIdFound;
+ // Indicates the bgp version used by this bgp peer
+ protected BGPVersion bgpVersion;
+ private BGPControllerImpl bgpControllerImpl;
+ private BGPPeerManager peerManager;
+ private InetSocketAddress inetAddress;
+ private IpAddress ipAddress;
+ private SocketAddress address;
+ private String peerAddr;
+ private BGPCfg bgpconfig;
+
/**
* Create a new unconnected BGPChannelHandler.
*
* @param bgpCtrlImpl bgp controller implementation object
*/
BGPChannelHandler(BGPControllerImpl bgpCtrlImpl) {
+ this.bgpControllerImpl = bgpCtrlImpl;
+ this.peerManager = bgpCtrlImpl.getPeerManager();
+ this.state = ChannelState.IDLE;
+ this.duplicateBGPIdFound = Boolean.FALSE;
+ this.bgpPacketStats = new BGPPacketStatsImpl();
+ this.bgpconfig = bgpCtrlImpl.getConfig();
+ }
+
+ // To disconnect peer session.
+ public void disconnectPeer() {
+ bgpPeer.disconnectPeer();
+ }
+
+ // *************************
+ // Channel State Machine
+ // *************************
+
+ /**
+ * The state machine for handling the peer/channel state. All state transitions should happen from within the state
+ * machine (and not from other parts of the code)
+ */
+ enum ChannelState {
+ /**
+ * Initial state before channel is connected.
+ */
+ IDLE(false) {
+
+ },
+
+ OPENSENT(false) {
+ @Override
+ void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
+ log.debug("message received in OPENSENT state");
+ // check for OPEN message
+ if (m.getType() != BGPType.OPEN) {
+ // When the message type is not keep alive message increment the wrong packet statistics
+ h.processUnknownMsg();
+ log.debug("Message is not OPEN message");
+ } else {
+ log.debug("Sending keep alive message in OPENSENT state");
+ h.bgpPacketStats.addInPacket();
+
+ // TODO: initialize openmessage BGPOpenMsg pOpenmsg = (BGPOpenMsg) m;
+ // TODO: initialize identifier from open messgae h.peerIdentifier = pOpenmsg.getBgpId();
+
+ // validate capabilities and open msg
+ if (h.openMsgValidation(h)) {
+ log.debug("Sending handshake OPEN message");
+
+ /*
+ * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
+ * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
+ * received in the OPEN message
+ */
+ // TODO: initialize holdtime from open message h.peerHoldTime = pOpenmsg.getHoldTime();
+ if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
+ h.channel.getPipeline().replace("holdTime",
+ "holdTime",
+ new ReadTimeoutHandler(BGPPipelineFactory.TIMER,
+ h.peerHoldTime));
+ }
+
+ log.info("Hold Time : " + h.peerHoldTime);
+
+ // TODO: get AS number for open message update AS number
+ }
+
+ // Send keepalive message to peer.
+ h.sendKeepAliveMessage();
+ h.bgpPacketStats.addOutPacket();
+ h.setState(OPENCONFIRM);
+ h.bgpconfig.setPeerConnState(h.peerAddr, BGPPeerCfg.State.OPENCONFIRM);
+ }
+ }
+ },
+
+ OPENWAIT(false) {
+ @Override
+ void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
+ log.debug("Message received in OPEN WAIT State");
+
+ // check for open message
+ if (m.getType() != BGPType.OPEN) {
+ // When the message type is not open message increment the wrong packet statistics
+ h.processUnknownMsg();
+ log.debug("Message is not OPEN message");
+ } else {
+ h.bgpPacketStats.addInPacket();
+
+ // TODO: initialize open message BGPOpenMsg pOpenmsg = (BGPOpenMsg) m;
+
+ // Validate open message
+ if (h.openMsgValidation(h)) {
+ log.debug("Sending handshake OPEN message");
+
+ /*
+ * RFC 4271, section 4.2: Upon receipt of an OPEN message, a BGP speaker MUST calculate the
+ * value of the Hold Timer by using the smaller of its configured Hold Time and the Hold Time
+ * received in the OPEN message
+ */
+ // TODO: get hold time from open message h.peerHoldTime = pOpenmsg.getHoldTime();
+ if (h.peerHoldTime < h.bgpconfig.getHoldTime()) {
+ h.channel.getPipeline().replace("holdTime",
+ "holdTime",
+ new ReadTimeoutHandler(BGPPipelineFactory.TIMER,
+ h.peerHoldTime));
+ }
+
+ log.debug("Hold Time : " + h.peerHoldTime);
+
+ //TODO: update AS number form open messsage update AS number
+
+ h.sendHandshakeOpenMessage();
+ h.bgpPacketStats.addOutPacket();
+ h.setState(OPENCONFIRM);
+ }
+ }
+ }
+ },
+
+ OPENCONFIRM(false) {
+ @Override
+ void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
+ log.debug("Message received in OPENCONFIRM state");
+ // check for keep alive message
+ if (m.getType() != BGPType.KEEP_ALIVE) {
+ // When the message type is not keep alive message handle the wrong packet
+ h.processUnknownMsg();
+ log.debug("Message is not KEEPALIVE message");
+ } else {
+
+ // Set the peer connected status
+ h.bgpPacketStats.addInPacket();
+ log.debug("Sending keep alive message in OPENCONFIRM state");
+
+ final InetSocketAddress inetAddress = (InetSocketAddress) h.address;
+ h.thisbgpId = BGPId.bgpId(IpAddress.valueOf(inetAddress.getAddress()));
+
+ h.bgpPeer = h.peerManager.getBGPPeerInstance(h.thisbgpId, h.bgpVersion, h.bgpPacketStats);
+ // set the status fo bgp as connected
+ h.bgpPeer.setConnected(true);
+ h.bgpPeer.setChannel(h.channel);
+
+ // set specific parameters to bgp peer
+ h.bgpPeer.setBgpPeerVersion(h.bgpVersion);
+ h.bgpPeer.setBgpPeerASNum(h.peerAsNum);
+ h.bgpPeer.setBgpPeerHoldTime(h.peerHoldTime);
+ h.bgpPeer.setBgpPeerIdentifier(h.peerIdentifier);
+
+ h.negotiatedHoldTime = (h.peerHoldTime < h.bgpconfig.getHoldTime()) ? h.peerHoldTime : h.bgpconfig
+ .getHoldTime();
+ h.bgpPeer.setNegotiatedHoldTime(h.negotiatedHoldTime);
+ /*
+ * RFC 4271, When an OPEN message is received, sends a KEEPALIVE message, If the negotiated hold
+ * time value is zero, then the HoldTimer and KeepaliveTimer are not started. A reasonable maximum
+ * time between KEEPALIVE messages would be one third of the Hold Time interval.
+ */
+ h.sendKeepAliveMessage();
+
+ if (h.negotiatedHoldTime != 0) {
+ h.keepAliveTimer
+ = new BGPKeepAliveTimer(h, (h.negotiatedHoldTime / BGP_MAX_KEEPALIVE_INTERVAL));
+ }
+
+ h.bgpPacketStats.addOutPacket();
+
+ // set the state handshake completion.
+ h.setHandshakeComplete(true);
+
+ if (!h.peerManager.addConnectedPeer(h.thisbgpId, h.bgpPeer)) {
+ /*
+ * RFC 4271, Section 6.8, Based on the value of the BGP identifier, a convention is established
+ * for detecting which BGP connection is to be preserved when a collision occurs. The convention
+ * is to compare the BGP Identifiers of the peers involved in the collision and to retain only
+ * the connection initiated by the BGP speaker with the higher-valued BGP Identifier..
+ */
+ // TODO: Connection collision handling.
+ disconnectDuplicate(h);
+ } else {
+ h.setState(ESTABLISHED);
+ h.bgpconfig.setPeerConnState(h.peerAddr, BGPPeerCfg.State.ESTABLISHED);
+ }
+ }
+ }
+ },
+
+ ESTABLISHED(true) {
+ @Override
+ void processBGPMessage(BGPChannelHandler h, BGPMessage m) throws IOException, BGPParseException {
+ log.debug("Message received in established state " + m.getType());
+ // dispatch the message
+ h.dispatchMessage(m);
+ }
+ };
+
+ private boolean handshakeComplete;
+
+ ChannelState(boolean handshakeComplete) {
+ this.handshakeComplete = handshakeComplete;
+ }
+
+ /**
+ * Is this a state in which the handshake has completed?
+ *
+ * @return true if the handshake is complete
+ */
+ public boolean isHandshakeComplete() {
+ return this.handshakeComplete;
+ }
+
+ /**
+ * Disconnect duplicate peer connection.
+ *
+ * @param h channel handler
+ */
+ protected void disconnectDuplicate(BGPChannelHandler h) {
+ log.error("Duplicated BGP IP or incompleted cleanup - " + "" + "disconnecting channel {}",
+ h.getPeerInfoString());
+ h.duplicateBGPIdFound = Boolean.TRUE;
+ h.channel.disconnect();
+ }
+
+ // set handshake completion status
+ public void setHandshakeComplete(boolean handshakeComplete) {
+ this.handshakeComplete = handshakeComplete;
+ }
+
+ void processBGPMessage(BGPChannelHandler bgpChannelHandler, BGPMessage pm)
+ throws IOException, BGPParseException {
+ // TODO Auto-generated method stub
+ log.debug("BGP message stub");
+ }
+
+ }
+
+ // *************************
+ // Channel handler methods
+ // *************************
+
+ @Override
+ public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+
+ channel = e.getChannel();
+ log.info("BGP connected from {}", channel.getRemoteAddress());
+
+ address = channel.getRemoteAddress();
+ if (!(address instanceof InetSocketAddress)) {
+ throw new IOException("Invalid peer connection.");
+ }
+
+ // Connection should establish only if local ip and Autonomous system number is configured.
+ if (bgpconfig.getState() != BGPCfg.State.IP_AS_CONFIGURED) {
+ channel.close();
+ log.info("BGP local AS and router ID not configured");
+ return;
+ }
+
+ inetAddress = (InetSocketAddress) address;
+ ipAddress = IpAddress.valueOf(inetAddress.getAddress());
+ peerAddr = ipAddress.toString();
+
+ // if peer is not configured disconnect session
+ if (!bgpconfig.isPeerConfigured(peerAddr)) {
+ log.debug("Peer is not configured {}", peerAddr);
+ channel.close();
+ return;
+ }
+
+ // if connection is already established close channel
+ if (peerManager.isPeerConnected(peerAddr)) {
+ log.debug("Duplicate connection received, peer {}", peerAddr);
+ channel.close();
+ return;
+ }
+
+ if (null != channel.getPipeline().get("PassiveHandler")) {
+ log.info("BGP handle connection request from peer");
+ // Wait for open message from bgp peer
+ setState(ChannelState.OPENWAIT);
+ } else if (null != channel.getPipeline().get("ActiveHandler")) {
+ log.info("BGP handle connection response from peer");
+
+ sendHandshakeOpenMessage();
+ bgpPacketStats.addOutPacket();
+ setState(ChannelState.OPENSENT);
+ bgpconfig.setPeerConnState(peerAddr, BGPPeerCfg.State.OPENSENT);
+ }
+ }
+
+ @Override
+ public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
+
+ channel = e.getChannel();
+ log.info("BGP disconnected callback for bgp:{}. Cleaning up ...", getPeerInfoString());
+
+ address = channel.getRemoteAddress();
+ if (!(address instanceof InetSocketAddress)) {
+ throw new IOException("Invalid peer connection.");
+ }
+
+ inetAddress = (InetSocketAddress) address;
+ ipAddress = IpAddress.valueOf(inetAddress.getAddress());
+ peerAddr = ipAddress.toString();
+
+ if (thisbgpId != null) {
+ if (!duplicateBGPIdFound) {
+ // if the disconnected peer (on this ChannelHandler)
+ // was not one with a duplicate, it is safe to remove all
+ // state for it at the controller. Notice that if the disconnected
+ // peer was a duplicate-ip, calling the method below would clear
+ // all state for the original peer (with the same ip),
+ // which we obviously don't want.
+ log.debug("{}:removal called", getPeerInfoString());
+ if (bgpPeer != null) {
+ peerManager.removeConnectedPeer(thisbgpId);
+ }
+ } else {
+ // A duplicate was disconnected on this ChannelHandler,
+ // this is the same peer reconnecting, but the original state was
+ // not cleaned up - XXX check liveness of original ChannelHandler
+ log.debug("{}:duplicate found", getPeerInfoString());
+ duplicateBGPIdFound = Boolean.FALSE;
+ }
+
+ if (null != keepAliveTimer) {
+ keepAliveTimer.getKeepAliveTimer().cancel();
+ }
+ } else {
+ log.warn("No bgp ip in channelHandler registered for " + "disconnected peer {}", getPeerInfoString());
+ }
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
+
+ log.info("[exceptionCaught]: " + e.toString());
+
+ if (e.getCause() instanceof ReadTimeoutException) {
+ if ((ChannelState.OPENWAIT == state) || (ChannelState.OPENSENT == state)) {
+
+ // When ReadTimeout timer is expired in OPENWAIT/OPENSENT state, it is considered
+ // TODO: Send notification
+ channel.close();
+ state = ChannelState.IDLE;
+ return;
+ } else if (ChannelState.OPENCONFIRM == state) {
+
+ // When ReadTimeout timer is expired in OPENCONFIRM state.
+ // TODO: Send Notification
+ channel.close();
+ state = ChannelState.IDLE;
+ return;
+ }
+ } else if (e.getCause() instanceof ClosedChannelException) {
+ log.debug("Channel for bgp {} already closed", getPeerInfoString());
+ } else if (e.getCause() instanceof IOException) {
+ log.error("Disconnecting peer {} due to IO Error: {}", getPeerInfoString(), e.getCause().getMessage());
+ if (log.isDebugEnabled()) {
+ // still print stack trace if debug is enabled
+ log.debug("StackTrace for previous Exception: ", e.getCause());
+ }
+ channel.close();
+ } else if (e.getCause() instanceof BGPParseException) {
+ // TODO: SEND NOTIFICATION
+ log.debug("BGP Parse Exception: ", e.getCause());
+ } else if (e.getCause() instanceof RejectedExecutionException) {
+ log.warn("Could not process message: queue full");
+ } else {
+ log.error("Error while processing message from peer " + getPeerInfoString() + "state " + this.state);
+ channel.close();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getPeerInfoString();
+ }
+
+ @Override
+ public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
+ if (e.getMessage() instanceof List) {
+ @SuppressWarnings("Unchecked")
+ List<BGPMessage> msglist = (List<BGPMessage>) e.getMessage();
+ for (BGPMessage pm : msglist) {
+ // Do the actual packet processing
+ state.processBGPMessage(this, pm);
+ }
+ } else {
+ state.processBGPMessage(this, (BGPMessage) e.getMessage());
+ }
+ }
+
+ // *************************
+ // Channel utility methods
+ // *************************
+ /**
+ * Set handshake status.
+ *
+ * @param handshakeComplete handshake complete status
+ */
+ public void setHandshakeComplete(boolean handshakeComplete) {
+ this.state.setHandshakeComplete(handshakeComplete);
+ }
+
+ /**
+ * Is this a state in which the handshake has completed?
+ *
+ * @return true if the handshake is complete
+ */
+ public boolean isHandshakeComplete() {
+ return state.isHandshakeComplete();
+ }
+
+ /**
+ * To handle the BGP message.
+ *
+ * @param m BGP message
+ */
+ private void dispatchMessage(BGPMessage m) throws BGPParseException {
+ bgpPacketStats.addInPacket();
+ bgpControllerImpl.processBGPPacket(thisbgpId, m);
+ }
+
+ /**
+ * Return a string describing this peer based on the already available information (ip address and/or remote
+ * socket).
+ *
+ * @return display string
+ */
+ private String getPeerInfoString() {
+ if (bgpPeer != null) {
+ return bgpPeer.toString();
+ }
+ String channelString;
+ if (channel == null || channel.getRemoteAddress() == null) {
+ channelString = "?";
+ } else {
+ channelString = channel.getRemoteAddress().toString();
+ }
+ String bgpIpString;
+ // TODO: implement functionality to get bgp id string
+ bgpIpString = "?";
+ return String.format("[%s BGP-IP[%s]]", channelString, bgpIpString);
+ }
+
+ /**
+ * Update the channels state. Only called from the state machine. TODO: enforce restricted state transitions
+ *
+ * @param state
+ */
+ private void setState(ChannelState state) {
+ this.state = state;
+ }
+
+ /**
+ * get packet statistics.
+ *
+ * @return packet statistics
+ */
+ public BGPPacketStatsImpl getBgpPacketStats() {
+ return bgpPacketStats;
+ }
+
+ /**
+ * Send handshake open message to the peer.
+ *
+ * @throws IOException ,BGPParseException
+ */
+ private void sendHandshakeOpenMessage() throws IOException, BGPParseException {
+ // TODO: send open message.
+
+ }
+
+ /**
+ * Send keep alive message.
+ *
+ * @throws IOException when channel is disconnected
+ * @throws BGPParseException while building keep alive message
+ */
+ synchronized void sendKeepAliveMessage() throws IOException, BGPParseException {
+
+ // TODO: send keep alive message.
+ }
+
+ /**
+ * Send notification and close channel with peer.
+ */
+ private void sendErrNotificationAndCloseChannel() {
+ // TODO: send notification
+ channel.close();
+ }
+
+ /**
+ * Process unknown BGP message received.
+ *
+ * @throws BGPParseException when received invalid message
+ */
+ public void processUnknownMsg() throws BGPParseException {
+ log.debug("UNKNOWN message received");
+ Date now = null;
+ if (bgpPacketStats.wrongPacketCount() == 0) {
+ now = new Date();
+ bgpPacketStats.setTime(now.getTime());
+ bgpPacketStats.addWrongPacket();
+ sendErrNotificationAndCloseChannel();
+ }
+ if (bgpPacketStats.wrongPacketCount() > 1) {
+ Date lastest = new Date();
+ bgpPacketStats.addWrongPacket();
+ // converting to seconds
+ if (((lastest.getTime() - bgpPacketStats.getTime()) / 1000) > 60) {
+ now = lastest;
+ bgpPacketStats.setTime(now.getTime());
+ bgpPacketStats.resetWrongPacket();
+ bgpPacketStats.addWrongPacket();
+ } else if (((int) (lastest.getTime() - now.getTime()) / 1000) < 60) {
+ if (MAX_WRONG_COUNT_PACKET <= bgpPacketStats.wrongPacketCount()) {
+ // reset once wrong packet count reaches MAX_WRONG_COUNT_PACKET
+ bgpPacketStats.resetWrongPacket();
+ // max wrong packets received send error message and close the session
+ sendErrNotificationAndCloseChannel();
+ }
+ }
+ }
+ }
+
+ /**
+ * Open message validation.
+ *
+ * @param h channel handler
+ * @return true if validation succeed, otherwise false
+ * @throws BGPParseException when received invalid message
+ */
+ public boolean openMsgValidation(BGPChannelHandler h) throws BGPParseException {
+ // TODO: Open message validation.
+ return true;
}
-} \ No newline at end of file
+}
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java
index 95eafdbc..d8378e31 100755
--- a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPControllerImpl.java
@@ -17,16 +17,24 @@
package org.onosproject.bgp.controller.impl;
import static org.onlab.util.Tools.groupedThreads;
+
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
import org.onosproject.bgp.controller.BGPCfg;
import org.onosproject.bgp.controller.BGPController;
import org.onosproject.bgp.controller.BGPId;
+import org.onosproject.bgp.controller.BGPPacketStats;
+import org.onosproject.bgp.controller.BGPPeer;
import org.onosproject.bgpio.protocol.BGPMessage;
+import org.onosproject.bgpio.protocol.BGPVersion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,8 +50,10 @@ public class BGPControllerImpl implements BGPController {
private final ExecutorService executorBarrier = Executors.newFixedThreadPool(4,
groupedThreads("onos/bgp",
- "event-barrier-%d"));
+ "event-barrier-%d"));
+ protected ConcurrentHashMap<BGPId, BGPPeer> connectedPeers = new ConcurrentHashMap<BGPId, BGPPeer>();
+ protected BGPPeerManager peerManager = new BGPPeerManager();
final Controller ctrl = new Controller(this);
private BGPConfig bgpconfig = new BGPConfig();
@@ -57,11 +67,22 @@ public class BGPControllerImpl implements BGPController {
@Deactivate
public void deactivate() {
// Close all connected peers
+ closeConnectedPeers();
this.ctrl.stop();
log.info("Stopped");
}
@Override
+ public Iterable<BGPPeer> getPeers() {
+ return this.connectedPeers.values();
+ }
+
+ @Override
+ public BGPPeer getPeer(BGPId bgpId) {
+ return this.connectedPeers.get(bgpId);
+ }
+
+ @Override
public void writeMsg(BGPId bgpId, BGPMessage msg) {
// TODO: Send message
}
@@ -88,17 +109,167 @@ public class BGPControllerImpl implements BGPController {
}
}
+ @Override
+ public void closeConnectedPeers() {
+ BGPPeer bgpPeer;
+ for (BGPId id : this.connectedPeers.keySet()) {
+ bgpPeer = getPeer(id);
+ bgpPeer.disconnectPeer();
+ }
+ }
+
/**
- * Get controller instance.
- *
- * @return ctrl the controller.
+ * Implementation of an BGP Peer which is responsible for keeping track of connected peers and the state in which
+ * they are.
*/
+ public class BGPPeerManager {
+
+ private final Logger log = LoggerFactory.getLogger(BGPPeerManager.class);
+ private final Lock peerLock = new ReentrantLock();
+
+ /**
+ * Add a BGP peer that has just connected to the system.
+ *
+ * @param bgpId the id of bgp peer to add
+ * @param bgpPeer the actual bgp peer object.
+ * @return true if added, false otherwise.
+ */
+ public boolean addConnectedPeer(BGPId bgpId, BGPPeer bgpPeer) {
+
+ if (connectedPeers.get(bgpId) != null) {
+ this.log.error("Trying to add connectedPeer but found previous " + "value for bgp ip: {}",
+ bgpId.toString());
+ return false;
+ } else {
+ this.log.debug("Added Peer {}", bgpId.toString());
+ connectedPeers.put(bgpId, bgpPeer);
+ return true;
+ }
+ }
+
+ /**
+ * Checks if the activation for this bgp peer is valid.
+ *
+ * @param bgpId the id of bgp peer to check
+ * @return true if valid, false otherwise
+ */
+ public boolean isPeerConnected(BGPId bgpId) {
+ if (connectedPeers.get(bgpId) == null) {
+ this.log.error("Trying to activate peer but is not in " + "connected peer: bgpIp {}. Aborting ..",
+ bgpId.toString());
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if the activation for this bgp peer is valid.
+ *
+ * @param routerid the routerid of bgp peer to check
+ * @return true if valid, false otherwise
+ */
+ public boolean isPeerConnected(String routerid) {
+
+ final BGPId bgpId;
+ bgpId = BGPId.bgpId(IpAddress.valueOf(routerid));
+
+ if (connectedPeers.get(bgpId) != null) {
+ this.log.info("Peer connection exist ");
+ return true;
+ }
+ this.log.info("Initiate connect request to " + "peer: bgpIp {}", bgpId.toString());
+
+ return false;
+ }
+
+ /**
+ * Clear all state in controller peer maps for a bgp peer that has
+ * disconnected from the local controller.
+ *
+ * @param bgpId the id of bgp peer to remove.
+ */
+ public void removeConnectedPeer(BGPId bgpId) {
+ connectedPeers.remove(bgpId);
+ }
+
+ /**
+ * Clear all state in controller peer maps for a bgp peer that has
+ * disconnected from the local controller.
+ *
+ * @param routerid the router id of bgp peer to remove.
+ */
+ public void removeConnectedPeer(String routerid) {
+ final BGPId bgpId;
+
+ bgpId = BGPId.bgpId(IpAddress.valueOf(routerid));
+
+ connectedPeers.remove(bgpId);
+ }
+
+ /**
+ * Gets bgp peer for connected peer map.
+ *
+ * @param routerid router id
+ * @return peer if available, null otherwise
+ */
+ public BGPPeer getPeer(String routerid) {
+ final BGPId bgpId;
+ bgpId = BGPId.bgpId(IpAddress.valueOf(routerid));
+
+ return connectedPeers.get(bgpId);
+ }
+
+ /**
+ * Gets bgp peer instance.
+ *
+ * @param bgpId bgp identifier.
+ * @param pv bgp version.
+ * @param pktStats packet statistics.
+ * @return BGPPeer peer instance.
+ */
+ public BGPPeer getBGPPeerInstance(BGPId bgpId, BGPVersion pv, BGPPacketStats pktStats) {
+ BGPPeer bgpPeer = new BGPPeerImpl();
+ bgpPeer.init(bgpId, pv, pktStats);
+ return bgpPeer;
+ }
+
+ }
+
+ /**
+ * Gets controller instance.
+ *
+ * @return Controller instance.
+ */
public Controller getController() {
return ctrl;
}
+ /**
+ * Gets connected peers.
+ *
+ * @return connectedPeers from connected Peers Map.
+ */
+ public ConcurrentHashMap<BGPId, BGPPeer> getConnectedPeers() {
+ return connectedPeers;
+ }
+
+ /**
+ * Gets peer manager.
+ *
+ * @return peerManager.
+ */
+ public BGPPeerManager getPeerManager() {
+ return peerManager;
+ }
+
@Override
public BGPCfg getConfig() {
return this.bgpconfig;
}
+
+ @Override
+ public int getBGPConnNumber() {
+ return connectedPeers.size();
+ }
} \ No newline at end of file
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPKeepAliveTimer.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPKeepAliveTimer.java
new file mode 100755
index 00000000..1c95804a
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPKeepAliveTimer.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgp.controller.impl;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implement sending keepalive message to connected peer periodically based on negotiated holdtime.
+ */
+public class BGPKeepAliveTimer {
+
+ private Timer keepAliveTimer;
+ private BGPChannelHandler handler;
+ private static final Logger log = LoggerFactory.getLogger(BGPKeepAliveTimer.class);
+
+ /**
+ * Gets keepalive timer object.
+ *
+ * @return keepAliveTimer keepalive timer.
+ */
+ public Timer getKeepAliveTimer() {
+ return keepAliveTimer;
+ }
+
+ /**
+ * Initialize timer to send keepalive message periodically.
+ *
+ * @param h channel handler
+ * @param seconds time interval.
+ */
+ public BGPKeepAliveTimer(BGPChannelHandler h, int seconds) {
+ this.handler = h;
+ this.keepAliveTimer = new Timer();
+ this.keepAliveTimer.schedule(new SendKeepAlive(), 0, seconds * 1000);
+ }
+
+ /**
+ * Send keepalive message to connected peer on schedule.
+ */
+ class SendKeepAlive extends TimerTask {
+ @Override
+ public void run() {
+ log.debug("Sending periodic KeepAlive");
+
+ try {
+ // Send keep alive message
+ handler.sendKeepAliveMessage();
+ handler.getBgpPacketStats().addOutPacket();
+ } catch (Exception e) {
+ log.info("Exception occured while sending keepAlive message" + e.toString());
+ }
+ }
+ }
+}
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java
index 41407dc4..09f4d452 100755
--- a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPacketStatsImpl.java
@@ -43,8 +43,7 @@ public class BGPPacketStatsImpl implements BGPPacketStats {
/**
* Get the outgoing packet count number.
*
- * @return
- * packet count
+ * @return packet count
*/
public int outPacketCount() {
return outPacketCount;
@@ -53,8 +52,7 @@ public class BGPPacketStatsImpl implements BGPPacketStats {
/**
* Get the incoming packet count number.
*
- * @return
- * packet count
+ * @return packet count
*/
public int inPacketCount() {
return inPacketCount;
@@ -63,8 +61,7 @@ public class BGPPacketStatsImpl implements BGPPacketStats {
/**
* Get the wrong packet count number.
*
- * @return
- * packet count
+ * @return packet count
*/
public int wrongPacketCount() {
return wrongPacketCount;
@@ -110,8 +107,7 @@ public class BGPPacketStatsImpl implements BGPPacketStats {
/**
* Get the time.
*
- * @return
- * time
+ * @return time
*/
public long getTime() {
return this.time;
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerImpl.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerImpl.java
new file mode 100755
index 00000000..212b24d3
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerImpl.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgp.controller.impl;
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.jboss.netty.channel.Channel;
+import org.onlab.packet.IpAddress;
+import org.onosproject.bgp.controller.BGPId;
+import org.onosproject.bgp.controller.BGPPacketStats;
+import org.onosproject.bgp.controller.BGPPeer;
+import org.onosproject.bgpio.protocol.BGPMessage;
+import org.onosproject.bgpio.protocol.BGPVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * BGPPeerImpl implements BGPPeer, maintains peer information and store updates in RIB .
+ */
+public class BGPPeerImpl implements BGPPeer {
+
+ protected final Logger log = LoggerFactory.getLogger(BGPPeerImpl.class);
+
+ private static final String SHUTDOWN_MSG = "Worker has already been shutdown";
+
+ private Channel channel;
+ protected String channelId;
+ private boolean connected;
+ protected boolean isHandShakeComplete = false;
+ public BGPSessionInfo sessionInfo;
+ private BGPPacketStatsImpl pktStats;
+
+ @Override
+ public void init(BGPId bgpId, BGPVersion bgpVersion, BGPPacketStats pktStats) {
+ this.sessionInfo.setRemoteBgpId(bgpId);
+ this.sessionInfo.setRemoteBgpVersion(bgpVersion);
+ this.pktStats = (BGPPacketStatsImpl) pktStats;
+ this.sessionInfo = new BGPSessionInfo();
+ }
+
+ // ************************
+ // Channel related
+ // ************************
+
+ @Override
+ public final void disconnectPeer() {
+ this.channel.close();
+ }
+
+ @Override
+ public final void sendMessage(BGPMessage m) {
+ log.debug("Sending message to {}", channel.getRemoteAddress());
+ try {
+ channel.write(Collections.singletonList(m));
+ this.pktStats.addOutPacket();
+ } catch (RejectedExecutionException e) {
+ log.warn(e.getMessage());
+ if (!e.getMessage().contains(SHUTDOWN_MSG)) {
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public final void sendMessage(List<BGPMessage> msgs) {
+ try {
+ channel.write(msgs);
+ this.pktStats.addOutPacket(msgs.size());
+ } catch (RejectedExecutionException e) {
+ log.warn(e.getMessage());
+ if (!e.getMessage().contains(SHUTDOWN_MSG)) {
+ throw e;
+ }
+ }
+ }
+
+ @Override
+ public final boolean isConnected() {
+ return this.connected;
+ }
+
+ @Override
+ public final void setConnected(boolean connected) {
+ this.connected = connected;
+ };
+
+ @Override
+ public final void setChannel(Channel channel) {
+ this.channel = channel;
+ final SocketAddress address = channel.getRemoteAddress();
+ if (address instanceof InetSocketAddress) {
+ final InetSocketAddress inetAddress = (InetSocketAddress) address;
+ final IpAddress ipAddress = IpAddress.valueOf(inetAddress.getAddress());
+ if (ipAddress.isIp4()) {
+ channelId = ipAddress.toString() + ':' + inetAddress.getPort();
+ } else {
+ channelId = '[' + ipAddress.toString() + "]:" + inetAddress.getPort();
+ }
+ }
+ };
+
+ @Override
+ public final Channel getChannel() {
+ return this.channel;
+ };
+
+ @Override
+ public String channelId() {
+ return channelId;
+ }
+
+ // ************************
+ // BGP Peer features related
+ // ************************
+
+ @Override
+ public final BGPId getBGPId() {
+ return this.sessionInfo.getRemoteBgpId();
+ };
+
+ @Override
+ public final String getStringId() {
+ return this.sessionInfo.getRemoteBgpId().toString();
+ }
+
+ @Override
+ public final void setBgpPeerVersion(BGPVersion peerVersion) {
+ this.sessionInfo.setRemoteBgpVersion(peerVersion);
+ }
+
+ @Override
+ public void setBgpPeerASNum(short peerASNum) {
+ this.sessionInfo.setRemoteBgpASNum(peerASNum);
+ }
+
+ @Override
+ public void setBgpPeerHoldTime(short peerHoldTime) {
+ this.sessionInfo.setRemoteBgpHoldTime(peerHoldTime);
+ }
+
+ @Override
+ public void setBgpPeerIdentifier(int peerIdentifier) {
+ this.sessionInfo.setRemoteBgpIdentifier(peerIdentifier);
+ }
+
+ @Override
+ public int getBgpPeerIdentifier() {
+ return this.sessionInfo.getRemoteBgpIdentifier();
+ }
+
+ @Override
+ public int getNegotiatedHoldTime() {
+ return this.sessionInfo.getNegotiatedholdTime();
+ }
+
+ @Override
+ public void setNegotiatedHoldTime(short negotiatedHoldTime) {
+ this.sessionInfo.setNegotiatedholdTime(negotiatedHoldTime);
+ }
+
+ @Override
+ public boolean isHandshakeComplete() {
+ return isHandShakeComplete;
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass()).omitNullValues().add("channel", channelId())
+ .add("bgpId", getBGPId()).toString();
+ }
+}
diff --git a/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPSessionInfo.java b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPSessionInfo.java
new file mode 100755
index 00000000..207d7831
--- /dev/null
+++ b/framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPSessionInfo.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.bgp.controller.impl;
+
+import org.onosproject.bgp.controller.BGPId;
+import org.onosproject.bgpio.protocol.BGPVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class maintains BGP peer session info.
+ */
+public class BGPSessionInfo {
+
+ protected final Logger log = LoggerFactory.getLogger(BGPSessionInfo.class);
+ private BGPId remoteBgpId;
+ private BGPVersion remoteBgpVersion;
+ private short remoteBgpASNum;
+ private short remoteBgpholdTime;
+ private int remoteBgpIdentifier;
+ private short negotiatedholdTime;
+
+ /**
+ * Gets the negotiated hold time for the session.
+ *
+ * @return negotiated hold time.
+ */
+ public short getNegotiatedholdTime() {
+ return negotiatedholdTime;
+ }
+
+ /**
+ * Sets the negotiated hold time for the session.
+ *
+ * @param negotiatedholdTime negotiated hold time.
+ */
+ public void setNegotiatedholdTime(short negotiatedholdTime) {
+ this.negotiatedholdTime = negotiatedholdTime;
+ }
+
+ /**
+ * Gets the BGP ID of BGP peer.
+ *
+ * @return bgp ID.
+ */
+ public BGPId getRemoteBgpId() {
+ return remoteBgpId;
+ }
+
+ /**
+ * Sets the BGP ID of bgp peer.
+ *
+ * @param bgpId BGP ID to set.
+ */
+ public void setRemoteBgpId(BGPId bgpId) {
+ log.debug("Remote BGP ID {}", bgpId);
+ this.remoteBgpId = bgpId;
+ }
+
+ /**
+ * Gets the BGP version of peer.
+ *
+ * @return bgp version.
+ */
+ public BGPVersion getRemoteBgpVersion() {
+ return remoteBgpVersion;
+ }
+
+ /**
+ * Sets the BGP version for this bgp peer.
+ *
+ * @param bgpVersion bgp version to set.
+ */
+ public void setRemoteBgpVersion(BGPVersion bgpVersion) {
+ log.debug("Remote BGP version {}", bgpVersion);
+ this.remoteBgpVersion = bgpVersion;
+ }
+
+ /**
+ * Gets the BGP remote bgp AS number.
+ *
+ * @return remoteBgpASNum peer AS number.
+ */
+ public short getRemoteBgpASNum() {
+ return remoteBgpASNum;
+ }
+
+ /**
+ * Sets the AS Number for this bgp peer.
+ *
+ * @param bgpASNum the autonomous system number value to set.
+ */
+ public void setRemoteBgpASNum(short bgpASNum) {
+ log.debug("Remote BGP AS number {}", bgpASNum);
+ this.remoteBgpASNum = bgpASNum;
+ }
+
+ /**
+ * Gets the BGP peer hold time.
+ *
+ * @return bgp hold time.
+ */
+ public short getRemoteBgpHoldTime() {
+ return remoteBgpholdTime;
+ }
+
+ /**
+ * Sets the hold time for this bgp peer.
+ *
+ * @param holdTime the hold timer value to set.
+ */
+ public void setRemoteBgpHoldTime(short holdTime) {
+ log.debug("Remote BGP HoldTime {}", holdTime);
+ this.remoteBgpholdTime = holdTime;
+ }
+
+ /**
+ * Gets the BGP version for this bgp peer.
+ *
+ * @return bgp identifier.
+ */
+ public int getRemoteBgpIdentifier() {
+ return remoteBgpIdentifier;
+ }
+
+ /**
+ * Sets the peer identifier value.
+ *
+ * @param bgpIdentifier the bgp peer identifier value.
+ */
+ public void setRemoteBgpIdentifier(int bgpIdentifier) {
+ log.debug("Remote BGP Identifier {}", bgpIdentifier);
+ this.remoteBgpIdentifier = bgpIdentifier;
+ }
+}