blob: f541dfccdb6b22f3097e6e6308d6b03b4885ccae [file] [log] [blame]
Hyunsun Moon44aac662017-02-18 02:07:01 +09001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2017-present Open Networking Foundation
Hyunsun Moon44aac662017-02-18 02:07:01 +09003 *
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.openstacknetworking.impl;
17
18import com.google.common.base.Strings;
19import com.google.common.collect.ImmutableSet;
Hyunsun Moon44aac662017-02-18 02:07:01 +090020import org.onlab.util.KryoNamespace;
21import org.onosproject.core.ApplicationId;
22import org.onosproject.core.CoreService;
daniel parkb5817102018-02-15 00:18:51 +090023import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090024import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
25import org.onosproject.openstacknetworking.api.OpenstackRouterStore;
26import org.onosproject.openstacknetworking.api.OpenstackRouterStoreDelegate;
27import org.onosproject.store.AbstractStore;
28import org.onosproject.store.serializers.KryoNamespaces;
29import org.onosproject.store.service.ConsistentMap;
30import org.onosproject.store.service.MapEvent;
31import org.onosproject.store.service.MapEventListener;
32import org.onosproject.store.service.Serializer;
33import org.onosproject.store.service.StorageService;
34import org.onosproject.store.service.Versioned;
35import org.openstack4j.model.network.ExternalGateway;
36import org.openstack4j.model.network.NetFloatingIP;
37import org.openstack4j.model.network.Router;
38import org.openstack4j.model.network.RouterInterface;
39import org.openstack4j.model.network.State;
40import org.openstack4j.openstack.networking.domain.NeutronExternalGateway;
41import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
42import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
43import org.openstack4j.openstack.networking.domain.NeutronRouter;
44import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
45import org.osgi.service.component.annotations.Activate;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070046import org.osgi.service.component.annotations.Component;
47import org.osgi.service.component.annotations.Deactivate;
48import org.osgi.service.component.annotations.Reference;
49import org.osgi.service.component.annotations.ReferenceCardinality;
Hyunsun Moon44aac662017-02-18 02:07:01 +090050import org.slf4j.Logger;
51
52import java.util.Set;
53import java.util.concurrent.ExecutorService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090054
55import static com.google.common.base.Preconditions.checkArgument;
56import static java.util.concurrent.Executors.newSingleThreadExecutor;
57import static org.onlab.util.Tools.groupedThreads;
58import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
Jian Li78885a22018-03-02 11:33:02 +090059import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_ASSOCIATED;
60import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_CREATED;
61import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_DISASSOCIATED;
62import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_REMOVED;
63import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_FLOATING_IP_UPDATED;
64import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_CREATED;
65import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_GATEWAY_ADDED;
66import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_GATEWAY_REMOVED;
67import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_INTERFACE_ADDED;
68import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_INTERFACE_REMOVED;
69import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_INTERFACE_UPDATED;
70import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_REMOVED;
71import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.OPENSTACK_ROUTER_UPDATED;
Hyunsun Moon44aac662017-02-18 02:07:01 +090072import static org.slf4j.LoggerFactory.getLogger;
73
74/**
75 * Manages the inventory of OpenStack router and floating IP using a {@code ConsistentMap}.
76 */
Ray Milkeyd84f89b2018-08-17 14:54:17 -070077@Component(immediate = true, service = OpenstackRouterStore.class)
Hyunsun Moon44aac662017-02-18 02:07:01 +090078public class DistributedOpenstackRouterStore
79 extends AbstractStore<OpenstackRouterEvent, OpenstackRouterStoreDelegate>
80 implements OpenstackRouterStore {
81
82 protected final Logger log = getLogger(getClass());
83
84 private static final String ERR_NOT_FOUND = " does not exist";
85 private static final String ERR_DUPLICATE = " already exists";
86
87 private static final KryoNamespace SERIALIZER_NEUTRON_L3 = KryoNamespace.newBuilder()
88 .register(KryoNamespaces.API)
89 .register(Router.class)
90 .register(NeutronRouter.class)
91 .register(State.class)
92 .register(NeutronHostRoute.class)
93 .register(ExternalGateway.class)
94 .register(NeutronExternalGateway.class)
95 .register(RouterInterface.class)
96 .register(NeutronRouterInterface.class)
97 .register(NetFloatingIP.class)
98 .register(NeutronFloatingIP.class)
99 .build();
100
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700101 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900102 protected CoreService coreService;
103
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700104 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Hyunsun Moon44aac662017-02-18 02:07:01 +0900105 protected StorageService storageService;
106
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700107 @Reference(cardinality = ReferenceCardinality.MANDATORY)
daniel parkb5817102018-02-15 00:18:51 +0900108 protected OpenstackNetworkService osNetworkService;
109
Hyunsun Moon44aac662017-02-18 02:07:01 +0900110 private final ExecutorService eventExecutor = newSingleThreadExecutor(
111 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
Jian Li5ecfd1a2018-12-10 11:41:03 +0900112 private final MapEventListener<String, Router>
113 routerMapListener = new OpenstackRouterMapListener();
114 private final MapEventListener<String, RouterInterface>
115 routerInterfaceMapListener = new OpenstackRouterInterfaceMapListener();
116 private final MapEventListener<String, NetFloatingIP>
117 floatingIpMapListener = new OpenstackFloatingIpMapListener();
Hyunsun Moon44aac662017-02-18 02:07:01 +0900118
119 private ConsistentMap<String, Router> osRouterStore;
120 private ConsistentMap<String, RouterInterface> osRouterInterfaceStore;
121 private ConsistentMap<String, NetFloatingIP> osFloatingIpStore;
122
123 @Activate
124 protected void activate() {
125 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
126
127 osRouterStore = storageService.<String, Router>consistentMapBuilder()
128 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
129 .withName("openstack-routerstore")
130 .withApplicationId(appId)
131 .build();
132 osRouterStore.addListener(routerMapListener);
133
134 osRouterInterfaceStore = storageService.<String, RouterInterface>consistentMapBuilder()
135 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
136 .withName("openstack-routerifacestore")
137 .withApplicationId(appId)
138 .build();
139 osRouterInterfaceStore.addListener(routerInterfaceMapListener);
140
141 osFloatingIpStore = storageService.<String, NetFloatingIP>consistentMapBuilder()
142 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
143 .withName("openstack-floatingipstore")
144 .withApplicationId(appId)
145 .build();
146 osFloatingIpStore.addListener(floatingIpMapListener);
147
148 log.info("Started");
149 }
150
151 @Deactivate
152 protected void deactivate() {
153 osRouterStore.removeListener(routerMapListener);
154 osRouterInterfaceStore.removeListener(routerInterfaceMapListener);
155 osFloatingIpStore.removeListener(floatingIpMapListener);
156 eventExecutor.shutdown();
157
158 log.info("Stopped");
159 }
160
161 @Override
162 public void createRouter(Router osRouter) {
163 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
164 final String error = osRouter.getName() + ERR_DUPLICATE;
165 checkArgument(existing == null, error);
166 return osRouter;
167 });
168 }
169
170 @Override
171 public void updateRouter(Router osRouter) {
172 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
173 final String error = osRouter.getName() + ERR_NOT_FOUND;
174 checkArgument(existing != null, error);
175 return osRouter;
176 });
177 }
178
179 @Override
180 public Router removeRouter(String routerId) {
181 Versioned<Router> osRouter = osRouterStore.remove(routerId);
182 return osRouter == null ? null : osRouter.value();
183 }
184
185 @Override
186 public Router router(String routerId) {
Jian Li78885a22018-03-02 11:33:02 +0900187 return osRouterStore.asJavaMap().get(routerId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900188 }
189
190 @Override
191 public Set<Router> routers() {
Jian Li78885a22018-03-02 11:33:02 +0900192 return ImmutableSet.copyOf(osRouterStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900193 }
194
195 @Override
196 public void addRouterInterface(RouterInterface osRouterIface) {
197 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
198 final String error = osRouterIface.getPortId() + ERR_DUPLICATE;
199 checkArgument(existing == null, error);
200 return osRouterIface;
201 });
202 }
203
204 @Override
205 public void updateRouterInterface(RouterInterface osRouterIface) {
206 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
207 final String error = osRouterIface.getPortId() + ERR_NOT_FOUND;
208 checkArgument(existing != null, error);
209 return osRouterIface;
210 });
211 }
212
213 @Override
214 public RouterInterface removeRouterInterface(String routerIfaceId) {
215 Versioned<RouterInterface> osRouterIface = osRouterInterfaceStore.remove(routerIfaceId);
216 return osRouterIface == null ? null : osRouterIface.value();
217 }
218
219 @Override
220 public RouterInterface routerInterface(String routerIfaceId) {
Jian Li78885a22018-03-02 11:33:02 +0900221 return osRouterInterfaceStore.asJavaMap().get(routerIfaceId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900222 }
223
224 @Override
225 public Set<RouterInterface> routerInterfaces() {
Jian Li78885a22018-03-02 11:33:02 +0900226 return ImmutableSet.copyOf(osRouterInterfaceStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900227 }
228
229 @Override
230 public void createFloatingIp(NetFloatingIP osFloatingIp) {
231 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
232 final String error = osFloatingIp.getId() + ERR_DUPLICATE;
233 checkArgument(existing == null, error);
234 return osFloatingIp;
235 });
236 }
237
238 @Override
239 public void updateFloatingIp(NetFloatingIP osFloatingIp) {
240 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
241 final String error = osFloatingIp.getId() + ERR_NOT_FOUND;
242 checkArgument(existing != null, error);
243 return osFloatingIp;
244 });
245 }
246
247 @Override
248 public NetFloatingIP removeFloatingIp(String floatingIpId) {
249 Versioned<NetFloatingIP> osFloatingIp = osFloatingIpStore.remove(floatingIpId);
250 return osFloatingIp == null ? null : osFloatingIp.value();
251 }
252
253 @Override
254 public NetFloatingIP floatingIp(String floatingIpId) {
Jian Li78885a22018-03-02 11:33:02 +0900255 return osFloatingIpStore.asJavaMap().get(floatingIpId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900256 }
257
258 @Override
259 public Set<NetFloatingIP> floatingIps() {
Jian Li78885a22018-03-02 11:33:02 +0900260 return ImmutableSet.copyOf(osFloatingIpStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900261 }
262
Hyunsun Moonc7219222017-03-27 11:05:59 +0900263 @Override
264 public void clear() {
265 osFloatingIpStore.clear();
266 osRouterInterfaceStore.clear();
267 osRouterStore.clear();
268 }
269
Hyunsun Moon44aac662017-02-18 02:07:01 +0900270 private class OpenstackRouterMapListener implements MapEventListener<String, Router> {
271
272 @Override
273 public void event(MapEvent<String, Router> event) {
274 switch (event.type()) {
275 case UPDATE:
Jian Li411bf2e2018-11-29 00:08:54 +0900276 eventExecutor.execute(() -> processRouterMapUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900277 break;
278 case INSERT:
Jian Li411bf2e2018-11-29 00:08:54 +0900279 eventExecutor.execute(() -> processRouterMapInsertion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900280 break;
281 case REMOVE:
Jian Li411bf2e2018-11-29 00:08:54 +0900282 eventExecutor.execute(() -> processRouterMapRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900283 break;
284 default:
Jian Li78885a22018-03-02 11:33:02 +0900285 log.error("Unsupported openstack router event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900286 break;
287 }
288 }
289
Jian Li411bf2e2018-11-29 00:08:54 +0900290 private void processRouterMapUpdate(MapEvent<String, Router> event) {
291 log.debug("OpenStack router updated");
292 notifyDelegate(new OpenstackRouterEvent(
293 OPENSTACK_ROUTER_UPDATED,
294 event.newValue().value()));
295 processGatewayUpdate(event);
296 }
297
298 private void processRouterMapInsertion(MapEvent<String, Router> event) {
299 log.debug("OpenStack router created");
300 notifyDelegate(new OpenstackRouterEvent(
301 OPENSTACK_ROUTER_CREATED,
302 event.newValue().value()));
303 }
304
305 private void processRouterMapRemoval(MapEvent<String, Router> event) {
306 log.debug("OpenStack router removed");
307 notifyDelegate(new OpenstackRouterEvent(
308 OPENSTACK_ROUTER_REMOVED,
309 event.oldValue().value()));
310 }
311
Hyunsun Moon44aac662017-02-18 02:07:01 +0900312 private void processGatewayUpdate(MapEvent<String, Router> event) {
313 ExternalGateway oldGateway = event.oldValue().value().getExternalGatewayInfo();
314 ExternalGateway newGateway = event.newValue().value().getExternalGatewayInfo();
315
316 if (oldGateway == null && newGateway != null) {
317 notifyDelegate(new OpenstackRouterEvent(
318 OPENSTACK_ROUTER_GATEWAY_ADDED,
319 event.newValue().value(), newGateway));
320 }
321 if (oldGateway != null && newGateway == null) {
322 notifyDelegate(new OpenstackRouterEvent(
Hyunsun Moona5b5f4e2017-03-17 19:01:12 +0900323 OPENSTACK_ROUTER_GATEWAY_REMOVED,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900324 event.newValue().value(), oldGateway));
325 }
326 }
327 }
328
Jian Li0488c732018-09-14 20:53:07 +0900329 private class OpenstackRouterInterfaceMapListener
330 implements MapEventListener<String, RouterInterface> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900331
332 @Override
333 public void event(MapEvent<String, RouterInterface> event) {
334 switch (event.type()) {
335 case UPDATE:
Jian Li411bf2e2018-11-29 00:08:54 +0900336 eventExecutor.execute(() -> processRouterIntfUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900337 break;
338 case INSERT:
Jian Li411bf2e2018-11-29 00:08:54 +0900339 eventExecutor.execute(() -> processRouterIntfInsertion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900340 break;
341 case REMOVE:
Jian Li411bf2e2018-11-29 00:08:54 +0900342 eventExecutor.execute(() -> processRouterIntfRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900343 break;
344 default:
Jian Li78885a22018-03-02 11:33:02 +0900345 log.error("Unsupported openstack router interface event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900346 break;
347 }
348 }
Jian Li411bf2e2018-11-29 00:08:54 +0900349
350 private void processRouterIntfUpdate(MapEvent<String, RouterInterface> event) {
351 log.debug("OpenStack router interface updated");
352 notifyDelegate(new OpenstackRouterEvent(
353 OPENSTACK_ROUTER_INTERFACE_UPDATED,
354 router(event.newValue().value().getId()),
355 event.newValue().value()));
356 }
357
358 private void processRouterIntfInsertion(MapEvent<String, RouterInterface> event) {
359 log.debug("OpenStack router interface created");
360 notifyDelegate(new OpenstackRouterEvent(
361 OPENSTACK_ROUTER_INTERFACE_ADDED,
362 router(event.newValue().value().getId()),
363 event.newValue().value()));
364 }
365
366 private void processRouterIntfRemoval(MapEvent<String, RouterInterface> event) {
367 log.debug("OpenStack router interface removed");
368 notifyDelegate(new OpenstackRouterEvent(
369 OPENSTACK_ROUTER_INTERFACE_REMOVED,
370 router(event.oldValue().value().getId()),
371 event.oldValue().value()));
372 }
Hyunsun Moon44aac662017-02-18 02:07:01 +0900373 }
374
Jian Li0488c732018-09-14 20:53:07 +0900375 private class OpenstackFloatingIpMapListener
376 implements MapEventListener<String, NetFloatingIP> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900377
378 @Override
379 public void event(MapEvent<String, NetFloatingIP> event) {
380 switch (event.type()) {
381 case UPDATE:
Jian Li411bf2e2018-11-29 00:08:54 +0900382 eventExecutor.execute(() -> processFloatingIpMapUpdate(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900383 break;
384 case INSERT:
Jian Li411bf2e2018-11-29 00:08:54 +0900385 eventExecutor.execute(() -> processFloatingIpMapInsertion(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900386 break;
387 case REMOVE:
Jian Li411bf2e2018-11-29 00:08:54 +0900388 eventExecutor.execute(() -> processFloatingIpMapRemoval(event));
Hyunsun Moon44aac662017-02-18 02:07:01 +0900389 break;
390 default:
Jian Li78885a22018-03-02 11:33:02 +0900391 log.error("Unsupported openstack floating IP event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900392 break;
393 }
394 }
395
Jian Li411bf2e2018-11-29 00:08:54 +0900396 private void processFloatingIpMapUpdate(MapEvent<String, NetFloatingIP> event) {
397 log.debug("OpenStack floating IP updated");
398 Router osRouter = Strings.isNullOrEmpty(
399 event.newValue().value().getRouterId()) ?
400 null :
401 router(event.newValue().value().getRouterId());
402 notifyDelegate(new OpenstackRouterEvent(
403 OPENSTACK_FLOATING_IP_UPDATED,
404 osRouter,
405 event.newValue().value()));
406 processFloatingIpUpdate(event, osRouter);
407 }
408
409 private void processFloatingIpMapInsertion(MapEvent<String, NetFloatingIP> event) {
410 log.debug("OpenStack floating IP created");
411 Router osRouter = Strings.isNullOrEmpty(
412 event.newValue().value().getRouterId()) ?
413 null :
414 router(event.newValue().value().getRouterId());
415 notifyDelegate(new OpenstackRouterEvent(
416 OPENSTACK_FLOATING_IP_CREATED,
417 osRouter,
418 event.newValue().value()));
419 }
420
421 private void processFloatingIpMapRemoval(MapEvent<String, NetFloatingIP> event) {
422 log.debug("OpenStack floating IP removed");
423 Router osRouter = Strings.isNullOrEmpty(
424 event.oldValue().value().getRouterId()) ?
425 null :
426 router(event.oldValue().value().getRouterId());
427 notifyDelegate(new OpenstackRouterEvent(
428 OPENSTACK_FLOATING_IP_REMOVED,
429 osRouter,
430 event.oldValue().value()));
431 }
432
Hyunsun Moon44aac662017-02-18 02:07:01 +0900433 private void processFloatingIpUpdate(MapEvent<String, NetFloatingIP> event,
434 Router osRouter) {
435 String oldPortId = event.oldValue().value().getPortId();
436 String newPortId = event.newValue().value().getPortId();
437
438 if (Strings.isNullOrEmpty(oldPortId) && !Strings.isNullOrEmpty(newPortId)) {
439 notifyDelegate(new OpenstackRouterEvent(
440 OPENSTACK_FLOATING_IP_ASSOCIATED,
441 osRouter,
442 event.newValue().value(), newPortId));
443 }
444 if (!Strings.isNullOrEmpty(oldPortId) && Strings.isNullOrEmpty(newPortId)) {
445 notifyDelegate(new OpenstackRouterEvent(
446 OPENSTACK_FLOATING_IP_DISASSOCIATED,
447 osRouter,
448 event.newValue().value(), oldPortId));
449 }
450 }
451 }
452}