2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.protocol.bmp.impl;
11 import static java.util.Objects.requireNonNull;
12 import static org.opendaylight.protocol.bmp.impl.BmpDispatcherUtil.createClientBootstrap;
13 import static org.opendaylight.protocol.bmp.impl.BmpDispatcherUtil.createServerBootstrap;
15 import io.netty.bootstrap.Bootstrap;
16 import io.netty.bootstrap.ServerBootstrap;
17 import io.netty.channel.ChannelFuture;
18 import io.netty.channel.ChannelFutureListener;
19 import io.netty.channel.EventLoop;
20 import io.netty.channel.EventLoopGroup;
21 import io.netty.channel.epoll.Epoll;
22 import io.netty.channel.epoll.EpollEventLoopGroup;
23 import java.net.InetSocketAddress;
24 import java.util.Timer;
25 import java.util.TimerTask;
26 import java.util.concurrent.TimeUnit;
27 import javax.annotation.concurrent.GuardedBy;
28 import org.opendaylight.protocol.bmp.api.BmpDispatcher;
29 import org.opendaylight.protocol.bmp.api.BmpSessionFactory;
30 import org.opendaylight.protocol.bmp.api.BmpSessionListenerFactory;
31 import org.opendaylight.protocol.bmp.spi.registry.BmpMessageRegistry;
32 import org.opendaylight.protocol.concepts.KeyMapping;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
36 public class BmpDispatcherImpl implements BmpDispatcher {
38 private static final Logger LOG = LoggerFactory.getLogger(BmpDispatcherImpl.class);
40 private static final int CONNECT_TIMEOUT = 5000;
41 private static final int INITIAL_BACKOFF = 30_000;
42 private static final int MAXIMUM_BACKOFF = 720_000;
43 private static final long TIMEOUT = 10;
45 private final BmpHandlerFactory hf;
46 private final EventLoopGroup bossGroup;
47 private final EventLoopGroup workerGroup;
48 private final BmpSessionFactory sessionFactory;
50 private boolean close;
52 public BmpDispatcherImpl(final EventLoopGroup bossGroup, final EventLoopGroup workerGroup,
53 final BmpMessageRegistry registry, final BmpSessionFactory sessionFactory) {
54 if (Epoll.isAvailable()) {
55 this.bossGroup = new EpollEventLoopGroup();
56 this.workerGroup = new EpollEventLoopGroup();
58 this.bossGroup = requireNonNull(bossGroup);
59 this.workerGroup = requireNonNull(workerGroup);
61 this.hf = new BmpHandlerFactory(requireNonNull(registry));
62 this.sessionFactory = requireNonNull(sessionFactory);
66 public ChannelFuture createClient(final InetSocketAddress remoteAddress, final BmpSessionListenerFactory slf,
67 final KeyMapping keys) {
68 final Bootstrap bootstrap = createClientBootstrap(this.sessionFactory, this.hf,
69 BmpDispatcherUtil::createChannelWithDecoder, slf, remoteAddress, this.workerGroup,
70 CONNECT_TIMEOUT, keys);
71 final ChannelFuture channelPromise = bootstrap.connect();
72 channelPromise.addListener(new BootstrapListener(bootstrap, remoteAddress, slf, keys));
73 LOG.debug("Initiated BMP Client {} at {}.", channelPromise, remoteAddress);
74 return channelPromise;
78 public ChannelFuture createServer(final InetSocketAddress address, final BmpSessionListenerFactory slf,
79 final KeyMapping keys) {
80 final ServerBootstrap serverBootstrap = createServerBootstrap(this.sessionFactory, this.hf, slf,
81 BmpDispatcherUtil::createChannelWithDecoder, this.bossGroup, this.workerGroup, keys);
82 final ChannelFuture channelFuture = serverBootstrap.bind(address);
83 LOG.debug("Initiated BMP server {} at {}.", channelFuture, address);
88 public synchronized void close() {
90 if (Epoll.isAvailable()) {
91 this.workerGroup.shutdownGracefully(0, TIMEOUT, TimeUnit.SECONDS);
92 this.bossGroup.shutdownGracefully(0, TIMEOUT, TimeUnit.SECONDS);
96 private class BootstrapListener implements ChannelFutureListener {
97 private final Bootstrap bootstrap;
98 private final InetSocketAddress remoteAddress;
99 private final BmpSessionListenerFactory slf;
100 private final KeyMapping keys;
102 private final Timer timer = new Timer();
104 BootstrapListener(final Bootstrap bootstrap,
105 final InetSocketAddress remoteAddress, final BmpSessionListenerFactory slf, final KeyMapping keys) {
106 this.bootstrap = bootstrap;
107 this.remoteAddress = remoteAddress;
108 this.delay = INITIAL_BACKOFF;
114 public void operationComplete(final ChannelFuture future) throws Exception {
115 if (future.isCancelled()) {
116 LOG.debug("Connection {} cancelled!", future);
117 } else if (future.isSuccess()) {
118 LOG.debug("Connection {} succeeded!", future);
119 future.channel().closeFuture().addListener((ChannelFutureListener) channelFuture -> scheduleConnect());
121 if (this.delay > MAXIMUM_BACKOFF) {
122 LOG.warn("The time of maximum backoff has been exceeded. No further connection attempts with BMP "
123 + "router {}.", this.remoteAddress);
124 future.cancel(false);
127 final EventLoop loop = future.channel().eventLoop();
128 loop.schedule(() -> this.bootstrap.connect().addListener(this), this.delay, TimeUnit.MILLISECONDS);
129 LOG.info("The connection try to BMP router {} failed. Next reconnection attempt in {} milliseconds.",
130 this.remoteAddress, this.delay);
135 private void scheduleConnect() {
136 if (!BmpDispatcherImpl.this.close) {
137 timer.schedule(new TimerTask() {
140 createClient(BootstrapListener.this.remoteAddress, BootstrapListener.this.slf,
141 BootstrapListener.this.keys);