blob: 4b28a14b63190dc65b759fe9eaff3f1d6d4eba10 [file] [log] [blame]
Hyunsun Moond0e932a2015-09-15 22:39:16 -07001/*
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 */
16package org.onosproject.cordvtn;
17
Hyunsun Moon1f145552015-10-08 22:25:30 -070018import com.google.common.collect.Collections2;
19import com.google.common.collect.Sets;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070020import org.apache.felix.scr.annotations.Activate;
21import org.apache.felix.scr.annotations.Component;
22import org.apache.felix.scr.annotations.Deactivate;
23import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
25import org.apache.felix.scr.annotations.Service;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070026import org.onlab.util.KryoNamespace;
Hyunsun Moon1f145552015-10-08 22:25:30 -070027import org.onosproject.cluster.ClusterService;
28import org.onosproject.core.ApplicationId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070029import org.onosproject.core.CoreService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070030import org.onosproject.net.Device;
31import org.onosproject.net.DeviceId;
32import org.onosproject.net.Host;
Hyunsun Moon1f145552015-10-08 22:25:30 -070033import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070034import org.onosproject.net.device.DeviceEvent;
35import org.onosproject.net.device.DeviceListener;
36import org.onosproject.net.device.DeviceService;
37import org.onosproject.net.host.HostEvent;
38import org.onosproject.net.host.HostListener;
39import org.onosproject.net.host.HostService;
Hyunsun Moon1f145552015-10-08 22:25:30 -070040import org.onosproject.ovsdb.controller.OvsdbClientService;
41import org.onosproject.ovsdb.controller.OvsdbController;
42import org.onosproject.ovsdb.controller.OvsdbNodeId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070043import org.onosproject.store.serializers.KryoNamespaces;
Hyunsun Moon1f145552015-10-08 22:25:30 -070044import org.onosproject.store.service.ConsistentMap;
45import org.onosproject.store.service.Serializer;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070046import org.onosproject.store.service.StorageService;
Hyunsun Moon1f145552015-10-08 22:25:30 -070047import org.onosproject.store.service.Versioned;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070048import org.slf4j.Logger;
49
Hyunsun Moon1f145552015-10-08 22:25:30 -070050import java.util.ArrayList;
51import java.util.HashMap;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070052import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070053import java.util.Map;
Hyunsun Moon523d9762015-10-19 12:38:21 -070054import java.util.NoSuchElementException;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070055import java.util.concurrent.ExecutorService;
56import java.util.concurrent.Executors;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070057
Hyunsun Moon1f145552015-10-08 22:25:30 -070058import static com.google.common.base.Preconditions.checkNotNull;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070059import static org.onlab.util.Tools.groupedThreads;
Hyunsun Moon2b530322015-09-23 13:24:35 -070060import static org.onosproject.net.Device.Type.SWITCH;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070061import static org.slf4j.LoggerFactory.getLogger;
62
63/**
Hyunsun Moon2b530322015-09-23 13:24:35 -070064 * Provides initial setup or cleanup for provisioning virtual tenant networks
65 * on ovsdb, integration bridge and vm when they are added or deleted.
Hyunsun Moond0e932a2015-09-15 22:39:16 -070066 */
67@Component(immediate = true)
68@Service
69public class CordVtn implements CordVtnService {
70
71 protected final Logger log = getLogger(getClass());
72
Hyunsun Moon2b530322015-09-23 13:24:35 -070073 private static final int NUM_THREADS = 1;
74 private static final KryoNamespace.Builder NODE_SERIALIZER = KryoNamespace.newBuilder()
75 .register(KryoNamespaces.API)
Hyunsun Moon1f145552015-10-08 22:25:30 -070076 .register(DefaultOvsdbNode.class);
77 private static final String DEFAULT_BRIDGE_NAME = "br-int";
Hyunsun Moon523d9762015-10-19 12:38:21 -070078 private static final String DEFAULT_TUNNEL = "vxlan";
79 private static final Map<String, String> DEFAULT_TUNNEL_OPTIONS = new HashMap<String, String>() {
Hyunsun Moon1f145552015-10-08 22:25:30 -070080 {
81 put("key", "flow");
82 put("local_ip", "flow");
83 put("remote_ip", "flow");
84 }
85 };
86 private static final int DPID_BEGIN = 3;
87 private static final int OFPORT = 6653;
Hyunsun Moon2b530322015-09-23 13:24:35 -070088
Hyunsun Moond0e932a2015-09-15 22:39:16 -070089 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected CoreService coreService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected StorageService storageService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -070096 protected DeviceService deviceService;
97
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected HostService hostService;
100
Hyunsun Moon1f145552015-10-08 22:25:30 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moon1f145552015-10-08 22:25:30 -0700102 protected OvsdbController controller;
103
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected ClusterService clusterService;
106
Hyunsun Moon2b530322015-09-23 13:24:35 -0700107 private final ExecutorService eventExecutor = Executors
108 .newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700109
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700110 private final DeviceListener deviceListener = new InternalDeviceListener();
111 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700112
113 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700114 private final BridgeHandler bridgeHandler = new BridgeHandler();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700115 private final VmHandler vmHandler = new VmHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700116
Hyunsun Moon1f145552015-10-08 22:25:30 -0700117 private ConsistentMap<DeviceId, OvsdbNode> nodeStore;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700118
119 @Activate
120 protected void activate() {
Hyunsun Moon523d9762015-10-19 12:38:21 -0700121 ApplicationId appId = coreService.registerApplication("org.onosproject.cordvtn");
Hyunsun Moon1f145552015-10-08 22:25:30 -0700122 nodeStore = storageService.<DeviceId, OvsdbNode>consistentMapBuilder()
123 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700124 .withName("cordvtn-nodestore")
Hyunsun Moon1f145552015-10-08 22:25:30 -0700125 .withApplicationId(appId)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700126 .build();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700127
128 deviceService.addListener(deviceListener);
129 hostService.addListener(hostListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700130
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700131 log.info("Started");
132 }
133
134 @Deactivate
135 protected void deactivate() {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700136 deviceService.removeListener(deviceListener);
137 hostService.removeListener(hostListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700138
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700139 eventExecutor.shutdown();
Hyunsun Moon1f145552015-10-08 22:25:30 -0700140 nodeStore.clear();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700141
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700142 log.info("Stopped");
143 }
144
145 @Override
Hyunsun Moon1f145552015-10-08 22:25:30 -0700146 public void addNode(OvsdbNode ovsdb) {
147 checkNotNull(ovsdb);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700148
Hyunsun Moonc10f7772015-10-20 13:58:02 -0700149 nodeStore.putIfAbsent(ovsdb.deviceId(), ovsdb);
Hyunsun Moon523d9762015-10-19 12:38:21 -0700150
151 if (isNodeConnected(ovsdb)) {
152 init(ovsdb);
153 } else {
154 connect(ovsdb);
155 }
Hyunsun Moon1f145552015-10-08 22:25:30 -0700156 }
157
158 @Override
159 public void deleteNode(OvsdbNode ovsdb) {
160 checkNotNull(ovsdb);
161
Hyunsun Moon523d9762015-10-19 12:38:21 -0700162 if (deviceService.getDevice(ovsdb.deviceId()) != null) {
163 if (deviceService.isAvailable(ovsdb.deviceId())) {
164 log.warn("Cannot delete connected node {}", ovsdb.host());
165 return;
166 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700167 }
Hyunsun Moon523d9762015-10-19 12:38:21 -0700168 nodeStore.remove(ovsdb.deviceId());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700169 }
170
171 @Override
Hyunsun Moon1f145552015-10-08 22:25:30 -0700172 public void connect(OvsdbNode ovsdb) {
173 checkNotNull(ovsdb);
174
175 if (!nodeStore.containsKey(ovsdb.deviceId())) {
176 log.warn("Node {} does not exist", ovsdb.host());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700177 return;
178 }
Hyunsun Moon523d9762015-10-19 12:38:21 -0700179
180 if (!isNodeConnected(ovsdb)) {
181 controller.connect(ovsdb.ip(), ovsdb.port());
182 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700183 }
184
185 @Override
Hyunsun Moon1f145552015-10-08 22:25:30 -0700186 public void disconnect(OvsdbNode ovsdb) {
187 checkNotNull(ovsdb);
188
189 if (!nodeStore.containsKey(ovsdb.deviceId())) {
190 log.warn("Node {} does not exist", ovsdb.host());
Hyunsun Moon2b530322015-09-23 13:24:35 -0700191 return;
192 }
Hyunsun Moon1f145552015-10-08 22:25:30 -0700193
Hyunsun Moon523d9762015-10-19 12:38:21 -0700194 if (isNodeConnected(ovsdb)) {
195 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700196 ovsdbClient.disconnect();
197 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700198 }
199
Hyunsun Moon523d9762015-10-19 12:38:21 -0700200 private void init(OvsdbNode ovsdb) {
201 checkNotNull(ovsdb);
202
203 if (!nodeStore.containsKey(ovsdb.deviceId())) {
204 log.warn("Node {} does not exist", ovsdb.host());
205 return;
206 }
207
208 if (!isNodeConnected(ovsdb)) {
209 log.warn("Node {} is not connected", ovsdb.host());
210 return;
211 }
212
213 if (deviceService.getDevice(ovsdb.intBrId()) == null ||
214 !deviceService.isAvailable(ovsdb.intBrId())) {
215 createIntegrationBridge(ovsdb);
216 } else if (!checkVxlanPort(ovsdb)) {
217 createVxlanPort(ovsdb);
218 }
219 }
220
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700221 @Override
222 public int getNodeCount() {
223 return nodeStore.size();
224 }
225
226 @Override
Hyunsun Moon2b530322015-09-23 13:24:35 -0700227 public OvsdbNode getNode(DeviceId deviceId) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700228 Versioned<OvsdbNode> ovsdb = nodeStore.get(deviceId);
229 if (ovsdb != null) {
230 return ovsdb.value();
231 } else {
232 return null;
233 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700234 }
235
236 @Override
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700237 public List<OvsdbNode> getNodes() {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700238 List<OvsdbNode> ovsdbs = new ArrayList<>();
239 ovsdbs.addAll(Collections2.transform(nodeStore.values(), Versioned::value));
240 return ovsdbs;
241 }
242
243 @Override
244 public boolean isNodeConnected(OvsdbNode ovsdb) {
245 checkNotNull(ovsdb);
246
247 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
248 if (ovsdbClient == null) {
249 return false;
250 } else {
251 return ovsdbClient.isConnected();
252 }
253 }
254
255 private OvsdbClientService getOvsdbClient(OvsdbNode ovsdb) {
256 checkNotNull(ovsdb);
257
258 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
259 new OvsdbNodeId(ovsdb.ip(), ovsdb.port().toInt()));
260 if (ovsdbClient == null) {
Hyunsun Moon523d9762015-10-19 12:38:21 -0700261 log.debug("Couldn't find ovsdb client for {}", ovsdb.host());
Hyunsun Moon1f145552015-10-08 22:25:30 -0700262 }
263 return ovsdbClient;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700264 }
265
Hyunsun Moon523d9762015-10-19 12:38:21 -0700266 private void createIntegrationBridge(OvsdbNode ovsdb) {
267 List<ControllerInfo> controllers = new ArrayList<>();
268 Sets.newHashSet(clusterService.getNodes())
269 .forEach(controller -> {
270 ControllerInfo ctrlInfo = new ControllerInfo(controller.ip(), OFPORT, "tcp");
271 controllers.add(ctrlInfo);
272 });
273 String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN);
274
275 // TODO change to use bridge config
276 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
277 ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers);
278 }
279
280 private void createVxlanPort(OvsdbNode ovsdb) {
281 // TODO change to use tunnel config and tunnel description
282 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
283 ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, DEFAULT_TUNNEL,
284 DEFAULT_TUNNEL, DEFAULT_TUNNEL_OPTIONS);
285 }
286
287 private boolean checkVxlanPort(OvsdbNode ovsdb) {
288 // TODO change to use tunnel config
289 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
290 try {
291 ovsdbClient.getPorts().stream()
292 .filter(p -> p.portName().value().equals(DEFAULT_TUNNEL))
293 .findFirst().get();
294 } catch (NoSuchElementException e) {
295 return false;
296 }
297 return true;
298 }
299
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700300 private class InternalDeviceListener implements DeviceListener {
301
302 @Override
303 public void event(DeviceEvent event) {
304 Device device = event.subject();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700305 ConnectionHandler handler = (device.type() == SWITCH ? bridgeHandler : ovsdbHandler);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700306
307 switch (event.type()) {
Hyunsun Moon2b530322015-09-23 13:24:35 -0700308 case DEVICE_ADDED:
309 eventExecutor.submit(() -> handler.connected(device));
310 break;
311 case DEVICE_AVAILABILITY_CHANGED:
Hyunsun Moon523d9762015-10-19 12:38:21 -0700312 if (deviceService.isAvailable(device.id())) {
313 eventExecutor.submit(() -> handler.connected(device));
314 } else {
315 eventExecutor.submit(() -> handler.disconnected(device));
316 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700317 break;
318 default:
319 break;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700320 }
321 }
322 }
323
324 private class InternalHostListener implements HostListener {
325
326 @Override
327 public void event(HostEvent event) {
328 Host vm = event.subject();
329
330 switch (event.type()) {
331 case HOST_ADDED:
332 eventExecutor.submit(() -> vmHandler.connected(vm));
333 break;
334 case HOST_REMOVED:
335 eventExecutor.submit(() -> vmHandler.disconnected(vm));
336 break;
337 default:
338 break;
339 }
340 }
341 }
342
Hyunsun Moon2b530322015-09-23 13:24:35 -0700343 private class OvsdbHandler implements ConnectionHandler<Device> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700344
345 @Override
346 public void connected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700347 log.info("Ovsdb {} is connected", device.id());
348
Hyunsun Moon1f145552015-10-08 22:25:30 -0700349 OvsdbNode ovsdb = getNode(device.id());
Hyunsun Moon523d9762015-10-19 12:38:21 -0700350 if (ovsdb != null) {
351 init(ovsdb);
352 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700353 }
354
355 @Override
356 public void disconnected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700357 log.warn("Ovsdb {} is disconnected", device.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700358 }
359 }
360
361 private class BridgeHandler implements ConnectionHandler<Device> {
362
363 @Override
364 public void connected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700365 log.info("Integration Bridge {} is detected", device.id());
366
Hyunsun Moon523d9762015-10-19 12:38:21 -0700367 OvsdbNode ovsdb;
368 try {
369 ovsdb = getNodes().stream()
370 .filter(node -> node.intBrId().equals(device.id()))
371 .findFirst().get();
372 } catch (NoSuchElementException e) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700373 log.warn("Couldn't find OVSDB associated with {}", device.id());
374 return;
375 }
376
Hyunsun Moon523d9762015-10-19 12:38:21 -0700377 if (!checkVxlanPort(ovsdb)) {
378 createVxlanPort(ovsdb);
Hyunsun Moon1f145552015-10-08 22:25:30 -0700379 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700380 }
381
382 @Override
383 public void disconnected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700384 log.info("Integration Bridge {} is vanished", device.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700385 }
386 }
387
Hyunsun Moon2b530322015-09-23 13:24:35 -0700388 private class VmHandler implements ConnectionHandler<Host> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700389
390 @Override
391 public void connected(Host host) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700392 log.info("VM {} is detected", host.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700393 }
394
395 @Override
396 public void disconnected(Host host) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700397 log.info("VM {} is vanished", host.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700398 }
399 }
400}