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