From e9bb60be43af477f17b30ee1f2ba205565b7fa15 Mon Sep 17 00:00:00 2001 From: Ashlee Young Date: Mon, 19 Oct 2015 10:14:31 -0700 Subject: Updated onos src tree to commit id 1e60f97ae50c05b94fcb6a10520738bfb5efdfd1 --- .../bgp/controller/impl/BGPChannelHandler.java | 601 ++++++++++++++++++++- .../bgp/controller/impl/BGPControllerImpl.java | 179 +++++- .../bgp/controller/impl/BGPKeepAliveTimer.java | 72 +++ .../bgp/controller/impl/BGPPacketStatsImpl.java | 12 +- .../bgp/controller/impl/BGPPeerImpl.java | 191 +++++++ .../bgp/controller/impl/BGPSessionInfo.java | 149 +++++ 6 files changed, 1190 insertions(+), 14 deletions(-) create mode 100755 framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPKeepAliveTimer.java create mode 100755 framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPPeerImpl.java create mode 100755 framework/src/onos/bgp/ctl/src/main/java/org/onosproject/bgp/controller/impl/BGPSessionInfo.java (limited to 'framework/src/onos/bgp/ctl') 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 msglist = (List) 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 connectedPeers = new ConcurrentHashMap(); + protected BGPPeerManager peerManager = new BGPPeerManager(); final Controller ctrl = new Controller(this); private BGPConfig bgpconfig = new BGPConfig(); @@ -57,10 +67,21 @@ public class BGPControllerImpl implements BGPController { @Deactivate public void deactivate() { // Close all connected peers + closeConnectedPeers(); this.ctrl.stop(); log.info("Stopped"); } + @Override + public Iterable 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 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 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; + } +} -- cgit 1.2.3-korg