Hyunsun Moon
Committed by Gerrit Code Review

CORD-333 Minimized OVSDB provider dependency

With this patch, cordvtn doesn't need to care for OVSDB connection state
anymore. It will make a connection to OVSDB server like befor but just
for node init and disconnect the OVSDB right after init is done.
- Changed OvsdbNode to CordVtnNode
- Removed OVSDB connect/disconnect and added initNode instead
- Changed ovsdb* commands to cordvtn-node* command, and removed
  connect/disconnect command and added init instead
- Fixed to remove OVSDB device from the system after node init or before
  making a connection to work around OVSDB device re-connect issue

Change-Id: If69369a06526947122494b2f7e816e37aa931f2c
......@@ -15,7 +15,6 @@
*/
package org.onosproject.cordvtn;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
......@@ -32,6 +31,7 @@ import org.onosproject.net.DefaultAnnotations;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.Port;
import org.onosproject.net.behaviour.BridgeConfig;
import org.onosproject.net.behaviour.BridgeName;
import org.onosproject.net.behaviour.ControllerInfo;
......@@ -39,6 +39,7 @@ import org.onosproject.net.behaviour.DefaultTunnelDescription;
import org.onosproject.net.behaviour.TunnelConfig;
import org.onosproject.net.behaviour.TunnelDescription;
import org.onosproject.net.behaviour.TunnelName;
import org.onosproject.net.device.DeviceAdminService;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
......@@ -54,7 +55,6 @@ import org.onosproject.store.serializers.KryoNamespaces;
import org.onosproject.store.service.ConsistentMap;
import org.onosproject.store.service.Serializer;
import org.onosproject.store.service.StorageService;
import org.onosproject.store.service.Versioned;
import org.slf4j.Logger;
import java.util.ArrayList;
......@@ -84,7 +84,8 @@ public class CordVtn implements CordVtnService {
private static final int NUM_THREADS = 1;
private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
.register(KryoNamespaces.API)
.register(DefaultOvsdbNode.class);
.register(CordVtnNode.class)
.register(NodeState.class);
private static final String DEFAULT_BRIDGE_NAME = "br-int";
private static final String DEFAULT_TUNNEL = "vxlan";
private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
......@@ -112,6 +113,9 @@ public class CordVtn implements CordVtnService {
protected DriverService driverService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected DeviceAdminService adminService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected OvsdbController controller;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
......@@ -127,12 +131,55 @@ public class CordVtn implements CordVtnService {
private final BridgeHandler bridgeHandler = new BridgeHandler();
private final VmHandler vmHandler = new VmHandler();
private ConsistentMap<DeviceId, OvsdbNode> nodeStore;
private ConsistentMap<CordVtnNode, NodeState> nodeStore;
private enum NodeState {
INIT {
@Override
public void process(CordVtn cordVtn, CordVtnNode node) {
cordVtn.connect(node);
}
},
OVSDB_CONNECTED {
@Override
public void process(CordVtn cordVtn, CordVtnNode node) {
if (!cordVtn.getOvsdbConnectionState(node)) {
cordVtn.connect(node);
} else {
cordVtn.createIntegrationBridge(node);
}
}
},
BRIDGE_CREATED {
@Override
public void process(CordVtn cordVtn, CordVtnNode node) {
if (!cordVtn.getOvsdbConnectionState(node)) {
cordVtn.connect(node);
} else {
cordVtn.createTunnelInterface(node);
}
}
},
COMPLETE {
@Override
public void process(CordVtn cordVtn, CordVtnNode node) {
cordVtn.postInit(node);
}
},
INCOMPLETE {
@Override
public void process(CordVtn cordVtn, CordVtnNode node) {
}
};
public abstract void process(CordVtn cordVtn, CordVtnNode node);
}
@Activate
protected void activate() {
ApplicationId appId = coreService.registerApplication("org.onosproject.cordvtn");
nodeStore = storageService.<DeviceId, OvsdbNode>consistentMapBuilder()
nodeStore = storageService.<CordVtnNode, NodeState>consistentMapBuilder()
.withSerializer(Serializer.using(NODE_SERIALIZER.build()))
.withName("cordvtn-nodestore")
.withApplicationId(appId)
......@@ -156,145 +203,272 @@ public class CordVtn implements CordVtnService {
}
@Override
public void addNode(OvsdbNode ovsdb) {
checkNotNull(ovsdb);
public void addNode(CordVtnNode node) {
checkNotNull(node);
nodeStore.putIfAbsent(ovsdb.deviceId(), ovsdb);
nodeStore.putIfAbsent(node, checkNodeState(node));
initNode(node);
}
if (isNodeConnected(ovsdb)) {
init(ovsdb);
} else {
connect(ovsdb);
@Override
public void deleteNode(CordVtnNode node) {
checkNotNull(node);
if (getOvsdbConnectionState(node)) {
disconnect(node);
}
nodeStore.remove(node);
}
@Override
public int getNodeCount() {
return nodeStore.size();
}
@Override
public void deleteNode(OvsdbNode ovsdb) {
checkNotNull(ovsdb);
public List<CordVtnNode> getNodes() {
List<CordVtnNode> nodes = new ArrayList<>();
nodes.addAll(nodeStore.keySet());
return nodes;
}
if (deviceService.getDevice(ovsdb.deviceId()) != null) {
if (deviceService.isAvailable(ovsdb.deviceId())) {
log.warn("Cannot delete connected node {}", ovsdb.host());
@Override
public void initNode(CordVtnNode node) {
checkNotNull(node);
if (!nodeStore.containsKey(node)) {
log.warn("Node {} does not exist, add node first", node.hostname());
return;
}
NodeState state = getNodeState(node);
if (state == null) {
return;
} else if (state.equals(NodeState.INCOMPLETE)) {
state = checkNodeState(node);
}
nodeStore.remove(ovsdb.deviceId());
state.process(this, node);
}
@Override
public void connect(OvsdbNode ovsdb) {
checkNotNull(ovsdb);
public boolean getNodeInitState(CordVtnNode node) {
checkNotNull(node);
if (!nodeStore.containsKey(ovsdb.deviceId())) {
log.warn("Node {} does not exist", ovsdb.host());
return;
NodeState state = getNodeState(node);
return state != null && state.equals(NodeState.COMPLETE);
}
if (!isNodeConnected(ovsdb)) {
controller.connect(ovsdb.ip(), ovsdb.port());
/**
* 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;
}
}
@Override
public void disconnect(OvsdbNode ovsdb) {
checkNotNull(ovsdb);
/**
* Sets a new state for a given cordvtn node.
*
* @param node cordvtn node
* @param newState new node state
*/
private void setNodeState(CordVtnNode node, NodeState newState) {
checkNotNull(node);
if (!nodeStore.containsKey(ovsdb.deviceId())) {
log.warn("Node {} does not exist", ovsdb.host());
return;
log.info("Changed {} state: {}", node.hostname(), newState.toString());
nodeStore.put(node, newState);
newState.process(this, node);
}
if (isNodeConnected(ovsdb)) {
OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
ovsdbClient.disconnect();
/**
* Checks current state of a given cordvtn node and returns it.
*
* @param node cordvtn node
* @return node state
*/
private NodeState checkNodeState(CordVtnNode node) {
checkNotNull(node);
if (checkIntegrationBridge(node) && checkTunnelInterface(node)) {
return NodeState.COMPLETE;
} else if (checkIntegrationBridge(node)) {
return NodeState.BRIDGE_CREATED;
} else if (getOvsdbConnectionState(node)) {
return NodeState.OVSDB_CONNECTED;
} else {
return NodeState.INIT;
}
}
private void init(OvsdbNode ovsdb) {
checkNotNull(ovsdb);
/**
* Performs tasks after node initialization.
*
* @param node cordvtn node
*/
private void postInit(CordVtnNode node) {
disconnect(node);
}
/**
* Returns connection state of OVSDB server for a given node.
*
* @param node cordvtn node
* @return true if it is connected, false otherwise
*/
private boolean getOvsdbConnectionState(CordVtnNode node) {
checkNotNull(node);
if (!nodeStore.containsKey(ovsdb.deviceId())) {
log.warn("Node {} does not exist", ovsdb.host());
return;
OvsdbClientService ovsdbClient = getOvsdbClient(node);
return deviceService.isAvailable(node.ovsdbId()) &&
ovsdbClient != null && ovsdbClient.isConnected();
}
if (!isNodeConnected(ovsdb)) {
log.warn("Node {} is not connected", ovsdb.host());
/**
* Connects to OVSDB server for a given node.
*
* @param node cordvtn node
*/
private void connect(CordVtnNode node) {
checkNotNull(node);
if (!nodeStore.containsKey(node)) {
log.warn("Node {} does not exist", node.hostname());
return;
}
if (deviceService.getDevice(ovsdb.intBrId()) == null ||
!deviceService.isAvailable(ovsdb.intBrId())) {
createIntegrationBridge(ovsdb);
} else if (!checkVxlanInterface(ovsdb)) {
createVxlanInterface(ovsdb);
if (!getOvsdbConnectionState(node)) {
// FIXME remove existing OVSDB device to work around OVSDB device re-connect issue
if (deviceService.getDevice(node.ovsdbId()) != null) {
adminService.removeDevice(node.ovsdbId());
}
controller.connect(node.ovsdbIp(), node.ovsdbPort());
}
@Override
public int getNodeCount() {
return nodeStore.size();
}
@Override
public OvsdbNode getNode(DeviceId deviceId) {
Versioned<OvsdbNode> ovsdb = nodeStore.get(deviceId);
if (ovsdb != null) {
return ovsdb.value();
} else {
return null;
/**
* Disconnects OVSDB server for a given node.
*
* @param node cordvtn node
*/
private void disconnect(CordVtnNode node) {
checkNotNull(node);
if (!nodeStore.containsKey(node)) {
log.warn("Node {} does not exist", node.hostname());
return;
}
if (getOvsdbConnectionState(node)) {
OvsdbClientService ovsdbClient = getOvsdbClient(node);
ovsdbClient.disconnect();
}
@Override
public List<OvsdbNode> getNodes() {
List<OvsdbNode> ovsdbs = new ArrayList<>();
ovsdbs.addAll(Collections2.transform(nodeStore.values(), Versioned::value));
return ovsdbs;
// FIXME remove existing OVSDB device to work around OVSDB device re-connect issue
if (deviceService.getDevice(node.ovsdbId()) != null) {
adminService.removeDevice(node.ovsdbId());
}
}
@Override
public boolean isNodeConnected(OvsdbNode ovsdb) {
checkNotNull(ovsdb);
/**
* Returns cordvtn node associated with a given OVSDB device.
*
* @param ovsdbId OVSDB device id
* @return cordvtn node, null if it fails to find the node
*/
private CordVtnNode getNodeByOvsdbId(DeviceId ovsdbId) {
try {
return getNodes().stream()
.filter(node -> node.ovsdbId().equals(ovsdbId))
.findFirst().get();
} catch (NoSuchElementException e) {
log.debug("Couldn't find node information for {}", ovsdbId);
return null;
}
}
OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
if (ovsdbClient == null) {
return false;
} else {
return ovsdbClient.isConnected();
/**
* Returns cordvtn node associated with a given integration bridge.
*
* @param bridgeId device id of integration bridge
* @return cordvtn node, null if it fails to find the node
*/
private CordVtnNode getNodeByBridgeId(DeviceId bridgeId) {
try {
return getNodes().stream()
.filter(node -> node.intBrId().equals(bridgeId))
.findFirst().get();
} catch (NoSuchElementException e) {
log.debug("Couldn't find node information for {}", bridgeId);
return null;
}
}
private OvsdbClientService getOvsdbClient(OvsdbNode ovsdb) {
checkNotNull(ovsdb);
/**
* Returns OVSDB client for a given node.
*
* @param node cordvtn node
* @return OVSDB client, or null if it fails to get OVSDB client
*/
private OvsdbClientService getOvsdbClient(CordVtnNode node) {
checkNotNull(node);
OvsdbClientService ovsdbClient = controller.getOvsdbClient(
new OvsdbNodeId(ovsdb.ip(), ovsdb.port().toInt()));
new OvsdbNodeId(node.ovsdbIp(), node.ovsdbPort().toInt()));
if (ovsdbClient == null) {
log.debug("Couldn't find ovsdb client for {}", ovsdb.host());
log.debug("Couldn't find OVSDB client for {}", node.hostname());
}
return ovsdbClient;
}
private void createIntegrationBridge(OvsdbNode ovsdb) {
/**
* Creates an integration bridge for a given node.
*
* @param node cordvtn node
*/
private void createIntegrationBridge(CordVtnNode node) {
if (checkIntegrationBridge(node)) {
return;
}
List<ControllerInfo> controllers = new ArrayList<>();
Sets.newHashSet(clusterService.getNodes())
.forEach(controller -> {
ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
controllers.add(ctrlInfo);
});
String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN);
String dpid = node.intBrId().toString().substring(DPID_BEGIN);
try {
DriverHandler handler = driverService.createHandler(ovsdb.deviceId());
DriverHandler handler = driverService.createHandler(node.ovsdbId());
BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
bridgeConfig.addBridge(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), dpid, controllers);
} catch (ItemNotFoundException e) {
log.warn("Failed to create integration bridge on {}", ovsdb.deviceId());
log.warn("Failed to create integration bridge on {}", node.ovsdbId());
}
}
private void createVxlanInterface(OvsdbNode ovsdb) {
/**
* Creates tunnel interface to the integration bridge for a given node.
*
* @param node cordvtn node
*/
private void createTunnelInterface(CordVtnNode node) {
if (checkTunnelInterface(node)) {
return;
}
DefaultAnnotations.Builder optionBuilder = DefaultAnnotations.builder();
for (String key : DEFAULT_TUNNEL_OPTIONS.keySet()) {
optionBuilder.set(key, DEFAULT_TUNNEL_OPTIONS.get(key));
......@@ -304,38 +478,63 @@ public class CordVtn implements CordVtnService {
TunnelName.tunnelName(DEFAULT_TUNNEL),
optionBuilder.build());
try {
DriverHandler handler = driverService.createHandler(ovsdb.deviceId());
DriverHandler handler = driverService.createHandler(node.ovsdbId());
TunnelConfig tunnelConfig = handler.behaviour(TunnelConfig.class);
tunnelConfig.createTunnelInterface(BridgeName.bridgeName(DEFAULT_BRIDGE_NAME), description);
} catch (ItemNotFoundException e) {
log.warn("Failed to create VXLAN interface on {}", ovsdb.deviceId());
log.warn("Failed to create tunnel interface on {}", node.ovsdbId());
}
}
/**
* Checks if integration bridge exists and available.
*
* @param node cordvtn node
* @return true if the bridge is available, false otherwise
*/
private boolean checkIntegrationBridge(CordVtnNode node) {
return (deviceService.getDevice(node.intBrId()) != null
&& deviceService.isAvailable(node.intBrId()));
}
private boolean checkVxlanInterface(OvsdbNode ovsdb) {
/**
* Checks if tunnel interface exists.
*
* @param node cordvtn node
* @return true if the interface exists, false otherwise
*/
private boolean checkTunnelInterface(CordVtnNode node) {
try {
DriverHandler handler = driverService.createHandler(ovsdb.deviceId());
BridgeConfig bridgeConfig = handler.behaviour(BridgeConfig.class);
bridgeConfig.getPorts().stream()
.filter(p -> p.annotations().value("portName").equals(DEFAULT_TUNNEL))
deviceService.getPorts(node.intBrId())
.stream()
.filter(p -> p.annotations().value("portName").contains(DEFAULT_TUNNEL)
&& p.isEnabled())
.findAny().get();
} catch (ItemNotFoundException | NoSuchElementException e) {
return true;
} catch (NoSuchElementException e) {
return false;
}
return true;
}
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
Device device = event.subject();
ConnectionHandler handler = (device.type() == SWITCH ? bridgeHandler : ovsdbHandler);
ConnectionHandler<Device> handler =
(device.type().equals(SWITCH) ? bridgeHandler : ovsdbHandler);
switch (event.type()) {
case DEVICE_ADDED:
eventExecutor.submit(() -> handler.connected(device));
case PORT_ADDED:
eventExecutor.submit(() -> bridgeHandler.portAdded(event.port()));
break;
case PORT_UPDATED:
if (!event.port().isEnabled()) {
eventExecutor.submit(() -> bridgeHandler.portRemoved(event.port()));
}
break;
case DEVICE_ADDED:
case DEVICE_AVAILABILITY_CHANGED:
if (deviceService.isAvailable(device.id())) {
eventExecutor.submit(() -> handler.connected(device));
......@@ -372,17 +571,15 @@ public class CordVtn implements CordVtnService {
@Override
public void connected(Device device) {
log.info("Ovsdb {} is connected", device.id());
OvsdbNode ovsdb = getNode(device.id());
if (ovsdb != null) {
init(ovsdb);
CordVtnNode node = getNodeByOvsdbId(device.id());
if (node != null) {
setNodeState(node, checkNodeState(node));
}
}
@Override
public void disconnected(Device device) {
log.warn("Ovsdb {} is disconnected", device.id());
log.info("OVSDB {} is disconnected", device.id());
}
}
......@@ -390,26 +587,56 @@ public class CordVtn implements CordVtnService {
@Override
public void connected(Device device) {
log.info("Integration Bridge {} is detected", device.id());
CordVtnNode node = getNodeByBridgeId(device.id());
if (node != null) {
setNodeState(node, checkNodeState(node));
}
}
OvsdbNode ovsdb;
try {
ovsdb = getNodes().stream()
.filter(node -> node.intBrId().equals(device.id()))
.findFirst().get();
} catch (NoSuchElementException e) {
log.warn("Couldn't find OVSDB associated with {}", device.id());
@Override
public void disconnected(Device device) {
CordVtnNode node = getNodeByBridgeId(device.id());
if (node != null) {
log.info("Integration Bridge is disconnected from {}", node.hostname());
setNodeState(node, NodeState.INCOMPLETE);
}
}
/**
* Handles port added situation.
* If the added port is tunnel port, proceed remaining node initialization.
* Otherwise, do nothing.
*
* @param port port
*/
public void portAdded(Port port) {
if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) {
return;
}
if (!checkVxlanInterface(ovsdb)) {
createVxlanInterface(ovsdb);
CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
if (node != null) {
setNodeState(node, checkNodeState(node));
}
}
@Override
public void disconnected(Device device) {
log.info("Integration Bridge {} is vanished", device.id());
/**
* Handles port removed situation.
* If the removed port is tunnel port, proceed remaining node initialization.
* Others, do nothing.
*
* @param port port
*/
public void portRemoved(Port port) {
if (!port.annotations().value("portName").contains(DEFAULT_TUNNEL)) {
return;
}
CordVtnNode node = getNodeByBridgeId((DeviceId) port.element().id());
if (node != null) {
log.info("Tunnel interface is removed from {}", node.hostname());
setNodeState(node, NodeState.INCOMPLETE);
}
}
}
......
......@@ -32,77 +32,82 @@ import static com.google.common.base.Preconditions.checkNotNull;
*/
public class CordVtnConfig extends Config<ApplicationId> {
public static final String OVSDB_NODES = "ovsdbNodes";
public static final String HOST = "host";
public static final String IP = "ip";
public static final String PORT = "port";
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";
/**
* Returns the set of ovsdb nodes read from network config.
* Returns the set of nodes read from network config.
*
* @return set of OvsdbNodeConfig or null
* @return set of CordVtnNodeConfig or null
*/
public Set<OvsdbNodeConfig> ovsdbNodes() {
Set<OvsdbNodeConfig> ovsdbNodes = Sets.newHashSet();
public Set<CordVtnNodeConfig> cordVtnNodes() {
Set<CordVtnNodeConfig> nodes = Sets.newHashSet();
JsonNode nodes = object.get(OVSDB_NODES);
if (nodes == null) {
JsonNode jsonNodes = object.get(CORDVTN_NODES);
if (jsonNodes == null) {
return null;
}
nodes.forEach(jsonNode -> ovsdbNodes.add(new OvsdbNodeConfig(
jsonNode.path(HOST).asText(),
IpAddress.valueOf(jsonNode.path(IP).asText()),
TpPort.tpPort(jsonNode.path(PORT).asInt()),
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()))));
return ovsdbNodes;
return nodes;
}
/**
* Configuration for an ovsdb node.
* Configuration for CordVtn node.
*/
public static class OvsdbNodeConfig {
public static class CordVtnNodeConfig {
private final String host;
private final IpAddress ip;
private final TpPort port;
private final String hostname;
private final IpAddress ovsdbIp;
private final TpPort ovsdbPort;
private final DeviceId bridgeId;
public OvsdbNodeConfig(String host, IpAddress ip, TpPort port, DeviceId bridgeId) {
this.host = checkNotNull(host);
this.ip = checkNotNull(ip);
this.port = checkNotNull(port);
public CordVtnNodeConfig(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort, DeviceId bridgeId) {
this.hostname = checkNotNull(hostname);
this.ovsdbIp = checkNotNull(ovsdbIp);
this.ovsdbPort = checkNotNull(ovsdbPort);
this.bridgeId = checkNotNull(bridgeId);
}
/**
* Returns host information of the node.
* Returns hostname of the node.
*
* @return host
* @return hostname
*/
public String host() {
return this.host;
public String hostname() {
return this.hostname;
}
/**
* Returns ip address to access ovsdb-server of the node.
* Returns OVSDB ip address of the node.
*
* @return ip address
* @return OVSDB server IP address
*/
public IpAddress ip() {
return this.ip;
public IpAddress ovsdbIp() {
return this.ovsdbIp;
}
/**
* Returns port number to access ovsdb-server of the node.
* Returns OVSDB port number of the node.
*
* @return port number
*/
public TpPort port() {
return this.port;
public TpPort ovsdbPort() {
return this.ovsdbPort;
}
/**
* Returns integration bridge id of the node.
*
* @return device id
*/
public DeviceId bridgeId() {
return this.bridgeId;
}
......
......@@ -88,10 +88,10 @@ public class CordVtnConfigManager {
return;
}
config.ovsdbNodes().forEach(node -> {
DefaultOvsdbNode ovsdb = new DefaultOvsdbNode(
node.host(), node.ip(), node.port(), node.bridgeId());
cordVtnService.addNode(ovsdb);
config.cordVtnNodes().forEach(node -> {
CordVtnNode cordVtnNode = new CordVtnNode(
node.hostname(), node.ovsdbIp(), node.ovsdbPort(), node.bridgeId());
cordVtnService.addNode(cordVtnNode);
});
}
......
/*
* Copyright 2014-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;
import com.google.common.base.MoreObjects;
import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onosproject.net.DeviceId;
import java.util.Comparator;
import java.util.Objects;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Representation of a compute infrastructure node for CORD VTN service.
*/
public final class CordVtnNode {
private final String hostname;
private final IpAddress ovsdbIp;
private final TpPort ovsdbPort;
private final DeviceId bridgeId;
public static final Comparator<CordVtnNode> CORDVTN_NODE_COMPARATOR =
(node1, node2) -> node1.hostname().compareTo(node2.hostname());
/**
* Creates a new node.
*
* @param hostname hostname
* @param ovsdbIp OVSDB server IP address
* @param ovsdbPort OVSDB server port number
* @param bridgeId integration bridge identifier
*/
public CordVtnNode(String hostname, IpAddress ovsdbIp, TpPort ovsdbPort, DeviceId bridgeId) {
this.hostname = checkNotNull(hostname);
this.ovsdbIp = checkNotNull(ovsdbIp);
this.ovsdbPort = checkNotNull(ovsdbPort);
this.bridgeId = checkNotNull(bridgeId);
}
/**
* 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;
}
/**
* Returns the hostname.
*
* @return hostname
*/
public String hostname() {
return this.hostname;
}
/**
* Returns the identifier of the integration bridge.
*
* @return device id
*/
public DeviceId intBrId() {
return this.bridgeId;
}
/**
* Returns the identifier of the OVSDB device.
*
* @return device id
*/
public DeviceId ovsdbId() {
return DeviceId.deviceId("ovsdb:" + this.ovsdbIp.toString());
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof CordVtnNode) {
CordVtnNode that = (CordVtnNode) obj;
if (Objects.equals(hostname, that.hostname) &&
Objects.equals(ovsdbIp, that.ovsdbIp) &&
Objects.equals(ovsdbPort, that.ovsdbPort) &&
Objects.equals(bridgeId, that.bridgeId)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(hostname, ovsdbIp, ovsdbPort);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("host", hostname)
.add("ip", ovsdbIp)
.add("port", ovsdbPort)
.add("bridgeId", bridgeId)
.toString();
}
}
......@@ -15,8 +15,6 @@
*/
package org.onosproject.cordvtn;
import org.onosproject.net.DeviceId;
import java.util.List;
/**
......@@ -28,30 +26,23 @@ public interface CordVtnService {
/**
* Adds a new node to the service.
*
* @param ovsdb ovsdb node
* @param node cordvtn node
*/
void addNode(OvsdbNode ovsdb);
void addNode(CordVtnNode node);
/**
* Deletes a node from the service.
*
* @param ovsdb ovsdb node
*/
void deleteNode(OvsdbNode ovsdb);
/**
* Connect to a node.
*
* @param ovsdb ovsdb node
* @param node cordvtn node
*/
void connect(OvsdbNode ovsdb);
void deleteNode(CordVtnNode node);
/**
* Disconnect a node.
* Initiates node to serve virtual tenant network.
*
* @param ovsdb ovsdb node
* @param node cordvtn node
*/
void disconnect(OvsdbNode ovsdb);
void initNode(CordVtnNode node);
/**
* Returns the number of the nodes known to the service.
......@@ -61,25 +52,17 @@ public interface CordVtnService {
int getNodeCount();
/**
* Returns OvsdbNode with given device id.
*
* @param deviceId device id
* @return ovsdb node
*/
OvsdbNode getNode(DeviceId deviceId);
/**
* Returns connection state of the node.
* Returns node initialization state.
*
* @param ovsdb ovsdb node
* @return true if the node is connected, false otherwise
* @param node cordvtn node
* @return true if initial node setup is completed, otherwise false
*/
boolean isNodeConnected(OvsdbNode ovsdb);
boolean getNodeInitState(CordVtnNode node);
/**
* Returns all nodes known to the service.
*
* @return list of nodes
*/
List<OvsdbNode> getNodes();
List<CordVtnNode> getNodes();
}
......
/*
* Copyright 2014-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;
import com.google.common.base.MoreObjects;
import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onosproject.net.DeviceId;
import java.util.Objects;
/**
* OvsdbNode implementation.
*/
public class DefaultOvsdbNode implements OvsdbNode {
private final String host;
private final IpAddress ip;
private final TpPort port;
private final DeviceId brId;
public DefaultOvsdbNode(String host, IpAddress ip, TpPort port, DeviceId brId) {
this.host = host;
this.ip = ip;
this.port = port;
this.brId = brId;
}
@Override
public IpAddress ip() {
return this.ip;
}
@Override
public TpPort port() {
return this.port;
}
@Override
public String host() {
return this.host;
}
@Override
public DeviceId intBrId() {
return this.brId;
}
@Override
public DeviceId deviceId() {
return DeviceId.deviceId("ovsdb:" + this.ip.toString());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof DefaultOvsdbNode) {
DefaultOvsdbNode that = (DefaultOvsdbNode) o;
if (this.host.equals(that.host) &&
this.ip.equals(that.ip) &&
this.port.equals(that.port) &&
this.brId.equals(that.brId)) {
return true;
}
}
return false;
}
@Override
public int hashCode() {
return Objects.hash(host, ip, port);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("host", host)
.add("ip", ip)
.add("port", port)
.add("bridgeId", brId)
.toString();
}
}
/*
* Copyright 2014-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;
import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onosproject.net.DeviceId;
import java.util.Comparator;
/**
* Representation of a node with ovsdb server.
*/
public interface OvsdbNode {
Comparator<OvsdbNode> OVSDB_NODE_COMPARATOR = new Comparator<OvsdbNode>() {
@Override
public int compare(OvsdbNode ovsdb1, OvsdbNode ovsdb2) {
return ovsdb1.host().compareTo(ovsdb2.host());
}
};
/**
* Returns the IP address of the ovsdb server.
*
* @return ip address
*/
IpAddress ip();
/**
* Returns the port number of the ovsdb server.
*
* @return port number
*/
TpPort port();
/**
* Returns the host information of the ovsdb server.
* It could be hostname or ip address.
*
* @return host
*/
String host();
/**
* Returns the device id of the ovsdb server.
*
* @return device id
*/
DeviceId deviceId();
/**
* Returns the device id of the integration bridge associated with the node.
*
* @return device id
*/
DeviceId intBrId();
}
......@@ -22,27 +22,26 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cordvtn.CordVtnService;
import org.onosproject.cordvtn.DefaultOvsdbNode;
import org.onosproject.cordvtn.OvsdbNode;
import org.onosproject.cordvtn.CordVtnNode;
import org.onosproject.net.DeviceId;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Adds a new OVSDB nodes.
* Adds a new node to the service.
*/
@Command(scope = "onos", name = "ovsdb-add",
description = "Adds a new OVSDB node to cordvtn")
public class OvsdbNodeAddCommand extends AbstractShellCommand {
@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 = "host", description = "Hostname or IP",
@Argument(index = 0, name = "hostname", description = "Hostname",
required = true, multiValued = false)
private String host = null;
private String hostname = null;
@Argument(index = 1, name = "address",
@Argument(index = 1, name = "ovsdb",
description = "OVSDB server listening address (ip:port)",
required = true, multiValued = false)
private String address = null;
private String ovsdb = null;
@Argument(index = 2, name = "bridgeId",
description = "Device ID of integration bridge",
......@@ -51,15 +50,15 @@ public class OvsdbNodeAddCommand extends AbstractShellCommand {
@Override
protected void execute() {
checkArgument(address.contains(":"), "address should be ip:port format");
checkArgument(ovsdb.contains(":"), "OVSDB address should be ip:port format");
checkArgument(bridgeId.startsWith("of:"), "bridgeId should be of:dpid format");
CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
String[] ipPort = address.split(":");
OvsdbNode ovsdb = new DefaultOvsdbNode(host,
String[] ipPort = ovsdb.split(":");
CordVtnNode node = new CordVtnNode(hostname,
IpAddress.valueOf(ipPort[0]),
TpPort.tpPort(Integer.parseInt(ipPort[1])),
DeviceId.deviceId(bridgeId));
service.addNode(ovsdb);
service.addNode(node);
}
}
......
......@@ -20,38 +20,38 @@ import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cordvtn.CordVtnService;
import org.onosproject.cordvtn.OvsdbNode;
import org.onosproject.cordvtn.CordVtnNode;
import java.util.NoSuchElementException;
/**
* Deletes OVSDB nodes from cordvtn.
* Deletes nodes from the service.
*/
@Command(scope = "onos", name = "ovsdb-delete",
description = "Deletes OVSDB nodes from cordvtn")
public class OvsdbNodeDeleteCommand extends AbstractShellCommand {
@Command(scope = "onos", name = "cordvtn-node-delete",
description = "Deletes nodes from CORD VTN service")
public class CordVtnNodeDeleteCommand extends AbstractShellCommand {
@Argument(index = 0, name = "hosts", description = "Hostname(s) or IP(s)",
@Argument(index = 0, name = "hostnames", description = "Hostname(s)",
required = true, multiValued = true)
private String[] hosts = null;
private String[] hostnames = null;
@Override
protected void execute() {
CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
for (String host : hosts) {
OvsdbNode ovsdb;
for (String hostname : hostnames) {
CordVtnNode node;
try {
ovsdb = service.getNodes().stream()
.filter(node -> node.host().equals(host))
node = service.getNodes()
.stream()
.filter(n -> n.hostname().equals(hostname))
.findFirst().get();
} catch (NoSuchElementException e) {
print("Unable to find %s", host);
print("Unable to find %s", hostname);
continue;
}
service.deleteNode(ovsdb);
service.deleteNode(node);
}
}
}
......
......@@ -20,41 +20,38 @@ import org.apache.karaf.shell.commands.Argument;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cordvtn.CordVtnService;
import org.onosproject.cordvtn.OvsdbNode;
import org.onosproject.cordvtn.CordVtnNode;
import java.util.NoSuchElementException;
/**
* Connects to OVSDBs.
* Initializes nodes for CordVtn service.
*/
@Command(scope = "onos", name = "ovsdb-connect",
description = "Connects to OVSDBs")
public class OvsdbNodeConnectCommand extends AbstractShellCommand {
@Command(scope = "onos", name = "cordvtn-node-init",
description = "Initializes nodes for CORD VTN service")
public class CordVtnNodeInitCommand extends AbstractShellCommand {
@Argument(index = 0, name = "hosts", description = "Hostname(s) or IP(s)",
@Argument(index = 0, name = "hostnames", description = "Hostname(s)",
required = true, multiValued = true)
private String[] hosts = null;
private String[] hostnames = null;
@Override
protected void execute() {
CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
for (String host : hosts) {
OvsdbNode ovsdb;
for (String hostname : hostnames) {
CordVtnNode node;
try {
ovsdb = service.getNodes().stream()
.filter(node -> node.host().equals(host))
node = service.getNodes()
.stream()
.filter(n -> n.hostname().equals(hostname))
.findFirst().get();
} catch (NoSuchElementException e) {
print("Unable to find %s", host);
print("Unable to find %s", hostname);
continue;
}
if (service.isNodeConnected(ovsdb)) {
print("OVSDB %s is already in connected state, do nothing", host);
} else {
service.connect(ovsdb);
}
service.initNode(node);
}
}
}
......
......@@ -22,53 +22,53 @@ import com.fasterxml.jackson.databind.node.ArrayNode;
import org.apache.karaf.shell.commands.Command;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.cordvtn.CordVtnService;
import org.onosproject.cordvtn.OvsdbNode;
import org.onosproject.cordvtn.CordVtnNode;
import java.util.Collections;
import java.util.List;
/**
* Lists all OVSDB nodes.
* Lists all nodes registered to the service.
*/
@Command(scope = "onos", name = "ovsdbs",
description = "Lists all OVSDB nodes registered in cordvtn application")
public class OvsdbNodeListCommand extends AbstractShellCommand {
@Command(scope = "onos", name = "cordvtn-nodes",
description = "Lists all nodes registered in CORD VTN service")
public class CordVtnNodeListCommand extends AbstractShellCommand {
@Override
protected void execute() {
CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
List<OvsdbNode> ovsdbs = service.getNodes();
Collections.sort(ovsdbs, OvsdbNode.OVSDB_NODE_COMPARATOR);
List<CordVtnNode> nodes = service.getNodes();
Collections.sort(nodes, CordVtnNode.CORDVTN_NODE_COMPARATOR);
if (outputJson()) {
print("%s", json(service, ovsdbs));
print("%s", json(service, nodes));
} else {
for (OvsdbNode ovsdb : ovsdbs) {
print("host=%s, address=%s, br-int=%s, state=%s",
ovsdb.host(),
ovsdb.ip().toString() + ":" + ovsdb.port().toString(),
ovsdb.intBrId().toString(),
getState(service, ovsdb));
for (CordVtnNode node : nodes) {
print("hostname=%s, ovsdb=%s, br-int=%s, init=%s",
node.hostname(),
node.ovsdbIp().toString() + ":" + node.ovsdbPort().toString(),
node.intBrId().toString(),
getState(service, node));
}
print("Total %s nodes", service.getNodeCount());
}
}
private JsonNode json(CordVtnService service, List<OvsdbNode> ovsdbs) {
private JsonNode json(CordVtnService service, List<CordVtnNode> nodes) {
ObjectMapper mapper = new ObjectMapper();
ArrayNode result = mapper.createArrayNode();
for (OvsdbNode ovsdb : ovsdbs) {
String ipPort = ovsdb.ip().toString() + ":" + ovsdb.port().toString();
for (CordVtnNode node : nodes) {
String ipPort = node.ovsdbIp().toString() + ":" + node.ovsdbPort().toString();
result.add(mapper.createObjectNode()
.put("host", ovsdb.host())
.put("address", ipPort)
.put("brInt", ovsdb.intBrId().toString())
.put("state", getState(service, ovsdb)));
.put("hostname", node.hostname())
.put("ovsdb", ipPort)
.put("brInt", node.intBrId().toString())
.put("init", getState(service, node)));
}
return result;
}
private String getState(CordVtnService service, OvsdbNode ovsdb) {
return service.isNodeConnected(ovsdb) ? "CONNECTED" : "DISCONNECTED";
private String getState(CordVtnService service, CordVtnNode node) {
return service.getNodeInitState(node) ? "COMPLETE" : "INCOMPLETE";
}
}
......
/*
* 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.onosproject.cli.AbstractShellCommand;
import org.onosproject.cordvtn.CordVtnService;
import org.onosproject.cordvtn.OvsdbNode;
import java.util.NoSuchElementException;
/**
* Disconnects OVSDBs.
*/
@Command(scope = "onos", name = "ovsdb-disconnect",
description = "Disconnects OVSDBs")
public class OvsdbNodeDisconnectCommand extends AbstractShellCommand {
@Argument(index = 0, name = "hosts", description = "Hostname(s) or IP(s)",
required = true, multiValued = true)
private String[] hosts = null;
@Override
protected void execute() {
CordVtnService service = AbstractShellCommand.get(CordVtnService.class);
for (String host : hosts) {
OvsdbNode ovsdb;
try {
ovsdb = service.getNodes().stream()
.filter(node -> node.host().equals(host))
.findFirst().get();
} catch (NoSuchElementException e) {
print("Unable to find %s", host);
continue;
}
if (!service.isNodeConnected(ovsdb)) {
print("OVSDB %s is already in disconnected state, do nothing", host);
} else {
service.disconnect(ovsdb);
}
}
}
}
......@@ -17,19 +17,16 @@
<command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
<command>
<action class="org.onosproject.cordvtn.cli.OvsdbNodeListCommand"/>
<action class="org.onosproject.cordvtn.cli.CordVtnNodeListCommand"/>
</command>
<command>
<action class="org.onosproject.cordvtn.cli.OvsdbNodeAddCommand"/>
<action class="org.onosproject.cordvtn.cli.CordVtnNodeAddCommand"/>
</command>
<command>
<action class="org.onosproject.cordvtn.cli.OvsdbNodeDeleteCommand"/>
<action class="org.onosproject.cordvtn.cli.CordVtnNodeDeleteCommand"/>
</command>
<command>
<action class="org.onosproject.cordvtn.cli.OvsdbNodeConnectCommand"/>
</command>
<command>
<action class="org.onosproject.cordvtn.cli.OvsdbNodeDisconnectCommand"/>
<action class="org.onosproject.cordvtn.cli.CordVtnNodeInitCommand"/>
</command>
</command-bundle>
</blueprint>
......