diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java index ab88a24ed7..c5f2092e0a 100644 --- a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java +++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbClientService.java @@ -228,4 +228,9 @@ public interface OvsdbClientService extends OvsdbRPC { * @return ovsdb ports */ Set getLocalPorts(Iterable ifaceids); + + /** + * Disconnects the ovsdb server. + */ + void disconnect(); } diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java index 9e2452408f..24bfeae95f 100644 --- a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java +++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/OvsdbController.java @@ -15,6 +15,9 @@ */ package org.onosproject.ovsdb.controller; +import org.onlab.packet.IpAddress; +import org.onlab.packet.TpPort; + import java.util.List; /** @@ -65,4 +68,12 @@ public interface OvsdbController { * @return OvsdbClient ovsdb node information */ OvsdbClientService getOvsdbClient(OvsdbNodeId nodeId); + + /** + * Connect to the ovsdb server with given ip address and port number. + * + * @param ip ip address + * @param port port number + */ + void connect(IpAddress ip, TpPort port); } diff --git a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java index 0c64cc0e9a..1b41be986e 100644 --- a/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java +++ b/ovsdb/api/src/main/java/org/onosproject/ovsdb/controller/driver/DefaultOvsdbClient.java @@ -821,7 +821,7 @@ public class DefaultOvsdbClient Function rowFunction = new Function() { @Override public DatabaseSchema apply(JsonNode input) { - log.info("Get ovsdb database schema", dbName); + log.info("Get ovsdb database schema {}", dbName); DatabaseSchema dbSchema = FromJsonUtil .jsonNodeToDbSchema(dbName, input); if (dbSchema == null) { @@ -1185,4 +1185,10 @@ public class DefaultOvsdbClient } return ifaceid; } + + @Override + public void disconnect() { + channel.disconnect(); + this.agent.removeConnectedNode(nodeId); + } } diff --git a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java index 075823275f..2e84a16a98 100644 --- a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java +++ b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/Controller.java @@ -15,25 +15,38 @@ */ package org.onosproject.ovsdb.controller.impl; +import io.netty.bootstrap.Bootstrap; import io.netty.bootstrap.ServerBootstrap; import io.netty.buffer.PooledByteBufAllocator; import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelFutureListener; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.EventLoop; import io.netty.channel.EventLoopGroup; import io.netty.channel.ServerChannel; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.string.StringEncoder; +import io.netty.handler.timeout.IdleState; +import io.netty.handler.timeout.IdleStateEvent; +import io.netty.handler.timeout.IdleStateHandler; import io.netty.util.CharsetUtil; import java.net.InetSocketAddress; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import org.onlab.packet.IpAddress; +import org.onlab.packet.TpPort; import org.onosproject.ovsdb.controller.OvsdbConstant; import org.onosproject.ovsdb.controller.OvsdbNodeId; import org.onosproject.ovsdb.controller.driver.DefaultOvsdbClient; @@ -63,6 +76,9 @@ public class Controller { private EventLoopGroup workerGroup; private Class serverChannelClass; + private static final int MAX_RETRY = 5; + private static final int IDLE_TIMEOUT_SEC = 10; + /** * Initialization. */ @@ -198,4 +214,86 @@ public class Controller { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); } + + /** + * Connect to the ovsdb server with given ip address and port number. + * + * @param ip ip address + * @param port port number + */ + public void connect(IpAddress ip, TpPort port) { + ChannelFutureListener listener = new ConnectionListener(this, ip, port); + connectRetry(ip, port, listener); + } + + private void connectRetry(IpAddress ip, TpPort port, ChannelFutureListener listener) { + try { + Bootstrap b = new Bootstrap(); + b.group(workerGroup) + .channel(NioSocketChannel.class) + .option(ChannelOption.TCP_NODELAY, true) + .handler(new ChannelInitializer() { + + @Override + protected void initChannel(SocketChannel channel) throws Exception { + ChannelPipeline p = channel.pipeline(); + p.addLast(new MessageDecoder(), + new StringEncoder(CharsetUtil.UTF_8), + new IdleStateHandler(IDLE_TIMEOUT_SEC, 0, 0), + new ConnectionHandler()); + } + }); + b.remoteAddress(ip.toString(), port.toInt()); + b.connect().addListener(listener); + } catch (Exception e) { + log.warn("Connection to the ovsdb server {}:{} failed", ip.toString(), port.toString()); + } + } + + private class ConnectionListener implements ChannelFutureListener { + private Controller controller; + private IpAddress ip; + private TpPort port; + private AtomicInteger count = new AtomicInteger(); + + public ConnectionListener(Controller controller, + IpAddress ip, + TpPort port) { + this.controller = controller; + this.ip = ip; + this.port = port; + } + + @Override + public void operationComplete(ChannelFuture channelFuture) throws Exception { + if (!channelFuture.isSuccess()) { + channelFuture.channel().close(); + + if (count.incrementAndGet() < MAX_RETRY) { + final EventLoop loop = channelFuture.channel().eventLoop(); + + loop.schedule(() -> { + controller.connectRetry(this.ip, this.port, this); + }, 1L, TimeUnit.SECONDS); + } else { + log.info("Connection to the ovsdb {}:{} failed", + this.ip.toString(), this.port.toString()); + } + } else { + handleNewNodeConnection(channelFuture.channel()); + } + } + } + + private class ConnectionHandler extends ChannelDuplexHandler { + + @Override + public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { + IdleStateEvent e = (IdleStateEvent) evt; + + if (e.state() == IdleState.READER_IDLE) { + ctx.close(); + } + } + } } diff --git a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java index 9b48296864..beeaa9c332 100644 --- a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java +++ b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbControllerImpl.java @@ -33,6 +33,7 @@ import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Service; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; +import org.onlab.packet.TpPort; import org.onosproject.ovsdb.controller.DefaultEventSubject; import org.onosproject.ovsdb.controller.EventSubject; import org.onosproject.ovsdb.controller.OvsdbClientService; @@ -142,6 +143,11 @@ public class OvsdbControllerImpl implements OvsdbController { return ovsdbClients.get(nodeId); } + @Override + public void connect(IpAddress ip, TpPort port) { + controller.connect(ip, port); + } + /** * Implementation of an Ovsdb Agent which is responsible for keeping track * of connected node and the state in which they are. diff --git a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java index 37942c2452..1956a1eb04 100644 --- a/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java +++ b/ovsdb/ctl/src/main/java/org/onosproject/ovsdb/controller/impl/OvsdbJsonRpcHandler.java @@ -89,7 +89,7 @@ public final class OvsdbJsonRpcHandler extends ChannelInboundHandlerAdapter { */ private void processOvsdbMessage(JsonNode jsonNode) { - log.info("Handle ovsdb message"); + log.debug("Handle ovsdb message"); if (jsonNode.has("result")) { diff --git a/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java b/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java index 5e4c56770f..7663a64dd3 100644 --- a/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java +++ b/providers/ovsdb/device/src/test/java/org/onosproject/ovsdb/providers/device/OvsdbDeviceProviderTest.java @@ -27,6 +27,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.onlab.packet.IpAddress; +import org.onlab.packet.TpPort; import org.onosproject.net.DeviceId; import org.onosproject.net.MastershipRole; import org.onosproject.net.device.DeviceDescription; @@ -193,6 +194,10 @@ public class OvsdbDeviceProviderTest { return null; } + @Override + public void connect(IpAddress ip, TpPort port) { + + } } } diff --git a/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java b/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java index 019cfa1f96..01e07dd84e 100644 --- a/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java +++ b/providers/ovsdb/host/src/test/java/org/onosproject/ovsdb/provider/host/OvsdbHostProviderTest.java @@ -26,6 +26,7 @@ import org.junit.Before; import org.junit.Test; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; +import org.onlab.packet.TpPort; import org.onosproject.net.DeviceId; import org.onosproject.net.HostId; import org.onosproject.net.host.HostDescription; @@ -201,5 +202,10 @@ public class OvsdbHostProviderTest { public OvsdbClientService getOvsdbClient(OvsdbNodeId nodeId) { return null; } + + @Override + public void connect(IpAddress ip, TpPort port) { + + } } }