CORD-524 Added a state to set data plane IP to br-int

Added new config fields
- SSH port, user, private key file
- localManagementIp for connection b/w a compute node and VM

Renamed some config fields and methods
- phyPortName is changed to dataPlaneIntf
- localIp is changed to dataPlaneIp
- ovsdbIp is changed to hostManagementIp and it is used to SSH as well
- checkXXX methods with boolean return are renamed to isXXX

Removed unnecessary OVSDB_CONNECTED state
Removed cordvtn-node-add CLI due to too many arguments

Change-Id: If5efb65fc58bfa8a10767047f01598dc2ac02a04
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
index bd8dad2..4017d5a 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtn.java
@@ -265,7 +265,7 @@
         SparseAnnotations annotations = DefaultAnnotations.builder()
                 .set(OPENSTACK_VM_ID, vPort.deviceId())
                 .set(SERVICE_ID, vPort.networkId())
-                .set(LOCATION_IP, node.localIp().toString())
+                .set(LOCATION_IP, node.dpIp().ip().toString())
                 .build();
 
         HostDescription hostDesc = new DefaultHostDescription(
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java
index 167d7bf..963019f 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnConfig.java
@@ -17,7 +17,6 @@
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.Sets;
-import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.TpPort;
 import org.onosproject.core.ApplicationId;
@@ -37,14 +36,19 @@
 
     protected final Logger log = getLogger(getClass());
 
-    public static final String CORDVTN_NODES = "nodes";
-    public static final String HOSTNAME = "hostname";
-    public static final String OVSDB_IP = "ovsdbIp";
-    public static final String OVSDB_PORT = "ovsdbPort";
-    public static final String BRIDGE_ID = "bridgeId";
-    public static final String PHYSICAL_PORT_NAME = "phyPortName";
-    public static final String LOCAL_IP = "localIp";
     public static final String GATEWAY_MAC = "gatewayMac";
+    public static final String LOCAL_MANAGEMENT_IP = "localManagementIp";
+    public static final String OVSDB_PORT = "ovsdbPort";
+    public static final String SSH_PORT = "sshPort";
+    public static final String SSH_USER = "sshUser";
+    public static final String SSH_KEY_FILE = "sshKeyFile";
+    public static final String CORDVTN_NODES = "nodes";
+
+    public static final String HOSTNAME = "hostname";
+    public static final String HOST_MANAGEMENT_IP = "hostManagementIp";
+    public static final String DATA_PLANE_IP = "dataPlaneIp";
+    public static final String DATA_PLANE_INTF = "dataPlaneIntf";
+    public static final String BRIDGE_ID = "bridgeId";
 
     /**
      * Returns the set of nodes read from network config.
@@ -58,13 +62,19 @@
         if (jsonNodes == null) {
             return null;
         }
-        jsonNodes.forEach(jsonNode -> nodes.add(new CordVtnNodeConfig(
-            jsonNode.path(HOSTNAME).asText(),
-            IpAddress.valueOf(jsonNode.path(OVSDB_IP).asText()),
-            TpPort.tpPort(jsonNode.path(OVSDB_PORT).asInt()),
-            DeviceId.deviceId(jsonNode.path(BRIDGE_ID).asText()),
-            jsonNode.path(PHYSICAL_PORT_NAME).asText(),
-            IpAddress.valueOf(jsonNode.path(LOCAL_IP).asText()))));
+
+        jsonNodes.forEach(jsonNode -> {
+            try {
+                nodes.add(new CordVtnNodeConfig(
+                        jsonNode.path(HOSTNAME).asText(),
+                        NetworkAddress.valueOf(jsonNode.path(HOST_MANAGEMENT_IP).asText()),
+                        NetworkAddress.valueOf(jsonNode.path(DATA_PLANE_IP).asText()),
+                        jsonNode.path(DATA_PLANE_INTF).asText(),
+                        DeviceId.deviceId(jsonNode.path(BRIDGE_ID).asText())));
+            } catch (IllegalArgumentException | NullPointerException e) {
+                log.error("Failed to read {}", e.toString());
+            }
+        });
 
         return nodes;
     }
@@ -89,25 +99,108 @@
     }
 
     /**
+     * Returns local management network address.
+     *
+     * @return network address
+     */
+    public NetworkAddress localMgmtIp() {
+        JsonNode jsonNode = object.get(LOCAL_MANAGEMENT_IP);
+        if (jsonNode == null) {
+            return null;
+        }
+
+        try {
+            return NetworkAddress.valueOf(jsonNode.asText());
+        } catch (IllegalArgumentException e) {
+            log.error("Wrong address format {}", jsonNode.asText());
+            return null;
+        }
+    }
+
+    /**
+     * Returns the port number used for OVSDB connection.
+     *
+     * @return port number, or null
+     */
+    public TpPort ovsdbPort() {
+        JsonNode jsonNode = object.get(OVSDB_PORT);
+        if (jsonNode == null) {
+            return null;
+        }
+
+        try {
+            return TpPort.tpPort(jsonNode.asInt());
+        } catch (IllegalArgumentException e) {
+            log.error("Wrong TCP port format {}", jsonNode.asText());
+            return null;
+        }
+    }
+
+    /**
+     * Returns the port number used for SSH connection.
+     *
+     * @return port number, or null
+     */
+    public TpPort sshPort() {
+        JsonNode jsonNode = object.get(SSH_PORT);
+        if (jsonNode == null) {
+            return null;
+        }
+
+        try {
+            return TpPort.tpPort(jsonNode.asInt());
+        } catch (IllegalArgumentException e) {
+            log.error("Wrong TCP port format {}", jsonNode.asText());
+            return null;
+        }
+    }
+
+    /**
+     * Returns the user name for SSH connection.
+     *
+     * @return user name, or null
+     */
+    public String sshUser() {
+        JsonNode jsonNode = object.get(SSH_USER);
+        if (jsonNode == null) {
+            return null;
+        }
+
+        return jsonNode.asText();
+    }
+
+    /**
+     * Returns the private key file for SSH connection.
+     *
+     * @return file path, or null
+     */
+    public String sshKeyFile() {
+        JsonNode jsonNode = object.get(SSH_KEY_FILE);
+        if (jsonNode == null) {
+            return null;
+        }
+
+        return jsonNode.asText();
+    }
+
+    /**
      * Configuration for CordVtn node.
      */
     public static class CordVtnNodeConfig {
 
         private final String hostname;
-        private final IpAddress ovsdbIp;
-        private final TpPort ovsdbPort;
+        private final NetworkAddress hostMgmtIp;
+        private final NetworkAddress dpIp;
+        private final String dpIntf;
         private final DeviceId bridgeId;
-        private final String phyPortName;
-        private final IpAddress localIp;
 
-        public CordVtnNodeConfig(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort,
-                                 DeviceId bridgeId, String phyPortName, IpAddress localIp) {
+        public CordVtnNodeConfig(String hostname, NetworkAddress hostMgmtIp, NetworkAddress dpIp,
+                                 String dpIntf, DeviceId bridgeId) {
             this.hostname = checkNotNull(hostname);
-            this.ovsdbIp = checkNotNull(ovsdbIp);
-            this.ovsdbPort = checkNotNull(ovsdbPort);
+            this.hostMgmtIp = checkNotNull(hostMgmtIp);
+            this.dpIp = checkNotNull(dpIp);
+            this.dpIntf = checkNotNull(dpIntf);
             this.bridgeId = checkNotNull(bridgeId);
-            this.phyPortName = checkNotNull(phyPortName);
-            this.localIp = checkNotNull(localIp);
         }
 
         /**
@@ -120,21 +213,30 @@
         }
 
         /**
-         * Returns OVSDB ip address of the node.
+         * Returns the host management network address of the node.
          *
-         * @return OVSDB server IP address
+         * @return management network address
          */
-        public IpAddress ovsdbIp() {
-            return this.ovsdbIp;
+        public NetworkAddress hostMgmtIp() {
+            return this.hostMgmtIp;
         }
 
         /**
-         * Returns OVSDB port number of the node.
+         * Returns the data plane network address.
          *
-         * @return port number
+         * @return network address
          */
-        public TpPort ovsdbPort() {
-            return this.ovsdbPort;
+        public NetworkAddress dpIp() {
+            return this.dpIp;
+        }
+
+        /**
+         * Returns the data plane interface name.
+         *
+         * @return interface name
+         */
+        public String dpIntf() {
+            return this.dpIntf;
         }
 
         /**
@@ -145,23 +247,5 @@
         public DeviceId bridgeId() {
             return this.bridgeId;
         }
-
-        /**
-         * Returns physical port name.
-         *
-         * @return physical port name
-         */
-        public String phyPortName() {
-            return this.phyPortName;
-        }
-
-        /**
-         * Returns local IP address.
-         *
-         * @return ip address
-         */
-        public IpAddress localIp() {
-            return this.localIp;
-        }
     }
 }
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNode.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNode.java
index 87caf6b..9ae8237 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNode.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNode.java
@@ -16,7 +16,6 @@
 package org.onosproject.cordvtn;
 
 import com.google.common.base.MoreObjects;
-import org.onlab.packet.IpAddress;
 import org.onlab.packet.TpPort;
 import org.onosproject.net.DeviceId;
 
@@ -31,11 +30,13 @@
 public final class CordVtnNode {
 
     private final String hostname;
-    private final IpAddress ovsdbIp;
+    private final NetworkAddress hostMgmtIp;
+    private final NetworkAddress localMgmtIp;
+    private final NetworkAddress dpIp;
     private final TpPort ovsdbPort;
+    private final SshAccessInfo sshInfo;
     private final DeviceId bridgeId;
-    private final String phyPortName;
-    private final IpAddress localIp;
+    private final String dpIntf;
 
     public static final Comparator<CordVtnNode> CORDVTN_NODE_COMPARATOR =
             (node1, node2) -> node1.hostname().compareTo(node2.hostname());
@@ -44,38 +45,25 @@
      * Creates a new node.
      *
      * @param hostname hostname
-     * @param ovsdbIp OVSDB server IP address
-     * @param ovsdbPort OVSDB server port number
+     * @param hostMgmtIp host management network address
+     * @param localMgmtIp local management network address
+     * @param dpIp data plane network address
+     * @param ovsdbPort port number for OVSDB connection
+     * @param sshInfo SSH access information
      * @param bridgeId integration bridge identifier
-     * @param phyPortName physical port name
-     * @param localIp local ip address of data plane
+     * @param dpIntf data plane interface name
      */
-    public CordVtnNode(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort,
-                       DeviceId bridgeId, String phyPortName, IpAddress localIp) {
-        this.hostname = checkNotNull(hostname);
-        this.ovsdbIp = checkNotNull(ovsdbIp);
-        this.ovsdbPort = checkNotNull(ovsdbPort);
-        this.bridgeId = checkNotNull(bridgeId);
-        this.phyPortName = checkNotNull(phyPortName);
-        this.localIp = checkNotNull(localIp);
-    }
-
-    /**
-     * Returns the OVSDB server IP address.
-     *
-     * @return ip address
-     */
-    public IpAddress ovsdbIp() {
-        return this.ovsdbIp;
-    }
-
-    /**
-     * Returns the OVSDB server port number.
-     *
-     * @return port number
-     */
-    public TpPort ovsdbPort() {
-        return this.ovsdbPort;
+    public CordVtnNode(String hostname, NetworkAddress hostMgmtIp, NetworkAddress localMgmtIp,
+                       NetworkAddress dpIp, TpPort ovsdbPort, SshAccessInfo sshInfo,
+                       DeviceId bridgeId, String dpIntf) {
+        this.hostname = checkNotNull(hostname, "hostname cannot be null");
+        this.hostMgmtIp = checkNotNull(hostMgmtIp, "hostMgmtIp cannot be null");
+        this.localMgmtIp = checkNotNull(localMgmtIp, "localMgmtIp cannot be null");
+        this.dpIp = checkNotNull(dpIp, "dpIp cannot be null");
+        this.ovsdbPort = checkNotNull(ovsdbPort, "ovsdbPort cannot be null");
+        this.sshInfo = checkNotNull(sshInfo, "sshInfo cannot be null");
+        this.bridgeId = checkNotNull(bridgeId, "bridgeId cannot be null");
+        this.dpIntf = checkNotNull(dpIntf, "dpIntf cannot be null");
     }
 
     /**
@@ -88,6 +76,51 @@
     }
 
     /**
+     * Returns the host management network address.
+     *
+     * @return network address
+     */
+    public NetworkAddress hostMgmtIp() {
+        return this.hostMgmtIp;
+    }
+
+    /**
+     * Returns the local management network address.
+     *
+     * @return network address
+     */
+    public NetworkAddress localMgmtIp() {
+        return this.localMgmtIp;
+    }
+
+    /**
+     * Returns the data plane network address.
+     *
+     * @return network address
+     */
+    public NetworkAddress dpIp() {
+        return this.dpIp;
+    }
+
+    /**
+     * Returns the port number used for OVSDB connection.
+     *
+     * @return port number
+     */
+    public TpPort ovsdbPort() {
+        return this.ovsdbPort;
+    }
+
+    /**
+     * Returns the SSH access information.
+     *
+     * @return ssh access information
+     */
+    public SshAccessInfo sshInfo() {
+        return this.sshInfo;
+    }
+
+    /**
      * Returns the identifier of the integration bridge.
      *
      * @return device id
@@ -102,25 +135,16 @@
      * @return device id
      */
     public DeviceId ovsdbId() {
-        return DeviceId.deviceId("ovsdb:" + this.ovsdbIp.toString());
+        return DeviceId.deviceId("ovsdb:" + this.hostMgmtIp.ip().toString());
     }
 
     /**
-     * Returns physical port name.
+     * Returns data plane interface name.
      *
-     * @return physical port name
+     * @return data plane interface name
      */
-    public String phyPortName() {
-        return this.phyPortName;
-    }
-
-    /**
-     * Returns local IP address.
-     *
-     * @return ip address
-     */
-    public IpAddress localIp() {
-        return this.localIp;
+    public String dpIntf() {
+        return this.dpIntf;
     }
 
     @Override
@@ -129,6 +153,8 @@
             return true;
         }
 
+        // hostname here is a network hostname and it is intended to be
+        // unique throughout the service.
         if (obj instanceof CordVtnNode) {
             CordVtnNode that = (CordVtnNode) obj;
             if (Objects.equals(hostname, that.hostname)) {
@@ -146,12 +172,14 @@
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
-                .add("host", hostname)
-                .add("ip", ovsdbIp)
+                .add("hostname", hostname)
+                .add("hostMgmtIp", hostMgmtIp)
+                .add("localMgmtIp", localMgmtIp)
+                .add("dpIp", dpIp)
                 .add("port", ovsdbPort)
+                .add("sshInfo", sshInfo)
                 .add("bridgeId", bridgeId)
-                .add("phyPortName", phyPortName)
-                .add("localIp", localIp)
+                .add("dpIntf", dpIntf)
                 .toString();
     }
 }
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNodeManager.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNodeManager.java
index 2a66263..9dd8c24 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNodeManager.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnNodeManager.java
@@ -16,12 +16,15 @@
 package org.onosproject.cordvtn;
 
 import com.google.common.collect.Sets;
+import com.jcraft.jsch.Session;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.TpPort;
 import org.onlab.util.ItemNotFoundException;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.cluster.ClusterService;
@@ -67,6 +70,7 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -89,8 +93,11 @@
 
     private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
             .register(KryoNamespaces.API)
+            .register(KryoNamespaces.MISC)
             .register(CordVtnNode.class)
-            .register(NodeState.class);
+            .register(NodeState.class)
+            .register(SshAccessInfo.class)
+            .register(NetworkAddress.class);
 
     private static final String DEFAULT_BRIDGE = "br-int";
     private static final String DEFAULT_TUNNEL = "vxlan";
@@ -167,13 +174,7 @@
         INIT {
             @Override
             public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
-                nodeManager.connectOvsdb(node);
-            }
-        },
-        OVSDB_CONNECTED {
-            @Override
-            public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
-                if (!nodeManager.getOvsdbConnectionState(node)) {
+                if (!nodeManager.isOvsdbConnected(node)) {
                     nodeManager.connectOvsdb(node);
                 } else {
                     nodeManager.createIntegrationBridge(node);
@@ -183,21 +184,18 @@
         BRIDGE_CREATED {
             @Override
             public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
-                if (!nodeManager.getOvsdbConnectionState(node)) {
+                if (!nodeManager.isOvsdbConnected(node)) {
                     nodeManager.connectOvsdb(node);
                 } else {
                     nodeManager.createTunnelInterface(node);
+                    nodeManager.addDataPlaneInterface(node);
                 }
             }
         },
-        TUNNEL_INTERFACE_CREATED {
+        PORTS_ADDED {
             @Override
             public void process(CordVtnNodeManager nodeManager, CordVtnNode node) {
-                if (!nodeManager.getOvsdbConnectionState(node)) {
-                    nodeManager.connectOvsdb(node);
-                } else {
-                    nodeManager.createPhyInterface(node);
-                }
+                nodeManager.setIpAddress(node);
             }
 
         },
@@ -213,8 +211,6 @@
             }
         };
 
-        // TODO Add physical port add state
-
         public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
     }
 
@@ -256,7 +252,7 @@
     public void addNode(CordVtnNode node) {
         checkNotNull(node);
 
-        nodeStore.putIfAbsent(node, checkNodeState(node));
+        nodeStore.putIfAbsent(node, getNodeState(node));
         initNode(node);
     }
 
@@ -268,7 +264,7 @@
     public void deleteNode(CordVtnNode node) {
         checkNotNull(node);
 
-        if (getOvsdbConnectionState(node)) {
+        if (isOvsdbConnected(node)) {
             disconnectOvsdb(node);
         }
 
@@ -288,7 +284,7 @@
             return;
         }
 
-        NodeState state = checkNodeState(node);
+        NodeState state = getNodeState(node);
         state.process(this, node);
     }
 
@@ -298,20 +294,13 @@
      * @param node cordvtn node
      * @return true if initial node setup is completed, otherwise false
      */
-    public boolean getNodeInitState(CordVtnNode node) {
+    public boolean isNodeInitComplete(CordVtnNode node) {
         checkNotNull(node);
-
-        NodeState state = getNodeState(node);
-        return state != null && state.equals(NodeState.COMPLETE);
+        return nodeStore.containsKey(node) && getNodeState(node).equals(NodeState.COMPLETE);
     }
 
     /**
      * Returns detailed node initialization state.
-     * Return string includes the following information.
-     *
-     * Integration bridge created/connected: OK or NO
-     * VXLAN interface created: OK or NO
-     * Physical interface added: OK or NO
      *
      * @param node cordvtn node
      * @return string including detailed node init state
@@ -319,19 +308,34 @@
     public String checkNodeInitState(CordVtnNode node) {
         checkNotNull(node);
 
-        NodeState state = getNodeState(node);
-        if (state == null) {
-            log.warn("Failed to get init state of {}", node.hostname());
+        if (!nodeStore.containsKey(node)) {
+            log.warn("Node {} does not exist, add node first", node.hostname());
             return null;
         }
 
+        Session session = RemoteIpCommandUtil.connect(node.sshInfo());
+        if (session == null) {
+            log.debug("Failed to SSH to {}", node.hostname());
+            return null;
+        }
+
+        Set<IpAddress> intBrIps = RemoteIpCommandUtil.getCurrentIps(session, DEFAULT_BRIDGE);
         String result = String.format(
                 "Integration bridge created/connected : %s (%s)%n" +
                         "VXLAN interface created : %s%n" +
-                        "Physical interface added : %s (%s)",
-                checkIntegrationBridge(node) ? OK : NO, DEFAULT_BRIDGE,
-                checkTunnelInterface(node) ? OK : NO,
-                checkPhyInterface(node) ? OK : NO, node.phyPortName());
+                        "Data plane interface added : %s (%s)%n" +
+                        "IP flushed from %s : %s%n" +
+                        "Data plane IP added to br-int : %s (%s)%n" +
+                        "Local management IP added to br-int : %s (%s)",
+                isBrIntCreated(node) ? OK : NO, DEFAULT_BRIDGE,
+                isTunnelIntfCreated(node) ? OK : NO,
+                isDataPlaneIntfAdded(node) ? OK : NO, node.dpIntf(),
+                node.dpIntf(),
+                RemoteIpCommandUtil.getCurrentIps(session, node.dpIntf()).isEmpty() ? OK : NO,
+                intBrIps.contains(node.dpIp().ip()) ? OK : NO, node.dpIp().cidr(),
+                intBrIps.contains(node.localMgmtIp().ip()) ? OK : NO, node.localMgmtIp().cidr());
+
+        RemoteIpCommandUtil.disconnect(session);
 
         return result;
     }
@@ -381,23 +385,6 @@
     }
 
     /**
-     * Returns state of a given cordvtn node.
-     *
-     * @param node cordvtn node
-     * @return node state, or null if no such node exists
-     */
-    private NodeState getNodeState(CordVtnNode node) {
-        checkNotNull(node);
-
-        try {
-            return nodeStore.get(node).value();
-        } catch (NullPointerException e) {
-            log.error("Failed to get state of {}", node.hostname());
-            return null;
-        }
-    }
-
-    /**
      * Sets a new state for a given cordvtn node.
      *
      * @param node cordvtn node
@@ -418,18 +405,16 @@
      * @param node cordvtn node
      * @return node state
      */
-    private NodeState checkNodeState(CordVtnNode node) {
+    private NodeState getNodeState(CordVtnNode node) {
         checkNotNull(node);
 
-        if (checkIntegrationBridge(node) && checkTunnelInterface(node) &&
-                checkPhyInterface(node)) {
+        if (isBrIntCreated(node) && isTunnelIntfCreated(node) &&
+                isDataPlaneIntfAdded(node) && isIpAddressSet(node)) {
             return NodeState.COMPLETE;
-        } else if (checkTunnelInterface(node)) {
-            return NodeState.TUNNEL_INTERFACE_CREATED;
-        } else if (checkIntegrationBridge(node)) {
+        } else if (isDataPlaneIntfAdded(node) && isTunnelIntfCreated(node)) {
+            return NodeState.PORTS_ADDED;
+        } else if (isBrIntCreated(node)) {
             return NodeState.BRIDGE_CREATED;
-        } else if (getOvsdbConnectionState(node)) {
-            return NodeState.OVSDB_CONNECTED;
         } else {
             return NodeState.INIT;
         }
@@ -445,7 +430,7 @@
     private void postInit(CordVtnNode node) {
         disconnectOvsdb(node);
 
-        ruleInstaller.init(node.intBrId(), node.phyPortName(), node.localIp());
+        ruleInstaller.init(node.intBrId(), node.dpIntf(), node.dpIp().ip());
 
         // add existing hosts to the service
         deviceService.getPorts(node.intBrId()).stream()
@@ -480,7 +465,7 @@
      * @param node cordvtn node
      * @return true if it is connected, false otherwise
      */
-    private boolean getOvsdbConnectionState(CordVtnNode node) {
+    private boolean isOvsdbConnected(CordVtnNode node) {
         checkNotNull(node);
 
         OvsdbClientService ovsdbClient = getOvsdbClient(node);
@@ -501,8 +486,8 @@
             return;
         }
 
-        if (!getOvsdbConnectionState(node)) {
-            controller.connect(node.ovsdbIp(), node.ovsdbPort());
+        if (!isOvsdbConnected(node)) {
+            controller.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
         }
     }
 
@@ -519,7 +504,7 @@
             return;
         }
 
-        if (getOvsdbConnectionState(node)) {
+        if (isOvsdbConnected(node)) {
             OvsdbClientService ovsdbClient = getOvsdbClient(node);
             ovsdbClient.disconnect();
         }
@@ -535,7 +520,7 @@
         checkNotNull(node);
 
         OvsdbClientService ovsdbClient = controller.getOvsdbClient(
-                new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
+                new OvsdbNodeId(node.hostMgmtIp().ip(), node.ovsdbPort().toInt()));
         if (ovsdbClient == null) {
             log.trace("Couldn't find OVSDB client for {}", node.hostname());
         }
@@ -548,7 +533,7 @@
      * @param node cordvtn node
      */
     private void createIntegrationBridge(CordVtnNode node) {
-        if (checkIntegrationBridge(node)) {
+        if (isBrIntCreated(node)) {
             return;
         }
 
@@ -576,7 +561,7 @@
      * @param node cordvtn node
      */
     private void createTunnelInterface(CordVtnNode node) {
-        if (checkTunnelInterface(node)) {
+        if (isTunnelIntfCreated(node)) {
             return;
         }
 
@@ -599,21 +584,47 @@
     }
 
     /**
-     * Creates physical interface to a given node.
+     * Adds data plane interface to a given node.
      *
      * @param node cordvtn node
      */
-    private void createPhyInterface(CordVtnNode node) {
-        if (checkPhyInterface(node)) {
+    private void addDataPlaneInterface(CordVtnNode node) {
+        if (isDataPlaneIntfAdded(node)) {
             return;
         }
 
         try {
             DriverHandler handler = driverService.createHandler(node.ovsdbId());
             BridgeConfig bridgeConfig =  handler.behaviour(BridgeConfig.class);
-            bridgeConfig.addPort(BridgeName.bridgeName(DEFAULT_BRIDGE), node.phyPortName());
+            bridgeConfig.addPort(BridgeName.bridgeName(DEFAULT_BRIDGE), node.dpIntf());
         } catch (ItemNotFoundException e) {
-            log.warn("Failed to add {} on {}", node.phyPortName(), node.hostname());
+            log.warn("Failed to add {} on {}", node.dpIntf(), node.hostname());
+        }
+    }
+
+    /**
+     * Flushes IP address from data plane interface and adds data plane IP address
+     * to integration bridge.
+     *
+     * @param node cordvtn node
+     */
+    private void setIpAddress(CordVtnNode node) {
+        Session session = RemoteIpCommandUtil.connect(node.sshInfo());
+        if (session == null) {
+            log.debug("Failed to SSH to {}", node.hostname());
+            return;
+        }
+
+        boolean result = RemoteIpCommandUtil.flushIp(session, node.dpIntf()) &&
+                RemoteIpCommandUtil.setInterfaceUp(session, node.dpIntf()) &&
+                RemoteIpCommandUtil.addIp(session, node.dpIp(), DEFAULT_BRIDGE) &&
+                RemoteIpCommandUtil.addIp(session, node.localMgmtIp(), DEFAULT_BRIDGE) &&
+                RemoteIpCommandUtil.setInterfaceUp(session, DEFAULT_BRIDGE);
+
+        RemoteIpCommandUtil.disconnect(session);
+
+        if (result) {
+            setNodeState(node, NodeState.COMPLETE);
         }
     }
 
@@ -623,7 +634,7 @@
      * @param node cordvtn node
      * @return true if the bridge is available, false otherwise
      */
-    private boolean checkIntegrationBridge(CordVtnNode node) {
+    private boolean isBrIntCreated(CordVtnNode node) {
         return (deviceService.getDevice(node.intBrId()) != null
                 && deviceService.isAvailable(node.intBrId()));
     }
@@ -634,7 +645,7 @@
      * @param node cordvtn node
      * @return true if the interface exists, false otherwise
      */
-    private boolean checkTunnelInterface(CordVtnNode node) {
+    private boolean isTunnelIntfCreated(CordVtnNode node) {
         return deviceService.getPorts(node.intBrId())
                     .stream()
                     .filter(p -> getPortName(p).contains(DEFAULT_TUNNEL) &&
@@ -643,20 +654,44 @@
     }
 
     /**
-     * Checks if physical interface exists.
+     * Checks if data plane interface exists.
      *
      * @param node cordvtn node
      * @return true if the interface exists, false otherwise
      */
-    private boolean checkPhyInterface(CordVtnNode node) {
+    private boolean isDataPlaneIntfAdded(CordVtnNode node) {
         return deviceService.getPorts(node.intBrId())
                     .stream()
-                    .filter(p -> getPortName(p).contains(node.phyPortName()) &&
+                    .filter(p -> getPortName(p).contains(node.dpIntf()) &&
                             p.isEnabled())
                     .findAny().isPresent();
     }
 
     /**
+     * Checks if the IP addresses are correctly set.
+     *
+     * @param node cordvtn node
+     * @return true if the IP is set, false otherwise
+     */
+    private boolean isIpAddressSet(CordVtnNode node) {
+        Session session = RemoteIpCommandUtil.connect(node.sshInfo());
+        if (session == null) {
+            log.debug("Failed to SSH to {}", node.hostname());
+            return false;
+        }
+
+        Set<IpAddress> intBrIps = RemoteIpCommandUtil.getCurrentIps(session, DEFAULT_BRIDGE);
+        boolean result = RemoteIpCommandUtil.getCurrentIps(session, node.dpIntf()).isEmpty() &&
+                RemoteIpCommandUtil.isInterfaceUp(session, node.dpIntf()) &&
+                intBrIps.contains(node.dpIp().ip()) &&
+                intBrIps.contains(node.localMgmtIp().ip()) &&
+                RemoteIpCommandUtil.isInterfaceUp(session, DEFAULT_BRIDGE);
+
+        RemoteIpCommandUtil.disconnect(session);
+        return result;
+    }
+
+    /**
      * Returns connect point of a given port.
      *
      * @param port port
@@ -682,7 +717,7 @@
         public void connected(Device device) {
             CordVtnNode node = getNodeByOvsdbId(device.id());
             if (node != null) {
-                setNodeState(node, checkNodeState(node));
+                setNodeState(node, getNodeState(node));
             } else {
                 log.debug("{} is detected on unregistered node, ignore it.", device.id());
             }
@@ -702,7 +737,7 @@
         public void connected(Device device) {
             CordVtnNode node = getNodeByBridgeId(device.id());
             if (node != null) {
-                setNodeState(node, checkNodeState(node));
+                setNodeState(node, getNodeState(node));
             } else {
                 log.debug("{} is detected on unregistered node, ignore it.", device.id());
             }
@@ -719,8 +754,8 @@
 
         /**
          * Handles port added situation.
-         * If the added port is tunnel or physical port, proceed remaining node
-         * initialization. Otherwise, do nothing.
+         * If the added port is tunnel or data plane interface, proceed to the remaining
+         * node initialization. Otherwise, do nothing.
          *
          * @param port port
          */
@@ -736,20 +771,20 @@
             log.debug("Port {} is added to {}", portName, node.hostname());
 
             if (portName.startsWith(VPORT_PREFIX)) {
-                if (getNodeInitState(node)) {
+                if (isNodeInitComplete(node)) {
                     cordVtnService.addServiceVm(node, getConnectPoint(port));
                 } else {
                     log.debug("VM is detected on incomplete node, ignore it.", portName);
                 }
-            } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.phyPortName())) {
-                setNodeState(node, checkNodeState(node));
+            } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.dpIntf())) {
+                setNodeState(node, getNodeState(node));
             }
         }
 
         /**
          * Handles port removed situation.
-         * If the removed port is tunnel or physical port, proceed remaining node
-         * initialization.Others, do nothing.
+         * If the removed port is tunnel or data plane interface, proceed to the remaining
+         * node initialization.Others, do nothing.
          *
          * @param port port
          */
@@ -764,12 +799,12 @@
             log.debug("Port {} is removed from {}", portName, node.hostname());
 
             if (portName.startsWith(VPORT_PREFIX)) {
-                if (getNodeInitState(node)) {
+                if (isNodeInitComplete(node)) {
                     cordVtnService.removeServiceVm(getConnectPoint(port));
                 } else {
                     log.debug("VM is vanished from incomplete node, ignore it.", portName);
                 }
-            } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.phyPortName())) {
+            } else if (portName.contains(DEFAULT_TUNNEL) || portName.equals(node.dpIntf())) {
                 setNodeState(node, NodeState.INCOMPLETE);
             }
         }
@@ -818,14 +853,26 @@
             return;
         }
 
+        NetworkAddress localMgmtIp = config.localMgmtIp();
+        TpPort ovsdbPort = config.ovsdbPort();
+        TpPort sshPort = config.sshPort();
+        String sshUser = config.sshUser();
+        String sshKeyFile = config.sshKeyFile();
+
         config.cordVtnNodes().forEach(node -> {
+            log.debug("Read node {}", node.hostname());
             CordVtnNode cordVtnNode = new CordVtnNode(
                     node.hostname(),
-                    node.ovsdbIp(),
-                    node.ovsdbPort(),
+                    node.hostMgmtIp(),
+                    localMgmtIp,
+                    node.dpIp(),
+                    ovsdbPort,
+                    new SshAccessInfo(node.hostMgmtIp().ip().getIp4Address(),
+                                      sshPort,
+                                      sshUser,
+                                      sshKeyFile),
                     node.bridgeId(),
-                    node.phyPortName(),
-                    node.localIp());
+                    node.dpIntf());
 
             addNode(cordVtnNode);
         });
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnRuleInstaller.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnRuleInstaller.java
index 7fb8574..8b52c34 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnRuleInstaller.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/CordVtnRuleInstaller.java
@@ -96,6 +96,7 @@
 
     protected final Logger log = getLogger(getClass());
 
+    private static final String PORT_NAME = "portName";
     private static final int TABLE_FIRST = 0;
     private static final int TABLE_IN_PORT = 1;
     private static final int TABLE_ACCESS_TYPE = 2;
@@ -150,18 +151,18 @@
      * Installs table miss rule to a give device.
      *
      * @param deviceId device id to install the rules
-     * @param phyPortName physical port name
-     * @param localIp local data plane ip address
+     * @param dpIntf data plane interface name
+     * @param dpIp data plane ip address
      */
-    public void init(DeviceId deviceId, String phyPortName, IpAddress localIp) {
+    public void init(DeviceId deviceId, String dpIntf, IpAddress dpIp) {
         // default is drop packets which can be accomplished without
         // a table miss entry for all table.
         PortNumber tunnelPort = getTunnelPort(deviceId);
-        PortNumber phyPort = getPhyPort(deviceId, phyPortName);
+        PortNumber dpPort = getDpPort(deviceId, dpIntf);
 
-        processFirstTable(deviceId, phyPort, localIp);
-        processInPortTable(deviceId, tunnelPort, phyPort);
-        processAccessTypeTable(deviceId, phyPort);
+        processFirstTable(deviceId, dpPort, dpIp);
+        processInPortTable(deviceId, tunnelPort, dpPort);
+        processAccessTypeTable(deviceId, dpPort);
     }
 
     /**
@@ -510,21 +511,21 @@
 
     /**
      * Populates default rules on the first table.
-     * The rules are for shuttling vxlan-encapped packets and supporting physical
-     * network connectivity.
+     * It includes the rules for shuttling vxlan-encapped packets between ovs and
+     * linux stack,and external network connectivity.
      *
      * @param deviceId device id
-     * @param phyPort physical port number
-     * @param localIp local data plane ip address
+     * @param dpPort data plane interface port number
+     * @param dpIp data plane ip address
      */
-    private void processFirstTable(DeviceId deviceId, PortNumber phyPort, IpAddress localIp) {
+    private void processFirstTable(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
         // take vxlan packet out onto the physical port
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchInPort(PortNumber.LOCAL)
                 .build();
 
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(phyPort)
+                .setOutput(dpPort)
                 .build();
 
         FlowRule flowRule = DefaultFlowRule.builder()
@@ -541,7 +542,7 @@
 
         // take a vxlan encap'd packet through the Linux stack
         selector = DefaultTrafficSelector.builder()
-                .matchInPort(phyPort)
+                .matchInPort(dpPort)
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPProtocol(IPv4.PROTOCOL_UDP)
                 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
@@ -563,11 +564,11 @@
 
         processFlowRule(true, flowRule);
 
-        // take a packet to the local ip through Linux stack
+        // take a packet to the data plane ip through Linux stack
         selector = DefaultTrafficSelector.builder()
-                .matchInPort(phyPort)
+                .matchInPort(dpPort)
                 .matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPDst(localIp.toIpPrefix())
+                .matchIPDst(dpIp.toIpPrefix())
                 .build();
 
         treatment = DefaultTrafficTreatment.builder()
@@ -588,7 +589,7 @@
 
         // take an arp packet from physical through Linux stack
         selector = DefaultTrafficSelector.builder()
-                .matchInPort(phyPort)
+                .matchInPort(dpPort)
                 .matchEthType(Ethernet.TYPE_ARP)
                 .build();
 
@@ -630,17 +631,17 @@
     }
 
     /**
-     * Forward table miss packets in ACCESS_TYPE table to physical port.
+     * Forward table miss packets in ACCESS_TYPE table to data plane port.
      *
      * @param deviceId device id
-     * @param phyPort physical port number
+     * @param dpPort data plane interface port number
      */
-    private void processAccessTypeTable(DeviceId deviceId, PortNumber phyPort) {
+    private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .build();
 
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(phyPort)
+                .setOutput(dpPort)
                 .build();
 
         FlowRule flowRule = DefaultFlowRule.builder()
@@ -659,13 +660,13 @@
     /**
      * Populates default rules for IN_PORT table.
      * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
-     * from physical port to ACCESS_TYPE table.
+     * from data plane interface port to ACCESS_TYPE table.
      *
      * @param deviceId device id to install the rules
      * @param tunnelPort tunnel port number
-     * @param phyPort physical port number
+     * @param dpPort data plane interface port number
      */
-    private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber phyPort) {
+    private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
         checkNotNull(tunnelPort);
 
         TrafficSelector selector = DefaultTrafficSelector.builder()
@@ -689,7 +690,7 @@
         processFlowRule(true, flowRule);
 
         selector = DefaultTrafficSelector.builder()
-                .matchInPort(phyPort)
+                .matchInPort(dpPort)
                 .build();
 
         treatment = DefaultTrafficTreatment.builder()
@@ -1027,22 +1028,22 @@
      */
     private PortNumber getTunnelPort(DeviceId deviceId) {
         Port port = deviceService.getPorts(deviceId).stream()
-                    .filter(p -> p.annotations().value("portName").contains(tunnelType))
+                    .filter(p -> p.annotations().value(PORT_NAME).contains(tunnelType))
                     .findFirst().orElse(null);
 
         return port == null ? null : port.number();
     }
 
     /**
-     * Returns physical port name of a given device.
+     * Returns data plane interface port name of a given device.
      *
      * @param deviceId device id
-     * @param phyPortName physical port name
-     * @return physical port number, or null if no physical port exists
+     * @param dpIntf data plane interface port name
+     * @return data plane interface port number, or null if no such port exists
      */
-    private PortNumber getPhyPort(DeviceId deviceId, String phyPortName) {
+    private PortNumber getDpPort(DeviceId deviceId, String dpIntf) {
         Port port = deviceService.getPorts(deviceId).stream()
-                    .filter(p -> p.annotations().value("portName").contains(phyPortName) &&
+                    .filter(p -> p.annotations().value(PORT_NAME).contains(dpIntf) &&
                             p.isEnabled())
                     .findFirst().orElse(null);
 
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NetworkAddress.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NetworkAddress.java
new file mode 100644
index 0000000..8054d56
--- /dev/null
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/NetworkAddress.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * 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.cordvtn;
+
+import com.google.common.base.MoreObjects;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Representation of a network address, which consists of IP address and prefix.
+ */
+public final class NetworkAddress {
+    private final IpAddress ip;
+    private final IpPrefix prefix;
+
+    /**
+     * Constructor for a given IP address and prefix.
+     *
+     * @param ip ip address
+     * @param prefix ip prefix
+     */
+    public NetworkAddress(IpAddress ip, IpPrefix prefix) {
+        this.ip = ip;
+        this.prefix = prefix;
+    }
+
+    /**
+     * Converts a CIDR notation string into a network address.
+     *
+     * @param cidr cidr
+     * @return network address
+     * @throws IllegalArgumentException if the cidr is not valid
+     */
+    public static NetworkAddress valueOf(String cidr) {
+        checkArgument(cidr.contains("/"));
+
+        IpAddress ipAddress = IpAddress.valueOf(cidr.split("/")[0]);
+        IpPrefix ipPrefix = IpPrefix.valueOf(cidr);
+
+        return new NetworkAddress(ipAddress, ipPrefix);
+    }
+
+    /**
+     * Returns the IP address value of the network address.
+     *
+     * @return ip address
+     */
+    public IpAddress ip() {
+        return this.ip;
+    }
+
+    /**
+     * Returns the IP prefix value of the network address.
+     *
+     * @return ip prefix
+     */
+    public IpPrefix prefix() {
+        return this.prefix;
+    }
+
+    /**
+     * Converts a network address to a CIDR notation.
+     *
+     * @return cidr notation string
+     */
+    public String cidr() {
+        return ip.toString() + "/" + prefix.prefixLength();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof NetworkAddress) {
+            NetworkAddress that = (NetworkAddress) obj;
+            if (Objects.equals(ip, that.ip) && Objects.equals(prefix, that.prefix)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(ip, prefix);
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(getClass())
+                .add("IpAddress", ip)
+                .add("IpPrefix", prefix)
+                .toString();
+    }
+}
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/RemoteIpCommandUtil.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/RemoteIpCommandUtil.java
index fd41125..29c920f 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/RemoteIpCommandUtil.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/RemoteIpCommandUtil.java
@@ -22,7 +22,7 @@
 import com.jcraft.jsch.JSch;
 import com.jcraft.jsch.JSchException;
 import com.jcraft.jsch.Session;
-import org.onlab.packet.IpPrefix;
+import org.onlab.packet.IpAddress;
 import org.slf4j.Logger;
 
 import java.io.IOException;
@@ -48,8 +48,10 @@
     private static final String DEFAULT_STRICT_HOST_CHECKING = "no";
     private static final int DEFAULT_SESSION_TIMEOUT = 60000; // milliseconds
 
-    private static final String IP_PATTERN = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.)" +
-            "{3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\\/([0-9]|[1-2][0-9]|3[0-2]))$";
+    private static final String IP_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
+            "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
+            "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." +
+            "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
 
     private static final String IP_ADDR_SHOW = "sudo ip addr show %s";
     private static final String IP_ADDR_FLUSH = "sudo ip addr flush %s";
@@ -68,18 +70,18 @@
      * Adds a given IP address to a given device.
      *
      * @param session ssh connection
-     * @param ip ip address
+     * @param ip network address
      * @param device device name to assign the ip address
      * @return true if the command succeeds, or false
      */
-    public static boolean addIp(Session session, IpPrefix ip, String device) {
+    public static boolean addIp(Session session, NetworkAddress ip, String device) {
         if (session == null || !session.isConnected()) {
             return false;
         }
 
-        executeCommand(session, String.format(IP_ADDR_ADD, ip, device));
-        Set<IpPrefix> result = getCurrentIps(session, device);
-        return result.contains(ip);
+        executeCommand(session, String.format(IP_ADDR_ADD, ip.cidr(), device));
+        Set<IpAddress> result = getCurrentIps(session, device);
+        return result.contains(ip.ip());
     }
 
     /**
@@ -90,13 +92,13 @@
      * @param device device name
      * @return true if the command succeeds, or false
      */
-    public static boolean deleteIp(Session session, IpPrefix ip, String device) {
+    public static boolean deleteIp(Session session, IpAddress ip, String device) {
         if (session == null || !session.isConnected()) {
             return false;
         }
 
         executeCommand(session, String.format(IP_ADDR_DELETE, ip, device));
-        Set<IpPrefix> result = getCurrentIps(session, device);
+        Set<IpAddress> result = getCurrentIps(session, device);
         return !result.contains(ip);
     }
 
@@ -123,16 +125,16 @@
      * @param device device name
      * @return set of IP prefix or empty set
      */
-    public static Set<IpPrefix> getCurrentIps(Session session, String device) {
+    public static Set<IpAddress> getCurrentIps(Session session, String device) {
         if (session == null || !session.isConnected()) {
             return Sets.newHashSet();
         }
 
         String output = executeCommand(session, String.format(IP_ADDR_SHOW, device));
-        Set<IpPrefix> result = Pattern.compile(" ")
+        Set<IpAddress> result = Pattern.compile(" |/")
                 .splitAsStream(output)
                 .filter(s -> s.matches(IP_PATTERN))
-                .map(IpPrefix::valueOf)
+                .map(IpAddress::valueOf)
                 .collect(Collectors.toSet());
 
         return result;
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/CordVtnNodeAddCommand.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/CordVtnNodeAddCommand.java
deleted file mode 100644
index 8995314..0000000
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/CordVtnNodeAddCommand.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2015 Open Networking Laboratory
- *
- * 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.cordvtn.cli;
-
-import org.apache.karaf.shell.commands.Argument;
-import org.apache.karaf.shell.commands.Command;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.TpPort;
-import org.onosproject.cli.AbstractShellCommand;
-import org.onosproject.cordvtn.CordVtnNodeManager;
-import org.onosproject.cordvtn.CordVtnNode;
-import org.onosproject.net.DeviceId;
-
-import static com.google.common.base.Preconditions.checkArgument;
-
-/**
- * Adds a new node to the service.
- */
-@Command(scope = "onos", name = "cordvtn-node-add",
-        description = "Adds a new node to CORD VTN service")
-public class CordVtnNodeAddCommand extends AbstractShellCommand {
-
-    @Argument(index = 0, name = "hostname", description = "Hostname",
-            required = true, multiValued = false)
-    private String hostname = null;
-
-    @Argument(index = 1, name = "ovsdb",
-            description = "OVSDB server listening address (ip:port)",
-            required = true, multiValued = false)
-    private String ovsdb = null;
-
-    @Argument(index = 2, name = "bridgeId",
-            description = "Device ID of integration bridge",
-            required = true, multiValued = false)
-    private String bridgeId = null;
-
-    @Argument(index = 3, name = "phyPortName",
-            description = "Physical port name",
-            required = true, multiValued = false)
-    private String phyPortName = null;
-
-    @Argument(index = 4, name = "localIp",
-            description = "Local data plane IP address",
-            required = true, multiValued = false)
-    private String localIp = null;
-
-    @Override
-    protected void execute() {
-        checkArgument(ovsdb.contains(":"), "OVSDB address should be ip:port format");
-        checkArgument(bridgeId.startsWith("of:"), "bridgeId should be of:dpid format");
-
-        CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class);
-        String[] ipPort = ovsdb.split(":");
-        CordVtnNode node = new CordVtnNode(hostname,
-                                           IpAddress.valueOf(ipPort[0]),
-                                           TpPort.tpPort(Integer.parseInt(ipPort[1])),
-                                           DeviceId.deviceId(bridgeId),
-                                           phyPortName,
-                                           IpAddress.valueOf(localIp));
-        nodeManager.addNode(node);
-    }
-}
diff --git a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/CordVtnNodeListCommand.java b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/CordVtnNodeListCommand.java
index 48e1112..407572a 100644
--- a/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/CordVtnNodeListCommand.java
+++ b/apps/cordvtn/src/main/java/org/onosproject/cordvtn/cli/CordVtnNodeListCommand.java
@@ -34,6 +34,9 @@
         description = "Lists all nodes registered in CORD VTN service")
 public class CordVtnNodeListCommand extends AbstractShellCommand {
 
+    private static final String COMPLETE = "COMPLETE";
+    private static final String INCOMPLETE = "INCOMPLETE";
+
     @Override
     protected void execute() {
         CordVtnNodeManager nodeManager = AbstractShellCommand.get(CordVtnNodeManager.class);
@@ -44,12 +47,12 @@
             print("%s", json(nodeManager, nodes));
         } else {
             for (CordVtnNode node : nodes) {
-                print("hostname=%s, ovsdb=%s, br-int=%s, phyPort=%s, localIp=%s, init=%s",
+                print("hostname=%s, hostMgmtIp=%s, dpIp=%s, br-int=%s, dpIntf=%s, init=%s",
                       node.hostname(),
-                      node.ovsdbIp().toString() + ":" + node.ovsdbPort().toString(),
+                      node.hostMgmtIp().cidr(),
+                      node.dpIp().cidr(),
                       node.intBrId().toString(),
-                      node.phyPortName(),
-                      node.localIp().toString(),
+                      node.dpIntf(),
                       getState(nodeManager, node));
             }
             print("Total %s nodes", nodeManager.getNodeCount());
@@ -60,19 +63,18 @@
         ObjectMapper mapper = new ObjectMapper();
         ArrayNode result = mapper.createArrayNode();
         for (CordVtnNode node : nodes) {
-            String ipPort = node.ovsdbIp().toString() + ":" + node.ovsdbPort().toString();
             result.add(mapper.createObjectNode()
                                .put("hostname", node.hostname())
-                               .put("ovsdb", ipPort)
-                               .put("brInt", node.intBrId().toString())
-                               .put("phyPort", node.phyPortName())
-                               .put("localIp", node.localIp().toString())
+                               .put("hostManagementIp", node.hostMgmtIp().cidr())
+                               .put("dataPlaneIp", node.dpIp().cidr())
+                               .put("bridgeId", node.intBrId().toString())
+                               .put("dataPlaneInterface", node.dpIntf())
                                .put("init", getState(nodeManager, node)));
         }
         return result;
     }
 
     private String getState(CordVtnNodeManager nodeManager, CordVtnNode node) {
-        return nodeManager.getNodeInitState(node) ? "COMPLETE" : "INCOMPLETE";
+        return nodeManager.isNodeInitComplete(node) ? COMPLETE : INCOMPLETE;
     }
 }
diff --git a/apps/cordvtn/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/cordvtn/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index b5c6009..9a2854f 100644
--- a/apps/cordvtn/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/cordvtn/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -20,9 +20,6 @@
             <action class="org.onosproject.cordvtn.cli.CordVtnNodeListCommand"/>
         </command>
         <command>
-            <action class="org.onosproject.cordvtn.cli.CordVtnNodeAddCommand"/>
-        </command>
-        <command>
             <action class="org.onosproject.cordvtn.cli.CordVtnNodeDeleteCommand"/>
         </command>
         <command>