Hyunsun Moon
Committed by Gerrit Code Review

CORD-151 Implement initial compute node setup

Followings are changed
- Changed nodeStore from eventually consistent map to consistent map
- Removed ovsdb connection management(ovsdb controller has connection status)
- Not only one leader but all onos instances make ovsdb session

Following jobs are done
- Reads compute node and ovsdb access info from network config
- Initiates ovsdb connection to the nodes
- Creates integration bridge on each ovsdbs
- Creates vxlan tunnel port on each integration bridges

Change-Id: I8df4061fcb1eae9b0abd545b7a3f540be50607a9
......@@ -49,6 +49,11 @@
<artifactId>onos-core-serializers</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.onosproject</groupId>
<artifactId>onos-ovsdb-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
......
......@@ -20,6 +20,7 @@ import com.google.common.collect.Sets;
import org.onlab.packet.IpAddress;
import org.onlab.packet.TpPort;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.DeviceId;
import org.onosproject.net.config.Config;
import java.util.Set;
......@@ -35,6 +36,7 @@ public class CordVtnConfig extends Config<ApplicationId> {
public static final String HOST = "host";
public static final String IP = "ip";
public static final String PORT = "port";
public static final String BRIDGE_ID = "bridgeId";
/**
* Returns the set of ovsdb nodes read from network config.
......@@ -51,7 +53,8 @@ public class CordVtnConfig extends Config<ApplicationId> {
nodes.forEach(jsonNode -> ovsdbNodes.add(new OvsdbNodeConfig(
jsonNode.path(HOST).asText(),
IpAddress.valueOf(jsonNode.path(IP).asText()),
TpPort.tpPort(jsonNode.path(PORT).asInt()))));
TpPort.tpPort(jsonNode.path(PORT).asInt()),
DeviceId.deviceId(jsonNode.path(BRIDGE_ID).asText()))));
return ovsdbNodes;
}
......@@ -64,11 +67,13 @@ public class CordVtnConfig extends Config<ApplicationId> {
private final String host;
private final IpAddress ip;
private final TpPort port;
private final DeviceId bridgeId;
public OvsdbNodeConfig(String host, IpAddress ip, TpPort port) {
public OvsdbNodeConfig(String host, IpAddress ip, TpPort port, DeviceId bridgeId) {
this.host = checkNotNull(host);
this.ip = checkNotNull(ip);
this.port = checkNotNull(port);
this.bridgeId = checkNotNull(bridgeId);
}
/**
......@@ -97,5 +102,9 @@ public class CordVtnConfig extends Config<ApplicationId> {
public TpPort port() {
return this.port;
}
public DeviceId bridgeId() {
return this.bridgeId;
}
}
}
......
......@@ -20,11 +20,6 @@ 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.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipEvent;
import org.onosproject.cluster.LeadershipEventListener;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
import org.onosproject.net.config.ConfigFactory;
......@@ -35,7 +30,6 @@ import org.onosproject.net.config.NetworkConfigService;
import org.onosproject.net.config.basics.SubjectFactories;
import org.slf4j.Logger;
import static org.onosproject.cordvtn.OvsdbNode.State.INIT;
import static org.slf4j.LoggerFactory.getLogger;
/**
......@@ -58,12 +52,6 @@ public class CordVtnConfigManager {
protected NetworkConfigService configService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected LeadershipService leadershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected CordVtnService cordVtnService;
private final ConfigFactory configFactory =
......@@ -74,29 +62,22 @@ public class CordVtnConfigManager {
}
};
private final LeadershipEventListener leadershipListener = new InternalLeadershipListener();
private final NetworkConfigListener configListener = new InternalConfigListener();
private NodeId local;
private ApplicationId appId;
@Activate
protected void active() {
local = clusterService.getLocalNode().id();
appId = coreService.getAppId(CordVtnService.CORDVTN_APP_ID);
configService.addListener(configListener);
configRegistry.registerConfigFactory(configFactory);
leadershipService.addListener(leadershipListener);
leadershipService.runForLeadership(CordVtnService.CORDVTN_APP_ID);
readConfiguration();
}
@Deactivate
protected void deactivate() {
leadershipService.removeListener(leadershipListener);
leadershipService.withdraw(appId.name());
configRegistry.unregisterConfigFactory(configFactory);
configService.removeListener(configListener);
}
......@@ -110,30 +91,13 @@ public class CordVtnConfigManager {
}
config.ovsdbNodes().forEach(node -> {
DefaultOvsdbNode ovsdbNode =
new DefaultOvsdbNode(node.host(), node.ip(), node.port(), INIT);
cordVtnService.addNode(ovsdbNode);
log.info("Add new node {}", node.host());
DefaultOvsdbNode ovsdb = new DefaultOvsdbNode(
node.host(), node.ip(), node.port(), node.bridgeId());
cordVtnService.addNode(ovsdb);
cordVtnService.connect(ovsdb);
});
}
private synchronized void processLeadershipChange(NodeId leader) {
if (leader == null || !leader.equals(local)) {
return;
}
readConfiguration();
}
private class InternalLeadershipListener implements LeadershipEventListener {
@Override
public void event(LeadershipEvent event) {
if (event.subject().topic().equals(appId.name())) {
processLeadershipChange(event.subject().leader());
}
}
}
private class InternalConfigListener implements NetworkConfigListener {
@Override
......
......@@ -15,7 +15,6 @@
*/
package org.onosproject.cordvtn;
import org.onosproject.cordvtn.OvsdbNode.State;
import org.onosproject.net.DeviceId;
import java.util.List;
......@@ -29,25 +28,30 @@ public interface CordVtnService {
/**
* Adds a new node to the service.
*
* @param ovsdbNode ovsdb node
* @param ovsdb ovsdb node
*/
void addNode(OvsdbNode ovsdbNode);
void addNode(OvsdbNode ovsdb);
/**
* Deletes a node from the service.
*
* @param ovsdbNode ovsdb node
* @param ovsdb ovsdb node
*/
void deleteNode(OvsdbNode ovsdbNode);
void deleteNode(OvsdbNode ovsdb);
/**
* Updates ovsdb node.
* It only used for updating node's connection state.
* Connect to a node.
*
* @param ovsdbNode ovsdb node
* @param state ovsdb connection state
* @param ovsdb ovsdb node
*/
void updateNode(OvsdbNode ovsdbNode, State state);
void connect(OvsdbNode ovsdb);
/**
* Disconnect a node.
*
* @param ovsdb ovsdb node
*/
void disconnect(OvsdbNode ovsdb);
/**
* Returns the number of the nodes known to the service.
......@@ -65,6 +69,14 @@ public interface CordVtnService {
OvsdbNode getNode(DeviceId deviceId);
/**
* Returns connection state of the node.
*
* @param ovsdb ovsdb node
* @return true if the node is connected, false otherwise
*/
boolean isNodeConnected(OvsdbNode ovsdb);
/**
* Returns all nodes known to the service.
*
* @return list of nodes
......
......@@ -30,13 +30,13 @@ public class DefaultOvsdbNode implements OvsdbNode {
private final String host;
private final IpAddress ip;
private final TpPort port;
private final State state;
private final DeviceId brId;
public DefaultOvsdbNode(String host, IpAddress ip, TpPort port, State state) {
public DefaultOvsdbNode(String host, IpAddress ip, TpPort port, DeviceId brId) {
this.host = host;
this.ip = ip;
this.port = port;
this.state = state;
this.brId = brId;
}
@Override
......@@ -55,8 +55,8 @@ public class DefaultOvsdbNode implements OvsdbNode {
}
@Override
public State state() {
return this.state;
public DeviceId intBrId() {
return this.brId;
}
@Override
......@@ -65,11 +65,6 @@ public class DefaultOvsdbNode implements OvsdbNode {
}
@Override
public DeviceId intBrId() {
return DeviceId.deviceId("of:" + this.host);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
......@@ -79,7 +74,8 @@ public class DefaultOvsdbNode implements OvsdbNode {
DefaultOvsdbNode that = (DefaultOvsdbNode) o;
if (this.host.equals(that.host) &&
this.ip.equals(that.ip) &&
this.port.equals(that.port)) {
this.port.equals(that.port) &&
this.brId.equals(that.brId)) {
return true;
}
}
......@@ -97,7 +93,7 @@ public class DefaultOvsdbNode implements OvsdbNode {
.add("host", host)
.add("ip", ip)
.add("port", port)
.add("state", state)
.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.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.onosproject.cluster.ClusterService;
import org.onosproject.cluster.LeadershipService;
import org.onosproject.cluster.NodeId;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.device.DeviceEvent;
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.slf4j.Logger;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.onlab.util.Tools.groupedThreads;
import static org.onosproject.cordvtn.OvsdbNode.State.CONNECTED;
import static org.onosproject.cordvtn.OvsdbNode.State.DISCONNECTED;
import static org.onosproject.cordvtn.OvsdbNode.State.READY;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Provides the connection state management of all nodes registered to the service
* so that the nodes keep connected unless it is requested to be deleted.
*/
@Component(immediate = true)
public class NodeConnectionManager {
protected final Logger log = getLogger(getClass());
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
MastershipService mastershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
LeadershipService leadershipService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
ClusterService clusterService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
DeviceService deviceService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
CordVtnService cordVtnService;
private static final int DELAY_SEC = 5;
private final DeviceListener deviceListener = new InternalDeviceListener();
private final ScheduledExecutorService connectionExecutor = Executors
.newSingleThreadScheduledExecutor(groupedThreads("onos/cordvtn", "connection-manager"));
private NodeId localId;
@Activate
protected void activate() {
localId = clusterService.getLocalNode().id();
deviceService.addListener(deviceListener);
connectionExecutor.scheduleWithFixedDelay(() -> cordVtnService.getNodes()
.stream()
.filter(node -> localId.equals(getMaster(node)))
.forEach(node -> {
connect(node);
disconnect(node);
}), 0, DELAY_SEC, TimeUnit.SECONDS);
}
@Deactivate
public void stop() {
connectionExecutor.shutdown();
deviceService.removeListener(deviceListener);
}
public void connect(OvsdbNode ovsdbNode) {
switch (ovsdbNode.state()) {
case INIT:
case DISCONNECTED:
setPassiveMode(ovsdbNode);
case READY:
setupConnection(ovsdbNode);
break;
default:
break;
}
}
public void disconnect(OvsdbNode ovsdbNode) {
switch (ovsdbNode.state()) {
case DISCONNECT:
// TODO: disconnect
break;
default:
break;
}
}
private class InternalDeviceListener implements DeviceListener {
@Override
public void event(DeviceEvent event) {
Device device = event.subject();
if (device.type() != Device.Type.CONTROLLER) {
return;
}
DefaultOvsdbNode node;
switch (event.type()) {
case DEVICE_ADDED:
node = (DefaultOvsdbNode) cordVtnService.getNode(device.id());
if (node != null) {
cordVtnService.updateNode(node, CONNECTED);
}
break;
case DEVICE_AVAILABILITY_CHANGED:
node = (DefaultOvsdbNode) cordVtnService.getNode(device.id());
if (node != null) {
cordVtnService.updateNode(node, DISCONNECTED);
}
break;
default:
break;
}
}
}
private NodeId getMaster(OvsdbNode ovsdbNode) {
NodeId master = mastershipService.getMasterFor(ovsdbNode.intBrId());
// master is null if there's no such device
if (master == null) {
master = leadershipService.getLeader(CordVtnService.CORDVTN_APP_ID);
}
return master;
}
private void setPassiveMode(OvsdbNode ovsdbNode) {
// TODO: need ovsdb client implementation first
// TODO: set the remove ovsdb server passive mode
cordVtnService.updateNode(ovsdbNode, READY);
}
private void setupConnection(OvsdbNode ovsdbNode) {
// TODO initiate connection
}
}
......@@ -23,12 +23,6 @@ import org.onosproject.net.DeviceId;
* Representation of a node with ovsdb server.
*/
public interface OvsdbNode {
/**
* Ovsdb connection state.
*/
enum State {
INIT, READY, CONNECTED, DISCONNECT, DISCONNECTED
}
/**
* Returns the IP address of the ovsdb server.
......@@ -53,13 +47,6 @@ public interface OvsdbNode {
String host();
/**
* Returns the connection state of the ovsdb server.
*
* @return connection state
*/
State state();
/**
* Returns the device id of the ovsdb server.
*
* @return device id
......