Patch for ONOS-6840 NETCONF timeouts per device

Change-Id: Ia2e578245b97e0f68ea720cefe783e708e255ca7
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
index 887e1dd..c991762 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfDeviceInfo.java
@@ -19,6 +19,8 @@
 import com.google.common.base.Preconditions;
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
+import org.onosproject.netconf.config.NetconfDeviceConfig;
+import org.onosproject.netconf.config.NetconfSshClientLib;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -26,6 +28,8 @@
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.Objects;
+import java.util.Optional;
+import java.util.OptionalInt;
 
 /**
  * Represents a Netconf device information.
@@ -43,6 +47,10 @@
     //File keyFile @deprecated 1.9.0
     @Deprecated
     private File keyFile;
+    private Optional<NetconfSshClientLib> sshClientLib;
+    private OptionalInt connectTimeoutSec;
+    private OptionalInt replyTimeoutSec;
+    private OptionalInt idleTimeoutSec;
     private DeviceId deviceId;
 
 
@@ -63,6 +71,10 @@
         this.password = password;
         this.ipAddress = ipAddress;
         this.port = port;
+        this.sshClientLib = Optional.empty();
+        this.connectTimeoutSec = OptionalInt.empty();
+        this.replyTimeoutSec = OptionalInt.empty();
+        this.idleTimeoutSec = OptionalInt.empty();
     }
 
     /**
@@ -90,6 +102,73 @@
         this.port = port;
         this.key = keyString.toCharArray();
         this.keyFile = new File(keyString);
+        this.sshClientLib = Optional.empty();
+        this.connectTimeoutSec = OptionalInt.empty();
+        this.replyTimeoutSec = OptionalInt.empty();
+        this.idleTimeoutSec = OptionalInt.empty();
+    }
+
+    /**
+     * Convenieince constructor that converts all known fields from NetCfg data.
+     * @param netconfConfig NetCf configuration
+     */
+    public NetconfDeviceInfo(NetconfDeviceConfig netconfConfig) {
+        Preconditions.checkArgument(!netconfConfig.username().isEmpty(), "Empty device name");
+        Preconditions.checkNotNull(netconfConfig.port() > 0, "Negative port");
+        Preconditions.checkNotNull(netconfConfig.ip(), "Null ip address");
+
+        this.name = netconfConfig.username();
+        this.password = netconfConfig.password();
+        this.ipAddress = netconfConfig.ip();
+        this.port = netconfConfig.port();
+        if (netconfConfig.sshKey() != null && !netconfConfig.sshKey().isEmpty()) {
+            this.key = netconfConfig.sshKey().toCharArray();
+        }
+        this.keyFile = new File(netconfConfig.sshKey());
+        if (netconfConfig.sshClient().isPresent()) {
+            this.sshClientLib = Optional.of(NetconfSshClientLib.getEnum(netconfConfig.sshClient().get()));
+        } else {
+            this.sshClientLib = Optional.empty();
+        }
+        this.connectTimeoutSec = netconfConfig.connectTimeout();
+        this.replyTimeoutSec = netconfConfig.replyTimeout();
+        this.idleTimeoutSec = netconfConfig.idleTimeout();
+    }
+
+    /**
+     * Allows the NETCONF SSH Client library to be set.
+     *
+     * @param sshClientLib An enumerated value
+     */
+    public void setSshClientLib(Optional<NetconfSshClientLib> sshClientLib) {
+        this.sshClientLib = sshClientLib;
+    }
+
+    /**
+     * Allows the NETCONF SSH session initial connect timeout to be set.
+     *
+     * @param connectTimeoutSec value in seconds
+     */
+    public void setConnectTimeoutSec(OptionalInt connectTimeoutSec) {
+        this.connectTimeoutSec = connectTimeoutSec;
+    }
+
+    /**
+     * Allows the NETCONF SSH session replies timeout to be set.
+     *
+     * @param replyTimeoutSec value in seconds
+     */
+    public void setReplyTimeoutSec(OptionalInt replyTimeoutSec) {
+        this.replyTimeoutSec = replyTimeoutSec;
+    }
+
+    /**
+     * Allows the NETCONF SSH session idle timeout to be set.
+     *
+     * @param idleTimeoutSec value in seconds
+     */
+    public void setIdleTimeoutSec(OptionalInt idleTimeoutSec) {
+        this.idleTimeoutSec = idleTimeoutSec;
     }
 
     /**
@@ -153,6 +232,42 @@
     }
 
     /**
+     * Exposes the Client library implementation.
+     *
+     * @return Enumerated value
+     */
+    public Optional<NetconfSshClientLib> sshClientLib() {
+        return sshClientLib;
+    }
+
+    /**
+     * Exposes the device specific connect timeout.
+     *
+     * @return The timeout value in seconds
+     */
+    public OptionalInt getConnectTimeoutSec() {
+        return connectTimeoutSec;
+    }
+
+    /**
+     * Exposes the device specific reply timeout.
+     *
+     * @return The timeout value in seconds
+     */
+    public OptionalInt getReplyTimeoutSec() {
+        return replyTimeoutSec;
+    }
+
+    /**
+     * Exposes the device specific idle timeout.
+     *
+     * @return The timeout value in seconds
+     */
+    public OptionalInt getIdleTimeoutSec() {
+        return idleTimeoutSec;
+    }
+
+    /**
      * Return the info about the device in a string.
      * String format: "netconf:name@ip:port"
      *
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
index 7a4df0b..06c8b9c 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/NetconfSession.java
@@ -593,4 +593,28 @@
      */
     void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener);
 
+    /**
+     * Read the connect timeout that this session was created with.
+     * @return timeout in seconds
+     */
+    default int timeoutConnectSec() {
+        return 0;
+    };
+
+    /**
+     * Read the reply timeout that this session was created with.
+     * @return timeout in seconds
+     */
+    default int timeoutReplySec() {
+        return 0;
+    };
+
+    /**
+     * Read the idle timeout that this session was created with.
+     * @return timeout in seconds
+     */
+    default int timeoutIdleSec() {
+        return 0;
+    };
+
 }
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java
index 1accaec..28758b5 100644
--- a/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfDeviceConfig.java
@@ -21,6 +21,10 @@
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.config.Config;
+
+import java.util.Optional;
+import java.util.OptionalInt;
+
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
@@ -34,16 +38,20 @@
      */
     public static final String CONFIG_KEY = "netconf";
 
-    private static final String IP = "ip";
-    private static final String PORT = "port";
-    private static final String USERNAME = "username";
-    private static final String PASSWORD = "password";
-    private static final String SSHKEY = "sshkey";
+    public static final String IP = "ip";
+    public static final String PORT = "port";
+    public static final String USERNAME = "username";
+    public static final String PASSWORD = "password";
+    public static final String SSHKEY = "sshkey";
+    public static final String SSHCLIENT = "ssh-client";
+    public static final String CONNECT_TIMEOUT = "connect-timeout";
+    public static final String REPLY_TIMEOUT = "reply-timeout";
+    public static final String IDLE_TIMEOUT = "idle-timeout";
 
     @Override
     public boolean isValid() {
-        return hasOnlyFields(IP, PORT, USERNAME, PASSWORD, SSHKEY) &&
-                ip() != null;
+        return hasOnlyFields(IP, PORT, USERNAME, PASSWORD, SSHKEY, SSHCLIENT,
+                CONNECT_TIMEOUT, REPLY_TIMEOUT, IDLE_TIMEOUT) && ip() != null;
     }
 
     /**
@@ -92,6 +100,47 @@
     }
 
     /**
+     * Gets the NETCONF SSH Client implementation.
+     * Expecting "apache-mina" or "ethz-ssh2"
+     *
+     * @return sshClient
+     */
+    public Optional<String> sshClient() {
+        String sshClient = get(SSHCLIENT, "");
+        return (sshClient.isEmpty() ? Optional.empty() : Optional.ofNullable(sshClient));
+    }
+
+    /**
+     * Gets the connect timeout of the SSH connection.
+     *
+     * @return connectTimeout
+     */
+    public OptionalInt connectTimeout() {
+        int connectTimeout = get(CONNECT_TIMEOUT, 0);
+        return (connectTimeout == 0) ? OptionalInt.empty() : OptionalInt.of(connectTimeout);
+    }
+
+    /**
+     * Gets the reply timeout of the SSH connection.
+     *
+     * @return replyTimeout
+     */
+    public OptionalInt replyTimeout() {
+        int replyTimeout = get(REPLY_TIMEOUT, 0);
+        return (replyTimeout == 0) ? OptionalInt.empty() : OptionalInt.of(replyTimeout);
+    }
+
+    /**
+     * Gets the idle timeout of the SSH connection.
+     *
+     * @return idleTimeout
+     */
+    public OptionalInt idleTimeout() {
+        int idleTimeout = get(IDLE_TIMEOUT, 0);
+        return (idleTimeout == 0) ? OptionalInt.empty() : OptionalInt.of(idleTimeout);
+    }
+
+    /**
      * Sets the Ip for the Device.
      *
      * @param ip the ip
@@ -141,6 +190,59 @@
         return (NetconfDeviceConfig) setOrClear(SSHKEY, sshKey);
     }
 
+    /**
+     * Sets the NETCONF Ssh client implementation for the Device.
+     * Must be 'apache-mina' or 'ethz-ssh2'
+     * When specified, overrides NetconfControllerImpl.sshLibrary for this device
+     *
+     * @param sshimpl sshimpl as string
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setSshImpl(String sshimpl) {
+        return (NetconfDeviceConfig) setOrClear(SSHCLIENT, sshimpl);
+    }
+
+    /**
+     * Sets the NETCONF Connect Timeout for the Device.
+     * This is the amount of time in seconds allowed for the SSH handshake to take place
+     * Minimum 1 second
+     * When specified, overrides NetconfControllerImpl.netconfConnectTimeout for this device
+     *
+     * @param connectTimeout connectTimeout as int
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setConnectTimeout(Integer connectTimeout) {
+        return (NetconfDeviceConfig) setOrClear(CONNECT_TIMEOUT, connectTimeout);
+    }
+
+    /**
+     * Sets the NETCONF Reply Timeout for the Device.
+     * This is the amount of time in seconds allowed for the NETCONF Reply to a command
+     * Minimum 1 second
+     * When specified, overrides NetconfControllerImpl.netconfReplyTimeout for this device
+     *
+     * @param replyTimeout replyTimeout as int
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setReplyTimeout(Integer replyTimeout) {
+        return (NetconfDeviceConfig) setOrClear(REPLY_TIMEOUT, replyTimeout);
+    }
+
+    /**
+     * Sets the NETCONF Idle Timeout for the Device.
+     * This is the amount of time in seconds after which the SSH connection will
+     * close if no traffic is detected
+     * Minimum 10 second
+     * When specified, overrides NetconfControllerImpl.netconfIdleTimeout for this device
+     *
+     * @param idleTimeout idleTimeout as int
+     * @return instance for chaining
+     */
+    public NetconfDeviceConfig setIdleTimeout(Integer idleTimeout) {
+        return (NetconfDeviceConfig) setOrClear(IDLE_TIMEOUT, idleTimeout);
+    }
+
+
     private Pair<String, Integer> extractIpPort() {
         // Assuming one of
         //  - netconf:ip:port
diff --git a/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfSshClientLib.java b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfSshClientLib.java
new file mode 100644
index 0000000..8ca1e93
--- /dev/null
+++ b/protocols/netconf/api/src/main/java/org/onosproject/netconf/config/NetconfSshClientLib.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2015-present Open Networking Foundation
+ *
+ * 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.netconf.config;
+
+/**
+ * Enumerated list of SSH client library types.
+ */
+public enum NetconfSshClientLib {
+    APACHE_MINA("apache-mina"),
+    ETHZ_SSH2("ethz-ssh2");
+
+    private String impl;
+
+    private NetconfSshClientLib(String impl) {
+        this.impl = impl;
+    }
+
+    @Override
+    public String toString() {
+        return impl;
+    }
+
+    public static NetconfSshClientLib getEnum(String valueOf) {
+        return valueOf(valueOf.toUpperCase().replace('-', '_'));
+    }
+}
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
index 0f98c77..a2c6a3d 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/NetconfSessionImpl.java
@@ -104,6 +104,9 @@
     private boolean subscriptionConnected = false;
     private String notificationFilterSchema = null;
 
+    private int connectTimeout;
+    private int replyTimeout;
+
 
     public NetconfSessionImpl(NetconfDeviceInfo deviceInfo) throws NetconfException {
         this.deviceInfo = deviceInfo;
@@ -112,13 +115,18 @@
         connectionActive = false;
         replies = new ConcurrentHashMap<>();
         errorReplies = new ArrayList<>();
+        connectTimeout = deviceInfo.getConnectTimeoutSec().orElse(
+                                    NetconfControllerImpl.netconfConnectTimeout);
+        replyTimeout = deviceInfo.getReplyTimeoutSec().orElse(
+                                    NetconfControllerImpl.netconfReplyTimeout);
+        log.info("Connecting to {} with timeouts C:{}, R:{}. idle=connect", deviceInfo,
+                connectTimeout, replyTimeout);
         startConnection();
     }
 
     private void startConnection() throws NetconfException {
         if (!connectionActive) {
             netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port());
-            int connectTimeout = NetconfControllerImpl.netconfConnectTimeout;
 
             try {
                 netconfConnection.connect(null, 1000 * connectTimeout, 1000 * connectTimeout);
@@ -312,7 +320,6 @@
         request = formatRequestMessageId(request, messageId);
         request = formatXmlHeader(request);
         CompletableFuture<String> futureReply = request(request, messageId);
-        int replyTimeout = NetconfControllerImpl.netconfReplyTimeout;
         String rp;
         try {
             rp = futureReply.get(replyTimeout, TimeUnit.SECONDS);
@@ -622,6 +629,24 @@
     }
 
     @Override
+    public int timeoutConnectSec() {
+        return connectTimeout;
+    }
+
+    @Override
+    public int timeoutReplySec() {
+        return replyTimeout;
+    }
+
+    /**
+     * Idle timeout is not settable on ETZ_SSH - the valuse used is the connect timeout.
+     */
+    @Override
+    public int timeoutIdleSec() {
+        return connectTimeout;
+    }
+
+    @Override
     public void addDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
         streamHandler.addDeviceEventListener(listener);
     }
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java
index 2265234..5e6d7f9 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfControllerImpl.java
@@ -29,6 +29,7 @@
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.key.DeviceKey;
 import org.onosproject.net.key.DeviceKeyId;
@@ -42,6 +43,8 @@
 import org.onosproject.netconf.NetconfDeviceOutputEvent;
 import org.onosproject.netconf.NetconfDeviceOutputEventListener;
 import org.onosproject.netconf.NetconfException;
+import org.onosproject.netconf.config.NetconfDeviceConfig;
+import org.onosproject.netconf.config.NetconfSshClientLib;
 import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -55,8 +58,8 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-import static com.google.common.base.Strings.isNullOrEmpty;
 import static org.onlab.util.Tools.get;
+import static org.onlab.util.Tools.getIntegerProperty;
 import static org.onlab.util.Tools.groupedThreads;
 
 /**
@@ -87,10 +90,10 @@
     protected static int netconfIdleTimeout = DEFAULT_IDLE_TIMEOUT_SECONDS;
 
     private static final String SSH_LIBRARY = "sshLibrary";
-    private static final String APACHE_MINA = "apache_mina";
-    @Property(name = SSH_LIBRARY, value = APACHE_MINA,
+    private static final String APACHE_MINA_STR = "apache-mina";
+    @Property(name = SSH_LIBRARY, value = APACHE_MINA_STR,
             label = "Ssh Library instead of apache_mina (i.e. ethz-ssh2")
-    protected static String sshLibrary = APACHE_MINA;
+    protected static NetconfSshClientLib sshLibrary = NetconfSshClientLib.APACHE_MINA;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected ComponentConfigService cfgService;
@@ -101,6 +104,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DeviceKeyService deviceKeyService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry netCfgService;
+
     public static final Logger log = LoggerFactory
             .getLogger(NetconfControllerImpl.class);
 
@@ -139,36 +145,24 @@
         if (context == null) {
             netconfReplyTimeout = DEFAULT_REPLY_TIMEOUT_SECONDS;
             netconfConnectTimeout = DEFAULT_CONNECT_TIMEOUT_SECONDS;
-            sshLibrary = APACHE_MINA;
+            netconfIdleTimeout = DEFAULT_IDLE_TIMEOUT_SECONDS;
+            sshLibrary = NetconfSshClientLib.APACHE_MINA;
             log.info("No component configuration");
             return;
         }
 
         Dictionary<?, ?> properties = context.getProperties();
 
-        int newNetconfReplyTimeout;
-        int newNetconfConnectTimeout;
-        int newNetconfIdleTimeout;
         String newSshLibrary;
-        try {
-            String s = get(properties, PROP_NETCONF_REPLY_TIMEOUT);
-            newNetconfReplyTimeout = isNullOrEmpty(s) ?
-                    netconfReplyTimeout : Integer.parseInt(s.trim());
 
-            s = get(properties, PROP_NETCONF_CONNECT_TIMEOUT);
-            newNetconfConnectTimeout = isNullOrEmpty(s) ?
-                    netconfConnectTimeout : Integer.parseInt(s.trim());
+        int newNetconfReplyTimeout = getIntegerProperty(
+                properties, PROP_NETCONF_REPLY_TIMEOUT, netconfReplyTimeout);
+        int newNetconfConnectTimeout = getIntegerProperty(
+                properties, PROP_NETCONF_CONNECT_TIMEOUT, netconfConnectTimeout);
+        int newNetconfIdleTimeout = getIntegerProperty(
+                properties, PROP_NETCONF_IDLE_TIMEOUT, netconfIdleTimeout);
 
-            s = get(properties, PROP_NETCONF_IDLE_TIMEOUT);
-            newNetconfIdleTimeout = isNullOrEmpty(s) ?
-                    netconfIdleTimeout : Integer.parseInt(s.trim());
-
-            newSshLibrary = get(properties, SSH_LIBRARY);
-
-        } catch (NumberFormatException e) {
-            log.warn("Component configuration had invalid value", e);
-            return;
-        }
+        newSshLibrary = get(properties, SSH_LIBRARY);
 
         if (newNetconfConnectTimeout < 0) {
             log.warn("netconfConnectTimeout is invalid - less than 0");
@@ -184,8 +178,10 @@
         netconfReplyTimeout = newNetconfReplyTimeout;
         netconfConnectTimeout = newNetconfConnectTimeout;
         netconfIdleTimeout = newNetconfIdleTimeout;
-        sshLibrary = newSshLibrary;
-        log.info("Settings: {} = {}, {} = {}, {} = {}",
+        if (newSshLibrary != null) {
+            sshLibrary = NetconfSshClientLib.getEnum(newSshLibrary);
+        }
+        log.info("Settings: {} = {}, {} = {}, {} = {}, {} = {}",
                  PROP_NETCONF_REPLY_TIMEOUT, netconfReplyTimeout,
                  PROP_NETCONF_CONNECT_TIMEOUT, netconfConnectTimeout,
                  PROP_NETCONF_IDLE_TIMEOUT, netconfIdleTimeout,
@@ -221,9 +217,17 @@
 
     @Override
     public NetconfDevice connectDevice(DeviceId deviceId) throws NetconfException {
+        NetconfDeviceConfig netCfg  = netCfgService.getConfig(
+                deviceId, NetconfDeviceConfig.class);
+        NetconfDeviceInfo deviceInfo = null;
+
         if (netconfDeviceMap.containsKey(deviceId)) {
             log.debug("Device {} is already present", deviceId);
             return netconfDeviceMap.get(deviceId);
+        } else if (netCfg != null) {
+            log.debug("Device {} is present in NetworkConfig", deviceId);
+            deviceInfo = new NetconfDeviceInfo(netCfg);
+
         } else {
             log.debug("Creating NETCONF device {}", deviceId);
             Device device = deviceService.getDevice(deviceId);
@@ -249,7 +253,6 @@
             try {
                 DeviceKey deviceKey = deviceKeyService.getDeviceKey(
                         DeviceKeyId.deviceKeyId(deviceId.toString()));
-                NetconfDeviceInfo deviceInfo = null;
                 if (deviceKey.type() == DeviceKey.Type.USERNAME_PASSWORD) {
                     UsernamePassword usernamepasswd = deviceKey.asUsernamePassword();
 
@@ -271,13 +274,13 @@
                 } else {
                     log.error("Unknown device key for device {}", deviceId);
                 }
-                NetconfDevice netconfDevicedevice = createDevice(deviceInfo);
-                netconfDevicedevice.getSession().addDeviceOutputListener(downListener);
-                return netconfDevicedevice;
             } catch (NullPointerException e) {
                 throw new NetconfException("No Device Key for device " + deviceId, e);
             }
         }
+        NetconfDevice netconfDevicedevice = createDevice(deviceInfo);
+        netconfDevicedevice.getSession().addDeviceOutputListener(downListener);
+        return netconfDevicedevice;
     }
 
     @Override
@@ -341,10 +344,15 @@
         @Override
         public NetconfDevice createNetconfDevice(NetconfDeviceInfo netconfDeviceInfo)
                 throws NetconfException {
-            if (sshLibrary.equals(ETHZ_SSH2)) {
+            if (NetconfSshClientLib.ETHZ_SSH2.equals(netconfDeviceInfo.sshClientLib()) ||
+                    NetconfSshClientLib.ETHZ_SSH2.equals(sshLibrary)) {
+                log.info("Creating NETCONF session to {} with {}",
+                            netconfDeviceInfo.name(), NetconfSshClientLib.ETHZ_SSH2);
                 return new DefaultNetconfDevice(netconfDeviceInfo,
-                                                new NetconfSessionImpl.SshNetconfSessionFactory());
+                            new NetconfSessionImpl.SshNetconfSessionFactory());
             }
+            log.info("Creating NETCONF session to {} with {}",
+                    netconfDeviceInfo.getDeviceId(), NetconfSshClientLib.APACHE_MINA);
             return new DefaultNetconfDevice(netconfDeviceInfo);
         }
     }
@@ -372,8 +380,8 @@
 
                     } catch (NetconfException e) {
                         log.error("The SSH connection with device {} couldn't be " +
-                                          "reestablished due to {}. " +
-                                          "Marking the device as unreachable", e.getMessage());
+                                "reestablished due to {}. " +
+                                "Marking the device as unreachable", e.getMessage());
                         log.debug("Complete exception: ", e);
                         removeDevice(did);
                     }
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
index 99ad5f2..959c807 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionImpl.java
@@ -136,6 +136,8 @@
     private final Collection<NetconfSession> children =
             new CopyOnWriteArrayList<>();
 
+    private int connectTimeout;
+    private int replyTimeout;
 
     public NetconfSessionImpl(NetconfDeviceInfo deviceInfo) throws NetconfException {
         this.deviceInfo = deviceInfo;
@@ -144,6 +146,7 @@
         connectionActive = false;
         replies = new ConcurrentHashMap<>();
         errorReplies = new ArrayList<>();
+
         startConnection();
     }
 
@@ -160,9 +163,15 @@
     }
 
     private void startConnection() throws NetconfException {
+        connectTimeout = deviceInfo.getConnectTimeoutSec().orElse(
+                                    NetconfControllerImpl.netconfConnectTimeout);
+        replyTimeout = deviceInfo.getReplyTimeoutSec().orElse(
+                                    NetconfControllerImpl.netconfReplyTimeout);
+        log.debug("Connecting to {} with timeouts C:{}, R:{}. I:connect-timeout", deviceInfo,
+                connectTimeout, replyTimeout);
+
         if (!connectionActive) {
             netconfConnection = new Connection(deviceInfo.ip().toString(), deviceInfo.port());
-            int connectTimeout = NetconfControllerImpl.netconfConnectTimeout;
 
             try {
                 netconfConnection.connect(null, 1000 * connectTimeout, 1000 * connectTimeout);
@@ -431,16 +440,18 @@
         request = formatXmlHeader(request);
         request = formatRequestMessageId(request, messageId);
         CompletableFuture<String> futureReply = request(request, messageId);
-        int replyTimeout = NetconfControllerImpl.netconfReplyTimeout;
         String rp;
         try {
+            log.debug("Sending request to NETCONF with timeout {} for {}",
+                    replyTimeout, deviceInfo.name());
             rp = futureReply.get(replyTimeout, TimeUnit.SECONDS);
             replies.remove(messageId);
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             throw new NetconfException("Interrupted waiting for reply for request" + request, e);
         } catch (TimeoutException e) {
-            throw new NetconfException("Timed out waiting for reply for request " + request, e);
+            throw new NetconfException("Timed out waiting for reply for request " +
+                    request + " after " + replyTimeout + " sec.", e);
         } catch (ExecutionException e) {
             log.warn("Closing session {} for {} due to unexpected Error", sessionID, deviceInfo, e);
 
@@ -790,7 +801,6 @@
         onosCapabilities = capabilities;
     }
 
-
     @Override
     public void addDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
         streamHandler.addDeviceEventListener(listener);
@@ -798,6 +808,24 @@
     }
 
     @Override
+    public int timeoutConnectSec() {
+        return connectTimeout;
+    }
+
+    @Override
+    public int timeoutReplySec() {
+        return replyTimeout;
+    }
+
+    /**
+     * Idle timeout is not settable on ETZ_SSH - the valuse used is the connect timeout.
+     */
+    @Override
+    public int timeoutIdleSec() {
+        return connectTimeout;
+    }
+
+    @Override
     public void removeDeviceOutputListener(NetconfDeviceOutputEventListener listener) {
         primaryListeners.remove(listener);
         streamHandler.removeDeviceEventListener(listener);
@@ -902,4 +930,4 @@
             return new NetconfSessionImpl(netconfDeviceInfo);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
index 0e2e3ea..6d30314 100644
--- a/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
+++ b/protocols/netconf/ctl/src/main/java/org/onosproject/netconf/ctl/impl/NetconfSessionMinaImpl.java
@@ -143,6 +143,10 @@
     private final Collection<NetconfSession> children =
             new CopyOnWriteArrayList<>();
 
+    private int connectTimeout;
+    private int replyTimeout;
+    private int idleTimeout;
+
 
     private ClientChannel channel = null;
     private ClientSession session = null;
@@ -153,6 +157,7 @@
         this.deviceInfo = deviceInfo;
         replies = new ConcurrentHashMap<>();
         errorReplies = new ArrayList<>();
+
         startConnection();
     }
 
@@ -165,6 +170,15 @@
     }
 
     private void startConnection() throws NetconfException {
+        connectTimeout = deviceInfo.getConnectTimeoutSec().orElse(
+                                NetconfControllerImpl.netconfConnectTimeout);
+        replyTimeout = deviceInfo.getReplyTimeoutSec().orElse(
+                                NetconfControllerImpl.netconfReplyTimeout);
+        idleTimeout = deviceInfo.getIdleTimeoutSec().orElse(
+                                NetconfControllerImpl.netconfIdleTimeout);
+        log.info("Connecting to {} with timeouts C:{}, R:{}, I:{}", deviceInfo,
+                connectTimeout, replyTimeout, idleTimeout);
+
         try {
             startClient();
         } catch (IOException e) {
@@ -174,11 +188,10 @@
 
     private void startClient() throws IOException {
         client = SshClient.setUpDefaultClient();
-        int replyTimeoutSec = NetconfControllerImpl.netconfIdleTimeout;
         client.getProperties().putIfAbsent(FactoryManager.IDLE_TIMEOUT,
-                TimeUnit.SECONDS.toMillis(replyTimeoutSec));
+                TimeUnit.SECONDS.toMillis(idleTimeout));
         client.getProperties().putIfAbsent(FactoryManager.NIO2_READ_TIMEOUT,
-                TimeUnit.SECONDS.toMillis(replyTimeoutSec + 15L));
+                TimeUnit.SECONDS.toMillis(idleTimeout + 15L));
         client.start();
         client.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
         startSession();
@@ -189,7 +202,7 @@
         connectFuture = client.connect(deviceInfo.name(),
                 deviceInfo.ip().toString(),
                 deviceInfo.port())
-                .verify(NetconfControllerImpl.netconfConnectTimeout, TimeUnit.SECONDS);
+                .verify(connectTimeout, TimeUnit.SECONDS);
         session = connectFuture.getSession();
         //Using the device ssh key if possible
         if (deviceInfo.getKey() != null) {
@@ -213,7 +226,7 @@
         } else {
             session.addPasswordIdentity(deviceInfo.password());
         }
-        session.auth().verify(NetconfControllerImpl.netconfConnectTimeout, TimeUnit.SECONDS);
+        session.auth().verify(connectTimeout, TimeUnit.SECONDS);
         Set<ClientSession.ClientSessionEvent> event = session.waitFor(
                 ImmutableSet.of(ClientSession.ClientSessionEvent.WAIT_AUTH,
                         ClientSession.ClientSessionEvent.CLOSED,
@@ -239,7 +252,7 @@
     private void openChannel() throws IOException {
         channel = session.createSubsystemChannel("netconf");
         OpenFuture channelFuture = channel.open();
-        if (channelFuture.await(NetconfControllerImpl.netconfConnectTimeout, TimeUnit.SECONDS)) {
+        if (channelFuture.await(connectTimeout, TimeUnit.SECONDS)) {
             if (channelFuture.isOpened()) {
                 streamHandler = new NetconfStreamThread(channel.getInvertedOut(), channel.getInvertedIn(),
                         channel.getInvertedErr(), deviceInfo,
@@ -456,6 +469,21 @@
         return streamHandler.sendMessage(request);
     }
 
+    @Override
+    public int timeoutConnectSec() {
+        return connectTimeout;
+    }
+
+    @Override
+    public int timeoutReplySec() {
+        return replyTimeout;
+    }
+
+    @Override
+    public int timeoutIdleSec() {
+        return idleTimeout;
+    }
+
     private CompletableFuture<String> request(String request, int messageId) {
         return streamHandler.sendMessage(request, messageId);
     }
@@ -474,16 +502,18 @@
         request = formatXmlHeader(request);
         request = formatRequestMessageId(request, messageId);
         CompletableFuture<String> futureReply = request(request, messageId);
-        int replyTimeout = NetconfControllerImpl.netconfReplyTimeout;
         String rp;
         try {
+            log.debug("Sending request to NETCONF with timeout {} for {}",
+                    replyTimeout, deviceInfo.name());
             rp = futureReply.get(replyTimeout, TimeUnit.SECONDS);
             replies.remove(messageId); // Why here???
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             throw new NetconfException("Interrupted waiting for reply for request" + request, e);
         } catch (TimeoutException e) {
-            throw new NetconfException("Timed out waiting for reply for request " + request, e);
+            throw new NetconfException("Timed out waiting for reply for request " +
+                    request + " after " + replyTimeout + " sec.", e);
         } catch (ExecutionException e) {
             log.warn("Closing session {} for {} due to unexpected Error", sessionID, deviceInfo, e);
             try {
@@ -951,4 +981,4 @@
             return new NetconfSessionMinaImpl(netconfDeviceInfo);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java
index eab21fd..ed4eabf 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfControllerImplTest.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.netconf.ctl.impl;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.easymock.EasyMock;
 import org.junit.After;
 import org.junit.Before;
@@ -24,6 +26,12 @@
 import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.config.NetworkConfigRegistryAdapter;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.key.DeviceKeyService;
 import org.onosproject.netconf.NetconfDevice;
@@ -34,8 +42,12 @@
 import org.onosproject.netconf.NetconfDeviceOutputEventListener;
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
+import org.onosproject.netconf.config.NetconfDeviceConfig;
+import org.onosproject.netconf.config.NetconfSshClientLib;
 import org.osgi.service.component.ComponentContext;
 
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.util.Dictionary;
 import java.util.Enumeration;
@@ -51,6 +63,9 @@
  * Unit tests for the Netconf controller implementation test.
  */
 public class NetconfControllerImplTest {
+    private final Set<ConfigFactory> cfgFactories = new HashSet<>();
+    private final Set<NetworkConfigListener> netCfgListeners = new HashSet<>();
+    private boolean available = false;
 
     NetconfControllerImpl ctrl;
 
@@ -60,6 +75,9 @@
     NetconfDeviceInfo badDeviceInfo3;
     NetconfDeviceInfo deviceInfoIpV6;
 
+    NetconfDeviceConfig deviceConfig10;
+    DeviceId deviceConfig10Id;
+
     //Devices & DeviceId
     NetconfDevice device1;
     DeviceId deviceId1;
@@ -77,16 +95,25 @@
     private static final String DEVICE_1_IP = "10.10.10.11";
     private static final String DEVICE_2_IP = "10.10.10.12";
     private static final String BAD_DEVICE_IP = "10.10.10.13";
+    private static final String DEVICE_10_IP = "10.10.10.10";
     private static final String DEVICE_IPV6 = "2001:db8::1";
 
     private static final int DEVICE_1_PORT = 11;
     private static final int DEVICE_2_PORT = 12;
     private static final int BAD_DEVICE_PORT = 13;
     private static final int IPV6_DEVICE_PORT = 14;
+    private static final int DEVICE_10_PORT = 10;
+
+    private static final String DEVICE_10_USERNAME = "device10";
+    private static final String DEVICE_10_PASSWORD = "010";
+    private static final int DEVICE_10_CONNECT_TIMEOUT = 10;
+    private static final int DEVICE_10_REPLY_TIMEOUT = 11;
+    private static final int DEVICE_10_IDLE_TIMEOUT = 12;
 
     private static ComponentConfigService cfgService = new ComponentConfigAdapter();
     private static DeviceService deviceService = new NetconfDeviceServiceMock();
     private static DeviceKeyService deviceKeyService = new NetconfDeviceKeyServiceMock();
+    private final NetworkConfigRegistry netCfgService = new MockNetworkConfigRegistry();
 
     private final ComponentContext context = new MockComponentContext();
 
@@ -97,13 +124,35 @@
         ctrl.cfgService = cfgService;
         ctrl.deviceService = deviceService;
         ctrl.deviceKeyService = deviceKeyService;
+        ctrl.netCfgService = netCfgService;
 
         //Creating mock devices
         deviceInfo1 = new NetconfDeviceInfo("device1", "001", IpAddress.valueOf(DEVICE_1_IP), DEVICE_1_PORT);
         deviceInfo2 = new NetconfDeviceInfo("device2", "002", IpAddress.valueOf(DEVICE_2_IP), DEVICE_2_PORT);
+        deviceInfo2.setSshClientLib(Optional.of(NetconfSshClientLib.ETHZ_SSH2));
         badDeviceInfo3 = new NetconfDeviceInfo("device3", "003", IpAddress.valueOf(BAD_DEVICE_IP), BAD_DEVICE_PORT);
         deviceInfoIpV6 = new NetconfDeviceInfo("deviceIpv6", "004", IpAddress.valueOf(DEVICE_IPV6), IPV6_DEVICE_PORT);
 
+        deviceConfig10Id = DeviceId.deviceId("netconf:" + DEVICE_10_IP + ":" + DEVICE_10_PORT);
+        //Create a JSON entry just like Network Config accepts
+        ObjectMapper mapper = new ObjectMapper();
+        String jsonMessage = "{\n" +
+                "  \"ip\":\"" + DEVICE_10_IP + "\",\n" +
+                "  \"port\":" + DEVICE_10_PORT + ",\n" +
+                "  \"username\":\"" + DEVICE_10_USERNAME + "\",\n" +
+                "  \"password\":\"" + DEVICE_10_PASSWORD + "\",\n" +
+                "  \"" + NetconfDeviceConfig.CONNECT_TIMEOUT + "\":" + DEVICE_10_CONNECT_TIMEOUT + ",\n" +
+                "  \"" + NetconfDeviceConfig.REPLY_TIMEOUT + "\":" + DEVICE_10_REPLY_TIMEOUT + ",\n" +
+                "  \"" + NetconfDeviceConfig.IDLE_TIMEOUT + "\":" + DEVICE_10_IDLE_TIMEOUT + ",\n" +
+                "  \"" + NetconfDeviceConfig.SSHCLIENT + "\":\"" + NetconfSshClientLib.ETHZ_SSH2.toString() + "\"\n" +
+                "}";
+        InputStream jsonStream = new ByteArrayInputStream(jsonMessage.getBytes());
+        JsonNode jsonNode = mapper.readTree(jsonStream);
+        jsonStream.close();
+        ConfigApplyDelegate delegate = new MockDelegate();
+        deviceConfig10 = new NetconfDeviceConfig();
+        deviceConfig10.init(deviceConfig10Id, "netconf", jsonNode, mapper, delegate);
+
         device1 = new TestNetconfDevice(deviceInfo1);
         deviceId1 = deviceInfo1.getDeviceId();
         device2 = new TestNetconfDevice(deviceInfo2);
@@ -162,7 +211,7 @@
                      2, ctrl.netconfConnectTimeout);
         assertEquals("Incorrect NetConf session timeout",
                      1, ctrl.netconfReplyTimeout);
-        assertEquals("ethz-ssh2", ctrl.sshLibrary);
+        assertEquals("ethz-ssh2", ctrl.sshLibrary.toString());
     }
 
     /**
@@ -228,13 +277,41 @@
     }
 
     /**
+     * Check for connection by netconfDeviceConfig.
+     */
+    @Test
+    public void testConnectDeviceNetConfig10() throws Exception {
+        NetconfDevice fetchedDevice10 = ctrl.connectDevice(deviceConfig10Id);
+        assertEquals("Incorrect device fetched - ip",
+                fetchedDevice10.getDeviceInfo().ip().toString(), DEVICE_10_IP);
+        assertEquals("Incorrect device fetched - port",
+                fetchedDevice10.getDeviceInfo().port(), DEVICE_10_PORT);
+        assertEquals("Incorrect device fetched - username",
+                fetchedDevice10.getDeviceInfo().name(), DEVICE_10_USERNAME);
+        assertEquals("Incorrect device fetched - password",
+                fetchedDevice10.getDeviceInfo().password(), DEVICE_10_PASSWORD);
+        assertEquals("Incorrect device fetched - connectTimeout",
+                fetchedDevice10.getDeviceInfo().getConnectTimeoutSec().getAsInt(),
+                DEVICE_10_CONNECT_TIMEOUT);
+        assertEquals("Incorrect device fetched - replyTimeout",
+                fetchedDevice10.getDeviceInfo().getReplyTimeoutSec().getAsInt(),
+                DEVICE_10_REPLY_TIMEOUT);
+        assertEquals("Incorrect device fetched - idleTimeout",
+                fetchedDevice10.getDeviceInfo().getIdleTimeoutSec().getAsInt(),
+                DEVICE_10_IDLE_TIMEOUT);
+        assertEquals("Incorrect device fetched - sshClient",
+                fetchedDevice10.getDeviceInfo().sshClientLib().get(),
+                NetconfSshClientLib.ETHZ_SSH2);
+    }
+
+    /**
      * Check for correct device connection. In this case the device map get modified.
      */
     @Test
     public void testConnectCorrectDevice() throws Exception {
         reflectedDeviceMap.clear();
-        ctrl.connectDevice(deviceInfo1.getDeviceId());
-        ctrl.connectDevice(deviceInfo2.getDeviceId());
+        NetconfDevice device1 = ctrl.connectDevice(deviceInfo1.getDeviceId());
+        NetconfDevice device2 = ctrl.connectDevice(deviceInfo2.getDeviceId());
         assertTrue("Incorrect device connection", ctrl.getDevicesMap().containsKey(deviceId1));
         assertTrue("Incorrect device connection", ctrl.getDevicesMap().containsKey(deviceId2));
         assertEquals("Incorrect device connection", 2, ctrl.getDevicesMap().size());
@@ -416,4 +493,46 @@
             return null;
         }
     }
+
+    private class MockNetworkConfigRegistry extends NetworkConfigRegistryAdapter {
+        NetconfDeviceConfig cfg = null;
+
+        @Override
+        public void registerConfigFactory(ConfigFactory configFactory) {
+            cfgFactories.add(configFactory);
+        }
+
+        @Override
+        public void unregisterConfigFactory(ConfigFactory configFactory) {
+            cfgFactories.remove(configFactory);
+        }
+
+        @Override
+        public void addListener(NetworkConfigListener listener) {
+            netCfgListeners.add(listener);
+        }
+
+        @Override
+        public void removeListener(NetworkConfigListener listener) {
+            netCfgListeners.remove(listener);
+        }
+
+
+        @Override
+        public <S, C extends Config<S>> C getConfig(S subject, Class<C> configClass) {
+            DeviceId did = (DeviceId) subject;
+            if (configClass.equals(NetconfDeviceConfig.class)
+                    && did.equals(deviceConfig10Id)) {
+                return (C) deviceConfig10;
+            }
+            return null;
+        }
+
+    }
+
+    private class MockDelegate implements ConfigApplyDelegate {
+        @Override
+        public void onApply(Config configFile) {
+        }
+    }
 }
diff --git a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
index 1b5e7fa..842bafd 100644
--- a/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
+++ b/protocols/netconf/ctl/src/test/java/org/onosproject/netconf/ctl/impl/NetconfSessionImplTest.java
@@ -16,6 +16,7 @@
 package org.onosproject.netconf.ctl.impl;
 
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
@@ -28,6 +29,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Optional;
+import java.util.OptionalInt;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -46,10 +48,11 @@
 import org.junit.Test;
 import org.onlab.junit.TestTools;
 import org.onlab.packet.Ip4Address;
+import org.onosproject.netconf.DatastoreId;
+import org.onosproject.netconf.NetconfController;
 import org.onosproject.netconf.NetconfDeviceInfo;
 import org.onosproject.netconf.NetconfException;
 import org.onosproject.netconf.NetconfSession;
-import org.onosproject.netconf.DatastoreId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -116,28 +119,36 @@
         sshServerNetconf.open();
         log.info("SSH Server opened on port {}", PORT_NUMBER);
 
-        NetconfDeviceInfo deviceInfo = new NetconfDeviceInfo(
+        NetconfController netconfCtl = new NetconfControllerImpl();
+
+        NetconfDeviceInfo deviceInfo1 = new NetconfDeviceInfo(
                 TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), PORT_NUMBER);
 
-        session1 = new NetconfSessionImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
+        session1 = new NetconfSessionImpl(deviceInfo1, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session1.getSessionId());
         assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session1.getSessionId().equalsIgnoreCase("0"));
         assertThat(session1.getDeviceCapabilitiesSet(), containsInAnyOrder(
                 NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES.toArray()));
-        session2 = new NetconfSessionImpl(deviceInfo, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
+
+        NetconfDeviceInfo deviceInfo2 = new NetconfDeviceInfo(
+                TEST_USERNAME, TEST_PASSWORD, Ip4Address.valueOf(TEST_HOSTNAME), PORT_NUMBER);
+        deviceInfo2.setConnectTimeoutSec(OptionalInt.of(11));
+        deviceInfo2.setReplyTimeoutSec(OptionalInt.of(10));
+        deviceInfo2.setIdleTimeoutSec(OptionalInt.of(12));
+        session2 = new NetconfSessionMinaImpl(deviceInfo2, ImmutableList.of("urn:ietf:params:netconf:base:1.0"));
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session2.getSessionId());
         assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session2.getSessionId().equalsIgnoreCase("0"));
         assertThat(session2.getDeviceCapabilitiesSet(), containsInAnyOrder(
                 NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES.toArray()));
-        session3 = new NetconfSessionImpl(deviceInfo);
+        session3 = new NetconfSessionImpl(deviceInfo1);
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session3.getSessionId());
         assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session3.getSessionId().equalsIgnoreCase("0"));
         assertThat(session3.getDeviceCapabilitiesSet(), containsInAnyOrder(
                 NetconfSessionMinaImplTest.DEFAULT_CAPABILITIES_1_1.toArray()));
-        session4 = new NetconfSessionImpl(deviceInfo);
+        session4 = new NetconfSessionImpl(deviceInfo1);
         log.info("Started NETCONF Session {} with test SSHD server in Unit Test", session4.getSessionId());
         assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("-1"));
         assertTrue("Incorrect sessionId", !session4.getSessionId().equalsIgnoreCase("0"));
@@ -572,6 +583,18 @@
         fail("NETCONF test failed to complete.");
     }
 
+    @Test
+    public void testSessionTimeouts() {
+        assertTrue("SSH Client wrong", session1 instanceof NetconfSessionImpl);
+        assertEquals("Timeout wrong", 5, session1.timeoutConnectSec());
+        assertEquals("Timeout wrong", 5, session1.timeoutReplySec());
+        assertEquals("Timeout wrong", 5, session1.timeoutIdleSec());
+
+        assertTrue("SSH Client wrong", session2 instanceof NetconfSessionMinaImpl);
+        assertEquals("Timeout wrong", 11, session2.timeoutConnectSec());
+        assertEquals("Timeout wrong", 10, session2.timeoutReplySec());
+        assertEquals("Timeout wrong", 12, session2.timeoutIdleSec());
+    }
 
     public static String getTestHelloReply(Optional<Long> sessionId, boolean useChunkedFraming) {
         if (useChunkedFraming) {
@@ -736,4 +759,4 @@
             return session.copyConfig(target, source);
         }
     }
-}
\ No newline at end of file
+}