blob: 62fc7ac98e5811a92e9f68f790e738ae3ac50802 [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;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.util.KryoNamespace;
26import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
daniel parkb5817102018-02-15 00:18:51 +090028import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
Hyunsun Moon44aac662017-02-18 02:07:01 +090029import org.onosproject.openstacknetworking.api.OpenstackRouterEvent;
30import org.onosproject.openstacknetworking.api.OpenstackRouterStore;
31import org.onosproject.openstacknetworking.api.OpenstackRouterStoreDelegate;
32import org.onosproject.store.AbstractStore;
33import org.onosproject.store.serializers.KryoNamespaces;
34import org.onosproject.store.service.ConsistentMap;
35import org.onosproject.store.service.MapEvent;
36import org.onosproject.store.service.MapEventListener;
37import org.onosproject.store.service.Serializer;
38import org.onosproject.store.service.StorageService;
39import org.onosproject.store.service.Versioned;
40import org.openstack4j.model.network.ExternalGateway;
41import org.openstack4j.model.network.NetFloatingIP;
42import org.openstack4j.model.network.Router;
43import org.openstack4j.model.network.RouterInterface;
44import org.openstack4j.model.network.State;
45import org.openstack4j.openstack.networking.domain.NeutronExternalGateway;
46import org.openstack4j.openstack.networking.domain.NeutronFloatingIP;
47import org.openstack4j.openstack.networking.domain.NeutronHostRoute;
48import org.openstack4j.openstack.networking.domain.NeutronRouter;
49import org.openstack4j.openstack.networking.domain.NeutronRouterInterface;
50import org.osgi.service.component.annotations.Activate;
51import org.slf4j.Logger;
52
53import java.util.Set;
54import java.util.concurrent.ExecutorService;
55import java.util.stream.Collectors;
56
57import static com.google.common.base.Preconditions.checkArgument;
58import static java.util.concurrent.Executors.newSingleThreadExecutor;
59import static org.onlab.util.Tools.groupedThreads;
60import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
61import static org.onosproject.openstacknetworking.api.OpenstackRouterEvent.Type.*;
62import static org.slf4j.LoggerFactory.getLogger;
63
64/**
65 * Manages the inventory of OpenStack router and floating IP using a {@code ConsistentMap}.
66 */
67@Service
68@Component(immediate = true)
69public class DistributedOpenstackRouterStore
70 extends AbstractStore<OpenstackRouterEvent, OpenstackRouterStoreDelegate>
71 implements OpenstackRouterStore {
72
73 protected final Logger log = getLogger(getClass());
74
75 private static final String ERR_NOT_FOUND = " does not exist";
76 private static final String ERR_DUPLICATE = " already exists";
77
78 private static final KryoNamespace SERIALIZER_NEUTRON_L3 = KryoNamespace.newBuilder()
79 .register(KryoNamespaces.API)
80 .register(Router.class)
81 .register(NeutronRouter.class)
82 .register(State.class)
83 .register(NeutronHostRoute.class)
84 .register(ExternalGateway.class)
85 .register(NeutronExternalGateway.class)
86 .register(RouterInterface.class)
87 .register(NeutronRouterInterface.class)
88 .register(NetFloatingIP.class)
89 .register(NeutronFloatingIP.class)
90 .build();
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected CoreService coreService;
94
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 protected StorageService storageService;
97
daniel parkb5817102018-02-15 00:18:51 +090098 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 protected OpenstackNetworkService osNetworkService;
100
Hyunsun Moon44aac662017-02-18 02:07:01 +0900101 private final ExecutorService eventExecutor = newSingleThreadExecutor(
102 groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
103 private final MapEventListener<String, Router> routerMapListener = new OpenstackRouterMapListener();
104 private final MapEventListener<String, RouterInterface> routerInterfaceMapListener =
105 new OpenstackRouterInterfaceMapListener();
106 private final MapEventListener<String, NetFloatingIP> floatingIpMapListener =
107 new OpenstackFloatingIpMapListener();
108
109 private ConsistentMap<String, Router> osRouterStore;
110 private ConsistentMap<String, RouterInterface> osRouterInterfaceStore;
111 private ConsistentMap<String, NetFloatingIP> osFloatingIpStore;
112
113 @Activate
114 protected void activate() {
115 ApplicationId appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
116
117 osRouterStore = storageService.<String, Router>consistentMapBuilder()
118 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
119 .withName("openstack-routerstore")
120 .withApplicationId(appId)
121 .build();
122 osRouterStore.addListener(routerMapListener);
123
124 osRouterInterfaceStore = storageService.<String, RouterInterface>consistentMapBuilder()
125 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
126 .withName("openstack-routerifacestore")
127 .withApplicationId(appId)
128 .build();
129 osRouterInterfaceStore.addListener(routerInterfaceMapListener);
130
131 osFloatingIpStore = storageService.<String, NetFloatingIP>consistentMapBuilder()
132 .withSerializer(Serializer.using(SERIALIZER_NEUTRON_L3))
133 .withName("openstack-floatingipstore")
134 .withApplicationId(appId)
135 .build();
136 osFloatingIpStore.addListener(floatingIpMapListener);
137
138 log.info("Started");
139 }
140
141 @Deactivate
142 protected void deactivate() {
143 osRouterStore.removeListener(routerMapListener);
144 osRouterInterfaceStore.removeListener(routerInterfaceMapListener);
145 osFloatingIpStore.removeListener(floatingIpMapListener);
146 eventExecutor.shutdown();
147
148 log.info("Stopped");
149 }
150
151 @Override
152 public void createRouter(Router osRouter) {
153 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
154 final String error = osRouter.getName() + ERR_DUPLICATE;
155 checkArgument(existing == null, error);
156 return osRouter;
157 });
158 }
159
160 @Override
161 public void updateRouter(Router osRouter) {
162 osRouterStore.compute(osRouter.getId(), (id, existing) -> {
163 final String error = osRouter.getName() + ERR_NOT_FOUND;
164 checkArgument(existing != null, error);
165 return osRouter;
166 });
167 }
168
169 @Override
170 public Router removeRouter(String routerId) {
171 Versioned<Router> osRouter = osRouterStore.remove(routerId);
172 return osRouter == null ? null : osRouter.value();
173 }
174
175 @Override
176 public Router router(String routerId) {
177 Versioned<Router> versioned = osRouterStore.get(routerId);
178 return versioned == null ? null : versioned.value();
179 }
180
181 @Override
182 public Set<Router> routers() {
183 Set<Router> osRouters = osRouterStore.values().stream()
184 .map(Versioned::value)
185 .collect(Collectors.toSet());
186 return ImmutableSet.copyOf(osRouters);
187 }
188
189 @Override
190 public void addRouterInterface(RouterInterface osRouterIface) {
191 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
192 final String error = osRouterIface.getPortId() + ERR_DUPLICATE;
193 checkArgument(existing == null, error);
194 return osRouterIface;
195 });
196 }
197
198 @Override
199 public void updateRouterInterface(RouterInterface osRouterIface) {
200 osRouterInterfaceStore.compute(osRouterIface.getPortId(), (id, existing) -> {
201 final String error = osRouterIface.getPortId() + ERR_NOT_FOUND;
202 checkArgument(existing != null, error);
203 return osRouterIface;
204 });
205 }
206
207 @Override
208 public RouterInterface removeRouterInterface(String routerIfaceId) {
209 Versioned<RouterInterface> osRouterIface = osRouterInterfaceStore.remove(routerIfaceId);
210 return osRouterIface == null ? null : osRouterIface.value();
211 }
212
213 @Override
214 public RouterInterface routerInterface(String routerIfaceId) {
215 Versioned<RouterInterface> osRouterIface = osRouterInterfaceStore.get(routerIfaceId);
216 return osRouterIface == null ? null : osRouterIface.value();
217 }
218
219 @Override
220 public Set<RouterInterface> routerInterfaces() {
221 Set<RouterInterface> osRouterIfaces = osRouterInterfaceStore.values().stream()
222 .map(Versioned::value)
223 .collect(Collectors.toSet());
224 return ImmutableSet.copyOf(osRouterIfaces);
225 }
226
227 @Override
228 public void createFloatingIp(NetFloatingIP osFloatingIp) {
229 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
230 final String error = osFloatingIp.getId() + ERR_DUPLICATE;
231 checkArgument(existing == null, error);
232 return osFloatingIp;
233 });
234 }
235
236 @Override
237 public void updateFloatingIp(NetFloatingIP osFloatingIp) {
238 osFloatingIpStore.compute(osFloatingIp.getId(), (id, existing) -> {
239 final String error = osFloatingIp.getId() + ERR_NOT_FOUND;
240 checkArgument(existing != null, error);
241 return osFloatingIp;
242 });
243 }
244
245 @Override
246 public NetFloatingIP removeFloatingIp(String floatingIpId) {
247 Versioned<NetFloatingIP> osFloatingIp = osFloatingIpStore.remove(floatingIpId);
248 return osFloatingIp == null ? null : osFloatingIp.value();
249 }
250
251 @Override
252 public NetFloatingIP floatingIp(String floatingIpId) {
253 Versioned<NetFloatingIP> osFloatingIp = osFloatingIpStore.get(floatingIpId);
254 return osFloatingIp == null ? null : osFloatingIp.value();
255 }
256
257 @Override
258 public Set<NetFloatingIP> floatingIps() {
259 Set<NetFloatingIP> osFloatingIps = osFloatingIpStore.values().stream()
260 .map(Versioned::value)
261 .collect(Collectors.toSet());
262 return ImmutableSet.copyOf(osFloatingIps);
263 }
264
Hyunsun Moonc7219222017-03-27 11:05:59 +0900265 @Override
266 public void clear() {
267 osFloatingIpStore.clear();
268 osRouterInterfaceStore.clear();
269 osRouterStore.clear();
270 }
271
Hyunsun Moon44aac662017-02-18 02:07:01 +0900272 private class OpenstackRouterMapListener implements MapEventListener<String, Router> {
273
274 @Override
275 public void event(MapEvent<String, Router> event) {
276 switch (event.type()) {
277 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900278 log.debug("OpenStack router updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900279 eventExecutor.execute(() -> {
280 notifyDelegate(new OpenstackRouterEvent(
281 OPENSTACK_ROUTER_UPDATED,
282 event.newValue().value()));
283 processGatewayUpdate(event);
284 });
285 break;
286 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900287 log.debug("OpenStack router created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900288 eventExecutor.execute(() -> {
289 notifyDelegate(new OpenstackRouterEvent(
290 OPENSTACK_ROUTER_CREATED,
291 event.newValue().value()));
292 });
293 break;
294 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900295 log.debug("OpenStack router removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900296 eventExecutor.execute(() -> {
297 notifyDelegate(new OpenstackRouterEvent(
298 OPENSTACK_ROUTER_REMOVED,
299 event.oldValue().value()));
300 });
301 break;
302 default:
303 log.error("Unsupported event type");
304 break;
305 }
306 }
307
308 private void processGatewayUpdate(MapEvent<String, Router> event) {
309 ExternalGateway oldGateway = event.oldValue().value().getExternalGatewayInfo();
310 ExternalGateway newGateway = event.newValue().value().getExternalGatewayInfo();
311
312 if (oldGateway == null && newGateway != null) {
313 notifyDelegate(new OpenstackRouterEvent(
314 OPENSTACK_ROUTER_GATEWAY_ADDED,
315 event.newValue().value(), newGateway));
316 }
317 if (oldGateway != null && newGateway == null) {
318 notifyDelegate(new OpenstackRouterEvent(
Hyunsun Moona5b5f4e2017-03-17 19:01:12 +0900319 OPENSTACK_ROUTER_GATEWAY_REMOVED,
Hyunsun Moon44aac662017-02-18 02:07:01 +0900320 event.newValue().value(), oldGateway));
321 }
322 }
323 }
324
325 private class OpenstackRouterInterfaceMapListener implements MapEventListener<String, RouterInterface> {
326
327 @Override
328 public void event(MapEvent<String, RouterInterface> event) {
329 switch (event.type()) {
330 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900331 log.debug("OpenStack router interface updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900332 eventExecutor.execute(() -> {
333 notifyDelegate(new OpenstackRouterEvent(
334 OPENSTACK_ROUTER_INTERFACE_UPDATED,
335 router(event.newValue().value().getId()),
336 event.newValue().value()));
337 });
338 break;
339 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900340 log.debug("OpenStack router interface created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900341 eventExecutor.execute(() -> {
342 notifyDelegate(new OpenstackRouterEvent(
343 OPENSTACK_ROUTER_INTERFACE_ADDED,
344 router(event.newValue().value().getId()),
345 event.newValue().value()));
346 });
347 break;
348 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900349 log.debug("OpenStack router interface removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900350 eventExecutor.execute(() -> {
351 notifyDelegate(new OpenstackRouterEvent(
352 OPENSTACK_ROUTER_INTERFACE_REMOVED,
353 router(event.oldValue().value().getId()),
354 event.oldValue().value()));
355 });
356 break;
357 default:
358 log.error("Unsupported event type");
359 break;
360 }
361 }
362 }
363
364 private class OpenstackFloatingIpMapListener implements MapEventListener<String, NetFloatingIP> {
365
366 @Override
367 public void event(MapEvent<String, NetFloatingIP> event) {
368 switch (event.type()) {
369 case UPDATE:
daniel parkb5817102018-02-15 00:18:51 +0900370 log.debug("OpenStack floating IP updated");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900371 eventExecutor.execute(() -> {
372 Router osRouter = Strings.isNullOrEmpty(
373 event.newValue().value().getRouterId()) ?
374 null :
375 router(event.newValue().value().getRouterId());
376 notifyDelegate(new OpenstackRouterEvent(
377 OPENSTACK_FLOATING_IP_UPDATED,
378 osRouter,
379 event.newValue().value()));
380 processFloatingIpUpdate(event, osRouter);
381 });
382 break;
383 case INSERT:
daniel parkb5817102018-02-15 00:18:51 +0900384 log.debug("OpenStack floating IP created");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900385 eventExecutor.execute(() -> {
386 Router osRouter = Strings.isNullOrEmpty(
387 event.newValue().value().getRouterId()) ?
388 null :
389 router(event.newValue().value().getRouterId());
390 notifyDelegate(new OpenstackRouterEvent(
391 OPENSTACK_FLOATING_IP_CREATED,
392 osRouter,
393 event.newValue().value()));
394 });
395 break;
396 case REMOVE:
daniel parkb5817102018-02-15 00:18:51 +0900397 log.debug("OpenStack floating IP removed");
Hyunsun Moon44aac662017-02-18 02:07:01 +0900398 eventExecutor.execute(() -> {
399 Router osRouter = Strings.isNullOrEmpty(
400 event.oldValue().value().getRouterId()) ?
401 null :
402 router(event.oldValue().value().getRouterId());
403 notifyDelegate(new OpenstackRouterEvent(
404 OPENSTACK_FLOATING_IP_REMOVED,
405 osRouter,
406 event.oldValue().value()));
407 });
408 break;
409 default:
410 log.error("Unsupported event type");
411 break;
412 }
413 }
414
415 private void processFloatingIpUpdate(MapEvent<String, NetFloatingIP> event,
416 Router osRouter) {
417 String oldPortId = event.oldValue().value().getPortId();
418 String newPortId = event.newValue().value().getPortId();
419
420 if (Strings.isNullOrEmpty(oldPortId) && !Strings.isNullOrEmpty(newPortId)) {
421 notifyDelegate(new OpenstackRouterEvent(
422 OPENSTACK_FLOATING_IP_ASSOCIATED,
423 osRouter,
424 event.newValue().value(), newPortId));
425 }
426 if (!Strings.isNullOrEmpty(oldPortId) && Strings.isNullOrEmpty(newPortId)) {
427 notifyDelegate(new OpenstackRouterEvent(
428 OPENSTACK_FLOATING_IP_DISASSOCIATED,
429 osRouter,
430 event.newValue().value(), oldPortId));
431 }
432 }
433 }
434}