Committed by
Gerrit Code Review
CORD-151 add initial skeleton for cord-vtn application
Change-Id: I57bf17445f1e571b51bca2fe7c2631e65cd43145
Showing
8 changed files
with
726 additions
and
34 deletions
| ... | @@ -36,6 +36,19 @@ | ... | @@ -36,6 +36,19 @@ |
| 36 | </properties> | 36 | </properties> |
| 37 | 37 | ||
| 38 | <dependencies> | 38 | <dependencies> |
| 39 | + <dependency> | ||
| 40 | + <groupId>org.osgi</groupId> | ||
| 41 | + <artifactId>org.osgi.compendium</artifactId> | ||
| 42 | + </dependency> | ||
| 43 | + <dependency> | ||
| 44 | + <groupId>org.onosproject</groupId> | ||
| 45 | + <artifactId>onos-api</artifactId> | ||
| 46 | + </dependency> | ||
| 47 | + <dependency> | ||
| 48 | + <groupId>org.onosproject</groupId> | ||
| 49 | + <artifactId>onos-core-serializers</artifactId> | ||
| 50 | + <version>${project.version}</version> | ||
| 51 | + </dependency> | ||
| 39 | </dependencies> | 52 | </dependencies> |
| 40 | 53 | ||
| 41 | </project> | 54 | </project> | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.cordvtn; | ||
| 17 | + | ||
| 18 | +/** | ||
| 19 | + * Entity capable of handling a subject connected and disconnected situation. | ||
| 20 | + */ | ||
| 21 | +public interface ConnectionHandler<T> { | ||
| 22 | + | ||
| 23 | + /** | ||
| 24 | + * Processes the connected subject. | ||
| 25 | + * | ||
| 26 | + * @param subject subject | ||
| 27 | + */ | ||
| 28 | + void connected(T subject); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * Processes the disconnected subject. | ||
| 32 | + * | ||
| 33 | + * @param subject subject. | ||
| 34 | + */ | ||
| 35 | + void disconnected(T subject); | ||
| 36 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.cordvtn; | ||
| 17 | + | ||
| 18 | +import org.apache.felix.scr.annotations.Activate; | ||
| 19 | +import org.apache.felix.scr.annotations.Component; | ||
| 20 | +import org.apache.felix.scr.annotations.Deactivate; | ||
| 21 | +import org.apache.felix.scr.annotations.Reference; | ||
| 22 | +import org.apache.felix.scr.annotations.ReferenceCardinality; | ||
| 23 | +import org.apache.felix.scr.annotations.Service; | ||
| 24 | +import org.onlab.packet.IpAddress; | ||
| 25 | +import org.onlab.packet.TpPort; | ||
| 26 | +import org.onlab.util.KryoNamespace; | ||
| 27 | +import org.onosproject.cluster.ClusterService; | ||
| 28 | +import org.onosproject.cluster.LeadershipEvent; | ||
| 29 | +import org.onosproject.cluster.LeadershipEventListener; | ||
| 30 | +import org.onosproject.cluster.LeadershipService; | ||
| 31 | +import org.onosproject.cluster.NodeId; | ||
| 32 | +import org.onosproject.core.ApplicationId; | ||
| 33 | +import org.onosproject.core.CoreService; | ||
| 34 | +import org.onosproject.mastership.MastershipService; | ||
| 35 | +import org.onosproject.net.Device; | ||
| 36 | +import org.onosproject.net.DeviceId; | ||
| 37 | +import org.onosproject.net.Host; | ||
| 38 | +import org.onosproject.net.config.ConfigFactory; | ||
| 39 | +import org.onosproject.net.config.NetworkConfigRegistry; | ||
| 40 | +import org.onosproject.net.config.NetworkConfigService; | ||
| 41 | +import org.onosproject.net.config.basics.SubjectFactories; | ||
| 42 | +import org.onosproject.net.device.DeviceEvent; | ||
| 43 | +import org.onosproject.net.device.DeviceListener; | ||
| 44 | +import org.onosproject.net.device.DeviceService; | ||
| 45 | +import org.onosproject.net.host.HostEvent; | ||
| 46 | +import org.onosproject.net.host.HostListener; | ||
| 47 | +import org.onosproject.net.host.HostService; | ||
| 48 | +import org.onosproject.store.serializers.KryoNamespaces; | ||
| 49 | +import org.onosproject.store.service.EventuallyConsistentMap; | ||
| 50 | +import org.onosproject.store.service.LogicalClockService; | ||
| 51 | +import org.onosproject.store.service.StorageService; | ||
| 52 | +import org.slf4j.Logger; | ||
| 53 | + | ||
| 54 | +import java.util.List; | ||
| 55 | +import java.util.concurrent.ExecutorService; | ||
| 56 | +import java.util.concurrent.Executors; | ||
| 57 | +import java.util.stream.Collectors; | ||
| 58 | + | ||
| 59 | +import static org.onlab.util.Tools.groupedThreads; | ||
| 60 | +import static org.onosproject.cordvtn.OvsdbNode.State.INIT; | ||
| 61 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 62 | + | ||
| 63 | +/** | ||
| 64 | + * CORD VTN Application that provisions overlay virtual tenant networks. | ||
| 65 | + */ | ||
| 66 | +@Component(immediate = true) | ||
| 67 | +@Service | ||
| 68 | +public class CordVtn implements CordVtnService { | ||
| 69 | + | ||
| 70 | + protected final Logger log = getLogger(getClass()); | ||
| 71 | + | ||
| 72 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 73 | + protected CoreService coreService; | ||
| 74 | + | ||
| 75 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 76 | + protected StorageService storageService; | ||
| 77 | + | ||
| 78 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 79 | + protected LogicalClockService clockService; | ||
| 80 | + | ||
| 81 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 82 | + protected ClusterService clusterService; | ||
| 83 | + | ||
| 84 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 85 | + protected LeadershipService leadershipService; | ||
| 86 | + | ||
| 87 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 88 | + protected NetworkConfigService configService; | ||
| 89 | + | ||
| 90 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 91 | + protected NetworkConfigRegistry configRegistry; | ||
| 92 | + | ||
| 93 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 94 | + protected DeviceService deviceService; | ||
| 95 | + | ||
| 96 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 97 | + protected HostService hostService; | ||
| 98 | + | ||
| 99 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
| 100 | + protected MastershipService mastershipService; | ||
| 101 | + | ||
| 102 | + private static final int DEFAULT_NUM_THREADS = 1; | ||
| 103 | + private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder() | ||
| 104 | + .register(KryoNamespaces.API) | ||
| 105 | + .register(OvsdbNode.class); | ||
| 106 | + | ||
| 107 | + private final ExecutorService eventExecutor = Executors.newFixedThreadPool( | ||
| 108 | + DEFAULT_NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler")); | ||
| 109 | + | ||
| 110 | + private final LeadershipEventListener leadershipListener = new InternalLeadershipListener(); | ||
| 111 | + private final DeviceListener deviceListener = new InternalDeviceListener(); | ||
| 112 | + private final HostListener hostListener = new InternalHostListener(); | ||
| 113 | + private final NodeHandler nodeHandler = new NodeHandler(); | ||
| 114 | + private final BridgeHandler bridgeHandler = new BridgeHandler(); | ||
| 115 | + private final VirtualMachineHandler vmHandler = new VirtualMachineHandler(); | ||
| 116 | + | ||
| 117 | + private final ConfigFactory configFactory = | ||
| 118 | + new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, CordVtnConfig.class, "cordvtn") { | ||
| 119 | + @Override | ||
| 120 | + public CordVtnConfig createConfig() { | ||
| 121 | + return new CordVtnConfig(); | ||
| 122 | + } | ||
| 123 | + }; | ||
| 124 | + | ||
| 125 | + private ApplicationId appId; | ||
| 126 | + private NodeId local; | ||
| 127 | + private EventuallyConsistentMap<DeviceId, OvsdbNode> nodeStore; | ||
| 128 | + private NodeConnectionManager nodeConnectionManager; | ||
| 129 | + | ||
| 130 | + @Activate | ||
| 131 | + protected void activate() { | ||
| 132 | + appId = coreService.registerApplication("org.onosproject.cordvtn"); | ||
| 133 | + | ||
| 134 | + local = clusterService.getLocalNode().id(); | ||
| 135 | + nodeStore = storageService.<DeviceId, OvsdbNode>eventuallyConsistentMapBuilder() | ||
| 136 | + .withName("cordvtn-nodestore") | ||
| 137 | + .withSerializer(NODE_SERIALIZER) | ||
| 138 | + .withTimestampProvider((k, v) -> clockService.getTimestamp()) | ||
| 139 | + .build(); | ||
| 140 | + configRegistry.registerConfigFactory(configFactory); | ||
| 141 | + | ||
| 142 | + deviceService.addListener(deviceListener); | ||
| 143 | + hostService.addListener(hostListener); | ||
| 144 | + leadershipService.addListener(leadershipListener); | ||
| 145 | + leadershipService.runForLeadership(appId.name()); | ||
| 146 | + nodeConnectionManager = new NodeConnectionManager(appId, local, nodeStore, | ||
| 147 | + mastershipService, leadershipService); | ||
| 148 | + nodeConnectionManager.start(); | ||
| 149 | + log.info("Started"); | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + @Deactivate | ||
| 153 | + protected void deactivate() { | ||
| 154 | + nodeConnectionManager.stop(); | ||
| 155 | + leadershipService.removeListener(leadershipListener); | ||
| 156 | + leadershipService.withdraw(appId.name()); | ||
| 157 | + deviceService.removeListener(deviceListener); | ||
| 158 | + hostService.removeListener(hostListener); | ||
| 159 | + eventExecutor.shutdown(); | ||
| 160 | + nodeStore.destroy(); | ||
| 161 | + configRegistry.unregisterConfigFactory(configFactory); | ||
| 162 | + log.info("Stopped"); | ||
| 163 | + } | ||
| 164 | + | ||
| 165 | + @Override | ||
| 166 | + public void addNode(String hostname, IpAddress ip, TpPort port) { | ||
| 167 | + DefaultOvsdbNode node = new DefaultOvsdbNode(hostname, ip, port, DeviceId.NONE, INIT); | ||
| 168 | + | ||
| 169 | + if (nodeStore.containsKey(node.deviceId())) { | ||
| 170 | + log.warn("Node {} with ovsdb-server {}:{} already exists", hostname, ip, port); | ||
| 171 | + return; | ||
| 172 | + } | ||
| 173 | + nodeStore.put(node.deviceId(), node); | ||
| 174 | + log.info("New node {} with ovsdb-server {}:{} has been added", hostname, ip, port); | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + @Override | ||
| 178 | + public void deleteNode(IpAddress ip, TpPort port) { | ||
| 179 | + DeviceId deviceId = DeviceId.deviceId("ovsdb:" + ip + ":" + port); | ||
| 180 | + OvsdbNode node = nodeStore.get(deviceId); | ||
| 181 | + | ||
| 182 | + if (node == null) { | ||
| 183 | + log.warn("Node with ovsdb-server on {}:{} does not exist", ip, port); | ||
| 184 | + return; | ||
| 185 | + } | ||
| 186 | + nodeConnectionManager.disconnectNode(node); | ||
| 187 | + nodeStore.remove(node.deviceId()); | ||
| 188 | + } | ||
| 189 | + | ||
| 190 | + @Override | ||
| 191 | + public int getNodeCount() { | ||
| 192 | + return nodeStore.size(); | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + @Override | ||
| 196 | + public List<OvsdbNode> getNodes() { | ||
| 197 | + return nodeStore.values() | ||
| 198 | + .stream() | ||
| 199 | + .collect(Collectors.toList()); | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + private void initialSetup() { | ||
| 203 | + // Read ovsdb nodes from network config | ||
| 204 | + CordVtnConfig config = configService.getConfig(appId, CordVtnConfig.class); | ||
| 205 | + if (config == null) { | ||
| 206 | + log.warn("No configuration found"); | ||
| 207 | + return; | ||
| 208 | + } | ||
| 209 | + config.ovsdbNodes().forEach( | ||
| 210 | + node -> addNode(node.hostname(), node.ip(), node.port())); | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + private synchronized void processLeadershipChange(NodeId leader) { | ||
| 214 | + // Only the leader performs the initial setup | ||
| 215 | + if (leader == null || !leader.equals(local)) { | ||
| 216 | + return; | ||
| 217 | + } | ||
| 218 | + initialSetup(); | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + private class InternalLeadershipListener implements LeadershipEventListener { | ||
| 222 | + | ||
| 223 | + @Override | ||
| 224 | + public void event(LeadershipEvent event) { | ||
| 225 | + if (event.subject().topic().equals(appId.name())) { | ||
| 226 | + processLeadershipChange(event.subject().leader()); | ||
| 227 | + } | ||
| 228 | + } | ||
| 229 | + } | ||
| 230 | + | ||
| 231 | + private class InternalDeviceListener implements DeviceListener { | ||
| 232 | + | ||
| 233 | + @Override | ||
| 234 | + public void event(DeviceEvent event) { | ||
| 235 | + Device device = event.subject(); | ||
| 236 | + ConnectionHandler handler = | ||
| 237 | + (device.type() == Device.Type.CONTROLLER ? nodeHandler : bridgeHandler); | ||
| 238 | + | ||
| 239 | + switch (event.type()) { | ||
| 240 | + case DEVICE_ADDED: | ||
| 241 | + eventExecutor.submit(() -> handler.connected(device)); | ||
| 242 | + break; | ||
| 243 | + case DEVICE_AVAILABILITY_CHANGED: | ||
| 244 | + eventExecutor.submit(() -> handler.disconnected(device)); | ||
| 245 | + break; | ||
| 246 | + default: | ||
| 247 | + break; | ||
| 248 | + } | ||
| 249 | + } | ||
| 250 | + } | ||
| 251 | + | ||
| 252 | + private class InternalHostListener implements HostListener { | ||
| 253 | + | ||
| 254 | + @Override | ||
| 255 | + public void event(HostEvent event) { | ||
| 256 | + Host vm = event.subject(); | ||
| 257 | + | ||
| 258 | + switch (event.type()) { | ||
| 259 | + case HOST_ADDED: | ||
| 260 | + eventExecutor.submit(() -> vmHandler.connected(vm)); | ||
| 261 | + break; | ||
| 262 | + case HOST_REMOVED: | ||
| 263 | + eventExecutor.submit(() -> vmHandler.disconnected(vm)); | ||
| 264 | + break; | ||
| 265 | + default: | ||
| 266 | + break; | ||
| 267 | + } | ||
| 268 | + } | ||
| 269 | + } | ||
| 270 | + | ||
| 271 | + private class NodeHandler implements ConnectionHandler<Device> { | ||
| 272 | + | ||
| 273 | + @Override | ||
| 274 | + public void connected(Device device) { | ||
| 275 | + // create bridge and set bridgeId | ||
| 276 | + // set node state connected | ||
| 277 | + } | ||
| 278 | + | ||
| 279 | + @Override | ||
| 280 | + public void disconnected(Device device) { | ||
| 281 | + // set node state disconnected if the node exists | ||
| 282 | + // which means that the node is not deleted explicitly | ||
| 283 | + } | ||
| 284 | + } | ||
| 285 | + | ||
| 286 | + private class BridgeHandler implements ConnectionHandler<Device> { | ||
| 287 | + | ||
| 288 | + @Override | ||
| 289 | + public void connected(Device device) { | ||
| 290 | + // create vxlan port | ||
| 291 | + } | ||
| 292 | + | ||
| 293 | + @Override | ||
| 294 | + public void disconnected(Device device) { | ||
| 295 | + | ||
| 296 | + } | ||
| 297 | + } | ||
| 298 | + | ||
| 299 | + private class VirtualMachineHandler implements ConnectionHandler<Host> { | ||
| 300 | + | ||
| 301 | + @Override | ||
| 302 | + public void connected(Host host) { | ||
| 303 | + // install flow rules for this vm | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + @Override | ||
| 307 | + public void disconnected(Host host) { | ||
| 308 | + // uninstall flow rules associated with this vm | ||
| 309 | + } | ||
| 310 | + } | ||
| 311 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.cordvtn; | ||
| 17 | + | ||
| 18 | +import com.fasterxml.jackson.databind.JsonNode; | ||
| 19 | +import com.google.common.collect.Sets; | ||
| 20 | +import org.onlab.packet.IpAddress; | ||
| 21 | +import org.onlab.packet.TpPort; | ||
| 22 | +import org.onosproject.core.ApplicationId; | ||
| 23 | +import org.onosproject.net.config.Config; | ||
| 24 | + | ||
| 25 | +import java.util.Set; | ||
| 26 | + | ||
| 27 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
| 28 | + | ||
| 29 | +/** | ||
| 30 | + * Configuration object for CORD VTN service. | ||
| 31 | + */ | ||
| 32 | +public class CordVtnConfig extends Config<ApplicationId> { | ||
| 33 | + | ||
| 34 | + public static final String OVSDB_NODES = "ovsdbNodes"; | ||
| 35 | + public static final String HOSTNAME = "hostname"; | ||
| 36 | + public static final String IP = "ip"; | ||
| 37 | + public static final String PORT = "port"; | ||
| 38 | + | ||
| 39 | + /** | ||
| 40 | + * Returns the set of ovsdb nodes read from network config. | ||
| 41 | + * | ||
| 42 | + * @return set of OvsdbNodeConfig or null | ||
| 43 | + */ | ||
| 44 | + public Set<OvsdbNodeConfig> ovsdbNodes() { | ||
| 45 | + Set<OvsdbNodeConfig> ovsdbNodes = Sets.newHashSet(); | ||
| 46 | + | ||
| 47 | + JsonNode nodes = object.get(OVSDB_NODES); | ||
| 48 | + if (nodes == null) { | ||
| 49 | + return null; | ||
| 50 | + } | ||
| 51 | + nodes.forEach(jsonNode -> ovsdbNodes.add(new OvsdbNodeConfig( | ||
| 52 | + jsonNode.path(HOSTNAME).asText(), | ||
| 53 | + IpAddress.valueOf(jsonNode.path(IP).asText()), | ||
| 54 | + TpPort.tpPort(jsonNode.path(PORT).asInt())))); | ||
| 55 | + | ||
| 56 | + return ovsdbNodes; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + /** | ||
| 60 | + * Configuration for an OVSDB node. | ||
| 61 | + */ | ||
| 62 | + public static class OvsdbNodeConfig { | ||
| 63 | + | ||
| 64 | + private final String hostname; | ||
| 65 | + private final IpAddress ip; | ||
| 66 | + private final TpPort port; | ||
| 67 | + | ||
| 68 | + public OvsdbNodeConfig(String hostname, IpAddress ip, TpPort port) { | ||
| 69 | + this.hostname = checkNotNull(hostname); | ||
| 70 | + this.ip = checkNotNull(ip); | ||
| 71 | + this.port = checkNotNull(port); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + /** | ||
| 75 | + * Returns hostname of the node. | ||
| 76 | + * | ||
| 77 | + * @return hostname | ||
| 78 | + */ | ||
| 79 | + public String hostname() { | ||
| 80 | + return this.hostname; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + /** | ||
| 84 | + * Returns ip address to access ovsdb-server of the node. | ||
| 85 | + * | ||
| 86 | + * @return ip address | ||
| 87 | + */ | ||
| 88 | + public IpAddress ip() { | ||
| 89 | + return this.ip; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + /** | ||
| 93 | + * Returns port number to access ovsdb-server of the node. | ||
| 94 | + * | ||
| 95 | + * @return port number | ||
| 96 | + */ | ||
| 97 | + public TpPort port() { | ||
| 98 | + return this.port; | ||
| 99 | + } | ||
| 100 | + } | ||
| 101 | +} |
| ... | @@ -15,6 +15,9 @@ | ... | @@ -15,6 +15,9 @@ |
| 15 | */ | 15 | */ |
| 16 | package org.onosproject.cordvtn; | 16 | package org.onosproject.cordvtn; |
| 17 | 17 | ||
| 18 | +import org.onlab.packet.IpAddress; | ||
| 19 | +import org.onlab.packet.TpPort; | ||
| 20 | + | ||
| 18 | import java.util.List; | 21 | import java.util.List; |
| 19 | 22 | ||
| 20 | /** | 23 | /** |
| ... | @@ -22,19 +25,21 @@ import java.util.List; | ... | @@ -22,19 +25,21 @@ import java.util.List; |
| 22 | */ | 25 | */ |
| 23 | public interface CordVtnService { | 26 | public interface CordVtnService { |
| 24 | /** | 27 | /** |
| 25 | - * Adds new nodes to the service and processes initial setup. | 28 | + * Adds a new node to the service. |
| 26 | * | 29 | * |
| 27 | - * @param ovsdbNodes list of nodes | 30 | + * @param hostname hostname of the node |
| 31 | + * @param ip ip address to access the ovsdb server running on the node | ||
| 32 | + * @param port port number to access the ovsdb server running on the node | ||
| 28 | */ | 33 | */ |
| 29 | - void addNodes(List<OvsdbNode> ovsdbNodes); | 34 | + void addNode(String hostname, IpAddress ip, TpPort port); |
| 30 | 35 | ||
| 31 | /** | 36 | /** |
| 32 | - * Deletes the nodes from the service and cleans up unnecessary configurations | 37 | + * Deletes the node from the service. |
| 33 | - * associated with the deleted nodes. | ||
| 34 | * | 38 | * |
| 35 | - * @param ovsdbNodes list of nodes | 39 | + * @param ip ip address to access the ovsdb server running on the node |
| 40 | + * @param port port number to access the ovsdb server running on the node | ||
| 36 | */ | 41 | */ |
| 37 | - void deleteNodes(List<OvsdbNode> ovsdbNodes); | 42 | + void deleteNode(IpAddress ip, TpPort port); |
| 38 | 43 | ||
| 39 | /** | 44 | /** |
| 40 | * Returns the number of the nodes known to the service. | 45 | * Returns the number of the nodes known to the service. | ... | ... |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.cordvtn; | ||
| 17 | + | ||
| 18 | +import org.onlab.packet.IpAddress; | ||
| 19 | +import org.onlab.packet.TpPort; | ||
| 20 | +import org.onosproject.net.DeviceId; | ||
| 21 | + | ||
| 22 | +import java.util.Objects; | ||
| 23 | + | ||
| 24 | +/** | ||
| 25 | + * OvsdbNode implementation. | ||
| 26 | + */ | ||
| 27 | +public class DefaultOvsdbNode implements OvsdbNode { | ||
| 28 | + | ||
| 29 | + private final String hostname; | ||
| 30 | + private final IpAddress ip; | ||
| 31 | + private final TpPort port; | ||
| 32 | + private final DeviceId deviceId; | ||
| 33 | + private final DeviceId bridgeId; | ||
| 34 | + private final State state; | ||
| 35 | + | ||
| 36 | + public DefaultOvsdbNode(String hostname, IpAddress ip, TpPort port, | ||
| 37 | + DeviceId bridgeId, State state) { | ||
| 38 | + this.hostname = hostname; | ||
| 39 | + this.ip = ip; | ||
| 40 | + this.port = port; | ||
| 41 | + this.deviceId = DeviceId.deviceId( | ||
| 42 | + "ovsdb:" + ip.toString() + ":" + port.toString()); | ||
| 43 | + this.bridgeId = bridgeId; | ||
| 44 | + this.state = state; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + @Override | ||
| 48 | + public IpAddress ip() { | ||
| 49 | + return this.ip; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @Override | ||
| 53 | + public TpPort port() { | ||
| 54 | + return this.port; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + @Override | ||
| 58 | + public String hostname() { | ||
| 59 | + return this.hostname; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public State state() { | ||
| 64 | + return this.state; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + @Override | ||
| 68 | + public DeviceId deviceId() { | ||
| 69 | + return this.deviceId; | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + @Override | ||
| 73 | + public DeviceId bridgeId() { | ||
| 74 | + return this.bridgeId; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @Override | ||
| 78 | + public boolean equals(Object o) { | ||
| 79 | + if (this == o) { | ||
| 80 | + return true; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + if (o instanceof DefaultOvsdbNode) { | ||
| 84 | + DefaultOvsdbNode that = (DefaultOvsdbNode) o; | ||
| 85 | + // We compare the ip and port only. | ||
| 86 | + if (this.ip.equals(that.ip) && this.port.equals(that.port)) { | ||
| 87 | + return true; | ||
| 88 | + } | ||
| 89 | + } | ||
| 90 | + return false; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + @Override | ||
| 94 | + public int hashCode() { | ||
| 95 | + return Objects.hash(ip, port); | ||
| 96 | + } | ||
| 97 | +} |
| 1 | +/* | ||
| 2 | + * Copyright 2014-2015 Open Networking Laboratory | ||
| 3 | + * | ||
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| 5 | + * you may not use this file except in compliance with the License. | ||
| 6 | + * You may obtain a copy of the License at | ||
| 7 | + * | ||
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
| 9 | + * | ||
| 10 | + * Unless required by applicable law or agreed to in writing, software | ||
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| 13 | + * See the License for the specific language governing permissions and | ||
| 14 | + * limitations under the License. | ||
| 15 | + */ | ||
| 16 | +package org.onosproject.cordvtn; | ||
| 17 | + | ||
| 18 | +import org.onosproject.cluster.LeadershipService; | ||
| 19 | +import org.onosproject.cluster.NodeId; | ||
| 20 | +import org.onosproject.core.ApplicationId; | ||
| 21 | +import org.onosproject.mastership.MastershipService; | ||
| 22 | +import org.onosproject.net.DeviceId; | ||
| 23 | +import org.onosproject.store.service.EventuallyConsistentMap; | ||
| 24 | +import org.slf4j.Logger; | ||
| 25 | + | ||
| 26 | +import java.util.concurrent.Executors; | ||
| 27 | +import java.util.concurrent.ScheduledExecutorService; | ||
| 28 | +import java.util.concurrent.TimeUnit; | ||
| 29 | + | ||
| 30 | +import static org.onlab.util.Tools.groupedThreads; | ||
| 31 | +import static org.slf4j.LoggerFactory.getLogger; | ||
| 32 | + | ||
| 33 | +/** | ||
| 34 | + * Node connection manager. | ||
| 35 | + */ | ||
| 36 | +public class NodeConnectionManager { | ||
| 37 | + protected final Logger log = getLogger(getClass()); | ||
| 38 | + | ||
| 39 | + private final ApplicationId appId; | ||
| 40 | + private final NodeId localId; | ||
| 41 | + private final EventuallyConsistentMap<DeviceId, OvsdbNode> nodeStore; | ||
| 42 | + private final MastershipService mastershipService; | ||
| 43 | + private final LeadershipService leadershipService; | ||
| 44 | + | ||
| 45 | + private static final int DELAY_SEC = 5; | ||
| 46 | + private ScheduledExecutorService connectionExecutor; | ||
| 47 | + | ||
| 48 | + /** | ||
| 49 | + * Creates a new NodeConnectionManager. | ||
| 50 | + * | ||
| 51 | + * @param localId local id | ||
| 52 | + * @param nodeStore node store | ||
| 53 | + * @param mastershipService mastership service | ||
| 54 | + */ | ||
| 55 | + public NodeConnectionManager(ApplicationId appId, NodeId localId, | ||
| 56 | + EventuallyConsistentMap<DeviceId, OvsdbNode> nodeStore, | ||
| 57 | + MastershipService mastershipService, | ||
| 58 | + LeadershipService leadershipService) { | ||
| 59 | + this.appId = appId; | ||
| 60 | + this.localId = localId; | ||
| 61 | + this.nodeStore = nodeStore; | ||
| 62 | + this.mastershipService = mastershipService; | ||
| 63 | + this.leadershipService = leadershipService; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + /** | ||
| 67 | + * Starts the node connection manager. | ||
| 68 | + */ | ||
| 69 | + public void start() { | ||
| 70 | + connectionExecutor = Executors.newSingleThreadScheduledExecutor( | ||
| 71 | + groupedThreads("onos/cordvtn", "connection-executor")); | ||
| 72 | + connectionExecutor.scheduleWithFixedDelay(() -> nodeStore.values() | ||
| 73 | + .stream() | ||
| 74 | + .filter(node -> localId.equals(getMaster(node))) | ||
| 75 | + .forEach(node -> connectNode(node)), 0, DELAY_SEC, TimeUnit.SECONDS); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * Stops the node connection manager. | ||
| 80 | + */ | ||
| 81 | + public void stop() { | ||
| 82 | + connectionExecutor.shutdown(); | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + /** | ||
| 86 | + * Adds a new node to the system. | ||
| 87 | + * | ||
| 88 | + * @param ovsdbNode ovsdb node | ||
| 89 | + */ | ||
| 90 | + public void connectNode(OvsdbNode ovsdbNode) { | ||
| 91 | + switch (ovsdbNode.state()) { | ||
| 92 | + case INIT: | ||
| 93 | + case DISCONNECTED: | ||
| 94 | + // TODO: set the node to passive mode | ||
| 95 | + case READY: | ||
| 96 | + // TODO: initiate connection | ||
| 97 | + break; | ||
| 98 | + case CONNECTED: | ||
| 99 | + break; | ||
| 100 | + default: | ||
| 101 | + } | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + /** | ||
| 105 | + * Deletes the ovsdb node. | ||
| 106 | + * | ||
| 107 | + * @param ovsdbNode ovsdb node | ||
| 108 | + */ | ||
| 109 | + public void disconnectNode(OvsdbNode ovsdbNode) { | ||
| 110 | + switch (ovsdbNode.state()) { | ||
| 111 | + case CONNECTED: | ||
| 112 | + // TODO: disconnect | ||
| 113 | + break; | ||
| 114 | + case INIT: | ||
| 115 | + case READY: | ||
| 116 | + case DISCONNECTED: | ||
| 117 | + break; | ||
| 118 | + default: | ||
| 119 | + } | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + private NodeId getMaster(OvsdbNode ovsdbNode) { | ||
| 123 | + // Return the master of the bridge(switch) if it exist or | ||
| 124 | + // return the current leader | ||
| 125 | + if (ovsdbNode.bridgeId() == DeviceId.NONE) { | ||
| 126 | + return leadershipService.getLeader(this.appId.name()); | ||
| 127 | + } else { | ||
| 128 | + return mastershipService.getMasterFor(ovsdbNode.bridgeId()); | ||
| 129 | + } | ||
| 130 | + } | ||
| 131 | + | ||
| 132 | + private void setPassiveMode(OvsdbNode ovsdbNode) { | ||
| 133 | + // TODO: need ovsdb client implementation first | ||
| 134 | + // TODO: set the remove ovsdb server passive mode | ||
| 135 | + // TODO: set the node state READY if it succeed | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + private void connect(OvsdbNode ovsdbNode) { | ||
| 139 | + // TODO: need ovsdb client implementation first | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + private void disconnect(OvsdbNode ovsdbNode) { | ||
| 143 | + // TODO: need ovsdb client implementation first | ||
| 144 | + } | ||
| 145 | +} |
| ... | @@ -18,8 +18,6 @@ package org.onosproject.cordvtn; | ... | @@ -18,8 +18,6 @@ package org.onosproject.cordvtn; |
| 18 | import org.onlab.packet.IpAddress; | 18 | import org.onlab.packet.IpAddress; |
| 19 | import org.onlab.packet.TpPort; | 19 | import org.onlab.packet.TpPort; |
| 20 | import org.onosproject.net.DeviceId; | 20 | import org.onosproject.net.DeviceId; |
| 21 | -import org.onosproject.net.behaviour.BridgeConfig; | ||
| 22 | -import org.onosproject.net.behaviour.TunnelConfig; | ||
| 23 | 21 | ||
| 24 | /** | 22 | /** |
| 25 | * Representation of a node with ovsdb server. | 23 | * Representation of a node with ovsdb server. |
| ... | @@ -29,7 +27,7 @@ public interface OvsdbNode { | ... | @@ -29,7 +27,7 @@ public interface OvsdbNode { |
| 29 | * State of the ovsdb node. | 27 | * State of the ovsdb node. |
| 30 | */ | 28 | */ |
| 31 | enum State { | 29 | enum State { |
| 32 | - READY, CONNECTED, DISCONNECTED | 30 | + INIT, READY, CONNECTED, DISCONNECTED |
| 33 | } | 31 | } |
| 34 | 32 | ||
| 35 | /** | 33 | /** |
| ... | @@ -47,44 +45,30 @@ public interface OvsdbNode { | ... | @@ -47,44 +45,30 @@ public interface OvsdbNode { |
| 47 | TpPort port(); | 45 | TpPort port(); |
| 48 | 46 | ||
| 49 | /** | 47 | /** |
| 50 | - * Returns the state of the node. | 48 | + * Returns the hostname of the node. |
| 51 | * | 49 | * |
| 52 | - * @return state of the node | 50 | + * @return hostname |
| 53 | */ | 51 | */ |
| 54 | - State getState(); | 52 | + String hostname(); |
| 55 | 53 | ||
| 56 | /** | 54 | /** |
| 57 | - * Sets the state of the node. | 55 | + * Returns the state of the node. |
| 58 | * | 56 | * |
| 59 | - * @param state state of the node | 57 | + * @return state of the node |
| 60 | */ | 58 | */ |
| 61 | - void setState(State state); | 59 | + State state(); |
| 62 | 60 | ||
| 63 | /** | 61 | /** |
| 64 | * Returns the device ID of the node. | 62 | * Returns the device ID of the node. |
| 65 | * | 63 | * |
| 66 | * @return device id | 64 | * @return device id |
| 67 | */ | 65 | */ |
| 68 | - DeviceId getDeviceId(); | 66 | + DeviceId deviceId(); |
| 69 | 67 | ||
| 70 | /** | 68 | /** |
| 71 | - * Sets the device id of the node. | 69 | + * Returns the device ID of the bridge associated with this node. |
| 72 | * | 70 | * |
| 73 | - * @param deviceId device identifier | 71 | + * @return device id |
| 74 | - */ | ||
| 75 | - void setDeviceId(DeviceId deviceId); | ||
| 76 | - | ||
| 77 | - /** | ||
| 78 | - * Returns the bridge configuration handler of the node. | ||
| 79 | - * | ||
| 80 | - * @return bridge config behavior instance | ||
| 81 | - */ | ||
| 82 | - BridgeConfig getBridgeConfig(); | ||
| 83 | - | ||
| 84 | - /** | ||
| 85 | - * Returns the tunnel configuration handler of the node. | ||
| 86 | - * | ||
| 87 | - * @return tunnel config behavior instance | ||
| 88 | */ | 72 | */ |
| 89 | - TunnelConfig getTunnelConfig(); | 73 | + DeviceId bridgeId(); |
| 90 | } | 74 | } | ... | ... |
-
Please register or login to post a comment