blob: a8cf5d8e743f12044eab36c144b7dc9aae2c6860 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Jonathan Hartf4bd0482017-01-27 15:11:18 -08002 * Copyright 2017-present Open Networking Laboratory
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Jonathan Hartf4bd0482017-01-27 15:11:18 -080016
Jonathan Hart41349e92015-02-09 14:14:02 -080017package org.onosproject.routing.bgp;
Jonathan Hartab63aac2014-10-16 08:52:55 -070018
Jonathan Hartd24fafb2015-02-09 17:55:32 -080019import org.apache.felix.scr.annotations.Activate;
Jonathan Hart41349e92015-02-09 14:14:02 -080020import org.apache.felix.scr.annotations.Component;
Jonathan Hartd24fafb2015-02-09 17:55:32 -080021import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Modified;
Jonathan Hart1ad75f22016-04-13 21:24:13 -070023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Hart41349e92015-02-09 14:14:02 -080025import org.apache.felix.scr.annotations.Service;
Jonathan Hartab63aac2014-10-16 08:52:55 -070026import org.jboss.netty.bootstrap.ServerBootstrap;
27import org.jboss.netty.channel.Channel;
28import org.jboss.netty.channel.ChannelException;
29import org.jboss.netty.channel.ChannelFactory;
30import org.jboss.netty.channel.ChannelPipeline;
31import org.jboss.netty.channel.ChannelPipelineFactory;
32import org.jboss.netty.channel.Channels;
Pavlin Radoslavov7e190942014-11-13 18:50:59 -080033import org.jboss.netty.channel.group.ChannelGroup;
34import org.jboss.netty.channel.group.DefaultChannelGroup;
Jonathan Hartab63aac2014-10-16 08:52:55 -070035import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080036import org.onlab.packet.Ip4Address;
37import org.onlab.packet.Ip4Prefix;
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080038import org.onlab.packet.Ip6Prefix;
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080039import org.onlab.packet.IpPrefix;
Jonathan Hart1ad75f22016-04-13 21:24:13 -070040import org.onosproject.incubator.net.routing.Route;
41import org.onosproject.incubator.net.routing.RouteAdminService;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080042import org.osgi.service.component.ComponentContext;
Jonathan Hartab63aac2014-10-16 08:52:55 -070043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
45
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080046import java.net.InetAddress;
47import java.net.InetSocketAddress;
48import java.net.SocketAddress;
49import java.util.Collection;
Jonathan Hartd24fafb2015-02-09 17:55:32 -080050import java.util.Dictionary;
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080051import java.util.concurrent.ConcurrentHashMap;
52import java.util.concurrent.ConcurrentMap;
53
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080054import static java.util.concurrent.Executors.newCachedThreadPool;
Thomas Vachuska6f94ded2015-02-21 14:02:38 -080055import static org.onlab.util.Tools.groupedThreads;
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080056
Jonathan Hartab63aac2014-10-16 08:52:55 -070057/**
58 * BGP Session Manager class.
59 */
Jonathan Hartc22e8472015-11-17 18:25:45 -080060@Component(immediate = true, enabled = false)
Jonathan Hart41349e92015-02-09 14:14:02 -080061@Service
Jonathan Hart1ad75f22016-04-13 21:24:13 -070062public class BgpSessionManager implements BgpInfoService {
Jonathan Hartab63aac2014-10-16 08:52:55 -070063 private static final Logger log =
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080064 LoggerFactory.getLogger(BgpSessionManager.class);
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080065
Jonathan Hart1ad75f22016-04-13 21:24:13 -070066 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected RouteAdminService routeService;
68
Pavlin Radoslavov7e190942014-11-13 18:50:59 -080069 boolean isShutdown = true;
Jonathan Hartab63aac2014-10-16 08:52:55 -070070 private Channel serverChannel; // Listener for incoming BGP connections
Pavlin Radoslavov7e190942014-11-13 18:50:59 -080071 private ServerBootstrap serverBootstrap;
72 private ChannelGroup allChannels = new DefaultChannelGroup();
Jonathan Hartab63aac2014-10-16 08:52:55 -070073 private ConcurrentMap<SocketAddress, BgpSession> bgpSessions =
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080074 new ConcurrentHashMap<>();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -080075 private Ip4Address myBgpId; // Same BGP ID for all peers
Jonathan Hartab63aac2014-10-16 08:52:55 -070076
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080077 private BgpRouteSelector bgpRouteSelector = new BgpRouteSelector(this);
78 private ConcurrentMap<Ip4Prefix, BgpRouteEntry> bgpRoutes4 =
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080079 new ConcurrentHashMap<>();
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -080080 private ConcurrentMap<Ip6Prefix, BgpRouteEntry> bgpRoutes6 =
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -080081 new ConcurrentHashMap<>();
Jonathan Hartab63aac2014-10-16 08:52:55 -070082
Jonathan Hartd24fafb2015-02-09 17:55:32 -080083 private static final int DEFAULT_BGP_PORT = 2000;
84 private int bgpPort;
85
86 @Activate
87 protected void activate(ComponentContext context) {
88 readComponentConfiguration(context);
Jonathan Hart1ad75f22016-04-13 21:24:13 -070089 start();
Jonathan Hartd24fafb2015-02-09 17:55:32 -080090 log.info("BgpSessionManager started");
91 }
92
93 @Deactivate
94 protected void deactivate() {
Jonathan Hart1ad75f22016-04-13 21:24:13 -070095 stop();
Jonathan Hartd24fafb2015-02-09 17:55:32 -080096 log.info("BgpSessionManager stopped");
97 }
98
99 /**
100 * Extracts properties from the component configuration context.
101 *
102 * @param context the component context
103 */
104 private void readComponentConfiguration(ComponentContext context) {
105 Dictionary<?, ?> properties = context.getProperties();
106 try {
107 String strPort = (String) properties.get("bgpPort");
108 if (strPort != null) {
109 bgpPort = Integer.parseInt(strPort);
110 } else {
111 bgpPort = DEFAULT_BGP_PORT;
112 }
Pavlin Radoslavovb9e50df2015-02-20 20:01:26 -0800113 } catch (NumberFormatException | ClassCastException e) {
Jonathan Hartd24fafb2015-02-09 17:55:32 -0800114 bgpPort = DEFAULT_BGP_PORT;
115 }
116 log.debug("BGP port is set to {}", bgpPort);
117 }
118
119 @Modified
120 public void modified(ComponentContext context) {
121 // Blank @Modified method to catch modifications to the context.
122 // If no @Modified method exists, it seems @Activate is called again
123 // when the context is modified.
124 }
125
Jonathan Hartab63aac2014-10-16 08:52:55 -0700126 /**
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800127 * Checks whether the BGP Session Manager is shutdown.
128 *
129 * @return true if the BGP Session Manager is shutdown, otherwise false
130 */
131 boolean isShutdown() {
132 return this.isShutdown;
133 }
134
135 /**
Jonathan Hartab63aac2014-10-16 08:52:55 -0700136 * Gets the BGP sessions.
137 *
138 * @return the BGP sessions
139 */
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700140 @Override
Jonathan Hartab63aac2014-10-16 08:52:55 -0700141 public Collection<BgpSession> getBgpSessions() {
142 return bgpSessions.values();
143 }
144
145 /**
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800146 * Gets the selected IPv4 BGP routes among all BGP sessions.
Jonathan Hartab63aac2014-10-16 08:52:55 -0700147 *
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800148 * @return the selected IPv4 BGP routes among all BGP sessions
Jonathan Hartab63aac2014-10-16 08:52:55 -0700149 */
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700150 @Override
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800151 public Collection<BgpRouteEntry> getBgpRoutes4() {
152 return bgpRoutes4.values();
153 }
154
155 /**
156 * Gets the selected IPv6 BGP routes among all BGP sessions.
157 *
158 * @return the selected IPv6 BGP routes among all BGP sessions
159 */
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700160 @Override
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800161 public Collection<BgpRouteEntry> getBgpRoutes6() {
162 return bgpRoutes6.values();
163 }
164
165 /**
166 * Finds a BGP route for a prefix. The prefix can be either IPv4 or IPv6.
167 *
168 * @param prefix the prefix to use
169 * @return the BGP route if found, otherwise null
170 */
171 BgpRouteEntry findBgpRoute(IpPrefix prefix) {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700172 if (prefix.isIp4()) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800173 return bgpRoutes4.get(prefix.getIp4Prefix()); // IPv4
174 }
175 return bgpRoutes6.get(prefix.getIp6Prefix()); // IPv6
176 }
177
178 /**
179 * Adds a BGP route. The route can be either IPv4 or IPv6.
180 *
181 * @param bgpRouteEntry the BGP route entry to use
182 */
183 void addBgpRoute(BgpRouteEntry bgpRouteEntry) {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700184 if (bgpRouteEntry.isIp4()) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800185 bgpRoutes4.put(bgpRouteEntry.prefix().getIp4Prefix(), // IPv4
186 bgpRouteEntry);
187 } else {
188 bgpRoutes6.put(bgpRouteEntry.prefix().getIp6Prefix(), // IPv6
189 bgpRouteEntry);
190 }
191 }
192
193 /**
194 * Removes a BGP route for a prefix. The prefix can be either IPv4 or IPv6.
195 *
196 * @param prefix the prefix to use
197 * @return true if the route was found and removed, otherwise false
198 */
199 boolean removeBgpRoute(IpPrefix prefix) {
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700200 if (prefix.isIp4()) {
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800201 return (bgpRoutes4.remove(prefix.getIp4Prefix()) != null); // IPv4
202 }
203 return (bgpRoutes6.remove(prefix.getIp6Prefix()) != null); // IPv6
Jonathan Hartab63aac2014-10-16 08:52:55 -0700204 }
205
206 /**
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800207 * Adds the channel for a BGP session.
208 *
209 * @param channel the channel to add
210 */
211 void addSessionChannel(Channel channel) {
212 allChannels.add(channel);
213 }
214
215 /**
216 * Removes the channel for a BGP session.
217 *
218 * @param channel the channel to remove
219 */
220 void removeSessionChannel(Channel channel) {
221 allChannels.remove(channel);
222 }
223
224 /**
Jonathan Hartab63aac2014-10-16 08:52:55 -0700225 * Processes the connection from a BGP peer.
226 *
227 * @param bgpSession the BGP session for the peer
228 * @return true if the connection can be established, otherwise false
229 */
230 boolean peerConnected(BgpSession bgpSession) {
231
232 // Test whether there is already a session from the same remote
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800233 if (bgpSessions.get(bgpSession.remoteInfo().address()) != null) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700234 return false; // Duplicate BGP session
235 }
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800236 bgpSessions.put(bgpSession.remoteInfo().address(), bgpSession);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700237
238 //
239 // If the first connection, set my BGP ID to the local address
240 // of the socket.
241 //
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800242 if (bgpSession.localInfo().address() instanceof InetSocketAddress) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700243 InetAddress inetAddr =
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800244 ((InetSocketAddress) bgpSession.localInfo().address()).getAddress();
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800245 Ip4Address ip4Address = Ip4Address.valueOf(inetAddr.getAddress());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700246 updateMyBgpId(ip4Address);
247 }
248 return true;
249 }
250
251 /**
252 * Processes the disconnection from a BGP peer.
253 *
254 * @param bgpSession the BGP session for the peer
255 */
256 void peerDisconnected(BgpSession bgpSession) {
Pavlin Radoslavov8a36ce32015-01-28 12:26:57 -0800257 bgpSessions.remove(bgpSession.remoteInfo().address());
Jonathan Hartab63aac2014-10-16 08:52:55 -0700258 }
259
260 /**
261 * Conditionally updates the local BGP ID if it wasn't set already.
262 * <p/>
263 * NOTE: A BGP instance should use same BGP ID across all BGP sessions.
264 *
265 * @param ip4Address the IPv4 address to use as BGP ID
266 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800267 private synchronized void updateMyBgpId(Ip4Address ip4Address) {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700268 if (myBgpId == null) {
269 myBgpId = ip4Address;
270 log.debug("BGP: My BGP ID is {}", myBgpId);
271 }
272 }
273
274 /**
275 * Gets the local BGP Identifier as an IPv4 address.
276 *
277 * @return the local BGP Identifier as an IPv4 address
278 */
Pavlin Radoslavov6b570732014-11-06 13:16:45 -0800279 Ip4Address getMyBgpId() {
Jonathan Hartab63aac2014-10-16 08:52:55 -0700280 return myBgpId;
281 }
282
283 /**
284 * Gets the BGP Route Selector.
285 *
286 * @return the BGP Route Selector
287 */
288 BgpRouteSelector getBgpRouteSelector() {
289 return bgpRouteSelector;
290 }
291
Jonathan Hart1ad75f22016-04-13 21:24:13 -0700292 /**
293 * Sends updates routes to the route service.
294 *
295 * @param updates routes to update
296 */
297 void update(Collection<Route> updates) {
298 routeService.update(updates);
299 }
300
301 /**
302 * Sends withdrawn routes to the routes service.
303 *
304 * @param withdraws routes to withdraw
305 */
306 void withdraw(Collection<Route> withdraws) {
307 routeService.withdraw(withdraws);
308 }
309
310
311 public void start() {
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800312 log.debug("BGP Session Manager start.");
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800313 isShutdown = false;
Jonathan Hartab63aac2014-10-16 08:52:55 -0700314
Pavlin Radoslavov3a0a52e2015-01-06 17:41:37 -0800315 ChannelFactory channelFactory = new NioServerSocketChannelFactory(
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700316 newCachedThreadPool(groupedThreads("onos/bgp", "sm-boss-%d", log)),
317 newCachedThreadPool(groupedThreads("onos/bgp", "sm-worker-%d", log)));
Sho SHIMIZU74626412015-09-11 11:46:27 -0700318 ChannelPipelineFactory pipelineFactory = () -> {
319 // Allocate a new session per connection
320 BgpSession bgpSessionHandler =
321 new BgpSession(BgpSessionManager.this);
322 BgpFrameDecoder bgpFrameDecoder =
323 new BgpFrameDecoder(bgpSessionHandler);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700324
Sho SHIMIZU74626412015-09-11 11:46:27 -0700325 // Setup the processing pipeline
326 ChannelPipeline pipeline = Channels.pipeline();
327 pipeline.addLast("BgpFrameDecoder", bgpFrameDecoder);
328 pipeline.addLast("BgpSession", bgpSessionHandler);
329 return pipeline;
Thomas Vachuska9ea3e6f2015-01-23 16:34:22 -0800330 };
Jonathan Hartab63aac2014-10-16 08:52:55 -0700331 InetSocketAddress listenAddress =
Jonathan Hartd24fafb2015-02-09 17:55:32 -0800332 new InetSocketAddress(bgpPort);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700333
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800334 serverBootstrap = new ServerBootstrap(channelFactory);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700335 // serverBootstrap.setOptions("reuseAddr", true);
336 serverBootstrap.setOption("child.keepAlive", true);
337 serverBootstrap.setOption("child.tcpNoDelay", true);
338 serverBootstrap.setPipelineFactory(pipelineFactory);
339 try {
340 serverChannel = serverBootstrap.bind(listenAddress);
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800341 allChannels.add(serverChannel);
Jonathan Hartab63aac2014-10-16 08:52:55 -0700342 } catch (ChannelException e) {
343 log.debug("Exception binding to BGP port {}: ",
344 listenAddress.getPort(), e);
345 }
346 }
347
Pavlin Radoslavova071b1e2014-11-17 13:37:57 -0800348 public void stop() {
Pavlin Radoslavov7e190942014-11-13 18:50:59 -0800349 isShutdown = true;
350 allChannels.close().awaitUninterruptibly();
351 serverBootstrap.releaseExternalResources();
Jonathan Hartab63aac2014-10-16 08:52:55 -0700352 }
Jonathan Hartab63aac2014-10-16 08:52:55 -0700353}