blob: ba7078003b98ec5bb90747192074ab9e0b5b63ac [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 Moon1f145552015-10-08 22:25:30 -070030import org.onosproject.mastership.MastershipService;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070031import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.Host;
Hyunsun Moon1f145552015-10-08 22:25:30 -070034import org.onosproject.net.behaviour.ControllerInfo;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070035import org.onosproject.net.device.DeviceEvent;
36import org.onosproject.net.device.DeviceListener;
37import org.onosproject.net.device.DeviceService;
38import org.onosproject.net.host.HostEvent;
39import org.onosproject.net.host.HostListener;
40import org.onosproject.net.host.HostService;
Hyunsun Moon1f145552015-10-08 22:25:30 -070041import org.onosproject.ovsdb.controller.OvsdbClientService;
42import org.onosproject.ovsdb.controller.OvsdbController;
43import org.onosproject.ovsdb.controller.OvsdbNodeId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070044import org.onosproject.store.serializers.KryoNamespaces;
Hyunsun Moon1f145552015-10-08 22:25:30 -070045import org.onosproject.store.service.ConsistentMap;
46import org.onosproject.store.service.Serializer;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070047import org.onosproject.store.service.StorageService;
Hyunsun Moon1f145552015-10-08 22:25:30 -070048import org.onosproject.store.service.Versioned;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070049import org.slf4j.Logger;
50
Hyunsun Moon1f145552015-10-08 22:25:30 -070051import java.util.ArrayList;
52import java.util.HashMap;
Hyunsun Moond0e932a2015-09-15 22:39:16 -070053import java.util.List;
Hyunsun Moon1f145552015-10-08 22:25:30 -070054import java.util.Map;
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";
78 private static final Map<String, String> VXLAN_OPTIONS = new HashMap<String, String>() {
79 {
80 put("key", "flow");
81 put("local_ip", "flow");
82 put("remote_ip", "flow");
83 }
84 };
85 private static final int DPID_BEGIN = 3;
86 private static final int OFPORT = 6653;
Hyunsun Moon2b530322015-09-23 13:24:35 -070087
Hyunsun Moond0e932a2015-09-15 22:39:16 -070088 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected CoreService coreService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected StorageService storageService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Hyunsun Moond0e932a2015-09-15 22:39:16 -070095 protected DeviceService deviceService;
96
97 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 protected HostService hostService;
99
Hyunsun Moon1f145552015-10-08 22:25:30 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 protected MastershipService mastershipService;
102
103 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 protected OvsdbController controller;
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected ClusterService clusterService;
108
Hyunsun Moon2b530322015-09-23 13:24:35 -0700109 private final ExecutorService eventExecutor = Executors
110 .newFixedThreadPool(NUM_THREADS, groupedThreads("onos/cordvtn", "event-handler"));
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700111
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700112 private final DeviceListener deviceListener = new InternalDeviceListener();
113 private final HostListener hostListener = new InternalHostListener();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700114
115 private final OvsdbHandler ovsdbHandler = new OvsdbHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700116 private final BridgeHandler bridgeHandler = new BridgeHandler();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700117 private final VmHandler vmHandler = new VmHandler();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700118
Hyunsun Moon1f145552015-10-08 22:25:30 -0700119 private ConsistentMap<DeviceId, OvsdbNode> nodeStore;
120 private ApplicationId appId;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700121
122 @Activate
123 protected void activate() {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700124 appId = coreService.registerApplication("org.onosproject.cordvtn");
125 nodeStore = storageService.<DeviceId, OvsdbNode>consistentMapBuilder()
126 .withSerializer(Serializer.using(NODE_SERIALIZER.build()))
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700127 .withName("cordvtn-nodestore")
Hyunsun Moon1f145552015-10-08 22:25:30 -0700128 .withApplicationId(appId)
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700129 .build();
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700130
131 deviceService.addListener(deviceListener);
132 hostService.addListener(hostListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700133
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700134 log.info("Started");
135 }
136
137 @Deactivate
138 protected void deactivate() {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700139 deviceService.removeListener(deviceListener);
140 hostService.removeListener(hostListener);
Hyunsun Moon2b530322015-09-23 13:24:35 -0700141
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700142 eventExecutor.shutdown();
Hyunsun Moon1f145552015-10-08 22:25:30 -0700143 nodeStore.clear();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700144
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700145 log.info("Stopped");
146 }
147
148 @Override
Hyunsun Moon1f145552015-10-08 22:25:30 -0700149 public void addNode(OvsdbNode ovsdb) {
150 checkNotNull(ovsdb);
151 nodeStore.put(ovsdb.deviceId(), ovsdb);
152 }
153
154 @Override
155 public void deleteNode(OvsdbNode ovsdb) {
156 checkNotNull(ovsdb);
157
158 if (!nodeStore.containsKey(ovsdb.deviceId())) {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700159 return;
160 }
Hyunsun Moon1f145552015-10-08 22:25:30 -0700161
162 // check ovsdb and integration bridge connection state first
163 if (isNodeConnected(ovsdb)) {
164 log.warn("Cannot delete connected node {}", ovsdb.host());
165 } else {
166 nodeStore.remove(ovsdb.deviceId());
Hyunsun Moon2b530322015-09-23 13:24:35 -0700167 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700168 }
169
170 @Override
Hyunsun Moon1f145552015-10-08 22:25:30 -0700171 public void connect(OvsdbNode ovsdb) {
172 checkNotNull(ovsdb);
173
174 if (!nodeStore.containsKey(ovsdb.deviceId())) {
175 log.warn("Node {} does not exist", ovsdb.host());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700176 return;
177 }
Hyunsun Moon1f145552015-10-08 22:25:30 -0700178 controller.connect(ovsdb.ip(), ovsdb.port());
Hyunsun Moon2b530322015-09-23 13:24:35 -0700179 }
180
181 @Override
Hyunsun Moon1f145552015-10-08 22:25:30 -0700182 public void disconnect(OvsdbNode ovsdb) {
183 checkNotNull(ovsdb);
184
185 if (!nodeStore.containsKey(ovsdb.deviceId())) {
186 log.warn("Node {} does not exist", ovsdb.host());
Hyunsun Moon2b530322015-09-23 13:24:35 -0700187 return;
188 }
Hyunsun Moon1f145552015-10-08 22:25:30 -0700189
190 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
191 checkNotNull(ovsdbClient);
192
193 if (ovsdbClient.isConnected()) {
194 ovsdbClient.disconnect();
195 }
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700196 }
197
198 @Override
199 public int getNodeCount() {
200 return nodeStore.size();
201 }
202
203 @Override
Hyunsun Moon2b530322015-09-23 13:24:35 -0700204 public OvsdbNode getNode(DeviceId deviceId) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700205 Versioned<OvsdbNode> ovsdb = nodeStore.get(deviceId);
206 if (ovsdb != null) {
207 return ovsdb.value();
208 } else {
209 return null;
210 }
Hyunsun Moon2b530322015-09-23 13:24:35 -0700211 }
212
213 @Override
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700214 public List<OvsdbNode> getNodes() {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700215 List<OvsdbNode> ovsdbs = new ArrayList<>();
216 ovsdbs.addAll(Collections2.transform(nodeStore.values(), Versioned::value));
217 return ovsdbs;
218 }
219
220 @Override
221 public boolean isNodeConnected(OvsdbNode ovsdb) {
222 checkNotNull(ovsdb);
223
224 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
225 if (ovsdbClient == null) {
226 return false;
227 } else {
228 return ovsdbClient.isConnected();
229 }
230 }
231
232 private OvsdbClientService getOvsdbClient(OvsdbNode ovsdb) {
233 checkNotNull(ovsdb);
234
235 OvsdbClientService ovsdbClient = controller.getOvsdbClient(
236 new OvsdbNodeId(ovsdb.ip(), ovsdb.port().toInt()));
237 if (ovsdbClient == null) {
238 log.warn("Couldn't find ovsdb client of node {}", ovsdb.host());
239 }
240 return ovsdbClient;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700241 }
242
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700243 private class InternalDeviceListener implements DeviceListener {
244
245 @Override
246 public void event(DeviceEvent event) {
247 Device device = event.subject();
Hyunsun Moon2b530322015-09-23 13:24:35 -0700248 ConnectionHandler handler = (device.type() == SWITCH ? bridgeHandler : ovsdbHandler);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700249
250 switch (event.type()) {
Hyunsun Moon2b530322015-09-23 13:24:35 -0700251 case DEVICE_ADDED:
252 eventExecutor.submit(() -> handler.connected(device));
253 break;
254 case DEVICE_AVAILABILITY_CHANGED:
255 eventExecutor.submit(() -> handler.disconnected(device));
Hyunsun Moon1f145552015-10-08 22:25:30 -0700256 // TODO handle the case that the device is recovered
Hyunsun Moon2b530322015-09-23 13:24:35 -0700257 break;
258 default:
259 break;
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700260 }
261 }
262 }
263
264 private class InternalHostListener implements HostListener {
265
266 @Override
267 public void event(HostEvent event) {
268 Host vm = event.subject();
269
270 switch (event.type()) {
271 case HOST_ADDED:
272 eventExecutor.submit(() -> vmHandler.connected(vm));
273 break;
274 case HOST_REMOVED:
275 eventExecutor.submit(() -> vmHandler.disconnected(vm));
276 break;
277 default:
278 break;
279 }
280 }
281 }
282
Hyunsun Moon2b530322015-09-23 13:24:35 -0700283 private class OvsdbHandler implements ConnectionHandler<Device> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700284
285 @Override
286 public void connected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700287 log.info("Ovsdb {} is connected", device.id());
288
289 if (!mastershipService.isLocalMaster(device.id())) {
290 return;
291 }
292
293 // TODO change to use bridge config
294 OvsdbNode ovsdb = getNode(device.id());
295 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
296
297 List<ControllerInfo> controllers = new ArrayList<>();
298 Sets.newHashSet(clusterService.getNodes()).forEach(controller ->
299 controllers.add(new ControllerInfo(controller.ip(), OFPORT, "tcp")));
300 String dpid = ovsdb.intBrId().toString().substring(DPID_BEGIN);
301
302 ovsdbClient.createBridge(DEFAULT_BRIDGE_NAME, dpid, controllers);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700303 }
304
305 @Override
306 public void disconnected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700307 log.warn("Ovsdb {} is disconnected", device.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700308 }
309 }
310
311 private class BridgeHandler implements ConnectionHandler<Device> {
312
313 @Override
314 public void connected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700315 log.info("Integration Bridge {} is detected", device.id());
316
317 OvsdbNode ovsdb = getNodes().stream()
318 .filter(node -> node.intBrId().equals(device.id()))
319 .findFirst().get();
320
321 if (ovsdb == null) {
322 log.warn("Couldn't find OVSDB associated with {}", device.id());
323 return;
324 }
325
326 if (!mastershipService.isLocalMaster(ovsdb.deviceId())) {
327 return;
328 }
329
330 // TODO change to use tunnel config and tunnel description
331 OvsdbClientService ovsdbClient = getOvsdbClient(ovsdb);
332 ovsdbClient.createTunnel(DEFAULT_BRIDGE_NAME, "vxlan", "vxlan", VXLAN_OPTIONS);
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700333 }
334
335 @Override
336 public void disconnected(Device device) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700337 log.info("Integration Bridge {} is vanished", device.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700338 }
339 }
340
Hyunsun Moon2b530322015-09-23 13:24:35 -0700341 private class VmHandler implements ConnectionHandler<Host> {
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700342
343 @Override
344 public void connected(Host host) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700345 log.info("VM {} is detected", host.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700346 }
347
348 @Override
349 public void disconnected(Host host) {
Hyunsun Moon1f145552015-10-08 22:25:30 -0700350 log.info("VM {} is vanished", host.id());
Hyunsun Moond0e932a2015-09-15 22:39:16 -0700351 }
352 }
353}