Hyunsun Moon
Committed by Gerrit Code Review

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
......@@ -265,7 +265,7 @@ public class CordVtn extends AbstractProvider implements CordVtnService, HostPro
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(
......
......@@ -17,7 +17,6 @@ package org.onosproject.cordvtn;
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 @@ public class CordVtnConfig extends Config<ApplicationId> {
protected final Logger log = getLogger(getClass());
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 OVSDB_IP = "ovsdbIp";
public static final String OVSDB_PORT = "ovsdbPort";
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";
public static final String PHYSICAL_PORT_NAME = "phyPortName";
public static final String LOCAL_IP = "localIp";
public static final String GATEWAY_MAC = "gatewayMac";
/**
* Returns the set of nodes read from network config.
......@@ -58,13 +62,19 @@ public class CordVtnConfig extends Config<ApplicationId> {
if (jsonNodes == null) {
return null;
}
jsonNodes.forEach(jsonNode -> nodes.add(new CordVtnNodeConfig(
jsonNodes.forEach(jsonNode -> {
try {
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()))));
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 @@ public class CordVtnConfig extends Config<ApplicationId> {
}
/**
* 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,48 +213,39 @@ public class CordVtnConfig extends Config<ApplicationId> {
}
/**
* Returns OVSDB ip address of the node.
*
* @return OVSDB server IP address
*/
public IpAddress ovsdbIp() {
return this.ovsdbIp;
}
/**
* Returns OVSDB port number of the node.
* Returns the host management network address of the node.
*
* @return port number
* @return management network address
*/
public TpPort ovsdbPort() {
return this.ovsdbPort;
public NetworkAddress hostMgmtIp() {
return this.hostMgmtIp;
}
/**
* Returns integration bridge id of the node.
* Returns the data plane network address.
*
* @return device id
* @return network address
*/
public DeviceId bridgeId() {
return this.bridgeId;
public NetworkAddress dpIp() {
return this.dpIp;
}
/**
* Returns physical port name.
* Returns the data plane interface name.
*
* @return physical port name
* @return interface name
*/
public String phyPortName() {
return this.phyPortName;
public String dpIntf() {
return this.dpIntf;
}
/**
* Returns local IP address.
* Returns integration bridge id of the node.
*
* @return ip address
* @return device id
*/
public IpAddress localIp() {
return this.localIp;
public DeviceId bridgeId() {
return this.bridgeId;
}
}
}
......
......@@ -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 @@ import static com.google.common.base.Preconditions.checkNotNull;
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,33 +45,65 @@ public final class CordVtnNode {
* 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);
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");
}
/**
* Returns the OVSDB server IP address.
* Returns the hostname.
*
* @return hostname
*/
public String hostname() {
return this.hostname;
}
/**
* Returns the host management network address.
*
* @return network address
*/
public NetworkAddress hostMgmtIp() {
return this.hostMgmtIp;
}
/**
* Returns the local management network address.
*
* @return ip address
* @return network address
*/
public IpAddress ovsdbIp() {
return this.ovsdbIp;
public NetworkAddress localMgmtIp() {
return this.localMgmtIp;
}
/**
* Returns the OVSDB server port number.
* 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
*/
......@@ -79,12 +112,12 @@ public final class CordVtnNode {
}
/**
* Returns the hostname.
* Returns the SSH access information.
*
* @return hostname
* @return ssh access information
*/
public String hostname() {
return this.hostname;
public SshAccessInfo sshInfo() {
return this.sshInfo;
}
/**
......@@ -102,25 +135,16 @@ public final class CordVtnNode {
* @return device id
*/
public DeviceId ovsdbId() {
return DeviceId.deviceId("ovsdb:" + this.ovsdbIp.toString());
}
/**
* Returns physical port name.
*
* @return physical port name
*/
public String phyPortName() {
return this.phyPortName;
return DeviceId.deviceId("ovsdb:" + this.hostMgmtIp.ip().toString());
}
/**
* Returns local IP address.
* Returns data plane interface name.
*
* @return ip address
* @return data plane interface name
*/
public IpAddress localIp() {
return this.localIp;
public String dpIntf() {
return this.dpIntf;
}
@Override
......@@ -129,6 +153,8 @@ public final class CordVtnNode {
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 @@ public final class CordVtnNode {
@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();
}
}
......
......@@ -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.ArrayList;
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 @@ public class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
}
};
// TODO Add physical port add state
public abstract void process(CordVtnNodeManager nodeManager, CordVtnNode node);
}
......@@ -256,7 +252,7 @@ public class CordVtnNodeManager {
public void addNode(CordVtnNode node) {
checkNotNull(node);
nodeStore.putIfAbsent(node, checkNodeState(node));
nodeStore.putIfAbsent(node, getNodeState(node));
initNode(node);
}
......@@ -268,7 +264,7 @@ public class CordVtnNodeManager {
public void deleteNode(CordVtnNode node) {
checkNotNull(node);
if (getOvsdbConnectionState(node)) {
if (isOvsdbConnected(node)) {
disconnectOvsdb(node);
}
......@@ -288,7 +284,7 @@ public class CordVtnNodeManager {
return;
}
NodeState state = checkNodeState(node);
NodeState state = getNodeState(node);
state.process(this, node);
}
......@@ -298,20 +294,13 @@ public class CordVtnNodeManager {
* @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 class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
}
/**
* 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 @@ public class CordVtnNodeManager {
* @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 @@ public class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
* @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 @@ public class CordVtnNodeManager {
return;
}
if (!getOvsdbConnectionState(node)) {
controller.connect(node.ovsdbIp(), node.ovsdbPort());
if (!isOvsdbConnected(node)) {
controller.connect(node.hostMgmtIp().ip(), node.ovsdbPort());
}
}
......@@ -519,7 +504,7 @@ public class CordVtnNodeManager {
return;
}
if (getOvsdbConnectionState(node)) {
if (isOvsdbConnected(node)) {
OvsdbClientService ovsdbClient = getOvsdbClient(node);
ovsdbClient.disconnect();
}
......@@ -535,7 +520,7 @@ public class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
* @param node cordvtn node
*/
private void createIntegrationBridge(CordVtnNode node) {
if (checkIntegrationBridge(node)) {
if (isBrIntCreated(node)) {
return;
}
......@@ -576,7 +561,7 @@ public class CordVtnNodeManager {
* @param node cordvtn node
*/
private void createTunnelInterface(CordVtnNode node) {
if (checkTunnelInterface(node)) {
if (isTunnelIntfCreated(node)) {
return;
}
......@@ -599,21 +584,47 @@ public class CordVtnNodeManager {
}
/**
* 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 @@ public class CordVtnNodeManager {
* @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 @@ public class CordVtnNodeManager {
* @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 @@ public class CordVtnNodeManager {
}
/**
* 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 class CordVtnNodeManager {
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 class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
/**
* 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 @@ public class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
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 @@ public class CordVtnNodeManager {
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);
});
......
......@@ -96,6 +96,7 @@ public class CordVtnRuleInstaller {
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 @@ public class CordVtnRuleInstaller {
* 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 @@ public class CordVtnRuleInstaller {
/**
* 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 @@ public class CordVtnRuleInstaller {
// 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 @@ public class CordVtnRuleInstaller {
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 @@ public class CordVtnRuleInstaller {
// 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 @@ public class CordVtnRuleInstaller {
}
/**
* 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 @@ public class CordVtnRuleInstaller {
/**
* 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 @@ public class CordVtnRuleInstaller {
processFlowRule(true, flowRule);
selector = DefaultTrafficSelector.builder()
.matchInPort(phyPort)
.matchInPort(dpPort)
.build();
treatment = DefaultTrafficTreatment.builder()
......@@ -1027,22 +1028,22 @@ public class CordVtnRuleInstaller {
*/
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);
......
/*
* 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();
}
}
......@@ -22,7 +22,7 @@ import com.jcraft.jsch.ChannelExec;
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 @@ public final class RemoteIpCommandUtil {
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 @@ public final class RemoteIpCommandUtil {
* 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 @@ public final class RemoteIpCommandUtil {
* @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 @@ public final class RemoteIpCommandUtil {
* @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;
......
/*
* 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);
}
}
......@@ -34,6 +34,9 @@ import java.util.List;
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 @@ public class CordVtnNodeListCommand extends AbstractShellCommand {
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 @@ public class CordVtnNodeListCommand extends AbstractShellCommand {
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;
}
}
......
......@@ -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>
......