diff options
author | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
---|---|---|
committer | Ashlee Young <ashlee@onosfw.com> | 2015-09-09 22:15:21 -0700 |
commit | 13d05bc8458758ee39cb829098241e89616717ee (patch) | |
tree | 22a4d1ce65f15952f07a3df5af4b462b4697cb3a /framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpSessionManager.java | |
parent | 6139282e1e93c2322076de4b91b1c85d0bc4a8b3 (diff) |
ONOS checkin based on commit tag e796610b1f721d02f9b0e213cf6f7790c10ecd60
Change-Id: Ife8810491034fe7becdba75dda20de4267bd15cd
Diffstat (limited to 'framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpSessionManager.java')
-rw-r--r-- | framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpSessionManager.java | 342 |
1 files changed, 342 insertions, 0 deletions
diff --git a/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpSessionManager.java b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpSessionManager.java new file mode 100644 index 00000000..57481c20 --- /dev/null +++ b/framework/src/onos/apps/routing/src/main/java/org/onosproject/routing/bgp/BgpSessionManager.java @@ -0,0 +1,342 @@ +/* + * Copyright 2014-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.routing.bgp; + +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.Modified; +import org.apache.felix.scr.annotations.Service; +import org.jboss.netty.bootstrap.ServerBootstrap; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelException; +import org.jboss.netty.channel.ChannelFactory; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.Channels; +import org.jboss.netty.channel.group.ChannelGroup; +import org.jboss.netty.channel.group.DefaultChannelGroup; +import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; +import org.onlab.packet.Ip4Address; +import org.onlab.packet.Ip4Prefix; +import org.onlab.packet.Ip6Prefix; +import org.onlab.packet.IpPrefix; +import org.onosproject.routing.BgpService; +import org.onosproject.routing.RouteListener; +import org.osgi.service.component.ComponentContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.util.Collection; +import java.util.Dictionary; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import static com.google.common.base.Preconditions.checkNotNull; +import static java.util.concurrent.Executors.newCachedThreadPool; +import static org.onlab.util.Tools.groupedThreads; + +/** + * BGP Session Manager class. + */ +@Component(immediate = true) +@Service +public class BgpSessionManager implements BgpInfoService, BgpService { + private static final Logger log = + LoggerFactory.getLogger(BgpSessionManager.class); + + boolean isShutdown = true; + private Channel serverChannel; // Listener for incoming BGP connections + private ServerBootstrap serverBootstrap; + private ChannelGroup allChannels = new DefaultChannelGroup(); + private ConcurrentMap<SocketAddress, BgpSession> bgpSessions = + new ConcurrentHashMap<>(); + private Ip4Address myBgpId; // Same BGP ID for all peers + + private BgpRouteSelector bgpRouteSelector = new BgpRouteSelector(this); + private ConcurrentMap<Ip4Prefix, BgpRouteEntry> bgpRoutes4 = + new ConcurrentHashMap<>(); + private ConcurrentMap<Ip6Prefix, BgpRouteEntry> bgpRoutes6 = + new ConcurrentHashMap<>(); + + private RouteListener routeListener; + + private static final int DEFAULT_BGP_PORT = 2000; + private int bgpPort; + + @Activate + protected void activate(ComponentContext context) { + readComponentConfiguration(context); + log.info("BgpSessionManager started"); + } + + @Deactivate + protected void deactivate() { + log.info("BgpSessionManager stopped"); + } + + /** + * Extracts properties from the component configuration context. + * + * @param context the component context + */ + private void readComponentConfiguration(ComponentContext context) { + Dictionary<?, ?> properties = context.getProperties(); + try { + String strPort = (String) properties.get("bgpPort"); + if (strPort != null) { + bgpPort = Integer.parseInt(strPort); + } else { + bgpPort = DEFAULT_BGP_PORT; + } + } catch (NumberFormatException | ClassCastException e) { + bgpPort = DEFAULT_BGP_PORT; + } + log.debug("BGP port is set to {}", bgpPort); + } + + @Modified + public void modified(ComponentContext context) { + // Blank @Modified method to catch modifications to the context. + // If no @Modified method exists, it seems @Activate is called again + // when the context is modified. + } + + /** + * Checks whether the BGP Session Manager is shutdown. + * + * @return true if the BGP Session Manager is shutdown, otherwise false + */ + boolean isShutdown() { + return this.isShutdown; + } + + /** + * Gets the route listener. + * + * @return the route listener to use + */ + RouteListener getRouteListener() { + return routeListener; + } + + /** + * Gets the BGP sessions. + * + * @return the BGP sessions + */ + public Collection<BgpSession> getBgpSessions() { + return bgpSessions.values(); + } + + /** + * Gets the selected IPv4 BGP routes among all BGP sessions. + * + * @return the selected IPv4 BGP routes among all BGP sessions + */ + public Collection<BgpRouteEntry> getBgpRoutes4() { + return bgpRoutes4.values(); + } + + /** + * Gets the selected IPv6 BGP routes among all BGP sessions. + * + * @return the selected IPv6 BGP routes among all BGP sessions + */ + public Collection<BgpRouteEntry> getBgpRoutes6() { + return bgpRoutes6.values(); + } + + /** + * Finds a BGP route for a prefix. The prefix can be either IPv4 or IPv6. + * + * @param prefix the prefix to use + * @return the BGP route if found, otherwise null + */ + BgpRouteEntry findBgpRoute(IpPrefix prefix) { + if (prefix.isIp4()) { + return bgpRoutes4.get(prefix.getIp4Prefix()); // IPv4 + } + return bgpRoutes6.get(prefix.getIp6Prefix()); // IPv6 + } + + /** + * Adds a BGP route. The route can be either IPv4 or IPv6. + * + * @param bgpRouteEntry the BGP route entry to use + */ + void addBgpRoute(BgpRouteEntry bgpRouteEntry) { + if (bgpRouteEntry.isIp4()) { + bgpRoutes4.put(bgpRouteEntry.prefix().getIp4Prefix(), // IPv4 + bgpRouteEntry); + } else { + bgpRoutes6.put(bgpRouteEntry.prefix().getIp6Prefix(), // IPv6 + bgpRouteEntry); + } + } + + /** + * Removes a BGP route for a prefix. The prefix can be either IPv4 or IPv6. + * + * @param prefix the prefix to use + * @return true if the route was found and removed, otherwise false + */ + boolean removeBgpRoute(IpPrefix prefix) { + if (prefix.isIp4()) { + return (bgpRoutes4.remove(prefix.getIp4Prefix()) != null); // IPv4 + } + return (bgpRoutes6.remove(prefix.getIp6Prefix()) != null); // IPv6 + } + + /** + * Adds the channel for a BGP session. + * + * @param channel the channel to add + */ + void addSessionChannel(Channel channel) { + allChannels.add(channel); + } + + /** + * Removes the channel for a BGP session. + * + * @param channel the channel to remove + */ + void removeSessionChannel(Channel channel) { + allChannels.remove(channel); + } + + /** + * Processes the connection from a BGP peer. + * + * @param bgpSession the BGP session for the peer + * @return true if the connection can be established, otherwise false + */ + boolean peerConnected(BgpSession bgpSession) { + + // Test whether there is already a session from the same remote + if (bgpSessions.get(bgpSession.remoteInfo().address()) != null) { + return false; // Duplicate BGP session + } + bgpSessions.put(bgpSession.remoteInfo().address(), bgpSession); + + // + // If the first connection, set my BGP ID to the local address + // of the socket. + // + if (bgpSession.localInfo().address() instanceof InetSocketAddress) { + InetAddress inetAddr = + ((InetSocketAddress) bgpSession.localInfo().address()).getAddress(); + Ip4Address ip4Address = Ip4Address.valueOf(inetAddr.getAddress()); + updateMyBgpId(ip4Address); + } + return true; + } + + /** + * Processes the disconnection from a BGP peer. + * + * @param bgpSession the BGP session for the peer + */ + void peerDisconnected(BgpSession bgpSession) { + bgpSessions.remove(bgpSession.remoteInfo().address()); + } + + /** + * Conditionally updates the local BGP ID if it wasn't set already. + * <p/> + * NOTE: A BGP instance should use same BGP ID across all BGP sessions. + * + * @param ip4Address the IPv4 address to use as BGP ID + */ + private synchronized void updateMyBgpId(Ip4Address ip4Address) { + if (myBgpId == null) { + myBgpId = ip4Address; + log.debug("BGP: My BGP ID is {}", myBgpId); + } + } + + /** + * Gets the local BGP Identifier as an IPv4 address. + * + * @return the local BGP Identifier as an IPv4 address + */ + Ip4Address getMyBgpId() { + return myBgpId; + } + + /** + * Gets the BGP Route Selector. + * + * @return the BGP Route Selector + */ + BgpRouteSelector getBgpRouteSelector() { + return bgpRouteSelector; + } + + @Override + public void start(RouteListener routeListener) { + log.debug("BGP Session Manager start."); + isShutdown = false; + + this.routeListener = checkNotNull(routeListener); + + ChannelFactory channelFactory = new NioServerSocketChannelFactory( + newCachedThreadPool(groupedThreads("onos/bgp", "sm-boss-%d")), + newCachedThreadPool(groupedThreads("onos/bgp", "sm-worker-%d"))); + ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() { + @Override + public ChannelPipeline getPipeline() throws Exception { + // Allocate a new session per connection + BgpSession bgpSessionHandler = + new BgpSession(BgpSessionManager.this); + BgpFrameDecoder bgpFrameDecoder = + new BgpFrameDecoder(bgpSessionHandler); + + // Setup the processing pipeline + ChannelPipeline pipeline = Channels.pipeline(); + pipeline.addLast("BgpFrameDecoder", bgpFrameDecoder); + pipeline.addLast("BgpSession", bgpSessionHandler); + return pipeline; + } + }; + InetSocketAddress listenAddress = + new InetSocketAddress(bgpPort); + + serverBootstrap = new ServerBootstrap(channelFactory); + // serverBootstrap.setOptions("reuseAddr", true); + serverBootstrap.setOption("child.keepAlive", true); + serverBootstrap.setOption("child.tcpNoDelay", true); + serverBootstrap.setPipelineFactory(pipelineFactory); + try { + serverChannel = serverBootstrap.bind(listenAddress); + allChannels.add(serverChannel); + } catch (ChannelException e) { + log.debug("Exception binding to BGP port {}: ", + listenAddress.getPort(), e); + } + } + + @Override + public void stop() { + isShutdown = true; + allChannels.close().awaitUninterruptibly(); + serverBootstrap.releaseExternalResources(); + } +} |