blob: c8bd92570764e844107e9c7d3353efe988a2c87a [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));
112 private final MapEventListener<String, Router> routerMapListener = new OpenstackRouterMapListener();
113 private final MapEventListener<String, RouterInterface> routerInterfaceMapListener =
114 new OpenstackRouterInterfaceMapListener();
115 private final MapEventListener<String, NetFloatingIP> floatingIpMapListener =
116 new OpenstackFloatingIpMapListener();
117
118 private ConsistentMap<String, Router> osRouterStore;
119 private ConsistentMap<String, RouterInterface> osRouterInterfaceStore;
120 private ConsistentMap<String, NetFloatingIP> osFloatingIpStore;
121
122 @Activate
123 protected void activate() {
124 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
125
126 osRouterStore = storageService.<String, Router>consistentMapBuilder()
127 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
128 .withName("openstack-routerstore")
129 .withApplicationId(appId)
130 .build();
131 osRouterStore.addListener(routerMapListener);
132
133 osRouterInterfaceStore = storageService.<String, RouterInterface>consistentMapBuilder()
134 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
135 .withName("openstack-routerifacestore")
136 .withApplicationId(appId)
137 .build();
138 osRouterInterfaceStore.addListener(routerInterfaceMapListener);
139
140 osFloatingIpStore = storageService.<String, NetFloatingIP>consistentMapBuilder()
141 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
142 .withName("openstack-floatingipstore")
143 .withApplicationId(appId)
144 .build();
145 osFloatingIpStore.addListener(floatingIpMapListener);
146
147 log.info("Started");
148 }
149
150 @Deactivate
151 protected void deactivate() {
152 osRouterStore.removeListener(routerMapListener);
153 osRouterInterfaceStore.removeListener(routerInterfaceMapListener);
154 osFloatingIpStore.removeListener(floatingIpMapListener);
155 eventExecutor.shutdown();
156
157 log.info("Stopped");
158 }
159
160 @Override
161 public void createRouter(Router osRouter) {
162 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
163 final String error = osRouter.getName() + ERR_DUPLICATE;
164 checkArgument(existing == null, error);
165 return osRouter;
166 });
167 }
168
169 @Override
170 public void updateRouter(Router osRouter) {
171 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
172 final String error = osRouter.getName() + ERR_NOT_FOUND;
173 checkArgument(existing != null, error);
174 return osRouter;
175 });
176 }
177
178 @Override
179 public Router removeRouter(String routerId) {
180 Versioned<Router> osRouter = osRouterStore.remove(routerId);
181 return osRouter == null ? null : osRouter.value();
182 }
183
184 @Override
185 public Router router(String routerId) {
Jian Li78885a22018-03-02 11:33:02 +0900186 return osRouterStore.asJavaMap().get(routerId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900187 }
188
189 @Override
190 public Set<Router> routers() {
Jian Li78885a22018-03-02 11:33:02 +0900191 return ImmutableSet.copyOf(osRouterStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900192 }
193
194 @Override
195 public void addRouterInterface(RouterInterface osRouterIface) {
196 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
197 final String error = osRouterIface.getPortId() + ERR_DUPLICATE;
198 checkArgument(existing == null, error);
199 return osRouterIface;
200 });
201 }
202
203 @Override
204 public void updateRouterInterface(RouterInterface osRouterIface) {
205 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
206 final String error = osRouterIface.getPortId() + ERR_NOT_FOUND;
207 checkArgument(existing != null, error);
208 return osRouterIface;
209 });
210 }
211
212 @Override
213 public RouterInterface removeRouterInterface(String routerIfaceId) {
214 Versioned<RouterInterface> osRouterIface = osRouterInterfaceStore.remove(routerIfaceId);
215 return osRouterIface == null ? null : osRouterIface.value();
216 }
217
218 @Override
219 public RouterInterface routerInterface(String routerIfaceId) {
Jian Li78885a22018-03-02 11:33:02 +0900220 return osRouterInterfaceStore.asJavaMap().get(routerIfaceId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900221 }
222
223 @Override
224 public Set<RouterInterface> routerInterfaces() {
Jian Li78885a22018-03-02 11:33:02 +0900225 return ImmutableSet.copyOf(osRouterInterfaceStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900226 }
227
228 @Override
229 public void createFloatingIp(NetFloatingIP osFloatingIp) {
230 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
231 final String error = osFloatingIp.getId() + ERR_DUPLICATE;
232 checkArgument(existing == null, error);
233 return osFloatingIp;
234 });
235 }
236
237 @Override
238 public void updateFloatingIp(NetFloatingIP osFloatingIp) {
239 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
240 final String error = osFloatingIp.getId() + ERR_NOT_FOUND;
241 checkArgument(existing != null, error);
242 return osFloatingIp;
243 });
244 }
245
246 @Override
247 public NetFloatingIP removeFloatingIp(String floatingIpId) {
248 Versioned<NetFloatingIP> osFloatingIp = osFloatingIpStore.remove(floatingIpId);
249 return osFloatingIp == null ? null : osFloatingIp.value();
250 }
251
252 @Override
253 public NetFloatingIP floatingIp(String floatingIpId) {
Jian Li78885a22018-03-02 11:33:02 +0900254 return osFloatingIpStore.asJavaMap().get(floatingIpId);
Hyunsun Moon44aac662017-02-18 02:07:01 +0900255 }
256
257 @Override
258 public Set<NetFloatingIP> floatingIps() {
Jian Li78885a22018-03-02 11:33:02 +0900259 return ImmutableSet.copyOf(osFloatingIpStore.asJavaMap().values());
Hyunsun Moon44aac662017-02-18 02:07:01 +0900260 }
261
Hyunsun Moonc7219222017-03-27 11:05:59 +0900262 @Override
263 public void clear() {
264 osFloatingIpStore.clear();
265 osRouterInterfaceStore.clear();
266 osRouterStore.clear();
267 }
268
Hyunsun Moon44aac662017-02-18 02:07:01 +0900269 private class OpenstackRouterMapListener implements MapEventListener<String, Router> {
270
271 @Override
272 public void event(MapEvent<String, Router> event) {
273 switch (event.type()) {
274 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900275 log.debug("OpenStack router updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900276 eventExecutor.execute(() -> {
277 notifyDelegate(new OpenstackRouterEvent(
278 OPENSTACK_ROUTER_UPDATED,
279 event.newValue().value()));
280 processGatewayUpdate(event);
281 });
282 break;
283 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900284 log.debug("OpenStack router created");
Jian Li78885a22018-03-02 11:33:02 +0900285 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900286 notifyDelegate(new OpenstackRouterEvent(
287 OPENSTACK_ROUTER_CREATED,
Jian Li78885a22018-03-02 11:33:02 +0900288 event.newValue().value()))
289 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900290 break;
291 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900292 log.debug("OpenStack router removed");
Jian Li78885a22018-03-02 11:33:02 +0900293 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900294 notifyDelegate(new OpenstackRouterEvent(
295 OPENSTACK_ROUTER_REMOVED,
Jian Li78885a22018-03-02 11:33:02 +0900296 event.oldValue().value()))
297 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900298 break;
299 default:
Jian Li78885a22018-03-02 11:33:02 +0900300 log.error("Unsupported openstack router event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900301 break;
302 }
303 }
304
305 private void processGatewayUpdate(MapEvent<String, Router> event) {
306 ExternalGateway oldGateway = event.oldValue().value().getExternalGatewayInfo();
307 ExternalGateway newGateway = event.newValue().value().getExternalGatewayInfo();
308
309 if (oldGateway == null && newGateway != null) {
310 notifyDelegate(new OpenstackRouterEvent(
311 OPENSTACK_ROUTER_GATEWAY_ADDED,
312 event.newValue().value(), newGateway));
313 }
314 if (oldGateway != null && newGateway == null) {
315 notifyDelegate(new OpenstackRouterEvent(
Hyunsun Moona5b5f4e2017-03-17 19:01:12 +0900316 OPENSTACK_ROUTER_GATEWAY_REMOVED,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900317 event.newValue().value(), oldGateway));
318 }
319 }
320 }
321
Jian Li0488c732018-09-14 20:53:07 +0900322 private class OpenstackRouterInterfaceMapListener
323 implements MapEventListener<String, RouterInterface> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900324
325 @Override
326 public void event(MapEvent<String, RouterInterface> event) {
327 switch (event.type()) {
328 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900329 log.debug("OpenStack router interface updated");
Jian Li78885a22018-03-02 11:33:02 +0900330 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900331 notifyDelegate(new OpenstackRouterEvent(
332 OPENSTACK_ROUTER_INTERFACE_UPDATED,
333 router(event.newValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900334 event.newValue().value()))
335 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900336 break;
337 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900338 log.debug("OpenStack router interface created");
Jian Li78885a22018-03-02 11:33:02 +0900339 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900340 notifyDelegate(new OpenstackRouterEvent(
341 OPENSTACK_ROUTER_INTERFACE_ADDED,
342 router(event.newValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900343 event.newValue().value()))
344 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900345 break;
346 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900347 log.debug("OpenStack router interface removed");
Jian Li78885a22018-03-02 11:33:02 +0900348 eventExecutor.execute(() ->
Hyunsun Moon44aac662017-02-18 02:07:01 +0900349 notifyDelegate(new OpenstackRouterEvent(
350 OPENSTACK_ROUTER_INTERFACE_REMOVED,
351 router(event.oldValue().value().getId()),
Jian Li78885a22018-03-02 11:33:02 +0900352 event.oldValue().value()))
353 );
Hyunsun Moon44aac662017-02-18 02:07:01 +0900354 break;
355 default:
Jian Li78885a22018-03-02 11:33:02 +0900356 log.error("Unsupported openstack router interface event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900357 break;
358 }
359 }
360 }
361
Jian Li0488c732018-09-14 20:53:07 +0900362 private class OpenstackFloatingIpMapListener
363 implements MapEventListener<String, NetFloatingIP> {
Hyunsun Moon44aac662017-02-18 02:07:01 +0900364
365 @Override
366 public void event(MapEvent<String, NetFloatingIP> event) {
367 switch (event.type()) {
368 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900369 log.debug("OpenStack floating IP updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900370 eventExecutor.execute(() -> {
371 Router osRouter = Strings.isNullOrEmpty(
372 event.newValue().value().getRouterId()) ?
373 null :
374 router(event.newValue().value().getRouterId());
375 notifyDelegate(new OpenstackRouterEvent(
376 OPENSTACK_FLOATING_IP_UPDATED,
377 osRouter,
378 event.newValue().value()));
379 processFloatingIpUpdate(event, osRouter);
380 });
381 break;
382 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900383 log.debug("OpenStack floating IP created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900384 eventExecutor.execute(() -> {
385 Router osRouter = Strings.isNullOrEmpty(
386 event.newValue().value().getRouterId()) ?
387 null :
388 router(event.newValue().value().getRouterId());
389 notifyDelegate(new OpenstackRouterEvent(
390 OPENSTACK_FLOATING_IP_CREATED,
391 osRouter,
392 event.newValue().value()));
393 });
394 break;
395 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900396 log.debug("OpenStack floating IP removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900397 eventExecutor.execute(() -> {
398 Router osRouter = Strings.isNullOrEmpty(
399 event.oldValue().value().getRouterId()) ?
400 null :
401 router(event.oldValue().value().getRouterId());
402 notifyDelegate(new OpenstackRouterEvent(
403 OPENSTACK_FLOATING_IP_REMOVED,
404 osRouter,
405 event.oldValue().value()));
406 });
407 break;
408 default:
Jian Li78885a22018-03-02 11:33:02 +0900409 log.error("Unsupported openstack floating IP event type");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900410 break;
411 }
412 }
413
414 private void processFloatingIpUpdate(MapEvent<String, NetFloatingIP> event,
415 Router osRouter) {
416 String oldPortId = event.oldValue().value().getPortId();
417 String newPortId = event.newValue().value().getPortId();
418
419 if (Strings.isNullOrEmpty(oldPortId) && !Strings.isNullOrEmpty(newPortId)) {
420 notifyDelegate(new OpenstackRouterEvent(
421 OPENSTACK_FLOATING_IP_ASSOCIATED,
422 osRouter,
423 event.newValue().value(), newPortId));
424 }
425 if (!Strings.isNullOrEmpty(oldPortId) && Strings.isNullOrEmpty(newPortId)) {
426 notifyDelegate(new OpenstackRouterEvent(
427 OPENSTACK_FLOATING_IP_DISASSOCIATED,
428 osRouter,
429 event.newValue().value(), oldPortId));
430 }
431 }
432 }
433}