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
8 package org.opendaylight.protocol.bmp.impl;
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.protocol.bmp.impl.BmpDispatcherUtil.createClientBootstrap;
12 import static org.opendaylight.protocol.bmp.impl.BmpDispatcherUtil.createServerBootstrap;
14 import io.netty.bootstrap.Bootstrap;
15 import io.netty.bootstrap.ServerBootstrap;
16 import io.netty.channel.ChannelFuture;
17 import io.netty.channel.ChannelFutureListener;
18 import io.netty.channel.EventLoop;
19 import io.netty.channel.EventLoopGroup;
20 import io.netty.channel.epoll.Epoll;
21 import io.netty.channel.epoll.EpollEventLoopGroup;
22 import java.net.InetSocketAddress;
23 import java.util.Timer;
24 import java.util.TimerTask;
25 import java.util.concurrent.TimeUnit;
26 import org.checkerframework.checker.lock.qual.GuardedBy;
27 import org.opendaylight.protocol.bmp.api.BmpDispatcher;
28 import org.opendaylight.protocol.bmp.api.BmpSessionFactory;
29 import org.opendaylight.protocol.bmp.api.BmpSessionListenerFactory;
30 import org.opendaylight.protocol.bmp.spi.registry.BmpMessageRegistry;
31 import org.opendaylight.protocol.concepts.KeyMapping;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 public class BmpDispatcherImpl implements BmpDispatcher {
37 private static final Logger LOG = LoggerFactory.getLogger(BmpDispatcherImpl.class);
39 private static final int CONNECT_TIMEOUT = 5000;
40 private static final int INITIAL_BACKOFF = 30_000;
41 private static final int MAXIMUM_BACKOFF = 720_000;
42 private static final long TIMEOUT = 10;
44 private final BmpHandlerFactory hf;
45 private final EventLoopGroup bossGroup;
46 private final EventLoopGroup workerGroup;
47 private final BmpSessionFactory sessionFactory;
49 private boolean close;
51 public BmpDispatcherImpl(final EventLoopGroup bossGroup, final EventLoopGroup workerGroup,
52 final BmpMessageRegistry registry, final BmpSessionFactory sessionFactory) {
53 if (Epoll.isAvailable()) {
54 this.bossGroup = new EpollEventLoopGroup();
55 this.workerGroup = new EpollEventLoopGroup();
57 this.bossGroup = requireNonNull(bossGroup);
58 this.workerGroup = requireNonNull(workerGroup);
60 this.hf = new BmpHandlerFactory(requireNonNull(registry));
61 this.sessionFactory = requireNonNull(sessionFactory);
65 public ChannelFuture createClient(final InetSocketAddress remoteAddress, final BmpSessionListenerFactory slf,
66 final KeyMapping keys) {
67 final Bootstrap bootstrap = createClientBootstrap(this.sessionFactory, this.hf,
68 BmpDispatcherUtil::createChannelWithDecoder, slf, remoteAddress, this.workerGroup,
69 CONNECT_TIMEOUT, keys);
70 final ChannelFuture channelPromise = bootstrap.connect();
71 channelPromise.addListener(new BootstrapListener(bootstrap, remoteAddress, slf, keys));
72 LOG.debug("Initiated BMP Client {} at {}.", channelPromise, remoteAddress);
73 return channelPromise;
77 public ChannelFuture createServer(final InetSocketAddress address, final BmpSessionListenerFactory slf,
78 final KeyMapping keys) {
79 final ServerBootstrap serverBootstrap = createServerBootstrap(this.sessionFactory, this.hf, slf,
80 BmpDispatcherUtil::createChannelWithDecoder, this.bossGroup, this.workerGroup, keys);
81 final ChannelFuture channelFuture = serverBootstrap.bind(address);
82 LOG.debug("Initiated BMP server {} at {}.", channelFuture, address);
87 public synchronized void close() {
89 if (Epoll.isAvailable()) {
90 this.workerGroup.shutdownGracefully(0, TIMEOUT, TimeUnit.SECONDS);
91 this.bossGroup.shutdownGracefully(0, TIMEOUT, TimeUnit.SECONDS);
95 private class BootstrapListener implements ChannelFutureListener {
96 private final Bootstrap bootstrap;
97 private final InetSocketAddress remoteAddress;
98 private final BmpSessionListenerFactory slf;
99 private final KeyMapping keys;
101 private final Timer timer = new Timer();
103 BootstrapListener(final Bootstrap bootstrap,
104 final InetSocketAddress remoteAddress, final BmpSessionListenerFactory slf, final KeyMapping keys) {
105 this.bootstrap = bootstrap;
106 this.remoteAddress = remoteAddress;
107 this.delay = INITIAL_BACKOFF;
113 public void operationComplete(final ChannelFuture future) throws Exception {
114 if (future.isCancelled()) {
115 LOG.debug("Connection {} cancelled!", future);
116 } else if (future.isSuccess()) {
117 LOG.debug("Connection {} succeeded!", future);
118 future.channel().closeFuture().addListener((ChannelFutureListener) channelFuture -> scheduleConnect());
120 if (this.delay > MAXIMUM_BACKOFF) {
121 LOG.warn("The time of maximum backoff has been exceeded. No further connection attempts with BMP "
122 + "router {}.", this.remoteAddress);
123 future.cancel(false);
126 final EventLoop loop = future.channel().eventLoop();
127 loop.schedule(() -> this.bootstrap.connect().addListener(this), this.delay, TimeUnit.MILLISECONDS);
128 LOG.info("The connection try to BMP router {} failed. Next reconnection attempt in {} milliseconds.",
129 this.remoteAddress, this.delay);
134 private void scheduleConnect() {
135 if (!BmpDispatcherImpl.this.close) {
136 timer.schedule(new TimerTask() {
139 createClient(BootstrapListener.this.remoteAddress, BootstrapListener.this.slf,
140 BootstrapListener.this.keys);